summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/mattermost/mattermost-server
diff options
context:
space:
mode:
authorWim <wim@42.be>2020-08-10 00:29:54 +0200
committerGitHub <noreply@github.com>2020-08-10 00:29:54 +0200
commit4e50fd864921c556988c919269448efdb90fa961 (patch)
treea3625f03f8de3c4f3841364000a4ea3aa42c1533 /vendor/github.com/mattermost/mattermost-server
parentdfdffa0027334e55ce213fc6eb62206dbf48baf6 (diff)
downloadmatterbridge-msglm-4e50fd864921c556988c919269448efdb90fa961.tar.gz
matterbridge-msglm-4e50fd864921c556988c919269448efdb90fa961.tar.bz2
matterbridge-msglm-4e50fd864921c556988c919269448efdb90fa961.zip
Use mattermost v5 module (#1192)
Diffstat (limited to 'vendor/github.com/mattermost/mattermost-server')
-rw-r--r--vendor/github.com/mattermost/mattermost-server/model/channel.go222
-rw-r--r--vendor/github.com/mattermost/mattermost-server/model/channel_search.go26
-rw-r--r--vendor/github.com/mattermost/mattermost-server/model/client4.go3839
-rw-r--r--vendor/github.com/mattermost/mattermost-server/model/command_args.go34
-rw-r--r--vendor/github.com/mattermost/mattermost-server/model/config.go2569
-rw-r--r--vendor/github.com/mattermost/mattermost-server/model/ldap.go8
-rw-r--r--vendor/github.com/mattermost/mattermost-server/model/migration.go8
-rw-r--r--vendor/github.com/mattermost/mattermost-server/model/push_notification.go70
-rw-r--r--vendor/github.com/mattermost/mattermost-server/model/role.go363
-rw-r--r--vendor/github.com/mattermost/mattermost-server/model/saml.go37
-rw-r--r--vendor/github.com/mattermost/mattermost-server/model/search_params.go228
-rw-r--r--vendor/github.com/mattermost/mattermost-server/model/system.go47
-rw-r--r--vendor/github.com/mattermost/mattermost-server/model/team_member.go102
-rw-r--r--vendor/github.com/mattermost/mattermost-server/model/user_search.go32
-rw-r--r--vendor/github.com/mattermost/mattermost-server/model/webrtc.go39
-rw-r--r--vendor/github.com/mattermost/mattermost-server/model/websocket_client.go195
-rw-r--r--vendor/github.com/mattermost/mattermost-server/model/websocket_message.go165
-rw-r--r--vendor/github.com/mattermost/mattermost-server/model/websocket_request.go34
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/LICENSE.txt (renamed from vendor/github.com/mattermost/mattermost-server/LICENSE.txt)2
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/NOTICE.txt (renamed from vendor/github.com/mattermost/mattermost-server/NOTICE.txt)473
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/mlog/default.go (renamed from vendor/github.com/mattermost/mattermost-server/mlog/default.go)9
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/mlog/global.go (renamed from vendor/github.com/mattermost/mattermost-server/mlog/global.go)2
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/mlog/log.go (renamed from vendor/github.com/mattermost/mattermost-server/mlog/log.go)13
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/mlog/stdlog.go (renamed from vendor/github.com/mattermost/mattermost-server/mlog/stdlog.go)4
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/mlog/sugar.go (renamed from vendor/github.com/mattermost/mattermost-server/mlog/sugar.go)0
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/mlog/testing.go43
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/access.go (renamed from vendor/github.com/mattermost/mattermost-server/model/access.go)8
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/analytics_row.go (renamed from vendor/github.com/mattermost/mattermost-server/model/analytics_row.go)2
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/at_mentions.go47
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/audit.go (renamed from vendor/github.com/mattermost/mattermost-server/model/audit.go)2
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/auditconv.go667
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/audits.go (renamed from vendor/github.com/mattermost/mattermost-server/model/audits.go)2
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/authorize.go (renamed from vendor/github.com/mattermost/mattermost-server/model/authorize.go)8
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/bot.go233
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/bot_default_image.go288
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/builtin.go (renamed from vendor/github.com/mattermost/mattermost-server/model/builtin.go)2
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/bundle_info.go (renamed from vendor/github.com/mattermost/mattermost-server/model/bundle_info.go)4
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/channel.go364
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/channel_count.go (renamed from vendor/github.com/mattermost/mattermost-server/model/channel_count.go)2
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/channel_data.go (renamed from vendor/github.com/mattermost/mattermost-server/model/channel_data.go)2
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/channel_list.go (renamed from vendor/github.com/mattermost/mattermost-server/model/channel_list.go)44
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/channel_member.go (renamed from vendor/github.com/mattermost/mattermost-server/model/channel_member.go)64
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/channel_member_history.go (renamed from vendor/github.com/mattermost/mattermost-server/model/channel_member_history.go)4
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/channel_member_history_result.go (renamed from vendor/github.com/mattermost/mattermost-server/model/channel_member_history_result.go)5
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/channel_mentions.go (renamed from vendor/github.com/mattermost/mattermost-server/model/channel_mentions.go)2
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/channel_search.go32
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/channel_stats.go (renamed from vendor/github.com/mattermost/mattermost-server/model/channel_stats.go)8
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/channel_view.go (renamed from vendor/github.com/mattermost/mattermost-server/model/channel_view.go)4
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/client4.go5095
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/cluster_discovery.go (renamed from vendor/github.com/mattermost/mattermost-server/model/cluster_discovery.go)14
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/cluster_info.go (renamed from vendor/github.com/mattermost/mattermost-server/model/cluster_info.go)2
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/cluster_message.go (renamed from vendor/github.com/mattermost/mattermost-server/model/cluster_message.go)24
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/cluster_stats.go (renamed from vendor/github.com/mattermost/mattermost-server/model/cluster_stats.go)2
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/command.go (renamed from vendor/github.com/mattermost/mattermost-server/model/command.go)53
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/command_args.go57
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/command_autocomplete.go455
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/command_request.go31
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/command_response.go (renamed from vendor/github.com/mattermost/mattermost-server/model/command_response.go)32
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/command_webhook.go (renamed from vendor/github.com/mattermost/mattermost-server/model/command_webhook.go)16
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/compliance.go (renamed from vendor/github.com/mattermost/mattermost-server/model/compliance.go)60
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/compliance_post.go (renamed from vendor/github.com/mattermost/mattermost-server/model/compliance_post.go)13
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/config.go3451
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/data_retention_policy.go (renamed from vendor/github.com/mattermost/mattermost-server/model/data_retention_policy.go)4
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/emoji.go (renamed from vendor/github.com/mattermost/mattermost-server/model/emoji.go)14
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/emoji_data.go (renamed from vendor/github.com/mattermost/mattermost-server/model/emoji_data.go)4
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/emoji_search.go (renamed from vendor/github.com/mattermost/mattermost-server/model/emoji_search.go)4
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/file.go (renamed from vendor/github.com/mattermost/mattermost-server/model/file.go)8
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/file_info.go (renamed from vendor/github.com/mattermost/mattermost-server/model/file_info.go)95
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/gitlab.go (renamed from vendor/github.com/mattermost/mattermost-server/model/gitlab.go)2
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/group.go210
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/group_member.go23
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/group_syncable.go180
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/guest_invite.go53
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/incoming_webhook.go (renamed from vendor/github.com/mattermost/mattermost-server/model/incoming_webhook.go)11
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/initial_load.go (renamed from vendor/github.com/mattermost/mattermost-server/model/initial_load.go)4
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/integration_action.go525
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/job.go (renamed from vendor/github.com/mattermost/mattermost-server/model/job.go)19
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/ldap.go8
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/license.go (renamed from vendor/github.com/mattermost/mattermost-server/model/license.go)90
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/link_metadata.go193
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/manifest.go (renamed from vendor/github.com/mattermost/mattermost-server/model/manifest.go)250
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/marketplace_plugin.go124
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/mention_map.go80
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/message_export.go (renamed from vendor/github.com/mattermost/mattermost-server/model/message_export.go)8
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/mfa_secret.go (renamed from vendor/github.com/mattermost/mattermost-server/model/mfa_secret.go)4
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/migration.go20
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/oauth.go (renamed from vendor/github.com/mattermost/mattermost-server/model/oauth.go)7
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/outgoing_webhook.go (renamed from vendor/github.com/mattermost/mattermost-server/model/outgoing_webhook.go)16
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/permission.go (renamed from vendor/github.com/mattermost/mattermost-server/model/permission.go)214
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/plugin_event_data.go25
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/plugin_key_value.go (renamed from vendor/github.com/mattermost/mattermost-server/model/plugin_key_value.go)5
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/plugin_kvset_options.go47
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/plugin_status.go (renamed from vendor/github.com/mattermost/mattermost-server/model/plugin_status.go)2
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/plugin_valid.go39
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/plugins_response.go (renamed from vendor/github.com/mattermost/mattermost-server/model/plugins_response.go)2
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/post.go (renamed from vendor/github.com/mattermost/mattermost-server/model/post.go)328
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/post_embed.go23
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/post_list.go (renamed from vendor/github.com/mattermost/mattermost-server/model/post_list.go)50
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/post_metadata.go45
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/post_search_results.go (renamed from vendor/github.com/mattermost/mattermost-server/model/post_search_results.go)2
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/preference.go (renamed from vendor/github.com/mattermost/mattermost-server/model/preference.go)9
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/preferences.go (renamed from vendor/github.com/mattermost/mattermost-server/model/preferences.go)2
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/push_notification.go117
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/push_response.go (renamed from vendor/github.com/mattermost/mattermost-server/model/push_response.go)2
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/reaction.go (renamed from vendor/github.com/mattermost/mattermost-server/model/reaction.go)24
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/role.go632
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/saml.go199
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/scheduled_task.go (renamed from vendor/github.com/mattermost/mattermost-server/model/scheduled_task.go)4
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/scheme.go (renamed from vendor/github.com/mattermost/mattermost-server/model/scheme.go)25
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/search_params.go369
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/security_bulletin.go (renamed from vendor/github.com/mattermost/mattermost-server/model/security_bulletin.go)2
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/session.go (renamed from vendor/github.com/mattermost/mattermost-server/model/session.go)48
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/slack_attachment.go (renamed from vendor/github.com/mattermost/mattermost-server/model/slack_attachment.go)123
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/slack_compatibility.go30
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/status.go (renamed from vendor/github.com/mattermost/mattermost-server/model/status.go)27
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/suggest_command.go (renamed from vendor/github.com/mattermost/mattermost-server/model/suggest_command.go)2
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/switch_request.go (renamed from vendor/github.com/mattermost/mattermost-server/model/switch_request.go)4
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/system.go71
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/team.go (renamed from vendor/github.com/mattermost/mattermost-server/model/team.go)70
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/team_member.go186
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/team_search.go (renamed from vendor/github.com/mattermost/mattermost-server/model/team_search.go)16
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/team_stats.go (renamed from vendor/github.com/mattermost/mattermost-server/model/team_stats.go)4
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/terms_of_service.go (renamed from vendor/github.com/mattermost/mattermost-server/model/terms_of_service.go)9
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/token.go (renamed from vendor/github.com/mattermost/mattermost-server/model/token.go)6
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/user.go (renamed from vendor/github.com/mattermost/mattermost-server/model/user.go)408
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/user_access_token.go (renamed from vendor/github.com/mattermost/mattermost-server/model/user_access_token.go)8
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/user_access_token_search.go (renamed from vendor/github.com/mattermost/mattermost-server/model/user_access_token_search.go)4
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/user_autocomplete.go (renamed from vendor/github.com/mattermost/mattermost-server/model/user_autocomplete.go)4
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/user_count.go18
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/user_get.go38
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/user_search.go67
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/user_terms_of_service.go61
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/users_stats.go (renamed from vendor/github.com/mattermost/mattermost-server/model/users_stats.go)4
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/utils.go (renamed from vendor/github.com/mattermost/mattermost-server/model/utils.go)183
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/version.go (renamed from vendor/github.com/mattermost/mattermost-server/model/version.go)22
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/websocket_client.go321
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/websocket_message.go259
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/model/websocket_request.go35
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/services/timezones/default.go (renamed from vendor/github.com/mattermost/mattermost-server/model/timezone.go)35
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/services/timezones/timezones.go29
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/utils/jsonutils/json.go (renamed from vendor/github.com/mattermost/mattermost-server/utils/jsonutils/json.go)2
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/utils/markdown/autolink.go (renamed from vendor/github.com/mattermost/mattermost-server/utils/markdown/autolink.go)8
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/utils/markdown/block_quote.go (renamed from vendor/github.com/mattermost/mattermost-server/utils/markdown/block_quote.go)4
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/utils/markdown/blocks.go (renamed from vendor/github.com/mattermost/mattermost-server/utils/markdown/blocks.go)8
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/utils/markdown/document.go (renamed from vendor/github.com/mattermost/mattermost-server/utils/markdown/document.go)4
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/utils/markdown/fenced_code.go (renamed from vendor/github.com/mattermost/mattermost-server/utils/markdown/fenced_code.go)4
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/utils/markdown/html.go (renamed from vendor/github.com/mattermost/mattermost-server/utils/markdown/html.go)4
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/utils/markdown/html_entities.go (renamed from vendor/github.com/mattermost/mattermost-server/utils/markdown/html_entities.go)4
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/utils/markdown/indented_code.go (renamed from vendor/github.com/mattermost/mattermost-server/utils/markdown/indented_code.go)4
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/utils/markdown/inlines.go (renamed from vendor/github.com/mattermost/mattermost-server/utils/markdown/inlines.go)8
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/utils/markdown/inspect.go (renamed from vendor/github.com/mattermost/mattermost-server/utils/markdown/inspect.go)4
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/utils/markdown/lines.go (renamed from vendor/github.com/mattermost/mattermost-server/utils/markdown/lines.go)4
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/utils/markdown/links.go (renamed from vendor/github.com/mattermost/mattermost-server/utils/markdown/links.go)4
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/utils/markdown/list.go (renamed from vendor/github.com/mattermost/mattermost-server/utils/markdown/list.go)4
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/utils/markdown/markdown.go (renamed from vendor/github.com/mattermost/mattermost-server/utils/markdown/markdown.go)4
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/utils/markdown/paragraph.go (renamed from vendor/github.com/mattermost/mattermost-server/utils/markdown/paragraph.go)4
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/utils/markdown/reference_definition.go (renamed from vendor/github.com/mattermost/mattermost-server/utils/markdown/reference_definition.go)4
157 files changed, 17264 insertions, 8692 deletions
diff --git a/vendor/github.com/mattermost/mattermost-server/model/channel.go b/vendor/github.com/mattermost/mattermost-server/model/channel.go
deleted file mode 100644
index 529c49d3..00000000
--- a/vendor/github.com/mattermost/mattermost-server/model/channel.go
+++ /dev/null
@@ -1,222 +0,0 @@
-// 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"
- "sort"
- "strings"
- "unicode/utf8"
-)
-
-const (
- CHANNEL_OPEN = "O"
- CHANNEL_PRIVATE = "P"
- CHANNEL_DIRECT = "D"
- CHANNEL_GROUP = "G"
- CHANNEL_GROUP_MAX_USERS = 8
- CHANNEL_GROUP_MIN_USERS = 3
- DEFAULT_CHANNEL = "town-square"
- CHANNEL_DISPLAY_NAME_MAX_RUNES = 64
- CHANNEL_NAME_MIN_LENGTH = 2
- CHANNEL_NAME_MAX_LENGTH = 64
- CHANNEL_NAME_UI_MAX_LENGTH = 22
- CHANNEL_HEADER_MAX_RUNES = 1024
- CHANNEL_PURPOSE_MAX_RUNES = 250
- CHANNEL_CACHE_SIZE = 25000
-)
-
-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 string `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]interface{} `json:"props" db:"-"`
-}
-
-type ChannelPatch struct {
- DisplayName *string `json:"display_name"`
- Name *string `json:"name"`
- Header *string `json:"header"`
- Purpose *string `json:"purpose"`
-}
-
-type ChannelForExport struct {
- Channel
- TeamName string
- SchemeName *string
-}
-
-func (o *Channel) DeepCopy() *Channel {
- copy := *o
- if copy.SchemeId != nil {
- copy.SchemeId = NewString(*o.SchemeId)
- }
- return &copy
-}
-
-func (o *Channel) ToJson() string {
- b, _ := json.Marshal(o)
- return string(b)
-}
-
-func (o *ChannelPatch) ToJson() string {
- b, _ := json.Marshal(o)
- return string(b)
-}
-
-func ChannelFromJson(data io.Reader) *Channel {
- var o *Channel
- json.NewDecoder(data).Decode(&o)
- return o
-}
-
-func ChannelPatchFromJson(data io.Reader) *ChannelPatch {
- var o *ChannelPatch
- json.NewDecoder(data).Decode(&o)
- return o
-}
-
-func (o *Channel) Etag() string {
- return Etag(o.Id, o.UpdateAt)
-}
-
-func (o *Channel) IsValid() *AppError {
- if len(o.Id) != 26 {
- 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) > CHANNEL_DISPLAY_NAME_MAX_RUNES {
- 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.2_or_more.app_error", nil, "id="+o.Id, http.StatusBadRequest)
- }
-
- if !(o.Type == CHANNEL_OPEN || o.Type == CHANNEL_PRIVATE || o.Type == CHANNEL_DIRECT || o.Type == CHANNEL_GROUP) {
- return NewAppError("Channel.IsValid", "model.channel.is_valid.type.app_error", nil, "id="+o.Id, http.StatusBadRequest)
- }
-
- if utf8.RuneCountInString(o.Header) > CHANNEL_HEADER_MAX_RUNES {
- return NewAppError("Channel.IsValid", "model.channel.is_valid.header.app_error", nil, "id="+o.Id, http.StatusBadRequest)
- }
-
- if utf8.RuneCountInString(o.Purpose) > CHANNEL_PURPOSE_MAX_RUNES {
- 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)
- }
-
- return nil
-}
-
-func (o *Channel) PreSave() {
- if o.Id == "" {
- o.Id = NewId()
- }
-
- o.CreateAt = GetMillis()
- o.UpdateAt = o.CreateAt
- o.ExtraUpdateAt = 0
-}
-
-func (o *Channel) PreUpdate() {
- o.UpdateAt = GetMillis()
-}
-
-func (o *Channel) IsGroupOrDirect() bool {
- return o.Type == CHANNEL_DIRECT || o.Type == CHANNEL_GROUP
-}
-
-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
- }
-}
-
-func (o *Channel) MakeNonNil() {
- if o.Props == nil {
- o.Props = make(map[string]interface{})
- }
-}
-
-func (o *Channel) AddProp(key string, value interface{}) {
- o.MakeNonNil()
-
- o.Props[key] = value
-}
-
-func GetDMNameFromIds(userId1, userId2 string) string {
- if userId1 > userId2 {
- return userId2 + "__" + userId1
- } else {
- 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) > CHANNEL_NAME_MAX_LENGTH {
- name = name[:CHANNEL_NAME_MAX_LENGTH]
- }
-
- 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))
-}
diff --git a/vendor/github.com/mattermost/mattermost-server/model/channel_search.go b/vendor/github.com/mattermost/mattermost-server/model/channel_search.go
deleted file mode 100644
index 593cf669..00000000
--- a/vendor/github.com/mattermost/mattermost-server/model/channel_search.go
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-package model
-
-import (
- "encoding/json"
- "io"
-)
-
-type ChannelSearch struct {
- Term string `json:"term"`
-}
-
-// ToJson convert a Channel to a json string
-func (c *ChannelSearch) ToJson() string {
- b, _ := json.Marshal(c)
- return string(b)
-}
-
-// ChannelSearchFromJson will decode the input and return a Channel
-func ChannelSearchFromJson(data io.Reader) *ChannelSearch {
- var cs *ChannelSearch
- json.NewDecoder(data).Decode(&cs)
- return cs
-}
diff --git a/vendor/github.com/mattermost/mattermost-server/model/client4.go b/vendor/github.com/mattermost/mattermost-server/model/client4.go
deleted file mode 100644
index 57c4fb7c..00000000
--- a/vendor/github.com/mattermost/mattermost-server/model/client4.go
+++ /dev/null
@@ -1,3839 +0,0 @@
-// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-package model
-
-import (
- "bytes"
- "fmt"
- "io"
- "io/ioutil"
- "mime/multipart"
- "net/http"
- "net/url"
- "strconv"
- "strings"
- "time"
-)
-
-const (
- HEADER_REQUEST_ID = "X-Request-ID"
- HEADER_VERSION_ID = "X-Version-ID"
- HEADER_CLUSTER_ID = "X-Cluster-ID"
- HEADER_ETAG_SERVER = "ETag"
- HEADER_ETAG_CLIENT = "If-None-Match"
- HEADER_FORWARDED = "X-Forwarded-For"
- HEADER_REAL_IP = "X-Real-IP"
- HEADER_FORWARDED_PROTO = "X-Forwarded-Proto"
- HEADER_TOKEN = "token"
- HEADER_BEARER = "BEARER"
- HEADER_AUTH = "Authorization"
- HEADER_REQUESTED_WITH = "X-Requested-With"
- HEADER_REQUESTED_WITH_XML = "XMLHttpRequest"
- STATUS = "status"
- STATUS_OK = "OK"
- STATUS_FAIL = "FAIL"
- STATUS_REMOVE = "REMOVE"
-
- CLIENT_DIR = "client"
-
- API_URL_SUFFIX_V1 = "/api/v1"
- API_URL_SUFFIX_V4 = "/api/v4"
- API_URL_SUFFIX = API_URL_SUFFIX_V4
-)
-
-type Response struct {
- StatusCode int
- Error *AppError
- RequestId string
- Etag string
- ServerVersion string
- Header http.Header
-}
-
-type Client4 struct {
- Url string // The location of the server, for example "http://localhost:8065"
- ApiUrl string // The api location of the server, for example "http://localhost:8065/api/v4"
- HttpClient *http.Client // The http client
- AuthToken string
- AuthType string
- HttpHeader map[string]string // Headers to be copied over for each request
-}
-
-func closeBody(r *http.Response) {
- if r.Body != nil {
- ioutil.ReadAll(r.Body)
- r.Body.Close()
- }
-}
-
-// Must is a convenience function used for testing.
-func (c *Client4) Must(result interface{}, resp *Response) interface{} {
- if resp.Error != nil {
-
- time.Sleep(time.Second)
- panic(resp.Error)
- }
-
- return result
-}
-
-func NewAPIv4Client(url string) *Client4 {
- return &Client4{url, url + API_URL_SUFFIX, &http.Client{}, "", "", map[string]string{}}
-}
-
-func BuildErrorResponse(r *http.Response, err *AppError) *Response {
- var statusCode int
- var header http.Header
- if r != nil {
- statusCode = r.StatusCode
- header = r.Header
- } else {
- statusCode = 0
- header = make(http.Header)
- }
-
- return &Response{
- StatusCode: statusCode,
- Error: err,
- Header: header,
- }
-}
-
-func BuildResponse(r *http.Response) *Response {
- return &Response{
- StatusCode: r.StatusCode,
- RequestId: r.Header.Get(HEADER_REQUEST_ID),
- Etag: r.Header.Get(HEADER_ETAG_SERVER),
- ServerVersion: r.Header.Get(HEADER_VERSION_ID),
- Header: r.Header,
- }
-}
-
-func (c *Client4) MockSession(sessionToken string) {
- c.AuthToken = sessionToken
- c.AuthType = HEADER_BEARER
-}
-
-func (c *Client4) SetOAuthToken(token string) {
- c.AuthToken = token
- c.AuthType = HEADER_TOKEN
-}
-
-func (c *Client4) ClearOAuthToken() {
- c.AuthToken = ""
- c.AuthType = HEADER_BEARER
-}
-
-func (c *Client4) GetUsersRoute() string {
- return fmt.Sprintf("/users")
-}
-
-func (c *Client4) GetUserRoute(userId string) string {
- return fmt.Sprintf(c.GetUsersRoute()+"/%v", userId)
-}
-
-func (c *Client4) GetUserAccessTokensRoute() string {
- return fmt.Sprintf(c.GetUsersRoute() + "/tokens")
-}
-
-func (c *Client4) GetUserAccessTokenRoute(tokenId string) string {
- return fmt.Sprintf(c.GetUsersRoute()+"/tokens/%v", tokenId)
-}
-
-func (c *Client4) GetUserByUsernameRoute(userName string) string {
- return fmt.Sprintf(c.GetUsersRoute()+"/username/%v", userName)
-}
-
-func (c *Client4) GetUserByEmailRoute(email string) string {
- return fmt.Sprintf(c.GetUsersRoute()+"/email/%v", email)
-}
-
-func (c *Client4) GetTeamsRoute() string {
- return fmt.Sprintf("/teams")
-}
-
-func (c *Client4) GetTeamRoute(teamId string) string {
- return fmt.Sprintf(c.GetTeamsRoute()+"/%v", teamId)
-}
-
-func (c *Client4) GetTeamAutoCompleteCommandsRoute(teamId string) string {
- return fmt.Sprintf(c.GetTeamsRoute()+"/%v/commands/autocomplete", teamId)
-}
-
-func (c *Client4) GetTeamByNameRoute(teamName string) string {
- return fmt.Sprintf(c.GetTeamsRoute()+"/name/%v", teamName)
-}
-
-func (c *Client4) GetTeamMemberRoute(teamId, userId string) string {
- return fmt.Sprintf(c.GetTeamRoute(teamId)+"/members/%v", userId)
-}
-
-func (c *Client4) GetTeamMembersRoute(teamId string) string {
- return fmt.Sprintf(c.GetTeamRoute(teamId) + "/members")
-}
-
-func (c *Client4) GetTeamStatsRoute(teamId string) string {
- return fmt.Sprintf(c.GetTeamRoute(teamId) + "/stats")
-}
-
-func (c *Client4) GetTeamImportRoute(teamId string) string {
- return fmt.Sprintf(c.GetTeamRoute(teamId) + "/import")
-}
-
-func (c *Client4) GetChannelsRoute() string {
- return fmt.Sprintf("/channels")
-}
-
-func (c *Client4) GetChannelsForTeamRoute(teamId string) string {
- return fmt.Sprintf(c.GetTeamRoute(teamId) + "/channels")
-}
-
-func (c *Client4) GetChannelRoute(channelId string) string {
- return fmt.Sprintf(c.GetChannelsRoute()+"/%v", channelId)
-}
-
-func (c *Client4) GetChannelByNameRoute(channelName, teamId string) string {
- return fmt.Sprintf(c.GetTeamRoute(teamId)+"/channels/name/%v", channelName)
-}
-
-func (c *Client4) GetChannelByNameForTeamNameRoute(channelName, teamName string) string {
- return fmt.Sprintf(c.GetTeamByNameRoute(teamName)+"/channels/name/%v", channelName)
-}
-
-func (c *Client4) GetChannelMembersRoute(channelId string) string {
- return fmt.Sprintf(c.GetChannelRoute(channelId) + "/members")
-}
-
-func (c *Client4) GetChannelMemberRoute(channelId, userId string) string {
- return fmt.Sprintf(c.GetChannelMembersRoute(channelId)+"/%v", userId)
-}
-
-func (c *Client4) GetPostsRoute() string {
- return fmt.Sprintf("/posts")
-}
-
-func (c *Client4) GetPostsEphemeralRoute() string {
- return fmt.Sprintf("/posts/ephemeral")
-}
-
-func (c *Client4) GetConfigRoute() string {
- return fmt.Sprintf("/config")
-}
-
-func (c *Client4) GetLicenseRoute() string {
- return fmt.Sprintf("/license")
-}
-
-func (c *Client4) GetPostRoute(postId string) string {
- return fmt.Sprintf(c.GetPostsRoute()+"/%v", postId)
-}
-
-func (c *Client4) GetFilesRoute() string {
- return fmt.Sprintf("/files")
-}
-
-func (c *Client4) GetFileRoute(fileId string) string {
- return fmt.Sprintf(c.GetFilesRoute()+"/%v", fileId)
-}
-
-func (c *Client4) GetPluginsRoute() string {
- return fmt.Sprintf("/plugins")
-}
-
-func (c *Client4) GetPluginRoute(pluginId string) string {
- return fmt.Sprintf(c.GetPluginsRoute()+"/%v", pluginId)
-}
-
-func (c *Client4) GetSystemRoute() string {
- return fmt.Sprintf("/system")
-}
-
-func (c *Client4) GetTestEmailRoute() string {
- return fmt.Sprintf("/email/test")
-}
-
-func (c *Client4) GetTestS3Route() string {
- return fmt.Sprintf("/file/s3_test")
-}
-
-func (c *Client4) GetDatabaseRoute() string {
- return fmt.Sprintf("/database")
-}
-
-func (c *Client4) GetCacheRoute() string {
- return fmt.Sprintf("/caches")
-}
-
-func (c *Client4) GetClusterRoute() string {
- return fmt.Sprintf("/cluster")
-}
-
-func (c *Client4) GetIncomingWebhooksRoute() string {
- return fmt.Sprintf("/hooks/incoming")
-}
-
-func (c *Client4) GetIncomingWebhookRoute(hookID string) string {
- return fmt.Sprintf(c.GetIncomingWebhooksRoute()+"/%v", hookID)
-}
-
-func (c *Client4) GetComplianceReportsRoute() string {
- return fmt.Sprintf("/compliance/reports")
-}
-
-func (c *Client4) GetComplianceReportRoute(reportId string) string {
- return fmt.Sprintf("/compliance/reports/%v", reportId)
-}
-
-func (c *Client4) GetOutgoingWebhooksRoute() string {
- return fmt.Sprintf("/hooks/outgoing")
-}
-
-func (c *Client4) GetOutgoingWebhookRoute(hookID string) string {
- return fmt.Sprintf(c.GetOutgoingWebhooksRoute()+"/%v", hookID)
-}
-
-func (c *Client4) GetPreferencesRoute(userId string) string {
- return fmt.Sprintf(c.GetUserRoute(userId) + "/preferences")
-}
-
-func (c *Client4) GetUserStatusRoute(userId string) string {
- return fmt.Sprintf(c.GetUserRoute(userId) + "/status")
-}
-
-func (c *Client4) GetUserStatusesRoute() string {
- return fmt.Sprintf(c.GetUsersRoute() + "/status")
-}
-
-func (c *Client4) GetSamlRoute() string {
- return fmt.Sprintf("/saml")
-}
-
-func (c *Client4) GetLdapRoute() string {
- return fmt.Sprintf("/ldap")
-}
-
-func (c *Client4) GetBrandRoute() string {
- return fmt.Sprintf("/brand")
-}
-
-func (c *Client4) GetDataRetentionRoute() string {
- return fmt.Sprintf("/data_retention")
-}
-
-func (c *Client4) GetElasticsearchRoute() string {
- return fmt.Sprintf("/elasticsearch")
-}
-
-func (c *Client4) GetCommandsRoute() string {
- return fmt.Sprintf("/commands")
-}
-
-func (c *Client4) GetCommandRoute(commandId string) string {
- return fmt.Sprintf(c.GetCommandsRoute()+"/%v", commandId)
-}
-
-func (c *Client4) GetEmojisRoute() string {
- return fmt.Sprintf("/emoji")
-}
-
-func (c *Client4) GetEmojiRoute(emojiId string) string {
- return fmt.Sprintf(c.GetEmojisRoute()+"/%v", emojiId)
-}
-
-func (c *Client4) GetEmojiByNameRoute(name string) string {
- return fmt.Sprintf(c.GetEmojisRoute()+"/name/%v", name)
-}
-
-func (c *Client4) GetReactionsRoute() string {
- return fmt.Sprintf("/reactions")
-}
-
-func (c *Client4) GetOAuthAppsRoute() string {
- return fmt.Sprintf("/oauth/apps")
-}
-
-func (c *Client4) GetOAuthAppRoute(appId string) string {
- return fmt.Sprintf("/oauth/apps/%v", appId)
-}
-
-func (c *Client4) GetOpenGraphRoute() string {
- return fmt.Sprintf("/opengraph")
-}
-
-func (c *Client4) GetJobsRoute() string {
- return fmt.Sprintf("/jobs")
-}
-
-func (c *Client4) GetRolesRoute() string {
- return fmt.Sprintf("/roles")
-}
-
-func (c *Client4) GetSchemesRoute() string {
- return fmt.Sprintf("/schemes")
-}
-
-func (c *Client4) GetSchemeRoute(id string) string {
- return c.GetSchemesRoute() + fmt.Sprintf("/%v", id)
-}
-
-func (c *Client4) GetAnalyticsRoute() string {
- return fmt.Sprintf("/analytics")
-}
-
-func (c *Client4) GetTimezonesRoute() string {
- return fmt.Sprintf(c.GetSystemRoute() + "/timezones")
-}
-
-func (c *Client4) GetChannelSchemeRoute(channelId string) string {
- return fmt.Sprintf(c.GetChannelsRoute()+"/%v/scheme", channelId)
-}
-
-func (c *Client4) GetTeamSchemeRoute(teamId string) string {
- return fmt.Sprintf(c.GetTeamsRoute()+"/%v/scheme", teamId)
-}
-
-func (c *Client4) GetTotalUsersStatsRoute() string {
- return fmt.Sprintf(c.GetUsersRoute() + "/stats")
-}
-
-func (c *Client4) GetRedirectLocationRoute() string {
- return fmt.Sprintf("/redirect_location")
-}
-
-func (c *Client4) GetRegisterTermsOfServiceRoute(userId string) string {
- return c.GetUserRoute(userId) + "/terms_of_service"
-}
-
-func (c *Client4) GetTermsOfServiceRoute() string {
- return "/terms_of_service"
-}
-
-func (c *Client4) DoApiGet(url string, etag string) (*http.Response, *AppError) {
- return c.DoApiRequest(http.MethodGet, c.ApiUrl+url, "", etag)
-}
-
-func (c *Client4) DoApiPost(url string, data string) (*http.Response, *AppError) {
- return c.DoApiRequest(http.MethodPost, c.ApiUrl+url, data, "")
-}
-
-func (c *Client4) DoApiPut(url string, data string) (*http.Response, *AppError) {
- return c.DoApiRequest(http.MethodPut, c.ApiUrl+url, data, "")
-}
-
-func (c *Client4) DoApiDelete(url string) (*http.Response, *AppError) {
- return c.DoApiRequest(http.MethodDelete, c.ApiUrl+url, "", "")
-}
-
-func (c *Client4) DoApiRequest(method, url, data, etag string) (*http.Response, *AppError) {
- rq, _ := http.NewRequest(method, url, strings.NewReader(data))
-
- if len(etag) > 0 {
- rq.Header.Set(HEADER_ETAG_CLIENT, etag)
- }
-
- if len(c.AuthToken) > 0 {
- rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken)
- }
-
- if c.HttpHeader != nil && len(c.HttpHeader) > 0 {
-
- for k, v := range c.HttpHeader {
- rq.Header.Set(k, v)
- }
- }
-
- if rp, err := c.HttpClient.Do(rq); err != nil || rp == nil {
- return nil, NewAppError(url, "model.client.connecting.app_error", nil, err.Error(), 0)
- } else if rp.StatusCode == 304 {
- return rp, nil
- } else if rp.StatusCode >= 300 {
- defer closeBody(rp)
- return rp, AppErrorFromJson(rp.Body)
- } else {
- return rp, nil
- }
-}
-
-func (c *Client4) DoUploadFile(url string, data []byte, contentType string) (*FileUploadResponse, *Response) {
- rq, _ := http.NewRequest("POST", c.ApiUrl+url, bytes.NewReader(data))
- rq.Header.Set("Content-Type", contentType)
-
- if len(c.AuthToken) > 0 {
- rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken)
- }
-
- if rp, err := c.HttpClient.Do(rq); err != nil || rp == nil {
- return nil, BuildErrorResponse(rp, NewAppError(url, "model.client.connecting.app_error", nil, err.Error(), 0))
- } else {
- defer closeBody(rp)
-
- if rp.StatusCode >= 300 {
- return nil, BuildErrorResponse(rp, AppErrorFromJson(rp.Body))
- } else {
- return FileUploadResponseFromJson(rp.Body), BuildResponse(rp)
- }
- }
-}
-
-func (c *Client4) DoEmojiUploadFile(url string, data []byte, contentType string) (*Emoji, *Response) {
- rq, _ := http.NewRequest("POST", c.ApiUrl+url, bytes.NewReader(data))
- rq.Header.Set("Content-Type", contentType)
-
- if len(c.AuthToken) > 0 {
- rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken)
- }
-
- if rp, err := c.HttpClient.Do(rq); err != nil || rp == nil {
- return nil, BuildErrorResponse(rp, NewAppError(url, "model.client.connecting.app_error", nil, err.Error(), 0))
- } else {
- defer closeBody(rp)
-
- if rp.StatusCode >= 300 {
- return nil, BuildErrorResponse(rp, AppErrorFromJson(rp.Body))
- } else {
- return EmojiFromJson(rp.Body), BuildResponse(rp)
- }
- }
-}
-
-func (c *Client4) DoUploadImportTeam(url string, data []byte, contentType string) (map[string]string, *Response) {
- rq, _ := http.NewRequest("POST", c.ApiUrl+url, bytes.NewReader(data))
- rq.Header.Set("Content-Type", contentType)
-
- if len(c.AuthToken) > 0 {
- rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken)
- }
-
- if rp, err := c.HttpClient.Do(rq); err != nil || rp == nil {
- return nil, BuildErrorResponse(rp, NewAppError(url, "model.client.connecting.app_error", nil, err.Error(), 0))
- } else {
- defer closeBody(rp)
-
- if rp.StatusCode >= 300 {
- return nil, BuildErrorResponse(rp, AppErrorFromJson(rp.Body))
- } else {
- return MapFromJson(rp.Body), BuildResponse(rp)
- }
- }
-}
-
-// CheckStatusOK is a convenience function for checking the standard OK response
-// from the web service.
-func CheckStatusOK(r *http.Response) bool {
- m := MapFromJson(r.Body)
- defer closeBody(r)
-
- if m != nil && m[STATUS] == STATUS_OK {
- return true
- }
-
- return false
-}
-
-// Authentication Section
-
-// LoginById authenticates a user by user id and password.
-func (c *Client4) LoginById(id string, password string) (*User, *Response) {
- m := make(map[string]string)
- m["id"] = id
- m["password"] = password
- return c.login(m)
-}
-
-// Login authenticates a user by login id, which can be username, email or some sort
-// of SSO identifier based on server configuration, and a password.
-func (c *Client4) Login(loginId string, password string) (*User, *Response) {
- m := make(map[string]string)
- m["login_id"] = loginId
- m["password"] = password
- return c.login(m)
-}
-
-// LoginByLdap authenticates a user by LDAP id and password.
-func (c *Client4) LoginByLdap(loginId string, password string) (*User, *Response) {
- m := make(map[string]string)
- m["login_id"] = loginId
- m["password"] = password
- m["ldap_only"] = "true"
- return c.login(m)
-}
-
-// LoginWithDevice authenticates a user by login id (username, email or some sort
-// of SSO identifier based on configuration), password and attaches a device id to
-// the session.
-func (c *Client4) LoginWithDevice(loginId string, password string, deviceId string) (*User, *Response) {
- m := make(map[string]string)
- m["login_id"] = loginId
- m["password"] = password
- m["device_id"] = deviceId
- return c.login(m)
-}
-
-func (c *Client4) login(m map[string]string) (*User, *Response) {
- if r, err := c.DoApiPost("/users/login", MapToJson(m)); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- c.AuthToken = r.Header.Get(HEADER_TOKEN)
- c.AuthType = HEADER_BEARER
- defer closeBody(r)
- return UserFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// Logout terminates the current user's session.
-func (c *Client4) Logout() (bool, *Response) {
- if r, err := c.DoApiPost("/users/logout", ""); err != nil {
- return false, BuildErrorResponse(r, err)
- } else {
- c.AuthToken = ""
- c.AuthType = HEADER_BEARER
-
- defer closeBody(r)
- return CheckStatusOK(r), BuildResponse(r)
- }
-}
-
-// SwitchAccountType changes a user's login type from one type to another.
-func (c *Client4) SwitchAccountType(switchRequest *SwitchRequest) (string, *Response) {
- if r, err := c.DoApiPost(c.GetUsersRoute()+"/login/switch", switchRequest.ToJson()); err != nil {
- return "", BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return MapFromJson(r.Body)["follow_link"], BuildResponse(r)
- }
-}
-
-// User Section
-
-// CreateUser creates a user in the system based on the provided user struct.
-func (c *Client4) CreateUser(user *User) (*User, *Response) {
- if r, err := c.DoApiPost(c.GetUsersRoute(), user.ToJson()); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return UserFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// CreateUserWithToken creates a user in the system based on the provided tokenId.
-func (c *Client4) CreateUserWithToken(user *User, tokenId string) (*User, *Response) {
- var query string
- if tokenId != "" {
- query = fmt.Sprintf("?t=%v", tokenId)
- } else {
- err := NewAppError("MissingHashOrData", "api.user.create_user.missing_token.app_error", nil, "", http.StatusBadRequest)
- return nil, &Response{StatusCode: err.StatusCode, Error: err}
- }
- if r, err := c.DoApiPost(c.GetUsersRoute()+query, user.ToJson()); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return UserFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// CreateUserWithInviteId creates a user in the system based on the provided invited id.
-func (c *Client4) CreateUserWithInviteId(user *User, inviteId string) (*User, *Response) {
- var query string
- if inviteId != "" {
- query = fmt.Sprintf("?iid=%v", url.QueryEscape(inviteId))
- } else {
- err := NewAppError("MissingInviteId", "api.user.create_user.missing_invite_id.app_error", nil, "", http.StatusBadRequest)
- return nil, &Response{StatusCode: err.StatusCode, Error: err}
- }
- if r, err := c.DoApiPost(c.GetUsersRoute()+query, user.ToJson()); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return UserFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// GetMe returns the logged in user.
-func (c *Client4) GetMe(etag string) (*User, *Response) {
- if r, err := c.DoApiGet(c.GetUserRoute(ME), etag); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return UserFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// GetUser returns a user based on the provided user id string.
-func (c *Client4) GetUser(userId, etag string) (*User, *Response) {
- if r, err := c.DoApiGet(c.GetUserRoute(userId), etag); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return UserFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// GetUserByUsername returns a user based on the provided user name string.
-func (c *Client4) GetUserByUsername(userName, etag string) (*User, *Response) {
- if r, err := c.DoApiGet(c.GetUserByUsernameRoute(userName), etag); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return UserFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// GetUserByEmail returns a user based on the provided user email string.
-func (c *Client4) GetUserByEmail(email, etag string) (*User, *Response) {
- if r, err := c.DoApiGet(c.GetUserByEmailRoute(email), etag); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return UserFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// AutocompleteUsersInTeam returns the users on a team based on search term.
-func (c *Client4) AutocompleteUsersInTeam(teamId string, username string, etag string) (*UserAutocomplete, *Response) {
- query := fmt.Sprintf("?in_team=%v&name=%v", teamId, username)
- if r, err := c.DoApiGet(c.GetUsersRoute()+"/autocomplete"+query, etag); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return UserAutocompleteFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// AutocompleteUsersInChannel returns the users in a channel based on search term.
-func (c *Client4) AutocompleteUsersInChannel(teamId string, channelId string, username string, etag string) (*UserAutocomplete, *Response) {
- query := fmt.Sprintf("?in_team=%v&in_channel=%v&name=%v", teamId, channelId, username)
- if r, err := c.DoApiGet(c.GetUsersRoute()+"/autocomplete"+query, etag); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return UserAutocompleteFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// AutocompleteUsers returns the users in the system based on search term.
-func (c *Client4) AutocompleteUsers(username string, etag string) (*UserAutocomplete, *Response) {
- query := fmt.Sprintf("?name=%v", username)
- if r, err := c.DoApiGet(c.GetUsersRoute()+"/autocomplete"+query, etag); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return UserAutocompleteFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// GetProfileImage gets user's profile image. Must be logged in or be a system administrator.
-func (c *Client4) GetProfileImage(userId, etag string) ([]byte, *Response) {
- if r, err := c.DoApiGet(c.GetUserRoute(userId)+"/image", etag); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
-
- if data, err := ioutil.ReadAll(r.Body); err != nil {
- return nil, BuildErrorResponse(r, NewAppError("GetProfileImage", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode))
- } else {
- return data, BuildResponse(r)
- }
- }
-}
-
-// GetUsers returns a page of users on the system. Page counting starts at 0.
-func (c *Client4) GetUsers(page int, perPage int, etag string) ([]*User, *Response) {
- query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
- if r, err := c.DoApiGet(c.GetUsersRoute()+query, etag); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return UserListFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// GetUsersInTeam returns a page of users on a team. Page counting starts at 0.
-func (c *Client4) GetUsersInTeam(teamId string, page int, perPage int, etag string) ([]*User, *Response) {
- query := fmt.Sprintf("?in_team=%v&page=%v&per_page=%v", teamId, page, perPage)
- if r, err := c.DoApiGet(c.GetUsersRoute()+query, etag); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return UserListFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// GetNewUsersInTeam returns a page of users on a team. Page counting starts at 0.
-func (c *Client4) GetNewUsersInTeam(teamId string, page int, perPage int, etag string) ([]*User, *Response) {
- query := fmt.Sprintf("?sort=create_at&in_team=%v&page=%v&per_page=%v", teamId, page, perPage)
- if r, err := c.DoApiGet(c.GetUsersRoute()+query, etag); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return UserListFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// GetRecentlyActiveUsersInTeam returns a page of users on a team. Page counting starts at 0.
-func (c *Client4) GetRecentlyActiveUsersInTeam(teamId string, page int, perPage int, etag string) ([]*User, *Response) {
- query := fmt.Sprintf("?sort=last_activity_at&in_team=%v&page=%v&per_page=%v", teamId, page, perPage)
- if r, err := c.DoApiGet(c.GetUsersRoute()+query, etag); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return UserListFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// GetUsersNotInTeam returns a page of users who are not in a team. Page counting starts at 0.
-func (c *Client4) GetUsersNotInTeam(teamId string, page int, perPage int, etag string) ([]*User, *Response) {
- query := fmt.Sprintf("?not_in_team=%v&page=%v&per_page=%v", teamId, page, perPage)
- if r, err := c.DoApiGet(c.GetUsersRoute()+query, etag); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return UserListFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// GetUsersInChannel returns a page of users in a channel. Page counting starts at 0.
-func (c *Client4) GetUsersInChannel(channelId string, page int, perPage int, etag string) ([]*User, *Response) {
- query := fmt.Sprintf("?in_channel=%v&page=%v&per_page=%v", channelId, page, perPage)
- if r, err := c.DoApiGet(c.GetUsersRoute()+query, etag); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return UserListFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// GetUsersInChannelStatus returns a page of users in a channel. Page counting starts at 0. Sorted by Status
-func (c *Client4) GetUsersInChannelByStatus(channelId string, page int, perPage int, etag string) ([]*User, *Response) {
- query := fmt.Sprintf("?in_channel=%v&page=%v&per_page=%v&sort=status", channelId, page, perPage)
- if r, err := c.DoApiGet(c.GetUsersRoute()+query, etag); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return UserListFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// GetUsersNotInChannel returns a page of users not in a channel. Page counting starts at 0.
-func (c *Client4) GetUsersNotInChannel(teamId, channelId string, page int, perPage int, etag string) ([]*User, *Response) {
- query := fmt.Sprintf("?in_team=%v&not_in_channel=%v&page=%v&per_page=%v", teamId, channelId, page, perPage)
- if r, err := c.DoApiGet(c.GetUsersRoute()+query, etag); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return UserListFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// GetUsersWithoutTeam returns a page of users on the system that aren't on any teams. Page counting starts at 0.
-func (c *Client4) GetUsersWithoutTeam(page int, perPage int, etag string) ([]*User, *Response) {
- query := fmt.Sprintf("?without_team=1&page=%v&per_page=%v", page, perPage)
- if r, err := c.DoApiGet(c.GetUsersRoute()+query, etag); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return UserListFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// GetUsersByIds returns a list of users based on the provided user ids.
-func (c *Client4) GetUsersByIds(userIds []string) ([]*User, *Response) {
- if r, err := c.DoApiPost(c.GetUsersRoute()+"/ids", ArrayToJson(userIds)); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return UserListFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// GetUsersByUsernames returns a list of users based on the provided usernames.
-func (c *Client4) GetUsersByUsernames(usernames []string) ([]*User, *Response) {
- if r, err := c.DoApiPost(c.GetUsersRoute()+"/usernames", ArrayToJson(usernames)); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return UserListFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// SearchUsers returns a list of users based on some search criteria.
-func (c *Client4) SearchUsers(search *UserSearch) ([]*User, *Response) {
- if r, err := c.DoApiPost(c.GetUsersRoute()+"/search", search.ToJson()); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return UserListFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// UpdateUser updates a user in the system based on the provided user struct.
-func (c *Client4) UpdateUser(user *User) (*User, *Response) {
- if r, err := c.DoApiPut(c.GetUserRoute(user.Id), user.ToJson()); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return UserFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// PatchUser partially updates a user in the system. Any missing fields are not updated.
-func (c *Client4) PatchUser(userId string, patch *UserPatch) (*User, *Response) {
- if r, err := c.DoApiPut(c.GetUserRoute(userId)+"/patch", patch.ToJson()); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return UserFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// UpdateUserAuth updates a user AuthData (uthData, authService and password) in the system.
-func (c *Client4) UpdateUserAuth(userId string, userAuth *UserAuth) (*UserAuth, *Response) {
- if r, err := c.DoApiPut(c.GetUserRoute(userId)+"/auth", userAuth.ToJson()); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return UserAuthFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// UpdateUserMfa activates multi-factor authentication for a user if activate
-// is true and a valid code is provided. If activate is false, then code is not
-// required and multi-factor authentication is disabled for the user.
-func (c *Client4) UpdateUserMfa(userId, code string, activate bool) (bool, *Response) {
- requestBody := make(map[string]interface{})
- requestBody["activate"] = activate
- requestBody["code"] = code
-
- if r, err := c.DoApiPut(c.GetUserRoute(userId)+"/mfa", StringInterfaceToJson(requestBody)); err != nil {
- return false, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return CheckStatusOK(r), BuildResponse(r)
- }
-}
-
-// CheckUserMfa checks whether a user has MFA active on their account or not based on the
-// provided login id.
-func (c *Client4) CheckUserMfa(loginId string) (bool, *Response) {
- requestBody := make(map[string]interface{})
- requestBody["login_id"] = loginId
-
- if r, err := c.DoApiPost(c.GetUsersRoute()+"/mfa", StringInterfaceToJson(requestBody)); err != nil {
- return false, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- data := StringInterfaceFromJson(r.Body)
- if mfaRequired, ok := data["mfa_required"].(bool); !ok {
- return false, BuildResponse(r)
- } else {
- return mfaRequired, BuildResponse(r)
- }
- }
-}
-
-// GenerateMfaSecret will generate a new MFA secret for a user and return it as a string and
-// as a base64 encoded image QR code.
-func (c *Client4) GenerateMfaSecret(userId string) (*MfaSecret, *Response) {
- if r, err := c.DoApiPost(c.GetUserRoute(userId)+"/mfa/generate", ""); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return MfaSecretFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// UpdateUserPassword updates a user's password. Must be logged in as the user or be a system administrator.
-func (c *Client4) UpdateUserPassword(userId, currentPassword, newPassword string) (bool, *Response) {
- requestBody := map[string]string{"current_password": currentPassword, "new_password": newPassword}
- if r, err := c.DoApiPut(c.GetUserRoute(userId)+"/password", MapToJson(requestBody)); err != nil {
- return false, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return CheckStatusOK(r), BuildResponse(r)
- }
-}
-
-// UpdateUserRoles updates a user's roles in the system. A user can have "system_user" and "system_admin" roles.
-func (c *Client4) UpdateUserRoles(userId, roles string) (bool, *Response) {
- requestBody := map[string]string{"roles": roles}
- if r, err := c.DoApiPut(c.GetUserRoute(userId)+"/roles", MapToJson(requestBody)); err != nil {
- return false, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return CheckStatusOK(r), BuildResponse(r)
- }
-}
-
-// UpdateUserActive updates status of a user whether active or not.
-func (c *Client4) UpdateUserActive(userId string, active bool) (bool, *Response) {
- requestBody := make(map[string]interface{})
- requestBody["active"] = active
-
- if r, err := c.DoApiPut(c.GetUserRoute(userId)+"/active", StringInterfaceToJson(requestBody)); err != nil {
- return false, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return CheckStatusOK(r), BuildResponse(r)
- }
-}
-
-// DeleteUser deactivates a user in the system based on the provided user id string.
-func (c *Client4) DeleteUser(userId string) (bool, *Response) {
- if r, err := c.DoApiDelete(c.GetUserRoute(userId)); err != nil {
- return false, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return CheckStatusOK(r), BuildResponse(r)
- }
-}
-
-// SendPasswordResetEmail will send a link for password resetting to a user with the
-// provided email.
-func (c *Client4) SendPasswordResetEmail(email string) (bool, *Response) {
- requestBody := map[string]string{"email": email}
- if r, err := c.DoApiPost(c.GetUsersRoute()+"/password/reset/send", MapToJson(requestBody)); err != nil {
- return false, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return CheckStatusOK(r), BuildResponse(r)
- }
-}
-
-// ResetPassword uses a recovery code to update reset a user's password.
-func (c *Client4) ResetPassword(token, newPassword string) (bool, *Response) {
- requestBody := map[string]string{"token": token, "new_password": newPassword}
- if r, err := c.DoApiPost(c.GetUsersRoute()+"/password/reset", MapToJson(requestBody)); err != nil {
- return false, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return CheckStatusOK(r), BuildResponse(r)
- }
-}
-
-// GetSessions returns a list of sessions based on the provided user id string.
-func (c *Client4) GetSessions(userId, etag string) ([]*Session, *Response) {
- if r, err := c.DoApiGet(c.GetUserRoute(userId)+"/sessions", etag); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return SessionsFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// RevokeSession revokes a user session based on the provided user id and session id strings.
-func (c *Client4) RevokeSession(userId, sessionId string) (bool, *Response) {
- requestBody := map[string]string{"session_id": sessionId}
- if r, err := c.DoApiPost(c.GetUserRoute(userId)+"/sessions/revoke", MapToJson(requestBody)); err != nil {
- return false, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return CheckStatusOK(r), BuildResponse(r)
- }
-}
-
-// RevokeAllSessions revokes all sessions for the provided user id string.
-func (c *Client4) RevokeAllSessions(userId string) (bool, *Response) {
- if r, err := c.DoApiPost(c.GetUserRoute(userId)+"/sessions/revoke/all", ""); err != nil {
- return false, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return CheckStatusOK(r), BuildResponse(r)
- }
-}
-
-// AttachDeviceId attaches a mobile device ID to the current session.
-func (c *Client4) AttachDeviceId(deviceId string) (bool, *Response) {
- requestBody := map[string]string{"device_id": deviceId}
- if r, err := c.DoApiPut(c.GetUsersRoute()+"/sessions/device", MapToJson(requestBody)); err != nil {
- return false, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return CheckStatusOK(r), BuildResponse(r)
- }
-}
-
-// GetTeamsUnreadForUser will return an array with TeamUnread objects that contain the amount
-// of unread messages and mentions the current user has for the teams it belongs to.
-// An optional team ID can be set to exclude that team from the results. Must be authenticated.
-func (c *Client4) GetTeamsUnreadForUser(userId, teamIdToExclude string) ([]*TeamUnread, *Response) {
- optional := ""
- if teamIdToExclude != "" {
- optional += fmt.Sprintf("?exclude_team=%s", url.QueryEscape(teamIdToExclude))
- }
-
- if r, err := c.DoApiGet(c.GetUserRoute(userId)+"/teams/unread"+optional, ""); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return TeamsUnreadFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// GetUserAudits returns a list of audit based on the provided user id string.
-func (c *Client4) GetUserAudits(userId string, page int, perPage int, etag string) (Audits, *Response) {
- query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
- if r, err := c.DoApiGet(c.GetUserRoute(userId)+"/audits"+query, etag); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return AuditsFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// VerifyUserEmail will verify a user's email using the supplied token.
-func (c *Client4) VerifyUserEmail(token string) (bool, *Response) {
- requestBody := map[string]string{"token": token}
- if r, err := c.DoApiPost(c.GetUsersRoute()+"/email/verify", MapToJson(requestBody)); err != nil {
- return false, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return CheckStatusOK(r), BuildResponse(r)
- }
-}
-
-// SendVerificationEmail will send an email to the user with the provided email address, if
-// that user exists. The email will contain a link that can be used to verify the user's
-// email address.
-func (c *Client4) SendVerificationEmail(email string) (bool, *Response) {
- requestBody := map[string]string{"email": email}
- if r, err := c.DoApiPost(c.GetUsersRoute()+"/email/verify/send", MapToJson(requestBody)); err != nil {
- return false, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return CheckStatusOK(r), BuildResponse(r)
- }
-}
-
-// SetProfileImage sets profile image of the user
-func (c *Client4) SetProfileImage(userId string, data []byte) (bool, *Response) {
- body := &bytes.Buffer{}
- writer := multipart.NewWriter(body)
-
- if part, err := writer.CreateFormFile("image", "profile.png"); err != nil {
- return false, &Response{Error: NewAppError("SetProfileImage", "model.client.set_profile_user.no_file.app_error", nil, err.Error(), http.StatusBadRequest)}
- } else if _, err = io.Copy(part, bytes.NewBuffer(data)); err != nil {
- return false, &Response{Error: NewAppError("SetProfileImage", "model.client.set_profile_user.no_file.app_error", nil, err.Error(), http.StatusBadRequest)}
- }
-
- if err := writer.Close(); err != nil {
- return false, &Response{Error: NewAppError("SetProfileImage", "model.client.set_profile_user.writer.app_error", nil, err.Error(), http.StatusBadRequest)}
- }
-
- rq, _ := http.NewRequest("POST", c.ApiUrl+c.GetUserRoute(userId)+"/image", bytes.NewReader(body.Bytes()))
- rq.Header.Set("Content-Type", writer.FormDataContentType())
-
- if len(c.AuthToken) > 0 {
- rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken)
- }
-
- if rp, err := c.HttpClient.Do(rq); err != nil || rp == nil {
- // set to http.StatusForbidden(403)
- return false, &Response{StatusCode: http.StatusForbidden, Error: NewAppError(c.GetUserRoute(userId)+"/image", "model.client.connecting.app_error", nil, err.Error(), 403)}
- } else {
- defer closeBody(rp)
-
- if rp.StatusCode >= 300 {
- return false, BuildErrorResponse(rp, AppErrorFromJson(rp.Body))
- } else {
- return CheckStatusOK(rp), BuildResponse(rp)
- }
- }
-}
-
-// CreateUserAccessToken will generate a user access token that can be used in place
-// of a session token to access the REST API. Must have the 'create_user_access_token'
-// permission and if generating for another user, must have the 'edit_other_users'
-// permission. A non-blank description is required.
-func (c *Client4) CreateUserAccessToken(userId, description string) (*UserAccessToken, *Response) {
- requestBody := map[string]string{"description": description}
- if r, err := c.DoApiPost(c.GetUserRoute(userId)+"/tokens", MapToJson(requestBody)); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return UserAccessTokenFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// GetUserAccessTokens will get a page of access tokens' id, description, is_active
-// and the user_id in the system. The actual token will not be returned. Must have
-// the 'manage_system' permission.
-func (c *Client4) GetUserAccessTokens(page int, perPage int) ([]*UserAccessToken, *Response) {
- query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
- if r, err := c.DoApiGet(c.GetUserAccessTokensRoute()+query, ""); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return UserAccessTokenListFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// GetUserAccessToken will get a user access tokens' id, description, is_active
-// and the user_id of the user it is for. The actual token will not be returned.
-// Must have the 'read_user_access_token' permission and if getting for another
-// user, must have the 'edit_other_users' permission.
-func (c *Client4) GetUserAccessToken(tokenId string) (*UserAccessToken, *Response) {
- if r, err := c.DoApiGet(c.GetUserAccessTokenRoute(tokenId), ""); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return UserAccessTokenFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// GetUserAccessTokensForUser will get a paged list of user access tokens showing id,
-// description and user_id for each. The actual tokens will not be returned. Must have
-// the 'read_user_access_token' permission and if getting for another user, must have the
-// 'edit_other_users' permission.
-func (c *Client4) GetUserAccessTokensForUser(userId string, page, perPage int) ([]*UserAccessToken, *Response) {
- query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
- if r, err := c.DoApiGet(c.GetUserRoute(userId)+"/tokens"+query, ""); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return UserAccessTokenListFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// RevokeUserAccessToken will revoke a user access token by id. Must have the
-// 'revoke_user_access_token' permission and if revoking for another user, must have the
-// 'edit_other_users' permission.
-func (c *Client4) RevokeUserAccessToken(tokenId string) (bool, *Response) {
- requestBody := map[string]string{"token_id": tokenId}
- if r, err := c.DoApiPost(c.GetUsersRoute()+"/tokens/revoke", MapToJson(requestBody)); err != nil {
- return false, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return CheckStatusOK(r), BuildResponse(r)
- }
-}
-
-// SearchUserAccessTokens returns user access tokens matching the provided search term.
-func (c *Client4) SearchUserAccessTokens(search *UserAccessTokenSearch) ([]*UserAccessToken, *Response) {
- if r, err := c.DoApiPost(c.GetUsersRoute()+"/tokens/search", search.ToJson()); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return UserAccessTokenListFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// DisableUserAccessToken will disable a user access token by id. Must have the
-// 'revoke_user_access_token' permission and if disabling for another user, must have the
-// 'edit_other_users' permission.
-func (c *Client4) DisableUserAccessToken(tokenId string) (bool, *Response) {
- requestBody := map[string]string{"token_id": tokenId}
- if r, err := c.DoApiPost(c.GetUsersRoute()+"/tokens/disable", MapToJson(requestBody)); err != nil {
- return false, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return CheckStatusOK(r), BuildResponse(r)
- }
-}
-
-// EnableUserAccessToken will enable a user access token by id. Must have the
-// 'create_user_access_token' permission and if enabling for another user, must have the
-// 'edit_other_users' permission.
-func (c *Client4) EnableUserAccessToken(tokenId string) (bool, *Response) {
- requestBody := map[string]string{"token_id": tokenId}
- if r, err := c.DoApiPost(c.GetUsersRoute()+"/tokens/enable", MapToJson(requestBody)); err != nil {
- return false, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return CheckStatusOK(r), BuildResponse(r)
- }
-}
-
-// Team Section
-
-// CreateTeam creates a team in the system based on the provided team struct.
-func (c *Client4) CreateTeam(team *Team) (*Team, *Response) {
- if r, err := c.DoApiPost(c.GetTeamsRoute(), team.ToJson()); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return TeamFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// GetTeam returns a team based on the provided team id string.
-func (c *Client4) GetTeam(teamId, etag string) (*Team, *Response) {
- if r, err := c.DoApiGet(c.GetTeamRoute(teamId), etag); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return TeamFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// GetAllTeams returns all teams based on permissions.
-func (c *Client4) GetAllTeams(etag string, page int, perPage int) ([]*Team, *Response) {
- query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
- if r, err := c.DoApiGet(c.GetTeamsRoute()+query, etag); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return TeamListFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// GetTeamByName returns a team based on the provided team name string.
-func (c *Client4) GetTeamByName(name, etag string) (*Team, *Response) {
- if r, err := c.DoApiGet(c.GetTeamByNameRoute(name), etag); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return TeamFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// SearchTeams returns teams matching the provided search term.
-func (c *Client4) SearchTeams(search *TeamSearch) ([]*Team, *Response) {
- if r, err := c.DoApiPost(c.GetTeamsRoute()+"/search", search.ToJson()); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return TeamListFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// TeamExists returns true or false if the team exist or not.
-func (c *Client4) TeamExists(name, etag string) (bool, *Response) {
- if r, err := c.DoApiGet(c.GetTeamByNameRoute(name)+"/exists", etag); err != nil {
- return false, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return MapBoolFromJson(r.Body)["exists"], BuildResponse(r)
- }
-}
-
-// GetTeamsForUser returns a list of teams a user is on. Must be logged in as the user
-// or be a system administrator.
-func (c *Client4) GetTeamsForUser(userId, etag string) ([]*Team, *Response) {
- if r, err := c.DoApiGet(c.GetUserRoute(userId)+"/teams", etag); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return TeamListFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// GetTeamMember returns a team member based on the provided team and user id strings.
-func (c *Client4) GetTeamMember(teamId, userId, etag string) (*TeamMember, *Response) {
- if r, err := c.DoApiGet(c.GetTeamMemberRoute(teamId, userId), etag); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return TeamMemberFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// UpdateTeamMemberRoles will update the roles on a team for a user.
-func (c *Client4) UpdateTeamMemberRoles(teamId, userId, newRoles string) (bool, *Response) {
- requestBody := map[string]string{"roles": newRoles}
- if r, err := c.DoApiPut(c.GetTeamMemberRoute(teamId, userId)+"/roles", MapToJson(requestBody)); err != nil {
- return false, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return CheckStatusOK(r), BuildResponse(r)
- }
-}
-
-// UpdateTeamMemberSchemeRoles will update the scheme-derived roles on a team for a user.
-func (c *Client4) UpdateTeamMemberSchemeRoles(teamId string, userId string, schemeRoles *SchemeRoles) (bool, *Response) {
- if r, err := c.DoApiPut(c.GetTeamMemberRoute(teamId, userId)+"/schemeRoles", schemeRoles.ToJson()); err != nil {
- return false, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return CheckStatusOK(r), BuildResponse(r)
- }
-}
-
-// UpdateTeam will update a team.
-func (c *Client4) UpdateTeam(team *Team) (*Team, *Response) {
- if r, err := c.DoApiPut(c.GetTeamRoute(team.Id), team.ToJson()); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return TeamFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// PatchTeam partially updates a team. Any missing fields are not updated.
-func (c *Client4) PatchTeam(teamId string, patch *TeamPatch) (*Team, *Response) {
- if r, err := c.DoApiPut(c.GetTeamRoute(teamId)+"/patch", patch.ToJson()); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return TeamFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// SoftDeleteTeam deletes the team softly (archive only, not permanent delete).
-func (c *Client4) SoftDeleteTeam(teamId string) (bool, *Response) {
- if r, err := c.DoApiDelete(c.GetTeamRoute(teamId)); err != nil {
- return false, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return CheckStatusOK(r), BuildResponse(r)
- }
-}
-
-// PermanentDeleteTeam deletes the team, should only be used when needed for
-// compliance and the like
-func (c *Client4) PermanentDeleteTeam(teamId string) (bool, *Response) {
- if r, err := c.DoApiDelete(c.GetTeamRoute(teamId) + "?permanent=true"); err != nil {
- return false, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return CheckStatusOK(r), BuildResponse(r)
- }
-}
-
-// GetTeamMembers returns team members based on the provided team id string.
-func (c *Client4) GetTeamMembers(teamId string, page int, perPage int, etag string) ([]*TeamMember, *Response) {
- query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
- if r, err := c.DoApiGet(c.GetTeamMembersRoute(teamId)+query, etag); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return TeamMembersFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// GetTeamMembersForUser returns the team members for a user.
-func (c *Client4) GetTeamMembersForUser(userId string, etag string) ([]*TeamMember, *Response) {
- if r, err := c.DoApiGet(c.GetUserRoute(userId)+"/teams/members", etag); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return TeamMembersFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// GetTeamMembersByIds will return an array of team members based on the
-// team id and a list of user ids provided. Must be authenticated.
-func (c *Client4) GetTeamMembersByIds(teamId string, userIds []string) ([]*TeamMember, *Response) {
- if r, err := c.DoApiPost(fmt.Sprintf("/teams/%v/members/ids", teamId), ArrayToJson(userIds)); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return TeamMembersFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// AddTeamMember adds user to a team and return a team member.
-func (c *Client4) AddTeamMember(teamId, userId string) (*TeamMember, *Response) {
- member := &TeamMember{TeamId: teamId, UserId: userId}
-
- if r, err := c.DoApiPost(c.GetTeamMembersRoute(teamId), member.ToJson()); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return TeamMemberFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// AddTeamMemberFromInvite adds a user to a team and return a team member using an invite id
-// or an invite token/data pair.
-func (c *Client4) AddTeamMemberFromInvite(token, inviteId string) (*TeamMember, *Response) {
- var query string
-
- if inviteId != "" {
- query += fmt.Sprintf("?invite_id=%v", inviteId)
- }
-
- if token != "" {
- query += fmt.Sprintf("?token=%v", token)
- }
-
- if r, err := c.DoApiPost(c.GetTeamsRoute()+"/members/invite"+query, ""); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return TeamMemberFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// AddTeamMembers adds a number of users to a team and returns the team members.
-func (c *Client4) AddTeamMembers(teamId string, userIds []string) ([]*TeamMember, *Response) {
- var members []*TeamMember
- for _, userId := range userIds {
- member := &TeamMember{TeamId: teamId, UserId: userId}
- members = append(members, member)
- }
-
- if r, err := c.DoApiPost(c.GetTeamMembersRoute(teamId)+"/batch", TeamMembersToJson(members)); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return TeamMembersFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// RemoveTeamMember will remove a user from a team.
-func (c *Client4) RemoveTeamMember(teamId, userId string) (bool, *Response) {
- if r, err := c.DoApiDelete(c.GetTeamMemberRoute(teamId, userId)); err != nil {
- return false, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return CheckStatusOK(r), BuildResponse(r)
- }
-}
-
-// GetTeamStats returns a team stats based on the team id string.
-// Must be authenticated.
-func (c *Client4) GetTeamStats(teamId, etag string) (*TeamStats, *Response) {
- if r, err := c.DoApiGet(c.GetTeamStatsRoute(teamId), etag); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return TeamStatsFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// GetTotalUsersStats returns a total system user stats.
-// Must be authenticated.
-func (c *Client4) GetTotalUsersStats(etag string) (*UsersStats, *Response) {
- if r, err := c.DoApiGet(c.GetTotalUsersStatsRoute(), etag); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return UsersStatsFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// GetTeamUnread will return a TeamUnread object that contains the amount of
-// unread messages and mentions the user has for the specified team.
-// Must be authenticated.
-func (c *Client4) GetTeamUnread(teamId, userId string) (*TeamUnread, *Response) {
- if r, err := c.DoApiGet(c.GetUserRoute(userId)+c.GetTeamRoute(teamId)+"/unread", ""); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return TeamUnreadFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// ImportTeam will import an exported team from other app into a existing team.
-func (c *Client4) ImportTeam(data []byte, filesize int, importFrom, filename, teamId string) (map[string]string, *Response) {
- body := &bytes.Buffer{}
- writer := multipart.NewWriter(body)
-
- if part, err := writer.CreateFormFile("file", filename); err != nil {
- return nil, &Response{Error: NewAppError("UploadImportTeam", "model.client.upload_post_attachment.file.app_error", nil, err.Error(), http.StatusBadRequest)}
- } else if _, err = io.Copy(part, bytes.NewBuffer(data)); err != nil {
- return nil, &Response{Error: NewAppError("UploadImportTeam", "model.client.upload_post_attachment.file.app_error", nil, err.Error(), http.StatusBadRequest)}
- }
-
- if part, err := writer.CreateFormField("filesize"); err != nil {
- return nil, &Response{Error: NewAppError("UploadImportTeam", "model.client.upload_post_attachment.file_size.app_error", nil, err.Error(), http.StatusBadRequest)}
- } else if _, err = io.Copy(part, strings.NewReader(strconv.Itoa(filesize))); err != nil {
- return nil, &Response{Error: NewAppError("UploadImportTeam", "model.client.upload_post_attachment.file_size.app_error", nil, err.Error(), http.StatusBadRequest)}
- }
-
- if part, err := writer.CreateFormField("importFrom"); err != nil {
- return nil, &Response{Error: NewAppError("UploadImportTeam", "model.client.upload_post_attachment.import_from.app_error", nil, err.Error(), http.StatusBadRequest)}
- } else if _, err = io.Copy(part, strings.NewReader(importFrom)); err != nil {
- return nil, &Response{Error: NewAppError("UploadImportTeam", "model.client.upload_post_attachment.import_from.app_error", nil, err.Error(), http.StatusBadRequest)}
- }
-
- if err := writer.Close(); err != nil {
- return nil, &Response{Error: NewAppError("UploadImportTeam", "model.client.upload_post_attachment.writer.app_error", nil, err.Error(), http.StatusBadRequest)}
- }
-
- return c.DoUploadImportTeam(c.GetTeamImportRoute(teamId), body.Bytes(), writer.FormDataContentType())
-}
-
-// InviteUsersToTeam invite users by email to the team.
-func (c *Client4) InviteUsersToTeam(teamId string, userEmails []string) (bool, *Response) {
- if r, err := c.DoApiPost(c.GetTeamRoute(teamId)+"/invite/email", ArrayToJson(userEmails)); err != nil {
- return false, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return CheckStatusOK(r), BuildResponse(r)
- }
-}
-
-// GetTeamInviteInfo returns a team object from an invite id containing sanitized information.
-func (c *Client4) GetTeamInviteInfo(inviteId string) (*Team, *Response) {
- if r, err := c.DoApiGet(c.GetTeamsRoute()+"/invite/"+inviteId, ""); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return TeamFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// SetTeamIcon sets team icon of the team
-func (c *Client4) SetTeamIcon(teamId string, data []byte) (bool, *Response) {
-
- body := &bytes.Buffer{}
- writer := multipart.NewWriter(body)
-
- if part, err := writer.CreateFormFile("image", "teamIcon.png"); err != nil {
- return false, &Response{Error: NewAppError("SetTeamIcon", "model.client.set_team_icon.no_file.app_error", nil, err.Error(), http.StatusBadRequest)}
- } else if _, err = io.Copy(part, bytes.NewBuffer(data)); err != nil {
- return false, &Response{Error: NewAppError("SetTeamIcon", "model.client.set_team_icon.no_file.app_error", nil, err.Error(), http.StatusBadRequest)}
- }
-
- if err := writer.Close(); err != nil {
- return false, &Response{Error: NewAppError("SetTeamIcon", "model.client.set_team_icon.writer.app_error", nil, err.Error(), http.StatusBadRequest)}
- }
-
- rq, _ := http.NewRequest("POST", c.ApiUrl+c.GetTeamRoute(teamId)+"/image", bytes.NewReader(body.Bytes()))
- rq.Header.Set("Content-Type", writer.FormDataContentType())
-
- if len(c.AuthToken) > 0 {
- rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken)
- }
-
- if rp, err := c.HttpClient.Do(rq); err != nil || rp == nil {
- // set to http.StatusForbidden(403)
- return false, &Response{StatusCode: http.StatusForbidden, Error: NewAppError(c.GetTeamRoute(teamId)+"/image", "model.client.connecting.app_error", nil, err.Error(), 403)}
- } else {
- defer closeBody(rp)
-
- if rp.StatusCode >= 300 {
- return false, BuildErrorResponse(rp, AppErrorFromJson(rp.Body))
- } else {
- return CheckStatusOK(rp), BuildResponse(rp)
- }
- }
-}
-
-// GetTeamIcon gets the team icon of the team
-func (c *Client4) GetTeamIcon(teamId, etag string) ([]byte, *Response) {
- if r, err := c.DoApiGet(c.GetTeamRoute(teamId)+"/image", etag); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
-
- if data, err := ioutil.ReadAll(r.Body); err != nil {
- return nil, BuildErrorResponse(r, NewAppError("GetTeamIcon", "model.client.get_team_icon.app_error", nil, err.Error(), r.StatusCode))
- } else {
- return data, BuildResponse(r)
- }
- }
-}
-
-// RemoveTeamIcon updates LastTeamIconUpdate to 0 which indicates team icon is removed.
-func (c *Client4) RemoveTeamIcon(teamId string) (bool, *Response) {
- if r, err := c.DoApiDelete(c.GetTeamRoute(teamId) + "/image"); err != nil {
- return false, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return CheckStatusOK(r), BuildResponse(r)
- }
-}
-
-// Channel Section
-
-// CreateChannel creates a channel based on the provided channel struct.
-func (c *Client4) CreateChannel(channel *Channel) (*Channel, *Response) {
- if r, err := c.DoApiPost(c.GetChannelsRoute(), channel.ToJson()); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return ChannelFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// UpdateChannel update a channel based on the provided channel struct.
-func (c *Client4) UpdateChannel(channel *Channel) (*Channel, *Response) {
- if r, err := c.DoApiPut(c.GetChannelRoute(channel.Id), channel.ToJson()); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return ChannelFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// PatchChannel partially updates a channel. Any missing fields are not updated.
-func (c *Client4) PatchChannel(channelId string, patch *ChannelPatch) (*Channel, *Response) {
- if r, err := c.DoApiPut(c.GetChannelRoute(channelId)+"/patch", patch.ToJson()); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return ChannelFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// ConvertChannelToPrivate converts public to private channel.
-func (c *Client4) ConvertChannelToPrivate(channelId string) (*Channel, *Response) {
- if r, err := c.DoApiPost(c.GetChannelRoute(channelId)+"/convert", ""); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return ChannelFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// RestoreChannel restores a previously deleted channel. Any missing fields are not updated.
-func (c *Client4) RestoreChannel(channelId string) (*Channel, *Response) {
- if r, err := c.DoApiPost(c.GetChannelRoute(channelId)+"/restore", ""); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return ChannelFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// CreateDirectChannel creates a direct message channel based on the two user
-// ids provided.
-func (c *Client4) CreateDirectChannel(userId1, userId2 string) (*Channel, *Response) {
- requestBody := []string{userId1, userId2}
- if r, err := c.DoApiPost(c.GetChannelsRoute()+"/direct", ArrayToJson(requestBody)); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return ChannelFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// CreateGroupChannel creates a group message channel based on userIds provided
-func (c *Client4) CreateGroupChannel(userIds []string) (*Channel, *Response) {
- if r, err := c.DoApiPost(c.GetChannelsRoute()+"/group", ArrayToJson(userIds)); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return ChannelFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// GetChannel returns a channel based on the provided channel id string.
-func (c *Client4) GetChannel(channelId, etag string) (*Channel, *Response) {
- if r, err := c.DoApiGet(c.GetChannelRoute(channelId), etag); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return ChannelFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// GetChannelStats returns statistics for a channel.
-func (c *Client4) GetChannelStats(channelId string, etag string) (*ChannelStats, *Response) {
- if r, err := c.DoApiGet(c.GetChannelRoute(channelId)+"/stats", etag); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return ChannelStatsFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// GetPinnedPosts gets a list of pinned posts.
-func (c *Client4) GetPinnedPosts(channelId string, etag string) (*PostList, *Response) {
- if r, err := c.DoApiGet(c.GetChannelRoute(channelId)+"/pinned", etag); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return PostListFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// GetPublicChannelsForTeam returns a list of public channels based on the provided team id string.
-func (c *Client4) GetPublicChannelsForTeam(teamId string, page int, perPage int, etag string) ([]*Channel, *Response) {
- query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
- if r, err := c.DoApiGet(c.GetChannelsForTeamRoute(teamId)+query, etag); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return ChannelSliceFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// GetDeletedChannelsForTeam returns a list of public channels based on the provided team id string.
-func (c *Client4) GetDeletedChannelsForTeam(teamId string, page int, perPage int, etag string) ([]*Channel, *Response) {
- query := fmt.Sprintf("/deleted?page=%v&per_page=%v", page, perPage)
- if r, err := c.DoApiGet(c.GetChannelsForTeamRoute(teamId)+query, etag); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return ChannelSliceFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// GetPublicChannelsByIdsForTeam returns a list of public channels based on provided team id string
-func (c *Client4) GetPublicChannelsByIdsForTeam(teamId string, channelIds []string) ([]*Channel, *Response) {
- if r, err := c.DoApiPost(c.GetChannelsForTeamRoute(teamId)+"/ids", ArrayToJson(channelIds)); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return ChannelSliceFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// GetChannelsForTeamForUser returns a list channels of on a team for a user.
-func (c *Client4) GetChannelsForTeamForUser(teamId, userId, etag string) ([]*Channel, *Response) {
- if r, err := c.DoApiGet(c.GetUserRoute(userId)+c.GetTeamRoute(teamId)+"/channels", etag); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return ChannelSliceFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// SearchChannels returns the channels on a team matching the provided search term.
-func (c *Client4) SearchChannels(teamId string, search *ChannelSearch) ([]*Channel, *Response) {
- if r, err := c.DoApiPost(c.GetChannelsForTeamRoute(teamId)+"/search", search.ToJson()); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return ChannelSliceFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// DeleteChannel deletes channel based on the provided channel id string.
-func (c *Client4) DeleteChannel(channelId string) (bool, *Response) {
- if r, err := c.DoApiDelete(c.GetChannelRoute(channelId)); err != nil {
- return false, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return CheckStatusOK(r), BuildResponse(r)
- }
-}
-
-// GetChannelByName returns a channel based on the provided channel name and team id strings.
-func (c *Client4) GetChannelByName(channelName, teamId string, etag string) (*Channel, *Response) {
- if r, err := c.DoApiGet(c.GetChannelByNameRoute(channelName, teamId), etag); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return ChannelFromJson(r.Body), BuildResponse(r)
- }
-}
-
-func (c *Client4) GetChannelByNameIncludeDeleted(channelName, teamId string, etag string) (*Channel, *Response) {
- if r, err := c.DoApiGet(c.GetChannelByNameRoute(channelName, teamId)+"?include_deleted=true", etag); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return ChannelFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// GetChannelByNameForTeamName returns a channel based on the provided channel name and team name strings.
-func (c *Client4) GetChannelByNameForTeamName(channelName, teamName string, etag string) (*Channel, *Response) {
- if r, err := c.DoApiGet(c.GetChannelByNameForTeamNameRoute(channelName, teamName), etag); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return ChannelFromJson(r.Body), BuildResponse(r)
- }
-}
-
-func (c *Client4) GetChannelByNameForTeamNameIncludeDeleted(channelName, teamName string, etag string) (*Channel, *Response) {
- if r, err := c.DoApiGet(c.GetChannelByNameForTeamNameRoute(channelName, teamName)+"?include_deleted=true", etag); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return ChannelFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// GetChannelMembers gets a page of channel members.
-func (c *Client4) GetChannelMembers(channelId string, page, perPage int, etag string) (*ChannelMembers, *Response) {
- query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
- if r, err := c.DoApiGet(c.GetChannelMembersRoute(channelId)+query, etag); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return ChannelMembersFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// GetChannelMembersByIds gets the channel members in a channel for a list of user ids.
-func (c *Client4) GetChannelMembersByIds(channelId string, userIds []string) (*ChannelMembers, *Response) {
- if r, err := c.DoApiPost(c.GetChannelMembersRoute(channelId)+"/ids", ArrayToJson(userIds)); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return ChannelMembersFromJson(r.Body), BuildResponse(r)
-
- }
-}
-
-// GetChannelMember gets a channel member.
-func (c *Client4) GetChannelMember(channelId, userId, etag string) (*ChannelMember, *Response) {
- if r, err := c.DoApiGet(c.GetChannelMemberRoute(channelId, userId), etag); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return ChannelMemberFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// GetChannelMembersForUser gets all the channel members for a user on a team.
-func (c *Client4) GetChannelMembersForUser(userId, teamId, etag string) (*ChannelMembers, *Response) {
- if r, err := c.DoApiGet(fmt.Sprintf(c.GetUserRoute(userId)+"/teams/%v/channels/members", teamId), etag); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return ChannelMembersFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// ViewChannel performs a view action for a user. Synonymous with switching channels or marking channels as read by a user.
-func (c *Client4) ViewChannel(userId string, view *ChannelView) (*ChannelViewResponse, *Response) {
- url := fmt.Sprintf(c.GetChannelsRoute()+"/members/%v/view", userId)
- if r, err := c.DoApiPost(url, view.ToJson()); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return ChannelViewResponseFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// GetChannelUnread will return a ChannelUnread object that contains the number of
-// unread messages and mentions for a user.
-func (c *Client4) GetChannelUnread(channelId, userId string) (*ChannelUnread, *Response) {
- if r, err := c.DoApiGet(c.GetUserRoute(userId)+c.GetChannelRoute(channelId)+"/unread", ""); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return ChannelUnreadFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// UpdateChannelRoles will update the roles on a channel for a user.
-func (c *Client4) UpdateChannelRoles(channelId, userId, roles string) (bool, *Response) {
- requestBody := map[string]string{"roles": roles}
- if r, err := c.DoApiPut(c.GetChannelMemberRoute(channelId, userId)+"/roles", MapToJson(requestBody)); err != nil {
- return false, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return CheckStatusOK(r), BuildResponse(r)
- }
-}
-
-// UpdateChannelMemberSchemeRoles will update the scheme-derived roles on a channel for a user.
-func (c *Client4) UpdateChannelMemberSchemeRoles(channelId string, userId string, schemeRoles *SchemeRoles) (bool, *Response) {
- if r, err := c.DoApiPut(c.GetChannelMemberRoute(channelId, userId)+"/schemeRoles", schemeRoles.ToJson()); err != nil {
- return false, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return CheckStatusOK(r), BuildResponse(r)
- }
-}
-
-// UpdateChannelNotifyProps will update the notification properties on a channel for a user.
-func (c *Client4) UpdateChannelNotifyProps(channelId, userId string, props map[string]string) (bool, *Response) {
- if r, err := c.DoApiPut(c.GetChannelMemberRoute(channelId, userId)+"/notify_props", MapToJson(props)); err != nil {
- return false, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return CheckStatusOK(r), BuildResponse(r)
- }
-}
-
-// AddChannelMember adds user to channel and return a channel member.
-func (c *Client4) AddChannelMember(channelId, userId string) (*ChannelMember, *Response) {
- requestBody := map[string]string{"user_id": userId}
- if r, err := c.DoApiPost(c.GetChannelMembersRoute(channelId)+"", MapToJson(requestBody)); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return ChannelMemberFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// AddChannelMemberWithRootId adds user to channel and return a channel member. Post add to channel message has the postRootId.
-func (c *Client4) AddChannelMemberWithRootId(channelId, userId, postRootId string) (*ChannelMember, *Response) {
- requestBody := map[string]string{"user_id": userId, "post_root_id": postRootId}
- if r, err := c.DoApiPost(c.GetChannelMembersRoute(channelId)+"", MapToJson(requestBody)); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return ChannelMemberFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// RemoveUserFromChannel will delete the channel member object for a user, effectively removing the user from a channel.
-func (c *Client4) RemoveUserFromChannel(channelId, userId string) (bool, *Response) {
- if r, err := c.DoApiDelete(c.GetChannelMemberRoute(channelId, userId)); err != nil {
- return false, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return CheckStatusOK(r), BuildResponse(r)
- }
-}
-
-// AutocompleteChannelsForTeam will return an ordered list of channels autocomplete suggestions
-func (c *Client4) AutocompleteChannelsForTeam(teamId, name string) (*ChannelList, *Response) {
- query := fmt.Sprintf("?name=%v", name)
- if r, err := c.DoApiGet(c.GetChannelsForTeamRoute(teamId)+"/autocomplete"+query, ""); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return ChannelListFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// AutocompleteChannelsForTeamForSearch will return an ordered list of your channels autocomplete suggestions
-func (c *Client4) AutocompleteChannelsForTeamForSearch(teamId, name string) (*ChannelList, *Response) {
- query := fmt.Sprintf("?name=%v", name)
- if r, err := c.DoApiGet(c.GetChannelsForTeamRoute(teamId)+"/search_autocomplete"+query, ""); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return ChannelListFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// Post Section
-
-// CreatePost creates a post based on the provided post struct.
-func (c *Client4) CreatePost(post *Post) (*Post, *Response) {
- if r, err := c.DoApiPost(c.GetPostsRoute(), post.ToUnsanitizedJson()); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return PostFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// CreatePostEphemeral creates a ephemeral post based on the provided post struct which is send to the given user id
-func (c *Client4) CreatePostEphemeral(post *PostEphemeral) (*Post, *Response) {
- if r, err := c.DoApiPost(c.GetPostsEphemeralRoute(), post.ToUnsanitizedJson()); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return PostFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// UpdatePost updates a post based on the provided post struct.
-func (c *Client4) UpdatePost(postId string, post *Post) (*Post, *Response) {
- if r, err := c.DoApiPut(c.GetPostRoute(postId), post.ToUnsanitizedJson()); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return PostFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// PatchPost partially updates a post. Any missing fields are not updated.
-func (c *Client4) PatchPost(postId string, patch *PostPatch) (*Post, *Response) {
- if r, err := c.DoApiPut(c.GetPostRoute(postId)+"/patch", patch.ToJson()); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return PostFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// PinPost pin a post based on provided post id string.
-func (c *Client4) PinPost(postId string) (bool, *Response) {
- if r, err := c.DoApiPost(c.GetPostRoute(postId)+"/pin", ""); err != nil {
- return false, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return CheckStatusOK(r), BuildResponse(r)
- }
-}
-
-// UnpinPost unpin a post based on provided post id string.
-func (c *Client4) UnpinPost(postId string) (bool, *Response) {
- if r, err := c.DoApiPost(c.GetPostRoute(postId)+"/unpin", ""); err != nil {
- return false, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return CheckStatusOK(r), BuildResponse(r)
- }
-}
-
-// GetPost gets a single post.
-func (c *Client4) GetPost(postId string, etag string) (*Post, *Response) {
- if r, err := c.DoApiGet(c.GetPostRoute(postId), etag); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return PostFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// DeletePost deletes a post from the provided post id string.
-func (c *Client4) DeletePost(postId string) (bool, *Response) {
- if r, err := c.DoApiDelete(c.GetPostRoute(postId)); err != nil {
- return false, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return CheckStatusOK(r), BuildResponse(r)
- }
-}
-
-// GetPostThread gets a post with all the other posts in the same thread.
-func (c *Client4) GetPostThread(postId string, etag string) (*PostList, *Response) {
- if r, err := c.DoApiGet(c.GetPostRoute(postId)+"/thread", etag); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return PostListFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// GetPostsForChannel gets a page of posts with an array for ordering for a channel.
-func (c *Client4) GetPostsForChannel(channelId string, page, perPage int, etag string) (*PostList, *Response) {
- query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
- if r, err := c.DoApiGet(c.GetChannelRoute(channelId)+"/posts"+query, etag); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return PostListFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// GetFlaggedPostsForUser returns flagged posts of a user based on user id string.
-func (c *Client4) GetFlaggedPostsForUser(userId string, page int, perPage int) (*PostList, *Response) {
- query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
- if r, err := c.DoApiGet(c.GetUserRoute(userId)+"/posts/flagged"+query, ""); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return PostListFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// GetFlaggedPostsForUserInTeam returns flagged posts in team of a user based on user id string.
-func (c *Client4) GetFlaggedPostsForUserInTeam(userId string, teamId string, page int, perPage int) (*PostList, *Response) {
- if len(teamId) == 0 || len(teamId) != 26 {
- return nil, &Response{StatusCode: http.StatusBadRequest, Error: NewAppError("GetFlaggedPostsForUserInTeam", "model.client.get_flagged_posts_in_team.missing_parameter.app_error", nil, "", http.StatusBadRequest)}
- }
-
- query := fmt.Sprintf("?team_id=%v&page=%v&per_page=%v", teamId, page, perPage)
- if r, err := c.DoApiGet(c.GetUserRoute(userId)+"/posts/flagged"+query, ""); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return PostListFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// GetFlaggedPostsForUserInChannel returns flagged posts in channel of a user based on user id string.
-func (c *Client4) GetFlaggedPostsForUserInChannel(userId string, channelId string, page int, perPage int) (*PostList, *Response) {
- if len(channelId) == 0 || len(channelId) != 26 {
- return nil, &Response{StatusCode: http.StatusBadRequest, Error: NewAppError("GetFlaggedPostsForUserInChannel", "model.client.get_flagged_posts_in_channel.missing_parameter.app_error", nil, "", http.StatusBadRequest)}
- }
-
- query := fmt.Sprintf("?channel_id=%v&page=%v&per_page=%v", channelId, page, perPage)
- if r, err := c.DoApiGet(c.GetUserRoute(userId)+"/posts/flagged"+query, ""); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return PostListFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// GetPostsSince gets posts created after a specified time as Unix time in milliseconds.
-func (c *Client4) GetPostsSince(channelId string, time int64) (*PostList, *Response) {
- query := fmt.Sprintf("?since=%v", time)
- if r, err := c.DoApiGet(c.GetChannelRoute(channelId)+"/posts"+query, ""); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return PostListFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// GetPostsAfter gets a page of posts that were posted after the post provided.
-func (c *Client4) GetPostsAfter(channelId, postId string, page, perPage int, etag string) (*PostList, *Response) {
- query := fmt.Sprintf("?page=%v&per_page=%v&after=%v", page, perPage, postId)
- if r, err := c.DoApiGet(c.GetChannelRoute(channelId)+"/posts"+query, etag); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return PostListFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// GetPostsBefore gets a page of posts that were posted before the post provided.
-func (c *Client4) GetPostsBefore(channelId, postId string, page, perPage int, etag string) (*PostList, *Response) {
- query := fmt.Sprintf("?page=%v&per_page=%v&before=%v", page, perPage, postId)
- if r, err := c.DoApiGet(c.GetChannelRoute(channelId)+"/posts"+query, etag); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return PostListFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// SearchPosts returns any posts with matching terms string.
-func (c *Client4) SearchPosts(teamId string, terms string, isOrSearch bool) (*PostList, *Response) {
- params := SearchParameter{
- Terms: &terms,
- IsOrSearch: &isOrSearch,
- }
- return c.SearchPostsWithParams(teamId, &params)
-}
-
-// SearchPosts returns any posts with matching terms string.
-func (c *Client4) SearchPostsWithParams(teamId string, params *SearchParameter) (*PostList, *Response) {
- if r, err := c.DoApiPost(c.GetTeamRoute(teamId)+"/posts/search", params.SearchParameterToJson()); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return PostListFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// SearchPosts returns any posts with matching terms string, including .
-func (c *Client4) SearchPostsWithMatches(teamId string, terms string, isOrSearch bool) (*PostSearchResults, *Response) {
- requestBody := map[string]interface{}{"terms": terms, "is_or_search": isOrSearch}
- if r, err := c.DoApiPost(c.GetTeamRoute(teamId)+"/posts/search", StringInterfaceToJson(requestBody)); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return PostSearchResultsFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// DoPostAction performs a post action.
-func (c *Client4) DoPostAction(postId, actionId string) (bool, *Response) {
- if r, err := c.DoApiPost(c.GetPostRoute(postId)+"/actions/"+actionId, ""); err != nil {
- return false, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return CheckStatusOK(r), BuildResponse(r)
- }
-}
-
-// File Section
-
-// UploadFile will upload a file to a channel using a multipart request, to be later attached to a post.
-// This method is functionally equivalent to Client4.UploadFileAsRequestBody.
-func (c *Client4) UploadFile(data []byte, channelId string, filename string) (*FileUploadResponse, *Response) {
- body := &bytes.Buffer{}
- writer := multipart.NewWriter(body)
-
- if part, err := writer.CreateFormFile("files", filename); err != nil {
- return nil, &Response{Error: NewAppError("UploadPostAttachment", "model.client.upload_post_attachment.file.app_error", nil, err.Error(), http.StatusBadRequest)}
- } else if _, err = io.Copy(part, bytes.NewBuffer(data)); err != nil {
- return nil, &Response{Error: NewAppError("UploadPostAttachment", "model.client.upload_post_attachment.file.app_error", nil, err.Error(), http.StatusBadRequest)}
- }
-
- if part, err := writer.CreateFormField("channel_id"); err != nil {
- return nil, &Response{Error: NewAppError("UploadPostAttachment", "model.client.upload_post_attachment.channel_id.app_error", nil, err.Error(), http.StatusBadRequest)}
- } else if _, err = io.Copy(part, strings.NewReader(channelId)); err != nil {
- return nil, &Response{Error: NewAppError("UploadPostAttachment", "model.client.upload_post_attachment.channel_id.app_error", nil, err.Error(), http.StatusBadRequest)}
- }
-
- if err := writer.Close(); err != nil {
- return nil, &Response{Error: NewAppError("UploadPostAttachment", "model.client.upload_post_attachment.writer.app_error", nil, err.Error(), http.StatusBadRequest)}
- }
-
- return c.DoUploadFile(c.GetFilesRoute(), body.Bytes(), writer.FormDataContentType())
-}
-
-// UploadFileAsRequestBody will upload a file to a channel as the body of a request, to be later attached
-// to a post. This method is functionally equivalent to Client4.UploadFile.
-func (c *Client4) UploadFileAsRequestBody(data []byte, channelId string, filename string) (*FileUploadResponse, *Response) {
- return c.DoUploadFile(c.GetFilesRoute()+fmt.Sprintf("?channel_id=%v&filename=%v", url.QueryEscape(channelId), url.QueryEscape(filename)), data, http.DetectContentType(data))
-}
-
-// GetFile gets the bytes for a file by id.
-func (c *Client4) GetFile(fileId string) ([]byte, *Response) {
- if r, err := c.DoApiGet(c.GetFileRoute(fileId), ""); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
-
- if data, err := ioutil.ReadAll(r.Body); err != nil {
- return nil, BuildErrorResponse(r, NewAppError("GetFile", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode))
- } else {
- return data, BuildResponse(r)
- }
- }
-}
-
-// DownloadFile gets the bytes for a file by id, optionally adding headers to force the browser to download it
-func (c *Client4) DownloadFile(fileId string, download bool) ([]byte, *Response) {
- if r, err := c.DoApiGet(c.GetFileRoute(fileId)+fmt.Sprintf("?download=%v", download), ""); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
-
- if data, err := ioutil.ReadAll(r.Body); err != nil {
- return nil, BuildErrorResponse(r, NewAppError("DownloadFile", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode))
- } else {
- return data, BuildResponse(r)
- }
- }
-}
-
-// GetFileThumbnail gets the bytes for a file by id.
-func (c *Client4) GetFileThumbnail(fileId string) ([]byte, *Response) {
- if r, err := c.DoApiGet(c.GetFileRoute(fileId)+"/thumbnail", ""); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
-
- if data, err := ioutil.ReadAll(r.Body); err != nil {
- return nil, BuildErrorResponse(r, NewAppError("GetFileThumbnail", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode))
- } else {
- return data, BuildResponse(r)
- }
- }
-}
-
-// DownloadFileThumbnail gets the bytes for a file by id, optionally adding headers to force the browser to download it.
-func (c *Client4) DownloadFileThumbnail(fileId string, download bool) ([]byte, *Response) {
- if r, err := c.DoApiGet(c.GetFileRoute(fileId)+fmt.Sprintf("/thumbnail?download=%v", download), ""); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
-
- if data, err := ioutil.ReadAll(r.Body); err != nil {
- return nil, BuildErrorResponse(r, NewAppError("DownloadFileThumbnail", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode))
- } else {
- return data, BuildResponse(r)
- }
- }
-}
-
-// GetFileLink gets the public link of a file by id.
-func (c *Client4) GetFileLink(fileId string) (string, *Response) {
- if r, err := c.DoApiGet(c.GetFileRoute(fileId)+"/link", ""); err != nil {
- return "", BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
-
- return MapFromJson(r.Body)["link"], BuildResponse(r)
- }
-}
-
-// GetFilePreview gets the bytes for a file by id.
-func (c *Client4) GetFilePreview(fileId string) ([]byte, *Response) {
- if r, err := c.DoApiGet(c.GetFileRoute(fileId)+"/preview", ""); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
-
- if data, err := ioutil.ReadAll(r.Body); err != nil {
- return nil, BuildErrorResponse(r, NewAppError("GetFilePreview", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode))
- } else {
- return data, BuildResponse(r)
- }
- }
-}
-
-// DownloadFilePreview gets the bytes for a file by id.
-func (c *Client4) DownloadFilePreview(fileId string, download bool) ([]byte, *Response) {
- if r, err := c.DoApiGet(c.GetFileRoute(fileId)+fmt.Sprintf("/preview?download=%v", download), ""); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
-
- if data, err := ioutil.ReadAll(r.Body); err != nil {
- return nil, BuildErrorResponse(r, NewAppError("DownloadFilePreview", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode))
- } else {
- return data, BuildResponse(r)
- }
- }
-}
-
-// GetFileInfo gets all the file info objects.
-func (c *Client4) GetFileInfo(fileId string) (*FileInfo, *Response) {
- if r, err := c.DoApiGet(c.GetFileRoute(fileId)+"/info", ""); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return FileInfoFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// GetFileInfosForPost gets all the file info objects attached to a post.
-func (c *Client4) GetFileInfosForPost(postId string, etag string) ([]*FileInfo, *Response) {
- if r, err := c.DoApiGet(c.GetPostRoute(postId)+"/files/info", etag); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return FileInfosFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// General/System Section
-
-// GetPing will return ok if the running goRoutines are below the threshold and unhealthy for above.
-func (c *Client4) GetPing() (string, *Response) {
- if r, err := c.DoApiGet(c.GetSystemRoute()+"/ping", ""); r != nil && r.StatusCode == 500 {
- defer r.Body.Close()
- return "unhealthy", BuildErrorResponse(r, err)
- } else if err != nil {
- return "", BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return MapFromJson(r.Body)["status"], BuildResponse(r)
- }
-}
-
-// TestEmail will attempt to connect to the configured SMTP server.
-func (c *Client4) TestEmail(config *Config) (bool, *Response) {
- if r, err := c.DoApiPost(c.GetTestEmailRoute(), config.ToJson()); err != nil {
- return false, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return CheckStatusOK(r), BuildResponse(r)
- }
-}
-
-// TestS3Connection will attempt to connect to the AWS S3.
-func (c *Client4) TestS3Connection(config *Config) (bool, *Response) {
- if r, err := c.DoApiPost(c.GetTestS3Route(), config.ToJson()); err != nil {
- return false, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return CheckStatusOK(r), BuildResponse(r)
- }
-}
-
-// GetConfig will retrieve the server config with some sanitized items.
-func (c *Client4) GetConfig() (*Config, *Response) {
- if r, err := c.DoApiGet(c.GetConfigRoute(), ""); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return ConfigFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// ReloadConfig will reload the server configuration.
-func (c *Client4) ReloadConfig() (bool, *Response) {
- if r, err := c.DoApiPost(c.GetConfigRoute()+"/reload", ""); err != nil {
- return false, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return CheckStatusOK(r), BuildResponse(r)
- }
-}
-
-// GetOldClientConfig will retrieve the parts of the server configuration needed by the
-// client, formatted in the old format.
-func (c *Client4) GetOldClientConfig(etag string) (map[string]string, *Response) {
- if r, err := c.DoApiGet(c.GetConfigRoute()+"/client?format=old", etag); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return MapFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// GetEnvironmentConfig will retrieve a map mirroring the server configuration where fields
-// are set to true if the corresponding config setting is set through an environment variable.
-// Settings that haven't been set through environment variables will be missing from the map.
-func (c *Client4) GetEnvironmentConfig() (map[string]interface{}, *Response) {
- if r, err := c.DoApiGet(c.GetConfigRoute()+"/environment", ""); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return StringInterfaceFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// GetOldClientLicense will retrieve the parts of the server license needed by the
-// client, formatted in the old format.
-func (c *Client4) GetOldClientLicense(etag string) (map[string]string, *Response) {
- if r, err := c.DoApiGet(c.GetLicenseRoute()+"/client?format=old", etag); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return MapFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// DatabaseRecycle will recycle the connections. Discard current connection and get new one.
-func (c *Client4) DatabaseRecycle() (bool, *Response) {
- if r, err := c.DoApiPost(c.GetDatabaseRoute()+"/recycle", ""); err != nil {
- return false, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return CheckStatusOK(r), BuildResponse(r)
- }
-}
-
-// InvalidateCaches will purge the cache and can affect the performance while is cleaning.
-func (c *Client4) InvalidateCaches() (bool, *Response) {
- if r, err := c.DoApiPost(c.GetCacheRoute()+"/invalidate", ""); err != nil {
- return false, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return CheckStatusOK(r), BuildResponse(r)
- }
-}
-
-// UpdateConfig will update the server configuration.
-func (c *Client4) UpdateConfig(config *Config) (*Config, *Response) {
- if r, err := c.DoApiPut(c.GetConfigRoute(), config.ToJson()); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return ConfigFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// UploadLicenseFile will add a license file to the system.
-func (c *Client4) UploadLicenseFile(data []byte) (bool, *Response) {
- body := &bytes.Buffer{}
- writer := multipart.NewWriter(body)
-
- if part, err := writer.CreateFormFile("license", "test-license.mattermost-license"); err != nil {
- return false, &Response{Error: NewAppError("UploadLicenseFile", "model.client.set_profile_user.no_file.app_error", nil, err.Error(), http.StatusBadRequest)}
- } else if _, err = io.Copy(part, bytes.NewBuffer(data)); err != nil {
- return false, &Response{Error: NewAppError("UploadLicenseFile", "model.client.set_profile_user.no_file.app_error", nil, err.Error(), http.StatusBadRequest)}
- }
-
- if err := writer.Close(); err != nil {
- return false, &Response{Error: NewAppError("UploadLicenseFile", "model.client.set_profile_user.writer.app_error", nil, err.Error(), http.StatusBadRequest)}
- }
-
- rq, _ := http.NewRequest("POST", c.ApiUrl+c.GetLicenseRoute(), bytes.NewReader(body.Bytes()))
- rq.Header.Set("Content-Type", writer.FormDataContentType())
-
- if len(c.AuthToken) > 0 {
- rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken)
- }
-
- if rp, err := c.HttpClient.Do(rq); err != nil || rp == nil {
- return false, &Response{StatusCode: http.StatusForbidden, Error: NewAppError(c.GetLicenseRoute(), "model.client.connecting.app_error", nil, err.Error(), http.StatusForbidden)}
- } else {
- defer closeBody(rp)
-
- if rp.StatusCode >= 300 {
- return false, BuildErrorResponse(rp, AppErrorFromJson(rp.Body))
- } else {
- return CheckStatusOK(rp), BuildResponse(rp)
- }
- }
-}
-
-// RemoveLicenseFile will remove the server license it exists. Note that this will
-// disable all enterprise features.
-func (c *Client4) RemoveLicenseFile() (bool, *Response) {
- if r, err := c.DoApiDelete(c.GetLicenseRoute()); err != nil {
- return false, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return CheckStatusOK(r), BuildResponse(r)
- }
-}
-
-// GetAnalyticsOld will retrieve analytics using the old format. New format is not
-// available but the "/analytics" endpoint is reserved for it. The "name" argument is optional
-// and defaults to "standard". The "teamId" argument is optional and will limit results
-// to a specific team.
-func (c *Client4) GetAnalyticsOld(name, teamId string) (AnalyticsRows, *Response) {
- query := fmt.Sprintf("?name=%v&team_id=%v", name, teamId)
- if r, err := c.DoApiGet(c.GetAnalyticsRoute()+"/old"+query, ""); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return AnalyticsRowsFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// Webhooks Section
-
-// CreateIncomingWebhook creates an incoming webhook for a channel.
-func (c *Client4) CreateIncomingWebhook(hook *IncomingWebhook) (*IncomingWebhook, *Response) {
- if r, err := c.DoApiPost(c.GetIncomingWebhooksRoute(), hook.ToJson()); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return IncomingWebhookFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// UpdateIncomingWebhook updates an incoming webhook for a channel.
-func (c *Client4) UpdateIncomingWebhook(hook *IncomingWebhook) (*IncomingWebhook, *Response) {
- if r, err := c.DoApiPut(c.GetIncomingWebhookRoute(hook.Id), hook.ToJson()); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return IncomingWebhookFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// GetIncomingWebhooks returns a page of incoming webhooks on the system. Page counting starts at 0.
-func (c *Client4) GetIncomingWebhooks(page int, perPage int, etag string) ([]*IncomingWebhook, *Response) {
- query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
- if r, err := c.DoApiGet(c.GetIncomingWebhooksRoute()+query, etag); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return IncomingWebhookListFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// GetIncomingWebhooksForTeam returns a page of incoming webhooks for a team. Page counting starts at 0.
-func (c *Client4) GetIncomingWebhooksForTeam(teamId string, page int, perPage int, etag string) ([]*IncomingWebhook, *Response) {
- query := fmt.Sprintf("?page=%v&per_page=%v&team_id=%v", page, perPage, teamId)
- if r, err := c.DoApiGet(c.GetIncomingWebhooksRoute()+query, etag); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return IncomingWebhookListFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// GetIncomingWebhook returns an Incoming webhook given the hook ID
-func (c *Client4) GetIncomingWebhook(hookID string, etag string) (*IncomingWebhook, *Response) {
- if r, err := c.DoApiGet(c.GetIncomingWebhookRoute(hookID), etag); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return IncomingWebhookFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// DeleteIncomingWebhook deletes and Incoming Webhook given the hook ID
-func (c *Client4) DeleteIncomingWebhook(hookID string) (bool, *Response) {
- if r, err := c.DoApiDelete(c.GetIncomingWebhookRoute(hookID)); err != nil {
- return false, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return CheckStatusOK(r), BuildResponse(r)
- }
-}
-
-// CreateOutgoingWebhook creates an outgoing webhook for a team or channel.
-func (c *Client4) CreateOutgoingWebhook(hook *OutgoingWebhook) (*OutgoingWebhook, *Response) {
- if r, err := c.DoApiPost(c.GetOutgoingWebhooksRoute(), hook.ToJson()); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return OutgoingWebhookFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// UpdateOutgoingWebhook creates an outgoing webhook for a team or channel.
-func (c *Client4) UpdateOutgoingWebhook(hook *OutgoingWebhook) (*OutgoingWebhook, *Response) {
- if r, err := c.DoApiPut(c.GetOutgoingWebhookRoute(hook.Id), hook.ToJson()); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return OutgoingWebhookFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// GetOutgoingWebhooks returns a page of outgoing webhooks on the system. Page counting starts at 0.
-func (c *Client4) GetOutgoingWebhooks(page int, perPage int, etag string) ([]*OutgoingWebhook, *Response) {
- query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
- if r, err := c.DoApiGet(c.GetOutgoingWebhooksRoute()+query, etag); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return OutgoingWebhookListFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// GetOutgoingWebhook outgoing webhooks on the system requested by Hook Id.
-func (c *Client4) GetOutgoingWebhook(hookId string) (*OutgoingWebhook, *Response) {
- if r, err := c.DoApiGet(c.GetOutgoingWebhookRoute(hookId), ""); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return OutgoingWebhookFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// GetOutgoingWebhooksForChannel returns a page of outgoing webhooks for a channel. Page counting starts at 0.
-func (c *Client4) GetOutgoingWebhooksForChannel(channelId string, page int, perPage int, etag string) ([]*OutgoingWebhook, *Response) {
- query := fmt.Sprintf("?page=%v&per_page=%v&channel_id=%v", page, perPage, channelId)
- if r, err := c.DoApiGet(c.GetOutgoingWebhooksRoute()+query, etag); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return OutgoingWebhookListFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// GetOutgoingWebhooksForTeam returns a page of outgoing webhooks for a team. Page counting starts at 0.
-func (c *Client4) GetOutgoingWebhooksForTeam(teamId string, page int, perPage int, etag string) ([]*OutgoingWebhook, *Response) {
- query := fmt.Sprintf("?page=%v&per_page=%v&team_id=%v", page, perPage, teamId)
- if r, err := c.DoApiGet(c.GetOutgoingWebhooksRoute()+query, etag); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return OutgoingWebhookListFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// RegenOutgoingHookToken regenerate the outgoing webhook token.
-func (c *Client4) RegenOutgoingHookToken(hookId string) (*OutgoingWebhook, *Response) {
- if r, err := c.DoApiPost(c.GetOutgoingWebhookRoute(hookId)+"/regen_token", ""); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return OutgoingWebhookFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// DeleteOutgoingWebhook delete the outgoing webhook on the system requested by Hook Id.
-func (c *Client4) DeleteOutgoingWebhook(hookId string) (bool, *Response) {
- if r, err := c.DoApiDelete(c.GetOutgoingWebhookRoute(hookId)); err != nil {
- return false, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return CheckStatusOK(r), BuildResponse(r)
- }
-}
-
-// Preferences Section
-
-// GetPreferences returns the user's preferences.
-func (c *Client4) GetPreferences(userId string) (Preferences, *Response) {
- if r, err := c.DoApiGet(c.GetPreferencesRoute(userId), ""); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- preferences, _ := PreferencesFromJson(r.Body)
- defer closeBody(r)
- return preferences, BuildResponse(r)
- }
-}
-
-// UpdatePreferences saves the user's preferences.
-func (c *Client4) UpdatePreferences(userId string, preferences *Preferences) (bool, *Response) {
- if r, err := c.DoApiPut(c.GetPreferencesRoute(userId), preferences.ToJson()); err != nil {
- return false, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return true, BuildResponse(r)
- }
-}
-
-// DeletePreferences deletes the user's preferences.
-func (c *Client4) DeletePreferences(userId string, preferences *Preferences) (bool, *Response) {
- if r, err := c.DoApiPost(c.GetPreferencesRoute(userId)+"/delete", preferences.ToJson()); err != nil {
- return false, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return true, BuildResponse(r)
- }
-}
-
-// GetPreferencesByCategory returns the user's preferences from the provided category string.
-func (c *Client4) GetPreferencesByCategory(userId string, category string) (Preferences, *Response) {
- url := fmt.Sprintf(c.GetPreferencesRoute(userId)+"/%s", category)
- if r, err := c.DoApiGet(url, ""); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- preferences, _ := PreferencesFromJson(r.Body)
- defer closeBody(r)
- return preferences, BuildResponse(r)
- }
-}
-
-// GetPreferenceByCategoryAndName returns the user's preferences from the provided category and preference name string.
-func (c *Client4) GetPreferenceByCategoryAndName(userId string, category string, preferenceName string) (*Preference, *Response) {
- url := fmt.Sprintf(c.GetPreferencesRoute(userId)+"/%s/name/%v", category, preferenceName)
- if r, err := c.DoApiGet(url, ""); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return PreferenceFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// SAML Section
-
-// GetSamlMetadata returns metadata for the SAML configuration.
-func (c *Client4) GetSamlMetadata() (string, *Response) {
- if r, err := c.DoApiGet(c.GetSamlRoute()+"/metadata", ""); err != nil {
- return "", BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- buf := new(bytes.Buffer)
- buf.ReadFrom(r.Body)
- return buf.String(), BuildResponse(r)
- }
-}
-
-func samlFileToMultipart(data []byte, filename string) ([]byte, *multipart.Writer, error) {
- body := &bytes.Buffer{}
- writer := multipart.NewWriter(body)
-
- if part, err := writer.CreateFormFile("certificate", filename); err != nil {
- return nil, nil, err
- } else if _, err = io.Copy(part, bytes.NewBuffer(data)); err != nil {
- return nil, nil, err
- }
-
- if err := writer.Close(); err != nil {
- return nil, nil, err
- }
-
- return body.Bytes(), writer, nil
-}
-
-// UploadSamlIdpCertificate will upload an IDP certificate for SAML and set the config to use it.
-func (c *Client4) UploadSamlIdpCertificate(data []byte, filename string) (bool, *Response) {
- body, writer, err := samlFileToMultipart(data, filename)
- if err != nil {
- return false, &Response{Error: NewAppError("UploadSamlIdpCertificate", "model.client.upload_saml_cert.app_error", nil, err.Error(), http.StatusBadRequest)}
- }
-
- _, resp := c.DoUploadFile(c.GetSamlRoute()+"/certificate/idp", body, writer.FormDataContentType())
- return resp.Error == nil, resp
-}
-
-// UploadSamlPublicCertificate will upload a public certificate for SAML and set the config to use it.
-func (c *Client4) UploadSamlPublicCertificate(data []byte, filename string) (bool, *Response) {
- body, writer, err := samlFileToMultipart(data, filename)
- if err != nil {
- return false, &Response{Error: NewAppError("UploadSamlPublicCertificate", "model.client.upload_saml_cert.app_error", nil, err.Error(), http.StatusBadRequest)}
- }
-
- _, resp := c.DoUploadFile(c.GetSamlRoute()+"/certificate/public", body, writer.FormDataContentType())
- return resp.Error == nil, resp
-}
-
-// UploadSamlPrivateCertificate will upload a private key for SAML and set the config to use it.
-func (c *Client4) UploadSamlPrivateCertificate(data []byte, filename string) (bool, *Response) {
- body, writer, err := samlFileToMultipart(data, filename)
- if err != nil {
- return false, &Response{Error: NewAppError("UploadSamlPrivateCertificate", "model.client.upload_saml_cert.app_error", nil, err.Error(), http.StatusBadRequest)}
- }
-
- _, resp := c.DoUploadFile(c.GetSamlRoute()+"/certificate/private", body, writer.FormDataContentType())
- return resp.Error == nil, resp
-}
-
-// DeleteSamlIdpCertificate deletes the SAML IDP certificate from the server and updates the config to not use it and disable SAML.
-func (c *Client4) DeleteSamlIdpCertificate() (bool, *Response) {
- if r, err := c.DoApiDelete(c.GetSamlRoute() + "/certificate/idp"); err != nil {
- return false, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return CheckStatusOK(r), BuildResponse(r)
- }
-}
-
-// DeleteSamlPublicCertificate deletes the SAML IDP certificate from the server and updates the config to not use it and disable SAML.
-func (c *Client4) DeleteSamlPublicCertificate() (bool, *Response) {
- if r, err := c.DoApiDelete(c.GetSamlRoute() + "/certificate/public"); err != nil {
- return false, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return CheckStatusOK(r), BuildResponse(r)
- }
-}
-
-// DeleteSamlPrivateCertificate deletes the SAML IDP certificate from the server and updates the config to not use it and disable SAML.
-func (c *Client4) DeleteSamlPrivateCertificate() (bool, *Response) {
- if r, err := c.DoApiDelete(c.GetSamlRoute() + "/certificate/private"); err != nil {
- return false, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return CheckStatusOK(r), BuildResponse(r)
- }
-}
-
-// GetSamlCertificateStatus returns metadata for the SAML configuration.
-func (c *Client4) GetSamlCertificateStatus() (*SamlCertificateStatus, *Response) {
- if r, err := c.DoApiGet(c.GetSamlRoute()+"/certificate/status", ""); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return SamlCertificateStatusFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// Compliance Section
-
-// CreateComplianceReport creates an incoming webhook for a channel.
-func (c *Client4) CreateComplianceReport(report *Compliance) (*Compliance, *Response) {
- if r, err := c.DoApiPost(c.GetComplianceReportsRoute(), report.ToJson()); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return ComplianceFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// GetComplianceReports returns list of compliance reports.
-func (c *Client4) GetComplianceReports(page, perPage int) (Compliances, *Response) {
- query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
- if r, err := c.DoApiGet(c.GetComplianceReportsRoute()+query, ""); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return CompliancesFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// GetComplianceReport returns a compliance report.
-func (c *Client4) GetComplianceReport(reportId string) (*Compliance, *Response) {
- if r, err := c.DoApiGet(c.GetComplianceReportRoute(reportId), ""); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return ComplianceFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// DownloadComplianceReport returns a full compliance report as a file.
-func (c *Client4) DownloadComplianceReport(reportId string) ([]byte, *Response) {
- var rq *http.Request
- rq, _ = http.NewRequest("GET", c.ApiUrl+c.GetComplianceReportRoute(reportId), nil)
-
- if len(c.AuthToken) > 0 {
- rq.Header.Set(HEADER_AUTH, "BEARER "+c.AuthToken)
- }
-
- if rp, err := c.HttpClient.Do(rq); err != nil || rp == nil {
- return nil, &Response{Error: NewAppError("DownloadComplianceReport", "model.client.connecting.app_error", nil, err.Error(), http.StatusBadRequest)}
- } else {
- defer closeBody(rp)
-
- if rp.StatusCode >= 300 {
- return nil, BuildErrorResponse(rp, AppErrorFromJson(rp.Body))
- } else if data, err := ioutil.ReadAll(rp.Body); err != nil {
- return nil, BuildErrorResponse(rp, NewAppError("DownloadComplianceReport", "model.client.read_file.app_error", nil, err.Error(), rp.StatusCode))
- } else {
- return data, BuildResponse(rp)
- }
- }
-}
-
-// Cluster Section
-
-// GetClusterStatus returns the status of all the configured cluster nodes.
-func (c *Client4) GetClusterStatus() ([]*ClusterInfo, *Response) {
- if r, err := c.DoApiGet(c.GetClusterRoute()+"/status", ""); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return ClusterInfosFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// LDAP Section
-
-// SyncLdap will force a sync with the configured LDAP server.
-func (c *Client4) SyncLdap() (bool, *Response) {
- if r, err := c.DoApiPost(c.GetLdapRoute()+"/sync", ""); err != nil {
- return false, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return CheckStatusOK(r), BuildResponse(r)
- }
-}
-
-// TestLdap will attempt to connect to the configured LDAP server and return OK if configured
-// correctly.
-func (c *Client4) TestLdap() (bool, *Response) {
- if r, err := c.DoApiPost(c.GetLdapRoute()+"/test", ""); err != nil {
- return false, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return CheckStatusOK(r), BuildResponse(r)
- }
-}
-
-// Audits Section
-
-// GetAudits returns a list of audits for the whole system.
-func (c *Client4) GetAudits(page int, perPage int, etag string) (Audits, *Response) {
- query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
- if r, err := c.DoApiGet("/audits"+query, etag); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return AuditsFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// Brand Section
-
-// GetBrandImage retrieves the previously uploaded brand image.
-func (c *Client4) GetBrandImage() ([]byte, *Response) {
- if r, err := c.DoApiGet(c.GetBrandRoute()+"/image", ""); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
-
- if r.StatusCode >= 300 {
- return nil, BuildErrorResponse(r, AppErrorFromJson(r.Body))
- } else if data, err := ioutil.ReadAll(r.Body); err != nil {
- return nil, BuildErrorResponse(r, NewAppError("GetBrandImage", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode))
- } else {
- return data, BuildResponse(r)
- }
- }
-}
-
-// UploadBrandImage sets the brand image for the system.
-func (c *Client4) UploadBrandImage(data []byte) (bool, *Response) {
- body := &bytes.Buffer{}
- writer := multipart.NewWriter(body)
-
- if part, err := writer.CreateFormFile("image", "brand.png"); err != nil {
- return false, &Response{Error: NewAppError("UploadBrandImage", "model.client.set_profile_user.no_file.app_error", nil, err.Error(), http.StatusBadRequest)}
- } else if _, err = io.Copy(part, bytes.NewBuffer(data)); err != nil {
- return false, &Response{Error: NewAppError("UploadBrandImage", "model.client.set_profile_user.no_file.app_error", nil, err.Error(), http.StatusBadRequest)}
- }
-
- if err := writer.Close(); err != nil {
- return false, &Response{Error: NewAppError("UploadBrandImage", "model.client.set_profile_user.writer.app_error", nil, err.Error(), http.StatusBadRequest)}
- }
-
- rq, _ := http.NewRequest("POST", c.ApiUrl+c.GetBrandRoute()+"/image", bytes.NewReader(body.Bytes()))
- rq.Header.Set("Content-Type", writer.FormDataContentType())
-
- if len(c.AuthToken) > 0 {
- rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken)
- }
-
- if rp, err := c.HttpClient.Do(rq); err != nil || rp == nil {
- return false, &Response{StatusCode: http.StatusForbidden, Error: NewAppError(c.GetBrandRoute()+"/image", "model.client.connecting.app_error", nil, err.Error(), http.StatusForbidden)}
- } else {
- defer closeBody(rp)
-
- if rp.StatusCode >= 300 {
- return false, BuildErrorResponse(rp, AppErrorFromJson(rp.Body))
- } else {
- return CheckStatusOK(rp), BuildResponse(rp)
- }
- }
-}
-
-// Logs Section
-
-// GetLogs page of logs as a string array.
-func (c *Client4) GetLogs(page, perPage int) ([]string, *Response) {
- query := fmt.Sprintf("?page=%v&logs_per_page=%v", page, perPage)
- if r, err := c.DoApiGet("/logs"+query, ""); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return ArrayFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// PostLog is a convenience Web Service call so clients can log messages into
-// the server-side logs. For example we typically log javascript error messages
-// into the server-side. It returns the log message if the logging was successful.
-func (c *Client4) PostLog(message map[string]string) (map[string]string, *Response) {
- if r, err := c.DoApiPost("/logs", MapToJson(message)); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return MapFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// OAuth Section
-
-// CreateOAuthApp will register a new OAuth 2.0 client application with Mattermost acting as an OAuth 2.0 service provider.
-func (c *Client4) CreateOAuthApp(app *OAuthApp) (*OAuthApp, *Response) {
- if r, err := c.DoApiPost(c.GetOAuthAppsRoute(), app.ToJson()); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return OAuthAppFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// UpdateOAuthApp
-func (c *Client4) UpdateOAuthApp(app *OAuthApp) (*OAuthApp, *Response) {
- if r, err := c.DoApiPut(c.GetOAuthAppRoute(app.Id), app.ToJson()); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return OAuthAppFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// GetOAuthApps gets a page of registered OAuth 2.0 client applications with Mattermost acting as an OAuth 2.0 service provider.
-func (c *Client4) GetOAuthApps(page, perPage int) ([]*OAuthApp, *Response) {
- query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
- if r, err := c.DoApiGet(c.GetOAuthAppsRoute()+query, ""); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return OAuthAppListFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// GetOAuthApp gets a registered OAuth 2.0 client application with Mattermost acting as an OAuth 2.0 service provider.
-func (c *Client4) GetOAuthApp(appId string) (*OAuthApp, *Response) {
- if r, err := c.DoApiGet(c.GetOAuthAppRoute(appId), ""); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return OAuthAppFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// GetOAuthAppInfo gets a sanitized version of a registered OAuth 2.0 client application with Mattermost acting as an OAuth 2.0 service provider.
-func (c *Client4) GetOAuthAppInfo(appId string) (*OAuthApp, *Response) {
- if r, err := c.DoApiGet(c.GetOAuthAppRoute(appId)+"/info", ""); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return OAuthAppFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// DeleteOAuthApp deletes a registered OAuth 2.0 client application.
-func (c *Client4) DeleteOAuthApp(appId string) (bool, *Response) {
- if r, err := c.DoApiDelete(c.GetOAuthAppRoute(appId)); err != nil {
- return false, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return CheckStatusOK(r), BuildResponse(r)
- }
-}
-
-// RegenerateOAuthAppSecret regenerates the client secret for a registered OAuth 2.0 client application.
-func (c *Client4) RegenerateOAuthAppSecret(appId string) (*OAuthApp, *Response) {
- if r, err := c.DoApiPost(c.GetOAuthAppRoute(appId)+"/regen_secret", ""); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return OAuthAppFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// GetAuthorizedOAuthAppsForUser gets a page of OAuth 2.0 client applications the user has authorized to use access their account.
-func (c *Client4) GetAuthorizedOAuthAppsForUser(userId string, page, perPage int) ([]*OAuthApp, *Response) {
- query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
- if r, err := c.DoApiGet(c.GetUserRoute(userId)+"/oauth/apps/authorized"+query, ""); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return OAuthAppListFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// AuthorizeOAuthApp will authorize an OAuth 2.0 client application to access a user's account and provide a redirect link to follow.
-func (c *Client4) AuthorizeOAuthApp(authRequest *AuthorizeRequest) (string, *Response) {
- if r, err := c.DoApiRequest(http.MethodPost, c.Url+"/oauth/authorize", authRequest.ToJson(), ""); err != nil {
- return "", BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return MapFromJson(r.Body)["redirect"], BuildResponse(r)
- }
-}
-
-// DeauthorizeOAuthApp will deauthorize an OAuth 2.0 client application from accessing a user's account.
-func (c *Client4) DeauthorizeOAuthApp(appId string) (bool, *Response) {
- requestData := map[string]string{"client_id": appId}
- if r, err := c.DoApiRequest(http.MethodPost, c.Url+"/oauth/deauthorize", MapToJson(requestData), ""); err != nil {
- return false, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return CheckStatusOK(r), BuildResponse(r)
- }
-}
-
-// GetOAuthAccessToken is a test helper function for the OAuth access token endpoint.
-func (c *Client4) GetOAuthAccessToken(data url.Values) (*AccessResponse, *Response) {
- rq, _ := http.NewRequest(http.MethodPost, c.Url+"/oauth/access_token", strings.NewReader(data.Encode()))
- rq.Header.Set("Content-Type", "application/x-www-form-urlencoded")
-
- if len(c.AuthToken) > 0 {
- rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken)
- }
-
- if rp, err := c.HttpClient.Do(rq); err != nil || rp == nil {
- return nil, &Response{StatusCode: http.StatusForbidden, Error: NewAppError(c.Url+"/oauth/access_token", "model.client.connecting.app_error", nil, err.Error(), 403)}
- } else {
- defer closeBody(rp)
- if rp.StatusCode >= 300 {
- return nil, BuildErrorResponse(rp, AppErrorFromJson(rp.Body))
- } else {
- return AccessResponseFromJson(rp.Body), BuildResponse(rp)
- }
- }
-}
-
-// Elasticsearch Section
-
-// TestElasticsearch will attempt to connect to the configured Elasticsearch server and return OK if configured
-// correctly.
-func (c *Client4) TestElasticsearch() (bool, *Response) {
- if r, err := c.DoApiPost(c.GetElasticsearchRoute()+"/test", ""); err != nil {
- return false, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return CheckStatusOK(r), BuildResponse(r)
- }
-}
-
-// PurgeElasticsearchIndexes immediately deletes all Elasticsearch indexes.
-func (c *Client4) PurgeElasticsearchIndexes() (bool, *Response) {
- if r, err := c.DoApiPost(c.GetElasticsearchRoute()+"/purge_indexes", ""); err != nil {
- return false, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return CheckStatusOK(r), BuildResponse(r)
- }
-}
-
-// Data Retention Section
-
-// GetDataRetentionPolicy will get the current server data retention policy details.
-func (c *Client4) GetDataRetentionPolicy() (*DataRetentionPolicy, *Response) {
- if r, err := c.DoApiGet(c.GetDataRetentionRoute()+"/policy", ""); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return DataRetentionPolicyFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// Commands Section
-
-// CreateCommand will create a new command if the user have the right permissions.
-func (c *Client4) CreateCommand(cmd *Command) (*Command, *Response) {
- if r, err := c.DoApiPost(c.GetCommandsRoute(), cmd.ToJson()); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return CommandFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// UpdateCommand updates a command based on the provided Command struct
-func (c *Client4) UpdateCommand(cmd *Command) (*Command, *Response) {
- if r, err := c.DoApiPut(c.GetCommandRoute(cmd.Id), cmd.ToJson()); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return CommandFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// DeleteCommand deletes a command based on the provided command id string
-func (c *Client4) DeleteCommand(commandId string) (bool, *Response) {
- if r, err := c.DoApiDelete(c.GetCommandRoute(commandId)); err != nil {
- return false, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return CheckStatusOK(r), BuildResponse(r)
- }
-}
-
-// ListCommands will retrieve a list of commands available in the team.
-func (c *Client4) ListCommands(teamId string, customOnly bool) ([]*Command, *Response) {
- query := fmt.Sprintf("?team_id=%v&custom_only=%v", teamId, customOnly)
- if r, err := c.DoApiGet(c.GetCommandsRoute()+query, ""); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return CommandListFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// ExecuteCommand executes a given slash command.
-func (c *Client4) ExecuteCommand(channelId, command string) (*CommandResponse, *Response) {
- commandArgs := &CommandArgs{
- ChannelId: channelId,
- Command: command,
- }
- if r, err := c.DoApiPost(c.GetCommandsRoute()+"/execute", commandArgs.ToJson()); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
-
- response, _ := CommandResponseFromJson(r.Body)
- return response, BuildResponse(r)
- }
-}
-
-// ExecuteCommand executes a given slash command against the specified team
-// Use this when executing slash commands in a DM/GM, since the team id cannot be inferred in that case
-func (c *Client4) ExecuteCommandWithTeam(channelId, teamId, command string) (*CommandResponse, *Response) {
- commandArgs := &CommandArgs{
- ChannelId: channelId,
- TeamId: teamId,
- Command: command,
- }
- if r, err := c.DoApiPost(c.GetCommandsRoute()+"/execute", commandArgs.ToJson()); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
-
- response, _ := CommandResponseFromJson(r.Body)
- return response, BuildResponse(r)
- }
-}
-
-// ListCommands will retrieve a list of commands available in the team.
-func (c *Client4) ListAutocompleteCommands(teamId string) ([]*Command, *Response) {
- if r, err := c.DoApiGet(c.GetTeamAutoCompleteCommandsRoute(teamId), ""); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return CommandListFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// RegenCommandToken will create a new token if the user have the right permissions.
-func (c *Client4) RegenCommandToken(commandId string) (string, *Response) {
- if r, err := c.DoApiPut(c.GetCommandRoute(commandId)+"/regen_token", ""); err != nil {
- return "", BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return MapFromJson(r.Body)["token"], BuildResponse(r)
- }
-}
-
-// Status Section
-
-// GetUserStatus returns a user based on the provided user id string.
-func (c *Client4) GetUserStatus(userId, etag string) (*Status, *Response) {
- if r, err := c.DoApiGet(c.GetUserStatusRoute(userId), etag); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return StatusFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// GetUsersStatusesByIds returns a list of users status based on the provided user ids.
-func (c *Client4) GetUsersStatusesByIds(userIds []string) ([]*Status, *Response) {
- if r, err := c.DoApiPost(c.GetUserStatusesRoute()+"/ids", ArrayToJson(userIds)); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return StatusListFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// UpdateUserStatus sets a user's status based on the provided user id string.
-func (c *Client4) UpdateUserStatus(userId string, userStatus *Status) (*Status, *Response) {
- if r, err := c.DoApiPut(c.GetUserStatusRoute(userId), userStatus.ToJson()); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return StatusFromJson(r.Body), BuildResponse(r)
-
- }
-}
-
-// Webrtc Section
-
-// GetWebrtcToken returns a valid token, stun server and turn server with credentials to
-// use with the Mattermost WebRTC service.
-func (c *Client4) GetWebrtcToken() (*WebrtcInfoResponse, *Response) {
- if r, err := c.DoApiGet("/webrtc/token", ""); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return WebrtcInfoResponseFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// Emoji Section
-
-// CreateEmoji will save an emoji to the server if the current user has permission
-// to do so. If successful, the provided emoji will be returned with its Id field
-// filled in. Otherwise, an error will be returned.
-func (c *Client4) CreateEmoji(emoji *Emoji, image []byte, filename string) (*Emoji, *Response) {
- body := &bytes.Buffer{}
- writer := multipart.NewWriter(body)
-
- if part, err := writer.CreateFormFile("image", filename); err != nil {
- return nil, &Response{StatusCode: http.StatusForbidden, Error: NewAppError("CreateEmoji", "model.client.create_emoji.image.app_error", nil, err.Error(), 0)}
- } else if _, err = io.Copy(part, bytes.NewBuffer(image)); err != nil {
- return nil, &Response{StatusCode: http.StatusForbidden, Error: NewAppError("CreateEmoji", "model.client.create_emoji.image.app_error", nil, err.Error(), 0)}
- }
-
- if err := writer.WriteField("emoji", emoji.ToJson()); err != nil {
- return nil, &Response{StatusCode: http.StatusForbidden, Error: NewAppError("CreateEmoji", "model.client.create_emoji.emoji.app_error", nil, err.Error(), 0)}
- }
-
- if err := writer.Close(); err != nil {
- return nil, &Response{StatusCode: http.StatusForbidden, Error: NewAppError("CreateEmoji", "model.client.create_emoji.writer.app_error", nil, err.Error(), 0)}
- }
-
- return c.DoEmojiUploadFile(c.GetEmojisRoute(), body.Bytes(), writer.FormDataContentType())
-}
-
-// GetEmojiList returns a page of custom emoji on the system.
-func (c *Client4) GetEmojiList(page, perPage int) ([]*Emoji, *Response) {
- query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
- if r, err := c.DoApiGet(c.GetEmojisRoute()+query, ""); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return EmojiListFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// GetSortedEmojiList returns a page of custom emoji on the system sorted based on the sort
-// parameter, blank for no sorting and "name" to sort by emoji names.
-func (c *Client4) GetSortedEmojiList(page, perPage int, sort string) ([]*Emoji, *Response) {
- query := fmt.Sprintf("?page=%v&per_page=%v&sort=%v", page, perPage, sort)
- if r, err := c.DoApiGet(c.GetEmojisRoute()+query, ""); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return EmojiListFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// DeleteEmoji delete an custom emoji on the provided emoji id string.
-func (c *Client4) DeleteEmoji(emojiId string) (bool, *Response) {
- if r, err := c.DoApiDelete(c.GetEmojiRoute(emojiId)); err != nil {
- return false, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return CheckStatusOK(r), BuildResponse(r)
- }
-}
-
-// GetEmoji returns a custom emoji based on the emojiId string.
-func (c *Client4) GetEmoji(emojiId string) (*Emoji, *Response) {
- if r, err := c.DoApiGet(c.GetEmojiRoute(emojiId), ""); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return EmojiFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// GetEmojiByName returns a custom emoji based on the name string.
-func (c *Client4) GetEmojiByName(name string) (*Emoji, *Response) {
- if r, err := c.DoApiGet(c.GetEmojiByNameRoute(name), ""); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return EmojiFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// GetEmojiImage returns the emoji image.
-func (c *Client4) GetEmojiImage(emojiId string) ([]byte, *Response) {
- if r, err := c.DoApiGet(c.GetEmojiRoute(emojiId)+"/image", ""); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
-
- if data, err := ioutil.ReadAll(r.Body); err != nil {
- return nil, BuildErrorResponse(r, NewAppError("GetEmojiImage", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode))
- } else {
- return data, BuildResponse(r)
- }
- }
-}
-
-// SearchEmoji returns a list of emoji matching some search criteria.
-func (c *Client4) SearchEmoji(search *EmojiSearch) ([]*Emoji, *Response) {
- if r, err := c.DoApiPost(c.GetEmojisRoute()+"/search", search.ToJson()); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return EmojiListFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// AutocompleteEmoji returns a list of emoji starting with or matching name.
-func (c *Client4) AutocompleteEmoji(name string, etag string) ([]*Emoji, *Response) {
- query := fmt.Sprintf("?name=%v", name)
- if r, err := c.DoApiGet(c.GetEmojisRoute()+"/autocomplete"+query, ""); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return EmojiListFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// Reaction Section
-
-// SaveReaction saves an emoji reaction for a post. Returns the saved reaction if successful, otherwise an error will be returned.
-func (c *Client4) SaveReaction(reaction *Reaction) (*Reaction, *Response) {
- if r, err := c.DoApiPost(c.GetReactionsRoute(), reaction.ToJson()); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return ReactionFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// GetReactions returns a list of reactions to a post.
-func (c *Client4) GetReactions(postId string) ([]*Reaction, *Response) {
- if r, err := c.DoApiGet(c.GetPostRoute(postId)+"/reactions", ""); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return ReactionsFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// DeleteReaction deletes reaction of a user in a post.
-func (c *Client4) DeleteReaction(reaction *Reaction) (bool, *Response) {
- if r, err := c.DoApiDelete(c.GetUserRoute(reaction.UserId) + c.GetPostRoute(reaction.PostId) + fmt.Sprintf("/reactions/%v", reaction.EmojiName)); err != nil {
- return false, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return CheckStatusOK(r), BuildResponse(r)
- }
-}
-
-// Timezone Section
-
-// GetSupportedTimezone returns a page of supported timezones on the system.
-func (c *Client4) GetSupportedTimezone() (SupportedTimezones, *Response) {
- if r, err := c.DoApiGet(c.GetTimezonesRoute(), ""); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return TimezonesFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// Open Graph Metadata Section
-
-// OpenGraph return the open graph metadata for a particular url if the site have the metadata
-func (c *Client4) OpenGraph(url string) (map[string]string, *Response) {
- requestBody := make(map[string]string)
- requestBody["url"] = url
-
- if r, err := c.DoApiPost(c.GetOpenGraphRoute(), MapToJson(requestBody)); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return MapFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// Jobs Section
-
-// GetJob gets a single job.
-func (c *Client4) GetJob(id string) (*Job, *Response) {
- if r, err := c.DoApiGet(c.GetJobsRoute()+fmt.Sprintf("/%v", id), ""); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return JobFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// Get all jobs, sorted with the job that was created most recently first.
-func (c *Client4) GetJobs(page int, perPage int) ([]*Job, *Response) {
- if r, err := c.DoApiGet(c.GetJobsRoute()+fmt.Sprintf("?page=%v&per_page=%v", page, perPage), ""); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return JobsFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// GetJobsByType gets all jobs of a given type, sorted with the job that was created most recently first.
-func (c *Client4) GetJobsByType(jobType string, page int, perPage int) ([]*Job, *Response) {
- if r, err := c.DoApiGet(c.GetJobsRoute()+fmt.Sprintf("/type/%v?page=%v&per_page=%v", jobType, page, perPage), ""); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return JobsFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// CreateJob creates a job based on the provided job struct.
-func (c *Client4) CreateJob(job *Job) (*Job, *Response) {
- if r, err := c.DoApiPost(c.GetJobsRoute(), job.ToJson()); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return JobFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// CancelJob requests the cancellation of the job with the provided Id.
-func (c *Client4) CancelJob(jobId string) (bool, *Response) {
- if r, err := c.DoApiPost(c.GetJobsRoute()+fmt.Sprintf("/%v/cancel", jobId), ""); err != nil {
- return false, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return CheckStatusOK(r), BuildResponse(r)
- }
-}
-
-// Roles Section
-
-// GetRole gets a single role by ID.
-func (c *Client4) GetRole(id string) (*Role, *Response) {
- if r, err := c.DoApiGet(c.GetRolesRoute()+fmt.Sprintf("/%v", id), ""); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return RoleFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// GetRoleByName gets a single role by Name.
-func (c *Client4) GetRoleByName(name string) (*Role, *Response) {
- if r, err := c.DoApiGet(c.GetRolesRoute()+fmt.Sprintf("/name/%v", name), ""); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return RoleFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// GetRolesByNames returns a list of roles based on the provided role names.
-func (c *Client4) GetRolesByNames(roleNames []string) ([]*Role, *Response) {
- if r, err := c.DoApiPost(c.GetRolesRoute()+"/names", ArrayToJson(roleNames)); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return RoleListFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// PatchRole partially updates a role in the system. Any missing fields are not updated.
-func (c *Client4) PatchRole(roleId string, patch *RolePatch) (*Role, *Response) {
- if r, err := c.DoApiPut(c.GetRolesRoute()+fmt.Sprintf("/%v/patch", roleId), patch.ToJson()); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return RoleFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// Schemes Section
-
-// CreateScheme creates a new Scheme.
-func (c *Client4) CreateScheme(scheme *Scheme) (*Scheme, *Response) {
- if r, err := c.DoApiPost(c.GetSchemesRoute(), scheme.ToJson()); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return SchemeFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// GetScheme gets a single scheme by ID.
-func (c *Client4) GetScheme(id string) (*Scheme, *Response) {
- if r, err := c.DoApiGet(c.GetSchemeRoute(id), ""); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return SchemeFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// Get all schemes, sorted with the most recently created first, optionally filtered by scope.
-func (c *Client4) GetSchemes(scope string, page int, perPage int) ([]*Scheme, *Response) {
- if r, err := c.DoApiGet(c.GetSchemesRoute()+fmt.Sprintf("?scope=%v&page=%v&per_page=%v", scope, page, perPage), ""); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return SchemesFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// DeleteScheme deletes a single scheme by ID.
-func (c *Client4) DeleteScheme(id string) (bool, *Response) {
- if r, err := c.DoApiDelete(c.GetSchemeRoute(id)); err != nil {
- return false, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return CheckStatusOK(r), BuildResponse(r)
- }
-}
-
-// PatchScheme partially updates a scheme in the system. Any missing fields are not updated.
-func (c *Client4) PatchScheme(id string, patch *SchemePatch) (*Scheme, *Response) {
- if r, err := c.DoApiPut(c.GetSchemeRoute(id)+"/patch", patch.ToJson()); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return SchemeFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// Get the teams using this scheme, sorted alphabetically by display name.
-func (c *Client4) GetTeamsForScheme(schemeId string, page int, perPage int) ([]*Team, *Response) {
- if r, err := c.DoApiGet(c.GetSchemeRoute(schemeId)+fmt.Sprintf("/teams?page=%v&per_page=%v", page, perPage), ""); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return TeamListFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// Get the channels using this scheme, sorted alphabetically by display name.
-func (c *Client4) GetChannelsForScheme(schemeId string, page int, perPage int) (ChannelList, *Response) {
- if r, err := c.DoApiGet(c.GetSchemeRoute(schemeId)+fmt.Sprintf("/channels?page=%v&per_page=%v", page, perPage), ""); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return *ChannelListFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// Plugin Section
-
-// UploadPlugin takes an io.Reader stream pointing to the contents of a .tar.gz plugin.
-// WARNING: PLUGINS ARE STILL EXPERIMENTAL. THIS FUNCTION IS SUBJECT TO CHANGE.
-func (c *Client4) UploadPlugin(file io.Reader) (*Manifest, *Response) {
- body := new(bytes.Buffer)
- writer := multipart.NewWriter(body)
-
- if part, err := writer.CreateFormFile("plugin", "plugin.tar.gz"); err != nil {
- return nil, &Response{Error: NewAppError("UploadPlugin", "model.client.writer.app_error", nil, err.Error(), 0)}
- } else if _, err = io.Copy(part, file); err != nil {
- return nil, &Response{Error: NewAppError("UploadPlugin", "model.client.writer.app_error", nil, err.Error(), 0)}
- }
-
- if err := writer.Close(); err != nil {
- return nil, &Response{Error: NewAppError("UploadPlugin", "model.client.writer.app_error", nil, err.Error(), 0)}
- }
-
- rq, _ := http.NewRequest("POST", c.ApiUrl+c.GetPluginsRoute(), body)
- rq.Header.Set("Content-Type", writer.FormDataContentType())
-
- if len(c.AuthToken) > 0 {
- rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken)
- }
-
- if rp, err := c.HttpClient.Do(rq); err != nil || rp == nil {
- return nil, BuildErrorResponse(rp, NewAppError("UploadPlugin", "model.client.connecting.app_error", nil, err.Error(), 0))
- } else {
- defer closeBody(rp)
-
- if rp.StatusCode >= 300 {
- return nil, BuildErrorResponse(rp, AppErrorFromJson(rp.Body))
- } else {
- return ManifestFromJson(rp.Body), BuildResponse(rp)
- }
- }
-}
-
-// GetPlugins will return a list of plugin manifests for currently active plugins.
-// WARNING: PLUGINS ARE STILL EXPERIMENTAL. THIS FUNCTION IS SUBJECT TO CHANGE.
-func (c *Client4) GetPlugins() (*PluginsResponse, *Response) {
- if r, err := c.DoApiGet(c.GetPluginsRoute(), ""); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return PluginsResponseFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// GetPluginStatuses will return the plugins installed on any server in the cluster, for reporting
-// to the administrator via the system console.
-// WARNING: PLUGINS ARE STILL EXPERIMENTAL. THIS FUNCTION IS SUBJECT TO CHANGE.
-func (c *Client4) GetPluginStatuses() (PluginStatuses, *Response) {
- if r, err := c.DoApiGet(c.GetPluginsRoute(), "/statuses"); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return PluginStatusesFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// RemovePlugin will deactivate and delete a plugin.
-// WARNING: PLUGINS ARE STILL EXPERIMENTAL. THIS FUNCTION IS SUBJECT TO CHANGE.
-func (c *Client4) RemovePlugin(id string) (bool, *Response) {
- if r, err := c.DoApiDelete(c.GetPluginRoute(id)); err != nil {
- return false, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return CheckStatusOK(r), BuildResponse(r)
- }
-}
-
-// GetWebappPlugins will return a list of plugins that the webapp should download.
-// WARNING: PLUGINS ARE STILL EXPERIMENTAL. THIS FUNCTION IS SUBJECT TO CHANGE.
-func (c *Client4) GetWebappPlugins() ([]*Manifest, *Response) {
- if r, err := c.DoApiGet(c.GetPluginsRoute()+"/webapp", ""); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return ManifestListFromJson(r.Body), BuildResponse(r)
- }
-}
-
-// ActivatePlugin will activate an plugin installed.
-// WARNING: PLUGINS ARE STILL EXPERIMENTAL. THIS FUNCTION IS SUBJECT TO CHANGE.
-func (c *Client4) EnablePlugin(id string) (bool, *Response) {
- if r, err := c.DoApiPost(c.GetPluginRoute(id)+"/enable", ""); err != nil {
- return false, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return CheckStatusOK(r), BuildResponse(r)
- }
-}
-
-// DeactivatePlugin will deactivate an active plugin.
-// WARNING: PLUGINS ARE STILL EXPERIMENTAL. THIS FUNCTION IS SUBJECT TO CHANGE.
-func (c *Client4) DisablePlugin(id string) (bool, *Response) {
- if r, err := c.DoApiPost(c.GetPluginRoute(id)+"/disable", ""); err != nil {
- return false, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return CheckStatusOK(r), BuildResponse(r)
- }
-}
-
-// UpdateChannelScheme will update a channel's scheme.
-func (c *Client4) UpdateChannelScheme(channelId, schemeId string) (bool, *Response) {
- sip := &SchemeIDPatch{SchemeID: &schemeId}
- if r, err := c.DoApiPut(c.GetChannelSchemeRoute(channelId), sip.ToJson()); err != nil {
- return false, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return CheckStatusOK(r), BuildResponse(r)
- }
-}
-
-// UpdateTeamScheme will update a team's scheme.
-func (c *Client4) UpdateTeamScheme(teamId, schemeId string) (bool, *Response) {
- sip := &SchemeIDPatch{SchemeID: &schemeId}
- if r, err := c.DoApiPut(c.GetTeamSchemeRoute(teamId), sip.ToJson()); err != nil {
- return false, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return CheckStatusOK(r), BuildResponse(r)
- }
-}
-
-// GetRedirectLocation retrieves the value of the 'Location' header of an HTTP response for a given URL.
-func (c *Client4) GetRedirectLocation(urlParam, etag string) (string, *Response) {
- url := fmt.Sprintf("%s?url=%s", c.GetRedirectLocationRoute(), url.QueryEscape(urlParam))
- if r, err := c.DoApiGet(url, etag); err != nil {
- return "", BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return MapFromJson(r.Body)["location"], BuildResponse(r)
- }
-}
-
-func (c *Client4) RegisteTermsOfServiceAction(userId, termsOfServiceId string, accepted bool) (*bool, *Response) {
- url := c.GetRegisterTermsOfServiceRoute(userId)
- data := map[string]interface{}{"termsOfServiceId": termsOfServiceId, "accepted": accepted}
-
- if r, err := c.DoApiPost(url, StringInterfaceToJson(data)); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return NewBool(CheckStatusOK(r)), BuildResponse(r)
- }
-}
-
-func (c *Client4) GetTermsOfService(etag string) (*TermsOfService, *Response) {
- url := c.GetTermsOfServiceRoute()
-
- if r, err := c.DoApiGet(url, etag); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return TermsOfServiceFromJson(r.Body), BuildResponse(r)
- }
-}
-
-func (c *Client4) CreateTermsOfService(text, userId string) (*TermsOfService, *Response) {
- url := c.GetTermsOfServiceRoute()
-
- data := map[string]string{"text": text}
- if r, err := c.DoApiPost(url, MapToJson(data)); err != nil {
- return nil, BuildErrorResponse(r, err)
- } else {
- defer closeBody(r)
- return TermsOfServiceFromJson(r.Body), BuildResponse(r)
- }
-}
diff --git a/vendor/github.com/mattermost/mattermost-server/model/command_args.go b/vendor/github.com/mattermost/mattermost-server/model/command_args.go
deleted file mode 100644
index 4a635a1a..00000000
--- a/vendor/github.com/mattermost/mattermost-server/model/command_args.go
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-package model
-
-import (
- "encoding/json"
- "io"
-
- goi18n "github.com/nicksnyder/go-i18n/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"`
- Command string `json:"command"`
- SiteURL string `json:"-"`
- T goi18n.TranslateFunc `json:"-"`
- Session Session `json:"-"`
-}
-
-func (o *CommandArgs) ToJson() string {
- b, _ := json.Marshal(o)
- return string(b)
-}
-
-func CommandArgsFromJson(data io.Reader) *CommandArgs {
- var o *CommandArgs
- json.NewDecoder(data).Decode(&o)
- return o
-}
diff --git a/vendor/github.com/mattermost/mattermost-server/model/config.go b/vendor/github.com/mattermost/mattermost-server/model/config.go
deleted file mode 100644
index d59b8d6d..00000000
--- a/vendor/github.com/mattermost/mattermost-server/model/config.go
+++ /dev/null
@@ -1,2569 +0,0 @@
-// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-package model
-
-import (
- "encoding/json"
- "io"
- "math"
- "net"
- "net/http"
- "net/url"
- "regexp"
- "strconv"
- "strings"
- "time"
-)
-
-const (
- CONN_SECURITY_NONE = ""
- CONN_SECURITY_PLAIN = "PLAIN"
- CONN_SECURITY_TLS = "TLS"
- CONN_SECURITY_STARTTLS = "STARTTLS"
-
- IMAGE_DRIVER_LOCAL = "local"
- IMAGE_DRIVER_S3 = "amazons3"
-
- DATABASE_DRIVER_SQLITE = "sqlite3"
- DATABASE_DRIVER_MYSQL = "mysql"
- DATABASE_DRIVER_POSTGRES = "postgres"
-
- MINIO_ACCESS_KEY = "minioaccesskey"
- MINIO_SECRET_KEY = "miniosecretkey"
- MINIO_BUCKET = "mattermost-test"
-
- PASSWORD_MAXIMUM_LENGTH = 64
- PASSWORD_MINIMUM_LENGTH = 5
-
- SERVICE_GITLAB = "gitlab"
- SERVICE_GOOGLE = "google"
- SERVICE_OFFICE365 = "office365"
-
- GENERIC_NO_CHANNEL_NOTIFICATION = "generic_no_channel"
- GENERIC_NOTIFICATION = "generic"
- FULL_NOTIFICATION = "full"
-
- DIRECT_MESSAGE_ANY = "any"
- DIRECT_MESSAGE_TEAM = "team"
-
- SHOW_USERNAME = "username"
- SHOW_NICKNAME_FULLNAME = "nickname_full_name"
- SHOW_FULLNAME = "full_name"
-
- PERMISSIONS_ALL = "all"
- PERMISSIONS_CHANNEL_ADMIN = "channel_admin"
- PERMISSIONS_TEAM_ADMIN = "team_admin"
- PERMISSIONS_SYSTEM_ADMIN = "system_admin"
-
- FAKE_SETTING = "********************************"
-
- RESTRICT_EMOJI_CREATION_ALL = "all"
- RESTRICT_EMOJI_CREATION_ADMIN = "admin"
- RESTRICT_EMOJI_CREATION_SYSTEM_ADMIN = "system_admin"
-
- PERMISSIONS_DELETE_POST_ALL = "all"
- PERMISSIONS_DELETE_POST_TEAM_ADMIN = "team_admin"
- PERMISSIONS_DELETE_POST_SYSTEM_ADMIN = "system_admin"
-
- ALLOW_EDIT_POST_ALWAYS = "always"
- ALLOW_EDIT_POST_NEVER = "never"
- ALLOW_EDIT_POST_TIME_LIMIT = "time_limit"
-
- GROUP_UNREAD_CHANNELS_DISABLED = "disabled"
- GROUP_UNREAD_CHANNELS_DEFAULT_ON = "default_on"
- GROUP_UNREAD_CHANNELS_DEFAULT_OFF = "default_off"
-
- EMAIL_BATCHING_BUFFER_SIZE = 256
- EMAIL_BATCHING_INTERVAL = 30
-
- EMAIL_NOTIFICATION_CONTENTS_FULL = "full"
- EMAIL_NOTIFICATION_CONTENTS_GENERIC = "generic"
-
- SITENAME_MAX_LENGTH = 30
-
- SERVICE_SETTINGS_DEFAULT_SITE_URL = ""
- SERVICE_SETTINGS_DEFAULT_TLS_CERT_FILE = ""
- SERVICE_SETTINGS_DEFAULT_TLS_KEY_FILE = ""
- SERVICE_SETTINGS_DEFAULT_READ_TIMEOUT = 300
- SERVICE_SETTINGS_DEFAULT_WRITE_TIMEOUT = 300
- SERVICE_SETTINGS_DEFAULT_MAX_LOGIN_ATTEMPTS = 10
- SERVICE_SETTINGS_DEFAULT_ALLOW_CORS_FROM = ""
- SERVICE_SETTINGS_DEFAULT_LISTEN_AND_ADDRESS = ":8065"
- SERVICE_SETTINGS_DEFAULT_GFYCAT_API_KEY = "2_KtH_W5"
- SERVICE_SETTINGS_DEFAULT_GFYCAT_API_SECRET = "3wLVZPiswc3DnaiaFoLkDvB4X0IV6CpMkj4tf2inJRsBY6-FnkT08zGmppWFgeof"
-
- TEAM_SETTINGS_DEFAULT_MAX_USERS_PER_TEAM = 50
- TEAM_SETTINGS_DEFAULT_CUSTOM_BRAND_TEXT = ""
- TEAM_SETTINGS_DEFAULT_CUSTOM_DESCRIPTION_TEXT = ""
- TEAM_SETTINGS_DEFAULT_USER_STATUS_AWAY_TIMEOUT = 300
-
- SQL_SETTINGS_DEFAULT_DATA_SOURCE = "mmuser:mostest@tcp(dockerhost:3306)/mattermost_test?charset=utf8mb4,utf8&readTimeout=30s&writeTimeout=30s"
-
- FILE_SETTINGS_DEFAULT_DIRECTORY = "./data/"
-
- EMAIL_SETTINGS_DEFAULT_FEEDBACK_ORGANIZATION = ""
-
- SUPPORT_SETTINGS_DEFAULT_TERMS_OF_SERVICE_LINK = "https://about.mattermost.com/default-terms/"
- SUPPORT_SETTINGS_DEFAULT_PRIVACY_POLICY_LINK = "https://about.mattermost.com/default-privacy-policy/"
- SUPPORT_SETTINGS_DEFAULT_ABOUT_LINK = "https://about.mattermost.com/default-about/"
- SUPPORT_SETTINGS_DEFAULT_HELP_LINK = "https://about.mattermost.com/default-help/"
- SUPPORT_SETTINGS_DEFAULT_REPORT_A_PROBLEM_LINK = "https://about.mattermost.com/default-report-a-problem/"
- SUPPORT_SETTINGS_DEFAULT_SUPPORT_EMAIL = "feedback@mattermost.com"
-
- LDAP_SETTINGS_DEFAULT_FIRST_NAME_ATTRIBUTE = ""
- LDAP_SETTINGS_DEFAULT_LAST_NAME_ATTRIBUTE = ""
- LDAP_SETTINGS_DEFAULT_EMAIL_ATTRIBUTE = ""
- LDAP_SETTINGS_DEFAULT_USERNAME_ATTRIBUTE = ""
- LDAP_SETTINGS_DEFAULT_NICKNAME_ATTRIBUTE = ""
- LDAP_SETTINGS_DEFAULT_ID_ATTRIBUTE = ""
- LDAP_SETTINGS_DEFAULT_POSITION_ATTRIBUTE = ""
- LDAP_SETTINGS_DEFAULT_LOGIN_FIELD_NAME = ""
-
- SAML_SETTINGS_DEFAULT_ID_ATTRIBUTE = ""
- SAML_SETTINGS_DEFAULT_FIRST_NAME_ATTRIBUTE = ""
- SAML_SETTINGS_DEFAULT_LAST_NAME_ATTRIBUTE = ""
- SAML_SETTINGS_DEFAULT_EMAIL_ATTRIBUTE = ""
- SAML_SETTINGS_DEFAULT_USERNAME_ATTRIBUTE = ""
- SAML_SETTINGS_DEFAULT_NICKNAME_ATTRIBUTE = ""
- SAML_SETTINGS_DEFAULT_LOCALE_ATTRIBUTE = ""
- SAML_SETTINGS_DEFAULT_POSITION_ATTRIBUTE = ""
-
- NATIVEAPP_SETTINGS_DEFAULT_APP_DOWNLOAD_LINK = "https://about.mattermost.com/downloads/"
- NATIVEAPP_SETTINGS_DEFAULT_ANDROID_APP_DOWNLOAD_LINK = "https://about.mattermost.com/mattermost-android-app/"
- NATIVEAPP_SETTINGS_DEFAULT_IOS_APP_DOWNLOAD_LINK = "https://about.mattermost.com/mattermost-ios-app/"
-
- WEBRTC_SETTINGS_DEFAULT_STUN_URI = ""
- WEBRTC_SETTINGS_DEFAULT_TURN_URI = ""
-
- ANALYTICS_SETTINGS_DEFAULT_MAX_USERS_FOR_STATISTICS = 2500
-
- ANNOUNCEMENT_SETTINGS_DEFAULT_BANNER_COLOR = "#f2a93b"
- ANNOUNCEMENT_SETTINGS_DEFAULT_BANNER_TEXT_COLOR = "#333333"
-
- TEAM_SETTINGS_DEFAULT_TEAM_TEXT = "default"
-
- ELASTICSEARCH_SETTINGS_DEFAULT_CONNECTION_URL = ""
- ELASTICSEARCH_SETTINGS_DEFAULT_USERNAME = ""
- ELASTICSEARCH_SETTINGS_DEFAULT_PASSWORD = ""
- ELASTICSEARCH_SETTINGS_DEFAULT_POST_INDEX_REPLICAS = 1
- ELASTICSEARCH_SETTINGS_DEFAULT_POST_INDEX_SHARDS = 1
- ELASTICSEARCH_SETTINGS_DEFAULT_AGGREGATE_POSTS_AFTER_DAYS = 365
- ELASTICSEARCH_SETTINGS_DEFAULT_POSTS_AGGREGATOR_JOB_START_TIME = "03:00"
- ELASTICSEARCH_SETTINGS_DEFAULT_INDEX_PREFIX = ""
- ELASTICSEARCH_SETTINGS_DEFAULT_LIVE_INDEXING_BATCH_SIZE = 1
- ELASTICSEARCH_SETTINGS_DEFAULT_BULK_INDEXING_TIME_WINDOW_SECONDS = 3600
- ELASTICSEARCH_SETTINGS_DEFAULT_REQUEST_TIMEOUT_SECONDS = 30
-
- DATA_RETENTION_SETTINGS_DEFAULT_MESSAGE_RETENTION_DAYS = 365
- DATA_RETENTION_SETTINGS_DEFAULT_FILE_RETENTION_DAYS = 365
- DATA_RETENTION_SETTINGS_DEFAULT_DELETION_JOB_START_TIME = "02:00"
-
- PLUGIN_SETTINGS_DEFAULT_DIRECTORY = "./plugins"
- PLUGIN_SETTINGS_DEFAULT_CLIENT_DIRECTORY = "./client/plugins"
-
- TIMEZONE_SETTINGS_DEFAULT_SUPPORTED_TIMEZONES_PATH = "timezones.json"
-
- COMPLIANCE_EXPORT_TYPE_CSV = "csv"
- COMPLIANCE_EXPORT_TYPE_ACTIANCE = "actiance"
- COMPLIANCE_EXPORT_TYPE_GLOBALRELAY = "globalrelay"
- GLOBALRELAY_CUSTOMER_TYPE_A9 = "A9"
- GLOBALRELAY_CUSTOMER_TYPE_A10 = "A10"
-
- CLIENT_SIDE_CERT_CHECK_PRIMARY_AUTH = "primary"
- CLIENT_SIDE_CERT_CHECK_SECONDARY_AUTH = "secondary"
-)
-
-type ServiceSettings struct {
- SiteURL *string
- WebsocketURL *string
- LicenseFileLocation *string
- ListenAddress *string
- ConnectionSecurity *string
- TLSCertFile *string
- TLSKeyFile *string
- UseLetsEncrypt *bool
- LetsEncryptCertificateCacheFile *string
- Forward80To443 *bool
- ReadTimeout *int
- WriteTimeout *int
- MaximumLoginAttempts *int
- GoroutineHealthThreshold *int
- GoogleDeveloperKey string
- EnableOAuthServiceProvider bool
- EnableIncomingWebhooks bool
- EnableOutgoingWebhooks bool
- EnableCommands *bool
- EnableOnlyAdminIntegrations *bool
- EnablePostUsernameOverride bool
- EnablePostIconOverride bool
- EnableLinkPreviews *bool
- EnableTesting bool
- EnableDeveloper *bool
- EnableSecurityFixAlert *bool
- EnableInsecureOutgoingConnections *bool
- AllowedUntrustedInternalConnections *string
- EnableMultifactorAuthentication *bool
- EnforceMultifactorAuthentication *bool
- EnableUserAccessTokens *bool
- AllowCorsFrom *string
- CorsExposedHeaders *string
- CorsAllowCredentials *bool
- CorsDebug *bool
- AllowCookiesForSubdomains *bool
- SessionLengthWebInDays *int
- SessionLengthMobileInDays *int
- SessionLengthSSOInDays *int
- SessionCacheInMinutes *int
- SessionIdleTimeoutInMinutes *int
- WebsocketSecurePort *int
- WebsocketPort *int
- WebserverMode *string
- EnableCustomEmoji *bool
- EnableEmojiPicker *bool
- EnableGifPicker *bool
- GfycatApiKey *string
- GfycatApiSecret *string
- RestrictCustomEmojiCreation *string
- RestrictPostDelete *string
- AllowEditPost *string
- PostEditTimeLimit *int
- TimeBetweenUserTypingUpdatesMilliseconds *int64
- EnablePostSearch *bool
- EnableUserTypingMessages *bool
- EnableChannelViewedMessages *bool
- EnableUserStatuses *bool
- ExperimentalEnableAuthenticationTransfer *bool
- ClusterLogTimeoutMilliseconds *int
- CloseUnusedDirectMessages *bool
- EnablePreviewFeatures *bool
- EnableTutorial *bool
- ExperimentalEnableDefaultChannelLeaveJoinMessages *bool
- ExperimentalGroupUnreadChannels *string
- ExperimentalChannelOrganization *bool
- ImageProxyType *string
- ImageProxyURL *string
- ImageProxyOptions *string
- EnableAPITeamDeletion *bool
- ExperimentalEnableHardenedMode *bool
- ExperimentalLimitClientConfig *bool
- EnableEmailInvitations *bool
-}
-
-func (s *ServiceSettings) SetDefaults() {
- if s.EnableEmailInvitations == nil {
- // If the site URL is also not present then assume this is a clean install
- if s.SiteURL == nil {
- s.EnableEmailInvitations = NewBool(false)
- } else {
- s.EnableEmailInvitations = NewBool(true)
- }
- }
-
- if s.SiteURL == nil {
- s.SiteURL = NewString(SERVICE_SETTINGS_DEFAULT_SITE_URL)
- }
-
- if s.WebsocketURL == nil {
- s.WebsocketURL = NewString("")
- }
-
- if s.LicenseFileLocation == nil {
- s.LicenseFileLocation = NewString("")
- }
-
- if s.ListenAddress == nil {
- s.ListenAddress = NewString(SERVICE_SETTINGS_DEFAULT_LISTEN_AND_ADDRESS)
- }
-
- if s.EnableLinkPreviews == nil {
- s.EnableLinkPreviews = NewBool(false)
- }
-
- if s.EnableDeveloper == nil {
- s.EnableDeveloper = NewBool(false)
- }
-
- if s.EnableSecurityFixAlert == nil {
- s.EnableSecurityFixAlert = NewBool(true)
- }
-
- if s.EnableInsecureOutgoingConnections == nil {
- s.EnableInsecureOutgoingConnections = NewBool(false)
- }
-
- if s.AllowedUntrustedInternalConnections == nil {
- s.AllowedUntrustedInternalConnections = NewString("")
- }
-
- if s.EnableMultifactorAuthentication == nil {
- s.EnableMultifactorAuthentication = NewBool(false)
- }
-
- if s.EnforceMultifactorAuthentication == nil {
- s.EnforceMultifactorAuthentication = NewBool(false)
- }
-
- if s.EnableUserAccessTokens == nil {
- s.EnableUserAccessTokens = NewBool(false)
- }
-
- if s.GoroutineHealthThreshold == nil {
- s.GoroutineHealthThreshold = NewInt(-1)
- }
-
- if s.ConnectionSecurity == nil {
- s.ConnectionSecurity = NewString("")
- }
-
- if s.TLSKeyFile == nil {
- s.TLSKeyFile = NewString(SERVICE_SETTINGS_DEFAULT_TLS_KEY_FILE)
- }
-
- if s.TLSCertFile == nil {
- s.TLSCertFile = NewString(SERVICE_SETTINGS_DEFAULT_TLS_CERT_FILE)
- }
-
- if s.UseLetsEncrypt == nil {
- s.UseLetsEncrypt = NewBool(false)
- }
-
- if s.LetsEncryptCertificateCacheFile == nil {
- s.LetsEncryptCertificateCacheFile = NewString("./config/letsencrypt.cache")
- }
-
- if s.ReadTimeout == nil {
- s.ReadTimeout = NewInt(SERVICE_SETTINGS_DEFAULT_READ_TIMEOUT)
- }
-
- if s.WriteTimeout == nil {
- s.WriteTimeout = NewInt(SERVICE_SETTINGS_DEFAULT_WRITE_TIMEOUT)
- }
-
- if s.MaximumLoginAttempts == nil {
- s.MaximumLoginAttempts = NewInt(SERVICE_SETTINGS_DEFAULT_MAX_LOGIN_ATTEMPTS)
- }
-
- if s.Forward80To443 == nil {
- s.Forward80To443 = NewBool(false)
- }
-
- if s.TimeBetweenUserTypingUpdatesMilliseconds == nil {
- s.TimeBetweenUserTypingUpdatesMilliseconds = NewInt64(5000)
- }
-
- if s.EnablePostSearch == nil {
- s.EnablePostSearch = NewBool(true)
- }
-
- if s.EnableUserTypingMessages == nil {
- s.EnableUserTypingMessages = NewBool(true)
- }
-
- if s.EnableChannelViewedMessages == nil {
- s.EnableChannelViewedMessages = NewBool(true)
- }
-
- if s.EnableUserStatuses == nil {
- s.EnableUserStatuses = NewBool(true)
- }
-
- if s.ClusterLogTimeoutMilliseconds == nil {
- s.ClusterLogTimeoutMilliseconds = NewInt(2000)
- }
-
- if s.CloseUnusedDirectMessages == nil {
- s.CloseUnusedDirectMessages = NewBool(false)
- }
-
- if s.EnableTutorial == nil {
- s.EnableTutorial = NewBool(true)
- }
-
- if s.SessionLengthWebInDays == nil {
- s.SessionLengthWebInDays = NewInt(30)
- }
-
- if s.SessionLengthMobileInDays == nil {
- s.SessionLengthMobileInDays = NewInt(30)
- }
-
- if s.SessionLengthSSOInDays == nil {
- s.SessionLengthSSOInDays = NewInt(30)
- }
-
- if s.SessionCacheInMinutes == nil {
- s.SessionCacheInMinutes = NewInt(10)
- }
-
- if s.SessionIdleTimeoutInMinutes == nil {
- s.SessionIdleTimeoutInMinutes = NewInt(0)
- }
-
- if s.EnableCommands == nil {
- s.EnableCommands = NewBool(false)
- }
-
- if s.EnableOnlyAdminIntegrations == nil {
- s.EnableOnlyAdminIntegrations = NewBool(true)
- }
-
- if s.WebsocketPort == nil {
- s.WebsocketPort = NewInt(80)
- }
-
- if s.WebsocketSecurePort == nil {
- s.WebsocketSecurePort = NewInt(443)
- }
-
- if s.AllowCorsFrom == nil {
- s.AllowCorsFrom = NewString(SERVICE_SETTINGS_DEFAULT_ALLOW_CORS_FROM)
- }
-
- if s.CorsExposedHeaders == nil {
- s.CorsExposedHeaders = NewString("")
- }
-
- if s.CorsAllowCredentials == nil {
- s.CorsAllowCredentials = NewBool(false)
- }
-
- if s.CorsDebug == nil {
- s.CorsDebug = NewBool(false)
- }
-
- if s.AllowCookiesForSubdomains == nil {
- s.AllowCookiesForSubdomains = NewBool(false)
- }
-
- if s.WebserverMode == nil {
- s.WebserverMode = NewString("gzip")
- } else if *s.WebserverMode == "regular" {
- *s.WebserverMode = "gzip"
- }
-
- if s.EnableCustomEmoji == nil {
- s.EnableCustomEmoji = NewBool(false)
- }
-
- if s.EnableEmojiPicker == nil {
- s.EnableEmojiPicker = NewBool(true)
- }
-
- if s.EnableGifPicker == nil {
- s.EnableGifPicker = NewBool(false)
- }
-
- if s.GfycatApiKey == nil || *s.GfycatApiKey == "" {
- s.GfycatApiKey = NewString(SERVICE_SETTINGS_DEFAULT_GFYCAT_API_KEY)
- }
-
- if s.GfycatApiSecret == nil || *s.GfycatApiSecret == "" {
- s.GfycatApiSecret = NewString(SERVICE_SETTINGS_DEFAULT_GFYCAT_API_SECRET)
- }
-
- if s.RestrictCustomEmojiCreation == nil {
- s.RestrictCustomEmojiCreation = NewString(RESTRICT_EMOJI_CREATION_ALL)
- }
-
- if s.RestrictPostDelete == nil {
- s.RestrictPostDelete = NewString(PERMISSIONS_DELETE_POST_ALL)
- }
-
- if s.AllowEditPost == nil {
- s.AllowEditPost = NewString(ALLOW_EDIT_POST_ALWAYS)
- }
-
- if s.ExperimentalEnableAuthenticationTransfer == nil {
- s.ExperimentalEnableAuthenticationTransfer = NewBool(true)
- }
-
- if s.PostEditTimeLimit == nil {
- s.PostEditTimeLimit = NewInt(-1)
- }
-
- if s.EnablePreviewFeatures == nil {
- s.EnablePreviewFeatures = NewBool(true)
- }
-
- if s.ExperimentalEnableDefaultChannelLeaveJoinMessages == nil {
- s.ExperimentalEnableDefaultChannelLeaveJoinMessages = NewBool(true)
- }
-
- if s.ExperimentalGroupUnreadChannels == nil {
- s.ExperimentalGroupUnreadChannels = NewString(GROUP_UNREAD_CHANNELS_DISABLED)
- } else if *s.ExperimentalGroupUnreadChannels == "0" {
- s.ExperimentalGroupUnreadChannels = NewString(GROUP_UNREAD_CHANNELS_DISABLED)
- } else if *s.ExperimentalGroupUnreadChannels == "1" {
- s.ExperimentalGroupUnreadChannels = NewString(GROUP_UNREAD_CHANNELS_DEFAULT_ON)
- }
-
- if s.ExperimentalChannelOrganization == nil {
- experimentalUnreadEnabled := *s.ExperimentalGroupUnreadChannels != GROUP_UNREAD_CHANNELS_DISABLED
- s.ExperimentalChannelOrganization = NewBool(experimentalUnreadEnabled)
- }
-
- if s.ImageProxyType == nil {
- s.ImageProxyType = NewString("")
- }
-
- if s.ImageProxyURL == nil {
- s.ImageProxyURL = NewString("")
- }
-
- if s.ImageProxyOptions == nil {
- s.ImageProxyOptions = NewString("")
- }
-
- if s.EnableAPITeamDeletion == nil {
- s.EnableAPITeamDeletion = NewBool(false)
- }
-
- if s.ExperimentalEnableHardenedMode == nil {
- s.ExperimentalEnableHardenedMode = NewBool(false)
- }
-
- if s.ExperimentalLimitClientConfig == nil {
- s.ExperimentalLimitClientConfig = NewBool(false)
- }
-}
-
-type ClusterSettings struct {
- Enable *bool
- ClusterName *string
- OverrideHostname *string
- UseIpAddress *bool
- UseExperimentalGossip *bool
- ReadOnlyConfig *bool
- GossipPort *int
- StreamingPort *int
- MaxIdleConns *int
- MaxIdleConnsPerHost *int
- IdleConnTimeoutMilliseconds *int
-}
-
-func (s *ClusterSettings) SetDefaults() {
- if s.Enable == nil {
- s.Enable = NewBool(false)
- }
-
- if s.ClusterName == nil {
- s.ClusterName = NewString("")
- }
-
- if s.OverrideHostname == nil {
- s.OverrideHostname = NewString("")
- }
-
- if s.UseIpAddress == nil {
- s.UseIpAddress = NewBool(true)
- }
-
- if s.UseExperimentalGossip == nil {
- s.UseExperimentalGossip = NewBool(false)
- }
-
- if s.ReadOnlyConfig == nil {
- s.ReadOnlyConfig = NewBool(true)
- }
-
- if s.GossipPort == nil {
- s.GossipPort = NewInt(8074)
- }
-
- if s.StreamingPort == nil {
- s.StreamingPort = NewInt(8075)
- }
-
- if s.MaxIdleConns == nil {
- s.MaxIdleConns = NewInt(100)
- }
-
- if s.MaxIdleConnsPerHost == nil {
- s.MaxIdleConnsPerHost = NewInt(128)
- }
-
- if s.IdleConnTimeoutMilliseconds == nil {
- s.IdleConnTimeoutMilliseconds = NewInt(90000)
- }
-}
-
-type MetricsSettings struct {
- Enable *bool
- BlockProfileRate *int
- ListenAddress *string
-}
-
-func (s *MetricsSettings) SetDefaults() {
- if s.ListenAddress == nil {
- s.ListenAddress = NewString(":8067")
- }
-
- if s.Enable == nil {
- s.Enable = NewBool(false)
- }
-
- if s.BlockProfileRate == nil {
- s.BlockProfileRate = NewInt(0)
- }
-}
-
-type ExperimentalSettings struct {
- ClientSideCertEnable *bool
- ClientSideCertCheck *string
-}
-
-func (s *ExperimentalSettings) SetDefaults() {
- if s.ClientSideCertEnable == nil {
- s.ClientSideCertEnable = NewBool(false)
- }
-
- if s.ClientSideCertCheck == nil {
- s.ClientSideCertCheck = NewString(CLIENT_SIDE_CERT_CHECK_SECONDARY_AUTH)
- }
-}
-
-type AnalyticsSettings struct {
- MaxUsersForStatistics *int
-}
-
-func (s *AnalyticsSettings) SetDefaults() {
- if s.MaxUsersForStatistics == nil {
- s.MaxUsersForStatistics = NewInt(ANALYTICS_SETTINGS_DEFAULT_MAX_USERS_FOR_STATISTICS)
- }
-}
-
-type SSOSettings struct {
- Enable bool
- Secret string
- Id string
- Scope string
- AuthEndpoint string
- TokenEndpoint string
- UserApiEndpoint string
-}
-
-type SqlSettings struct {
- DriverName *string
- DataSource *string
- DataSourceReplicas []string
- DataSourceSearchReplicas []string
- MaxIdleConns *int
- ConnMaxLifetimeMilliseconds *int
- MaxOpenConns *int
- Trace bool
- AtRestEncryptKey string
- QueryTimeout *int
- EnablePublicChannelsMaterialization *bool
-}
-
-func (s *SqlSettings) SetDefaults() {
- if s.DriverName == nil {
- s.DriverName = NewString(DATABASE_DRIVER_MYSQL)
- }
-
- if s.DataSource == nil {
- s.DataSource = NewString(SQL_SETTINGS_DEFAULT_DATA_SOURCE)
- }
-
- if len(s.AtRestEncryptKey) == 0 {
- s.AtRestEncryptKey = NewRandomString(32)
- }
-
- if s.MaxIdleConns == nil {
- s.MaxIdleConns = NewInt(20)
- }
-
- if s.MaxOpenConns == nil {
- s.MaxOpenConns = NewInt(300)
- }
-
- if s.ConnMaxLifetimeMilliseconds == nil {
- s.ConnMaxLifetimeMilliseconds = NewInt(3600000)
- }
-
- if s.QueryTimeout == nil {
- s.QueryTimeout = NewInt(30)
- }
-
- if s.EnablePublicChannelsMaterialization == nil {
- s.EnablePublicChannelsMaterialization = NewBool(true)
- }
-}
-
-type LogSettings struct {
- EnableConsole bool
- ConsoleLevel string
- ConsoleJson *bool
- EnableFile bool
- FileLevel string
- FileJson *bool
- FileLocation string
- EnableWebhookDebugging bool
- EnableDiagnostics *bool
-}
-
-func (s *LogSettings) SetDefaults() {
- if s.EnableDiagnostics == nil {
- s.EnableDiagnostics = NewBool(true)
- }
-
- if s.ConsoleJson == nil {
- s.ConsoleJson = NewBool(true)
- }
-
- if s.FileJson == nil {
- s.FileJson = NewBool(true)
- }
-}
-
-type PasswordSettings struct {
- MinimumLength *int
- Lowercase *bool
- Number *bool
- Uppercase *bool
- Symbol *bool
-}
-
-func (s *PasswordSettings) SetDefaults() {
- if s.MinimumLength == nil {
- s.MinimumLength = NewInt(PASSWORD_MINIMUM_LENGTH)
- }
-
- if s.Lowercase == nil {
- s.Lowercase = NewBool(false)
- }
-
- if s.Number == nil {
- s.Number = NewBool(false)
- }
-
- if s.Uppercase == nil {
- s.Uppercase = NewBool(false)
- }
-
- if s.Symbol == nil {
- s.Symbol = NewBool(false)
- }
-}
-
-type FileSettings struct {
- EnableFileAttachments *bool
- EnableMobileUpload *bool
- EnableMobileDownload *bool
- MaxFileSize *int64
- DriverName *string
- Directory string
- EnablePublicLink bool
- PublicLinkSalt *string
- InitialFont string
- AmazonS3AccessKeyId string
- AmazonS3SecretAccessKey string
- AmazonS3Bucket string
- AmazonS3Region string
- AmazonS3Endpoint string
- AmazonS3SSL *bool
- AmazonS3SignV2 *bool
- AmazonS3SSE *bool
- AmazonS3Trace *bool
-}
-
-func (s *FileSettings) SetDefaults() {
- if s.DriverName == nil {
- s.DriverName = NewString(IMAGE_DRIVER_LOCAL)
- }
-
- if s.AmazonS3Endpoint == "" {
- // Defaults to "s3.amazonaws.com"
- s.AmazonS3Endpoint = "s3.amazonaws.com"
- }
-
- if s.AmazonS3SSL == nil {
- s.AmazonS3SSL = NewBool(true) // Secure by default.
- }
-
- if s.AmazonS3SignV2 == nil {
- s.AmazonS3SignV2 = new(bool)
- // Signature v2 is not enabled by default.
- }
-
- if s.AmazonS3SSE == nil {
- s.AmazonS3SSE = NewBool(false) // Not Encrypted by default.
- }
-
- if s.AmazonS3Trace == nil {
- s.AmazonS3Trace = NewBool(false)
- }
-
- if s.EnableFileAttachments == nil {
- s.EnableFileAttachments = NewBool(true)
- }
-
- if s.EnableMobileUpload == nil {
- s.EnableMobileUpload = NewBool(true)
- }
-
- if s.EnableMobileDownload == nil {
- s.EnableMobileDownload = NewBool(true)
- }
-
- if s.MaxFileSize == nil {
- s.MaxFileSize = NewInt64(52428800) // 50 MB
- }
-
- if s.PublicLinkSalt == nil || len(*s.PublicLinkSalt) == 0 {
- s.PublicLinkSalt = NewString(NewRandomString(32))
- }
-
- if s.InitialFont == "" {
- // Defaults to "nunito-bold.ttf"
- s.InitialFont = "nunito-bold.ttf"
- }
-
- if s.Directory == "" {
- s.Directory = FILE_SETTINGS_DEFAULT_DIRECTORY
- }
-}
-
-type EmailSettings struct {
- EnableSignUpWithEmail bool
- EnableSignInWithEmail *bool
- EnableSignInWithUsername *bool
- SendEmailNotifications bool
- UseChannelInEmailNotifications *bool
- RequireEmailVerification bool
- FeedbackName string
- FeedbackEmail string
- FeedbackOrganization *string
- EnableSMTPAuth *bool
- SMTPUsername string
- SMTPPassword string
- SMTPServer string
- SMTPPort string
- ConnectionSecurity string
- InviteSalt string
- SendPushNotifications *bool
- PushNotificationServer *string
- PushNotificationContents *string
- EnableEmailBatching *bool
- EmailBatchingBufferSize *int
- EmailBatchingInterval *int
- EnablePreviewModeBanner *bool
- SkipServerCertificateVerification *bool
- EmailNotificationContentsType *string
- LoginButtonColor *string
- LoginButtonBorderColor *string
- LoginButtonTextColor *string
-}
-
-func (s *EmailSettings) SetDefaults() {
- if len(s.InviteSalt) == 0 {
- s.InviteSalt = NewRandomString(32)
- }
-
- if s.EnableSignInWithEmail == nil {
- s.EnableSignInWithEmail = NewBool(s.EnableSignUpWithEmail)
- }
-
- if s.EnableSignInWithUsername == nil {
- s.EnableSignInWithUsername = NewBool(false)
- }
-
- if s.UseChannelInEmailNotifications == nil {
- s.UseChannelInEmailNotifications = NewBool(false)
- }
-
- if s.SendPushNotifications == nil {
- s.SendPushNotifications = NewBool(false)
- }
-
- if s.PushNotificationServer == nil {
- s.PushNotificationServer = NewString("")
- }
-
- if s.PushNotificationContents == nil {
- s.PushNotificationContents = NewString(GENERIC_NOTIFICATION)
- }
-
- if s.FeedbackOrganization == nil {
- s.FeedbackOrganization = NewString(EMAIL_SETTINGS_DEFAULT_FEEDBACK_ORGANIZATION)
- }
-
- if s.EnableEmailBatching == nil {
- s.EnableEmailBatching = NewBool(false)
- }
-
- if s.EmailBatchingBufferSize == nil {
- s.EmailBatchingBufferSize = NewInt(EMAIL_BATCHING_BUFFER_SIZE)
- }
-
- if s.EmailBatchingInterval == nil {
- s.EmailBatchingInterval = NewInt(EMAIL_BATCHING_INTERVAL)
- }
-
- if s.EnablePreviewModeBanner == nil {
- s.EnablePreviewModeBanner = NewBool(true)
- }
-
- if s.EnableSMTPAuth == nil {
- s.EnableSMTPAuth = new(bool)
- if s.ConnectionSecurity == CONN_SECURITY_NONE {
- *s.EnableSMTPAuth = false
- } else {
- *s.EnableSMTPAuth = true
- }
- }
-
- if s.ConnectionSecurity == CONN_SECURITY_PLAIN {
- s.ConnectionSecurity = CONN_SECURITY_NONE
- }
-
- if s.SkipServerCertificateVerification == nil {
- s.SkipServerCertificateVerification = NewBool(false)
- }
-
- if s.EmailNotificationContentsType == nil {
- s.EmailNotificationContentsType = NewString(EMAIL_NOTIFICATION_CONTENTS_FULL)
- }
-
- if s.LoginButtonColor == nil {
- s.LoginButtonColor = NewString("#0000")
- }
-
- if s.LoginButtonBorderColor == nil {
- s.LoginButtonBorderColor = NewString("#2389D7")
- }
-
- if s.LoginButtonTextColor == nil {
- s.LoginButtonTextColor = NewString("#2389D7")
- }
-}
-
-type ExtensionSettings struct {
- EnableExperimentalExtensions *bool
- AllowedExtensionsIDs []string
-}
-
-func (s *ExtensionSettings) SetDefaults() {
- if s.EnableExperimentalExtensions == nil {
- s.EnableExperimentalExtensions = NewBool(false)
- }
-
- if s.AllowedExtensionsIDs == nil {
- s.AllowedExtensionsIDs = []string{}
- }
-}
-
-type RateLimitSettings struct {
- Enable *bool
- PerSec *int
- MaxBurst *int
- MemoryStoreSize *int
- VaryByRemoteAddr *bool
- VaryByUser *bool
- VaryByHeader string
-}
-
-func (s *RateLimitSettings) SetDefaults() {
- if s.Enable == nil {
- s.Enable = NewBool(false)
- }
-
- if s.PerSec == nil {
- s.PerSec = NewInt(10)
- }
-
- if s.MaxBurst == nil {
- s.MaxBurst = NewInt(100)
- }
-
- if s.MemoryStoreSize == nil {
- s.MemoryStoreSize = NewInt(10000)
- }
-
- if s.VaryByRemoteAddr == nil {
- s.VaryByRemoteAddr = NewBool(true)
- }
-
- if s.VaryByUser == nil {
- s.VaryByUser = NewBool(false)
- }
-}
-
-type PrivacySettings struct {
- ShowEmailAddress bool
- ShowFullName bool
-}
-
-type SupportSettings struct {
- TermsOfServiceLink *string
- PrivacyPolicyLink *string
- AboutLink *string
- HelpLink *string
- ReportAProblemLink *string
- SupportEmail *string
- CustomTermsOfServiceEnabled *bool
-}
-
-func (s *SupportSettings) SetDefaults() {
- if !IsSafeLink(s.TermsOfServiceLink) {
- *s.TermsOfServiceLink = SUPPORT_SETTINGS_DEFAULT_TERMS_OF_SERVICE_LINK
- }
-
- if s.TermsOfServiceLink == nil {
- s.TermsOfServiceLink = NewString(SUPPORT_SETTINGS_DEFAULT_TERMS_OF_SERVICE_LINK)
- }
-
- if !IsSafeLink(s.PrivacyPolicyLink) {
- *s.PrivacyPolicyLink = ""
- }
-
- if s.PrivacyPolicyLink == nil {
- s.PrivacyPolicyLink = NewString(SUPPORT_SETTINGS_DEFAULT_PRIVACY_POLICY_LINK)
- }
-
- if !IsSafeLink(s.AboutLink) {
- *s.AboutLink = ""
- }
-
- if s.AboutLink == nil {
- s.AboutLink = NewString(SUPPORT_SETTINGS_DEFAULT_ABOUT_LINK)
- }
-
- if !IsSafeLink(s.HelpLink) {
- *s.HelpLink = ""
- }
-
- if s.HelpLink == nil {
- s.HelpLink = NewString(SUPPORT_SETTINGS_DEFAULT_HELP_LINK)
- }
-
- if !IsSafeLink(s.ReportAProblemLink) {
- *s.ReportAProblemLink = ""
- }
-
- if s.ReportAProblemLink == nil {
- s.ReportAProblemLink = NewString(SUPPORT_SETTINGS_DEFAULT_REPORT_A_PROBLEM_LINK)
- }
-
- if s.SupportEmail == nil {
- s.SupportEmail = NewString(SUPPORT_SETTINGS_DEFAULT_SUPPORT_EMAIL)
- }
-
- if s.CustomTermsOfServiceEnabled == nil {
- s.CustomTermsOfServiceEnabled = NewBool(false)
- }
-}
-
-type AnnouncementSettings struct {
- EnableBanner *bool
- BannerText *string
- BannerColor *string
- BannerTextColor *string
- AllowBannerDismissal *bool
-}
-
-func (s *AnnouncementSettings) SetDefaults() {
- if s.EnableBanner == nil {
- s.EnableBanner = NewBool(false)
- }
-
- if s.BannerText == nil {
- s.BannerText = NewString("")
- }
-
- if s.BannerColor == nil {
- s.BannerColor = NewString(ANNOUNCEMENT_SETTINGS_DEFAULT_BANNER_COLOR)
- }
-
- if s.BannerTextColor == nil {
- s.BannerTextColor = NewString(ANNOUNCEMENT_SETTINGS_DEFAULT_BANNER_TEXT_COLOR)
- }
-
- if s.AllowBannerDismissal == nil {
- s.AllowBannerDismissal = NewBool(true)
- }
-}
-
-type ThemeSettings struct {
- EnableThemeSelection *bool
- DefaultTheme *string
- AllowCustomThemes *bool
- AllowedThemes []string
-}
-
-func (s *ThemeSettings) SetDefaults() {
- if s.EnableThemeSelection == nil {
- s.EnableThemeSelection = NewBool(true)
- }
-
- if s.DefaultTheme == nil {
- s.DefaultTheme = NewString(TEAM_SETTINGS_DEFAULT_TEAM_TEXT)
- }
-
- if s.AllowCustomThemes == nil {
- s.AllowCustomThemes = NewBool(true)
- }
-
- if s.AllowedThemes == nil {
- s.AllowedThemes = []string{}
- }
-}
-
-type TeamSettings struct {
- SiteName string
- MaxUsersPerTeam *int
- EnableTeamCreation *bool
- EnableUserCreation *bool
- EnableOpenServer *bool
- EnableUserDeactivation *bool
- RestrictCreationToDomains string
- EnableCustomBrand *bool
- CustomBrandText *string
- CustomDescriptionText *string
- RestrictDirectMessage *string
- RestrictTeamInvite *string
- RestrictPublicChannelManagement *string
- RestrictPrivateChannelManagement *string
- RestrictPublicChannelCreation *string
- RestrictPrivateChannelCreation *string
- RestrictPublicChannelDeletion *string
- RestrictPrivateChannelDeletion *string
- RestrictPrivateChannelManageMembers *string
- EnableXToLeaveChannelsFromLHS *bool
- UserStatusAwayTimeout *int64
- MaxChannelsPerTeam *int64
- MaxNotificationsPerChannel *int64
- EnableConfirmNotificationsToChannel *bool
- TeammateNameDisplay *string
- ExperimentalViewArchivedChannels *bool
- ExperimentalEnableAutomaticReplies *bool
- ExperimentalHideTownSquareinLHS *bool
- ExperimentalTownSquareIsReadOnly *bool
- ExperimentalPrimaryTeam *string
- ExperimentalDefaultChannels []string
-}
-
-func (s *TeamSettings) SetDefaults() {
- if s.MaxUsersPerTeam == nil {
- s.MaxUsersPerTeam = NewInt(TEAM_SETTINGS_DEFAULT_MAX_USERS_PER_TEAM)
- }
-
- if s.EnableCustomBrand == nil {
- s.EnableCustomBrand = NewBool(false)
- }
-
- if s.EnableUserDeactivation == nil {
- s.EnableUserDeactivation = NewBool(false)
- }
-
- if s.CustomBrandText == nil {
- s.CustomBrandText = NewString(TEAM_SETTINGS_DEFAULT_CUSTOM_BRAND_TEXT)
- }
-
- if s.CustomDescriptionText == nil {
- s.CustomDescriptionText = NewString(TEAM_SETTINGS_DEFAULT_CUSTOM_DESCRIPTION_TEXT)
- }
-
- if s.EnableOpenServer == nil {
- s.EnableOpenServer = NewBool(false)
- }
-
- if s.RestrictDirectMessage == nil {
- s.RestrictDirectMessage = NewString(DIRECT_MESSAGE_ANY)
- }
-
- if s.RestrictTeamInvite == nil {
- s.RestrictTeamInvite = NewString(PERMISSIONS_ALL)
- }
-
- if s.RestrictPublicChannelManagement == nil {
- s.RestrictPublicChannelManagement = NewString(PERMISSIONS_ALL)
- }
-
- if s.RestrictPrivateChannelManagement == nil {
- s.RestrictPrivateChannelManagement = NewString(PERMISSIONS_ALL)
- }
-
- if s.RestrictPublicChannelCreation == nil {
- s.RestrictPublicChannelCreation = new(string)
- // If this setting does not exist, assume migration from <3.6, so use management setting as default.
- if *s.RestrictPublicChannelManagement == PERMISSIONS_CHANNEL_ADMIN {
- *s.RestrictPublicChannelCreation = PERMISSIONS_TEAM_ADMIN
- } else {
- *s.RestrictPublicChannelCreation = *s.RestrictPublicChannelManagement
- }
- }
-
- if s.RestrictPrivateChannelCreation == nil {
- // If this setting does not exist, assume migration from <3.6, so use management setting as default.
- if *s.RestrictPrivateChannelManagement == PERMISSIONS_CHANNEL_ADMIN {
- s.RestrictPrivateChannelCreation = NewString(PERMISSIONS_TEAM_ADMIN)
- } else {
- s.RestrictPrivateChannelCreation = NewString(*s.RestrictPrivateChannelManagement)
- }
- }
-
- if s.RestrictPublicChannelDeletion == nil {
- // If this setting does not exist, assume migration from <3.6, so use management setting as default.
- s.RestrictPublicChannelDeletion = NewString(*s.RestrictPublicChannelManagement)
- }
-
- if s.RestrictPrivateChannelDeletion == nil {
- // If this setting does not exist, assume migration from <3.6, so use management setting as default.
- s.RestrictPrivateChannelDeletion = NewString(*s.RestrictPrivateChannelManagement)
- }
-
- if s.RestrictPrivateChannelManageMembers == nil {
- s.RestrictPrivateChannelManageMembers = NewString(PERMISSIONS_ALL)
- }
-
- if s.EnableXToLeaveChannelsFromLHS == nil {
- s.EnableXToLeaveChannelsFromLHS = NewBool(false)
- }
-
- if s.UserStatusAwayTimeout == nil {
- s.UserStatusAwayTimeout = NewInt64(TEAM_SETTINGS_DEFAULT_USER_STATUS_AWAY_TIMEOUT)
- }
-
- if s.MaxChannelsPerTeam == nil {
- s.MaxChannelsPerTeam = NewInt64(2000)
- }
-
- if s.MaxNotificationsPerChannel == nil {
- s.MaxNotificationsPerChannel = NewInt64(1000)
- }
-
- if s.EnableConfirmNotificationsToChannel == nil {
- s.EnableConfirmNotificationsToChannel = NewBool(true)
- }
-
- if s.ExperimentalEnableAutomaticReplies == nil {
- s.ExperimentalEnableAutomaticReplies = NewBool(false)
- }
-
- if s.ExperimentalHideTownSquareinLHS == nil {
- s.ExperimentalHideTownSquareinLHS = NewBool(false)
- }
-
- if s.ExperimentalTownSquareIsReadOnly == nil {
- s.ExperimentalTownSquareIsReadOnly = NewBool(false)
- }
-
- if s.ExperimentalPrimaryTeam == nil {
- s.ExperimentalPrimaryTeam = NewString("")
- }
-
- if s.ExperimentalDefaultChannels == nil {
- s.ExperimentalDefaultChannels = []string{}
- }
-
- if s.EnableTeamCreation == nil {
- s.EnableTeamCreation = NewBool(true)
- }
-
- if s.EnableUserCreation == nil {
- s.EnableUserCreation = NewBool(true)
- }
-
- if s.ExperimentalViewArchivedChannels == nil {
- s.ExperimentalViewArchivedChannels = NewBool(false)
- }
-}
-
-type ClientRequirements struct {
- AndroidLatestVersion string
- AndroidMinVersion string
- DesktopLatestVersion string
- DesktopMinVersion string
- IosLatestVersion string
- IosMinVersion string
-}
-
-type LdapSettings struct {
- // Basic
- Enable *bool
- EnableSync *bool
- LdapServer *string
- LdapPort *int
- ConnectionSecurity *string
- BaseDN *string
- BindUsername *string
- BindPassword *string
-
- // Filtering
- UserFilter *string
-
- // User Mapping
- FirstNameAttribute *string
- LastNameAttribute *string
- EmailAttribute *string
- UsernameAttribute *string
- NicknameAttribute *string
- IdAttribute *string
- PositionAttribute *string
- LoginIdAttribute *string
-
- // Synchronization
- SyncIntervalMinutes *int
-
- // Advanced
- SkipCertificateVerification *bool
- QueryTimeout *int
- MaxPageSize *int
-
- // Customization
- LoginFieldName *string
-
- LoginButtonColor *string
- LoginButtonBorderColor *string
- LoginButtonTextColor *string
-}
-
-func (s *LdapSettings) SetDefaults() {
- if s.Enable == nil {
- s.Enable = NewBool(false)
- }
-
- // When unset should default to LDAP Enabled
- if s.EnableSync == nil {
- s.EnableSync = NewBool(*s.Enable)
- }
-
- if s.LdapServer == nil {
- s.LdapServer = NewString("")
- }
-
- if s.LdapPort == nil {
- s.LdapPort = NewInt(389)
- }
-
- if s.ConnectionSecurity == nil {
- s.ConnectionSecurity = NewString("")
- }
-
- if s.BaseDN == nil {
- s.BaseDN = NewString("")
- }
-
- if s.BindUsername == nil {
- s.BindUsername = NewString("")
- }
-
- if s.BindPassword == nil {
- s.BindPassword = NewString("")
- }
-
- if s.UserFilter == nil {
- s.UserFilter = NewString("")
- }
-
- if s.FirstNameAttribute == nil {
- s.FirstNameAttribute = NewString(LDAP_SETTINGS_DEFAULT_FIRST_NAME_ATTRIBUTE)
- }
-
- if s.LastNameAttribute == nil {
- s.LastNameAttribute = NewString(LDAP_SETTINGS_DEFAULT_LAST_NAME_ATTRIBUTE)
- }
-
- if s.EmailAttribute == nil {
- s.EmailAttribute = NewString(LDAP_SETTINGS_DEFAULT_EMAIL_ATTRIBUTE)
- }
-
- if s.UsernameAttribute == nil {
- s.UsernameAttribute = NewString(LDAP_SETTINGS_DEFAULT_USERNAME_ATTRIBUTE)
- }
-
- if s.NicknameAttribute == nil {
- s.NicknameAttribute = NewString(LDAP_SETTINGS_DEFAULT_NICKNAME_ATTRIBUTE)
- }
-
- if s.IdAttribute == nil {
- s.IdAttribute = NewString(LDAP_SETTINGS_DEFAULT_ID_ATTRIBUTE)
- }
-
- if s.PositionAttribute == nil {
- s.PositionAttribute = NewString(LDAP_SETTINGS_DEFAULT_POSITION_ATTRIBUTE)
- }
-
- // For those upgrading to the version when LoginIdAttribute was added
- // they need IdAttribute == LoginIdAttribute not to break
- if s.LoginIdAttribute == nil {
- s.LoginIdAttribute = s.IdAttribute
- }
-
- if s.SyncIntervalMinutes == nil {
- s.SyncIntervalMinutes = NewInt(60)
- }
-
- if s.SkipCertificateVerification == nil {
- s.SkipCertificateVerification = NewBool(false)
- }
-
- if s.QueryTimeout == nil {
- s.QueryTimeout = NewInt(60)
- }
-
- if s.MaxPageSize == nil {
- s.MaxPageSize = NewInt(0)
- }
-
- if s.LoginFieldName == nil {
- s.LoginFieldName = NewString(LDAP_SETTINGS_DEFAULT_LOGIN_FIELD_NAME)
- }
-
- if s.LoginButtonColor == nil {
- s.LoginButtonColor = NewString("#0000")
- }
-
- if s.LoginButtonBorderColor == nil {
- s.LoginButtonBorderColor = NewString("#2389D7")
- }
-
- if s.LoginButtonTextColor == nil {
- s.LoginButtonTextColor = NewString("#2389D7")
- }
-}
-
-type ComplianceSettings struct {
- Enable *bool
- Directory *string
- EnableDaily *bool
-}
-
-func (s *ComplianceSettings) SetDefaults() {
- if s.Enable == nil {
- s.Enable = NewBool(false)
- }
-
- if s.Directory == nil {
- s.Directory = NewString("./data/")
- }
-
- if s.EnableDaily == nil {
- s.EnableDaily = NewBool(false)
- }
-}
-
-type LocalizationSettings struct {
- DefaultServerLocale *string
- DefaultClientLocale *string
- AvailableLocales *string
-}
-
-func (s *LocalizationSettings) SetDefaults() {
- if s.DefaultServerLocale == nil {
- s.DefaultServerLocale = NewString(DEFAULT_LOCALE)
- }
-
- if s.DefaultClientLocale == nil {
- s.DefaultClientLocale = NewString(DEFAULT_LOCALE)
- }
-
- if s.AvailableLocales == nil {
- s.AvailableLocales = NewString("")
- }
-}
-
-type SamlSettings struct {
- // Basic
- Enable *bool
- EnableSyncWithLdap *bool
- EnableSyncWithLdapIncludeAuth *bool
-
- Verify *bool
- Encrypt *bool
-
- IdpUrl *string
- IdpDescriptorUrl *string
- AssertionConsumerServiceURL *string
-
- ScopingIDPProviderId *string
- ScopingIDPName *string
-
- IdpCertificateFile *string
- PublicCertificateFile *string
- PrivateKeyFile *string
-
- // User Mapping
- IdAttribute *string
- FirstNameAttribute *string
- LastNameAttribute *string
- EmailAttribute *string
- UsernameAttribute *string
- NicknameAttribute *string
- LocaleAttribute *string
- PositionAttribute *string
-
- LoginButtonText *string
-
- LoginButtonColor *string
- LoginButtonBorderColor *string
- LoginButtonTextColor *string
-}
-
-func (s *SamlSettings) SetDefaults() {
- if s.Enable == nil {
- s.Enable = NewBool(false)
- }
-
- if s.EnableSyncWithLdap == nil {
- s.EnableSyncWithLdap = NewBool(false)
- }
-
- if s.EnableSyncWithLdapIncludeAuth == nil {
- s.EnableSyncWithLdapIncludeAuth = NewBool(false)
- }
-
- if s.Verify == nil {
- s.Verify = NewBool(true)
- }
-
- if s.Encrypt == nil {
- s.Encrypt = NewBool(true)
- }
-
- if s.IdpUrl == nil {
- s.IdpUrl = NewString("")
- }
-
- if s.IdpDescriptorUrl == nil {
- s.IdpDescriptorUrl = NewString("")
- }
-
- if s.IdpCertificateFile == nil {
- s.IdpCertificateFile = NewString("")
- }
-
- if s.PublicCertificateFile == nil {
- s.PublicCertificateFile = NewString("")
- }
-
- if s.PrivateKeyFile == nil {
- s.PrivateKeyFile = NewString("")
- }
-
- if s.AssertionConsumerServiceURL == nil {
- s.AssertionConsumerServiceURL = NewString("")
- }
-
- if s.ScopingIDPProviderId == nil {
- s.ScopingIDPProviderId = NewString("")
- }
-
- if s.ScopingIDPName == nil {
- s.ScopingIDPName = NewString("")
- }
-
- if s.LoginButtonText == nil || *s.LoginButtonText == "" {
- s.LoginButtonText = NewString(USER_AUTH_SERVICE_SAML_TEXT)
- }
-
- if s.IdAttribute == nil {
- s.IdAttribute = NewString(SAML_SETTINGS_DEFAULT_ID_ATTRIBUTE)
- }
-
- if s.FirstNameAttribute == nil {
- s.FirstNameAttribute = NewString(SAML_SETTINGS_DEFAULT_FIRST_NAME_ATTRIBUTE)
- }
-
- if s.LastNameAttribute == nil {
- s.LastNameAttribute = NewString(SAML_SETTINGS_DEFAULT_LAST_NAME_ATTRIBUTE)
- }
-
- if s.EmailAttribute == nil {
- s.EmailAttribute = NewString(SAML_SETTINGS_DEFAULT_EMAIL_ATTRIBUTE)
- }
-
- if s.UsernameAttribute == nil {
- s.UsernameAttribute = NewString(SAML_SETTINGS_DEFAULT_USERNAME_ATTRIBUTE)
- }
-
- if s.NicknameAttribute == nil {
- s.NicknameAttribute = NewString(SAML_SETTINGS_DEFAULT_NICKNAME_ATTRIBUTE)
- }
-
- if s.PositionAttribute == nil {
- s.PositionAttribute = NewString(SAML_SETTINGS_DEFAULT_POSITION_ATTRIBUTE)
- }
-
- if s.LocaleAttribute == nil {
- s.LocaleAttribute = NewString(SAML_SETTINGS_DEFAULT_LOCALE_ATTRIBUTE)
- }
-
- if s.LoginButtonColor == nil {
- s.LoginButtonColor = NewString("#34a28b")
- }
-
- if s.LoginButtonBorderColor == nil {
- s.LoginButtonBorderColor = NewString("#2389D7")
- }
-
- if s.LoginButtonTextColor == nil {
- s.LoginButtonTextColor = NewString("#ffffff")
- }
-}
-
-type NativeAppSettings struct {
- AppDownloadLink *string
- AndroidAppDownloadLink *string
- IosAppDownloadLink *string
-}
-
-func (s *NativeAppSettings) SetDefaults() {
- if s.AppDownloadLink == nil {
- s.AppDownloadLink = NewString(NATIVEAPP_SETTINGS_DEFAULT_APP_DOWNLOAD_LINK)
- }
-
- if s.AndroidAppDownloadLink == nil {
- s.AndroidAppDownloadLink = NewString(NATIVEAPP_SETTINGS_DEFAULT_ANDROID_APP_DOWNLOAD_LINK)
- }
-
- if s.IosAppDownloadLink == nil {
- s.IosAppDownloadLink = NewString(NATIVEAPP_SETTINGS_DEFAULT_IOS_APP_DOWNLOAD_LINK)
- }
-}
-
-type WebrtcSettings struct {
- Enable *bool
- GatewayWebsocketUrl *string
- GatewayAdminUrl *string
- GatewayAdminSecret *string
- StunURI *string
- TurnURI *string
- TurnUsername *string
- TurnSharedKey *string
-}
-
-func (s *WebrtcSettings) SetDefaults() {
- if s.Enable == nil {
- s.Enable = NewBool(false)
- }
-
- if s.GatewayWebsocketUrl == nil {
- s.GatewayWebsocketUrl = NewString("")
- }
-
- if s.GatewayAdminUrl == nil {
- s.GatewayAdminUrl = NewString("")
- }
-
- if s.GatewayAdminSecret == nil {
- s.GatewayAdminSecret = NewString("")
- }
-
- if s.StunURI == nil {
- s.StunURI = NewString(WEBRTC_SETTINGS_DEFAULT_STUN_URI)
- }
-
- if s.TurnURI == nil {
- s.TurnURI = NewString(WEBRTC_SETTINGS_DEFAULT_TURN_URI)
- }
-
- if s.TurnUsername == nil {
- s.TurnUsername = NewString("")
- }
-
- if s.TurnSharedKey == nil {
- s.TurnSharedKey = NewString("")
- }
-}
-
-type ElasticsearchSettings struct {
- ConnectionUrl *string
- Username *string
- Password *string
- EnableIndexing *bool
- EnableSearching *bool
- Sniff *bool
- PostIndexReplicas *int
- PostIndexShards *int
- AggregatePostsAfterDays *int
- PostsAggregatorJobStartTime *string
- IndexPrefix *string
- LiveIndexingBatchSize *int
- BulkIndexingTimeWindowSeconds *int
- RequestTimeoutSeconds *int
-}
-
-func (s *ElasticsearchSettings) SetDefaults() {
- if s.ConnectionUrl == nil {
- s.ConnectionUrl = NewString(ELASTICSEARCH_SETTINGS_DEFAULT_CONNECTION_URL)
- }
-
- if s.Username == nil {
- s.Username = NewString(ELASTICSEARCH_SETTINGS_DEFAULT_USERNAME)
- }
-
- if s.Password == nil {
- s.Password = NewString(ELASTICSEARCH_SETTINGS_DEFAULT_PASSWORD)
- }
-
- if s.EnableIndexing == nil {
- s.EnableIndexing = NewBool(false)
- }
-
- if s.EnableSearching == nil {
- s.EnableSearching = NewBool(false)
- }
-
- if s.Sniff == nil {
- s.Sniff = NewBool(true)
- }
-
- if s.PostIndexReplicas == nil {
- s.PostIndexReplicas = NewInt(ELASTICSEARCH_SETTINGS_DEFAULT_POST_INDEX_REPLICAS)
- }
-
- if s.PostIndexShards == nil {
- s.PostIndexShards = NewInt(ELASTICSEARCH_SETTINGS_DEFAULT_POST_INDEX_SHARDS)
- }
-
- if s.AggregatePostsAfterDays == nil {
- s.AggregatePostsAfterDays = NewInt(ELASTICSEARCH_SETTINGS_DEFAULT_AGGREGATE_POSTS_AFTER_DAYS)
- }
-
- if s.PostsAggregatorJobStartTime == nil {
- s.PostsAggregatorJobStartTime = NewString(ELASTICSEARCH_SETTINGS_DEFAULT_POSTS_AGGREGATOR_JOB_START_TIME)
- }
-
- if s.IndexPrefix == nil {
- s.IndexPrefix = NewString(ELASTICSEARCH_SETTINGS_DEFAULT_INDEX_PREFIX)
- }
-
- if s.LiveIndexingBatchSize == nil {
- s.LiveIndexingBatchSize = NewInt(ELASTICSEARCH_SETTINGS_DEFAULT_LIVE_INDEXING_BATCH_SIZE)
- }
-
- if s.BulkIndexingTimeWindowSeconds == nil {
- s.BulkIndexingTimeWindowSeconds = NewInt(ELASTICSEARCH_SETTINGS_DEFAULT_BULK_INDEXING_TIME_WINDOW_SECONDS)
- }
-
- if s.RequestTimeoutSeconds == nil {
- s.RequestTimeoutSeconds = NewInt(ELASTICSEARCH_SETTINGS_DEFAULT_REQUEST_TIMEOUT_SECONDS)
- }
-}
-
-type DataRetentionSettings struct {
- EnableMessageDeletion *bool
- EnableFileDeletion *bool
- MessageRetentionDays *int
- FileRetentionDays *int
- DeletionJobStartTime *string
-}
-
-func (s *DataRetentionSettings) SetDefaults() {
- if s.EnableMessageDeletion == nil {
- s.EnableMessageDeletion = NewBool(false)
- }
-
- if s.EnableFileDeletion == nil {
- s.EnableFileDeletion = NewBool(false)
- }
-
- if s.MessageRetentionDays == nil {
- s.MessageRetentionDays = NewInt(DATA_RETENTION_SETTINGS_DEFAULT_MESSAGE_RETENTION_DAYS)
- }
-
- if s.FileRetentionDays == nil {
- s.FileRetentionDays = NewInt(DATA_RETENTION_SETTINGS_DEFAULT_FILE_RETENTION_DAYS)
- }
-
- if s.DeletionJobStartTime == nil {
- s.DeletionJobStartTime = NewString(DATA_RETENTION_SETTINGS_DEFAULT_DELETION_JOB_START_TIME)
- }
-}
-
-type JobSettings struct {
- RunJobs *bool
- RunScheduler *bool
-}
-
-func (s *JobSettings) SetDefaults() {
- if s.RunJobs == nil {
- s.RunJobs = NewBool(true)
- }
-
- if s.RunScheduler == nil {
- s.RunScheduler = NewBool(true)
- }
-}
-
-type PluginState struct {
- Enable bool
-}
-
-type PluginSettings struct {
- Enable *bool
- EnableUploads *bool
- Directory *string
- ClientDirectory *string
- Plugins map[string]map[string]interface{}
- PluginStates map[string]*PluginState
-}
-
-func (s *PluginSettings) SetDefaults() {
- if s.Enable == nil {
- s.Enable = NewBool(true)
- }
-
- if s.EnableUploads == nil {
- s.EnableUploads = NewBool(false)
- }
-
- if s.Directory == nil {
- s.Directory = NewString(PLUGIN_SETTINGS_DEFAULT_DIRECTORY)
- }
-
- if *s.Directory == "" {
- *s.Directory = PLUGIN_SETTINGS_DEFAULT_DIRECTORY
- }
-
- if s.ClientDirectory == nil {
- s.ClientDirectory = NewString(PLUGIN_SETTINGS_DEFAULT_CLIENT_DIRECTORY)
- }
-
- if *s.ClientDirectory == "" {
- *s.ClientDirectory = PLUGIN_SETTINGS_DEFAULT_CLIENT_DIRECTORY
- }
-
- if s.Plugins == nil {
- s.Plugins = make(map[string]map[string]interface{})
- }
-
- if s.PluginStates == nil {
- s.PluginStates = make(map[string]*PluginState)
- }
-}
-
-type GlobalRelayMessageExportSettings struct {
- CustomerType *string // must be either A9 or A10, dictates SMTP server url
- SmtpUsername *string
- SmtpPassword *string
- EmailAddress *string // the address to send messages to
-}
-
-func (s *GlobalRelayMessageExportSettings) SetDefaults() {
- if s.CustomerType == nil {
- s.CustomerType = NewString(GLOBALRELAY_CUSTOMER_TYPE_A9)
- }
- if s.SmtpUsername == nil {
- s.SmtpUsername = NewString("")
- }
- if s.SmtpPassword == nil {
- s.SmtpPassword = NewString("")
- }
- if s.EmailAddress == nil {
- s.EmailAddress = NewString("")
- }
-}
-
-type MessageExportSettings struct {
- EnableExport *bool
- ExportFormat *string
- DailyRunTime *string
- ExportFromTimestamp *int64
- BatchSize *int
-
- // formatter-specific settings - these are only expected to be non-nil if ExportFormat is set to the associated format
- GlobalRelaySettings *GlobalRelayMessageExportSettings
-}
-
-func (s *MessageExportSettings) SetDefaults() {
- if s.EnableExport == nil {
- s.EnableExport = NewBool(false)
- }
-
- if s.ExportFormat == nil {
- s.ExportFormat = NewString(COMPLIANCE_EXPORT_TYPE_ACTIANCE)
- }
-
- if s.DailyRunTime == nil {
- s.DailyRunTime = NewString("01:00")
- }
-
- if s.ExportFromTimestamp == nil {
- s.ExportFromTimestamp = NewInt64(0)
- }
-
- if s.EnableExport != nil && *s.EnableExport && *s.ExportFromTimestamp == int64(0) {
- // when the feature is enabled via the System Console, use the current timestamp as the start time for future exports
- s.ExportFromTimestamp = NewInt64(GetMillis())
- } else if s.EnableExport != nil && !*s.EnableExport {
- // when the feature is disabled, reset the timestamp so that the timestamp will be set if the feature is re-enabled
- s.ExportFromTimestamp = NewInt64(0)
- }
-
- if s.BatchSize == nil {
- s.BatchSize = NewInt(10000)
- }
-
- if s.GlobalRelaySettings == nil {
- s.GlobalRelaySettings = &GlobalRelayMessageExportSettings{}
- }
- s.GlobalRelaySettings.SetDefaults()
-}
-
-type DisplaySettings struct {
- CustomUrlSchemes *[]string
- ExperimentalTimezone *bool
-}
-
-func (s *DisplaySettings) SetDefaults() {
- if s.CustomUrlSchemes == nil {
- customUrlSchemes := []string{}
- s.CustomUrlSchemes = &customUrlSchemes
- }
-
- if s.ExperimentalTimezone == nil {
- s.ExperimentalTimezone = NewBool(false)
- }
-}
-
-type TimezoneSettings struct {
- SupportedTimezonesPath *string
-}
-
-func (s *TimezoneSettings) SetDefaults() {
- if s.SupportedTimezonesPath == nil {
- s.SupportedTimezonesPath = NewString(TIMEZONE_SETTINGS_DEFAULT_SUPPORTED_TIMEZONES_PATH)
- }
-}
-
-type ConfigFunc func() *Config
-
-type Config struct {
- ServiceSettings ServiceSettings
- TeamSettings TeamSettings
- ClientRequirements ClientRequirements
- SqlSettings SqlSettings
- LogSettings LogSettings
- PasswordSettings PasswordSettings
- FileSettings FileSettings
- EmailSettings EmailSettings
- ExtensionSettings ExtensionSettings
- RateLimitSettings RateLimitSettings
- PrivacySettings PrivacySettings
- SupportSettings SupportSettings
- AnnouncementSettings AnnouncementSettings
- ThemeSettings ThemeSettings
- GitLabSettings SSOSettings
- GoogleSettings SSOSettings
- Office365Settings SSOSettings
- LdapSettings LdapSettings
- ComplianceSettings ComplianceSettings
- LocalizationSettings LocalizationSettings
- SamlSettings SamlSettings
- NativeAppSettings NativeAppSettings
- ClusterSettings ClusterSettings
- MetricsSettings MetricsSettings
- ExperimentalSettings ExperimentalSettings
- AnalyticsSettings AnalyticsSettings
- WebrtcSettings WebrtcSettings
- ElasticsearchSettings ElasticsearchSettings
- DataRetentionSettings DataRetentionSettings
- MessageExportSettings MessageExportSettings
- JobSettings JobSettings
- PluginSettings PluginSettings
- DisplaySettings DisplaySettings
- TimezoneSettings TimezoneSettings
-}
-
-func (o *Config) Clone() *Config {
- var ret Config
- if err := json.Unmarshal([]byte(o.ToJson()), &ret); err != nil {
- panic(err)
- }
- return &ret
-}
-
-func (o *Config) ToJson() string {
- b, _ := json.Marshal(o)
- return string(b)
-}
-
-func (o *Config) GetSSOService(service string) *SSOSettings {
- switch service {
- case SERVICE_GITLAB:
- return &o.GitLabSettings
- case SERVICE_GOOGLE:
- return &o.GoogleSettings
- case SERVICE_OFFICE365:
- return &o.Office365Settings
- }
-
- return nil
-}
-
-func ConfigFromJson(data io.Reader) *Config {
- var o *Config
- json.NewDecoder(data).Decode(&o)
- return o
-}
-
-func (o *Config) SetDefaults() {
- o.LdapSettings.SetDefaults()
- o.SamlSettings.SetDefaults()
-
- if o.TeamSettings.TeammateNameDisplay == nil {
- o.TeamSettings.TeammateNameDisplay = NewString(SHOW_USERNAME)
-
- if *o.SamlSettings.Enable || *o.LdapSettings.Enable {
- *o.TeamSettings.TeammateNameDisplay = SHOW_FULLNAME
- }
- }
-
- o.SqlSettings.SetDefaults()
- o.FileSettings.SetDefaults()
- o.EmailSettings.SetDefaults()
- o.ServiceSettings.SetDefaults()
- o.PasswordSettings.SetDefaults()
- o.TeamSettings.SetDefaults()
- o.MetricsSettings.SetDefaults()
- o.ExperimentalSettings.SetDefaults()
- o.SupportSettings.SetDefaults()
- o.AnnouncementSettings.SetDefaults()
- o.ThemeSettings.SetDefaults()
- o.ClusterSettings.SetDefaults()
- o.PluginSettings.SetDefaults()
- o.AnalyticsSettings.SetDefaults()
- o.ComplianceSettings.SetDefaults()
- o.LocalizationSettings.SetDefaults()
- o.ElasticsearchSettings.SetDefaults()
- o.NativeAppSettings.SetDefaults()
- o.DataRetentionSettings.SetDefaults()
- o.RateLimitSettings.SetDefaults()
- o.LogSettings.SetDefaults()
- o.JobSettings.SetDefaults()
- o.WebrtcSettings.SetDefaults()
- o.MessageExportSettings.SetDefaults()
- o.TimezoneSettings.SetDefaults()
- o.DisplaySettings.SetDefaults()
- o.ExtensionSettings.SetDefaults()
-}
-
-func (o *Config) IsValid() *AppError {
- if len(*o.ServiceSettings.SiteURL) == 0 && *o.EmailSettings.EnableEmailBatching {
- return NewAppError("Config.IsValid", "model.config.is_valid.site_url_email_batching.app_error", nil, "", http.StatusBadRequest)
- }
-
- if *o.ClusterSettings.Enable && *o.EmailSettings.EnableEmailBatching {
- return NewAppError("Config.IsValid", "model.config.is_valid.cluster_email_batching.app_error", nil, "", http.StatusBadRequest)
- }
-
- if len(*o.ServiceSettings.SiteURL) == 0 && *o.ServiceSettings.AllowCookiesForSubdomains {
- return NewAppError("Config.IsValid", "model.config.is_valid.allow_cookies_for_subdomains.app_error", nil, "", http.StatusBadRequest)
- }
-
- if err := o.TeamSettings.isValid(); err != nil {
- return err
- }
-
- if err := o.SqlSettings.isValid(); err != nil {
- return err
- }
-
- if err := o.FileSettings.isValid(); err != nil {
- return err
- }
-
- if err := o.EmailSettings.isValid(); err != nil {
- return err
- }
-
- if err := o.LdapSettings.isValid(); err != nil {
- return err
- }
-
- if err := o.SamlSettings.isValid(); err != nil {
- return err
- }
-
- if *o.PasswordSettings.MinimumLength < PASSWORD_MINIMUM_LENGTH || *o.PasswordSettings.MinimumLength > PASSWORD_MAXIMUM_LENGTH {
- return NewAppError("Config.IsValid", "model.config.is_valid.password_length.app_error", map[string]interface{}{"MinLength": PASSWORD_MINIMUM_LENGTH, "MaxLength": PASSWORD_MAXIMUM_LENGTH}, "", http.StatusBadRequest)
- }
-
- if err := o.RateLimitSettings.isValid(); err != nil {
- return err
- }
-
- if err := o.WebrtcSettings.isValid(); err != nil {
- return err
- }
-
- if err := o.ServiceSettings.isValid(); err != nil {
- return err
- }
-
- if err := o.ElasticsearchSettings.isValid(); err != nil {
- return err
- }
-
- if err := o.DataRetentionSettings.isValid(); err != nil {
- return err
- }
-
- if err := o.LocalizationSettings.isValid(); err != nil {
- return err
- }
-
- if err := o.MessageExportSettings.isValid(o.FileSettings); err != nil {
- return err
- }
-
- if err := o.DisplaySettings.isValid(); err != nil {
- return err
- }
-
- return nil
-}
-
-func (ts *TeamSettings) isValid() *AppError {
- if *ts.MaxUsersPerTeam <= 0 {
- return NewAppError("Config.IsValid", "model.config.is_valid.max_users.app_error", nil, "", http.StatusBadRequest)
- }
-
- if *ts.MaxChannelsPerTeam <= 0 {
- return NewAppError("Config.IsValid", "model.config.is_valid.max_channels.app_error", nil, "", http.StatusBadRequest)
- }
-
- if *ts.MaxNotificationsPerChannel <= 0 {
- return NewAppError("Config.IsValid", "model.config.is_valid.max_notify_per_channel.app_error", nil, "", http.StatusBadRequest)
- }
-
- if !(*ts.RestrictDirectMessage == DIRECT_MESSAGE_ANY || *ts.RestrictDirectMessage == DIRECT_MESSAGE_TEAM) {
- return NewAppError("Config.IsValid", "model.config.is_valid.restrict_direct_message.app_error", nil, "", http.StatusBadRequest)
- }
-
- if !(*ts.TeammateNameDisplay == SHOW_FULLNAME || *ts.TeammateNameDisplay == SHOW_NICKNAME_FULLNAME || *ts.TeammateNameDisplay == SHOW_USERNAME) {
- return NewAppError("Config.IsValid", "model.config.is_valid.teammate_name_display.app_error", nil, "", http.StatusBadRequest)
- }
-
- if len(ts.SiteName) > SITENAME_MAX_LENGTH {
- return NewAppError("Config.IsValid", "model.config.is_valid.sitename_length.app_error", map[string]interface{}{"MaxLength": SITENAME_MAX_LENGTH}, "", http.StatusBadRequest)
- }
-
- return nil
-}
-
-func (ss *SqlSettings) isValid() *AppError {
- if len(ss.AtRestEncryptKey) < 32 {
- return NewAppError("Config.IsValid", "model.config.is_valid.encrypt_sql.app_error", nil, "", http.StatusBadRequest)
- }
-
- if !(*ss.DriverName == DATABASE_DRIVER_MYSQL || *ss.DriverName == DATABASE_DRIVER_POSTGRES) {
- return NewAppError("Config.IsValid", "model.config.is_valid.sql_driver.app_error", nil, "", http.StatusBadRequest)
- }
-
- if *ss.MaxIdleConns <= 0 {
- return NewAppError("Config.IsValid", "model.config.is_valid.sql_idle.app_error", nil, "", http.StatusBadRequest)
- }
-
- if *ss.ConnMaxLifetimeMilliseconds < 0 {
- return NewAppError("Config.IsValid", "model.config.is_valid.sql_conn_max_lifetime_milliseconds.app_error", nil, "", http.StatusBadRequest)
- }
-
- if *ss.QueryTimeout <= 0 {
- return NewAppError("Config.IsValid", "model.config.is_valid.sql_query_timeout.app_error", nil, "", http.StatusBadRequest)
- }
-
- if len(*ss.DataSource) == 0 {
- return NewAppError("Config.IsValid", "model.config.is_valid.sql_data_src.app_error", nil, "", http.StatusBadRequest)
- }
-
- if *ss.MaxOpenConns <= 0 {
- return NewAppError("Config.IsValid", "model.config.is_valid.sql_max_conn.app_error", nil, "", http.StatusBadRequest)
- }
-
- return nil
-}
-
-func (fs *FileSettings) isValid() *AppError {
- if *fs.MaxFileSize <= 0 {
- return NewAppError("Config.IsValid", "model.config.is_valid.max_file_size.app_error", nil, "", http.StatusBadRequest)
- }
-
- if !(*fs.DriverName == IMAGE_DRIVER_LOCAL || *fs.DriverName == IMAGE_DRIVER_S3) {
- return NewAppError("Config.IsValid", "model.config.is_valid.file_driver.app_error", nil, "", http.StatusBadRequest)
- }
-
- if len(*fs.PublicLinkSalt) < 32 {
- return NewAppError("Config.IsValid", "model.config.is_valid.file_salt.app_error", nil, "", http.StatusBadRequest)
- }
-
- return nil
-}
-
-func (es *EmailSettings) isValid() *AppError {
- if !(es.ConnectionSecurity == CONN_SECURITY_NONE || es.ConnectionSecurity == CONN_SECURITY_TLS || es.ConnectionSecurity == CONN_SECURITY_STARTTLS || es.ConnectionSecurity == CONN_SECURITY_PLAIN) {
- return NewAppError("Config.IsValid", "model.config.is_valid.email_security.app_error", nil, "", http.StatusBadRequest)
- }
-
- if len(es.InviteSalt) < 32 {
- return NewAppError("Config.IsValid", "model.config.is_valid.email_salt.app_error", nil, "", http.StatusBadRequest)
- }
-
- if *es.EmailBatchingBufferSize <= 0 {
- return NewAppError("Config.IsValid", "model.config.is_valid.email_batching_buffer_size.app_error", nil, "", http.StatusBadRequest)
- }
-
- if *es.EmailBatchingInterval < 30 {
- return NewAppError("Config.IsValid", "model.config.is_valid.email_batching_interval.app_error", nil, "", http.StatusBadRequest)
- }
-
- if !(*es.EmailNotificationContentsType == EMAIL_NOTIFICATION_CONTENTS_FULL || *es.EmailNotificationContentsType == EMAIL_NOTIFICATION_CONTENTS_GENERIC) {
- return NewAppError("Config.IsValid", "model.config.is_valid.email_notification_contents_type.app_error", nil, "", http.StatusBadRequest)
- }
-
- return nil
-}
-
-func (rls *RateLimitSettings) isValid() *AppError {
- if *rls.MemoryStoreSize <= 0 {
- return NewAppError("Config.IsValid", "model.config.is_valid.rate_mem.app_error", nil, "", http.StatusBadRequest)
- }
-
- if *rls.PerSec <= 0 {
- return NewAppError("Config.IsValid", "model.config.is_valid.rate_sec.app_error", nil, "", http.StatusBadRequest)
- }
-
- if *rls.MaxBurst <= 0 {
- return NewAppError("Config.IsValid", "model.config.is_valid.max_burst.app_error", nil, "", http.StatusBadRequest)
- }
-
- return nil
-}
-
-func (ls *LdapSettings) isValid() *AppError {
- if !(*ls.ConnectionSecurity == CONN_SECURITY_NONE || *ls.ConnectionSecurity == CONN_SECURITY_TLS || *ls.ConnectionSecurity == CONN_SECURITY_STARTTLS) {
- return NewAppError("Config.IsValid", "model.config.is_valid.ldap_security.app_error", nil, "", http.StatusBadRequest)
- }
-
- if *ls.SyncIntervalMinutes <= 0 {
- return NewAppError("Config.IsValid", "model.config.is_valid.ldap_sync_interval.app_error", nil, "", http.StatusBadRequest)
- }
-
- if *ls.MaxPageSize < 0 {
- return NewAppError("Config.IsValid", "model.config.is_valid.ldap_max_page_size.app_error", nil, "", http.StatusBadRequest)
- }
-
- if *ls.Enable {
- if *ls.LdapServer == "" {
- return NewAppError("Config.IsValid", "model.config.is_valid.ldap_server", nil, "", http.StatusBadRequest)
- }
-
- if *ls.BaseDN == "" {
- return NewAppError("Config.IsValid", "model.config.is_valid.ldap_basedn", nil, "", http.StatusBadRequest)
- }
-
- if *ls.EmailAttribute == "" {
- return NewAppError("Config.IsValid", "model.config.is_valid.ldap_email", nil, "", http.StatusBadRequest)
- }
-
- if *ls.UsernameAttribute == "" {
- return NewAppError("Config.IsValid", "model.config.is_valid.ldap_username", nil, "", http.StatusBadRequest)
- }
-
- if *ls.IdAttribute == "" {
- return NewAppError("Config.IsValid", "model.config.is_valid.ldap_id", nil, "", http.StatusBadRequest)
- }
-
- if *ls.LoginIdAttribute == "" {
- return NewAppError("Config.IsValid", "model.config.is_valid.ldap_login_id", nil, "", http.StatusBadRequest)
- }
- }
-
- return nil
-}
-
-func (ss *SamlSettings) isValid() *AppError {
- if *ss.Enable {
- if len(*ss.IdpUrl) == 0 || !IsValidHttpUrl(*ss.IdpUrl) {
- return NewAppError("Config.IsValid", "model.config.is_valid.saml_idp_url.app_error", nil, "", http.StatusBadRequest)
- }
-
- if len(*ss.IdpDescriptorUrl) == 0 || !IsValidHttpUrl(*ss.IdpDescriptorUrl) {
- return NewAppError("Config.IsValid", "model.config.is_valid.saml_idp_descriptor_url.app_error", nil, "", http.StatusBadRequest)
- }
-
- if len(*ss.IdpCertificateFile) == 0 {
- return NewAppError("Config.IsValid", "model.config.is_valid.saml_idp_cert.app_error", nil, "", http.StatusBadRequest)
- }
-
- if len(*ss.EmailAttribute) == 0 {
- return NewAppError("Config.IsValid", "model.config.is_valid.saml_email_attribute.app_error", nil, "", http.StatusBadRequest)
- }
-
- if len(*ss.UsernameAttribute) == 0 {
- return NewAppError("Config.IsValid", "model.config.is_valid.saml_username_attribute.app_error", nil, "", http.StatusBadRequest)
- }
-
- if *ss.Verify {
- if len(*ss.AssertionConsumerServiceURL) == 0 || !IsValidHttpUrl(*ss.AssertionConsumerServiceURL) {
- return NewAppError("Config.IsValid", "model.config.is_valid.saml_assertion_consumer_service_url.app_error", nil, "", http.StatusBadRequest)
- }
- }
-
- if *ss.Encrypt {
- if len(*ss.PrivateKeyFile) == 0 {
- return NewAppError("Config.IsValid", "model.config.is_valid.saml_private_key.app_error", nil, "", http.StatusBadRequest)
- }
-
- if len(*ss.PublicCertificateFile) == 0 {
- return NewAppError("Config.IsValid", "model.config.is_valid.saml_public_cert.app_error", nil, "", http.StatusBadRequest)
- }
- }
-
- if len(*ss.EmailAttribute) == 0 {
- return NewAppError("Config.IsValid", "model.config.is_valid.saml_email_attribute.app_error", nil, "", http.StatusBadRequest)
- }
- }
-
- return nil
-}
-
-func (ws *WebrtcSettings) isValid() *AppError {
- if *ws.Enable {
- if len(*ws.GatewayWebsocketUrl) == 0 || !IsValidWebsocketUrl(*ws.GatewayWebsocketUrl) {
- return NewAppError("Config.IsValid", "model.config.is_valid.webrtc_gateway_ws_url.app_error", nil, "", http.StatusBadRequest)
- } else if len(*ws.GatewayAdminUrl) == 0 || !IsValidHttpUrl(*ws.GatewayAdminUrl) {
- return NewAppError("Config.IsValid", "model.config.is_valid.webrtc_gateway_admin_url.app_error", nil, "", http.StatusBadRequest)
- } else if len(*ws.GatewayAdminSecret) == 0 {
- return NewAppError("Config.IsValid", "model.config.is_valid.webrtc_gateway_admin_secret.app_error", nil, "", http.StatusBadRequest)
- } else if len(*ws.StunURI) != 0 && !IsValidTurnOrStunServer(*ws.StunURI) {
- return NewAppError("Config.IsValid", "model.config.is_valid.webrtc_stun_uri.app_error", nil, "", http.StatusBadRequest)
- } else if len(*ws.TurnURI) != 0 {
- if !IsValidTurnOrStunServer(*ws.TurnURI) {
- return NewAppError("Config.IsValid", "model.config.is_valid.webrtc_turn_uri.app_error", nil, "", http.StatusBadRequest)
- }
- if len(*ws.TurnUsername) == 0 {
- return NewAppError("Config.IsValid", "model.config.is_valid.webrtc_turn_username.app_error", nil, "", http.StatusBadRequest)
- } else if len(*ws.TurnSharedKey) == 0 {
- return NewAppError("Config.IsValid", "model.config.is_valid.webrtc_turn_shared_key.app_error", nil, "", http.StatusBadRequest)
- }
- }
- }
-
- return nil
-}
-
-func (ss *ServiceSettings) isValid() *AppError {
- if !(*ss.ConnectionSecurity == CONN_SECURITY_NONE || *ss.ConnectionSecurity == CONN_SECURITY_TLS) {
- return NewAppError("Config.IsValid", "model.config.is_valid.webserver_security.app_error", nil, "", http.StatusBadRequest)
- }
-
- if *ss.ReadTimeout <= 0 {
- return NewAppError("Config.IsValid", "model.config.is_valid.read_timeout.app_error", nil, "", http.StatusBadRequest)
- }
-
- if *ss.WriteTimeout <= 0 {
- return NewAppError("Config.IsValid", "model.config.is_valid.write_timeout.app_error", nil, "", http.StatusBadRequest)
- }
-
- if *ss.TimeBetweenUserTypingUpdatesMilliseconds < 1000 {
- return NewAppError("Config.IsValid", "model.config.is_valid.time_between_user_typing.app_error", nil, "", http.StatusBadRequest)
- }
-
- if *ss.MaximumLoginAttempts <= 0 {
- return NewAppError("Config.IsValid", "model.config.is_valid.login_attempts.app_error", nil, "", http.StatusBadRequest)
- }
-
- if len(*ss.SiteURL) != 0 {
- if _, err := url.ParseRequestURI(*ss.SiteURL); err != nil {
- return NewAppError("Config.IsValid", "model.config.is_valid.site_url.app_error", nil, "", http.StatusBadRequest)
- }
- }
-
- if len(*ss.WebsocketURL) != 0 {
- if _, err := url.ParseRequestURI(*ss.WebsocketURL); err != nil {
- return NewAppError("Config.IsValid", "model.config.is_valid.websocket_url.app_error", nil, "", http.StatusBadRequest)
- }
- }
-
- host, port, _ := net.SplitHostPort(*ss.ListenAddress)
- var isValidHost bool
- if host == "" {
- isValidHost = true
- } else {
- isValidHost = (net.ParseIP(host) != nil) || IsDomainName(host)
- }
- portInt, err := strconv.Atoi(port)
- if err != nil || !isValidHost || portInt < 0 || portInt > math.MaxUint16 {
- return NewAppError("Config.IsValid", "model.config.is_valid.listen_address.app_error", nil, "", http.StatusBadRequest)
- }
-
- if *ss.ExperimentalGroupUnreadChannels != GROUP_UNREAD_CHANNELS_DISABLED &&
- *ss.ExperimentalGroupUnreadChannels != GROUP_UNREAD_CHANNELS_DEFAULT_ON &&
- *ss.ExperimentalGroupUnreadChannels != GROUP_UNREAD_CHANNELS_DEFAULT_OFF {
- return NewAppError("Config.IsValid", "model.config.is_valid.group_unread_channels.app_error", nil, "", http.StatusBadRequest)
- }
-
- switch *ss.ImageProxyType {
- case "":
- case "atmos/camo":
- if *ss.ImageProxyOptions == "" {
- return NewAppError("Config.IsValid", "model.config.is_valid.atmos_camo_image_proxy_options.app_error", nil, "", http.StatusBadRequest)
- }
- default:
- return NewAppError("Config.IsValid", "model.config.is_valid.image_proxy_type.app_error", nil, "", http.StatusBadRequest)
- }
-
- return nil
-}
-
-func (ess *ElasticsearchSettings) isValid() *AppError {
- if *ess.EnableIndexing {
- if len(*ess.ConnectionUrl) == 0 {
- return NewAppError("Config.IsValid", "model.config.is_valid.elastic_search.connection_url.app_error", nil, "", http.StatusBadRequest)
- }
- }
-
- if *ess.EnableSearching && !*ess.EnableIndexing {
- return NewAppError("Config.IsValid", "model.config.is_valid.elastic_search.enable_searching.app_error", nil, "", http.StatusBadRequest)
- }
-
- if *ess.AggregatePostsAfterDays < 1 {
- return NewAppError("Config.IsValid", "model.config.is_valid.elastic_search.aggregate_posts_after_days.app_error", nil, "", http.StatusBadRequest)
- }
-
- if _, err := time.Parse("15:04", *ess.PostsAggregatorJobStartTime); err != nil {
- return NewAppError("Config.IsValid", "model.config.is_valid.elastic_search.posts_aggregator_job_start_time.app_error", nil, err.Error(), http.StatusBadRequest)
- }
-
- if *ess.LiveIndexingBatchSize < 1 {
- return NewAppError("Config.IsValid", "model.config.is_valid.elastic_search.live_indexing_batch_size.app_error", nil, "", http.StatusBadRequest)
- }
-
- if *ess.BulkIndexingTimeWindowSeconds < 1 {
- return NewAppError("Config.IsValid", "model.config.is_valid.elastic_search.bulk_indexing_time_window_seconds.app_error", nil, "", http.StatusBadRequest)
- }
-
- if *ess.RequestTimeoutSeconds < 1 {
- return NewAppError("Config.IsValid", "model.config.is_valid.elastic_search.request_timeout_seconds.app_error", nil, "", http.StatusBadRequest)
- }
-
- return nil
-}
-
-func (drs *DataRetentionSettings) isValid() *AppError {
- if *drs.MessageRetentionDays <= 0 {
- return NewAppError("Config.IsValid", "model.config.is_valid.data_retention.message_retention_days_too_low.app_error", nil, "", http.StatusBadRequest)
- }
-
- if *drs.FileRetentionDays <= 0 {
- return NewAppError("Config.IsValid", "model.config.is_valid.data_retention.file_retention_days_too_low.app_error", nil, "", http.StatusBadRequest)
- }
-
- if _, err := time.Parse("15:04", *drs.DeletionJobStartTime); err != nil {
- return NewAppError("Config.IsValid", "model.config.is_valid.data_retention.deletion_job_start_time.app_error", nil, err.Error(), http.StatusBadRequest)
- }
-
- return nil
-}
-
-func (ls *LocalizationSettings) isValid() *AppError {
- if len(*ls.AvailableLocales) > 0 {
- if !strings.Contains(*ls.AvailableLocales, *ls.DefaultClientLocale) {
- return NewAppError("Config.IsValid", "model.config.is_valid.localization.available_locales.app_error", nil, "", http.StatusBadRequest)
- }
- }
-
- return nil
-}
-
-func (mes *MessageExportSettings) isValid(fs FileSettings) *AppError {
- if mes.EnableExport == nil {
- return NewAppError("Config.IsValid", "model.config.is_valid.message_export.enable.app_error", nil, "", http.StatusBadRequest)
- }
- if *mes.EnableExport {
- if mes.ExportFromTimestamp == nil || *mes.ExportFromTimestamp < 0 || *mes.ExportFromTimestamp > GetMillis() {
- return NewAppError("Config.IsValid", "model.config.is_valid.message_export.export_from.app_error", nil, "", http.StatusBadRequest)
- } else if mes.DailyRunTime == nil {
- return NewAppError("Config.IsValid", "model.config.is_valid.message_export.daily_runtime.app_error", nil, "", http.StatusBadRequest)
- } else if _, err := time.Parse("15:04", *mes.DailyRunTime); err != nil {
- return NewAppError("Config.IsValid", "model.config.is_valid.message_export.daily_runtime.app_error", nil, err.Error(), http.StatusBadRequest)
- } else if mes.BatchSize == nil || *mes.BatchSize < 0 {
- return NewAppError("Config.IsValid", "model.config.is_valid.message_export.batch_size.app_error", nil, "", http.StatusBadRequest)
- } else if mes.ExportFormat == nil || (*mes.ExportFormat != COMPLIANCE_EXPORT_TYPE_ACTIANCE && *mes.ExportFormat != COMPLIANCE_EXPORT_TYPE_GLOBALRELAY && *mes.ExportFormat != COMPLIANCE_EXPORT_TYPE_CSV) {
- return NewAppError("Config.IsValid", "model.config.is_valid.message_export.export_type.app_error", nil, "", http.StatusBadRequest)
- }
-
- if *mes.ExportFormat == COMPLIANCE_EXPORT_TYPE_GLOBALRELAY {
- if mes.GlobalRelaySettings == nil {
- return NewAppError("Config.IsValid", "model.config.is_valid.message_export.global_relay.config_missing.app_error", nil, "", http.StatusBadRequest)
- } else if mes.GlobalRelaySettings.CustomerType == nil || (*mes.GlobalRelaySettings.CustomerType != GLOBALRELAY_CUSTOMER_TYPE_A9 && *mes.GlobalRelaySettings.CustomerType != GLOBALRELAY_CUSTOMER_TYPE_A10) {
- return NewAppError("Config.IsValid", "model.config.is_valid.message_export.global_relay.customer_type.app_error", nil, "", http.StatusBadRequest)
- } else if mes.GlobalRelaySettings.EmailAddress == nil || !strings.Contains(*mes.GlobalRelaySettings.EmailAddress, "@") {
- // validating email addresses is hard - just make sure it contains an '@' sign
- // see https://stackoverflow.com/questions/201323/using-a-regular-expression-to-validate-an-email-address
- return NewAppError("Config.IsValid", "model.config.is_valid.message_export.global_relay.email_address.app_error", nil, "", http.StatusBadRequest)
- } else if mes.GlobalRelaySettings.SmtpUsername == nil || *mes.GlobalRelaySettings.SmtpUsername == "" {
- return NewAppError("Config.IsValid", "model.config.is_valid.message_export.global_relay.smtp_username.app_error", nil, "", http.StatusBadRequest)
- } else if mes.GlobalRelaySettings.SmtpPassword == nil || *mes.GlobalRelaySettings.SmtpPassword == "" {
- return NewAppError("Config.IsValid", "model.config.is_valid.message_export.global_relay.smtp_password.app_error", nil, "", http.StatusBadRequest)
- }
- }
- }
- return nil
-}
-
-func (ds *DisplaySettings) isValid() *AppError {
- if len(*ds.CustomUrlSchemes) != 0 {
- validProtocolPattern := regexp.MustCompile(`(?i)^\s*[a-z][a-z0-9-]*\s*$`)
-
- for _, scheme := range *ds.CustomUrlSchemes {
- if !validProtocolPattern.MatchString(scheme) {
- return NewAppError(
- "Config.IsValid",
- "model.config.is_valid.display.custom_url_schemes.app_error",
- map[string]interface{}{"Scheme": scheme},
- "",
- http.StatusBadRequest,
- )
- }
- }
- }
-
- return nil
-}
-
-func (o *Config) GetSanitizeOptions() map[string]bool {
- options := map[string]bool{}
- options["fullname"] = o.PrivacySettings.ShowFullName
- options["email"] = o.PrivacySettings.ShowEmailAddress
-
- return options
-}
-
-func (o *Config) Sanitize() {
- if o.LdapSettings.BindPassword != nil && len(*o.LdapSettings.BindPassword) > 0 {
- *o.LdapSettings.BindPassword = FAKE_SETTING
- }
-
- *o.FileSettings.PublicLinkSalt = FAKE_SETTING
- if len(o.FileSettings.AmazonS3SecretAccessKey) > 0 {
- o.FileSettings.AmazonS3SecretAccessKey = FAKE_SETTING
- }
-
- o.EmailSettings.InviteSalt = FAKE_SETTING
- if len(o.EmailSettings.SMTPPassword) > 0 {
- o.EmailSettings.SMTPPassword = FAKE_SETTING
- }
-
- if len(o.GitLabSettings.Secret) > 0 {
- o.GitLabSettings.Secret = FAKE_SETTING
- }
-
- *o.SqlSettings.DataSource = FAKE_SETTING
- o.SqlSettings.AtRestEncryptKey = FAKE_SETTING
-
- for i := range o.SqlSettings.DataSourceReplicas {
- o.SqlSettings.DataSourceReplicas[i] = FAKE_SETTING
- }
-
- for i := range o.SqlSettings.DataSourceSearchReplicas {
- o.SqlSettings.DataSourceSearchReplicas[i] = FAKE_SETTING
- }
-
- *o.ElasticsearchSettings.Password = FAKE_SETTING
-}
diff --git a/vendor/github.com/mattermost/mattermost-server/model/ldap.go b/vendor/github.com/mattermost/mattermost-server/model/ldap.go
deleted file mode 100644
index 9051c5a3..00000000
--- a/vendor/github.com/mattermost/mattermost-server/model/ldap.go
+++ /dev/null
@@ -1,8 +0,0 @@
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-package model
-
-const (
- USER_AUTH_SERVICE_LDAP = "ldap"
-)
diff --git a/vendor/github.com/mattermost/mattermost-server/model/migration.go b/vendor/github.com/mattermost/mattermost-server/model/migration.go
deleted file mode 100644
index ead7acce..00000000
--- a/vendor/github.com/mattermost/mattermost-server/model/migration.go
+++ /dev/null
@@ -1,8 +0,0 @@
-// Copyright (c) 2018-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-package model
-
-const (
- MIGRATION_KEY_ADVANCED_PERMISSIONS_PHASE_2 = "migration_advanced_permissions_phase_2"
-)
diff --git a/vendor/github.com/mattermost/mattermost-server/model/push_notification.go b/vendor/github.com/mattermost/mattermost-server/model/push_notification.go
deleted file mode 100644
index 5268a98f..00000000
--- a/vendor/github.com/mattermost/mattermost-server/model/push_notification.go
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-package model
-
-import (
- "encoding/json"
- "io"
- "strings"
-)
-
-const (
- PUSH_NOTIFY_APPLE = "apple"
- PUSH_NOTIFY_ANDROID = "android"
- PUSH_NOTIFY_APPLE_REACT_NATIVE = "apple_rn"
- PUSH_NOTIFY_ANDROID_REACT_NATIVE = "android_rn"
-
- PUSH_TYPE_MESSAGE = "message"
- PUSH_TYPE_CLEAR = "clear"
- PUSH_MESSAGE_V2 = "v2"
-
- // The category is set to handle a set of interactive Actions
- // with the push notifications
- CATEGORY_CAN_REPLY = "CAN_REPLY"
-
- MHPNS = "https://push.mattermost.com"
-)
-
-type PushNotification struct {
- Platform string `json:"platform"`
- ServerId string `json:"server_id"`
- DeviceId string `json:"device_id"`
- Category string `json:"category"`
- Sound string `json:"sound"`
- Message string `json:"message"`
- Badge int `json:"badge"`
- ContentAvailable int `json:"cont_ava"`
- TeamId string `json:"team_id"`
- ChannelId string `json:"channel_id"`
- PostId string `json:"post_id"`
- RootId string `json:"root_id"`
- ChannelName string `json:"channel_name"`
- Type string `json:"type"`
- SenderId string `json:"sender_id"`
- OverrideUsername string `json:"override_username"`
- OverrideIconUrl string `json:"override_icon_url"`
- FromWebhook string `json:"from_webhook"`
- Version string `json:"version"`
-}
-
-func (me *PushNotification) ToJson() string {
- b, _ := json.Marshal(me)
- return string(b)
-}
-
-func (me *PushNotification) SetDeviceIdAndPlatform(deviceId string) {
-
- index := strings.Index(deviceId, ":")
-
- if index > -1 {
- me.Platform = deviceId[:index]
- me.DeviceId = deviceId[index+1:]
- }
-}
-
-func PushNotificationFromJson(data io.Reader) *PushNotification {
- var me *PushNotification
- json.NewDecoder(data).Decode(&me)
- return me
-}
diff --git a/vendor/github.com/mattermost/mattermost-server/model/role.go b/vendor/github.com/mattermost/mattermost-server/model/role.go
deleted file mode 100644
index 27b32ed6..00000000
--- a/vendor/github.com/mattermost/mattermost-server/model/role.go
+++ /dev/null
@@ -1,363 +0,0 @@
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-package model
-
-import (
- "encoding/json"
- "io"
- "strings"
-)
-
-const (
- SYSTEM_USER_ROLE_ID = "system_user"
- SYSTEM_ADMIN_ROLE_ID = "system_admin"
- SYSTEM_POST_ALL_ROLE_ID = "system_post_all"
- SYSTEM_POST_ALL_PUBLIC_ROLE_ID = "system_post_all_public"
- SYSTEM_USER_ACCESS_TOKEN_ROLE_ID = "system_user_access_token"
-
- TEAM_USER_ROLE_ID = "team_user"
- TEAM_ADMIN_ROLE_ID = "team_admin"
- TEAM_POST_ALL_ROLE_ID = "team_post_all"
- TEAM_POST_ALL_PUBLIC_ROLE_ID = "team_post_all_public"
-
- CHANNEL_USER_ROLE_ID = "channel_user"
- CHANNEL_ADMIN_ROLE_ID = "channel_admin"
-
- ROLE_NAME_MAX_LENGTH = 64
- ROLE_DISPLAY_NAME_MAX_LENGTH = 128
- ROLE_DESCRIPTION_MAX_LENGTH = 1024
-)
-
-type Role struct {
- Id string `json:"id"`
- Name string `json:"name"`
- DisplayName string `json:"display_name"`
- Description string `json:"description"`
- CreateAt int64 `json:"create_at"`
- UpdateAt int64 `json:"update_at"`
- DeleteAt int64 `json:"delete_at"`
- Permissions []string `json:"permissions"`
- SchemeManaged bool `json:"scheme_managed"`
- BuiltIn bool `json:"built_in"`
-}
-
-type RolePatch struct {
- Permissions *[]string `json:"permissions"`
-}
-
-func (role *Role) ToJson() string {
- b, _ := json.Marshal(role)
- return string(b)
-}
-
-func RoleFromJson(data io.Reader) *Role {
- var role *Role
- json.NewDecoder(data).Decode(&role)
- return role
-}
-
-func RoleListToJson(r []*Role) string {
- b, _ := json.Marshal(r)
- return string(b)
-}
-
-func RoleListFromJson(data io.Reader) []*Role {
- var roles []*Role
- json.NewDecoder(data).Decode(&roles)
- return roles
-}
-
-func (r *RolePatch) ToJson() string {
- b, _ := json.Marshal(r)
- return string(b)
-}
-
-func RolePatchFromJson(data io.Reader) *RolePatch {
- var rolePatch *RolePatch
- json.NewDecoder(data).Decode(&rolePatch)
- return rolePatch
-}
-
-func (o *Role) Patch(patch *RolePatch) {
- if patch.Permissions != nil {
- o.Permissions = *patch.Permissions
- }
-}
-
-// Returns an array of permissions that are in either role.Permissions
-// or patch.Permissions, but not both.
-func PermissionsChangedByPatch(role *Role, patch *RolePatch) []string {
- var result []string
-
- if patch.Permissions == nil {
- return result
- }
-
- roleMap := make(map[string]bool)
- patchMap := make(map[string]bool)
-
- for _, permission := range role.Permissions {
- roleMap[permission] = true
- }
-
- for _, permission := range *patch.Permissions {
- patchMap[permission] = true
- }
-
- for _, permission := range role.Permissions {
- if !patchMap[permission] {
- result = append(result, permission)
- }
- }
-
- for _, permission := range *patch.Permissions {
- if !roleMap[permission] {
- result = append(result, permission)
- }
- }
-
- return result
-}
-
-func (role *Role) IsValid() bool {
- if len(role.Id) != 26 {
- return false
- }
-
- return role.IsValidWithoutId()
-}
-
-func (role *Role) IsValidWithoutId() bool {
- if !IsValidRoleName(role.Name) {
- return false
- }
-
- if len(role.DisplayName) == 0 || len(role.DisplayName) > ROLE_DISPLAY_NAME_MAX_LENGTH {
- return false
- }
-
- if len(role.Description) > ROLE_DESCRIPTION_MAX_LENGTH {
- return false
- }
-
- for _, permission := range role.Permissions {
- permissionValidated := false
- for _, p := range ALL_PERMISSIONS {
- if permission == p.Id {
- permissionValidated = true
- break
- }
- }
-
- if !permissionValidated {
- return false
- }
- }
-
- return true
-}
-
-func IsValidRoleName(roleName string) bool {
- if len(roleName) <= 0 || len(roleName) > ROLE_NAME_MAX_LENGTH {
- return false
- }
-
- if strings.TrimLeft(roleName, "abcdefghijklmnopqrstuvwxyz0123456789_") != "" {
- return false
- }
-
- return true
-}
-
-func MakeDefaultRoles() map[string]*Role {
- roles := make(map[string]*Role)
-
- roles[CHANNEL_USER_ROLE_ID] = &Role{
- Name: "channel_user",
- DisplayName: "authentication.roles.channel_user.name",
- Description: "authentication.roles.channel_user.description",
- Permissions: []string{
- PERMISSION_READ_CHANNEL.Id,
- PERMISSION_ADD_REACTION.Id,
- PERMISSION_REMOVE_REACTION.Id,
- PERMISSION_MANAGE_PUBLIC_CHANNEL_MEMBERS.Id,
- PERMISSION_UPLOAD_FILE.Id,
- PERMISSION_GET_PUBLIC_LINK.Id,
- PERMISSION_CREATE_POST.Id,
- PERMISSION_USE_SLASH_COMMANDS.Id,
- },
- SchemeManaged: true,
- BuiltIn: true,
- }
-
- roles[CHANNEL_ADMIN_ROLE_ID] = &Role{
- Name: "channel_admin",
- DisplayName: "authentication.roles.channel_admin.name",
- Description: "authentication.roles.channel_admin.description",
- Permissions: []string{
- PERMISSION_MANAGE_CHANNEL_ROLES.Id,
- },
- SchemeManaged: true,
- BuiltIn: true,
- }
-
- roles[TEAM_USER_ROLE_ID] = &Role{
- Name: "team_user",
- DisplayName: "authentication.roles.team_user.name",
- Description: "authentication.roles.team_user.description",
- Permissions: []string{
- PERMISSION_LIST_TEAM_CHANNELS.Id,
- PERMISSION_JOIN_PUBLIC_CHANNELS.Id,
- PERMISSION_READ_PUBLIC_CHANNEL.Id,
- PERMISSION_VIEW_TEAM.Id,
- },
- SchemeManaged: true,
- BuiltIn: true,
- }
-
- roles[TEAM_POST_ALL_ROLE_ID] = &Role{
- Name: "team_post_all",
- DisplayName: "authentication.roles.team_post_all.name",
- Description: "authentication.roles.team_post_all.description",
- Permissions: []string{
- PERMISSION_CREATE_POST.Id,
- },
- SchemeManaged: false,
- BuiltIn: true,
- }
-
- roles[TEAM_POST_ALL_PUBLIC_ROLE_ID] = &Role{
- Name: "team_post_all_public",
- DisplayName: "authentication.roles.team_post_all_public.name",
- Description: "authentication.roles.team_post_all_public.description",
- Permissions: []string{
- PERMISSION_CREATE_POST_PUBLIC.Id,
- },
- SchemeManaged: false,
- BuiltIn: true,
- }
-
- roles[TEAM_ADMIN_ROLE_ID] = &Role{
- Name: "team_admin",
- DisplayName: "authentication.roles.team_admin.name",
- Description: "authentication.roles.team_admin.description",
- Permissions: []string{
- PERMISSION_REMOVE_USER_FROM_TEAM.Id,
- PERMISSION_MANAGE_TEAM.Id,
- PERMISSION_IMPORT_TEAM.Id,
- PERMISSION_MANAGE_TEAM_ROLES.Id,
- PERMISSION_MANAGE_CHANNEL_ROLES.Id,
- PERMISSION_MANAGE_OTHERS_WEBHOOKS.Id,
- PERMISSION_MANAGE_SLASH_COMMANDS.Id,
- PERMISSION_MANAGE_OTHERS_SLASH_COMMANDS.Id,
- PERMISSION_MANAGE_WEBHOOKS.Id,
- },
- SchemeManaged: true,
- BuiltIn: true,
- }
-
- roles[SYSTEM_USER_ROLE_ID] = &Role{
- Name: "system_user",
- DisplayName: "authentication.roles.global_user.name",
- Description: "authentication.roles.global_user.description",
- Permissions: []string{
- PERMISSION_CREATE_DIRECT_CHANNEL.Id,
- PERMISSION_CREATE_GROUP_CHANNEL.Id,
- PERMISSION_PERMANENT_DELETE_USER.Id,
- },
- SchemeManaged: true,
- BuiltIn: true,
- }
-
- roles[SYSTEM_POST_ALL_ROLE_ID] = &Role{
- Name: "system_post_all",
- DisplayName: "authentication.roles.system_post_all.name",
- Description: "authentication.roles.system_post_all.description",
- Permissions: []string{
- PERMISSION_CREATE_POST.Id,
- },
- SchemeManaged: false,
- BuiltIn: true,
- }
-
- roles[SYSTEM_POST_ALL_PUBLIC_ROLE_ID] = &Role{
- Name: "system_post_all_public",
- DisplayName: "authentication.roles.system_post_all_public.name",
- Description: "authentication.roles.system_post_all_public.description",
- Permissions: []string{
- PERMISSION_CREATE_POST_PUBLIC.Id,
- },
- SchemeManaged: false,
- BuiltIn: true,
- }
-
- roles[SYSTEM_USER_ACCESS_TOKEN_ROLE_ID] = &Role{
- Name: "system_user_access_token",
- DisplayName: "authentication.roles.system_user_access_token.name",
- Description: "authentication.roles.system_user_access_token.description",
- Permissions: []string{
- PERMISSION_CREATE_USER_ACCESS_TOKEN.Id,
- PERMISSION_READ_USER_ACCESS_TOKEN.Id,
- PERMISSION_REVOKE_USER_ACCESS_TOKEN.Id,
- },
- SchemeManaged: false,
- BuiltIn: true,
- }
-
- roles[SYSTEM_ADMIN_ROLE_ID] = &Role{
- Name: "system_admin",
- DisplayName: "authentication.roles.global_admin.name",
- Description: "authentication.roles.global_admin.description",
- // System admins can do anything channel and team admins can do
- // plus everything members of teams and channels can do to all teams
- // and channels on the system
- Permissions: append(
- append(
- append(
- append(
- []string{
- PERMISSION_ASSIGN_SYSTEM_ADMIN_ROLE.Id,
- PERMISSION_MANAGE_SYSTEM.Id,
- PERMISSION_MANAGE_ROLES.Id,
- PERMISSION_MANAGE_PUBLIC_CHANNEL_PROPERTIES.Id,
- PERMISSION_MANAGE_PUBLIC_CHANNEL_MEMBERS.Id,
- PERMISSION_MANAGE_PRIVATE_CHANNEL_MEMBERS.Id,
- PERMISSION_DELETE_PUBLIC_CHANNEL.Id,
- PERMISSION_CREATE_PUBLIC_CHANNEL.Id,
- PERMISSION_MANAGE_PRIVATE_CHANNEL_PROPERTIES.Id,
- PERMISSION_DELETE_PRIVATE_CHANNEL.Id,
- PERMISSION_CREATE_PRIVATE_CHANNEL.Id,
- PERMISSION_MANAGE_SYSTEM_WIDE_OAUTH.Id,
- PERMISSION_MANAGE_OTHERS_WEBHOOKS.Id,
- PERMISSION_EDIT_OTHER_USERS.Id,
- PERMISSION_EDIT_OTHERS_POSTS.Id,
- PERMISSION_MANAGE_OAUTH.Id,
- PERMISSION_INVITE_USER.Id,
- PERMISSION_DELETE_POST.Id,
- PERMISSION_DELETE_OTHERS_POSTS.Id,
- PERMISSION_CREATE_TEAM.Id,
- PERMISSION_ADD_USER_TO_TEAM.Id,
- PERMISSION_LIST_USERS_WITHOUT_TEAM.Id,
- PERMISSION_MANAGE_JOBS.Id,
- PERMISSION_CREATE_POST_PUBLIC.Id,
- PERMISSION_CREATE_POST_EPHEMERAL.Id,
- PERMISSION_CREATE_USER_ACCESS_TOKEN.Id,
- PERMISSION_READ_USER_ACCESS_TOKEN.Id,
- PERMISSION_REVOKE_USER_ACCESS_TOKEN.Id,
- PERMISSION_REMOVE_OTHERS_REACTIONS.Id,
- },
- roles[TEAM_USER_ROLE_ID].Permissions...,
- ),
- roles[CHANNEL_USER_ROLE_ID].Permissions...,
- ),
- roles[TEAM_ADMIN_ROLE_ID].Permissions...,
- ),
- roles[CHANNEL_ADMIN_ROLE_ID].Permissions...,
- ),
- SchemeManaged: true,
- BuiltIn: true,
- }
-
- return roles
-}
diff --git a/vendor/github.com/mattermost/mattermost-server/model/saml.go b/vendor/github.com/mattermost/mattermost-server/model/saml.go
deleted file mode 100644
index 528ac45c..00000000
--- a/vendor/github.com/mattermost/mattermost-server/model/saml.go
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-package model
-
-import (
- "encoding/json"
- "io"
-)
-
-const (
- USER_AUTH_SERVICE_SAML = "saml"
- USER_AUTH_SERVICE_SAML_TEXT = "With SAML"
-)
-
-type SamlAuthRequest struct {
- Base64AuthRequest string
- URL string
- RelayState string
-}
-
-type SamlCertificateStatus struct {
- IdpCertificateFile bool `json:"idp_certificate_file"`
- PrivateKeyFile bool `json:"private_key_file"`
- PublicCertificateFile bool `json:"public_certificate_file"`
-}
-
-func (s *SamlCertificateStatus) ToJson() string {
- b, _ := json.Marshal(s)
- return string(b)
-}
-
-func SamlCertificateStatusFromJson(data io.Reader) *SamlCertificateStatus {
- var status *SamlCertificateStatus
- json.NewDecoder(data).Decode(&status)
- return status
-}
diff --git a/vendor/github.com/mattermost/mattermost-server/model/search_params.go b/vendor/github.com/mattermost/mattermost-server/model/search_params.go
deleted file mode 100644
index 65358066..00000000
--- a/vendor/github.com/mattermost/mattermost-server/model/search_params.go
+++ /dev/null
@@ -1,228 +0,0 @@
-// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-package model
-
-import (
- "regexp"
- "strings"
- "time"
-)
-
-var searchTermPuncStart = regexp.MustCompile(`^[^\pL\d\s#"]+`)
-var searchTermPuncEnd = regexp.MustCompile(`[^\pL\d\s*"]+$`)
-
-type SearchParams struct {
- Terms string
- IsHashtag bool
- InChannels []string
- FromUsers []string
- AfterDate string
- BeforeDate string
- OnDate string
- OrTerms bool
- IncludeDeletedChannels bool
- TimeZoneOffset int
-}
-
-// Returns the epoch timestamp of the start of the day specified by SearchParams.AfterDate
-func (p *SearchParams) GetAfterDateMillis() int64 {
- date, err := time.Parse("2006-01-02", PadDateStringZeros(p.AfterDate))
- if err != nil {
- date = time.Now()
- }
-
- // travel forward 1 day
- oneDay := time.Hour * 24
- afterDate := date.Add(oneDay)
- return GetStartOfDayMillis(afterDate, p.TimeZoneOffset)
-}
-
-// Returns the epoch timestamp of the end of the day specified by SearchParams.BeforeDate
-func (p *SearchParams) GetBeforeDateMillis() int64 {
- date, err := time.Parse("2006-01-02", PadDateStringZeros(p.BeforeDate))
- if err != nil {
- return 0
- }
-
- // travel back 1 day
- oneDay := time.Hour * -24
- beforeDate := date.Add(oneDay)
- return GetEndOfDayMillis(beforeDate, p.TimeZoneOffset)
-}
-
-// Returns the epoch timestamps of the start and end of the day specified by SearchParams.OnDate
-func (p *SearchParams) GetOnDateMillis() (int64, int64) {
- date, err := time.Parse("2006-01-02", PadDateStringZeros(p.OnDate))
- if err != nil {
- return 0, 0
- }
-
- return GetStartOfDayMillis(date, p.TimeZoneOffset), GetEndOfDayMillis(date, p.TimeZoneOffset)
-}
-
-var searchFlags = [...]string{"from", "channel", "in", "before", "after", "on"}
-
-func splitWords(text string) []string {
- words := []string{}
-
- foundQuote := false
- location := 0
- for i, char := range text {
- if char == '"' {
- if foundQuote {
- // Grab the quoted section
- word := text[location : i+1]
- words = append(words, word)
- foundQuote = false
- location = i + 1
- } else {
- words = append(words, strings.Fields(text[location:i])...)
- foundQuote = true
- location = i
- }
- }
- }
-
- words = append(words, strings.Fields(text[location:])...)
-
- return words
-}
-
-func parseSearchFlags(input []string) ([]string, [][2]string) {
- words := []string{}
- flags := [][2]string{}
-
- skipNextWord := false
- for i, word := range input {
- if skipNextWord {
- skipNextWord = false
- continue
- }
-
- isFlag := false
-
- if colon := strings.Index(word, ":"); colon != -1 {
- flag := word[:colon]
- value := word[colon+1:]
-
- for _, searchFlag := range searchFlags {
- // check for case insensitive equality
- if strings.EqualFold(flag, searchFlag) {
- if value != "" {
- flags = append(flags, [2]string{searchFlag, value})
- isFlag = true
- } else if i < len(input)-1 {
- flags = append(flags, [2]string{searchFlag, input[i+1]})
- skipNextWord = true
- isFlag = true
- }
-
- if isFlag {
- break
- }
- }
- }
- }
-
- if !isFlag {
- // trim off surrounding punctuation (note that we leave trailing asterisks to allow wildcards)
- word = searchTermPuncStart.ReplaceAllString(word, "")
- word = searchTermPuncEnd.ReplaceAllString(word, "")
-
- // and remove extra pound #s
- word = hashtagStart.ReplaceAllString(word, "#")
-
- if len(word) != 0 {
- words = append(words, word)
- }
- }
- }
-
- return words, flags
-}
-
-func ParseSearchParams(text string, timeZoneOffset int) []*SearchParams {
- words, flags := parseSearchFlags(splitWords(text))
-
- hashtagTermList := []string{}
- plainTermList := []string{}
-
- for _, word := range words {
- if validHashtag.MatchString(word) {
- hashtagTermList = append(hashtagTermList, word)
- } else {
- plainTermList = append(plainTermList, word)
- }
- }
-
- hashtagTerms := strings.Join(hashtagTermList, " ")
- plainTerms := strings.Join(plainTermList, " ")
-
- inChannels := []string{}
- fromUsers := []string{}
- afterDate := ""
- beforeDate := ""
- onDate := ""
-
- for _, flagPair := range flags {
- flag := flagPair[0]
- value := flagPair[1]
-
- if flag == "in" || flag == "channel" {
- inChannels = append(inChannels, value)
- } else if flag == "from" {
- fromUsers = append(fromUsers, value)
- } else if flag == "after" {
- afterDate = value
- } else if flag == "before" {
- beforeDate = value
- } else if flag == "on" {
- onDate = value
- }
- }
-
- paramsList := []*SearchParams{}
-
- if len(plainTerms) > 0 {
- paramsList = append(paramsList, &SearchParams{
- Terms: plainTerms,
- IsHashtag: false,
- InChannels: inChannels,
- FromUsers: fromUsers,
- AfterDate: afterDate,
- BeforeDate: beforeDate,
- OnDate: onDate,
- TimeZoneOffset: timeZoneOffset,
- })
- }
-
- if len(hashtagTerms) > 0 {
- paramsList = append(paramsList, &SearchParams{
- Terms: hashtagTerms,
- IsHashtag: true,
- InChannels: inChannels,
- FromUsers: fromUsers,
- AfterDate: afterDate,
- BeforeDate: beforeDate,
- OnDate: onDate,
- TimeZoneOffset: timeZoneOffset,
- })
- }
-
- // special case for when no terms are specified but we still have a filter
- if len(plainTerms) == 0 && len(hashtagTerms) == 0 && (len(inChannels) != 0 || len(fromUsers) != 0 || len(afterDate) != 0 || len(beforeDate) != 0 || len(onDate) != 0) {
- paramsList = append(paramsList, &SearchParams{
- Terms: "",
- IsHashtag: false,
- InChannels: inChannels,
- FromUsers: fromUsers,
- AfterDate: afterDate,
- BeforeDate: beforeDate,
- OnDate: onDate,
- TimeZoneOffset: timeZoneOffset,
- })
- }
-
- return paramsList
-}
diff --git a/vendor/github.com/mattermost/mattermost-server/model/system.go b/vendor/github.com/mattermost/mattermost-server/model/system.go
deleted file mode 100644
index 4228516d..00000000
--- a/vendor/github.com/mattermost/mattermost-server/model/system.go
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-package model
-
-import (
- "encoding/json"
- "io"
- "math/big"
-)
-
-const (
- SYSTEM_DIAGNOSTIC_ID = "DiagnosticId"
- SYSTEM_RAN_UNIT_TESTS = "RanUnitTests"
- SYSTEM_LAST_SECURITY_TIME = "LastSecurityTime"
- SYSTEM_ACTIVE_LICENSE_ID = "ActiveLicenseId"
- SYSTEM_LAST_COMPLIANCE_TIME = "LastComplianceTime"
- SYSTEM_ASYMMETRIC_SIGNING_KEY = "AsymmetricSigningKey"
- SYSTEM_INSTALLATION_DATE_KEY = "InstallationDate"
-)
-
-type System struct {
- Name string `json:"name"`
- Value string `json:"value"`
-}
-
-func (o *System) ToJson() string {
- b, _ := json.Marshal(o)
- return string(b)
-}
-
-func SystemFromJson(data io.Reader) *System {
- var o *System
- json.NewDecoder(data).Decode(&o)
- return o
-}
-
-type SystemAsymmetricSigningKey struct {
- ECDSAKey *SystemECDSAKey `json:"ecdsa_key,omitempty"`
-}
-
-type SystemECDSAKey struct {
- Curve string `json:"curve"`
- X *big.Int `json:"x"`
- Y *big.Int `json:"y"`
- D *big.Int `json:"d,omitempty"`
-}
diff --git a/vendor/github.com/mattermost/mattermost-server/model/team_member.go b/vendor/github.com/mattermost/mattermost-server/model/team_member.go
deleted file mode 100644
index 3bae3d7e..00000000
--- a/vendor/github.com/mattermost/mattermost-server/model/team_member.go
+++ /dev/null
@@ -1,102 +0,0 @@
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-package model
-
-import (
- "encoding/json"
- "io"
- "net/http"
- "strings"
-)
-
-type TeamMember struct {
- TeamId string `json:"team_id"`
- UserId string `json:"user_id"`
- Roles string `json:"roles"`
- DeleteAt int64 `json:"delete_at"`
- SchemeUser bool `json:"scheme_user"`
- SchemeAdmin bool `json:"scheme_admin"`
- ExplicitRoles string `json:"explicit_roles"`
-}
-
-type TeamUnread struct {
- TeamId string `json:"team_id"`
- MsgCount int64 `json:"msg_count"`
- MentionCount int64 `json:"mention_count"`
-}
-
-type TeamMemberForExport struct {
- TeamMember
- TeamName string
-}
-
-func (o *TeamMember) ToJson() string {
- b, _ := json.Marshal(o)
- return string(b)
-}
-
-func (o *TeamUnread) ToJson() string {
- b, _ := json.Marshal(o)
- return string(b)
-}
-
-func TeamMemberFromJson(data io.Reader) *TeamMember {
- var o *TeamMember
- json.NewDecoder(data).Decode(&o)
- return o
-}
-
-func TeamUnreadFromJson(data io.Reader) *TeamUnread {
- var o *TeamUnread
- json.NewDecoder(data).Decode(&o)
- return o
-}
-
-func TeamMembersToJson(o []*TeamMember) string {
- if b, err := json.Marshal(o); err != nil {
- return "[]"
- } else {
- return string(b)
- }
-}
-
-func TeamMembersFromJson(data io.Reader) []*TeamMember {
- var o []*TeamMember
- json.NewDecoder(data).Decode(&o)
- return o
-}
-
-func TeamsUnreadToJson(o []*TeamUnread) string {
- if b, err := json.Marshal(o); err != nil {
- return "[]"
- } else {
- return string(b)
- }
-}
-
-func TeamsUnreadFromJson(data io.Reader) []*TeamUnread {
- var o []*TeamUnread
- json.NewDecoder(data).Decode(&o)
- return o
-}
-
-func (o *TeamMember) IsValid() *AppError {
-
- if len(o.TeamId) != 26 {
- return NewAppError("TeamMember.IsValid", "model.team_member.is_valid.team_id.app_error", nil, "", http.StatusBadRequest)
- }
-
- if len(o.UserId) != 26 {
- return NewAppError("TeamMember.IsValid", "model.team_member.is_valid.user_id.app_error", nil, "", http.StatusBadRequest)
- }
-
- return nil
-}
-
-func (o *TeamMember) PreUpdate() {
-}
-
-func (o *TeamMember) GetRoles() []string {
- return strings.Fields(o.Roles)
-}
diff --git a/vendor/github.com/mattermost/mattermost-server/model/user_search.go b/vendor/github.com/mattermost/mattermost-server/model/user_search.go
deleted file mode 100644
index 94596bdc..00000000
--- a/vendor/github.com/mattermost/mattermost-server/model/user_search.go
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-package model
-
-import (
- "encoding/json"
- "io"
-)
-
-type UserSearch struct {
- Term string `json:"term"`
- TeamId string `json:"team_id"`
- NotInTeamId string `json:"not_in_team_id"`
- InChannelId string `json:"in_channel_id"`
- NotInChannelId string `json:"not_in_channel_id"`
- AllowInactive bool `json:"allow_inactive"`
- WithoutTeam bool `json:"without_team"`
-}
-
-// ToJson convert a User to a json string
-func (u *UserSearch) ToJson() string {
- b, _ := json.Marshal(u)
- return string(b)
-}
-
-// UserSearchFromJson will decode the input and return a User
-func UserSearchFromJson(data io.Reader) *UserSearch {
- var us *UserSearch
- json.NewDecoder(data).Decode(&us)
- return us
-}
diff --git a/vendor/github.com/mattermost/mattermost-server/model/webrtc.go b/vendor/github.com/mattermost/mattermost-server/model/webrtc.go
deleted file mode 100644
index 59797a5b..00000000
--- a/vendor/github.com/mattermost/mattermost-server/model/webrtc.go
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-package model
-
-import (
- "encoding/json"
- "io"
-)
-
-type WebrtcInfoResponse struct {
- Token string `json:"token"`
- GatewayUrl string `json:"gateway_url"`
- StunUri string `json:"stun_uri,omitempty"`
- TurnUri string `json:"turn_uri,omitempty"`
- TurnPassword string `json:"turn_password,omitempty"`
- TurnUsername string `json:"turn_username,omitempty"`
-}
-
-type GatewayResponse struct {
- Status string `json:"janus"`
-}
-
-func GatewayResponseFromJson(data io.Reader) *GatewayResponse {
- var o *GatewayResponse
- json.NewDecoder(data).Decode(&o)
- return o
-}
-
-func (o *WebrtcInfoResponse) ToJson() string {
- b, _ := json.Marshal(o)
- return string(b)
-}
-
-func WebrtcInfoResponseFromJson(data io.Reader) *WebrtcInfoResponse {
- var o *WebrtcInfoResponse
- json.NewDecoder(data).Decode(&o)
- return o
-}
diff --git a/vendor/github.com/mattermost/mattermost-server/model/websocket_client.go b/vendor/github.com/mattermost/mattermost-server/model/websocket_client.go
deleted file mode 100644
index 4e6c1d8c..00000000
--- a/vendor/github.com/mattermost/mattermost-server/model/websocket_client.go
+++ /dev/null
@@ -1,195 +0,0 @@
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-package model
-
-import (
- "encoding/json"
- "net/http"
- "time"
-
- "github.com/gorilla/websocket"
-)
-
-const (
- SOCKET_MAX_MESSAGE_SIZE_KB = 8 * 1024 // 8KB
- PING_TIMEOUT_BUFFER_SECONDS = 5
-)
-
-type WebSocketClient struct {
- Url string // The location of the server like "ws://localhost:8065"
- ApiUrl string // The api location of the server like "ws://localhost:8065/api/v3"
- ConnectUrl string // The websocket URL to connect to like "ws://localhost:8065/api/v3/path/to/websocket"
- Conn *websocket.Conn // The WebSocket connection
- AuthToken string // The token used to open the WebSocket
- Sequence int64 // The ever-incrementing sequence attached to each WebSocket action
- PingTimeoutChannel chan bool // The channel used to signal ping timeouts
- EventChannel chan *WebSocketEvent
- ResponseChannel chan *WebSocketResponse
- ListenError *AppError
- pingTimeoutTimer *time.Timer
-}
-
-// NewWebSocketClient constructs a new WebSocket client with convenience
-// methods for talking to the server.
-func NewWebSocketClient(url, authToken string) (*WebSocketClient, *AppError) {
- return NewWebSocketClientWithDialer(websocket.DefaultDialer, url, authToken)
-}
-
-// NewWebSocketClientWithDialer constructs a new WebSocket client with convenience
-// methods for talking to the server using a custom dialer.
-func NewWebSocketClientWithDialer(dialer *websocket.Dialer, url, authToken string) (*WebSocketClient, *AppError) {
- conn, _, err := dialer.Dial(url+API_URL_SUFFIX+"/websocket", nil)
- if err != nil {
- return nil, NewAppError("NewWebSocketClient", "model.websocket_client.connect_fail.app_error", nil, err.Error(), http.StatusInternalServerError)
- }
-
- client := &WebSocketClient{
- url,
- url + API_URL_SUFFIX,
- url + API_URL_SUFFIX + "/websocket",
- conn,
- authToken,
- 1,
- make(chan bool, 1),
- make(chan *WebSocketEvent, 100),
- make(chan *WebSocketResponse, 100),
- nil,
- nil,
- }
-
- client.configurePingHandling()
-
- client.SendMessage(WEBSOCKET_AUTHENTICATION_CHALLENGE, map[string]interface{}{"token": authToken})
-
- return client, nil
-}
-
-// NewWebSocketClient4 constructs a new WebSocket client with convenience
-// methods for talking to the server. Uses the v4 endpoint.
-func NewWebSocketClient4(url, authToken string) (*WebSocketClient, *AppError) {
- return NewWebSocketClient4WithDialer(websocket.DefaultDialer, url, authToken)
-}
-
-// NewWebSocketClient4WithDialer constructs a new WebSocket client with convenience
-// methods for talking to the server using a custom dialer. Uses the v4 endpoint.
-func NewWebSocketClient4WithDialer(dialer *websocket.Dialer, url, authToken string) (*WebSocketClient, *AppError) {
- return NewWebSocketClientWithDialer(dialer, url, authToken)
-}
-
-func (wsc *WebSocketClient) Connect() *AppError {
- return wsc.ConnectWithDialer(websocket.DefaultDialer)
-}
-
-func (wsc *WebSocketClient) ConnectWithDialer(dialer *websocket.Dialer) *AppError {
- var err error
- wsc.Conn, _, err = dialer.Dial(wsc.ConnectUrl, nil)
- if err != nil {
- return NewAppError("Connect", "model.websocket_client.connect_fail.app_error", nil, err.Error(), http.StatusInternalServerError)
- }
-
- wsc.configurePingHandling()
-
- wsc.EventChannel = make(chan *WebSocketEvent, 100)
- wsc.ResponseChannel = make(chan *WebSocketResponse, 100)
-
- wsc.SendMessage(WEBSOCKET_AUTHENTICATION_CHALLENGE, map[string]interface{}{"token": wsc.AuthToken})
-
- return nil
-}
-
-func (wsc *WebSocketClient) Close() {
- wsc.Conn.Close()
-}
-
-func (wsc *WebSocketClient) Listen() {
- go func() {
- defer func() {
- wsc.Conn.Close()
- close(wsc.EventChannel)
- close(wsc.ResponseChannel)
- }()
-
- for {
- var rawMsg json.RawMessage
- var err error
- if _, rawMsg, err = wsc.Conn.ReadMessage(); err != nil {
- if !websocket.IsCloseError(err, websocket.CloseNormalClosure, websocket.CloseNoStatusReceived) {
- wsc.ListenError = NewAppError("NewWebSocketClient", "model.websocket_client.connect_fail.app_error", nil, err.Error(), http.StatusInternalServerError)
- }
-
- return
- }
-
- var event WebSocketEvent
- if err := json.Unmarshal(rawMsg, &event); err == nil && event.IsValid() {
- wsc.EventChannel <- &event
- continue
- }
-
- var response WebSocketResponse
- if err := json.Unmarshal(rawMsg, &response); err == nil && response.IsValid() {
- wsc.ResponseChannel <- &response
- continue
- }
-
- }
- }()
-}
-
-func (wsc *WebSocketClient) SendMessage(action string, data map[string]interface{}) {
- req := &WebSocketRequest{}
- req.Seq = wsc.Sequence
- req.Action = action
- req.Data = data
-
- wsc.Sequence++
-
- wsc.Conn.WriteJSON(req)
-}
-
-// UserTyping will push a user_typing event out to all connected users
-// who are in the specified channel
-func (wsc *WebSocketClient) UserTyping(channelId, parentId string) {
- data := map[string]interface{}{
- "channel_id": channelId,
- "parent_id": parentId,
- }
-
- wsc.SendMessage("user_typing", data)
-}
-
-// GetStatuses will return a map of string statuses using user id as the key
-func (wsc *WebSocketClient) GetStatuses() {
- wsc.SendMessage("get_statuses", nil)
-}
-
-// GetStatusesByIds will fetch certain user statuses based on ids and return
-// a map of string statuses using user id as the key
-func (wsc *WebSocketClient) GetStatusesByIds(userIds []string) {
- data := map[string]interface{}{
- "user_ids": userIds,
- }
- wsc.SendMessage("get_statuses_by_ids", data)
-}
-
-func (wsc *WebSocketClient) configurePingHandling() {
- wsc.Conn.SetPingHandler(wsc.pingHandler)
- wsc.pingTimeoutTimer = time.NewTimer(time.Second * (60 + PING_TIMEOUT_BUFFER_SECONDS))
- go wsc.pingWatchdog()
-}
-
-func (wsc *WebSocketClient) pingHandler(appData string) error {
- if !wsc.pingTimeoutTimer.Stop() {
- <-wsc.pingTimeoutTimer.C
- }
-
- wsc.pingTimeoutTimer.Reset(time.Second * (60 + PING_TIMEOUT_BUFFER_SECONDS))
- wsc.Conn.WriteMessage(websocket.PongMessage, []byte{})
- return nil
-}
-
-func (wsc *WebSocketClient) pingWatchdog() {
- <-wsc.pingTimeoutTimer.C
- wsc.PingTimeoutChannel <- true
-}
diff --git a/vendor/github.com/mattermost/mattermost-server/model/websocket_message.go b/vendor/github.com/mattermost/mattermost-server/model/websocket_message.go
deleted file mode 100644
index ea8872d7..00000000
--- a/vendor/github.com/mattermost/mattermost-server/model/websocket_message.go
+++ /dev/null
@@ -1,165 +0,0 @@
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-package model
-
-import (
- "encoding/json"
- "fmt"
- "io"
-)
-
-const (
- WEBSOCKET_EVENT_TYPING = "typing"
- WEBSOCKET_EVENT_POSTED = "posted"
- WEBSOCKET_EVENT_POST_EDITED = "post_edited"
- WEBSOCKET_EVENT_POST_DELETED = "post_deleted"
- WEBSOCKET_EVENT_CHANNEL_CONVERTED = "channel_converted"
- WEBSOCKET_EVENT_CHANNEL_CREATED = "channel_created"
- WEBSOCKET_EVENT_CHANNEL_DELETED = "channel_deleted"
- WEBSOCKET_EVENT_CHANNEL_UPDATED = "channel_updated"
- WEBSOCKET_EVENT_CHANNEL_MEMBER_UPDATED = "channel_member_updated"
- WEBSOCKET_EVENT_DIRECT_ADDED = "direct_added"
- WEBSOCKET_EVENT_GROUP_ADDED = "group_added"
- WEBSOCKET_EVENT_NEW_USER = "new_user"
- WEBSOCKET_EVENT_ADDED_TO_TEAM = "added_to_team"
- WEBSOCKET_EVENT_LEAVE_TEAM = "leave_team"
- WEBSOCKET_EVENT_UPDATE_TEAM = "update_team"
- WEBSOCKET_EVENT_DELETE_TEAM = "delete_team"
- WEBSOCKET_EVENT_USER_ADDED = "user_added"
- WEBSOCKET_EVENT_USER_UPDATED = "user_updated"
- WEBSOCKET_EVENT_USER_ROLE_UPDATED = "user_role_updated"
- WEBSOCKET_EVENT_MEMBERROLE_UPDATED = "memberrole_updated"
- WEBSOCKET_EVENT_USER_REMOVED = "user_removed"
- WEBSOCKET_EVENT_PREFERENCE_CHANGED = "preference_changed"
- WEBSOCKET_EVENT_PREFERENCES_CHANGED = "preferences_changed"
- WEBSOCKET_EVENT_PREFERENCES_DELETED = "preferences_deleted"
- WEBSOCKET_EVENT_EPHEMERAL_MESSAGE = "ephemeral_message"
- WEBSOCKET_EVENT_STATUS_CHANGE = "status_change"
- WEBSOCKET_EVENT_HELLO = "hello"
- WEBSOCKET_EVENT_WEBRTC = "webrtc"
- WEBSOCKET_AUTHENTICATION_CHALLENGE = "authentication_challenge"
- WEBSOCKET_EVENT_REACTION_ADDED = "reaction_added"
- WEBSOCKET_EVENT_REACTION_REMOVED = "reaction_removed"
- WEBSOCKET_EVENT_RESPONSE = "response"
- WEBSOCKET_EVENT_EMOJI_ADDED = "emoji_added"
- WEBSOCKET_EVENT_CHANNEL_VIEWED = "channel_viewed"
- WEBSOCKET_EVENT_PLUGIN_STATUSES_CHANGED = "plugin_statuses_changed"
- WEBSOCKET_EVENT_PLUGIN_ENABLED = "plugin_enabled"
- WEBSOCKET_EVENT_PLUGIN_DISABLED = "plugin_disabled"
- WEBSOCKET_EVENT_ROLE_UPDATED = "role_updated"
- WEBSOCKET_EVENT_LICENSE_CHANGED = "license_changed"
- WEBSOCKET_EVENT_CONFIG_CHANGED = "config_changed"
-)
-
-type WebSocketMessage interface {
- ToJson() string
- IsValid() bool
- EventType() string
-}
-
-type WebsocketBroadcast struct {
- OmitUsers map[string]bool `json:"omit_users"` // broadcast is omitted for users listed here
- UserId string `json:"user_id"` // broadcast only occurs for this user
- ChannelId string `json:"channel_id"` // broadcast only occurs for users in this channel
- TeamId string `json:"team_id"` // broadcast only occurs for users in this team
- ContainsSanitizedData bool `json:"-"`
- ContainsSensitiveData bool `json:"-"`
-}
-
-type precomputedWebSocketEventJSON struct {
- Event json.RawMessage
- Data json.RawMessage
- Broadcast json.RawMessage
-}
-
-type WebSocketEvent struct {
- Event string `json:"event"`
- Data map[string]interface{} `json:"data"`
- Broadcast *WebsocketBroadcast `json:"broadcast"`
- Sequence int64 `json:"seq"`
-
- precomputedJSON *precomputedWebSocketEventJSON
-}
-
-// PrecomputeJSON precomputes and stores the serialized JSON for all fields other than Sequence.
-// This makes ToJson much more efficient when sending the same event to multiple connections.
-func (m *WebSocketEvent) PrecomputeJSON() {
- event, _ := json.Marshal(m.Event)
- data, _ := json.Marshal(m.Data)
- broadcast, _ := json.Marshal(m.Broadcast)
- m.precomputedJSON = &precomputedWebSocketEventJSON{
- Event: json.RawMessage(event),
- Data: json.RawMessage(data),
- Broadcast: json.RawMessage(broadcast),
- }
-}
-
-func (m *WebSocketEvent) Add(key string, value interface{}) {
- m.Data[key] = value
-}
-
-func NewWebSocketEvent(event, teamId, channelId, userId string, omitUsers map[string]bool) *WebSocketEvent {
- return &WebSocketEvent{Event: event, Data: make(map[string]interface{}),
- Broadcast: &WebsocketBroadcast{TeamId: teamId, ChannelId: channelId, UserId: userId, OmitUsers: omitUsers}}
-}
-
-func (o *WebSocketEvent) IsValid() bool {
- return o.Event != ""
-}
-
-func (o *WebSocketEvent) EventType() string {
- return o.Event
-}
-
-func (o *WebSocketEvent) ToJson() string {
- if o.precomputedJSON != nil {
- return fmt.Sprintf(`{"event": %s, "data": %s, "broadcast": %s, "seq": %d}`, o.precomputedJSON.Event, o.precomputedJSON.Data, o.precomputedJSON.Broadcast, o.Sequence)
- }
- b, _ := json.Marshal(o)
- return string(b)
-}
-
-func WebSocketEventFromJson(data io.Reader) *WebSocketEvent {
- var o *WebSocketEvent
- json.NewDecoder(data).Decode(&o)
- return o
-}
-
-type WebSocketResponse struct {
- Status string `json:"status"`
- SeqReply int64 `json:"seq_reply,omitempty"`
- Data map[string]interface{} `json:"data,omitempty"`
- Error *AppError `json:"error,omitempty"`
-}
-
-func (m *WebSocketResponse) Add(key string, value interface{}) {
- m.Data[key] = value
-}
-
-func NewWebSocketResponse(status string, seqReply int64, data map[string]interface{}) *WebSocketResponse {
- return &WebSocketResponse{Status: status, SeqReply: seqReply, Data: data}
-}
-
-func NewWebSocketError(seqReply int64, err *AppError) *WebSocketResponse {
- return &WebSocketResponse{Status: STATUS_FAIL, SeqReply: seqReply, Error: err}
-}
-
-func (o *WebSocketResponse) IsValid() bool {
- return o.Status != ""
-}
-
-func (o *WebSocketResponse) EventType() string {
- return WEBSOCKET_EVENT_RESPONSE
-}
-
-func (o *WebSocketResponse) ToJson() string {
- b, _ := json.Marshal(o)
- return string(b)
-}
-
-func WebSocketResponseFromJson(data io.Reader) *WebSocketResponse {
- var o *WebSocketResponse
- json.NewDecoder(data).Decode(&o)
- return o
-}
diff --git a/vendor/github.com/mattermost/mattermost-server/model/websocket_request.go b/vendor/github.com/mattermost/mattermost-server/model/websocket_request.go
deleted file mode 100644
index 4da626e2..00000000
--- a/vendor/github.com/mattermost/mattermost-server/model/websocket_request.go
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-package model
-
-import (
- "encoding/json"
- "io"
-
- goi18n "github.com/nicksnyder/go-i18n/i18n"
-)
-
-type WebSocketRequest struct {
- // Client-provided fields
- Seq int64 `json:"seq"`
- Action string `json:"action"`
- Data map[string]interface{} `json:"data"`
-
- // Server-provided fields
- Session Session `json:"-"`
- T goi18n.TranslateFunc `json:"-"`
- Locale string `json:"-"`
-}
-
-func (o *WebSocketRequest) ToJson() string {
- b, _ := json.Marshal(o)
- return string(b)
-}
-
-func WebSocketRequestFromJson(data io.Reader) *WebSocketRequest {
- var o *WebSocketRequest
- json.NewDecoder(data).Decode(&o)
- return o
-}
diff --git a/vendor/github.com/mattermost/mattermost-server/LICENSE.txt b/vendor/github.com/mattermost/mattermost-server/v5/LICENSE.txt
index 76e4c455..b40b5e58 100644
--- a/vendor/github.com/mattermost/mattermost-server/LICENSE.txt
+++ b/vendor/github.com/mattermost/mattermost-server/v5/LICENSE.txt
@@ -11,7 +11,7 @@ You may be licensed to use source code to create compiled versions not produced
1. Under the Free Software Foundation’s GNU AGPL v.3.0, subject to the exceptions outlined in this policy; or
2. Under a commercial license available from Mattermost, Inc. by contacting commercial@mattermost.com
-You are licensed to use the source code in Admin Tools and Configuration Files (templates/, config/, model/,
+You are licensed to use the source code in Admin Tools and Configuration Files (templates/, config/default.json, model/,
plugin/ and all subdirectories thereof) under the Apache License v2.0.
We promise that we will not enforce the copyleft provisions in AGPL v3.0 against you if your application (a) does not
diff --git a/vendor/github.com/mattermost/mattermost-server/NOTICE.txt b/vendor/github.com/mattermost/mattermost-server/v5/NOTICE.txt
index 55141290..0316f702 100644
--- a/vendor/github.com/mattermost/mattermost-server/NOTICE.txt
+++ b/vendor/github.com/mattermost/mattermost-server/v5/NOTICE.txt
@@ -6,13 +6,89 @@ NOTICES:
This document includes a list of open source components used in Mattermost Server, including those that have been modified.
+-----
+
+## Go
+
+This product uses the Go programming language by the Go authors.
+
+* HOMEPAGE:
+ * https://golang.org
+
+* LICENSE: BSD-style
+
+Copyright (c) 2009 The Go Authors. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+ * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+---
+
+## Masterminds/squirrel
+
+This product contains 'squirrel' by GitHub user "Masterminds".
+
+Fluent SQL generation for golang
+
+* HOMEPAGE:
+ * https://github.com/Masterminds/squirrel
+
+* LICENSE: MIT
+
+Squirrel
+The Masterminds
+Copyright (C) 2014-2015, Lann Martin
+Copyright (C) 2015-2016, Google
+Copyright (C) 2015, Matt Farina and Matt Butcher
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
---
## NYTimes/gziphandler
This product contains 'gziphandler' by The New York Times.
-Golang middleware to gzip HTTP responses
+Go middleware to gzip HTTP responses
* HOMEPAGE:
* https://github.com/NYTimes/gziphandler
@@ -429,6 +505,41 @@ Go package for fast and reliable abstraction of browser user agent strings.
---
+## blang/semver
+
+This product contains 'semver' by Benedikt Lang.
+
+Semantic Versioning (semver) library written in golang
+
+* HOMEPAGE:
+ * https://github.com/blang/semver
+
+* LICENSE: MIT
+
+The MIT License
+
+Copyright (c) 2014 Benedikt Lang <github at benediktlang.de>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+---
+
## dgryski/dgoogauth
This product contains 'dgoogauth' by Damian Gryski.
@@ -502,7 +613,7 @@ 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 2018 Damian Gryski
+Copyright 2019 Damian Gryski
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -531,7 +642,7 @@ Imaging is a simple image processing package for Go
The MIT License (MIT)
-Copyright (c) 2012-2018 Grigory Dryapak
+Copyright (c) 2012 Grigory Dryapak
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@@ -2282,9 +2393,9 @@ SOFTWARE.
## minio/minio-go
-This product contains 'minio-go' by Minio Cloud Storage.
+This product contains 'minio-go' by Object Storage for AI.
-Minio Client SDK for Go
+MinIO Client SDK for Go
* HOMEPAGE:
* https://github.com/minio/minio-go
@@ -2497,18 +2608,18 @@ Minio Client SDK for Go
* This package includes the following NOTICE:
minio-go
-Copyright 2015-2017 Minio, Inc.
+Copyright 2015-2017 MinIO, Inc.
---
## nicksnyder/go-i18n
-This product contains 'go-i18n' by Nick Snyder.
+This product contains 'go-i18n' by Mattermost, modified (forked) from original GitHub repo 'nicksnyder/go-i18n' owned by Nick Snyder.
Translate your Go program into multiple languages.
* HOMEPAGE:
- * https://github.com/nicksnyder/go-i18n
+ * https://github.com/mattermost/go-i18n
* LICENSE: MIT
@@ -2947,6 +3058,41 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
---
+## sirupsen/logrus
+
+This product contains 'logrus' by Simon Eskildsen.
+
+Structured, pluggable logging for Go.
+
+* HOMEPAGE:
+ * https://github.com/sirupsen/logrus
+
+* LICENSE: MIT
+
+The MIT License (MIT)
+
+Copyright (c) 2014 Simon Eskildsen
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+---
+
## spf13/cobra
This product contains 'cobra' by Steve Francia.
@@ -3135,6 +3281,42 @@ A Commander for modern Go CLI interactions
---
+## jmoiron/sqlx
+
+This product contains 'sqlx' by Jason Moiron.
+
+general purpose extensions to golang's database/sql
+
+* HOMEPAGE:
+ * https://github.com/jmoiron/sqlx
+
+* LICENSE: MIT
+
+ Copyright (c) 2013, Jason Moiron
+
+ Permission is hereby granted, free of charge, to any person
+ obtaining a copy of this software and associated documentation
+ files (the "Software"), to deal in the Software without
+ restriction, including without limitation the rights to use,
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following
+ conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ OTHER DEALINGS IN THE SOFTWARE.
+
+---
+
## stretchr/testify
This product contains 'testify' by Stretchr, Inc..
@@ -3146,28 +3328,27 @@ A toolkit with common assertions and mocks that plays nicely with the standard l
* LICENSE: MIT
-Copyright (c) 2012 - 2013 Mat Ryer and Tyler Bunnell
+MIT License
-Please consider promoting this project if you find it useful.
+Copyright (c) 2012-2018 Mat Ryer and Tyler Bunnell
-Permission is hereby granted, free of charge, to any person
-obtaining a copy of this software and associated documentation
-files (the "Software"), to deal in the Software without restriction,
-including without limitation the rights to use, copy, modify, merge,
-publish, distribute, sublicense, and/or sell copies of the Software,
-and to permit persons to whom the Software is furnished to do so,
-subject to the following conditions:
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
-The above copyright notice and this permission notice shall be included
-in all copies or substantial portions of the Software.
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
-DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
-OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
-OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
---
@@ -3388,14 +3569,55 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---
-## go-gomail/gomail
+## x/text
+
+This product contains 'text' by The Go Authors.
+
+[mirror] Go text processing support
+
+* HOMEPAGE:
+ * https://github.com/golang/text
+
+* LICENSE: BSD-3-Clause
+
+Copyright (c) 2009 The Go Authors. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+ * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+---
+
+## mail
-This product contains 'gomail' by Gomail.
+This product contains 'mail' by GitHub user "go-mail", modified (forked) from original GitHub repo 'go-gomail/gomail' owned by Gomail.
-The best way to send emails in Go.
+Actively maintained fork of gomail. The best way to send emails in Go.
* HOMEPAGE:
- * https://github.com/go-gomail/gomail
+ * https://github.com/go-mail/mail
* LICENSE: MIT
@@ -3719,3 +3941,194 @@ 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.
+
+---
+
+## go/imageproxy
+
+This product contains 'imageproxy' by Will Norris.
+
+A caching, resizing image proxy written in Go
+
+* HOMEPAGE:
+ * https://github.com/willnorris/imageproxy
+
+* LICENSE: Apache-2.0
+
+
+ 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
diff --git a/vendor/github.com/mattermost/mattermost-server/mlog/default.go b/vendor/github.com/mattermost/mattermost-server/v5/mlog/default.go
index 366d22f8..f356eec7 100644
--- a/vendor/github.com/mattermost/mattermost-server/mlog/default.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/mlog/default.go
@@ -1,14 +1,15 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// See LICENSE.txt for license information.
package mlog
import (
"encoding/json"
"fmt"
+ "os"
)
-// defaultLog manually encodes the log to STDOUT, providing a basic, default logging implementation
+// defaultLog manually encodes the log to STDERR, providing a basic, default logging implementation
// before mlog is fully configured.
func defaultLog(level, msg string, fields ...Field) {
log := struct {
@@ -22,9 +23,9 @@ func defaultLog(level, msg string, fields ...Field) {
}
if b, err := json.Marshal(log); err != nil {
- fmt.Printf(`{"level":"error","msg":"failed to encode log message"}%s`, "\n")
+ fmt.Fprintf(os.Stderr, `{"level":"error","msg":"failed to encode log message"}%s`, "\n")
} else {
- fmt.Printf("%s\n", b)
+ fmt.Fprintf(os.Stderr, "%s\n", b)
}
}
diff --git a/vendor/github.com/mattermost/mattermost-server/mlog/global.go b/vendor/github.com/mattermost/mattermost-server/v5/mlog/global.go
index ba90ace2..73f40b2f 100644
--- a/vendor/github.com/mattermost/mattermost-server/mlog/global.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/mlog/global.go
@@ -1,5 +1,5 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// See LICENSE.txt for license information.
package mlog
diff --git a/vendor/github.com/mattermost/mattermost-server/mlog/log.go b/vendor/github.com/mattermost/mattermost-server/v5/mlog/log.go
index e3bc38d8..1a6c2de9 100644
--- a/vendor/github.com/mattermost/mattermost-server/mlog/log.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/mlog/log.go
@@ -1,5 +1,5 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// See LICENSE.txt for license information.
package mlog
@@ -28,12 +28,15 @@ const (
type Field = zapcore.Field
var Int64 = zap.Int64
+var Int32 = zap.Int32
var Int = zap.Int
var Uint32 = zap.Uint32
var String = zap.String
var Any = zap.Any
var Err = zap.Error
+var NamedErr = zap.NamedError
var Bool = zap.Bool
+var Duration = zap.Duration
type LoggerConfiguration struct {
EnableConsole bool
@@ -84,7 +87,7 @@ func NewLogger(config *LoggerConfiguration) *Logger {
}
if config.EnableConsole {
- writer := zapcore.Lock(os.Stdout)
+ writer := zapcore.Lock(os.Stderr)
core := zapcore.NewCore(makeEncoder(config.ConsoleJson), writer, logger.consoleLevel)
cores = append(cores, core)
}
@@ -102,7 +105,6 @@ func NewLogger(config *LoggerConfiguration) *Logger {
combinedCore := zapcore.NewTee(cores...)
logger.zap = zap.New(combinedCore,
- zap.AddCallerSkip(1),
zap.AddCaller(),
)
@@ -128,6 +130,11 @@ func (l *Logger) StdLog(fields ...Field) *log.Logger {
return zap.NewStdLog(l.With(fields...).zap.WithOptions(getStdLogOption()))
}
+// StdLogAt returns *log.Logger which writes to supplied zap logger at required level.
+func (l *Logger) StdLogAt(level string, fields ...Field) (*log.Logger, error) {
+ return zap.NewStdLogAt(l.With(fields...).zap.WithOptions(getStdLogOption()), getZapLevel(level))
+}
+
// StdLogWriter returns a writer that can be hooked up to the output of a golang standard logger
// anything written will be interpreted as log entries accordingly
func (l *Logger) StdLogWriter() io.Writer {
diff --git a/vendor/github.com/mattermost/mattermost-server/mlog/stdlog.go b/vendor/github.com/mattermost/mattermost-server/v5/mlog/stdlog.go
index 7839ddfa..fd702abf 100644
--- a/vendor/github.com/mattermost/mattermost-server/mlog/stdlog.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/mlog/stdlog.go
@@ -1,5 +1,5 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// See LICENSE.txt for license information.
package mlog
@@ -81,7 +81,7 @@ type loggerWriter struct {
func (l *loggerWriter) Write(p []byte) (int, error) {
trimmed := string(bytes.TrimSpace(p))
for _, line := range strings.Split(trimmed, "\n") {
- l.logFunc(string(line))
+ l.logFunc(line)
}
return len(p), nil
}
diff --git a/vendor/github.com/mattermost/mattermost-server/mlog/sugar.go b/vendor/github.com/mattermost/mattermost-server/v5/mlog/sugar.go
index c00a8bbf..c00a8bbf 100644
--- a/vendor/github.com/mattermost/mattermost-server/mlog/sugar.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/mlog/sugar.go
diff --git a/vendor/github.com/mattermost/mattermost-server/v5/mlog/testing.go b/vendor/github.com/mattermost/mattermost-server/v5/mlog/testing.go
new file mode 100644
index 00000000..bf1bcedf
--- /dev/null
+++ b/vendor/github.com/mattermost/mattermost-server/v5/mlog/testing.go
@@ -0,0 +1,43 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
+
+package mlog
+
+import (
+ "io"
+ "strings"
+ "testing"
+
+ "go.uber.org/zap"
+ "go.uber.org/zap/zapcore"
+)
+
+// testingWriter is an io.Writer that writes through t.Log
+type testingWriter struct {
+ tb testing.TB
+}
+
+func (tw *testingWriter) Write(b []byte) (int, error) {
+ tw.tb.Log(strings.TrimSpace(string(b)))
+ return len(b), nil
+}
+
+// NewTestingLogger creates a Logger that proxies logs through a testing interface.
+// This allows tests that spin up App instances to avoid spewing logs unless the test fails or -verbose is specified.
+func NewTestingLogger(tb testing.TB, writer io.Writer) *Logger {
+ logWriter := &testingWriter{tb}
+ multiWriter := io.MultiWriter(logWriter, writer)
+ logWriterSync := zapcore.AddSync(multiWriter)
+
+ testingLogger := &Logger{
+ consoleLevel: zap.NewAtomicLevelAt(getZapLevel("debug")),
+ fileLevel: zap.NewAtomicLevelAt(getZapLevel("info")),
+ }
+
+ logWriterCore := zapcore.NewCore(makeEncoder(true), logWriterSync, testingLogger.consoleLevel)
+
+ testingLogger.zap = zap.New(logWriterCore,
+ zap.AddCaller(),
+ )
+ return testingLogger
+}
diff --git a/vendor/github.com/mattermost/mattermost-server/model/access.go b/vendor/github.com/mattermost/mattermost-server/v5/model/access.go
index e9603c78..bbac3601 100644
--- a/vendor/github.com/mattermost/mattermost-server/model/access.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/access.go
@@ -1,5 +1,5 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// See LICENSE.txt for license information.
package model
@@ -60,13 +60,13 @@ func (ad *AccessData) IsValid() *AppError {
return nil
}
-func (me *AccessData) IsExpired() bool {
+func (ad *AccessData) IsExpired() bool {
- if me.ExpiresAt <= 0 {
+ if ad.ExpiresAt <= 0 {
return false
}
- if GetMillis() > me.ExpiresAt {
+ if GetMillis() > ad.ExpiresAt {
return true
}
diff --git a/vendor/github.com/mattermost/mattermost-server/model/analytics_row.go b/vendor/github.com/mattermost/mattermost-server/v5/model/analytics_row.go
index 4615bb79..1180ad22 100644
--- a/vendor/github.com/mattermost/mattermost-server/model/analytics_row.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/analytics_row.go
@@ -1,5 +1,5 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// See LICENSE.txt for license information.
package model
diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/at_mentions.go b/vendor/github.com/mattermost/mattermost-server/v5/model/at_mentions.go
new file mode 100644
index 00000000..f41d182a
--- /dev/null
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/at_mentions.go
@@ -0,0 +1,47 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
+
+package model
+
+import (
+ "regexp"
+ "strings"
+)
+
+var atMentionRegexp = regexp.MustCompile(`\B@[[:alnum:]][[:alnum:]\.\-_]*`)
+
+const usernameSpecialChars = ".-_"
+
+// PossibleAtMentions returns all substrings in message that look like valid @
+// mentions.
+func PossibleAtMentions(message string) []string {
+ var names []string
+
+ if !strings.Contains(message, "@") {
+ return names
+ }
+
+ alreadyMentioned := make(map[string]bool)
+ for _, match := range atMentionRegexp.FindAllString(message, -1) {
+ name := NormalizeUsername(match[1:])
+ if !alreadyMentioned[name] && IsValidUsername(name) {
+ names = append(names, name)
+ alreadyMentioned[name] = true
+ }
+ }
+
+ return names
+}
+
+// TrimUsernameSpecialChar tries to remove the last character from word if it
+// is a special character for usernames (dot, dash or underscore). If not, it
+// returns the same string.
+func TrimUsernameSpecialChar(word string) (string, bool) {
+ len := len(word)
+
+ if len > 0 && strings.LastIndexAny(word, usernameSpecialChars) == (len-1) {
+ return word[:len-1], true
+ }
+
+ return word, false
+}
diff --git a/vendor/github.com/mattermost/mattermost-server/model/audit.go b/vendor/github.com/mattermost/mattermost-server/v5/model/audit.go
index e3d1bdf9..dd1e0602 100644
--- a/vendor/github.com/mattermost/mattermost-server/model/audit.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/audit.go
@@ -1,5 +1,5 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// See LICENSE.txt for license information.
package model
diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/auditconv.go b/vendor/github.com/mattermost/mattermost-server/v5/model/auditconv.go
new file mode 100644
index 00000000..50af2880
--- /dev/null
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/auditconv.go
@@ -0,0 +1,667 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
+
+package model
+
+import "github.com/francoispqt/gojay"
+
+// AuditModelTypeConv converts key model types to something better suited for audit output.
+func AuditModelTypeConv(val interface{}) (newVal interface{}, converted bool) {
+ if val == nil {
+ return nil, false
+ }
+ switch v := val.(type) {
+ case *Channel:
+ return newAuditChannel(v), true
+ case *Team:
+ return newAuditTeam(v), true
+ case *User:
+ return newAuditUser(v), true
+ case *Command:
+ return newAuditCommand(v), true
+ case *CommandArgs:
+ return newAuditCommandArgs(v), true
+ case *Bot:
+ return newAuditBot(v), true
+ case *ChannelModerationPatch:
+ return newAuditChannelModerationPatch(v), true
+ case *Emoji:
+ return newAuditEmoji(v), true
+ case *FileInfo:
+ return newAuditFileInfo(v), true
+ case *Group:
+ return newAuditGroup(v), true
+ case *Job:
+ return newAuditJob(v), true
+ case *OAuthApp:
+ return newAuditOAuthApp(v), true
+ case *Post:
+ return newAuditPost(v), true
+ case *Role:
+ return newAuditRole(v), true
+ case *Scheme:
+ return newAuditScheme(v), true
+ case *SchemeRoles:
+ return newAuditSchemeRoles(v), true
+ case *Session:
+ return newAuditSession(v), true
+ case *IncomingWebhook:
+ return newAuditIncomingWebhook(v), true
+ case *OutgoingWebhook:
+ return newAuditOutgoingWebhook(v), true
+ }
+ return val, false
+}
+
+type auditChannel struct {
+ ID string
+ Name string
+ Type string
+}
+
+// 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", 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
+}
+
+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
+ cmdargs.Command = ca.Command
+ }
+ 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
+}
diff --git a/vendor/github.com/mattermost/mattermost-server/model/audits.go b/vendor/github.com/mattermost/mattermost-server/v5/model/audits.go
index 3673eb61..a8f01e1b 100644
--- a/vendor/github.com/mattermost/mattermost-server/model/audits.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/audits.go
@@ -1,5 +1,5 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// See LICENSE.txt for license information.
package model
diff --git a/vendor/github.com/mattermost/mattermost-server/model/authorize.go b/vendor/github.com/mattermost/mattermost-server/v5/model/authorize.go
index 922adc07..0191a670 100644
--- a/vendor/github.com/mattermost/mattermost-server/model/authorize.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/authorize.go
@@ -1,5 +1,5 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// See LICENSE.txt for license information.
package model
@@ -39,11 +39,11 @@ type AuthorizeRequest struct {
// correctly.
func (ad *AuthData) IsValid() *AppError {
- if len(ad.ClientId) != 26 {
+ if !IsValidId(ad.ClientId) {
return NewAppError("AuthData.IsValid", "model.authorize.is_valid.client_id.app_error", nil, "", http.StatusBadRequest)
}
- if len(ad.UserId) != 26 {
+ if !IsValidId(ad.UserId) {
return NewAppError("AuthData.IsValid", "model.authorize.is_valid.user_id.app_error", nil, "", http.StatusBadRequest)
}
@@ -78,7 +78,7 @@ func (ad *AuthData) IsValid() *AppError {
// correctly.
func (ar *AuthorizeRequest) IsValid() *AppError {
- if len(ar.ClientId) != 26 {
+ if !IsValidId(ar.ClientId) {
return NewAppError("AuthData.IsValid", "model.authorize.is_valid.client_id.app_error", nil, "", http.StatusBadRequest)
}
diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/bot.go b/vendor/github.com/mattermost/mattermost-server/v5/model/bot.go
new file mode 100644
index 00000000..15ef6a70
--- /dev/null
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/bot.go
@@ -0,0 +1,233 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
+
+package model
+
+import (
+ "encoding/json"
+ "fmt"
+ "io"
+ "net/http"
+ "strings"
+ "unicode/utf8"
+)
+
+const (
+ BOT_DISPLAY_NAME_MAX_RUNES = USER_FIRST_NAME_MAX_RUNES
+ BOT_DESCRIPTION_MAX_RUNES = 1024
+ BOT_CREATOR_ID_MAX_RUNES = KEY_VALUE_PLUGIN_ID_MAX_RUNES // UserId or PluginId
+)
+
+// 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"`
+}
+
+// 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"`
+}
+
+// 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]interface{} {
+ return map[string]interface{}{"user_id": b.UserId}
+}
+
+// Clone returns a shallow copy of the bot.
+func (b *Bot) Clone() *Bot {
+ copy := *b
+ return &copy
+}
+
+// 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 !IsValidUsername(b.Username) {
+ return NewAppError("Bot.IsValid", "model.bot.is_valid.username.app_error", b.Trace(), "", http.StatusBadRequest)
+ }
+
+ if utf8.RuneCountInString(b.DisplayName) > BOT_DISPLAY_NAME_MAX_RUNES {
+ return NewAppError("Bot.IsValid", "model.bot.is_valid.user_id.app_error", b.Trace(), "", http.StatusBadRequest)
+ }
+
+ if utf8.RuneCountInString(b.Description) > BOT_DESCRIPTION_MAX_RUNES {
+ return NewAppError("Bot.IsValid", "model.bot.is_valid.description.app_error", b.Trace(), "", http.StatusBadRequest)
+ }
+
+ if len(b.OwnerId) == 0 || utf8.RuneCountInString(b.OwnerId) > BOT_CREATOR_ID_MAX_RUNES {
+ return NewAppError("Bot.IsValid", "model.bot.is_valid.creator_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 nil
+}
+
+// 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)
+}
+
+// ToJson serializes the bot to json.
+func (b *Bot) ToJson() []byte {
+ data, _ := json.Marshal(b)
+ return data
+}
+
+// BotFromJson deserializes a bot from json.
+func BotFromJson(data io.Reader) *Bot {
+ var bot *Bot
+ json.NewDecoder(data).Decode(&bot)
+ return bot
+}
+
+// Patch modifies an existing bot with optional fields from the given patch.
+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
+ }
+}
+
+// ToJson serializes the bot patch to json.
+func (b *BotPatch) ToJson() []byte {
+ data, err := json.Marshal(b)
+ if err != nil {
+ return nil
+ }
+
+ return data
+}
+
+// BotPatchFromJson deserializes a bot patch from json.
+func BotPatchFromJson(data io.Reader) *BotPatch {
+ decoder := json.NewDecoder(data)
+ var botPatch BotPatch
+ err := decoder.Decode(&botPatch)
+ if err != nil {
+ return nil
+ }
+
+ return &botPatch
+}
+
+// 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: SYSTEM_USER_ROLE_ID,
+ }
+}
+
+// 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(SHOW_USERNAME),
+ }
+}
+
+// BotListFromJson deserializes a list of bots from json.
+func BotListFromJson(data io.Reader) BotList {
+ var bots BotList
+ json.NewDecoder(data).Decode(&bots)
+ return bots
+}
+
+// ToJson serializes a list of bots to json.
+func (l *BotList) ToJson() []byte {
+ b, _ := json.Marshal(l)
+ return b
+}
+
+// Etag computes the etag for a list of bots.
+func (l *BotList) Etag() string {
+ id := "0"
+ var t int64 = 0
+ var delta int64 = 0
+
+ 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(userId string) *AppError {
+ return NewAppError("SqlBotStore.Get", "store.sql_bot.get.missing.app_error", map[string]interface{}{"user_id": userId}, "", http.StatusNotFound)
+}
+
+func IsBotDMChannel(channel *Channel, botUserID string) bool {
+ if channel.Type != CHANNEL_DIRECT {
+ return false
+ }
+
+ if !strings.HasPrefix(channel.Name, botUserID+"__") && !strings.HasSuffix(channel.Name, "__"+botUserID) {
+ return false
+ }
+
+ return true
+}
diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/bot_default_image.go b/vendor/github.com/mattermost/mattermost-server/v5/model/bot_default_image.go
new file mode 100644
index 00000000..d9cdd2e2
--- /dev/null
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/bot_default_image.go
@@ -0,0 +1,288 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
+
+package model
+
+var BotDefaultImage = []byte{
+ 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d,
+ 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x7e,
+ 0x08, 0x06, 0x00, 0x00, 0x00, 0xec, 0xa6, 0x19, 0xa2, 0x00, 0x00, 0x00,
+ 0x04, 0x67, 0x41, 0x4d, 0x41, 0x00, 0x00, 0xb1, 0x8f, 0x0b, 0xfc, 0x61,
+ 0x05, 0x00, 0x00, 0x0c, 0xe3, 0x49, 0x44, 0x41, 0x54, 0x78, 0x01, 0xed,
+ 0x5d, 0x5b, 0x88, 0x15, 0xc9, 0x19, 0xae, 0xf1, 0xba, 0x5e, 0xc6, 0x4b,
+ 0xbc, 0xa0, 0x46, 0xd7, 0x2b, 0xce, 0x2a, 0xba, 0xca, 0x8a, 0xa3, 0x82,
+ 0x38, 0xa3, 0x46, 0x47, 0x5d, 0x59, 0xa3, 0x2f, 0x9b, 0x28, 0x6e, 0xc2,
+ 0xea, 0x83, 0x22, 0x04, 0x82, 0x78, 0x41, 0xf2, 0xb2, 0x04, 0xd4, 0x07,
+ 0x49, 0x22, 0xc4, 0x07, 0xcd, 0x53, 0x30, 0x26, 0x1a, 0xa2, 0x08, 0xee,
+ 0xaa, 0xa8, 0x71, 0xb2, 0x41, 0x11, 0xbc, 0xdf, 0xd0, 0x8d, 0x6e, 0x24,
+ 0x82, 0xe3, 0x65, 0x32, 0x9b, 0x19, 0x1d, 0x47, 0xd7, 0xeb, 0xc9, 0xf7,
+ 0xb5, 0xa7, 0x0f, 0xe7, 0x9c, 0xe9, 0x3e, 0xdd, 0xe7, 0x4c, 0x57, 0x77,
+ 0x75, 0x75, 0xfd, 0xf0, 0x9f, 0xee, 0xae, 0xaa, 0xae, 0xfa, 0xff, 0xef,
+ 0xfb, 0x4f, 0x9d, 0xee, 0xaa, 0xea, 0x3e, 0x65, 0x42, 0x4f, 0xe9, 0x0b,
+ 0xb7, 0x46, 0x43, 0x2b, 0xd2, 0xdb, 0x91, 0xd8, 0xf6, 0x84, 0x96, 0x67,
+ 0x69, 0xf7, 0xf4, 0x3e, 0x36, 0xa2, 0x19, 0xfa, 0x34, 0xbd, 0xe5, 0x3e,
+ 0xf5, 0x31, 0xf4, 0xdf, 0xd0, 0x5b, 0xd0, 0x7f, 0xa5, 0xb7, 0x0d, 0xd8,
+ 0x6a, 0x25, 0x65, 0x1a, 0x78, 0xd3, 0x1b, 0x3e, 0x54, 0x41, 0x67, 0x42,
+ 0x2b, 0xa1, 0x24, 0x9d, 0x69, 0x32, 0xa4, 0x11, 0x95, 0x32, 0x18, 0xce,
+ 0x42, 0x6b, 0xa1, 0x5f, 0x43, 0x99, 0x16, 0x5b, 0x89, 0x63, 0x00, 0x74,
+ 0x03, 0xda, 0xb3, 0xa0, 0x24, 0xbc, 0x1a, 0x3a, 0x01, 0xda, 0x0e, 0x1a,
+ 0x85, 0xbc, 0x45, 0xa3, 0x57, 0xa0, 0xff, 0x80, 0x32, 0x20, 0x4e, 0x42,
+ 0x5b, 0xa0, 0x46, 0x02, 0x46, 0xa0, 0x3d, 0xea, 0xab, 0x81, 0xee, 0x86,
+ 0xb2, 0xab, 0x4e, 0x29, 0xaa, 0xb4, 0x8d, 0x36, 0xd2, 0x56, 0xda, 0x6c,
+ 0xa4, 0x8d, 0x08, 0x7c, 0x84, 0xf3, 0x7f, 0x03, 0x7d, 0x00, 0x55, 0x95,
+ 0x74, 0x37, 0xbb, 0x68, 0x33, 0x6d, 0xa7, 0x0f, 0x46, 0x8a, 0x44, 0xe0,
+ 0x63, 0x94, 0x3f, 0x0d, 0x75, 0x03, 0x37, 0x6e, 0xe9, 0xf4, 0x85, 0x3e,
+ 0x19, 0x29, 0x80, 0x00, 0xbb, 0xcc, 0x9f, 0x40, 0xf9, 0x9b, 0x1a, 0x37,
+ 0x82, 0xfd, 0xda, 0x4b, 0xdf, 0xe8, 0xa3, 0xf9, 0x79, 0x00, 0x08, 0xb6,
+ 0xf0, 0x02, 0xee, 0x73, 0xe8, 0xb7, 0x50, 0xbf, 0x40, 0xc6, 0xbd, 0x1c,
+ 0x7d, 0xa5, 0xcf, 0x51, 0x5d, 0xbc, 0xa2, 0x69, 0x35, 0x84, 0xb7, 0x6d,
+ 0xe7, 0xa0, 0x71, 0x27, 0xb4, 0x54, 0xfb, 0xe9, 0x3b, 0x31, 0x48, 0x9c,
+ 0x70, 0xa0, 0x66, 0x17, 0x94, 0xb7, 0x51, 0xa5, 0x82, 0xa7, 0xcb, 0x79,
+ 0xc4, 0x80, 0x58, 0x10, 0x13, 0xed, 0x85, 0xe3, 0x0e, 0xab, 0xa0, 0xdf,
+ 0x41, 0x75, 0x21, 0x30, 0x28, 0x3f, 0x88, 0x09, 0xb1, 0x89, 0xe3, 0xd8,
+ 0x0c, 0xcc, 0xf6, 0x16, 0x46, 0xf8, 0x57, 0xd0, 0xa0, 0x00, 0xd3, 0xb5,
+ 0x1e, 0x62, 0xa4, 0x5d, 0x6f, 0x50, 0x0d, 0xa7, 0xea, 0x0c, 0xf9, 0xbe,
+ 0x83, 0x9f, 0x58, 0x11, 0xb3, 0xd8, 0x0b, 0x6f, 0x77, 0xbe, 0x80, 0xbe,
+ 0x81, 0xea, 0xfa, 0x8d, 0x95, 0xe5, 0x17, 0x31, 0x23, 0x76, 0xb1, 0xbd,
+ 0x65, 0xe4, 0x84, 0x4c, 0xad, 0x21, 0xbe, 0xcd, 0x81, 0x4f, 0x0c, 0x89,
+ 0x65, 0xac, 0xe4, 0x7d, 0x58, 0x7b, 0x03, 0x2a, 0xeb, 0xdb, 0x91, 0xb4,
+ 0x7a, 0x89, 0x25, 0x31, 0x8d, 0x85, 0x8c, 0x87, 0x95, 0xf7, 0xa0, 0x49,
+ 0x23, 0x49, 0xb6, 0xbf, 0xc4, 0x94, 0xd8, 0x2a, 0x2d, 0xd5, 0xb0, 0xae,
+ 0x09, 0x2a, 0x1b, 0x8c, 0xa4, 0xd6, 0x4f, 0x6c, 0x89, 0xb1, 0x92, 0xf2,
+ 0x09, 0xac, 0xfa, 0x1e, 0x9a, 0x54, 0x72, 0xc2, 0xf2, 0x9b, 0x18, 0x13,
+ 0x6b, 0xa5, 0xa4, 0x1a, 0xd6, 0x18, 0xf2, 0xc3, 0x0b, 0x7e, 0x62, 0x4d,
+ 0xcc, 0x95, 0x90, 0x49, 0xb0, 0xe2, 0x09, 0x34, 0xac, 0x6f, 0x80, 0x69,
+ 0xe7, 0x1d, 0xd6, 0xc4, 0x9c, 0xd8, 0x47, 0x2a, 0x5c, 0x78, 0x59, 0x0f,
+ 0x35, 0xa4, 0x44, 0x83, 0x01, 0xb1, 0x27, 0x07, 0x91, 0xc8, 0x60, 0xb4,
+ 0x7a, 0x17, 0x6a, 0xc8, 0x8f, 0x16, 0x03, 0x72, 0x40, 0x2e, 0x42, 0x95,
+ 0x4e, 0x68, 0x2d, 0xc9, 0xd3, 0xb8, 0xaa, 0x05, 0x3d, 0xb9, 0x20, 0x27,
+ 0x45, 0x4b, 0xa9, 0xc3, 0x8c, 0xdb, 0xd1, 0xd2, 0x8f, 0x8b, 0x6e, 0xcd,
+ 0x9c, 0x20, 0x0b, 0x81, 0x41, 0xa8, 0xf8, 0x07, 0xd0, 0xc3, 0xb2, 0x1a,
+ 0xc8, 0xae, 0xf7, 0x53, 0x1c, 0xa8, 0xf6, 0x0d, 0x30, 0xf6, 0xbc, 0xe3,
+ 0x84, 0xdc, 0x48, 0x15, 0x5e, 0x70, 0x98, 0x2b, 0x7e, 0x75, 0xbf, 0x00,
+ 0xe4, 0xa6, 0xa8, 0x8b, 0xc2, 0x62, 0xd6, 0xa4, 0xbd, 0x87, 0xca, 0xff,
+ 0x06, 0x2d, 0x87, 0x1a, 0x51, 0x13, 0x01, 0x72, 0x43, 0x8e, 0xc8, 0x95,
+ 0x2f, 0x29, 0x26, 0x00, 0x7e, 0x85, 0x1a, 0x95, 0x1f, 0x8b, 0xf6, 0xe3,
+ 0xf5, 0x80, 0x01, 0x03, 0xc4, 0xee, 0xdd, 0xbb, 0x45, 0x5d, 0x5d, 0x9d,
+ 0xa5, 0xdc, 0x67, 0x9a, 0x26, 0x42, 0x8e, 0xc8, 0x55, 0xa0, 0xf2, 0x01,
+ 0x6a, 0x7b, 0x01, 0x8d, 0xfd, 0x6f, 0x6d, 0xbf, 0x7e, 0xfd, 0x52, 0x0f,
+ 0x1f, 0x3e, 0x4c, 0xe5, 0x0b, 0xd3, 0x98, 0xa7, 0x83, 0x8f, 0x69, 0xae,
+ 0xc8, 0x59, 0x60, 0x52, 0x8b, 0x9a, 0xb4, 0x00, 0x67, 0xd7, 0xae, 0x5d,
+ 0xf9, 0xdc, 0x67, 0x8e, 0x99, 0xa7, 0x8b, 0x9f, 0xf0, 0x83, 0x9c, 0x05,
+ 0x22, 0x9f, 0xa1, 0x16, 0x6d, 0x80, 0xb9, 0x7d, 0xfb, 0x76, 0x86, 0xf0,
+ 0xfc, 0x1d, 0xe6, 0xe9, 0xe4, 0x2b, 0x7c, 0x21, 0x77, 0x05, 0xa5, 0xac,
+ 0x60, 0xee, 0xbb, 0x95, 0x28, 0x7c, 0x1c, 0xba, 0x9f, 0x47, 0xb9, 0xd8,
+ 0x64, 0xbf, 0x78, 0xf1, 0x42, 0x74, 0xea, 0xe4, 0x3c, 0x66, 0xf2, 0xf2,
+ 0xe5, 0x4b, 0xd1, 0xb9, 0x73, 0xe7, 0xd8, 0xf8, 0xe2, 0xc3, 0xd0, 0xff,
+ 0xa2, 0x4c, 0x05, 0xd4, 0xf5, 0x11, 0x76, 0xaf, 0x8b, 0xc0, 0x8d, 0x38,
+ 0x59, 0x1b, 0xf2, 0x7d, 0x00, 0xa6, 0x5b, 0x11, 0x72, 0x47, 0x0e, 0x5d,
+ 0xa5, 0x50, 0x0f, 0xc0, 0x91, 0x25, 0x8e, 0x33, 0xf3, 0x4d, 0x1a, 0xda,
+ 0x48, 0xc2, 0x7a, 0x00, 0xf2, 0xf6, 0x14, 0x3a, 0x14, 0xfa, 0x3f, 0x1e,
+ 0xe4, 0x4b, 0xa1, 0x1e, 0xe0, 0x97, 0x28, 0xac, 0x15, 0xf9, 0xf9, 0xce,
+ 0x27, 0xe4, 0x98, 0x1c, 0x92, 0x4b, 0x47, 0x71, 0xeb, 0x01, 0x7a, 0xa1,
+ 0xf4, 0x7f, 0xa0, 0x3d, 0x1d, 0xcf, 0x8a, 0x71, 0x62, 0x02, 0x7b, 0x00,
+ 0xb2, 0xf5, 0x18, 0x3a, 0x0c, 0xca, 0x25, 0x65, 0x39, 0xe2, 0xd6, 0x03,
+ 0xfc, 0x02, 0xa5, 0xb4, 0x23, 0x3f, 0xc7, 0xf3, 0x64, 0x1d, 0x90, 0x4b,
+ 0x72, 0xda, 0x4a, 0x9c, 0x7a, 0x80, 0x2e, 0x28, 0xc5, 0x15, 0xa8, 0xbc,
+ 0x06, 0xd0, 0x4e, 0x12, 0xda, 0x03, 0x90, 0x47, 0x5e, 0x03, 0x70, 0xdd,
+ 0xc0, 0x73, 0x1e, 0xd8, 0xe2, 0xd4, 0x03, 0x70, 0x9a, 0x57, 0x4b, 0xf2,
+ 0x6d, 0xa7, 0x13, 0xba, 0x25, 0xa7, 0xad, 0xa6, 0xf0, 0x3b, 0x38, 0x80,
+ 0xf1, 0x73, 0x87, 0xb4, 0xc8, 0x93, 0x78, 0x7f, 0x3e, 0x67, 0xce, 0x1c,
+ 0x31, 0x7d, 0xfa, 0x74, 0x31, 0x68, 0xd0, 0x20, 0xd1, 0xbb, 0x77, 0xef,
+ 0x92, 0x6c, 0xea, 0xd8, 0xb1, 0xa3, 0xeb, 0x79, 0xcc, 0x3b, 0x74, 0xe8,
+ 0x90, 0x6b, 0x7e, 0xa1, 0x8c, 0xc6, 0xc6, 0x46, 0x6b, 0x5e, 0xe1, 0xf4,
+ 0xe9, 0xd3, 0xe2, 0xf8, 0xf1, 0xe3, 0x82, 0x3d, 0x8d, 0x82, 0xf2, 0x33,
+ 0xd8, 0xf4, 0x97, 0x42, 0x76, 0xfd, 0x10, 0x99, 0x4a, 0x3d, 0xc7, 0xd7,
+ 0xa5, 0x4b, 0x97, 0xd4, 0xa6, 0x4d, 0x9b, 0x52, 0x4d, 0x4d, 0x4d, 0xf9,
+ 0x03, 0x77, 0xca, 0x1e, 0xd3, 0x56, 0xda, 0x4c, 0xdb, 0x81, 0xa7, 0x4a,
+ 0x4a, 0x6e, 0xc9, 0xb1, 0xab, 0x6c, 0x40, 0x8e, 0x32, 0x06, 0x8f, 0x18,
+ 0x31, 0x22, 0x75, 0xe3, 0xc6, 0x0d, 0x65, 0x89, 0xf6, 0x32, 0x8c, 0xb6,
+ 0xd3, 0x07, 0x95, 0x30, 0x85, 0x2d, 0xe4, 0xd8, 0x55, 0x94, 0x79, 0x9e,
+ 0x6f, 0xd4, 0xa8, 0x51, 0xa9, 0xfa, 0xfa, 0x7a, 0x2f, 0x8c, 0x95, 0xcf,
+ 0xa7, 0x0f, 0xf4, 0x05, 0x88, 0xab, 0xa2, 0xe4, 0xd8, 0x51, 0x3e, 0x44,
+ 0xaa, 0x12, 0x46, 0x76, 0xed, 0xda, 0x35, 0x75, 0xed, 0xda, 0x35, 0xe5,
+ 0xc9, 0xf5, 0x6b, 0x20, 0x7d, 0xa1, 0x4f, 0xaa, 0xe0, 0x0b, 0x3b, 0xc8,
+ 0xb5, 0x25, 0xd9, 0x77, 0x01, 0x3f, 0xb2, 0x13, 0xa3, 0xde, 0xae, 0x5d,
+ 0xbb, 0x56, 0x8c, 0x1b, 0x37, 0x2e, 0x6a, 0x33, 0x02, 0x6b, 0x9f, 0xbe,
+ 0xd0, 0x27, 0x85, 0xc4, 0x91, 0x6b, 0xbe, 0x9a, 0x24, 0xf2, 0x28, 0x2d,
+ 0x2f, 0x2f, 0x8f, 0xd5, 0x05, 0x9f, 0xdf, 0x5e, 0x80, 0x17, 0x86, 0xf4,
+ 0x4d, 0x05, 0x8c, 0x61, 0xc3, 0x97, 0x76, 0x30, 0xda, 0x3d, 0x00, 0x6f,
+ 0x07, 0x67, 0xd8, 0x89, 0x51, 0x6e, 0x6b, 0x6a, 0x6a, 0x44, 0xcf, 0x9e,
+ 0xfa, 0x0d, 0x42, 0xd2, 0x27, 0xfa, 0xa6, 0x88, 0x54, 0xc1, 0x0e, 0x6b,
+ 0x08, 0xc0, 0x0e, 0x80, 0x4a, 0x24, 0x28, 0x31, 0xf1, 0x33, 0x77, 0xee,
+ 0x5c, 0x45, 0x30, 0x0a, 0xde, 0x0c, 0x85, 0x7c, 0x23, 0xd7, 0xe4, 0x3c,
+ 0xf3, 0xa6, 0xca, 0xd9, 0xc1, 0xbb, 0x5b, 0x5a, 0x8d, 0x43, 0x87, 0x0e,
+ 0x2d, 0xed, 0xc4, 0x18, 0x9c, 0xa5, 0x98, 0x6f, 0x16, 0xe7, 0x76, 0x0f,
+ 0x30, 0x5d, 0x15, 0xfc, 0xfa, 0xf7, 0xef, 0xaf, 0x8a, 0x29, 0x81, 0xdb,
+ 0xa1, 0x98, 0x6f, 0x16, 0xe7, 0x76, 0x00, 0x8c, 0x09, 0xdc, 0xdb, 0x12,
+ 0x2b, 0xec, 0xd0, 0xc1, 0xfa, 0x69, 0x2a, 0xf1, 0x6c, 0xb5, 0x4f, 0x53,
+ 0xcc, 0x37, 0x8b, 0x73, 0x06, 0x40, 0x37, 0x28, 0x67, 0x89, 0x8c, 0x24,
+ 0x0b, 0x01, 0x72, 0xde, 0x8d, 0x01, 0xc0, 0x45, 0x83, 0x4e, 0xd3, 0xc2,
+ 0xc9, 0x82, 0x23, 0x79, 0xde, 0x92, 0xf3, 0x0a, 0x3b, 0x00, 0x92, 0xe7,
+ 0xbe, 0xf1, 0x98, 0x08, 0x58, 0x01, 0x10, 0xe8, 0x13, 0x24, 0x51, 0xe0,
+ 0x7a, 0xe2, 0xc4, 0x09, 0xb1, 0x62, 0xc5, 0x0a, 0x31, 0x71, 0xe2, 0x44,
+ 0x31, 0x73, 0xe6, 0x4c, 0xb1, 0x7e, 0xfd, 0x7a, 0x71, 0xff, 0xfe, 0xfd,
+ 0xc0, 0x4c, 0x39, 0x7b, 0xf6, 0xac, 0x58, 0xb9, 0x72, 0xa5, 0x98, 0x30,
+ 0x61, 0x82, 0x98, 0x3f, 0x7f, 0xbe, 0xd8, 0xb6, 0x6d, 0x9b, 0x78, 0xf5,
+ 0xea, 0x55, 0x60, 0xf5, 0x47, 0x58, 0x91, 0xc5, 0xfd, 0x9f, 0x61, 0x40,
+ 0x28, 0x23, 0x54, 0x3d, 0x7a, 0xf4, 0xb0, 0x66, 0xc7, 0x38, 0x43, 0x46,
+ 0x1d, 0x3c, 0x78, 0x70, 0xab, 0x76, 0x8b, 0x99, 0x03, 0x78, 0xfb, 0xf6,
+ 0x6d, 0x6a, 0xf5, 0xea, 0xd5, 0xad, 0xea, 0xa0, 0x3f, 0x58, 0x2f, 0x90,
+ 0x3a, 0x78, 0xf0, 0xa0, 0xdf, 0x81, 0x3a, 0xd7, 0x72, 0x3b, 0x76, 0xec,
+ 0x48, 0x61, 0x9d, 0x40, 0xab, 0x36, 0x2a, 0x2b, 0x2b, 0x8b, 0x9e, 0xac,
+ 0xa2, 0x6f, 0xf9, 0x58, 0x13, 0x03, 0x1b, 0x0f, 0x6e, 0x89, 0x51, 0x7e,
+ 0x19, 0x89, 0xc7, 0xe4, 0x5e, 0x1c, 0x91, 0xd8, 0x80, 0xe5, 0xcc, 0xe4,
+ 0xc9, 0x93, 0x53, 0x17, 0x2e, 0x5c, 0x48, 0x91, 0xb0, 0x6c, 0x71, 0x02,
+ 0xa4, 0x98, 0x00, 0xd8, 0xbe, 0x7d, 0x7b, 0x41, 0xb0, 0xba, 0x77, 0xef,
+ 0x9e, 0xba, 0x73, 0xe7, 0x4e, 0x76, 0x93, 0x45, 0xed, 0x5f, 0xb9, 0x72,
+ 0x25, 0x85, 0x2b, 0x77, 0xd7, 0x36, 0x96, 0x2d, 0x5b, 0x56, 0x54, 0x7d,
+ 0x7e, 0xfc, 0x25, 0x46, 0xc4, 0x8a, 0x98, 0xc9, 0xe6, 0x25, 0xcd, 0xbd,
+ 0x38, 0x25, 0xb3, 0xa1, 0xb1, 0x63, 0xc7, 0xa6, 0xb0, 0x3a, 0xc6, 0x11,
+ 0x28, 0x3f, 0x80, 0x38, 0x9e, 0x88, 0xc4, 0xe7, 0xcf, 0x9f, 0xfb, 0x9a,
+ 0x61, 0x5b, 0xba, 0x74, 0xa9, 0x5b, 0x15, 0x9e, 0xe9, 0x4b, 0x96, 0x2c,
+ 0xf1, 0x24, 0xe1, 0xe6, 0xcd, 0x9b, 0x9e, 0xf5, 0xd8, 0x05, 0x8a, 0xf1,
+ 0x97, 0x98, 0x11, 0x3b, 0x99, 0xdc, 0xa0, 0xee, 0x53, 0xbc, 0x08, 0xec,
+ 0x01, 0x95, 0x26, 0x5b, 0xb6, 0x6c, 0x71, 0x7d, 0x14, 0xab, 0x2d, 0x8d,
+ 0xe2, 0xdb, 0x29, 0x9e, 0x3d, 0x7b, 0xe6, 0x59, 0xc5, 0x99, 0x33, 0x67,
+ 0x3c, 0xcb, 0xb8, 0x15, 0x38, 0x77, 0x8e, 0xaf, 0xde, 0x29, 0x2c, 0xe7,
+ 0xcf, 0x9f, 0x2f, 0x5c, 0xa0, 0xc4, 0x5c, 0x3e, 0xbe, 0x46, 0xec, 0x24,
+ 0x4b, 0x0f, 0x06, 0x80, 0xd4, 0x17, 0x3e, 0x4c, 0x9d, 0x3a, 0x55, 0x8a,
+ 0x0f, 0x77, 0xef, 0xde, 0xf5, 0x55, 0xef, 0xbd, 0x7b, 0xf7, 0x04, 0xba,
+ 0x55, 0x5f, 0x65, 0xb3, 0x0b, 0xf1, 0x9c, 0x07, 0x0f, 0x1e, 0x64, 0x27,
+ 0x39, 0xee, 0xb3, 0x7e, 0x59, 0x22, 0x0b, 0xbb, 0x2c, 0x7b, 0xcb, 0xa5,
+ 0x07, 0x80, 0xac, 0xe1, 0xcf, 0xf1, 0xe3, 0xfd, 0xbd, 0xab, 0x02, 0xdd,
+ 0xa8, 0x68, 0xd7, 0x8e, 0x6e, 0x16, 0x27, 0x3c, 0x67, 0xf4, 0xe8, 0xd1,
+ 0x9e, 0x27, 0x8d, 0x19, 0x23, 0x6f, 0x10, 0x55, 0x16, 0x76, 0x59, 0x4e,
+ 0xc9, 0x0f, 0x80, 0xac, 0xc6, 0x02, 0xdd, 0xad, 0xa8, 0xa8, 0x10, 0xc3,
+ 0x87, 0x0f, 0xf7, 0xac, 0x73, 0xde, 0xbc, 0x79, 0x9e, 0x65, 0xdc, 0x0a,
+ 0xcc, 0x9a, 0x35, 0xcb, 0x2d, 0xcb, 0x4a, 0xc7, 0xa2, 0x4f, 0x11, 0xc2,
+ 0xb7, 0xb4, 0xa0, 0x0d, 0x6d, 0xcc, 0xb4, 0x7a, 0x7f, 0xa9, 0x6f, 0xfe,
+ 0xb0, 0x2f, 0x80, 0x9c, 0xb6, 0xc5, 0x5c, 0x14, 0x39, 0x9d, 0x7f, 0xf2,
+ 0xe4, 0xc9, 0x54, 0x59, 0x59, 0x99, 0xeb, 0x85, 0x12, 0xd7, 0xe2, 0xb5,
+ 0xb4, 0xb4, 0x38, 0x9d, 0xea, 0x2b, 0xad, 0xa1, 0xa1, 0x21, 0xd5, 0xb7,
+ 0x6f, 0x5f, 0xd7, 0xfa, 0x37, 0x6f, 0xde, 0xec, 0xab, 0x1e, 0xbb, 0x50,
+ 0x29, 0xfe, 0x82, 0x60, 0xd7, 0xf6, 0x03, 0xc8, 0x7b, 0xc1, 0xbe, 0xb1,
+ 0xb9, 0x8d, 0x51, 0x14, 0xd9, 0xe9, 0x1c, 0xf4, 0xd9, 0xbf, 0x7f, 0xbf,
+ 0xc0, 0xab, 0x5d, 0x5a, 0xd9, 0x30, 0x63, 0xc6, 0x0c, 0x71, 0xec, 0xd8,
+ 0x31, 0x81, 0xb5, 0x78, 0xad, 0xf2, 0xfc, 0x26, 0xf4, 0xe9, 0xd3, 0x47,
+ 0x1c, 0x3d, 0x7a, 0x54, 0x8c, 0x1c, 0x39, 0x32, 0xe7, 0x14, 0x04, 0x9d,
+ 0xd8, 0xb0, 0x61, 0x83, 0x58, 0xb7, 0x6e, 0x5d, 0x4e, 0x7a, 0x0c, 0x0f,
+ 0x9a, 0x39, 0xf5, 0xc6, 0x00, 0xe8, 0x13, 0x43, 0xe3, 0x2d, 0x93, 0x17,
+ 0x2f, 0x5e, 0x2c, 0xaa, 0xaa, 0xaa, 0xac, 0x87, 0x31, 0x2e, 0x5e, 0xbc,
+ 0x28, 0x7a, 0xf5, 0xea, 0x25, 0x70, 0x0f, 0x2d, 0x66, 0xcf, 0x9e, 0x2d,
+ 0x48, 0x54, 0x5b, 0x65, 0xd2, 0xa4, 0x49, 0xe2, 0xd2, 0xa5, 0x4b, 0xe2,
+ 0xc8, 0x91, 0x23, 0x82, 0x57, 0xfc, 0x03, 0x07, 0x0e, 0x14, 0xfc, 0x69,
+ 0xe0, 0xa8, 0xa0, 0x06, 0x62, 0x7d, 0xf9, 0xaf, 0xc2, 0x11, 0x69, 0xdd,
+ 0x8c, 0xdd, 0xfd, 0x39, 0x6d, 0x4b, 0xe9, 0x12, 0x9d, 0xea, 0x89, 0x4b,
+ 0x5a, 0x29, 0xfe, 0xca, 0xe4, 0x06, 0x75, 0x5f, 0xe5, 0x4f, 0xc0, 0x13,
+ 0xa8, 0x91, 0x64, 0x22, 0xf0, 0x24, 0xd6, 0xd7, 0x00, 0xc9, 0xe4, 0x2c,
+ 0x50, 0xaf, 0x9b, 0x19, 0x00, 0x8d, 0x81, 0x56, 0x69, 0x2a, 0x8b, 0x13,
+ 0x02, 0x8d, 0x0c, 0x80, 0xdb, 0x71, 0xb2, 0xd8, 0xd8, 0x1a, 0x28, 0x02,
+ 0xb7, 0x19, 0x00, 0xdf, 0x04, 0x5a, 0xa5, 0xa9, 0x2c, 0x4e, 0x08, 0x7c,
+ 0xc3, 0x00, 0xe0, 0x7b, 0x00, 0x8d, 0x24, 0x13, 0x81, 0x4c, 0x00, 0xf0,
+ 0x36, 0xd0, 0x48, 0xb2, 0x10, 0x20, 0xe7, 0xb7, 0xd8, 0x03, 0xb4, 0x40,
+ 0xe5, 0x4d, 0x69, 0x25, 0x0b, 0xd4, 0x38, 0x79, 0x4b, 0xce, 0x5b, 0x18,
+ 0x00, 0x94, 0x9b, 0xef, 0x36, 0xe6, 0x33, 0x41, 0x08, 0x58, 0x9c, 0x73,
+ 0x28, 0x98, 0x72, 0x0a, 0x3a, 0xd7, 0xda, 0x8b, 0xd9, 0xc7, 0x9b, 0x37,
+ 0x6f, 0x04, 0x46, 0x02, 0x5d, 0xad, 0xce, 0x7f, 0x18, 0x83, 0xf3, 0xfc,
+ 0x85, 0xd6, 0x07, 0xb4, 0x6f, 0xdf, 0x3e, 0x67, 0x08, 0xf9, 0xf5, 0xeb,
+ 0xd7, 0xae, 0x75, 0x73, 0xa8, 0x99, 0xe5, 0x63, 0x2a, 0xe4, 0x3c, 0xf3,
+ 0x6c, 0xe0, 0xdf, 0x65, 0x39, 0xd1, 0xdc, 0x2c, 0x77, 0xae, 0x69, 0xf9,
+ 0xf2, 0xe5, 0x82, 0x2f, 0x77, 0x72, 0xd3, 0xeb, 0xd7, 0xaf, 0xe7, 0xb8,
+ 0xb6, 0x75, 0xeb, 0x56, 0xd7, 0xb2, 0xac, 0x63, 0xdf, 0xbe, 0x7d, 0x99,
+ 0xf2, 0x3c, 0xd7, 0xad, 0x5e, 0xa6, 0xb3, 0x6d, 0x99, 0x22, 0x19, 0x3b,
+ 0x8b, 0x73, 0xfb, 0x27, 0xe0, 0x2c, 0x1c, 0x91, 0xc2, 0xd4, 0xe5, 0xcb,
+ 0x97, 0x65, 0x62, 0xa4, 0x75, 0xdd, 0x12, 0xb1, 0x23, 0xd7, 0xe4, 0x3c,
+ 0xd3, 0x03, 0xb0, 0x9f, 0xfb, 0x27, 0x13, 0x82, 0x16, 0xcc, 0x99, 0x07,
+ 0x5d, 0xa5, 0xd4, 0xfa, 0x0a, 0xfd, 0x9c, 0x48, 0x6d, 0xd8, 0xa1, 0x72,
+ 0x89, 0xd8, 0x91, 0x6b, 0xeb, 0xb7, 0xcd, 0xee, 0x01, 0xd8, 0xbc, 0x94,
+ 0x9f, 0x01, 0xce, 0xa7, 0xaf, 0x5a, 0xb5, 0xca, 0xd7, 0x02, 0x4e, 0x07,
+ 0x0c, 0x42, 0x4f, 0x0a, 0x62, 0x0a, 0xb9, 0xad, 0x46, 0x73, 0xb1, 0x2b,
+ 0x31, 0x23, 0x76, 0x92, 0x24, 0xc3, 0xb5, 0x7d, 0x11, 0xc8, 0x76, 0x32,
+ 0x89, 0x41, 0x37, 0xba, 0x73, 0xe7, 0x4e, 0xb1, 0x77, 0xef, 0x5e, 0x6b,
+ 0x9e, 0x3e, 0x7b, 0x9d, 0xdb, 0xe3, 0xc7, 0x7c, 0x87, 0x71, 0xdb, 0x64,
+ 0xcd, 0x9a, 0x35, 0x62, 0xe1, 0xc2, 0x85, 0xae, 0x95, 0x0c, 0x19, 0x32,
+ 0x24, 0x27, 0x6f, 0xd1, 0xa2, 0x45, 0x62, 0xd8, 0xb0, 0x61, 0x39, 0x69,
+ 0xd9, 0x07, 0xd3, 0xa6, 0x4d, 0xcb, 0x1c, 0xf2, 0xdc, 0x3d, 0x7b, 0xf6,
+ 0x64, 0x8e, 0xf3, 0x77, 0x82, 0x78, 0xde, 0x7f, 0xe3, 0xc6, 0x8d, 0x39,
+ 0x6f, 0x44, 0xc1, 0x5b, 0xc5, 0x04, 0x57, 0x23, 0x07, 0x81, 0x4d, 0xbe,
+ 0xbd, 0x59, 0xc7, 0xae, 0x5c, 0xdf, 0x40, 0x21, 0x69, 0x6b, 0x03, 0xfc,
+ 0xd4, 0xcd, 0x39, 0x73, 0x5d, 0xc5, 0x69, 0x3d, 0x80, 0x1f, 0x4c, 0x02,
+ 0x2e, 0x43, 0x8e, 0x33, 0x92, 0xfd, 0x13, 0xc0, 0xc4, 0x3f, 0x66, 0x72,
+ 0xcc, 0x8e, 0xae, 0x08, 0xe4, 0x70, 0x9c, 0x1f, 0x00, 0x7f, 0x82, 0xd7,
+ 0xc5, 0x2f, 0xa2, 0xd7, 0x15, 0x2a, 0xfd, 0xfc, 0x22, 0xb7, 0xe4, 0x38,
+ 0x23, 0xf9, 0x01, 0x50, 0x87, 0x9c, 0xe3, 0x99, 0xdc, 0x08, 0x76, 0x0a,
+ 0x0d, 0xbc, 0x44, 0x60, 0x4e, 0xa0, 0x4d, 0x2a, 0xf0, 0x44, 0x31, 0xb9,
+ 0x25, 0xc7, 0x19, 0xc9, 0x0f, 0x00, 0x66, 0xe4, 0x74, 0x11, 0x99, 0x92,
+ 0x21, 0xed, 0xe0, 0x0f, 0x1c, 0x43, 0x6a, 0x29, 0xfc, 0x66, 0x1e, 0x3d,
+ 0x7a, 0x14, 0x7e, 0xa3, 0xb9, 0x2d, 0xb6, 0xe2, 0xd6, 0x29, 0x00, 0x0e,
+ 0xe2, 0x1c, 0xfe, 0xb9, 0x40, 0x24, 0x22, 0x71, 0xf0, 0x23, 0x12, 0x7f,
+ 0xb2, 0x1b, 0x8d, 0xd8, 0x37, 0x72, 0x4a, 0x6e, 0x73, 0xc4, 0x29, 0x00,
+ 0x9e, 0xa3, 0xc4, 0xef, 0x72, 0x4a, 0x85, 0x78, 0x70, 0xe0, 0xc0, 0x81,
+ 0x10, 0x5b, 0x0b, 0xb7, 0xa9, 0x88, 0x7d, 0x23, 0xa7, 0xe4, 0xd6, 0x97,
+ 0xf4, 0x42, 0xa9, 0x26, 0x68, 0x24, 0xb7, 0x84, 0x18, 0x00, 0xd1, 0xee,
+ 0x4e, 0x90, 0x3e, 0x45, 0x85, 0x67, 0x9a, 0x4b, 0x72, 0x5a, 0x94, 0xfc,
+ 0x1a, 0xa5, 0x23, 0x31, 0x1a, 0x03, 0x35, 0x29, 0x3e, 0x96, 0xa5, 0x8b,
+ 0xd0, 0x17, 0xfa, 0x14, 0x15, 0x9e, 0x68, 0x97, 0x5c, 0x16, 0x2d, 0xfc,
+ 0x8f, 0x19, 0x4e, 0x1a, 0x44, 0x62, 0xf8, 0x94, 0x29, 0x53, 0x8a, 0x7e,
+ 0x05, 0x8b, 0x8a, 0x01, 0xc3, 0xff, 0x0b, 0xa0, 0x2f, 0x51, 0xe1, 0x98,
+ 0xe6, 0x90, 0x5c, 0x96, 0x24, 0x5b, 0x71, 0x56, 0x64, 0xc6, 0x63, 0x28,
+ 0x36, 0x85, 0x21, 0xe4, 0x56, 0xaf, 0x96, 0x51, 0x91, 0xe8, 0x7c, 0x9b,
+ 0xb0, 0xe6, 0xc0, 0xb2, 0x9d, 0x3e, 0x44, 0x89, 0x21, 0xda, 0x26, 0x87,
+ 0xae, 0x52, 0xe6, 0x9a, 0xf3, 0x2e, 0x83, 0xff, 0xcc, 0xc4, 0x45, 0xa3,
+ 0xad, 0x9f, 0xbe, 0xf4, 0x38, 0x31, 0xc8, 0x6c, 0xbc, 0x48, 0x49, 0x2c,
+ 0x58, 0xb0, 0x40, 0xe0, 0x25, 0x4a, 0x25, 0xff, 0x59, 0x54, 0x90, 0xf6,
+ 0x14, 0xaa, 0x8b, 0x7f, 0x1e, 0x85, 0xf7, 0x12, 0x89, 0xc3, 0x87, 0x0f,
+ 0x0b, 0x99, 0x2f, 0x8f, 0x28, 0x64, 0x43, 0x56, 0x9e, 0xe7, 0x9f, 0x47,
+ 0x67, 0x95, 0x75, 0xdd, 0xfd, 0x0c, 0x39, 0x51, 0x47, 0xb1, 0x69, 0xbf,
+ 0x34, 0x0e, 0x96, 0xbb, 0xb2, 0x5a, 0x64, 0x46, 0xad, 0x09, 0x82, 0xd8,
+ 0x7d, 0x09, 0xc8, 0x99, 0xa7, 0x78, 0xfd, 0x04, 0xd8, 0x15, 0x7c, 0x80,
+ 0x9d, 0x2b, 0xd0, 0x4e, 0x76, 0x82, 0xd9, 0x2a, 0x8d, 0xc0, 0x4b, 0x58,
+ 0xc7, 0xe7, 0xd7, 0x3d, 0x1f, 0xfa, 0xf1, 0xbb, 0xa2, 0xb1, 0x01, 0x95,
+ 0xbd, 0x07, 0x9d, 0x01, 0x35, 0xa2, 0x3e, 0x02, 0xbc, 0xf0, 0xfb, 0x6b,
+ 0xd0, 0x66, 0x32, 0x00, 0xa4, 0xbe, 0x4b, 0x00, 0xf5, 0x9b, 0xdf, 0xfa,
+ 0xb6, 0x63, 0x40, 0x8e, 0xc8, 0x95, 0x14, 0xe1, 0x6b, 0xb3, 0x9e, 0x40,
+ 0x0d, 0x51, 0x6a, 0x62, 0x40, 0x6e, 0xc8, 0x91, 0x54, 0xf9, 0x14, 0xb5,
+ 0x9b, 0x00, 0x50, 0x13, 0x03, 0x72, 0x13, 0x8a, 0xfc, 0x1e, 0xad, 0x98,
+ 0x20, 0x50, 0x0b, 0x03, 0x72, 0x12, 0x9a, 0xf0, 0x6e, 0x80, 0xef, 0x51,
+ 0x35, 0x41, 0xa0, 0x06, 0x06, 0xe4, 0x22, 0xf4, 0x3b, 0x34, 0xfe, 0xe5,
+ 0xc8, 0x5d, 0x13, 0x04, 0x91, 0x7f, 0x09, 0xc8, 0x01, 0xb9, 0x88, 0x44,
+ 0x78, 0xc1, 0x51, 0x0f, 0x35, 0x3d, 0x41, 0x34, 0x18, 0x10, 0x7b, 0xe9,
+ 0x17, 0x7d, 0x5e, 0x91, 0x35, 0x09, 0x05, 0xcc, 0x9d, 0x41, 0xf8, 0x01,
+ 0x40, 0xcc, 0x89, 0xbd, 0x12, 0x52, 0x0d, 0x2b, 0xbe, 0x87, 0x9a, 0x9e,
+ 0x20, 0x1c, 0x0c, 0x88, 0x35, 0x31, 0x57, 0x4a, 0x3e, 0x81, 0x35, 0x26,
+ 0x08, 0xe4, 0x07, 0x00, 0x31, 0x26, 0xd6, 0x4a, 0x4a, 0x35, 0xac, 0x8a,
+ 0x6c, 0x29, 0x19, 0xda, 0xd6, 0xbd, 0x07, 0x22, 0xb6, 0xc4, 0x58, 0x69,
+ 0xe1, 0x8b, 0xfc, 0xef, 0x41, 0x75, 0x27, 0x23, 0x6c, 0xff, 0x88, 0xa9,
+ 0xbf, 0x3f, 0x49, 0x50, 0x20, 0x3c, 0xde, 0x87, 0x0d, 0x91, 0x3f, 0x67,
+ 0xa8, 0x51, 0x10, 0x12, 0x4b, 0x62, 0x1a, 0x2b, 0xe1, 0x6a, 0xa2, 0x5a,
+ 0x68, 0xd8, 0xdf, 0x14, 0xdd, 0xda, 0x23, 0x86, 0xc4, 0x32, 0x96, 0xc2,
+ 0xe9, 0xe6, 0x2f, 0xa0, 0x6f, 0xa0, 0xba, 0x11, 0x23, 0xdb, 0x1f, 0x62,
+ 0x46, 0xec, 0xfc, 0x4e, 0xd9, 0xa3, 0xa8, 0xba, 0x52, 0x0d, 0xd3, 0xf8,
+ 0x4c, 0x9a, 0x6c, 0xd0, 0x74, 0xa9, 0x9f, 0x58, 0x11, 0x33, 0xad, 0xa4,
+ 0x2f, 0xbc, 0xf9, 0x0a, 0xaa, 0x0b, 0x49, 0xb2, 0xfc, 0x20, 0x46, 0xc4,
+ 0x4a, 0x4b, 0x29, 0x83, 0x57, 0xab, 0xa0, 0xdf, 0x41, 0x65, 0x01, 0x18,
+ 0xd7, 0x7a, 0x89, 0x09, 0xb1, 0x21, 0x46, 0xda, 0x0b, 0x23, 0xfc, 0x0f,
+ 0xd0, 0xb7, 0xd0, 0xb8, 0x12, 0x16, 0x94, 0xdd, 0xc4, 0x80, 0x58, 0x68,
+ 0xfb, 0xad, 0x87, 0x6f, 0xae, 0x52, 0x89, 0x9c, 0x24, 0x4f, 0x2b, 0xd3,
+ 0x77, 0x62, 0x90, 0x68, 0xe1, 0x13, 0xca, 0x9f, 0x43, 0xbf, 0x85, 0x06,
+ 0xf5, 0xad, 0x52, 0xbd, 0x1e, 0xfa, 0x4a, 0x9f, 0xe9, 0xbb, 0x91, 0x34,
+ 0x02, 0xbc, 0xdd, 0xf9, 0x29, 0x94, 0xcb, 0xcf, 0x55, 0x27, 0xb0, 0x54,
+ 0xfb, 0xe8, 0x1b, 0x7d, 0xd4, 0xe2, 0xd6, 0x0e, 0x7e, 0x48, 0x93, 0x8f,
+ 0x51, 0xf3, 0x69, 0x68, 0xa9, 0x40, 0xab, 0x76, 0x1e, 0x7d, 0xa1, 0x4f,
+ 0x46, 0x8a, 0x44, 0xe0, 0x23, 0x94, 0xff, 0x2d, 0x94, 0xff, 0xe2, 0xac,
+ 0x1a, 0xa9, 0x5e, 0xf6, 0xd0, 0x66, 0xda, 0x4e, 0x1f, 0x8c, 0xb4, 0x11,
+ 0x01, 0x76, 0x99, 0x35, 0xd0, 0xdd, 0xd0, 0xa7, 0x50, 0x2f, 0xf0, 0xa3,
+ 0xca, 0xa7, 0x6d, 0xb4, 0x91, 0xb6, 0xc6, 0xa2, 0x9b, 0x8f, 0xe3, 0x3d,
+ 0x67, 0x37, 0x80, 0x3b, 0x0b, 0x3a, 0x33, 0xad, 0x1f, 0x62, 0x1b, 0xd5,
+ 0xc5, 0x14, 0x6f, 0xe1, 0xae, 0x42, 0x6b, 0xd3, 0x7a, 0x12, 0x5b, 0xfe,
+ 0x01, 0x47, 0x6c, 0x24, 0x8e, 0x01, 0x90, 0x0f, 0x2e, 0x27, 0x4a, 0xaa,
+ 0xa0, 0x0c, 0x08, 0xde, 0x52, 0x55, 0x40, 0x65, 0x4d, 0x9e, 0xf0, 0x2f,
+ 0xf6, 0xf8, 0xb8, 0x3c, 0xdf, 0xb4, 0x4d, 0xd2, 0xbf, 0x86, 0x32, 0x2d,
+ 0xb6, 0xa2, 0x43, 0x00, 0x38, 0x81, 0xcf, 0x41, 0x15, 0x06, 0x02, 0x17,
+ 0x4c, 0x72, 0x3b, 0x02, 0xca, 0x77, 0xe4, 0x74, 0x87, 0x96, 0xa7, 0xd5,
+ 0xde, 0xc7, 0xa1, 0xf5, 0x26, 0x14, 0x76, 0xdf, 0x7c, 0x23, 0x0a, 0x95,
+ 0xfb, 0x5c, 0x7c, 0x71, 0x07, 0x4a, 0xc2, 0x6f, 0xa5, 0xb7, 0x7c, 0x46,
+ 0x52, 0x2b, 0xf9, 0x3f, 0x92, 0xc9, 0x00, 0xb6, 0x61, 0xee, 0xab, 0xc9,
+ 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82,
+}
diff --git a/vendor/github.com/mattermost/mattermost-server/model/builtin.go b/vendor/github.com/mattermost/mattermost-server/v5/model/builtin.go
index 5dd00a96..38e01f8b 100644
--- a/vendor/github.com/mattermost/mattermost-server/model/builtin.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/builtin.go
@@ -1,5 +1,5 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// See LICENSE.txt for license information.
package model
diff --git a/vendor/github.com/mattermost/mattermost-server/model/bundle_info.go b/vendor/github.com/mattermost/mattermost-server/v5/model/bundle_info.go
index 7cb06701..429e1c3d 100644
--- a/vendor/github.com/mattermost/mattermost-server/model/bundle_info.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/bundle_info.go
@@ -1,9 +1,9 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// See LICENSE.txt for license information.
package model
-import "github.com/mattermost/mattermost-server/mlog"
+import "github.com/mattermost/mattermost-server/v5/mlog"
type BundleInfo struct {
Path string
diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/channel.go b/vendor/github.com/mattermost/mattermost-server/v5/model/channel.go
new file mode 100644
index 00000000..6a84b355
--- /dev/null
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/channel.go
@@ -0,0 +1,364 @@
+// 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"
+ "sort"
+ "strings"
+ "unicode/utf8"
+)
+
+const (
+ CHANNEL_OPEN = "O"
+ CHANNEL_PRIVATE = "P"
+ CHANNEL_DIRECT = "D"
+ CHANNEL_GROUP = "G"
+ CHANNEL_GROUP_MAX_USERS = 8
+ CHANNEL_GROUP_MIN_USERS = 3
+ DEFAULT_CHANNEL = "town-square"
+ CHANNEL_DISPLAY_NAME_MAX_RUNES = 64
+ CHANNEL_NAME_MIN_LENGTH = 2
+ CHANNEL_NAME_MAX_LENGTH = 64
+ CHANNEL_HEADER_MAX_RUNES = 1024
+ CHANNEL_PURPOSE_MAX_RUNES = 250
+ CHANNEL_CACHE_SIZE = 25000
+
+ CHANNEL_SORT_BY_USERNAME = "username"
+ CHANNEL_SORT_BY_STATUS = "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 string `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]interface{} `json:"props" db:"-"`
+ GroupConstrained *bool `json:"group_constrained"`
+}
+
+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"`
+}
+
+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"`
+}
+
+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.
+// 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
+ ExcludeChannelNames []string
+ Page *int
+ PerPage *int
+}
+
+type ChannelMemberCountByGroup struct {
+ GroupId string `db:"-" json:"group_id"`
+ ChannelMemberCount int64 `db:"-" json:"channel_member_count"`
+ ChannelMemberTimezonesCount int64 `db:"-" json:"channel_member_timezones_count"`
+}
+
+func (o *Channel) DeepCopy() *Channel {
+ copy := *o
+ if copy.SchemeId != nil {
+ copy.SchemeId = NewString(*o.SchemeId)
+ }
+ return &copy
+}
+
+func (o *Channel) ToJson() string {
+ b, _ := json.Marshal(o)
+ return string(b)
+}
+
+func (o *ChannelPatch) ToJson() string {
+ b, _ := json.Marshal(o)
+ return string(b)
+}
+
+func (o *ChannelsWithCount) ToJson() []byte {
+ b, _ := json.Marshal(o)
+ return b
+}
+
+func ChannelsWithCountFromJson(data io.Reader) *ChannelsWithCount {
+ var o *ChannelsWithCount
+ json.NewDecoder(data).Decode(&o)
+ return o
+}
+
+func ChannelFromJson(data io.Reader) *Channel {
+ var o *Channel
+ json.NewDecoder(data).Decode(&o)
+ return o
+}
+
+func ChannelPatchFromJson(data io.Reader) *ChannelPatch {
+ var o *ChannelPatch
+ json.NewDecoder(data).Decode(&o)
+ return o
+}
+
+func ChannelModerationsFromJson(data io.Reader) []*ChannelModeration {
+ var o []*ChannelModeration
+ json.NewDecoder(data).Decode(&o)
+ return o
+}
+
+func ChannelModerationsPatchFromJson(data io.Reader) []*ChannelModerationPatch {
+ var o []*ChannelModerationPatch
+ json.NewDecoder(data).Decode(&o)
+ return o
+}
+
+func ChannelMemberCountsByGroupFromJson(data io.Reader) []*ChannelMemberCountByGroup {
+ var o []*ChannelMemberCountByGroup
+ json.NewDecoder(data).Decode(&o)
+ return o
+}
+
+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) > CHANNEL_DISPLAY_NAME_MAX_RUNES {
+ 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.2_or_more.app_error", nil, "id="+o.Id, http.StatusBadRequest)
+ }
+
+ if !(o.Type == CHANNEL_OPEN || o.Type == CHANNEL_PRIVATE || o.Type == CHANNEL_DIRECT || o.Type == CHANNEL_GROUP) {
+ return NewAppError("Channel.IsValid", "model.channel.is_valid.type.app_error", nil, "id="+o.Id, http.StatusBadRequest)
+ }
+
+ if utf8.RuneCountInString(o.Header) > CHANNEL_HEADER_MAX_RUNES {
+ return NewAppError("Channel.IsValid", "model.channel.is_valid.header.app_error", nil, "id="+o.Id, http.StatusBadRequest)
+ }
+
+ if utf8.RuneCountInString(o.Purpose) > CHANNEL_PURPOSE_MAX_RUNES {
+ 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)
+ }
+
+ userIds := strings.Split(o.Name, "__")
+ if o.Type != CHANNEL_DIRECT && 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)
+
+ 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 == CHANNEL_DIRECT || o.Type == CHANNEL_GROUP
+}
+
+func (o *Channel) IsOpen() bool {
+ return o.Type == CHANNEL_OPEN
+}
+
+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]interface{})
+ }
+}
+
+func (o *Channel) AddProp(key string, value interface{}) {
+ o.MakeNonNil()
+
+ o.Props[key] = value
+}
+
+func (o *Channel) IsGroupConstrained() bool {
+ return o.GroupConstrained != nil && *o.GroupConstrained
+}
+
+func (o *Channel) GetOtherUserIdForDM(userId string) string {
+ if o.Type != CHANNEL_DIRECT {
+ return ""
+ }
+
+ userIds := strings.Split(o.Name, "__")
+
+ var otherUserId string
+
+ if userIds[0] != userIds[1] {
+ if userIds[0] == userId {
+ otherUserId = userIds[1]
+ } else {
+ otherUserId = userIds[0]
+ }
+ }
+
+ return otherUserId
+}
+
+func GetDMNameFromIds(userId1, userId2 string) string {
+ if userId1 > userId2 {
+ return userId2 + "__" + userId1
+ } else {
+ 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) > CHANNEL_NAME_MAX_LENGTH {
+ name = name[:CHANNEL_NAME_MAX_LENGTH]
+ }
+
+ 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))
+}
diff --git a/vendor/github.com/mattermost/mattermost-server/model/channel_count.go b/vendor/github.com/mattermost/mattermost-server/v5/model/channel_count.go
index 8c6d8dd0..11ddeec4 100644
--- a/vendor/github.com/mattermost/mattermost-server/model/channel_count.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/channel_count.go
@@ -1,5 +1,5 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// See LICENSE.txt for license information.
package model
diff --git a/vendor/github.com/mattermost/mattermost-server/model/channel_data.go b/vendor/github.com/mattermost/mattermost-server/v5/model/channel_data.go
index aae0a149..0a1e0d57 100644
--- a/vendor/github.com/mattermost/mattermost-server/model/channel_data.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/channel_data.go
@@ -1,5 +1,5 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// See LICENSE.txt for license information.
package model
diff --git a/vendor/github.com/mattermost/mattermost-server/model/channel_list.go b/vendor/github.com/mattermost/mattermost-server/v5/model/channel_list.go
index 1b3bda46..b47077ae 100644
--- a/vendor/github.com/mattermost/mattermost-server/model/channel_list.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/channel_list.go
@@ -1,5 +1,5 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// See LICENSE.txt for license information.
package model
@@ -51,3 +51,45 @@ func ChannelSliceFromJson(data io.Reader) []*Channel {
json.NewDecoder(data).Decode(&o)
return o
}
+
+type ChannelListWithTeamData []*ChannelWithTeamData
+
+func (o *ChannelListWithTeamData) ToJson() string {
+ if b, err := json.Marshal(o); err != nil {
+ return "[]"
+ } else {
+ return string(b)
+ }
+}
+
+func (o *ChannelListWithTeamData) Etag() string {
+
+ id := "0"
+ var t int64 = 0
+ var delta int64 = 0
+
+ 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))
+}
+
+func ChannelListWithTeamDataFromJson(data io.Reader) *ChannelListWithTeamData {
+ var o *ChannelListWithTeamData
+ json.NewDecoder(data).Decode(&o)
+ return o
+}
diff --git a/vendor/github.com/mattermost/mattermost-server/model/channel_member.go b/vendor/github.com/mattermost/mattermost-server/v5/model/channel_member.go
index 941db62f..e38bfffe 100644
--- a/vendor/github.com/mattermost/mattermost-server/model/channel_member.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/channel_member.go
@@ -1,5 +1,5 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// See LICENSE.txt for license information.
package model
@@ -11,12 +11,16 @@ import (
)
const (
- CHANNEL_NOTIFY_DEFAULT = "default"
- CHANNEL_NOTIFY_ALL = "all"
- CHANNEL_NOTIFY_MENTION = "mention"
- CHANNEL_NOTIFY_NONE = "none"
- CHANNEL_MARK_UNREAD_ALL = "all"
- CHANNEL_MARK_UNREAD_MENTION = "mention"
+ CHANNEL_NOTIFY_DEFAULT = "default"
+ CHANNEL_NOTIFY_ALL = "all"
+ CHANNEL_NOTIFY_MENTION = "mention"
+ CHANNEL_NOTIFY_NONE = "none"
+ CHANNEL_MARK_UNREAD_ALL = "all"
+ CHANNEL_MARK_UNREAD_MENTION = "mention"
+ IGNORE_CHANNEL_MENTIONS_DEFAULT = "default"
+ IGNORE_CHANNEL_MENTIONS_OFF = "off"
+ IGNORE_CHANNEL_MENTIONS_ON = "on"
+ IGNORE_CHANNEL_MENTIONS_NOTIFY_PROP = "ignore_channel_mentions"
)
type ChannelUnread struct {
@@ -27,6 +31,16 @@ type ChannelUnread struct {
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"`
+ LastViewedAt int64 `json:"last_viewed_at"`
+ NotifyProps StringMap `json:"-"`
+}
+
type ChannelMember struct {
ChannelId string `json:"channel_id"`
UserId string `json:"user_id"`
@@ -36,6 +50,7 @@ type ChannelMember struct {
MentionCount int64 `json:"mention_count"`
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"`
@@ -46,6 +61,7 @@ type ChannelMembers []ChannelMember
type ChannelMemberForExport struct {
ChannelMember
ChannelName string
+ Username string
}
func (o *ChannelMembers) ToJson() string {
@@ -61,6 +77,11 @@ func (o *ChannelUnread) ToJson() string {
return string(b)
}
+func (o *ChannelUnreadAt) ToJson() string {
+ b, _ := json.Marshal(o)
+ return string(b)
+}
+
func ChannelMembersFromJson(data io.Reader) *ChannelMembers {
var o *ChannelMembers
json.NewDecoder(data).Decode(&o)
@@ -73,6 +94,12 @@ func ChannelUnreadFromJson(data io.Reader) *ChannelUnread {
return o
}
+func ChannelUnreadAtFromJson(data io.Reader) *ChannelUnreadAt {
+ var o *ChannelUnreadAt
+ json.NewDecoder(data).Decode(&o)
+ return o
+}
+
func (o *ChannelMember) ToJson() string {
b, _ := json.Marshal(o)
return string(b)
@@ -86,11 +113,11 @@ func ChannelMemberFromJson(data io.Reader) *ChannelMember {
func (o *ChannelMember) IsValid() *AppError {
- if len(o.ChannelId) != 26 {
+ if !IsValidId(o.ChannelId) {
return NewAppError("ChannelMember.IsValid", "model.channel_member.is_valid.channel_id.app_error", nil, "", http.StatusBadRequest)
}
- if len(o.UserId) != 26 {
+ if !IsValidId(o.UserId) {
return NewAppError("ChannelMember.IsValid", "model.channel_member.is_valid.user_id.app_error", nil, "", http.StatusBadRequest)
}
@@ -116,6 +143,12 @@ func (o *ChannelMember) IsValid() *AppError {
}
}
+ if ignoreChannelMentions, ok := o.NotifyProps[IGNORE_CHANNEL_MENTIONS_NOTIFY_PROP]; 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)
+ }
+ }
+
return nil
}
@@ -146,11 +179,16 @@ func IsSendEmailValid(sendEmail string) bool {
return sendEmail == CHANNEL_NOTIFY_DEFAULT || sendEmail == "true" || sendEmail == "false"
}
+func IsIgnoreChannelMentionsValid(ignoreChannelMentions string) bool {
+ return ignoreChannelMentions == IGNORE_CHANNEL_MENTIONS_ON || ignoreChannelMentions == IGNORE_CHANNEL_MENTIONS_OFF || ignoreChannelMentions == IGNORE_CHANNEL_MENTIONS_DEFAULT
+}
+
func GetDefaultChannelNotifyProps() StringMap {
return StringMap{
- DESKTOP_NOTIFY_PROP: CHANNEL_NOTIFY_DEFAULT,
- MARK_UNREAD_NOTIFY_PROP: CHANNEL_MARK_UNREAD_ALL,
- PUSH_NOTIFY_PROP: CHANNEL_NOTIFY_DEFAULT,
- EMAIL_NOTIFY_PROP: CHANNEL_NOTIFY_DEFAULT,
+ DESKTOP_NOTIFY_PROP: CHANNEL_NOTIFY_DEFAULT,
+ MARK_UNREAD_NOTIFY_PROP: CHANNEL_MARK_UNREAD_ALL,
+ PUSH_NOTIFY_PROP: CHANNEL_NOTIFY_DEFAULT,
+ EMAIL_NOTIFY_PROP: CHANNEL_NOTIFY_DEFAULT,
+ IGNORE_CHANNEL_MENTIONS_NOTIFY_PROP: IGNORE_CHANNEL_MENTIONS_DEFAULT,
}
}
diff --git a/vendor/github.com/mattermost/mattermost-server/model/channel_member_history.go b/vendor/github.com/mattermost/mattermost-server/v5/model/channel_member_history.go
index 55435c32..b77e0ff9 100644
--- a/vendor/github.com/mattermost/mattermost-server/model/channel_member_history.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/channel_member_history.go
@@ -1,5 +1,5 @@
-// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
package model
diff --git a/vendor/github.com/mattermost/mattermost-server/model/channel_member_history_result.go b/vendor/github.com/mattermost/mattermost-server/v5/model/channel_member_history_result.go
index ed3e7963..6197d410 100644
--- a/vendor/github.com/mattermost/mattermost-server/model/channel_member_history_result.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/channel_member_history_result.go
@@ -1,5 +1,5 @@
-// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
package model
@@ -12,4 +12,5 @@ type ChannelMemberHistoryResult struct {
// 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
}
diff --git a/vendor/github.com/mattermost/mattermost-server/model/channel_mentions.go b/vendor/github.com/mattermost/mattermost-server/v5/model/channel_mentions.go
index 795ec379..eb14e8ed 100644
--- a/vendor/github.com/mattermost/mattermost-server/model/channel_mentions.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/channel_mentions.go
@@ -1,5 +1,5 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// See LICENSE.txt for license information.
package model
diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/channel_search.go b/vendor/github.com/mattermost/mattermost-server/v5/model/channel_search.go
new file mode 100644
index 00000000..2e994227
--- /dev/null
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/channel_search.go
@@ -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"
+)
+
+const CHANNEL_SEARCH_DEFAULT_LIMIT = 50
+
+type ChannelSearch struct {
+ Term string `json:"term"`
+ ExcludeDefaultChannels bool `json:"exclude_default_channels"`
+ NotAssociatedToGroup string `json:"not_associated_to_group"`
+ Page *int `json:"page,omitempty"`
+ PerPage *int `json:"per_page,omitempty"`
+}
+
+// ToJson convert a Channel to a json string
+func (c *ChannelSearch) ToJson() string {
+ b, _ := json.Marshal(c)
+ return string(b)
+}
+
+// ChannelSearchFromJson will decode the input and return a Channel
+func ChannelSearchFromJson(data io.Reader) *ChannelSearch {
+ var cs *ChannelSearch
+ json.NewDecoder(data).Decode(&cs)
+ return cs
+}
diff --git a/vendor/github.com/mattermost/mattermost-server/model/channel_stats.go b/vendor/github.com/mattermost/mattermost-server/v5/model/channel_stats.go
index 21af920f..76f682aa 100644
--- a/vendor/github.com/mattermost/mattermost-server/model/channel_stats.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/channel_stats.go
@@ -1,5 +1,5 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// See LICENSE.txt for license information.
package model
@@ -9,8 +9,10 @@ import (
)
type ChannelStats struct {
- ChannelId string `json:"channel_id"`
- MemberCount int64 `json:"member_count"`
+ ChannelId string `json:"channel_id"`
+ MemberCount int64 `json:"member_count"`
+ GuestCount int64 `json:"guest_count"`
+ PinnedPostCount int64 `json:"pinnedpost_count"`
}
func (o *ChannelStats) ToJson() string {
diff --git a/vendor/github.com/mattermost/mattermost-server/model/channel_view.go b/vendor/github.com/mattermost/mattermost-server/v5/model/channel_view.go
index 650d14ce..42fcac3a 100644
--- a/vendor/github.com/mattermost/mattermost-server/model/channel_view.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/channel_view.go
@@ -1,5 +1,5 @@
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
package model
diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/client4.go b/vendor/github.com/mattermost/mattermost-server/v5/model/client4.go
new file mode 100644
index 00000000..b522ecb8
--- /dev/null
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/client4.go
@@ -0,0 +1,5095 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
+
+package model
+
+import (
+ "bytes"
+ "encoding/json"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "mime/multipart"
+ "net/http"
+ "net/url"
+ "strconv"
+ "strings"
+ "time"
+)
+
+const (
+ HEADER_REQUEST_ID = "X-Request-ID"
+ HEADER_VERSION_ID = "X-Version-ID"
+ HEADER_CLUSTER_ID = "X-Cluster-ID"
+ HEADER_ETAG_SERVER = "ETag"
+ HEADER_ETAG_CLIENT = "If-None-Match"
+ HEADER_FORWARDED = "X-Forwarded-For"
+ HEADER_REAL_IP = "X-Real-IP"
+ HEADER_FORWARDED_PROTO = "X-Forwarded-Proto"
+ HEADER_TOKEN = "token"
+ HEADER_CSRF_TOKEN = "X-CSRF-Token"
+ HEADER_BEARER = "BEARER"
+ HEADER_AUTH = "Authorization"
+ HEADER_REQUESTED_WITH = "X-Requested-With"
+ HEADER_REQUESTED_WITH_XML = "XMLHttpRequest"
+ STATUS = "status"
+ STATUS_OK = "OK"
+ STATUS_FAIL = "FAIL"
+ STATUS_UNHEALTHY = "UNHEALTHY"
+ STATUS_REMOVE = "REMOVE"
+
+ CLIENT_DIR = "client"
+
+ API_URL_SUFFIX_V1 = "/api/v1"
+ API_URL_SUFFIX_V4 = "/api/v4"
+ API_URL_SUFFIX = API_URL_SUFFIX_V4
+)
+
+type Response struct {
+ StatusCode int
+ Error *AppError
+ RequestId string
+ Etag string
+ ServerVersion string
+ Header http.Header
+}
+
+type Client4 struct {
+ Url string // The location of the server, for example "http://localhost:8065"
+ ApiUrl string // The api location of the server, for example "http://localhost:8065/api/v4"
+ HttpClient *http.Client // The http client
+ AuthToken string
+ AuthType string
+ HttpHeader map[string]string // Headers to be copied over for each request
+}
+
+func closeBody(r *http.Response) {
+ if r.Body != nil {
+ _, _ = io.Copy(ioutil.Discard, r.Body)
+ _ = r.Body.Close()
+ }
+}
+
+// Must is a convenience function used for testing.
+func (c *Client4) Must(result interface{}, resp *Response) interface{} {
+ if resp.Error != nil {
+ time.Sleep(time.Second)
+ panic(resp.Error)
+ }
+
+ return result
+}
+
+func NewAPIv4Client(url string) *Client4 {
+ return &Client4{url, url + API_URL_SUFFIX, &http.Client{}, "", "", map[string]string{}}
+}
+
+func BuildErrorResponse(r *http.Response, err *AppError) *Response {
+ var statusCode int
+ var header http.Header
+ if r != nil {
+ statusCode = r.StatusCode
+ header = r.Header
+ } else {
+ statusCode = 0
+ header = make(http.Header)
+ }
+
+ return &Response{
+ StatusCode: statusCode,
+ Error: err,
+ Header: header,
+ }
+}
+
+func BuildResponse(r *http.Response) *Response {
+ return &Response{
+ StatusCode: r.StatusCode,
+ RequestId: r.Header.Get(HEADER_REQUEST_ID),
+ Etag: r.Header.Get(HEADER_ETAG_SERVER),
+ ServerVersion: r.Header.Get(HEADER_VERSION_ID),
+ Header: r.Header,
+ }
+}
+
+func (c *Client4) SetToken(token string) {
+ c.AuthToken = token
+ c.AuthType = HEADER_BEARER
+}
+
+// MockSession is deprecated in favour of SetToken
+func (c *Client4) MockSession(token string) {
+ c.SetToken(token)
+}
+
+func (c *Client4) SetOAuthToken(token string) {
+ c.AuthToken = token
+ c.AuthType = HEADER_TOKEN
+}
+
+func (c *Client4) ClearOAuthToken() {
+ c.AuthToken = ""
+ c.AuthType = HEADER_BEARER
+}
+
+func (c *Client4) GetUsersRoute() string {
+ return "/users"
+}
+
+func (c *Client4) GetUserRoute(userId string) string {
+ return fmt.Sprintf(c.GetUsersRoute()+"/%v", userId)
+}
+
+func (c *Client4) GetUserAccessTokensRoute() string {
+ return fmt.Sprintf(c.GetUsersRoute() + "/tokens")
+}
+
+func (c *Client4) GetUserAccessTokenRoute(tokenId string) string {
+ return fmt.Sprintf(c.GetUsersRoute()+"/tokens/%v", tokenId)
+}
+
+func (c *Client4) GetUserByUsernameRoute(userName string) string {
+ return fmt.Sprintf(c.GetUsersRoute()+"/username/%v", userName)
+}
+
+func (c *Client4) GetUserByEmailRoute(email string) string {
+ return fmt.Sprintf(c.GetUsersRoute()+"/email/%v", email)
+}
+
+func (c *Client4) GetBotsRoute() string {
+ return "/bots"
+}
+
+func (c *Client4) GetBotRoute(botUserId string) string {
+ return fmt.Sprintf("%s/%s", c.GetBotsRoute(), botUserId)
+}
+
+func (c *Client4) GetTeamsRoute() string {
+ return "/teams"
+}
+
+func (c *Client4) GetTeamRoute(teamId string) string {
+ return fmt.Sprintf(c.GetTeamsRoute()+"/%v", teamId)
+}
+
+func (c *Client4) GetTeamAutoCompleteCommandsRoute(teamId string) string {
+ return fmt.Sprintf(c.GetTeamsRoute()+"/%v/commands/autocomplete", teamId)
+}
+
+func (c *Client4) GetTeamByNameRoute(teamName string) string {
+ return fmt.Sprintf(c.GetTeamsRoute()+"/name/%v", teamName)
+}
+
+func (c *Client4) GetTeamMemberRoute(teamId, userId string) string {
+ return fmt.Sprintf(c.GetTeamRoute(teamId)+"/members/%v", userId)
+}
+
+func (c *Client4) GetTeamMembersRoute(teamId string) string {
+ return fmt.Sprintf(c.GetTeamRoute(teamId) + "/members")
+}
+
+func (c *Client4) GetTeamStatsRoute(teamId string) string {
+ return fmt.Sprintf(c.GetTeamRoute(teamId) + "/stats")
+}
+
+func (c *Client4) GetTeamImportRoute(teamId string) string {
+ return fmt.Sprintf(c.GetTeamRoute(teamId) + "/import")
+}
+
+func (c *Client4) GetChannelsRoute() string {
+ return "/channels"
+}
+
+func (c *Client4) GetChannelsForTeamRoute(teamId string) string {
+ return fmt.Sprintf(c.GetTeamRoute(teamId) + "/channels")
+}
+
+func (c *Client4) GetChannelRoute(channelId string) string {
+ return fmt.Sprintf(c.GetChannelsRoute()+"/%v", channelId)
+}
+
+func (c *Client4) GetChannelByNameRoute(channelName, teamId string) string {
+ return fmt.Sprintf(c.GetTeamRoute(teamId)+"/channels/name/%v", channelName)
+}
+
+func (c *Client4) GetChannelsForTeamForUserRoute(teamId, userId string, includeDeleted bool) string {
+ route := fmt.Sprintf(c.GetUserRoute(userId) + c.GetTeamRoute(teamId) + "/channels")
+ if includeDeleted {
+ query := fmt.Sprintf("?include_deleted=%v", includeDeleted)
+ return route + query
+ }
+ return route
+}
+
+func (c *Client4) GetChannelByNameForTeamNameRoute(channelName, teamName string) string {
+ return fmt.Sprintf(c.GetTeamByNameRoute(teamName)+"/channels/name/%v", channelName)
+}
+
+func (c *Client4) GetChannelMembersRoute(channelId string) string {
+ return fmt.Sprintf(c.GetChannelRoute(channelId) + "/members")
+}
+
+func (c *Client4) GetChannelMemberRoute(channelId, userId string) string {
+ return fmt.Sprintf(c.GetChannelMembersRoute(channelId)+"/%v", userId)
+}
+
+func (c *Client4) GetPostsRoute() string {
+ return "/posts"
+}
+
+func (c *Client4) GetPostsEphemeralRoute() string {
+ return "/posts/ephemeral"
+}
+
+func (c *Client4) GetConfigRoute() string {
+ return "/config"
+}
+
+func (c *Client4) GetLicenseRoute() string {
+ return "/license"
+}
+
+func (c *Client4) GetPostRoute(postId string) string {
+ return fmt.Sprintf(c.GetPostsRoute()+"/%v", postId)
+}
+
+func (c *Client4) GetFilesRoute() string {
+ return "/files"
+}
+
+func (c *Client4) GetFileRoute(fileId string) string {
+ return fmt.Sprintf(c.GetFilesRoute()+"/%v", fileId)
+}
+
+func (c *Client4) GetPluginsRoute() string {
+ return "/plugins"
+}
+
+func (c *Client4) GetPluginRoute(pluginId string) string {
+ return fmt.Sprintf(c.GetPluginsRoute()+"/%v", pluginId)
+}
+
+func (c *Client4) GetSystemRoute() string {
+ return "/system"
+}
+
+func (c *Client4) GetTestEmailRoute() string {
+ return "/email/test"
+}
+
+func (c *Client4) GetTestSiteURLRoute() string {
+ return "/site_url/test"
+}
+
+func (c *Client4) GetTestS3Route() string {
+ return "/file/s3_test"
+}
+
+func (c *Client4) GetDatabaseRoute() string {
+ return "/database"
+}
+
+func (c *Client4) GetCacheRoute() string {
+ return "/caches"
+}
+
+func (c *Client4) GetClusterRoute() string {
+ return "/cluster"
+}
+
+func (c *Client4) GetIncomingWebhooksRoute() string {
+ return "/hooks/incoming"
+}
+
+func (c *Client4) GetIncomingWebhookRoute(hookID string) string {
+ return fmt.Sprintf(c.GetIncomingWebhooksRoute()+"/%v", hookID)
+}
+
+func (c *Client4) GetComplianceReportsRoute() string {
+ return "/compliance/reports"
+}
+
+func (c *Client4) GetComplianceReportRoute(reportId string) string {
+ return fmt.Sprintf("/compliance/reports/%v", reportId)
+}
+
+func (c *Client4) GetOutgoingWebhooksRoute() string {
+ return "/hooks/outgoing"
+}
+
+func (c *Client4) GetOutgoingWebhookRoute(hookID string) string {
+ return fmt.Sprintf(c.GetOutgoingWebhooksRoute()+"/%v", hookID)
+}
+
+func (c *Client4) GetPreferencesRoute(userId string) string {
+ return fmt.Sprintf(c.GetUserRoute(userId) + "/preferences")
+}
+
+func (c *Client4) GetUserStatusRoute(userId string) string {
+ return fmt.Sprintf(c.GetUserRoute(userId) + "/status")
+}
+
+func (c *Client4) GetUserStatusesRoute() string {
+ return fmt.Sprintf(c.GetUsersRoute() + "/status")
+}
+
+func (c *Client4) GetSamlRoute() string {
+ return "/saml"
+}
+
+func (c *Client4) GetLdapRoute() string {
+ return "/ldap"
+}
+
+func (c *Client4) GetBrandRoute() string {
+ return "/brand"
+}
+
+func (c *Client4) GetDataRetentionRoute() string {
+ return "/data_retention"
+}
+
+func (c *Client4) GetElasticsearchRoute() string {
+ return "/elasticsearch"
+}
+
+func (c *Client4) GetBleveRoute() string {
+ return "/bleve"
+}
+
+func (c *Client4) GetCommandsRoute() string {
+ return "/commands"
+}
+
+func (c *Client4) GetCommandRoute(commandId string) string {
+ return fmt.Sprintf(c.GetCommandsRoute()+"/%v", commandId)
+}
+
+func (c *Client4) GetCommandMoveRoute(commandId string) string {
+ return fmt.Sprintf(c.GetCommandsRoute()+"/%v/move", commandId)
+}
+
+func (c *Client4) GetEmojisRoute() string {
+ return "/emoji"
+}
+
+func (c *Client4) GetEmojiRoute(emojiId string) string {
+ return fmt.Sprintf(c.GetEmojisRoute()+"/%v", emojiId)
+}
+
+func (c *Client4) GetEmojiByNameRoute(name string) string {
+ return fmt.Sprintf(c.GetEmojisRoute()+"/name/%v", name)
+}
+
+func (c *Client4) GetReactionsRoute() string {
+ return "/reactions"
+}
+
+func (c *Client4) GetOAuthAppsRoute() string {
+ return "/oauth/apps"
+}
+
+func (c *Client4) GetOAuthAppRoute(appId string) string {
+ return fmt.Sprintf("/oauth/apps/%v", appId)
+}
+
+func (c *Client4) GetOpenGraphRoute() string {
+ return "/opengraph"
+}
+
+func (c *Client4) GetJobsRoute() string {
+ return "/jobs"
+}
+
+func (c *Client4) GetRolesRoute() string {
+ return "/roles"
+}
+
+func (c *Client4) GetSchemesRoute() string {
+ return "/schemes"
+}
+
+func (c *Client4) GetSchemeRoute(id string) string {
+ return c.GetSchemesRoute() + fmt.Sprintf("/%v", id)
+}
+
+func (c *Client4) GetAnalyticsRoute() string {
+ return "/analytics"
+}
+
+func (c *Client4) GetTimezonesRoute() string {
+ return fmt.Sprintf(c.GetSystemRoute() + "/timezones")
+}
+
+func (c *Client4) GetChannelSchemeRoute(channelId string) string {
+ return fmt.Sprintf(c.GetChannelsRoute()+"/%v/scheme", channelId)
+}
+
+func (c *Client4) GetTeamSchemeRoute(teamId string) string {
+ return fmt.Sprintf(c.GetTeamsRoute()+"/%v/scheme", teamId)
+}
+
+func (c *Client4) GetTotalUsersStatsRoute() string {
+ return fmt.Sprintf(c.GetUsersRoute() + "/stats")
+}
+
+func (c *Client4) GetRedirectLocationRoute() string {
+ return "/redirect_location"
+}
+
+func (c *Client4) GetServerBusyRoute() string {
+ return "/server_busy"
+}
+
+func (c *Client4) GetUserTermsOfServiceRoute(userId string) string {
+ return c.GetUserRoute(userId) + "/terms_of_service"
+}
+
+func (c *Client4) GetTermsOfServiceRoute() string {
+ return "/terms_of_service"
+}
+
+func (c *Client4) GetGroupsRoute() string {
+ return "/groups"
+}
+
+func (c *Client4) GetGroupRoute(groupID string) string {
+ return fmt.Sprintf("%s/%s", c.GetGroupsRoute(), groupID)
+}
+
+func (c *Client4) GetGroupSyncableRoute(groupID, syncableID string, syncableType GroupSyncableType) string {
+ return fmt.Sprintf("%s/%ss/%s", c.GetGroupRoute(groupID), strings.ToLower(syncableType.String()), syncableID)
+}
+
+func (c *Client4) GetGroupSyncablesRoute(groupID string, syncableType GroupSyncableType) string {
+ return fmt.Sprintf("%s/%ss", c.GetGroupRoute(groupID), strings.ToLower(syncableType.String()))
+}
+
+func (c *Client4) DoApiGet(url string, etag string) (*http.Response, *AppError) {
+ return c.DoApiRequest(http.MethodGet, c.ApiUrl+url, "", etag)
+}
+
+func (c *Client4) DoApiPost(url string, data string) (*http.Response, *AppError) {
+ return c.DoApiRequest(http.MethodPost, c.ApiUrl+url, data, "")
+}
+
+func (c *Client4) doApiPostBytes(url string, data []byte) (*http.Response, *AppError) {
+ return c.doApiRequestBytes(http.MethodPost, c.ApiUrl+url, data, "")
+}
+
+func (c *Client4) DoApiPut(url string, data string) (*http.Response, *AppError) {
+ return c.DoApiRequest(http.MethodPut, c.ApiUrl+url, data, "")
+}
+
+func (c *Client4) doApiPutBytes(url string, data []byte) (*http.Response, *AppError) {
+ return c.doApiRequestBytes(http.MethodPut, c.ApiUrl+url, data, "")
+}
+
+func (c *Client4) DoApiDelete(url string) (*http.Response, *AppError) {
+ return c.DoApiRequest(http.MethodDelete, c.ApiUrl+url, "", "")
+}
+
+func (c *Client4) DoApiRequest(method, url, data, etag string) (*http.Response, *AppError) {
+ return c.doApiRequestReader(method, url, strings.NewReader(data), etag)
+}
+
+func (c *Client4) doApiRequestBytes(method, url string, data []byte, etag string) (*http.Response, *AppError) {
+ return c.doApiRequestReader(method, url, bytes.NewReader(data), etag)
+}
+
+func (c *Client4) doApiRequestReader(method, url string, data io.Reader, etag string) (*http.Response, *AppError) {
+ rq, err := http.NewRequest(method, url, data)
+ if err != nil {
+ return nil, NewAppError(url, "model.client.connecting.app_error", nil, err.Error(), http.StatusBadRequest)
+ }
+
+ if len(etag) > 0 {
+ rq.Header.Set(HEADER_ETAG_CLIENT, etag)
+ }
+
+ if len(c.AuthToken) > 0 {
+ rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken)
+ }
+
+ if c.HttpHeader != nil && len(c.HttpHeader) > 0 {
+ for k, v := range c.HttpHeader {
+ rq.Header.Set(k, v)
+ }
+ }
+
+ rp, err := c.HttpClient.Do(rq)
+ if err != nil || rp == nil {
+ return nil, NewAppError(url, "model.client.connecting.app_error", nil, err.Error(), 0)
+ }
+
+ if rp.StatusCode == 304 {
+ return rp, nil
+ }
+
+ if rp.StatusCode >= 300 {
+ defer closeBody(rp)
+ return rp, AppErrorFromJson(rp.Body)
+ }
+
+ return rp, nil
+}
+
+func (c *Client4) DoUploadFile(url string, data []byte, contentType string) (*FileUploadResponse, *Response) {
+ return c.doUploadFile(url, bytes.NewReader(data), contentType, 0)
+}
+
+func (c *Client4) doUploadFile(url string, body io.Reader, contentType string, contentLength int64) (*FileUploadResponse, *Response) {
+ rq, err := http.NewRequest("POST", c.ApiUrl+url, body)
+ if err != nil {
+ return nil, &Response{Error: NewAppError(url, "model.client.connecting.app_error", nil, err.Error(), http.StatusBadRequest)}
+ }
+ if contentLength != 0 {
+ rq.ContentLength = contentLength
+ }
+ rq.Header.Set("Content-Type", contentType)
+
+ if len(c.AuthToken) > 0 {
+ rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken)
+ }
+
+ rp, err := c.HttpClient.Do(rq)
+ if err != nil || rp == nil {
+ return nil, BuildErrorResponse(rp, NewAppError(url, "model.client.connecting.app_error", nil, err.Error(), 0))
+ }
+ defer closeBody(rp)
+
+ if rp.StatusCode >= 300 {
+ return nil, BuildErrorResponse(rp, AppErrorFromJson(rp.Body))
+ }
+
+ return FileUploadResponseFromJson(rp.Body), BuildResponse(rp)
+}
+
+func (c *Client4) DoEmojiUploadFile(url string, data []byte, contentType string) (*Emoji, *Response) {
+ rq, err := http.NewRequest("POST", c.ApiUrl+url, bytes.NewReader(data))
+ if err != nil {
+ return nil, &Response{Error: NewAppError(url, "model.client.connecting.app_error", nil, err.Error(), http.StatusBadRequest)}
+ }
+ rq.Header.Set("Content-Type", contentType)
+
+ if len(c.AuthToken) > 0 {
+ rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken)
+ }
+
+ rp, err := c.HttpClient.Do(rq)
+ if err != nil || rp == nil {
+ return nil, BuildErrorResponse(rp, NewAppError(url, "model.client.connecting.app_error", nil, err.Error(), 0))
+ }
+ defer closeBody(rp)
+
+ if rp.StatusCode >= 300 {
+ return nil, BuildErrorResponse(rp, AppErrorFromJson(rp.Body))
+ }
+
+ return EmojiFromJson(rp.Body), BuildResponse(rp)
+}
+
+func (c *Client4) DoUploadImportTeam(url string, data []byte, contentType string) (map[string]string, *Response) {
+ rq, err := http.NewRequest("POST", c.ApiUrl+url, bytes.NewReader(data))
+ if err != nil {
+ return nil, &Response{Error: NewAppError(url, "model.client.connecting.app_error", nil, err.Error(), http.StatusBadRequest)}
+ }
+ rq.Header.Set("Content-Type", contentType)
+
+ if len(c.AuthToken) > 0 {
+ rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken)
+ }
+
+ rp, err := c.HttpClient.Do(rq)
+ if err != nil || rp == nil {
+ return nil, BuildErrorResponse(rp, NewAppError(url, "model.client.connecting.app_error", nil, err.Error(), 0))
+ }
+ defer closeBody(rp)
+
+ if rp.StatusCode >= 300 {
+ return nil, BuildErrorResponse(rp, AppErrorFromJson(rp.Body))
+ }
+
+ return MapFromJson(rp.Body), BuildResponse(rp)
+}
+
+// CheckStatusOK is a convenience function for checking the standard OK response
+// from the web service.
+func CheckStatusOK(r *http.Response) bool {
+ m := MapFromJson(r.Body)
+ defer closeBody(r)
+
+ if m != nil && m[STATUS] == STATUS_OK {
+ return true
+ }
+
+ return false
+}
+
+// Authentication Section
+
+// LoginById authenticates a user by user id and password.
+func (c *Client4) LoginById(id string, password string) (*User, *Response) {
+ m := make(map[string]string)
+ m["id"] = id
+ m["password"] = password
+ return c.login(m)
+}
+
+// Login authenticates a user by login id, which can be username, email or some sort
+// of SSO identifier based on server configuration, and a password.
+func (c *Client4) Login(loginId string, password string) (*User, *Response) {
+ m := make(map[string]string)
+ m["login_id"] = loginId
+ m["password"] = password
+ return c.login(m)
+}
+
+// LoginByLdap authenticates a user by LDAP id and password.
+func (c *Client4) LoginByLdap(loginId string, password string) (*User, *Response) {
+ m := make(map[string]string)
+ m["login_id"] = loginId
+ m["password"] = password
+ m["ldap_only"] = "true"
+ return c.login(m)
+}
+
+// LoginWithDevice authenticates a user by login id (username, email or some sort
+// of SSO identifier based on configuration), password and attaches a device id to
+// the session.
+func (c *Client4) LoginWithDevice(loginId string, password string, deviceId string) (*User, *Response) {
+ m := make(map[string]string)
+ m["login_id"] = loginId
+ m["password"] = password
+ m["device_id"] = deviceId
+ return c.login(m)
+}
+
+// LoginWithMFA logs a user in with a MFA token
+func (c *Client4) LoginWithMFA(loginId, password, mfaToken string) (*User, *Response) {
+ m := make(map[string]string)
+ m["login_id"] = loginId
+ m["password"] = password
+ m["token"] = mfaToken
+ return c.login(m)
+}
+
+func (c *Client4) login(m map[string]string) (*User, *Response) {
+ r, err := c.DoApiPost("/users/login", MapToJson(m))
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ c.AuthToken = r.Header.Get(HEADER_TOKEN)
+ c.AuthType = HEADER_BEARER
+ return UserFromJson(r.Body), BuildResponse(r)
+}
+
+// Logout terminates the current user's session.
+func (c *Client4) Logout() (bool, *Response) {
+ r, err := c.DoApiPost("/users/logout", "")
+ if err != nil {
+ return false, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ c.AuthToken = ""
+ c.AuthType = HEADER_BEARER
+ return CheckStatusOK(r), BuildResponse(r)
+}
+
+// SwitchAccountType changes a user's login type from one type to another.
+func (c *Client4) SwitchAccountType(switchRequest *SwitchRequest) (string, *Response) {
+ r, err := c.DoApiPost(c.GetUsersRoute()+"/login/switch", switchRequest.ToJson())
+ if err != nil {
+ return "", BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return MapFromJson(r.Body)["follow_link"], BuildResponse(r)
+}
+
+// User Section
+
+// CreateUser creates a user in the system based on the provided user struct.
+func (c *Client4) CreateUser(user *User) (*User, *Response) {
+ r, err := c.DoApiPost(c.GetUsersRoute(), user.ToJson())
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return UserFromJson(r.Body), BuildResponse(r)
+}
+
+// CreateUserWithToken creates a user in the system based on the provided tokenId.
+func (c *Client4) CreateUserWithToken(user *User, tokenId string) (*User, *Response) {
+ if tokenId == "" {
+ err := NewAppError("MissingHashOrData", "api.user.create_user.missing_token.app_error", nil, "", http.StatusBadRequest)
+ return nil, &Response{StatusCode: err.StatusCode, Error: err}
+ }
+
+ query := fmt.Sprintf("?t=%v", tokenId)
+ r, err := c.DoApiPost(c.GetUsersRoute()+query, user.ToJson())
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+
+ return UserFromJson(r.Body), BuildResponse(r)
+}
+
+// CreateUserWithInviteId creates a user in the system based on the provided invited id.
+func (c *Client4) CreateUserWithInviteId(user *User, inviteId string) (*User, *Response) {
+ if inviteId == "" {
+ err := NewAppError("MissingInviteId", "api.user.create_user.missing_invite_id.app_error", nil, "", http.StatusBadRequest)
+ return nil, &Response{StatusCode: err.StatusCode, Error: err}
+ }
+
+ query := fmt.Sprintf("?iid=%v", url.QueryEscape(inviteId))
+ r, err := c.DoApiPost(c.GetUsersRoute()+query, user.ToJson())
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+
+ return UserFromJson(r.Body), BuildResponse(r)
+}
+
+// GetMe returns the logged in user.
+func (c *Client4) GetMe(etag string) (*User, *Response) {
+ r, err := c.DoApiGet(c.GetUserRoute(ME), etag)
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return UserFromJson(r.Body), BuildResponse(r)
+}
+
+// GetUser returns a user based on the provided user id string.
+func (c *Client4) GetUser(userId, etag string) (*User, *Response) {
+ r, err := c.DoApiGet(c.GetUserRoute(userId), etag)
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return UserFromJson(r.Body), BuildResponse(r)
+}
+
+// GetUserByUsername returns a user based on the provided user name string.
+func (c *Client4) GetUserByUsername(userName, etag string) (*User, *Response) {
+ r, err := c.DoApiGet(c.GetUserByUsernameRoute(userName), etag)
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return UserFromJson(r.Body), BuildResponse(r)
+}
+
+// GetUserByEmail returns a user based on the provided user email string.
+func (c *Client4) GetUserByEmail(email, etag string) (*User, *Response) {
+ r, err := c.DoApiGet(c.GetUserByEmailRoute(email), etag)
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return UserFromJson(r.Body), BuildResponse(r)
+}
+
+// AutocompleteUsersInTeam returns the users on a team based on search term.
+func (c *Client4) AutocompleteUsersInTeam(teamId string, username string, limit int, etag string) (*UserAutocomplete, *Response) {
+ query := fmt.Sprintf("?in_team=%v&name=%v&limit=%d", teamId, username, limit)
+ r, err := c.DoApiGet(c.GetUsersRoute()+"/autocomplete"+query, etag)
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return UserAutocompleteFromJson(r.Body), BuildResponse(r)
+}
+
+// AutocompleteUsersInChannel returns the users in a channel based on search term.
+func (c *Client4) AutocompleteUsersInChannel(teamId string, channelId string, username string, limit int, etag string) (*UserAutocomplete, *Response) {
+ query := fmt.Sprintf("?in_team=%v&in_channel=%v&name=%v&limit=%d", teamId, channelId, username, limit)
+ r, err := c.DoApiGet(c.GetUsersRoute()+"/autocomplete"+query, etag)
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return UserAutocompleteFromJson(r.Body), BuildResponse(r)
+}
+
+// AutocompleteUsers returns the users in the system based on search term.
+func (c *Client4) AutocompleteUsers(username string, limit int, etag string) (*UserAutocomplete, *Response) {
+ query := fmt.Sprintf("?name=%v&limit=%d", username, limit)
+ r, err := c.DoApiGet(c.GetUsersRoute()+"/autocomplete"+query, etag)
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return UserAutocompleteFromJson(r.Body), BuildResponse(r)
+}
+
+// GetDefaultProfileImage gets the default user's profile image. Must be logged in.
+func (c *Client4) GetDefaultProfileImage(userId string) ([]byte, *Response) {
+ r, appErr := c.DoApiGet(c.GetUserRoute(userId)+"/image/default", "")
+ if appErr != nil {
+ return nil, BuildErrorResponse(r, appErr)
+ }
+ defer closeBody(r)
+
+ data, err := ioutil.ReadAll(r.Body)
+ if err != nil {
+ return nil, BuildErrorResponse(r, NewAppError("GetDefaultProfileImage", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode))
+ }
+
+ return data, BuildResponse(r)
+}
+
+// GetProfileImage gets user's profile image. Must be logged in.
+func (c *Client4) GetProfileImage(userId, etag string) ([]byte, *Response) {
+ r, appErr := c.DoApiGet(c.GetUserRoute(userId)+"/image", etag)
+ if appErr != nil {
+ return nil, BuildErrorResponse(r, appErr)
+ }
+ defer closeBody(r)
+
+ data, err := ioutil.ReadAll(r.Body)
+ if err != nil {
+ return nil, BuildErrorResponse(r, NewAppError("GetProfileImage", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode))
+ }
+ return data, BuildResponse(r)
+}
+
+// GetUsers returns a page of users on the system. Page counting starts at 0.
+func (c *Client4) GetUsers(page int, perPage int, etag string) ([]*User, *Response) {
+ query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
+ r, err := c.DoApiGet(c.GetUsersRoute()+query, etag)
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return UserListFromJson(r.Body), BuildResponse(r)
+}
+
+// GetUsersInTeam returns a page of users on a team. Page counting starts at 0.
+func (c *Client4) GetUsersInTeam(teamId string, page int, perPage int, etag string) ([]*User, *Response) {
+ query := fmt.Sprintf("?in_team=%v&page=%v&per_page=%v", teamId, page, perPage)
+ r, err := c.DoApiGet(c.GetUsersRoute()+query, etag)
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return UserListFromJson(r.Body), BuildResponse(r)
+}
+
+// GetNewUsersInTeam returns a page of users on a team. Page counting starts at 0.
+func (c *Client4) GetNewUsersInTeam(teamId string, page int, perPage int, etag string) ([]*User, *Response) {
+ query := fmt.Sprintf("?sort=create_at&in_team=%v&page=%v&per_page=%v", teamId, page, perPage)
+ r, err := c.DoApiGet(c.GetUsersRoute()+query, etag)
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return UserListFromJson(r.Body), BuildResponse(r)
+}
+
+// GetRecentlyActiveUsersInTeam returns a page of users on a team. Page counting starts at 0.
+func (c *Client4) GetRecentlyActiveUsersInTeam(teamId string, page int, perPage int, etag string) ([]*User, *Response) {
+ query := fmt.Sprintf("?sort=last_activity_at&in_team=%v&page=%v&per_page=%v", teamId, page, perPage)
+ r, err := c.DoApiGet(c.GetUsersRoute()+query, etag)
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return UserListFromJson(r.Body), BuildResponse(r)
+}
+
+// GetActiveUsersInTeam returns a page of users on a team. Page counting starts at 0.
+func (c *Client4) GetActiveUsersInTeam(teamId string, page int, perPage int, etag string) ([]*User, *Response) {
+ query := fmt.Sprintf("?active=true&in_team=%v&page=%v&per_page=%v", teamId, page, perPage)
+ r, err := c.DoApiGet(c.GetUsersRoute()+query, etag)
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return UserListFromJson(r.Body), BuildResponse(r)
+}
+
+// GetUsersNotInTeam returns a page of users who are not in a team. Page counting starts at 0.
+func (c *Client4) GetUsersNotInTeam(teamId string, page int, perPage int, etag string) ([]*User, *Response) {
+ query := fmt.Sprintf("?not_in_team=%v&page=%v&per_page=%v", teamId, page, perPage)
+ r, err := c.DoApiGet(c.GetUsersRoute()+query, etag)
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return UserListFromJson(r.Body), BuildResponse(r)
+}
+
+// GetUsersInChannel returns a page of users in a channel. Page counting starts at 0.
+func (c *Client4) GetUsersInChannel(channelId string, page int, perPage int, etag string) ([]*User, *Response) {
+ query := fmt.Sprintf("?in_channel=%v&page=%v&per_page=%v", channelId, page, perPage)
+ r, err := c.DoApiGet(c.GetUsersRoute()+query, etag)
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return UserListFromJson(r.Body), BuildResponse(r)
+}
+
+// GetUsersInChannelByStatus returns a page of users in a channel. Page counting starts at 0. Sorted by Status
+func (c *Client4) GetUsersInChannelByStatus(channelId string, page int, perPage int, etag string) ([]*User, *Response) {
+ query := fmt.Sprintf("?in_channel=%v&page=%v&per_page=%v&sort=status", channelId, page, perPage)
+ r, err := c.DoApiGet(c.GetUsersRoute()+query, etag)
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return UserListFromJson(r.Body), BuildResponse(r)
+}
+
+// GetUsersNotInChannel returns a page of users not in a channel. Page counting starts at 0.
+func (c *Client4) GetUsersNotInChannel(teamId, channelId string, page int, perPage int, etag string) ([]*User, *Response) {
+ query := fmt.Sprintf("?in_team=%v&not_in_channel=%v&page=%v&per_page=%v", teamId, channelId, page, perPage)
+ r, err := c.DoApiGet(c.GetUsersRoute()+query, etag)
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return UserListFromJson(r.Body), BuildResponse(r)
+}
+
+// GetUsersWithoutTeam returns a page of users on the system that aren't on any teams. Page counting starts at 0.
+func (c *Client4) GetUsersWithoutTeam(page int, perPage int, etag string) ([]*User, *Response) {
+ query := fmt.Sprintf("?without_team=1&page=%v&per_page=%v", page, perPage)
+ r, err := c.DoApiGet(c.GetUsersRoute()+query, etag)
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return UserListFromJson(r.Body), BuildResponse(r)
+}
+
+// GetUsersByIds returns a list of users based on the provided user ids.
+func (c *Client4) GetUsersByIds(userIds []string) ([]*User, *Response) {
+ r, err := c.DoApiPost(c.GetUsersRoute()+"/ids", ArrayToJson(userIds))
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return UserListFromJson(r.Body), BuildResponse(r)
+}
+
+// GetUsersByIds returns a list of users based on the provided user ids.
+func (c *Client4) GetUsersByIdsWithOptions(userIds []string, options *UserGetByIdsOptions) ([]*User, *Response) {
+ v := url.Values{}
+ if options.Since != 0 {
+ v.Set("since", fmt.Sprintf("%d", options.Since))
+ }
+
+ url := c.GetUsersRoute() + "/ids"
+ if len(v) > 0 {
+ url += "?" + v.Encode()
+ }
+
+ r, err := c.DoApiPost(url, ArrayToJson(userIds))
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return UserListFromJson(r.Body), BuildResponse(r)
+}
+
+// GetUsersByUsernames returns a list of users based on the provided usernames.
+func (c *Client4) GetUsersByUsernames(usernames []string) ([]*User, *Response) {
+ r, err := c.DoApiPost(c.GetUsersRoute()+"/usernames", ArrayToJson(usernames))
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return UserListFromJson(r.Body), BuildResponse(r)
+}
+
+// GetUsersByGroupChannelIds returns a map with channel ids as keys
+// and a list of users as values based on the provided user ids.
+func (c *Client4) GetUsersByGroupChannelIds(groupChannelIds []string) (map[string][]*User, *Response) {
+ r, err := c.DoApiPost(c.GetUsersRoute()+"/group_channels", ArrayToJson(groupChannelIds))
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+
+ usersByChannelId := map[string][]*User{}
+ json.NewDecoder(r.Body).Decode(&usersByChannelId)
+ return usersByChannelId, BuildResponse(r)
+}
+
+// SearchUsers returns a list of users based on some search criteria.
+func (c *Client4) SearchUsers(search *UserSearch) ([]*User, *Response) {
+ r, err := c.doApiPostBytes(c.GetUsersRoute()+"/search", search.ToJson())
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return UserListFromJson(r.Body), BuildResponse(r)
+}
+
+// UpdateUser updates a user in the system based on the provided user struct.
+func (c *Client4) UpdateUser(user *User) (*User, *Response) {
+ r, err := c.DoApiPut(c.GetUserRoute(user.Id), user.ToJson())
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return UserFromJson(r.Body), BuildResponse(r)
+}
+
+// PatchUser partially updates a user in the system. Any missing fields are not updated.
+func (c *Client4) PatchUser(userId string, patch *UserPatch) (*User, *Response) {
+ r, err := c.DoApiPut(c.GetUserRoute(userId)+"/patch", patch.ToJson())
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return UserFromJson(r.Body), BuildResponse(r)
+}
+
+// UpdateUserAuth updates a user AuthData (uthData, authService and password) in the system.
+func (c *Client4) UpdateUserAuth(userId string, userAuth *UserAuth) (*UserAuth, *Response) {
+ r, err := c.DoApiPut(c.GetUserRoute(userId)+"/auth", userAuth.ToJson())
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return UserAuthFromJson(r.Body), BuildResponse(r)
+}
+
+// UpdateUserMfa activates multi-factor authentication for a user if activate
+// is true and a valid code is provided. If activate is false, then code is not
+// required and multi-factor authentication is disabled for the user.
+func (c *Client4) UpdateUserMfa(userId, code string, activate bool) (bool, *Response) {
+ requestBody := make(map[string]interface{})
+ requestBody["activate"] = activate
+ requestBody["code"] = code
+
+ r, err := c.DoApiPut(c.GetUserRoute(userId)+"/mfa", StringInterfaceToJson(requestBody))
+ if err != nil {
+ return false, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return CheckStatusOK(r), BuildResponse(r)
+}
+
+// CheckUserMfa checks whether a user has MFA active on their account or not based on the
+// provided login id.
+// Deprecated: Clients should use Login method and check for MFA Error
+func (c *Client4) CheckUserMfa(loginId string) (bool, *Response) {
+ requestBody := make(map[string]interface{})
+ requestBody["login_id"] = loginId
+ r, err := c.DoApiPost(c.GetUsersRoute()+"/mfa", StringInterfaceToJson(requestBody))
+ if err != nil {
+ return false, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+
+ data := StringInterfaceFromJson(r.Body)
+ mfaRequired, ok := data["mfa_required"].(bool)
+ if !ok {
+ return false, BuildResponse(r)
+ }
+ return mfaRequired, BuildResponse(r)
+}
+
+// GenerateMfaSecret will generate a new MFA secret for a user and return it as a string and
+// as a base64 encoded image QR code.
+func (c *Client4) GenerateMfaSecret(userId string) (*MfaSecret, *Response) {
+ r, err := c.DoApiPost(c.GetUserRoute(userId)+"/mfa/generate", "")
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return MfaSecretFromJson(r.Body), BuildResponse(r)
+}
+
+// UpdateUserPassword updates a user's password. Must be logged in as the user or be a system administrator.
+func (c *Client4) UpdateUserPassword(userId, currentPassword, newPassword string) (bool, *Response) {
+ requestBody := map[string]string{"current_password": currentPassword, "new_password": newPassword}
+ r, err := c.DoApiPut(c.GetUserRoute(userId)+"/password", MapToJson(requestBody))
+ if err != nil {
+ return false, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return CheckStatusOK(r), BuildResponse(r)
+}
+
+// PromoteGuestToUser convert a guest into a regular user
+func (c *Client4) PromoteGuestToUser(guestId string) (bool, *Response) {
+ r, err := c.DoApiPost(c.GetUserRoute(guestId)+"/promote", "")
+ if err != nil {
+ return false, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return CheckStatusOK(r), BuildResponse(r)
+}
+
+// DemoteUserToGuest convert a regular user into a guest
+func (c *Client4) DemoteUserToGuest(guestId string) (bool, *Response) {
+ r, err := c.DoApiPost(c.GetUserRoute(guestId)+"/demote", "")
+ if err != nil {
+ return false, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return CheckStatusOK(r), BuildResponse(r)
+}
+
+// UpdateUserRoles updates a user's roles in the system. A user can have "system_user" and "system_admin" roles.
+func (c *Client4) UpdateUserRoles(userId, roles string) (bool, *Response) {
+ requestBody := map[string]string{"roles": roles}
+ r, err := c.DoApiPut(c.GetUserRoute(userId)+"/roles", MapToJson(requestBody))
+ if err != nil {
+ return false, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return CheckStatusOK(r), BuildResponse(r)
+}
+
+// UpdateUserActive updates status of a user whether active or not.
+func (c *Client4) UpdateUserActive(userId string, active bool) (bool, *Response) {
+ requestBody := make(map[string]interface{})
+ requestBody["active"] = active
+ r, err := c.DoApiPut(c.GetUserRoute(userId)+"/active", StringInterfaceToJson(requestBody))
+ if err != nil {
+ return false, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+
+ return CheckStatusOK(r), BuildResponse(r)
+}
+
+// DeleteUser deactivates a user in the system based on the provided user id string.
+func (c *Client4) DeleteUser(userId string) (bool, *Response) {
+ r, err := c.DoApiDelete(c.GetUserRoute(userId))
+ if err != nil {
+ return false, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return CheckStatusOK(r), BuildResponse(r)
+}
+
+// SendPasswordResetEmail will send a link for password resetting to a user with the
+// provided email.
+func (c *Client4) SendPasswordResetEmail(email string) (bool, *Response) {
+ requestBody := map[string]string{"email": email}
+ r, err := c.DoApiPost(c.GetUsersRoute()+"/password/reset/send", MapToJson(requestBody))
+ if err != nil {
+ return false, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return CheckStatusOK(r), BuildResponse(r)
+}
+
+// ResetPassword uses a recovery code to update reset a user's password.
+func (c *Client4) ResetPassword(token, newPassword string) (bool, *Response) {
+ requestBody := map[string]string{"token": token, "new_password": newPassword}
+ r, err := c.DoApiPost(c.GetUsersRoute()+"/password/reset", MapToJson(requestBody))
+ if err != nil {
+ return false, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return CheckStatusOK(r), BuildResponse(r)
+}
+
+// GetSessions returns a list of sessions based on the provided user id string.
+func (c *Client4) GetSessions(userId, etag string) ([]*Session, *Response) {
+ r, err := c.DoApiGet(c.GetUserRoute(userId)+"/sessions", etag)
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return SessionsFromJson(r.Body), BuildResponse(r)
+}
+
+// RevokeSession revokes a user session based on the provided user id and session id strings.
+func (c *Client4) RevokeSession(userId, sessionId string) (bool, *Response) {
+ requestBody := map[string]string{"session_id": sessionId}
+ r, err := c.DoApiPost(c.GetUserRoute(userId)+"/sessions/revoke", MapToJson(requestBody))
+ if err != nil {
+ return false, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return CheckStatusOK(r), BuildResponse(r)
+}
+
+// RevokeAllSessions revokes all sessions for the provided user id string.
+func (c *Client4) RevokeAllSessions(userId string) (bool, *Response) {
+ r, err := c.DoApiPost(c.GetUserRoute(userId)+"/sessions/revoke/all", "")
+ if err != nil {
+ return false, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return CheckStatusOK(r), BuildResponse(r)
+}
+
+// RevokeAllSessions revokes all sessions for all the users.
+func (c *Client4) RevokeSessionsFromAllUsers() (bool, *Response) {
+ r, err := c.DoApiPost(c.GetUsersRoute()+"/sessions/revoke/all", "")
+ if err != nil {
+ return false, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return CheckStatusOK(r), BuildResponse(r)
+}
+
+// AttachDeviceId attaches a mobile device ID to the current session.
+func (c *Client4) AttachDeviceId(deviceId string) (bool, *Response) {
+ requestBody := map[string]string{"device_id": deviceId}
+ r, err := c.DoApiPut(c.GetUsersRoute()+"/sessions/device", MapToJson(requestBody))
+ if err != nil {
+ return false, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return CheckStatusOK(r), BuildResponse(r)
+}
+
+// GetTeamsUnreadForUser will return an array with TeamUnread objects that contain the amount
+// of unread messages and mentions the current user has for the teams it belongs to.
+// An optional team ID can be set to exclude that team from the results. Must be authenticated.
+func (c *Client4) GetTeamsUnreadForUser(userId, teamIdToExclude string) ([]*TeamUnread, *Response) {
+ var optional string
+ if teamIdToExclude != "" {
+ optional += fmt.Sprintf("?exclude_team=%s", url.QueryEscape(teamIdToExclude))
+ }
+
+ r, err := c.DoApiGet(c.GetUserRoute(userId)+"/teams/unread"+optional, "")
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return TeamsUnreadFromJson(r.Body), BuildResponse(r)
+}
+
+// GetUserAudits returns a list of audit based on the provided user id string.
+func (c *Client4) GetUserAudits(userId string, page int, perPage int, etag string) (Audits, *Response) {
+ query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
+ r, err := c.DoApiGet(c.GetUserRoute(userId)+"/audits"+query, etag)
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return AuditsFromJson(r.Body), BuildResponse(r)
+}
+
+// VerifyUserEmail will verify a user's email using the supplied token.
+func (c *Client4) VerifyUserEmail(token string) (bool, *Response) {
+ requestBody := map[string]string{"token": token}
+ r, err := c.DoApiPost(c.GetUsersRoute()+"/email/verify", MapToJson(requestBody))
+ if err != nil {
+ return false, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return CheckStatusOK(r), BuildResponse(r)
+}
+
+// SendVerificationEmail will send an email to the user with the provided email address, if
+// that user exists. The email will contain a link that can be used to verify the user's
+// email address.
+func (c *Client4) SendVerificationEmail(email string) (bool, *Response) {
+ requestBody := map[string]string{"email": email}
+ r, err := c.DoApiPost(c.GetUsersRoute()+"/email/verify/send", MapToJson(requestBody))
+ if err != nil {
+ return false, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return CheckStatusOK(r), BuildResponse(r)
+}
+
+// SetDefaultProfileImage resets the profile image to a default generated one.
+func (c *Client4) SetDefaultProfileImage(userId string) (bool, *Response) {
+ r, err := c.DoApiDelete(c.GetUserRoute(userId) + "/image")
+ if err != nil {
+ return false, BuildErrorResponse(r, err)
+ }
+ return CheckStatusOK(r), BuildResponse(r)
+}
+
+// SetProfileImage sets profile image of the user.
+func (c *Client4) SetProfileImage(userId string, data []byte) (bool, *Response) {
+ body := &bytes.Buffer{}
+ writer := multipart.NewWriter(body)
+
+ part, err := writer.CreateFormFile("image", "profile.png")
+ if err != nil {
+ return false, &Response{Error: NewAppError("SetProfileImage", "model.client.set_profile_user.no_file.app_error", nil, err.Error(), http.StatusBadRequest)}
+ }
+
+ if _, err = io.Copy(part, bytes.NewBuffer(data)); err != nil {
+ return false, &Response{Error: NewAppError("SetProfileImage", "model.client.set_profile_user.no_file.app_error", nil, err.Error(), http.StatusBadRequest)}
+ }
+
+ if err = writer.Close(); err != nil {
+ return false, &Response{Error: NewAppError("SetProfileImage", "model.client.set_profile_user.writer.app_error", nil, err.Error(), http.StatusBadRequest)}
+ }
+
+ rq, err := http.NewRequest("POST", c.ApiUrl+c.GetUserRoute(userId)+"/image", bytes.NewReader(body.Bytes()))
+ if err != nil {
+ return false, &Response{Error: NewAppError("SetProfileImage", "model.client.connecting.app_error", nil, err.Error(), http.StatusBadRequest)}
+ }
+ rq.Header.Set("Content-Type", writer.FormDataContentType())
+
+ if len(c.AuthToken) > 0 {
+ rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken)
+ }
+
+ rp, err := c.HttpClient.Do(rq)
+ if err != nil || rp == nil {
+ return false, &Response{StatusCode: http.StatusForbidden, Error: NewAppError(c.GetUserRoute(userId)+"/image", "model.client.connecting.app_error", nil, err.Error(), http.StatusForbidden)}
+ }
+ defer closeBody(rp)
+
+ if rp.StatusCode >= 300 {
+ return false, BuildErrorResponse(rp, AppErrorFromJson(rp.Body))
+ }
+
+ return CheckStatusOK(rp), BuildResponse(rp)
+}
+
+// CreateUserAccessToken will generate a user access token that can be used in place
+// of a session token to access the REST API. Must have the 'create_user_access_token'
+// permission and if generating for another user, must have the 'edit_other_users'
+// permission. A non-blank description is required.
+func (c *Client4) CreateUserAccessToken(userId, description string) (*UserAccessToken, *Response) {
+ requestBody := map[string]string{"description": description}
+ r, err := c.DoApiPost(c.GetUserRoute(userId)+"/tokens", MapToJson(requestBody))
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return UserAccessTokenFromJson(r.Body), BuildResponse(r)
+}
+
+// GetUserAccessTokens will get a page of access tokens' id, description, is_active
+// and the user_id in the system. The actual token will not be returned. Must have
+// the 'manage_system' permission.
+func (c *Client4) GetUserAccessTokens(page int, perPage int) ([]*UserAccessToken, *Response) {
+ query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
+ r, err := c.DoApiGet(c.GetUserAccessTokensRoute()+query, "")
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return UserAccessTokenListFromJson(r.Body), BuildResponse(r)
+}
+
+// GetUserAccessToken will get a user access tokens' id, description, is_active
+// and the user_id of the user it is for. The actual token will not be returned.
+// Must have the 'read_user_access_token' permission and if getting for another
+// user, must have the 'edit_other_users' permission.
+func (c *Client4) GetUserAccessToken(tokenId string) (*UserAccessToken, *Response) {
+ r, err := c.DoApiGet(c.GetUserAccessTokenRoute(tokenId), "")
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return UserAccessTokenFromJson(r.Body), BuildResponse(r)
+}
+
+// GetUserAccessTokensForUser will get a paged list of user access tokens showing id,
+// description and user_id for each. The actual tokens will not be returned. Must have
+// the 'read_user_access_token' permission and if getting for another user, must have the
+// 'edit_other_users' permission.
+func (c *Client4) GetUserAccessTokensForUser(userId string, page, perPage int) ([]*UserAccessToken, *Response) {
+ query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
+ r, err := c.DoApiGet(c.GetUserRoute(userId)+"/tokens"+query, "")
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return UserAccessTokenListFromJson(r.Body), BuildResponse(r)
+}
+
+// RevokeUserAccessToken will revoke a user access token by id. Must have the
+// 'revoke_user_access_token' permission and if revoking for another user, must have the
+// 'edit_other_users' permission.
+func (c *Client4) RevokeUserAccessToken(tokenId string) (bool, *Response) {
+ requestBody := map[string]string{"token_id": tokenId}
+ r, err := c.DoApiPost(c.GetUsersRoute()+"/tokens/revoke", MapToJson(requestBody))
+ if err != nil {
+ return false, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return CheckStatusOK(r), BuildResponse(r)
+}
+
+// SearchUserAccessTokens returns user access tokens matching the provided search term.
+func (c *Client4) SearchUserAccessTokens(search *UserAccessTokenSearch) ([]*UserAccessToken, *Response) {
+ r, err := c.DoApiPost(c.GetUsersRoute()+"/tokens/search", search.ToJson())
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return UserAccessTokenListFromJson(r.Body), BuildResponse(r)
+}
+
+// DisableUserAccessToken will disable a user access token by id. Must have the
+// 'revoke_user_access_token' permission and if disabling for another user, must have the
+// 'edit_other_users' permission.
+func (c *Client4) DisableUserAccessToken(tokenId string) (bool, *Response) {
+ requestBody := map[string]string{"token_id": tokenId}
+ r, err := c.DoApiPost(c.GetUsersRoute()+"/tokens/disable", MapToJson(requestBody))
+ if err != nil {
+ return false, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return CheckStatusOK(r), BuildResponse(r)
+}
+
+// EnableUserAccessToken will enable a user access token by id. Must have the
+// 'create_user_access_token' permission and if enabling for another user, must have the
+// 'edit_other_users' permission.
+func (c *Client4) EnableUserAccessToken(tokenId string) (bool, *Response) {
+ requestBody := map[string]string{"token_id": tokenId}
+ r, err := c.DoApiPost(c.GetUsersRoute()+"/tokens/enable", MapToJson(requestBody))
+ if err != nil {
+ return false, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return CheckStatusOK(r), BuildResponse(r)
+}
+
+// Bots section
+
+// CreateBot creates a bot in the system based on the provided bot struct.
+func (c *Client4) CreateBot(bot *Bot) (*Bot, *Response) {
+ r, err := c.doApiPostBytes(c.GetBotsRoute(), bot.ToJson())
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return BotFromJson(r.Body), BuildResponse(r)
+}
+
+// PatchBot partially updates a bot. Any missing fields are not updated.
+func (c *Client4) PatchBot(userId string, patch *BotPatch) (*Bot, *Response) {
+ r, err := c.doApiPutBytes(c.GetBotRoute(userId), patch.ToJson())
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return BotFromJson(r.Body), BuildResponse(r)
+}
+
+// GetBot fetches the given, undeleted bot.
+func (c *Client4) GetBot(userId string, etag string) (*Bot, *Response) {
+ r, err := c.DoApiGet(c.GetBotRoute(userId), etag)
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return BotFromJson(r.Body), BuildResponse(r)
+}
+
+// GetBot fetches the given bot, even if it is deleted.
+func (c *Client4) GetBotIncludeDeleted(userId string, etag string) (*Bot, *Response) {
+ r, err := c.DoApiGet(c.GetBotRoute(userId)+"?include_deleted=true", etag)
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return BotFromJson(r.Body), BuildResponse(r)
+}
+
+// GetBots fetches the given page of bots, excluding deleted.
+func (c *Client4) GetBots(page, perPage int, etag string) ([]*Bot, *Response) {
+ query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
+ r, err := c.DoApiGet(c.GetBotsRoute()+query, etag)
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return BotListFromJson(r.Body), BuildResponse(r)
+}
+
+// GetBotsIncludeDeleted fetches the given page of bots, including deleted.
+func (c *Client4) GetBotsIncludeDeleted(page, perPage int, etag string) ([]*Bot, *Response) {
+ query := fmt.Sprintf("?page=%v&per_page=%v&include_deleted=true", page, perPage)
+ r, err := c.DoApiGet(c.GetBotsRoute()+query, etag)
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return BotListFromJson(r.Body), BuildResponse(r)
+}
+
+// GetBotsOrphaned fetches the given page of bots, only including orphanded bots.
+func (c *Client4) GetBotsOrphaned(page, perPage int, etag string) ([]*Bot, *Response) {
+ query := fmt.Sprintf("?page=%v&per_page=%v&only_orphaned=true", page, perPage)
+ r, err := c.DoApiGet(c.GetBotsRoute()+query, etag)
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return BotListFromJson(r.Body), BuildResponse(r)
+}
+
+// DisableBot disables the given bot in the system.
+func (c *Client4) DisableBot(botUserId string) (*Bot, *Response) {
+ r, err := c.doApiPostBytes(c.GetBotRoute(botUserId)+"/disable", nil)
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return BotFromJson(r.Body), BuildResponse(r)
+}
+
+// EnableBot disables the given bot in the system.
+func (c *Client4) EnableBot(botUserId string) (*Bot, *Response) {
+ r, err := c.doApiPostBytes(c.GetBotRoute(botUserId)+"/enable", nil)
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return BotFromJson(r.Body), BuildResponse(r)
+}
+
+// AssignBot assigns the given bot to the given user
+func (c *Client4) AssignBot(botUserId, newOwnerId string) (*Bot, *Response) {
+ r, err := c.doApiPostBytes(c.GetBotRoute(botUserId)+"/assign/"+newOwnerId, nil)
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return BotFromJson(r.Body), BuildResponse(r)
+}
+
+// SetBotIconImage sets LHS bot icon image.
+func (c *Client4) SetBotIconImage(botUserId string, data []byte) (bool, *Response) {
+ body := &bytes.Buffer{}
+ writer := multipart.NewWriter(body)
+
+ part, err := writer.CreateFormFile("image", "icon.svg")
+ if err != nil {
+ return false, &Response{Error: NewAppError("SetBotIconImage", "model.client.set_bot_icon_image.no_file.app_error", nil, err.Error(), http.StatusBadRequest)}
+ }
+
+ if _, err = io.Copy(part, bytes.NewBuffer(data)); err != nil {
+ return false, &Response{Error: NewAppError("SetBotIconImage", "model.client.set_bot_icon_image.no_file.app_error", nil, err.Error(), http.StatusBadRequest)}
+ }
+
+ if err = writer.Close(); err != nil {
+ return false, &Response{Error: NewAppError("SetBotIconImage", "model.client.set_bot_icon_image.writer.app_error", nil, err.Error(), http.StatusBadRequest)}
+ }
+
+ rq, err := http.NewRequest("POST", c.ApiUrl+c.GetBotRoute(botUserId)+"/icon", bytes.NewReader(body.Bytes()))
+ if err != nil {
+ return false, &Response{Error: NewAppError("SetBotIconImage", "model.client.connecting.app_error", nil, err.Error(), http.StatusBadRequest)}
+ }
+ rq.Header.Set("Content-Type", writer.FormDataContentType())
+
+ if len(c.AuthToken) > 0 {
+ rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken)
+ }
+
+ rp, err := c.HttpClient.Do(rq)
+ if err != nil || rp == nil {
+ return false, &Response{StatusCode: http.StatusForbidden, Error: NewAppError(c.GetBotRoute(botUserId)+"/icon", "model.client.connecting.app_error", nil, err.Error(), http.StatusForbidden)}
+ }
+ defer closeBody(rp)
+
+ if rp.StatusCode >= 300 {
+ return false, BuildErrorResponse(rp, AppErrorFromJson(rp.Body))
+ }
+
+ return CheckStatusOK(rp), BuildResponse(rp)
+}
+
+// GetBotIconImage gets LHS bot icon image. Must be logged in.
+func (c *Client4) GetBotIconImage(botUserId string) ([]byte, *Response) {
+ r, appErr := c.DoApiGet(c.GetBotRoute(botUserId)+"/icon", "")
+ if appErr != nil {
+ return nil, BuildErrorResponse(r, appErr)
+ }
+ defer closeBody(r)
+
+ data, err := ioutil.ReadAll(r.Body)
+ if err != nil {
+ return nil, BuildErrorResponse(r, NewAppError("GetBotIconImage", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode))
+ }
+ return data, BuildResponse(r)
+}
+
+// DeleteBotIconImage deletes LHS bot icon image. Must be logged in.
+func (c *Client4) DeleteBotIconImage(botUserId string) (bool, *Response) {
+ r, appErr := c.DoApiDelete(c.GetBotRoute(botUserId) + "/icon")
+ if appErr != nil {
+ return false, BuildErrorResponse(r, appErr)
+ }
+ defer closeBody(r)
+ return CheckStatusOK(r), BuildResponse(r)
+}
+
+// Team Section
+
+// CreateTeam creates a team in the system based on the provided team struct.
+func (c *Client4) CreateTeam(team *Team) (*Team, *Response) {
+ r, err := c.DoApiPost(c.GetTeamsRoute(), team.ToJson())
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return TeamFromJson(r.Body), BuildResponse(r)
+}
+
+// GetTeam returns a team based on the provided team id string.
+func (c *Client4) GetTeam(teamId, etag string) (*Team, *Response) {
+ r, err := c.DoApiGet(c.GetTeamRoute(teamId), etag)
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return TeamFromJson(r.Body), BuildResponse(r)
+}
+
+// GetAllTeams returns all teams based on permissions.
+func (c *Client4) GetAllTeams(etag string, page int, perPage int) ([]*Team, *Response) {
+ query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
+ r, err := c.DoApiGet(c.GetTeamsRoute()+query, etag)
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return TeamListFromJson(r.Body), BuildResponse(r)
+}
+
+// GetAllTeamsWithTotalCount returns all teams based on permissions.
+func (c *Client4) GetAllTeamsWithTotalCount(etag string, page int, perPage int) ([]*Team, int64, *Response) {
+ query := fmt.Sprintf("?page=%v&per_page=%v&include_total_count=true", page, perPage)
+ r, err := c.DoApiGet(c.GetTeamsRoute()+query, etag)
+ if err != nil {
+ return nil, 0, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ teamsListWithCount := TeamsWithCountFromJson(r.Body)
+ return teamsListWithCount.Teams, teamsListWithCount.TotalCount, BuildResponse(r)
+}
+
+// GetTeamByName returns a team based on the provided team name string.
+func (c *Client4) GetTeamByName(name, etag string) (*Team, *Response) {
+ r, err := c.DoApiGet(c.GetTeamByNameRoute(name), etag)
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return TeamFromJson(r.Body), BuildResponse(r)
+}
+
+// SearchTeams returns teams matching the provided search term.
+func (c *Client4) SearchTeams(search *TeamSearch) ([]*Team, *Response) {
+ r, err := c.DoApiPost(c.GetTeamsRoute()+"/search", search.ToJson())
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return TeamListFromJson(r.Body), BuildResponse(r)
+}
+
+// SearchTeamsPaged returns a page of teams and the total count matching the provided search term.
+func (c *Client4) SearchTeamsPaged(search *TeamSearch) ([]*Team, int64, *Response) {
+ if search.Page == nil {
+ search.Page = NewInt(0)
+ }
+ if search.PerPage == nil {
+ search.PerPage = NewInt(100)
+ }
+ r, err := c.DoApiPost(c.GetTeamsRoute()+"/search", search.ToJson())
+ if err != nil {
+ return nil, 0, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ twc := TeamsWithCountFromJson(r.Body)
+ return twc.Teams, twc.TotalCount, BuildResponse(r)
+}
+
+// TeamExists returns true or false if the team exist or not.
+func (c *Client4) TeamExists(name, etag string) (bool, *Response) {
+ r, err := c.DoApiGet(c.GetTeamByNameRoute(name)+"/exists", etag)
+ if err != nil {
+ return false, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return MapBoolFromJson(r.Body)["exists"], BuildResponse(r)
+}
+
+// GetTeamsForUser returns a list of teams a user is on. Must be logged in as the user
+// or be a system administrator.
+func (c *Client4) GetTeamsForUser(userId, etag string) ([]*Team, *Response) {
+ r, err := c.DoApiGet(c.GetUserRoute(userId)+"/teams", etag)
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return TeamListFromJson(r.Body), BuildResponse(r)
+}
+
+// GetTeamMember returns a team member based on the provided team and user id strings.
+func (c *Client4) GetTeamMember(teamId, userId, etag string) (*TeamMember, *Response) {
+ r, err := c.DoApiGet(c.GetTeamMemberRoute(teamId, userId), etag)
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return TeamMemberFromJson(r.Body), BuildResponse(r)
+}
+
+// UpdateTeamMemberRoles will update the roles on a team for a user.
+func (c *Client4) UpdateTeamMemberRoles(teamId, userId, newRoles string) (bool, *Response) {
+ requestBody := map[string]string{"roles": newRoles}
+ r, err := c.DoApiPut(c.GetTeamMemberRoute(teamId, userId)+"/roles", MapToJson(requestBody))
+ if err != nil {
+ return false, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return CheckStatusOK(r), BuildResponse(r)
+}
+
+// UpdateTeamMemberSchemeRoles will update the scheme-derived roles on a team for a user.
+func (c *Client4) UpdateTeamMemberSchemeRoles(teamId string, userId string, schemeRoles *SchemeRoles) (bool, *Response) {
+ r, err := c.DoApiPut(c.GetTeamMemberRoute(teamId, userId)+"/schemeRoles", schemeRoles.ToJson())
+ if err != nil {
+ return false, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return CheckStatusOK(r), BuildResponse(r)
+}
+
+// UpdateTeam will update a team.
+func (c *Client4) UpdateTeam(team *Team) (*Team, *Response) {
+ r, err := c.DoApiPut(c.GetTeamRoute(team.Id), team.ToJson())
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return TeamFromJson(r.Body), BuildResponse(r)
+}
+
+// PatchTeam partially updates a team. Any missing fields are not updated.
+func (c *Client4) PatchTeam(teamId string, patch *TeamPatch) (*Team, *Response) {
+ r, err := c.DoApiPut(c.GetTeamRoute(teamId)+"/patch", patch.ToJson())
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return TeamFromJson(r.Body), BuildResponse(r)
+}
+
+// RestoreTeam restores a previously deleted team.
+func (c *Client4) RestoreTeam(teamId string) (*Team, *Response) {
+ r, err := c.DoApiPost(c.GetTeamRoute(teamId)+"/restore", "")
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return TeamFromJson(r.Body), BuildResponse(r)
+}
+
+// RegenerateTeamInviteId requests a new invite ID to be generated.
+func (c *Client4) RegenerateTeamInviteId(teamId string) (*Team, *Response) {
+ r, err := c.DoApiPost(c.GetTeamRoute(teamId)+"/regenerate_invite_id", "")
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return TeamFromJson(r.Body), BuildResponse(r)
+}
+
+// SoftDeleteTeam deletes the team softly (archive only, not permanent delete).
+func (c *Client4) SoftDeleteTeam(teamId string) (bool, *Response) {
+ r, err := c.DoApiDelete(c.GetTeamRoute(teamId))
+ if err != nil {
+ return false, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return CheckStatusOK(r), BuildResponse(r)
+}
+
+// PermanentDeleteTeam deletes the team, should only be used when needed for
+// compliance and the like.
+func (c *Client4) PermanentDeleteTeam(teamId string) (bool, *Response) {
+ r, err := c.DoApiDelete(c.GetTeamRoute(teamId) + "?permanent=true")
+ if err != nil {
+ return false, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return CheckStatusOK(r), BuildResponse(r)
+}
+
+// UpdateTeamPrivacy modifies the team type (model.TEAM_OPEN <--> model.TEAM_INVITE) and sets
+// the corresponding AllowOpenInvite appropriately.
+func (c *Client4) UpdateTeamPrivacy(teamId string, privacy string) (*Team, *Response) {
+ requestBody := map[string]string{"privacy": privacy}
+ r, err := c.DoApiPut(c.GetTeamRoute(teamId)+"/privacy", MapToJson(requestBody))
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return TeamFromJson(r.Body), BuildResponse(r)
+}
+
+// GetTeamMembers returns team members based on the provided team id string.
+func (c *Client4) GetTeamMembers(teamId string, page int, perPage int, etag string) ([]*TeamMember, *Response) {
+ query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
+ r, err := c.DoApiGet(c.GetTeamMembersRoute(teamId)+query, etag)
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return TeamMembersFromJson(r.Body), BuildResponse(r)
+}
+
+// GetTeamMembersWithoutDeletedUsers returns team members based on the provided team id string. Additional parameters of sort and exclude_deleted_users accepted as well
+// Could not add it to above function due to it be a breaking change.
+func (c *Client4) GetTeamMembersSortAndWithoutDeletedUsers(teamId string, page int, perPage int, sort string, exclude_deleted_users bool, etag string) ([]*TeamMember, *Response) {
+ query := fmt.Sprintf("?page=%v&per_page=%v&sort=%v&exclude_deleted_users=%v", page, perPage, sort, exclude_deleted_users)
+ r, err := c.DoApiGet(c.GetTeamMembersRoute(teamId)+query, etag)
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return TeamMembersFromJson(r.Body), BuildResponse(r)
+}
+
+// GetTeamMembersForUser returns the team members for a user.
+func (c *Client4) GetTeamMembersForUser(userId string, etag string) ([]*TeamMember, *Response) {
+ r, err := c.DoApiGet(c.GetUserRoute(userId)+"/teams/members", etag)
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return TeamMembersFromJson(r.Body), BuildResponse(r)
+}
+
+// GetTeamMembersByIds will return an array of team members based on the
+// team id and a list of user ids provided. Must be authenticated.
+func (c *Client4) GetTeamMembersByIds(teamId string, userIds []string) ([]*TeamMember, *Response) {
+ r, err := c.DoApiPost(fmt.Sprintf("/teams/%v/members/ids", teamId), ArrayToJson(userIds))
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return TeamMembersFromJson(r.Body), BuildResponse(r)
+}
+
+// AddTeamMember adds user to a team and return a team member.
+func (c *Client4) AddTeamMember(teamId, userId string) (*TeamMember, *Response) {
+ member := &TeamMember{TeamId: teamId, UserId: userId}
+ r, err := c.DoApiPost(c.GetTeamMembersRoute(teamId), member.ToJson())
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return TeamMemberFromJson(r.Body), BuildResponse(r)
+}
+
+// AddTeamMemberFromInvite adds a user to a team and return a team member using an invite id
+// or an invite token/data pair.
+func (c *Client4) AddTeamMemberFromInvite(token, inviteId string) (*TeamMember, *Response) {
+ var query string
+
+ if inviteId != "" {
+ query += fmt.Sprintf("?invite_id=%v", inviteId)
+ }
+
+ if token != "" {
+ query += fmt.Sprintf("?token=%v", token)
+ }
+
+ r, err := c.DoApiPost(c.GetTeamsRoute()+"/members/invite"+query, "")
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return TeamMemberFromJson(r.Body), BuildResponse(r)
+}
+
+// AddTeamMembers adds a number of users to a team and returns the team members.
+func (c *Client4) AddTeamMembers(teamId string, userIds []string) ([]*TeamMember, *Response) {
+ var members []*TeamMember
+ for _, userId := range userIds {
+ member := &TeamMember{TeamId: teamId, UserId: userId}
+ members = append(members, member)
+ }
+
+ r, err := c.DoApiPost(c.GetTeamMembersRoute(teamId)+"/batch", TeamMembersToJson(members))
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return TeamMembersFromJson(r.Body), BuildResponse(r)
+}
+
+// AddTeamMembers adds a number of users to a team and returns the team members.
+func (c *Client4) AddTeamMembersGracefully(teamId string, userIds []string) ([]*TeamMemberWithError, *Response) {
+ var members []*TeamMember
+ for _, userId := range userIds {
+ member := &TeamMember{TeamId: teamId, UserId: userId}
+ members = append(members, member)
+ }
+
+ r, err := c.DoApiPost(c.GetTeamMembersRoute(teamId)+"/batch?graceful=true", TeamMembersToJson(members))
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return TeamMembersWithErrorFromJson(r.Body), BuildResponse(r)
+}
+
+// RemoveTeamMember will remove a user from a team.
+func (c *Client4) RemoveTeamMember(teamId, userId string) (bool, *Response) {
+ r, err := c.DoApiDelete(c.GetTeamMemberRoute(teamId, userId))
+ if err != nil {
+ return false, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return CheckStatusOK(r), BuildResponse(r)
+}
+
+// GetTeamStats returns a team stats based on the team id string.
+// Must be authenticated.
+func (c *Client4) GetTeamStats(teamId, etag string) (*TeamStats, *Response) {
+ r, err := c.DoApiGet(c.GetTeamStatsRoute(teamId), etag)
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return TeamStatsFromJson(r.Body), BuildResponse(r)
+}
+
+// GetTotalUsersStats returns a total system user stats.
+// Must be authenticated.
+func (c *Client4) GetTotalUsersStats(etag string) (*UsersStats, *Response) {
+ r, err := c.DoApiGet(c.GetTotalUsersStatsRoute(), etag)
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return UsersStatsFromJson(r.Body), BuildResponse(r)
+}
+
+// GetTeamUnread will return a TeamUnread object that contains the amount of
+// unread messages and mentions the user has for the specified team.
+// Must be authenticated.
+func (c *Client4) GetTeamUnread(teamId, userId string) (*TeamUnread, *Response) {
+ r, err := c.DoApiGet(c.GetUserRoute(userId)+c.GetTeamRoute(teamId)+"/unread", "")
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return TeamUnreadFromJson(r.Body), BuildResponse(r)
+}
+
+// ImportTeam will import an exported team from other app into a existing team.
+func (c *Client4) ImportTeam(data []byte, filesize int, importFrom, filename, teamId string) (map[string]string, *Response) {
+ body := &bytes.Buffer{}
+ writer := multipart.NewWriter(body)
+
+ part, err := writer.CreateFormFile("file", filename)
+ if err != nil {
+ return nil, &Response{Error: NewAppError("UploadImportTeam", "model.client.upload_post_attachment.file.app_error", nil, err.Error(), http.StatusBadRequest)}
+ }
+
+ if _, err = io.Copy(part, bytes.NewBuffer(data)); err != nil {
+ return nil, &Response{Error: NewAppError("UploadImportTeam", "model.client.upload_post_attachment.file.app_error", nil, err.Error(), http.StatusBadRequest)}
+ }
+
+ part, err = writer.CreateFormField("filesize")
+ if err != nil {
+ return nil, &Response{Error: NewAppError("UploadImportTeam", "model.client.upload_post_attachment.file_size.app_error", nil, err.Error(), http.StatusBadRequest)}
+ }
+
+ if _, err = io.Copy(part, strings.NewReader(strconv.Itoa(filesize))); err != nil {
+ return nil, &Response{Error: NewAppError("UploadImportTeam", "model.client.upload_post_attachment.file_size.app_error", nil, err.Error(), http.StatusBadRequest)}
+ }
+
+ part, err = writer.CreateFormField("importFrom")
+ if err != nil {
+ return nil, &Response{Error: NewAppError("UploadImportTeam", "model.client.upload_post_attachment.import_from.app_error", nil, err.Error(), http.StatusBadRequest)}
+ }
+
+ if _, err := io.Copy(part, strings.NewReader(importFrom)); err != nil {
+ return nil, &Response{Error: NewAppError("UploadImportTeam", "model.client.upload_post_attachment.import_from.app_error", nil, err.Error(), http.StatusBadRequest)}
+ }
+
+ if err := writer.Close(); err != nil {
+ return nil, &Response{Error: NewAppError("UploadImportTeam", "model.client.upload_post_attachment.writer.app_error", nil, err.Error(), http.StatusBadRequest)}
+ }
+
+ return c.DoUploadImportTeam(c.GetTeamImportRoute(teamId), body.Bytes(), writer.FormDataContentType())
+}
+
+// InviteUsersToTeam invite users by email to the team.
+func (c *Client4) InviteUsersToTeam(teamId string, userEmails []string) (bool, *Response) {
+ r, err := c.DoApiPost(c.GetTeamRoute(teamId)+"/invite/email", ArrayToJson(userEmails))
+ if err != nil {
+ return false, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return CheckStatusOK(r), BuildResponse(r)
+}
+
+// InviteGuestsToTeam invite guest by email to some channels in a team.
+func (c *Client4) InviteGuestsToTeam(teamId string, userEmails []string, channels []string, message string) (bool, *Response) {
+ guestsInvite := GuestsInvite{
+ Emails: userEmails,
+ Channels: channels,
+ Message: message,
+ }
+ r, err := c.DoApiPost(c.GetTeamRoute(teamId)+"/invite-guests/email", guestsInvite.ToJson())
+ if err != nil {
+ return false, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return CheckStatusOK(r), BuildResponse(r)
+}
+
+// InviteUsersToTeam invite users by email to the team.
+func (c *Client4) InviteUsersToTeamGracefully(teamId string, userEmails []string) ([]*EmailInviteWithError, *Response) {
+ r, err := c.DoApiPost(c.GetTeamRoute(teamId)+"/invite/email?graceful=true", ArrayToJson(userEmails))
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return EmailInviteWithErrorFromJson(r.Body), BuildResponse(r)
+}
+
+// InviteGuestsToTeam invite guest by email to some channels in a team.
+func (c *Client4) InviteGuestsToTeamGracefully(teamId string, userEmails []string, channels []string, message string) ([]*EmailInviteWithError, *Response) {
+ guestsInvite := GuestsInvite{
+ Emails: userEmails,
+ Channels: channels,
+ Message: message,
+ }
+ r, err := c.DoApiPost(c.GetTeamRoute(teamId)+"/invite-guests/email?graceful=true", guestsInvite.ToJson())
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return EmailInviteWithErrorFromJson(r.Body), BuildResponse(r)
+}
+
+// InvalidateEmailInvites will invalidate active email invitations that have not been accepted by the user.
+func (c *Client4) InvalidateEmailInvites() (bool, *Response) {
+ r, err := c.DoApiDelete(c.GetTeamsRoute() + "/invites/email")
+ if err != nil {
+ return false, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return CheckStatusOK(r), BuildResponse(r)
+}
+
+// GetTeamInviteInfo returns a team object from an invite id containing sanitized information.
+func (c *Client4) GetTeamInviteInfo(inviteId string) (*Team, *Response) {
+ r, err := c.DoApiGet(c.GetTeamsRoute()+"/invite/"+inviteId, "")
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return TeamFromJson(r.Body), BuildResponse(r)
+}
+
+// SetTeamIcon sets team icon of the team.
+func (c *Client4) SetTeamIcon(teamId string, data []byte) (bool, *Response) {
+ body := &bytes.Buffer{}
+ writer := multipart.NewWriter(body)
+
+ part, err := writer.CreateFormFile("image", "teamIcon.png")
+ if err != nil {
+ return false, &Response{Error: NewAppError("SetTeamIcon", "model.client.set_team_icon.no_file.app_error", nil, err.Error(), http.StatusBadRequest)}
+ }
+
+ if _, err = io.Copy(part, bytes.NewBuffer(data)); err != nil {
+ return false, &Response{Error: NewAppError("SetTeamIcon", "model.client.set_team_icon.no_file.app_error", nil, err.Error(), http.StatusBadRequest)}
+ }
+
+ if err = writer.Close(); err != nil {
+ return false, &Response{Error: NewAppError("SetTeamIcon", "model.client.set_team_icon.writer.app_error", nil, err.Error(), http.StatusBadRequest)}
+ }
+
+ rq, err := http.NewRequest("POST", c.ApiUrl+c.GetTeamRoute(teamId)+"/image", bytes.NewReader(body.Bytes()))
+ if err != nil {
+ return false, &Response{Error: NewAppError("SetTeamIcon", "model.client.connecting.app_error", nil, err.Error(), http.StatusBadRequest)}
+ }
+ rq.Header.Set("Content-Type", writer.FormDataContentType())
+
+ if len(c.AuthToken) > 0 {
+ rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken)
+ }
+
+ rp, err := c.HttpClient.Do(rq)
+ if err != nil || rp == nil {
+ // set to http.StatusForbidden(403)
+ return false, &Response{StatusCode: http.StatusForbidden, Error: NewAppError(c.GetTeamRoute(teamId)+"/image", "model.client.connecting.app_error", nil, err.Error(), 403)}
+ }
+ defer closeBody(rp)
+
+ if rp.StatusCode >= 300 {
+ return false, BuildErrorResponse(rp, AppErrorFromJson(rp.Body))
+ }
+
+ return CheckStatusOK(rp), BuildResponse(rp)
+}
+
+// GetTeamIcon gets the team icon of the team.
+func (c *Client4) GetTeamIcon(teamId, etag string) ([]byte, *Response) {
+ r, appErr := c.DoApiGet(c.GetTeamRoute(teamId)+"/image", etag)
+ if appErr != nil {
+ return nil, BuildErrorResponse(r, appErr)
+ }
+ defer closeBody(r)
+
+ data, err := ioutil.ReadAll(r.Body)
+ if err != nil {
+ return nil, BuildErrorResponse(r, NewAppError("GetTeamIcon", "model.client.get_team_icon.app_error", nil, err.Error(), r.StatusCode))
+ }
+ return data, BuildResponse(r)
+}
+
+// RemoveTeamIcon updates LastTeamIconUpdate to 0 which indicates team icon is removed.
+func (c *Client4) RemoveTeamIcon(teamId string) (bool, *Response) {
+ r, err := c.DoApiDelete(c.GetTeamRoute(teamId) + "/image")
+ if err != nil {
+ return false, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return CheckStatusOK(r), BuildResponse(r)
+}
+
+// Channel Section
+
+// GetAllChannels get all the channels. Must be a system administrator.
+func (c *Client4) GetAllChannels(page int, perPage int, etag string) (*ChannelListWithTeamData, *Response) {
+ query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
+ r, err := c.DoApiGet(c.GetChannelsRoute()+query, etag)
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return ChannelListWithTeamDataFromJson(r.Body), BuildResponse(r)
+}
+
+// GetAllChannelsWithCount get all the channels including the total count. Must be a system administrator.
+func (c *Client4) GetAllChannelsWithCount(page int, perPage int, etag string) (*ChannelListWithTeamData, int64, *Response) {
+ query := fmt.Sprintf("?page=%v&per_page=%v&include_total_count=true", page, perPage)
+ r, err := c.DoApiGet(c.GetChannelsRoute()+query, etag)
+ if err != nil {
+ return nil, 0, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ cwc := ChannelsWithCountFromJson(r.Body)
+ return cwc.Channels, cwc.TotalCount, BuildResponse(r)
+}
+
+// CreateChannel creates a channel based on the provided channel struct.
+func (c *Client4) CreateChannel(channel *Channel) (*Channel, *Response) {
+ r, err := c.DoApiPost(c.GetChannelsRoute(), channel.ToJson())
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return ChannelFromJson(r.Body), BuildResponse(r)
+}
+
+// UpdateChannel updates a channel based on the provided channel struct.
+func (c *Client4) UpdateChannel(channel *Channel) (*Channel, *Response) {
+ r, err := c.DoApiPut(c.GetChannelRoute(channel.Id), channel.ToJson())
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return ChannelFromJson(r.Body), BuildResponse(r)
+}
+
+// PatchChannel partially updates a channel. Any missing fields are not updated.
+func (c *Client4) PatchChannel(channelId string, patch *ChannelPatch) (*Channel, *Response) {
+ r, err := c.DoApiPut(c.GetChannelRoute(channelId)+"/patch", patch.ToJson())
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return ChannelFromJson(r.Body), BuildResponse(r)
+}
+
+// ConvertChannelToPrivate converts public to private channel.
+func (c *Client4) ConvertChannelToPrivate(channelId string) (*Channel, *Response) {
+ r, err := c.DoApiPost(c.GetChannelRoute(channelId)+"/convert", "")
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return ChannelFromJson(r.Body), BuildResponse(r)
+}
+
+// UpdateChannelPrivacy updates channel privacy
+func (c *Client4) UpdateChannelPrivacy(channelId string, privacy string) (*Channel, *Response) {
+ requestBody := map[string]string{"privacy": privacy}
+ r, err := c.DoApiPut(c.GetChannelRoute(channelId)+"/privacy", MapToJson(requestBody))
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return ChannelFromJson(r.Body), BuildResponse(r)
+}
+
+// RestoreChannel restores a previously deleted channel. Any missing fields are not updated.
+func (c *Client4) RestoreChannel(channelId string) (*Channel, *Response) {
+ r, err := c.DoApiPost(c.GetChannelRoute(channelId)+"/restore", "")
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return ChannelFromJson(r.Body), BuildResponse(r)
+}
+
+// CreateDirectChannel creates a direct message channel based on the two user
+// ids provided.
+func (c *Client4) CreateDirectChannel(userId1, userId2 string) (*Channel, *Response) {
+ requestBody := []string{userId1, userId2}
+ r, err := c.DoApiPost(c.GetChannelsRoute()+"/direct", ArrayToJson(requestBody))
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return ChannelFromJson(r.Body), BuildResponse(r)
+}
+
+// CreateGroupChannel creates a group message channel based on userIds provided.
+func (c *Client4) CreateGroupChannel(userIds []string) (*Channel, *Response) {
+ r, err := c.DoApiPost(c.GetChannelsRoute()+"/group", ArrayToJson(userIds))
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return ChannelFromJson(r.Body), BuildResponse(r)
+}
+
+// GetChannel returns a channel based on the provided channel id string.
+func (c *Client4) GetChannel(channelId, etag string) (*Channel, *Response) {
+ r, err := c.DoApiGet(c.GetChannelRoute(channelId), etag)
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return ChannelFromJson(r.Body), BuildResponse(r)
+}
+
+// GetChannelStats returns statistics for a channel.
+func (c *Client4) GetChannelStats(channelId string, etag string) (*ChannelStats, *Response) {
+ r, err := c.DoApiGet(c.GetChannelRoute(channelId)+"/stats", etag)
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return ChannelStatsFromJson(r.Body), BuildResponse(r)
+}
+
+// GetChannelMembersTimezones gets a list of timezones for a channel.
+func (c *Client4) GetChannelMembersTimezones(channelId string) ([]string, *Response) {
+ r, err := c.DoApiGet(c.GetChannelRoute(channelId)+"/timezones", "")
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return ArrayFromJson(r.Body), BuildResponse(r)
+}
+
+// GetPinnedPosts gets a list of pinned posts.
+func (c *Client4) GetPinnedPosts(channelId string, etag string) (*PostList, *Response) {
+ r, err := c.DoApiGet(c.GetChannelRoute(channelId)+"/pinned", etag)
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return PostListFromJson(r.Body), BuildResponse(r)
+}
+
+// GetPublicChannelsForTeam returns a list of public channels based on the provided team id string.
+func (c *Client4) GetPublicChannelsForTeam(teamId string, page int, perPage int, etag string) ([]*Channel, *Response) {
+ query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
+ r, err := c.DoApiGet(c.GetChannelsForTeamRoute(teamId)+query, etag)
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return ChannelSliceFromJson(r.Body), BuildResponse(r)
+}
+
+// GetDeletedChannelsForTeam returns a list of public channels based on the provided team id string.
+func (c *Client4) GetDeletedChannelsForTeam(teamId string, page int, perPage int, etag string) ([]*Channel, *Response) {
+ query := fmt.Sprintf("/deleted?page=%v&per_page=%v", page, perPage)
+ r, err := c.DoApiGet(c.GetChannelsForTeamRoute(teamId)+query, etag)
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return ChannelSliceFromJson(r.Body), BuildResponse(r)
+}
+
+// GetPublicChannelsByIdsForTeam returns a list of public channels based on provided team id string.
+func (c *Client4) GetPublicChannelsByIdsForTeam(teamId string, channelIds []string) ([]*Channel, *Response) {
+ r, err := c.DoApiPost(c.GetChannelsForTeamRoute(teamId)+"/ids", ArrayToJson(channelIds))
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return ChannelSliceFromJson(r.Body), BuildResponse(r)
+}
+
+// GetChannelsForTeamForUser returns a list channels of on a team for a user.
+func (c *Client4) GetChannelsForTeamForUser(teamId, userId string, includeDeleted bool, etag string) ([]*Channel, *Response) {
+ r, err := c.DoApiGet(c.GetChannelsForTeamForUserRoute(teamId, userId, includeDeleted), etag)
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return ChannelSliceFromJson(r.Body), BuildResponse(r)
+}
+
+// SearchChannels returns the channels on a team matching the provided search term.
+func (c *Client4) SearchChannels(teamId string, search *ChannelSearch) ([]*Channel, *Response) {
+ r, err := c.DoApiPost(c.GetChannelsForTeamRoute(teamId)+"/search", search.ToJson())
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return ChannelSliceFromJson(r.Body), BuildResponse(r)
+}
+
+// SearchArchivedChannels returns the archived channels on a team matching the provided search term.
+func (c *Client4) SearchArchivedChannels(teamId string, search *ChannelSearch) ([]*Channel, *Response) {
+ r, err := c.DoApiPost(c.GetChannelsForTeamRoute(teamId)+"/search_archived", search.ToJson())
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return ChannelSliceFromJson(r.Body), BuildResponse(r)
+}
+
+// SearchAllChannels search in all the channels. Must be a system administrator.
+func (c *Client4) SearchAllChannels(search *ChannelSearch) (*ChannelListWithTeamData, *Response) {
+ r, err := c.DoApiPost(c.GetChannelsRoute()+"/search", search.ToJson())
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return ChannelListWithTeamDataFromJson(r.Body), BuildResponse(r)
+}
+
+// SearchAllChannelsPaged searches all the channels and returns the results paged with the total count.
+func (c *Client4) SearchAllChannelsPaged(search *ChannelSearch) (*ChannelsWithCount, *Response) {
+ r, err := c.DoApiPost(c.GetChannelsRoute()+"/search", search.ToJson())
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return ChannelsWithCountFromJson(r.Body), BuildResponse(r)
+}
+
+// SearchGroupChannels returns the group channels of the user whose members' usernames match the search term.
+func (c *Client4) SearchGroupChannels(search *ChannelSearch) ([]*Channel, *Response) {
+ r, err := c.DoApiPost(c.GetChannelsRoute()+"/group/search", search.ToJson())
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return ChannelSliceFromJson(r.Body), BuildResponse(r)
+}
+
+// DeleteChannel deletes channel based on the provided channel id string.
+func (c *Client4) DeleteChannel(channelId string) (bool, *Response) {
+ r, err := c.DoApiDelete(c.GetChannelRoute(channelId))
+ if err != nil {
+ return false, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return CheckStatusOK(r), BuildResponse(r)
+}
+
+// GetChannelByName returns a channel based on the provided channel name and team id strings.
+func (c *Client4) GetChannelByName(channelName, teamId string, etag string) (*Channel, *Response) {
+ r, err := c.DoApiGet(c.GetChannelByNameRoute(channelName, teamId), etag)
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return ChannelFromJson(r.Body), BuildResponse(r)
+}
+
+// GetChannelByNameIncludeDeleted returns a channel based on the provided channel name and team id strings. Other then GetChannelByName it will also return deleted channels.
+func (c *Client4) GetChannelByNameIncludeDeleted(channelName, teamId string, etag string) (*Channel, *Response) {
+ r, err := c.DoApiGet(c.GetChannelByNameRoute(channelName, teamId)+"?include_deleted=true", etag)
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return ChannelFromJson(r.Body), BuildResponse(r)
+}
+
+// GetChannelByNameForTeamName returns a channel based on the provided channel name and team name strings.
+func (c *Client4) GetChannelByNameForTeamName(channelName, teamName string, etag string) (*Channel, *Response) {
+ r, err := c.DoApiGet(c.GetChannelByNameForTeamNameRoute(channelName, teamName), etag)
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return ChannelFromJson(r.Body), BuildResponse(r)
+}
+
+// GetChannelByNameForTeamNameIncludeDeleted returns a channel based on the provided channel name and team name strings. Other then GetChannelByNameForTeamName it will also return deleted channels.
+func (c *Client4) GetChannelByNameForTeamNameIncludeDeleted(channelName, teamName string, etag string) (*Channel, *Response) {
+ r, err := c.DoApiGet(c.GetChannelByNameForTeamNameRoute(channelName, teamName)+"?include_deleted=true", etag)
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return ChannelFromJson(r.Body), BuildResponse(r)
+}
+
+// GetChannelMembers gets a page of channel members.
+func (c *Client4) GetChannelMembers(channelId string, page, perPage int, etag string) (*ChannelMembers, *Response) {
+ query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
+ r, err := c.DoApiGet(c.GetChannelMembersRoute(channelId)+query, etag)
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return ChannelMembersFromJson(r.Body), BuildResponse(r)
+}
+
+// GetChannelMembersByIds gets the channel members in a channel for a list of user ids.
+func (c *Client4) GetChannelMembersByIds(channelId string, userIds []string) (*ChannelMembers, *Response) {
+ r, err := c.DoApiPost(c.GetChannelMembersRoute(channelId)+"/ids", ArrayToJson(userIds))
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return ChannelMembersFromJson(r.Body), BuildResponse(r)
+}
+
+// GetChannelMember gets a channel member.
+func (c *Client4) GetChannelMember(channelId, userId, etag string) (*ChannelMember, *Response) {
+ r, err := c.DoApiGet(c.GetChannelMemberRoute(channelId, userId), etag)
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return ChannelMemberFromJson(r.Body), BuildResponse(r)
+}
+
+// GetChannelMembersForUser gets all the channel members for a user on a team.
+func (c *Client4) GetChannelMembersForUser(userId, teamId, etag string) (*ChannelMembers, *Response) {
+ r, err := c.DoApiGet(fmt.Sprintf(c.GetUserRoute(userId)+"/teams/%v/channels/members", teamId), etag)
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return ChannelMembersFromJson(r.Body), BuildResponse(r)
+}
+
+// ViewChannel performs a view action for a user. Synonymous with switching channels or marking channels as read by a user.
+func (c *Client4) ViewChannel(userId string, view *ChannelView) (*ChannelViewResponse, *Response) {
+ url := fmt.Sprintf(c.GetChannelsRoute()+"/members/%v/view", userId)
+ r, err := c.DoApiPost(url, view.ToJson())
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return ChannelViewResponseFromJson(r.Body), BuildResponse(r)
+}
+
+// GetChannelUnread will return a ChannelUnread object that contains the number of
+// unread messages and mentions for a user.
+func (c *Client4) GetChannelUnread(channelId, userId string) (*ChannelUnread, *Response) {
+ r, err := c.DoApiGet(c.GetUserRoute(userId)+c.GetChannelRoute(channelId)+"/unread", "")
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return ChannelUnreadFromJson(r.Body), BuildResponse(r)
+}
+
+// UpdateChannelRoles will update the roles on a channel for a user.
+func (c *Client4) UpdateChannelRoles(channelId, userId, roles string) (bool, *Response) {
+ requestBody := map[string]string{"roles": roles}
+ r, err := c.DoApiPut(c.GetChannelMemberRoute(channelId, userId)+"/roles", MapToJson(requestBody))
+ if err != nil {
+ return false, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return CheckStatusOK(r), BuildResponse(r)
+}
+
+// UpdateChannelMemberSchemeRoles will update the scheme-derived roles on a channel for a user.
+func (c *Client4) UpdateChannelMemberSchemeRoles(channelId string, userId string, schemeRoles *SchemeRoles) (bool, *Response) {
+ r, err := c.DoApiPut(c.GetChannelMemberRoute(channelId, userId)+"/schemeRoles", schemeRoles.ToJson())
+ if err != nil {
+ return false, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return CheckStatusOK(r), BuildResponse(r)
+}
+
+// UpdateChannelNotifyProps will update the notification properties on a channel for a user.
+func (c *Client4) UpdateChannelNotifyProps(channelId, userId string, props map[string]string) (bool, *Response) {
+ r, err := c.DoApiPut(c.GetChannelMemberRoute(channelId, userId)+"/notify_props", MapToJson(props))
+ if err != nil {
+ return false, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return CheckStatusOK(r), BuildResponse(r)
+}
+
+// AddChannelMember adds user to channel and return a channel member.
+func (c *Client4) AddChannelMember(channelId, userId string) (*ChannelMember, *Response) {
+ requestBody := map[string]string{"user_id": userId}
+ r, err := c.DoApiPost(c.GetChannelMembersRoute(channelId)+"", MapToJson(requestBody))
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return ChannelMemberFromJson(r.Body), BuildResponse(r)
+}
+
+// AddChannelMemberWithRootId adds user to channel and return a channel member. Post add to channel message has the postRootId.
+func (c *Client4) AddChannelMemberWithRootId(channelId, userId, postRootId string) (*ChannelMember, *Response) {
+ requestBody := map[string]string{"user_id": userId, "post_root_id": postRootId}
+ r, err := c.DoApiPost(c.GetChannelMembersRoute(channelId)+"", MapToJson(requestBody))
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return ChannelMemberFromJson(r.Body), BuildResponse(r)
+}
+
+// RemoveUserFromChannel will delete the channel member object for a user, effectively removing the user from a channel.
+func (c *Client4) RemoveUserFromChannel(channelId, userId string) (bool, *Response) {
+ r, err := c.DoApiDelete(c.GetChannelMemberRoute(channelId, userId))
+ if err != nil {
+ return false, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return CheckStatusOK(r), BuildResponse(r)
+}
+
+// AutocompleteChannelsForTeam will return an ordered list of channels autocomplete suggestions.
+func (c *Client4) AutocompleteChannelsForTeam(teamId, name string) (*ChannelList, *Response) {
+ query := fmt.Sprintf("?name=%v", name)
+ r, err := c.DoApiGet(c.GetChannelsForTeamRoute(teamId)+"/autocomplete"+query, "")
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return ChannelListFromJson(r.Body), BuildResponse(r)
+}
+
+// AutocompleteChannelsForTeamForSearch will return an ordered list of your channels autocomplete suggestions.
+func (c *Client4) AutocompleteChannelsForTeamForSearch(teamId, name string) (*ChannelList, *Response) {
+ query := fmt.Sprintf("?name=%v", name)
+ r, err := c.DoApiGet(c.GetChannelsForTeamRoute(teamId)+"/search_autocomplete"+query, "")
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return ChannelListFromJson(r.Body), BuildResponse(r)
+}
+
+// Post Section
+
+// CreatePost creates a post based on the provided post struct.
+func (c *Client4) CreatePost(post *Post) (*Post, *Response) {
+ r, err := c.DoApiPost(c.GetPostsRoute(), post.ToUnsanitizedJson())
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return PostFromJson(r.Body), BuildResponse(r)
+}
+
+// CreatePostEphemeral creates a ephemeral post based on the provided post struct which is send to the given user id.
+func (c *Client4) CreatePostEphemeral(post *PostEphemeral) (*Post, *Response) {
+ r, err := c.DoApiPost(c.GetPostsEphemeralRoute(), post.ToUnsanitizedJson())
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return PostFromJson(r.Body), BuildResponse(r)
+}
+
+// UpdatePost updates a post based on the provided post struct.
+func (c *Client4) UpdatePost(postId string, post *Post) (*Post, *Response) {
+ r, err := c.DoApiPut(c.GetPostRoute(postId), post.ToUnsanitizedJson())
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return PostFromJson(r.Body), BuildResponse(r)
+}
+
+// PatchPost partially updates a post. Any missing fields are not updated.
+func (c *Client4) PatchPost(postId string, patch *PostPatch) (*Post, *Response) {
+ r, err := c.DoApiPut(c.GetPostRoute(postId)+"/patch", patch.ToJson())
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return PostFromJson(r.Body), BuildResponse(r)
+}
+
+// SetPostUnread marks channel where post belongs as unread on the time of the provided post.
+func (c *Client4) SetPostUnread(userId string, postId string) *Response {
+ r, err := c.DoApiPost(c.GetUserRoute(userId)+c.GetPostRoute(postId)+"/set_unread", "")
+ if err != nil {
+ return BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return BuildResponse(r)
+}
+
+// PinPost pin a post based on provided post id string.
+func (c *Client4) PinPost(postId string) (bool, *Response) {
+ r, err := c.DoApiPost(c.GetPostRoute(postId)+"/pin", "")
+ if err != nil {
+ return false, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return CheckStatusOK(r), BuildResponse(r)
+}
+
+// UnpinPost unpin a post based on provided post id string.
+func (c *Client4) UnpinPost(postId string) (bool, *Response) {
+ r, err := c.DoApiPost(c.GetPostRoute(postId)+"/unpin", "")
+ if err != nil {
+ return false, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return CheckStatusOK(r), BuildResponse(r)
+}
+
+// GetPost gets a single post.
+func (c *Client4) GetPost(postId string, etag string) (*Post, *Response) {
+ r, err := c.DoApiGet(c.GetPostRoute(postId), etag)
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return PostFromJson(r.Body), BuildResponse(r)
+}
+
+// DeletePost deletes a post from the provided post id string.
+func (c *Client4) DeletePost(postId string) (bool, *Response) {
+ r, err := c.DoApiDelete(c.GetPostRoute(postId))
+ if err != nil {
+ return false, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return CheckStatusOK(r), BuildResponse(r)
+}
+
+// GetPostThread gets a post with all the other posts in the same thread.
+func (c *Client4) GetPostThread(postId string, etag string) (*PostList, *Response) {
+ r, err := c.DoApiGet(c.GetPostRoute(postId)+"/thread", etag)
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return PostListFromJson(r.Body), BuildResponse(r)
+}
+
+// GetPostsForChannel gets a page of posts with an array for ordering for a channel.
+func (c *Client4) GetPostsForChannel(channelId string, page, perPage int, etag string) (*PostList, *Response) {
+ query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
+ r, err := c.DoApiGet(c.GetChannelRoute(channelId)+"/posts"+query, etag)
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return PostListFromJson(r.Body), BuildResponse(r)
+}
+
+// GetFlaggedPostsForUser returns flagged posts of a user based on user id string.
+func (c *Client4) GetFlaggedPostsForUser(userId string, page int, perPage int) (*PostList, *Response) {
+ query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
+ r, err := c.DoApiGet(c.GetUserRoute(userId)+"/posts/flagged"+query, "")
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return PostListFromJson(r.Body), BuildResponse(r)
+}
+
+// GetFlaggedPostsForUserInTeam returns flagged posts in team of a user based on user id string.
+func (c *Client4) GetFlaggedPostsForUserInTeam(userId string, teamId string, page int, perPage int) (*PostList, *Response) {
+ if !IsValidId(teamId) {
+ return nil, &Response{StatusCode: http.StatusBadRequest, Error: NewAppError("GetFlaggedPostsForUserInTeam", "model.client.get_flagged_posts_in_team.missing_parameter.app_error", nil, "", http.StatusBadRequest)}
+ }
+
+ query := fmt.Sprintf("?team_id=%v&page=%v&per_page=%v", teamId, page, perPage)
+ r, err := c.DoApiGet(c.GetUserRoute(userId)+"/posts/flagged"+query, "")
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return PostListFromJson(r.Body), BuildResponse(r)
+}
+
+// GetFlaggedPostsForUserInChannel returns flagged posts in channel of a user based on user id string.
+func (c *Client4) GetFlaggedPostsForUserInChannel(userId string, channelId string, page int, perPage int) (*PostList, *Response) {
+ if !IsValidId(channelId) {
+ return nil, &Response{StatusCode: http.StatusBadRequest, Error: NewAppError("GetFlaggedPostsForUserInChannel", "model.client.get_flagged_posts_in_channel.missing_parameter.app_error", nil, "", http.StatusBadRequest)}
+ }
+
+ query := fmt.Sprintf("?channel_id=%v&page=%v&per_page=%v", channelId, page, perPage)
+ r, err := c.DoApiGet(c.GetUserRoute(userId)+"/posts/flagged"+query, "")
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return PostListFromJson(r.Body), BuildResponse(r)
+}
+
+// GetPostsSince gets posts created after a specified time as Unix time in milliseconds.
+func (c *Client4) GetPostsSince(channelId string, time int64) (*PostList, *Response) {
+ query := fmt.Sprintf("?since=%v", time)
+ r, err := c.DoApiGet(c.GetChannelRoute(channelId)+"/posts"+query, "")
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return PostListFromJson(r.Body), BuildResponse(r)
+}
+
+// GetPostsAfter gets a page of posts that were posted after the post provided.
+func (c *Client4) GetPostsAfter(channelId, postId string, page, perPage int, etag string) (*PostList, *Response) {
+ query := fmt.Sprintf("?page=%v&per_page=%v&after=%v", page, perPage, postId)
+ r, err := c.DoApiGet(c.GetChannelRoute(channelId)+"/posts"+query, etag)
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return PostListFromJson(r.Body), BuildResponse(r)
+}
+
+// GetPostsBefore gets a page of posts that were posted before the post provided.
+func (c *Client4) GetPostsBefore(channelId, postId string, page, perPage int, etag string) (*PostList, *Response) {
+ query := fmt.Sprintf("?page=%v&per_page=%v&before=%v", page, perPage, postId)
+ r, err := c.DoApiGet(c.GetChannelRoute(channelId)+"/posts"+query, etag)
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return PostListFromJson(r.Body), BuildResponse(r)
+}
+
+// GetPostsAroundLastUnread gets a list of posts around last unread post by a user in a channel.
+func (c *Client4) GetPostsAroundLastUnread(userId, channelId string, limitBefore, limitAfter int) (*PostList, *Response) {
+ query := fmt.Sprintf("?limit_before=%v&limit_after=%v", limitBefore, limitAfter)
+ if r, err := c.DoApiGet(c.GetUserRoute(userId)+c.GetChannelRoute(channelId)+"/posts/unread"+query, ""); err != nil {
+ return nil, BuildErrorResponse(r, err)
+ } else {
+ defer closeBody(r)
+ return PostListFromJson(r.Body), BuildResponse(r)
+ }
+}
+
+// SearchPosts returns any posts with matching terms string.
+func (c *Client4) SearchPosts(teamId string, terms string, isOrSearch bool) (*PostList, *Response) {
+ params := SearchParameter{
+ Terms: &terms,
+ IsOrSearch: &isOrSearch,
+ }
+ return c.SearchPostsWithParams(teamId, &params)
+}
+
+// SearchPostsWithParams returns any posts with matching terms string.
+func (c *Client4) SearchPostsWithParams(teamId string, params *SearchParameter) (*PostList, *Response) {
+ r, err := c.DoApiPost(c.GetTeamRoute(teamId)+"/posts/search", params.SearchParameterToJson())
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return PostListFromJson(r.Body), BuildResponse(r)
+}
+
+// SearchPostsWithMatches returns any posts with matching terms string, including.
+func (c *Client4) SearchPostsWithMatches(teamId string, terms string, isOrSearch bool) (*PostSearchResults, *Response) {
+ requestBody := map[string]interface{}{"terms": terms, "is_or_search": isOrSearch}
+ r, err := c.DoApiPost(c.GetTeamRoute(teamId)+"/posts/search", StringInterfaceToJson(requestBody))
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return PostSearchResultsFromJson(r.Body), BuildResponse(r)
+}
+
+// DoPostAction performs a post action.
+func (c *Client4) DoPostAction(postId, actionId string) (bool, *Response) {
+ r, err := c.DoApiPost(c.GetPostRoute(postId)+"/actions/"+actionId, "")
+ if err != nil {
+ return false, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return CheckStatusOK(r), BuildResponse(r)
+}
+
+// DoPostActionWithCookie performs a post action with extra arguments
+func (c *Client4) DoPostActionWithCookie(postId, actionId, selected, cookieStr string) (bool, *Response) {
+ var body []byte
+ if selected != "" || cookieStr != "" {
+ body, _ = json.Marshal(DoPostActionRequest{
+ SelectedOption: selected,
+ Cookie: cookieStr,
+ })
+ }
+ r, err := c.DoApiPost(c.GetPostRoute(postId)+"/actions/"+actionId, string(body))
+ if err != nil {
+ return false, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return CheckStatusOK(r), BuildResponse(r)
+}
+
+// OpenInteractiveDialog sends a WebSocket event to a user's clients to
+// open interactive dialogs, based on the provided trigger ID and other
+// provided data. Used with interactive message buttons, menus and
+// slash commands.
+func (c *Client4) OpenInteractiveDialog(request OpenDialogRequest) (bool, *Response) {
+ b, _ := json.Marshal(request)
+ r, err := c.DoApiPost("/actions/dialogs/open", string(b))
+ if err != nil {
+ return false, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return CheckStatusOK(r), BuildResponse(r)
+}
+
+// SubmitInteractiveDialog will submit the provided dialog data to the integration
+// configured by the URL. Used with the interactive dialogs integration feature.
+func (c *Client4) SubmitInteractiveDialog(request SubmitDialogRequest) (*SubmitDialogResponse, *Response) {
+ b, _ := json.Marshal(request)
+ r, err := c.DoApiPost("/actions/dialogs/submit", string(b))
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+
+ var resp SubmitDialogResponse
+ json.NewDecoder(r.Body).Decode(&resp)
+ return &resp, BuildResponse(r)
+}
+
+// UploadFile will upload a file to a channel using a multipart request, to be later attached to a post.
+// This method is functionally equivalent to Client4.UploadFileAsRequestBody.
+func (c *Client4) UploadFile(data []byte, channelId string, filename string) (*FileUploadResponse, *Response) {
+ body := &bytes.Buffer{}
+ writer := multipart.NewWriter(body)
+
+ part, err := writer.CreateFormField("channel_id")
+ if err != nil {
+ return nil, &Response{Error: NewAppError("UploadPostAttachment", "model.client.upload_post_attachment.channel_id.app_error", nil, err.Error(), http.StatusBadRequest)}
+ }
+
+ _, err = io.Copy(part, strings.NewReader(channelId))
+ if err != nil {
+ return nil, &Response{Error: NewAppError("UploadPostAttachment", "model.client.upload_post_attachment.channel_id.app_error", nil, err.Error(), http.StatusBadRequest)}
+ }
+
+ part, err = writer.CreateFormFile("files", filename)
+ if err != nil {
+ return nil, &Response{Error: NewAppError("UploadPostAttachment", "model.client.upload_post_attachment.file.app_error", nil, err.Error(), http.StatusBadRequest)}
+ }
+ _, err = io.Copy(part, bytes.NewBuffer(data))
+ if err != nil {
+ return nil, &Response{Error: NewAppError("UploadPostAttachment", "model.client.upload_post_attachment.file.app_error", nil, err.Error(), http.StatusBadRequest)}
+ }
+
+ err = writer.Close()
+ if err != nil {
+ return nil, &Response{Error: NewAppError("UploadPostAttachment", "model.client.upload_post_attachment.writer.app_error", nil, err.Error(), http.StatusBadRequest)}
+ }
+
+ return c.DoUploadFile(c.GetFilesRoute(), body.Bytes(), writer.FormDataContentType())
+}
+
+// UploadFileAsRequestBody will upload a file to a channel as the body of a request, to be later attached
+// to a post. This method is functionally equivalent to Client4.UploadFile.
+func (c *Client4) UploadFileAsRequestBody(data []byte, channelId string, filename string) (*FileUploadResponse, *Response) {
+ return c.DoUploadFile(c.GetFilesRoute()+fmt.Sprintf("?channel_id=%v&filename=%v", url.QueryEscape(channelId), url.QueryEscape(filename)), data, http.DetectContentType(data))
+}
+
+// GetFile gets the bytes for a file by id.
+func (c *Client4) GetFile(fileId string) ([]byte, *Response) {
+ r, appErr := c.DoApiGet(c.GetFileRoute(fileId), "")
+ if appErr != nil {
+ return nil, BuildErrorResponse(r, appErr)
+ }
+ defer closeBody(r)
+
+ data, err := ioutil.ReadAll(r.Body)
+ if err != nil {
+ return nil, BuildErrorResponse(r, NewAppError("GetFile", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode))
+ }
+ return data, BuildResponse(r)
+}
+
+// DownloadFile gets the bytes for a file by id, optionally adding headers to force the browser to download it.
+func (c *Client4) DownloadFile(fileId string, download bool) ([]byte, *Response) {
+ r, appErr := c.DoApiGet(c.GetFileRoute(fileId)+fmt.Sprintf("?download=%v", download), "")
+ if appErr != nil {
+ return nil, BuildErrorResponse(r, appErr)
+ }
+ defer closeBody(r)
+
+ data, err := ioutil.ReadAll(r.Body)
+ if err != nil {
+ return nil, BuildErrorResponse(r, NewAppError("DownloadFile", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode))
+ }
+ return data, BuildResponse(r)
+}
+
+// GetFileThumbnail gets the bytes for a file by id.
+func (c *Client4) GetFileThumbnail(fileId string) ([]byte, *Response) {
+ r, appErr := c.DoApiGet(c.GetFileRoute(fileId)+"/thumbnail", "")
+ if appErr != nil {
+ return nil, BuildErrorResponse(r, appErr)
+ }
+ defer closeBody(r)
+
+ data, err := ioutil.ReadAll(r.Body)
+ if err != nil {
+ return nil, BuildErrorResponse(r, NewAppError("GetFileThumbnail", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode))
+ }
+ return data, BuildResponse(r)
+}
+
+// DownloadFileThumbnail gets the bytes for a file by id, optionally adding headers to force the browser to download it.
+func (c *Client4) DownloadFileThumbnail(fileId string, download bool) ([]byte, *Response) {
+ r, appErr := c.DoApiGet(c.GetFileRoute(fileId)+fmt.Sprintf("/thumbnail?download=%v", download), "")
+ if appErr != nil {
+ return nil, BuildErrorResponse(r, appErr)
+ }
+ defer closeBody(r)
+
+ data, err := ioutil.ReadAll(r.Body)
+ if err != nil {
+ return nil, BuildErrorResponse(r, NewAppError("DownloadFileThumbnail", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode))
+ }
+ return data, BuildResponse(r)
+}
+
+// GetFileLink gets the public link of a file by id.
+func (c *Client4) GetFileLink(fileId string) (string, *Response) {
+ r, err := c.DoApiGet(c.GetFileRoute(fileId)+"/link", "")
+ if err != nil {
+ return "", BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return MapFromJson(r.Body)["link"], BuildResponse(r)
+}
+
+// GetFilePreview gets the bytes for a file by id.
+func (c *Client4) GetFilePreview(fileId string) ([]byte, *Response) {
+ r, appErr := c.DoApiGet(c.GetFileRoute(fileId)+"/preview", "")
+ if appErr != nil {
+ return nil, BuildErrorResponse(r, appErr)
+ }
+ defer closeBody(r)
+
+ data, err := ioutil.ReadAll(r.Body)
+ if err != nil {
+ return nil, BuildErrorResponse(r, NewAppError("GetFilePreview", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode))
+ }
+ return data, BuildResponse(r)
+}
+
+// DownloadFilePreview gets the bytes for a file by id.
+func (c *Client4) DownloadFilePreview(fileId string, download bool) ([]byte, *Response) {
+ r, appErr := c.DoApiGet(c.GetFileRoute(fileId)+fmt.Sprintf("/preview?download=%v", download), "")
+ if appErr != nil {
+ return nil, BuildErrorResponse(r, appErr)
+ }
+ defer closeBody(r)
+
+ data, err := ioutil.ReadAll(r.Body)
+ if err != nil {
+ return nil, BuildErrorResponse(r, NewAppError("DownloadFilePreview", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode))
+ }
+ return data, BuildResponse(r)
+}
+
+// GetFileInfo gets all the file info objects.
+func (c *Client4) GetFileInfo(fileId string) (*FileInfo, *Response) {
+ r, err := c.DoApiGet(c.GetFileRoute(fileId)+"/info", "")
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return FileInfoFromJson(r.Body), BuildResponse(r)
+}
+
+// GetFileInfosForPost gets all the file info objects attached to a post.
+func (c *Client4) GetFileInfosForPost(postId string, etag string) ([]*FileInfo, *Response) {
+ r, err := c.DoApiGet(c.GetPostRoute(postId)+"/files/info", etag)
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return FileInfosFromJson(r.Body), BuildResponse(r)
+}
+
+// General/System Section
+
+// GetPing will return ok if the running goRoutines are below the threshold and unhealthy for above.
+func (c *Client4) GetPing() (string, *Response) {
+ r, err := c.DoApiGet(c.GetSystemRoute()+"/ping", "")
+ if r != nil && r.StatusCode == 500 {
+ defer r.Body.Close()
+ return STATUS_UNHEALTHY, BuildErrorResponse(r, err)
+ }
+ if err != nil {
+ return "", BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return MapFromJson(r.Body)["status"], BuildResponse(r)
+}
+
+// GetPingWithServerStatus will return ok if several basic server health checks
+// all pass successfully.
+func (c *Client4) GetPingWithServerStatus() (string, *Response) {
+ r, err := c.DoApiGet(c.GetSystemRoute()+"/ping?get_server_status=true", "")
+ if r != nil && r.StatusCode == 500 {
+ defer r.Body.Close()
+ return STATUS_UNHEALTHY, BuildErrorResponse(r, err)
+ }
+ if err != nil {
+ return "", BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return MapFromJson(r.Body)["status"], BuildResponse(r)
+}
+
+// TestEmail will attempt to connect to the configured SMTP server.
+func (c *Client4) TestEmail(config *Config) (bool, *Response) {
+ r, err := c.DoApiPost(c.GetTestEmailRoute(), config.ToJson())
+ if err != nil {
+ return false, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return CheckStatusOK(r), BuildResponse(r)
+}
+
+// TestSiteURL will test the validity of a site URL.
+func (c *Client4) TestSiteURL(siteURL string) (bool, *Response) {
+ requestBody := make(map[string]string)
+ requestBody["site_url"] = siteURL
+ r, err := c.DoApiPost(c.GetTestSiteURLRoute(), MapToJson(requestBody))
+ if err != nil {
+ return false, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return CheckStatusOK(r), BuildResponse(r)
+}
+
+// TestS3Connection will attempt to connect to the AWS S3.
+func (c *Client4) TestS3Connection(config *Config) (bool, *Response) {
+ r, err := c.DoApiPost(c.GetTestS3Route(), config.ToJson())
+ if err != nil {
+ return false, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return CheckStatusOK(r), BuildResponse(r)
+}
+
+// GetConfig will retrieve the server config with some sanitized items.
+func (c *Client4) GetConfig() (*Config, *Response) {
+ r, err := c.DoApiGet(c.GetConfigRoute(), "")
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return ConfigFromJson(r.Body), BuildResponse(r)
+}
+
+// ReloadConfig will reload the server configuration.
+func (c *Client4) ReloadConfig() (bool, *Response) {
+ r, err := c.DoApiPost(c.GetConfigRoute()+"/reload", "")
+ if err != nil {
+ return false, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return CheckStatusOK(r), BuildResponse(r)
+}
+
+// GetOldClientConfig will retrieve the parts of the server configuration needed by the
+// client, formatted in the old format.
+func (c *Client4) GetOldClientConfig(etag string) (map[string]string, *Response) {
+ r, err := c.DoApiGet(c.GetConfigRoute()+"/client?format=old", etag)
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return MapFromJson(r.Body), BuildResponse(r)
+}
+
+// GetEnvironmentConfig will retrieve a map mirroring the server configuration where fields
+// are set to true if the corresponding config setting is set through an environment variable.
+// Settings that haven't been set through environment variables will be missing from the map.
+func (c *Client4) GetEnvironmentConfig() (map[string]interface{}, *Response) {
+ r, err := c.DoApiGet(c.GetConfigRoute()+"/environment", "")
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return StringInterfaceFromJson(r.Body), BuildResponse(r)
+}
+
+// GetOldClientLicense will retrieve the parts of the server license needed by the
+// client, formatted in the old format.
+func (c *Client4) GetOldClientLicense(etag string) (map[string]string, *Response) {
+ r, err := c.DoApiGet(c.GetLicenseRoute()+"/client?format=old", etag)
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return MapFromJson(r.Body), BuildResponse(r)
+}
+
+// DatabaseRecycle will recycle the connections. Discard current connection and get new one.
+func (c *Client4) DatabaseRecycle() (bool, *Response) {
+ r, err := c.DoApiPost(c.GetDatabaseRoute()+"/recycle", "")
+ if err != nil {
+ return false, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return CheckStatusOK(r), BuildResponse(r)
+}
+
+// InvalidateCaches will purge the cache and can affect the performance while is cleaning.
+func (c *Client4) InvalidateCaches() (bool, *Response) {
+ r, err := c.DoApiPost(c.GetCacheRoute()+"/invalidate", "")
+ if err != nil {
+ return false, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return CheckStatusOK(r), BuildResponse(r)
+}
+
+// UpdateConfig will update the server configuration.
+func (c *Client4) UpdateConfig(config *Config) (*Config, *Response) {
+ r, err := c.DoApiPut(c.GetConfigRoute(), config.ToJson())
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return ConfigFromJson(r.Body), BuildResponse(r)
+}
+
+// UploadLicenseFile will add a license file to the system.
+func (c *Client4) UploadLicenseFile(data []byte) (bool, *Response) {
+ body := &bytes.Buffer{}
+ writer := multipart.NewWriter(body)
+
+ part, err := writer.CreateFormFile("license", "test-license.mattermost-license")
+ if err != nil {
+ return false, &Response{Error: NewAppError("UploadLicenseFile", "model.client.set_profile_user.no_file.app_error", nil, err.Error(), http.StatusBadRequest)}
+ }
+
+ if _, err = io.Copy(part, bytes.NewBuffer(data)); err != nil {
+ return false, &Response{Error: NewAppError("UploadLicenseFile", "model.client.set_profile_user.no_file.app_error", nil, err.Error(), http.StatusBadRequest)}
+ }
+
+ if err = writer.Close(); err != nil {
+ return false, &Response{Error: NewAppError("UploadLicenseFile", "model.client.set_profile_user.writer.app_error", nil, err.Error(), http.StatusBadRequest)}
+ }
+
+ rq, err := http.NewRequest("POST", c.ApiUrl+c.GetLicenseRoute(), bytes.NewReader(body.Bytes()))
+ if err != nil {
+ return false, &Response{Error: NewAppError("UploadLicenseFile", "model.client.connecting.app_error", nil, err.Error(), http.StatusBadRequest)}
+ }
+ rq.Header.Set("Content-Type", writer.FormDataContentType())
+
+ if len(c.AuthToken) > 0 {
+ rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken)
+ }
+
+ rp, err := c.HttpClient.Do(rq)
+ if err != nil || rp == nil {
+ return false, &Response{StatusCode: http.StatusForbidden, Error: NewAppError(c.GetLicenseRoute(), "model.client.connecting.app_error", nil, err.Error(), http.StatusForbidden)}
+ }
+ defer closeBody(rp)
+
+ if rp.StatusCode >= 300 {
+ return false, BuildErrorResponse(rp, AppErrorFromJson(rp.Body))
+ }
+
+ return CheckStatusOK(rp), BuildResponse(rp)
+}
+
+// RemoveLicenseFile will remove the server license it exists. Note that this will
+// disable all enterprise features.
+func (c *Client4) RemoveLicenseFile() (bool, *Response) {
+ r, err := c.DoApiDelete(c.GetLicenseRoute())
+ if err != nil {
+ return false, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return CheckStatusOK(r), BuildResponse(r)
+}
+
+// GetAnalyticsOld will retrieve analytics using the old format. New format is not
+// available but the "/analytics" endpoint is reserved for it. The "name" argument is optional
+// and defaults to "standard". The "teamId" argument is optional and will limit results
+// to a specific team.
+func (c *Client4) GetAnalyticsOld(name, teamId string) (AnalyticsRows, *Response) {
+ query := fmt.Sprintf("?name=%v&team_id=%v", name, teamId)
+ r, err := c.DoApiGet(c.GetAnalyticsRoute()+"/old"+query, "")
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return AnalyticsRowsFromJson(r.Body), BuildResponse(r)
+}
+
+// Webhooks Section
+
+// CreateIncomingWebhook creates an incoming webhook for a channel.
+func (c *Client4) CreateIncomingWebhook(hook *IncomingWebhook) (*IncomingWebhook, *Response) {
+ r, err := c.DoApiPost(c.GetIncomingWebhooksRoute(), hook.ToJson())
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return IncomingWebhookFromJson(r.Body), BuildResponse(r)
+}
+
+// UpdateIncomingWebhook updates an incoming webhook for a channel.
+func (c *Client4) UpdateIncomingWebhook(hook *IncomingWebhook) (*IncomingWebhook, *Response) {
+ r, err := c.DoApiPut(c.GetIncomingWebhookRoute(hook.Id), hook.ToJson())
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return IncomingWebhookFromJson(r.Body), BuildResponse(r)
+}
+
+// GetIncomingWebhooks returns a page of incoming webhooks on the system. Page counting starts at 0.
+func (c *Client4) GetIncomingWebhooks(page int, perPage int, etag string) ([]*IncomingWebhook, *Response) {
+ query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
+ r, err := c.DoApiGet(c.GetIncomingWebhooksRoute()+query, etag)
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return IncomingWebhookListFromJson(r.Body), BuildResponse(r)
+}
+
+// GetIncomingWebhooksForTeam returns a page of incoming webhooks for a team. Page counting starts at 0.
+func (c *Client4) GetIncomingWebhooksForTeam(teamId string, page int, perPage int, etag string) ([]*IncomingWebhook, *Response) {
+ query := fmt.Sprintf("?page=%v&per_page=%v&team_id=%v", page, perPage, teamId)
+ r, err := c.DoApiGet(c.GetIncomingWebhooksRoute()+query, etag)
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return IncomingWebhookListFromJson(r.Body), BuildResponse(r)
+}
+
+// GetIncomingWebhook returns an Incoming webhook given the hook ID.
+func (c *Client4) GetIncomingWebhook(hookID string, etag string) (*IncomingWebhook, *Response) {
+ r, err := c.DoApiGet(c.GetIncomingWebhookRoute(hookID), etag)
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return IncomingWebhookFromJson(r.Body), BuildResponse(r)
+}
+
+// DeleteIncomingWebhook deletes and Incoming Webhook given the hook ID.
+func (c *Client4) DeleteIncomingWebhook(hookID string) (bool, *Response) {
+ r, err := c.DoApiDelete(c.GetIncomingWebhookRoute(hookID))
+ if err != nil {
+ return false, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return CheckStatusOK(r), BuildResponse(r)
+}
+
+// CreateOutgoingWebhook creates an outgoing webhook for a team or channel.
+func (c *Client4) CreateOutgoingWebhook(hook *OutgoingWebhook) (*OutgoingWebhook, *Response) {
+ r, err := c.DoApiPost(c.GetOutgoingWebhooksRoute(), hook.ToJson())
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return OutgoingWebhookFromJson(r.Body), BuildResponse(r)
+}
+
+// UpdateOutgoingWebhook creates an outgoing webhook for a team or channel.
+func (c *Client4) UpdateOutgoingWebhook(hook *OutgoingWebhook) (*OutgoingWebhook, *Response) {
+ r, err := c.DoApiPut(c.GetOutgoingWebhookRoute(hook.Id), hook.ToJson())
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return OutgoingWebhookFromJson(r.Body), BuildResponse(r)
+}
+
+// GetOutgoingWebhooks returns a page of outgoing webhooks on the system. Page counting starts at 0.
+func (c *Client4) GetOutgoingWebhooks(page int, perPage int, etag string) ([]*OutgoingWebhook, *Response) {
+ query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
+ r, err := c.DoApiGet(c.GetOutgoingWebhooksRoute()+query, etag)
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return OutgoingWebhookListFromJson(r.Body), BuildResponse(r)
+}
+
+// GetOutgoingWebhook outgoing webhooks on the system requested by Hook Id.
+func (c *Client4) GetOutgoingWebhook(hookId string) (*OutgoingWebhook, *Response) {
+ r, err := c.DoApiGet(c.GetOutgoingWebhookRoute(hookId), "")
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return OutgoingWebhookFromJson(r.Body), BuildResponse(r)
+}
+
+// GetOutgoingWebhooksForChannel returns a page of outgoing webhooks for a channel. Page counting starts at 0.
+func (c *Client4) GetOutgoingWebhooksForChannel(channelId string, page int, perPage int, etag string) ([]*OutgoingWebhook, *Response) {
+ query := fmt.Sprintf("?page=%v&per_page=%v&channel_id=%v", page, perPage, channelId)
+ r, err := c.DoApiGet(c.GetOutgoingWebhooksRoute()+query, etag)
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return OutgoingWebhookListFromJson(r.Body), BuildResponse(r)
+}
+
+// GetOutgoingWebhooksForTeam returns a page of outgoing webhooks for a team. Page counting starts at 0.
+func (c *Client4) GetOutgoingWebhooksForTeam(teamId string, page int, perPage int, etag string) ([]*OutgoingWebhook, *Response) {
+ query := fmt.Sprintf("?page=%v&per_page=%v&team_id=%v", page, perPage, teamId)
+ r, err := c.DoApiGet(c.GetOutgoingWebhooksRoute()+query, etag)
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return OutgoingWebhookListFromJson(r.Body), BuildResponse(r)
+}
+
+// RegenOutgoingHookToken regenerate the outgoing webhook token.
+func (c *Client4) RegenOutgoingHookToken(hookId string) (*OutgoingWebhook, *Response) {
+ r, err := c.DoApiPost(c.GetOutgoingWebhookRoute(hookId)+"/regen_token", "")
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return OutgoingWebhookFromJson(r.Body), BuildResponse(r)
+}
+
+// DeleteOutgoingWebhook delete the outgoing webhook on the system requested by Hook Id.
+func (c *Client4) DeleteOutgoingWebhook(hookId string) (bool, *Response) {
+ r, err := c.DoApiDelete(c.GetOutgoingWebhookRoute(hookId))
+ if err != nil {
+ return false, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return CheckStatusOK(r), BuildResponse(r)
+}
+
+// Preferences Section
+
+// GetPreferences returns the user's preferences.
+func (c *Client4) GetPreferences(userId string) (Preferences, *Response) {
+ r, err := c.DoApiGet(c.GetPreferencesRoute(userId), "")
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ preferences, _ := PreferencesFromJson(r.Body)
+ return preferences, BuildResponse(r)
+}
+
+// UpdatePreferences saves the user's preferences.
+func (c *Client4) UpdatePreferences(userId string, preferences *Preferences) (bool, *Response) {
+ r, err := c.DoApiPut(c.GetPreferencesRoute(userId), preferences.ToJson())
+ if err != nil {
+ return false, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return true, BuildResponse(r)
+}
+
+// DeletePreferences deletes the user's preferences.
+func (c *Client4) DeletePreferences(userId string, preferences *Preferences) (bool, *Response) {
+ r, err := c.DoApiPost(c.GetPreferencesRoute(userId)+"/delete", preferences.ToJson())
+ if err != nil {
+ return false, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return true, BuildResponse(r)
+}
+
+// GetPreferencesByCategory returns the user's preferences from the provided category string.
+func (c *Client4) GetPreferencesByCategory(userId string, category string) (Preferences, *Response) {
+ url := fmt.Sprintf(c.GetPreferencesRoute(userId)+"/%s", category)
+ r, err := c.DoApiGet(url, "")
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ preferences, _ := PreferencesFromJson(r.Body)
+ return preferences, BuildResponse(r)
+}
+
+// GetPreferenceByCategoryAndName returns the user's preferences from the provided category and preference name string.
+func (c *Client4) GetPreferenceByCategoryAndName(userId string, category string, preferenceName string) (*Preference, *Response) {
+ url := fmt.Sprintf(c.GetPreferencesRoute(userId)+"/%s/name/%v", category, preferenceName)
+ r, err := c.DoApiGet(url, "")
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return PreferenceFromJson(r.Body), BuildResponse(r)
+}
+
+// SAML Section
+
+// GetSamlMetadata returns metadata for the SAML configuration.
+func (c *Client4) GetSamlMetadata() (string, *Response) {
+ r, err := c.DoApiGet(c.GetSamlRoute()+"/metadata", "")
+ if err != nil {
+ return "", BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ buf := new(bytes.Buffer)
+ _, _ = buf.ReadFrom(r.Body)
+ return buf.String(), BuildResponse(r)
+}
+
+func samlFileToMultipart(data []byte, filename string) ([]byte, *multipart.Writer, error) {
+ body := &bytes.Buffer{}
+ writer := multipart.NewWriter(body)
+
+ part, err := writer.CreateFormFile("certificate", filename)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ if _, err = io.Copy(part, bytes.NewBuffer(data)); err != nil {
+ return nil, nil, err
+ }
+
+ if err := writer.Close(); err != nil {
+ return nil, nil, err
+ }
+
+ return body.Bytes(), writer, nil
+}
+
+// UploadSamlIdpCertificate will upload an IDP certificate for SAML and set the config to use it.
+// The filename parameter is deprecated and ignored: the server will pick a hard-coded filename when writing to disk.
+func (c *Client4) UploadSamlIdpCertificate(data []byte, filename string) (bool, *Response) {
+ body, writer, err := samlFileToMultipart(data, filename)
+ if err != nil {
+ return false, &Response{Error: NewAppError("UploadSamlIdpCertificate", "model.client.upload_saml_cert.app_error", nil, err.Error(), http.StatusBadRequest)}
+ }
+
+ _, resp := c.DoUploadFile(c.GetSamlRoute()+"/certificate/idp", body, writer.FormDataContentType())
+ return resp.Error == nil, resp
+}
+
+// UploadSamlPublicCertificate will upload a public certificate for SAML and set the config to use it.
+// The filename parameter is deprecated and ignored: the server will pick a hard-coded filename when writing to disk.
+func (c *Client4) UploadSamlPublicCertificate(data []byte, filename string) (bool, *Response) {
+ body, writer, err := samlFileToMultipart(data, filename)
+ if err != nil {
+ return false, &Response{Error: NewAppError("UploadSamlPublicCertificate", "model.client.upload_saml_cert.app_error", nil, err.Error(), http.StatusBadRequest)}
+ }
+
+ _, resp := c.DoUploadFile(c.GetSamlRoute()+"/certificate/public", body, writer.FormDataContentType())
+ return resp.Error == nil, resp
+}
+
+// UploadSamlPrivateCertificate will upload a private key for SAML and set the config to use it.
+// The filename parameter is deprecated and ignored: the server will pick a hard-coded filename when writing to disk.
+func (c *Client4) UploadSamlPrivateCertificate(data []byte, filename string) (bool, *Response) {
+ body, writer, err := samlFileToMultipart(data, filename)
+ if err != nil {
+ return false, &Response{Error: NewAppError("UploadSamlPrivateCertificate", "model.client.upload_saml_cert.app_error", nil, err.Error(), http.StatusBadRequest)}
+ }
+
+ _, resp := c.DoUploadFile(c.GetSamlRoute()+"/certificate/private", body, writer.FormDataContentType())
+ return resp.Error == nil, resp
+}
+
+// DeleteSamlIdpCertificate deletes the SAML IDP certificate from the server and updates the config to not use it and disable SAML.
+func (c *Client4) DeleteSamlIdpCertificate() (bool, *Response) {
+ r, err := c.DoApiDelete(c.GetSamlRoute() + "/certificate/idp")
+ if err != nil {
+ return false, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return CheckStatusOK(r), BuildResponse(r)
+}
+
+// DeleteSamlPublicCertificate deletes the SAML IDP certificate from the server and updates the config to not use it and disable SAML.
+func (c *Client4) DeleteSamlPublicCertificate() (bool, *Response) {
+ r, err := c.DoApiDelete(c.GetSamlRoute() + "/certificate/public")
+ if err != nil {
+ return false, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return CheckStatusOK(r), BuildResponse(r)
+}
+
+// DeleteSamlPrivateCertificate deletes the SAML IDP certificate from the server and updates the config to not use it and disable SAML.
+func (c *Client4) DeleteSamlPrivateCertificate() (bool, *Response) {
+ r, err := c.DoApiDelete(c.GetSamlRoute() + "/certificate/private")
+ if err != nil {
+ return false, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return CheckStatusOK(r), BuildResponse(r)
+}
+
+// GetSamlCertificateStatus returns metadata for the SAML configuration.
+func (c *Client4) GetSamlCertificateStatus() (*SamlCertificateStatus, *Response) {
+ r, err := c.DoApiGet(c.GetSamlRoute()+"/certificate/status", "")
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return SamlCertificateStatusFromJson(r.Body), BuildResponse(r)
+}
+
+func (c *Client4) GetSamlMetadataFromIdp(samlMetadataURL string) (*SamlMetadataResponse, *Response) {
+ requestBody := make(map[string]string)
+ requestBody["saml_metadata_url"] = samlMetadataURL
+ r, err := c.DoApiPost(c.GetSamlRoute()+"/metadatafromidp", MapToJson(requestBody))
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+
+ defer closeBody(r)
+ return SamlMetadataResponseFromJson(r.Body), BuildResponse(r)
+}
+
+// Compliance Section
+
+// CreateComplianceReport creates an incoming webhook for a channel.
+func (c *Client4) CreateComplianceReport(report *Compliance) (*Compliance, *Response) {
+ r, err := c.DoApiPost(c.GetComplianceReportsRoute(), report.ToJson())
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return ComplianceFromJson(r.Body), BuildResponse(r)
+}
+
+// GetComplianceReports returns list of compliance reports.
+func (c *Client4) GetComplianceReports(page, perPage int) (Compliances, *Response) {
+ query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
+ r, err := c.DoApiGet(c.GetComplianceReportsRoute()+query, "")
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return CompliancesFromJson(r.Body), BuildResponse(r)
+}
+
+// GetComplianceReport returns a compliance report.
+func (c *Client4) GetComplianceReport(reportId string) (*Compliance, *Response) {
+ r, err := c.DoApiGet(c.GetComplianceReportRoute(reportId), "")
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return ComplianceFromJson(r.Body), BuildResponse(r)
+}
+
+// DownloadComplianceReport returns a full compliance report as a file.
+func (c *Client4) DownloadComplianceReport(reportId string) ([]byte, *Response) {
+ rq, err := http.NewRequest("GET", c.ApiUrl+c.GetComplianceReportRoute(reportId), nil)
+ if err != nil {
+ return nil, &Response{Error: NewAppError("DownloadComplianceReport", "model.client.connecting.app_error", nil, err.Error(), http.StatusBadRequest)}
+ }
+
+ if len(c.AuthToken) > 0 {
+ rq.Header.Set(HEADER_AUTH, "BEARER "+c.AuthToken)
+ }
+
+ rp, err := c.HttpClient.Do(rq)
+ if err != nil || rp == nil {
+ return nil, &Response{Error: NewAppError("DownloadComplianceReport", "model.client.connecting.app_error", nil, err.Error(), http.StatusBadRequest)}
+ }
+ defer closeBody(rp)
+
+ if rp.StatusCode >= 300 {
+ return nil, BuildErrorResponse(rp, AppErrorFromJson(rp.Body))
+ }
+
+ data, err := ioutil.ReadAll(rp.Body)
+ if err != nil {
+ return nil, BuildErrorResponse(rp, NewAppError("DownloadComplianceReport", "model.client.read_file.app_error", nil, err.Error(), rp.StatusCode))
+ }
+
+ return data, BuildResponse(rp)
+}
+
+// Cluster Section
+
+// GetClusterStatus returns the status of all the configured cluster nodes.
+func (c *Client4) GetClusterStatus() ([]*ClusterInfo, *Response) {
+ r, err := c.DoApiGet(c.GetClusterRoute()+"/status", "")
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return ClusterInfosFromJson(r.Body), BuildResponse(r)
+}
+
+// LDAP Section
+
+// SyncLdap will force a sync with the configured LDAP server.
+func (c *Client4) SyncLdap() (bool, *Response) {
+ r, err := c.DoApiPost(c.GetLdapRoute()+"/sync", "")
+ if err != nil {
+ return false, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return CheckStatusOK(r), BuildResponse(r)
+}
+
+// TestLdap will attempt to connect to the configured LDAP server and return OK if configured
+// correctly.
+func (c *Client4) TestLdap() (bool, *Response) {
+ r, err := c.DoApiPost(c.GetLdapRoute()+"/test", "")
+ if err != nil {
+ return false, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return CheckStatusOK(r), BuildResponse(r)
+}
+
+// GetLdapGroups retrieves the immediate child groups of the given parent group.
+func (c *Client4) GetLdapGroups() ([]*Group, *Response) {
+ path := fmt.Sprintf("%s/groups", c.GetLdapRoute())
+
+ r, appErr := c.DoApiGet(path, "")
+ if appErr != nil {
+ return nil, BuildErrorResponse(r, appErr)
+ }
+ defer closeBody(r)
+
+ return GroupsFromJson(r.Body), BuildResponse(r)
+}
+
+// LinkLdapGroup creates or undeletes a Mattermost group and associates it to the given LDAP group DN.
+func (c *Client4) LinkLdapGroup(dn string) (*Group, *Response) {
+ path := fmt.Sprintf("%s/groups/%s/link", c.GetLdapRoute(), dn)
+
+ r, appErr := c.DoApiPost(path, "")
+ if appErr != nil {
+ return nil, BuildErrorResponse(r, appErr)
+ }
+ defer closeBody(r)
+
+ return GroupFromJson(r.Body), BuildResponse(r)
+}
+
+// UnlinkLdapGroup deletes the Mattermost group associated with the given LDAP group DN.
+func (c *Client4) UnlinkLdapGroup(dn string) (*Group, *Response) {
+ path := fmt.Sprintf("%s/groups/%s/link", c.GetLdapRoute(), dn)
+
+ r, appErr := c.DoApiDelete(path)
+ if appErr != nil {
+ return nil, BuildErrorResponse(r, appErr)
+ }
+ defer closeBody(r)
+
+ return GroupFromJson(r.Body), BuildResponse(r)
+}
+
+// GetGroupsByChannel retrieves the Mattermost Groups associated with a given channel
+func (c *Client4) GetGroupsByChannel(channelId string, opts GroupSearchOpts) ([]*GroupWithSchemeAdmin, int, *Response) {
+ path := fmt.Sprintf("%s/groups?q=%v&include_member_count=%v&filter_allow_reference=%v", c.GetChannelRoute(channelId), opts.Q, opts.IncludeMemberCount, opts.FilterAllowReference)
+ if opts.PageOpts != nil {
+ path = fmt.Sprintf("%s&page=%v&per_page=%v", path, opts.PageOpts.Page, opts.PageOpts.PerPage)
+ }
+ r, appErr := c.DoApiGet(path, "")
+ if appErr != nil {
+ return nil, 0, BuildErrorResponse(r, appErr)
+ }
+ defer closeBody(r)
+
+ responseData := struct {
+ Groups []*GroupWithSchemeAdmin `json:"groups"`
+ Count int `json:"total_group_count"`
+ }{}
+ if err := json.NewDecoder(r.Body).Decode(&responseData); err != nil {
+ appErr := NewAppError("Api4.GetGroupsByChannel", "api.marshal_error", nil, err.Error(), http.StatusInternalServerError)
+ return nil, 0, BuildErrorResponse(r, appErr)
+ }
+
+ return responseData.Groups, responseData.Count, BuildResponse(r)
+}
+
+// GetGroupsByTeam retrieves the Mattermost Groups associated with a given team
+func (c *Client4) GetGroupsByTeam(teamId string, opts GroupSearchOpts) ([]*GroupWithSchemeAdmin, int, *Response) {
+ path := fmt.Sprintf("%s/groups?q=%v&include_member_count=%v&filter_allow_reference=%v", c.GetTeamRoute(teamId), opts.Q, opts.IncludeMemberCount, opts.FilterAllowReference)
+ if opts.PageOpts != nil {
+ path = fmt.Sprintf("%s&page=%v&per_page=%v", path, opts.PageOpts.Page, opts.PageOpts.PerPage)
+ }
+ r, appErr := c.DoApiGet(path, "")
+ if appErr != nil {
+ return nil, 0, BuildErrorResponse(r, appErr)
+ }
+ defer closeBody(r)
+
+ responseData := struct {
+ Groups []*GroupWithSchemeAdmin `json:"groups"`
+ Count int `json:"total_group_count"`
+ }{}
+ if err := json.NewDecoder(r.Body).Decode(&responseData); err != nil {
+ appErr := NewAppError("Api4.GetGroupsByTeam", "api.marshal_error", nil, err.Error(), http.StatusInternalServerError)
+ return nil, 0, BuildErrorResponse(r, appErr)
+ }
+
+ return responseData.Groups, responseData.Count, BuildResponse(r)
+}
+
+// GetGroupsAssociatedToChannelsByTeam retrieves the Mattermost Groups associated with channels in a given team
+func (c *Client4) GetGroupsAssociatedToChannelsByTeam(teamId string, opts GroupSearchOpts) (map[string][]*GroupWithSchemeAdmin, *Response) {
+ path := fmt.Sprintf("%s/groups_by_channels?q=%v&filter_allow_reference=%v", c.GetTeamRoute(teamId), opts.Q, opts.FilterAllowReference)
+ if opts.PageOpts != nil {
+ path = fmt.Sprintf("%s&page=%v&per_page=%v", path, opts.PageOpts.Page, opts.PageOpts.PerPage)
+ }
+ r, appErr := c.DoApiGet(path, "")
+ if appErr != nil {
+ return nil, BuildErrorResponse(r, appErr)
+ }
+ defer closeBody(r)
+
+ responseData := struct {
+ GroupsAssociatedToChannels map[string][]*GroupWithSchemeAdmin `json:"groups"`
+ }{}
+ if err := json.NewDecoder(r.Body).Decode(&responseData); err != nil {
+ appErr := NewAppError("Api4.GetGroupsAssociatedToChannelsByTeam", "api.marshal_error", nil, err.Error(), http.StatusInternalServerError)
+ return nil, BuildErrorResponse(r, appErr)
+ }
+
+ return responseData.GroupsAssociatedToChannels, BuildResponse(r)
+}
+
+// GetGroups retrieves Mattermost Groups
+func (c *Client4) GetGroups(opts GroupSearchOpts) ([]*Group, *Response) {
+ path := fmt.Sprintf(
+ "%s?include_member_count=%v&not_associated_to_team=%v&not_associated_to_channel=%v&filter_allow_reference=%v&q=%v&filter_parent_team_permitted=%v",
+ c.GetGroupsRoute(),
+ opts.IncludeMemberCount,
+ opts.NotAssociatedToTeam,
+ opts.NotAssociatedToChannel,
+ opts.FilterAllowReference,
+ opts.Q,
+ opts.FilterParentTeamPermitted,
+ )
+ if opts.Since > 0 {
+ path = fmt.Sprintf("%s&since=%v", path, opts.Since)
+ }
+ if opts.PageOpts != nil {
+ path = fmt.Sprintf("%s&page=%v&per_page=%v", path, opts.PageOpts.Page, opts.PageOpts.PerPage)
+ }
+ r, appErr := c.DoApiGet(path, "")
+ if appErr != nil {
+ return nil, BuildErrorResponse(r, appErr)
+ }
+ defer closeBody(r)
+
+ return GroupsFromJson(r.Body), BuildResponse(r)
+}
+
+// GetGroupsByUserId retrieves Mattermost Groups for a user
+func (c *Client4) GetGroupsByUserId(userId string) ([]*Group, *Response) {
+ path := fmt.Sprintf(
+ "%s/%v/groups",
+ c.GetUsersRoute(),
+ userId,
+ )
+
+ r, appErr := c.DoApiGet(path, "")
+ if appErr != nil {
+ return nil, BuildErrorResponse(r, appErr)
+ }
+ defer closeBody(r)
+ return GroupsFromJson(r.Body), BuildResponse(r)
+}
+
+// Audits Section
+
+// GetAudits returns a list of audits for the whole system.
+func (c *Client4) GetAudits(page int, perPage int, etag string) (Audits, *Response) {
+ query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
+ r, err := c.DoApiGet("/audits"+query, etag)
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return AuditsFromJson(r.Body), BuildResponse(r)
+}
+
+// Brand Section
+
+// GetBrandImage retrieves the previously uploaded brand image.
+func (c *Client4) GetBrandImage() ([]byte, *Response) {
+ r, appErr := c.DoApiGet(c.GetBrandRoute()+"/image", "")
+ if appErr != nil {
+ return nil, BuildErrorResponse(r, appErr)
+ }
+ defer closeBody(r)
+
+ if r.StatusCode >= 300 {
+ return nil, BuildErrorResponse(r, AppErrorFromJson(r.Body))
+ }
+
+ data, err := ioutil.ReadAll(r.Body)
+ if err != nil {
+ return nil, BuildErrorResponse(r, NewAppError("GetBrandImage", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode))
+ }
+
+ return data, BuildResponse(r)
+}
+
+// DeleteBrandImage deletes the brand image for the system.
+func (c *Client4) DeleteBrandImage() *Response {
+ r, err := c.DoApiDelete(c.GetBrandRoute() + "/image")
+ if err != nil {
+ return BuildErrorResponse(r, err)
+ }
+ return BuildResponse(r)
+}
+
+// UploadBrandImage sets the brand image for the system.
+func (c *Client4) UploadBrandImage(data []byte) (bool, *Response) {
+ body := &bytes.Buffer{}
+ writer := multipart.NewWriter(body)
+
+ part, err := writer.CreateFormFile("image", "brand.png")
+ if err != nil {
+ return false, &Response{Error: NewAppError("UploadBrandImage", "model.client.set_profile_user.no_file.app_error", nil, err.Error(), http.StatusBadRequest)}
+ }
+
+ if _, err = io.Copy(part, bytes.NewBuffer(data)); err != nil {
+ return false, &Response{Error: NewAppError("UploadBrandImage", "model.client.set_profile_user.no_file.app_error", nil, err.Error(), http.StatusBadRequest)}
+ }
+
+ if err = writer.Close(); err != nil {
+ return false, &Response{Error: NewAppError("UploadBrandImage", "model.client.set_profile_user.writer.app_error", nil, err.Error(), http.StatusBadRequest)}
+ }
+
+ rq, err := http.NewRequest("POST", c.ApiUrl+c.GetBrandRoute()+"/image", bytes.NewReader(body.Bytes()))
+ if err != nil {
+ return false, &Response{Error: NewAppError("UploadBrandImage", "model.client.connecting.app_error", nil, err.Error(), http.StatusBadRequest)}
+ }
+ rq.Header.Set("Content-Type", writer.FormDataContentType())
+
+ if len(c.AuthToken) > 0 {
+ rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken)
+ }
+
+ rp, err := c.HttpClient.Do(rq)
+ if err != nil || rp == nil {
+ return false, &Response{StatusCode: http.StatusForbidden, Error: NewAppError(c.GetBrandRoute()+"/image", "model.client.connecting.app_error", nil, err.Error(), http.StatusForbidden)}
+ }
+ defer closeBody(rp)
+
+ if rp.StatusCode >= 300 {
+ return false, BuildErrorResponse(rp, AppErrorFromJson(rp.Body))
+ }
+
+ return CheckStatusOK(rp), BuildResponse(rp)
+}
+
+// Logs Section
+
+// GetLogs page of logs as a string array.
+func (c *Client4) GetLogs(page, perPage int) ([]string, *Response) {
+ query := fmt.Sprintf("?page=%v&logs_per_page=%v", page, perPage)
+ r, err := c.DoApiGet("/logs"+query, "")
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return ArrayFromJson(r.Body), BuildResponse(r)
+}
+
+// PostLog is a convenience Web Service call so clients can log messages into
+// the server-side logs. For example we typically log javascript error messages
+// into the server-side. It returns the log message if the logging was successful.
+func (c *Client4) PostLog(message map[string]string) (map[string]string, *Response) {
+ r, err := c.DoApiPost("/logs", MapToJson(message))
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return MapFromJson(r.Body), BuildResponse(r)
+}
+
+// OAuth Section
+
+// CreateOAuthApp will register a new OAuth 2.0 client application with Mattermost acting as an OAuth 2.0 service provider.
+func (c *Client4) CreateOAuthApp(app *OAuthApp) (*OAuthApp, *Response) {
+ r, err := c.DoApiPost(c.GetOAuthAppsRoute(), app.ToJson())
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return OAuthAppFromJson(r.Body), BuildResponse(r)
+}
+
+// UpdateOAuthApp updates a page of registered OAuth 2.0 client applications with Mattermost acting as an OAuth 2.0 service provider.
+func (c *Client4) UpdateOAuthApp(app *OAuthApp) (*OAuthApp, *Response) {
+ r, err := c.DoApiPut(c.GetOAuthAppRoute(app.Id), app.ToJson())
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return OAuthAppFromJson(r.Body), BuildResponse(r)
+}
+
+// GetOAuthApps gets a page of registered OAuth 2.0 client applications with Mattermost acting as an OAuth 2.0 service provider.
+func (c *Client4) GetOAuthApps(page, perPage int) ([]*OAuthApp, *Response) {
+ query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
+ r, err := c.DoApiGet(c.GetOAuthAppsRoute()+query, "")
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return OAuthAppListFromJson(r.Body), BuildResponse(r)
+}
+
+// GetOAuthApp gets a registered OAuth 2.0 client application with Mattermost acting as an OAuth 2.0 service provider.
+func (c *Client4) GetOAuthApp(appId string) (*OAuthApp, *Response) {
+ r, err := c.DoApiGet(c.GetOAuthAppRoute(appId), "")
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return OAuthAppFromJson(r.Body), BuildResponse(r)
+}
+
+// GetOAuthAppInfo gets a sanitized version of a registered OAuth 2.0 client application with Mattermost acting as an OAuth 2.0 service provider.
+func (c *Client4) GetOAuthAppInfo(appId string) (*OAuthApp, *Response) {
+ r, err := c.DoApiGet(c.GetOAuthAppRoute(appId)+"/info", "")
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return OAuthAppFromJson(r.Body), BuildResponse(r)
+}
+
+// DeleteOAuthApp deletes a registered OAuth 2.0 client application.
+func (c *Client4) DeleteOAuthApp(appId string) (bool, *Response) {
+ r, err := c.DoApiDelete(c.GetOAuthAppRoute(appId))
+ if err != nil {
+ return false, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return CheckStatusOK(r), BuildResponse(r)
+}
+
+// RegenerateOAuthAppSecret regenerates the client secret for a registered OAuth 2.0 client application.
+func (c *Client4) RegenerateOAuthAppSecret(appId string) (*OAuthApp, *Response) {
+ r, err := c.DoApiPost(c.GetOAuthAppRoute(appId)+"/regen_secret", "")
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return OAuthAppFromJson(r.Body), BuildResponse(r)
+}
+
+// GetAuthorizedOAuthAppsForUser gets a page of OAuth 2.0 client applications the user has authorized to use access their account.
+func (c *Client4) GetAuthorizedOAuthAppsForUser(userId string, page, perPage int) ([]*OAuthApp, *Response) {
+ query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
+ r, err := c.DoApiGet(c.GetUserRoute(userId)+"/oauth/apps/authorized"+query, "")
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return OAuthAppListFromJson(r.Body), BuildResponse(r)
+}
+
+// AuthorizeOAuthApp will authorize an OAuth 2.0 client application to access a user's account and provide a redirect link to follow.
+func (c *Client4) AuthorizeOAuthApp(authRequest *AuthorizeRequest) (string, *Response) {
+ r, err := c.DoApiRequest(http.MethodPost, c.Url+"/oauth/authorize", authRequest.ToJson(), "")
+ if err != nil {
+ return "", BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return MapFromJson(r.Body)["redirect"], BuildResponse(r)
+}
+
+// DeauthorizeOAuthApp will deauthorize an OAuth 2.0 client application from accessing a user's account.
+func (c *Client4) DeauthorizeOAuthApp(appId string) (bool, *Response) {
+ requestData := map[string]string{"client_id": appId}
+ r, err := c.DoApiRequest(http.MethodPost, c.Url+"/oauth/deauthorize", MapToJson(requestData), "")
+ if err != nil {
+ return false, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return CheckStatusOK(r), BuildResponse(r)
+}
+
+// GetOAuthAccessToken is a test helper function for the OAuth access token endpoint.
+func (c *Client4) GetOAuthAccessToken(data url.Values) (*AccessResponse, *Response) {
+ rq, err := http.NewRequest(http.MethodPost, c.Url+"/oauth/access_token", strings.NewReader(data.Encode()))
+ if err != nil {
+ return nil, &Response{Error: NewAppError(c.Url+"/oauth/access_token", "model.client.connecting.app_error", nil, err.Error(), http.StatusBadRequest)}
+ }
+ rq.Header.Set("Content-Type", "application/x-www-form-urlencoded")
+
+ if len(c.AuthToken) > 0 {
+ rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken)
+ }
+
+ rp, err := c.HttpClient.Do(rq)
+ if err != nil || rp == nil {
+ return nil, &Response{StatusCode: http.StatusForbidden, Error: NewAppError(c.Url+"/oauth/access_token", "model.client.connecting.app_error", nil, err.Error(), 403)}
+ }
+ defer closeBody(rp)
+
+ if rp.StatusCode >= 300 {
+ return nil, BuildErrorResponse(rp, AppErrorFromJson(rp.Body))
+ }
+
+ return AccessResponseFromJson(rp.Body), BuildResponse(rp)
+}
+
+// Elasticsearch Section
+
+// TestElasticsearch will attempt to connect to the configured Elasticsearch server and return OK if configured.
+// correctly.
+func (c *Client4) TestElasticsearch() (bool, *Response) {
+ r, err := c.DoApiPost(c.GetElasticsearchRoute()+"/test", "")
+ if err != nil {
+ return false, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return CheckStatusOK(r), BuildResponse(r)
+}
+
+// PurgeElasticsearchIndexes immediately deletes all Elasticsearch indexes.
+func (c *Client4) PurgeElasticsearchIndexes() (bool, *Response) {
+ r, err := c.DoApiPost(c.GetElasticsearchRoute()+"/purge_indexes", "")
+ if err != nil {
+ return false, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return CheckStatusOK(r), BuildResponse(r)
+}
+
+// Bleve Section
+
+// PurgeBleveIndexes immediately deletes all Bleve indexes.
+func (c *Client4) PurgeBleveIndexes() (bool, *Response) {
+ r, err := c.DoApiPost(c.GetBleveRoute()+"/purge_indexes", "")
+ if err != nil {
+ return false, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return CheckStatusOK(r), BuildResponse(r)
+}
+
+// Data Retention Section
+
+// GetDataRetentionPolicy will get the current server data retention policy details.
+func (c *Client4) GetDataRetentionPolicy() (*DataRetentionPolicy, *Response) {
+ r, err := c.DoApiGet(c.GetDataRetentionRoute()+"/policy", "")
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return DataRetentionPolicyFromJson(r.Body), BuildResponse(r)
+}
+
+// Commands Section
+
+// CreateCommand will create a new command if the user have the right permissions.
+func (c *Client4) CreateCommand(cmd *Command) (*Command, *Response) {
+ r, err := c.DoApiPost(c.GetCommandsRoute(), cmd.ToJson())
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return CommandFromJson(r.Body), BuildResponse(r)
+}
+
+// UpdateCommand updates a command based on the provided Command struct.
+func (c *Client4) UpdateCommand(cmd *Command) (*Command, *Response) {
+ r, err := c.DoApiPut(c.GetCommandRoute(cmd.Id), cmd.ToJson())
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return CommandFromJson(r.Body), BuildResponse(r)
+}
+
+// MoveCommand moves a command to a different team.
+func (c *Client4) MoveCommand(teamId string, commandId string) (bool, *Response) {
+ cmr := CommandMoveRequest{TeamId: teamId}
+ r, err := c.DoApiPut(c.GetCommandMoveRoute(commandId), cmr.ToJson())
+ if err != nil {
+ return false, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return CheckStatusOK(r), BuildResponse(r)
+}
+
+// DeleteCommand deletes a command based on the provided command id string.
+func (c *Client4) DeleteCommand(commandId string) (bool, *Response) {
+ r, err := c.DoApiDelete(c.GetCommandRoute(commandId))
+ if err != nil {
+ return false, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return CheckStatusOK(r), BuildResponse(r)
+}
+
+// ListCommands will retrieve a list of commands available in the team.
+func (c *Client4) ListCommands(teamId string, customOnly bool) ([]*Command, *Response) {
+ query := fmt.Sprintf("?team_id=%v&custom_only=%v", teamId, customOnly)
+ r, err := c.DoApiGet(c.GetCommandsRoute()+query, "")
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return CommandListFromJson(r.Body), BuildResponse(r)
+}
+
+// ListCommandAutocompleteSuggestions will retrieve a list of suggestions for a userInput.
+func (c *Client4) ListCommandAutocompleteSuggestions(userInput, teamId string) ([]AutocompleteSuggestion, *Response) {
+ query := fmt.Sprintf("/commands/autocomplete_suggestions?user_input=%v", userInput)
+ r, err := c.DoApiGet(c.GetTeamRoute(teamId)+query, "")
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return AutocompleteSuggestionsFromJSON(r.Body), BuildResponse(r)
+}
+
+// GetCommandById will retrieve a command by id.
+func (c *Client4) GetCommandById(cmdId string) (*Command, *Response) {
+ url := fmt.Sprintf("%s/%s", c.GetCommandsRoute(), cmdId)
+ r, err := c.DoApiGet(url, "")
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return CommandFromJson(r.Body), BuildResponse(r)
+}
+
+// ExecuteCommand executes a given slash command.
+func (c *Client4) ExecuteCommand(channelId, command string) (*CommandResponse, *Response) {
+ commandArgs := &CommandArgs{
+ ChannelId: channelId,
+ Command: command,
+ }
+ r, err := c.DoApiPost(c.GetCommandsRoute()+"/execute", commandArgs.ToJson())
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+
+ response, _ := CommandResponseFromJson(r.Body)
+ return response, BuildResponse(r)
+}
+
+// ExecuteCommandWithTeam executes a given slash command against the specified team.
+// Use this when executing slash commands in a DM/GM, since the team id cannot be inferred in that case.
+func (c *Client4) ExecuteCommandWithTeam(channelId, teamId, command string) (*CommandResponse, *Response) {
+ commandArgs := &CommandArgs{
+ ChannelId: channelId,
+ TeamId: teamId,
+ Command: command,
+ }
+ r, err := c.DoApiPost(c.GetCommandsRoute()+"/execute", commandArgs.ToJson())
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+
+ response, _ := CommandResponseFromJson(r.Body)
+ return response, BuildResponse(r)
+}
+
+// ListAutocompleteCommands will retrieve a list of commands available in the team.
+func (c *Client4) ListAutocompleteCommands(teamId string) ([]*Command, *Response) {
+ r, err := c.DoApiGet(c.GetTeamAutoCompleteCommandsRoute(teamId), "")
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return CommandListFromJson(r.Body), BuildResponse(r)
+}
+
+// RegenCommandToken will create a new token if the user have the right permissions.
+func (c *Client4) RegenCommandToken(commandId string) (string, *Response) {
+ r, err := c.DoApiPut(c.GetCommandRoute(commandId)+"/regen_token", "")
+ if err != nil {
+ return "", BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return MapFromJson(r.Body)["token"], BuildResponse(r)
+}
+
+// Status Section
+
+// GetUserStatus returns a user based on the provided user id string.
+func (c *Client4) GetUserStatus(userId, etag string) (*Status, *Response) {
+ r, err := c.DoApiGet(c.GetUserStatusRoute(userId), etag)
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return StatusFromJson(r.Body), BuildResponse(r)
+}
+
+// GetUsersStatusesByIds returns a list of users status based on the provided user ids.
+func (c *Client4) GetUsersStatusesByIds(userIds []string) ([]*Status, *Response) {
+ r, err := c.DoApiPost(c.GetUserStatusesRoute()+"/ids", ArrayToJson(userIds))
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return StatusListFromJson(r.Body), BuildResponse(r)
+}
+
+// UpdateUserStatus sets a user's status based on the provided user id string.
+func (c *Client4) UpdateUserStatus(userId string, userStatus *Status) (*Status, *Response) {
+ r, err := c.DoApiPut(c.GetUserStatusRoute(userId), userStatus.ToJson())
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return StatusFromJson(r.Body), BuildResponse(r)
+}
+
+// Emoji Section
+
+// CreateEmoji will save an emoji to the server if the current user has permission
+// to do so. If successful, the provided emoji will be returned with its Id field
+// filled in. Otherwise, an error will be returned.
+func (c *Client4) CreateEmoji(emoji *Emoji, image []byte, filename string) (*Emoji, *Response) {
+ body := &bytes.Buffer{}
+ writer := multipart.NewWriter(body)
+
+ part, err := writer.CreateFormFile("image", filename)
+ if err != nil {
+ return nil, &Response{StatusCode: http.StatusForbidden, Error: NewAppError("CreateEmoji", "model.client.create_emoji.image.app_error", nil, err.Error(), 0)}
+ }
+
+ if _, err := io.Copy(part, bytes.NewBuffer(image)); err != nil {
+ return nil, &Response{StatusCode: http.StatusForbidden, Error: NewAppError("CreateEmoji", "model.client.create_emoji.image.app_error", nil, err.Error(), 0)}
+ }
+
+ if err := writer.WriteField("emoji", emoji.ToJson()); err != nil {
+ return nil, &Response{StatusCode: http.StatusForbidden, Error: NewAppError("CreateEmoji", "model.client.create_emoji.emoji.app_error", nil, err.Error(), 0)}
+ }
+
+ if err := writer.Close(); err != nil {
+ return nil, &Response{StatusCode: http.StatusForbidden, Error: NewAppError("CreateEmoji", "model.client.create_emoji.writer.app_error", nil, err.Error(), 0)}
+ }
+
+ return c.DoEmojiUploadFile(c.GetEmojisRoute(), body.Bytes(), writer.FormDataContentType())
+}
+
+// GetEmojiList returns a page of custom emoji on the system.
+func (c *Client4) GetEmojiList(page, perPage int) ([]*Emoji, *Response) {
+ query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
+ r, err := c.DoApiGet(c.GetEmojisRoute()+query, "")
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return EmojiListFromJson(r.Body), BuildResponse(r)
+}
+
+// GetSortedEmojiList returns a page of custom emoji on the system sorted based on the sort
+// parameter, blank for no sorting and "name" to sort by emoji names.
+func (c *Client4) GetSortedEmojiList(page, perPage int, sort string) ([]*Emoji, *Response) {
+ query := fmt.Sprintf("?page=%v&per_page=%v&sort=%v", page, perPage, sort)
+ r, err := c.DoApiGet(c.GetEmojisRoute()+query, "")
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return EmojiListFromJson(r.Body), BuildResponse(r)
+}
+
+// DeleteEmoji delete an custom emoji on the provided emoji id string.
+func (c *Client4) DeleteEmoji(emojiId string) (bool, *Response) {
+ r, err := c.DoApiDelete(c.GetEmojiRoute(emojiId))
+ if err != nil {
+ return false, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return CheckStatusOK(r), BuildResponse(r)
+}
+
+// GetEmoji returns a custom emoji based on the emojiId string.
+func (c *Client4) GetEmoji(emojiId string) (*Emoji, *Response) {
+ r, err := c.DoApiGet(c.GetEmojiRoute(emojiId), "")
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return EmojiFromJson(r.Body), BuildResponse(r)
+}
+
+// GetEmojiByName returns a custom emoji based on the name string.
+func (c *Client4) GetEmojiByName(name string) (*Emoji, *Response) {
+ r, err := c.DoApiGet(c.GetEmojiByNameRoute(name), "")
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return EmojiFromJson(r.Body), BuildResponse(r)
+}
+
+// GetEmojiImage returns the emoji image.
+func (c *Client4) GetEmojiImage(emojiId string) ([]byte, *Response) {
+ r, apErr := c.DoApiGet(c.GetEmojiRoute(emojiId)+"/image", "")
+ if apErr != nil {
+ return nil, BuildErrorResponse(r, apErr)
+ }
+ defer closeBody(r)
+
+ data, err := ioutil.ReadAll(r.Body)
+ if err != nil {
+ return nil, BuildErrorResponse(r, NewAppError("GetEmojiImage", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode))
+ }
+
+ return data, BuildResponse(r)
+}
+
+// SearchEmoji returns a list of emoji matching some search criteria.
+func (c *Client4) SearchEmoji(search *EmojiSearch) ([]*Emoji, *Response) {
+ r, err := c.DoApiPost(c.GetEmojisRoute()+"/search", search.ToJson())
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return EmojiListFromJson(r.Body), BuildResponse(r)
+}
+
+// AutocompleteEmoji returns a list of emoji starting with or matching name.
+func (c *Client4) AutocompleteEmoji(name string, etag string) ([]*Emoji, *Response) {
+ query := fmt.Sprintf("?name=%v", name)
+ r, err := c.DoApiGet(c.GetEmojisRoute()+"/autocomplete"+query, "")
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return EmojiListFromJson(r.Body), BuildResponse(r)
+}
+
+// Reaction Section
+
+// SaveReaction saves an emoji reaction for a post. Returns the saved reaction if successful, otherwise an error will be returned.
+func (c *Client4) SaveReaction(reaction *Reaction) (*Reaction, *Response) {
+ r, err := c.DoApiPost(c.GetReactionsRoute(), reaction.ToJson())
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return ReactionFromJson(r.Body), BuildResponse(r)
+}
+
+// GetReactions returns a list of reactions to a post.
+func (c *Client4) GetReactions(postId string) ([]*Reaction, *Response) {
+ r, err := c.DoApiGet(c.GetPostRoute(postId)+"/reactions", "")
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return ReactionsFromJson(r.Body), BuildResponse(r)
+}
+
+// DeleteReaction deletes reaction of a user in a post.
+func (c *Client4) DeleteReaction(reaction *Reaction) (bool, *Response) {
+ r, err := c.DoApiDelete(c.GetUserRoute(reaction.UserId) + c.GetPostRoute(reaction.PostId) + fmt.Sprintf("/reactions/%v", reaction.EmojiName))
+ if err != nil {
+ return false, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return CheckStatusOK(r), BuildResponse(r)
+}
+
+// FetchBulkReactions returns a map of postIds and corresponding reactions
+func (c *Client4) GetBulkReactions(postIds []string) (map[string][]*Reaction, *Response) {
+ r, err := c.DoApiPost(c.GetPostsRoute()+"/ids/reactions", ArrayToJson(postIds))
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return MapPostIdToReactionsFromJson(r.Body), BuildResponse(r)
+}
+
+// Timezone Section
+
+// GetSupportedTimezone returns a page of supported timezones on the system.
+func (c *Client4) GetSupportedTimezone() ([]string, *Response) {
+ r, err := c.DoApiGet(c.GetTimezonesRoute(), "")
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ var timezones []string
+ json.NewDecoder(r.Body).Decode(&timezones)
+ return timezones, BuildResponse(r)
+}
+
+// Open Graph Metadata Section
+
+// OpenGraph return the open graph metadata for a particular url if the site have the metadata.
+func (c *Client4) OpenGraph(url string) (map[string]string, *Response) {
+ requestBody := make(map[string]string)
+ requestBody["url"] = url
+
+ r, err := c.DoApiPost(c.GetOpenGraphRoute(), MapToJson(requestBody))
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return MapFromJson(r.Body), BuildResponse(r)
+}
+
+// Jobs Section
+
+// GetJob gets a single job.
+func (c *Client4) GetJob(id string) (*Job, *Response) {
+ r, err := c.DoApiGet(c.GetJobsRoute()+fmt.Sprintf("/%v", id), "")
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return JobFromJson(r.Body), BuildResponse(r)
+}
+
+// GetJobs gets all jobs, sorted with the job that was created most recently first.
+func (c *Client4) GetJobs(page int, perPage int) ([]*Job, *Response) {
+ r, err := c.DoApiGet(c.GetJobsRoute()+fmt.Sprintf("?page=%v&per_page=%v", page, perPage), "")
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return JobsFromJson(r.Body), BuildResponse(r)
+}
+
+// GetJobsByType gets all jobs of a given type, sorted with the job that was created most recently first.
+func (c *Client4) GetJobsByType(jobType string, page int, perPage int) ([]*Job, *Response) {
+ r, err := c.DoApiGet(c.GetJobsRoute()+fmt.Sprintf("/type/%v?page=%v&per_page=%v", jobType, page, perPage), "")
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return JobsFromJson(r.Body), BuildResponse(r)
+}
+
+// CreateJob creates a job based on the provided job struct.
+func (c *Client4) CreateJob(job *Job) (*Job, *Response) {
+ r, err := c.DoApiPost(c.GetJobsRoute(), job.ToJson())
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return JobFromJson(r.Body), BuildResponse(r)
+}
+
+// CancelJob requests the cancellation of the job with the provided Id.
+func (c *Client4) CancelJob(jobId string) (bool, *Response) {
+ r, err := c.DoApiPost(c.GetJobsRoute()+fmt.Sprintf("/%v/cancel", jobId), "")
+ if err != nil {
+ return false, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return CheckStatusOK(r), BuildResponse(r)
+}
+
+// Roles Section
+
+// GetRole gets a single role by ID.
+func (c *Client4) GetRole(id string) (*Role, *Response) {
+ r, err := c.DoApiGet(c.GetRolesRoute()+fmt.Sprintf("/%v", id), "")
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return RoleFromJson(r.Body), BuildResponse(r)
+}
+
+// GetRoleByName gets a single role by Name.
+func (c *Client4) GetRoleByName(name string) (*Role, *Response) {
+ r, err := c.DoApiGet(c.GetRolesRoute()+fmt.Sprintf("/name/%v", name), "")
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return RoleFromJson(r.Body), BuildResponse(r)
+}
+
+// GetRolesByNames returns a list of roles based on the provided role names.
+func (c *Client4) GetRolesByNames(roleNames []string) ([]*Role, *Response) {
+ r, err := c.DoApiPost(c.GetRolesRoute()+"/names", ArrayToJson(roleNames))
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return RoleListFromJson(r.Body), BuildResponse(r)
+}
+
+// PatchRole partially updates a role in the system. Any missing fields are not updated.
+func (c *Client4) PatchRole(roleId string, patch *RolePatch) (*Role, *Response) {
+ r, err := c.DoApiPut(c.GetRolesRoute()+fmt.Sprintf("/%v/patch", roleId), patch.ToJson())
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return RoleFromJson(r.Body), BuildResponse(r)
+}
+
+// Schemes Section
+
+// CreateScheme creates a new Scheme.
+func (c *Client4) CreateScheme(scheme *Scheme) (*Scheme, *Response) {
+ r, err := c.DoApiPost(c.GetSchemesRoute(), scheme.ToJson())
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return SchemeFromJson(r.Body), BuildResponse(r)
+}
+
+// GetScheme gets a single scheme by ID.
+func (c *Client4) GetScheme(id string) (*Scheme, *Response) {
+ r, err := c.DoApiGet(c.GetSchemeRoute(id), "")
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return SchemeFromJson(r.Body), BuildResponse(r)
+}
+
+// GetSchemes gets all schemes, sorted with the most recently created first, optionally filtered by scope.
+func (c *Client4) GetSchemes(scope string, page int, perPage int) ([]*Scheme, *Response) {
+ r, err := c.DoApiGet(c.GetSchemesRoute()+fmt.Sprintf("?scope=%v&page=%v&per_page=%v", scope, page, perPage), "")
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return SchemesFromJson(r.Body), BuildResponse(r)
+}
+
+// DeleteScheme deletes a single scheme by ID.
+func (c *Client4) DeleteScheme(id string) (bool, *Response) {
+ r, err := c.DoApiDelete(c.GetSchemeRoute(id))
+ if err != nil {
+ return false, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return CheckStatusOK(r), BuildResponse(r)
+}
+
+// PatchScheme partially updates a scheme in the system. Any missing fields are not updated.
+func (c *Client4) PatchScheme(id string, patch *SchemePatch) (*Scheme, *Response) {
+ r, err := c.DoApiPut(c.GetSchemeRoute(id)+"/patch", patch.ToJson())
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return SchemeFromJson(r.Body), BuildResponse(r)
+}
+
+// GetTeamsForScheme gets the teams using this scheme, sorted alphabetically by display name.
+func (c *Client4) GetTeamsForScheme(schemeId string, page int, perPage int) ([]*Team, *Response) {
+ r, err := c.DoApiGet(c.GetSchemeRoute(schemeId)+fmt.Sprintf("/teams?page=%v&per_page=%v", page, perPage), "")
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return TeamListFromJson(r.Body), BuildResponse(r)
+}
+
+// GetChannelsForScheme gets the channels using this scheme, sorted alphabetically by display name.
+func (c *Client4) GetChannelsForScheme(schemeId string, page int, perPage int) (ChannelList, *Response) {
+ r, err := c.DoApiGet(c.GetSchemeRoute(schemeId)+fmt.Sprintf("/channels?page=%v&per_page=%v", page, perPage), "")
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return *ChannelListFromJson(r.Body), BuildResponse(r)
+}
+
+// Plugin Section
+
+// UploadPlugin takes an io.Reader stream pointing to the contents of a .tar.gz plugin.
+// WARNING: PLUGINS ARE STILL EXPERIMENTAL. THIS FUNCTION IS SUBJECT TO CHANGE.
+func (c *Client4) UploadPlugin(file io.Reader) (*Manifest, *Response) {
+ return c.uploadPlugin(file, false)
+}
+
+func (c *Client4) UploadPluginForced(file io.Reader) (*Manifest, *Response) {
+ return c.uploadPlugin(file, true)
+}
+
+func (c *Client4) uploadPlugin(file io.Reader, force bool) (*Manifest, *Response) {
+ body := new(bytes.Buffer)
+ writer := multipart.NewWriter(body)
+
+ if force {
+ err := writer.WriteField("force", "true")
+ if err != nil {
+ return nil, &Response{Error: NewAppError("UploadPlugin", "model.client.writer.app_error", nil, err.Error(), 0)}
+ }
+ }
+
+ part, err := writer.CreateFormFile("plugin", "plugin.tar.gz")
+ if err != nil {
+ return nil, &Response{Error: NewAppError("UploadPlugin", "model.client.writer.app_error", nil, err.Error(), 0)}
+ }
+
+ if _, err = io.Copy(part, file); err != nil {
+ return nil, &Response{Error: NewAppError("UploadPlugin", "model.client.writer.app_error", nil, err.Error(), 0)}
+ }
+
+ if err = writer.Close(); err != nil {
+ return nil, &Response{Error: NewAppError("UploadPlugin", "model.client.writer.app_error", nil, err.Error(), 0)}
+ }
+
+ rq, err := http.NewRequest("POST", c.ApiUrl+c.GetPluginsRoute(), body)
+ if err != nil {
+ return nil, &Response{Error: NewAppError("UploadPlugin", "model.client.connecting.app_error", nil, err.Error(), http.StatusBadRequest)}
+ }
+ rq.Header.Set("Content-Type", writer.FormDataContentType())
+
+ if len(c.AuthToken) > 0 {
+ rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken)
+ }
+
+ rp, err := c.HttpClient.Do(rq)
+ if err != nil || rp == nil {
+ return nil, BuildErrorResponse(rp, NewAppError("UploadPlugin", "model.client.connecting.app_error", nil, err.Error(), 0))
+ }
+ defer closeBody(rp)
+
+ if rp.StatusCode >= 300 {
+ return nil, BuildErrorResponse(rp, AppErrorFromJson(rp.Body))
+ }
+
+ return ManifestFromJson(rp.Body), BuildResponse(rp)
+}
+
+func (c *Client4) InstallPluginFromUrl(downloadUrl string, force bool) (*Manifest, *Response) {
+ forceStr := "false"
+ if force {
+ forceStr = "true"
+ }
+
+ url := fmt.Sprintf("%s?plugin_download_url=%s&force=%s", c.GetPluginsRoute()+"/install_from_url", url.QueryEscape(downloadUrl), forceStr)
+ r, err := c.DoApiPost(url, "")
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return ManifestFromJson(r.Body), BuildResponse(r)
+}
+
+// InstallMarketplacePlugin will install marketplace plugin.
+// WARNING: PLUGINS ARE STILL EXPERIMENTAL. THIS FUNCTION IS SUBJECT TO CHANGE.
+func (c *Client4) InstallMarketplacePlugin(request *InstallMarketplacePluginRequest) (*Manifest, *Response) {
+ json, err := request.ToJson()
+ if err != nil {
+ return nil, &Response{Error: NewAppError("InstallMarketplacePlugin", "model.client.plugin_request_to_json.app_error", nil, err.Error(), http.StatusBadRequest)}
+ }
+ r, appErr := c.DoApiPost(c.GetPluginsRoute()+"/marketplace", json)
+ if appErr != nil {
+ return nil, BuildErrorResponse(r, appErr)
+ }
+ defer closeBody(r)
+ return ManifestFromJson(r.Body), BuildResponse(r)
+}
+
+// GetPlugins will return a list of plugin manifests for currently active plugins.
+// WARNING: PLUGINS ARE STILL EXPERIMENTAL. THIS FUNCTION IS SUBJECT TO CHANGE.
+func (c *Client4) GetPlugins() (*PluginsResponse, *Response) {
+ r, err := c.DoApiGet(c.GetPluginsRoute(), "")
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return PluginsResponseFromJson(r.Body), BuildResponse(r)
+}
+
+// GetPluginStatuses will return the plugins installed on any server in the cluster, for reporting
+// to the administrator via the system console.
+// WARNING: PLUGINS ARE STILL EXPERIMENTAL. THIS FUNCTION IS SUBJECT TO CHANGE.
+func (c *Client4) GetPluginStatuses() (PluginStatuses, *Response) {
+ r, err := c.DoApiGet(c.GetPluginsRoute()+"/statuses", "")
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return PluginStatusesFromJson(r.Body), BuildResponse(r)
+}
+
+// RemovePlugin will disable and delete a plugin.
+// WARNING: PLUGINS ARE STILL EXPERIMENTAL. THIS FUNCTION IS SUBJECT TO CHANGE.
+func (c *Client4) RemovePlugin(id string) (bool, *Response) {
+ r, err := c.DoApiDelete(c.GetPluginRoute(id))
+ if err != nil {
+ return false, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return CheckStatusOK(r), BuildResponse(r)
+}
+
+// GetWebappPlugins will return a list of plugins that the webapp should download.
+// WARNING: PLUGINS ARE STILL EXPERIMENTAL. THIS FUNCTION IS SUBJECT TO CHANGE.
+func (c *Client4) GetWebappPlugins() ([]*Manifest, *Response) {
+ r, err := c.DoApiGet(c.GetPluginsRoute()+"/webapp", "")
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return ManifestListFromJson(r.Body), BuildResponse(r)
+}
+
+// EnablePlugin will enable an plugin installed.
+// WARNING: PLUGINS ARE STILL EXPERIMENTAL. THIS FUNCTION IS SUBJECT TO CHANGE.
+func (c *Client4) EnablePlugin(id string) (bool, *Response) {
+ r, err := c.DoApiPost(c.GetPluginRoute(id)+"/enable", "")
+ if err != nil {
+ return false, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return CheckStatusOK(r), BuildResponse(r)
+}
+
+// DisablePlugin will disable an enabled plugin.
+// WARNING: PLUGINS ARE STILL EXPERIMENTAL. THIS FUNCTION IS SUBJECT TO CHANGE.
+func (c *Client4) DisablePlugin(id string) (bool, *Response) {
+ r, err := c.DoApiPost(c.GetPluginRoute(id)+"/disable", "")
+ if err != nil {
+ return false, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return CheckStatusOK(r), BuildResponse(r)
+}
+
+// GetMarketplacePlugins will return a list of plugins that an admin can install.
+// WARNING: PLUGINS ARE STILL EXPERIMENTAL. THIS FUNCTION IS SUBJECT TO CHANGE.
+func (c *Client4) GetMarketplacePlugins(filter *MarketplacePluginFilter) ([]*MarketplacePlugin, *Response) {
+ route := c.GetPluginsRoute() + "/marketplace"
+ u, parseErr := url.Parse(route)
+ if parseErr != nil {
+ return nil, &Response{Error: NewAppError("GetMarketplacePlugins", "model.client.parse_plugins.app_error", nil, parseErr.Error(), http.StatusBadRequest)}
+ }
+
+ filter.ApplyToURL(u)
+
+ r, err := c.DoApiGet(u.String(), "")
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+
+ plugins, readerErr := MarketplacePluginsFromReader(r.Body)
+ if readerErr != nil {
+ return nil, BuildErrorResponse(r, NewAppError(route, "model.client.parse_plugins.app_error", nil, err.Error(), http.StatusBadRequest))
+ }
+
+ return plugins, BuildResponse(r)
+}
+
+// UpdateChannelScheme will update a channel's scheme.
+func (c *Client4) UpdateChannelScheme(channelId, schemeId string) (bool, *Response) {
+ sip := &SchemeIDPatch{SchemeID: &schemeId}
+ r, err := c.DoApiPut(c.GetChannelSchemeRoute(channelId), sip.ToJson())
+ if err != nil {
+ return false, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return CheckStatusOK(r), BuildResponse(r)
+}
+
+// UpdateTeamScheme will update a team's scheme.
+func (c *Client4) UpdateTeamScheme(teamId, schemeId string) (bool, *Response) {
+ sip := &SchemeIDPatch{SchemeID: &schemeId}
+ r, err := c.DoApiPut(c.GetTeamSchemeRoute(teamId), sip.ToJson())
+ if err != nil {
+ return false, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return CheckStatusOK(r), BuildResponse(r)
+}
+
+// GetRedirectLocation retrieves the value of the 'Location' header of an HTTP response for a given URL.
+func (c *Client4) GetRedirectLocation(urlParam, etag string) (string, *Response) {
+ url := fmt.Sprintf("%s?url=%s", c.GetRedirectLocationRoute(), url.QueryEscape(urlParam))
+ r, err := c.DoApiGet(url, etag)
+ if err != nil {
+ return "", BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return MapFromJson(r.Body)["location"], BuildResponse(r)
+}
+
+// SetServerBusy will mark the server as busy, which disables non-critical services for `secs` seconds.
+func (c *Client4) SetServerBusy(secs int) (bool, *Response) {
+ url := fmt.Sprintf("%s?seconds=%d", c.GetServerBusyRoute(), secs)
+ r, err := c.DoApiPost(url, "")
+ if err != nil {
+ return false, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return CheckStatusOK(r), BuildResponse(r)
+}
+
+// ClearServerBusy will mark the server as not busy.
+func (c *Client4) ClearServerBusy() (bool, *Response) {
+ r, err := c.DoApiDelete(c.GetServerBusyRoute())
+ if err != nil {
+ return false, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return CheckStatusOK(r), BuildResponse(r)
+}
+
+// GetServerBusy returns the current ServerBusyState including the time when a server marked busy
+// will automatically have the flag cleared.
+func (c *Client4) GetServerBusy() (*ServerBusyState, *Response) {
+ r, err := c.DoApiGet(c.GetServerBusyRoute(), "")
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+
+ sbs := ServerBusyStateFromJson(r.Body)
+ return sbs, BuildResponse(r)
+}
+
+// GetServerBusyExpires returns the time when a server marked busy
+// will automatically have the flag cleared.
+//
+// Deprecated: Use GetServerBusy instead.
+func (c *Client4) GetServerBusyExpires() (*time.Time, *Response) {
+ r, err := c.DoApiGet(c.GetServerBusyRoute(), "")
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+
+ sbs := ServerBusyStateFromJson(r.Body)
+ expires := time.Unix(sbs.Expires, 0)
+ return &expires, BuildResponse(r)
+}
+
+// RegisterTermsOfServiceAction saves action performed by a user against a specific terms of service.
+func (c *Client4) RegisterTermsOfServiceAction(userId, termsOfServiceId string, accepted bool) (*bool, *Response) {
+ url := c.GetUserTermsOfServiceRoute(userId)
+ data := map[string]interface{}{"termsOfServiceId": termsOfServiceId, "accepted": accepted}
+ r, err := c.DoApiPost(url, StringInterfaceToJson(data))
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return NewBool(CheckStatusOK(r)), BuildResponse(r)
+}
+
+// GetTermsOfService fetches the latest terms of service
+func (c *Client4) GetTermsOfService(etag string) (*TermsOfService, *Response) {
+ url := c.GetTermsOfServiceRoute()
+ r, err := c.DoApiGet(url, etag)
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return TermsOfServiceFromJson(r.Body), BuildResponse(r)
+}
+
+// GetUserTermsOfService fetches user's latest terms of service action if the latest action was for acceptance.
+func (c *Client4) GetUserTermsOfService(userId, etag string) (*UserTermsOfService, *Response) {
+ url := c.GetUserTermsOfServiceRoute(userId)
+ r, err := c.DoApiGet(url, etag)
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return UserTermsOfServiceFromJson(r.Body), BuildResponse(r)
+}
+
+// CreateTermsOfService creates new terms of service.
+func (c *Client4) CreateTermsOfService(text, userId string) (*TermsOfService, *Response) {
+ url := c.GetTermsOfServiceRoute()
+ data := map[string]interface{}{"text": text}
+ r, err := c.DoApiPost(url, StringInterfaceToJson(data))
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return TermsOfServiceFromJson(r.Body), BuildResponse(r)
+}
+
+func (c *Client4) GetGroup(groupID, etag string) (*Group, *Response) {
+ r, appErr := c.DoApiGet(c.GetGroupRoute(groupID), etag)
+ if appErr != nil {
+ return nil, BuildErrorResponse(r, appErr)
+ }
+ defer closeBody(r)
+ return GroupFromJson(r.Body), BuildResponse(r)
+}
+
+func (c *Client4) PatchGroup(groupID string, patch *GroupPatch) (*Group, *Response) {
+ payload, _ := json.Marshal(patch)
+ r, appErr := c.DoApiPut(c.GetGroupRoute(groupID)+"/patch", string(payload))
+ if appErr != nil {
+ return nil, BuildErrorResponse(r, appErr)
+ }
+ defer closeBody(r)
+ return GroupFromJson(r.Body), BuildResponse(r)
+}
+
+func (c *Client4) LinkGroupSyncable(groupID, syncableID string, syncableType GroupSyncableType, patch *GroupSyncablePatch) (*GroupSyncable, *Response) {
+ payload, _ := json.Marshal(patch)
+ url := fmt.Sprintf("%s/link", c.GetGroupSyncableRoute(groupID, syncableID, syncableType))
+ r, appErr := c.DoApiPost(url, string(payload))
+ if appErr != nil {
+ return nil, BuildErrorResponse(r, appErr)
+ }
+ defer closeBody(r)
+ return GroupSyncableFromJson(r.Body), BuildResponse(r)
+}
+
+func (c *Client4) UnlinkGroupSyncable(groupID, syncableID string, syncableType GroupSyncableType) *Response {
+ url := fmt.Sprintf("%s/link", c.GetGroupSyncableRoute(groupID, syncableID, syncableType))
+ r, appErr := c.DoApiDelete(url)
+ if appErr != nil {
+ return BuildErrorResponse(r, appErr)
+ }
+ defer closeBody(r)
+ return BuildResponse(r)
+}
+
+func (c *Client4) GetGroupSyncable(groupID, syncableID string, syncableType GroupSyncableType, etag string) (*GroupSyncable, *Response) {
+ r, appErr := c.DoApiGet(c.GetGroupSyncableRoute(groupID, syncableID, syncableType), etag)
+ if appErr != nil {
+ return nil, BuildErrorResponse(r, appErr)
+ }
+ defer closeBody(r)
+ return GroupSyncableFromJson(r.Body), BuildResponse(r)
+}
+
+func (c *Client4) GetGroupSyncables(groupID string, syncableType GroupSyncableType, etag string) ([]*GroupSyncable, *Response) {
+ r, appErr := c.DoApiGet(c.GetGroupSyncablesRoute(groupID, syncableType), etag)
+ if appErr != nil {
+ return nil, BuildErrorResponse(r, appErr)
+ }
+ defer closeBody(r)
+ return GroupSyncablesFromJson(r.Body), BuildResponse(r)
+}
+
+func (c *Client4) PatchGroupSyncable(groupID, syncableID string, syncableType GroupSyncableType, patch *GroupSyncablePatch) (*GroupSyncable, *Response) {
+ payload, _ := json.Marshal(patch)
+ r, appErr := c.DoApiPut(c.GetGroupSyncableRoute(groupID, syncableID, syncableType)+"/patch", string(payload))
+ if appErr != nil {
+ return nil, BuildErrorResponse(r, appErr)
+ }
+ defer closeBody(r)
+ return GroupSyncableFromJson(r.Body), BuildResponse(r)
+}
+
+func (c *Client4) TeamMembersMinusGroupMembers(teamID string, groupIDs []string, page, perPage int, etag string) ([]*UserWithGroups, int64, *Response) {
+ groupIDStr := strings.Join(groupIDs, ",")
+ query := fmt.Sprintf("?group_ids=%s&page=%d&per_page=%d", groupIDStr, page, perPage)
+ r, err := c.DoApiGet(c.GetTeamRoute(teamID)+"/members_minus_group_members"+query, etag)
+ if err != nil {
+ return nil, 0, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ ugc := UsersWithGroupsAndCountFromJson(r.Body)
+ return ugc.Users, ugc.Count, BuildResponse(r)
+}
+
+func (c *Client4) ChannelMembersMinusGroupMembers(channelID string, groupIDs []string, page, perPage int, etag string) ([]*UserWithGroups, int64, *Response) {
+ groupIDStr := strings.Join(groupIDs, ",")
+ query := fmt.Sprintf("?group_ids=%s&page=%d&per_page=%d", groupIDStr, page, perPage)
+ r, err := c.DoApiGet(c.GetChannelRoute(channelID)+"/members_minus_group_members"+query, etag)
+ if err != nil {
+ return nil, 0, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ ugc := UsersWithGroupsAndCountFromJson(r.Body)
+ return ugc.Users, ugc.Count, BuildResponse(r)
+}
+
+func (c *Client4) PatchConfig(config *Config) (*Config, *Response) {
+ r, err := c.DoApiPut(c.GetConfigRoute()+"/patch", config.ToJson())
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return ConfigFromJson(r.Body), BuildResponse(r)
+}
+
+func (c *Client4) GetChannelModerations(channelID string, etag string) ([]*ChannelModeration, *Response) {
+ r, err := c.DoApiGet(c.GetChannelRoute(channelID)+"/moderations", etag)
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return ChannelModerationsFromJson(r.Body), BuildResponse(r)
+}
+
+func (c *Client4) PatchChannelModerations(channelID string, patch []*ChannelModerationPatch) ([]*ChannelModeration, *Response) {
+ payload, _ := json.Marshal(patch)
+ r, err := c.DoApiPut(c.GetChannelRoute(channelID)+"/moderations/patch", string(payload))
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return ChannelModerationsFromJson(r.Body), BuildResponse(r)
+}
+
+func (c *Client4) GetKnownUsers() ([]string, *Response) {
+ r, err := c.DoApiGet(c.GetUsersRoute()+"/known", "")
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ var userIds []string
+ json.NewDecoder(r.Body).Decode(&userIds)
+ return userIds, BuildResponse(r)
+}
+
+func (c *Client4) GetChannelMemberCountsByGroup(channelID string, includeTimezones bool, etag string) ([]*ChannelMemberCountByGroup, *Response) {
+ r, err := c.DoApiGet(c.GetChannelRoute(channelID)+"/member_counts_by_group?include_timezones="+strconv.FormatBool(includeTimezones), etag)
+ if err != nil {
+ return nil, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return ChannelMemberCountsByGroupFromJson(r.Body), BuildResponse(r)
+}
+
+// RequestTrialLicense will request a trial license and install it in the server
+func (c *Client4) RequestTrialLicense(users int) (bool, *Response) {
+ b, _ := json.Marshal(map[string]int{"users": users})
+ r, err := c.DoApiPost("/trial-license", string(b))
+ if err != nil {
+ return false, BuildErrorResponse(r, err)
+ }
+ defer closeBody(r)
+ return CheckStatusOK(r), BuildResponse(r)
+}
diff --git a/vendor/github.com/mattermost/mattermost-server/model/cluster_discovery.go b/vendor/github.com/mattermost/mattermost-server/v5/model/cluster_discovery.go
index 796d3dda..f6c9275a 100644
--- a/vendor/github.com/mattermost/mattermost-server/model/cluster_discovery.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/cluster_discovery.go
@@ -1,5 +1,5 @@
-// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
package model
@@ -46,10 +46,14 @@ func (o *ClusterDiscovery) AutoFillHostname() {
}
}
-func (o *ClusterDiscovery) AutoFillIpAddress() {
+func (o *ClusterDiscovery) AutoFillIpAddress(iface string, ipAddress string) {
// attempt to set the hostname to the first non-local IP address
if len(o.Hostname) == 0 {
- o.Hostname = GetServerIpAddress()
+ if len(ipAddress) > 0 {
+ o.Hostname = ipAddress
+ } else {
+ o.Hostname = GetServerIpAddress(iface)
+ }
}
}
@@ -85,7 +89,7 @@ func FilterClusterDiscovery(vs []*ClusterDiscovery, f func(*ClusterDiscovery) bo
}
func (o *ClusterDiscovery) IsValid() *AppError {
- if len(o.Id) != 26 {
+ if !IsValidId(o.Id) {
return NewAppError("ClusterDiscovery.IsValid", "model.cluster.is_valid.id.app_error", nil, "", http.StatusBadRequest)
}
diff --git a/vendor/github.com/mattermost/mattermost-server/model/cluster_info.go b/vendor/github.com/mattermost/mattermost-server/v5/model/cluster_info.go
index 46a3487a..82437469 100644
--- a/vendor/github.com/mattermost/mattermost-server/model/cluster_info.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/cluster_info.go
@@ -1,5 +1,5 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// See LICENSE.txt for license information.
package model
diff --git a/vendor/github.com/mattermost/mattermost-server/model/cluster_message.go b/vendor/github.com/mattermost/mattermost-server/v5/model/cluster_message.go
index d02da3ee..86113d78 100644
--- a/vendor/github.com/mattermost/mattermost-server/model/cluster_message.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/cluster_message.go
@@ -1,5 +1,5 @@
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
package model
@@ -19,11 +19,31 @@ const (
CLUSTER_EVENT_INVALIDATE_CACHE_FOR_CHANNEL_MEMBERS = "inv_channel_members"
CLUSTER_EVENT_INVALIDATE_CACHE_FOR_CHANNEL_BY_NAME = "inv_channel_name"
CLUSTER_EVENT_INVALIDATE_CACHE_FOR_CHANNEL = "inv_channel"
+ CLUSTER_EVENT_INVALIDATE_CACHE_FOR_CHANNEL_GUEST_COUNT = "inv_channel_guest_count"
CLUSTER_EVENT_INVALIDATE_CACHE_FOR_USER = "inv_user"
+ CLUSTER_EVENT_INVALIDATE_CACHE_FOR_USER_TEAMS = "inv_user_teams"
CLUSTER_EVENT_CLEAR_SESSION_CACHE_FOR_USER = "clear_session_user"
CLUSTER_EVENT_INVALIDATE_CACHE_FOR_ROLES = "inv_roles"
+ CLUSTER_EVENT_INVALIDATE_CACHE_FOR_ROLE_PERMISSIONS = "inv_role_permissions"
+ CLUSTER_EVENT_INVALIDATE_CACHE_FOR_PROFILE_BY_IDS = "inv_profile_ids"
+ CLUSTER_EVENT_INVALIDATE_CACHE_FOR_PROFILE_IN_CHANNEL = "inv_profile_in_channel"
CLUSTER_EVENT_INVALIDATE_CACHE_FOR_SCHEMES = "inv_schemes"
+ CLUSTER_EVENT_INVALIDATE_CACHE_FOR_FILE_INFOS = "inv_file_infos"
+ CLUSTER_EVENT_INVALIDATE_CACHE_FOR_WEBHOOKS = "inv_webhooks"
+ CLUSTER_EVENT_INVALIDATE_CACHE_FOR_EMOJIS_BY_ID = "inv_emojis_by_id"
+ CLUSTER_EVENT_INVALIDATE_CACHE_FOR_EMOJIS_ID_BY_NAME = "inv_emojis_id_by_name"
+ CLUSTER_EVENT_INVALIDATE_CACHE_FOR_CHANNEL_PINNEDPOSTS_COUNTS = "inv_channel_pinnedposts_counts"
+ CLUSTER_EVENT_INVALIDATE_CACHE_FOR_CHANNEL_MEMBER_COUNTS = "inv_channel_member_counts"
+ CLUSTER_EVENT_INVALIDATE_CACHE_FOR_LAST_POSTS = "inv_last_posts"
+ CLUSTER_EVENT_INVALIDATE_CACHE_FOR_LAST_POST_TIME = "inv_last_post_time"
+ CLUSTER_EVENT_INVALIDATE_CACHE_FOR_TEAMS = "inv_teams"
+ CLUSTER_EVENT_CLEAR_SESSION_CACHE_FOR_ALL_USERS = "inv_all_user_sessions"
+ CLUSTER_EVENT_INSTALL_PLUGIN = "install_plugin"
+ CLUSTER_EVENT_REMOVE_PLUGIN = "remove_plugin"
+ CLUSTER_EVENT_INVALIDATE_CACHE_FOR_TERMS_OF_SERVICE = "inv_terms_of_service"
+ CLUSTER_EVENT_BUSY_STATE_CHANGED = "busy_state_change"
+ // SendTypes for ClusterMessage.
CLUSTER_SEND_BEST_EFFORT = "best_effort"
CLUSTER_SEND_RELIABLE = "reliable"
)
diff --git a/vendor/github.com/mattermost/mattermost-server/model/cluster_stats.go b/vendor/github.com/mattermost/mattermost-server/v5/model/cluster_stats.go
index 064f7b81..afc2ab44 100644
--- a/vendor/github.com/mattermost/mattermost-server/model/cluster_stats.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/cluster_stats.go
@@ -1,5 +1,5 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// See LICENSE.txt for license information.
package model
diff --git a/vendor/github.com/mattermost/mattermost-server/model/command.go b/vendor/github.com/mattermost/mattermost-server/v5/model/command.go
index b23e5020..6dcf52ae 100644
--- a/vendor/github.com/mattermost/mattermost-server/model/command.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/command.go
@@ -1,5 +1,5 @@
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
package model
@@ -18,23 +18,26 @@ const (
)
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"`
+ 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"`
+ AutocompleteData *AutocompleteData `db:"-" json:"autocomplete_data,omitempty"`
+ // AutocompleteIconData is a base64 encoded svg
+ AutocompleteIconData string `db:"-" json:"autocomplete_icon_data,omitempty"`
}
func (o *Command) ToJson() string {
@@ -61,7 +64,7 @@ func CommandListFromJson(data io.Reader) []*Command {
func (o *Command) IsValid() *AppError {
- if len(o.Id) != 26 {
+ if !IsValidId(o.Id) {
return NewAppError("Command.IsValid", "model.command.is_valid.id.app_error", nil, "", http.StatusBadRequest)
}
@@ -77,11 +80,11 @@ func (o *Command) IsValid() *AppError {
return NewAppError("Command.IsValid", "model.command.is_valid.update_at.app_error", nil, "", http.StatusBadRequest)
}
- if len(o.CreatorId) != 26 {
+ if !IsValidId(o.CreatorId) {
return NewAppError("Command.IsValid", "model.command.is_valid.user_id.app_error", nil, "", http.StatusBadRequest)
}
- if len(o.TeamId) != 26 {
+ if !IsValidId(o.TeamId) {
return NewAppError("Command.IsValid", "model.command.is_valid.team_id.app_error", nil, "", http.StatusBadRequest)
}
@@ -109,6 +112,12 @@ func (o *Command) IsValid() *AppError {
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, err.Error(), http.StatusBadRequest)
+ }
+ }
+
return nil
}
diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/command_args.go b/vendor/github.com/mattermost/mattermost-server/v5/model/command_args.go
new file mode 100644
index 00000000..a3bbb4c9
--- /dev/null
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/command_args.go
@@ -0,0 +1,57 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
+
+package model
+
+import (
+ "encoding/json"
+ "io"
+
+ goi18n "github.com/mattermost/go-i18n/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 goi18n.TranslateFunc `json:"-"`
+ Session Session `json:"-"`
+ UserMentions UserMentionMap `json:"-"`
+ ChannelMentions ChannelMentionMap `json:"-"`
+}
+
+func (o *CommandArgs) ToJson() string {
+ b, _ := json.Marshal(o)
+ return string(b)
+}
+
+func CommandArgsFromJson(data io.Reader) *CommandArgs {
+ var o *CommandArgs
+ json.NewDecoder(data).Decode(&o)
+ return o
+}
+
+// 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
+}
diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/command_autocomplete.go b/vendor/github.com/mattermost/mattermost-server/v5/model/command_autocomplete.go
new file mode 100644
index 00000000..68d91b23
--- /dev/null
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/command_autocomplete.go
@@ -0,0 +1,455 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
+
+package model
+
+import (
+ "encoding/json"
+ "io"
+ "net/url"
+ "path"
+ "reflect"
+ "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 determins if argument is optional or not.
+ Required bool
+ // Actual data of the argument (depends on the Type)
+ Data interface{}
+}
+
+// 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: SYSTEM_USER_ROLE_ID,
+ 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{SYSTEM_ADMIN_ROLE_ID, SYSTEM_USER_ROLE_ID, ""}
+ if stringNotInSlice(ad.RoleID, roles) {
+ 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
+}
+
+// ToJSON encodes AutocompleteData struct to the json
+func (ad *AutocompleteData) ToJSON() ([]byte, error) {
+ b, err := json.Marshal(ad)
+ if err != nil {
+ return nil, errors.Wrapf(err, "can't marshal slash command %s", ad.Trigger)
+ }
+ return b, nil
+}
+
+// AutocompleteDataFromJSON decodes AutocompleteData struct from the json
+func AutocompleteDataFromJSON(data []byte) (*AutocompleteData, error) {
+ var ad AutocompleteData
+ if err := json.Unmarshal(data, &ad); err != nil {
+ return nil, errors.Wrap(err, "can't unmarshal AutocompleteData")
+ }
+ return &ad, 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]interface{}
+ 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]interface{})
+ 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]interface{})
+ if !ok {
+ return errors.Errorf("Wrong Data type in the StaticList argument %s", string(b))
+ }
+ list, ok := m["PossibleArguments"].([]interface{})
+ 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]interface{})
+ 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]interface{})
+ 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
+}
+
+// AutocompleteSuggestionsToJSON returns json for a list of AutocompleteSuggestion objects
+func AutocompleteSuggestionsToJSON(suggestions []AutocompleteSuggestion) []byte {
+ b, _ := json.Marshal(suggestions)
+ return b
+}
+
+// AutocompleteSuggestionsFromJSON returns list of AutocompleteSuggestions from json.
+func AutocompleteSuggestionsFromJSON(data io.Reader) []AutocompleteSuggestion {
+ var o []AutocompleteSuggestion
+ json.NewDecoder(data).Decode(&o)
+ return o
+}
+
+// AutocompleteStaticListItemsToJSON returns json for a list of AutocompleteStaticListItem objects
+func AutocompleteStaticListItemsToJSON(items []AutocompleteListItem) []byte {
+ b, _ := json.Marshal(items)
+ return b
+}
+
+// AutocompleteStaticListItemsFromJSON returns list of AutocompleteStaticListItem from json.
+func AutocompleteStaticListItemsFromJSON(data io.Reader) []AutocompleteListItem {
+ var o []AutocompleteListItem
+ json.NewDecoder(data).Decode(&o)
+ return o
+}
+
+func stringNotInSlice(a string, slice []string) bool {
+ for _, b := range slice {
+ if b == a {
+ return false
+ }
+ }
+ return true
+}
diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/command_request.go b/vendor/github.com/mattermost/mattermost-server/v5/model/command_request.go
new file mode 100644
index 00000000..9a4e40c8
--- /dev/null
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/command_request.go
@@ -0,0 +1,31 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
+
+package model
+
+import (
+ "encoding/json"
+ "io"
+)
+
+type CommandMoveRequest struct {
+ TeamId string `json:"team_id"`
+}
+
+func CommandMoveRequestFromJson(data io.Reader) (*CommandMoveRequest, error) {
+ decoder := json.NewDecoder(data)
+ var cmr CommandMoveRequest
+ err := decoder.Decode(&cmr)
+ if err != nil {
+ return nil, err
+ }
+ return &cmr, nil
+}
+
+func (cmr *CommandMoveRequest) ToJson() string {
+ b, err := json.Marshal(cmr)
+ if err != nil {
+ return ""
+ }
+ return string(b)
+}
diff --git a/vendor/github.com/mattermost/mattermost-server/model/command_response.go b/vendor/github.com/mattermost/mattermost-server/v5/model/command_response.go
index 1ed5286d..26b6cceb 100644
--- a/vendor/github.com/mattermost/mattermost-server/model/command_response.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/command_response.go
@@ -1,5 +1,5 @@
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
package model
@@ -9,7 +9,7 @@ import (
"io/ioutil"
"strings"
- "github.com/mattermost/mattermost-server/utils/jsonutils"
+ "github.com/mattermost/mattermost-server/v5/utils/jsonutils"
)
const (
@@ -18,14 +18,18 @@ const (
)
type CommandResponse struct {
- ResponseType string `json:"response_type"`
- Text string `json:"text"`
- Username string `json:"username"`
- IconURL string `json:"icon_url"`
- Type string `json:"type"`
- Props StringInterface `json:"props"`
- GotoLocation string `json:"goto_location"`
- Attachments []*SlackAttachment `json:"attachments"`
+ 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 (o *CommandResponse) ToJson() string {
@@ -63,5 +67,11 @@ func CommandResponseFromJson(data io.Reader) (*CommandResponse, error) {
o.Attachments = StringifySlackFieldValue(o.Attachments)
+ if o.ExtraResponses != nil {
+ for _, resp := range o.ExtraResponses {
+ resp.Attachments = StringifySlackFieldValue(resp.Attachments)
+ }
+ }
+
return &o, nil
}
diff --git a/vendor/github.com/mattermost/mattermost-server/model/command_webhook.go b/vendor/github.com/mattermost/mattermost-server/v5/model/command_webhook.go
index 0b00e00b..42a16cc7 100644
--- a/vendor/github.com/mattermost/mattermost-server/model/command_webhook.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/command_webhook.go
@@ -1,5 +1,5 @@
-// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
package model
@@ -33,7 +33,7 @@ func (o *CommandWebhook) PreSave() {
}
func (o *CommandWebhook) IsValid() *AppError {
- if len(o.Id) != 26 {
+ if !IsValidId(o.Id) {
return NewAppError("CommandWebhook.IsValid", "model.command_hook.id.app_error", nil, "", http.StatusBadRequest)
}
@@ -41,23 +41,23 @@ func (o *CommandWebhook) IsValid() *AppError {
return NewAppError("CommandWebhook.IsValid", "model.command_hook.create_at.app_error", nil, "id="+o.Id, http.StatusBadRequest)
}
- if len(o.CommandId) != 26 {
+ if !IsValidId(o.CommandId) {
return NewAppError("CommandWebhook.IsValid", "model.command_hook.command_id.app_error", nil, "", http.StatusBadRequest)
}
- if len(o.UserId) != 26 {
+ if !IsValidId(o.UserId) {
return NewAppError("CommandWebhook.IsValid", "model.command_hook.user_id.app_error", nil, "", http.StatusBadRequest)
}
- if len(o.ChannelId) != 26 {
+ if !IsValidId(o.ChannelId) {
return NewAppError("CommandWebhook.IsValid", "model.command_hook.channel_id.app_error", nil, "", http.StatusBadRequest)
}
- if len(o.RootId) != 0 && len(o.RootId) != 26 {
+ if len(o.RootId) != 0 && !IsValidId(o.RootId) {
return NewAppError("CommandWebhook.IsValid", "model.command_hook.root_id.app_error", nil, "", http.StatusBadRequest)
}
- if len(o.ParentId) != 0 && len(o.ParentId) != 26 {
+ if len(o.ParentId) != 0 && !IsValidId(o.ParentId) {
return NewAppError("CommandWebhook.IsValid", "model.command_hook.parent_id.app_error", nil, "", http.StatusBadRequest)
}
diff --git a/vendor/github.com/mattermost/mattermost-server/model/compliance.go b/vendor/github.com/mattermost/mattermost-server/v5/model/compliance.go
index 5546b783..a86087c1 100644
--- a/vendor/github.com/mattermost/mattermost-server/model/compliance.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/compliance.go
@@ -1,5 +1,5 @@
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
package model
@@ -37,61 +37,61 @@ type Compliance struct {
type Compliances []Compliance
-func (o *Compliance) ToJson() string {
- b, _ := json.Marshal(o)
+func (c *Compliance) ToJson() string {
+ b, _ := json.Marshal(c)
return string(b)
}
-func (me *Compliance) PreSave() {
- if me.Id == "" {
- me.Id = NewId()
+func (c *Compliance) PreSave() {
+ if c.Id == "" {
+ c.Id = NewId()
}
- if me.Status == "" {
- me.Status = COMPLIANCE_STATUS_CREATED
+ if c.Status == "" {
+ c.Status = COMPLIANCE_STATUS_CREATED
}
- me.Count = 0
- me.Emails = NormalizeEmail(me.Emails)
- me.Keywords = strings.ToLower(me.Keywords)
+ c.Count = 0
+ c.Emails = NormalizeEmail(c.Emails)
+ c.Keywords = strings.ToLower(c.Keywords)
- me.CreateAt = GetMillis()
+ c.CreateAt = GetMillis()
}
-func (me *Compliance) JobName() string {
- jobName := me.Type
- if me.Type == COMPLIANCE_TYPE_DAILY {
- jobName += "-" + me.Desc
+func (c *Compliance) JobName() string {
+ jobName := c.Type
+ if c.Type == COMPLIANCE_TYPE_DAILY {
+ jobName += "-" + c.Desc
}
- jobName += "-" + me.Id
+ jobName += "-" + c.Id
return jobName
}
-func (me *Compliance) IsValid() *AppError {
+func (c *Compliance) IsValid() *AppError {
- if len(me.Id) != 26 {
+ if !IsValidId(c.Id) {
return NewAppError("Compliance.IsValid", "model.compliance.is_valid.id.app_error", nil, "", http.StatusBadRequest)
}
- if me.CreateAt == 0 {
+ if c.CreateAt == 0 {
return NewAppError("Compliance.IsValid", "model.compliance.is_valid.create_at.app_error", nil, "", http.StatusBadRequest)
}
- if len(me.Desc) > 512 || len(me.Desc) == 0 {
+ if len(c.Desc) > 512 || len(c.Desc) == 0 {
return NewAppError("Compliance.IsValid", "model.compliance.is_valid.desc.app_error", nil, "", http.StatusBadRequest)
}
- if me.StartAt == 0 {
+ if c.StartAt == 0 {
return NewAppError("Compliance.IsValid", "model.compliance.is_valid.start_at.app_error", nil, "", http.StatusBadRequest)
}
- if me.EndAt == 0 {
+ if c.EndAt == 0 {
return NewAppError("Compliance.IsValid", "model.compliance.is_valid.end_at.app_error", nil, "", http.StatusBadRequest)
}
- if me.EndAt <= me.StartAt {
+ if c.EndAt <= c.StartAt {
return NewAppError("Compliance.IsValid", "model.compliance.is_valid.start_end_at.app_error", nil, "", http.StatusBadRequest)
}
@@ -99,13 +99,13 @@ func (me *Compliance) IsValid() *AppError {
}
func ComplianceFromJson(data io.Reader) *Compliance {
- var o *Compliance
- json.NewDecoder(data).Decode(&o)
- return o
+ var c *Compliance
+ json.NewDecoder(data).Decode(&c)
+ return c
}
-func (o Compliances) ToJson() string {
- if b, err := json.Marshal(o); err != nil {
+func (c Compliances) ToJson() string {
+ if b, err := json.Marshal(c); err != nil {
return "[]"
} else {
return string(b)
diff --git a/vendor/github.com/mattermost/mattermost-server/model/compliance_post.go b/vendor/github.com/mattermost/mattermost-server/v5/model/compliance_post.go
index 75e8de1f..fcf65075 100644
--- a/vendor/github.com/mattermost/mattermost-server/model/compliance_post.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/compliance_post.go
@@ -1,5 +1,5 @@
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
package model
@@ -37,6 +37,8 @@ type CompliancePost struct {
PostProps string
PostHashtags string
PostFileIds string
+
+ IsBot bool
}
func CompliancePostHeader() []string {
@@ -64,6 +66,7 @@ func CompliancePostHeader() []string {
"PostProps",
"PostHashtags",
"PostFileIds",
+ "UserType",
}
}
@@ -88,6 +91,11 @@ func (me *CompliancePost) Row() []string {
postUpdateAt = time.Unix(0, me.PostUpdateAt*int64(1000*1000)).Format(time.RFC3339)
}
+ userType := "user"
+ if me.IsBot {
+ userType = "bot"
+ }
+
return []string{
cleanComplianceStrings(me.TeamName),
cleanComplianceStrings(me.TeamDisplayName),
@@ -99,6 +107,7 @@ func (me *CompliancePost) Row() []string {
cleanComplianceStrings(me.UserUsername),
cleanComplianceStrings(me.UserEmail),
cleanComplianceStrings(me.UserNickname),
+ userType,
me.PostId,
time.Unix(0, me.PostCreateAt*int64(1000*1000)).Format(time.RFC3339),
diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/config.go b/vendor/github.com/mattermost/mattermost-server/v5/model/config.go
new file mode 100644
index 00000000..4ca62e79
--- /dev/null
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/config.go
@@ -0,0 +1,3451 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
+
+package model
+
+import (
+ "crypto/tls"
+ "encoding/json"
+ "io"
+ "math"
+ "net"
+ "net/http"
+ "net/url"
+ "os"
+ "regexp"
+ "strconv"
+ "strings"
+ "time"
+
+ "github.com/mattermost/ldap"
+)
+
+const (
+ CONN_SECURITY_NONE = ""
+ CONN_SECURITY_PLAIN = "PLAIN"
+ CONN_SECURITY_TLS = "TLS"
+ CONN_SECURITY_STARTTLS = "STARTTLS"
+
+ IMAGE_DRIVER_LOCAL = "local"
+ IMAGE_DRIVER_S3 = "amazons3"
+
+ DATABASE_DRIVER_SQLITE = "sqlite3"
+ DATABASE_DRIVER_MYSQL = "mysql"
+ DATABASE_DRIVER_POSTGRES = "postgres"
+
+ MINIO_ACCESS_KEY = "minioaccesskey"
+ MINIO_SECRET_KEY = "miniosecretkey"
+ MINIO_BUCKET = "mattermost-test"
+
+ PASSWORD_MAXIMUM_LENGTH = 64
+ PASSWORD_MINIMUM_LENGTH = 5
+
+ SERVICE_GITLAB = "gitlab"
+ SERVICE_GOOGLE = "google"
+ SERVICE_OFFICE365 = "office365"
+
+ GENERIC_NO_CHANNEL_NOTIFICATION = "generic_no_channel"
+ GENERIC_NOTIFICATION = "generic"
+ GENERIC_NOTIFICATION_SERVER = "https://push-test.mattermost.com"
+ FULL_NOTIFICATION = "full"
+ ID_LOADED_NOTIFICATION = "id_loaded"
+
+ DIRECT_MESSAGE_ANY = "any"
+ DIRECT_MESSAGE_TEAM = "team"
+
+ SHOW_USERNAME = "username"
+ SHOW_NICKNAME_FULLNAME = "nickname_full_name"
+ SHOW_FULLNAME = "full_name"
+
+ PERMISSIONS_ALL = "all"
+ PERMISSIONS_CHANNEL_ADMIN = "channel_admin"
+ PERMISSIONS_TEAM_ADMIN = "team_admin"
+ PERMISSIONS_SYSTEM_ADMIN = "system_admin"
+
+ FAKE_SETTING = "********************************"
+
+ RESTRICT_EMOJI_CREATION_ALL = "all"
+ RESTRICT_EMOJI_CREATION_ADMIN = "admin"
+ RESTRICT_EMOJI_CREATION_SYSTEM_ADMIN = "system_admin"
+
+ PERMISSIONS_DELETE_POST_ALL = "all"
+ PERMISSIONS_DELETE_POST_TEAM_ADMIN = "team_admin"
+ PERMISSIONS_DELETE_POST_SYSTEM_ADMIN = "system_admin"
+
+ ALLOW_EDIT_POST_ALWAYS = "always"
+ ALLOW_EDIT_POST_NEVER = "never"
+ ALLOW_EDIT_POST_TIME_LIMIT = "time_limit"
+
+ GROUP_UNREAD_CHANNELS_DISABLED = "disabled"
+ GROUP_UNREAD_CHANNELS_DEFAULT_ON = "default_on"
+ GROUP_UNREAD_CHANNELS_DEFAULT_OFF = "default_off"
+
+ EMAIL_BATCHING_BUFFER_SIZE = 256
+ EMAIL_BATCHING_INTERVAL = 30
+
+ EMAIL_NOTIFICATION_CONTENTS_FULL = "full"
+ EMAIL_NOTIFICATION_CONTENTS_GENERIC = "generic"
+
+ SITENAME_MAX_LENGTH = 30
+
+ SERVICE_SETTINGS_DEFAULT_SITE_URL = "http://localhost:8065"
+ SERVICE_SETTINGS_DEFAULT_TLS_CERT_FILE = ""
+ SERVICE_SETTINGS_DEFAULT_TLS_KEY_FILE = ""
+ SERVICE_SETTINGS_DEFAULT_READ_TIMEOUT = 300
+ SERVICE_SETTINGS_DEFAULT_WRITE_TIMEOUT = 300
+ SERVICE_SETTINGS_DEFAULT_IDLE_TIMEOUT = 60
+ SERVICE_SETTINGS_DEFAULT_MAX_LOGIN_ATTEMPTS = 10
+ SERVICE_SETTINGS_DEFAULT_ALLOW_CORS_FROM = ""
+ SERVICE_SETTINGS_DEFAULT_LISTEN_AND_ADDRESS = ":8065"
+ SERVICE_SETTINGS_DEFAULT_GFYCAT_API_KEY = "2_KtH_W5"
+ SERVICE_SETTINGS_DEFAULT_GFYCAT_API_SECRET = "3wLVZPiswc3DnaiaFoLkDvB4X0IV6CpMkj4tf2inJRsBY6-FnkT08zGmppWFgeof"
+
+ TEAM_SETTINGS_DEFAULT_SITE_NAME = "Mattermost"
+ TEAM_SETTINGS_DEFAULT_MAX_USERS_PER_TEAM = 50
+ TEAM_SETTINGS_DEFAULT_CUSTOM_BRAND_TEXT = ""
+ TEAM_SETTINGS_DEFAULT_CUSTOM_DESCRIPTION_TEXT = ""
+ TEAM_SETTINGS_DEFAULT_USER_STATUS_AWAY_TIMEOUT = 300
+
+ SQL_SETTINGS_DEFAULT_DATA_SOURCE = "mmuser:mostest@tcp(localhost:3306)/mattermost_test?charset=utf8mb4,utf8&readTimeout=30s&writeTimeout=30s"
+
+ FILE_SETTINGS_DEFAULT_DIRECTORY = "./data/"
+
+ EMAIL_SETTINGS_DEFAULT_FEEDBACK_ORGANIZATION = ""
+
+ SUPPORT_SETTINGS_DEFAULT_TERMS_OF_SERVICE_LINK = "https://about.mattermost.com/default-terms/"
+ SUPPORT_SETTINGS_DEFAULT_PRIVACY_POLICY_LINK = "https://about.mattermost.com/default-privacy-policy/"
+ SUPPORT_SETTINGS_DEFAULT_ABOUT_LINK = "https://about.mattermost.com/default-about/"
+ SUPPORT_SETTINGS_DEFAULT_HELP_LINK = "https://about.mattermost.com/default-help/"
+ SUPPORT_SETTINGS_DEFAULT_REPORT_A_PROBLEM_LINK = "https://about.mattermost.com/default-report-a-problem/"
+ SUPPORT_SETTINGS_DEFAULT_SUPPORT_EMAIL = "feedback@mattermost.com"
+ SUPPORT_SETTINGS_DEFAULT_RE_ACCEPTANCE_PERIOD = 365
+
+ LDAP_SETTINGS_DEFAULT_FIRST_NAME_ATTRIBUTE = ""
+ LDAP_SETTINGS_DEFAULT_LAST_NAME_ATTRIBUTE = ""
+ LDAP_SETTINGS_DEFAULT_EMAIL_ATTRIBUTE = ""
+ LDAP_SETTINGS_DEFAULT_USERNAME_ATTRIBUTE = ""
+ LDAP_SETTINGS_DEFAULT_NICKNAME_ATTRIBUTE = ""
+ LDAP_SETTINGS_DEFAULT_ID_ATTRIBUTE = ""
+ LDAP_SETTINGS_DEFAULT_POSITION_ATTRIBUTE = ""
+ LDAP_SETTINGS_DEFAULT_LOGIN_FIELD_NAME = ""
+ LDAP_SETTINGS_DEFAULT_GROUP_DISPLAY_NAME_ATTRIBUTE = ""
+ LDAP_SETTINGS_DEFAULT_GROUP_ID_ATTRIBUTE = ""
+ LDAP_SETTINGS_DEFAULT_PICTURE_ATTRIBUTE = ""
+
+ SAML_SETTINGS_DEFAULT_ID_ATTRIBUTE = ""
+ SAML_SETTINGS_DEFAULT_GUEST_ATTRIBUTE = ""
+ SAML_SETTINGS_DEFAULT_ADMIN_ATTRIBUTE = ""
+ SAML_SETTINGS_DEFAULT_FIRST_NAME_ATTRIBUTE = ""
+ SAML_SETTINGS_DEFAULT_LAST_NAME_ATTRIBUTE = ""
+ SAML_SETTINGS_DEFAULT_EMAIL_ATTRIBUTE = ""
+ SAML_SETTINGS_DEFAULT_USERNAME_ATTRIBUTE = ""
+ SAML_SETTINGS_DEFAULT_NICKNAME_ATTRIBUTE = ""
+ SAML_SETTINGS_DEFAULT_LOCALE_ATTRIBUTE = ""
+ SAML_SETTINGS_DEFAULT_POSITION_ATTRIBUTE = ""
+
+ SAML_SETTINGS_SIGNATURE_ALGORITHM_SHA1 = "RSAwithSHA1"
+ SAML_SETTINGS_SIGNATURE_ALGORITHM_SHA256 = "RSAwithSHA256"
+ SAML_SETTINGS_SIGNATURE_ALGORITHM_SHA512 = "RSAwithSHA512"
+ SAML_SETTINGS_DEFAULT_SIGNATURE_ALGORITHM = SAML_SETTINGS_SIGNATURE_ALGORITHM_SHA1
+
+ SAML_SETTINGS_CANONICAL_ALGORITHM_C14N = "Canonical1.0"
+ SAML_SETTINGS_CANONICAL_ALGORITHM_C14N11 = "Canonical1.1"
+ SAML_SETTINGS_DEFAULT_CANONICAL_ALGORITHM = SAML_SETTINGS_CANONICAL_ALGORITHM_C14N
+
+ NATIVEAPP_SETTINGS_DEFAULT_APP_DOWNLOAD_LINK = "https://mattermost.com/download/#mattermostApps"
+ NATIVEAPP_SETTINGS_DEFAULT_ANDROID_APP_DOWNLOAD_LINK = "https://about.mattermost.com/mattermost-android-app/"
+ NATIVEAPP_SETTINGS_DEFAULT_IOS_APP_DOWNLOAD_LINK = "https://about.mattermost.com/mattermost-ios-app/"
+
+ EXPERIMENTAL_SETTINGS_DEFAULT_LINK_METADATA_TIMEOUT_MILLISECONDS = 5000
+
+ ANALYTICS_SETTINGS_DEFAULT_MAX_USERS_FOR_STATISTICS = 2500
+
+ ANNOUNCEMENT_SETTINGS_DEFAULT_BANNER_COLOR = "#f2a93b"
+ ANNOUNCEMENT_SETTINGS_DEFAULT_BANNER_TEXT_COLOR = "#333333"
+
+ TEAM_SETTINGS_DEFAULT_TEAM_TEXT = "default"
+
+ ELASTICSEARCH_SETTINGS_DEFAULT_CONNECTION_URL = "http://localhost:9200"
+ ELASTICSEARCH_SETTINGS_DEFAULT_USERNAME = "elastic"
+ ELASTICSEARCH_SETTINGS_DEFAULT_PASSWORD = "changeme"
+ ELASTICSEARCH_SETTINGS_DEFAULT_POST_INDEX_REPLICAS = 1
+ ELASTICSEARCH_SETTINGS_DEFAULT_POST_INDEX_SHARDS = 1
+ ELASTICSEARCH_SETTINGS_DEFAULT_CHANNEL_INDEX_REPLICAS = 1
+ ELASTICSEARCH_SETTINGS_DEFAULT_CHANNEL_INDEX_SHARDS = 1
+ ELASTICSEARCH_SETTINGS_DEFAULT_USER_INDEX_REPLICAS = 1
+ ELASTICSEARCH_SETTINGS_DEFAULT_USER_INDEX_SHARDS = 1
+ ELASTICSEARCH_SETTINGS_DEFAULT_AGGREGATE_POSTS_AFTER_DAYS = 365
+ ELASTICSEARCH_SETTINGS_DEFAULT_POSTS_AGGREGATOR_JOB_START_TIME = "03:00"
+ ELASTICSEARCH_SETTINGS_DEFAULT_INDEX_PREFIX = ""
+ ELASTICSEARCH_SETTINGS_DEFAULT_LIVE_INDEXING_BATCH_SIZE = 1
+ ELASTICSEARCH_SETTINGS_DEFAULT_BULK_INDEXING_TIME_WINDOW_SECONDS = 3600
+ ELASTICSEARCH_SETTINGS_DEFAULT_REQUEST_TIMEOUT_SECONDS = 30
+
+ BLEVE_SETTINGS_DEFAULT_INDEX_DIR = ""
+ BLEVE_SETTINGS_DEFAULT_BULK_INDEXING_TIME_WINDOW_SECONDS = 3600
+
+ DATA_RETENTION_SETTINGS_DEFAULT_MESSAGE_RETENTION_DAYS = 365
+ DATA_RETENTION_SETTINGS_DEFAULT_FILE_RETENTION_DAYS = 365
+ DATA_RETENTION_SETTINGS_DEFAULT_DELETION_JOB_START_TIME = "02:00"
+
+ PLUGIN_SETTINGS_DEFAULT_DIRECTORY = "./plugins"
+ PLUGIN_SETTINGS_DEFAULT_CLIENT_DIRECTORY = "./client/plugins"
+ PLUGIN_SETTINGS_DEFAULT_ENABLE_MARKETPLACE = true
+ PLUGIN_SETTINGS_DEFAULT_MARKETPLACE_URL = "https://api.integrations.mattermost.com"
+ PLUGIN_SETTINGS_OLD_MARKETPLACE_URL = "https://marketplace.integrations.mattermost.com"
+
+ COMPLIANCE_EXPORT_TYPE_CSV = "csv"
+ COMPLIANCE_EXPORT_TYPE_ACTIANCE = "actiance"
+ COMPLIANCE_EXPORT_TYPE_GLOBALRELAY = "globalrelay"
+ COMPLIANCE_EXPORT_TYPE_GLOBALRELAY_ZIP = "globalrelay-zip"
+ GLOBALRELAY_CUSTOMER_TYPE_A9 = "A9"
+ GLOBALRELAY_CUSTOMER_TYPE_A10 = "A10"
+
+ CLIENT_SIDE_CERT_CHECK_PRIMARY_AUTH = "primary"
+ CLIENT_SIDE_CERT_CHECK_SECONDARY_AUTH = "secondary"
+
+ IMAGE_PROXY_TYPE_LOCAL = "local"
+ IMAGE_PROXY_TYPE_ATMOS_CAMO = "atmos/camo"
+
+ GOOGLE_SETTINGS_DEFAULT_SCOPE = "profile email"
+ GOOGLE_SETTINGS_DEFAULT_AUTH_ENDPOINT = "https://accounts.google.com/o/oauth2/v2/auth"
+ GOOGLE_SETTINGS_DEFAULT_TOKEN_ENDPOINT = "https://www.googleapis.com/oauth2/v4/token"
+ GOOGLE_SETTINGS_DEFAULT_USER_API_ENDPOINT = "https://people.googleapis.com/v1/people/me?personFields=names,emailAddresses,nicknames,metadata"
+
+ OFFICE365_SETTINGS_DEFAULT_SCOPE = "User.Read"
+ OFFICE365_SETTINGS_DEFAULT_AUTH_ENDPOINT = "https://login.microsoftonline.com/common/oauth2/v2.0/authorize"
+ OFFICE365_SETTINGS_DEFAULT_TOKEN_ENDPOINT = "https://login.microsoftonline.com/common/oauth2/v2.0/token"
+ OFFICE365_SETTINGS_DEFAULT_USER_API_ENDPOINT = "https://graph.microsoft.com/v1.0/me"
+
+ LOCAL_MODE_SOCKET_PATH = "/var/tmp/mattermost_local.socket"
+)
+
+var ServerTLSSupportedCiphers = map[string]uint16{
+ "TLS_RSA_WITH_RC4_128_SHA": tls.TLS_RSA_WITH_RC4_128_SHA,
+ "TLS_RSA_WITH_3DES_EDE_CBC_SHA": tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA,
+ "TLS_RSA_WITH_AES_128_CBC_SHA": tls.TLS_RSA_WITH_AES_128_CBC_SHA,
+ "TLS_RSA_WITH_AES_256_CBC_SHA": tls.TLS_RSA_WITH_AES_256_CBC_SHA,
+ "TLS_RSA_WITH_AES_128_CBC_SHA256": tls.TLS_RSA_WITH_AES_128_CBC_SHA256,
+ "TLS_RSA_WITH_AES_128_GCM_SHA256": tls.TLS_RSA_WITH_AES_128_GCM_SHA256,
+ "TLS_RSA_WITH_AES_256_GCM_SHA384": tls.TLS_RSA_WITH_AES_256_GCM_SHA384,
+ "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA": tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
+ "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA": tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
+ "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA": tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
+ "TLS_ECDHE_RSA_WITH_RC4_128_SHA": tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA,
+ "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA": tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
+ "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA": tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+ "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA": tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+ "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256": tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
+ "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256": tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
+ "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256": tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256": tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+ "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384": tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+ "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384": tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+ "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305": tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
+ "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305": tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
+}
+
+type ServiceSettings struct {
+ SiteURL *string `restricted:"true"`
+ WebsocketURL *string `restricted:"true"`
+ LicenseFileLocation *string `restricted:"true"`
+ ListenAddress *string `restricted:"true"`
+ ConnectionSecurity *string `restricted:"true"`
+ TLSCertFile *string `restricted:"true"`
+ TLSKeyFile *string `restricted:"true"`
+ TLSMinVer *string `restricted:"true"`
+ TLSStrictTransport *bool `restricted:"true"`
+ TLSStrictTransportMaxAge *int64 `restricted:"true"`
+ TLSOverwriteCiphers []string `restricted:"true"`
+ UseLetsEncrypt *bool `restricted:"true"`
+ LetsEncryptCertificateCacheFile *string `restricted:"true"`
+ Forward80To443 *bool `restricted:"true"`
+ TrustedProxyIPHeader []string `restricted:"true"`
+ ReadTimeout *int `restricted:"true"`
+ WriteTimeout *int `restricted:"true"`
+ IdleTimeout *int `restricted:"true"`
+ MaximumLoginAttempts *int `restricted:"true"`
+ GoroutineHealthThreshold *int `restricted:"true"`
+ GoogleDeveloperKey *string `restricted:"true"`
+ EnableOAuthServiceProvider *bool
+ EnableIncomingWebhooks *bool
+ EnableOutgoingWebhooks *bool
+ EnableCommands *bool
+ DEPRECATED_DO_NOT_USE_EnableOnlyAdminIntegrations *bool `json:"EnableOnlyAdminIntegrations" mapstructure:"EnableOnlyAdminIntegrations"` // This field is deprecated and must not be used.
+ EnablePostUsernameOverride *bool
+ EnablePostIconOverride *bool
+ EnableLinkPreviews *bool
+ EnableTesting *bool `restricted:"true"`
+ EnableDeveloper *bool `restricted:"true"`
+ EnableOpenTracing *bool `restricted:"true"`
+ EnableSecurityFixAlert *bool `restricted:"true"`
+ EnableInsecureOutgoingConnections *bool `restricted:"true"`
+ AllowedUntrustedInternalConnections *string `restricted:"true"`
+ EnableMultifactorAuthentication *bool
+ EnforceMultifactorAuthentication *bool
+ EnableUserAccessTokens *bool
+ AllowCorsFrom *string `restricted:"true"`
+ CorsExposedHeaders *string `restricted:"true"`
+ CorsAllowCredentials *bool `restricted:"true"`
+ CorsDebug *bool `restricted:"true"`
+ AllowCookiesForSubdomains *bool `restricted:"true"`
+ ExtendSessionLengthWithActivity *bool `restricted:"true"`
+ SessionLengthWebInDays *int `restricted:"true"`
+ SessionLengthMobileInDays *int `restricted:"true"`
+ SessionLengthSSOInDays *int `restricted:"true"`
+ SessionCacheInMinutes *int `restricted:"true"`
+ SessionIdleTimeoutInMinutes *int `restricted:"true"`
+ WebsocketSecurePort *int `restricted:"true"`
+ WebsocketPort *int `restricted:"true"`
+ WebserverMode *string `restricted:"true"`
+ EnableCustomEmoji *bool
+ EnableEmojiPicker *bool
+ EnableGifPicker *bool
+ GfycatApiKey *string
+ GfycatApiSecret *string
+ DEPRECATED_DO_NOT_USE_RestrictCustomEmojiCreation *string `json:"RestrictCustomEmojiCreation" mapstructure:"RestrictCustomEmojiCreation"` // This field is deprecated and must not be used.
+ DEPRECATED_DO_NOT_USE_RestrictPostDelete *string `json:"RestrictPostDelete" mapstructure:"RestrictPostDelete"` // This field is deprecated and must not be used.
+ DEPRECATED_DO_NOT_USE_AllowEditPost *string `json:"AllowEditPost" mapstructure:"AllowEditPost"` // This field is deprecated and must not be used.
+ PostEditTimeLimit *int
+ TimeBetweenUserTypingUpdatesMilliseconds *int64 `restricted:"true"`
+ EnablePostSearch *bool `restricted:"true"`
+ MinimumHashtagLength *int `restricted:"true"`
+ EnableUserTypingMessages *bool `restricted:"true"`
+ EnableChannelViewedMessages *bool `restricted:"true"`
+ EnableUserStatuses *bool `restricted:"true"`
+ ExperimentalEnableAuthenticationTransfer *bool `restricted:"true"`
+ ClusterLogTimeoutMilliseconds *int `restricted:"true"`
+ CloseUnusedDirectMessages *bool
+ EnablePreviewFeatures *bool
+ EnableTutorial *bool
+ ExperimentalEnableDefaultChannelLeaveJoinMessages *bool
+ ExperimentalGroupUnreadChannels *string
+ ExperimentalChannelOrganization *bool
+ ExperimentalChannelSidebarOrganization *string
+ DEPRECATED_DO_NOT_USE_ImageProxyType *string `json:"ImageProxyType" mapstructure:"ImageProxyType"` // This field is deprecated and must not be used.
+ DEPRECATED_DO_NOT_USE_ImageProxyURL *string `json:"ImageProxyURL" mapstructure:"ImageProxyURL"` // This field is deprecated and must not be used.
+ DEPRECATED_DO_NOT_USE_ImageProxyOptions *string `json:"ImageProxyOptions" mapstructure:"ImageProxyOptions"` // This field is deprecated and must not be used.
+ EnableAPITeamDeletion *bool
+ ExperimentalEnableHardenedMode *bool
+ DisableLegacyMFA *bool `restricted:"true"`
+ ExperimentalStrictCSRFEnforcement *bool `restricted:"true"`
+ EnableEmailInvitations *bool
+ DisableBotsWhenOwnerIsDeactivated *bool `restricted:"true"`
+ EnableBotAccountCreation *bool
+ EnableSVGs *bool
+ EnableLatex *bool
+ EnableLocalMode *bool
+ LocalModeSocketLocation *string
+}
+
+func (s *ServiceSettings) SetDefaults(isUpdate bool) {
+ if s.EnableEmailInvitations == nil {
+ // If the site URL is also not present then assume this is a clean install
+ if s.SiteURL == nil {
+ s.EnableEmailInvitations = NewBool(false)
+ } else {
+ s.EnableEmailInvitations = NewBool(true)
+ }
+ }
+
+ if s.SiteURL == nil {
+ if s.EnableDeveloper != nil && *s.EnableDeveloper {
+ s.SiteURL = NewString(SERVICE_SETTINGS_DEFAULT_SITE_URL)
+ } else {
+ s.SiteURL = NewString("")
+ }
+ }
+
+ if s.WebsocketURL == nil {
+ s.WebsocketURL = NewString("")
+ }
+
+ if s.LicenseFileLocation == nil {
+ s.LicenseFileLocation = NewString("")
+ }
+
+ if s.ListenAddress == nil {
+ s.ListenAddress = NewString(SERVICE_SETTINGS_DEFAULT_LISTEN_AND_ADDRESS)
+ }
+
+ if s.EnableLinkPreviews == nil {
+ s.EnableLinkPreviews = NewBool(true)
+ }
+
+ if s.EnableTesting == nil {
+ s.EnableTesting = NewBool(false)
+ }
+
+ if s.EnableDeveloper == nil {
+ s.EnableDeveloper = NewBool(false)
+ }
+
+ if s.EnableOpenTracing == nil {
+ s.EnableOpenTracing = NewBool(false)
+ }
+
+ if s.EnableSecurityFixAlert == nil {
+ s.EnableSecurityFixAlert = NewBool(true)
+ }
+
+ if s.EnableInsecureOutgoingConnections == nil {
+ s.EnableInsecureOutgoingConnections = NewBool(false)
+ }
+
+ if s.AllowedUntrustedInternalConnections == nil {
+ s.AllowedUntrustedInternalConnections = NewString("")
+ }
+
+ if s.EnableMultifactorAuthentication == nil {
+ s.EnableMultifactorAuthentication = NewBool(false)
+ }
+
+ if s.EnforceMultifactorAuthentication == nil {
+ s.EnforceMultifactorAuthentication = NewBool(false)
+ }
+
+ if s.EnableUserAccessTokens == nil {
+ s.EnableUserAccessTokens = NewBool(false)
+ }
+
+ if s.GoroutineHealthThreshold == nil {
+ s.GoroutineHealthThreshold = NewInt(-1)
+ }
+
+ if s.GoogleDeveloperKey == nil {
+ s.GoogleDeveloperKey = NewString("")
+ }
+
+ if s.EnableOAuthServiceProvider == nil {
+ s.EnableOAuthServiceProvider = NewBool(false)
+ }
+
+ if s.EnableIncomingWebhooks == nil {
+ s.EnableIncomingWebhooks = NewBool(true)
+ }
+
+ if s.EnableOutgoingWebhooks == nil {
+ s.EnableOutgoingWebhooks = NewBool(true)
+ }
+
+ if s.ConnectionSecurity == nil {
+ s.ConnectionSecurity = NewString("")
+ }
+
+ if s.TLSKeyFile == nil {
+ s.TLSKeyFile = NewString(SERVICE_SETTINGS_DEFAULT_TLS_KEY_FILE)
+ }
+
+ if s.TLSCertFile == nil {
+ s.TLSCertFile = NewString(SERVICE_SETTINGS_DEFAULT_TLS_CERT_FILE)
+ }
+
+ if s.TLSMinVer == nil {
+ s.TLSMinVer = NewString("1.2")
+ }
+
+ if s.TLSStrictTransport == nil {
+ s.TLSStrictTransport = NewBool(false)
+ }
+
+ if s.TLSStrictTransportMaxAge == nil {
+ s.TLSStrictTransportMaxAge = NewInt64(63072000)
+ }
+
+ if s.TLSOverwriteCiphers == nil {
+ s.TLSOverwriteCiphers = []string{}
+ }
+
+ if s.UseLetsEncrypt == nil {
+ s.UseLetsEncrypt = NewBool(false)
+ }
+
+ if s.LetsEncryptCertificateCacheFile == nil {
+ s.LetsEncryptCertificateCacheFile = NewString("./config/letsencrypt.cache")
+ }
+
+ if s.ReadTimeout == nil {
+ s.ReadTimeout = NewInt(SERVICE_SETTINGS_DEFAULT_READ_TIMEOUT)
+ }
+
+ if s.WriteTimeout == nil {
+ s.WriteTimeout = NewInt(SERVICE_SETTINGS_DEFAULT_WRITE_TIMEOUT)
+ }
+
+ if s.IdleTimeout == nil {
+ s.IdleTimeout = NewInt(SERVICE_SETTINGS_DEFAULT_IDLE_TIMEOUT)
+ }
+
+ if s.MaximumLoginAttempts == nil {
+ s.MaximumLoginAttempts = NewInt(SERVICE_SETTINGS_DEFAULT_MAX_LOGIN_ATTEMPTS)
+ }
+
+ if s.Forward80To443 == nil {
+ s.Forward80To443 = NewBool(false)
+ }
+
+ if isUpdate {
+ // When updating an existing configuration, ensure that defaults are set.
+ if s.TrustedProxyIPHeader == nil {
+ s.TrustedProxyIPHeader = []string{HEADER_FORWARDED, HEADER_REAL_IP}
+ }
+ } else {
+ // When generating a blank configuration, leave the list empty.
+ s.TrustedProxyIPHeader = []string{}
+ }
+
+ if s.TimeBetweenUserTypingUpdatesMilliseconds == nil {
+ s.TimeBetweenUserTypingUpdatesMilliseconds = NewInt64(5000)
+ }
+
+ if s.EnablePostSearch == nil {
+ s.EnablePostSearch = NewBool(true)
+ }
+
+ if s.MinimumHashtagLength == nil {
+ s.MinimumHashtagLength = NewInt(3)
+ }
+
+ if s.EnableUserTypingMessages == nil {
+ s.EnableUserTypingMessages = NewBool(true)
+ }
+
+ if s.EnableChannelViewedMessages == nil {
+ s.EnableChannelViewedMessages = NewBool(true)
+ }
+
+ if s.EnableUserStatuses == nil {
+ s.EnableUserStatuses = NewBool(true)
+ }
+
+ if s.ClusterLogTimeoutMilliseconds == nil {
+ s.ClusterLogTimeoutMilliseconds = NewInt(2000)
+ }
+
+ if s.CloseUnusedDirectMessages == nil {
+ s.CloseUnusedDirectMessages = NewBool(false)
+ }
+
+ if s.EnableTutorial == nil {
+ s.EnableTutorial = NewBool(true)
+ }
+
+ // Must be manually enabled for existing installations.
+ if s.ExtendSessionLengthWithActivity == nil {
+ s.ExtendSessionLengthWithActivity = NewBool(!isUpdate)
+ }
+
+ if s.SessionLengthWebInDays == nil {
+ if isUpdate {
+ s.SessionLengthWebInDays = NewInt(180)
+ } else {
+ s.SessionLengthWebInDays = NewInt(30)
+ }
+ }
+
+ if s.SessionLengthMobileInDays == nil {
+ if isUpdate {
+ s.SessionLengthMobileInDays = NewInt(180)
+ } else {
+ s.SessionLengthMobileInDays = NewInt(30)
+ }
+ }
+
+ if s.SessionLengthSSOInDays == nil {
+ s.SessionLengthSSOInDays = NewInt(30)
+ }
+
+ if s.SessionCacheInMinutes == nil {
+ s.SessionCacheInMinutes = NewInt(10)
+ }
+
+ if s.SessionIdleTimeoutInMinutes == nil {
+ s.SessionIdleTimeoutInMinutes = NewInt(43200)
+ }
+
+ if s.EnableCommands == nil {
+ s.EnableCommands = NewBool(true)
+ }
+
+ if s.DEPRECATED_DO_NOT_USE_EnableOnlyAdminIntegrations == nil {
+ s.DEPRECATED_DO_NOT_USE_EnableOnlyAdminIntegrations = NewBool(true)
+ }
+
+ if s.EnablePostUsernameOverride == nil {
+ s.EnablePostUsernameOverride = NewBool(false)
+ }
+
+ if s.EnablePostIconOverride == nil {
+ s.EnablePostIconOverride = NewBool(false)
+ }
+
+ if s.WebsocketPort == nil {
+ s.WebsocketPort = NewInt(80)
+ }
+
+ if s.WebsocketSecurePort == nil {
+ s.WebsocketSecurePort = NewInt(443)
+ }
+
+ if s.AllowCorsFrom == nil {
+ s.AllowCorsFrom = NewString(SERVICE_SETTINGS_DEFAULT_ALLOW_CORS_FROM)
+ }
+
+ if s.CorsExposedHeaders == nil {
+ s.CorsExposedHeaders = NewString("")
+ }
+
+ if s.CorsAllowCredentials == nil {
+ s.CorsAllowCredentials = NewBool(false)
+ }
+
+ if s.CorsDebug == nil {
+ s.CorsDebug = NewBool(false)
+ }
+
+ if s.AllowCookiesForSubdomains == nil {
+ s.AllowCookiesForSubdomains = NewBool(false)
+ }
+
+ if s.WebserverMode == nil {
+ s.WebserverMode = NewString("gzip")
+ } else if *s.WebserverMode == "regular" {
+ *s.WebserverMode = "gzip"
+ }
+
+ if s.EnableCustomEmoji == nil {
+ s.EnableCustomEmoji = NewBool(false)
+ }
+
+ if s.EnableEmojiPicker == nil {
+ s.EnableEmojiPicker = NewBool(true)
+ }
+
+ if s.EnableGifPicker == nil {
+ s.EnableGifPicker = NewBool(false)
+ }
+
+ if s.GfycatApiKey == nil || *s.GfycatApiKey == "" {
+ s.GfycatApiKey = NewString(SERVICE_SETTINGS_DEFAULT_GFYCAT_API_KEY)
+ }
+
+ if s.GfycatApiSecret == nil || *s.GfycatApiSecret == "" {
+ s.GfycatApiSecret = NewString(SERVICE_SETTINGS_DEFAULT_GFYCAT_API_SECRET)
+ }
+
+ if s.DEPRECATED_DO_NOT_USE_RestrictCustomEmojiCreation == nil {
+ s.DEPRECATED_DO_NOT_USE_RestrictCustomEmojiCreation = NewString(RESTRICT_EMOJI_CREATION_ALL)
+ }
+
+ if s.DEPRECATED_DO_NOT_USE_RestrictPostDelete == nil {
+ s.DEPRECATED_DO_NOT_USE_RestrictPostDelete = NewString(PERMISSIONS_DELETE_POST_ALL)
+ }
+
+ if s.DEPRECATED_DO_NOT_USE_AllowEditPost == nil {
+ s.DEPRECATED_DO_NOT_USE_AllowEditPost = NewString(ALLOW_EDIT_POST_ALWAYS)
+ }
+
+ if s.ExperimentalEnableAuthenticationTransfer == nil {
+ s.ExperimentalEnableAuthenticationTransfer = NewBool(true)
+ }
+
+ if s.PostEditTimeLimit == nil {
+ s.PostEditTimeLimit = NewInt(-1)
+ }
+
+ if s.EnablePreviewFeatures == nil {
+ s.EnablePreviewFeatures = NewBool(true)
+ }
+
+ if s.ExperimentalEnableDefaultChannelLeaveJoinMessages == nil {
+ s.ExperimentalEnableDefaultChannelLeaveJoinMessages = NewBool(true)
+ }
+
+ if s.ExperimentalGroupUnreadChannels == nil {
+ s.ExperimentalGroupUnreadChannels = NewString(GROUP_UNREAD_CHANNELS_DISABLED)
+ } else if *s.ExperimentalGroupUnreadChannels == "0" {
+ s.ExperimentalGroupUnreadChannels = NewString(GROUP_UNREAD_CHANNELS_DISABLED)
+ } else if *s.ExperimentalGroupUnreadChannels == "1" {
+ s.ExperimentalGroupUnreadChannels = NewString(GROUP_UNREAD_CHANNELS_DEFAULT_ON)
+ }
+
+ if s.ExperimentalChannelOrganization == nil {
+ experimentalUnreadEnabled := *s.ExperimentalGroupUnreadChannels != GROUP_UNREAD_CHANNELS_DISABLED
+ s.ExperimentalChannelOrganization = NewBool(experimentalUnreadEnabled)
+ }
+
+ if s.ExperimentalChannelSidebarOrganization == nil {
+ s.ExperimentalChannelSidebarOrganization = NewString("disabled")
+ }
+
+ if s.DEPRECATED_DO_NOT_USE_ImageProxyType == nil {
+ s.DEPRECATED_DO_NOT_USE_ImageProxyType = NewString("")
+ }
+
+ if s.DEPRECATED_DO_NOT_USE_ImageProxyURL == nil {
+ s.DEPRECATED_DO_NOT_USE_ImageProxyURL = NewString("")
+ }
+
+ if s.DEPRECATED_DO_NOT_USE_ImageProxyOptions == nil {
+ s.DEPRECATED_DO_NOT_USE_ImageProxyOptions = NewString("")
+ }
+
+ if s.EnableAPITeamDeletion == nil {
+ s.EnableAPITeamDeletion = NewBool(false)
+ }
+
+ if s.ExperimentalEnableHardenedMode == nil {
+ s.ExperimentalEnableHardenedMode = NewBool(false)
+ }
+
+ if s.DisableLegacyMFA == nil {
+ s.DisableLegacyMFA = NewBool(!isUpdate)
+ }
+
+ if s.ExperimentalStrictCSRFEnforcement == nil {
+ s.ExperimentalStrictCSRFEnforcement = NewBool(false)
+ }
+
+ if s.DisableBotsWhenOwnerIsDeactivated == nil {
+ s.DisableBotsWhenOwnerIsDeactivated = NewBool(true)
+ }
+
+ if s.EnableBotAccountCreation == nil {
+ s.EnableBotAccountCreation = NewBool(false)
+ }
+
+ if s.EnableSVGs == nil {
+ if isUpdate {
+ s.EnableSVGs = NewBool(true)
+ } else {
+ s.EnableSVGs = NewBool(false)
+ }
+ }
+
+ if s.EnableLatex == nil {
+ if isUpdate {
+ s.EnableLatex = NewBool(true)
+ } else {
+ s.EnableLatex = NewBool(false)
+ }
+ }
+
+ if s.EnableLocalMode == nil {
+ s.EnableLocalMode = NewBool(false)
+ }
+
+ if s.LocalModeSocketLocation == nil {
+ s.LocalModeSocketLocation = NewString(LOCAL_MODE_SOCKET_PATH)
+ }
+}
+
+type ClusterSettings struct {
+ Enable *bool `restricted:"true"`
+ ClusterName *string `restricted:"true"`
+ OverrideHostname *string `restricted:"true"`
+ NetworkInterface *string `restricted:"true"`
+ BindAddress *string `restricted:"true"`
+ AdvertiseAddress *string `restricted:"true"`
+ UseIpAddress *bool `restricted:"true"`
+ UseExperimentalGossip *bool `restricted:"true"`
+ ReadOnlyConfig *bool `restricted:"true"`
+ GossipPort *int `restricted:"true"`
+ StreamingPort *int `restricted:"true"`
+ MaxIdleConns *int `restricted:"true"`
+ MaxIdleConnsPerHost *int `restricted:"true"`
+ IdleConnTimeoutMilliseconds *int `restricted:"true"`
+}
+
+func (s *ClusterSettings) SetDefaults() {
+ if s.Enable == nil {
+ s.Enable = NewBool(false)
+ }
+
+ if s.ClusterName == nil {
+ s.ClusterName = NewString("")
+ }
+
+ if s.OverrideHostname == nil {
+ s.OverrideHostname = NewString("")
+ }
+
+ if s.NetworkInterface == nil {
+ s.NetworkInterface = NewString("")
+ }
+
+ if s.BindAddress == nil {
+ s.BindAddress = NewString("")
+ }
+
+ if s.AdvertiseAddress == nil {
+ s.AdvertiseAddress = NewString("")
+ }
+
+ if s.UseIpAddress == nil {
+ s.UseIpAddress = NewBool(true)
+ }
+
+ if s.UseExperimentalGossip == nil {
+ s.UseExperimentalGossip = NewBool(false)
+ }
+
+ if s.ReadOnlyConfig == nil {
+ s.ReadOnlyConfig = NewBool(true)
+ }
+
+ if s.GossipPort == nil {
+ s.GossipPort = NewInt(8074)
+ }
+
+ if s.StreamingPort == nil {
+ s.StreamingPort = NewInt(8075)
+ }
+
+ if s.MaxIdleConns == nil {
+ s.MaxIdleConns = NewInt(100)
+ }
+
+ if s.MaxIdleConnsPerHost == nil {
+ s.MaxIdleConnsPerHost = NewInt(128)
+ }
+
+ if s.IdleConnTimeoutMilliseconds == nil {
+ s.IdleConnTimeoutMilliseconds = NewInt(90000)
+ }
+}
+
+type MetricsSettings struct {
+ Enable *bool `restricted:"true"`
+ BlockProfileRate *int `restricted:"true"`
+ ListenAddress *string `restricted:"true"`
+}
+
+func (s *MetricsSettings) SetDefaults() {
+ if s.ListenAddress == nil {
+ s.ListenAddress = NewString(":8067")
+ }
+
+ if s.Enable == nil {
+ s.Enable = NewBool(false)
+ }
+
+ if s.BlockProfileRate == nil {
+ s.BlockProfileRate = NewInt(0)
+ }
+}
+
+type ExperimentalSettings struct {
+ ClientSideCertEnable *bool
+ ClientSideCertCheck *string
+ EnableClickToReply *bool `restricted:"true"`
+ LinkMetadataTimeoutMilliseconds *int64 `restricted:"true"`
+ RestrictSystemAdmin *bool `restricted:"true"`
+ UseNewSAMLLibrary *bool
+}
+
+func (s *ExperimentalSettings) SetDefaults() {
+ if s.ClientSideCertEnable == nil {
+ s.ClientSideCertEnable = NewBool(false)
+ }
+
+ if s.ClientSideCertCheck == nil {
+ s.ClientSideCertCheck = NewString(CLIENT_SIDE_CERT_CHECK_SECONDARY_AUTH)
+ }
+
+ if s.EnableClickToReply == nil {
+ s.EnableClickToReply = NewBool(false)
+ }
+
+ if s.LinkMetadataTimeoutMilliseconds == nil {
+ s.LinkMetadataTimeoutMilliseconds = NewInt64(EXPERIMENTAL_SETTINGS_DEFAULT_LINK_METADATA_TIMEOUT_MILLISECONDS)
+ }
+
+ if s.RestrictSystemAdmin == nil {
+ s.RestrictSystemAdmin = NewBool(false)
+ }
+ if s.UseNewSAMLLibrary == nil {
+ s.UseNewSAMLLibrary = NewBool(false)
+ }
+}
+
+type AnalyticsSettings struct {
+ MaxUsersForStatistics *int `restricted:"true"`
+}
+
+func (s *AnalyticsSettings) SetDefaults() {
+ if s.MaxUsersForStatistics == nil {
+ s.MaxUsersForStatistics = NewInt(ANALYTICS_SETTINGS_DEFAULT_MAX_USERS_FOR_STATISTICS)
+ }
+}
+
+type SSOSettings struct {
+ Enable *bool
+ Secret *string
+ Id *string
+ Scope *string
+ AuthEndpoint *string
+ TokenEndpoint *string
+ UserApiEndpoint *string
+}
+
+func (s *SSOSettings) setDefaults(scope, authEndpoint, tokenEndpoint, userApiEndpoint string) {
+ if s.Enable == nil {
+ s.Enable = NewBool(false)
+ }
+
+ if s.Secret == nil {
+ s.Secret = NewString("")
+ }
+
+ if s.Id == nil {
+ s.Id = NewString("")
+ }
+
+ if s.Scope == nil {
+ s.Scope = NewString(scope)
+ }
+
+ if s.AuthEndpoint == nil {
+ s.AuthEndpoint = NewString(authEndpoint)
+ }
+
+ if s.TokenEndpoint == nil {
+ s.TokenEndpoint = NewString(tokenEndpoint)
+ }
+
+ if s.UserApiEndpoint == nil {
+ s.UserApiEndpoint = NewString(userApiEndpoint)
+ }
+}
+
+type Office365Settings struct {
+ Enable *bool
+ Secret *string
+ Id *string
+ Scope *string
+ AuthEndpoint *string
+ TokenEndpoint *string
+ UserApiEndpoint *string
+ DirectoryId *string
+}
+
+func (s *Office365Settings) setDefaults() {
+ if s.Enable == nil {
+ s.Enable = NewBool(false)
+ }
+
+ if s.Id == nil {
+ s.Id = NewString("")
+ }
+
+ if s.Secret == nil {
+ s.Secret = NewString("")
+ }
+
+ if s.Scope == nil {
+ s.Scope = NewString(OFFICE365_SETTINGS_DEFAULT_SCOPE)
+ }
+
+ if s.AuthEndpoint == nil {
+ s.AuthEndpoint = NewString(OFFICE365_SETTINGS_DEFAULT_AUTH_ENDPOINT)
+ }
+
+ if s.TokenEndpoint == nil {
+ s.TokenEndpoint = NewString(OFFICE365_SETTINGS_DEFAULT_TOKEN_ENDPOINT)
+ }
+
+ if s.UserApiEndpoint == nil {
+ s.UserApiEndpoint = NewString(OFFICE365_SETTINGS_DEFAULT_USER_API_ENDPOINT)
+ }
+
+ if s.DirectoryId == nil {
+ s.DirectoryId = NewString("")
+ }
+}
+
+func (s *Office365Settings) SSOSettings() *SSOSettings {
+ ssoSettings := SSOSettings{}
+ ssoSettings.Enable = s.Enable
+ ssoSettings.Secret = s.Secret
+ ssoSettings.Id = s.Id
+ ssoSettings.Scope = s.Scope
+ ssoSettings.AuthEndpoint = s.AuthEndpoint
+ ssoSettings.TokenEndpoint = s.TokenEndpoint
+ ssoSettings.UserApiEndpoint = s.UserApiEndpoint
+ return &ssoSettings
+}
+
+type SqlSettings struct {
+ DriverName *string `restricted:"true"`
+ DataSource *string `restricted:"true"`
+ DataSourceReplicas []string `restricted:"true"`
+ DataSourceSearchReplicas []string `restricted:"true"`
+ MaxIdleConns *int `restricted:"true"`
+ ConnMaxLifetimeMilliseconds *int `restricted:"true"`
+ MaxOpenConns *int `restricted:"true"`
+ Trace *bool `restricted:"true"`
+ AtRestEncryptKey *string `restricted:"true"`
+ QueryTimeout *int `restricted:"true"`
+ DisableDatabaseSearch *bool `restricted:"true"`
+}
+
+func (s *SqlSettings) SetDefaults(isUpdate bool) {
+ if s.DriverName == nil {
+ s.DriverName = NewString(DATABASE_DRIVER_MYSQL)
+ }
+
+ if s.DataSource == nil {
+ s.DataSource = NewString(SQL_SETTINGS_DEFAULT_DATA_SOURCE)
+ }
+
+ if s.DataSourceReplicas == nil {
+ s.DataSourceReplicas = []string{}
+ }
+
+ if s.DataSourceSearchReplicas == nil {
+ s.DataSourceSearchReplicas = []string{}
+ }
+
+ if isUpdate {
+ // When updating an existing configuration, ensure an encryption key has been specified.
+ if s.AtRestEncryptKey == nil || len(*s.AtRestEncryptKey) == 0 {
+ s.AtRestEncryptKey = NewString(NewRandomString(32))
+ }
+ } else {
+ // When generating a blank configuration, leave this key empty to be generated on server start.
+ s.AtRestEncryptKey = NewString("")
+ }
+
+ if s.MaxIdleConns == nil {
+ s.MaxIdleConns = NewInt(20)
+ }
+
+ if s.MaxOpenConns == nil {
+ s.MaxOpenConns = NewInt(300)
+ }
+
+ if s.ConnMaxLifetimeMilliseconds == nil {
+ s.ConnMaxLifetimeMilliseconds = NewInt(3600000)
+ }
+
+ if s.Trace == nil {
+ s.Trace = NewBool(false)
+ }
+
+ if s.QueryTimeout == nil {
+ s.QueryTimeout = NewInt(30)
+ }
+
+ if s.DisableDatabaseSearch == nil {
+ s.DisableDatabaseSearch = NewBool(false)
+ }
+}
+
+type LogSettings struct {
+ EnableConsole *bool `restricted:"true"`
+ ConsoleLevel *string `restricted:"true"`
+ ConsoleJson *bool `restricted:"true"`
+ EnableFile *bool `restricted:"true"`
+ FileLevel *string `restricted:"true"`
+ FileJson *bool `restricted:"true"`
+ FileLocation *string `restricted:"true"`
+ EnableWebhookDebugging *bool `restricted:"true"`
+ EnableDiagnostics *bool `restricted:"true"`
+}
+
+func (s *LogSettings) SetDefaults() {
+ if s.EnableConsole == nil {
+ s.EnableConsole = NewBool(true)
+ }
+
+ if s.ConsoleLevel == nil {
+ s.ConsoleLevel = NewString("DEBUG")
+ }
+
+ if s.EnableFile == nil {
+ s.EnableFile = NewBool(true)
+ }
+
+ if s.FileLevel == nil {
+ s.FileLevel = NewString("INFO")
+ }
+
+ if s.FileLocation == nil {
+ s.FileLocation = NewString("")
+ }
+
+ if s.EnableWebhookDebugging == nil {
+ s.EnableWebhookDebugging = NewBool(true)
+ }
+
+ if s.EnableDiagnostics == nil {
+ s.EnableDiagnostics = NewBool(true)
+ }
+
+ if s.ConsoleJson == nil {
+ s.ConsoleJson = NewBool(true)
+ }
+
+ if s.FileJson == nil {
+ s.FileJson = NewBool(true)
+ }
+}
+
+type ExperimentalAuditSettings struct {
+ SysLogEnabled *bool `restricted:"true"`
+ SysLogIP *string `restricted:"true"`
+ SysLogPort *int `restricted:"true"`
+ SysLogTag *string `restricted:"true"`
+ SysLogCert *string `restricted:"true"`
+ SysLogInsecure *bool `restricted:"true"`
+ SysLogMaxQueueSize *int `restricted:"true"`
+
+ FileEnabled *bool `restricted:"true"`
+ FileName *string `restricted:"true"`
+ FileMaxSizeMB *int `restricted:"true"`
+ FileMaxAgeDays *int `restricted:"true"`
+ FileMaxBackups *int `restricted:"true"`
+ FileCompress *bool `restricted:"true"`
+ FileMaxQueueSize *int `restricted:"true"`
+}
+
+func (s *ExperimentalAuditSettings) SetDefaults() {
+ if s.SysLogEnabled == nil {
+ s.SysLogEnabled = NewBool(false)
+ }
+
+ if s.SysLogIP == nil {
+ s.SysLogIP = NewString("localhost")
+ }
+
+ if s.SysLogPort == nil {
+ s.SysLogPort = NewInt(6514)
+ }
+
+ if s.SysLogTag == nil {
+ s.SysLogTag = NewString("")
+ }
+
+ if s.SysLogCert == nil {
+ s.SysLogCert = NewString("")
+ }
+
+ if s.SysLogInsecure == nil {
+ s.SysLogInsecure = NewBool(false)
+ }
+
+ if s.SysLogMaxQueueSize == nil {
+ s.SysLogMaxQueueSize = NewInt(1000)
+ }
+
+ if s.FileEnabled == nil {
+ s.FileEnabled = NewBool(false)
+ }
+
+ if s.FileName == nil {
+ s.FileName = NewString("")
+ }
+
+ if s.FileMaxSizeMB == nil {
+ s.FileMaxSizeMB = NewInt(100)
+ }
+
+ if s.FileMaxAgeDays == nil {
+ s.FileMaxAgeDays = NewInt(0) // no limit on age
+ }
+
+ if s.FileMaxBackups == nil { // no limit on number of backups
+ s.FileMaxBackups = NewInt(0)
+ }
+
+ if s.FileCompress == nil {
+ s.FileCompress = NewBool(false)
+ }
+
+ if s.FileMaxQueueSize == nil {
+ s.FileMaxQueueSize = NewInt(1000)
+ }
+}
+
+type NotificationLogSettings struct {
+ EnableConsole *bool `restricted:"true"`
+ ConsoleLevel *string `restricted:"true"`
+ ConsoleJson *bool `restricted:"true"`
+ EnableFile *bool `restricted:"true"`
+ FileLevel *string `restricted:"true"`
+ FileJson *bool `restricted:"true"`
+ FileLocation *string `restricted:"true"`
+}
+
+func (s *NotificationLogSettings) SetDefaults() {
+ if s.EnableConsole == nil {
+ s.EnableConsole = NewBool(true)
+ }
+
+ if s.ConsoleLevel == nil {
+ s.ConsoleLevel = NewString("DEBUG")
+ }
+
+ if s.EnableFile == nil {
+ s.EnableFile = NewBool(true)
+ }
+
+ if s.FileLevel == nil {
+ s.FileLevel = NewString("INFO")
+ }
+
+ if s.FileLocation == nil {
+ s.FileLocation = NewString("")
+ }
+
+ if s.ConsoleJson == nil {
+ s.ConsoleJson = NewBool(true)
+ }
+
+ if s.FileJson == nil {
+ s.FileJson = NewBool(true)
+ }
+}
+
+type PasswordSettings struct {
+ MinimumLength *int
+ Lowercase *bool
+ Number *bool
+ Uppercase *bool
+ Symbol *bool
+}
+
+func (s *PasswordSettings) SetDefaults() {
+ if s.MinimumLength == nil {
+ s.MinimumLength = NewInt(10)
+ }
+
+ if s.Lowercase == nil {
+ s.Lowercase = NewBool(true)
+ }
+
+ if s.Number == nil {
+ s.Number = NewBool(true)
+ }
+
+ if s.Uppercase == nil {
+ s.Uppercase = NewBool(true)
+ }
+
+ if s.Symbol == nil {
+ s.Symbol = NewBool(true)
+ }
+}
+
+type FileSettings struct {
+ EnableFileAttachments *bool
+ EnableMobileUpload *bool
+ EnableMobileDownload *bool
+ MaxFileSize *int64
+ DriverName *string `restricted:"true"`
+ Directory *string `restricted:"true"`
+ EnablePublicLink *bool
+ PublicLinkSalt *string
+ InitialFont *string
+ AmazonS3AccessKeyId *string `restricted:"true"`
+ AmazonS3SecretAccessKey *string `restricted:"true"`
+ AmazonS3Bucket *string `restricted:"true"`
+ AmazonS3Region *string `restricted:"true"`
+ AmazonS3Endpoint *string `restricted:"true"`
+ AmazonS3SSL *bool `restricted:"true"`
+ AmazonS3SignV2 *bool `restricted:"true"`
+ AmazonS3SSE *bool `restricted:"true"`
+ AmazonS3Trace *bool `restricted:"true"`
+}
+
+func (s *FileSettings) SetDefaults(isUpdate bool) {
+ if s.EnableFileAttachments == nil {
+ s.EnableFileAttachments = NewBool(true)
+ }
+
+ if s.EnableMobileUpload == nil {
+ s.EnableMobileUpload = NewBool(true)
+ }
+
+ if s.EnableMobileDownload == nil {
+ s.EnableMobileDownload = NewBool(true)
+ }
+
+ if s.MaxFileSize == nil {
+ s.MaxFileSize = NewInt64(52428800) // 50 MB
+ }
+
+ if s.DriverName == nil {
+ s.DriverName = NewString(IMAGE_DRIVER_LOCAL)
+ }
+
+ if s.Directory == nil {
+ s.Directory = NewString(FILE_SETTINGS_DEFAULT_DIRECTORY)
+ }
+
+ if s.EnablePublicLink == nil {
+ s.EnablePublicLink = NewBool(false)
+ }
+
+ if isUpdate {
+ // When updating an existing configuration, ensure link salt has been specified.
+ if s.PublicLinkSalt == nil || len(*s.PublicLinkSalt) == 0 {
+ s.PublicLinkSalt = NewString(NewRandomString(32))
+ }
+ } else {
+ // When generating a blank configuration, leave link salt empty to be generated on server start.
+ s.PublicLinkSalt = NewString("")
+ }
+
+ if s.InitialFont == nil {
+ // Defaults to "nunito-bold.ttf"
+ s.InitialFont = NewString("nunito-bold.ttf")
+ }
+
+ if s.AmazonS3AccessKeyId == nil {
+ s.AmazonS3AccessKeyId = NewString("")
+ }
+
+ if s.AmazonS3SecretAccessKey == nil {
+ s.AmazonS3SecretAccessKey = NewString("")
+ }
+
+ if s.AmazonS3Bucket == nil {
+ s.AmazonS3Bucket = NewString("")
+ }
+
+ if s.AmazonS3Region == nil {
+ s.AmazonS3Region = NewString("")
+ }
+
+ if s.AmazonS3Endpoint == nil || len(*s.AmazonS3Endpoint) == 0 {
+ // Defaults to "s3.amazonaws.com"
+ s.AmazonS3Endpoint = NewString("s3.amazonaws.com")
+ }
+
+ if s.AmazonS3SSL == nil {
+ s.AmazonS3SSL = NewBool(true) // Secure by default.
+ }
+
+ if s.AmazonS3SignV2 == nil {
+ s.AmazonS3SignV2 = new(bool)
+ // Signature v2 is not enabled by default.
+ }
+
+ if s.AmazonS3SSE == nil {
+ s.AmazonS3SSE = NewBool(false) // Not Encrypted by default.
+ }
+
+ if s.AmazonS3Trace == nil {
+ s.AmazonS3Trace = NewBool(false)
+ }
+}
+
+type EmailSettings struct {
+ EnableSignUpWithEmail *bool
+ EnableSignInWithEmail *bool
+ EnableSignInWithUsername *bool
+ SendEmailNotifications *bool
+ UseChannelInEmailNotifications *bool
+ RequireEmailVerification *bool
+ FeedbackName *string
+ FeedbackEmail *string
+ ReplyToAddress *string
+ FeedbackOrganization *string
+ EnableSMTPAuth *bool `restricted:"true"`
+ SMTPUsername *string `restricted:"true"`
+ SMTPPassword *string `restricted:"true"`
+ SMTPServer *string `restricted:"true"`
+ SMTPPort *string `restricted:"true"`
+ SMTPServerTimeout *int
+ ConnectionSecurity *string `restricted:"true"`
+ SendPushNotifications *bool
+ PushNotificationServer *string
+ PushNotificationContents *string
+ EnableEmailBatching *bool
+ EmailBatchingBufferSize *int
+ EmailBatchingInterval *int
+ EnablePreviewModeBanner *bool
+ SkipServerCertificateVerification *bool `restricted:"true"`
+ EmailNotificationContentsType *string
+ LoginButtonColor *string
+ LoginButtonBorderColor *string
+ LoginButtonTextColor *string
+}
+
+func (s *EmailSettings) SetDefaults(isUpdate bool) {
+ if s.EnableSignUpWithEmail == nil {
+ s.EnableSignUpWithEmail = NewBool(true)
+ }
+
+ if s.EnableSignInWithEmail == nil {
+ s.EnableSignInWithEmail = NewBool(*s.EnableSignUpWithEmail)
+ }
+
+ if s.EnableSignInWithUsername == nil {
+ s.EnableSignInWithUsername = NewBool(true)
+ }
+
+ if s.SendEmailNotifications == nil {
+ s.SendEmailNotifications = NewBool(true)
+ }
+
+ if s.UseChannelInEmailNotifications == nil {
+ s.UseChannelInEmailNotifications = NewBool(false)
+ }
+
+ if s.RequireEmailVerification == nil {
+ s.RequireEmailVerification = NewBool(false)
+ }
+
+ if s.FeedbackName == nil {
+ s.FeedbackName = NewString("")
+ }
+
+ if s.FeedbackEmail == nil {
+ s.FeedbackEmail = NewString("test@example.com")
+ }
+
+ if s.ReplyToAddress == nil {
+ s.ReplyToAddress = NewString("test@example.com")
+ }
+
+ if s.FeedbackOrganization == nil {
+ s.FeedbackOrganization = NewString(EMAIL_SETTINGS_DEFAULT_FEEDBACK_ORGANIZATION)
+ }
+
+ if s.EnableSMTPAuth == nil {
+ if s.ConnectionSecurity == nil || *s.ConnectionSecurity == CONN_SECURITY_NONE {
+ s.EnableSMTPAuth = NewBool(false)
+ } else {
+ s.EnableSMTPAuth = NewBool(true)
+ }
+ }
+
+ if s.SMTPUsername == nil {
+ s.SMTPUsername = NewString("")
+ }
+
+ if s.SMTPPassword == nil {
+ s.SMTPPassword = NewString("")
+ }
+
+ if s.SMTPServer == nil || len(*s.SMTPServer) == 0 {
+ s.SMTPServer = NewString("localhost")
+ }
+
+ if s.SMTPPort == nil || len(*s.SMTPPort) == 0 {
+ s.SMTPPort = NewString("10025")
+ }
+
+ if s.SMTPServerTimeout == nil || *s.SMTPServerTimeout == 0 {
+ s.SMTPServerTimeout = NewInt(10)
+ }
+
+ if s.ConnectionSecurity == nil || *s.ConnectionSecurity == CONN_SECURITY_PLAIN {
+ s.ConnectionSecurity = NewString(CONN_SECURITY_NONE)
+ }
+
+ if s.SendPushNotifications == nil {
+ s.SendPushNotifications = NewBool(!isUpdate)
+ }
+
+ if s.PushNotificationServer == nil {
+ if isUpdate {
+ s.PushNotificationServer = NewString("")
+ } else {
+ s.PushNotificationServer = NewString(GENERIC_NOTIFICATION_SERVER)
+ }
+ }
+
+ if s.PushNotificationContents == nil {
+ s.PushNotificationContents = NewString(FULL_NOTIFICATION)
+ }
+
+ if s.EnableEmailBatching == nil {
+ s.EnableEmailBatching = NewBool(false)
+ }
+
+ if s.EmailBatchingBufferSize == nil {
+ s.EmailBatchingBufferSize = NewInt(EMAIL_BATCHING_BUFFER_SIZE)
+ }
+
+ if s.EmailBatchingInterval == nil {
+ s.EmailBatchingInterval = NewInt(EMAIL_BATCHING_INTERVAL)
+ }
+
+ if s.EnablePreviewModeBanner == nil {
+ s.EnablePreviewModeBanner = NewBool(true)
+ }
+
+ if s.EnableSMTPAuth == nil {
+ if *s.ConnectionSecurity == CONN_SECURITY_NONE {
+ s.EnableSMTPAuth = NewBool(false)
+ } else {
+ s.EnableSMTPAuth = NewBool(true)
+ }
+ }
+
+ if *s.ConnectionSecurity == CONN_SECURITY_PLAIN {
+ *s.ConnectionSecurity = CONN_SECURITY_NONE
+ }
+
+ if s.SkipServerCertificateVerification == nil {
+ s.SkipServerCertificateVerification = NewBool(false)
+ }
+
+ if s.EmailNotificationContentsType == nil {
+ s.EmailNotificationContentsType = NewString(EMAIL_NOTIFICATION_CONTENTS_FULL)
+ }
+
+ if s.LoginButtonColor == nil {
+ s.LoginButtonColor = NewString("#0000")
+ }
+
+ if s.LoginButtonBorderColor == nil {
+ s.LoginButtonBorderColor = NewString("#2389D7")
+ }
+
+ if s.LoginButtonTextColor == nil {
+ s.LoginButtonTextColor = NewString("#2389D7")
+ }
+}
+
+type RateLimitSettings struct {
+ Enable *bool `restricted:"true"`
+ PerSec *int `restricted:"true"`
+ MaxBurst *int `restricted:"true"`
+ MemoryStoreSize *int `restricted:"true"`
+ VaryByRemoteAddr *bool `restricted:"true"`
+ VaryByUser *bool `restricted:"true"`
+ VaryByHeader string `restricted:"true"`
+}
+
+func (s *RateLimitSettings) SetDefaults() {
+ if s.Enable == nil {
+ s.Enable = NewBool(false)
+ }
+
+ if s.PerSec == nil {
+ s.PerSec = NewInt(10)
+ }
+
+ if s.MaxBurst == nil {
+ s.MaxBurst = NewInt(100)
+ }
+
+ if s.MemoryStoreSize == nil {
+ s.MemoryStoreSize = NewInt(10000)
+ }
+
+ if s.VaryByRemoteAddr == nil {
+ s.VaryByRemoteAddr = NewBool(true)
+ }
+
+ if s.VaryByUser == nil {
+ s.VaryByUser = NewBool(false)
+ }
+}
+
+type PrivacySettings struct {
+ ShowEmailAddress *bool
+ ShowFullName *bool
+}
+
+func (s *PrivacySettings) setDefaults() {
+ if s.ShowEmailAddress == nil {
+ s.ShowEmailAddress = NewBool(true)
+ }
+
+ if s.ShowFullName == nil {
+ s.ShowFullName = NewBool(true)
+ }
+}
+
+type SupportSettings struct {
+ TermsOfServiceLink *string `restricted:"true"`
+ PrivacyPolicyLink *string `restricted:"true"`
+ AboutLink *string `restricted:"true"`
+ HelpLink *string `restricted:"true"`
+ ReportAProblemLink *string `restricted:"true"`
+ SupportEmail *string
+ CustomTermsOfServiceEnabled *bool
+ CustomTermsOfServiceReAcceptancePeriod *int
+}
+
+func (s *SupportSettings) SetDefaults() {
+ if !IsSafeLink(s.TermsOfServiceLink) {
+ *s.TermsOfServiceLink = SUPPORT_SETTINGS_DEFAULT_TERMS_OF_SERVICE_LINK
+ }
+
+ if s.TermsOfServiceLink == nil {
+ s.TermsOfServiceLink = NewString(SUPPORT_SETTINGS_DEFAULT_TERMS_OF_SERVICE_LINK)
+ }
+
+ if !IsSafeLink(s.PrivacyPolicyLink) {
+ *s.PrivacyPolicyLink = ""
+ }
+
+ if s.PrivacyPolicyLink == nil {
+ s.PrivacyPolicyLink = NewString(SUPPORT_SETTINGS_DEFAULT_PRIVACY_POLICY_LINK)
+ }
+
+ if !IsSafeLink(s.AboutLink) {
+ *s.AboutLink = ""
+ }
+
+ if s.AboutLink == nil {
+ s.AboutLink = NewString(SUPPORT_SETTINGS_DEFAULT_ABOUT_LINK)
+ }
+
+ if !IsSafeLink(s.HelpLink) {
+ *s.HelpLink = ""
+ }
+
+ if s.HelpLink == nil {
+ s.HelpLink = NewString(SUPPORT_SETTINGS_DEFAULT_HELP_LINK)
+ }
+
+ if !IsSafeLink(s.ReportAProblemLink) {
+ *s.ReportAProblemLink = ""
+ }
+
+ if s.ReportAProblemLink == nil {
+ s.ReportAProblemLink = NewString(SUPPORT_SETTINGS_DEFAULT_REPORT_A_PROBLEM_LINK)
+ }
+
+ if s.SupportEmail == nil {
+ s.SupportEmail = NewString(SUPPORT_SETTINGS_DEFAULT_SUPPORT_EMAIL)
+ }
+
+ if s.CustomTermsOfServiceEnabled == nil {
+ s.CustomTermsOfServiceEnabled = NewBool(false)
+ }
+
+ if s.CustomTermsOfServiceReAcceptancePeriod == nil {
+ s.CustomTermsOfServiceReAcceptancePeriod = NewInt(SUPPORT_SETTINGS_DEFAULT_RE_ACCEPTANCE_PERIOD)
+ }
+}
+
+type AnnouncementSettings struct {
+ EnableBanner *bool
+ BannerText *string
+ BannerColor *string
+ BannerTextColor *string
+ AllowBannerDismissal *bool
+}
+
+func (s *AnnouncementSettings) SetDefaults() {
+ if s.EnableBanner == nil {
+ s.EnableBanner = NewBool(false)
+ }
+
+ if s.BannerText == nil {
+ s.BannerText = NewString("")
+ }
+
+ if s.BannerColor == nil {
+ s.BannerColor = NewString(ANNOUNCEMENT_SETTINGS_DEFAULT_BANNER_COLOR)
+ }
+
+ if s.BannerTextColor == nil {
+ s.BannerTextColor = NewString(ANNOUNCEMENT_SETTINGS_DEFAULT_BANNER_TEXT_COLOR)
+ }
+
+ if s.AllowBannerDismissal == nil {
+ s.AllowBannerDismissal = NewBool(true)
+ }
+}
+
+type ThemeSettings struct {
+ EnableThemeSelection *bool
+ DefaultTheme *string
+ AllowCustomThemes *bool
+ AllowedThemes []string
+}
+
+func (s *ThemeSettings) SetDefaults() {
+ if s.EnableThemeSelection == nil {
+ s.EnableThemeSelection = NewBool(true)
+ }
+
+ if s.DefaultTheme == nil {
+ s.DefaultTheme = NewString(TEAM_SETTINGS_DEFAULT_TEAM_TEXT)
+ }
+
+ if s.AllowCustomThemes == nil {
+ s.AllowCustomThemes = NewBool(true)
+ }
+
+ if s.AllowedThemes == nil {
+ s.AllowedThemes = []string{}
+ }
+}
+
+type TeamSettings struct {
+ SiteName *string
+ MaxUsersPerTeam *int
+ DEPRECATED_DO_NOT_USE_EnableTeamCreation *bool `json:"EnableTeamCreation" mapstructure:"EnableTeamCreation"` // This field is deprecated and must not be used.
+ EnableUserCreation *bool
+ EnableOpenServer *bool
+ EnableUserDeactivation *bool
+ RestrictCreationToDomains *string
+ EnableCustomBrand *bool
+ CustomBrandText *string
+ CustomDescriptionText *string
+ RestrictDirectMessage *string
+ DEPRECATED_DO_NOT_USE_RestrictTeamInvite *string `json:"RestrictTeamInvite" mapstructure:"RestrictTeamInvite"` // This field is deprecated and must not be used.
+ DEPRECATED_DO_NOT_USE_RestrictPublicChannelManagement *string `json:"RestrictPublicChannelManagement" mapstructure:"RestrictPublicChannelManagement"` // This field is deprecated and must not be used.
+ DEPRECATED_DO_NOT_USE_RestrictPrivateChannelManagement *string `json:"RestrictPrivateChannelManagement" mapstructure:"RestrictPrivateChannelManagement"` // This field is deprecated and must not be used.
+ DEPRECATED_DO_NOT_USE_RestrictPublicChannelCreation *string `json:"RestrictPublicChannelCreation" mapstructure:"RestrictPublicChannelCreation"` // This field is deprecated and must not be used.
+ DEPRECATED_DO_NOT_USE_RestrictPrivateChannelCreation *string `json:"RestrictPrivateChannelCreation" mapstructure:"RestrictPrivateChannelCreation"` // This field is deprecated and must not be used.
+ DEPRECATED_DO_NOT_USE_RestrictPublicChannelDeletion *string `json:"RestrictPublicChannelDeletion" mapstructure:"RestrictPublicChannelDeletion"` // This field is deprecated and must not be used.
+ DEPRECATED_DO_NOT_USE_RestrictPrivateChannelDeletion *string `json:"RestrictPrivateChannelDeletion" mapstructure:"RestrictPrivateChannelDeletion"` // This field is deprecated and must not be used.
+ DEPRECATED_DO_NOT_USE_RestrictPrivateChannelManageMembers *string `json:"RestrictPrivateChannelManageMembers" mapstructure:"RestrictPrivateChannelManageMembers"` // This field is deprecated and must not be used.
+ EnableXToLeaveChannelsFromLHS *bool
+ UserStatusAwayTimeout *int64
+ MaxChannelsPerTeam *int64
+ MaxNotificationsPerChannel *int64
+ EnableConfirmNotificationsToChannel *bool
+ TeammateNameDisplay *string
+ ExperimentalViewArchivedChannels *bool
+ ExperimentalEnableAutomaticReplies *bool
+ ExperimentalHideTownSquareinLHS *bool
+ ExperimentalTownSquareIsReadOnly *bool
+ LockTeammateNameDisplay *bool
+ ExperimentalPrimaryTeam *string
+ ExperimentalDefaultChannels []string
+}
+
+func (s *TeamSettings) SetDefaults() {
+
+ if s.SiteName == nil || *s.SiteName == "" {
+ s.SiteName = NewString(TEAM_SETTINGS_DEFAULT_SITE_NAME)
+ }
+
+ if s.MaxUsersPerTeam == nil {
+ s.MaxUsersPerTeam = NewInt(TEAM_SETTINGS_DEFAULT_MAX_USERS_PER_TEAM)
+ }
+
+ if s.DEPRECATED_DO_NOT_USE_EnableTeamCreation == nil {
+ s.DEPRECATED_DO_NOT_USE_EnableTeamCreation = NewBool(true)
+ }
+
+ if s.EnableUserCreation == nil {
+ s.EnableUserCreation = NewBool(true)
+ }
+
+ if s.EnableOpenServer == nil {
+ s.EnableOpenServer = NewBool(false)
+ }
+
+ if s.RestrictCreationToDomains == nil {
+ s.RestrictCreationToDomains = NewString("")
+ }
+
+ if s.EnableCustomBrand == nil {
+ s.EnableCustomBrand = NewBool(false)
+ }
+
+ if s.EnableUserDeactivation == nil {
+ s.EnableUserDeactivation = NewBool(false)
+ }
+
+ if s.CustomBrandText == nil {
+ s.CustomBrandText = NewString(TEAM_SETTINGS_DEFAULT_CUSTOM_BRAND_TEXT)
+ }
+
+ if s.CustomDescriptionText == nil {
+ s.CustomDescriptionText = NewString(TEAM_SETTINGS_DEFAULT_CUSTOM_DESCRIPTION_TEXT)
+ }
+
+ if s.RestrictDirectMessage == nil {
+ s.RestrictDirectMessage = NewString(DIRECT_MESSAGE_ANY)
+ }
+
+ if s.DEPRECATED_DO_NOT_USE_RestrictTeamInvite == nil {
+ s.DEPRECATED_DO_NOT_USE_RestrictTeamInvite = NewString(PERMISSIONS_ALL)
+ }
+
+ if s.DEPRECATED_DO_NOT_USE_RestrictPublicChannelManagement == nil {
+ s.DEPRECATED_DO_NOT_USE_RestrictPublicChannelManagement = NewString(PERMISSIONS_ALL)
+ }
+
+ if s.DEPRECATED_DO_NOT_USE_RestrictPrivateChannelManagement == nil {
+ s.DEPRECATED_DO_NOT_USE_RestrictPrivateChannelManagement = NewString(PERMISSIONS_ALL)
+ }
+
+ if s.DEPRECATED_DO_NOT_USE_RestrictPublicChannelCreation == nil {
+ s.DEPRECATED_DO_NOT_USE_RestrictPublicChannelCreation = new(string)
+ // If this setting does not exist, assume migration from <3.6, so use management setting as default.
+ if *s.DEPRECATED_DO_NOT_USE_RestrictPublicChannelManagement == PERMISSIONS_CHANNEL_ADMIN {
+ *s.DEPRECATED_DO_NOT_USE_RestrictPublicChannelCreation = PERMISSIONS_TEAM_ADMIN
+ } else {
+ *s.DEPRECATED_DO_NOT_USE_RestrictPublicChannelCreation = *s.DEPRECATED_DO_NOT_USE_RestrictPublicChannelManagement
+ }
+ }
+
+ if s.DEPRECATED_DO_NOT_USE_RestrictPrivateChannelCreation == nil {
+ // If this setting does not exist, assume migration from <3.6, so use management setting as default.
+ if *s.DEPRECATED_DO_NOT_USE_RestrictPrivateChannelManagement == PERMISSIONS_CHANNEL_ADMIN {
+ s.DEPRECATED_DO_NOT_USE_RestrictPrivateChannelCreation = NewString(PERMISSIONS_TEAM_ADMIN)
+ } else {
+ s.DEPRECATED_DO_NOT_USE_RestrictPrivateChannelCreation = NewString(*s.DEPRECATED_DO_NOT_USE_RestrictPrivateChannelManagement)
+ }
+ }
+
+ if s.DEPRECATED_DO_NOT_USE_RestrictPublicChannelDeletion == nil {
+ // If this setting does not exist, assume migration from <3.6, so use management setting as default.
+ s.DEPRECATED_DO_NOT_USE_RestrictPublicChannelDeletion = NewString(*s.DEPRECATED_DO_NOT_USE_RestrictPublicChannelManagement)
+ }
+
+ if s.DEPRECATED_DO_NOT_USE_RestrictPrivateChannelDeletion == nil {
+ // If this setting does not exist, assume migration from <3.6, so use management setting as default.
+ s.DEPRECATED_DO_NOT_USE_RestrictPrivateChannelDeletion = NewString(*s.DEPRECATED_DO_NOT_USE_RestrictPrivateChannelManagement)
+ }
+
+ if s.DEPRECATED_DO_NOT_USE_RestrictPrivateChannelManageMembers == nil {
+ s.DEPRECATED_DO_NOT_USE_RestrictPrivateChannelManageMembers = NewString(PERMISSIONS_ALL)
+ }
+
+ if s.EnableXToLeaveChannelsFromLHS == nil {
+ s.EnableXToLeaveChannelsFromLHS = NewBool(false)
+ }
+
+ if s.UserStatusAwayTimeout == nil {
+ s.UserStatusAwayTimeout = NewInt64(TEAM_SETTINGS_DEFAULT_USER_STATUS_AWAY_TIMEOUT)
+ }
+
+ if s.MaxChannelsPerTeam == nil {
+ s.MaxChannelsPerTeam = NewInt64(2000)
+ }
+
+ if s.MaxNotificationsPerChannel == nil {
+ s.MaxNotificationsPerChannel = NewInt64(1000)
+ }
+
+ if s.EnableConfirmNotificationsToChannel == nil {
+ s.EnableConfirmNotificationsToChannel = NewBool(true)
+ }
+
+ if s.ExperimentalEnableAutomaticReplies == nil {
+ s.ExperimentalEnableAutomaticReplies = NewBool(false)
+ }
+
+ if s.ExperimentalHideTownSquareinLHS == nil {
+ s.ExperimentalHideTownSquareinLHS = NewBool(false)
+ }
+
+ if s.ExperimentalTownSquareIsReadOnly == nil {
+ s.ExperimentalTownSquareIsReadOnly = NewBool(false)
+ }
+
+ if s.ExperimentalPrimaryTeam == nil {
+ s.ExperimentalPrimaryTeam = NewString("")
+ }
+
+ if s.ExperimentalDefaultChannels == nil {
+ s.ExperimentalDefaultChannels = []string{}
+ }
+
+ if s.DEPRECATED_DO_NOT_USE_EnableTeamCreation == nil {
+ s.DEPRECATED_DO_NOT_USE_EnableTeamCreation = NewBool(true)
+ }
+
+ if s.EnableUserCreation == nil {
+ s.EnableUserCreation = NewBool(true)
+ }
+
+ if s.ExperimentalViewArchivedChannels == nil {
+ s.ExperimentalViewArchivedChannels = NewBool(false)
+ }
+
+ if s.LockTeammateNameDisplay == nil {
+ s.LockTeammateNameDisplay = NewBool(false)
+ }
+}
+
+type ClientRequirements struct {
+ AndroidLatestVersion string `restricted:"true"`
+ AndroidMinVersion string `restricted:"true"`
+ DesktopLatestVersion string `restricted:"true"`
+ DesktopMinVersion string `restricted:"true"`
+ IosLatestVersion string `restricted:"true"`
+ IosMinVersion string `restricted:"true"`
+}
+
+type LdapSettings struct {
+ // Basic
+ Enable *bool
+ EnableSync *bool
+ LdapServer *string
+ LdapPort *int
+ ConnectionSecurity *string
+ BaseDN *string
+ BindUsername *string
+ BindPassword *string
+
+ // Filtering
+ UserFilter *string
+ GroupFilter *string
+ GuestFilter *string
+ EnableAdminFilter *bool
+ AdminFilter *string
+
+ // Group Mapping
+ GroupDisplayNameAttribute *string
+ GroupIdAttribute *string
+
+ // User Mapping
+ FirstNameAttribute *string
+ LastNameAttribute *string
+ EmailAttribute *string
+ UsernameAttribute *string
+ NicknameAttribute *string
+ IdAttribute *string
+ PositionAttribute *string
+ LoginIdAttribute *string
+ PictureAttribute *string
+
+ // Synchronization
+ SyncIntervalMinutes *int
+
+ // Advanced
+ SkipCertificateVerification *bool
+ QueryTimeout *int
+ MaxPageSize *int
+
+ // Customization
+ LoginFieldName *string
+
+ LoginButtonColor *string
+ LoginButtonBorderColor *string
+ LoginButtonTextColor *string
+
+ Trace *bool
+}
+
+func (s *LdapSettings) SetDefaults() {
+ if s.Enable == nil {
+ s.Enable = NewBool(false)
+ }
+
+ // When unset should default to LDAP Enabled
+ if s.EnableSync == nil {
+ s.EnableSync = NewBool(*s.Enable)
+ }
+
+ if s.EnableAdminFilter == nil {
+ s.EnableAdminFilter = NewBool(false)
+ }
+
+ if s.LdapServer == nil {
+ s.LdapServer = NewString("")
+ }
+
+ if s.LdapPort == nil {
+ s.LdapPort = NewInt(389)
+ }
+
+ if s.ConnectionSecurity == nil {
+ s.ConnectionSecurity = NewString("")
+ }
+
+ if s.BaseDN == nil {
+ s.BaseDN = NewString("")
+ }
+
+ if s.BindUsername == nil {
+ s.BindUsername = NewString("")
+ }
+
+ if s.BindPassword == nil {
+ s.BindPassword = NewString("")
+ }
+
+ if s.UserFilter == nil {
+ s.UserFilter = NewString("")
+ }
+
+ if s.GuestFilter == nil {
+ s.GuestFilter = NewString("")
+ }
+
+ if s.AdminFilter == nil {
+ s.AdminFilter = NewString("")
+ }
+
+ if s.GroupFilter == nil {
+ s.GroupFilter = NewString("")
+ }
+
+ if s.GroupDisplayNameAttribute == nil {
+ s.GroupDisplayNameAttribute = NewString(LDAP_SETTINGS_DEFAULT_GROUP_DISPLAY_NAME_ATTRIBUTE)
+ }
+
+ if s.GroupIdAttribute == nil {
+ s.GroupIdAttribute = NewString(LDAP_SETTINGS_DEFAULT_GROUP_ID_ATTRIBUTE)
+ }
+
+ if s.FirstNameAttribute == nil {
+ s.FirstNameAttribute = NewString(LDAP_SETTINGS_DEFAULT_FIRST_NAME_ATTRIBUTE)
+ }
+
+ if s.LastNameAttribute == nil {
+ s.LastNameAttribute = NewString(LDAP_SETTINGS_DEFAULT_LAST_NAME_ATTRIBUTE)
+ }
+
+ if s.EmailAttribute == nil {
+ s.EmailAttribute = NewString(LDAP_SETTINGS_DEFAULT_EMAIL_ATTRIBUTE)
+ }
+
+ if s.UsernameAttribute == nil {
+ s.UsernameAttribute = NewString(LDAP_SETTINGS_DEFAULT_USERNAME_ATTRIBUTE)
+ }
+
+ if s.NicknameAttribute == nil {
+ s.NicknameAttribute = NewString(LDAP_SETTINGS_DEFAULT_NICKNAME_ATTRIBUTE)
+ }
+
+ if s.IdAttribute == nil {
+ s.IdAttribute = NewString(LDAP_SETTINGS_DEFAULT_ID_ATTRIBUTE)
+ }
+
+ if s.PositionAttribute == nil {
+ s.PositionAttribute = NewString(LDAP_SETTINGS_DEFAULT_POSITION_ATTRIBUTE)
+ }
+
+ if s.PictureAttribute == nil {
+ s.PictureAttribute = NewString(LDAP_SETTINGS_DEFAULT_PICTURE_ATTRIBUTE)
+ }
+
+ // For those upgrading to the version when LoginIdAttribute was added
+ // they need IdAttribute == LoginIdAttribute not to break
+ if s.LoginIdAttribute == nil {
+ s.LoginIdAttribute = s.IdAttribute
+ }
+
+ if s.SyncIntervalMinutes == nil {
+ s.SyncIntervalMinutes = NewInt(60)
+ }
+
+ if s.SkipCertificateVerification == nil {
+ s.SkipCertificateVerification = NewBool(false)
+ }
+
+ if s.QueryTimeout == nil {
+ s.QueryTimeout = NewInt(60)
+ }
+
+ if s.MaxPageSize == nil {
+ s.MaxPageSize = NewInt(0)
+ }
+
+ if s.LoginFieldName == nil {
+ s.LoginFieldName = NewString(LDAP_SETTINGS_DEFAULT_LOGIN_FIELD_NAME)
+ }
+
+ if s.LoginButtonColor == nil {
+ s.LoginButtonColor = NewString("#0000")
+ }
+
+ if s.LoginButtonBorderColor == nil {
+ s.LoginButtonBorderColor = NewString("#2389D7")
+ }
+
+ if s.LoginButtonTextColor == nil {
+ s.LoginButtonTextColor = NewString("#2389D7")
+ }
+
+ if s.Trace == nil {
+ s.Trace = NewBool(false)
+ }
+}
+
+type ComplianceSettings struct {
+ Enable *bool
+ Directory *string
+ EnableDaily *bool
+}
+
+func (s *ComplianceSettings) SetDefaults() {
+ if s.Enable == nil {
+ s.Enable = NewBool(false)
+ }
+
+ if s.Directory == nil {
+ s.Directory = NewString("./data/")
+ }
+
+ if s.EnableDaily == nil {
+ s.EnableDaily = NewBool(false)
+ }
+}
+
+type LocalizationSettings struct {
+ DefaultServerLocale *string
+ DefaultClientLocale *string
+ AvailableLocales *string
+}
+
+func (s *LocalizationSettings) SetDefaults() {
+ if s.DefaultServerLocale == nil {
+ s.DefaultServerLocale = NewString(DEFAULT_LOCALE)
+ }
+
+ if s.DefaultClientLocale == nil {
+ s.DefaultClientLocale = NewString(DEFAULT_LOCALE)
+ }
+
+ if s.AvailableLocales == nil {
+ s.AvailableLocales = NewString("")
+ }
+}
+
+type SamlSettings struct {
+ // Basic
+ Enable *bool
+ EnableSyncWithLdap *bool
+ EnableSyncWithLdapIncludeAuth *bool
+
+ Verify *bool
+ Encrypt *bool
+ SignRequest *bool
+
+ IdpUrl *string
+ IdpDescriptorUrl *string
+ IdpMetadataUrl *string
+ ServiceProviderIdentifier *string
+ AssertionConsumerServiceURL *string
+
+ SignatureAlgorithm *string
+ CanonicalAlgorithm *string
+
+ ScopingIDPProviderId *string
+ ScopingIDPName *string
+
+ IdpCertificateFile *string
+ PublicCertificateFile *string
+ PrivateKeyFile *string
+
+ // User Mapping
+ IdAttribute *string
+ GuestAttribute *string
+ EnableAdminAttribute *bool
+ AdminAttribute *string
+ FirstNameAttribute *string
+ LastNameAttribute *string
+ EmailAttribute *string
+ UsernameAttribute *string
+ NicknameAttribute *string
+ LocaleAttribute *string
+ PositionAttribute *string
+
+ LoginButtonText *string
+
+ LoginButtonColor *string
+ LoginButtonBorderColor *string
+ LoginButtonTextColor *string
+}
+
+func (s *SamlSettings) SetDefaults() {
+ if s.Enable == nil {
+ s.Enable = NewBool(false)
+ }
+
+ if s.EnableSyncWithLdap == nil {
+ s.EnableSyncWithLdap = NewBool(false)
+ }
+
+ if s.EnableSyncWithLdapIncludeAuth == nil {
+ s.EnableSyncWithLdapIncludeAuth = NewBool(false)
+ }
+
+ if s.EnableAdminAttribute == nil {
+ s.EnableAdminAttribute = NewBool(false)
+ }
+
+ if s.Verify == nil {
+ s.Verify = NewBool(true)
+ }
+
+ if s.Encrypt == nil {
+ s.Encrypt = NewBool(true)
+ }
+
+ if s.SignRequest == nil {
+ s.SignRequest = NewBool(false)
+ }
+
+ if s.SignatureAlgorithm == nil {
+ s.SignatureAlgorithm = NewString(SAML_SETTINGS_DEFAULT_SIGNATURE_ALGORITHM)
+ }
+
+ if s.CanonicalAlgorithm == nil {
+ s.CanonicalAlgorithm = NewString(SAML_SETTINGS_DEFAULT_CANONICAL_ALGORITHM)
+ }
+
+ if s.IdpUrl == nil {
+ s.IdpUrl = NewString("")
+ }
+
+ if s.IdpDescriptorUrl == nil {
+ s.IdpDescriptorUrl = NewString("")
+ }
+
+ if s.ServiceProviderIdentifier == nil {
+ if s.IdpDescriptorUrl != nil {
+ s.ServiceProviderIdentifier = NewString(*s.IdpDescriptorUrl)
+ } else {
+ s.ServiceProviderIdentifier = NewString("")
+ }
+ }
+
+ if s.IdpMetadataUrl == nil {
+ s.IdpMetadataUrl = NewString("")
+ }
+
+ if s.IdpCertificateFile == nil {
+ s.IdpCertificateFile = NewString("")
+ }
+
+ if s.PublicCertificateFile == nil {
+ s.PublicCertificateFile = NewString("")
+ }
+
+ if s.PrivateKeyFile == nil {
+ s.PrivateKeyFile = NewString("")
+ }
+
+ if s.AssertionConsumerServiceURL == nil {
+ s.AssertionConsumerServiceURL = NewString("")
+ }
+
+ if s.ScopingIDPProviderId == nil {
+ s.ScopingIDPProviderId = NewString("")
+ }
+
+ if s.ScopingIDPName == nil {
+ s.ScopingIDPName = NewString("")
+ }
+
+ if s.LoginButtonText == nil || *s.LoginButtonText == "" {
+ s.LoginButtonText = NewString(USER_AUTH_SERVICE_SAML_TEXT)
+ }
+
+ if s.IdAttribute == nil {
+ s.IdAttribute = NewString(SAML_SETTINGS_DEFAULT_ID_ATTRIBUTE)
+ }
+
+ if s.GuestAttribute == nil {
+ s.GuestAttribute = NewString(SAML_SETTINGS_DEFAULT_GUEST_ATTRIBUTE)
+ }
+ if s.AdminAttribute == nil {
+ s.AdminAttribute = NewString(SAML_SETTINGS_DEFAULT_ADMIN_ATTRIBUTE)
+ }
+ if s.FirstNameAttribute == nil {
+ s.FirstNameAttribute = NewString(SAML_SETTINGS_DEFAULT_FIRST_NAME_ATTRIBUTE)
+ }
+
+ if s.LastNameAttribute == nil {
+ s.LastNameAttribute = NewString(SAML_SETTINGS_DEFAULT_LAST_NAME_ATTRIBUTE)
+ }
+
+ if s.EmailAttribute == nil {
+ s.EmailAttribute = NewString(SAML_SETTINGS_DEFAULT_EMAIL_ATTRIBUTE)
+ }
+
+ if s.UsernameAttribute == nil {
+ s.UsernameAttribute = NewString(SAML_SETTINGS_DEFAULT_USERNAME_ATTRIBUTE)
+ }
+
+ if s.NicknameAttribute == nil {
+ s.NicknameAttribute = NewString(SAML_SETTINGS_DEFAULT_NICKNAME_ATTRIBUTE)
+ }
+
+ if s.PositionAttribute == nil {
+ s.PositionAttribute = NewString(SAML_SETTINGS_DEFAULT_POSITION_ATTRIBUTE)
+ }
+
+ if s.LocaleAttribute == nil {
+ s.LocaleAttribute = NewString(SAML_SETTINGS_DEFAULT_LOCALE_ATTRIBUTE)
+ }
+
+ if s.LoginButtonColor == nil {
+ s.LoginButtonColor = NewString("#34a28b")
+ }
+
+ if s.LoginButtonBorderColor == nil {
+ s.LoginButtonBorderColor = NewString("#2389D7")
+ }
+
+ if s.LoginButtonTextColor == nil {
+ s.LoginButtonTextColor = NewString("#ffffff")
+ }
+}
+
+type NativeAppSettings struct {
+ AppDownloadLink *string `restricted:"true"`
+ AndroidAppDownloadLink *string `restricted:"true"`
+ IosAppDownloadLink *string `restricted:"true"`
+}
+
+func (s *NativeAppSettings) SetDefaults() {
+ if s.AppDownloadLink == nil {
+ s.AppDownloadLink = NewString(NATIVEAPP_SETTINGS_DEFAULT_APP_DOWNLOAD_LINK)
+ }
+
+ if s.AndroidAppDownloadLink == nil {
+ s.AndroidAppDownloadLink = NewString(NATIVEAPP_SETTINGS_DEFAULT_ANDROID_APP_DOWNLOAD_LINK)
+ }
+
+ if s.IosAppDownloadLink == nil {
+ s.IosAppDownloadLink = NewString(NATIVEAPP_SETTINGS_DEFAULT_IOS_APP_DOWNLOAD_LINK)
+ }
+}
+
+type ElasticsearchSettings struct {
+ ConnectionUrl *string `restricted:"true"`
+ Username *string `restricted:"true"`
+ Password *string `restricted:"true"`
+ EnableIndexing *bool `restricted:"true"`
+ EnableSearching *bool `restricted:"true"`
+ EnableAutocomplete *bool `restricted:"true"`
+ Sniff *bool `restricted:"true"`
+ PostIndexReplicas *int `restricted:"true"`
+ PostIndexShards *int `restricted:"true"`
+ ChannelIndexReplicas *int `restricted:"true"`
+ ChannelIndexShards *int `restricted:"true"`
+ UserIndexReplicas *int `restricted:"true"`
+ UserIndexShards *int `restricted:"true"`
+ AggregatePostsAfterDays *int `restricted:"true"`
+ PostsAggregatorJobStartTime *string `restricted:"true"`
+ IndexPrefix *string `restricted:"true"`
+ LiveIndexingBatchSize *int `restricted:"true"`
+ BulkIndexingTimeWindowSeconds *int `restricted:"true"`
+ RequestTimeoutSeconds *int `restricted:"true"`
+ SkipTLSVerification *bool `restricted:"true"`
+ Trace *string `restricted:"true"`
+}
+
+func (s *ElasticsearchSettings) SetDefaults() {
+ if s.ConnectionUrl == nil {
+ s.ConnectionUrl = NewString(ELASTICSEARCH_SETTINGS_DEFAULT_CONNECTION_URL)
+ }
+
+ if s.Username == nil {
+ s.Username = NewString(ELASTICSEARCH_SETTINGS_DEFAULT_USERNAME)
+ }
+
+ if s.Password == nil {
+ s.Password = NewString(ELASTICSEARCH_SETTINGS_DEFAULT_PASSWORD)
+ }
+
+ if s.EnableIndexing == nil {
+ s.EnableIndexing = NewBool(false)
+ }
+
+ if s.EnableSearching == nil {
+ s.EnableSearching = NewBool(false)
+ }
+
+ if s.EnableAutocomplete == nil {
+ s.EnableAutocomplete = NewBool(false)
+ }
+
+ if s.Sniff == nil {
+ s.Sniff = NewBool(true)
+ }
+
+ if s.PostIndexReplicas == nil {
+ s.PostIndexReplicas = NewInt(ELASTICSEARCH_SETTINGS_DEFAULT_POST_INDEX_REPLICAS)
+ }
+
+ if s.PostIndexShards == nil {
+ s.PostIndexShards = NewInt(ELASTICSEARCH_SETTINGS_DEFAULT_POST_INDEX_SHARDS)
+ }
+
+ if s.ChannelIndexReplicas == nil {
+ s.ChannelIndexReplicas = NewInt(ELASTICSEARCH_SETTINGS_DEFAULT_CHANNEL_INDEX_REPLICAS)
+ }
+
+ if s.ChannelIndexShards == nil {
+ s.ChannelIndexShards = NewInt(ELASTICSEARCH_SETTINGS_DEFAULT_CHANNEL_INDEX_SHARDS)
+ }
+
+ if s.UserIndexReplicas == nil {
+ s.UserIndexReplicas = NewInt(ELASTICSEARCH_SETTINGS_DEFAULT_USER_INDEX_REPLICAS)
+ }
+
+ if s.UserIndexShards == nil {
+ s.UserIndexShards = NewInt(ELASTICSEARCH_SETTINGS_DEFAULT_USER_INDEX_SHARDS)
+ }
+
+ if s.AggregatePostsAfterDays == nil {
+ s.AggregatePostsAfterDays = NewInt(ELASTICSEARCH_SETTINGS_DEFAULT_AGGREGATE_POSTS_AFTER_DAYS)
+ }
+
+ if s.PostsAggregatorJobStartTime == nil {
+ s.PostsAggregatorJobStartTime = NewString(ELASTICSEARCH_SETTINGS_DEFAULT_POSTS_AGGREGATOR_JOB_START_TIME)
+ }
+
+ if s.IndexPrefix == nil {
+ s.IndexPrefix = NewString(ELASTICSEARCH_SETTINGS_DEFAULT_INDEX_PREFIX)
+ }
+
+ if s.LiveIndexingBatchSize == nil {
+ s.LiveIndexingBatchSize = NewInt(ELASTICSEARCH_SETTINGS_DEFAULT_LIVE_INDEXING_BATCH_SIZE)
+ }
+
+ if s.BulkIndexingTimeWindowSeconds == nil {
+ s.BulkIndexingTimeWindowSeconds = NewInt(ELASTICSEARCH_SETTINGS_DEFAULT_BULK_INDEXING_TIME_WINDOW_SECONDS)
+ }
+
+ if s.RequestTimeoutSeconds == nil {
+ s.RequestTimeoutSeconds = NewInt(ELASTICSEARCH_SETTINGS_DEFAULT_REQUEST_TIMEOUT_SECONDS)
+ }
+
+ if s.SkipTLSVerification == nil {
+ s.SkipTLSVerification = NewBool(false)
+ }
+
+ if s.Trace == nil {
+ s.Trace = NewString("")
+ }
+}
+
+type BleveSettings struct {
+ IndexDir *string
+ EnableIndexing *bool
+ EnableSearching *bool
+ EnableAutocomplete *bool
+ BulkIndexingTimeWindowSeconds *int
+}
+
+func (bs *BleveSettings) SetDefaults() {
+ if bs.IndexDir == nil {
+ bs.IndexDir = NewString(BLEVE_SETTINGS_DEFAULT_INDEX_DIR)
+ }
+
+ if bs.EnableIndexing == nil {
+ bs.EnableIndexing = NewBool(false)
+ }
+
+ if bs.EnableSearching == nil {
+ bs.EnableSearching = NewBool(false)
+ }
+
+ if bs.EnableAutocomplete == nil {
+ bs.EnableAutocomplete = NewBool(false)
+ }
+
+ if bs.BulkIndexingTimeWindowSeconds == nil {
+ bs.BulkIndexingTimeWindowSeconds = NewInt(BLEVE_SETTINGS_DEFAULT_BULK_INDEXING_TIME_WINDOW_SECONDS)
+ }
+}
+
+type DataRetentionSettings struct {
+ EnableMessageDeletion *bool
+ EnableFileDeletion *bool
+ MessageRetentionDays *int
+ FileRetentionDays *int
+ DeletionJobStartTime *string
+}
+
+func (s *DataRetentionSettings) SetDefaults() {
+ if s.EnableMessageDeletion == nil {
+ s.EnableMessageDeletion = NewBool(false)
+ }
+
+ if s.EnableFileDeletion == nil {
+ s.EnableFileDeletion = NewBool(false)
+ }
+
+ if s.MessageRetentionDays == nil {
+ s.MessageRetentionDays = NewInt(DATA_RETENTION_SETTINGS_DEFAULT_MESSAGE_RETENTION_DAYS)
+ }
+
+ if s.FileRetentionDays == nil {
+ s.FileRetentionDays = NewInt(DATA_RETENTION_SETTINGS_DEFAULT_FILE_RETENTION_DAYS)
+ }
+
+ if s.DeletionJobStartTime == nil {
+ s.DeletionJobStartTime = NewString(DATA_RETENTION_SETTINGS_DEFAULT_DELETION_JOB_START_TIME)
+ }
+}
+
+type JobSettings struct {
+ RunJobs *bool `restricted:"true"`
+ RunScheduler *bool `restricted:"true"`
+}
+
+func (s *JobSettings) SetDefaults() {
+ if s.RunJobs == nil {
+ s.RunJobs = NewBool(true)
+ }
+
+ if s.RunScheduler == nil {
+ s.RunScheduler = NewBool(true)
+ }
+}
+
+type PluginState struct {
+ Enable bool
+}
+
+type PluginSettings struct {
+ Enable *bool
+ EnableUploads *bool `restricted:"true"`
+ AllowInsecureDownloadUrl *bool `restricted:"true"`
+ EnableHealthCheck *bool `restricted:"true"`
+ Directory *string `restricted:"true"`
+ ClientDirectory *string `restricted:"true"`
+ Plugins map[string]map[string]interface{}
+ PluginStates map[string]*PluginState
+ EnableMarketplace *bool
+ EnableRemoteMarketplace *bool
+ AutomaticPrepackagedPlugins *bool
+ RequirePluginSignature *bool
+ MarketplaceUrl *string
+ SignaturePublicKeyFiles []string
+}
+
+func (s *PluginSettings) SetDefaults(ls LogSettings) {
+ if s.Enable == nil {
+ s.Enable = NewBool(true)
+ }
+
+ if s.EnableUploads == nil {
+ s.EnableUploads = NewBool(false)
+ }
+
+ if s.AllowInsecureDownloadUrl == nil {
+ s.AllowInsecureDownloadUrl = NewBool(false)
+ }
+
+ if s.EnableHealthCheck == nil {
+ s.EnableHealthCheck = NewBool(true)
+ }
+
+ if s.Directory == nil || *s.Directory == "" {
+ s.Directory = NewString(PLUGIN_SETTINGS_DEFAULT_DIRECTORY)
+ }
+
+ if s.ClientDirectory == nil || *s.ClientDirectory == "" {
+ s.ClientDirectory = NewString(PLUGIN_SETTINGS_DEFAULT_CLIENT_DIRECTORY)
+ }
+
+ if s.Plugins == nil {
+ s.Plugins = make(map[string]map[string]interface{})
+ }
+
+ if s.PluginStates == nil {
+ s.PluginStates = make(map[string]*PluginState)
+ }
+
+ if s.PluginStates["com.mattermost.nps"] == nil {
+ // Enable the NPS plugin by default if diagnostics are enabled
+ s.PluginStates["com.mattermost.nps"] = &PluginState{Enable: ls.EnableDiagnostics == nil || *ls.EnableDiagnostics}
+ }
+
+ if s.EnableMarketplace == nil {
+ s.EnableMarketplace = NewBool(PLUGIN_SETTINGS_DEFAULT_ENABLE_MARKETPLACE)
+ }
+
+ if s.EnableRemoteMarketplace == nil {
+ s.EnableRemoteMarketplace = NewBool(true)
+ }
+
+ if s.AutomaticPrepackagedPlugins == nil {
+ s.AutomaticPrepackagedPlugins = NewBool(true)
+ }
+
+ if s.MarketplaceUrl == nil || *s.MarketplaceUrl == "" || *s.MarketplaceUrl == PLUGIN_SETTINGS_OLD_MARKETPLACE_URL {
+ s.MarketplaceUrl = NewString(PLUGIN_SETTINGS_DEFAULT_MARKETPLACE_URL)
+ }
+
+ if s.RequirePluginSignature == nil {
+ s.RequirePluginSignature = NewBool(false)
+ }
+
+ if s.SignaturePublicKeyFiles == nil {
+ s.SignaturePublicKeyFiles = []string{}
+ }
+}
+
+type GlobalRelayMessageExportSettings struct {
+ CustomerType *string // must be either A9 or A10, dictates SMTP server url
+ SmtpUsername *string
+ SmtpPassword *string
+ EmailAddress *string // the address to send messages to
+}
+
+func (s *GlobalRelayMessageExportSettings) SetDefaults() {
+ if s.CustomerType == nil {
+ s.CustomerType = NewString(GLOBALRELAY_CUSTOMER_TYPE_A9)
+ }
+ if s.SmtpUsername == nil {
+ s.SmtpUsername = NewString("")
+ }
+ if s.SmtpPassword == nil {
+ s.SmtpPassword = NewString("")
+ }
+ if s.EmailAddress == nil {
+ s.EmailAddress = NewString("")
+ }
+}
+
+type MessageExportSettings struct {
+ EnableExport *bool
+ ExportFormat *string
+ DailyRunTime *string
+ ExportFromTimestamp *int64
+ BatchSize *int
+
+ // formatter-specific settings - these are only expected to be non-nil if ExportFormat is set to the associated format
+ GlobalRelaySettings *GlobalRelayMessageExportSettings
+}
+
+func (s *MessageExportSettings) SetDefaults() {
+ if s.EnableExport == nil {
+ s.EnableExport = NewBool(false)
+ }
+
+ if s.ExportFormat == nil {
+ s.ExportFormat = NewString(COMPLIANCE_EXPORT_TYPE_ACTIANCE)
+ }
+
+ if s.DailyRunTime == nil {
+ s.DailyRunTime = NewString("01:00")
+ }
+
+ if s.ExportFromTimestamp == nil {
+ s.ExportFromTimestamp = NewInt64(0)
+ }
+
+ if s.BatchSize == nil {
+ s.BatchSize = NewInt(10000)
+ }
+
+ if s.GlobalRelaySettings == nil {
+ s.GlobalRelaySettings = &GlobalRelayMessageExportSettings{}
+ }
+ s.GlobalRelaySettings.SetDefaults()
+}
+
+type DisplaySettings struct {
+ CustomUrlSchemes []string
+ ExperimentalTimezone *bool
+}
+
+func (s *DisplaySettings) SetDefaults() {
+ if s.CustomUrlSchemes == nil {
+ customUrlSchemes := []string{}
+ s.CustomUrlSchemes = customUrlSchemes
+ }
+
+ if s.ExperimentalTimezone == nil {
+ s.ExperimentalTimezone = NewBool(false)
+ }
+}
+
+type GuestAccountsSettings struct {
+ Enable *bool
+ AllowEmailAccounts *bool
+ EnforceMultifactorAuthentication *bool
+ RestrictCreationToDomains *string
+}
+
+func (s *GuestAccountsSettings) SetDefaults() {
+ if s.Enable == nil {
+ s.Enable = NewBool(false)
+ }
+
+ if s.AllowEmailAccounts == nil {
+ s.AllowEmailAccounts = NewBool(true)
+ }
+
+ if s.EnforceMultifactorAuthentication == nil {
+ s.EnforceMultifactorAuthentication = NewBool(false)
+ }
+
+ if s.RestrictCreationToDomains == nil {
+ s.RestrictCreationToDomains = NewString("")
+ }
+}
+
+type ImageProxySettings struct {
+ Enable *bool
+ ImageProxyType *string
+ RemoteImageProxyURL *string
+ RemoteImageProxyOptions *string
+}
+
+func (s *ImageProxySettings) SetDefaults(ss ServiceSettings) {
+ if s.Enable == nil {
+ if ss.DEPRECATED_DO_NOT_USE_ImageProxyType == nil || *ss.DEPRECATED_DO_NOT_USE_ImageProxyType == "" {
+ s.Enable = NewBool(false)
+ } else {
+ s.Enable = NewBool(true)
+ }
+ }
+
+ if s.ImageProxyType == nil {
+ if ss.DEPRECATED_DO_NOT_USE_ImageProxyType == nil || *ss.DEPRECATED_DO_NOT_USE_ImageProxyType == "" {
+ s.ImageProxyType = NewString(IMAGE_PROXY_TYPE_LOCAL)
+ } else {
+ s.ImageProxyType = ss.DEPRECATED_DO_NOT_USE_ImageProxyType
+ }
+ }
+
+ if s.RemoteImageProxyURL == nil {
+ if ss.DEPRECATED_DO_NOT_USE_ImageProxyURL == nil {
+ s.RemoteImageProxyURL = NewString("")
+ } else {
+ s.RemoteImageProxyURL = ss.DEPRECATED_DO_NOT_USE_ImageProxyURL
+ }
+ }
+
+ if s.RemoteImageProxyOptions == nil {
+ if ss.DEPRECATED_DO_NOT_USE_ImageProxyOptions == nil {
+ s.RemoteImageProxyOptions = NewString("")
+ } else {
+ s.RemoteImageProxyOptions = ss.DEPRECATED_DO_NOT_USE_ImageProxyOptions
+ }
+ }
+}
+
+type ConfigFunc func() *Config
+
+type Config struct {
+ ServiceSettings ServiceSettings
+ TeamSettings TeamSettings
+ ClientRequirements ClientRequirements
+ SqlSettings SqlSettings
+ LogSettings LogSettings
+ ExperimentalAuditSettings ExperimentalAuditSettings
+ NotificationLogSettings NotificationLogSettings
+ PasswordSettings PasswordSettings
+ FileSettings FileSettings
+ EmailSettings EmailSettings
+ RateLimitSettings RateLimitSettings
+ PrivacySettings PrivacySettings
+ SupportSettings SupportSettings
+ AnnouncementSettings AnnouncementSettings
+ ThemeSettings ThemeSettings
+ GitLabSettings SSOSettings
+ GoogleSettings SSOSettings
+ Office365Settings Office365Settings
+ LdapSettings LdapSettings
+ ComplianceSettings ComplianceSettings
+ LocalizationSettings LocalizationSettings
+ SamlSettings SamlSettings
+ NativeAppSettings NativeAppSettings
+ ClusterSettings ClusterSettings
+ MetricsSettings MetricsSettings
+ ExperimentalSettings ExperimentalSettings
+ AnalyticsSettings AnalyticsSettings
+ ElasticsearchSettings ElasticsearchSettings
+ BleveSettings BleveSettings
+ DataRetentionSettings DataRetentionSettings
+ MessageExportSettings MessageExportSettings
+ JobSettings JobSettings
+ PluginSettings PluginSettings
+ DisplaySettings DisplaySettings
+ GuestAccountsSettings GuestAccountsSettings
+ ImageProxySettings ImageProxySettings
+}
+
+func (o *Config) Clone() *Config {
+ var ret Config
+ if err := json.Unmarshal([]byte(o.ToJson()), &ret); err != nil {
+ panic(err)
+ }
+ return &ret
+}
+
+func (o *Config) ToJson() string {
+ b, _ := json.Marshal(o)
+ return string(b)
+}
+
+func (o *Config) GetSSOService(service string) *SSOSettings {
+ switch service {
+ case SERVICE_GITLAB:
+ return &o.GitLabSettings
+ case SERVICE_GOOGLE:
+ return &o.GoogleSettings
+ case SERVICE_OFFICE365:
+ return o.Office365Settings.SSOSettings()
+ }
+
+ return nil
+}
+
+func ConfigFromJson(data io.Reader) *Config {
+ var o *Config
+ json.NewDecoder(data).Decode(&o)
+ return o
+}
+
+// isUpdate detects a pre-existing config based on whether SiteURL has been changed
+func (o *Config) isUpdate() bool {
+ return o.ServiceSettings.SiteURL != nil
+}
+
+func (o *Config) SetDefaults() {
+ isUpdate := o.isUpdate()
+
+ o.LdapSettings.SetDefaults()
+ o.SamlSettings.SetDefaults()
+
+ if o.TeamSettings.TeammateNameDisplay == nil {
+ o.TeamSettings.TeammateNameDisplay = NewString(SHOW_USERNAME)
+
+ if *o.SamlSettings.Enable || *o.LdapSettings.Enable {
+ *o.TeamSettings.TeammateNameDisplay = SHOW_FULLNAME
+ }
+ }
+
+ o.SqlSettings.SetDefaults(isUpdate)
+ o.FileSettings.SetDefaults(isUpdate)
+ o.EmailSettings.SetDefaults(isUpdate)
+ o.PrivacySettings.setDefaults()
+ o.Office365Settings.setDefaults()
+ o.GitLabSettings.setDefaults("", "", "", "")
+ o.GoogleSettings.setDefaults(GOOGLE_SETTINGS_DEFAULT_SCOPE, GOOGLE_SETTINGS_DEFAULT_AUTH_ENDPOINT, GOOGLE_SETTINGS_DEFAULT_TOKEN_ENDPOINT, GOOGLE_SETTINGS_DEFAULT_USER_API_ENDPOINT)
+ o.ServiceSettings.SetDefaults(isUpdate)
+ o.PasswordSettings.SetDefaults()
+ o.TeamSettings.SetDefaults()
+ o.MetricsSettings.SetDefaults()
+ o.ExperimentalSettings.SetDefaults()
+ o.SupportSettings.SetDefaults()
+ o.AnnouncementSettings.SetDefaults()
+ o.ThemeSettings.SetDefaults()
+ o.ClusterSettings.SetDefaults()
+ o.PluginSettings.SetDefaults(o.LogSettings)
+ o.AnalyticsSettings.SetDefaults()
+ o.ComplianceSettings.SetDefaults()
+ o.LocalizationSettings.SetDefaults()
+ o.ElasticsearchSettings.SetDefaults()
+ o.BleveSettings.SetDefaults()
+ o.NativeAppSettings.SetDefaults()
+ o.DataRetentionSettings.SetDefaults()
+ o.RateLimitSettings.SetDefaults()
+ o.LogSettings.SetDefaults()
+ o.ExperimentalAuditSettings.SetDefaults()
+ o.NotificationLogSettings.SetDefaults()
+ o.JobSettings.SetDefaults()
+ o.MessageExportSettings.SetDefaults()
+ o.DisplaySettings.SetDefaults()
+ o.GuestAccountsSettings.SetDefaults()
+ o.ImageProxySettings.SetDefaults(o.ServiceSettings)
+}
+
+func (o *Config) IsValid() *AppError {
+ if len(*o.ServiceSettings.SiteURL) == 0 && *o.EmailSettings.EnableEmailBatching {
+ return NewAppError("Config.IsValid", "model.config.is_valid.site_url_email_batching.app_error", nil, "", http.StatusBadRequest)
+ }
+
+ if *o.ClusterSettings.Enable && *o.EmailSettings.EnableEmailBatching {
+ return NewAppError("Config.IsValid", "model.config.is_valid.cluster_email_batching.app_error", nil, "", http.StatusBadRequest)
+ }
+
+ if len(*o.ServiceSettings.SiteURL) == 0 && *o.ServiceSettings.AllowCookiesForSubdomains {
+ return NewAppError("Config.IsValid", "model.config.is_valid.allow_cookies_for_subdomains.app_error", nil, "", http.StatusBadRequest)
+ }
+
+ if err := o.TeamSettings.isValid(); err != nil {
+ return err
+ }
+
+ if err := o.SqlSettings.isValid(); err != nil {
+ return err
+ }
+
+ if err := o.FileSettings.isValid(); err != nil {
+ return err
+ }
+
+ if err := o.EmailSettings.isValid(); err != nil {
+ return err
+ }
+
+ if err := o.LdapSettings.isValid(); err != nil {
+ return err
+ }
+
+ if err := o.SamlSettings.isValid(); err != nil {
+ return err
+ }
+
+ if *o.PasswordSettings.MinimumLength < PASSWORD_MINIMUM_LENGTH || *o.PasswordSettings.MinimumLength > PASSWORD_MAXIMUM_LENGTH {
+ return NewAppError("Config.IsValid", "model.config.is_valid.password_length.app_error", map[string]interface{}{"MinLength": PASSWORD_MINIMUM_LENGTH, "MaxLength": PASSWORD_MAXIMUM_LENGTH}, "", http.StatusBadRequest)
+ }
+
+ if err := o.RateLimitSettings.isValid(); err != nil {
+ return err
+ }
+
+ if err := o.ServiceSettings.isValid(); err != nil {
+ return err
+ }
+
+ if err := o.ElasticsearchSettings.isValid(); err != nil {
+ return err
+ }
+
+ if err := o.BleveSettings.isValid(); err != nil {
+ return err
+ }
+
+ if err := o.DataRetentionSettings.isValid(); err != nil {
+ return err
+ }
+
+ if err := o.LocalizationSettings.isValid(); err != nil {
+ return err
+ }
+
+ if err := o.MessageExportSettings.isValid(o.FileSettings); err != nil {
+ return err
+ }
+
+ if err := o.DisplaySettings.isValid(); err != nil {
+ return err
+ }
+
+ if err := o.ImageProxySettings.isValid(); err != nil {
+ return err
+ }
+ return nil
+}
+
+func (s *TeamSettings) isValid() *AppError {
+ if *s.MaxUsersPerTeam <= 0 {
+ return NewAppError("Config.IsValid", "model.config.is_valid.max_users.app_error", nil, "", http.StatusBadRequest)
+ }
+
+ if *s.MaxChannelsPerTeam <= 0 {
+ return NewAppError("Config.IsValid", "model.config.is_valid.max_channels.app_error", nil, "", http.StatusBadRequest)
+ }
+
+ if *s.MaxNotificationsPerChannel <= 0 {
+ return NewAppError("Config.IsValid", "model.config.is_valid.max_notify_per_channel.app_error", nil, "", http.StatusBadRequest)
+ }
+
+ if !(*s.RestrictDirectMessage == DIRECT_MESSAGE_ANY || *s.RestrictDirectMessage == DIRECT_MESSAGE_TEAM) {
+ return NewAppError("Config.IsValid", "model.config.is_valid.restrict_direct_message.app_error", nil, "", http.StatusBadRequest)
+ }
+
+ if !(*s.TeammateNameDisplay == SHOW_FULLNAME || *s.TeammateNameDisplay == SHOW_NICKNAME_FULLNAME || *s.TeammateNameDisplay == SHOW_USERNAME) {
+ return NewAppError("Config.IsValid", "model.config.is_valid.teammate_name_display.app_error", nil, "", http.StatusBadRequest)
+ }
+
+ if len(*s.SiteName) > SITENAME_MAX_LENGTH {
+ return NewAppError("Config.IsValid", "model.config.is_valid.sitename_length.app_error", map[string]interface{}{"MaxLength": SITENAME_MAX_LENGTH}, "", http.StatusBadRequest)
+ }
+
+ return nil
+}
+
+func (s *SqlSettings) isValid() *AppError {
+ if *s.AtRestEncryptKey != "" && len(*s.AtRestEncryptKey) < 32 {
+ return NewAppError("Config.IsValid", "model.config.is_valid.encrypt_sql.app_error", nil, "", http.StatusBadRequest)
+ }
+
+ if !(*s.DriverName == DATABASE_DRIVER_MYSQL || *s.DriverName == DATABASE_DRIVER_POSTGRES) {
+ return NewAppError("Config.IsValid", "model.config.is_valid.sql_driver.app_error", nil, "", http.StatusBadRequest)
+ }
+
+ if *s.MaxIdleConns <= 0 {
+ return NewAppError("Config.IsValid", "model.config.is_valid.sql_idle.app_error", nil, "", http.StatusBadRequest)
+ }
+
+ if *s.ConnMaxLifetimeMilliseconds < 0 {
+ return NewAppError("Config.IsValid", "model.config.is_valid.sql_conn_max_lifetime_milliseconds.app_error", nil, "", http.StatusBadRequest)
+ }
+
+ if *s.QueryTimeout <= 0 {
+ return NewAppError("Config.IsValid", "model.config.is_valid.sql_query_timeout.app_error", nil, "", http.StatusBadRequest)
+ }
+
+ if len(*s.DataSource) == 0 {
+ return NewAppError("Config.IsValid", "model.config.is_valid.sql_data_src.app_error", nil, "", http.StatusBadRequest)
+ }
+
+ if *s.MaxOpenConns <= 0 {
+ return NewAppError("Config.IsValid", "model.config.is_valid.sql_max_conn.app_error", nil, "", http.StatusBadRequest)
+ }
+
+ return nil
+}
+
+func (s *FileSettings) isValid() *AppError {
+ if *s.MaxFileSize <= 0 {
+ return NewAppError("Config.IsValid", "model.config.is_valid.max_file_size.app_error", nil, "", http.StatusBadRequest)
+ }
+
+ if !(*s.DriverName == IMAGE_DRIVER_LOCAL || *s.DriverName == IMAGE_DRIVER_S3) {
+ return NewAppError("Config.IsValid", "model.config.is_valid.file_driver.app_error", nil, "", http.StatusBadRequest)
+ }
+
+ if *s.PublicLinkSalt != "" && len(*s.PublicLinkSalt) < 32 {
+ return NewAppError("Config.IsValid", "model.config.is_valid.file_salt.app_error", nil, "", http.StatusBadRequest)
+ }
+
+ return nil
+}
+
+func (s *EmailSettings) isValid() *AppError {
+ if !(*s.ConnectionSecurity == CONN_SECURITY_NONE || *s.ConnectionSecurity == CONN_SECURITY_TLS || *s.ConnectionSecurity == CONN_SECURITY_STARTTLS || *s.ConnectionSecurity == CONN_SECURITY_PLAIN) {
+ return NewAppError("Config.IsValid", "model.config.is_valid.email_security.app_error", nil, "", http.StatusBadRequest)
+ }
+
+ if *s.EmailBatchingBufferSize <= 0 {
+ return NewAppError("Config.IsValid", "model.config.is_valid.email_batching_buffer_size.app_error", nil, "", http.StatusBadRequest)
+ }
+
+ if *s.EmailBatchingInterval < 30 {
+ return NewAppError("Config.IsValid", "model.config.is_valid.email_batching_interval.app_error", nil, "", http.StatusBadRequest)
+ }
+
+ if !(*s.EmailNotificationContentsType == EMAIL_NOTIFICATION_CONTENTS_FULL || *s.EmailNotificationContentsType == EMAIL_NOTIFICATION_CONTENTS_GENERIC) {
+ return NewAppError("Config.IsValid", "model.config.is_valid.email_notification_contents_type.app_error", nil, "", http.StatusBadRequest)
+ }
+
+ return nil
+}
+
+func (s *RateLimitSettings) isValid() *AppError {
+ if *s.MemoryStoreSize <= 0 {
+ return NewAppError("Config.IsValid", "model.config.is_valid.rate_mem.app_error", nil, "", http.StatusBadRequest)
+ }
+
+ if *s.PerSec <= 0 {
+ return NewAppError("Config.IsValid", "model.config.is_valid.rate_sec.app_error", nil, "", http.StatusBadRequest)
+ }
+
+ if *s.MaxBurst <= 0 {
+ return NewAppError("Config.IsValid", "model.config.is_valid.max_burst.app_error", nil, "", http.StatusBadRequest)
+ }
+
+ return nil
+}
+
+func (s *LdapSettings) isValid() *AppError {
+ if !(*s.ConnectionSecurity == CONN_SECURITY_NONE || *s.ConnectionSecurity == CONN_SECURITY_TLS || *s.ConnectionSecurity == CONN_SECURITY_STARTTLS) {
+ return NewAppError("Config.IsValid", "model.config.is_valid.ldap_security.app_error", nil, "", http.StatusBadRequest)
+ }
+
+ if *s.SyncIntervalMinutes <= 0 {
+ return NewAppError("Config.IsValid", "model.config.is_valid.ldap_sync_interval.app_error", nil, "", http.StatusBadRequest)
+ }
+
+ if *s.MaxPageSize < 0 {
+ return NewAppError("Config.IsValid", "model.config.is_valid.ldap_max_page_size.app_error", nil, "", http.StatusBadRequest)
+ }
+
+ if *s.Enable {
+ if *s.LdapServer == "" {
+ return NewAppError("Config.IsValid", "model.config.is_valid.ldap_server", nil, "", http.StatusBadRequest)
+ }
+
+ if *s.BaseDN == "" {
+ return NewAppError("Config.IsValid", "model.config.is_valid.ldap_basedn", nil, "", http.StatusBadRequest)
+ }
+
+ if *s.EmailAttribute == "" {
+ return NewAppError("Config.IsValid", "model.config.is_valid.ldap_email", nil, "", http.StatusBadRequest)
+ }
+
+ if *s.UsernameAttribute == "" {
+ return NewAppError("Config.IsValid", "model.config.is_valid.ldap_username", nil, "", http.StatusBadRequest)
+ }
+
+ if *s.IdAttribute == "" {
+ return NewAppError("Config.IsValid", "model.config.is_valid.ldap_id", nil, "", http.StatusBadRequest)
+ }
+
+ if *s.LoginIdAttribute == "" {
+ return NewAppError("Config.IsValid", "model.config.is_valid.ldap_login_id", nil, "", http.StatusBadRequest)
+ }
+
+ if *s.UserFilter != "" {
+ if _, err := ldap.CompileFilter(*s.UserFilter); err != nil {
+ return NewAppError("ValidateFilter", "ent.ldap.validate_filter.app_error", nil, err.Error(), http.StatusBadRequest)
+ }
+ }
+
+ if *s.GuestFilter != "" {
+ if _, err := ldap.CompileFilter(*s.GuestFilter); err != nil {
+ return NewAppError("LdapSettings.isValid", "ent.ldap.validate_guest_filter.app_error", nil, err.Error(), http.StatusBadRequest)
+ }
+ }
+
+ if *s.AdminFilter != "" {
+ if _, err := ldap.CompileFilter(*s.AdminFilter); err != nil {
+ return NewAppError("LdapSettings.isValid", "ent.ldap.validate_admin_filter.app_error", nil, err.Error(), http.StatusBadRequest)
+ }
+ }
+ }
+
+ return nil
+}
+
+func (s *SamlSettings) isValid() *AppError {
+ if *s.Enable {
+ if len(*s.IdpUrl) == 0 || !IsValidHttpUrl(*s.IdpUrl) {
+ return NewAppError("Config.IsValid", "model.config.is_valid.saml_idp_url.app_error", nil, "", http.StatusBadRequest)
+ }
+
+ if len(*s.IdpDescriptorUrl) == 0 || !IsValidHttpUrl(*s.IdpDescriptorUrl) {
+ return NewAppError("Config.IsValid", "model.config.is_valid.saml_idp_descriptor_url.app_error", nil, "", http.StatusBadRequest)
+ }
+
+ if len(*s.IdpCertificateFile) == 0 {
+ return NewAppError("Config.IsValid", "model.config.is_valid.saml_idp_cert.app_error", nil, "", http.StatusBadRequest)
+ }
+
+ if len(*s.EmailAttribute) == 0 {
+ return NewAppError("Config.IsValid", "model.config.is_valid.saml_email_attribute.app_error", nil, "", http.StatusBadRequest)
+ }
+
+ if len(*s.UsernameAttribute) == 0 {
+ return NewAppError("Config.IsValid", "model.config.is_valid.saml_username_attribute.app_error", nil, "", http.StatusBadRequest)
+ }
+
+ if len(*s.ServiceProviderIdentifier) == 0 {
+ return NewAppError("Config.IsValid", "model.config.is_valid.saml_spidentifier_attribute.app_error", nil, "", http.StatusBadRequest)
+ }
+
+ if *s.Verify {
+ if len(*s.AssertionConsumerServiceURL) == 0 || !IsValidHttpUrl(*s.AssertionConsumerServiceURL) {
+ return NewAppError("Config.IsValid", "model.config.is_valid.saml_assertion_consumer_service_url.app_error", nil, "", http.StatusBadRequest)
+ }
+ }
+
+ if *s.Encrypt {
+ if len(*s.PrivateKeyFile) == 0 {
+ return NewAppError("Config.IsValid", "model.config.is_valid.saml_private_key.app_error", nil, "", http.StatusBadRequest)
+ }
+
+ if len(*s.PublicCertificateFile) == 0 {
+ return NewAppError("Config.IsValid", "model.config.is_valid.saml_public_cert.app_error", nil, "", http.StatusBadRequest)
+ }
+ }
+
+ if len(*s.EmailAttribute) == 0 {
+ return NewAppError("Config.IsValid", "model.config.is_valid.saml_email_attribute.app_error", nil, "", http.StatusBadRequest)
+ }
+
+ if !(*s.SignatureAlgorithm == SAML_SETTINGS_SIGNATURE_ALGORITHM_SHA1 || *s.SignatureAlgorithm == SAML_SETTINGS_SIGNATURE_ALGORITHM_SHA256 || *s.SignatureAlgorithm == SAML_SETTINGS_SIGNATURE_ALGORITHM_SHA512) {
+ return NewAppError("Config.IsValid", "model.config.is_valid.saml_signature_algorithm.app_error", nil, "", http.StatusBadRequest)
+ }
+ if !(*s.CanonicalAlgorithm == SAML_SETTINGS_CANONICAL_ALGORITHM_C14N || *s.CanonicalAlgorithm == SAML_SETTINGS_CANONICAL_ALGORITHM_C14N11) {
+ return NewAppError("Config.IsValid", "model.config.is_valid.saml_canonical_algorithm.app_error", nil, "", http.StatusBadRequest)
+ }
+
+ if len(*s.GuestAttribute) > 0 {
+ if !(strings.Contains(*s.GuestAttribute, "=")) {
+ return NewAppError("Config.IsValid", "model.config.is_valid.saml_guest_attribute.app_error", nil, "", http.StatusBadRequest)
+ }
+ if len(strings.Split(*s.GuestAttribute, "=")) != 2 {
+ return NewAppError("Config.IsValid", "model.config.is_valid.saml_guest_attribute.app_error", nil, "", http.StatusBadRequest)
+ }
+ }
+
+ if len(*s.AdminAttribute) > 0 {
+ if !(strings.Contains(*s.AdminAttribute, "=")) {
+ return NewAppError("Config.IsValid", "model.config.is_valid.saml_admin_attribute.app_error", nil, "", http.StatusBadRequest)
+ }
+ if len(strings.Split(*s.AdminAttribute, "=")) != 2 {
+ return NewAppError("Config.IsValid", "model.config.is_valid.saml_admin_attribute.app_error", nil, "", http.StatusBadRequest)
+ }
+ }
+ }
+
+ return nil
+}
+
+func (s *ServiceSettings) isValid() *AppError {
+ if !(*s.ConnectionSecurity == CONN_SECURITY_NONE || *s.ConnectionSecurity == CONN_SECURITY_TLS) {
+ return NewAppError("Config.IsValid", "model.config.is_valid.webserver_security.app_error", nil, "", http.StatusBadRequest)
+ }
+
+ if *s.ConnectionSecurity == CONN_SECURITY_TLS && !*s.UseLetsEncrypt {
+ appErr := NewAppError("Config.IsValid", "model.config.is_valid.tls_cert_file.app_error", nil, "", http.StatusBadRequest)
+
+ if *s.TLSCertFile == "" {
+ return appErr
+ } else if _, err := os.Stat(*s.TLSCertFile); os.IsNotExist(err) {
+ return appErr
+ }
+
+ appErr = NewAppError("Config.IsValid", "model.config.is_valid.tls_key_file.app_error", nil, "", http.StatusBadRequest)
+
+ if *s.TLSKeyFile == "" {
+ return appErr
+ } else if _, err := os.Stat(*s.TLSKeyFile); os.IsNotExist(err) {
+ return appErr
+ }
+ }
+
+ if len(s.TLSOverwriteCiphers) > 0 {
+ for _, cipher := range s.TLSOverwriteCiphers {
+ if _, ok := ServerTLSSupportedCiphers[cipher]; !ok {
+ return NewAppError("Config.IsValid", "model.config.is_valid.tls_overwrite_cipher.app_error", map[string]interface{}{"name": cipher}, "", http.StatusBadRequest)
+ }
+ }
+ }
+
+ if *s.ReadTimeout <= 0 {
+ return NewAppError("Config.IsValid", "model.config.is_valid.read_timeout.app_error", nil, "", http.StatusBadRequest)
+ }
+
+ if *s.WriteTimeout <= 0 {
+ return NewAppError("Config.IsValid", "model.config.is_valid.write_timeout.app_error", nil, "", http.StatusBadRequest)
+ }
+
+ if *s.TimeBetweenUserTypingUpdatesMilliseconds < 1000 {
+ return NewAppError("Config.IsValid", "model.config.is_valid.time_between_user_typing.app_error", nil, "", http.StatusBadRequest)
+ }
+
+ if *s.MaximumLoginAttempts <= 0 {
+ return NewAppError("Config.IsValid", "model.config.is_valid.login_attempts.app_error", nil, "", http.StatusBadRequest)
+ }
+
+ if len(*s.SiteURL) != 0 {
+ if _, err := url.ParseRequestURI(*s.SiteURL); err != nil {
+ return NewAppError("Config.IsValid", "model.config.is_valid.site_url.app_error", nil, "", http.StatusBadRequest)
+ }
+ }
+
+ if len(*s.WebsocketURL) != 0 {
+ if _, err := url.ParseRequestURI(*s.WebsocketURL); err != nil {
+ return NewAppError("Config.IsValid", "model.config.is_valid.websocket_url.app_error", nil, "", http.StatusBadRequest)
+ }
+ }
+
+ host, port, _ := net.SplitHostPort(*s.ListenAddress)
+ var isValidHost bool
+ if host == "" {
+ isValidHost = true
+ } else {
+ isValidHost = (net.ParseIP(host) != nil) || IsDomainName(host)
+ }
+ portInt, err := strconv.Atoi(port)
+ if err != nil || !isValidHost || portInt < 0 || portInt > math.MaxUint16 {
+ return NewAppError("Config.IsValid", "model.config.is_valid.listen_address.app_error", nil, "", http.StatusBadRequest)
+ }
+
+ if *s.ExperimentalGroupUnreadChannels != GROUP_UNREAD_CHANNELS_DISABLED &&
+ *s.ExperimentalGroupUnreadChannels != GROUP_UNREAD_CHANNELS_DEFAULT_ON &&
+ *s.ExperimentalGroupUnreadChannels != GROUP_UNREAD_CHANNELS_DEFAULT_OFF {
+ return NewAppError("Config.IsValid", "model.config.is_valid.group_unread_channels.app_error", nil, "", http.StatusBadRequest)
+ }
+
+ return nil
+}
+
+func (s *ElasticsearchSettings) isValid() *AppError {
+ if *s.EnableIndexing {
+ if len(*s.ConnectionUrl) == 0 {
+ return NewAppError("Config.IsValid", "model.config.is_valid.elastic_search.connection_url.app_error", nil, "", http.StatusBadRequest)
+ }
+ }
+
+ if *s.EnableSearching && !*s.EnableIndexing {
+ return NewAppError("Config.IsValid", "model.config.is_valid.elastic_search.enable_searching.app_error", nil, "", http.StatusBadRequest)
+ }
+
+ if *s.EnableAutocomplete && !*s.EnableIndexing {
+ return NewAppError("Config.IsValid", "model.config.is_valid.elastic_search.enable_autocomplete.app_error", nil, "", http.StatusBadRequest)
+ }
+
+ if *s.AggregatePostsAfterDays < 1 {
+ return NewAppError("Config.IsValid", "model.config.is_valid.elastic_search.aggregate_posts_after_days.app_error", nil, "", http.StatusBadRequest)
+ }
+
+ if _, err := time.Parse("15:04", *s.PostsAggregatorJobStartTime); err != nil {
+ return NewAppError("Config.IsValid", "model.config.is_valid.elastic_search.posts_aggregator_job_start_time.app_error", nil, err.Error(), http.StatusBadRequest)
+ }
+
+ if *s.LiveIndexingBatchSize < 1 {
+ return NewAppError("Config.IsValid", "model.config.is_valid.elastic_search.live_indexing_batch_size.app_error", nil, "", http.StatusBadRequest)
+ }
+
+ if *s.BulkIndexingTimeWindowSeconds < 1 {
+ return NewAppError("Config.IsValid", "model.config.is_valid.elastic_search.bulk_indexing_time_window_seconds.app_error", nil, "", http.StatusBadRequest)
+ }
+
+ if *s.RequestTimeoutSeconds < 1 {
+ return NewAppError("Config.IsValid", "model.config.is_valid.elastic_search.request_timeout_seconds.app_error", nil, "", http.StatusBadRequest)
+ }
+
+ return nil
+}
+
+func (bs *BleveSettings) isValid() *AppError {
+ if *bs.EnableIndexing {
+ if len(*bs.IndexDir) == 0 {
+ return NewAppError("Config.IsValid", "model.config.is_valid.bleve_search.filename.app_error", nil, "", http.StatusBadRequest)
+ }
+ } else {
+ if *bs.EnableSearching {
+ return NewAppError("Config.IsValid", "model.config.is_valid.bleve_search.enable_searching.app_error", nil, "", http.StatusBadRequest)
+ }
+ if *bs.EnableAutocomplete {
+ return NewAppError("Config.IsValid", "model.config.is_valid.bleve_search.enable_autocomplete.app_error", nil, "", http.StatusBadRequest)
+ }
+ }
+ if *bs.BulkIndexingTimeWindowSeconds < 1 {
+ return NewAppError("Config.IsValid", "model.config.is_valid.bleve_search.bulk_indexing_time_window_seconds.app_error", nil, "", http.StatusBadRequest)
+ }
+
+ return nil
+}
+
+func (s *DataRetentionSettings) isValid() *AppError {
+ if *s.MessageRetentionDays <= 0 {
+ return NewAppError("Config.IsValid", "model.config.is_valid.data_retention.message_retention_days_too_low.app_error", nil, "", http.StatusBadRequest)
+ }
+
+ if *s.FileRetentionDays <= 0 {
+ return NewAppError("Config.IsValid", "model.config.is_valid.data_retention.file_retention_days_too_low.app_error", nil, "", http.StatusBadRequest)
+ }
+
+ if _, err := time.Parse("15:04", *s.DeletionJobStartTime); err != nil {
+ return NewAppError("Config.IsValid", "model.config.is_valid.data_retention.deletion_job_start_time.app_error", nil, err.Error(), http.StatusBadRequest)
+ }
+
+ return nil
+}
+
+func (s *LocalizationSettings) isValid() *AppError {
+ if len(*s.AvailableLocales) > 0 {
+ if !strings.Contains(*s.AvailableLocales, *s.DefaultClientLocale) {
+ return NewAppError("Config.IsValid", "model.config.is_valid.localization.available_locales.app_error", nil, "", http.StatusBadRequest)
+ }
+ }
+
+ return nil
+}
+
+func (s *MessageExportSettings) isValid(fs FileSettings) *AppError {
+ if s.EnableExport == nil {
+ return NewAppError("Config.IsValid", "model.config.is_valid.message_export.enable.app_error", nil, "", http.StatusBadRequest)
+ }
+ if *s.EnableExport {
+ if s.ExportFromTimestamp == nil || *s.ExportFromTimestamp < 0 || *s.ExportFromTimestamp > GetMillis() {
+ return NewAppError("Config.IsValid", "model.config.is_valid.message_export.export_from.app_error", nil, "", http.StatusBadRequest)
+ } else if s.DailyRunTime == nil {
+ return NewAppError("Config.IsValid", "model.config.is_valid.message_export.daily_runtime.app_error", nil, "", http.StatusBadRequest)
+ } else if _, err := time.Parse("15:04", *s.DailyRunTime); err != nil {
+ return NewAppError("Config.IsValid", "model.config.is_valid.message_export.daily_runtime.app_error", nil, err.Error(), http.StatusBadRequest)
+ } else if s.BatchSize == nil || *s.BatchSize < 0 {
+ return NewAppError("Config.IsValid", "model.config.is_valid.message_export.batch_size.app_error", nil, "", http.StatusBadRequest)
+ } else if s.ExportFormat == nil || (*s.ExportFormat != COMPLIANCE_EXPORT_TYPE_ACTIANCE && *s.ExportFormat != COMPLIANCE_EXPORT_TYPE_GLOBALRELAY && *s.ExportFormat != COMPLIANCE_EXPORT_TYPE_CSV) {
+ return NewAppError("Config.IsValid", "model.config.is_valid.message_export.export_type.app_error", nil, "", http.StatusBadRequest)
+ }
+
+ if *s.ExportFormat == COMPLIANCE_EXPORT_TYPE_GLOBALRELAY {
+ if s.GlobalRelaySettings == nil {
+ return NewAppError("Config.IsValid", "model.config.is_valid.message_export.global_relay.config_missing.app_error", nil, "", http.StatusBadRequest)
+ } else if s.GlobalRelaySettings.CustomerType == nil || (*s.GlobalRelaySettings.CustomerType != GLOBALRELAY_CUSTOMER_TYPE_A9 && *s.GlobalRelaySettings.CustomerType != GLOBALRELAY_CUSTOMER_TYPE_A10) {
+ return NewAppError("Config.IsValid", "model.config.is_valid.message_export.global_relay.customer_type.app_error", nil, "", http.StatusBadRequest)
+ } else if s.GlobalRelaySettings.EmailAddress == nil || !strings.Contains(*s.GlobalRelaySettings.EmailAddress, "@") {
+ // validating email addresses is hard - just make sure it contains an '@' sign
+ // see https://stackoverflow.com/questions/201323/using-a-regular-expression-to-validate-an-email-address
+ return NewAppError("Config.IsValid", "model.config.is_valid.message_export.global_relay.email_address.app_error", nil, "", http.StatusBadRequest)
+ } else if s.GlobalRelaySettings.SmtpUsername == nil || *s.GlobalRelaySettings.SmtpUsername == "" {
+ return NewAppError("Config.IsValid", "model.config.is_valid.message_export.global_relay.smtp_username.app_error", nil, "", http.StatusBadRequest)
+ } else if s.GlobalRelaySettings.SmtpPassword == nil || *s.GlobalRelaySettings.SmtpPassword == "" {
+ return NewAppError("Config.IsValid", "model.config.is_valid.message_export.global_relay.smtp_password.app_error", nil, "", http.StatusBadRequest)
+ }
+ }
+ }
+ return nil
+}
+
+func (s *DisplaySettings) isValid() *AppError {
+ if len(s.CustomUrlSchemes) != 0 {
+ validProtocolPattern := regexp.MustCompile(`(?i)^\s*[A-Za-z][A-Za-z0-9.+-]*\s*$`)
+
+ for _, scheme := range s.CustomUrlSchemes {
+ if !validProtocolPattern.MatchString(scheme) {
+ return NewAppError(
+ "Config.IsValid",
+ "model.config.is_valid.display.custom_url_schemes.app_error",
+ map[string]interface{}{"Scheme": scheme},
+ "",
+ http.StatusBadRequest,
+ )
+ }
+ }
+ }
+
+ return nil
+}
+
+func (s *ImageProxySettings) isValid() *AppError {
+ if *s.Enable {
+ switch *s.ImageProxyType {
+ case IMAGE_PROXY_TYPE_LOCAL:
+ // No other settings to validate
+ case IMAGE_PROXY_TYPE_ATMOS_CAMO:
+ if *s.RemoteImageProxyURL == "" {
+ return NewAppError("Config.IsValid", "model.config.is_valid.atmos_camo_image_proxy_url.app_error", nil, "", http.StatusBadRequest)
+ }
+
+ if *s.RemoteImageProxyOptions == "" {
+ return NewAppError("Config.IsValid", "model.config.is_valid.atmos_camo_image_proxy_options.app_error", nil, "", http.StatusBadRequest)
+ }
+ default:
+ return NewAppError("Config.IsValid", "model.config.is_valid.image_proxy_type.app_error", nil, "", http.StatusBadRequest)
+ }
+ }
+
+ return nil
+}
+
+func (o *Config) GetSanitizeOptions() map[string]bool {
+ options := map[string]bool{}
+ options["fullname"] = *o.PrivacySettings.ShowFullName
+ options["email"] = *o.PrivacySettings.ShowEmailAddress
+
+ return options
+}
+
+func (o *Config) Sanitize() {
+ if o.LdapSettings.BindPassword != nil && len(*o.LdapSettings.BindPassword) > 0 {
+ *o.LdapSettings.BindPassword = FAKE_SETTING
+ }
+
+ *o.FileSettings.PublicLinkSalt = FAKE_SETTING
+
+ if len(*o.FileSettings.AmazonS3SecretAccessKey) > 0 {
+ *o.FileSettings.AmazonS3SecretAccessKey = FAKE_SETTING
+ }
+
+ if o.EmailSettings.SMTPPassword != nil && len(*o.EmailSettings.SMTPPassword) > 0 {
+ *o.EmailSettings.SMTPPassword = FAKE_SETTING
+ }
+
+ if len(*o.GitLabSettings.Secret) > 0 {
+ *o.GitLabSettings.Secret = FAKE_SETTING
+ }
+
+ *o.SqlSettings.DataSource = FAKE_SETTING
+ *o.SqlSettings.AtRestEncryptKey = FAKE_SETTING
+
+ *o.ElasticsearchSettings.Password = FAKE_SETTING
+
+ for i := range o.SqlSettings.DataSourceReplicas {
+ o.SqlSettings.DataSourceReplicas[i] = FAKE_SETTING
+ }
+
+ for i := range o.SqlSettings.DataSourceSearchReplicas {
+ o.SqlSettings.DataSourceSearchReplicas[i] = FAKE_SETTING
+ }
+}
diff --git a/vendor/github.com/mattermost/mattermost-server/model/data_retention_policy.go b/vendor/github.com/mattermost/mattermost-server/v5/model/data_retention_policy.go
index dbb13374..a39ff911 100644
--- a/vendor/github.com/mattermost/mattermost-server/model/data_retention_policy.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/data_retention_policy.go
@@ -1,5 +1,5 @@
-// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
package model
diff --git a/vendor/github.com/mattermost/mattermost-server/model/emoji.go b/vendor/github.com/mattermost/mattermost-server/v5/model/emoji.go
index f14af89d..aeee9b38 100644
--- a/vendor/github.com/mattermost/mattermost-server/model/emoji.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/emoji.go
@@ -1,5 +1,5 @@
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
package model
@@ -7,6 +7,7 @@ import (
"encoding/json"
"io"
"net/http"
+ "regexp"
)
const (
@@ -14,6 +15,8 @@ const (
EMOJI_SORT_BY_NAME = "name"
)
+var EMOJI_PATTERN = regexp.MustCompile(`:[a-zA-Z0-9_-]+:`)
+
type Emoji struct {
Id string `json:"id"`
CreateAt int64 `json:"create_at"`
@@ -28,8 +31,13 @@ func inSystemEmoji(emojiName string) bool {
return ok
}
+func GetSystemEmojiId(emojiName string) (string, bool) {
+ id, found := SystemEmojis[emojiName]
+ return id, found
+}
+
func (emoji *Emoji) IsValid() *AppError {
- if len(emoji.Id) != 26 {
+ if !IsValidId(emoji.Id) {
return NewAppError("Emoji.IsValid", "model.emoji.id.app_error", nil, "", http.StatusBadRequest)
}
diff --git a/vendor/github.com/mattermost/mattermost-server/model/emoji_data.go b/vendor/github.com/mattermost/mattermost-server/v5/model/emoji_data.go
index f6e62e68..807f6abb 100644
--- a/vendor/github.com/mattermost/mattermost-server/model/emoji_data.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/emoji_data.go
@@ -1,5 +1,5 @@
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
package model
diff --git a/vendor/github.com/mattermost/mattermost-server/model/emoji_search.go b/vendor/github.com/mattermost/mattermost-server/v5/model/emoji_search.go
index 3a768a57..71e2671c 100644
--- a/vendor/github.com/mattermost/mattermost-server/model/emoji_search.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/emoji_search.go
@@ -1,5 +1,5 @@
-// Copyright (c) 2018-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
package model
diff --git a/vendor/github.com/mattermost/mattermost-server/model/file.go b/vendor/github.com/mattermost/mattermost-server/v5/model/file.go
index c7ffbf0b..9f76bac1 100644
--- a/vendor/github.com/mattermost/mattermost-server/model/file.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/file.go
@@ -1,5 +1,5 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// See LICENSE.txt for license information.
package model
@@ -9,12 +9,12 @@ import (
)
const (
- MaxImageSize = 6048 * 4032 // 24 megapixels, roughly 36MB as a raw image
+ MaxImageSize = int64(6048 * 4032) // 24 megapixels, roughly 36MB as a raw image
)
var (
- IMAGE_EXTENSIONS = [5]string{".jpg", ".jpeg", ".gif", ".bmp", ".png"}
- IMAGE_MIME_TYPES = map[string]string{".jpg": "image/jpeg", ".jpeg": "image/jpeg", ".gif": "image/gif", ".bmp": "image/bmp", ".png": "image/png", ".tiff": "image/tiff"}
+ IMAGE_EXTENSIONS = [7]string{".jpg", ".jpeg", ".gif", ".bmp", ".png", ".tiff", "tif"}
+ IMAGE_MIME_TYPES = map[string]string{".jpg": "image/jpeg", ".jpeg": "image/jpeg", ".gif": "image/gif", ".bmp": "image/bmp", ".png": "image/png", ".tiff": "image/tiff", ".tif": "image/tif"}
)
type FileUploadResponse struct {
diff --git a/vendor/github.com/mattermost/mattermost-server/model/file_info.go b/vendor/github.com/mattermost/mattermost-server/v5/model/file_info.go
index e0bbfcfc..8a3a5cc0 100644
--- a/vendor/github.com/mattermost/mattermost-server/model/file_info.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/file_info.go
@@ -1,5 +1,5 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// See LICENSE.txt for license information.
package model
@@ -15,6 +15,27 @@ import (
"strings"
)
+const (
+ FILEINFO_SORT_BY_CREATED = "CreateAt"
+ FILEINFO_SORT_BY_SIZE = "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"`
@@ -34,19 +55,19 @@ type FileInfo struct {
HasPreviewImage bool `json:"has_preview_image,omitempty"`
}
-func (info *FileInfo) ToJson() string {
- b, _ := json.Marshal(info)
+func (fi *FileInfo) ToJson() string {
+ b, _ := json.Marshal(fi)
return string(b)
}
func FileInfoFromJson(data io.Reader) *FileInfo {
decoder := json.NewDecoder(data)
- var info FileInfo
- if err := decoder.Decode(&info); err != nil {
+ var fi FileInfo
+ if err := decoder.Decode(&fi); err != nil {
return nil
} else {
- return &info
+ return &fi
}
}
@@ -66,50 +87,68 @@ func FileInfosFromJson(data io.Reader) []*FileInfo {
}
}
-func (o *FileInfo) PreSave() {
- if o.Id == "" {
- o.Id = NewId()
+func (fi *FileInfo) PreSave() {
+ if fi.Id == "" {
+ fi.Id = NewId()
}
- if o.CreateAt == 0 {
- o.CreateAt = GetMillis()
+ if fi.CreateAt == 0 {
+ fi.CreateAt = GetMillis()
}
- if o.UpdateAt < o.CreateAt {
- o.UpdateAt = o.CreateAt
+ if fi.UpdateAt < fi.CreateAt {
+ fi.UpdateAt = fi.CreateAt
}
}
-func (o *FileInfo) IsValid() *AppError {
- if len(o.Id) != 26 {
+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 len(o.CreatorId) != 26 {
- return NewAppError("FileInfo.IsValid", "model.file_info.is_valid.user_id.app_error", nil, "id="+o.Id, http.StatusBadRequest)
+ if !IsValidId(fi.CreatorId) && fi.CreatorId != "nouser" {
+ return NewAppError("FileInfo.IsValid", "model.file_info.is_valid.user_id.app_error", nil, "id="+fi.Id, http.StatusBadRequest)
}
- if len(o.PostId) != 0 && len(o.PostId) != 26 {
- return NewAppError("FileInfo.IsValid", "model.file_info.is_valid.post_id.app_error", nil, "id="+o.Id, http.StatusBadRequest)
+ if len(fi.PostId) != 0 && !IsValidId(fi.PostId) {
+ return NewAppError("FileInfo.IsValid", "model.file_info.is_valid.post_id.app_error", nil, "id="+fi.Id, http.StatusBadRequest)
}
- if o.CreateAt == 0 {
- return NewAppError("FileInfo.IsValid", "model.file_info.is_valid.create_at.app_error", nil, "id="+o.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 o.UpdateAt == 0 {
- return NewAppError("FileInfo.IsValid", "model.file_info.is_valid.update_at.app_error", nil, "id="+o.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 o.Path == "" {
- return NewAppError("FileInfo.IsValid", "model.file_info.is_valid.path.app_error", nil, "id="+o.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 (o *FileInfo) IsImage() bool {
- return strings.HasPrefix(o.MimeType, "image")
+func (fi *FileInfo) IsImage() bool {
+ return strings.HasPrefix(fi.MimeType, "image")
+}
+
+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 GetInfoForBytes(name string, data []byte) (*FileInfo, *AppError) {
@@ -140,7 +179,7 @@ func GetInfoForBytes(name string, data []byte) (*FileInfo, *AppError) {
if gifConfig, err := gif.DecodeAll(bytes.NewReader(data)); err != nil {
// Still return the rest of the info even though it doesn't appear to be an actual gif
info.HasPreviewImage = true
- err = NewAppError("GetInfoForBytes", "model.file_info.get.gif.app_error", nil, "name="+name, http.StatusBadRequest)
+ return info, NewAppError("GetInfoForBytes", "model.file_info.get.gif.app_error", nil, "name="+name, http.StatusBadRequest)
} else {
info.HasPreviewImage = len(gifConfig.Image) == 1
}
diff --git a/vendor/github.com/mattermost/mattermost-server/model/gitlab.go b/vendor/github.com/mattermost/mattermost-server/v5/model/gitlab.go
index 8777614c..0b069cd6 100644
--- a/vendor/github.com/mattermost/mattermost-server/model/gitlab.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/gitlab.go
@@ -1,5 +1,5 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// See LICENSE.txt for license information.
package model
diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/group.go b/vendor/github.com/mattermost/mattermost-server/v5/model/group.go
new file mode 100644
index 00000000..4de0dcc4
--- /dev/null
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/group.go
@@ -0,0 +1,210 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
+
+package model
+
+import (
+ "encoding/json"
+ "io"
+ "net/http"
+ "regexp"
+)
+
+const (
+ GroupSourceLdap GroupSource = "ldap"
+
+ GroupNameMaxLength = 64
+ GroupSourceMaxLength = 64
+ GroupDisplayNameMaxLength = 128
+ GroupDescriptionMaxLength = 1024
+ GroupRemoteIDMaxLength = 48
+)
+
+type GroupSource string
+
+var allGroupSources = []GroupSource{
+ GroupSourceLdap,
+}
+
+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"`
+}
+
+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"`
+}
+
+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
+
+ // 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
+}
+
+type PageOpts struct {
+ Page int
+ PerPage int
+}
+
+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 {
+ err := group.IsValidName()
+ if err != nil {
+ return err
+ }
+
+ if l := len(group.DisplayName); l == 0 || l > GroupDisplayNameMaxLength {
+ return NewAppError("Group.IsValidForCreate", "model.group.display_name.app_error", map[string]interface{}{"GroupDisplayNameMaxLength": GroupDisplayNameMaxLength}, "", http.StatusBadRequest)
+ }
+
+ if len(group.Description) > GroupDescriptionMaxLength {
+ return NewAppError("Group.IsValidForCreate", "model.group.description.app_error", map[string]interface{}{"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 len(group.RemoteId) > GroupRemoteIDMaxLength || (len(group.RemoteId) == 0 && group.requiresRemoteId()) {
+ 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", "model.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 err := group.IsValidForCreate(); err != nil {
+ return err
+ }
+ return nil
+}
+
+func (group *Group) ToJson() string {
+ b, _ := json.Marshal(group)
+ return string(b)
+}
+
+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]interface{}{"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]interface{}{"GroupNameMaxLength": GroupNameMaxLength}, "", http.StatusBadRequest)
+ }
+
+ if !validGroupnameChars.MatchString(*group.Name) {
+ return NewAppError("Group.IsValidName", "model.group.name.invalid_chars.app_error", nil, "", http.StatusBadRequest)
+ }
+ }
+ return nil
+}
+
+func GroupFromJson(data io.Reader) *Group {
+ var group *Group
+ json.NewDecoder(data).Decode(&group)
+ return group
+}
+
+func GroupsFromJson(data io.Reader) []*Group {
+ var groups []*Group
+ json.NewDecoder(data).Decode(&groups)
+ return groups
+}
+
+func GroupPatchFromJson(data io.Reader) *GroupPatch {
+ var groupPatch *GroupPatch
+ json.NewDecoder(data).Decode(&groupPatch)
+ return groupPatch
+}
diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/group_member.go b/vendor/github.com/mattermost/mattermost-server/v5/model/group_member.go
new file mode 100644
index 00000000..d18d7849
--- /dev/null
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/group_member.go
@@ -0,0 +1,23 @@
+// 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
+}
diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/group_syncable.go b/vendor/github.com/mattermost/mattermost-server/v5/model/group_syncable.go
new file mode 100644
index 00000000..6a4d4023
--- /dev/null
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/group_syncable.go
@@ -0,0 +1,180 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
+
+package model
+
+import (
+ "encoding/json"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "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) 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]interface{}
+ err := json.Unmarshal(b, &kvp)
+ if err != nil {
+ return err
+ }
+ for key, value := range kvp {
+ switch key {
+ case "team_id":
+ syncable.SyncableId = value.(string)
+ syncable.Type = GroupSyncableTypeTeam
+ case "channel_id":
+ syncable.SyncableId = value.(string)
+ syncable.Type = GroupSyncableTypeChannel
+ case "group_id":
+ syncable.GroupId = value.(string)
+ case "auto_add":
+ syncable.AutoAdd = value.(bool)
+ default:
+ }
+ }
+ 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"`
+ *Alias
+ }{
+ TeamDisplayName: syncable.TeamDisplayName,
+ TeamType: syncable.TeamType,
+ TeamID: syncable.SyncableId,
+ 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"`
+
+ 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,
+
+ TeamID: syncable.TeamID,
+ TeamDisplayName: syncable.TeamDisplayName,
+ TeamType: syncable.TeamType,
+
+ Alias: (*Alias)(syncable),
+ })
+ default:
+ return nil, &json.MarshalerError{
+ Err: fmt.Errorf("unknown syncable type: %s", syncable.Type),
+ }
+ }
+}
+
+type GroupSyncablePatch struct {
+ AutoAdd *bool `json:"auto_add"`
+ SchemeAdmin *bool `json:"scheme_admin"`
+}
+
+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 GroupSyncableFromJson(data io.Reader) *GroupSyncable {
+ groupSyncable := &GroupSyncable{}
+ bodyBytes, _ := ioutil.ReadAll(data)
+ json.Unmarshal(bodyBytes, groupSyncable)
+ return groupSyncable
+}
+
+func GroupSyncablesFromJson(data io.Reader) []*GroupSyncable {
+ groupSyncables := []*GroupSyncable{}
+ bodyBytes, _ := ioutil.ReadAll(data)
+ json.Unmarshal(bodyBytes, &groupSyncables)
+ return groupSyncables
+}
+
+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,
+ }
+}
diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/guest_invite.go b/vendor/github.com/mattermost/mattermost-server/v5/model/guest_invite.go
new file mode 100644
index 00000000..3cdd4893
--- /dev/null
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/guest_invite.go
@@ -0,0 +1,53 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
+
+package model
+
+import (
+ "encoding/json"
+ "io"
+ "net/http"
+)
+
+type GuestsInvite struct {
+ Emails []string `json:"emails"`
+ Channels []string `json:"channels"`
+ Message string `json:"message"`
+}
+
+// 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) > USER_EMAIL_MAX_LENGTH || len(email) == 0 || !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
+}
+
+// GuestsInviteFromJson will decode the input and return a GuestsInvite
+func GuestsInviteFromJson(data io.Reader) *GuestsInvite {
+ var i *GuestsInvite
+ json.NewDecoder(data).Decode(&i)
+ return i
+}
+
+func (i *GuestsInvite) ToJson() string {
+ b, _ := json.Marshal(i)
+ return string(b)
+}
diff --git a/vendor/github.com/mattermost/mattermost-server/model/incoming_webhook.go b/vendor/github.com/mattermost/mattermost-server/v5/model/incoming_webhook.go
index 3856d22f..78f1e4e8 100644
--- a/vendor/github.com/mattermost/mattermost-server/model/incoming_webhook.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/incoming_webhook.go
@@ -1,5 +1,5 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// See LICENSE.txt for license information.
package model
@@ -38,6 +38,7 @@ type IncomingWebhookRequest struct {
Props StringInterface `json:"props"`
Attachments []*SlackAttachment `json:"attachments"`
Type string `json:"type"`
+ IconEmoji string `json:"icon_emoji"`
}
func (o *IncomingWebhook) ToJson() string {
@@ -64,7 +65,7 @@ func IncomingWebhookListFromJson(data io.Reader) []*IncomingWebhook {
func (o *IncomingWebhook) IsValid() *AppError {
- if len(o.Id) != 26 {
+ if !IsValidId(o.Id) {
return NewAppError("IncomingWebhook.IsValid", "model.incoming_hook.id.app_error", nil, "", http.StatusBadRequest)
}
@@ -77,15 +78,15 @@ func (o *IncomingWebhook) IsValid() *AppError {
return NewAppError("IncomingWebhook.IsValid", "model.incoming_hook.update_at.app_error", nil, "id="+o.Id, http.StatusBadRequest)
}
- if len(o.UserId) != 26 {
+ if !IsValidId(o.UserId) {
return NewAppError("IncomingWebhook.IsValid", "model.incoming_hook.user_id.app_error", nil, "", http.StatusBadRequest)
}
- if len(o.ChannelId) != 26 {
+ if !IsValidId(o.ChannelId) {
return NewAppError("IncomingWebhook.IsValid", "model.incoming_hook.channel_id.app_error", nil, "", http.StatusBadRequest)
}
- if len(o.TeamId) != 26 {
+ if !IsValidId(o.TeamId) {
return NewAppError("IncomingWebhook.IsValid", "model.incoming_hook.team_id.app_error", nil, "", http.StatusBadRequest)
}
diff --git a/vendor/github.com/mattermost/mattermost-server/model/initial_load.go b/vendor/github.com/mattermost/mattermost-server/v5/model/initial_load.go
index 3be68044..9368f371 100644
--- a/vendor/github.com/mattermost/mattermost-server/model/initial_load.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/initial_load.go
@@ -1,5 +1,5 @@
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
package model
diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/integration_action.go b/vendor/github.com/mattermost/mattermost-server/v5/model/integration_action.go
new file mode 100644
index 00000000..3f362d64
--- /dev/null
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/integration_action.go
@@ -0,0 +1,525 @@
+// 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"
+ "strconv"
+ "strings"
+)
+
+const (
+ POST_ACTION_TYPE_BUTTON = "button"
+ POST_ACTION_TYPE_SELECT = "select"
+ INTERACTIVE_DIALOG_TRIGGER_TIMEOUT_MILLISECONDS = 3000
+)
+
+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 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
+ }
+
+ if 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]interface{} `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]interface{} `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]interface{} `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]interface{} `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, err.Error(), http.StatusInternalServerError)
+ }
+
+ 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, err := GenerateTriggerId(r.UserId, s)
+ if err != nil {
+ return "", "", err
+ }
+
+ r.TriggerId = triggerId
+ return clientTriggerId, triggerId, nil
+}
+
+func DecodeAndVerifyTriggerId(triggerId string, s *ecdsa.PrivateKey) (string, string, *AppError) {
+ triggerIdBytes, err := base64.StdEncoding.DecodeString(triggerId)
+ if err != nil {
+ return "", "", NewAppError("DecodeAndVerifyTriggerId", "interactive_message.decode_trigger_id.base64_decode_failed", nil, err.Error(), http.StatusBadRequest)
+ }
+
+ 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)
+
+ now := GetMillis()
+ if now-timestamp > INTERACTIVE_DIALOG_TRIGGER_TIMEOUT_MILLISECONDS {
+ return "", "", NewAppError("DecodeAndVerifyTriggerId", "interactive_message.decode_trigger_id.expired", map[string]interface{}{"Seconds": INTERACTIVE_DIALOG_TRIGGER_TIMEOUT_MILLISECONDS / 1000}, "", 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, err.Error(), http.StatusBadRequest)
+ }
+
+ 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, err.Error(), http.StatusBadRequest)
+ }
+
+ 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) (string, string, *AppError) {
+ return DecodeAndVerifyTriggerId(r.TriggerId, s)
+}
+
+func (r *PostActionIntegrationRequest) ToJson() []byte {
+ b, _ := json.Marshal(r)
+ return b
+}
+
+func PostActionIntegrationRequestFromJson(data io.Reader) *PostActionIntegrationRequest {
+ var o *PostActionIntegrationRequest
+ err := json.NewDecoder(data).Decode(&o)
+ if err != nil {
+ return nil
+ }
+ return o
+}
+
+func (r *PostActionIntegrationResponse) ToJson() []byte {
+ b, _ := json.Marshal(r)
+ return b
+}
+
+func PostActionIntegrationResponseFromJson(data io.Reader) *PostActionIntegrationResponse {
+ var o *PostActionIntegrationResponse
+ err := json.NewDecoder(data).Decode(&o)
+ if err != nil {
+ return nil
+ }
+ return o
+}
+
+func SubmitDialogRequestFromJson(data io.Reader) *SubmitDialogRequest {
+ var o *SubmitDialogRequest
+ err := json.NewDecoder(data).Decode(&o)
+ if err != nil {
+ return nil
+ }
+ return o
+}
+
+func (r *SubmitDialogRequest) ToJson() []byte {
+ b, _ := json.Marshal(r)
+ return b
+}
+
+func SubmitDialogResponseFromJson(data io.Reader) *SubmitDialogResponse {
+ var o *SubmitDialogResponse
+ err := json.NewDecoder(data).Decode(&o)
+ if err != nil {
+ return nil
+ }
+ return o
+}
+
+func (r *SubmitDialogResponse) ToJson() []byte {
+ b, _ := json.Marshal(r)
+ return b
+}
+
+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.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.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]interface{}{}
+ 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...)
+ 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
+}
+
+func DoPostActionRequestFromJson(data io.Reader) *DoPostActionRequest {
+ var o *DoPostActionRequest
+ json.NewDecoder(data).Decode(&o)
+ return o
+}
diff --git a/vendor/github.com/mattermost/mattermost-server/model/job.go b/vendor/github.com/mattermost/mattermost-server/v5/model/job.go
index c1661495..e6e1d689 100644
--- a/vendor/github.com/mattermost/mattermost-server/model/job.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/job.go
@@ -1,5 +1,5 @@
-// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
package model
@@ -15,8 +15,10 @@ const (
JOB_TYPE_MESSAGE_EXPORT = "message_export"
JOB_TYPE_ELASTICSEARCH_POST_INDEXING = "elasticsearch_post_indexing"
JOB_TYPE_ELASTICSEARCH_POST_AGGREGATION = "elasticsearch_post_aggregation"
+ JOB_TYPE_BLEVE_POST_INDEXING = "bleve_post_indexing"
JOB_TYPE_LDAP_SYNC = "ldap_sync"
JOB_TYPE_MIGRATIONS = "migrations"
+ JOB_TYPE_PLUGINS = "plugins"
JOB_STATUS_PENDING = "pending"
JOB_STATUS_IN_PROGRESS = "in_progress"
@@ -24,6 +26,7 @@ const (
JOB_STATUS_ERROR = "error"
JOB_STATUS_CANCEL_REQUESTED = "cancel_requested"
JOB_STATUS_CANCELED = "canceled"
+ JOB_STATUS_WARNING = "warning"
)
type Job struct {
@@ -39,7 +42,7 @@ type Job struct {
}
func (j *Job) IsValid() *AppError {
- if len(j.Id) != 26 {
+ if !IsValidId(j.Id) {
return NewAppError("Job.IsValid", "model.job.is_valid.id.app_error", nil, "id="+j.Id, http.StatusBadRequest)
}
@@ -51,9 +54,11 @@ func (j *Job) IsValid() *AppError {
case JOB_TYPE_DATA_RETENTION:
case JOB_TYPE_ELASTICSEARCH_POST_INDEXING:
case JOB_TYPE_ELASTICSEARCH_POST_AGGREGATION:
+ case JOB_TYPE_BLEVE_POST_INDEXING:
case JOB_TYPE_LDAP_SYNC:
case JOB_TYPE_MESSAGE_EXPORT:
case JOB_TYPE_MIGRATIONS:
+ case JOB_TYPE_PLUGINS:
default:
return NewAppError("Job.IsValid", "model.job.is_valid.type.app_error", nil, "id="+j.Id, http.StatusBadRequest)
}
@@ -72,8 +77,8 @@ func (j *Job) IsValid() *AppError {
return nil
}
-func (js *Job) ToJson() string {
- b, _ := json.Marshal(js)
+func (j *Job) ToJson() string {
+ b, _ := json.Marshal(j)
return string(b)
}
@@ -100,8 +105,8 @@ func JobsFromJson(data io.Reader) []*Job {
}
}
-func (js *Job) DataToJson() string {
- b, _ := json.Marshal(js.Data)
+func (j *Job) DataToJson() string {
+ b, _ := json.Marshal(j.Data)
return string(b)
}
diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/ldap.go b/vendor/github.com/mattermost/mattermost-server/v5/model/ldap.go
new file mode 100644
index 00000000..d5f98f1a
--- /dev/null
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/ldap.go
@@ -0,0 +1,8 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
+
+package model
+
+const (
+ USER_AUTH_SERVICE_LDAP = "ldap"
+)
diff --git a/vendor/github.com/mattermost/mattermost-server/model/license.go b/vendor/github.com/mattermost/mattermost-server/v5/model/license.go
index c30fecf7..0504edc0 100644
--- a/vendor/github.com/mattermost/mattermost-server/model/license.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/license.go
@@ -1,5 +1,5 @@
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
package model
@@ -12,6 +12,8 @@ import (
const (
EXPIRED_LICENSE_ERROR = "api.license.add_license.expired.app_error"
INVALID_LICENSE_ERROR = "api.license.add_license.invalid.app_error"
+ LICENSE_GRACE_PERIOD = 1000 * 60 * 60 * 24 * 10 //10 days
+ LICENSE_RENEWAL_LINK = "https://licensing.mattermost.com/renew"
)
type LicenseRecord struct {
@@ -21,25 +23,43 @@ type LicenseRecord struct {
}
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"`
+ 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"`
}
type Customer struct {
- Id string `json:"id"`
- Name string `json:"name"`
- Email string `json:"email"`
- Company string `json:"company"`
- PhoneNumber string `json:"phone_number"`
+ 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"`
+}
+
+func (tlr *TrialLicenseRequest) ToJson() string {
+ b, _ := json.Marshal(tlr)
+ return string(b)
}
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"`
@@ -56,14 +76,20 @@ type Features struct {
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"`
- // after we enabled more features for webrtc we'll need to control them with this
+ // after we enabled more features we'll need to control them with this
FutureFeatures *bool `json:"future_features"`
}
func (f *Features) ToMap() map[string]interface{} {
return map[string]interface{}{
"ldap": *f.LDAP,
+ "ldap_groups": *f.LDAPGroups,
"mfa": *f.MFA,
"google": *f.GoogleOAuth,
"office365": *f.Office365OAuth,
@@ -77,6 +103,11 @@ func (f *Features) ToMap() map[string]interface{} {
"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,
"future": *f.FutureFeatures,
}
}
@@ -94,6 +125,10 @@ func (f *Features) SetDefaults() {
f.LDAP = NewBool(*f.FutureFeatures)
}
+ if f.LDAPGroups == nil {
+ f.LDAPGroups = NewBool(*f.FutureFeatures)
+ }
+
if f.MFA == nil {
f.MFA = NewBool(*f.FutureFeatures)
}
@@ -154,15 +189,40 @@ func (f *Features) SetDefaults() {
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)
+ }
}
func (l *License) IsExpired() bool {
return l.ExpiresAt < GetMillis()
}
+func (l *License) IsPastGracePeriod() bool {
+ timeDiff := GetMillis() - l.ExpiresAt
+ return timeDiff > LICENSE_GRACE_PERIOD
+}
+
func (l *License) IsStarted() bool {
return l.StartsAt < GetMillis()
}
@@ -198,7 +258,7 @@ func LicenseFromJson(data io.Reader) *License {
}
func (lr *LicenseRecord) IsValid() *AppError {
- if len(lr.Id) != 26 {
+ if !IsValidId(lr.Id) {
return NewAppError("LicenseRecord.IsValid", "model.license_record.is_valid.id.app_error", nil, "", http.StatusBadRequest)
}
diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/link_metadata.go b/vendor/github.com/mattermost/mattermost-server/v5/model/link_metadata.go
new file mode 100644
index 00000000..d20be2cb
--- /dev/null
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/link_metadata.go
@@ -0,0 +1,193 @@
+// 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"
+)
+
+const (
+ LINK_METADATA_TYPE_IMAGE LinkMetadataType = "image"
+ LINK_METADATA_TYPE_NONE LinkMetadataType = "none"
+ LINK_METADATA_TYPE_OPENGRAPH LinkMetadataType = "opengraph"
+ MAX_IMAGES 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 interface{}
+}
+
+// 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 []*opengraph.Image, maxImages int) []*opengraph.Image {
+ if maxImages < 0 { // dont break stuff, if it's weird, go for sane defaults
+ maxImages = MAX_IMAGES
+ }
+ 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, MAX_IMAGES)
+ 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 LINK_METADATA_TYPE_IMAGE:
+ 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 LINK_METADATA_TYPE_NONE:
+ if o.Data != nil {
+ return NewAppError("LinkMetadata.IsValid", "model.link_metadata.is_valid.data_type.app_error", nil, "", http.StatusBadRequest)
+ }
+ case LINK_METADATA_TYPE_OPENGRAPH:
+ 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 interface{}
+ var err error
+
+ switch o.Type {
+ case LINK_METADATA_TYPE_IMAGE:
+ image := &PostImage{}
+
+ err = json.Unmarshal(b, &image)
+
+ data = image
+ case LINK_METADATA_TYPE_OPENGRAPH:
+ 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))
+
+ return time.Date(t.Year(), t.Month(), t.Day(), t.Hour(), 0, 0, 0, t.Location()).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())
+}
diff --git a/vendor/github.com/mattermost/mattermost-server/model/manifest.go b/vendor/github.com/mattermost/mattermost-server/v5/model/manifest.go
index 6a7df59f..7c09830a 100644
--- a/vendor/github.com/mattermost/mattermost-server/model/manifest.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/manifest.go
@@ -1,5 +1,5 @@
-// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
package model
@@ -12,6 +12,8 @@ import (
"path/filepath"
"strings"
+ "github.com/blang/semver"
+ "github.com/pkg/errors"
"gopkg.in/yaml.v2"
)
@@ -23,6 +25,20 @@ type PluginOption struct {
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"`
@@ -45,16 +61,22 @@ type PluginSetting struct {
//
// "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 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.
+ // 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 "text", "generated" and "username" types when blank.
+ // 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.
@@ -66,10 +88,10 @@ type PluginSetting struct {
}
type PluginSettingsSchema struct {
- // Optional text to display above the settings.
+ // Optional text to display above the settings. Supports Markdown formatting.
Header string `json:"header" yaml:"header"`
- // Optional text to display below the settings.
+ // Optional text to display below the settings. Supports Markdown formatting.
Footer string `json:"footer" yaml:"footer"`
// A list of setting definitions.
@@ -80,20 +102,44 @@ type PluginSettingsSchema struct {
// file should be named plugin.json or plugin.yaml and placed in the top of your
// plugin bundle.
//
-// Example plugin.yaml:
+// Example plugin.json:
//
-// id: com.mycompany.myplugin
-// name: My Plugin
-// description: This is my plugin. It does stuff.
-// server:
-// executable: myplugin
-// settings_schema:
-// settings:
-// - key: enable_extra_thing
-// type: bool
-// display_name: Enable Extra Thing
-// help_text: When true, an extra thing will be enabled!
-// default: false
+//
+// {
+// "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-_\.]+$.
@@ -106,9 +152,27 @@ type Manifest struct {
// 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"`
@@ -121,6 +185,14 @@ type Manifest struct {
// 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]interface{} `json:"props,omitempty" yaml:"props,omitempty"`
+
+ // RequiredConfig defines any required server configuration fields for the plugin to function properly.
+ //
+ // Use the plugin helpers CheckRequiredServerConfiguration method to enforce this.
+ RequiredConfig *Config `json:"required_configuration,omitempty" yaml:"required_configuration,omitempty"`
}
type ManifestServer struct {
@@ -240,6 +312,129 @@ 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 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) {
+ return errors.New("should not set Placeholder for setting type not in text, generated or username")
+ }
+
+ 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
@@ -252,25 +447,23 @@ func FindManifest(dir string) (manifest *Manifest, path string, err error) {
f, ferr := os.Open(path)
if ferr != nil {
if !os.IsNotExist(ferr) {
- err = ferr
- return
+ return nil, "", ferr
}
continue
}
b, ioerr := ioutil.ReadAll(f)
f.Close()
if ioerr != nil {
- err = ioerr
- return
+ return nil, path, ioerr
}
var parsed Manifest
err = yaml.Unmarshal(b, &parsed)
if err != nil {
- return
+ return nil, path, err
}
manifest = &parsed
manifest.Id = strings.ToLower(manifest.Id)
- return
+ return manifest, path, nil
}
path = filepath.Join(dir, "plugin.json")
@@ -279,16 +472,15 @@ func FindManifest(dir string) (manifest *Manifest, path string, err error) {
if os.IsNotExist(ferr) {
path = ""
}
- err = ferr
- return
+ return nil, path, ferr
}
defer f.Close()
var parsed Manifest
err = json.NewDecoder(f).Decode(&parsed)
if err != nil {
- return
+ return nil, path, err
}
manifest = &parsed
manifest.Id = strings.ToLower(manifest.Id)
- return
+ return manifest, path, nil
}
diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/marketplace_plugin.go b/vendor/github.com/mattermost/mattermost-server/v5/model/marketplace_plugin.go
new file mode 100644
index 00000000..47644513
--- /dev/null
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/marketplace_plugin.go
@@ -0,0 +1,124 @@
+// 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"`
+ 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
+ LocalOnly 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("local_only", strconv.FormatBool(filter.LocalOnly))
+ 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
+}
+
+// ToJson method will return json from plugin request.
+func (r *InstallMarketplacePluginRequest) ToJson() (string, error) {
+ b, err := json.Marshal(r)
+ if err != nil {
+ return "", err
+ }
+ return string(b), nil
+}
diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/mention_map.go b/vendor/github.com/mattermost/mattermost-server/v5/model/mention_map.go
new file mode 100644
index 00000000..2f3444dd
--- /dev/null
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/mention_map.go
@@ -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
+}
diff --git a/vendor/github.com/mattermost/mattermost-server/model/message_export.go b/vendor/github.com/mattermost/mattermost-server/v5/model/message_export.go
index 1cf764a6..88108e2e 100644
--- a/vendor/github.com/mattermost/mattermost-server/model/message_export.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/message_export.go
@@ -1,5 +1,5 @@
-// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
package model
@@ -16,12 +16,16 @@ type MessageExport struct {
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
}
diff --git a/vendor/github.com/mattermost/mattermost-server/model/mfa_secret.go b/vendor/github.com/mattermost/mattermost-server/v5/model/mfa_secret.go
index 23a903c8..979ff342 100644
--- a/vendor/github.com/mattermost/mattermost-server/model/mfa_secret.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/mfa_secret.go
@@ -1,5 +1,5 @@
-// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
package model
diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/migration.go b/vendor/github.com/mattermost/mattermost-server/v5/model/migration.go
new file mode 100644
index 00000000..7dd08bef
--- /dev/null
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/migration.go
@@ -0,0 +1,20 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
+
+package model
+
+const (
+ MIGRATION_KEY_ADVANCED_PERMISSIONS_PHASE_2 = "migration_advanced_permissions_phase_2"
+
+ MIGRATION_KEY_EMOJI_PERMISSIONS_SPLIT = "emoji_permissions_split"
+ MIGRATION_KEY_WEBHOOK_PERMISSIONS_SPLIT = "webhook_permissions_split"
+ MIGRATION_KEY_LIST_JOIN_PUBLIC_PRIVATE_TEAMS = "list_join_public_private_teams"
+ MIGRATION_KEY_REMOVE_PERMANENT_DELETE_USER = "remove_permanent_delete_user"
+ MIGRATION_KEY_ADD_BOT_PERMISSIONS = "add_bot_permissions"
+ MIGRATION_KEY_APPLY_CHANNEL_MANAGE_DELETE_TO_CHANNEL_USER = "apply_channel_manage_delete_to_channel_user"
+ MIGRATION_KEY_REMOVE_CHANNEL_MANAGE_DELETE_FROM_TEAM_USER = "remove_channel_manage_delete_from_team_user"
+ MIGRATION_KEY_VIEW_MEMBERS_NEW_PERMISSION = "view_members_new_permission"
+ MIGRATION_KEY_ADD_MANAGE_GUESTS_PERMISSIONS = "add_manage_guests_permissions"
+ MIGRATION_KEY_CHANNEL_MODERATIONS_PERMISSIONS = "channel_moderations_permissions"
+ MIGRATION_KEY_ADD_USE_GROUP_MENTIONS_PERMISSION = "add_use_group_mentions_permission"
+)
diff --git a/vendor/github.com/mattermost/mattermost-server/model/oauth.go b/vendor/github.com/mattermost/mattermost-server/v5/model/oauth.go
index 6f662a5a..4a345a6e 100644
--- a/vendor/github.com/mattermost/mattermost-server/model/oauth.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/oauth.go
@@ -1,5 +1,5 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// See LICENSE.txt for license information.
package model
@@ -17,7 +17,6 @@ const (
OAUTH_ACTION_EMAIL_TO_SSO = "email_to_sso"
OAUTH_ACTION_SSO_TO_EMAIL = "sso_to_email"
OAUTH_ACTION_MOBILE = "mobile"
- OAUTH_ACTION_CLIENT = "client"
)
type OAuthApp struct {
@@ -38,7 +37,7 @@ type OAuthApp struct {
// correctly.
func (a *OAuthApp) IsValid() *AppError {
- if len(a.Id) != 26 {
+ if !IsValidId(a.Id) {
return NewAppError("OAuthApp.IsValid", "model.oauth.is_valid.app_id.app_error", nil, "", http.StatusBadRequest)
}
@@ -50,7 +49,7 @@ func (a *OAuthApp) IsValid() *AppError {
return NewAppError("OAuthApp.IsValid", "model.oauth.is_valid.update_at.app_error", nil, "app_id="+a.Id, http.StatusBadRequest)
}
- if len(a.CreatorId) != 26 {
+ if !IsValidId(a.CreatorId) {
return NewAppError("OAuthApp.IsValid", "model.oauth.is_valid.creator_id.app_error", nil, "app_id="+a.Id, http.StatusBadRequest)
}
diff --git a/vendor/github.com/mattermost/mattermost-server/model/outgoing_webhook.go b/vendor/github.com/mattermost/mattermost-server/v5/model/outgoing_webhook.go
index 5f7a67d0..f4278de0 100644
--- a/vendor/github.com/mattermost/mattermost-server/model/outgoing_webhook.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/outgoing_webhook.go
@@ -1,5 +1,5 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// See LICENSE.txt for license information.
package model
@@ -109,15 +109,15 @@ func (o *OutgoingWebhookResponse) ToJson() string {
return string(b)
}
-func OutgoingWebhookResponseFromJson(data io.Reader) *OutgoingWebhookResponse {
+func OutgoingWebhookResponseFromJson(data io.Reader) (*OutgoingWebhookResponse, error) {
var o *OutgoingWebhookResponse
- json.NewDecoder(data).Decode(&o)
- return o
+ err := json.NewDecoder(data).Decode(&o)
+ return o, err
}
func (o *OutgoingWebhook) IsValid() *AppError {
- if len(o.Id) != 26 {
+ if !IsValidId(o.Id) {
return NewAppError("OutgoingWebhook.IsValid", "model.outgoing_hook.is_valid.id.app_error", nil, "", http.StatusBadRequest)
}
@@ -133,15 +133,15 @@ func (o *OutgoingWebhook) IsValid() *AppError {
return NewAppError("OutgoingWebhook.IsValid", "model.outgoing_hook.is_valid.update_at.app_error", nil, "id="+o.Id, http.StatusBadRequest)
}
- if len(o.CreatorId) != 26 {
+ if !IsValidId(o.CreatorId) {
return NewAppError("OutgoingWebhook.IsValid", "model.outgoing_hook.is_valid.user_id.app_error", nil, "", http.StatusBadRequest)
}
- if len(o.ChannelId) != 0 && len(o.ChannelId) != 26 {
+ if len(o.ChannelId) != 0 && !IsValidId(o.ChannelId) {
return NewAppError("OutgoingWebhook.IsValid", "model.outgoing_hook.is_valid.channel_id.app_error", nil, "", http.StatusBadRequest)
}
- if len(o.TeamId) != 26 {
+ if !IsValidId(o.TeamId) {
return NewAppError("OutgoingWebhook.IsValid", "model.outgoing_hook.is_valid.team_id.app_error", nil, "", http.StatusBadRequest)
}
diff --git a/vendor/github.com/mattermost/mattermost-server/model/permission.go b/vendor/github.com/mattermost/mattermost-server/v5/model/permission.go
index 737321cc..cc3c5a70 100644
--- a/vendor/github.com/mattermost/mattermost-server/model/permission.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/permission.go
@@ -1,5 +1,5 @@
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
package model
@@ -33,6 +33,10 @@ var PERMISSION_CREATE_DIRECT_CHANNEL *Permission
var PERMISSION_CREATE_GROUP_CHANNEL *Permission
var PERMISSION_MANAGE_PUBLIC_CHANNEL_PROPERTIES *Permission
var PERMISSION_MANAGE_PRIVATE_CHANNEL_PROPERTIES *Permission
+var PERMISSION_LIST_PUBLIC_TEAMS *Permission
+var PERMISSION_JOIN_PUBLIC_TEAMS *Permission
+var PERMISSION_LIST_PRIVATE_TEAMS *Permission
+var PERMISSION_JOIN_PRIVATE_TEAMS *Permission
var PERMISSION_LIST_TEAM_CHANNELS *Permission
var PERMISSION_JOIN_PUBLIC_CHANNELS *Permission
var PERMISSION_DELETE_PUBLIC_CHANNEL *Permission
@@ -48,10 +52,17 @@ var PERMISSION_UPLOAD_FILE *Permission
var PERMISSION_GET_PUBLIC_LINK *Permission
var PERMISSION_MANAGE_WEBHOOKS *Permission
var PERMISSION_MANAGE_OTHERS_WEBHOOKS *Permission
+var PERMISSION_MANAGE_INCOMING_WEBHOOKS *Permission
+var PERMISSION_MANAGE_OUTGOING_WEBHOOKS *Permission
+var PERMISSION_MANAGE_OTHERS_INCOMING_WEBHOOKS *Permission
+var PERMISSION_MANAGE_OTHERS_OUTGOING_WEBHOOKS *Permission
var PERMISSION_MANAGE_OAUTH *Permission
var PERMISSION_MANAGE_SYSTEM_WIDE_OAUTH *Permission
var PERMISSION_MANAGE_EMOJIS *Permission
var PERMISSION_MANAGE_OTHERS_EMOJIS *Permission
+var PERMISSION_CREATE_EMOJIS *Permission
+var PERMISSION_DELETE_EMOJIS *Permission
+var PERMISSION_DELETE_OTHERS_EMOJIS *Permission
var PERMISSION_CREATE_POST *Permission
var PERMISSION_CREATE_POST_PUBLIC *Permission
var PERMISSION_CREATE_POST_EPHEMERAL *Permission
@@ -69,6 +80,18 @@ var PERMISSION_MANAGE_JOBS *Permission
var PERMISSION_CREATE_USER_ACCESS_TOKEN *Permission
var PERMISSION_READ_USER_ACCESS_TOKEN *Permission
var PERMISSION_REVOKE_USER_ACCESS_TOKEN *Permission
+var PERMISSION_CREATE_BOT *Permission
+var PERMISSION_ASSIGN_BOT *Permission
+var PERMISSION_READ_BOTS *Permission
+var PERMISSION_READ_OTHERS_BOTS *Permission
+var PERMISSION_MANAGE_BOTS *Permission
+var PERMISSION_MANAGE_OTHERS_BOTS *Permission
+var PERMISSION_VIEW_MEMBERS *Permission
+var PERMISSION_INVITE_GUEST *Permission
+var PERMISSION_PROMOTE_GUEST *Permission
+var PERMISSION_DEMOTE_TO_GUEST *Permission
+var PERMISSION_USE_CHANNEL_MENTIONS *Permission
+var PERMISSION_USE_GROUP_MENTIONS *Permission
// General permission that encompasses all system admin functions
// in the future this could be broken up to allow access to some
@@ -77,6 +100,9 @@ var PERMISSION_MANAGE_SYSTEM *Permission
var ALL_PERMISSIONS []*Permission
+var CHANNEL_MODERATED_PERMISSIONS []string
+var CHANNEL_MODERATED_PERMISSIONS_MAP map[string]string
+
func initializePermissions() {
PERMISSION_INVITE_USER = &Permission{
"invite_user",
@@ -186,6 +212,30 @@ func initializePermissions() {
"authentication.permissions.manage_private_channel_properties.description",
PERMISSION_SCOPE_CHANNEL,
}
+ PERMISSION_LIST_PUBLIC_TEAMS = &Permission{
+ "list_public_teams",
+ "authentication.permissions.list_public_teams.name",
+ "authentication.permissions.list_public_teams.description",
+ PERMISSION_SCOPE_SYSTEM,
+ }
+ PERMISSION_JOIN_PUBLIC_TEAMS = &Permission{
+ "join_public_teams",
+ "authentication.permissions.join_public_teams.name",
+ "authentication.permissions.join_public_teams.description",
+ PERMISSION_SCOPE_SYSTEM,
+ }
+ PERMISSION_LIST_PRIVATE_TEAMS = &Permission{
+ "list_private_teams",
+ "authentication.permissions.list_private_teams.name",
+ "authentication.permissions.list_private_teams.description",
+ PERMISSION_SCOPE_SYSTEM,
+ }
+ PERMISSION_JOIN_PRIVATE_TEAMS = &Permission{
+ "join_private_teams",
+ "authentication.permissions.join_private_teams.name",
+ "authentication.permissions.join_private_teams.description",
+ PERMISSION_SCOPE_SYSTEM,
+ }
PERMISSION_LIST_TEAM_CHANNELS = &Permission{
"list_team_channels",
"authentication.permissions.list_team_channels.name",
@@ -246,6 +296,7 @@ func initializePermissions() {
"authentication.permissions.remove_others_reactions.description",
PERMISSION_SCOPE_CHANNEL,
}
+ // DEPRECATED
PERMISSION_PERMANENT_DELETE_USER = &Permission{
"permanent_delete_user",
"authentication.permissions.permanent_delete_user.name",
@@ -264,18 +315,44 @@ func initializePermissions() {
"authentication.permissions.get_public_link.description",
PERMISSION_SCOPE_SYSTEM,
}
+ // DEPRECATED
PERMISSION_MANAGE_WEBHOOKS = &Permission{
"manage_webhooks",
"authentication.permissions.manage_webhooks.name",
"authentication.permissions.manage_webhooks.description",
PERMISSION_SCOPE_TEAM,
}
+ // DEPRECATED
PERMISSION_MANAGE_OTHERS_WEBHOOKS = &Permission{
"manage_others_webhooks",
"authentication.permissions.manage_others_webhooks.name",
"authentication.permissions.manage_others_webhooks.description",
PERMISSION_SCOPE_TEAM,
}
+ PERMISSION_MANAGE_INCOMING_WEBHOOKS = &Permission{
+ "manage_incoming_webhooks",
+ "authentication.permissions.manage_incoming_webhooks.name",
+ "authentication.permissions.manage_incoming_webhooks.description",
+ PERMISSION_SCOPE_TEAM,
+ }
+ PERMISSION_MANAGE_OUTGOING_WEBHOOKS = &Permission{
+ "manage_outgoing_webhooks",
+ "authentication.permissions.manage_outgoing_webhooks.name",
+ "authentication.permissions.manage_outgoing_webhooks.description",
+ PERMISSION_SCOPE_TEAM,
+ }
+ PERMISSION_MANAGE_OTHERS_INCOMING_WEBHOOKS = &Permission{
+ "manage_others_incoming_webhooks",
+ "authentication.permissions.manage_others_incoming_webhooks.name",
+ "authentication.permissions.manage_others_incoming_webhooks.description",
+ PERMISSION_SCOPE_TEAM,
+ }
+ PERMISSION_MANAGE_OTHERS_OUTGOING_WEBHOOKS = &Permission{
+ "manage_others_outgoing_webhooks",
+ "authentication.permissions.manage_others_outgoing_webhooks.name",
+ "authentication.permissions.manage_others_outgoing_webhooks.description",
+ PERMISSION_SCOPE_TEAM,
+ }
PERMISSION_MANAGE_OAUTH = &Permission{
"manage_oauth",
"authentication.permissions.manage_oauth.name",
@@ -288,18 +365,38 @@ func initializePermissions() {
"authentication.permissions.manage_system_wide_oauth.description",
PERMISSION_SCOPE_SYSTEM,
}
+ // DEPRECATED
PERMISSION_MANAGE_EMOJIS = &Permission{
"manage_emojis",
"authentication.permissions.manage_emojis.name",
"authentication.permissions.manage_emojis.description",
PERMISSION_SCOPE_TEAM,
}
+ // DEPRECATED
PERMISSION_MANAGE_OTHERS_EMOJIS = &Permission{
"manage_others_emojis",
"authentication.permissions.manage_others_emojis.name",
"authentication.permissions.manage_others_emojis.description",
PERMISSION_SCOPE_TEAM,
}
+ PERMISSION_CREATE_EMOJIS = &Permission{
+ "create_emojis",
+ "authentication.permissions.create_emojis.name",
+ "authentication.permissions.create_emojis.description",
+ PERMISSION_SCOPE_TEAM,
+ }
+ PERMISSION_DELETE_EMOJIS = &Permission{
+ "delete_emojis",
+ "authentication.permissions.delete_emojis.name",
+ "authentication.permissions.delete_emojis.description",
+ PERMISSION_SCOPE_TEAM,
+ }
+ PERMISSION_DELETE_OTHERS_EMOJIS = &Permission{
+ "delete_others_emojis",
+ "authentication.permissions.delete_others_emojis.name",
+ "authentication.permissions.delete_others_emojis.description",
+ PERMISSION_SCOPE_TEAM,
+ }
PERMISSION_CREATE_POST = &Permission{
"create_post",
"authentication.permissions.create_post.name",
@@ -396,12 +493,87 @@ func initializePermissions() {
"authentication.permissions.revoke_user_access_token.description",
PERMISSION_SCOPE_SYSTEM,
}
+ PERMISSION_CREATE_BOT = &Permission{
+ "create_bot",
+ "authentication.permissions.create_bot.name",
+ "authentication.permissions.create_bot.description",
+ PERMISSION_SCOPE_SYSTEM,
+ }
+ PERMISSION_ASSIGN_BOT = &Permission{
+ "assign_bot",
+ "authentication.permissions.assign_bot.name",
+ "authentication.permissions.assign_bot.description",
+ PERMISSION_SCOPE_SYSTEM,
+ }
+ PERMISSION_READ_BOTS = &Permission{
+ "read_bots",
+ "authentication.permissions.read_bots.name",
+ "authentication.permissions.read_bots.description",
+ PERMISSION_SCOPE_SYSTEM,
+ }
+ PERMISSION_READ_OTHERS_BOTS = &Permission{
+ "read_others_bots",
+ "authentication.permissions.read_others_bots.name",
+ "authentication.permissions.read_others_bots.description",
+ PERMISSION_SCOPE_SYSTEM,
+ }
+ PERMISSION_MANAGE_BOTS = &Permission{
+ "manage_bots",
+ "authentication.permissions.manage_bots.name",
+ "authentication.permissions.manage_bots.description",
+ PERMISSION_SCOPE_SYSTEM,
+ }
+ PERMISSION_MANAGE_OTHERS_BOTS = &Permission{
+ "manage_others_bots",
+ "authentication.permissions.manage_others_bots.name",
+ "authentication.permissions.manage_others_bots.description",
+ PERMISSION_SCOPE_SYSTEM,
+ }
PERMISSION_MANAGE_JOBS = &Permission{
"manage_jobs",
"authentication.permisssions.manage_jobs.name",
"authentication.permisssions.manage_jobs.description",
PERMISSION_SCOPE_SYSTEM,
}
+ PERMISSION_VIEW_MEMBERS = &Permission{
+ "view_members",
+ "authentication.permisssions.view_members.name",
+ "authentication.permisssions.view_members.description",
+ PERMISSION_SCOPE_TEAM,
+ }
+ PERMISSION_INVITE_GUEST = &Permission{
+ "invite_guest",
+ "authentication.permissions.invite_guest.name",
+ "authentication.permissions.invite_guest.description",
+ PERMISSION_SCOPE_TEAM,
+ }
+ PERMISSION_PROMOTE_GUEST = &Permission{
+ "promote_guest",
+ "authentication.permissions.promote_guest.name",
+ "authentication.permissions.promote_guest.description",
+ PERMISSION_SCOPE_SYSTEM,
+ }
+
+ PERMISSION_DEMOTE_TO_GUEST = &Permission{
+ "demote_to_guest",
+ "authentication.permissions.demote_to_guest.name",
+ "authentication.permissions.demote_to_guest.description",
+ PERMISSION_SCOPE_SYSTEM,
+ }
+
+ PERMISSION_USE_CHANNEL_MENTIONS = &Permission{
+ "use_channel_mentions",
+ "authentication.permissions.use_channel_mentions.name",
+ "authentication.permissions.use_channel_mentions.description",
+ PERMISSION_SCOPE_CHANNEL,
+ }
+
+ PERMISSION_USE_GROUP_MENTIONS = &Permission{
+ "use_group_mentions",
+ "authentication.permissions.use_group_mentions.name",
+ "authentication.permissions.use_group_mentions.description",
+ PERMISSION_SCOPE_CHANNEL,
+ }
ALL_PERMISSIONS = []*Permission{
PERMISSION_INVITE_USER,
@@ -421,6 +593,10 @@ func initializePermissions() {
PERMISSION_CREATE_GROUP_CHANNEL,
PERMISSION_MANAGE_PUBLIC_CHANNEL_PROPERTIES,
PERMISSION_MANAGE_PRIVATE_CHANNEL_PROPERTIES,
+ PERMISSION_LIST_PUBLIC_TEAMS,
+ PERMISSION_JOIN_PUBLIC_TEAMS,
+ PERMISSION_LIST_PRIVATE_TEAMS,
+ PERMISSION_JOIN_PRIVATE_TEAMS,
PERMISSION_LIST_TEAM_CHANNELS,
PERMISSION_JOIN_PUBLIC_CHANNELS,
PERMISSION_DELETE_PUBLIC_CHANNEL,
@@ -436,10 +612,17 @@ func initializePermissions() {
PERMISSION_GET_PUBLIC_LINK,
PERMISSION_MANAGE_WEBHOOKS,
PERMISSION_MANAGE_OTHERS_WEBHOOKS,
+ PERMISSION_MANAGE_INCOMING_WEBHOOKS,
+ PERMISSION_MANAGE_OUTGOING_WEBHOOKS,
+ PERMISSION_MANAGE_OTHERS_INCOMING_WEBHOOKS,
+ PERMISSION_MANAGE_OTHERS_OUTGOING_WEBHOOKS,
PERMISSION_MANAGE_OAUTH,
PERMISSION_MANAGE_SYSTEM_WIDE_OAUTH,
PERMISSION_MANAGE_EMOJIS,
PERMISSION_MANAGE_OTHERS_EMOJIS,
+ PERMISSION_CREATE_EMOJIS,
+ PERMISSION_DELETE_EMOJIS,
+ PERMISSION_DELETE_OTHERS_EMOJIS,
PERMISSION_CREATE_POST,
PERMISSION_CREATE_POST_PUBLIC,
PERMISSION_CREATE_POST_EPHEMERAL,
@@ -457,7 +640,34 @@ func initializePermissions() {
PERMISSION_CREATE_USER_ACCESS_TOKEN,
PERMISSION_READ_USER_ACCESS_TOKEN,
PERMISSION_REVOKE_USER_ACCESS_TOKEN,
+ PERMISSION_CREATE_BOT,
+ PERMISSION_READ_BOTS,
+ PERMISSION_READ_OTHERS_BOTS,
+ PERMISSION_MANAGE_BOTS,
+ PERMISSION_MANAGE_OTHERS_BOTS,
PERMISSION_MANAGE_SYSTEM,
+ PERMISSION_VIEW_MEMBERS,
+ PERMISSION_INVITE_GUEST,
+ PERMISSION_PROMOTE_GUEST,
+ PERMISSION_DEMOTE_TO_GUEST,
+ PERMISSION_USE_CHANNEL_MENTIONS,
+ PERMISSION_USE_GROUP_MENTIONS,
+ }
+
+ CHANNEL_MODERATED_PERMISSIONS = []string{
+ PERMISSION_CREATE_POST.Id,
+ "create_reactions",
+ "manage_members",
+ PERMISSION_USE_CHANNEL_MENTIONS.Id,
+ }
+
+ CHANNEL_MODERATED_PERMISSIONS_MAP = map[string]string{
+ PERMISSION_CREATE_POST.Id: CHANNEL_MODERATED_PERMISSIONS[0],
+ PERMISSION_ADD_REACTION.Id: CHANNEL_MODERATED_PERMISSIONS[1],
+ PERMISSION_REMOVE_REACTION.Id: CHANNEL_MODERATED_PERMISSIONS[1],
+ PERMISSION_MANAGE_PUBLIC_CHANNEL_MEMBERS.Id: CHANNEL_MODERATED_PERMISSIONS[2],
+ PERMISSION_MANAGE_PRIVATE_CHANNEL_MEMBERS.Id: CHANNEL_MODERATED_PERMISSIONS[2],
+ PERMISSION_USE_CHANNEL_MENTIONS.Id: CHANNEL_MODERATED_PERMISSIONS[3],
}
}
diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/plugin_event_data.go b/vendor/github.com/mattermost/mattermost-server/v5/model/plugin_event_data.go
new file mode 100644
index 00000000..c704c993
--- /dev/null
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/plugin_event_data.go
@@ -0,0 +1,25 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
+
+package model
+
+import (
+ "encoding/json"
+ "io"
+)
+
+// PluginEventData used to notify peers about plugin changes.
+type PluginEventData struct {
+ Id string `json:"id"`
+}
+
+func (p *PluginEventData) ToJson() string {
+ b, _ := json.Marshal(p)
+ return string(b)
+}
+
+func PluginEventDataFromJson(data io.Reader) PluginEventData {
+ var m PluginEventData
+ json.NewDecoder(data).Decode(&m)
+ return m
+}
diff --git a/vendor/github.com/mattermost/mattermost-server/model/plugin_key_value.go b/vendor/github.com/mattermost/mattermost-server/v5/model/plugin_key_value.go
index b7a7731c..cd5406ea 100644
--- a/vendor/github.com/mattermost/mattermost-server/model/plugin_key_value.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/plugin_key_value.go
@@ -1,5 +1,5 @@
-// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
package model
@@ -17,6 +17,7 @@ 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 {
diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/plugin_kvset_options.go b/vendor/github.com/mattermost/mattermost-server/v5/model/plugin_kvset_options.go
new file mode 100644
index 00000000..1d374c80
--- /dev/null
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/plugin_kvset_options.go
@@ -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
+}
diff --git a/vendor/github.com/mattermost/mattermost-server/model/plugin_status.go b/vendor/github.com/mattermost/mattermost-server/v5/model/plugin_status.go
index db276402..b4ba2e73 100644
--- a/vendor/github.com/mattermost/mattermost-server/model/plugin_status.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/plugin_status.go
@@ -13,7 +13,7 @@ const (
PluginStateStarting = 1 // unused by server
PluginStateRunning = 2
PluginStateFailedToStart = 3
- PluginStateFailedToStayRunning = 4 // unused by server
+ PluginStateFailedToStayRunning = 4
PluginStateStopping = 5 // unused by server
)
diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/plugin_valid.go b/vendor/github.com/mattermost/mattermost-server/v5/model/plugin_valid.go
new file mode 100644
index 00000000..b6144513
--- /dev/null
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/plugin_valid.go
@@ -0,0 +1,39 @@
+// 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)
+}
diff --git a/vendor/github.com/mattermost/mattermost-server/model/plugins_response.go b/vendor/github.com/mattermost/mattermost-server/v5/model/plugins_response.go
index 177cfe6c..421ee2f5 100644
--- a/vendor/github.com/mattermost/mattermost-server/model/plugins_response.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/plugins_response.go
@@ -1,5 +1,5 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// See LICENSE.txt for license information.
package model
diff --git a/vendor/github.com/mattermost/mattermost-server/model/post.go b/vendor/github.com/mattermost/mattermost-server/v5/model/post.go
index 5d2438fc..817ca08a 100644
--- a/vendor/github.com/mattermost/mattermost-server/model/post.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/post.go
@@ -1,17 +1,20 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// See LICENSE.txt for license information.
package model
import (
"encoding/json"
+ "errors"
"io"
"net/http"
+ "regexp"
"sort"
"strings"
+ "sync"
"unicode/utf8"
- "github.com/mattermost/mattermost-server/utils/markdown"
+ "github.com/mattermost/mattermost-server/v5/utils/markdown"
)
const (
@@ -21,12 +24,14 @@ const (
POST_SYSTEM_GENERIC = "system_generic"
POST_JOIN_LEAVE = "system_join_leave" // Deprecated, use POST_JOIN_CHANNEL or POST_LEAVE_CHANNEL instead
POST_JOIN_CHANNEL = "system_join_channel"
+ POST_GUEST_JOIN_CHANNEL = "system_guest_join_channel"
POST_LEAVE_CHANNEL = "system_leave_channel"
POST_JOIN_TEAM = "system_join_team"
POST_LEAVE_TEAM = "system_leave_team"
POST_AUTO_RESPONDER = "system_auto_responder"
POST_ADD_REMOVE = "system_add_remove" // Deprecated, use POST_ADD_TO_CHANNEL or POST_REMOVE_FROM_CHANNEL instead
POST_ADD_TO_CHANNEL = "system_add_to_channel"
+ POST_ADD_GUEST_TO_CHANNEL = "system_add_guest_to_chan"
POST_REMOVE_FROM_CHANNEL = "system_remove_from_channel"
POST_MOVE_CHANNEL = "system_move_channel"
POST_ADD_TO_TEAM = "system_add_to_team"
@@ -36,8 +41,10 @@ const (
POST_CONVERT_CHANNEL = "system_convert_channel"
POST_PURPOSE_CHANGE = "system_purpose_change"
POST_CHANNEL_DELETED = "system_channel_deleted"
+ POST_CHANNEL_RESTORED = "system_channel_restored"
POST_EPHEMERAL = "system_ephemeral"
POST_CHANGE_CHANNEL_PRIVACY = "system_change_chan_privacy"
+ POST_ADD_BOT_TEAMS_CHANNELS = "add_bot_teams_channels"
POST_FILEIDS_MAX_RUNES = 150
POST_FILENAMES_MAX_RUNES = 4000
POST_HASHTAGS_MAX_RUNES = 1000
@@ -47,13 +54,20 @@ const (
POST_PROPS_MAX_RUNES = 8000
POST_PROPS_MAX_USER_RUNES = POST_PROPS_MAX_RUNES - 400 // Leave some room for system / pre-save modifications
POST_CUSTOM_TYPE_PREFIX = "custom_"
+ POST_ME = "me"
PROPS_ADD_CHANNEL_MEMBER = "add_channel_member"
- POST_PROPS_ADDED_USER_ID = "addedUserId"
- POST_PROPS_DELETE_BY = "deleteBy"
- POST_ACTION_TYPE_BUTTON = "button"
- POST_ACTION_TYPE_SELECT = "select"
+
+ POST_PROPS_ADDED_USER_ID = "addedUserId"
+ POST_PROPS_DELETE_BY = "deleteBy"
+ POST_PROPS_OVERRIDE_ICON_URL = "override_icon_url"
+ POST_PROPS_OVERRIDE_ICON_EMOJI = "override_icon_emoji"
+
+ POST_PROPS_MENTION_HIGHLIGHT_DISABLED = "mentionHighlightDisabled"
+ POST_PROPS_GROUP_HIGHLIGHT_DISABLED = "disable_group_highlight"
)
+var AT_MENTION_PATTEN = regexp.MustCompile(`\B@`)
+
type Post struct {
Id string `json:"id"`
CreateAt int64 `json:"create_at"`
@@ -68,19 +82,23 @@ type Post struct {
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" db:"-"`
Type string `json:"type"`
- Props StringInterface `json:"props"`
+ 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:"filenames,omitempty"` // Deprecated, do not use this field any more
FileIds StringArray `json:"file_ids,omitempty"`
PendingPostId string `json:"pending_post_id" db:"-"`
HasReactions bool `json:"has_reactions,omitempty"`
+
+ // Transient data populated before sending a post to the client
+ ReplyCount int64 `json:"reply_count" db:"-"`
+ Metadata *PostMetadata `json:"metadata,omitempty" db:"-"`
}
type PostEphemeral struct {
@@ -105,6 +123,12 @@ type SearchParameter struct {
IncludeDeletedChannels *bool `json:"include_deleted_channels"`
}
+type AnalyticsPostCountsOptions struct {
+ TeamId string
+ BotsOnly bool
+ YesterdayOnly bool
+}
+
func (o *PostPatch) WithRewrittenImageURLs(f func(string) string) *PostPatch {
copy := *o
if copy.Message != nil {
@@ -121,6 +145,12 @@ type PostForExport struct {
ReplyCount int
}
+type DirectPostForExport struct {
+ Post
+ User string
+ ChannelMembers *[]string
+}
+
type ReplyForExport struct {
Post
Username string
@@ -132,48 +162,52 @@ type PostForIndexing struct {
ParentCreateAt *int64 `json:"parent_create_at"`
}
-type DoPostActionRequest struct {
- SelectedOption string `json:"selected_option"`
-}
-
-type PostAction struct {
- Id string `json:"id"`
- Name string `json:"name"`
- Type string `json:"type"`
- DataSource string `json:"data_source"`
- Options []*PostActionOptions `json:"options"`
- Integration *PostActionIntegration `json:"integration,omitempty"`
-}
-
-type PostActionOptions struct {
- Text string `json:"text"`
- Value string `json:"value"`
-}
-
-type PostActionIntegration struct {
- URL string `json:"url,omitempty"`
- Context StringInterface `json:"context,omitempty"`
-}
-
-type PostActionIntegrationRequest struct {
- UserId string `json:"user_id"`
- ChannelId string `json:"channel_id"`
- TeamId string `json:"team_id"`
- PostId string `json:"post_id"`
- Type string `json:"type"`
- DataSource string `json:"data_source"`
- Context StringInterface `json:"context,omitempty"`
+// 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.ParentId = o.ParentId
+ 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.Metadata = o.Metadata
+ return nil
}
-type PostActionIntegrationResponse struct {
- Update *Post `json:"update"`
- EphemeralText string `json:"ephemeral_text"`
+// Clone shallowly copies the post and returns the copy.
+func (o *Post) Clone() *Post {
+ copy := &Post{}
+ o.ShallowCopy(copy)
+ return copy
}
func (o *Post) ToJson() string {
- copy := *o
+ copy := o.Clone()
copy.StripActionIntegrations()
- b, _ := json.Marshal(&copy)
+ b, _ := json.Marshal(copy)
return string(b)
}
@@ -182,6 +216,20 @@ func (o *Post) ToUnsanitizedJson() string {
return string(b)
}
+type GetPostsSinceOptions struct {
+ ChannelId string
+ Time int64
+ SkipFetchThreads bool
+}
+
+type GetPostsOptions struct {
+ ChannelId string
+ PostId string
+ Page int
+ PerPage int
+ SkipFetchThreads bool
+}
+
func PostFromJson(data io.Reader) *Post {
var o *Post
json.NewDecoder(data).Decode(&o)
@@ -193,8 +241,7 @@ func (o *Post) Etag() string {
}
func (o *Post) IsValid(maxPostSize int) *AppError {
-
- if len(o.Id) != 26 {
+ if !IsValidId(o.Id) {
return NewAppError("Post.IsValid", "model.post.is_valid.id.app_error", nil, "", http.StatusBadRequest)
}
@@ -206,19 +253,19 @@ func (o *Post) IsValid(maxPostSize int) *AppError {
return NewAppError("Post.IsValid", "model.post.is_valid.update_at.app_error", nil, "id="+o.Id, http.StatusBadRequest)
}
- if len(o.UserId) != 26 {
+ if !IsValidId(o.UserId) {
return NewAppError("Post.IsValid", "model.post.is_valid.user_id.app_error", nil, "", http.StatusBadRequest)
}
- if len(o.ChannelId) != 26 {
+ if !IsValidId(o.ChannelId) {
return NewAppError("Post.IsValid", "model.post.is_valid.channel_id.app_error", nil, "", http.StatusBadRequest)
}
- if !(len(o.RootId) == 26 || len(o.RootId) == 0) {
+ if !(IsValidId(o.RootId) || len(o.RootId) == 0) {
return NewAppError("Post.IsValid", "model.post.is_valid.root_id.app_error", nil, "", http.StatusBadRequest)
}
- if !(len(o.ParentId) == 26 || len(o.ParentId) == 0) {
+ if !(IsValidId(o.ParentId) || len(o.ParentId) == 0) {
return NewAppError("Post.IsValid", "model.post.is_valid.parent_id.app_error", nil, "", http.StatusBadRequest)
}
@@ -241,14 +288,17 @@ func (o *Post) IsValid(maxPostSize int) *AppError {
switch o.Type {
case
POST_DEFAULT,
+ POST_SYSTEM_GENERIC,
POST_JOIN_LEAVE,
POST_AUTO_RESPONDER,
POST_ADD_REMOVE,
POST_JOIN_CHANNEL,
+ POST_GUEST_JOIN_CHANNEL,
POST_LEAVE_CHANNEL,
POST_JOIN_TEAM,
POST_LEAVE_TEAM,
POST_ADD_TO_CHANNEL,
+ POST_ADD_GUEST_TO_CHANNEL,
POST_REMOVE_FROM_CHANNEL,
POST_MOVE_CHANNEL,
POST_ADD_TO_TEAM,
@@ -259,7 +309,10 @@ func (o *Post) IsValid(maxPostSize int) *AppError {
POST_DISPLAYNAME_CHANGE,
POST_CONVERT_CHANNEL,
POST_CHANNEL_DELETED,
- POST_CHANGE_CHANNEL_PRIVACY:
+ POST_CHANNEL_RESTORED,
+ POST_CHANGE_CHANNEL_PRIVACY,
+ POST_ME,
+ POST_ADD_BOT_TEAMS_CHANNELS:
default:
if !strings.HasPrefix(o.Type, POST_CUSTOM_TYPE_PREFIX) {
return NewAppError("Post.IsValid", "model.post.is_valid.type.app_error", nil, "id="+o.Type, http.StatusBadRequest)
@@ -274,7 +327,7 @@ func (o *Post) IsValid(maxPostSize int) *AppError {
return NewAppError("Post.IsValid", "model.post.is_valid.file_ids.app_error", nil, "id="+o.Id, http.StatusBadRequest)
}
- if utf8.RuneCountInString(StringInterfaceToJson(o.Props)) > POST_PROPS_MAX_RUNES {
+ if utf8.RuneCountInString(StringInterfaceToJson(o.GetProps())) > POST_PROPS_MAX_RUNES {
return NewAppError("Post.IsValid", "model.post.is_valid.props.app_error", nil, "id="+o.Id, http.StatusBadRequest)
}
@@ -287,8 +340,8 @@ func (o *Post) SanitizeProps() {
}
for _, member := range membersToSanitize {
- if _, ok := o.Props[member]; ok {
- delete(o.Props, member)
+ if _, ok := o.GetProps()[member]; ok {
+ o.DelProp(member)
}
}
}
@@ -309,8 +362,8 @@ func (o *Post) PreSave() {
}
func (o *Post) PreCommit() {
- if o.Props == nil {
- o.Props = make(map[string]interface{})
+ if o.GetProps() == nil {
+ o.SetProps(make(map[string]interface{}))
}
if o.Filenames == nil {
@@ -322,44 +375,94 @@ func (o *Post) PreCommit() {
}
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.Props == nil {
- o.Props = make(map[string]interface{})
+ if o.GetProps() == nil {
+ o.SetProps(make(map[string]interface{}))
}
}
+func (o *Post) DelProp(key string) {
+ o.propsMu.Lock()
+ defer o.propsMu.Unlock()
+ propsCopy := make(map[string]interface{}, 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 interface{}) {
+ o.propsMu.Lock()
+ defer o.propsMu.Unlock()
+ propsCopy := make(map[string]interface{}, 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
+}
- o.MakeNonNil()
+func (o *Post) SetProps(props StringInterface) {
+ o.propsMu.Lock()
+ defer o.propsMu.Unlock()
+ o.Props = props
+}
- o.Props[key] = value
+func (o *Post) GetProp(key string) interface{} {
+ o.propsMu.RLock()
+ defer o.propsMu.RUnlock()
+ return o.Props[key]
}
func (o *Post) IsSystemMessage() bool {
return len(o.Type) >= len(POST_SYSTEM_MESSAGE_PREFIX) && o.Type[:len(POST_SYSTEM_MESSAGE_PREFIX)] == POST_SYSTEM_MESSAGE_PREFIX
}
-func (p *Post) Patch(patch *PostPatch) {
+func (o *Post) IsJoinLeaveMessage() bool {
+ return o.Type == POST_JOIN_LEAVE ||
+ o.Type == POST_ADD_REMOVE ||
+ o.Type == POST_JOIN_CHANNEL ||
+ o.Type == POST_LEAVE_CHANNEL ||
+ o.Type == POST_JOIN_TEAM ||
+ o.Type == POST_LEAVE_TEAM ||
+ o.Type == POST_ADD_TO_CHANNEL ||
+ o.Type == POST_REMOVE_FROM_CHANNEL ||
+ o.Type == POST_ADD_TO_TEAM ||
+ o.Type == POST_REMOVE_FROM_TEAM
+}
+
+func (o *Post) Patch(patch *PostPatch) {
if patch.IsPinned != nil {
- p.IsPinned = *patch.IsPinned
+ o.IsPinned = *patch.IsPinned
}
if patch.Message != nil {
- p.Message = *patch.Message
+ o.Message = *patch.Message
}
if patch.Props != nil {
- p.Props = *patch.Props
+ newProps := *patch.Props
+ o.SetProps(newProps)
}
if patch.FileIds != nil {
- p.FileIds = *patch.FileIds
+ o.FileIds = *patch.FileIds
}
if patch.HasReactions != nil {
- p.HasReactions = *patch.HasReactions
+ o.HasReactions = *patch.HasReactions
}
}
@@ -407,40 +510,40 @@ func (o *Post) ChannelMentions() []string {
return ChannelMentions(o.Message)
}
-func (r *PostActionIntegrationRequest) ToJson() string {
- b, _ := json.Marshal(r)
- return string(b)
-}
-
-func PostActionIntegrationRequesteFromJson(data io.Reader) *PostActionIntegrationRequest {
- var o *PostActionIntegrationRequest
- err := json.NewDecoder(data).Decode(&o)
- if err != nil {
- return nil
+// 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(POST_PROPS_MENTION_HIGHLIGHT_DISABLED, true)
}
- return o
+ return mention
}
-func (r *PostActionIntegrationResponse) ToJson() string {
- b, _ := json.Marshal(r)
- return string(b)
+// DisableMentionHighlights disables mention highlighting for a post patch if required.
+func (o *PostPatch) DisableMentionHighlights() {
+ if _, hasMentions := findAtChannelMention(*o.Message); hasMentions {
+ if o.Props == nil {
+ o.Props = &StringInterface{}
+ }
+ (*o.Props)[POST_PROPS_MENTION_HIGHLIGHT_DISABLED] = true
+ }
}
-func PostActionIntegrationResponseFromJson(data io.Reader) *PostActionIntegrationResponse {
- var o *PostActionIntegrationResponse
- err := json.NewDecoder(data).Decode(&o)
- if err != nil {
- return nil
+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 o
+ return
}
func (o *Post) Attachments() []*SlackAttachment {
- if attachments, ok := o.Props["attachments"].([]*SlackAttachment); ok {
+ if attachments, ok := o.GetProp("attachments").([]*SlackAttachment); ok {
return attachments
}
var ret []*SlackAttachment
- if attachments, ok := o.Props["attachments"].([]interface{}); ok {
+ if attachments, ok := o.GetProp("attachments").([]interface{}); ok {
for _, attachment := range attachments {
if enc, err := json.Marshal(attachment); err == nil {
var decoded SlackAttachment
@@ -453,42 +556,21 @@ func (o *Post) Attachments() []*SlackAttachment {
return ret
}
-func (o *Post) StripActionIntegrations() {
+func (o *Post) AttachmentsEqual(input *Post) bool {
attachments := o.Attachments()
- if o.Props["attachments"] != nil {
- o.Props["attachments"] = attachments
- }
- for _, attachment := range attachments {
- for _, action := range attachment.Actions {
- action.Integration = nil
- }
- }
-}
+ inputAttachments := input.Attachments()
-func (o *Post) GetAction(id string) *PostAction {
- for _, attachment := range o.Attachments() {
- for _, action := range attachment.Actions {
- if action.Id == id {
- return action
- }
- }
+ if len(attachments) != len(inputAttachments) {
+ return false
}
- return nil
-}
-func (o *Post) GenerateActionIds() {
- if o.Props["attachments"] != nil {
- o.Props["attachments"] = o.Attachments()
- }
- if attachments, ok := o.Props["attachments"].([]*SlackAttachment); ok {
- for _, attachment := range attachments {
- for _, action := range attachment.Actions {
- if action.Id == "" {
- action.Id = NewId()
- }
- }
+ for i := range attachments {
+ if !attachments[i].Equals(inputAttachments[i]) {
+ return false
}
}
+
+ return true
}
var markdownDestinationEscaper = strings.NewReplacer(
@@ -502,12 +584,12 @@ 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 {
- copy := *o
+ copy := o.Clone()
copy.Message = RewriteImageURLs(o.Message, f)
if copy.MessageSource == "" && copy.Message != o.Message {
copy.MessageSource = o.Message
}
- return &copy
+ return copy
}
func (o *PostEphemeral) ToUnsanitizedJson() string {
@@ -515,12 +597,6 @@ func (o *PostEphemeral) ToUnsanitizedJson() string {
return string(b)
}
-func DoPostActionRequestFromJson(data io.Reader) *DoPostActionRequest {
- var o *DoPostActionRequest
- json.NewDecoder(data).Decode(&o)
- return o
-}
-
// 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.
diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/post_embed.go b/vendor/github.com/mattermost/mattermost-server/v5/model/post_embed.go
new file mode 100644
index 00000000..5c6efec1
--- /dev/null
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/post_embed.go
@@ -0,0 +1,23 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
+
+package model
+
+const (
+ POST_EMBED_IMAGE PostEmbedType = "image"
+ POST_EMBED_MESSAGE_ATTACHMENT PostEmbedType = "message_attachment"
+ POST_EMBED_OPENGRAPH PostEmbedType = "opengraph"
+ POST_EMBED_LINK PostEmbedType = "link"
+)
+
+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 interface{} `json:"data,omitempty"`
+}
diff --git a/vendor/github.com/mattermost/mattermost-server/model/post_list.go b/vendor/github.com/mattermost/mattermost-server/v5/model/post_list.go
index 27c22e7b..d00b68b5 100644
--- a/vendor/github.com/mattermost/mattermost-server/model/post_list.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/post_list.go
@@ -1,5 +1,5 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// See LICENSE.txt for license information.
package model
@@ -10,17 +10,29 @@ import (
)
type PostList struct {
- Order []string `json:"order"`
- Posts map[string]*Post `json:"posts"`
+ Order []string `json:"order"`
+ Posts map[string]*Post `json:"posts"`
+ NextPostId string `json:"next_post_id"`
+ PrevPostId string `json:"prev_post_id"`
}
func NewPostList() *PostList {
return &PostList{
- Order: make([]string, 0),
- Posts: make(map[string]*Post),
+ Order: make([]string, 0),
+ Posts: make(map[string]*Post),
+ NextPostId: "",
+ PrevPostId: "",
}
}
+func (o *PostList) ToSlice() []*Post {
+ var posts []*Post
+ for _, id := range o.Order {
+ posts = append(posts, o.Posts[id])
+ }
+ return posts
+}
+
func (o *PostList) WithRewrittenImageURLs(f func(string) string) *PostList {
copy := *o
copy.Posts = make(map[string]*Post)
@@ -34,9 +46,9 @@ func (o *PostList) StripActionIntegrations() {
posts := o.Posts
o.Posts = make(map[string]*Post)
for id, post := range posts {
- pcopy := *post
+ pcopy := post.Clone()
pcopy.StripActionIntegrations()
- o.Posts[id] = &pcopy
+ o.Posts[id] = pcopy
}
}
@@ -83,13 +95,29 @@ func (o *PostList) AddPost(post *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 {
- if _, ok := o.Posts[postId]; !ok {
- o.AddPost(other.Posts[postId])
- o.AddOrder(postId)
- }
+ o.AddOrder(postId)
}
+
+ o.UniqueOrder()
}
func (o *PostList) SortByCreateAt() {
diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/post_metadata.go b/vendor/github.com/mattermost/mattermost-server/v5/model/post_metadata.go
new file mode 100644
index 00000000..7b0687ca
--- /dev/null
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/post_metadata.go
@@ -0,0 +1,45 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
+
+package model
+
+import (
+ "encoding/json"
+)
+
+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 diemsnions.
+ // 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"`
+}
+
+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"`
+}
+
+func (o *PostImage) ToJson() string {
+ b, _ := json.Marshal(o)
+ return string(b)
+}
diff --git a/vendor/github.com/mattermost/mattermost-server/model/post_search_results.go b/vendor/github.com/mattermost/mattermost-server/v5/model/post_search_results.go
index 2317f183..74ef4b52 100644
--- a/vendor/github.com/mattermost/mattermost-server/model/post_search_results.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/post_search_results.go
@@ -1,5 +1,5 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// See LICENSE.txt for license information.
package model
diff --git a/vendor/github.com/mattermost/mattermost-server/model/preference.go b/vendor/github.com/mattermost/mattermost-server/v5/model/preference.go
index 6f13c38e..346f88f8 100644
--- a/vendor/github.com/mattermost/mattermost-server/model/preference.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/preference.go
@@ -1,5 +1,5 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// See LICENSE.txt for license information.
package model
@@ -42,6 +42,11 @@ const (
PREFERENCE_EMAIL_INTERVAL_NO_BATCHING_SECONDS = "30" // the "immediate" setting is actually 30s
PREFERENCE_EMAIL_INTERVAL_BATCHING_SECONDS = "900" // fifteen minutes is 900 seconds
+ PREFERENCE_EMAIL_INTERVAL_IMMEDIATELY = "immediately"
+ PREFERENCE_EMAIL_INTERVAL_FIFTEEN = "fifteen"
+ PREFERENCE_EMAIL_INTERVAL_FIFTEEN_AS_SECONDS = "900"
+ PREFERENCE_EMAIL_INTERVAL_HOUR = "hour"
+ PREFERENCE_EMAIL_INTERVAL_HOUR_AS_SECONDS = "3600"
)
type Preference struct {
@@ -63,7 +68,7 @@ func PreferenceFromJson(data io.Reader) *Preference {
}
func (o *Preference) IsValid() *AppError {
- if len(o.UserId) != 26 {
+ if !IsValidId(o.UserId) {
return NewAppError("Preference.IsValid", "model.preference.is_valid.id.app_error", nil, "user_id="+o.UserId, http.StatusBadRequest)
}
diff --git a/vendor/github.com/mattermost/mattermost-server/model/preferences.go b/vendor/github.com/mattermost/mattermost-server/v5/model/preferences.go
index 172e1aa8..6ed845b6 100644
--- a/vendor/github.com/mattermost/mattermost-server/model/preferences.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/preferences.go
@@ -1,5 +1,5 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// See LICENSE.txt for license information.
package model
diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/push_notification.go b/vendor/github.com/mattermost/mattermost-server/v5/model/push_notification.go
new file mode 100644
index 00000000..5b0118ce
--- /dev/null
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/push_notification.go
@@ -0,0 +1,117 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
+
+package model
+
+import (
+ "encoding/json"
+ "errors"
+ "io"
+ "strings"
+)
+
+const (
+ PUSH_NOTIFY_APPLE = "apple"
+ PUSH_NOTIFY_ANDROID = "android"
+ PUSH_NOTIFY_APPLE_REACT_NATIVE = "apple_rn"
+ PUSH_NOTIFY_ANDROID_REACT_NATIVE = "android_rn"
+
+ PUSH_TYPE_MESSAGE = "message"
+ PUSH_TYPE_CLEAR = "clear"
+ PUSH_TYPE_UPDATE_BADGE = "update_badge"
+ PUSH_MESSAGE_V2 = "v2"
+
+ PUSH_SOUND_NONE = "none"
+
+ // The category is set to handle a set of interactive Actions
+ // with the push notifications
+ CATEGORY_CAN_REPLY = "CAN_REPLY"
+
+ MHPNS = "https://push.mattermost.com"
+
+ PUSH_SEND_PREPARE = "Prepared to send"
+ PUSH_SEND_SUCCESS = "Successful"
+ PUSH_NOT_SENT = "Not Sent due to preferences"
+ PUSH_RECEIVED = "Received by device"
+)
+
+type PushNotificationAck struct {
+ Id string `json:"id"`
+ ClientReceivedAt int64 `json:"received_at"`
+ ClientPlatform string `json:"platform"`
+ NotificationType string `json:"type"`
+ PostId string `json:"post_id,omitempty"`
+ IsIdLoaded bool `json:"is_id_loaded"`
+}
+
+type PushNotification struct {
+ AckId string `json:"ack_id"`
+ Platform string `json:"platform"`
+ ServerId string `json:"server_id"`
+ DeviceId string `json:"device_id"`
+ PostId string `json:"post_id"`
+ Category string `json:"category,omitempty"`
+ Sound string `json:"sound,omitempty"`
+ Message string `json:"message,omitempty"`
+ Badge int `json:"badge,omitempty"`
+ ContentAvailable int `json:"cont_ava,omitempty"`
+ TeamId string `json:"team_id,omitempty"`
+ ChannelId string `json:"channel_id,omitempty"`
+ RootId string `json:"root_id,omitempty"`
+ ChannelName string `json:"channel_name,omitempty"`
+ Type string `json:"type,omitempty"`
+ SenderId string `json:"sender_id,omitempty"`
+ SenderName string `json:"sender_name,omitempty"`
+ OverrideUsername string `json:"override_username,omitempty"`
+ OverrideIconUrl string `json:"override_icon_url,omitempty"`
+ FromWebhook string `json:"from_webhook,omitempty"`
+ Version string `json:"version,omitempty"`
+ IsIdLoaded bool `json:"is_id_loaded"`
+}
+
+func (me *PushNotification) ToJson() string {
+ b, _ := json.Marshal(me)
+ return string(b)
+}
+
+func (me *PushNotification) DeepCopy() *PushNotification {
+ copy := *me
+ return &copy
+}
+
+func (me *PushNotification) SetDeviceIdAndPlatform(deviceId string) {
+
+ index := strings.Index(deviceId, ":")
+
+ if index > -1 {
+ me.Platform = deviceId[:index]
+ me.DeviceId = deviceId[index+1:]
+ }
+}
+
+func PushNotificationFromJson(data io.Reader) (*PushNotification, error) {
+ if data == nil {
+ return nil, errors.New("push notification data can't be nil")
+ }
+ var me *PushNotification
+ if err := json.NewDecoder(data).Decode(&me); err != nil {
+ return nil, err
+ }
+ return me, nil
+}
+
+func PushNotificationAckFromJson(data io.Reader) (*PushNotificationAck, error) {
+ if data == nil {
+ return nil, errors.New("push notification data can't be nil")
+ }
+ var ack *PushNotificationAck
+ if err := json.NewDecoder(data).Decode(&ack); err != nil {
+ return nil, err
+ }
+ return ack, nil
+}
+
+func (ack *PushNotificationAck) ToJson() string {
+ b, _ := json.Marshal(ack)
+ return string(b)
+}
diff --git a/vendor/github.com/mattermost/mattermost-server/model/push_response.go b/vendor/github.com/mattermost/mattermost-server/v5/model/push_response.go
index 1434a2b1..e6e8059b 100644
--- a/vendor/github.com/mattermost/mattermost-server/model/push_response.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/push_response.go
@@ -1,5 +1,5 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// See LICENSE.txt for license information.
package model
diff --git a/vendor/github.com/mattermost/mattermost-server/model/reaction.go b/vendor/github.com/mattermost/mattermost-server/v5/model/reaction.go
index c1b9c499..50879c67 100644
--- a/vendor/github.com/mattermost/mattermost-server/model/reaction.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/reaction.go
@@ -1,5 +1,5 @@
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
package model
@@ -37,6 +37,22 @@ func ReactionsToJson(o []*Reaction) string {
return string(b)
}
+func MapPostIdToReactionsToJson(o map[string][]*Reaction) string {
+ b, _ := json.Marshal(o)
+ return string(b)
+}
+
+func MapPostIdToReactionsFromJson(data io.Reader) map[string][]*Reaction {
+ decoder := json.NewDecoder(data)
+
+ var objmap map[string][]*Reaction
+ if err := decoder.Decode(&objmap); err != nil {
+ return make(map[string][]*Reaction)
+ } else {
+ return objmap
+ }
+}
+
func ReactionsFromJson(data io.Reader) []*Reaction {
var o []*Reaction
@@ -48,11 +64,11 @@ func ReactionsFromJson(data io.Reader) []*Reaction {
}
func (o *Reaction) IsValid() *AppError {
- if len(o.UserId) != 26 {
+ if !IsValidId(o.UserId) {
return NewAppError("Reaction.IsValid", "model.reaction.is_valid.user_id.app_error", nil, "user_id="+o.UserId, http.StatusBadRequest)
}
- if len(o.PostId) != 26 {
+ if !IsValidId(o.PostId) {
return NewAppError("Reaction.IsValid", "model.reaction.is_valid.post_id.app_error", nil, "post_id="+o.PostId, http.StatusBadRequest)
}
diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/role.go b/vendor/github.com/mattermost/mattermost-server/v5/model/role.go
new file mode 100644
index 00000000..38ac1ef7
--- /dev/null
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/role.go
@@ -0,0 +1,632 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
+
+package model
+
+import (
+ "encoding/json"
+ "io"
+ "strings"
+)
+
+var BuiltInSchemeManagedRoleIDs []string
+
+func init() {
+ BuiltInSchemeManagedRoleIDs = []string{
+ SYSTEM_GUEST_ROLE_ID,
+ SYSTEM_USER_ROLE_ID,
+ SYSTEM_ADMIN_ROLE_ID,
+ SYSTEM_POST_ALL_ROLE_ID,
+ SYSTEM_POST_ALL_PUBLIC_ROLE_ID,
+ SYSTEM_USER_ACCESS_TOKEN_ROLE_ID,
+
+ TEAM_GUEST_ROLE_ID,
+ TEAM_USER_ROLE_ID,
+ TEAM_ADMIN_ROLE_ID,
+ TEAM_POST_ALL_ROLE_ID,
+ TEAM_POST_ALL_PUBLIC_ROLE_ID,
+
+ CHANNEL_GUEST_ROLE_ID,
+ CHANNEL_USER_ROLE_ID,
+ CHANNEL_ADMIN_ROLE_ID,
+ }
+}
+
+type RoleType string
+type RoleScope string
+
+const (
+ SYSTEM_GUEST_ROLE_ID = "system_guest"
+ SYSTEM_USER_ROLE_ID = "system_user"
+ SYSTEM_ADMIN_ROLE_ID = "system_admin"
+ SYSTEM_POST_ALL_ROLE_ID = "system_post_all"
+ SYSTEM_POST_ALL_PUBLIC_ROLE_ID = "system_post_all_public"
+ SYSTEM_USER_ACCESS_TOKEN_ROLE_ID = "system_user_access_token"
+
+ TEAM_GUEST_ROLE_ID = "team_guest"
+ TEAM_USER_ROLE_ID = "team_user"
+ TEAM_ADMIN_ROLE_ID = "team_admin"
+ TEAM_POST_ALL_ROLE_ID = "team_post_all"
+ TEAM_POST_ALL_PUBLIC_ROLE_ID = "team_post_all_public"
+
+ CHANNEL_GUEST_ROLE_ID = "channel_guest"
+ CHANNEL_USER_ROLE_ID = "channel_user"
+ CHANNEL_ADMIN_ROLE_ID = "channel_admin"
+
+ ROLE_NAME_MAX_LENGTH = 64
+ ROLE_DISPLAY_NAME_MAX_LENGTH = 128
+ ROLE_DESCRIPTION_MAX_LENGTH = 1024
+
+ RoleScopeSystem RoleScope = "System"
+ RoleScopeTeam RoleScope = "Team"
+ RoleScopeChannel RoleScope = "Channel"
+
+ RoleTypeGuest RoleType = "Guest"
+ RoleTypeUser RoleType = "User"
+ RoleTypeAdmin RoleType = "Admin"
+)
+
+type Role struct {
+ Id string `json:"id"`
+ Name string `json:"name"`
+ DisplayName string `json:"display_name"`
+ Description string `json:"description"`
+ CreateAt int64 `json:"create_at"`
+ UpdateAt int64 `json:"update_at"`
+ DeleteAt int64 `json:"delete_at"`
+ Permissions []string `json:"permissions"`
+ SchemeManaged bool `json:"scheme_managed"`
+ BuiltIn bool `json:"built_in"`
+}
+
+type RolePatch struct {
+ Permissions *[]string `json:"permissions"`
+}
+
+type RolePermissions struct {
+ RoleID string
+ Permissions []string
+}
+
+func (r *Role) ToJson() string {
+ b, _ := json.Marshal(r)
+ return string(b)
+}
+
+func RoleFromJson(data io.Reader) *Role {
+ var r *Role
+ json.NewDecoder(data).Decode(&r)
+ return r
+}
+
+func RoleListToJson(r []*Role) string {
+ b, _ := json.Marshal(r)
+ return string(b)
+}
+
+func RoleListFromJson(data io.Reader) []*Role {
+ var roles []*Role
+ json.NewDecoder(data).Decode(&roles)
+ return roles
+}
+
+func (r *RolePatch) ToJson() string {
+ b, _ := json.Marshal(r)
+ return string(b)
+}
+
+func RolePatchFromJson(data io.Reader) *RolePatch {
+ var rolePatch *RolePatch
+ json.NewDecoder(data).Decode(&rolePatch)
+ return rolePatch
+}
+
+func (r *Role) Patch(patch *RolePatch) {
+ if patch.Permissions != nil {
+ r.Permissions = *patch.Permissions
+ }
+}
+
+// MergeChannelHigherScopedPermissions is meant to be invoked on a channel scheme's role and merges the higher-scoped
+// channel role's permissions.
+func (r *Role) MergeChannelHigherScopedPermissions(higherScopedPermissions *RolePermissions) {
+ mergedPermissions := []string{}
+
+ higherScopedPermissionsMap := AsStringBoolMap(higherScopedPermissions.Permissions)
+ rolePermissionsMap := AsStringBoolMap(r.Permissions)
+
+ for _, cp := range ALL_PERMISSIONS {
+ if cp.Scope != PERMISSION_SCOPE_CHANNEL {
+ continue
+ }
+
+ _, presentOnHigherScope := higherScopedPermissionsMap[cp.Id]
+
+ // For the channel admin role always look to the higher scope to determine if the role has ther permission.
+ // The channel admin is a special case because they're not part of the UI to be "channel moderated", only
+ // channel members and channel guests are.
+ if higherScopedPermissions.RoleID == CHANNEL_ADMIN_ROLE_ID && presentOnHigherScope {
+ mergedPermissions = append(mergedPermissions, cp.Id)
+ continue
+ }
+
+ _, permissionIsModerated := CHANNEL_MODERATED_PERMISSIONS_MAP[cp.Id]
+ if permissionIsModerated {
+ _, presentOnRole := rolePermissionsMap[cp.Id]
+ if presentOnRole && presentOnHigherScope {
+ mergedPermissions = append(mergedPermissions, cp.Id)
+ }
+ } else {
+ if presentOnHigherScope {
+ mergedPermissions = append(mergedPermissions, cp.Id)
+ }
+ }
+ }
+
+ r.Permissions = mergedPermissions
+}
+
+// Returns an array of permissions that are in either role.Permissions
+// or patch.Permissions, but not both.
+func PermissionsChangedByPatch(role *Role, patch *RolePatch) []string {
+ var result []string
+
+ if patch.Permissions == nil {
+ return result
+ }
+
+ roleMap := make(map[string]bool)
+ patchMap := make(map[string]bool)
+
+ for _, permission := range role.Permissions {
+ roleMap[permission] = true
+ }
+
+ for _, permission := range *patch.Permissions {
+ patchMap[permission] = true
+ }
+
+ for _, permission := range role.Permissions {
+ if !patchMap[permission] {
+ result = append(result, permission)
+ }
+ }
+
+ for _, permission := range *patch.Permissions {
+ if !roleMap[permission] {
+ result = append(result, permission)
+ }
+ }
+
+ return result
+}
+
+func ChannelModeratedPermissionsChangedByPatch(role *Role, patch *RolePatch) []string {
+ var result []string
+
+ if role == nil {
+ return result
+ }
+
+ if patch.Permissions == nil {
+ return result
+ }
+
+ roleMap := make(map[string]bool)
+ patchMap := make(map[string]bool)
+
+ for _, permission := range role.Permissions {
+ if channelModeratedPermissionName, found := CHANNEL_MODERATED_PERMISSIONS_MAP[permission]; found {
+ roleMap[channelModeratedPermissionName] = true
+ }
+ }
+
+ for _, permission := range *patch.Permissions {
+ if channelModeratedPermissionName, found := CHANNEL_MODERATED_PERMISSIONS_MAP[permission]; found {
+ patchMap[channelModeratedPermissionName] = true
+ }
+ }
+
+ for permissionKey := range roleMap {
+ if !patchMap[permissionKey] {
+ result = append(result, permissionKey)
+ }
+ }
+
+ for permissionKey := range patchMap {
+ if !roleMap[permissionKey] {
+ result = append(result, permissionKey)
+ }
+ }
+
+ return result
+}
+
+// GetChannelModeratedPermissions returns a map of channel moderated permissions that the role has access to
+func (r *Role) GetChannelModeratedPermissions(channelType string) map[string]bool {
+ moderatedPermissions := make(map[string]bool)
+ for _, permission := range r.Permissions {
+ if _, found := CHANNEL_MODERATED_PERMISSIONS_MAP[permission]; !found {
+ continue
+ }
+
+ for moderated, moderatedPermissionValue := range CHANNEL_MODERATED_PERMISSIONS_MAP {
+ // the moderated permission has already been found to be true so skip this iteration
+ if moderatedPermissions[moderatedPermissionValue] {
+ continue
+ }
+
+ if moderated == permission {
+ // Special case where the channel moderated permission for `manage_members` is different depending on whether the channel is private or public
+ if moderated == PERMISSION_MANAGE_PUBLIC_CHANNEL_MEMBERS.Id || moderated == PERMISSION_MANAGE_PRIVATE_CHANNEL_MEMBERS.Id {
+ canManagePublic := channelType == CHANNEL_OPEN && moderated == PERMISSION_MANAGE_PUBLIC_CHANNEL_MEMBERS.Id
+ canManagePrivate := channelType == CHANNEL_PRIVATE && moderated == PERMISSION_MANAGE_PRIVATE_CHANNEL_MEMBERS.Id
+ moderatedPermissions[moderatedPermissionValue] = canManagePublic || canManagePrivate
+ } else {
+ moderatedPermissions[moderatedPermissionValue] = true
+ }
+ }
+ }
+ }
+
+ return moderatedPermissions
+}
+
+// RolePatchFromChannelModerationsPatch Creates and returns a RolePatch based on a slice of ChannelModerationPatchs, roleName is expected to be either "members" or "guests".
+func (r *Role) RolePatchFromChannelModerationsPatch(channelModerationsPatch []*ChannelModerationPatch, roleName string) *RolePatch {
+ permissionsToAddToPatch := make(map[string]bool)
+
+ // Iterate through the list of existing permissions on the role and append permissions that we want to keep.
+ for _, permission := range r.Permissions {
+ // Permission is not moderated so dont add it to the patch and skip the channelModerationsPatch
+ if _, isModerated := CHANNEL_MODERATED_PERMISSIONS_MAP[permission]; !isModerated {
+ continue
+ }
+
+ permissionEnabled := true
+ // Check if permission has a matching moderated permission name inside the channel moderation patch
+ for _, channelModerationPatch := range channelModerationsPatch {
+ if *channelModerationPatch.Name == CHANNEL_MODERATED_PERMISSIONS_MAP[permission] {
+ // Permission key exists in patch with a value of false so skip over it
+ if roleName == "members" {
+ if channelModerationPatch.Roles.Members != nil && !*channelModerationPatch.Roles.Members {
+ permissionEnabled = false
+ }
+ } else if roleName == "guests" {
+ if channelModerationPatch.Roles.Guests != nil && !*channelModerationPatch.Roles.Guests {
+ permissionEnabled = false
+ }
+ }
+ }
+ }
+
+ if permissionEnabled {
+ permissionsToAddToPatch[permission] = true
+ }
+ }
+
+ // Iterate through the patch and add any permissions that dont already exist on the role
+ for _, channelModerationPatch := range channelModerationsPatch {
+ for permission, moderatedPermissionName := range CHANNEL_MODERATED_PERMISSIONS_MAP {
+ if roleName == "members" && channelModerationPatch.Roles.Members != nil && *channelModerationPatch.Roles.Members && *channelModerationPatch.Name == moderatedPermissionName {
+ permissionsToAddToPatch[permission] = true
+ }
+
+ if roleName == "guests" && channelModerationPatch.Roles.Guests != nil && *channelModerationPatch.Roles.Guests && *channelModerationPatch.Name == moderatedPermissionName {
+ permissionsToAddToPatch[permission] = true
+ }
+ }
+ }
+
+ patchPermissions := make([]string, 0, len(permissionsToAddToPatch))
+ for permission := range permissionsToAddToPatch {
+ patchPermissions = append(patchPermissions, permission)
+ }
+
+ return &RolePatch{Permissions: &patchPermissions}
+}
+
+func (r *Role) IsValid() bool {
+ if !IsValidId(r.Id) {
+ return false
+ }
+
+ return r.IsValidWithoutId()
+}
+
+func (r *Role) IsValidWithoutId() bool {
+ if !IsValidRoleName(r.Name) {
+ return false
+ }
+
+ if len(r.DisplayName) == 0 || len(r.DisplayName) > ROLE_DISPLAY_NAME_MAX_LENGTH {
+ return false
+ }
+
+ if len(r.Description) > ROLE_DESCRIPTION_MAX_LENGTH {
+ return false
+ }
+
+ for _, permission := range r.Permissions {
+ permissionValidated := false
+ for _, p := range ALL_PERMISSIONS {
+ if permission == p.Id {
+ permissionValidated = true
+ break
+ }
+ }
+
+ if !permissionValidated {
+ return false
+ }
+ }
+
+ return true
+}
+
+func IsValidRoleName(roleName string) bool {
+ if len(roleName) <= 0 || len(roleName) > ROLE_NAME_MAX_LENGTH {
+ return false
+ }
+
+ if strings.TrimLeft(roleName, "abcdefghijklmnopqrstuvwxyz0123456789_") != "" {
+ return false
+ }
+
+ return true
+}
+
+func MakeDefaultRoles() map[string]*Role {
+ roles := make(map[string]*Role)
+
+ roles[CHANNEL_GUEST_ROLE_ID] = &Role{
+ Name: "channel_guest",
+ DisplayName: "authentication.roles.channel_guest.name",
+ Description: "authentication.roles.channel_guest.description",
+ Permissions: []string{
+ PERMISSION_READ_CHANNEL.Id,
+ PERMISSION_ADD_REACTION.Id,
+ PERMISSION_REMOVE_REACTION.Id,
+ PERMISSION_UPLOAD_FILE.Id,
+ PERMISSION_EDIT_POST.Id,
+ PERMISSION_CREATE_POST.Id,
+ PERMISSION_USE_CHANNEL_MENTIONS.Id,
+ PERMISSION_USE_SLASH_COMMANDS.Id,
+ },
+ SchemeManaged: true,
+ BuiltIn: true,
+ }
+
+ roles[CHANNEL_USER_ROLE_ID] = &Role{
+ Name: "channel_user",
+ DisplayName: "authentication.roles.channel_user.name",
+ Description: "authentication.roles.channel_user.description",
+ Permissions: []string{
+ PERMISSION_READ_CHANNEL.Id,
+ PERMISSION_ADD_REACTION.Id,
+ PERMISSION_REMOVE_REACTION.Id,
+ PERMISSION_MANAGE_PUBLIC_CHANNEL_MEMBERS.Id,
+ PERMISSION_UPLOAD_FILE.Id,
+ PERMISSION_GET_PUBLIC_LINK.Id,
+ PERMISSION_CREATE_POST.Id,
+ PERMISSION_USE_CHANNEL_MENTIONS.Id,
+ PERMISSION_USE_SLASH_COMMANDS.Id,
+ },
+ SchemeManaged: true,
+ BuiltIn: true,
+ }
+
+ roles[CHANNEL_ADMIN_ROLE_ID] = &Role{
+ Name: "channel_admin",
+ DisplayName: "authentication.roles.channel_admin.name",
+ Description: "authentication.roles.channel_admin.description",
+ Permissions: []string{
+ PERMISSION_MANAGE_CHANNEL_ROLES.Id,
+ PERMISSION_USE_GROUP_MENTIONS.Id,
+ },
+ SchemeManaged: true,
+ BuiltIn: true,
+ }
+
+ roles[TEAM_GUEST_ROLE_ID] = &Role{
+ Name: "team_guest",
+ DisplayName: "authentication.roles.team_guest.name",
+ Description: "authentication.roles.team_guest.description",
+ Permissions: []string{
+ PERMISSION_VIEW_TEAM.Id,
+ },
+ SchemeManaged: true,
+ BuiltIn: true,
+ }
+
+ roles[TEAM_USER_ROLE_ID] = &Role{
+ Name: "team_user",
+ DisplayName: "authentication.roles.team_user.name",
+ Description: "authentication.roles.team_user.description",
+ Permissions: []string{
+ PERMISSION_LIST_TEAM_CHANNELS.Id,
+ PERMISSION_JOIN_PUBLIC_CHANNELS.Id,
+ PERMISSION_READ_PUBLIC_CHANNEL.Id,
+ PERMISSION_VIEW_TEAM.Id,
+ },
+ SchemeManaged: true,
+ BuiltIn: true,
+ }
+
+ roles[TEAM_POST_ALL_ROLE_ID] = &Role{
+ Name: "team_post_all",
+ DisplayName: "authentication.roles.team_post_all.name",
+ Description: "authentication.roles.team_post_all.description",
+ Permissions: []string{
+ PERMISSION_CREATE_POST.Id,
+ PERMISSION_USE_CHANNEL_MENTIONS.Id,
+ },
+ SchemeManaged: false,
+ BuiltIn: true,
+ }
+
+ roles[TEAM_POST_ALL_PUBLIC_ROLE_ID] = &Role{
+ Name: "team_post_all_public",
+ DisplayName: "authentication.roles.team_post_all_public.name",
+ Description: "authentication.roles.team_post_all_public.description",
+ Permissions: []string{
+ PERMISSION_CREATE_POST_PUBLIC.Id,
+ PERMISSION_USE_CHANNEL_MENTIONS.Id,
+ },
+ SchemeManaged: false,
+ BuiltIn: true,
+ }
+
+ roles[TEAM_ADMIN_ROLE_ID] = &Role{
+ Name: "team_admin",
+ DisplayName: "authentication.roles.team_admin.name",
+ Description: "authentication.roles.team_admin.description",
+ Permissions: []string{
+ PERMISSION_REMOVE_USER_FROM_TEAM.Id,
+ PERMISSION_MANAGE_TEAM.Id,
+ PERMISSION_IMPORT_TEAM.Id,
+ PERMISSION_MANAGE_TEAM_ROLES.Id,
+ PERMISSION_MANAGE_CHANNEL_ROLES.Id,
+ PERMISSION_MANAGE_OTHERS_INCOMING_WEBHOOKS.Id,
+ PERMISSION_MANAGE_OTHERS_OUTGOING_WEBHOOKS.Id,
+ PERMISSION_MANAGE_SLASH_COMMANDS.Id,
+ PERMISSION_MANAGE_OTHERS_SLASH_COMMANDS.Id,
+ PERMISSION_MANAGE_INCOMING_WEBHOOKS.Id,
+ PERMISSION_MANAGE_OUTGOING_WEBHOOKS.Id,
+ },
+ SchemeManaged: true,
+ BuiltIn: true,
+ }
+
+ roles[SYSTEM_GUEST_ROLE_ID] = &Role{
+ Name: "system_guest",
+ DisplayName: "authentication.roles.global_guest.name",
+ Description: "authentication.roles.global_guest.description",
+ Permissions: []string{
+ PERMISSION_CREATE_DIRECT_CHANNEL.Id,
+ PERMISSION_CREATE_GROUP_CHANNEL.Id,
+ },
+ SchemeManaged: true,
+ BuiltIn: true,
+ }
+
+ roles[SYSTEM_USER_ROLE_ID] = &Role{
+ Name: "system_user",
+ DisplayName: "authentication.roles.global_user.name",
+ Description: "authentication.roles.global_user.description",
+ Permissions: []string{
+ PERMISSION_LIST_PUBLIC_TEAMS.Id,
+ PERMISSION_JOIN_PUBLIC_TEAMS.Id,
+ PERMISSION_CREATE_DIRECT_CHANNEL.Id,
+ PERMISSION_CREATE_GROUP_CHANNEL.Id,
+ PERMISSION_VIEW_MEMBERS.Id,
+ },
+ SchemeManaged: true,
+ BuiltIn: true,
+ }
+
+ roles[SYSTEM_POST_ALL_ROLE_ID] = &Role{
+ Name: "system_post_all",
+ DisplayName: "authentication.roles.system_post_all.name",
+ Description: "authentication.roles.system_post_all.description",
+ Permissions: []string{
+ PERMISSION_CREATE_POST.Id,
+ PERMISSION_USE_CHANNEL_MENTIONS.Id,
+ },
+ SchemeManaged: false,
+ BuiltIn: true,
+ }
+
+ roles[SYSTEM_POST_ALL_PUBLIC_ROLE_ID] = &Role{
+ Name: "system_post_all_public",
+ DisplayName: "authentication.roles.system_post_all_public.name",
+ Description: "authentication.roles.system_post_all_public.description",
+ Permissions: []string{
+ PERMISSION_CREATE_POST_PUBLIC.Id,
+ PERMISSION_USE_CHANNEL_MENTIONS.Id,
+ },
+ SchemeManaged: false,
+ BuiltIn: true,
+ }
+
+ roles[SYSTEM_USER_ACCESS_TOKEN_ROLE_ID] = &Role{
+ Name: "system_user_access_token",
+ DisplayName: "authentication.roles.system_user_access_token.name",
+ Description: "authentication.roles.system_user_access_token.description",
+ Permissions: []string{
+ PERMISSION_CREATE_USER_ACCESS_TOKEN.Id,
+ PERMISSION_READ_USER_ACCESS_TOKEN.Id,
+ PERMISSION_REVOKE_USER_ACCESS_TOKEN.Id,
+ },
+ SchemeManaged: false,
+ BuiltIn: true,
+ }
+
+ roles[SYSTEM_ADMIN_ROLE_ID] = &Role{
+ Name: "system_admin",
+ DisplayName: "authentication.roles.global_admin.name",
+ Description: "authentication.roles.global_admin.description",
+ // System admins can do anything channel and team admins can do
+ // plus everything members of teams and channels can do to all teams
+ // and channels on the system
+ Permissions: append(
+ append(
+ append(
+ append(
+ []string{
+ PERMISSION_ASSIGN_SYSTEM_ADMIN_ROLE.Id,
+ PERMISSION_MANAGE_SYSTEM.Id,
+ PERMISSION_MANAGE_ROLES.Id,
+ PERMISSION_MANAGE_PUBLIC_CHANNEL_PROPERTIES.Id,
+ PERMISSION_MANAGE_PUBLIC_CHANNEL_MEMBERS.Id,
+ PERMISSION_MANAGE_PRIVATE_CHANNEL_MEMBERS.Id,
+ PERMISSION_DELETE_PUBLIC_CHANNEL.Id,
+ PERMISSION_CREATE_PUBLIC_CHANNEL.Id,
+ PERMISSION_MANAGE_PRIVATE_CHANNEL_PROPERTIES.Id,
+ PERMISSION_DELETE_PRIVATE_CHANNEL.Id,
+ PERMISSION_CREATE_PRIVATE_CHANNEL.Id,
+ PERMISSION_MANAGE_SYSTEM_WIDE_OAUTH.Id,
+ PERMISSION_MANAGE_OTHERS_INCOMING_WEBHOOKS.Id,
+ PERMISSION_MANAGE_OTHERS_OUTGOING_WEBHOOKS.Id,
+ PERMISSION_EDIT_OTHER_USERS.Id,
+ PERMISSION_EDIT_OTHERS_POSTS.Id,
+ PERMISSION_MANAGE_OAUTH.Id,
+ PERMISSION_INVITE_USER.Id,
+ PERMISSION_INVITE_GUEST.Id,
+ PERMISSION_PROMOTE_GUEST.Id,
+ PERMISSION_DEMOTE_TO_GUEST.Id,
+ PERMISSION_DELETE_POST.Id,
+ PERMISSION_DELETE_OTHERS_POSTS.Id,
+ PERMISSION_CREATE_TEAM.Id,
+ PERMISSION_ADD_USER_TO_TEAM.Id,
+ PERMISSION_LIST_USERS_WITHOUT_TEAM.Id,
+ PERMISSION_MANAGE_JOBS.Id,
+ PERMISSION_CREATE_POST_PUBLIC.Id,
+ PERMISSION_CREATE_POST_EPHEMERAL.Id,
+ PERMISSION_CREATE_USER_ACCESS_TOKEN.Id,
+ PERMISSION_READ_USER_ACCESS_TOKEN.Id,
+ PERMISSION_REVOKE_USER_ACCESS_TOKEN.Id,
+ PERMISSION_CREATE_BOT.Id,
+ PERMISSION_READ_BOTS.Id,
+ PERMISSION_READ_OTHERS_BOTS.Id,
+ PERMISSION_MANAGE_BOTS.Id,
+ PERMISSION_MANAGE_OTHERS_BOTS.Id,
+ PERMISSION_REMOVE_OTHERS_REACTIONS.Id,
+ PERMISSION_LIST_PRIVATE_TEAMS.Id,
+ PERMISSION_JOIN_PRIVATE_TEAMS.Id,
+ PERMISSION_VIEW_MEMBERS.Id,
+ },
+ roles[TEAM_USER_ROLE_ID].Permissions...,
+ ),
+ roles[CHANNEL_USER_ROLE_ID].Permissions...,
+ ),
+ roles[TEAM_ADMIN_ROLE_ID].Permissions...,
+ ),
+ roles[CHANNEL_ADMIN_ROLE_ID].Permissions...,
+ ),
+ SchemeManaged: true,
+ BuiltIn: true,
+ }
+
+ return roles
+}
diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/saml.go b/vendor/github.com/mattermost/mattermost-server/v5/model/saml.go
new file mode 100644
index 00000000..59ac2acc
--- /dev/null
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/saml.go
@@ -0,0 +1,199 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
+
+package model
+
+import (
+ "encoding/json"
+ "encoding/xml"
+ "io"
+ "time"
+)
+
+const (
+ USER_AUTH_SERVICE_SAML = "saml"
+ USER_AUTH_SERVICE_SAML_TEXT = "SAML"
+ USER_AUTH_SERVICE_IS_SAML = "isSaml"
+ USER_AUTH_SERVICE_IS_MOBILE = "isMobile"
+)
+
+type SamlAuthRequest struct {
+ Base64AuthRequest string
+ URL string
+ RelayState string
+}
+
+type SamlCertificateStatus struct {
+ IdpCertificateFile bool `json:"idp_certificate_file"`
+ PrivateKeyFile bool `json:"private_key_file"`
+ PublicCertificateFile bool `json:"public_certificate_file"`
+}
+
+type SamlMetadataResponse struct {
+ IdpDescriptorUrl string `json:"idp_descriptor_url"`
+ IdpUrl string `json:"idp_url"`
+ IdpPublicCertificate string `json:"idp_public_certificate"`
+}
+
+type NameIDFormat struct {
+ XMLName xml.Name
+ Format string `xml:",attr,omitempty"`
+ Value string `xml:",innerxml"`
+}
+
+type NameID struct {
+ NameQualifier string `xml:",attr"`
+ SPNameQualifier string `xml:",attr"`
+ Format string `xml:",attr,omitempty"`
+ SPProvidedID string `xml:",attr"`
+ Value string `xml:",chardata"`
+}
+
+type AttributeValue struct {
+ Type string `xml:"http://www.w3.org/2001/XMLSchema-instance type,attr"`
+ Value string `xml:",chardata"`
+ NameID *NameID
+}
+
+type Attribute struct {
+ XMLName xml.Name
+ FriendlyName string `xml:",attr"`
+ Name string `xml:",attr"`
+ NameFormat string `xml:",attr"`
+ Values []AttributeValue `xml:"AttributeValue"`
+}
+
+type Endpoint struct {
+ XMLName xml.Name
+ Binding string `xml:"Binding,attr"`
+ Location string `xml:"Location,attr"`
+ ResponseLocation string `xml:"ResponseLocation,attr,omitempty"`
+}
+
+type IndexedEndpoint struct {
+ XMLName xml.Name
+ Binding string `xml:"Binding,attr"`
+ Location string `xml:"Location,attr"`
+ ResponseLocation *string `xml:"ResponseLocation,attr,omitempty"`
+ Index int `xml:"index,attr"`
+ IsDefault *bool `xml:"isDefault,attr"`
+}
+
+type IDPSSODescriptor struct {
+ XMLName xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:metadata IDPSSODescriptor"`
+ SSODescriptor
+ WantAuthnRequestsSigned *bool `xml:",attr"`
+
+ SingleSignOnServices []Endpoint `xml:"SingleSignOnService"`
+ NameIDMappingServices []Endpoint `xml:"NameIDMappingService"`
+ AssertionIDRequestServices []Endpoint `xml:"AssertionIDRequestService"`
+ AttributeProfiles []string `xml:"AttributeProfile"`
+ Attributes []Attribute `xml:"Attribute"`
+}
+
+type SSODescriptor struct {
+ XMLName xml.Name
+ RoleDescriptor
+ ArtifactResolutionServices []IndexedEndpoint `xml:"ArtifactResolutionService"`
+ SingleLogoutServices []Endpoint `xml:"SingleLogoutService"`
+ ManageNameIDServices []Endpoint `xml:"ManageNameIDService"`
+ NameIDFormats []NameIDFormat `xml:"NameIDFormat"`
+}
+
+type X509Certificate struct {
+ XMLName xml.Name
+ Cert string `xml:",innerxml"`
+}
+
+type X509Data struct {
+ XMLName xml.Name
+ X509Certificate X509Certificate `xml:"X509Certificate"`
+}
+
+type KeyInfo struct {
+ XMLName xml.Name
+ DS string `xml:"xmlns:ds,attr"`
+ X509Data X509Data `xml:"X509Data"`
+}
+type EncryptionMethod struct {
+ Algorithm string `xml:"Algorithm,attr"`
+}
+
+type KeyDescriptor struct {
+ XMLName xml.Name
+ Use string `xml:"use,attr,omitempty"`
+ KeyInfo KeyInfo `xml:"http://www.w3.org/2000/09/xmldsig# KeyInfo,omitempty"`
+}
+
+type RoleDescriptor struct {
+ XMLName xml.Name
+ ID string `xml:",attr,omitempty"`
+ ValidUntil time.Time `xml:"validUntil,attr,omitempty"`
+ CacheDuration time.Duration `xml:"cacheDuration,attr,omitempty"`
+ ProtocolSupportEnumeration string `xml:"protocolSupportEnumeration,attr"`
+ ErrorURL string `xml:"errorURL,attr,omitempty"`
+ KeyDescriptors []KeyDescriptor `xml:"KeyDescriptor,omitempty"`
+ Organization *Organization `xml:"Organization,omitempty"`
+ ContactPersons []ContactPerson `xml:"ContactPerson,omitempty"`
+}
+
+type ContactPerson struct {
+ XMLName xml.Name
+ ContactType string `xml:"contactType,attr"`
+ Company string
+ GivenName string
+ SurName string
+ EmailAddresses []string `xml:"EmailAddress"`
+ TelephoneNumbers []string `xml:"TelephoneNumber"`
+}
+
+type LocalizedName struct {
+ Lang string `xml:"xml lang,attr"`
+ Value string `xml:",chardata"`
+}
+
+type LocalizedURI struct {
+ Lang string `xml:"xml lang,attr"`
+ Value string `xml:",chardata"`
+}
+
+type Organization struct {
+ XMLName xml.Name
+ OrganizationNames []LocalizedName `xml:"OrganizationName"`
+ OrganizationDisplayNames []LocalizedName `xml:"OrganizationDisplayName"`
+ OrganizationURLs []LocalizedURI `xml:"OrganizationURL"`
+}
+
+type EntityDescriptor struct {
+ XMLName xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:metadata EntityDescriptor"`
+ EntityID string `xml:"entityID,attr"`
+ ID string `xml:",attr,omitempty"`
+ ValidUntil time.Time `xml:"validUntil,attr,omitempty"`
+ CacheDuration time.Duration `xml:"cacheDuration,attr,omitempty"`
+ RoleDescriptors []RoleDescriptor `xml:"RoleDescriptor"`
+ IDPSSODescriptors []IDPSSODescriptor `xml:"IDPSSODescriptor"`
+ Organization Organization `xml:"Organization"`
+ ContactPerson ContactPerson `xml:"ContactPerson"`
+}
+
+func (s *SamlCertificateStatus) ToJson() string {
+ b, _ := json.Marshal(s)
+ return string(b)
+}
+
+func SamlCertificateStatusFromJson(data io.Reader) *SamlCertificateStatus {
+ var status *SamlCertificateStatus
+ json.NewDecoder(data).Decode(&status)
+ return status
+}
+
+func (s *SamlMetadataResponse) ToJson() string {
+ b, _ := json.Marshal(s)
+ return string(b)
+}
+
+func SamlMetadataResponseFromJson(data io.Reader) *SamlMetadataResponse {
+ var status *SamlMetadataResponse
+ json.NewDecoder(data).Decode(&status)
+ return status
+}
diff --git a/vendor/github.com/mattermost/mattermost-server/model/scheduled_task.go b/vendor/github.com/mattermost/mattermost-server/v5/model/scheduled_task.go
index f3529ded..657cc749 100644
--- a/vendor/github.com/mattermost/mattermost-server/model/scheduled_task.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/scheduled_task.go
@@ -1,5 +1,5 @@
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
package model
diff --git a/vendor/github.com/mattermost/mattermost-server/model/scheme.go b/vendor/github.com/mattermost/mattermost-server/v5/model/scheme.go
index 0c38b560..630f14a6 100644
--- a/vendor/github.com/mattermost/mattermost-server/model/scheme.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/scheme.go
@@ -1,5 +1,5 @@
-// Copyright (c) 2018-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
package model
@@ -31,6 +31,8 @@ type Scheme struct {
DefaultTeamUserRole string `json:"default_team_user_role"`
DefaultChannelAdminRole string `json:"default_channel_admin_role"`
DefaultChannelUserRole string `json:"default_channel_user_role"`
+ DefaultTeamGuestRole string `json:"default_team_guest_role"`
+ DefaultChannelGuestRole string `json:"default_channel_guest_role"`
}
type SchemePatch struct {
@@ -51,8 +53,10 @@ type SchemeConveyor struct {
Scope string `json:"scope"`
TeamAdmin string `json:"default_team_admin_role"`
TeamUser string `json:"default_team_user_role"`
+ TeamGuest string `json:"default_team_guest_role"`
ChannelAdmin string `json:"default_channel_admin_role"`
ChannelUser string `json:"default_channel_user_role"`
+ ChannelGuest string `json:"default_channel_guest_role"`
Roles []*Role `json:"roles"`
}
@@ -64,14 +68,17 @@ func (sc *SchemeConveyor) Scheme() *Scheme {
Scope: sc.Scope,
DefaultTeamAdminRole: sc.TeamAdmin,
DefaultTeamUserRole: sc.TeamUser,
+ DefaultTeamGuestRole: sc.TeamGuest,
DefaultChannelAdminRole: sc.ChannelAdmin,
DefaultChannelUserRole: sc.ChannelUser,
+ DefaultChannelGuestRole: sc.ChannelGuest,
}
}
type SchemeRoles struct {
SchemeAdmin bool `json:"scheme_admin"`
SchemeUser bool `json:"scheme_user"`
+ SchemeGuest bool `json:"scheme_guest"`
}
func (scheme *Scheme) ToJson() string {
@@ -100,7 +107,7 @@ func SchemesFromJson(data io.Reader) []*Scheme {
}
func (scheme *Scheme) IsValid() bool {
- if len(scheme.Id) != 26 {
+ if !IsValidId(scheme.Id) {
return false
}
@@ -134,6 +141,10 @@ func (scheme *Scheme) IsValidForCreate() bool {
return false
}
+ if !IsValidRoleName(scheme.DefaultChannelGuestRole) {
+ return false
+ }
+
if scheme.Scope == SCHEME_SCOPE_TEAM {
if !IsValidRoleName(scheme.DefaultTeamAdminRole) {
return false
@@ -142,6 +153,10 @@ func (scheme *Scheme) IsValidForCreate() bool {
if !IsValidRoleName(scheme.DefaultTeamUserRole) {
return false
}
+
+ if !IsValidRoleName(scheme.DefaultTeamGuestRole) {
+ return false
+ }
}
if scheme.Scope == SCHEME_SCOPE_CHANNEL {
@@ -152,6 +167,10 @@ func (scheme *Scheme) IsValidForCreate() bool {
if len(scheme.DefaultTeamUserRole) != 0 {
return false
}
+
+ if len(scheme.DefaultTeamGuestRole) != 0 {
+ return false
+ }
}
return true
diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/search_params.go b/vendor/github.com/mattermost/mattermost-server/v5/model/search_params.go
new file mode 100644
index 00000000..e6dce73c
--- /dev/null
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/search_params.go
@@ -0,0 +1,369 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
+
+package model
+
+import (
+ "regexp"
+ "strings"
+ "time"
+)
+
+var searchTermPuncStart = regexp.MustCompile(`^[^\pL\d\s#"]+`)
+var searchTermPuncEnd = regexp.MustCompile(`[^\pL\d\s*"]+$`)
+
+type SearchParams struct {
+ Terms string
+ ExcludedTerms string
+ IsHashtag bool
+ InChannels []string
+ ExcludedChannels []string
+ FromUsers []string
+ ExcludedUsers []string
+ AfterDate string
+ ExcludedAfterDate string
+ BeforeDate string
+ ExcludedBeforeDate string
+ OnDate string
+ ExcludedDate string
+ OrTerms bool
+ IncludeDeletedChannels bool
+ TimeZoneOffset int
+ // True if this search doesn't originate from a "current user".
+ SearchWithoutUserId bool
+}
+
+// Returns the epoch timestamp of the start of the day specified by SearchParams.AfterDate
+func (p *SearchParams) GetAfterDateMillis() int64 {
+ date, err := time.Parse("2006-01-02", PadDateStringZeros(p.AfterDate))
+ if err != nil {
+ date = time.Now()
+ }
+
+ // travel forward 1 day
+ oneDay := time.Hour * 24
+ afterDate := date.Add(oneDay)
+ return GetStartOfDayMillis(afterDate, p.TimeZoneOffset)
+}
+
+// Returns the epoch timestamp of the start of the day specified by SearchParams.ExcludedAfterDate
+func (p *SearchParams) GetExcludedAfterDateMillis() int64 {
+ date, err := time.Parse("2006-01-02", PadDateStringZeros(p.ExcludedAfterDate))
+ if err != nil {
+ date = time.Now()
+ }
+
+ // travel forward 1 day
+ oneDay := time.Hour * 24
+ afterDate := date.Add(oneDay)
+ return GetStartOfDayMillis(afterDate, p.TimeZoneOffset)
+}
+
+// Returns the epoch timestamp of the end of the day specified by SearchParams.BeforeDate
+func (p *SearchParams) GetBeforeDateMillis() int64 {
+ date, err := time.Parse("2006-01-02", PadDateStringZeros(p.BeforeDate))
+ if err != nil {
+ return 0
+ }
+
+ // travel back 1 day
+ oneDay := time.Hour * -24
+ beforeDate := date.Add(oneDay)
+ return GetEndOfDayMillis(beforeDate, p.TimeZoneOffset)
+}
+
+// Returns the epoch timestamp of the end of the day specified by SearchParams.ExcludedBeforeDate
+func (p *SearchParams) GetExcludedBeforeDateMillis() int64 {
+ date, err := time.Parse("2006-01-02", PadDateStringZeros(p.ExcludedBeforeDate))
+ if err != nil {
+ return 0
+ }
+
+ // travel back 1 day
+ oneDay := time.Hour * -24
+ beforeDate := date.Add(oneDay)
+ return GetEndOfDayMillis(beforeDate, p.TimeZoneOffset)
+}
+
+// Returns the epoch timestamps of the start and end of the day specified by SearchParams.OnDate
+func (p *SearchParams) GetOnDateMillis() (int64, int64) {
+ date, err := time.Parse("2006-01-02", PadDateStringZeros(p.OnDate))
+ if err != nil {
+ return 0, 0
+ }
+
+ return GetStartOfDayMillis(date, p.TimeZoneOffset), GetEndOfDayMillis(date, p.TimeZoneOffset)
+}
+
+// Returns the epoch timestamps of the start and end of the day specified by SearchParams.ExcludedDate
+func (p *SearchParams) GetExcludedDateMillis() (int64, int64) {
+ date, err := time.Parse("2006-01-02", PadDateStringZeros(p.ExcludedDate))
+ if err != nil {
+ return 0, 0
+ }
+
+ return GetStartOfDayMillis(date, p.TimeZoneOffset), GetEndOfDayMillis(date, p.TimeZoneOffset)
+}
+
+var searchFlags = [...]string{"from", "channel", "in", "before", "after", "on"}
+
+type flag struct {
+ name string
+ value string
+ exclude bool
+}
+
+type searchWord struct {
+ value string
+ exclude bool
+}
+
+func splitWords(text string) []string {
+ words := []string{}
+
+ foundQuote := false
+ location := 0
+ for i, char := range text {
+ if char == '"' {
+ if foundQuote {
+ // Grab the quoted section
+ word := text[location : i+1]
+ words = append(words, word)
+ foundQuote = false
+ location = i + 1
+ } else {
+ nextStart := i
+ if i > 0 && text[i-1] == '-' {
+ nextStart = i - 1
+ }
+ words = append(words, strings.Fields(text[location:nextStart])...)
+ foundQuote = true
+ location = nextStart
+ }
+ }
+ }
+
+ words = append(words, strings.Fields(text[location:])...)
+
+ return words
+}
+
+func parseSearchFlags(input []string) ([]searchWord, []flag) {
+ words := []searchWord{}
+ flags := []flag{}
+
+ skipNextWord := false
+ for i, word := range input {
+ if skipNextWord {
+ skipNextWord = false
+ continue
+ }
+
+ isFlag := false
+
+ if colon := strings.Index(word, ":"); colon != -1 {
+ var flagName string
+ var exclude bool
+ if strings.HasPrefix(word, "-") {
+ flagName = word[1:colon]
+ exclude = true
+ } else {
+ flagName = word[:colon]
+ exclude = false
+ }
+
+ value := word[colon+1:]
+
+ for _, searchFlag := range searchFlags {
+ // check for case insensitive equality
+ if strings.EqualFold(flagName, searchFlag) {
+ if value != "" {
+ flags = append(flags, flag{
+ searchFlag,
+ value,
+ exclude,
+ })
+ isFlag = true
+ } else if i < len(input)-1 {
+ flags = append(flags, flag{
+ searchFlag,
+ input[i+1],
+ exclude,
+ })
+ skipNextWord = true
+ isFlag = true
+ }
+
+ if isFlag {
+ break
+ }
+ }
+ }
+ }
+
+ if !isFlag {
+ exclude := false
+ if strings.HasPrefix(word, "-") {
+ exclude = true
+ }
+ // trim off surrounding punctuation (note that we leave trailing asterisks to allow wildcards)
+ word = searchTermPuncStart.ReplaceAllString(word, "")
+ word = searchTermPuncEnd.ReplaceAllString(word, "")
+
+ // and remove extra pound #s
+ word = hashtagStart.ReplaceAllString(word, "#")
+
+ if len(word) != 0 {
+ words = append(words, searchWord{
+ word,
+ exclude,
+ })
+ }
+ }
+ }
+
+ return words, flags
+}
+
+func ParseSearchParams(text string, timeZoneOffset int) []*SearchParams {
+ words, flags := parseSearchFlags(splitWords(text))
+
+ hashtagTermList := []string{}
+ excludedHashtagTermList := []string{}
+ plainTermList := []string{}
+ excludedPlainTermList := []string{}
+
+ for _, word := range words {
+ if validHashtag.MatchString(word.value) {
+ if word.exclude {
+ excludedHashtagTermList = append(excludedHashtagTermList, word.value)
+ } else {
+ hashtagTermList = append(hashtagTermList, word.value)
+ }
+ } else {
+ if word.exclude {
+ excludedPlainTermList = append(excludedPlainTermList, word.value)
+ } else {
+ plainTermList = append(plainTermList, word.value)
+ }
+ }
+ }
+
+ hashtagTerms := strings.Join(hashtagTermList, " ")
+ excludedHashtagTerms := strings.Join(excludedHashtagTermList, " ")
+ plainTerms := strings.Join(plainTermList, " ")
+ excludedPlainTerms := strings.Join(excludedPlainTermList, " ")
+
+ inChannels := []string{}
+ excludedChannels := []string{}
+ fromUsers := []string{}
+ excludedUsers := []string{}
+ afterDate := ""
+ excludedAfterDate := ""
+ beforeDate := ""
+ excludedBeforeDate := ""
+ onDate := ""
+ excludedDate := ""
+
+ for _, flag := range flags {
+ if flag.name == "in" || flag.name == "channel" {
+ if flag.exclude {
+ excludedChannels = append(excludedChannels, flag.value)
+ } else {
+ inChannels = append(inChannels, flag.value)
+ }
+ } else if flag.name == "from" {
+ if flag.exclude {
+ excludedUsers = append(excludedUsers, flag.value)
+ } else {
+ fromUsers = append(fromUsers, flag.value)
+ }
+ } else if flag.name == "after" {
+ if flag.exclude {
+ excludedAfterDate = flag.value
+ } else {
+ afterDate = flag.value
+ }
+ } else if flag.name == "before" {
+ if flag.exclude {
+ excludedBeforeDate = flag.value
+ } else {
+ beforeDate = flag.value
+ }
+ } else if flag.name == "on" {
+ if flag.exclude {
+ excludedDate = flag.value
+ } else {
+ onDate = flag.value
+ }
+ }
+ }
+
+ paramsList := []*SearchParams{}
+
+ if len(plainTerms) > 0 || len(excludedPlainTerms) > 0 {
+ paramsList = append(paramsList, &SearchParams{
+ Terms: plainTerms,
+ ExcludedTerms: excludedPlainTerms,
+ IsHashtag: false,
+ InChannels: inChannels,
+ ExcludedChannels: excludedChannels,
+ FromUsers: fromUsers,
+ ExcludedUsers: excludedUsers,
+ AfterDate: afterDate,
+ ExcludedAfterDate: excludedAfterDate,
+ BeforeDate: beforeDate,
+ ExcludedBeforeDate: excludedBeforeDate,
+ OnDate: onDate,
+ ExcludedDate: excludedDate,
+ TimeZoneOffset: timeZoneOffset,
+ })
+ }
+
+ if len(hashtagTerms) > 0 || len(excludedHashtagTerms) > 0 {
+ paramsList = append(paramsList, &SearchParams{
+ Terms: hashtagTerms,
+ ExcludedTerms: excludedHashtagTerms,
+ IsHashtag: true,
+ InChannels: inChannels,
+ ExcludedChannels: excludedChannels,
+ FromUsers: fromUsers,
+ ExcludedUsers: excludedUsers,
+ AfterDate: afterDate,
+ ExcludedAfterDate: excludedAfterDate,
+ BeforeDate: beforeDate,
+ ExcludedBeforeDate: excludedBeforeDate,
+ OnDate: onDate,
+ ExcludedDate: excludedDate,
+ TimeZoneOffset: timeZoneOffset,
+ })
+ }
+
+ // special case for when no terms are specified but we still have a filter
+ if len(plainTerms) == 0 && len(hashtagTerms) == 0 &&
+ len(excludedPlainTerms) == 0 && len(excludedHashtagTerms) == 0 &&
+ (len(inChannels) != 0 || len(fromUsers) != 0 ||
+ len(excludedChannels) != 0 || len(excludedUsers) != 0 ||
+ len(afterDate) != 0 || len(excludedAfterDate) != 0 ||
+ len(beforeDate) != 0 || len(excludedBeforeDate) != 0 ||
+ len(onDate) != 0 || len(excludedDate) != 0) {
+ paramsList = append(paramsList, &SearchParams{
+ Terms: "",
+ ExcludedTerms: "",
+ IsHashtag: false,
+ InChannels: inChannels,
+ ExcludedChannels: excludedChannels,
+ FromUsers: fromUsers,
+ ExcludedUsers: excludedUsers,
+ AfterDate: afterDate,
+ ExcludedAfterDate: excludedAfterDate,
+ BeforeDate: beforeDate,
+ ExcludedBeforeDate: excludedBeforeDate,
+ OnDate: onDate,
+ ExcludedDate: excludedDate,
+ TimeZoneOffset: timeZoneOffset,
+ })
+ }
+
+ return paramsList
+}
diff --git a/vendor/github.com/mattermost/mattermost-server/model/security_bulletin.go b/vendor/github.com/mattermost/mattermost-server/v5/model/security_bulletin.go
index 958b9c9e..ae66cf30 100644
--- a/vendor/github.com/mattermost/mattermost-server/model/security_bulletin.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/security_bulletin.go
@@ -1,5 +1,5 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// See LICENSE.txt for license information.
package model
diff --git a/vendor/github.com/mattermost/mattermost-server/model/session.go b/vendor/github.com/mattermost/mattermost-server/v5/model/session.go
index d59e9b18..b5567a65 100644
--- a/vendor/github.com/mattermost/mattermost-server/model/session.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/session.go
@@ -1,24 +1,31 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// See LICENSE.txt for license information.
package model
import (
"encoding/json"
"io"
+ "strconv"
"strings"
+
+ "github.com/mattermost/mattermost-server/v5/mlog"
)
const (
SESSION_COOKIE_TOKEN = "MMAUTHTOKEN"
SESSION_COOKIE_USER = "MMUSERID"
+ SESSION_COOKIE_CSRF = "MMCSRF"
SESSION_CACHE_SIZE = 35000
SESSION_PROP_PLATFORM = "platform"
SESSION_PROP_OS = "os"
SESSION_PROP_BROWSER = "browser"
SESSION_PROP_TYPE = "type"
SESSION_PROP_USER_ACCESS_TOKEN_ID = "user_access_token_id"
+ SESSION_PROP_IS_BOT = "is_bot"
+ SESSION_PROP_IS_BOT_VALUE = "true"
SESSION_TYPE_USER_ACCESS_TOKEN = "UserAccessToken"
+ SESSION_PROP_IS_GUEST = "is_guest"
SESSION_ACTIVITY_TIMEOUT = 1000 * 60 * 5 // 5 minutes
SESSION_USER_ACCESS_TOKEN_EXPIRY = 100 * 365 // 100 years
)
@@ -35,6 +42,13 @@ type Session struct {
IsOAuth bool `json:"is_oauth"`
Props StringMap `json:"props"`
TeamMembers []*TeamMember `json:"team_members" db:"-"`
+ Local bool `json:"local" db:"-"`
+}
+
+// Returns true if the session is unrestricted, which should grant it
+// with all permissions. This is used for local mode sessions
+func (me *Session) IsUnrestricted() bool {
+ return me.Local
}
func (me *Session) DeepCopy() *Session {
@@ -128,7 +142,37 @@ func (me *Session) GetTeamByTeamId(teamId string) *TeamMember {
}
func (me *Session) IsMobileApp() bool {
- return len(me.DeviceId) > 0
+ return len(me.DeviceId) > 0 || me.IsMobile()
+}
+
+func (me *Session) IsMobile() bool {
+ val, ok := me.Props[USER_AUTH_SERVICE_IS_MOBILE]
+ if !ok {
+ return false
+ }
+ isMobile, err := strconv.ParseBool(val)
+ if err != nil {
+ mlog.Error("Error parsing boolean property from Session", mlog.Err(err))
+ return false
+ }
+ return isMobile
+}
+
+func (me *Session) IsSaml() bool {
+ val, ok := me.Props[USER_AUTH_SERVICE_IS_SAML]
+ if !ok {
+ return false
+ }
+ isSaml, err := strconv.ParseBool(val)
+ if err != nil {
+ mlog.Error("Error parsing boolean property from Session", mlog.Err(err))
+ return false
+ }
+ return isSaml
+}
+
+func (me *Session) IsSSOLogin() bool {
+ return me.IsOAuth || me.IsSaml()
}
func (me *Session) GetUserRoles() []string {
diff --git a/vendor/github.com/mattermost/mattermost-server/model/slack_attachment.go b/vendor/github.com/mattermost/mattermost-server/v5/model/slack_attachment.go
index 827bf35b..a85c6be2 100644
--- a/vendor/github.com/mattermost/mattermost-server/model/slack_attachment.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/slack_attachment.go
@@ -1,5 +1,5 @@
-// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
package model
@@ -30,10 +30,110 @@ type SlackAttachment struct {
Actions []*PostAction `json:"actions,omitempty"`
}
+func (s *SlackAttachment) Equals(input *SlackAttachment) bool {
+ // Direct comparison of simple types
+
+ if s.Id != input.Id {
+ return false
+ }
+
+ if s.Fallback != input.Fallback {
+ return false
+ }
+
+ if s.Color != input.Color {
+ return false
+ }
+
+ if s.Pretext != input.Pretext {
+ return false
+ }
+
+ if s.AuthorName != input.AuthorName {
+ return false
+ }
+
+ if s.AuthorLink != input.AuthorLink {
+ return false
+ }
+
+ if s.AuthorIcon != input.AuthorIcon {
+ return false
+ }
+
+ if s.Title != input.Title {
+ return false
+ }
+
+ if s.TitleLink != input.TitleLink {
+ return false
+ }
+
+ if s.Text != input.Text {
+ return false
+ }
+
+ if s.ImageURL != input.ImageURL {
+ return false
+ }
+
+ if s.ThumbURL != input.ThumbURL {
+ return false
+ }
+
+ if s.Footer != input.Footer {
+ return false
+ }
+
+ if s.FooterIcon != input.FooterIcon {
+ return false
+ }
+
+ // Compare length & slice values of fields
+ if len(s.Fields) != len(input.Fields) {
+ return false
+ }
+
+ for j := range s.Fields {
+ if !s.Fields[j].Equals(input.Fields[j]) {
+ return false
+ }
+ }
+
+ // Compare length & slice values of actions
+ if len(s.Actions) != len(input.Actions) {
+ return false
+ }
+
+ for j := range s.Actions {
+ if !s.Actions[j].Equals(input.Actions[j]) {
+ return false
+ }
+ }
+
+ return s.Timestamp == input.Timestamp
+}
+
type SlackAttachmentField struct {
- Title string `json:"title"`
- Value interface{} `json:"value"`
- Short bool `json:"short"`
+ Title string `json:"title"`
+ Value interface{} `json:"value"`
+ Short SlackCompatibleBool `json:"short"`
+}
+
+func (s *SlackAttachmentField) Equals(input *SlackAttachmentField) bool {
+ if s.Title != input.Title {
+ return false
+ }
+
+ if s.Value != input.Value {
+ return false
+ }
+
+ if s.Short != input.Short {
+ return false
+ }
+
+ return true
}
func StringifySlackFieldValue(a []*SlackAttachment) []*SlackAttachment {
@@ -64,9 +164,17 @@ func StringifySlackFieldValue(a []*SlackAttachment) []*SlackAttachment {
// This method only parses and processes the attachments,
// all else should be set in the post which is passed
func ParseSlackAttachment(post *Post, attachments []*SlackAttachment) {
- post.Type = POST_SLACK_ATTACHMENT
+ if post.Type == "" {
+ post.Type = POST_SLACK_ATTACHMENT
+ }
+
+ postAttachments := []*SlackAttachment{}
for _, attachment := range attachments {
+ if attachment == nil {
+ continue
+ }
+
attachment.Text = ParseSlackLinksToMarkdown(attachment.Text)
attachment.Pretext = ParseSlackLinksToMarkdown(attachment.Pretext)
@@ -75,8 +183,9 @@ func ParseSlackAttachment(post *Post, attachments []*SlackAttachment) {
field.Value = ParseSlackLinksToMarkdown(value)
}
}
+ postAttachments = append(postAttachments, attachment)
}
- post.AddProp("attachments", attachments)
+ post.AddProp("attachments", postAttachments)
}
func ParseSlackLinksToMarkdown(text string) string {
diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/slack_compatibility.go b/vendor/github.com/mattermost/mattermost-server/v5/model/slack_compatibility.go
new file mode 100644
index 00000000..2d3e2878
--- /dev/null
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/slack_compatibility.go
@@ -0,0 +1,30 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
+
+package model
+
+import (
+ "fmt"
+ "strings"
+)
+
+// SlackCompatibleBool is an alias for bool that implements json.Unmarshaler
+type SlackCompatibleBool bool
+
+// UnmarshalJSON implements json.Unmarshaler
+//
+// Slack allows bool values to be represented as strings ("true"/"false") or
+// literals (true/false). To maintain compatibility, we define an Unmarshaler
+// that supports both.
+func (b *SlackCompatibleBool) UnmarshalJSON(data []byte) error {
+ value := strings.ToLower(string(data))
+ if value == "true" || value == `"true"` {
+ *b = true
+ } else if value == "false" || value == `"false"` {
+ *b = false
+ } else {
+ return fmt.Errorf("unmarshal: unable to convert %s to bool", data)
+ }
+
+ return nil
+}
diff --git a/vendor/github.com/mattermost/mattermost-server/model/status.go b/vendor/github.com/mattermost/mattermost-server/v5/model/status.go
index 7888c60a..741fa1ed 100644
--- a/vendor/github.com/mattermost/mattermost-server/model/status.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/status.go
@@ -1,5 +1,5 @@
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
package model
@@ -28,10 +28,9 @@ type Status struct {
}
func (o *Status) ToJson() string {
- tempChannelId := o.ActiveChannel
- o.ActiveChannel = ""
- b, _ := json.Marshal(o)
- o.ActiveChannel = tempChannelId
+ oCopy := *o
+ oCopy.ActiveChannel = ""
+ b, _ := json.Marshal(oCopy)
return string(b)
}
@@ -47,18 +46,14 @@ func StatusFromJson(data io.Reader) *Status {
}
func StatusListToJson(u []*Status) string {
- activeChannels := make([]string, len(u))
- for index, s := range u {
- activeChannels[index] = s.ActiveChannel
- s.ActiveChannel = ""
- }
-
- b, _ := json.Marshal(u)
-
- for index, s := range u {
- s.ActiveChannel = activeChannels[index]
+ uCopy := make([]Status, len(u))
+ for i, s := range u {
+ sCopy := *s
+ sCopy.ActiveChannel = ""
+ uCopy[i] = sCopy
}
+ b, _ := json.Marshal(uCopy)
return string(b)
}
diff --git a/vendor/github.com/mattermost/mattermost-server/model/suggest_command.go b/vendor/github.com/mattermost/mattermost-server/v5/model/suggest_command.go
index 44f46bf7..45a7af38 100644
--- a/vendor/github.com/mattermost/mattermost-server/model/suggest_command.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/suggest_command.go
@@ -1,5 +1,5 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// See LICENSE.txt for license information.
package model
diff --git a/vendor/github.com/mattermost/mattermost-server/model/switch_request.go b/vendor/github.com/mattermost/mattermost-server/v5/model/switch_request.go
index 2a522f49..0ec4db7d 100644
--- a/vendor/github.com/mattermost/mattermost-server/model/switch_request.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/switch_request.go
@@ -1,5 +1,5 @@
-// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
package model
diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/system.go b/vendor/github.com/mattermost/mattermost-server/v5/model/system.go
new file mode 100644
index 00000000..4c3132e2
--- /dev/null
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/system.go
@@ -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"
+ "math/big"
+)
+
+const (
+ SYSTEM_DIAGNOSTIC_ID = "DiagnosticId"
+ SYSTEM_RAN_UNIT_TESTS = "RanUnitTests"
+ SYSTEM_LAST_SECURITY_TIME = "LastSecurityTime"
+ SYSTEM_ACTIVE_LICENSE_ID = "ActiveLicenseId"
+ SYSTEM_LAST_COMPLIANCE_TIME = "LastComplianceTime"
+ SYSTEM_ASYMMETRIC_SIGNING_KEY = "AsymmetricSigningKey"
+ SYSTEM_POST_ACTION_COOKIE_SECRET = "PostActionCookieSecret"
+ SYSTEM_INSTALLATION_DATE_KEY = "InstallationDate"
+ SYSTEM_FIRST_SERVER_RUN_TIMESTAMP_KEY = "FirstServerRunTimestamp"
+)
+
+type System struct {
+ Name string `json:"name"`
+ Value string `json:"value"`
+}
+
+func (o *System) ToJson() string {
+ b, _ := json.Marshal(o)
+ return string(b)
+}
+
+func SystemFromJson(data io.Reader) *System {
+ var o *System
+ json.NewDecoder(data).Decode(&o)
+ return o
+}
+
+type SystemPostActionCookieSecret struct {
+ Secret []byte `json:"key,omitempty"`
+}
+
+type SystemAsymmetricSigningKey struct {
+ ECDSAKey *SystemECDSAKey `json:"ecdsa_key,omitempty"`
+}
+
+type SystemECDSAKey struct {
+ Curve string `json:"curve"`
+ X *big.Int `json:"x"`
+ Y *big.Int `json:"y"`
+ D *big.Int `json:"d,omitempty"`
+}
+
+// ServerBusyState provides serialization for app.Busy.
+type ServerBusyState struct {
+ Busy bool `json:"busy"`
+ Expires int64 `json:"expires"`
+ Expires_ts string `json:"expires_ts,omitempty"`
+}
+
+func (sbs *ServerBusyState) ToJson() string {
+ b, _ := json.Marshal(sbs)
+ return string(b)
+}
+
+func ServerBusyStateFromJson(r io.Reader) *ServerBusyState {
+ var sbs *ServerBusyState
+ json.NewDecoder(r).Decode(&sbs)
+ return sbs
+}
diff --git a/vendor/github.com/mattermost/mattermost-server/model/team.go b/vendor/github.com/mattermost/mattermost-server/v5/model/team.go
index eadd0522..381eb8bb 100644
--- a/vendor/github.com/mattermost/mattermost-server/model/team.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/team.go
@@ -1,5 +1,5 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// See LICENSE.txt for license information.
package model
@@ -41,15 +41,16 @@ type Team struct {
AllowOpenInvite bool `json:"allow_open_invite"`
LastTeamIconUpdate int64 `json:"last_team_icon_update,omitempty"`
SchemeId *string `json:"scheme_id"`
+ GroupConstrained *bool `json:"group_constrained"`
}
type TeamPatch struct {
- DisplayName *string `json:"display_name"`
- Description *string `json:"description"`
- CompanyName *string `json:"company_name"`
- AllowedDomains *string `json:"allowed_domains"`
- InviteId *string `json:"invite_id"`
- AllowOpenInvite *bool `json:"allow_open_invite"`
+ DisplayName *string `json:"display_name"`
+ Description *string `json:"description"`
+ CompanyName *string `json:"company_name"`
+ AllowedDomains *string `json:"allowed_domains"`
+ AllowOpenInvite *bool `json:"allow_open_invite"`
+ GroupConstrained *bool `json:"group_constrained"`
}
type TeamForExport struct {
@@ -61,6 +62,11 @@ type Invites struct {
Invites []map[string]string `json:"invites"`
}
+type TeamsWithCount struct {
+ Teams []*Team `json:"teams"`
+ TotalCount int64 `json:"total_count"`
+}
+
func InvitesFromJson(data io.Reader) *Invites {
var o *Invites
json.NewDecoder(data).Decode(&o)
@@ -107,6 +113,17 @@ func TeamListToJson(t []*Team) string {
return string(b)
}
+func TeamsWithCountToJson(tlc *TeamsWithCount) []byte {
+ b, _ := json.Marshal(tlc)
+ return b
+}
+
+func TeamsWithCountFromJson(data io.Reader) *TeamsWithCount {
+ var twc *TeamsWithCount
+ json.NewDecoder(data).Decode(&twc)
+ return twc
+}
+
func TeamListFromJson(data io.Reader) []*Team {
var teams []*Team
json.NewDecoder(data).Decode(&teams)
@@ -119,7 +136,7 @@ func (o *Team) Etag() string {
func (o *Team) IsValid() *AppError {
- if len(o.Id) != 26 {
+ if !IsValidId(o.Id) {
return NewAppError("Team.IsValid", "model.team.is_valid.id.app_error", nil, "", http.StatusBadRequest)
}
@@ -151,6 +168,10 @@ func (o *Team) IsValid() *AppError {
return NewAppError("Team.IsValid", "model.team.is_valid.description.app_error", nil, "id="+o.Id, http.StatusBadRequest)
}
+ if len(o.InviteId) == 0 {
+ return NewAppError("Team.IsValid", "model.team.is_valid.invite_id.app_error", nil, "id="+o.Id, http.StatusBadRequest)
+ }
+
if IsReservedTeamName(o.Name) {
return NewAppError("Team.IsValid", "model.team.is_valid.reserved.app_error", nil, "id="+o.Id, http.StatusBadRequest)
}
@@ -182,6 +203,11 @@ func (o *Team) PreSave() {
o.CreateAt = GetMillis()
o.UpdateAt = o.CreateAt
+ o.Name = SanitizeUnicode(o.Name)
+ o.DisplayName = SanitizeUnicode(o.DisplayName)
+ o.Description = SanitizeUnicode(o.Description)
+ o.CompanyName = SanitizeUnicode(o.CompanyName)
+
if len(o.InviteId) == 0 {
o.InviteId = NewId()
}
@@ -189,6 +215,10 @@ func (o *Team) PreSave() {
func (o *Team) PreUpdate() {
o.UpdateAt = GetMillis()
+ o.Name = SanitizeUnicode(o.Name)
+ o.DisplayName = SanitizeUnicode(o.DisplayName)
+ o.Description = SanitizeUnicode(o.Description)
+ o.CompanyName = SanitizeUnicode(o.CompanyName)
}
func IsReservedTeamName(s string) bool {
@@ -204,7 +234,6 @@ func IsReservedTeamName(s string) bool {
}
func IsValidTeamName(s string) bool {
-
if !IsValidAlphaNum(s) {
return false
}
@@ -247,34 +276,39 @@ func CleanTeamName(s string) string {
func (o *Team) Sanitize() {
o.Email = ""
+ o.InviteId = ""
}
-func (t *Team) Patch(patch *TeamPatch) {
+func (o *Team) Patch(patch *TeamPatch) {
if patch.DisplayName != nil {
- t.DisplayName = *patch.DisplayName
+ o.DisplayName = *patch.DisplayName
}
if patch.Description != nil {
- t.Description = *patch.Description
+ o.Description = *patch.Description
}
if patch.CompanyName != nil {
- t.CompanyName = *patch.CompanyName
+ o.CompanyName = *patch.CompanyName
}
if patch.AllowedDomains != nil {
- t.AllowedDomains = *patch.AllowedDomains
+ o.AllowedDomains = *patch.AllowedDomains
}
- if patch.InviteId != nil {
- t.InviteId = *patch.InviteId
+ if patch.AllowOpenInvite != nil {
+ o.AllowOpenInvite = *patch.AllowOpenInvite
}
- if patch.AllowOpenInvite != nil {
- t.AllowOpenInvite = *patch.AllowOpenInvite
+ if patch.GroupConstrained != nil {
+ o.GroupConstrained = patch.GroupConstrained
}
}
+func (o *Team) IsGroupConstrained() bool {
+ return o.GroupConstrained != nil && *o.GroupConstrained
+}
+
func (t *TeamPatch) ToJson() string {
b, err := json.Marshal(t)
if err != nil {
diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/team_member.go b/vendor/github.com/mattermost/mattermost-server/v5/model/team_member.go
new file mode 100644
index 00000000..b747f17c
--- /dev/null
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/team_member.go
@@ -0,0 +1,186 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
+
+package model
+
+import (
+ "encoding/json"
+ "fmt"
+ "io"
+ "net/http"
+ "strings"
+)
+
+const (
+ USERNAME = "Username"
+)
+
+type TeamMember struct {
+ TeamId string `json:"team_id"`
+ UserId string `json:"user_id"`
+ Roles string `json:"roles"`
+ DeleteAt int64 `json:"delete_at"`
+ SchemeGuest bool `json:"scheme_guest"`
+ SchemeUser bool `json:"scheme_user"`
+ SchemeAdmin bool `json:"scheme_admin"`
+ ExplicitRoles string `json:"explicit_roles"`
+}
+
+type TeamUnread struct {
+ TeamId string `json:"team_id"`
+ MsgCount int64 `json:"msg_count"`
+ MentionCount int64 `json:"mention_count"`
+}
+
+type TeamMemberForExport struct {
+ TeamMember
+ TeamName string
+}
+
+type TeamMemberWithError struct {
+ UserId string `json:"user_id"`
+ Member *TeamMember `json:"member"`
+ Error *AppError `json:"error"`
+}
+
+type EmailInviteWithError struct {
+ Email string `json:"email"`
+ Error *AppError `json:"error"`
+}
+
+type TeamMembersGetOptions struct {
+ // Sort the team members. Accepts "Username", but defaults to "Id".
+ Sort string
+
+ // If true, exclude team members whose corresponding user is deleted.
+ ExcludeDeletedUsers bool
+
+ // Restrict to search in a list of teams and channels
+ ViewRestrictions *ViewUsersRestrictions
+}
+
+func (o *TeamMember) ToJson() string {
+ b, _ := json.Marshal(o)
+ return string(b)
+}
+
+func (o *TeamUnread) ToJson() string {
+ b, _ := json.Marshal(o)
+ return string(b)
+}
+
+func TeamMemberFromJson(data io.Reader) *TeamMember {
+ var o *TeamMember
+ json.NewDecoder(data).Decode(&o)
+ return o
+}
+
+func TeamUnreadFromJson(data io.Reader) *TeamUnread {
+ var o *TeamUnread
+ json.NewDecoder(data).Decode(&o)
+ return o
+}
+
+func EmailInviteWithErrorFromJson(data io.Reader) []*EmailInviteWithError {
+ var o []*EmailInviteWithError
+ json.NewDecoder(data).Decode(&o)
+ return o
+}
+
+func EmailInviteWithErrorToEmails(o []*EmailInviteWithError) []string {
+ var ret []string
+ for _, o := range o {
+ if o.Error == nil {
+ ret = append(ret, o.Email)
+ }
+ }
+ return ret
+}
+
+func EmailInviteWithErrorToJson(o []*EmailInviteWithError) string {
+ if b, err := json.Marshal(o); err != nil {
+ return "[]"
+ } else {
+ return string(b)
+ }
+}
+
+func EmailInviteWithErrorToString(o *EmailInviteWithError) string {
+ return fmt.Sprintf("%s:%s", o.Email, o.Error.Error())
+}
+
+func TeamMembersWithErrorToTeamMembers(o []*TeamMemberWithError) []*TeamMember {
+ var ret []*TeamMember
+ for _, o := range o {
+ if o.Error == nil {
+ ret = append(ret, o.Member)
+ }
+ }
+ return ret
+}
+
+func TeamMembersWithErrorToJson(o []*TeamMemberWithError) string {
+ if b, err := json.Marshal(o); err != nil {
+ return "[]"
+ } else {
+ return string(b)
+ }
+}
+
+func TeamMemberWithErrorToString(o *TeamMemberWithError) string {
+ return fmt.Sprintf("%s:%s", o.UserId, o.Error.Error())
+}
+
+func TeamMembersWithErrorFromJson(data io.Reader) []*TeamMemberWithError {
+ var o []*TeamMemberWithError
+ json.NewDecoder(data).Decode(&o)
+ return o
+}
+
+func TeamMembersToJson(o []*TeamMember) string {
+ if b, err := json.Marshal(o); err != nil {
+ return "[]"
+ } else {
+ return string(b)
+ }
+}
+
+func TeamMembersFromJson(data io.Reader) []*TeamMember {
+ var o []*TeamMember
+ json.NewDecoder(data).Decode(&o)
+ return o
+}
+
+func TeamsUnreadToJson(o []*TeamUnread) string {
+ if b, err := json.Marshal(o); err != nil {
+ return "[]"
+ } else {
+ return string(b)
+ }
+}
+
+func TeamsUnreadFromJson(data io.Reader) []*TeamUnread {
+ var o []*TeamUnread
+ json.NewDecoder(data).Decode(&o)
+ return o
+}
+
+func (o *TeamMember) IsValid() *AppError {
+
+ if !IsValidId(o.TeamId) {
+ return NewAppError("TeamMember.IsValid", "model.team_member.is_valid.team_id.app_error", nil, "", http.StatusBadRequest)
+ }
+
+ if !IsValidId(o.UserId) {
+ return NewAppError("TeamMember.IsValid", "model.team_member.is_valid.user_id.app_error", nil, "", http.StatusBadRequest)
+ }
+
+ return nil
+}
+
+func (o *TeamMember) PreUpdate() {
+}
+
+func (o *TeamMember) GetRoles() []string {
+ return strings.Fields(o.Roles)
+}
diff --git a/vendor/github.com/mattermost/mattermost-server/model/team_search.go b/vendor/github.com/mattermost/mattermost-server/v5/model/team_search.go
index e0676022..b8b1fe30 100644
--- a/vendor/github.com/mattermost/mattermost-server/model/team_search.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/team_search.go
@@ -1,5 +1,5 @@
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
package model
@@ -9,12 +9,18 @@ import (
)
type TeamSearch struct {
- Term string `json:"term"`
+ Term string `json:"term"`
+ Page *int `json:"page,omitempty"`
+ PerPage *int `json:"per_page,omitempty"`
+}
+
+func (t *TeamSearch) IsPaginated() bool {
+ return t.Page != nil && t.PerPage != nil
}
// ToJson convert a TeamSearch to json string
-func (c *TeamSearch) ToJson() string {
- b, err := json.Marshal(c)
+func (t *TeamSearch) ToJson() string {
+ b, err := json.Marshal(t)
if err != nil {
return ""
}
diff --git a/vendor/github.com/mattermost/mattermost-server/model/team_stats.go b/vendor/github.com/mattermost/mattermost-server/v5/model/team_stats.go
index 0d688b80..9209a0cf 100644
--- a/vendor/github.com/mattermost/mattermost-server/model/team_stats.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/team_stats.go
@@ -1,5 +1,5 @@
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
package model
diff --git a/vendor/github.com/mattermost/mattermost-server/model/terms_of_service.go b/vendor/github.com/mattermost/mattermost-server/v5/model/terms_of_service.go
index c99a7856..8ce5d350 100644
--- a/vendor/github.com/mattermost/mattermost-server/model/terms_of_service.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/terms_of_service.go
@@ -1,5 +1,5 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// See LICENSE.txt for license information.
package model
@@ -11,7 +11,6 @@ import (
"unicode/utf8"
)
-// we only ever need the latest version of terms of service
const TERMS_OF_SERVICE_CACHE_SIZE = 1
type TermsOfService struct {
@@ -22,7 +21,7 @@ type TermsOfService struct {
}
func (t *TermsOfService) IsValid() *AppError {
- if len(t.Id) != 26 {
+ if !IsValidId(t.Id) {
return InvalidTermsOfServiceError("id", "")
}
@@ -30,7 +29,7 @@ func (t *TermsOfService) IsValid() *AppError {
return InvalidTermsOfServiceError("create_at", t.Id)
}
- if len(t.UserId) != 26 {
+ if !IsValidId(t.UserId) {
return InvalidTermsOfServiceError("user_id", t.Id)
}
@@ -58,7 +57,7 @@ func InvalidTermsOfServiceError(fieldName string, termsOfServiceId string) *AppE
if termsOfServiceId != "" {
details = "terms_of_service_id=" + termsOfServiceId
}
- return NewAppError("TermsOfServiceStore.IsValid", id, map[string]interface{}{"MaxLength": POST_MESSAGE_MAX_RUNES_V2}, details, http.StatusBadRequest)
+ return NewAppError("TermsOfService.IsValid", id, map[string]interface{}{"MaxLength": POST_MESSAGE_MAX_RUNES_V2}, details, http.StatusBadRequest)
}
func (t *TermsOfService) PreSave() {
diff --git a/vendor/github.com/mattermost/mattermost-server/model/token.go b/vendor/github.com/mattermost/mattermost-server/v5/model/token.go
index a4d10c7f..0730778c 100644
--- a/vendor/github.com/mattermost/mattermost-server/model/token.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/token.go
@@ -1,5 +1,5 @@
-// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
package model
@@ -7,7 +7,7 @@ import "net/http"
const (
TOKEN_SIZE = 64
- MAX_TOKEN_EXIPRY_TIME = 1000 * 60 * 60 * 24 // 24 hour
+ MAX_TOKEN_EXIPRY_TIME = 1000 * 60 * 60 * 48 // 48 hour
TOKEN_TYPE_OAUTH = "oauth"
)
diff --git a/vendor/github.com/mattermost/mattermost-server/model/user.go b/vendor/github.com/mattermost/mattermost-server/v5/model/user.go
index 51f54c1b..168605ad 100644
--- a/vendor/github.com/mattermost/mattermost-server/model/user.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/user.go
@@ -1,37 +1,48 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// See LICENSE.txt for license information.
package model
import (
+ "crypto/sha256"
"encoding/json"
"fmt"
"io"
+ "io/ioutil"
+ "math/rand"
"net/http"
"regexp"
+ "sort"
"strings"
+ "time"
"unicode/utf8"
+ "github.com/mattermost/mattermost-server/v5/services/timezones"
"golang.org/x/crypto/bcrypt"
+ "golang.org/x/text/language"
)
const (
- ME = "me"
- USER_NOTIFY_ALL = "all"
- USER_NOTIFY_MENTION = "mention"
- USER_NOTIFY_NONE = "none"
- DESKTOP_NOTIFY_PROP = "desktop"
- DESKTOP_SOUND_NOTIFY_PROP = "desktop_sound"
- MARK_UNREAD_NOTIFY_PROP = "mark_unread"
- PUSH_NOTIFY_PROP = "push"
- PUSH_STATUS_NOTIFY_PROP = "push_status"
- EMAIL_NOTIFY_PROP = "email"
- CHANNEL_MENTIONS_NOTIFY_PROP = "channel"
- COMMENTS_NOTIFY_PROP = "comments"
- MENTION_KEYS_NOTIFY_PROP = "mention_keys"
- COMMENTS_NOTIFY_NEVER = "never"
- COMMENTS_NOTIFY_ROOT = "root"
- COMMENTS_NOTIFY_ANY = "any"
+ ME = "me"
+ USER_NOTIFY_ALL = "all"
+ USER_NOTIFY_HERE = "here"
+ USER_NOTIFY_MENTION = "mention"
+ USER_NOTIFY_NONE = "none"
+ DESKTOP_NOTIFY_PROP = "desktop"
+ DESKTOP_SOUND_NOTIFY_PROP = "desktop_sound"
+ MARK_UNREAD_NOTIFY_PROP = "mark_unread"
+ PUSH_NOTIFY_PROP = "push"
+ PUSH_STATUS_NOTIFY_PROP = "push_status"
+ EMAIL_NOTIFY_PROP = "email"
+ CHANNEL_MENTIONS_NOTIFY_PROP = "channel"
+ COMMENTS_NOTIFY_PROP = "comments"
+ MENTION_KEYS_NOTIFY_PROP = "mention_keys"
+ COMMENTS_NOTIFY_NEVER = "never"
+ COMMENTS_NOTIFY_ROOT = "root"
+ COMMENTS_NOTIFY_ANY = "any"
+ FIRST_NAME_NOTIFY_PROP = "first_name"
+ AUTO_RESPONDER_ACTIVE_NOTIFY_PROP = "auto_responder_active"
+ AUTO_RESPONDER_MESSAGE_NOTIFY_PROP = "auto_responder_message"
DEFAULT_LOCALE = "en"
USER_AUTH_SERVICE_EMAIL = "email"
@@ -45,40 +56,51 @@ const (
USER_NAME_MAX_LENGTH = 64
USER_NAME_MIN_LENGTH = 1
USER_PASSWORD_MAX_LENGTH = 72
+ USER_LOCALE_MAX_LENGTH = 5
)
type User struct {
- Id string `json:"id"`
- CreateAt int64 `json:"create_at,omitempty"`
- UpdateAt int64 `json:"update_at,omitempty"`
- DeleteAt int64 `json:"delete_at"`
- Username string `json:"username"`
- Password string `json:"password,omitempty"`
- AuthData *string `json:"auth_data,omitempty"`
- AuthService string `json:"auth_service"`
- Email string `json:"email"`
- EmailVerified bool `json:"email_verified,omitempty"`
- Nickname string `json:"nickname"`
- FirstName string `json:"first_name"`
- LastName string `json:"last_name"`
- Position string `json:"position"`
- Roles string `json:"roles"`
- AllowMarketing bool `json:"allow_marketing,omitempty"`
- Props StringMap `json:"props,omitempty"`
- NotifyProps StringMap `json:"notify_props,omitempty"`
- LastPasswordUpdate int64 `json:"last_password_update,omitempty"`
- LastPictureUpdate int64 `json:"last_picture_update,omitempty"`
- FailedAttempts int `json:"failed_attempts,omitempty"`
- Locale string `json:"locale"`
- Timezone StringMap `json:"timezone"`
- MfaActive bool `json:"mfa_active,omitempty"`
- MfaSecret string `json:"mfa_secret,omitempty"`
- LastActivityAt int64 `db:"-" json:"last_activity_at,omitempty"`
- AcceptedTermsOfServiceId string `json:"accepted_terms_of_service_id,omitempty"` // TODO remove this field when new TOS user action table is created
+ Id string `json:"id"`
+ CreateAt int64 `json:"create_at,omitempty"`
+ UpdateAt int64 `json:"update_at,omitempty"`
+ DeleteAt int64 `json:"delete_at"`
+ Username string `json:"username"`
+ Password string `json:"password,omitempty"`
+ AuthData *string `json:"auth_data,omitempty"`
+ AuthService string `json:"auth_service"`
+ Email string `json:"email"`
+ EmailVerified bool `json:"email_verified,omitempty"`
+ Nickname string `json:"nickname"`
+ FirstName string `json:"first_name"`
+ LastName string `json:"last_name"`
+ Position string `json:"position"`
+ Roles string `json:"roles"`
+ AllowMarketing bool `json:"allow_marketing,omitempty"`
+ Props StringMap `json:"props,omitempty"`
+ NotifyProps StringMap `json:"notify_props,omitempty"`
+ LastPasswordUpdate int64 `json:"last_password_update,omitempty"`
+ LastPictureUpdate int64 `json:"last_picture_update,omitempty"`
+ FailedAttempts int `json:"failed_attempts,omitempty"`
+ Locale string `json:"locale"`
+ Timezone StringMap `json:"timezone"`
+ MfaActive bool `json:"mfa_active,omitempty"`
+ MfaSecret string `json:"mfa_secret,omitempty"`
+ LastActivityAt int64 `db:"-" json:"last_activity_at,omitempty"`
+ IsBot bool `db:"-" json:"is_bot,omitempty"`
+ BotDescription string `db:"-" json:"bot_description,omitempty"`
+ BotLastIconUpdate int64 `db:"-" json:"bot_last_icon_update,omitempty"`
+ TermsOfServiceId string `db:"-" json:"terms_of_service_id,omitempty"`
+ TermsOfServiceCreateAt int64 `db:"-" json:"terms_of_service_create_at,omitempty"`
+}
+
+type UserUpdate struct {
+ Old *User
+ New *User
}
type UserPatch struct {
Username *string `json:"username"`
+ Password *string `json:"password,omitempty"`
Nickname *string `json:"nickname"`
FirstName *string `json:"first_name"`
LastName *string `json:"last_name"`
@@ -96,6 +118,105 @@ type UserAuth struct {
AuthService string `json:"auth_service,omitempty"`
}
+type UserForIndexing struct {
+ Id string `json:"id"`
+ Username string `json:"username"`
+ Nickname string `json:"nickname"`
+ FirstName string `json:"first_name"`
+ LastName string `json:"last_name"`
+ CreateAt int64 `json:"create_at"`
+ DeleteAt int64 `json:"delete_at"`
+ TeamsIds []string `json:"team_id"`
+ ChannelsIds []string `json:"channel_id"`
+}
+
+type ViewUsersRestrictions struct {
+ Teams []string
+ Channels []string
+}
+
+func (r *ViewUsersRestrictions) Hash() string {
+ if r == nil {
+ return ""
+ }
+ ids := append(r.Teams, r.Channels...)
+ sort.Strings(ids)
+ hash := sha256.New()
+ hash.Write([]byte(strings.Join(ids, "")))
+ return fmt.Sprintf("%x", hash.Sum(nil))
+}
+
+type UserSlice []*User
+
+func (u UserSlice) Usernames() []string {
+ usernames := []string{}
+ for _, user := range u {
+ usernames = append(usernames, user.Username)
+ }
+ sort.Strings(usernames)
+ return usernames
+}
+
+func (u UserSlice) IDs() []string {
+ ids := []string{}
+ for _, user := range u {
+ ids = append(ids, user.Id)
+ }
+ return ids
+}
+
+func (u UserSlice) FilterWithoutBots() UserSlice {
+ var matches []*User
+
+ for _, user := range u {
+ if !user.IsBot {
+ matches = append(matches, user)
+ }
+ }
+ return UserSlice(matches)
+}
+
+func (u UserSlice) FilterByActive(active bool) UserSlice {
+ var matches []*User
+
+ for _, user := range u {
+ if user.DeleteAt == 0 && active {
+ matches = append(matches, user)
+ } else if user.DeleteAt != 0 && !active {
+ matches = append(matches, user)
+ }
+ }
+ return UserSlice(matches)
+}
+
+func (u UserSlice) FilterByID(ids []string) UserSlice {
+ var matches []*User
+ for _, user := range u {
+ for _, id := range ids {
+ if id == user.Id {
+ matches = append(matches, user)
+ }
+ }
+ }
+ return UserSlice(matches)
+}
+
+func (u UserSlice) FilterWithoutID(ids []string) UserSlice {
+ var keep []*User
+ for _, user := range u {
+ present := false
+ for _, id := range ids {
+ if id == user.Id {
+ present = true
+ }
+ }
+ if !present {
+ keep = append(keep, user)
+ }
+ }
+ return UserSlice(keep)
+}
+
func (u *User) DeepCopy() *User {
copyUser := *u
if u.AuthData != nil {
@@ -117,7 +238,7 @@ func (u *User) DeepCopy() *User {
// correctly.
func (u *User) IsValid() *AppError {
- if len(u.Id) != 26 {
+ if !IsValidId(u.Id) {
return InvalidUserError("id", "")
}
@@ -169,6 +290,10 @@ func (u *User) IsValid() *AppError {
return InvalidUserError("password_limit", u.Id)
}
+ if !IsValidLocale(u.Locale) {
+ return InvalidUserError("locale", u.Id)
+ }
+
return nil
}
@@ -205,6 +330,11 @@ func (u *User) PreSave() {
u.AuthData = nil
}
+ u.Username = SanitizeUnicode(u.Username)
+ u.FirstName = SanitizeUnicode(u.FirstName)
+ u.LastName = SanitizeUnicode(u.LastName)
+ u.Nickname = SanitizeUnicode(u.Nickname)
+
u.Username = NormalizeUsername(u.Username)
u.Email = NormalizeEmail(u.Email)
@@ -228,7 +358,7 @@ func (u *User) PreSave() {
}
if u.Timezone == nil {
- u.Timezone = DefaultUserTimezone()
+ u.Timezone = timezones.DefaultUserTimezone()
}
if len(u.Password) > 0 {
@@ -238,57 +368,83 @@ func (u *User) PreSave() {
// PreUpdate should be run before updating the user in the db.
func (u *User) PreUpdate() {
+ u.Username = SanitizeUnicode(u.Username)
+ u.FirstName = SanitizeUnicode(u.FirstName)
+ u.LastName = SanitizeUnicode(u.LastName)
+ u.Nickname = SanitizeUnicode(u.Nickname)
+ u.BotDescription = SanitizeUnicode(u.BotDescription)
+
u.Username = NormalizeUsername(u.Username)
u.Email = NormalizeEmail(u.Email)
u.UpdateAt = GetMillis()
+ u.FirstName = SanitizeUnicode(u.FirstName)
+ u.LastName = SanitizeUnicode(u.LastName)
+ u.Nickname = SanitizeUnicode(u.Nickname)
+ u.BotDescription = SanitizeUnicode(u.BotDescription)
+
if u.AuthData != nil && *u.AuthData == "" {
u.AuthData = nil
}
if u.NotifyProps == nil || len(u.NotifyProps) == 0 {
u.SetDefaultNotifications()
- } else if _, ok := u.NotifyProps["mention_keys"]; ok {
+ } else if _, ok := u.NotifyProps[MENTION_KEYS_NOTIFY_PROP]; ok {
// Remove any blank mention keys
- splitKeys := strings.Split(u.NotifyProps["mention_keys"], ",")
+ splitKeys := strings.Split(u.NotifyProps[MENTION_KEYS_NOTIFY_PROP], ",")
goodKeys := []string{}
for _, key := range splitKeys {
if len(key) > 0 {
goodKeys = append(goodKeys, strings.ToLower(key))
}
}
- u.NotifyProps["mention_keys"] = strings.Join(goodKeys, ",")
+ u.NotifyProps[MENTION_KEYS_NOTIFY_PROP] = strings.Join(goodKeys, ",")
}
}
func (u *User) SetDefaultNotifications() {
u.NotifyProps = make(map[string]string)
- u.NotifyProps["email"] = "true"
- u.NotifyProps["push"] = USER_NOTIFY_MENTION
- u.NotifyProps["desktop"] = USER_NOTIFY_MENTION
- u.NotifyProps["desktop_sound"] = "true"
- u.NotifyProps["mention_keys"] = u.Username + ",@" + u.Username
- u.NotifyProps["channel"] = "true"
- u.NotifyProps["push_status"] = STATUS_AWAY
- u.NotifyProps["comments"] = "never"
- u.NotifyProps["first_name"] = "false"
-}
-
-func (user *User) UpdateMentionKeysFromUsername(oldUsername string) {
+ u.NotifyProps[EMAIL_NOTIFY_PROP] = "true"
+ u.NotifyProps[PUSH_NOTIFY_PROP] = USER_NOTIFY_MENTION
+ u.NotifyProps[DESKTOP_NOTIFY_PROP] = USER_NOTIFY_MENTION
+ u.NotifyProps[DESKTOP_SOUND_NOTIFY_PROP] = "true"
+ u.NotifyProps[MENTION_KEYS_NOTIFY_PROP] = ""
+ u.NotifyProps[CHANNEL_MENTIONS_NOTIFY_PROP] = "true"
+ u.NotifyProps[PUSH_STATUS_NOTIFY_PROP] = STATUS_AWAY
+ u.NotifyProps[COMMENTS_NOTIFY_PROP] = COMMENTS_NOTIFY_NEVER
+ u.NotifyProps[FIRST_NAME_NOTIFY_PROP] = "false"
+}
+
+func (u *User) UpdateMentionKeysFromUsername(oldUsername string) {
nonUsernameKeys := []string{}
- splitKeys := strings.Split(user.NotifyProps["mention_keys"], ",")
- for _, key := range splitKeys {
+ for _, key := range u.GetMentionKeys() {
if key != oldUsername && key != "@"+oldUsername {
nonUsernameKeys = append(nonUsernameKeys, key)
}
}
- user.NotifyProps["mention_keys"] = user.Username + ",@" + user.Username
+ u.NotifyProps[MENTION_KEYS_NOTIFY_PROP] = ""
if len(nonUsernameKeys) > 0 {
- user.NotifyProps["mention_keys"] += "," + strings.Join(nonUsernameKeys, ",")
+ u.NotifyProps[MENTION_KEYS_NOTIFY_PROP] += "," + strings.Join(nonUsernameKeys, ",")
}
}
+func (u *User) GetMentionKeys() []string {
+ var keys []string
+
+ for _, key := range strings.Split(u.NotifyProps[MENTION_KEYS_NOTIFY_PROP], ",") {
+ trimmedKey := strings.TrimSpace(key)
+
+ if trimmedKey == "" {
+ continue
+ }
+
+ keys = append(keys, trimmedKey)
+ }
+
+ return keys
+}
+
func (u *User) Patch(patch *UserPatch) {
if patch.Username != nil {
u.Username = *patch.Username
@@ -349,7 +505,7 @@ func (u *UserAuth) ToJson() string {
// Generate a valid strong etag so the browser can cache the results
func (u *User) Etag(showFullName, showEmail bool) string {
- return Etag(u.Id, u.UpdateAt, showFullName, showEmail)
+ return Etag(u.Id, u.UpdateAt, u.TermsOfServiceId, u.TermsOfServiceCreateAt, showFullName, showEmail, u.BotLastIconUpdate)
}
// Remove any private data from the user object
@@ -373,6 +529,20 @@ func (u *User) Sanitize(options map[string]bool) {
}
}
+// Remove any input data from the user object that is not user controlled
+func (u *User) SanitizeInput(isAdmin bool) {
+ if !isAdmin {
+ u.AuthData = NewString("")
+ u.AuthService = ""
+ }
+ u.LastPasswordUpdate = 0
+ u.LastPictureUpdate = 0
+ u.FailedAttempts = 0
+ u.EmailVerified = false
+ u.MfaActive = false
+ u.MfaSecret = ""
+}
+
func (u *User) ClearNonProfileFields() {
u.Password = ""
u.AuthData = NewString("")
@@ -418,8 +588,8 @@ func (u *User) GetFullName() string {
}
}
-func (u *User) GetDisplayName(nameFormat string) string {
- displayName := u.Username
+func (u *User) getDisplayName(baseName, nameFormat string) string {
+ displayName := baseName
if nameFormat == SHOW_NICKNAME_FULLNAME {
if len(u.Nickname) > 0 {
@@ -436,6 +606,18 @@ func (u *User) GetDisplayName(nameFormat string) string {
return displayName
}
+func (u *User) GetDisplayName(nameFormat string) string {
+ displayName := u.Username
+
+ return u.getDisplayName(displayName, nameFormat)
+}
+
+func (u *User) GetDisplayNameWithPrefix(nameFormat, prefix string) string {
+ displayName := prefix + u.Username
+
+ return u.getDisplayName(displayName, nameFormat)
+}
+
func (u *User) GetRoles() []string {
return strings.Fields(u.Roles)
}
@@ -464,6 +646,16 @@ func IsValidUserRoles(userRoles string) bool {
// Make sure you acually want to use this function. In context.go there are functions to check permissions
// This function should not be used to check permissions.
+func (u *User) IsGuest() bool {
+ return IsInRole(u.Roles, SYSTEM_GUEST_ROLE_ID)
+}
+
+func (u *User) IsSystemAdmin() bool {
+ return IsInRole(u.Roles, SYSTEM_ADMIN_ROLE_ID)
+}
+
+// Make sure you acually want to use this function. In context.go there are functions to check permissions
+// This function should not be used to check permissions.
func (u *User) IsInRole(inRole string) bool {
return IsInRole(u.Roles, inRole)
}
@@ -499,11 +691,7 @@ func (u *User) IsSAMLUser() bool {
}
func (u *User) GetPreferredTimezone() string {
- if u.Timezone["useAutomaticTimezone"] == "true" {
- return u.Timezone["automaticTimezone"]
- }
-
- return u.Timezone["manualTimezone"]
+ return GetPreferredTimezone(u.Timezone)
}
// UserFromJson will decode the input and return a User
@@ -639,3 +827,77 @@ func IsValidCommentsNotifyLevel(notifyLevel string) bool {
notifyLevel == COMMENTS_NOTIFY_ROOT ||
notifyLevel == COMMENTS_NOTIFY_NEVER
}
+
+func IsValidEmailBatchingInterval(emailInterval string) bool {
+ return emailInterval == PREFERENCE_EMAIL_INTERVAL_IMMEDIATELY ||
+ emailInterval == PREFERENCE_EMAIL_INTERVAL_FIFTEEN ||
+ emailInterval == PREFERENCE_EMAIL_INTERVAL_HOUR
+}
+
+func IsValidLocale(locale string) bool {
+ if locale != "" {
+ if len(locale) > USER_LOCALE_MAX_LENGTH {
+ return false
+ } else if _, err := language.Parse(locale); err != nil {
+ return false
+ }
+ }
+
+ return true
+}
+
+type UserWithGroups struct {
+ User
+ GroupIDs *string `json:"-"`
+ Groups []*Group `json:"groups"`
+ SchemeGuest bool `json:"scheme_guest"`
+ SchemeUser bool `json:"scheme_user"`
+ SchemeAdmin bool `json:"scheme_admin"`
+}
+
+func (u *UserWithGroups) GetGroupIDs() []string {
+ if u.GroupIDs == nil {
+ return nil
+ }
+ trimmed := strings.TrimSpace(*u.GroupIDs)
+ if len(trimmed) == 0 {
+ return nil
+ }
+ return strings.Split(trimmed, ",")
+}
+
+type UsersWithGroupsAndCount struct {
+ Users []*UserWithGroups `json:"users"`
+ Count int64 `json:"total_count"`
+}
+
+func UsersWithGroupsAndCountFromJson(data io.Reader) *UsersWithGroupsAndCount {
+ uwg := &UsersWithGroupsAndCount{}
+ bodyBytes, _ := ioutil.ReadAll(data)
+ json.Unmarshal(bodyBytes, uwg)
+ return uwg
+}
+
+var passwordRandomSource = rand.NewSource(time.Now().Unix())
+var passwordSpecialChars = "!$%^&*(),."
+var passwordNumbers = "0123456789"
+var passwordUpperCaseLetters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+var passwordLowerCaseLetters = "abcdefghijklmnopqrstuvwxyz"
+var passwordAllChars = passwordSpecialChars + passwordNumbers + passwordUpperCaseLetters + passwordLowerCaseLetters
+
+func GeneratePassword(minimumLength int) string {
+ r := rand.New(passwordRandomSource)
+
+ // Make sure we are guaranteed at least one of each type to meet any possible password complexity requirements.
+ password := string([]rune(passwordUpperCaseLetters)[r.Intn(len(passwordUpperCaseLetters))]) +
+ string([]rune(passwordNumbers)[r.Intn(len(passwordNumbers))]) +
+ string([]rune(passwordLowerCaseLetters)[r.Intn(len(passwordLowerCaseLetters))]) +
+ string([]rune(passwordSpecialChars)[r.Intn(len(passwordSpecialChars))])
+
+ for len(password) < minimumLength {
+ i := r.Intn(len(passwordAllChars))
+ password = password + string([]rune(passwordAllChars)[i])
+ }
+
+ return password
+}
diff --git a/vendor/github.com/mattermost/mattermost-server/model/user_access_token.go b/vendor/github.com/mattermost/mattermost-server/v5/model/user_access_token.go
index bffd9fcb..f458a6d9 100644
--- a/vendor/github.com/mattermost/mattermost-server/model/user_access_token.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/user_access_token.go
@@ -1,5 +1,5 @@
-// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
package model
@@ -18,7 +18,7 @@ type UserAccessToken struct {
}
func (t *UserAccessToken) IsValid() *AppError {
- if len(t.Id) != 26 {
+ if !IsValidId(t.Id) {
return NewAppError("UserAccessToken.IsValid", "model.user_access_token.is_valid.id.app_error", nil, "", http.StatusBadRequest)
}
@@ -26,7 +26,7 @@ func (t *UserAccessToken) IsValid() *AppError {
return NewAppError("UserAccessToken.IsValid", "model.user_access_token.is_valid.token.app_error", nil, "", http.StatusBadRequest)
}
- if len(t.UserId) != 26 {
+ if !IsValidId(t.UserId) {
return NewAppError("UserAccessToken.IsValid", "model.user_access_token.is_valid.user_id.app_error", nil, "", http.StatusBadRequest)
}
diff --git a/vendor/github.com/mattermost/mattermost-server/model/user_access_token_search.go b/vendor/github.com/mattermost/mattermost-server/v5/model/user_access_token_search.go
index 1b0146ed..a692f692 100644
--- a/vendor/github.com/mattermost/mattermost-server/model/user_access_token_search.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/user_access_token_search.go
@@ -1,5 +1,5 @@
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
package model
diff --git a/vendor/github.com/mattermost/mattermost-server/model/user_autocomplete.go b/vendor/github.com/mattermost/mattermost-server/v5/model/user_autocomplete.go
index b5edb45b..48a892e2 100644
--- a/vendor/github.com/mattermost/mattermost-server/model/user_autocomplete.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/user_autocomplete.go
@@ -1,5 +1,5 @@
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
package model
diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/user_count.go b/vendor/github.com/mattermost/mattermost-server/v5/model/user_count.go
new file mode 100644
index 00000000..3c20b23a
--- /dev/null
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/user_count.go
@@ -0,0 +1,18 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
+
+package model
+
+// Options for counting users
+type UserCountOptions struct {
+ // Should include users that are bots
+ IncludeBotAccounts bool
+ // Should include deleted users (of any type)
+ IncludeDeleted bool
+ // Exclude regular users
+ ExcludeRegularUsers bool
+ // Only include users on a specific team. "" for any team.
+ TeamId string
+ // Restrict to search in a list of teams and channels
+ ViewRestrictions *ViewUsersRestrictions
+}
diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/user_get.go b/vendor/github.com/mattermost/mattermost-server/v5/model/user_get.go
new file mode 100644
index 00000000..f865d53c
--- /dev/null
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/user_get.go
@@ -0,0 +1,38 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
+
+package model
+
+type UserGetOptions struct {
+ // Filters the users in the team
+ InTeamId string
+ // Filters the users not in the team
+ NotInTeamId string
+ // Filters the users in the channel
+ InChannelId string
+ // Filters the users not in the channel
+ NotInChannelId string
+ // Filters the users group constrained
+ GroupConstrained bool
+ // Filters the users without a team
+ WithoutTeam bool
+ // Filters the inactive users
+ Inactive bool
+ // Filters the active users
+ Active bool
+ // Filters for the given role
+ Role string
+ // Sorting option
+ Sort string
+ // Restrict to search in a list of teams and channels
+ ViewRestrictions *ViewUsersRestrictions
+ // Page
+ Page int
+ // Page size
+ PerPage int
+}
+
+type UserGetByIdsOptions struct {
+ // Since filters the users based on their UpdateAt timestamp.
+ Since int64
+}
diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/user_search.go b/vendor/github.com/mattermost/mattermost-server/v5/model/user_search.go
new file mode 100644
index 00000000..fa9fa8a2
--- /dev/null
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/user_search.go
@@ -0,0 +1,67 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
+
+package model
+
+import (
+ "encoding/json"
+ "io"
+)
+
+const USER_SEARCH_MAX_LIMIT = 1000
+const USER_SEARCH_DEFAULT_LIMIT = 100
+
+// UserSearch captures the parameters provided by a client for initiating a user search.
+type UserSearch struct {
+ Term string `json:"term"`
+ TeamId string `json:"team_id"`
+ NotInTeamId string `json:"not_in_team_id"`
+ InChannelId string `json:"in_channel_id"`
+ NotInChannelId string `json:"not_in_channel_id"`
+ GroupConstrained bool `json:"group_constrained"`
+ AllowInactive bool `json:"allow_inactive"`
+ WithoutTeam bool `json:"without_team"`
+ Limit int `json:"limit"`
+ Role string `json:"role"`
+}
+
+// ToJson convert a User to a json string
+func (u *UserSearch) ToJson() []byte {
+ b, _ := json.Marshal(u)
+ return b
+}
+
+// UserSearchFromJson will decode the input and return a User
+func UserSearchFromJson(data io.Reader) *UserSearch {
+ us := UserSearch{}
+ json.NewDecoder(data).Decode(&us)
+
+ if us.Limit == 0 {
+ us.Limit = USER_SEARCH_DEFAULT_LIMIT
+ }
+
+ return &us
+}
+
+// UserSearchOptions captures internal parameters derived from the user's permissions and a
+// UserSearch request.
+type UserSearchOptions struct {
+ // IsAdmin tracks whether or not the search is being conducted by an administrator.
+ IsAdmin bool
+ // AllowEmails allows search to examine the emails of users.
+ AllowEmails bool
+ // AllowFullNames allows search to examine the full names of users, vs. just usernames and nicknames.
+ AllowFullNames bool
+ // AllowInactive configures whether or not to return inactive users in the search results.
+ AllowInactive bool
+ // Narrows the search to the group constrained users
+ GroupConstrained bool
+ // Limit limits the total number of results returned.
+ Limit int
+ // Filters for the given role
+ Role string
+ // Restrict to search in a list of teams and channels
+ ViewRestrictions *ViewUsersRestrictions
+ // List of allowed channels
+ ListOfAllowedChannels []string
+}
diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/user_terms_of_service.go b/vendor/github.com/mattermost/mattermost-server/v5/model/user_terms_of_service.go
new file mode 100644
index 00000000..9a0f4f18
--- /dev/null
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/user_terms_of_service.go
@@ -0,0 +1,61 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
+
+package model
+
+import (
+ "encoding/json"
+ "fmt"
+ "io"
+ "net/http"
+)
+
+type UserTermsOfService struct {
+ UserId string `json:"user_id"`
+ TermsOfServiceId string `json:"terms_of_service_id"`
+ CreateAt int64 `json:"create_at"`
+}
+
+func (ut *UserTermsOfService) IsValid() *AppError {
+ if !IsValidId(ut.UserId) {
+ return InvalidUserTermsOfServiceError("user_id", ut.UserId)
+ }
+
+ if !IsValidId(ut.TermsOfServiceId) {
+ return InvalidUserTermsOfServiceError("terms_of_service_id", ut.UserId)
+ }
+
+ if ut.CreateAt == 0 {
+ return InvalidUserTermsOfServiceError("create_at", ut.UserId)
+ }
+
+ return nil
+}
+
+func (ut *UserTermsOfService) ToJson() string {
+ b, _ := json.Marshal(ut)
+ return string(b)
+}
+
+func (ut *UserTermsOfService) PreSave() {
+ if ut.UserId == "" {
+ ut.UserId = NewId()
+ }
+
+ ut.CreateAt = GetMillis()
+}
+
+func UserTermsOfServiceFromJson(data io.Reader) *UserTermsOfService {
+ var userTermsOfService *UserTermsOfService
+ json.NewDecoder(data).Decode(&userTermsOfService)
+ return userTermsOfService
+}
+
+func InvalidUserTermsOfServiceError(fieldName string, userTermsOfServiceId string) *AppError {
+ id := fmt.Sprintf("model.user_terms_of_service.is_valid.%s.app_error", fieldName)
+ details := ""
+ if userTermsOfServiceId != "" {
+ details = "user_terms_of_service_user_id=" + userTermsOfServiceId
+ }
+ return NewAppError("UserTermsOfService.IsValid", id, nil, details, http.StatusBadRequest)
+}
diff --git a/vendor/github.com/mattermost/mattermost-server/model/users_stats.go b/vendor/github.com/mattermost/mattermost-server/v5/model/users_stats.go
index 49c882e3..3e18296e 100644
--- a/vendor/github.com/mattermost/mattermost-server/model/users_stats.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/users_stats.go
@@ -1,5 +1,5 @@
-// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
package model
diff --git a/vendor/github.com/mattermost/mattermost-server/model/utils.go b/vendor/github.com/mattermost/mattermost-server/v5/model/utils.go
index 172b7824..e75fb022 100644
--- a/vendor/github.com/mattermost/mattermost-server/model/utils.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/utils.go
@@ -1,5 +1,5 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// See LICENSE.txt for license information.
package model
@@ -21,7 +21,7 @@ import (
"time"
"unicode"
- goi18n "github.com/nicksnyder/go-i18n/i18n"
+ goi18n "github.com/mattermost/go-i18n/i18n"
"github.com/pborman/uuid"
)
@@ -36,6 +36,22 @@ type StringInterface map[string]interface{}
type StringMap map[string]string
type StringArray []string
+func (sa StringArray) Equals(input StringArray) bool {
+
+ if len(sa) != len(input) {
+ return false
+ }
+
+ for index := range sa {
+
+ if sa[index] != input[index] {
+ return false
+ }
+ }
+
+ return true
+}
+
var translateFunc goi18n.TranslateFunc = nil
func AppErrorInit(t goi18n.TranslateFunc) {
@@ -130,15 +146,29 @@ func NewId() string {
return b.String()
}
+// NewRandomTeamName is a NewId that will be a valid team name.
+func NewRandomTeamName() string {
+ teamName := NewId()
+ for IsReservedTeamName(teamName) {
+ teamName = NewId()
+ }
+ return teamName
+}
+
+// NewRandomString returns a random string of the given length.
+// The resulting entropy will be (5 * length) bits.
func NewRandomString(length int) string {
- var b bytes.Buffer
- str := make([]byte, length+8)
- rand.Read(str)
- encoder := base32.NewEncoder(encoding, &b)
- encoder.Write(str)
- encoder.Close()
- b.Truncate(length) // removes the '==' padding
- return b.String()
+ data := make([]byte, 1+(length*5/8))
+ rand.Read(data)
+ return encoding.EncodeToString(data)[:length]
+}
+
+// NewRandomBase32String returns a base32 encoded string of a random slice
+// of bytes of the given size. The resulting entropy will be (8 * size) bits.
+func NewRandomBase32String(size int) string {
+ data := make([]byte, size)
+ rand.Read(data)
+ return base32.StdEncoding.EncodeToString(data)
}
// GetMillis is a convenience method to get milliseconds since epoch.
@@ -191,7 +221,7 @@ func MapToJson(objmap map[string]string) string {
return string(b)
}
-// MapToJson converts a map to a json string
+// MapBoolToJson converts a map to a json string
func MapBoolToJson(objmap map[string]bool) string {
b, _ := json.Marshal(objmap)
return string(b)
@@ -286,16 +316,35 @@ func StringFromJson(data io.Reader) string {
}
}
-func GetServerIpAddress() string {
- if addrs, err := net.InterfaceAddrs(); err != nil {
- return ""
+func GetServerIpAddress(iface string) string {
+ var addrs []net.Addr
+ if len(iface) == 0 {
+ var err error
+ addrs, err = net.InterfaceAddrs()
+ if err != nil {
+ return ""
+ }
} else {
- for _, addr := range addrs {
-
- if ip, ok := addr.(*net.IPNet); ok && !ip.IP.IsLoopback() && !ip.IP.IsLinkLocalUnicast() && !ip.IP.IsLinkLocalMulticast() {
- if ip.IP.To4() != nil {
- return ip.IP.String()
+ interfaces, err := net.Interfaces()
+ if err != nil {
+ return ""
+ }
+ for _, i := range interfaces {
+ if i.Name == iface {
+ addrs, err = i.Addrs()
+ if err != nil {
+ return ""
}
+ break
+ }
+ }
+ }
+
+ for _, addr := range addrs {
+
+ if ip, ok := addr.(*net.IPNet); ok && !ip.IP.IsLoopback() && !ip.IP.IsLinkLocalUnicast() && !ip.IP.IsLinkLocalMulticast() {
+ if ip.IP.To4() != nil {
+ return ip.IP.String()
}
}
}
@@ -323,13 +372,20 @@ func IsValidEmail(email string) bool {
}
var reservedName = []string{
- "signup",
- "login",
"admin",
- "channel",
- "post",
"api",
+ "channel",
+ "claim",
+ "error",
+ "help",
+ "landing",
+ "login",
+ "mfa",
"oauth",
+ "plug",
+ "plugins",
+ "post",
+ "signup",
}
func IsValidChannelIdentifier(s string) bool {
@@ -564,3 +620,84 @@ func IsDomainName(s string) bool {
return ok
}
+
+func RemoveDuplicateStrings(in []string) []string {
+ out := []string{}
+ seen := make(map[string]bool, len(in))
+
+ for _, item := range in {
+ if !seen[item] {
+ out = append(out, item)
+
+ seen[item] = true
+ }
+ }
+
+ return out
+}
+
+func GetPreferredTimezone(timezone StringMap) string {
+ if timezone["useAutomaticTimezone"] == "true" {
+ return timezone["automaticTimezone"]
+ }
+
+ return timezone["manualTimezone"]
+}
+
+// IsSamlFile checks if filename is a SAML file.
+func IsSamlFile(saml *SamlSettings, filename string) bool {
+ return filename == *saml.PublicCertificateFile || filename == *saml.PrivateKeyFile || filename == *saml.IdpCertificateFile
+}
+
+func AsStringBoolMap(list []string) map[string]bool {
+ listMap := map[string]bool{}
+ for _, p := range list {
+ listMap[p] = true
+ }
+ return listMap
+}
+
+// SanitizeUnicode will remove undesirable Unicode characters from a string.
+func SanitizeUnicode(s string) string {
+ return strings.Map(filterBlacklist, s)
+}
+
+// filterBlacklist returns `r` if it is not in the blacklist, otherwise drop (-1).
+// Blacklist is taken from https://www.w3.org/TR/unicode-xml/#Charlist
+func filterBlacklist(r rune) rune {
+ const drop = -1
+ switch r {
+ case '\u0340', '\u0341': // clones of grave and acute; deprecated in Unicode
+ return drop
+ case '\u17A3', '\u17D3': // obsolete characters for Khmer; deprecated in Unicode
+ return drop
+ case '\u2028', '\u2029': // line and paragraph separator
+ return drop
+ case '\u202A', '\u202B', '\u202C', '\u202D', '\u202E': // BIDI embedding controls
+ return drop
+ case '\u206A', '\u206B': // activate/inhibit symmetric swapping; deprecated in Unicode
+ return drop
+ case '\u206C', '\u206D': // activate/inhibit Arabic form shaping; deprecated in Unicode
+ return drop
+ case '\u206E', '\u206F': // activate/inhibit national digit shapes; deprecated in Unicode
+ return drop
+ case '\uFFF9', '\uFFFA', '\uFFFB': // interlinear annotation characters
+ return drop
+ case '\uFEFF': // byte order mark
+ return drop
+ case '\uFFFC': // object replacement character
+ return drop
+ }
+
+ // Scoping for musical notation
+ if r >= 0x0001D173 && r <= 0x0001D17A {
+ return drop
+ }
+
+ // Language tag code points
+ if r >= 0x000E0000 && r <= 0x000E007F {
+ return drop
+ }
+
+ return r
+}
diff --git a/vendor/github.com/mattermost/mattermost-server/model/version.go b/vendor/github.com/mattermost/mattermost-server/v5/model/version.go
index 1b09b0ad..3cefff8c 100644
--- a/vendor/github.com/mattermost/mattermost-server/model/version.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/version.go
@@ -1,5 +1,5 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// See LICENSE.txt for license information.
package model
@@ -13,6 +13,26 @@ import (
// It should be maintained in chronological order with most current
// release at the front of the list.
var versions = []string{
+ "5.25.0",
+ "5.24.0",
+ "5.23.0",
+ "5.22.0",
+ "5.21.0",
+ "5.20.0",
+ "5.19.0",
+ "5.18.0",
+ "5.17.0",
+ "5.16.0",
+ "5.15.0",
+ "5.14.0",
+ "5.13.0",
+ "5.12.0",
+ "5.11.0",
+ "5.10.0",
+ "5.9.0",
+ "5.8.0",
+ "5.7.0",
+ "5.6.0",
"5.5.0",
"5.4.0",
"5.3.0",
diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/websocket_client.go b/vendor/github.com/mattermost/mattermost-server/v5/model/websocket_client.go
new file mode 100644
index 00000000..72ca4a8f
--- /dev/null
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/websocket_client.go
@@ -0,0 +1,321 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
+
+package model
+
+import (
+ "bytes"
+ "encoding/json"
+ "net/http"
+ "sync/atomic"
+ "time"
+
+ "github.com/gorilla/websocket"
+)
+
+const (
+ SOCKET_MAX_MESSAGE_SIZE_KB = 8 * 1024 // 8KB
+ PING_TIMEOUT_BUFFER_SECONDS = 5
+)
+
+type msgType int
+
+const (
+ msgTypeJSON msgType = iota + 1
+ msgTypePong
+)
+
+type writeMessage struct {
+ msgType msgType
+ data interface{}
+}
+
+const avgReadMsgSizeBytes = 1024
+
+// WebSocketClient stores the necessary information required to
+// communicate with a WebSocket endpoint.
+// A client must read from PingTimeoutChannel, EventChannel and ResponseChannel to prevent
+// deadlocks from occuring in the program.
+type WebSocketClient struct {
+ Url string // The location of the server like "ws://localhost:8065"
+ ApiUrl string // The API location of the server like "ws://localhost:8065/api/v3"
+ ConnectUrl string // The WebSocket URL to connect to like "ws://localhost:8065/api/v3/path/to/websocket"
+ Conn *websocket.Conn // The WebSocket connection
+ AuthToken string // The token used to open the WebSocket connection
+ Sequence int64 // The ever-incrementing sequence attached to each WebSocket action
+ PingTimeoutChannel chan bool // The channel used to signal ping timeouts
+ EventChannel chan *WebSocketEvent // The channel used to receive various events pushed from the server. For example: typing, posted
+ ResponseChannel chan *WebSocketResponse // The channel used to receive responses for requests made to the server
+ ListenError *AppError // A field that is set if there was an abnormal closure of the WebSocket connection
+ writeChan chan writeMessage
+
+ pingTimeoutTimer *time.Timer
+ quitPingWatchdog chan struct{}
+
+ quitWriterChan chan struct{}
+ resetTimerChan chan struct{}
+ closed int32
+}
+
+// NewWebSocketClient constructs a new WebSocket client with convenience
+// methods for talking to the server.
+func NewWebSocketClient(url, authToken string) (*WebSocketClient, *AppError) {
+ return NewWebSocketClientWithDialer(websocket.DefaultDialer, url, authToken)
+}
+
+// NewWebSocketClientWithDialer constructs a new WebSocket client with convenience
+// methods for talking to the server using a custom dialer.
+func NewWebSocketClientWithDialer(dialer *websocket.Dialer, url, authToken string) (*WebSocketClient, *AppError) {
+ conn, _, err := dialer.Dial(url+API_URL_SUFFIX+"/websocket", nil)
+ if err != nil {
+ return nil, NewAppError("NewWebSocketClient", "model.websocket_client.connect_fail.app_error", nil, err.Error(), http.StatusInternalServerError)
+ }
+
+ client := &WebSocketClient{
+ Url: url,
+ ApiUrl: url + API_URL_SUFFIX,
+ ConnectUrl: url + API_URL_SUFFIX + "/websocket",
+ Conn: conn,
+ AuthToken: authToken,
+ Sequence: 1,
+ PingTimeoutChannel: make(chan bool, 1),
+ EventChannel: make(chan *WebSocketEvent, 100),
+ ResponseChannel: make(chan *WebSocketResponse, 100),
+ writeChan: make(chan writeMessage),
+ quitPingWatchdog: make(chan struct{}),
+ quitWriterChan: make(chan struct{}),
+ resetTimerChan: make(chan struct{}),
+ }
+
+ client.configurePingHandling()
+ go client.writer()
+
+ client.SendMessage(WEBSOCKET_AUTHENTICATION_CHALLENGE, map[string]interface{}{"token": authToken})
+
+ return client, nil
+}
+
+// NewWebSocketClient4 constructs a new WebSocket client with convenience
+// methods for talking to the server. Uses the v4 endpoint.
+func NewWebSocketClient4(url, authToken string) (*WebSocketClient, *AppError) {
+ return NewWebSocketClient4WithDialer(websocket.DefaultDialer, url, authToken)
+}
+
+// NewWebSocketClient4WithDialer constructs a new WebSocket client with convenience
+// methods for talking to the server using a custom dialer. Uses the v4 endpoint.
+func NewWebSocketClient4WithDialer(dialer *websocket.Dialer, url, authToken string) (*WebSocketClient, *AppError) {
+ return NewWebSocketClientWithDialer(dialer, url, authToken)
+}
+
+// Connect creates a websocket connection with the given ConnectUrl.
+// This is racy and error-prone should not be used. Use any of the New* functions to create a websocket.
+func (wsc *WebSocketClient) Connect() *AppError {
+ return wsc.ConnectWithDialer(websocket.DefaultDialer)
+}
+
+// ConnectWithDialer creates a websocket connection with the given ConnectUrl using the dialer.
+// This is racy and error-prone and should not be used. Use any of the New* functions to create a websocket.
+func (wsc *WebSocketClient) ConnectWithDialer(dialer *websocket.Dialer) *AppError {
+ var err error
+ wsc.Conn, _, err = dialer.Dial(wsc.ConnectUrl, nil)
+ if err != nil {
+ return NewAppError("Connect", "model.websocket_client.connect_fail.app_error", nil, err.Error(), http.StatusInternalServerError)
+ }
+ // Super racy and should not be done anyways.
+ // All of this needs to be redesigned for v6.
+ wsc.configurePingHandling()
+ // If it has been closed before, we just restart the writer.
+ if atomic.CompareAndSwapInt32(&wsc.closed, 1, 0) {
+ wsc.writeChan = make(chan writeMessage)
+ wsc.quitWriterChan = make(chan struct{})
+ go wsc.writer()
+ wsc.resetTimerChan = make(chan struct{})
+ wsc.quitPingWatchdog = make(chan struct{})
+ }
+
+ wsc.EventChannel = make(chan *WebSocketEvent, 100)
+ wsc.ResponseChannel = make(chan *WebSocketResponse, 100)
+
+ wsc.SendMessage(WEBSOCKET_AUTHENTICATION_CHALLENGE, map[string]interface{}{"token": wsc.AuthToken})
+
+ return nil
+}
+
+// Close closes the websocket client. It is recommended that a closed client should not be
+// reused again. Rather a new client should be created anew.
+func (wsc *WebSocketClient) Close() {
+ // CAS to 1 and proceed. Return if already 1.
+ if !atomic.CompareAndSwapInt32(&wsc.closed, 0, 1) {
+ return
+ }
+ wsc.quitWriterChan <- struct{}{}
+ close(wsc.writeChan)
+ // We close the connection, which breaks the reader loop.
+ // Then we let the defer block in the reader do further cleanup.
+ wsc.Conn.Close()
+}
+
+// TODO: un-export the Conn so that Write methods go through the writer
+func (wsc *WebSocketClient) writer() {
+ for {
+ select {
+ case msg := <-wsc.writeChan:
+ switch msg.msgType {
+ case msgTypeJSON:
+ wsc.Conn.WriteJSON(msg.data)
+ case msgTypePong:
+ wsc.Conn.WriteMessage(websocket.PongMessage, []byte{})
+ }
+ case <-wsc.quitWriterChan:
+ return
+ }
+ }
+}
+
+// Listen starts the read loop of the websocket client.
+func (wsc *WebSocketClient) Listen() {
+ // This loop can exit in 2 conditions:
+ // 1. Either the connection breaks naturally.
+ // 2. Close was explicitly called, which closes the connection manually.
+ //
+ // Due to the way the API is written, there is a requirement that a client may NOT
+ // call Listen at all and can still call Close and Connect.
+ // Therefore, we let the cleanup of the reader stuff rely on closing the connection
+ // and then we do the cleanup in the defer block.
+ //
+ // First, we close some channels and then CAS to 1 and proceed to close the writer chan also.
+ // This is needed because then the defer clause does not double-close the writer when (2) happens.
+ // But if (1) happens, we set the closed bit, and close the rest of the stuff.
+ go func() {
+ defer func() {
+ close(wsc.EventChannel)
+ close(wsc.ResponseChannel)
+ close(wsc.quitPingWatchdog)
+ close(wsc.resetTimerChan)
+ // We CAS to 1 and proceed.
+ if !atomic.CompareAndSwapInt32(&wsc.closed, 0, 1) {
+ return
+ }
+ wsc.quitWriterChan <- struct{}{}
+ close(wsc.writeChan)
+ wsc.Conn.Close() // This can most likely be removed. Needs to be checked.
+ }()
+
+ var buf bytes.Buffer
+ buf.Grow(avgReadMsgSizeBytes)
+
+ for {
+ // Reset buffer.
+ buf.Reset()
+ _, r, err := wsc.Conn.NextReader()
+ if err != nil {
+ if !websocket.IsCloseError(err, websocket.CloseNormalClosure, websocket.CloseNoStatusReceived) {
+ wsc.ListenError = NewAppError("NewWebSocketClient", "model.websocket_client.connect_fail.app_error", nil, err.Error(), http.StatusInternalServerError)
+ }
+ return
+ }
+ // Use pre-allocated buffer.
+ _, err = buf.ReadFrom(r)
+ if err != nil {
+ // This should use a different error ID, but en.json is not imported anyways.
+ // It's a different bug altogether but we let it be for now.
+ // See MM-24520.
+ wsc.ListenError = NewAppError("NewWebSocketClient", "model.websocket_client.connect_fail.app_error", nil, err.Error(), http.StatusInternalServerError)
+ return
+ }
+
+ event := WebSocketEventFromJson(bytes.NewReader(buf.Bytes()))
+ if event == nil {
+ continue
+ }
+ if event.IsValid() {
+ wsc.EventChannel <- event
+ continue
+ }
+
+ var response WebSocketResponse
+ if err := json.Unmarshal(buf.Bytes(), &response); err == nil && response.IsValid() {
+ wsc.ResponseChannel <- &response
+ continue
+ }
+ }
+ }()
+}
+
+func (wsc *WebSocketClient) SendMessage(action string, data map[string]interface{}) {
+ req := &WebSocketRequest{}
+ req.Seq = wsc.Sequence
+ req.Action = action
+ req.Data = data
+
+ wsc.Sequence++
+ wsc.writeChan <- writeMessage{
+ msgType: msgTypeJSON,
+ data: req,
+ }
+}
+
+// UserTyping will push a user_typing event out to all connected users
+// who are in the specified channel
+func (wsc *WebSocketClient) UserTyping(channelId, parentId string) {
+ data := map[string]interface{}{
+ "channel_id": channelId,
+ "parent_id": parentId,
+ }
+
+ wsc.SendMessage("user_typing", data)
+}
+
+// GetStatuses will return a map of string statuses using user id as the key
+func (wsc *WebSocketClient) GetStatuses() {
+ wsc.SendMessage("get_statuses", nil)
+}
+
+// GetStatusesByIds will fetch certain user statuses based on ids and return
+// a map of string statuses using user id as the key
+func (wsc *WebSocketClient) GetStatusesByIds(userIds []string) {
+ data := map[string]interface{}{
+ "user_ids": userIds,
+ }
+ wsc.SendMessage("get_statuses_by_ids", data)
+}
+
+func (wsc *WebSocketClient) configurePingHandling() {
+ wsc.Conn.SetPingHandler(wsc.pingHandler)
+ wsc.pingTimeoutTimer = time.NewTimer(time.Second * (60 + PING_TIMEOUT_BUFFER_SECONDS))
+ go wsc.pingWatchdog()
+}
+
+func (wsc *WebSocketClient) pingHandler(appData string) error {
+ if atomic.LoadInt32(&wsc.closed) == 1 {
+ return nil
+ }
+ wsc.resetTimerChan <- struct{}{}
+ wsc.writeChan <- writeMessage{
+ msgType: msgTypePong,
+ }
+ return nil
+}
+
+// pingWatchdog is used to send values to the PingTimeoutChannel whenever a timeout occurs.
+// We use the resetTimerChan from the pingHandler to pass the signal, and then reset the timer
+// after draining it. And if the timer naturally expires, we also extend it to prevent it from
+// being deadlocked when the resetTimerChan case runs. Because timer.Stop would return false,
+// and the code would be forever stuck trying to read from C.
+func (wsc *WebSocketClient) pingWatchdog() {
+ for {
+ select {
+ case <-wsc.resetTimerChan:
+ if !wsc.pingTimeoutTimer.Stop() {
+ <-wsc.pingTimeoutTimer.C
+ }
+ wsc.pingTimeoutTimer.Reset(time.Second * (60 + PING_TIMEOUT_BUFFER_SECONDS))
+
+ case <-wsc.pingTimeoutTimer.C:
+ wsc.PingTimeoutChannel <- true
+ wsc.pingTimeoutTimer.Reset(time.Second * (60 + PING_TIMEOUT_BUFFER_SECONDS))
+ case <-wsc.quitPingWatchdog:
+ return
+ }
+ }
+}
diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/websocket_message.go b/vendor/github.com/mattermost/mattermost-server/v5/model/websocket_message.go
new file mode 100644
index 00000000..b3e4b186
--- /dev/null
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/websocket_message.go
@@ -0,0 +1,259 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
+
+package model
+
+import (
+ "bytes"
+ "encoding/json"
+ "fmt"
+ "io"
+)
+
+const (
+ WEBSOCKET_EVENT_TYPING = "typing"
+ WEBSOCKET_EVENT_POSTED = "posted"
+ WEBSOCKET_EVENT_POST_EDITED = "post_edited"
+ WEBSOCKET_EVENT_POST_DELETED = "post_deleted"
+ WEBSOCKET_EVENT_POST_UNREAD = "post_unread"
+ WEBSOCKET_EVENT_CHANNEL_CONVERTED = "channel_converted"
+ WEBSOCKET_EVENT_CHANNEL_CREATED = "channel_created"
+ WEBSOCKET_EVENT_CHANNEL_DELETED = "channel_deleted"
+ WEBSOCKET_EVENT_CHANNEL_RESTORED = "channel_restored"
+ WEBSOCKET_EVENT_CHANNEL_UPDATED = "channel_updated"
+ WEBSOCKET_EVENT_CHANNEL_MEMBER_UPDATED = "channel_member_updated"
+ WEBSOCKET_EVENT_CHANNEL_SCHEME_UPDATED = "channel_scheme_updated"
+ WEBSOCKET_EVENT_DIRECT_ADDED = "direct_added"
+ WEBSOCKET_EVENT_GROUP_ADDED = "group_added"
+ WEBSOCKET_EVENT_NEW_USER = "new_user"
+ WEBSOCKET_EVENT_ADDED_TO_TEAM = "added_to_team"
+ WEBSOCKET_EVENT_LEAVE_TEAM = "leave_team"
+ WEBSOCKET_EVENT_UPDATE_TEAM = "update_team"
+ WEBSOCKET_EVENT_DELETE_TEAM = "delete_team"
+ WEBSOCKET_EVENT_RESTORE_TEAM = "restore_team"
+ WEBSOCKET_EVENT_UPDATE_TEAM_SCHEME = "update_team_scheme"
+ WEBSOCKET_EVENT_USER_ADDED = "user_added"
+ WEBSOCKET_EVENT_USER_UPDATED = "user_updated"
+ WEBSOCKET_EVENT_USER_ROLE_UPDATED = "user_role_updated"
+ WEBSOCKET_EVENT_MEMBERROLE_UPDATED = "memberrole_updated"
+ WEBSOCKET_EVENT_USER_REMOVED = "user_removed"
+ WEBSOCKET_EVENT_PREFERENCE_CHANGED = "preference_changed"
+ WEBSOCKET_EVENT_PREFERENCES_CHANGED = "preferences_changed"
+ WEBSOCKET_EVENT_PREFERENCES_DELETED = "preferences_deleted"
+ WEBSOCKET_EVENT_EPHEMERAL_MESSAGE = "ephemeral_message"
+ WEBSOCKET_EVENT_STATUS_CHANGE = "status_change"
+ WEBSOCKET_EVENT_HELLO = "hello"
+ WEBSOCKET_AUTHENTICATION_CHALLENGE = "authentication_challenge"
+ WEBSOCKET_EVENT_REACTION_ADDED = "reaction_added"
+ WEBSOCKET_EVENT_REACTION_REMOVED = "reaction_removed"
+ WEBSOCKET_EVENT_RESPONSE = "response"
+ WEBSOCKET_EVENT_EMOJI_ADDED = "emoji_added"
+ WEBSOCKET_EVENT_CHANNEL_VIEWED = "channel_viewed"
+ WEBSOCKET_EVENT_PLUGIN_STATUSES_CHANGED = "plugin_statuses_changed"
+ WEBSOCKET_EVENT_PLUGIN_ENABLED = "plugin_enabled"
+ WEBSOCKET_EVENT_PLUGIN_DISABLED = "plugin_disabled"
+ WEBSOCKET_EVENT_ROLE_UPDATED = "role_updated"
+ WEBSOCKET_EVENT_LICENSE_CHANGED = "license_changed"
+ WEBSOCKET_EVENT_CONFIG_CHANGED = "config_changed"
+ WEBSOCKET_EVENT_OPEN_DIALOG = "open_dialog"
+ WEBSOCKET_EVENT_GUESTS_DEACTIVATED = "guests_deactivated"
+ WEBSOCKET_EVENT_RECEIVED_GROUP = "received_group"
+ WEBSOCKET_EVENT_RECEIVED_GROUP_ASSOCIATED_TO_TEAM = "received_group_associated_to_team"
+ WEBSOCKET_EVENT_RECEIVED_GROUP_NOT_ASSOCIATED_TO_TEAM = "received_group_not_associated_to_team"
+ WEBSOCKET_EVENT_RECEIVED_GROUP_ASSOCIATED_TO_CHANNEL = "received_group_associated_to_channel"
+ WEBSOCKET_EVENT_RECEIVED_GROUP_NOT_ASSOCIATED_TO_CHANNEL = "received_group_not_associated_to_channel"
+)
+
+type WebSocketMessage interface {
+ ToJson() string
+ IsValid() bool
+ EventType() string
+}
+
+type WebsocketBroadcast struct {
+ OmitUsers map[string]bool `json:"omit_users"` // broadcast is omitted for users listed here
+ UserId string `json:"user_id"` // broadcast only occurs for this user
+ ChannelId string `json:"channel_id"` // broadcast only occurs for users in this channel
+ TeamId string `json:"team_id"` // broadcast only occurs for users in this team
+ ContainsSanitizedData bool `json:"-"`
+ ContainsSensitiveData bool `json:"-"`
+}
+
+type precomputedWebSocketEventJSON struct {
+ Event json.RawMessage
+ Data json.RawMessage
+ Broadcast json.RawMessage
+}
+
+// webSocketEventJSON mirrors WebSocketEvent to make some of its unexported fields serializable
+type webSocketEventJSON struct {
+ Event string `json:"event"`
+ Data map[string]interface{} `json:"data"`
+ Broadcast *WebsocketBroadcast `json:"broadcast"`
+ Sequence int64 `json:"seq"`
+}
+
+// **NOTE**: Direct access to WebSocketEvent fields is deprecated. They will be
+// made unexported in next major version release. Provided getter functions should be used instead.
+type WebSocketEvent struct {
+ Event string // Deprecated: use EventType()
+ Data map[string]interface{} // Deprecated: use GetData()
+ Broadcast *WebsocketBroadcast // Deprecated: use GetBroadcast()
+ Sequence int64 // Deprecated: use GetSequence()
+ precomputedJSON *precomputedWebSocketEventJSON
+}
+
+// PrecomputeJSON precomputes and stores the serialized JSON for all fields other than Sequence.
+// This makes ToJson much more efficient when sending the same event to multiple connections.
+func (ev *WebSocketEvent) PrecomputeJSON() *WebSocketEvent {
+ copy := ev.Copy()
+ event, _ := json.Marshal(copy.Event)
+ data, _ := json.Marshal(copy.Data)
+ broadcast, _ := json.Marshal(copy.Broadcast)
+ copy.precomputedJSON = &precomputedWebSocketEventJSON{
+ Event: json.RawMessage(event),
+ Data: json.RawMessage(data),
+ Broadcast: json.RawMessage(broadcast),
+ }
+ return copy
+}
+
+func (ev *WebSocketEvent) Add(key string, value interface{}) {
+ ev.Data[key] = value
+}
+
+func NewWebSocketEvent(event, teamId, channelId, userId string, omitUsers map[string]bool) *WebSocketEvent {
+ return &WebSocketEvent{Event: event, Data: make(map[string]interface{}),
+ Broadcast: &WebsocketBroadcast{TeamId: teamId, ChannelId: channelId, UserId: userId, OmitUsers: omitUsers}}
+}
+
+func (ev *WebSocketEvent) Copy() *WebSocketEvent {
+ copy := &WebSocketEvent{
+ Event: ev.Event,
+ Data: ev.Data,
+ Broadcast: ev.Broadcast,
+ Sequence: ev.Sequence,
+ precomputedJSON: ev.precomputedJSON,
+ }
+ return copy
+}
+
+func (ev *WebSocketEvent) GetData() map[string]interface{} {
+ return ev.Data
+}
+
+func (ev *WebSocketEvent) GetBroadcast() *WebsocketBroadcast {
+ return ev.Broadcast
+}
+
+func (ev *WebSocketEvent) GetSequence() int64 {
+ return ev.Sequence
+}
+
+func (ev *WebSocketEvent) SetEvent(event string) *WebSocketEvent {
+ copy := ev.Copy()
+ copy.Event = event
+ return copy
+}
+
+func (ev *WebSocketEvent) SetData(data map[string]interface{}) *WebSocketEvent {
+ copy := ev.Copy()
+ copy.Data = data
+ return copy
+}
+
+func (ev *WebSocketEvent) SetBroadcast(broadcast *WebsocketBroadcast) *WebSocketEvent {
+ copy := ev.Copy()
+ copy.Broadcast = broadcast
+ return copy
+}
+
+func (ev *WebSocketEvent) SetSequence(seq int64) *WebSocketEvent {
+ copy := ev.Copy()
+ copy.Sequence = seq
+ return copy
+}
+
+func (ev *WebSocketEvent) IsValid() bool {
+ return ev.Event != ""
+}
+
+func (ev *WebSocketEvent) EventType() string {
+ return ev.Event
+}
+
+func (ev *WebSocketEvent) ToJson() string {
+ if ev.precomputedJSON != nil {
+ return fmt.Sprintf(`{"event": %s, "data": %s, "broadcast": %s, "seq": %d}`, ev.precomputedJSON.Event, ev.precomputedJSON.Data, ev.precomputedJSON.Broadcast, ev.Sequence)
+ }
+ b, _ := json.Marshal(webSocketEventJSON{
+ ev.Event,
+ ev.Data,
+ ev.Broadcast,
+ ev.Sequence,
+ })
+ return string(b)
+}
+
+func WebSocketEventFromJson(data io.Reader) *WebSocketEvent {
+ var ev WebSocketEvent
+ var o webSocketEventJSON
+ if err := json.NewDecoder(data).Decode(&o); err != nil {
+ return nil
+ }
+ ev.Event = o.Event
+ if u, ok := o.Data["user"]; ok {
+ // We need to convert to and from JSON again
+ // because the user is in the form of a map[string]interface{}.
+ buf, err := json.Marshal(u)
+ if err != nil {
+ return nil
+ }
+ o.Data["user"] = UserFromJson(bytes.NewReader(buf))
+ }
+ ev.Data = o.Data
+ ev.Broadcast = o.Broadcast
+ ev.Sequence = o.Sequence
+ return &ev
+}
+
+// WebSocketResponse represents a response received through the WebSocket
+// for a request made to the server. This is available through the ResponseChannel
+// channel in WebSocketClient.
+type WebSocketResponse struct {
+ Status string `json:"status"` // The status of the response. For example: OK, FAIL.
+ SeqReply int64 `json:"seq_reply,omitempty"` // A counter which is incremented for every response sent.
+ Data map[string]interface{} `json:"data,omitempty"` // The data contained in the response.
+ Error *AppError `json:"error,omitempty"` // A field that is set if any error has occurred.
+}
+
+func (m *WebSocketResponse) Add(key string, value interface{}) {
+ m.Data[key] = value
+}
+
+func NewWebSocketResponse(status string, seqReply int64, data map[string]interface{}) *WebSocketResponse {
+ return &WebSocketResponse{Status: status, SeqReply: seqReply, Data: data}
+}
+
+func NewWebSocketError(seqReply int64, err *AppError) *WebSocketResponse {
+ return &WebSocketResponse{Status: STATUS_FAIL, SeqReply: seqReply, Error: err}
+}
+
+func (m *WebSocketResponse) IsValid() bool {
+ return m.Status != ""
+}
+
+func (m *WebSocketResponse) EventType() string {
+ return WEBSOCKET_EVENT_RESPONSE
+}
+
+func (m *WebSocketResponse) ToJson() string {
+ b, _ := json.Marshal(m)
+ return string(b)
+}
+
+func WebSocketResponseFromJson(data io.Reader) *WebSocketResponse {
+ var o *WebSocketResponse
+ json.NewDecoder(data).Decode(&o)
+ return o
+}
diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/websocket_request.go b/vendor/github.com/mattermost/mattermost-server/v5/model/websocket_request.go
new file mode 100644
index 00000000..6628a5c9
--- /dev/null
+++ b/vendor/github.com/mattermost/mattermost-server/v5/model/websocket_request.go
@@ -0,0 +1,35 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
+
+package model
+
+import (
+ "encoding/json"
+ "io"
+
+ goi18n "github.com/mattermost/go-i18n/i18n"
+)
+
+// WebSocketRequest represents a request made to the server through a websocket.
+type WebSocketRequest struct {
+ // Client-provided fields
+ Seq int64 `json:"seq"` // A counter which is incremented for every request made.
+ Action string `json:"action"` // The action to perform for a request. For example: get_statuses, user_typing.
+ Data map[string]interface{} `json:"data"` // The metadata for an action.
+
+ // Server-provided fields
+ Session Session `json:"-"`
+ T goi18n.TranslateFunc `json:"-"`
+ Locale string `json:"-"`
+}
+
+func (o *WebSocketRequest) ToJson() string {
+ b, _ := json.Marshal(o)
+ return string(b)
+}
+
+func WebSocketRequestFromJson(data io.Reader) *WebSocketRequest {
+ var o *WebSocketRequest
+ json.NewDecoder(data).Decode(&o)
+ return o
+}
diff --git a/vendor/github.com/mattermost/mattermost-server/model/timezone.go b/vendor/github.com/mattermost/mattermost-server/v5/services/timezones/default.go
index 420b9d2e..3d835f7d 100644
--- a/vendor/github.com/mattermost/mattermost-server/model/timezone.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/services/timezones/default.go
@@ -1,34 +1,7 @@
-// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
-package model
-
-import (
- "encoding/json"
- "io"
-)
-
-type SupportedTimezones []string
-
-func TimezonesToJson(timezoneList []string) string {
- b, _ := json.Marshal(timezoneList)
- return string(b)
-}
-
-func TimezonesFromJson(data io.Reader) SupportedTimezones {
- var timezones SupportedTimezones
- json.NewDecoder(data).Decode(&timezones)
- return timezones
-}
-
-func DefaultUserTimezone() map[string]string {
- defaultTimezone := make(map[string]string)
- defaultTimezone["useAutomaticTimezone"] = "true"
- defaultTimezone["automaticTimezone"] = ""
- defaultTimezone["manualTimezone"] = ""
-
- return defaultTimezone
-}
+package timezones
var DefaultSupportedTimezones = []string{
"Africa/Abidjan",
@@ -405,7 +378,6 @@ var DefaultSupportedTimezones = []string{
"CST6CDT",
"Canada/Atlantic",
"Canada/Central",
- "Canada/East-Saskatchewan",
"Canada/Eastern",
"Canada/Mountain",
"Canada/Newfoundland",
@@ -518,7 +490,6 @@ var DefaultSupportedTimezones = []string{
"Europe/Zagreb",
"Europe/Zaporozhye",
"Europe/Zurich",
- "Factory",
"GB",
"GB-Eire",
"GMT",
diff --git a/vendor/github.com/mattermost/mattermost-server/v5/services/timezones/timezones.go b/vendor/github.com/mattermost/mattermost-server/v5/services/timezones/timezones.go
new file mode 100644
index 00000000..e211a4cd
--- /dev/null
+++ b/vendor/github.com/mattermost/mattermost-server/v5/services/timezones/timezones.go
@@ -0,0 +1,29 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
+
+package timezones
+
+type Timezones struct {
+ supportedZones []string
+}
+
+func New() *Timezones {
+ timezones := Timezones{}
+
+ timezones.supportedZones = DefaultSupportedTimezones
+
+ return &timezones
+}
+
+func (t *Timezones) GetSupported() []string {
+ return t.supportedZones
+}
+
+func DefaultUserTimezone() map[string]string {
+ defaultTimezone := make(map[string]string)
+ defaultTimezone["useAutomaticTimezone"] = "true"
+ defaultTimezone["automaticTimezone"] = ""
+ defaultTimezone["manualTimezone"] = ""
+
+ return defaultTimezone
+}
diff --git a/vendor/github.com/mattermost/mattermost-server/utils/jsonutils/json.go b/vendor/github.com/mattermost/mattermost-server/v5/utils/jsonutils/json.go
index da77a2b6..4651ec87 100644
--- a/vendor/github.com/mattermost/mattermost-server/utils/jsonutils/json.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/utils/jsonutils/json.go
@@ -1,5 +1,5 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// See LICENSE.txt for license information.
package jsonutils
diff --git a/vendor/github.com/mattermost/mattermost-server/utils/markdown/autolink.go b/vendor/github.com/mattermost/mattermost-server/v5/utils/markdown/autolink.go
index 7f7d1117..14180836 100644
--- a/vendor/github.com/mattermost/mattermost-server/utils/markdown/autolink.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/utils/markdown/autolink.go
@@ -1,5 +1,5 @@
-// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
package markdown
@@ -78,6 +78,10 @@ func parseURLAutolink(data string, position int) (Range, bool) {
start -= 1
}
+ if start < 0 || position >= len(data) {
+ return Range{}, false
+ }
+
// Ensure that the URL scheme is allowed and that at least one character after the scheme is valid.
scheme := data[start:position]
if !isSchemeAllowed(scheme) || !isValidHostCharacter(data[position+3:]) {
diff --git a/vendor/github.com/mattermost/mattermost-server/utils/markdown/block_quote.go b/vendor/github.com/mattermost/mattermost-server/v5/utils/markdown/block_quote.go
index 04a32461..6ae2ff44 100644
--- a/vendor/github.com/mattermost/mattermost-server/utils/markdown/block_quote.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/utils/markdown/block_quote.go
@@ -1,5 +1,5 @@
-// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
package markdown
diff --git a/vendor/github.com/mattermost/mattermost-server/utils/markdown/blocks.go b/vendor/github.com/mattermost/mattermost-server/v5/utils/markdown/blocks.go
index 14972f94..44ee178d 100644
--- a/vendor/github.com/mattermost/mattermost-server/utils/markdown/blocks.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/utils/markdown/blocks.go
@@ -1,5 +1,5 @@
-// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
package markdown
@@ -77,10 +77,10 @@ func ParseBlocks(markdown string, lines []Line) (*Document, []*ReferenceDefiniti
didAdd := false
for i := lastMatchIndex; i >= 0; i-- {
if container, ok := openBlocks[i].(ContainerBlock); ok {
- if newBlocks := container.AddChild(newBlocks); newBlocks != nil {
+ if addedBlocks := container.AddChild(newBlocks); addedBlocks != nil {
closeBlocks(openBlocks[i+1:], &referenceDefinitions)
openBlocks = openBlocks[:i+1]
- openBlocks = append(openBlocks, newBlocks...)
+ openBlocks = append(openBlocks, addedBlocks...)
didAdd = true
break
}
diff --git a/vendor/github.com/mattermost/mattermost-server/utils/markdown/document.go b/vendor/github.com/mattermost/mattermost-server/v5/utils/markdown/document.go
index 224b5d21..306b93da 100644
--- a/vendor/github.com/mattermost/mattermost-server/utils/markdown/document.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/utils/markdown/document.go
@@ -1,5 +1,5 @@
-// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
package markdown
diff --git a/vendor/github.com/mattermost/mattermost-server/utils/markdown/fenced_code.go b/vendor/github.com/mattermost/mattermost-server/v5/utils/markdown/fenced_code.go
index 8b2ebd4f..4fd97fd0 100644
--- a/vendor/github.com/mattermost/mattermost-server/utils/markdown/fenced_code.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/utils/markdown/fenced_code.go
@@ -1,5 +1,5 @@
-// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
package markdown
diff --git a/vendor/github.com/mattermost/mattermost-server/utils/markdown/html.go b/vendor/github.com/mattermost/mattermost-server/v5/utils/markdown/html.go
index afb72bff..52583074 100644
--- a/vendor/github.com/mattermost/mattermost-server/utils/markdown/html.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/utils/markdown/html.go
@@ -1,5 +1,5 @@
-// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
package markdown
diff --git a/vendor/github.com/mattermost/mattermost-server/utils/markdown/html_entities.go b/vendor/github.com/mattermost/mattermost-server/v5/utils/markdown/html_entities.go
index 8fe24811..e94cebb9 100644
--- a/vendor/github.com/mattermost/mattermost-server/utils/markdown/html_entities.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/utils/markdown/html_entities.go
@@ -1,5 +1,5 @@
-// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
package markdown
diff --git a/vendor/github.com/mattermost/mattermost-server/utils/markdown/indented_code.go b/vendor/github.com/mattermost/mattermost-server/v5/utils/markdown/indented_code.go
index dc5dce1a..a89ee6c7 100644
--- a/vendor/github.com/mattermost/mattermost-server/utils/markdown/indented_code.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/utils/markdown/indented_code.go
@@ -1,5 +1,5 @@
-// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
package markdown
diff --git a/vendor/github.com/mattermost/mattermost-server/utils/markdown/inlines.go b/vendor/github.com/mattermost/mattermost-server/v5/utils/markdown/inlines.go
index a3abccef..4303607f 100644
--- a/vendor/github.com/mattermost/mattermost-server/utils/markdown/inlines.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/utils/markdown/inlines.go
@@ -1,5 +1,5 @@
-// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
package markdown
@@ -398,8 +398,8 @@ func (p *inlineParser) lookForLinkOrImage() {
p.inlines = append(p.inlines[:d.TextNode], inline)
} else {
p.inlines = append(p.inlines[:d.TextNode], inline)
- for element := element.Prev(); element != nil; element = element.Prev() {
- if d := element.Value.(*delimiter); d.Type == linkOpeningDelimiter {
+ for inlineElement := element.Prev(); inlineElement != nil; inlineElement = inlineElement.Prev() {
+ if d := inlineElement.Value.(*delimiter); d.Type == linkOpeningDelimiter {
d.IsInactive = true
}
}
diff --git a/vendor/github.com/mattermost/mattermost-server/utils/markdown/inspect.go b/vendor/github.com/mattermost/mattermost-server/v5/utils/markdown/inspect.go
index 80b5bc24..3c7f2d1c 100644
--- a/vendor/github.com/mattermost/mattermost-server/utils/markdown/inspect.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/utils/markdown/inspect.go
@@ -1,5 +1,5 @@
-// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
package markdown
diff --git a/vendor/github.com/mattermost/mattermost-server/utils/markdown/lines.go b/vendor/github.com/mattermost/mattermost-server/v5/utils/markdown/lines.go
index a38b5164..a0a64491 100644
--- a/vendor/github.com/mattermost/mattermost-server/utils/markdown/lines.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/utils/markdown/lines.go
@@ -1,5 +1,5 @@
-// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
package markdown
diff --git a/vendor/github.com/mattermost/mattermost-server/utils/markdown/links.go b/vendor/github.com/mattermost/mattermost-server/v5/utils/markdown/links.go
index 9f3128c4..df4aa748 100644
--- a/vendor/github.com/mattermost/mattermost-server/utils/markdown/links.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/utils/markdown/links.go
@@ -1,5 +1,5 @@
-// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
package markdown
diff --git a/vendor/github.com/mattermost/mattermost-server/utils/markdown/list.go b/vendor/github.com/mattermost/mattermost-server/v5/utils/markdown/list.go
index aea71156..39039295 100644
--- a/vendor/github.com/mattermost/mattermost-server/utils/markdown/list.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/utils/markdown/list.go
@@ -1,5 +1,5 @@
-// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
package markdown
diff --git a/vendor/github.com/mattermost/mattermost-server/utils/markdown/markdown.go b/vendor/github.com/mattermost/mattermost-server/v5/utils/markdown/markdown.go
index 57b10f3f..a9879cee 100644
--- a/vendor/github.com/mattermost/mattermost-server/utils/markdown/markdown.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/utils/markdown/markdown.go
@@ -1,5 +1,5 @@
-// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
// This package implements a parser for the subset of the CommonMark spec necessary for us to do
// server-side processing. It is not a full implementation and lacks many features. But it is
diff --git a/vendor/github.com/mattermost/mattermost-server/utils/markdown/paragraph.go b/vendor/github.com/mattermost/mattermost-server/v5/utils/markdown/paragraph.go
index 6a40fdf8..aef01b5e 100644
--- a/vendor/github.com/mattermost/mattermost-server/utils/markdown/paragraph.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/utils/markdown/paragraph.go
@@ -1,5 +1,5 @@
-// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
package markdown
diff --git a/vendor/github.com/mattermost/mattermost-server/utils/markdown/reference_definition.go b/vendor/github.com/mattermost/mattermost-server/v5/utils/markdown/reference_definition.go
index e2d0be35..69e8ed94 100644
--- a/vendor/github.com/mattermost/mattermost-server/utils/markdown/reference_definition.go
+++ b/vendor/github.com/mattermost/mattermost-server/v5/utils/markdown/reference_definition.go
@@ -1,5 +1,5 @@
-// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
package markdown