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

fixes mm-12 - Re-queue an item for next meeting #80

Closed
Closed
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
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module github.com/mattermost/mattermost-plugin-agenda
go 1.12

require (
github.com/go-humble/locstor v0.2.2 // indirect
github.com/mattermost/mattermost-server/v5 v5.3.2-0.20200723144633-ed34468996e6
github.com/pkg/errors v0.9.1
github.com/stretchr/testify v1.6.1
Expand Down
3 changes: 3 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,8 @@ github.com/go-asn1-ber/asn1-ber v1.5.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkPro
github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98=
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
github.com/go-gorp/gorp v2.2.0+incompatible/go.mod h1:7IfkAQnO7jfT/9IQ3R9wL1dFhukN6aQxzKTHnkxzA/E=
github.com/go-humble/locstor v0.2.2 h1:0aLPmhiOZPloL09EQC1+1KtGQfLTcLVJr5M/SEnssyU=
github.com/go-humble/locstor v0.2.2/go.mod h1:VtAIYu/7D3+ZurN6FQWA5M/PD+XkDU9cSLrOIPi42xM=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
Expand Down Expand Up @@ -208,6 +210,7 @@ github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk
github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gopherjs/gopherjs v0.0.0-20190910122728-9d188e94fb99 h1:twflg0XRTjwKpxb/jFExr4HGq6on2dEOmnL6FV+fgPw=
github.com/gopherjs/gopherjs v0.0.0-20190910122728-9d188e94fb99/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
github.com/gorilla/handlers v1.4.2/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ=
Expand Down
109 changes: 98 additions & 11 deletions server/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package main

import (
"fmt"
"regexp"
"strings"
"time"

Expand Down Expand Up @@ -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

Expand All @@ -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")
}
Expand Down Expand Up @@ -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)
Expand All @@ -174,6 +174,93 @@ 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")
}

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<date>.*) [0-9]+\) (?P<message>.*)?$`, 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)
}
Expand Down
28 changes: 21 additions & 7 deletions server/meeting.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ var (
type Meeting struct {
ChannelID string `json:"channelId"`
Schedule []time.Weekday `json:"schedule"`
HashtagFormat string `json:"hashtagFormat"` // Default: {ChannelName}-Jan02
HashtagFormat string `json:"hashtagFormat"` // Default: {ChannelName}-Jan-2
}

// GetMeeting returns a meeting
Expand All @@ -37,9 +37,10 @@ func (p *Plugin) GetMeeting(channelID string) (*Meeting, error) {
if err != nil {
return nil, err
}
paddedChannelName := strings.ReplaceAll(channel.Name, "-", "_")
meeting = &Meeting{
Schedule: []time.Weekday{time.Thursday},
HashtagFormat: strings.Join([]string{fmt.Sprintf("%.15s", channel.Name), "{{ Jan02 }}"}, "-"),
HashtagFormat: strings.Join([]string{fmt.Sprintf("%.15s", paddedChannelName), "{{ Jan 2 }}"}, "_"),
ChannelID: channelID,
}
}
Expand All @@ -62,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
Expand All @@ -74,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
Expand All @@ -92,8 +104,10 @@ func (p *Plugin) GenerateHashtag(channelID string, nextWeek bool, weekday int) (
prefix = matchGroups[1]
hashtagFormat = strings.TrimSpace(matchGroups[2])
postfix = matchGroups[3]
formattedDate := meetingDate.Format(hashtagFormat)
formattedDate = strings.ReplaceAll(formattedDate, " ", "_")

hashtag = fmt.Sprintf("#%s%v%s", prefix, meetingDate.Format(hashtagFormat), postfix)
hashtag = fmt.Sprintf("#%s%v%s", prefix, formattedDate, postfix)
} else {
hashtag = fmt.Sprintf("#%s", meeting.HashtagFormat)
}
Expand Down
24 changes: 12 additions & 12 deletions server/meeting_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,9 @@ func TestPlugin_GenerateHashtag(t *testing.T) {
meeting: &Meeting{
ChannelID: "QA",
Schedule: []time.Weekday{time.Wednesday},
HashtagFormat: "{{Jan02}}",
HashtagFormat: "{{Jan 2}}",
}},
want: "#" + assertNextWeekdayDate(time.Wednesday, true).Format("Jan02"),
want: "#" + strings.ReplaceAll(assertNextWeekdayDate(time.Wednesday, true).Format("Jan 2"), " ", "_"),
wantErr: false,
},
{
Expand All @@ -67,9 +67,9 @@ func TestPlugin_GenerateHashtag(t *testing.T) {
meeting: &Meeting{
ChannelID: "QA Backend",
Schedule: []time.Weekday{time.Monday},
HashtagFormat: "QA-{{January 02 2006}}",
HashtagFormat: "QA_{{January 02 2006}}",
}},
want: "#QA-" + assertNextWeekdayDate(time.Monday, true).Format("January 02 2006"),
want: "#QA_" + strings.ReplaceAll(assertNextWeekdayDate(time.Monday, true).Format("January 02 2006"), " ", "_"),
wantErr: false,
},
{
Expand All @@ -81,7 +81,7 @@ func TestPlugin_GenerateHashtag(t *testing.T) {
Schedule: []time.Weekday{time.Monday},
HashtagFormat: "{{January 02 2006}}.vue",
}},
want: "#" + assertNextWeekdayDate(time.Monday, false).Format("January 02 2006") + ".vue",
want: "#" + strings.ReplaceAll(assertNextWeekdayDate(time.Monday, false).Format("January 02 2006"), " ", "_") + ".vue",
wantErr: false,
},
{
Expand All @@ -93,7 +93,7 @@ func TestPlugin_GenerateHashtag(t *testing.T) {
Schedule: []time.Weekday{time.Monday},
HashtagFormat: "React {{January 02 2006}} Born",
}},
want: "#React " + assertNextWeekdayDate(time.Monday, false).Format("January 02 2006") + " Born",
want: "#React " + strings.ReplaceAll(assertNextWeekdayDate(time.Monday, false).Format("January 02 2006"), " ", "_") + " Born",
wantErr: false,
},
{
Expand All @@ -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 " + 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,
},
{
Expand All @@ -117,7 +117,7 @@ func TestPlugin_GenerateHashtag(t *testing.T) {
Schedule: []time.Weekday{time.Monday},
HashtagFormat: "{{ January 02 2006 }}",
}},
want: "#" + assertNextWeekdayDate(time.Monday, false).Format("January 02 2006"),
want: "#" + strings.ReplaceAll(assertNextWeekdayDate(time.Monday, false).Format("January 02 2006"), " ", "_"),
wantErr: false,
},
{
Expand All @@ -129,7 +129,7 @@ func TestPlugin_GenerateHashtag(t *testing.T) {
Schedule: []time.Weekday{time.Monday},
HashtagFormat: "{{ Mon Jan _2 }}",
}},
want: "#" + assertNextWeekdayDate(time.Monday, false).Format("Mon Jan _2"),
want: "#" + strings.ReplaceAll(assertNextWeekdayDate(time.Monday, false).Format("Mon Jan _2"), " ", "_"),
wantErr: false,
},
}
Expand All @@ -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
Expand Down Expand Up @@ -176,7 +176,7 @@ func TestPlugin_GetMeeting(t *testing.T) {
},
want: &Meeting{
Schedule: []time.Weekday{time.Thursday},
HashtagFormat: "Short-{{ Jan02 }}",
HashtagFormat: "Short_{{ Jan 2 }}",
ChannelID: "#short.name.channel",
},
wantErr: false,
Expand All @@ -190,7 +190,7 @@ func TestPlugin_GetMeeting(t *testing.T) {
},
want: &Meeting{
Schedule: []time.Weekday{time.Thursday},
HashtagFormat: "Very Long Chann-{{ Jan02 }}",
HashtagFormat: "Very Long Chann_{{ Jan 2 }}",
ChannelID: "#long.name.channel",
},
wantErr: false,
Expand Down
2 changes: 1 addition & 1 deletion server/plugin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ func TestServeHTTP(t *testing.T) {
defaultMeeting := &Meeting{
ChannelID: "myChannelId",
Schedule: []time.Weekday{time.Thursday},
HashtagFormat: "Jan02",
HashtagFormat: "Jan-2",
}

jsonMeeting, err := json.Marshal(defaultMeeting)
Expand Down
19 changes: 19 additions & 0 deletions server/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
Loading