Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[MM-21688] Use dedicated bot account in Azure #32

Merged
merged 5 commits into from
Feb 11, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions server/command/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,12 @@ func (c *Command) Handle() (string, error) {
handler = c.info
case "connect":
handler = c.connect
case "connect_bot":
handler = c.connectBot
case "disconnect":
handler = c.disconnect
case "disconnect_bot":
handler = c.disconnectBot
case "viewcal":
handler = c.viewCalendar
case "createcal":
Expand Down
23 changes: 23 additions & 0 deletions server/command/connect.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,34 @@ import (
"fmt"

"github.com/mattermost/mattermost-plugin-mscalendar/server/config"
"github.com/pkg/errors"
)

func (c *Command) connect(parameters ...string) (string, error) {
ru, err := c.MSCalendar.GetRemoteUser(c.Args.UserId)
if err == nil {
return fmt.Sprintf("Your Mattermost account is already connected to %s account `%s`. To connect to a different account, first run `/%s disconnect`.", config.ApplicationName, ru.Mail, config.CommandTrigger), nil
}

out := fmt.Sprintf("[Click here to link your %s account.](%s/oauth2/connect)",
config.ApplicationName,
c.Config.PluginURL)
return out, nil
}

func (c *Command) connectBot(parameters ...string) (string, error) {
isAdmin, err := c.MSCalendar.IsAuthorizedAdmin(c.Args.UserId)
if err != nil || !isAdmin {
return "", errors.New("non-admin user attempting to connect bot account")
}

ru, err := c.MSCalendar.GetRemoteUser(c.Config.BotUserID)
if err == nil {
return fmt.Sprintf("The bot account is already connected to %s account `%s`. To connect to a different account, first run `/%s disconnect_bot`.", config.ApplicationName, ru.Mail, config.CommandTrigger), nil
}

out := fmt.Sprintf("[Click here to link the bot's %s account.](%s/oauth2/connect_bot)",
config.ApplicationName,
c.Config.PluginURL)
return out, nil
}
118 changes: 118 additions & 0 deletions server/command/connect_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
package command

import (
"testing"

"github.com/golang/mock/gomock"
"github.com/mattermost/mattermost-plugin-mscalendar/server/config"
"github.com/mattermost/mattermost-plugin-mscalendar/server/mscalendar"
"github.com/mattermost/mattermost-plugin-mscalendar/server/mscalendar/mock_mscalendar"
"github.com/mattermost/mattermost-plugin-mscalendar/server/remote"
"github.com/mattermost/mattermost-server/v5/model"
"github.com/mattermost/mattermost-server/v5/plugin"
"github.com/pkg/errors"
"github.com/stretchr/testify/require"
)

func TestConnect(t *testing.T) {
tcs := []struct {
name string
command string
setup func(m mscalendar.MSCalendar)
expectedOutput string
expectedError string
}{
{
name: "user already connected",
command: "connect",
setup: func(m mscalendar.MSCalendar) {
mscal := m.(*mock_mscalendar.MockMSCalendar)
mscal.EXPECT().GetRemoteUser("user_id").Return(&remote.User{Mail: "user@email.com"}, nil).Times(1)
},
expectedOutput: "Your Mattermost account is already connected to Microsoft Calendar account `user@email.com`. To connect to a different account, first run `/mscalendar disconnect`.",
expectedError: "",
},
{
name: "user not connected",
command: "connect",
setup: func(m mscalendar.MSCalendar) {
mscal := m.(*mock_mscalendar.MockMSCalendar)
mscal.EXPECT().GetRemoteUser("user_id").Return(nil, errors.New("remote user not found")).Times(1)
},
expectedOutput: "[Click here to link your Microsoft Calendar account.](http://localhost/oauth2/connect)",
expectedError: "",
},
{
name: "non-admin connecting bot account",
command: "connect_bot",
setup: func(m mscalendar.MSCalendar) {
mscal := m.(*mock_mscalendar.MockMSCalendar)
mscal.EXPECT().IsAuthorizedAdmin("user_id").Return(false, nil).Times(1)
},
expectedOutput: "",
expectedError: "Command /mscalendar connect_bot failed: non-admin user attempting to connect bot account",
},
{
name: "bot user already connected",
command: "connect_bot",
setup: func(m mscalendar.MSCalendar) {
mscal := m.(*mock_mscalendar.MockMSCalendar)
mscal.EXPECT().IsAuthorizedAdmin("user_id").Return(true, nil).Times(1)
mscal.EXPECT().GetRemoteUser("bot_user_id").Return(&remote.User{Mail: "bot@email.com"}, nil).Times(1)
},
//The bot account is already connected to %s account `%s`. To connect to a different account, first run `/%s disconnect_bot
expectedOutput: "The bot account is already connected to Microsoft Calendar account `bot@email.com`. To connect to a different account, first run `/mscalendar disconnect_bot`.",
expectedError: "",
},
{
name: "bot user not connected",
command: "connect_bot",
setup: func(m mscalendar.MSCalendar) {
mscal := m.(*mock_mscalendar.MockMSCalendar)
mscal.EXPECT().IsAuthorizedAdmin("user_id").Return(true, nil).Times(1)
mscal.EXPECT().GetRemoteUser("bot_user_id").Return(nil, errors.New("remote user not found")).Times(1)
},
expectedOutput: "[Click here to link the bot's Microsoft Calendar account.](http://localhost/oauth2/connect_bot)",
expectedError: "",
},
}

for _, tc := range tcs {
t.Run(tc.name, func(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()

conf := &config.Config{
PluginURL: "http://localhost",
BotUserID: "bot_user_id",
}

mscal := mock_mscalendar.NewMockMSCalendar(ctrl)
command := Command{
Context: &plugin.Context{},
Args: &model.CommandArgs{
Command: "/mscalendar " + tc.command,
UserId: "user_id",
},
ChannelID: "channel_id",
Config: conf,
MSCalendar: mscal,
}

if tc.setup != nil {
tc.setup(mscal)
}

out, err := command.Handle()
if tc.expectedOutput != "" {
require.Equal(t, tc.expectedOutput, out)
}

if tc.expectedError != "" {
require.Equal(t, tc.expectedError, err.Error())
} else {
require.Nil(t, err)
}
})
}
}
29 changes: 29 additions & 0 deletions server/command/disconnect.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Copyright (c) 2019-present Mattermost, Inc. All Rights Reserved.
// See License for license information.

package command

import "github.com/pkg/errors"

func (c *Command) disconnect(parameters ...string) (string, error) {
err := c.MSCalendar.DisconnectUser(c.Args.UserId)
if err != nil {
return "", err
}

return "Successfully disconnected your account", nil
}

func (c *Command) disconnectBot(parameters ...string) (string, error) {
isAdmin, err := c.MSCalendar.IsAuthorizedAdmin(c.Args.UserId)
if err != nil || !isAdmin {
return "", errors.New("non-admin user attempting to disconnect bot account")
}

err = c.MSCalendar.DisconnectUser(c.Config.BotUserID)
if err != nil {
return "", err
}

return "Successfully disconnected bot user", nil
}
116 changes: 116 additions & 0 deletions server/command/disconnect_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
package command

import (
"testing"

"github.com/golang/mock/gomock"
"github.com/mattermost/mattermost-plugin-mscalendar/server/config"
"github.com/mattermost/mattermost-plugin-mscalendar/server/mscalendar"
"github.com/mattermost/mattermost-plugin-mscalendar/server/mscalendar/mock_mscalendar"
"github.com/mattermost/mattermost-server/v5/model"
"github.com/mattermost/mattermost-server/v5/plugin"
"github.com/pkg/errors"
"github.com/stretchr/testify/require"
)

func TestDisconnect(t *testing.T) {
tcs := []struct {
name string
command string
setup func(mscalendar.MSCalendar)
expectedOutput string
expectedError string
}{
{
name: "disconnect failed",
command: "disconnect",
setup: func(m mscalendar.MSCalendar) {
mscal := m.(*mock_mscalendar.MockMSCalendar)
mscal.EXPECT().DisconnectUser("user_id").Return(errors.New("Some error")).Times(1)
},
expectedOutput: "",
expectedError: "Command /mscalendar disconnect failed: Some error",
},
{
name: "disconnect successful",
command: "disconnect",
setup: func(m mscalendar.MSCalendar) {
mscal := m.(*mock_mscalendar.MockMSCalendar)
mscal.EXPECT().DisconnectUser("user_id").Return(nil).Times(1)
},
expectedOutput: "Successfully disconnected your account",
expectedError: "",
},
{
name: "non-admin disconnecting bot account",
command: "disconnect_bot",
setup: func(m mscalendar.MSCalendar) {
mscal := m.(*mock_mscalendar.MockMSCalendar)
mscal.EXPECT().IsAuthorizedAdmin("user_id").Return(false, nil).Times(1)
},
expectedOutput: "",
expectedError: "Command /mscalendar disconnect_bot failed: non-admin user attempting to disconnect bot account",
},
{
name: "bot disconnect failed",
command: "disconnect_bot",
setup: func(m mscalendar.MSCalendar) {
mscal := m.(*mock_mscalendar.MockMSCalendar)
mscal.EXPECT().IsAuthorizedAdmin("user_id").Return(true, nil).Times(1)
mscal.EXPECT().DisconnectUser("bot_user_id").Return(errors.New("Some error")).Times(1)
},
expectedOutput: "",
expectedError: "Command /mscalendar disconnect_bot failed: Some error",
},
{
name: "bot disconnect successful",
command: "disconnect_bot",
setup: func(m mscalendar.MSCalendar) {
mscal := m.(*mock_mscalendar.MockMSCalendar)
mscal.EXPECT().IsAuthorizedAdmin("user_id").Return(true, nil).Times(1)
mscal.EXPECT().DisconnectUser("bot_user_id").Return(nil).Times(1)
},
expectedOutput: "Successfully disconnected bot user",
expectedError: "",
},
}

for _, tc := range tcs {
t.Run(tc.name, func(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()

conf := &config.Config{
PluginURL: "http://localhost",
BotUserID: "bot_user_id",
}

mscal := mock_mscalendar.NewMockMSCalendar(ctrl)
command := Command{
Context: &plugin.Context{},
Args: &model.CommandArgs{
Command: "/mscalendar " + tc.command,
UserId: "user_id",
},
ChannelID: "channel_id",
Config: conf,
MSCalendar: mscal,
}

if tc.setup != nil {
tc.setup(mscal)
}

out, err := command.Handle()
if tc.expectedOutput != "" {
require.Equal(t, tc.expectedOutput, out)
}

if tc.expectedError != "" {
require.Equal(t, tc.expectedError, err.Error())
} else {
require.Nil(t, err)
}
})
}
}
25 changes: 21 additions & 4 deletions server/mscalendar/availability.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,25 @@ func (m *mscalendar) SyncStatusAll() (string, error) {
return "", err
}

mmIDs := userIndex.GetMattermostUserIDs()
return m.syncStatusUsers(mmIDs)
allIDs := userIndex.GetMattermostUserIDs()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

only if you do another push anyway... a nit of a nit, but maybe inline userIndex.GetMattermostUserIDs() and just use ids for the return? :)

