151 lines
4.0 KiB
Go
151 lines
4.0 KiB
Go
package lishwist
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
"strings"
|
|
"time"
|
|
|
|
"lishwist/core/internal/db"
|
|
)
|
|
|
|
const (
|
|
eventActionCreate = "CREATE"
|
|
eventActionHide = "HIDE"
|
|
eventActionUnhide = "UNHIDE"
|
|
eventActionClaim = "CLAIM"
|
|
eventActionUnclaim = "UNCLAIM"
|
|
eventActionComplete = "COMPLETE"
|
|
// eventActionDelete = "DELETE" NOTE: We can't have this, because there'll be no target to reference
|
|
)
|
|
|
|
const (
|
|
eventTargetGroup = "GROUP"
|
|
eventTargetUser = "USER"
|
|
eventTargetWish = "WISH"
|
|
eventTargetGroupMember = "GROUP_MEMBER"
|
|
)
|
|
|
|
type Event struct {
|
|
Id string
|
|
ActorId string
|
|
ActionType string
|
|
TargetType string
|
|
TargetId string
|
|
CreatedAt time.Time
|
|
}
|
|
|
|
// type EventCreateGroupMember struct {
|
|
// Event
|
|
// Actor User
|
|
// User
|
|
// Group
|
|
// }
|
|
|
|
func queryManyEvents(query string, args ...any) ([]Event, error) {
|
|
rows, err := db.Connection.Query(query, args...)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
events := []Event{}
|
|
for rows.Next() {
|
|
var g Event
|
|
var createdAt string
|
|
err = rows.Scan(&g.Id, &g.ActorId, &g.ActionType, &g.TargetType, &g.TargetId, &createdAt)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
g.CreatedAt, err = time.Parse(time.RFC3339Nano, createdAt)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to parse created_at: %w", err)
|
|
}
|
|
events = append(events, g)
|
|
}
|
|
err = rows.Err()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return events, nil
|
|
}
|
|
|
|
func queryOneEvent(query string, args ...any) (*Event, error) {
|
|
events, err := queryManyEvents(query, args...)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if len(events) < 1 {
|
|
return nil, nil
|
|
}
|
|
return &events[0], nil
|
|
}
|
|
|
|
func (a *Admin) ListEvents() ([]Event, error) {
|
|
query := "SELECT id, actor_id, action_type, target_type, target_id, created_at FROM event;"
|
|
return queryManyEvents(query)
|
|
}
|
|
|
|
func recordEvent(actorId, actionType, targetType string, targetIds ...string) {
|
|
// TODO: If this were to accept sql.Tx it could be used in atomic transactions
|
|
numTargets := len(targetIds)
|
|
if numTargets < 1 {
|
|
log.Println("Warning: recordEvent called with no target IDs. Skipping.")
|
|
return
|
|
}
|
|
stmt := "INSERT INTO event (actor_id, action_type, target_type, target_id) VALUES (?, ?, ?, ?)"
|
|
extraValuePlaceholders := strings.Repeat(", (?, ?, ?, ?)", numTargets-1)
|
|
args := make([]any, numTargets*4)
|
|
for i, id := range targetIds {
|
|
args[i*4] = actorId
|
|
args[i*4+1] = actionType
|
|
args[i*4+2] = targetType
|
|
args[i*4+3] = id
|
|
}
|
|
_, err := db.Connection.Exec(stmt+extraValuePlaceholders, args...)
|
|
if err == nil {
|
|
return
|
|
}
|
|
if numTargets == 1 {
|
|
log.Printf("Failed to record %s %s event: failed to execute query: %s\n", actionType, targetType, err)
|
|
} else {
|
|
log.Printf("Failed to record %d %s %s events: failed to execute query: %s\n", numTargets, actionType, targetType, err)
|
|
}
|
|
}
|
|
|
|
func recordEventCreateGroup(actorId, groupId string) {
|
|
recordEvent(actorId, eventActionCreate, eventTargetGroup, groupId)
|
|
}
|
|
|
|
func recordEventCreateUser(actorId, userId string) {
|
|
recordEvent(actorId, eventActionCreate, eventTargetUser, userId)
|
|
}
|
|
|
|
func recordEventCreateWish(actorId, wishId string) {
|
|
recordEvent(actorId, eventActionCreate, eventTargetWish, wishId)
|
|
}
|
|
|
|
func recordEventCreateGroupMember(actorId, groupMemberId string) {
|
|
recordEvent(actorId, eventActionCreate, eventTargetGroupMember, groupMemberId)
|
|
}
|
|
|
|
// FIXME: I can't use these yet because the associated actions use reference
|
|
// func recordEventHideUser(actorId, userId string) {
|
|
// recordEvent(actorId, eventActionHide, eventTargetUser, userId)
|
|
// }
|
|
|
|
// func recordEventUnhideUser(actorId, userId string) {
|
|
// recordEvent(actorId, eventActionUnhide, eventTargetUser, userId)
|
|
// }
|
|
|
|
func recordEventClaimWishes(actorId string, wishIds ...string) {
|
|
recordEvent(actorId, eventActionClaim, eventTargetWish, wishIds...)
|
|
}
|
|
|
|
func recordEventUnclaimWishes(actorId string, wishIds ...string) {
|
|
recordEvent(actorId, eventActionUnclaim, eventTargetWish, wishIds...)
|
|
}
|
|
|
|
func recordEventCompleteWishes(actorId string, wishIds ...string) {
|
|
recordEvent(actorId, eventActionComplete, eventTargetWish, wishIds...)
|
|
}
|