diff --git a/app/app_test.go b/app/app_test.go index 4be8fcfd5a..bfc383f743 100644 --- a/app/app_test.go +++ b/app/app_test.go @@ -182,7 +182,7 @@ func TestDoAdvancedPermissionsMigration(t *testing.T) { "system_admin": allPermissionIDs, } assert.Contains(t, allPermissionIDs, model.PERMISSION_MANAGE_SHARED_CHANNELS.Id, "manage_shared_channels permission not found") - assert.Contains(t, allPermissionIDs, model.PERMISSION_MANAGE_REMOTE_CLUSTERS.Id, "manage_remote_clusters permission not found") + assert.Contains(t, allPermissionIDs, model.PERMISSION_MANAGE_SECURE_CONNECTIONS.Id, "manage_secure_connections permission not found") // Check the migration matches what's expected. for name, permissions := range expected1 { diff --git a/app/permissions_migrations.go b/app/permissions_migrations.go index d73d352fc4..bba792fd4f 100644 --- a/app/permissions_migrations.go +++ b/app/permissions_migrations.go @@ -70,7 +70,8 @@ const ( PermissionReadPrivateChannelGroups = "read_private_channel_groups" PermissionEditBrand = "edit_brand" PermissionManageSharedChannels = "manage_shared_channels" - PermissionManageRemoteClusters = "manage_remote_clusters" + PermissionManageSecureConnections = "manage_secure_connections" + PermissionManageRemoteClusters = "manage_remote_clusters" // deprecated; use `manage_secure_connections` ) func isRole(roleName string) func(*model.Role, map[string]map[string]bool) bool { @@ -525,13 +526,24 @@ func (a *App) getBillingPermissionsMigration() (permissionsMap, error) { }, nil } -func (a *App) getAddManageRemoteClustersPermissionsMigration() (permissionsMap, error) { - return permissionsMap{ +func (a *App) getAddManageSecureConnectionsPermissionsMigration() (permissionsMap, error) { + transformations := []permissionTransformation{} + + // add the new permission to system admin + transformations = append(transformations, permissionTransformation{ On: isRole(model.SYSTEM_ADMIN_ROLE_ID), - Add: []string{PermissionManageRemoteClusters}, - }, - }, nil + Add: []string{PermissionManageSecureConnections}, + }) + + // remote the decprecated permission from system admin + transformations = append(transformations, + permissionTransformation{ + On: isRole(model.SYSTEM_ADMIN_ROLE_ID), + Remove: []string{PermissionManageRemoteClusters}, + }) + + return transformations, nil } func (a *App) getAddDownloadComplianceExportResult() (permissionsMap, error) { @@ -910,7 +922,7 @@ func (a *App) DoPermissionsMigrations() error { {Key: model.MIGRATION_KEY_ADD_SYSTEM_CONSOLE_PERMISSIONS, Migration: a.getAddSystemConsolePermissionsMigration}, {Key: model.MIGRATION_KEY_ADD_CONVERT_CHANNEL_PERMISSIONS, Migration: a.getAddConvertChannelPermissionsMigration}, {Key: model.MIGRATION_KEY_ADD_MANAGE_SHARED_CHANNEL_PERMISSIONS, Migration: a.getAddManageSharedChannelsPermissionsMigration}, - {Key: model.MIGRATION_KEY_ADD_MANAGE_REMOTE_CLUSTERS_PERMISSIONS, Migration: a.getAddManageRemoteClustersPermissionsMigration}, + {Key: model.MIGRATION_KEY_ADD_MANAGE_SECURE_CONNECTIONS_PERMISSIONS, Migration: a.getAddManageSecureConnectionsPermissionsMigration}, {Key: model.MIGRATION_KEY_ADD_SYSTEM_ROLES_PERMISSIONS, Migration: a.getSystemRolesPermissionsMigration}, {Key: model.MIGRATION_KEY_ADD_BILLING_PERMISSIONS, Migration: a.getBillingPermissionsMigration}, {Key: model.MIGRATION_KEY_ADD_DOWNLOAD_COMPLIANCE_EXPORT_RESULTS, Migration: a.getAddDownloadComplianceExportResult}, diff --git a/app/remote_cluster_test.go b/app/remote_cluster_test.go index 69d99b00a1..b93b33f98f 100644 --- a/app/remote_cluster_test.go +++ b/app/remote_cluster_test.go @@ -10,19 +10,20 @@ import ( "github.com/stretchr/testify/require" "github.com/mattermost/mattermost-server/v5/model" + "github.com/mattermost/mattermost-server/v5/shared/i18n" ) func TestAddRemoteCluster(t *testing.T) { - t.Run("adding remote cluster with duplicate site url and remote team id", func(t *testing.T) { - th := Setup(t).InitBasic() - defer th.TearDown() + th := Setup(t).InitBasic() + defer th.TearDown() + t.Run("adding remote cluster with duplicate site url and remote team id", func(t *testing.T) { remoteCluster := &model.RemoteCluster{ RemoteTeamId: model.NewId(), - Name: "test", - SiteURL: "http://localhost:8065", - Token: "test", - RemoteToken: "test", + Name: "test1", + SiteURL: "http://www1.example.com:8065", + Token: model.NewId(), + RemoteToken: model.NewId(), Topics: "", CreatorId: th.BasicUser.Id, } @@ -33,19 +34,16 @@ func TestAddRemoteCluster(t *testing.T) { remoteCluster.RemoteId = model.NewId() _, err = th.App.AddRemoteCluster(remoteCluster) require.NotNil(t, err, "Adding a duplicate remote cluster should error") - assert.Contains(t, err.Error(), "Remote cluster has already been added.") + assert.Contains(t, err.Error(), i18n.T("api.remote_cluster.save_not_unique.app_error")) }) t.Run("adding remote cluster with duplicate site url or remote team id is allowed", func(t *testing.T) { - th := Setup(t).InitBasic() - defer th.TearDown() - remoteCluster := &model.RemoteCluster{ RemoteTeamId: model.NewId(), - Name: "test", - SiteURL: "http://localhost:8065", - Token: "test", - RemoteToken: "test", + Name: "test2", + SiteURL: "http://www2.exmaple.com:8065", + Token: model.NewId(), + RemoteToken: model.NewId(), Topics: "", CreatorId: th.BasicUser.Id, } @@ -70,26 +68,26 @@ func TestAddRemoteCluster(t *testing.T) { } func TestUpdateRemoteCluster(t *testing.T) { - t.Run("update remote cluster with an already existing site url and team id", func(t *testing.T) { - th := Setup(t).InitBasic() - defer th.TearDown() + th := Setup(t).InitBasic() + defer th.TearDown() + t.Run("update remote cluster with an already existing site url and team id", func(t *testing.T) { remoteCluster := &model.RemoteCluster{ RemoteTeamId: model.NewId(), - Name: "test", - SiteURL: "http://localhost:8065", - Token: "test", - RemoteToken: "test", + Name: "test3", + SiteURL: "http://www3.exmaple.com:8065", + Token: model.NewId(), + RemoteToken: model.NewId(), Topics: "", CreatorId: th.BasicUser.Id, } otherRemoteCluster := &model.RemoteCluster{ RemoteTeamId: model.NewId(), - Name: "test", - SiteURL: "http://localhost:8066", - Token: "test", - RemoteToken: "test", + Name: "test4", + SiteURL: "http://www4.example.com:8066", + Token: model.NewId(), + RemoteToken: model.NewId(), Topics: "", CreatorId: th.BasicUser.Id, } @@ -104,29 +102,26 @@ func TestUpdateRemoteCluster(t *testing.T) { savedRemoteClustered.RemoteTeamId = remoteCluster.RemoteTeamId _, err = th.App.UpdateRemoteCluster(savedRemoteClustered) require.NotNil(t, err, "Updating remote cluster with duplicate site url should error") - assert.Contains(t, err.Error(), "Remote cluster with the same url already exists.") + assert.Contains(t, err.Error(), i18n.T("api.remote_cluster.update_not_unique.app_error")) }) t.Run("update remote cluster with an already existing site url or team id, is allowed", func(t *testing.T) { - th := Setup(t).InitBasic() - defer th.TearDown() - remoteCluster := &model.RemoteCluster{ RemoteTeamId: model.NewId(), - Name: "test", - SiteURL: "http://localhost:8065", - Token: "test", - RemoteToken: "test", + Name: "test5", + SiteURL: "http://www5.example.com:8065", + Token: model.NewId(), + RemoteToken: model.NewId(), Topics: "", CreatorId: th.BasicUser.Id, } otherRemoteCluster := &model.RemoteCluster{ RemoteTeamId: model.NewId(), - Name: "test", - SiteURL: "http://localhost:8066", - Token: "test", - RemoteToken: "test", + Name: "test6", + SiteURL: "http://www6.example.com:8065", + Token: model.NewId(), + RemoteToken: model.NewId(), Topics: "", CreatorId: th.BasicUser.Id, } diff --git a/app/shared_channel_notifier.go b/app/shared_channel_notifier.go index d2901d1dbe..e04db7e514 100644 --- a/app/shared_channel_notifier.go +++ b/app/shared_channel_notifier.go @@ -117,7 +117,7 @@ func handleInvitation(s *Server, syncService SharedChannelServiceIFace, event *m return errors.Wrap(err, fmt.Sprintf("couldn't find remote cluster %s, for creating shared channel invitation for a DM", *participant.RemoteId)) } - return syncService.SendChannelInvite(channel, creator.Id, "", rc, sharedchannel.WithDirectParticipantID(creator.Id), sharedchannel.WithDirectParticipantID(participant.Id)) + return syncService.SendChannelInvite(channel, creator.Id, rc, sharedchannel.WithDirectParticipantID(creator.Id), sharedchannel.WithDirectParticipantID(participant.Id)) } func getUserFromEvent(s *Server, event *model.WebSocketEvent, key string) (*model.User, error) { diff --git a/app/shared_channel_service_iface.go b/app/shared_channel_service_iface.go index fd2ae1e6e7..a074884f3b 100644 --- a/app/shared_channel_service_iface.go +++ b/app/shared_channel_service_iface.go @@ -13,7 +13,7 @@ type SharedChannelServiceIFace interface { Shutdown() error Start() error NotifyChannelChanged(channelId string) - SendChannelInvite(channel *model.Channel, userId string, description string, rc *model.RemoteCluster, options ...sharedchannel.InviteOption) error + SendChannelInvite(channel *model.Channel, userId string, rc *model.RemoteCluster, options ...sharedchannel.InviteOption) error Active() bool } @@ -56,7 +56,7 @@ func (mrcs *mockSharedChannelService) Active() bool { return mrcs.active } -func (mrcs *mockSharedChannelService) SendChannelInvite(channel *model.Channel, userId string, description string, rc *model.RemoteCluster, options ...sharedchannel.InviteOption) error { +func (mrcs *mockSharedChannelService) SendChannelInvite(channel *model.Channel, userId string, rc *model.RemoteCluster, options ...sharedchannel.InviteOption) error { mrcs.numInvitations += 1 return nil } diff --git a/app/slashcommands/command_remote.go b/app/slashcommands/command_remote.go index 43a32e69ab..99fd913afa 100644 --- a/app/slashcommands/command_remote.go +++ b/app/slashcommands/command_remote.go @@ -15,14 +15,14 @@ import ( ) const ( - AvailableRemoteActions = "invite, accept, remove, status" + AvailableRemoteActions = "create, accept, remove, status" ) type RemoteProvider struct { } const ( - CommandTriggerRemote = "remote" + CommandTriggerRemote = "secure-connection" ) func init() { @@ -37,23 +37,23 @@ func (rp *RemoteProvider) GetCommand(a *app.App, T i18n.TranslateFunc) *model.Co remote := model.NewAutocompleteData(rp.GetTrigger(), "[action]", T("api.command_remote.remote_add_remove.help", map[string]interface{}{"Actions": AvailableRemoteActions})) - invite := model.NewAutocompleteData("invite", "", T("api.command_remote.invite.help")) - invite.AddNamedTextArgument("password", T("api.command_remote.invite_password.help"), T("api.command_remote.invite_password.hint"), "", true) - invite.AddNamedTextArgument("name", T("api.command_remote.name.help"), T("api.command_remote.name.hint"), "", true) - invite.AddNamedTextArgument("displayname", T("api.command_remote.displayname.help"), T("api.command_remote.displayname.hint"), "", false) + create := model.NewAutocompleteData("create", "", T("api.command_remote.invite.help")) + create.AddNamedTextArgument("name", T("api.command_remote.name.help"), T("api.command_remote.name.hint"), "", true) + create.AddNamedTextArgument("displayname", T("api.command_remote.displayname.help"), T("api.command_remote.displayname.hint"), "", false) + create.AddNamedTextArgument("password", T("api.command_remote.invite_password.help"), T("api.command_remote.invite_password.hint"), "", true) accept := model.NewAutocompleteData("accept", "", T("api.command_remote.accept.help")) - accept.AddNamedTextArgument("password", T("api.command_remote.invite_password.help"), T("api.command_remote.invite_password.hint"), "", true) accept.AddNamedTextArgument("name", T("api.command_remote.name.help"), T("api.command_remote.name.hint"), "", true) accept.AddNamedTextArgument("displayname", T("api.command_remote.displayname.help"), T("api.command_remote.displayname.hint"), "", false) + accept.AddNamedTextArgument("password", T("api.command_remote.invite_password.help"), T("api.command_remote.invite_password.hint"), "", true) accept.AddNamedTextArgument("invite", T("api.command_remote.invitation.help"), T("api.command_remote.invitation.hint"), "", true) remove := model.NewAutocompleteData("remove", "", T("api.command_remote.remove.help")) - remove.AddNamedDynamicListArgument("remoteId", T("api.command_remote.remove_remote_id.help"), "builtin:remote", true) + remove.AddNamedDynamicListArgument("connectionID", T("api.command_remote.remove_remote_id.help"), "builtin:"+CommandTriggerRemote, true) status := model.NewAutocompleteData("status", "", T("api.command_remote.status.help")) - remote.AddCommand(invite) + remote.AddCommand(create) remote.AddCommand(accept) remote.AddCommand(remove) remote.AddCommand(status) @@ -69,8 +69,8 @@ func (rp *RemoteProvider) GetCommand(a *app.App, T i18n.TranslateFunc) *model.Co } func (rp *RemoteProvider) DoCommand(a *app.App, args *model.CommandArgs, message string) *model.CommandResponse { - if !a.HasPermissionTo(args.UserId, model.PERMISSION_MANAGE_SHARED_CHANNELS) { - return responsef(args.T("api.command_remote.permission_required", map[string]interface{}{"Permission": "manage_shared_channels"})) + if !a.HasPermissionTo(args.UserId, model.PERMISSION_MANAGE_SECURE_CONNECTIONS) { + return responsef(args.T("api.command_remote.permission_required", map[string]interface{}{"Permission": "manage_secure_connections"})) } margs := parseNamedArgs(args.Command) @@ -80,8 +80,8 @@ func (rp *RemoteProvider) DoCommand(a *app.App, args *model.CommandArgs, message } switch action { - case "invite": - return rp.doInvite(a, args, margs) + case "create": + return rp.doCreate(a, args, margs) case "accept": return rp.doAccept(a, args, margs) case "remove": @@ -94,19 +94,19 @@ func (rp *RemoteProvider) DoCommand(a *app.App, args *model.CommandArgs, message } func (rp *RemoteProvider) GetAutoCompleteListItems(a *app.App, commandArgs *model.CommandArgs, arg *model.AutocompleteArg, parsed, toBeParsed string) ([]model.AutocompleteListItem, error) { - if !a.HasPermissionTo(commandArgs.UserId, model.PERMISSION_MANAGE_SHARED_CHANNELS) { - return nil, errors.New("You require `manage_shared_channels` permission to manage remote clusters.") + if !a.HasPermissionTo(commandArgs.UserId, model.PERMISSION_MANAGE_SECURE_CONNECTIONS) { + return nil, errors.New("You require `manage_secure_connections` permission to manage secure connections.") } - if arg.Name == "remoteId" && strings.Contains(parsed, " remove ") { + if arg.Name == "connectionID" && strings.Contains(parsed, " remove ") { return getRemoteClusterAutocompleteListItems(a, true) } return nil, fmt.Errorf("`%s` is not a dynamic argument", arg.Name) } -// doInvite creates and displays an encrypted invite that can be used by a remote site to establish a simple trust. -func (rp *RemoteProvider) doInvite(a *app.App, args *model.CommandArgs, margs map[string]string) *model.CommandResponse { +// doCreate creates and displays an encrypted invite that can be used by a remote site to establish a simple trust. +func (rp *RemoteProvider) doCreate(a *app.App, args *model.CommandArgs, margs map[string]string) *model.CommandResponse { password := margs["password"] if password == "" { return responsef(args.T("api.command_remote.missing_empty", map[string]interface{}{"Arg": "password"})) @@ -153,7 +153,7 @@ func (rp *RemoteProvider) doInvite(a *app.App, args *model.CommandArgs, margs ma encoded := base64.URLEncoding.EncodeToString(encrypted) return responsef("##### " + args.T("api.command_remote.invitation_created") + "\n" + - args.T("api.command_remote.invite_summary", map[string]interface{}{"Command": "/remote accept", "Invitation": encoded, "SiteURL": invite.SiteURL})) + args.T("api.command_remote.invite_summary", map[string]interface{}{"Command": "/secure-connection accept", "Invitation": encoded, "SiteURL": invite.SiteURL})) } // doAccept accepts an invitation generated by a remote site. @@ -209,7 +209,7 @@ func (rp *RemoteProvider) doAccept(a *app.App, args *model.CommandArgs, margs ma // doRemove removes a remote cluster from the database, effectively revoking the trust relationship. func (rp *RemoteProvider) doRemove(a *app.App, args *model.CommandArgs, margs map[string]string) *model.CommandResponse { - id, ok := margs["remoteId"] + id, ok := margs["connectionID"] if !ok { return responsef(args.T("api.command_remote.missing_empty", map[string]interface{}{"Arg": "remoteId"})) } @@ -238,23 +238,16 @@ func (rp *RemoteProvider) doStatus(a *app.App, args *model.CommandArgs, _ map[st } var sb strings.Builder - fmt.Fprintf(&sb, args.T("api.command_remote.remote_table_header")+"| \n") - fmt.Fprintf(&sb, "| ---- | -------- | ---------- | :-------------: | :----: | ---------- |\n") + fmt.Fprintf(&sb, args.T("api.command_remote.remote_table_header")+" \n") + // | Secure Connection | Display name | ConnectionID | Site URL | Invite accepted | Online | Last ping | + fmt.Fprintf(&sb, "| :---- | :---- | :---- | :---- | :---- | :---- | :---- | \n") for _, rc := range list { - accepted := ":white_check_mark:" - if rc.SiteURL == "" { - accepted = ":x:" - } + accepted := formatBool(args.T, rc.SiteURL != "") + online := formatBool(args.T, isOnline(rc.LastPingAt)) + lastPing := formatTimestamp(rc.LastPingAt) - online := ":white_check_mark:" - if !isOnline(rc.LastPingAt) { - online = ":skull_and_crossbones:" - } - - lastPing := formatTimestamp(model.GetTimeForMillis(rc.LastPingAt)) - - fmt.Fprintf(&sb, "| %s | %s | %s | %s | %s | %s | %s |\n", rc.Name, rc.DisplayName, rc.SiteURL, rc.RemoteId, accepted, online, lastPing) + fmt.Fprintf(&sb, "| %s | %s | %s | %s | %s | %s | %s |\n", rc.Name, rc.DisplayName, rc.RemoteId, rc.SiteURL, accepted, online, lastPing) } return responsef(sb.String()) } diff --git a/app/slashcommands/command_share.go b/app/slashcommands/command_share.go index 2bbcc3c13d..29685a91ac 100644 --- a/app/slashcommands/command_share.go +++ b/app/slashcommands/command_share.go @@ -17,8 +17,8 @@ type ShareProvider struct { } const ( - CommandTriggerShare = "share" - AvailableShareActions = "share_channel, unshare_channel, invite_remove, uninvite_remote, status" + CommandTriggerShare = "share-channel" + AvailableShareActions = "invite, uninvite, unshare, status" ) func init() { @@ -32,29 +32,20 @@ func (sp *ShareProvider) GetTrigger() string { func (sp *ShareProvider) GetCommand(a *app.App, T i18n.TranslateFunc) *model.Command { share := model.NewAutocompleteData(CommandTriggerShare, "[action]", T("api.command_share.available_actions", map[string]interface{}{"Actions": AvailableShareActions})) - shareChannel := model.NewAutocompleteData("share_channel", "", T("api.command_share.share_current")) - shareChannel.AddNamedTextArgument("readonly", T("api.command_share.share_read_only.help"), T("api.command_share.share_read_only.hint"), "Y|N|y|n", false) - shareChannel.AddNamedTextArgument("name", T("api.command_share.channel_name.help"), T("api.command_share.channel_name.hint"), "", false) - shareChannel.AddNamedTextArgument("displayname", T("api.command_share.channel_display_name.help"), T("api.command_share.channel_display_name.hint"), "", false) - shareChannel.AddNamedTextArgument("purpose", T("api.command_share.channel_purpose.help"), T("api.command_share.channel_purpose.hint"), "", false) - shareChannel.AddNamedTextArgument("header", T("api.command_share.channel_header.help"), T("api.command_share.channel_header.hint"), "", false) + inviteRemote := model.NewAutocompleteData("invite", "", T("api.command_share.invite_remote.help")) + inviteRemote.AddNamedDynamicListArgument("connectionID", T("api.command_share.remote_id.help"), "builtin:"+CommandTriggerShare, true) + inviteRemote.AddNamedTextArgument("readonly", T("api.command_share.share_read_only.help"), T("api.command_share.share_read_only.hint"), "Y|N|y|n", false) - unshareChannel := model.NewAutocompleteData("unshare_channel", "", T("api.command_share.unshare_channel.help")) - unshareChannel.AddNamedTextArgument("are_you_sure", T("api.command_share.unshare_confirmation.help"), T("api.command_share.unshare_confirmation.hint"), "Y|N|y|n", true) + unInviteRemote := model.NewAutocompleteData("uninvite", "", T("api.command_share.uninvite_remote.help")) + unInviteRemote.AddNamedDynamicListArgument("connectionID", T("api.command_share.uninvite_remote_id.help"), "builtin:"+CommandTriggerShare, true) - inviteRemote := model.NewAutocompleteData("invite_remote", "", T("api.command_share.invite_remote.help")) - inviteRemote.AddNamedDynamicListArgument("remoteId", T("api.command_share.remote_id.help"), "builtin:share", true) - inviteRemote.AddNamedTextArgument("description", T("api.command_share.description_invite.help"), T("api.command_share.description_invite.hint"), "", false) - - unInviteRemote := model.NewAutocompleteData("uninvite_remote", "", T("api.command_share.uninvite_remote.help")) - unInviteRemote.AddNamedDynamicListArgument("remoteId", T("api.command_share.uninvite_remote_id.help"), "builtin:share", true) + unshareChannel := model.NewAutocompleteData("unshare", "", T("api.command_share.unshare_channel.help")) status := model.NewAutocompleteData("status", "", T("api.command_share.channel_status.help")) - share.AddCommand(shareChannel) - share.AddCommand(unshareChannel) share.AddCommand(inviteRemote) share.AddCommand(unInviteRemote) + share.AddCommand(unshareChannel) share.AddCommand(status) return &model.Command{ @@ -69,15 +60,15 @@ func (sp *ShareProvider) GetCommand(a *app.App, T i18n.TranslateFunc) *model.Com func (sp *ShareProvider) GetAutoCompleteListItems(a *app.App, commandArgs *model.CommandArgs, arg *model.AutocompleteArg, parsed, toBeParsed string) ([]model.AutocompleteListItem, error) { switch { - case strings.Contains(parsed, " share_channel "): + case strings.Contains(parsed, " share "): return sp.getAutoCompleteShareChannel(a, commandArgs, arg) - case strings.Contains(parsed, " invite_remote "): + case strings.Contains(parsed, " invite "): return sp.getAutoCompleteInviteRemote(a, commandArgs, arg) - case strings.Contains(parsed, " uninvite_remote "): + case strings.Contains(parsed, " uninvite "): return sp.getAutoCompleteUnInviteRemote(a, commandArgs, arg) @@ -112,7 +103,7 @@ func (sp *ShareProvider) getAutoCompleteShareChannel(a *app.App, commandArgs *mo func (sp *ShareProvider) getAutoCompleteInviteRemote(a *app.App, commandArgs *model.CommandArgs, arg *model.AutocompleteArg) ([]model.AutocompleteListItem, error) { switch arg.Name { - case "remoteId": + case "connectionID": return getRemoteClusterAutocompleteListItemsNotInChannel(a, commandArgs.ChannelId, true) default: return nil, fmt.Errorf("%s not a dynamic argument", arg.Name) @@ -121,7 +112,7 @@ func (sp *ShareProvider) getAutoCompleteInviteRemote(a *app.App, commandArgs *mo func (sp *ShareProvider) getAutoCompleteUnInviteRemote(a *app.App, _ *model.CommandArgs, arg *model.AutocompleteArg) ([]model.AutocompleteListItem, error) { switch arg.Name { - case "remoteId": + case "connectionID": return getRemoteClusterAutocompleteListItems(a, true) default: return nil, fmt.Errorf("%s not a dynamic argument", arg.Name) @@ -148,13 +139,13 @@ func (sp *ShareProvider) DoCommand(a *app.App, args *model.CommandArgs, message } switch action { - case "share_channel": + case "share": return sp.doShareChannel(a, args, margs) - case "unshare_channel": + case "unshare": return sp.doUnshareChannel(a, args, margs) - case "invite_remote": + case "invite": return sp.doInviteRemote(a, args, margs) - case "uninvite_remote": + case "uninvite": return sp.doUninviteRemote(a, args, margs) case "status": return sp.doStatus(a, args, margs) @@ -212,15 +203,6 @@ func (sp *ShareProvider) doShareChannel(a *app.App, args *model.CommandArgs, mar } func (sp *ShareProvider) doUnshareChannel(a *app.App, args *model.CommandArgs, margs map[string]string) *model.CommandResponse { - if _, ok := margs["are_you_sure"]; !ok { - margs["are_you_sure"] = "N" - } - - sure, err := parseBool(margs["are_you_sure"]) - if err != nil || !sure { - return responsef(args.T("api.command_share.shared_channel_not_deleted", map[string]interface{}{"Arg": "are_you_sure", "Expected": "Y"})) - } - sc, appErr := a.GetSharedChannel(args.ChannelId) if appErr != nil { return responsef(args.T("api.command_share.shared_channel_unshare.error", map[string]interface{}{"Error": appErr.Error()})) @@ -240,7 +222,7 @@ func (sp *ShareProvider) doUnshareChannel(a *app.App, args *model.CommandArgs, m } func (sp *ShareProvider) doInviteRemote(a *app.App, args *model.CommandArgs, margs map[string]string) (resp *model.CommandResponse) { - remoteId, ok := margs["remoteId"] + remoteId, ok := margs["connectionID"] if !ok || remoteId == "" { return responsef(args.T("api.command_share.must_specify_valid_remote")) } @@ -284,7 +266,7 @@ func (sp *ShareProvider) doInviteRemote(a *app.App, args *model.CommandArgs, mar return responsef(args.T("api.command_share.channel_invite.error", map[string]interface{}{"Name": rc.DisplayName, "Error": errApp.Error()})) } // send channel invite to remote cluster - if err := a.Srv().GetSharedChannelSyncService().SendChannelInvite(channel, args.UserId, margs["description"], rc); err != nil { + if err := a.Srv().GetSharedChannelSyncService().SendChannelInvite(channel, args.UserId, rc); err != nil { return responsef(args.T("api.command_share.channel_invite.error", map[string]interface{}{"Name": rc.DisplayName, "Error": err.Error()})) } @@ -292,7 +274,7 @@ func (sp *ShareProvider) doInviteRemote(a *app.App, args *model.CommandArgs, mar } func (sp *ShareProvider) doUninviteRemote(a *app.App, args *model.CommandArgs, margs map[string]string) *model.CommandResponse { - remoteId, ok := margs["remoteId"] + remoteId, ok := margs["connectionID"] if !ok || remoteId == "" { return responsef(args.T("api.command_share.remote_not_valid")) } @@ -323,19 +305,18 @@ func (sp *ShareProvider) doStatus(a *app.App, args *model.CommandArgs, _ map[str fmt.Fprintf(&sb, args.T("api.command_share.channel_status_id", map[string]interface{}{"ChannelId": statuses[0].ChannelId})+"\n\n") fmt.Fprintf(&sb, args.T("api.command_share.remote_table_header")+" \n") - fmt.Fprintf(&sb, "| ------ | ------- | ----------- | -------- | -------------- | ------ | --------- | \n") + // "| Secure Connection | SiteURL | ReadOnly | InviteAccepted | Online | Last Sync |" + fmt.Fprintf(&sb, "| ---- | ---- | ---- | ---- | ---- | ---- | \n") for _, status := range statuses { - online := ":white_check_mark:" - if !isOnline(status.LastPingAt) { - online = ":skull_and_crossbones:" - } + readonly := formatBool(args.T, status.ReadOnly) + accepted := formatBool(args.T, status.IsInviteAccepted) + online := formatBool(args.T, isOnline(status.LastPingAt)) - lastSync := formatTimestamp(model.GetTimeForMillis(status.NextSyncAt)) + lastSync := formatTimestamp(status.NextSyncAt) - fmt.Fprintf(&sb, "| %s | %s | %s | %t | %t | %s | %s |\n", - status.DisplayName, status.SiteURL, status.Description, - status.ReadOnly, status.IsInviteAccepted, online, lastSync) + fmt.Fprintf(&sb, "| %s | %s | %s | %s | %s | %s |\n", + status.DisplayName, status.SiteURL, readonly, accepted, online, lastSync) } return responsef(sb.String()) } diff --git a/app/slashcommands/command_share_test.go b/app/slashcommands/command_share_test.go index 0517b8ca1f..c3787d5f73 100644 --- a/app/slashcommands/command_share_test.go +++ b/app/slashcommands/command_share_test.go @@ -37,12 +37,13 @@ func TestShareProviderDoCommand(t *testing.T) { commandProvider := ShareProvider{} channel := th.CreateChannel(th.BasicTeam, WithShared(false)) + args := &model.CommandArgs{ T: func(s string, args ...interface{}) string { return s }, ChannelId: channel.Id, UserId: th.BasicUser.Id, TeamId: th.BasicTeam.Id, - Command: "/share share_channel", + Command: "/share-channel share", } response := commandProvider.DoCommand(th.App, args, "") @@ -77,7 +78,7 @@ func TestShareProviderDoCommand(t *testing.T) { ChannelId: channel.Id, UserId: th.BasicUser.Id, TeamId: th.BasicTeam.Id, - Command: "/share unshare_channel --are_you_sure Y", + Command: "/share-channel unshare", } response := commandProvider.DoCommand(th.App, args, "") diff --git a/app/slashcommands/util.go b/app/slashcommands/util.go index e7bb0462f9..e61bb142a1 100644 --- a/app/slashcommands/util.go +++ b/app/slashcommands/util.go @@ -9,6 +9,7 @@ import ( "time" "github.com/mattermost/mattermost-server/v5/model" + "github.com/mattermost/mattermost-server/v5/shared/i18n" ) const ( @@ -72,12 +73,25 @@ func parseBool(s string) (bool, error) { return false, fmt.Errorf("cannot parse '%s' as a boolean", s) } -func formatTimestamp(ts time.Time) string { +func formatBool(fn i18n.TranslateFunc, b bool) string { + if b { + return fn("True") + } + return fn("False") +} + +func formatTimestamp(timestamp int64) string { + if timestamp == 0 { + return "--" + } + + ts := model.GetTimeForMillis(timestamp) + if !isToday(ts) { return ts.Format("Jan 2 15:04:05 MST 2006") } date := ts.Format("15:04:05 MST 2006") - return fmt.Sprintf("today %s", date) + return fmt.Sprintf("Today %s", date) } func isToday(ts time.Time) bool { diff --git a/i18n/en.json b/i18n/en.json index cae1af740a..b375f0d7c2 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -1104,11 +1104,11 @@ }, { "id": "api.command_remote.add_remote.error", - "translation": "Could not add remote cluster: {{.Error}}" + "translation": "Could not add secure connection: {{.Error}}" }, { "id": "api.command_remote.cluster_removed", - "translation": "Remote cluster {{.RemoteId}} {{.Result}}." + "translation": "Secure connection {{.RemoteId}} {{.Result}}." }, { "id": "api.command_remote.decode_invitation.error", @@ -1120,11 +1120,11 @@ }, { "id": "api.command_remote.displayname.help", - "translation": "Remote cluster display name" + "translation": "Secure connection display name" }, { "id": "api.command_remote.displayname.hint", - "translation": "A display name for the remote cluster" + "translation": "A display name for the secure connection" }, { "id": "api.command_remote.encrypt_invitation.error", @@ -1132,7 +1132,7 @@ }, { "id": "api.command_remote.fetch_status.error", - "translation": "Could not fetch remote clusters: {{.Error}}" + "translation": "Could not fetch secure connections: {{.Error}}" }, { "id": "api.command_remote.hint", @@ -1144,11 +1144,11 @@ }, { "id": "api.command_remote.invitation.help", - "translation": "Invitation from remote cluster" + "translation": "Invitation from secure connection" }, { "id": "api.command_remote.invitation.hint", - "translation": "The encrypted invitation from a remote cluster" + "translation": "The encrypted invitation from a secure connection" }, { "id": "api.command_remote.invitation_created", @@ -1156,7 +1156,7 @@ }, { "id": "api.command_remote.invite.help", - "translation": "Invite a remote cluster" + "translation": "Create a secure connection" }, { "id": "api.command_remote.invite_password.help", @@ -1180,43 +1180,43 @@ }, { "id": "api.command_remote.name", - "translation": "remote" + "translation": "secure-connection" }, { "id": "api.command_remote.name.help", - "translation": "Remote cluster name" + "translation": "Secure connection name" }, { "id": "api.command_remote.name.hint", - "translation": "A unique name for the remote cluster" + "translation": "A unique name for the secure connection" }, { "id": "api.command_remote.permission_required", - "translation": "You require `{{.Permission}}` permission to manage remote clusters." + "translation": "You require `{{.Permission}}` permission to manage secure connections." }, { "id": "api.command_remote.remote_add_remove.help", - "translation": "Add/remove remote clusters. Available actions: {{.Actions}}" + "translation": "Add/remove secure connections. Available actions: {{.Actions}}" }, { "id": "api.command_remote.remote_table_header", - "translation": "| Name | SiteURL | RemoteId | Invite Accepted | Online | Last Ping |" + "translation": "| Secure Connection | Display name | ConnectionID | Site URL | Invite accepted | Online | Last ping |" }, { "id": "api.command_remote.remotes_not_found", - "translation": "No remote clusters found." + "translation": "No secure connections found." }, { "id": "api.command_remote.remove.help", - "translation": "Removes a remote cluster" + "translation": "Removes a secure connection" }, { "id": "api.command_remote.remove_remote.error", - "translation": "Could not remove remote cluster: {{.Error}}" + "translation": "Could not remove secure connection: {{.Error}}" }, { "id": "api.command_remote.remove_remote_id.help", - "translation": "Id of remote cluster remove" + "translation": "Id of secure connection remove" }, { "id": "api.command_remote.service_disabled", @@ -1232,7 +1232,7 @@ }, { "id": "api.command_remote.status.help", - "translation": "Displays status for all remote clusters" + "translation": "Displays status for all secure connections" }, { "id": "api.command_remote.unknown_action", @@ -1306,49 +1306,17 @@ "id": "api.command_share.available_actions", "translation": "Available actions: {{.Actions}}" }, - { - "id": "api.command_share.channel_display_name.help", - "translation": "Channel display name provided to remote instances" - }, - { - "id": "api.command_share.channel_display_name.hint", - "translation": "[displayname] - defaults to channel displayname" - }, - { - "id": "api.command_share.channel_header.help", - "translation": "Channel header provided to remote instances" - }, - { - "id": "api.command_share.channel_header.hint", - "translation": "[header] - defaults to channels header" - }, { "id": "api.command_share.channel_invite.error", "translation": "Error inviting `{{.Name}}` to this channel: {{.Error}}" }, { "id": "api.command_share.channel_invite_not_home.error", - "translation": "Cannot invite remote cluster to a shared channel originating somewhere else." - }, - { - "id": "api.command_share.channel_name.help", - "translation": "Channel name provided to remote instances" - }, - { - "id": "api.command_share.channel_name.hint", - "translation": "[name] - defaults to channel name" - }, - { - "id": "api.command_share.channel_purpose.help", - "translation": "Channel purpose provided to remote instances" - }, - { - "id": "api.command_share.channel_purpose.hint", - "translation": "[purpose] - defaults to channel purpose" + "translation": "Cannot invite secure connection to a shared channel originating somewhere else." }, { "id": "api.command_share.channel_remote_id_not_exists", - "translation": "Shared channel remote id `{{.RemoteId}}` does not exist for this channel." + "translation": "Shared channel secure connection `{{.RemoteId}}` does not exist for this channel." }, { "id": "api.command_share.channel_shared", @@ -1374,21 +1342,13 @@ "id": "api.command_share.desc", "translation": "Shares the current channel with a remote Mattermost instance." }, - { - "id": "api.command_share.description_invite.help", - "translation": "Description for invite" - }, - { - "id": "api.command_share.description_invite.hint", - "translation": "[description] - optional" - }, { "id": "api.command_share.fetch_remote.error", - "translation": "Error fetching remote clusters: {{.Error}}" + "translation": "Error fetching shared connections: {{.Error}}" }, { "id": "api.command_share.fetch_remote_status.error", - "translation": "Could not fetch status for remotes: {{.Error}}." + "translation": "Could not fetch status for secure connections: {{.Error}}." }, { "id": "api.command_share.hint", @@ -1412,15 +1372,15 @@ }, { "id": "api.command_share.must_specify_valid_remote", - "translation": "Must specify a valid remote cluster id to invite." + "translation": "Must specify a valid secure connection id to invite." }, { "id": "api.command_share.name", - "translation": "share" + "translation": "share-channel" }, { "id": "api.command_share.no_remote_invited", - "translation": "No remotes have been invited to this shared channel." + "translation": "No secure connections have been invited to this shared channel." }, { "id": "api.command_share.not_shared_channel_unshare", @@ -1432,27 +1392,27 @@ }, { "id": "api.command_share.remote_already_invited", - "translation": "The remote cluster has already been invited." + "translation": "The secure connection has already been invited." }, { "id": "api.command_share.remote_id.help", - "translation": "Id of an existing remote instance. See `remote` command to add a remote instance." + "translation": "Id of an existing secure connection. See `secure-connection` command to add a secure connection." }, { "id": "api.command_share.remote_id_invalid.error", - "translation": "Remote cluster id is invalid: {{.Error}}" + "translation": "Secure connection id is invalid: {{.Error}}" }, { "id": "api.command_share.remote_not_valid", - "translation": "Must specify a valid remote cluster to uninvite" + "translation": "Must specify a valid secure connection id to uninvite" }, { "id": "api.command_share.remote_table_header", - "translation": "| Remote | SiteURL | Description | ReadOnly | InviteAccepted | Online | Last Sync |" + "translation": "| Secure Connection | SiteURL | ReadOnly | InviteAccepted | Online | Last Sync |" }, { "id": "api.command_share.remote_uninvited", - "translation": "Remote `{{.RemoteId}}` uninvited." + "translation": "Secure connection `{{.RemoteId}}` uninvited." }, { "id": "api.command_share.service_disabled", @@ -1462,10 +1422,6 @@ "id": "api.command_share.share_channel.error", "translation": "Cannot share this channel: {{.Error}}" }, - { - "id": "api.command_share.share_current", - "translation": "Share the current channel" - }, { "id": "api.command_share.share_read_only.help", "translation": "Channel will be shared in read-only mode" @@ -1474,10 +1430,6 @@ "id": "api.command_share.share_read_only.hint", "translation": "[readonly] - 'Y' or 'N'. Defaults to 'N'" }, - { - "id": "api.command_share.shared_channel_not_deleted", - "translation": "Shared channel was not deleted: `{{.Arg}}` must be `{{.Expected}}`." - }, { "id": "api.command_share.shared_channel_unavailable", "translation": "This channel is no longer shared." @@ -1488,11 +1440,11 @@ }, { "id": "api.command_share.uninvite_remote.help", - "translation": "Uninvites a remote instance from this shared channel" + "translation": "Uninvites a secure connection from this shared channel" }, { "id": "api.command_share.uninvite_remote_id.help", - "translation": "Id of remote instance to uninvite." + "translation": "Id of secure connection to uninvite." }, { "id": "api.command_share.unknown_action", @@ -1502,14 +1454,6 @@ "id": "api.command_share.unshare_channel.help", "translation": "Unshares the current channel" }, - { - "id": "api.command_share.unshare_confirmation.help", - "translation": "Are you sure? This channel will be unshared and all remote instances will be uninvited" - }, - { - "id": "api.command_share.unshare_confirmation.hint", - "translation": "'Y' or 'N'" - }, { "id": "api.command_shortcuts.desc", "translation": "Displays a list of keyboard shortcuts" @@ -1608,15 +1552,15 @@ }, { "id": "api.context.remote_id_invalid.app_error", - "translation": "Unable to find remote cluster id {{.RemoteId}}." + "translation": "Unable to find secure connectionID {{.RemoteId}}." }, { "id": "api.context.remote_id_mismatch.app_error", - "translation": "Remote cluster id mismatch." + "translation": "Secure connection ID mismatch." }, { "id": "api.context.remote_id_missing.app_error", - "translation": "Remote cluster id missing." + "translation": "Secure connection ID missing." }, { "id": "api.context.server_busy.app_error", @@ -2432,11 +2376,11 @@ }, { "id": "api.remote_cluster.delete.app_error", - "translation": "We encountered an error deleting the remote cluster." + "translation": "We encountered an error deleting the secure connection." }, { "id": "api.remote_cluster.get.app_error", - "translation": "We encountered an error retrieving a remote cluster." + "translation": "We encountered an error retrieving a secure connection." }, { "id": "api.remote_cluster.invalid_id.app_error", @@ -2448,11 +2392,11 @@ }, { "id": "api.remote_cluster.save.app_error", - "translation": "We encountered an error saving the remote cluster." + "translation": "We encountered an error saving the secure connection." }, { "id": "api.remote_cluster.save_not_unique.app_error", - "translation": "Remote cluster has already been added." + "translation": "Secure connection has already been added." }, { "id": "api.remote_cluster.service_not_enabled.app_error", @@ -2460,11 +2404,11 @@ }, { "id": "api.remote_cluster.update.app_error", - "translation": "We encountered an error updating the remote cluster." + "translation": "We encountered an error updating the secure connection." }, { "id": "api.remote_cluster.update_not_unique.app_error", - "translation": "Remote cluster with the same url already exists." + "translation": "Secure connection with the same url already exists." }, { "id": "api.restricted_system_admin", @@ -7734,10 +7678,6 @@ "id": "model.channel.is_valid.creator_id.app_error", "translation": "Invalid creator id." }, - { - "id": "model.channel.is_valid.description.app_error", - "translation": "Invalid description." - }, { "id": "model.channel.is_valid.display_name.app_error", "translation": "Invalid display name." diff --git a/model/migration.go b/model/migration.go index 366f8ac207..2a8038e158 100644 --- a/model/migration.go +++ b/model/migration.go @@ -24,7 +24,7 @@ const ( MIGRATION_KEY_ADD_SYSTEM_ROLES_PERMISSIONS = "add_system_roles_permissions" MIGRATION_KEY_ADD_BILLING_PERMISSIONS = "add_billing_permissions" MIGRATION_KEY_ADD_MANAGE_SHARED_CHANNEL_PERMISSIONS = "manage_shared_channel_permissions" - MIGRATION_KEY_ADD_MANAGE_REMOTE_CLUSTERS_PERMISSIONS = "manage_remote_clusters_permissions" + MIGRATION_KEY_ADD_MANAGE_SECURE_CONNECTIONS_PERMISSIONS = "manage_secure_connections_permissions" MIGRATION_KEY_ADD_DOWNLOAD_COMPLIANCE_EXPORT_RESULTS = "download_compliance_export_results" MIGRATION_KEY_ADD_COMPLIANCE_SUBSECTION_PERMISSIONS = "compliance_subsection_permissions" MIGRATION_KEY_ADD_EXPERIMENTAL_SUBSECTION_PERMISSIONS = "experimental_subsection_permissions" diff --git a/model/permission.go b/model/permission.go index 017aee585e..bc4de236f5 100644 --- a/model/permission.go +++ b/model/permission.go @@ -100,7 +100,7 @@ var PERMISSION_USE_GROUP_MENTIONS *Permission var PERMISSION_READ_OTHER_USERS_TEAMS *Permission var PERMISSION_EDIT_BRAND *Permission var PERMISSION_MANAGE_SHARED_CHANNELS *Permission -var PERMISSION_MANAGE_REMOTE_CLUSTERS *Permission +var PERMISSION_MANAGE_SECURE_CONNECTIONS *Permission var PERMISSION_DOWNLOAD_COMPLIANCE_EXPORT_RESULT *Permission var PERMISSION_CREATE_DATA_RETENTION_JOB *Permission var PERMISSION_READ_DATA_RETENTION_JOB *Permission @@ -711,10 +711,10 @@ func initializePermissions() { "authentication.permissions.manage_shared_channels.description", PermissionScopeSystem, } - PERMISSION_MANAGE_REMOTE_CLUSTERS = &Permission{ - "manage_remote_clusters", - "authentication.permissions.manage_remote_clusters.name", - "authentication.permissions.manage_remote_clusters.description", + PERMISSION_MANAGE_SECURE_CONNECTIONS = &Permission{ + "manage_secure_connections", + "authentication.permissions.manage_secure_connections.name", + "authentication.permissions.manage_secure_connections.description", PermissionScopeSystem, } @@ -2041,7 +2041,7 @@ func initializePermissions() { PERMISSION_DEMOTE_TO_GUEST, PERMISSION_EDIT_BRAND, PERMISSION_MANAGE_SHARED_CHANNELS, - PERMISSION_MANAGE_REMOTE_CLUSTERS, + PERMISSION_MANAGE_SECURE_CONNECTIONS, PERMISSION_DOWNLOAD_COMPLIANCE_EXPORT_RESULT, PERMISSION_CREATE_DATA_RETENTION_JOB, PERMISSION_READ_DATA_RETENTION_JOB, diff --git a/model/shared_channel.go b/model/shared_channel.go index 3387db1cea..d9c43567dc 100644 --- a/model/shared_channel.go +++ b/model/shared_channel.go @@ -106,7 +106,6 @@ func (sc *SharedChannel) PreUpdate() { type SharedChannelRemote struct { Id string `json:"id"` ChannelId string `json:"channel_id"` - Description string `json:"description"` CreatorId string `json:"creator_id"` CreateAt int64 `json:"create_at"` UpdateAt int64 `json:"update_at"` @@ -136,10 +135,6 @@ func (sc *SharedChannelRemote) IsValid() *AppError { return NewAppError("SharedChannelRemote.IsValid", "model.channel.is_valid.id.app_error", nil, "ChannelId="+sc.ChannelId, http.StatusBadRequest) } - if len(sc.Description) > 64 { - return NewAppError("SharedChannelRemote.IsValid", "model.channel.is_valid.description.app_error", nil, "description="+sc.Description, http.StatusBadRequest) - } - if sc.CreateAt == 0 { return NewAppError("SharedChannelRemote.IsValid", "model.channel.is_valid.create_at.app_error", nil, "id="+sc.ChannelId, http.StatusBadRequest) } @@ -172,7 +167,6 @@ type SharedChannelRemoteStatus struct { SiteURL string `json:"site_url"` LastPingAt int64 `json:"last_ping_at"` NextSyncAt int64 `json:"next_sync_at"` - Description string `json:"description"` ReadOnly bool `json:"readonly"` IsInviteAccepted bool `json:"is_invite_accepted"` Token string `json:"token"` diff --git a/model/shared_channel_test.go b/model/shared_channel_test.go index d4664c0dda..10cc6bad06 100644 --- a/model/shared_channel_test.go +++ b/model/shared_channel_test.go @@ -76,12 +76,11 @@ func TestSharedChannelPreUpdate(t *testing.T) { } func TestSharedChannelRemoteJson(t *testing.T) { - o := SharedChannelRemote{Id: NewId(), ChannelId: NewId(), Description: "Test"} + o := SharedChannelRemote{Id: NewId(), ChannelId: NewId()} json := o.ToJson() ro, err := SharedChannelRemoteFromJson(strings.NewReader(json)) require.NoError(t, err) require.Equal(t, o.Id, ro.Id) require.Equal(t, o.ChannelId, ro.ChannelId) - require.Equal(t, o.Description, ro.Description) } diff --git a/services/remotecluster/service.go b/services/remotecluster/service.go index d2a6e15d7a..e8726bc598 100644 --- a/services/remotecluster/service.go +++ b/services/remotecluster/service.go @@ -75,7 +75,7 @@ type TopicListener func(msg model.RemoteClusterMsg, rc *model.RemoteCluster, res // ConnectionStateListener is used to listen to remote cluster connection state changes. type ConnectionStateListener func(rc *model.RemoteCluster, online bool) -// Service provides inter-cluster communication via topic based messages. +// Service provides inter-cluster communication via topic based messages. In product these are called "Secured Connections". type Service struct { server ServerIface httpClient *http.Client @@ -90,7 +90,7 @@ type Service struct { done chan struct{} } -// NewRemoteClusterService creates a RemoteClusterService instance. +// NewRemoteClusterService creates a RemoteClusterService instance. In product this is called a "Secured Connection". func NewRemoteClusterService(server ServerIface) (*Service, error) { transport := &http.Transport{ Proxy: http.ProxyFromEnvironment, diff --git a/services/sharedchannel/channelinvite.go b/services/sharedchannel/channelinvite.go index 1ec48d0345..01ad2d3243 100644 --- a/services/sharedchannel/channelinvite.go +++ b/services/sharedchannel/channelinvite.go @@ -38,7 +38,7 @@ func WithDirectParticipantID(participantID string) InviteOption { // SendChannelInvite asynchronously sends a channel invite to a remote cluster. The remote cluster is // expected to create a new channel with the same channel id, and respond with status OK. // If an error occurs on the remote cluster then an ephemeral message is posted to in the channel for userId. -func (scs *Service) SendChannelInvite(channel *model.Channel, userId string, description string, rc *model.RemoteCluster, options ...InviteOption) error { +func (scs *Service) SendChannelInvite(channel *model.Channel, userId string, rc *model.RemoteCluster, options ...InviteOption) error { rcs := scs.server.GetRemoteClusterService() if rcs == nil { return fmt.Errorf("cannot invite remote cluster for channel id %s; Remote Cluster Service not enabled", channel.Id) @@ -82,7 +82,6 @@ func (scs *Service) SendChannelInvite(channel *model.Channel, userId string, des scr := &model.SharedChannelRemote{ ChannelId: sc.ChannelId, - Description: description, CreatorId: userId, RemoteId: rc.RemoteId, IsInviteAccepted: true, @@ -165,7 +164,6 @@ func (scs *Service) onReceiveChannelInvite(msg model.RemoteClusterMsg, rc *model sharedChannelRemote := &model.SharedChannelRemote{ Id: model.NewId(), ChannelId: channel.Id, - Description: invite.DisplayName, CreatorId: channel.CreatorId, IsInviteAccepted: true, IsInviteConfirmed: true, diff --git a/store/sqlstore/shared_channel_store.go b/store/sqlstore/shared_channel_store.go index d2135ef56a..e5adfe6286 100644 --- a/store/sqlstore/shared_channel_store.go +++ b/store/sqlstore/shared_channel_store.go @@ -38,7 +38,6 @@ func newSqlSharedChannelStore(sqlStore *SqlStore) store.SharedChannelStore { tableSharedChannelRemotes := db.AddTableWithName(model.SharedChannelRemote{}, "SharedChannelRemotes").SetKeys(false, "Id", "ChannelId") tableSharedChannelRemotes.ColMap("Id").SetMaxSize(26) tableSharedChannelRemotes.ColMap("ChannelId").SetMaxSize(26) - tableSharedChannelRemotes.ColMap("Description").SetMaxSize(64) tableSharedChannelRemotes.ColMap("CreatorId").SetMaxSize(26) tableSharedChannelRemotes.ColMap("RemoteId").SetMaxSize(26) tableSharedChannelRemotes.SetUniqueTogether("ChannelId", "RemoteId") @@ -524,7 +523,7 @@ func (s SqlSharedChannelStore) GetRemotesStatus(channelId string) ([]*model.Shar var status []*model.SharedChannelRemoteStatus query := s.getQueryBuilder(). - Select("scr.ChannelId, rc.DisplayName, rc.SiteURL, rc.LastPingAt, scr.NextSyncAt, scr.Description, sc.ReadOnly, scr.IsInviteAccepted"). + Select("scr.ChannelId, rc.DisplayName, rc.SiteURL, rc.LastPingAt, scr.NextSyncAt, sc.ReadOnly, scr.IsInviteAccepted"). From("SharedChannelRemotes scr, RemoteClusters rc, SharedChannels sc"). Where("scr.RemoteId = rc.RemoteId"). Where("scr.ChannelId = sc.ChannelId"). diff --git a/store/storetest/remote_cluster_store.go b/store/storetest/remote_cluster_store.go index 95955dc9a5..0ad7c5b1fd 100644 --- a/store/storetest/remote_cluster_store.go +++ b/store/storetest/remote_cluster_store.go @@ -253,11 +253,11 @@ func testRemoteClusterGetAllInChannel(t *testing.T, ss store.Store) { // Create some shared channel remotes scrData := []*model.SharedChannelRemote{ - {ChannelId: channel1.Id, Description: "AAA Inc Share", RemoteId: rcData[0].RemoteId, CreatorId: model.NewId()}, - {ChannelId: channel1.Id, Description: "BBB Inc Share", RemoteId: rcData[1].RemoteId, CreatorId: model.NewId()}, - {ChannelId: channel2.Id, Description: "CCC Inc Share", RemoteId: rcData[2].RemoteId, CreatorId: model.NewId()}, - {ChannelId: channel2.Id, Description: "DDD Inc Share", RemoteId: rcData[3].RemoteId, CreatorId: model.NewId()}, - {ChannelId: channel2.Id, Description: "EEE Inc Share", RemoteId: rcData[4].RemoteId, CreatorId: model.NewId()}, + {ChannelId: channel1.Id, RemoteId: rcData[0].RemoteId, CreatorId: model.NewId()}, + {ChannelId: channel1.Id, RemoteId: rcData[1].RemoteId, CreatorId: model.NewId()}, + {ChannelId: channel2.Id, RemoteId: rcData[2].RemoteId, CreatorId: model.NewId()}, + {ChannelId: channel2.Id, RemoteId: rcData[3].RemoteId, CreatorId: model.NewId()}, + {ChannelId: channel2.Id, RemoteId: rcData[4].RemoteId, CreatorId: model.NewId()}, } for _, item := range scrData { _, err := ss.SharedChannel().SaveRemote(item) @@ -360,11 +360,11 @@ func testRemoteClusterGetAllNotInChannel(t *testing.T, ss store.Store) { // Create some shared channel remotes scrData := []*model.SharedChannelRemote{ - {ChannelId: channel1.Id, Description: "AAA Inc Share", RemoteId: rcData[0].RemoteId, CreatorId: model.NewId()}, - {ChannelId: channel1.Id, Description: "BBB Inc Share", RemoteId: rcData[1].RemoteId, CreatorId: model.NewId()}, - {ChannelId: channel2.Id, Description: "CCC Inc Share", RemoteId: rcData[2].RemoteId, CreatorId: model.NewId()}, - {ChannelId: channel2.Id, Description: "DDD Inc Share", RemoteId: rcData[3].RemoteId, CreatorId: model.NewId()}, - {ChannelId: channel3.Id, Description: "EEE Inc Share", RemoteId: rcData[4].RemoteId, CreatorId: model.NewId()}, + {ChannelId: channel1.Id, RemoteId: rcData[0].RemoteId, CreatorId: model.NewId()}, + {ChannelId: channel1.Id, RemoteId: rcData[1].RemoteId, CreatorId: model.NewId()}, + {ChannelId: channel2.Id, RemoteId: rcData[2].RemoteId, CreatorId: model.NewId()}, + {ChannelId: channel2.Id, RemoteId: rcData[3].RemoteId, CreatorId: model.NewId()}, + {ChannelId: channel3.Id, RemoteId: rcData[4].RemoteId, CreatorId: model.NewId()}, } for _, item := range scrData { _, err := ss.SharedChannel().SaveRemote(item) diff --git a/store/storetest/shared_channel_store.go b/store/storetest/shared_channel_store.go index 0182d484cd..fe85e04ea2 100644 --- a/store/storetest/shared_channel_store.go +++ b/store/storetest/shared_channel_store.go @@ -349,10 +349,9 @@ func testDeleteSharedChannel(t *testing.T, ss store.Store) { // add some remotes for i := 0; i < 10; i++ { remote := &model.SharedChannelRemote{ - ChannelId: channel.Id, - Description: "remote_" + strconv.Itoa(i), - CreatorId: model.NewId(), - RemoteId: model.NewId(), + ChannelId: channel.Id, + CreatorId: model.NewId(), + RemoteId: model.NewId(), } _, err := ss.SharedChannel().SaveRemote(remote) require.NoError(t, err, "couldn't add remote", err) @@ -391,10 +390,9 @@ func testSaveSharedChannelRemote(t *testing.T, ss store.Store) { require.NoError(t, err) remote := &model.SharedChannelRemote{ - ChannelId: channel.Id, - Description: "test_remote", - CreatorId: model.NewId(), - RemoteId: model.NewId(), + ChannelId: channel.Id, + CreatorId: model.NewId(), + RemoteId: model.NewId(), } remoteSaved, err := ss.SharedChannel().SaveRemote(remote) @@ -406,10 +404,9 @@ func testSaveSharedChannelRemote(t *testing.T, ss store.Store) { t.Run("Save invalid shared channel remote", func(t *testing.T) { remote := &model.SharedChannelRemote{ - ChannelId: "", - Description: "test_remote", - CreatorId: model.NewId(), - RemoteId: model.NewId(), + ChannelId: "", + CreatorId: model.NewId(), + RemoteId: model.NewId(), } _, err := ss.SharedChannel().SaveRemote(remote) @@ -418,10 +415,9 @@ func testSaveSharedChannelRemote(t *testing.T, ss store.Store) { t.Run("Save shared channel remote with invalid channel id", func(t *testing.T) { remote := &model.SharedChannelRemote{ - ChannelId: model.NewId(), - Description: "test_remote", - CreatorId: model.NewId(), - RemoteId: model.NewId(), + ChannelId: model.NewId(), + CreatorId: model.NewId(), + RemoteId: model.NewId(), } _, err := ss.SharedChannel().SaveRemote(remote) @@ -435,10 +431,9 @@ func testUpdateSharedChannelRemote(t *testing.T, ss store.Store) { require.NoError(t, err) remote := &model.SharedChannelRemote{ - ChannelId: channel.Id, - Description: "test_remote_update", - CreatorId: model.NewId(), - RemoteId: model.NewId(), + ChannelId: channel.Id, + CreatorId: model.NewId(), + RemoteId: model.NewId(), } remoteSaved, err := ss.SharedChannel().SaveRemote(remote) @@ -446,22 +441,19 @@ func testUpdateSharedChannelRemote(t *testing.T, ss store.Store) { remoteSaved.IsInviteAccepted = true remoteSaved.IsInviteConfirmed = true - remoteSaved.Description = "new_desc" remoteUpdated, err := ss.SharedChannel().UpdateRemote(remoteSaved) require.NoError(t, err, "couldn't update shared channel remote", err) require.Equal(t, true, remoteUpdated.IsInviteAccepted) require.Equal(t, true, remoteUpdated.IsInviteConfirmed) - require.Equal(t, "new_desc", remoteUpdated.Description) }) t.Run("Update invalid shared channel remote", func(t *testing.T) { remote := &model.SharedChannelRemote{ - ChannelId: "", - Description: "test_remote", - CreatorId: model.NewId(), - RemoteId: model.NewId(), + ChannelId: "", + CreatorId: model.NewId(), + RemoteId: model.NewId(), } _, err := ss.SharedChannel().UpdateRemote(remote) @@ -470,10 +462,9 @@ func testUpdateSharedChannelRemote(t *testing.T, ss store.Store) { t.Run("Update shared channel remote with invalid channel id", func(t *testing.T) { remote := &model.SharedChannelRemote{ - ChannelId: model.NewId(), - Description: "test_remote", - CreatorId: model.NewId(), - RemoteId: model.NewId(), + ChannelId: model.NewId(), + CreatorId: model.NewId(), + RemoteId: model.NewId(), } _, err := ss.SharedChannel().UpdateRemote(remote) @@ -486,10 +477,9 @@ func testGetSharedChannelRemote(t *testing.T, ss store.Store) { require.NoError(t, err) remote := &model.SharedChannelRemote{ - ChannelId: channel.Id, - Description: "test_remote", - CreatorId: model.NewId(), - RemoteId: model.NewId(), + ChannelId: channel.Id, + CreatorId: model.NewId(), + RemoteId: model.NewId(), } remoteSaved, err := ss.SharedChannel().SaveRemote(remote) @@ -501,7 +491,6 @@ func testGetSharedChannelRemote(t *testing.T, ss store.Store) { require.Equal(t, remoteSaved.Id, r.Id) require.Equal(t, remoteSaved.ChannelId, r.ChannelId) - require.Equal(t, remoteSaved.Description, r.Description) require.Equal(t, remoteSaved.CreatorId, r.CreatorId) require.Equal(t, remoteSaved.RemoteId, r.RemoteId) }) @@ -518,10 +507,9 @@ func testGetSharedChannelRemoteByIds(t *testing.T, ss store.Store) { require.NoError(t, err) remote := &model.SharedChannelRemote{ - ChannelId: channel.Id, - Description: "test_remote_by_ids", - CreatorId: model.NewId(), - RemoteId: model.NewId(), + ChannelId: channel.Id, + CreatorId: model.NewId(), + RemoteId: model.NewId(), } remoteSaved, err := ss.SharedChannel().SaveRemote(remote) @@ -533,7 +521,6 @@ func testGetSharedChannelRemoteByIds(t *testing.T, ss store.Store) { require.Equal(t, remoteSaved.Id, r.Id) require.Equal(t, remoteSaved.ChannelId, r.ChannelId) - require.Equal(t, remoteSaved.Description, r.Description) require.Equal(t, remoteSaved.CreatorId, r.CreatorId) require.Equal(t, remoteSaved.RemoteId, r.RemoteId) }) @@ -553,12 +540,12 @@ func testGetSharedChannelRemotes(t *testing.T, ss store.Store) { remoteId := model.NewId() data := []model.SharedChannelRemote{ - {ChannelId: channel.Id, CreatorId: creator, Description: "r1", RemoteId: model.NewId(), IsInviteConfirmed: true}, - {ChannelId: channel.Id, CreatorId: creator, Description: "r2", RemoteId: model.NewId(), IsInviteConfirmed: true}, - {ChannelId: channel.Id, CreatorId: creator, Description: "r3", RemoteId: model.NewId(), IsInviteConfirmed: true}, - {CreatorId: creator, Description: "r4", RemoteId: remoteId, IsInviteConfirmed: true}, - {CreatorId: creator, Description: "r5", RemoteId: remoteId, IsInviteConfirmed: true}, - {CreatorId: creator, Description: "r6", RemoteId: remoteId}, + {ChannelId: channel.Id, CreatorId: creator, RemoteId: model.NewId(), IsInviteConfirmed: true}, + {ChannelId: channel.Id, CreatorId: creator, RemoteId: model.NewId(), IsInviteConfirmed: true}, + {ChannelId: channel.Id, CreatorId: creator, RemoteId: model.NewId(), IsInviteConfirmed: true}, + {CreatorId: creator, RemoteId: remoteId, IsInviteConfirmed: true}, + {CreatorId: creator, RemoteId: remoteId, IsInviteConfirmed: true}, + {CreatorId: creator, RemoteId: remoteId}, } for i, r := range data { @@ -579,7 +566,7 @@ func testGetSharedChannelRemotes(t *testing.T, ss store.Store) { require.NoError(t, err, "should not error", err) require.Len(t, remotes, 3) for _, r := range remotes { - require.Contains(t, []string{"r1", "r2", "r3"}, r.Description) + require.Equal(t, channel.Id, r.ChannelId) } }) @@ -600,7 +587,8 @@ func testGetSharedChannelRemotes(t *testing.T, ss store.Store) { require.NoError(t, err, "should not error", err) require.Len(t, remotes, 2) // only confirmed invitations for _, r := range remotes { - require.Contains(t, []string{"r4", "r5"}, r.Description) + require.Equal(t, remoteId, r.RemoteId) + require.True(t, r.IsInviteConfirmed) } }) @@ -620,9 +608,9 @@ func testGetSharedChannelRemotes(t *testing.T, ss store.Store) { } remotes, err := ss.SharedChannel().GetRemotes(opts) require.NoError(t, err, "should not error", err) - require.Len(t, remotes, 3) // only confirmed invitations + require.Len(t, remotes, 3) for _, r := range remotes { - require.Contains(t, []string{"r4", "r5", "r6"}, r.Description) + require.Equal(t, remoteId, r.RemoteId) } }) } @@ -636,8 +624,8 @@ func testHasRemote(t *testing.T, ss store.Store) { creator := model.NewId() data := []model.SharedChannelRemote{ - {ChannelId: channel.Id, CreatorId: creator, Description: "r1", RemoteId: remote1}, - {ChannelId: channel.Id, CreatorId: creator, Description: "r2", RemoteId: remote2}, + {ChannelId: channel.Id, CreatorId: creator, RemoteId: remote1}, + {ChannelId: channel.Id, CreatorId: creator, RemoteId: remote2}, } for _, r := range data { @@ -731,10 +719,9 @@ func testUpdateSharedChannelRemoteNextSyncAt(t *testing.T, ss store.Store) { require.NoError(t, err) remote := &model.SharedChannelRemote{ - ChannelId: channel.Id, - Description: "test_remote", - CreatorId: model.NewId(), - RemoteId: model.NewId(), + ChannelId: channel.Id, + CreatorId: model.NewId(), + RemoteId: model.NewId(), } remoteSaved, err := ss.SharedChannel().SaveRemote(remote) @@ -762,10 +749,9 @@ func testDeleteSharedChannelRemote(t *testing.T, ss store.Store) { require.NoError(t, err) remote := &model.SharedChannelRemote{ - ChannelId: channel.Id, - Description: "test_remote", - CreatorId: model.NewId(), - RemoteId: model.NewId(), + ChannelId: channel.Id, + CreatorId: model.NewId(), + RemoteId: model.NewId(), } remoteSaved, err := ss.SharedChannel().SaveRemote(remote) diff --git a/testlib/store.go b/testlib/store.go index 884ffa4acc..e2c7b29dc2 100644 --- a/testlib/store.go +++ b/testlib/store.go @@ -59,7 +59,7 @@ func GetMockStoreForSetupFunctions() *mocks.Store { systemStore.On("GetByName", model.MIGRATION_KEY_ADD_ABOUT_SUBSECTION_PERMISSIONS).Return(&model.System{Name: model.MIGRATION_KEY_ADD_ABOUT_SUBSECTION_PERMISSIONS, Value: "true"}, nil) systemStore.On("GetByName", model.MIGRATION_KEY_ADD_INTEGRATIONS_SUBSECTION_PERMISSIONS).Return(&model.System{Name: model.MIGRATION_KEY_ADD_INTEGRATIONS_SUBSECTION_PERMISSIONS, Value: "true"}, nil) systemStore.On("GetByName", model.MIGRATION_KEY_ADD_MANAGE_SHARED_CHANNEL_PERMISSIONS).Return(&model.System{Name: model.MIGRATION_KEY_ADD_MANAGE_SHARED_CHANNEL_PERMISSIONS, Value: "true"}, nil) - systemStore.On("GetByName", model.MIGRATION_KEY_ADD_MANAGE_REMOTE_CLUSTERS_PERMISSIONS).Return(&model.System{Name: model.MIGRATION_KEY_ADD_MANAGE_REMOTE_CLUSTERS_PERMISSIONS, Value: "true"}, nil) + systemStore.On("GetByName", model.MIGRATION_KEY_ADD_MANAGE_SECURE_CONNECTIONS_PERMISSIONS).Return(&model.System{Name: model.MIGRATION_KEY_ADD_MANAGE_SECURE_CONNECTIONS_PERMISSIONS, Value: "true"}, nil) systemStore.On("Get").Return(make(model.StringMap), nil) systemStore.On("Save", mock.AnythingOfType("*model.System")).Return(nil)