277 lines
9.1 KiB
Go
277 lines
9.1 KiB
Go
package main
|
|
|
|
import (
|
|
"database/sql"
|
|
"fmt"
|
|
"strings"
|
|
"sync"
|
|
|
|
sq "github.com/Masterminds/squirrel"
|
|
"github.com/mattermost/mattermost/server/public/model"
|
|
"github.com/mattermost/mattermost/server/public/plugin"
|
|
pluginapi "github.com/mattermost/mattermost/server/public/pluginapi"
|
|
)
|
|
|
|
// Plugin implements the interface expected by the Mattermost server to communicate between the server and plugin processes.
|
|
type Plugin struct {
|
|
plugin.MattermostPlugin
|
|
|
|
// configurationLock synchronizes access to the configuration.
|
|
configurationLock sync.RWMutex
|
|
|
|
// configuration is the active plugin configuration. Consult getConfiguration and
|
|
// setConfiguration for usage.
|
|
configuration *configuration
|
|
|
|
apiClient *pluginapi.Client
|
|
|
|
db *sql.DB
|
|
}
|
|
|
|
// ServeHTTP demonstrates a plugin that handles HTTP requests by greeting the world.
|
|
// func (p *Plugin) ServeHTTP(c *plugin.Context, w http.ResponseWriter, r *http.Request) {
|
|
// fmt.Fprint(w, "Hello, world!")
|
|
// }
|
|
|
|
func (p *Plugin) Q() sq.StatementBuilderType {
|
|
return sq.StatementBuilder.PlaceholderFormat(sq.Dollar).RunWith(p.db)
|
|
}
|
|
|
|
func (p *Plugin) OnActivate() error {
|
|
p.apiClient = pluginapi.NewClient(p.API, p.Driver)
|
|
|
|
db, dbErr := p.apiClient.Store.GetMasterDB()
|
|
if dbErr != nil {
|
|
return dbErr
|
|
}
|
|
p.db = db
|
|
|
|
if err := p.API.UnregisterCommand("", "fawkes"); err != nil {
|
|
return err
|
|
}
|
|
|
|
autocompleteData := model.NewAutocompleteData("fawkes", "[command]", "Gets information about the msteams current state")
|
|
|
|
whitelistedCmd := model.NewAutocompleteData("count-whitelisted", "", "Counts the amount of whitelisted users in msteamssync_whitelisted_users")
|
|
// adds the from arg?
|
|
autocompleteData.AddCommand(whitelistedCmd)
|
|
|
|
lastConnectAtCmd := model.NewAutocompleteData("count-lastconnectat", "", "Counts the amount of users with a lastconnectat value != 0 in msteamssync_whitelisted_users")
|
|
autocompleteData.AddCommand(lastConnectAtCmd)
|
|
|
|
lastDisconnectAtCmd := model.NewAutocompleteData("count-lastdisconnectat", "", "Counts the amount of users with a lastdisconnectat value != 0 in msteamssync_whitelisted_users")
|
|
autocompleteData.AddCommand(lastDisconnectAtCmd)
|
|
|
|
userInfoCmd := model.NewAutocompleteData("user-info", "[username|email]", "Returns information about the user state regarding msteams")
|
|
autocompleteData.AddCommand(userInfoCmd)
|
|
|
|
channelInfoCmd := model.NewAutocompleteData("channel-info", "[channelID]", "Returns information about the channel state regarding msteams")
|
|
autocompleteData.AddCommand(channelInfoCmd)
|
|
|
|
listInvitesCmd := model.NewAutocompleteData("list-invites", "", "List the current invites")
|
|
autocompleteData.AddCommand(listInvitesCmd)
|
|
|
|
removeInviteCmd := model.NewAutocompleteData("remove-invite", "[mmUserID]", "Deletes the invite for the user ID")
|
|
autocompleteData.AddCommand(removeInviteCmd)
|
|
|
|
cmd := &model.Command{
|
|
Trigger: "fawkes",
|
|
AutoComplete: true,
|
|
AutoCompleteDesc: "Get insights of the user state",
|
|
AutocompleteData: autocompleteData,
|
|
}
|
|
|
|
if err := p.API.RegisterCommand(cmd); err != nil {
|
|
return err
|
|
}
|
|
p.API.LogDebug("plugin started")
|
|
|
|
return nil
|
|
}
|
|
|
|
func (p *Plugin) ExecuteCommand(_ *plugin.Context, args *model.CommandArgs) (*model.CommandResponse, *model.AppError) {
|
|
split := strings.Fields(args.Command)
|
|
command := split[0]
|
|
var parameters []string
|
|
action := ""
|
|
if len(split) > 1 {
|
|
action = split[1]
|
|
}
|
|
if len(split) > 2 {
|
|
parameters = split[2:]
|
|
}
|
|
|
|
if command != "/fawkes" {
|
|
return &model.CommandResponse{}, nil
|
|
}
|
|
|
|
switch (action) {
|
|
case "count-whitelisted":
|
|
rows, err := p.Q().Select("count(*)").From("msteamssync_whitelisted_users").Query()
|
|
if err != nil {
|
|
return p.sendEphemeralAndExit(fmt.Sprintf("ERROR: %s", err), args)
|
|
}
|
|
defer rows.Close()
|
|
|
|
var result int
|
|
rows.Next()
|
|
if err := rows.Scan(&result); err != nil {
|
|
return p.sendEphemeralAndExit(fmt.Sprintf("ERROR: %s", err), args)
|
|
}
|
|
|
|
return p.sendEphemeralAndExit(fmt.Sprintf("There are %d users in the msteamssync_whitelisted_users table", result), args)
|
|
case "count-lastconnectat":
|
|
rows, err := p.Q().Select("count(*)").From("msteamssync_users").Where(sq.NotEq{"lastconnectat": 0}).Query()
|
|
if err != nil {
|
|
return p.sendEphemeralAndExit(fmt.Sprintf("ERROR: %s", err), args)
|
|
}
|
|
defer rows.Close()
|
|
|
|
var result int
|
|
rows.Next()
|
|
if err := rows.Scan(&result); err != nil {
|
|
return p.sendEphemeralAndExit(fmt.Sprintf("ERROR: %s", err), args)
|
|
}
|
|
|
|
return p.sendEphemeralAndExit(fmt.Sprintf("There are %d users in the msteamssync_users table with `lastconnectat != 0`", result), args)
|
|
case "count-lastdisconnectat":
|
|
rows, err := p.Q().Select("count(*)").From("msteamssync_users").Where(sq.NotEq{"lastdisconnectat": 0}).Query()
|
|
if err != nil {
|
|
return p.sendEphemeralAndExit(fmt.Sprintf("ERROR: %s", err), args)
|
|
}
|
|
defer rows.Close()
|
|
|
|
var result int
|
|
rows.Next()
|
|
if err := rows.Scan(&result); err != nil {
|
|
return p.sendEphemeralAndExit(fmt.Sprintf("ERROR: %s", err), args)
|
|
}
|
|
|
|
return p.sendEphemeralAndExit(fmt.Sprintf("There are %d users in the msteamssync_users table with `lastdisconnectat != 0`", result), args)
|
|
case "user-info":
|
|
if len(parameters) != 1 {
|
|
return p.sendEphemeralAndExit("user-info must receive one \"username\" or \"email\" parameter", args)
|
|
}
|
|
|
|
email := parameters[0]
|
|
|
|
var user *model.User
|
|
var appErr *model.AppError
|
|
user, appErr = p.API.GetUserByEmail(email)
|
|
if appErr != nil {
|
|
user, appErr = p.API.GetUserByUsername(email)
|
|
if appErr != nil {
|
|
return p.sendEphemeralAndExit(fmt.Sprintf("ERROR getting the user by email and username: %s", appErr.Error()), args)
|
|
}
|
|
}
|
|
|
|
pref, appErr := p.API.GetPreferenceForUser(user.Id, "pp_com.mattermost.msteams-sync", "platform")
|
|
if appErr != nil {
|
|
return p.sendEphemeralAndExit(fmt.Sprintf("ERROR getting user preferences: %s", appErr.Error()), args)
|
|
}
|
|
|
|
rows, _ := p.Q().
|
|
Select("msteamsuserid, token, lastconnectat, lastdisconnectat").
|
|
From("msteamssync_users").
|
|
Where(sq.Eq{"mmuserid": user.Id}).
|
|
Query()
|
|
// if err != nil {
|
|
// return p.sendEphemeralAndExit(fmt.Sprintf("ERROR querying for msteamssync user: %s", err), args)
|
|
// }
|
|
defer rows.Close()
|
|
|
|
var mmTeamsUserID string
|
|
var token string
|
|
var lastConnectAt int
|
|
var lastDisconnectAt int
|
|
// if !rows.Next() {
|
|
// return p.sendEphemeralAndExit(fmt.Sprintf("User %q not found in the msteamssync_users table", email), args)
|
|
// }
|
|
if rows.Next() {
|
|
if err := rows.Scan(&mmTeamsUserID, &token, &lastConnectAt, &lastDisconnectAt); err != nil {
|
|
return p.sendEphemeralAndExit(fmt.Sprintf("ERROR scanning rows: %s", err), args)
|
|
}
|
|
}
|
|
|
|
var remoteID string
|
|
if user.RemoteId != nil {
|
|
remoteID = *user.RemoteId
|
|
}
|
|
|
|
hasToken := false
|
|
if token != "" {
|
|
hasToken = true
|
|
}
|
|
return p.sendEphemeralAndExit(fmt.Sprintf("User %q has\n - `mmTeamsUserID`: %s\n - `hasToken`: %v\n - `lastConnectAt`: %d\n - `lastDisconnectAt`: %d\n - `remoteID`: %s\n - `primaryPlatform preference`: %s", email, mmTeamsUserID, hasToken, lastConnectAt, lastDisconnectAt, remoteID, pref.Value), args)
|
|
case "channel-info":
|
|
if len(parameters) != 1 {
|
|
return p.sendEphemeralAndExit("channel-info must receive the channel ID", args)
|
|
}
|
|
|
|
channelID := parameters[0]
|
|
|
|
channel, appErr := p.API.GetChannel(channelID)
|
|
if appErr != nil {
|
|
return p.sendEphemeralAndExit(fmt.Sprintf("ERROR getting the channel: %s", appErr.Error()), args)
|
|
}
|
|
|
|
return p.sendEphemeralAndExit(fmt.Sprintf(" - `Id`: %s\n - `name`: %s\n - `IsShared`: %v", channel.Id, channel.Name, channel.IsShared()), args)
|
|
case "list-invites":
|
|
rows, err := p.Q().
|
|
Select("mmuserid, invitependingsince, invitelastsentat").
|
|
From("msteamssync_invited_users").
|
|
Query()
|
|
if err != nil {
|
|
return p.sendEphemeralAndExit(fmt.Sprintf("ERROR querying for invited users: %s", err), args)
|
|
}
|
|
defer rows.Close()
|
|
|
|
invites := []map[string]any{}
|
|
for rows.Next() {
|
|
var mmUserID string
|
|
var invitePendingSince int
|
|
var inviteLastSentAt int
|
|
if err := rows.Scan(&mmUserID, &invitePendingSince, &inviteLastSentAt); err != nil {
|
|
return p.sendEphemeralAndExit(fmt.Sprintf("ERROR scanning row: %s", err), args)
|
|
}
|
|
|
|
invites = append(invites, map[string]any{
|
|
"mmUserID": mmUserID,
|
|
"invitePendingSince": invitePendingSince,
|
|
"inviteLastSentAt": inviteLastSentAt,
|
|
})
|
|
}
|
|
|
|
message := "Invite list:\n"
|
|
for _, invite := range invites {
|
|
message += fmt.Sprintf(
|
|
" - `mmUserID`: %s :: `invitePendingSince`: %d :: `inviteLastSentAt`: %d\n",
|
|
invite["mmUserID"],
|
|
invite["invitePendingSince"],
|
|
invite["inviteLastSentAt"],
|
|
)
|
|
}
|
|
|
|
return p.sendEphemeralAndExit(message, args)
|
|
case "delete-invite":
|
|
return p.sendEphemeralAndExit("Not implemented yet", args)
|
|
default:
|
|
p.sendEphemeral(fmt.Sprintf("Invalid command %q", action), args)
|
|
return &model.CommandResponse{}, nil
|
|
}
|
|
}
|
|
|
|
func (p *Plugin) sendEphemeral(message string, args *model.CommandArgs) {
|
|
_ = p.API.SendEphemeralPost(args.UserId, &model.Post{
|
|
Message: message,
|
|
UserId: args.UserId,
|
|
ChannelId: args.ChannelId,
|
|
})
|
|
}
|
|
|
|
func (p *Plugin) sendEphemeralAndExit(message string, args *model.CommandArgs) (*model.CommandResponse, *model.AppError) {
|
|
p.sendEphemeral(message, args)
|
|
return &model.CommandResponse{}, nil
|
|
}
|
|
|
|
// See https://developers.mattermost.com/extend/plugins/server/reference/
|