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

Agenda item number should get updated if the items of the agenda are deleted #3

Merged
merged 4 commits into from
Jul 12, 2021
Merged
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
164 changes: 155 additions & 9 deletions server/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package main

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

Expand All @@ -16,6 +18,14 @@ const (
wsEventList = "list"
)

type ParsedMeetingMessage struct {
prefix string
hashTag string
date string
number string //TODO we don't need it right now
textMessage string
}

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`" +
Expand Down Expand Up @@ -49,6 +59,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 +82,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 @@ -132,6 +145,11 @@ func (p *Plugin) executeCommandQueue(args *model.CommandArgs) *model.CommandResp
return responsef("Missing parameters for queue command")
}

meeting, err := p.GetMeeting(args.ChannelId)
if err != nil {
return responsef("Can't find the meeting")
}

nextWeek := false
weekday := -1
message := strings.Join(split[2:], " ")
Expand All @@ -147,31 +165,159 @@ 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.")
}

numQueueItems, itemErr := calculateQueItemNumberAndUpdateOldItems(meeting, 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 calculateQueItemNumberAndUpdateOldItems(meeting *Meeting, args *model.CommandArgs, p *Plugin, hashtag string) (int, *model.CommandResponse) {
searchResults, appErr := p.API.SearchPostsInTeamForUser(args.TeamId, args.UserId, model.SearchParameter{Terms: &hashtag})

if appErr != nil {
return responsef("Error calculating list number")
return 0, responsef("Error calculating list number")
}

postList := *searchResults.PostList
numQueueItems := len(postList.Posts)
counter := 1

_, appErr = p.API.CreatePost(&model.Post{
var sortedPosts []*model.Post
// TODO we won't need to do this once we fix https://github.com/mattermost/mattermost-server/issues/11006
for _, post := range searchResults.PostList.Posts {
sortedPosts = append(sortedPosts, post)
}

sort.Slice(sortedPosts, func(i, j int) bool {
return sortedPosts[i].CreateAt < sortedPosts[j].CreateAt
})

for _, post := range sortedPosts {

_, parsedMessage, _ := parseMeetingPost(meeting, post)

_, findErr := p.API.UpdatePost(&model.Post{
Id: post.Id,
UserId: args.UserId,
ChannelId: args.ChannelId,
RootId: args.RootId,
Message: fmt.Sprintf("#### %v %v) %v", hashtag, counter, parsedMessage.textMessage),
})
counter++
if findErr != nil {
return 0, responsef("Error updating post: %s", findErr.Message)
}

}

return counter, nil
}

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 { //TODO locate why its not nil even if id is valid and working
// return responsef("Couldn't locate the post to requeue.")
//}
hashtagDateFormat, parsedMeetingMessage, errors := parseMeetingPost(meeting, postToBeReQueued)
if errors != nil {
return errors
}

originalPostDate := strings.ReplaceAll(strings.TrimSpace(parsedMeetingMessage.date), "_", " ") // reverse what we do to make it a valid hashtag
originalPostMessage := strings.TrimSpace(parsedMeetingMessage.textMessage)

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.")
}

numQueueItems, itemErr := calculateQueItemNumberAndUpdateOldItems(meeting, 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+1, message),
Message: fmt.Sprintf("#### %v %v) %v", hashtag, numQueueItems, originalPostMessage),
})
if appErr != nil {
return responsef("Error creating post: %s", appErr.Message)
return responsef("Error updating post: %s", appErr.Message)
}

return &model.CommandResponse{Text: fmt.Sprintf("Item has been Re-queued to %v", hashtag), ResponseType: model.COMMAND_RESPONSE_TYPE_EPHEMERAL}

}

func parseMeetingPost(meeting *Meeting, post *model.Post) (string, ParsedMeetingMessage, *model.CommandResponse) {
var (
prefix string
hashtagDateFormat string
)
if matchGroups := meetingDateFormatRegex.FindStringSubmatch(meeting.HashtagFormat); len(matchGroups) == 4 {
prefix = matchGroups[1]
hashtagDateFormat = strings.TrimSpace(matchGroups[2])
} else {
return "", ParsedMeetingMessage{}, responsef("Error 267")
}

var (
messageRegexFormat = regexp.MustCompile(fmt.Sprintf(`(?m)^#### #%s(?P<date>.*) ([0-9]+)\) (?P<message>.*)?$`, prefix))
)

matchGroups := messageRegexFormat.FindStringSubmatch(post.Message)
if len(matchGroups) == 4 {
parsedMeetingMessage := ParsedMeetingMessage{
date: matchGroups[1],
number: matchGroups[2],
textMessage: matchGroups[3],
}
return hashtagDateFormat, parsedMeetingMessage, nil
} else {
return hashtagDateFormat, ParsedMeetingMessage{}, responsef("Please ensure correct message format!")
}

return &model.CommandResponse{}
}

func (p *Plugin) executeCommandHelp(args *model.CommandArgs) *model.CommandResponse {
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
Loading