Added timers, error handling, validation on item number #1
2 changed files with 109 additions and 16 deletions
|
@ -2,5 +2,7 @@
|
||||||
"MatrixRoom": "!exampleEXAMPLEexample:cyberia.club",
|
"MatrixRoom": "!exampleEXAMPLEexample:cyberia.club",
|
||||||
"MatrixToken": "syt_exampleEXAMPLE_exampleEXAMPLE_example",
|
"MatrixToken": "syt_exampleEXAMPLE_exampleEXAMPLE_example",
|
||||||
"MatrixUsername": "@consensus-bot:cyberia.club",
|
"MatrixUsername": "@consensus-bot:cyberia.club",
|
||||||
"MatrixURL": "https://matrix.cyberia.club"
|
"MatrixURL": "https://matrix.cyberia.club",
|
||||||
}
|
"WarningTime": "144h",
|
||||||
|
"ActivationTimeAfterWarning":"24h"
|
||||||
|
}
|
||||||
|
|
119
main.go
119
main.go
|
@ -10,6 +10,7 @@ import (
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -25,10 +26,12 @@ const (
|
||||||
var config Config
|
var config Config
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
MatrixRoom string
|
MatrixRoom string
|
||||||
MatrixURL string
|
MatrixURL string
|
||||||
MatrixUsername string
|
MatrixUsername string
|
||||||
MatrixToken string
|
MatrixToken string
|
||||||
|
WarningTime string
|
||||||
|
ActivationTimeAfterWarning string
|
||||||
}
|
}
|
||||||
|
|
||||||
type RecordCount struct {
|
type RecordCount struct {
|
||||||
|
@ -38,11 +41,12 @@ type RecordCount struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type Item struct {
|
type Item struct {
|
||||||
author string
|
author string
|
||||||
date time.Time
|
date time.Time
|
||||||
number string
|
number string
|
||||||
name string
|
name string
|
||||||
path string
|
path string
|
||||||
|
currentTimer *time.Timer
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i Item) Status() string {
|
func (i Item) Status() string {
|
||||||
|
@ -300,6 +304,47 @@ important: let all items sit for awhile prior to closure
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func createTriggerOneDayAutoDecide(item Item) func() {
|
||||||
|
//TODO: add functions to extend the timer, and to cancel the timer if the item is closed before it fires
|
||||||
|
return func() {
|
||||||
|
records := countRecords(item.path)
|
||||||
|
if records.approvals != 0 && records.concerns == 0 {
|
||||||
|
handleClose(item.number, "approved")
|
||||||
|
|
||||||
|
}
|
||||||
|
if records.concerns > 0 {
|
||||||
|
handleClose(item.number, "cancelled")
|
||||||
|
}
|
||||||
|
if records.approvals == 0 && records.concerns == 0 {
|
||||||
|
|
||||||
|
openDays := time.Since(item.date).Hours() / 24
|
||||||
|
msg := fmt.Sprintf("consensus item %s is %v days old... but nobody has approved or concerned yet. Let's give it another %s, shall we?", item.number, openDays, config.WarningTime)
|
||||||
|
err := sendMessage(msg)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(fmt.Sprintf("Error (from notifFunc) sending message for item %s: %v", item.name, err))
|
||||||
|
}
|
||||||
|
notifFunc := createNotifFunc(item)
|
||||||
|
warningTime, _ := time.ParseDuration(config.WarningTime)
|
||||||
|
time.AfterFunc(warningTime, notifFunc)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func createNotifFunc(item Item) func() {
|
||||||
|
//TODO: add functions to extend the timer, and to cancel the timer if the item is closed before it fires
|
||||||
|
return func() {
|
||||||
|
openDays := time.Since(item.date).Hours() / 24
|
||||||
|
msg := fmt.Sprintf("consensus item %s is now %v days old: %s\nThe item will auto-pass after %s if there is unanimous approval, and auto-fail otherwise! So, now is a good time to weigh in if you haven't yet and have an opinion!", item.number, openDays, item.name, config.ActivationTimeAfterWarning)
|
||||||
|
err := sendMessage(msg)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(fmt.Sprintf("Error (from notifFunc) sending message for item %s: %v", item.name, err))
|
||||||
|
}
|
||||||
|
triggerOneDayAutoDecide := createTriggerOneDayAutoDecide(item)
|
||||||
|
activationTime, _ := time.ParseDuration(config.ActivationTimeAfterWarning)
|
||||||
|
time.AfterFunc(activationTime, triggerOneDayAutoDecide)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func handleNew(event *gomatrix.Event) error {
|
func handleNew(event *gomatrix.Event) error {
|
||||||
body, ok := event.Body()
|
body, ok := event.Body()
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -330,6 +375,12 @@ func handleNew(event *gomatrix.Event) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
//automatically check-in after time specified in configuration, then after the other time specified in configuration
|
||||||
|
//approve if it has unanimous approval or cancel if any concerns
|
||||||
|
notifFunc := createNotifFunc(item)
|
||||||
|
warningTime, _ := time.ParseDuration(config.WarningTime)
|
||||||
|
time.AfterFunc(warningTime, notifFunc)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -489,6 +540,11 @@ func handleClose(itemNumber string, status string) {
|
||||||
sendMessage("please specify an item number. see !help")
|
sendMessage("please specify an item number. see !help")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !isValidItemNumber(itemNumber) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
itemPath := recordDir + "/" + itemNumber + ".txt"
|
itemPath := recordDir + "/" + itemNumber + ".txt"
|
||||||
|
|
||||||
if !fileExists(itemPath) {
|
if !fileExists(itemPath) {
|
||||||
|
@ -523,12 +579,28 @@ func handleClose(itemNumber string, status string) {
|
||||||
sendMessage(msg)
|
sendMessage(msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isValidItemNumber(itemNumberCandidate string) bool {
|
||||||
|
_, err := strconv.Atoi(itemNumberCandidate)
|
||||||
|
if err != nil {
|
||||||
|
err = sendMessage("hold yer horses there pard, that ain't no item number like I ever seen before...")
|
||||||
|
if err != nil {
|
||||||
|
log.Println(fmt.Sprintf("Error (from isValidItemNumber) sending message: %v", err))
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
func handleShow(itemNumber string) {
|
func handleShow(itemNumber string) {
|
||||||
if strings.TrimSpace(itemNumber) == "" {
|
if strings.TrimSpace(itemNumber) == "" {
|
||||||
sendMessage("please specify an item number. see !help")
|
sendMessage("please specify an item number. see !help")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !isValidItemNumber(itemNumber) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
itemPath := recordDir + "/" + itemNumber + ".txt"
|
itemPath := recordDir + "/" + itemNumber + ".txt"
|
||||||
if !fileExists(itemPath) {
|
if !fileExists(itemPath) {
|
||||||
sendMessage("item specified does not exist")
|
sendMessage("item specified does not exist")
|
||||||
|
@ -546,30 +618,49 @@ func handleShow(itemNumber string) {
|
||||||
|
|
||||||
func handleComment(event *gomatrix.Event, itemNumber string, comment string, emoji string) {
|
func handleComment(event *gomatrix.Event, itemNumber string, comment string, emoji string) {
|
||||||
if strings.TrimSpace(itemNumber) == "" {
|
if strings.TrimSpace(itemNumber) == "" {
|
||||||
sendMessage("please specify an item number. see !help")
|
err := sendMessage("please specify an item number. see !help")
|
||||||
|
if err != nil {
|
||||||
|
log.Println(fmt.Sprintf("Error (from handleComment) sending messag: %v", err))
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if strings.TrimSpace(comment) == "" {
|
if strings.TrimSpace(comment) == "" {
|
||||||
sendMessage("please specify a comment. see !help")
|
err := sendMessage("please specify a comment. see !help")
|
||||||
|
if err != nil {
|
||||||
|
log.Println(fmt.Sprintf("Error (from handleComment) sending messag: %v", err))
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !isValidItemNumber(itemNumber) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
itemPath := recordDir + "/" + itemNumber + ".txt"
|
itemPath := recordDir + "/" + itemNumber + ".txt"
|
||||||
|
|
||||||
if !fileExists(itemPath) {
|
if !fileExists(itemPath) {
|
||||||
sendMessage("item specified does not exist")
|
err := sendMessage("item specified does not exist")
|
||||||
|
if err != nil {
|
||||||
|
log.Println(fmt.Sprintf("Error (from handleComment) sending messag: %v", err))
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
item, err := loadItemByPath(itemPath)
|
item, err := loadItemByPath(itemPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
sendMessage("item not found: " + err.Error())
|
err = sendMessage("item not found: " + err.Error())
|
||||||
|
if err != nil {
|
||||||
|
log.Println(fmt.Sprintf("Error (from handleComment) sending messag: %v", err))
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if !item.isActive() {
|
if !item.isActive() {
|
||||||
sendMessage(fmt.Sprintf("item %s (%s) is not active and may not be commented on", item.number, item.name))
|
err = sendMessage(fmt.Sprintf("item %s (%s) is not active and may not be commented on", item.number, item.name))
|
||||||
|
if err != nil {
|
||||||
|
log.Println(fmt.Sprintf("Error (from handleComment) sending messag: %v", err))
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue