diff options
-rw-r--r-- | cmd/mattermost/commands/init.go | 2 | ||||
-rw-r--r-- | cmd/mattermost/commands/plugin.go | 186 | ||||
-rw-r--r-- | cmd/mattermost/commands/plugin_test.go | 42 | ||||
-rw-r--r-- | tests/test-config.json | 412 |
4 files changed, 642 insertions, 0 deletions
diff --git a/cmd/mattermost/commands/init.go b/cmd/mattermost/commands/init.go index ea7e8ec84..8d8f12c53 100644 --- a/cmd/mattermost/commands/init.go +++ b/cmd/mattermost/commands/init.go @@ -17,6 +17,8 @@ func InitDBCommandContextCobra(command *cobra.Command) (*app.App, error) { } a, err := InitDBCommandContext(config) + a.InitPlugins(*a.Config().PluginSettings.Directory, *a.Config().PluginSettings.ClientDirectory) + if err != nil { // Returning an error just prints the usage message, so actually panic panic(err) diff --git a/cmd/mattermost/commands/plugin.go b/cmd/mattermost/commands/plugin.go new file mode 100644 index 000000000..56a57ddf1 --- /dev/null +++ b/cmd/mattermost/commands/plugin.go @@ -0,0 +1,186 @@ +// Copyright (c) 2018-present Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +package commands + +import ( + "errors" + "os" + + "github.com/spf13/cobra" +) + +var PluginCmd = &cobra.Command{ + Use: "plugin", + Short: "Management of plugins", +} + +var PluginAddCmd = &cobra.Command{ + Use: "add [plugins]", + Short: "Add plugins", + Long: "Add plugins to your Mattermost server.", + Example: ` plugin add hovercardexample.tar.gz pluginexample.tar.gz`, + RunE: pluginAddCmdF, +} + +var PluginDeleteCmd = &cobra.Command{ + Use: "delete [plugins]", + Short: "Delete plugins", + Long: "Delete previously uploaded plugins from your Mattermost server.", + Example: ` plugin delete hovercardexample pluginexample`, + RunE: pluginDeleteCmdF, +} + +var PluginEnableCmd = &cobra.Command{ + Use: "enable [plugins]", + Short: "Enable plugins", + Long: "Enable plugins for use on your Mattermost server.", + Example: ` plugin enable hovercardexample pluginexample`, + RunE: pluginEnableCmdF, +} + +var PluginDisableCmd = &cobra.Command{ + Use: "disable [plugins]", + Short: "Disable plugins", + Long: "Disable plugins. Disabled plugins are immediately removed from the user interface and logged out of all sessions.", + Example: ` plugin disable hovercardexample pluginexample`, + RunE: pluginDisableCmdF, +} + +var PluginListCmd = &cobra.Command{ + Use: "list", + Short: "List plugins", + Long: "List all active and inactive plugins installed on your Mattermost server.", + Example: ` plugin list`, + RunE: pluginListCmdF, +} + +func init() { + PluginCmd.AddCommand( + PluginAddCmd, + PluginDeleteCmd, + PluginEnableCmd, + PluginDisableCmd, + PluginListCmd, + ) + RootCmd.AddCommand(PluginCmd) +} + +func pluginAddCmdF(command *cobra.Command, args []string) error { + a, err := InitDBCommandContextCobra(command) + if err != nil { + return err + } + defer a.Shutdown() + + if len(args) < 1 { + return errors.New("Expected at least one argument. See help text for details.") + } + + for i, plugin := range args { + fileReader, err := os.Open(plugin) + if err != nil { + return err + } + + if _, err := a.InstallPlugin(fileReader); err != nil { + CommandPrintErrorln("Unable to add plugin: " + args[i] + ". Error: " + err.Error()) + } else { + CommandPrettyPrintln("Added plugin: " + plugin) + } + fileReader.Close() + } + + return nil +} + +func pluginDeleteCmdF(command *cobra.Command, args []string) error { + a, err := InitDBCommandContextCobra(command) + if err != nil { + return err + } + defer a.Shutdown() + + if len(args) < 1 { + return errors.New("Expected at least one argument. See help text for details.") + } + + for _, plugin := range args { + if err := a.RemovePlugin(plugin); err != nil { + CommandPrintErrorln("Unable to delete plugin: " + plugin + ". Error: " + err.Error()) + } else { + CommandPrettyPrintln("Deleted plugin: " + plugin) + } + } + + return nil +} + +func pluginEnableCmdF(command *cobra.Command, args []string) error { + a, err := InitDBCommandContextCobra(command) + if err != nil { + return err + } + defer a.Shutdown() + + if len(args) < 1 { + return errors.New("Expected at least one argument. See help text for details.") + } + + for _, plugin := range args { + if err := a.EnablePlugin(plugin); err != nil { + CommandPrintErrorln("Unable to enable plugin: " + plugin + ". Error: " + err.Error()) + } else { + CommandPrettyPrintln("Enabled plugin: " + plugin) + } + } + + return nil +} + +func pluginDisableCmdF(command *cobra.Command, args []string) error { + a, err := InitDBCommandContextCobra(command) + if err != nil { + return err + } + defer a.Shutdown() + + if len(args) < 1 { + return errors.New("Expected at least one argument. See help text for details.") + } + + for _, plugin := range args { + if err := a.DisablePlugin(plugin); err != nil { + CommandPrintErrorln("Unable to disable plugin: " + plugin + ". Error: " + err.Error()) + } else { + CommandPrettyPrintln("Disabled plugin: " + plugin) + } + } + + return nil +} + +func pluginListCmdF(command *cobra.Command, args []string) error { + a, err := InitDBCommandContextCobra(command) + if err != nil { + return err + } + defer a.Shutdown() + + pluginsResp, appErr := a.GetPlugins() + if appErr != nil { + return errors.New("Unable to list plugins. Error: " + appErr.Error()) + } + + CommandPrettyPrintln("Listing active plugins") + for _, plugin := range pluginsResp.Active { + CommandPrettyPrintln(plugin.Manifest.Name + ", Version: " + plugin.Manifest.Version) + } + + CommandPrettyPrintln("Listing inactive plugins") + for _, plugin := range pluginsResp.Inactive { + CommandPrettyPrintln(plugin.Manifest.Name + ", Version: " + plugin.Manifest.Version) + } + + return nil +} diff --git a/cmd/mattermost/commands/plugin_test.go b/cmd/mattermost/commands/plugin_test.go new file mode 100644 index 000000000..043823583 --- /dev/null +++ b/cmd/mattermost/commands/plugin_test.go @@ -0,0 +1,42 @@ +package commands + +import ( + "os" + "path/filepath" + "testing" + + "github.com/mattermost/mattermost-server/api4" + "github.com/mattermost/mattermost-server/utils" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestPlugin(t *testing.T) { + os.MkdirAll("./test-plugins", os.ModePerm) + os.MkdirAll("./test-client-plugins", os.ModePerm) + + th := api4.Setup().InitBasic().InitSystemAdmin() + defer th.TearDown() + + path, _ := utils.FindDir("tests") + + os.Chdir(filepath.Join("..", "..", "..")) + + CheckCommand(t, "--config", filepath.Join(path, "test-config.json"), "plugin", "add", filepath.Join(path, "testplugin.tar.gz")) + + CheckCommand(t, "--config", filepath.Join(path, "test-config.json"), "plugin", "enable", "testplugin") + cfg, _, _, err := utils.LoadConfig(filepath.Join(path, "test-config.json")) + require.Nil(t, err) + assert.Equal(t, cfg.PluginSettings.PluginStates["testplugin"].Enable, true) + + CheckCommand(t, "--config", filepath.Join(path, "test-config.json"), "plugin", "disable", "testplugin") + cfg, _, _, err = utils.LoadConfig(filepath.Join(path, "test-config.json")) + require.Nil(t, err) + assert.Equal(t, cfg.PluginSettings.PluginStates["testplugin"].Enable, false) + + CheckCommand(t, "--config", filepath.Join(path, "test-config.json"), "plugin", "list") + + CheckCommand(t, "--config", filepath.Join(path, "test-config.json"), "plugin", "delete", "testplugin") + + os.Chdir(filepath.Join("cmd", "mattermost", "commands")) +} diff --git a/tests/test-config.json b/tests/test-config.json new file mode 100644 index 000000000..d22a377d1 --- /dev/null +++ b/tests/test-config.json @@ -0,0 +1,412 @@ +{ + "ServiceSettings": { + "SiteURL": "", + "WebsocketURL": "", + "LicenseFileLocation": "", + "ListenAddress": ":8065", + "ConnectionSecurity": "", + "TLSCertFile": "", + "TLSKeyFile": "", + "UseLetsEncrypt": false, + "LetsEncryptCertificateCacheFile": "./config/letsencrypt.cache", + "Forward80To443": false, + "ReadTimeout": 300, + "WriteTimeout": 300, + "MaximumLoginAttempts": 10, + "GoroutineHealthThreshold": -1, + "GoogleDeveloperKey": "", + "EnableOAuthServiceProvider": false, + "EnableIncomingWebhooks": true, + "EnableOutgoingWebhooks": true, + "EnableCommands": true, + "EnableOnlyAdminIntegrations": true, + "EnablePostUsernameOverride": false, + "EnablePostIconOverride": false, + "EnableLinkPreviews": false, + "EnableTesting": false, + "EnableDeveloper": false, + "EnableSecurityFixAlert": true, + "EnableInsecureOutgoingConnections": false, + "AllowedUntrustedInternalConnections": "", + "EnableMultifactorAuthentication": false, + "EnforceMultifactorAuthentication": false, + "EnableUserAccessTokens": false, + "AllowCorsFrom": "", + "AllowCookiesForSubdomains": false, + "SessionLengthWebInDays": 30, + "SessionLengthMobileInDays": 30, + "SessionLengthSSOInDays": 30, + "SessionCacheInMinutes": 10, + "SessionIdleTimeoutInMinutes": 0, + "WebsocketSecurePort": 443, + "WebsocketPort": 80, + "WebserverMode": "gzip", + "EnableCustomEmoji": false, + "EnableEmojiPicker": true, + "RestrictCustomEmojiCreation": "all", + "RestrictPostDelete": "all", + "AllowEditPost": "always", + "PostEditTimeLimit": -1, + "TimeBetweenUserTypingUpdatesMilliseconds": 5000, + "EnablePostSearch": true, + "EnableUserTypingMessages": true, + "EnableChannelViewedMessages": true, + "EnableUserStatuses": true, + "ExperimentalEnableAuthenticationTransfer": true, + "ClusterLogTimeoutMilliseconds": 2000, + "CloseUnusedDirectMessages": false, + "EnablePreviewFeatures": true, + "EnableTutorial": true, + "ExperimentalEnableDefaultChannelLeaveJoinMessages": true, + "ExperimentalGroupUnreadChannels": "disabled", + "ImageProxyType": "", + "ImageProxyURL": "", + "ImageProxyOptions": "", + "EnableAPITeamDeletion": false, + "ExperimentalEnableHardenedMode": false, + "ExperimentalLimitClientConfig": false + }, + "TeamSettings": { + "SiteName": "Mattermost", + "MaxUsersPerTeam": 50, + "EnableTeamCreation": true, + "EnableUserCreation": true, + "EnableOpenServer": false, + "EnableUserDeactivation": false, + "RestrictCreationToDomains": "", + "EnableCustomBrand": false, + "CustomBrandText": "", + "CustomDescriptionText": "", + "RestrictDirectMessage": "any", + "RestrictTeamInvite": "all", + "RestrictPublicChannelManagement": "all", + "RestrictPrivateChannelManagement": "all", + "RestrictPublicChannelCreation": "all", + "RestrictPrivateChannelCreation": "all", + "RestrictPublicChannelDeletion": "all", + "RestrictPrivateChannelDeletion": "all", + "RestrictPrivateChannelManageMembers": "all", + "EnableXToLeaveChannelsFromLHS": false, + "UserStatusAwayTimeout": 300, + "MaxChannelsPerTeam": 2000, + "MaxNotificationsPerChannel": 1000, + "EnableConfirmNotificationsToChannel": true, + "TeammateNameDisplay": "username", + "ExperimentalEnableAutomaticReplies": false, + "ExperimentalHideTownSquareinLHS": false, + "ExperimentalTownSquareIsReadOnly": false, + "ExperimentalPrimaryTeam": "" + }, + "ClientRequirements": { + "AndroidLatestVersion": "", + "AndroidMinVersion": "", + "DesktopLatestVersion": "", + "DesktopMinVersion": "", + "IosLatestVersion": "", + "IosMinVersion": "" + }, + "SqlSettings": { + "DriverName": "mysql", + "DataSource": "mmuser:mostest@tcp(dockerhost:3306)/mattermost_test?charset=utf8mb4,utf8\u0026readTimeout=30s\u0026writeTimeout=30s", + "DataSourceReplicas": [], + "DataSourceSearchReplicas": [], + "MaxIdleConns": 20, + "MaxOpenConns": 300, + "Trace": false, + "AtRestEncryptKey": "jdh9iergmse3w9mt53snasugmmi9r6it", + "QueryTimeout": 30 + }, + "LogSettings": { + "EnableConsole": true, + "ConsoleLevel": "DEBUG", + "ConsoleJson": true, + "EnableFile": true, + "FileLevel": "INFO", + "FileJson": true, + "FileLocation": "", + "EnableWebhookDebugging": true, + "EnableDiagnostics": true + }, + "PasswordSettings": { + "MinimumLength": 5, + "Lowercase": false, + "Number": false, + "Uppercase": false, + "Symbol": false + }, + "FileSettings": { + "EnableFileAttachments": true, + "EnableMobileUpload": true, + "EnableMobileDownload": true, + "MaxFileSize": 52428800, + "DriverName": "local", + "Directory": "./data/", + "EnablePublicLink": false, + "PublicLinkSalt": "3xh7ztscuezjp1jkdjybtejrtw59xjt1", + "InitialFont": "luximbi.ttf", + "AmazonS3AccessKeyId": "", + "AmazonS3SecretAccessKey": "", + "AmazonS3Bucket": "", + "AmazonS3Region": "", + "AmazonS3Endpoint": "s3.amazonaws.com", + "AmazonS3SSL": true, + "AmazonS3SignV2": false, + "AmazonS3SSE": false, + "AmazonS3Trace": false + }, + "EmailSettings": { + "EnableSignUpWithEmail": true, + "EnableSignInWithEmail": true, + "EnableSignInWithUsername": true, + "SendEmailNotifications": true, + "UseChannelInEmailNotifications": false, + "RequireEmailVerification": false, + "FeedbackName": "", + "FeedbackEmail": "test@example.com", + "FeedbackOrganization": "", + "EnableSMTPAuth": false, + "SMTPUsername": "", + "SMTPPassword": "", + "SMTPServer": "dockerhost", + "SMTPPort": "2500", + "ConnectionSecurity": "", + "InviteSalt": "n3mceqsek4j5ichs5hw9sudwx3cfbtqa", + "SendPushNotifications": false, + "PushNotificationServer": "", + "PushNotificationContents": "generic", + "EnableEmailBatching": false, + "EmailBatchingBufferSize": 256, + "EmailBatchingInterval": 30, + "EnablePreviewModeBanner": true, + "SkipServerCertificateVerification": false, + "EmailNotificationContentsType": "full", + "LoginButtonColor": "", + "LoginButtonBorderColor": "", + "LoginButtonTextColor": "" + }, + "RateLimitSettings": { + "Enable": false, + "PerSec": 10, + "MaxBurst": 100, + "MemoryStoreSize": 10000, + "VaryByRemoteAddr": true, + "VaryByUser": false, + "VaryByHeader": "" + }, + "PrivacySettings": { + "ShowEmailAddress": true, + "ShowFullName": true + }, + "SupportSettings": { + "TermsOfServiceLink": "https://about.mattermost.com/default-terms/", + "PrivacyPolicyLink": "https://about.mattermost.com/default-privacy-policy/", + "AboutLink": "https://about.mattermost.com/default-about/", + "HelpLink": "https://about.mattermost.com/default-help/", + "ReportAProblemLink": "https://about.mattermost.com/default-report-a-problem/", + "SupportEmail": "feedback@mattermost.com" + }, + "AnnouncementSettings": { + "EnableBanner": false, + "BannerText": "", + "BannerColor": "#f2a93b", + "BannerTextColor": "#333333", + "AllowBannerDismissal": true + }, + "ThemeSettings": { + "EnableThemeSelection": true, + "DefaultTheme": "default", + "AllowCustomThemes": true, + "AllowedThemes": [] + }, + "GitLabSettings": { + "Enable": false, + "Secret": "", + "Id": "", + "Scope": "", + "AuthEndpoint": "", + "TokenEndpoint": "", + "UserApiEndpoint": "" + }, + "GoogleSettings": { + "Enable": false, + "Secret": "", + "Id": "", + "Scope": "profile email", + "AuthEndpoint": "https://accounts.google.com/o/oauth2/v2/auth", + "TokenEndpoint": "https://www.googleapis.com/oauth2/v4/token", + "UserApiEndpoint": "https://www.googleapis.com/plus/v1/people/me" + }, + "Office365Settings": { + "Enable": false, + "Secret": "", + "Id": "", + "Scope": "User.Read", + "AuthEndpoint": "https://login.microsoftonline.com/common/oauth2/v2.0/authorize", + "TokenEndpoint": "https://login.microsoftonline.com/common/oauth2/v2.0/token", + "UserApiEndpoint": "https://graph.microsoft.com/v1.0/me" + }, + "LdapSettings": { + "Enable": false, + "EnableSync": false, + "LdapServer": "", + "LdapPort": 389, + "ConnectionSecurity": "", + "BaseDN": "", + "BindUsername": "", + "BindPassword": "", + "UserFilter": "", + "FirstNameAttribute": "", + "LastNameAttribute": "", + "EmailAttribute": "", + "UsernameAttribute": "", + "NicknameAttribute": "", + "IdAttribute": "", + "PositionAttribute": "", + "LoginIdAttribute": "", + "SyncIntervalMinutes": 60, + "SkipCertificateVerification": false, + "QueryTimeout": 60, + "MaxPageSize": 0, + "LoginFieldName": "", + "LoginButtonColor": "", + "LoginButtonBorderColor": "", + "LoginButtonTextColor": "" + }, + "ComplianceSettings": { + "Enable": false, + "Directory": "./data/", + "EnableDaily": false + }, + "LocalizationSettings": { + "DefaultServerLocale": "en", + "DefaultClientLocale": "en", + "AvailableLocales": "" + }, + "SamlSettings": { + "Enable": false, + "EnableSyncWithLdap": false, + "Verify": true, + "Encrypt": true, + "IdpUrl": "", + "IdpDescriptorUrl": "", + "AssertionConsumerServiceURL": "", + "ScopingIDPProviderId": "", + "ScopingIDPName": "", + "IdpCertificateFile": "", + "PublicCertificateFile": "", + "PrivateKeyFile": "", + "FirstNameAttribute": "", + "LastNameAttribute": "", + "EmailAttribute": "", + "UsernameAttribute": "", + "NicknameAttribute": "", + "LocaleAttribute": "", + "PositionAttribute": "", + "LoginButtonText": "With SAML", + "LoginButtonColor": "", + "LoginButtonBorderColor": "", + "LoginButtonTextColor": "" + }, + "NativeAppSettings": { + "AppDownloadLink": "https://about.mattermost.com/downloads/", + "AndroidAppDownloadLink": "https://about.mattermost.com/mattermost-android-app/", + "IosAppDownloadLink": "https://about.mattermost.com/mattermost-ios-app/" + }, + "ClusterSettings": { + "Enable": false, + "ClusterName": "", + "OverrideHostname": "", + "UseIpAddress": true, + "UseExperimentalGossip": false, + "ReadOnlyConfig": true, + "GossipPort": 8074, + "StreamingPort": 8075, + "MaxIdleConns": 100, + "MaxIdleConnsPerHost": 128, + "IdleConnTimeoutMilliseconds": 90000 + }, + "MetricsSettings": { + "Enable": false, + "BlockProfileRate": 0, + "ListenAddress": ":8067" + }, + "ExperimentalSettings": { + "ClientSideCertEnable": false, + "ClientSideCertCheck": "secondary" + }, + "AnalyticsSettings": { + "MaxUsersForStatistics": 2500 + }, + "WebrtcSettings": { + "Enable": false, + "GatewayWebsocketUrl": "", + "GatewayAdminUrl": "", + "GatewayAdminSecret": "", + "StunURI": "", + "TurnURI": "", + "TurnUsername": "", + "TurnSharedKey": "" + }, + "ElasticsearchSettings": { + "ConnectionUrl": "http://dockerhost:9200", + "Username": "elastic", + "Password": "changeme", + "EnableIndexing": false, + "EnableSearching": false, + "Sniff": true, + "PostIndexReplicas": 1, + "PostIndexShards": 1, + "AggregatePostsAfterDays": 365, + "PostsAggregatorJobStartTime": "03:00", + "IndexPrefix": "", + "LiveIndexingBatchSize": 1, + "BulkIndexingTimeWindowSeconds": 3600, + "RequestTimeoutSeconds": 30 + }, + "DataRetentionSettings": { + "EnableMessageDeletion": false, + "EnableFileDeletion": false, + "MessageRetentionDays": 365, + "FileRetentionDays": 365, + "DeletionJobStartTime": "02:00" + }, + "MessageExportSettings": { + "EnableExport": false, + "ExportFormat": "actiance", + "DailyRunTime": "01:00", + "ExportFromTimestamp": 0, + "BatchSize": 10000, + "GlobalRelaySettings": { + "CustomerType": "A9", + "SmtpUsername": "", + "SmtpPassword": "", + "EmailAddress": "" + } + }, + "JobSettings": { + "RunJobs": true, + "RunScheduler": true + }, + "PluginSettings": { + "Enable": true, + "EnableUploads": true, + "Directory": "./test-plugins", + "ClientDirectory": "./test-client-plugins", + "Plugins": {}, + "PluginStates": { + "jira": { + "Enable": true + }, + "testplugin": { + "Enable": false + } + } + }, + "DisplaySettings": { + "CustomUrlSchemes": [], + "ExperimentalTimezone": false + }, + "TimezoneSettings": { + "SupportedTimezonesPath": "timezones.json" + } +}
\ No newline at end of file |