diff --git a/server/command.go b/server/command.go index 961e939..0649d76 100644 --- a/server/command.go +++ b/server/command.go @@ -1,227 +1,314 @@ -package main - -import ( - "fmt" - "strings" - "time" - - "github.com/mattermost/mattermost-server/v5/model" - "github.com/mattermost/mattermost-server/v5/plugin" - "github.com/pkg/errors" -) - -const ( - commandTriggerAgenda = "agenda" - - wsEventList = "list" -) - -const helpCommandText = "###### Mattermost Agenda Plugin - Slash Command Help\n" + - "The Agenda plugin lets you queue up meeting topics for channel discussion at a later time. When your meeting happens, you can click on the Hashtag to see all agenda items in the RHS. \n" + - "To configure the agenda for this channel, click on the Channel Name in Mattermost to access the channel options menu and select `Agenda Settings`" + - "\n* `/agenda queue [weekday (optional)] message` - Queue `message` as a topic on the next meeting. If `weekday` is provided, it will queue for the meeting for. \n" + - "* `/agenda list [weekday(optional)]` - Show a list of items queued for the next meeting. If `next-week` is provided, it will list the agenda for the next calendar week. \n" + - "* `/agenda setting ` - Update the setting with the given value. Field can be one of `schedule` or `hashtag` \n" + - "How can we make this better? Submit an issue to the [Agenda Plugin repo here](https://github.com/mattermost/mattermost-plugin-agenda/issues) \n" - -func (p *Plugin) registerCommands() error { - if err := p.API.RegisterCommand(createAgendaCommand()); err != nil { - return errors.Wrapf(err, "failed to register %s command", commandTriggerAgenda) - } - - return nil -} - -// ExecuteCommand executes a command that has been previously registered via the RegisterCommand -func (p *Plugin) ExecuteCommand(c *plugin.Context, args *model.CommandArgs) (*model.CommandResponse, *model.AppError) { - split := strings.Fields(args.Command) - - if len(split) < 2 { - return responsef("Missing command. You can try queue, list, setting"), nil - } - - action := split[1] - - switch action { - case "list": - return p.executeCommandList(args), nil - - case "queue": - return p.executeCommandQueue(args), nil - - case "setting": - return p.executeCommandSetting(args), nil - - case "help": - return p.executeCommandHelp(args), nil - } - - return responsef("Unknown action: %s", action), nil -} - -func (p *Plugin) executeCommandList(args *model.CommandArgs) *model.CommandResponse { - split := strings.Fields(args.Command) - nextWeek := len(split) > 2 && split[2] == "next-week" - - weekday := -1 - if !nextWeek && len(split) > 2 { - parsedWeekday, _ := parseSchedule(split[2]) - weekday = int(parsedWeekday) - } - - hashtag, err := p.GenerateHashtag(args.ChannelId, nextWeek, weekday) - if err != nil { - return responsef("Error calculating hashtags") - } - - // Send a websocket event to the web app that will open the RHS - p.API.PublishWebSocketEvent( - wsEventList, - map[string]interface{}{ - "hashtag": hashtag, - }, - &model.WebsocketBroadcast{UserId: args.UserId}, - ) - - return &model.CommandResponse{} -} - -func (p *Plugin) executeCommandSetting(args *model.CommandArgs) *model.CommandResponse { - // settings: hashtag, schedule - split := strings.Fields(args.Command) - - if len(split) < 4 { - return responsef("Setting parameters missing") - } - - field := split[2] - value := split[3] - - meeting, err := p.GetMeeting(args.ChannelId) - if err != nil { - return responsef("Error getting meeting information for this channel") - } - - switch field { - case "schedule": - // Set schedule - weekdayInt, err := parseSchedule(value) - if err != nil { - return responsef(err.Error()) - } - meeting.Schedule = []time.Weekday{weekdayInt} - - case "hashtag": - // Set hashtag - meeting.HashtagFormat = value - default: - return responsef("Unknown setting %s", field) - } - - if err := p.SaveMeeting(meeting); err != nil { - return responsef("Error saving setting") - } - - return responsef("Updated setting %v to %v", field, value) -} - -func (p *Plugin) executeCommandQueue(args *model.CommandArgs) *model.CommandResponse { - split := strings.Fields(args.Command) - - if len(split) <= 2 { - return responsef("Missing parameters for queue command") - } - - nextWeek := false - weekday := -1 - message := strings.Join(split[2:], " ") - - if split[2] == "next-week" { - nextWeek = true - } else { - parsedWeekday, _ := parseSchedule(split[2]) - weekday = int(parsedWeekday) - } - - if nextWeek || weekday > -1 { - message = strings.Join(split[3:], " ") - } - - hashtag, error := p.GenerateHashtag(args.ChannelId, nextWeek, weekday) - if error != nil { - return responsef("Error calculating hashtags. Check the meeting settings for this channel.") - } - - searchResults, appErr := p.API.SearchPostsInTeamForUser(args.TeamId, args.UserId, model.SearchParameter{Terms: &hashtag}) - - if appErr != nil { - return responsef("Error calculating list number") - } - - postList := *searchResults.PostList - numQueueItems := len(postList.Posts) - - _, appErr = p.API.CreatePost(&model.Post{ - UserId: args.UserId, - ChannelId: args.ChannelId, - RootId: args.RootId, - Message: fmt.Sprintf("#### %v %v) %v", hashtag, numQueueItems+1, message), - }) - if appErr != nil { - return responsef("Error creating post: %s", appErr.Message) - } - - return &model.CommandResponse{} -} - -func (p *Plugin) executeCommandHelp(args *model.CommandArgs) *model.CommandResponse { - return responsef(helpCommandText) -} - -func responsef(format string, args ...interface{}) *model.CommandResponse { - return &model.CommandResponse{ - ResponseType: model.COMMAND_RESPONSE_TYPE_EPHEMERAL, - Text: fmt.Sprintf(format, args...), - Type: model.POST_DEFAULT, - } -} - -func createAgendaCommand() *model.Command { - agenda := model.NewAutocompleteData(commandTriggerAgenda, "[command]", "Available commands: list, queue, setting, help") - - list := model.NewAutocompleteData("list", "", "Show a list of items queued for the next meeting") - list.AddDynamicListArgument("Day of the week for when to queue the meeting", "/api/v1/list-meeting-days-autocomplete", false) - agenda.AddCommand(list) - - queue := model.NewAutocompleteData("queue", "", "Queue `message` as a topic on the next meeting.") - queue.AddDynamicListArgument("Day of the week for when to queue the meeting", "/api/v1/meeting-days-autocomplete", false) - queue.AddTextArgument("Message for the next meeting date.", "[message]", "") - agenda.AddCommand(queue) - - setting := model.NewAutocompleteData("setting", "", "Update the setting.") - schedule := model.NewAutocompleteData("schedule", "", "Update schedule.") - schedule.AddStaticListArgument("weekday", true, []model.AutocompleteListItem{ - {Item: "Monday"}, - {Item: "Tuesday"}, - {Item: "Wednesday"}, - {Item: "Thursday"}, - {Item: "Friday"}, - {Item: "Saturday"}, - {Item: "Sunday"}, - }) - setting.AddCommand(schedule) - hashtag := model.NewAutocompleteData("hashtag", "", "Update hastag.") - hashtag.AddTextArgument("input hashtag", "Default: Jan02", "") - setting.AddCommand(hashtag) - agenda.AddCommand(setting) - - help := model.NewAutocompleteData("help", "", "Mattermost Agenda plugin slash command help") - agenda.AddCommand(help) - return &model.Command{ - Trigger: commandTriggerAgenda, - AutoComplete: true, - AutoCompleteDesc: "Available commands: list, queue, setting, help", - AutoCompleteHint: "[command]", - AutocompleteData: agenda, - } -} +package main + +import ( + "fmt" + "regexp" + "strings" + "time" + + "github.com/mattermost/mattermost-server/v5/model" + "github.com/mattermost/mattermost-server/v5/plugin" + "github.com/pkg/errors" +) + +const ( + commandTriggerAgenda = "agenda" + + wsEventList = "list" +) + +const helpCommandText = "###### Mattermost Agenda Plugin - Slash Command Help\n" + + "The Agenda plugin lets you queue up meeting topics for channel discussion at a later time. When your meeting happens, you can click on the Hashtag to see all agenda items in the RHS. \n" + + "To configure the agenda for this channel, click on the Channel Name in Mattermost to access the channel options menu and select `Agenda Settings`" + + "\n* `/agenda queue [weekday (optional)] message` - Queue `message` as a topic on the next meeting. If `weekday` is provided, it will queue for the meeting for. \n" + + "* `/agenda list [weekday(optional)]` - Show a list of items queued for the next meeting. If `next-week` is provided, it will list the agenda for the next calendar week. \n" + + "* `/agenda setting ` - Update the setting with the given value. Field can be one of `schedule` or `hashtag` \n" + + "How can we make this better? Submit an issue to the [Agenda Plugin repo here](https://github.com/mattermost/mattermost-plugin-agenda/issues) \n" + +func (p *Plugin) registerCommands() error { + if err := p.API.RegisterCommand(createAgendaCommand()); err != nil { + return errors.Wrapf(err, "failed to register %s command", commandTriggerAgenda) + } + + return nil +} + +// ExecuteCommand executes a command that has been previously registered via the RegisterCommand +func (p *Plugin) ExecuteCommand(c *plugin.Context, args *model.CommandArgs) (*model.CommandResponse, *model.AppError) { + split := strings.Fields(args.Command) + + if len(split) < 2 { + return responsef("Missing command. You can try queue, list, setting"), nil + } + + action := split[1] + + switch action { + case "list": + return p.executeCommandList(args), nil + + case "queue": + return p.executeCommandQueue(args), nil + + case "requeue": + return p.executeCommandReQueue(args), nil + + case "setting": + return p.executeCommandSetting(args), nil + + case "help": + return p.executeCommandHelp(args), nil + } + + return responsef("Unknown action: %s", action), nil +} + +func (p *Plugin) executeCommandList(args *model.CommandArgs) *model.CommandResponse { + split := strings.Fields(args.Command) + nextWeek := len(split) > 2 && split[2] == "next-week" + + weekday := -1 + if !nextWeek && len(split) > 2 { + parsedWeekday, _ := parseSchedule(split[2]) + weekday = int(parsedWeekday) + } + + hashtag, err := p.GenerateHashtag(args.ChannelId, nextWeek, weekday, false, time.Now().Weekday()) + if err != nil { + return responsef("Error calculating hashtags") + } + + // Send a websocket event to the web app that will open the RHS + p.API.PublishWebSocketEvent( + wsEventList, + map[string]interface{}{ + "hashtag": hashtag, + }, + &model.WebsocketBroadcast{UserId: args.UserId}, + ) + + return &model.CommandResponse{} +} + +func (p *Plugin) executeCommandSetting(args *model.CommandArgs) *model.CommandResponse { + // settings: hashtag, schedule + split := strings.Fields(args.Command) + + if len(split) < 4 { + return responsef("Setting parameters missing") + } + + field := split[2] + value := split[3] + + meeting, err := p.GetMeeting(args.ChannelId) + if err != nil { + return responsef("Error getting meeting information for this channel") + } + + switch field { + case "schedule": + // Set schedule + weekdayInt, err := parseSchedule(value) + if err != nil { + return responsef(err.Error()) + } + meeting.Schedule = []time.Weekday{weekdayInt} + + case "hashtag": + // Set hashtag + meeting.HashtagFormat = value + default: + return responsef("Unknown setting %s", field) + } + + if err := p.SaveMeeting(meeting); err != nil { + return responsef("Error saving setting") + } + + return responsef("Updated setting %v to %v", field, value) +} + +func (p *Plugin) executeCommandQueue(args *model.CommandArgs) *model.CommandResponse { + split := strings.Fields(args.Command) + + if len(split) <= 2 { + return responsef("Missing parameters for queue command") + } + + nextWeek := false + weekday := -1 + message := strings.Join(split[2:], " ") + + if split[2] == "next-week" { + nextWeek = true + } else { + parsedWeekday, _ := parseSchedule(split[2]) + weekday = int(parsedWeekday) + } + + if nextWeek || weekday > -1 { + message = strings.Join(split[3:], " ") + } + + hashtag, error := p.GenerateHashtag(args.ChannelId, nextWeek, weekday, false, time.Now().Weekday()) + if error != nil { + return responsef("Error calculating hashtags. Check the meeting settings for this channel.") + } + + itemErr, numQueueItems := calculateQueItemNumber(args, p, hashtag) + if itemErr != nil { + return itemErr + } + + _, appErr := p.API.CreatePost(&model.Post{ + UserId: args.UserId, + ChannelId: args.ChannelId, + RootId: args.RootId, + Message: fmt.Sprintf("#### %v %v) %v", hashtag, numQueueItems, message), + }) + if appErr != nil { + return responsef("Error creating post: %s", appErr.Message) + } + + return &model.CommandResponse{} +} + +func calculateQueItemNumber(args *model.CommandArgs, p *Plugin, hashtag string) (*model.CommandResponse, int) { + searchResults, appErr := p.API.SearchPostsInTeamForUser(args.TeamId, args.UserId, model.SearchParameter{Terms: &hashtag}) + if appErr != nil { + return responsef("Error calculating list number"), 0 + } + postList := *searchResults.PostList + numQueueItems := len(postList.Posts) + return nil, numQueueItems + 1 +} + +func (p *Plugin) executeCommandReQueue(args *model.CommandArgs) *model.CommandResponse { + split := strings.Fields(args.Command) + + if len(split) <= 2 { + return responsef("Missing parameters for requeue command") + } + + meeting, err := p.GetMeeting(args.ChannelId) + if err != nil { + return responsef("Can't find the meeting") + } + + oldPostId := split[2] + postToBeReQueued, err := p.API.GetPost(oldPostId) + //if err != nil { + // return responsef("Couldn't locate the post to requeue.") + //} + var ( + prefix string + hashtagDateFormat string + ) + if matchGroups := meetingDateFormatRegex.FindStringSubmatch(meeting.HashtagFormat); len(matchGroups) == 4 { + prefix = matchGroups[1] + hashtagDateFormat = strings.TrimSpace(matchGroups[2]) + } else { + return responsef("Error 203") + } + + var ( + messageRegexFormat = regexp.MustCompile(fmt.Sprintf(`(?m)^#### #%s(?P.*) [0-9]+\) (?P.*)?$`, prefix)) + ) + + if matchGroups := messageRegexFormat.FindStringSubmatch(postToBeReQueued.Message); len(matchGroups) == 3 { + + originalPostDate := strings.ReplaceAll(strings.TrimSpace(matchGroups[1]), "_", " ") // reverse what we do to make it a valid hashtag + originalPostMessage := strings.TrimSpace(matchGroups[2]) + + today := time.Now() + local, _ := time.LoadLocation("Local") + formattedDate, _ := time.ParseInLocation(hashtagDateFormat, originalPostDate, local) + if formattedDate.Year() == 0 { + thisYear := today.Year() + formattedDate = formattedDate.AddDate(thisYear, 0, 0) + } + + if today.Year() <= formattedDate.Year() && today.YearDay() < formattedDate.YearDay() { + return responsef("We don't support re-queuing future items, only available for present and past items.") + } + + hashtag, error := p.GenerateHashtag(args.ChannelId, false, -1, true, formattedDate.Weekday()) + if error != nil { + return responsef("Error calculating hashtags. Check the meeting settings for this channel.") + } + + itemErr, numQueueItems := calculateQueItemNumber(args, p, hashtag) + if itemErr != nil { + return itemErr + } + + _, appErr := p.API.UpdatePost(&model.Post{ + Id: oldPostId, + UserId: args.UserId, + ChannelId: args.ChannelId, + RootId: args.RootId, + Message: fmt.Sprintf("#### %v %v) %v", hashtag, numQueueItems, originalPostMessage), + }) + if appErr != nil { + return responsef("Error creating post: %s", appErr.Message) + } + + return &model.CommandResponse{Text: fmt.Sprintf("Item has been Re-queued to %v", hashtag), ResponseType: model.COMMAND_RESPONSE_TYPE_EPHEMERAL} + + } else { + return responsef("Make sure, message is in required format!") + } +} + +func (p *Plugin) executeCommandHelp(args *model.CommandArgs) *model.CommandResponse { + return responsef(helpCommandText) +} + +func responsef(format string, args ...interface{}) *model.CommandResponse { + return &model.CommandResponse{ + ResponseType: model.COMMAND_RESPONSE_TYPE_EPHEMERAL, + Text: fmt.Sprintf(format, args...), + Type: model.POST_DEFAULT, + } +} + +func createAgendaCommand() *model.Command { + agenda := model.NewAutocompleteData(commandTriggerAgenda, "[command]", "Available commands: list, queue, setting, help") + + list := model.NewAutocompleteData("list", "", "Show a list of items queued for the next meeting") + list.AddDynamicListArgument("Day of the week for when to queue the meeting", "/api/v1/list-meeting-days-autocomplete", false) + agenda.AddCommand(list) + + queue := model.NewAutocompleteData("queue", "", "Queue `message` as a topic on the next meeting.") + queue.AddDynamicListArgument("Day of the week for when to queue the meeting", "/api/v1/meeting-days-autocomplete", false) + queue.AddTextArgument("Message for the next meeting date.", "[message]", "") + agenda.AddCommand(queue) + + setting := model.NewAutocompleteData("setting", "", "Update the setting.") + schedule := model.NewAutocompleteData("schedule", "", "Update schedule.") + schedule.AddStaticListArgument("weekday", true, []model.AutocompleteListItem{ + {Item: "Monday"}, + {Item: "Tuesday"}, + {Item: "Wednesday"}, + {Item: "Thursday"}, + {Item: "Friday"}, + {Item: "Saturday"}, + {Item: "Sunday"}, + }) + setting.AddCommand(schedule) + hashtag := model.NewAutocompleteData("hashtag", "", "Update hastag.") + hashtag.AddTextArgument("input hashtag", "Default: Jan02", "") + setting.AddCommand(hashtag) + agenda.AddCommand(setting) + + help := model.NewAutocompleteData("help", "", "Mattermost Agenda plugin slash command help") + agenda.AddCommand(help) + return &model.Command{ + Trigger: commandTriggerAgenda, + AutoComplete: true, + AutoCompleteDesc: "Available commands: list, queue, setting, help", + AutoCompleteHint: "[command]", + AutocompleteData: agenda, + } +} diff --git a/server/meeting.go b/server/meeting.go index beb0403..c9e4c9c 100644 --- a/server/meeting.go +++ b/server/meeting.go @@ -37,7 +37,7 @@ func (p *Plugin) GetMeeting(channelID string) (*Meeting, error) { if err != nil { return nil, err } - paddedChannelName :=strings.ReplaceAll(channel.Name, "-", "_") + paddedChannelName := strings.ReplaceAll(channel.Name, "-", "_") meeting = &Meeting{ Schedule: []time.Weekday{time.Thursday}, HashtagFormat: strings.Join([]string{fmt.Sprintf("%.15s", paddedChannelName), "{{ Jan 2 }}"}, "_"), @@ -63,7 +63,7 @@ func (p *Plugin) SaveMeeting(meeting *Meeting) error { } // GenerateHashtag returns a meeting hashtag -func (p *Plugin) GenerateHashtag(channelID string, nextWeek bool, weekday int) (string, error) { +func (p *Plugin) GenerateHashtag(channelID string, nextWeek bool, weekday int, requeue bool, assignedDay time.Weekday) (string, error) { meeting, err := p.GetMeeting(channelID) if err != nil { return "", err @@ -75,11 +75,22 @@ func (p *Plugin) GenerateHashtag(channelID string, nextWeek bool, weekday int) ( if meetingDate, err = nextWeekdayDate(time.Weekday(weekday), nextWeek); err != nil { return "", err } + } else { - // Get date for the list of days of the week - if meetingDate, err = nextWeekdayDateInWeek(meeting.Schedule, nextWeek); err != nil { - return "", err + // user didn't provide any specific date, Get date for the list of days of the week + if !requeue { + if meetingDate, err = nextWeekdayDateInWeek(meeting.Schedule, nextWeek); err != nil { + return "", err + } + } else { + if len(meeting.Schedule) == 1 && meeting.Schedule[0] == assignedDay { // if this day is the only day selected in settings + nextWeek = true + } + if meetingDate, err = nextWeekdayDateInWeekSkippingDay(meeting.Schedule, nextWeek, assignedDay); err != nil { + return "", err + } } + //---- requeue Logic } var hashtag string diff --git a/server/meeting_test.go b/server/meeting_test.go index f6ddf10..12b89b2 100644 --- a/server/meeting_test.go +++ b/server/meeting_test.go @@ -57,7 +57,7 @@ func TestPlugin_GenerateHashtag(t *testing.T) { Schedule: []time.Weekday{time.Wednesday}, HashtagFormat: "{{Jan 2}}", }}, - want: "#" + strings.ReplaceAll(assertNextWeekdayDate(time.Wednesday, true).Format("Jan 2")," ","_"), + want: "#" + strings.ReplaceAll(assertNextWeekdayDate(time.Wednesday, true).Format("Jan 2"), " ", "_"), wantErr: false, }, { @@ -69,7 +69,7 @@ func TestPlugin_GenerateHashtag(t *testing.T) { Schedule: []time.Weekday{time.Monday}, HashtagFormat: "QA_{{January 02 2006}}", }}, - want: "#QA_" + strings.ReplaceAll(assertNextWeekdayDate(time.Monday, true).Format("January 02 2006")," ","_"), + want: "#QA_" + strings.ReplaceAll(assertNextWeekdayDate(time.Monday, true).Format("January 02 2006"), " ", "_"), wantErr: false, }, { @@ -81,7 +81,7 @@ func TestPlugin_GenerateHashtag(t *testing.T) { Schedule: []time.Weekday{time.Monday}, HashtagFormat: "{{January 02 2006}}.vue", }}, - want: "#" + strings.ReplaceAll(assertNextWeekdayDate(time.Monday, false).Format("January 02 2006")," ","_") + ".vue", + want: "#" + strings.ReplaceAll(assertNextWeekdayDate(time.Monday, false).Format("January 02 2006"), " ", "_") + ".vue", wantErr: false, }, { @@ -93,7 +93,7 @@ func TestPlugin_GenerateHashtag(t *testing.T) { Schedule: []time.Weekday{time.Monday}, HashtagFormat: "React {{January 02 2006}} Born", }}, - want: "#React " + strings.ReplaceAll(assertNextWeekdayDate(time.Monday, false).Format("January 02 2006")," ","_") + " Born", + want: "#React " + strings.ReplaceAll(assertNextWeekdayDate(time.Monday, false).Format("January 02 2006"), " ", "_") + " Born", wantErr: false, }, { @@ -105,7 +105,7 @@ func TestPlugin_GenerateHashtag(t *testing.T) { Schedule: []time.Weekday{time.Monday}, HashtagFormat: "January 02 2006 {{January 02 2006}} January 02 2006", }}, - want: "#January 02 2006 " + strings.ReplaceAll(assertNextWeekdayDate(time.Monday, false).Format("January 02 2006")," ","_") + " January 02 2006", + want: "#January 02 2006 " + strings.ReplaceAll(assertNextWeekdayDate(time.Monday, false).Format("January 02 2006"), " ", "_") + " January 02 2006", wantErr: false, }, { @@ -117,7 +117,7 @@ func TestPlugin_GenerateHashtag(t *testing.T) { Schedule: []time.Weekday{time.Monday}, HashtagFormat: "{{ January 02 2006 }}", }}, - want: "#" + strings.ReplaceAll(assertNextWeekdayDate(time.Monday, false).Format("January 02 2006")," ","_"), + want: "#" + strings.ReplaceAll(assertNextWeekdayDate(time.Monday, false).Format("January 02 2006"), " ", "_"), wantErr: false, }, { @@ -129,7 +129,7 @@ func TestPlugin_GenerateHashtag(t *testing.T) { Schedule: []time.Weekday{time.Monday}, HashtagFormat: "{{ Mon Jan _2 }}", }}, - want: "#" + strings.ReplaceAll(assertNextWeekdayDate(time.Monday, false).Format("Mon Jan _2")," ","_"), + want: "#" + strings.ReplaceAll(assertNextWeekdayDate(time.Monday, false).Format("Mon Jan _2"), " ", "_"), wantErr: false, }, } @@ -138,7 +138,7 @@ func TestPlugin_GenerateHashtag(t *testing.T) { jsonMeeting, err := json.Marshal(tt.args.meeting) tAssert.Nil(err) api.On("KVGet", tt.args.meeting.ChannelID).Return(jsonMeeting, nil) - got, err := mPlugin.GenerateHashtag(tt.args.meeting.ChannelID, tt.args.nextWeek, -1) + got, err := mPlugin.GenerateHashtag(tt.args.meeting.ChannelID, tt.args.nextWeek, -1, false) if (err != nil) != tt.wantErr { t.Errorf("GenerateHashtag() error = %v, wantErr %v", err, tt.wantErr) return diff --git a/server/utils.go b/server/utils.go index 799a076..3a1c3e3 100644 --- a/server/utils.go +++ b/server/utils.go @@ -72,6 +72,25 @@ func nextWeekdayDateInWeek(meetingDays []time.Weekday, nextWeek bool) (*time.Tim return nextWeekdayDate(meetingDay, nextWeek) } +func nextWeekdayDateInWeekSkippingDay(meetingDays []time.Weekday, nextWeek bool, dayToSkip time.Weekday) (*time.Time, error) { + if len(meetingDays) == 0 { + return nil, errors.New("missing weekdays to calculate date") + } + + todayWeekday := time.Now().Weekday() + + // Find which meeting weekday to calculate the date for + meetingDay := meetingDays[0] + for _, day := range meetingDays { + if todayWeekday <= day && day != dayToSkip { + meetingDay = day + break + } + } + + return nextWeekdayDate(meetingDay, nextWeek) +} + // nextWeekdayDate calculates the date of the next given weekday // from today's date. // If nextWeek is true, it will be based on the next calendar week. diff --git a/webapp/src/actions/index.js b/webapp/src/actions/index.js index fa540f7..d63e6cd 100644 --- a/webapp/src/actions/index.js +++ b/webapp/src/actions/index.js @@ -1,7 +1,12 @@ +import {AnyAction, Dispatch} from 'redux'; import {searchPostsWithParams} from 'mattermost-redux/actions/search'; - +import {getCurrentChannel} from 'mattermost-redux/selectors/entities/channels'; import {getCurrentTeamId} from 'mattermost-redux/selectors/entities/teams'; import {getConfig} from 'mattermost-redux/selectors/entities/general'; +import {GetStateFunc} from 'mattermost-redux/types/actions'; +import {Client4} from 'mattermost-redux/client'; +import {IntegrationTypes} from 'mattermost-redux/action_types'; + import Client from '../client'; @@ -80,4 +85,44 @@ export function performSearch(terms) { return dispatch(searchPostsWithParams(teamId, {terms, is_or_search: false, include_deleted_channels: viewArchivedChannels, page: 0, per_page: 20}, true)); }; +} + +export function setTriggerId(triggerId) { + return { + type: IntegrationTypes.RECEIVED_DIALOG_TRIGGER_ID, + data: triggerId, + }; +} + +export function requeueItem(itemId) { + return (dispatch, getState) => { + const command = `/agenda requeue ${itemId}`; + clientExecuteCommand(dispatch, getState, command).then(r => {console.log({r})}); + + return {data: true}; + }; +} + + +export async function clientExecuteCommand(dispatch, getState, command) { + let currentChannel = getCurrentChannel(getState()); + const currentTeamId = getCurrentTeamId(getState()); + + // Default to town square if there is no current channel (i.e., if Mattermost has not yet loaded) + if (!currentChannel) { + currentChannel = await Client4.getChannelByName(currentTeamId, 'town-square'); + } + + const args = { + channel_id: currentChannel?.id, + team_id: currentTeamId, + }; + + try { + //@ts-ignore Typing in mattermost-redux is wrong + const data = await Client4.executeCommand(command, args); + dispatch(setTriggerId(data?.trigger_id)); + } catch (error) { + console.error(error); //eslint-disable-line no-console + } } \ No newline at end of file diff --git a/webapp/src/index.js b/webapp/src/index.js index 270f5c9..ab79fe3 100644 --- a/webapp/src/index.js +++ b/webapp/src/index.js @@ -1,5 +1,12 @@ -import {updateSearchTerms, updateSearchResultsTerms, updateRhsState, performSearch, openMeetingSettingsModal} from './actions'; +import { + updateSearchTerms, + updateSearchResultsTerms, + updateRhsState, + performSearch, + openMeetingSettingsModal, + requeueItem +} from './actions'; import reducer from './reducer'; @@ -21,7 +28,7 @@ export default class Plugin { }); registry.registerPostDropdownMenuAction('Re-queue', (params)=>{ - console.log({params}) + store.dispatch(requeueItem(params)); }) } }