filteredIDs := []string{}
for _, id := range allIDs {
if id != m.Config.BotUserID {
levb marked this conversation as resolved.
Show resolved Hide resolved
filteredIDs = append(filteredIDs, id)
}
}
return m.syncStatusUsers(filteredIDs)
}

func (m *mscalendar) syncStatusUsers(mattermostUserIDs []string) (string, error) {
err := m.Filter(
withClient,
withUserExpanded(m.actingUser),
)
if err != nil {
return "", err
}

fullUserIndex, err := m.Store.LoadUserIndex()
if err != nil {
if err.Error() == "not found" {
Expand All @@ -66,7 +80,7 @@ func (m *mscalendar) syncStatusUsers(mattermostUserIDs []string) (string, error)
scheduleIDs = append(scheduleIDs, u.Email)
}

schedules, err := m.GetAvailabilities(filteredUsers[0].RemoteID, scheduleIDs)
schedules, err := m.GetAvailabilities(m.actingUser.Remote.ID, scheduleIDs)
if err != nil {
return "", err
}
Expand Down Expand Up @@ -111,7 +125,10 @@ func (m *mscalendar) setUserStatuses(filteredUsers store.UserIndex, schedules []
}

func (m *mscalendar) GetAvailabilities(remoteUserID string, scheduleIDs []string) ([]*remote.ScheduleInformation, error) {
client := m.MakeSuperuserClient()
client, err := m.MakeSuperuserClient()
if err != nil {
return nil, err
}

start := remote.NewDateTime(time.Now().UTC(), "UTC")
end := remote.NewDateTime(time.Now().UTC().Add(availabilityTimeWindowSize*time.Minute), "UTC")
Expand Down
Loading