Skip to content

Commit

Permalink
Merge pull request #2 from sanjaydemansol/Requeu
Browse files Browse the repository at this point in the history
Re-queue an item for next meeting mattermost-community#12
  • Loading branch information
maisnamrajusingh authored Jul 12, 2021
2 parents 2f22484 + e2d3b59 commit 267fc5d
Show file tree
Hide file tree
Showing 12 changed files with 3,056 additions and 4,597 deletions.
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

0 comments on commit 267fc5d

Please sign in to comment.