Send GM status update email on every attendance change
When a player's attendance is updated — either via email (awp-cli check) or via the web toggle — an email is sent to the GM with: - who changed, what they changed to, and how (email or the site) - a summary count of attending/not attending/no response - the full current player status list Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
3426d5ad3d
commit
01d2cae282
3 changed files with 67 additions and 13 deletions
|
|
@ -87,12 +87,12 @@ will attend the next session.`,
|
||||||
player.Attending = attending
|
player.Attending = attending
|
||||||
log.Default().Printf("Received player response for %s: %s", player.Name, player.Attending)
|
log.Default().Printf("Received player response for %s: %s", player.Name, player.Attending)
|
||||||
if !player.Gm {
|
if !player.Gm {
|
||||||
if err := sendEventNotice(
|
gmEmail := session.GMEmail()
|
||||||
session,
|
if gmEmail != "" {
|
||||||
"Received player response",
|
subject, body := session.FormatStatusUpdate(player.Name, attending, "email")
|
||||||
fmt.Sprintf(`Player %s has responded with %q`, player.Name, player.Attending),
|
if err := sendNotice(gmEmail, subject, body); err != nil {
|
||||||
); err != nil {
|
log.Default().Printf("ERROR sending GM notification: %s", err)
|
||||||
log.Default().Printf("ERROR: %s", err)
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ import (
|
||||||
"github.com/golang-jwt/jwt/v4"
|
"github.com/golang-jwt/jwt/v4"
|
||||||
"github.com/hculpan/areweplaying/cmd/web/templates"
|
"github.com/hculpan/areweplaying/cmd/web/templates"
|
||||||
"github.com/hculpan/areweplaying/pkg/data"
|
"github.com/hculpan/areweplaying/pkg/data"
|
||||||
|
"github.com/hculpan/areweplaying/pkg/email"
|
||||||
)
|
)
|
||||||
|
|
||||||
func routes(r *chi.Mux) {
|
func routes(r *chi.Mux) {
|
||||||
|
|
@ -145,23 +146,32 @@ func GenerateJWTAndStoreInCookie(w http.ResponseWriter, key []byte) error {
|
||||||
func updatePlayerAttending(name, attending string, session data.Session) error {
|
func updatePlayerAttending(name, attending string, session data.Session) error {
|
||||||
for i, p := range session.Players {
|
for i, p := range session.Players {
|
||||||
if p.Name == name {
|
if p.Name == name {
|
||||||
|
var newAttending string
|
||||||
switch strings.ToLower(attending) {
|
switch strings.ToLower(attending) {
|
||||||
case "yes", "no":
|
case "yes", "no":
|
||||||
session.Players[i].Attending = strings.ToLower(attending)
|
newAttending = strings.ToLower(attending)
|
||||||
return data.PersistSession(session)
|
|
||||||
case "toggle":
|
case "toggle":
|
||||||
newAttending := session.Players[i].Attending
|
switch session.Players[i].Attending {
|
||||||
switch newAttending {
|
|
||||||
case "unknown", "no":
|
case "unknown", "no":
|
||||||
newAttending = "yes"
|
newAttending = "yes"
|
||||||
case "yes":
|
default:
|
||||||
newAttending = "no"
|
newAttending = "no"
|
||||||
}
|
}
|
||||||
session.Players[i].Attending = newAttending
|
|
||||||
return data.PersistSession(session)
|
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("unrecognized attending indicator %q", attending)
|
return fmt.Errorf("unrecognized attending indicator %q", attending)
|
||||||
}
|
}
|
||||||
|
session.Players[i].Attending = newAttending
|
||||||
|
if err := data.PersistSession(session); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if gmEmail := session.GMEmail(); gmEmail != "" {
|
||||||
|
subject, body := session.FormatStatusUpdate(name, newAttending, "the site")
|
||||||
|
e := email.NewEmail([]string{gmEmail}, []string{}, gmEmail, subject, body)
|
||||||
|
if err := email.SendEmail(e); err != nil {
|
||||||
|
log.Default().Printf("ERROR sending GM notification: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,10 @@
|
||||||
package data
|
package data
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
DATE_FORMAT string = "Monday Jan 2, 2006 3:04pm"
|
DATE_FORMAT string = "Monday Jan 2, 2006 3:04pm"
|
||||||
)
|
)
|
||||||
|
|
@ -20,6 +25,45 @@ type Session struct {
|
||||||
Password string `json:"password"`
|
Password string `json:"password"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Session) GMEmail() string {
|
||||||
|
for _, p := range s.Players {
|
||||||
|
if p.Gm {
|
||||||
|
return p.Email
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Session) FormatStatusUpdate(playerName, newStatus, source string) (string, string) {
|
||||||
|
subject := fmt.Sprintf("Player Status Update: %s → %s", playerName, newStatus)
|
||||||
|
|
||||||
|
var yes, no, unknown int
|
||||||
|
for _, p := range s.Players {
|
||||||
|
switch p.Attending {
|
||||||
|
case "yes":
|
||||||
|
yes++
|
||||||
|
case "no":
|
||||||
|
no++
|
||||||
|
default:
|
||||||
|
unknown++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var sb strings.Builder
|
||||||
|
fmt.Fprintf(&sb, "%s has updated their status to %q (via %s).\n\n", playerName, newStatus, source)
|
||||||
|
fmt.Fprintf(&sb, "Attending: %d | Not attending: %d | No response: %d\n\n", yes, no, unknown)
|
||||||
|
sb.WriteString("Current player status:\n")
|
||||||
|
for _, p := range s.Players {
|
||||||
|
role := ""
|
||||||
|
if p.Gm {
|
||||||
|
role = " (GM)"
|
||||||
|
}
|
||||||
|
fmt.Fprintf(&sb, " %s%s: %s\n", p.Name, role, p.Attending)
|
||||||
|
}
|
||||||
|
|
||||||
|
return subject, sb.String()
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Session) GetPlayerByEmail(addr string) *Player {
|
func (s *Session) GetPlayerByEmail(addr string) *Player {
|
||||||
for i, p := range s.Players {
|
for i, p := range s.Players {
|
||||||
if addr == p.Email {
|
if addr == p.Email {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue