-
Notifications
You must be signed in to change notification settings - Fork 21
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
[GH-12] Added Ability to re-queue agenda Items. #89
Changes from 1 commit
19f30a6
51a8315
e4aa842
907377f
9457541
f4c0c33
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||
---|---|---|---|---|---|---|---|---|
|
@@ -2,6 +2,7 @@ package main | |||||||
|
||||||||
import ( | ||||||||
"fmt" | ||||||||
"regexp" | ||||||||
"strings" | ||||||||
"time" | ||||||||
|
||||||||
|
@@ -49,6 +50,9 @@ func (p *Plugin) ExecuteCommand(c *plugin.Context, args *model.CommandArgs) (*mo | |||||||
case "queue": | ||||||||
return p.executeCommandQueue(args), nil | ||||||||
|
||||||||
case "requeue": | ||||||||
return p.executeCommandReQueue(args), nil | ||||||||
|
||||||||
case "setting": | ||||||||
return p.executeCommandSetting(args), nil | ||||||||
|
||||||||
|
@@ -69,7 +73,7 @@ func (p *Plugin) executeCommandList(args *model.CommandArgs) *model.CommandRespo | |||||||
weekday = int(parsedWeekday) | ||||||||
} | ||||||||
|
||||||||
hashtag, err := p.GenerateHashtag(args.ChannelId, nextWeek, weekday) | ||||||||
hashtag, err := p.GenerateHashtag(args.ChannelId, nextWeek, weekday, false, time.Now().Weekday()) | ||||||||
if err != nil { | ||||||||
return responsef("Error calculating hashtags") | ||||||||
} | ||||||||
|
@@ -147,25 +151,21 @@ func (p *Plugin) executeCommandQueue(args *model.CommandArgs) *model.CommandResp | |||||||
message = strings.Join(split[3:], " ") | ||||||||
} | ||||||||
|
||||||||
hashtag, error := p.GenerateHashtag(args.ChannelId, nextWeek, weekday) | ||||||||
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.") | ||||||||
} | ||||||||
|
||||||||
searchResults, appErr := p.API.SearchPostsInTeamForUser(args.TeamId, args.UserId, model.SearchParameter{Terms: &hashtag}) | ||||||||
|
||||||||
if appErr != nil { | ||||||||
return responsef("Error calculating list number") | ||||||||
itemErr, numQueueItems := calculateQueItemNumber(args, p, hashtag) | ||||||||
if itemErr != nil { | ||||||||
return itemErr | ||||||||
} | ||||||||
|
||||||||
postList := *searchResults.PostList | ||||||||
numQueueItems := len(postList.Posts) | ||||||||
|
||||||||
_, appErr = p.API.CreatePost(&model.Post{ | ||||||||
_, 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), | ||||||||
Message: fmt.Sprintf("#### %v %v) %v", hashtag, numQueueItems, message), | ||||||||
}) | ||||||||
if appErr != nil { | ||||||||
return responsef("Error creating post: %s", appErr.Message) | ||||||||
|
@@ -174,6 +174,84 @@ func (p *Plugin) executeCommandQueue(args *model.CommandArgs) *model.CommandResp | |||||||
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") | ||||||||
mickmister marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||
} | ||||||||
|
||||||||
oldPostID := split[2] | ||||||||
postToBeReQueued, _ := p.API.GetPost(oldPostID) | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we check for an error here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||||||||
var ( | ||||||||
prefix string | ||||||||
hashtagDateFormat string | ||||||||
) | ||||||||
if matchGroups := meetingDateFormatRegex.FindStringSubmatch(meeting.HashtagFormat); len(matchGroups) == 4 { | ||||||||
prefix = matchGroups[1] | ||||||||
hashtagDateFormat = strings.TrimSpace(matchGroups[2]) | ||||||||
} | ||||||||
|
||||||||
var ( | ||||||||
messageRegexFormat = regexp.MustCompile(fmt.Sprintf(`(?m)^#### #%s(?P<date>.*) [0-9]+\) (?P<message>.*)?$`, prefix)) | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we define this regex at the top of this file? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 0/5, not optimal since we substitute another value in regex here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should use |
||||||||
) | ||||||||
|
||||||||
if matchGroups := messageRegexFormat.FindStringSubmatch(postToBeReQueued.Message); len(matchGroups) == 3 { | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In order to avoid this large indented block here
Suggested change
Then return an error in that if block, and continue on otherwise There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. great, done. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Seems that this is not done |
||||||||
originalPostDate := strings.ReplaceAll(strings.TrimSpace(matchGroups[1]), "_", " ") // reverse what we do to make it a valid hashtag | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can the "mutation" operations like this in its own function? Same with the operation that is the reverse of this There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||||||||
originalPostMessage := strings.TrimSpace(matchGroups[2]) | ||||||||
|
||||||||
today := time.Now() | ||||||||
local, _ := time.LoadLocation("Local") | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nope, should I remove it? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is usually used instead, or is the only instance of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @sanjaydemansol Please see my question above:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No localized methods are used anywhere. removing There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. time.LoadLocation is stored in local and is used here at. |
||||||||
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("Re-queing future items are not supported.") | ||||||||
mickmister marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||
} | ||||||||
|
||||||||
hashtag, err := p.GenerateHashtag(args.ChannelId, false, -1, true, formattedDate.Weekday()) | ||||||||
if err != nil { | ||||||||
return responsef("Error calculating hashtags. Check the meeting settings for this channel.") | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This error should be logged There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||||||||
} | ||||||||
|
||||||||
itemErr, numQueueItems := calculateQueItemNumber(args, p, hashtag) | ||||||||
if itemErr != nil { | ||||||||
return itemErr | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Our plugin doesn't support returning this as HTTP response. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think the problem is that |
||||||||
} | ||||||||
|
||||||||
_, 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) | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This error should be logged There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||||||||
} | ||||||||
return responsef(fmt.Sprintf("Item has been Re-queued to %v", hashtag)) | ||||||||
} | ||||||||
return responsef("Make sure, message is in required format!") | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Under what circumstances would this occur? We definitely don't want to yell at the user 🙂 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Replaced There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 0/5 it should be worded as
|
||||||||
} | ||||||||
|
||||||||
func (p *Plugin) executeCommandHelp(args *model.CommandArgs) *model.CommandResponse { | ||||||||
return responsef(helpCommandText) | ||||||||
} | ||||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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 | ||
} | ||
} | ||
Comment on lines
+83
to
+89
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we write unit tests for this function? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. sure |
||
|
||
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. | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,8 @@ | ||
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 {Client4} from 'mattermost-redux/client'; | ||
|
||
import Client from '../client'; | ||
|
||
|
@@ -80,4 +81,27 @@ 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 requeueItem(itemId) { | ||
return async (dispatch, getState) => { | ||
const command = `/agenda requeue ${itemId}`; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @mickmister we had a discussion for same at #88 (comment) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Right, the slash command makes sense then. Maybe we change this to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Copied over from #88 (comment): Made |
||
await clientExecuteCommand(dispatch, getState, command); | ||
return {data: true}; | ||
}; | ||
} | ||
|
||
export async function clientExecuteCommand(dispatch, getState, command) { | ||
const currentChannel = getCurrentChannel(getState()); | ||
const currentTeamId = getCurrentTeamId(getState()); | ||
mickmister marked this conversation as resolved.
Show resolved
Hide resolved
|
||
const args = { | ||
channel_id: currentChannel?.id, | ||
team_id: currentTeamId, | ||
}; | ||
|
||
try { | ||
return Client4.executeCommand(command, args); | ||
} catch (error) { | ||
return error; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
|
||
import {updateSearchTerms, updateSearchResultsTerms, updateRhsState, performSearch, openMeetingSettingsModal} from './actions'; | ||
import {updateSearchTerms, updateSearchResultsTerms, updateRhsState, performSearch, openMeetingSettingsModal, requeueItem} from './actions'; | ||
|
||
import reducer from './reducer'; | ||
|
||
|
@@ -19,6 +19,10 @@ export default class Plugin { | |
(channelId) => { | ||
store.dispatch(openMeetingSettingsModal(channelId)); | ||
}); | ||
|
||
registry.registerPostDropdownMenuAction('Re-queue', (itemId) => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We possibly want to use an identifier in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 0/5, for now we could ensure we only show There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I think this is a little too broad of a claim. Two reasons come to mind:
I'm a header
I think we should go with the Another option going along with this same strategy is for the server-side of the plugin to apply the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 for using There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks @mickmister @hanzei , nice approach. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 1/5 I'm thinking we should add it to this PR. @hanzei thoughts? I would want the change to block the release anyway There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @sanjaydemansol Note that the PR should be using |
||
store.dispatch(requeueItem(itemId)); | ||
mickmister marked this conversation as resolved.
Show resolved
Hide resolved
|
||
}); | ||
} | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's a lot going on in this function. Can we pull some of the logic out to be unit tested?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah absolutely, will refactor it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It doesn't look like this function was refactored, but we agreed it should be refactored and tested in this conversation