296 lines
6.9 KiB
Go
296 lines
6.9 KiB
Go
package lishwist
|
|
|
|
import (
|
|
"database/sql"
|
|
"errors"
|
|
"fmt"
|
|
"strings"
|
|
|
|
"lishwist/core/internal/db"
|
|
)
|
|
|
|
type Wish struct {
|
|
Id string
|
|
Name string
|
|
ClaimantId string `json:",omitempty"`
|
|
ClaimantName string `json:",omitempty"`
|
|
Sent bool
|
|
RecipientId string `json:",omitempty"`
|
|
RecipientName string `json:",omitempty"`
|
|
RecipientRef string `json:",omitempty"`
|
|
CreatorId string `json:",omitempty"`
|
|
CreatorName string `json:",omitempty"`
|
|
}
|
|
|
|
func (s *Session) GetWishes() ([]Wish, error) {
|
|
stmt := "SELECT wish.id, wish.name, wish.sent FROM wish WHERE wish.creator_id = ?1 AND wish.recipient_id = ?1"
|
|
rows, err := db.Connection.Query(stmt, s.User.Id)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("Query execution failed: %w", err)
|
|
}
|
|
defer rows.Close()
|
|
wishs := []Wish{}
|
|
for rows.Next() {
|
|
var id string
|
|
var name string
|
|
var sent bool
|
|
err = rows.Scan(&id, &name, &sent)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("Failed to scan a row: %w", err)
|
|
}
|
|
wish := Wish{
|
|
Id: id,
|
|
Name: name,
|
|
Sent: sent,
|
|
}
|
|
wishs = append(wishs, wish)
|
|
}
|
|
err = rows.Err()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("Rows returned an error: %w", err)
|
|
}
|
|
return wishs, nil
|
|
}
|
|
|
|
func (s *Session) MakeWish(name string) error {
|
|
stmt := "INSERT INTO wish (name, recipient_id, creator_id) VALUES (?, ?, ?)"
|
|
_, err := db.Connection.Exec(stmt, strings.TrimSpace(name), s.User.Id, s.User.Id)
|
|
if err != nil {
|
|
return fmt.Errorf("Query execution failed: %w", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (u *Session) deleteWishes(tx *sql.Tx, ids []string) error {
|
|
stmt := "DELETE FROM wish WHERE wish.creator_id = ? AND wish.id = ?"
|
|
for _, id := range ids {
|
|
r, err := tx.Exec(stmt, u.Id, id)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
rE, err := r.RowsAffected()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if rE < 1 {
|
|
return fmt.Errorf("Wish deletion failed for '%s'", id)
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (s *Session) RevokeWishes(ids ...string) error {
|
|
if len(ids) < 1 {
|
|
return fmt.Errorf("Attempt to remove zero wishes")
|
|
}
|
|
|
|
tx, err := db.Connection.Begin()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = s.deleteWishes(tx, ids)
|
|
if err != nil {
|
|
rollBackErr := tx.Rollback()
|
|
if rollBackErr != nil {
|
|
return err
|
|
}
|
|
return err
|
|
}
|
|
|
|
err = tx.Commit()
|
|
return err
|
|
}
|
|
|
|
func (s *Session) GetOthersWishes(userReference string) ([]Wish, error) {
|
|
otherUser, err := getUserByReference(userReference)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("Failed to get other user: %w", err)
|
|
}
|
|
if otherUser.Id == s.User.Id {
|
|
return nil, errors.New("Use (s *Session) GetWishes() to view your own wishes")
|
|
}
|
|
stmt := "SELECT wish.id, wish.name, claimant.id, claimant.name, wish.sent, wish.creator_id, creator.name, wish.recipient_id FROM wish JOIN v_user AS user ON wish.recipient_id = user.id LEFT JOIN v_user AS claimant ON wish.claimant_id = claimant.id LEFT JOIN v_user AS creator ON wish.creator_id = creator.id WHERE user.id = ?"
|
|
rows, err := db.Connection.Query(stmt, otherUser.Id)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("Failed to execute query: %w", err)
|
|
}
|
|
defer rows.Close()
|
|
wishes := []Wish{}
|
|
for rows.Next() {
|
|
var id string
|
|
var name string
|
|
var claimantId sql.NullString
|
|
var claimantName sql.NullString
|
|
var sent bool
|
|
var creatorId string
|
|
var creatorName string
|
|
var recipientId string
|
|
err = rows.Scan(&id, &name, &claimantId, &claimantName, &sent, &creatorId, &creatorName, &recipientId)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("Failed to scan a row: %w", err)
|
|
}
|
|
wish := Wish{
|
|
Id: id,
|
|
Name: name,
|
|
ClaimantId: claimantId.String,
|
|
ClaimantName: claimantName.String,
|
|
Sent: sent,
|
|
CreatorId: creatorId,
|
|
CreatorName: creatorName,
|
|
RecipientId: recipientId,
|
|
}
|
|
wishes = append(wishes, wish)
|
|
}
|
|
err = rows.Err()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("Rows returned an error: %w", err)
|
|
}
|
|
return wishes, nil
|
|
}
|
|
|
|
// NOTE: This could just be a field on the user... but only if we get this often
|
|
func (u *User) WishCount() (int, error) {
|
|
stmt := "SELECT COUNT(wish.id) AS wish_count FROM wish WHERE wish.creator_id = ?1 AND wish.recipient_id = ?1"
|
|
var wishCount int
|
|
err := db.Connection.QueryRow(stmt, u.Id).Scan(&wishCount)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return wishCount, nil
|
|
}
|
|
|
|
func (s *Session) executeClaims(tx *sql.Tx, claims, unclaims []string) error {
|
|
claimStmt := "UPDATE wish SET claimant_id = ? WHERE id = ?"
|
|
unclaimStmt := "UPDATE wish SET claimant_id = NULL WHERE id = ?"
|
|
for _, id := range claims {
|
|
r, err := tx.Exec(claimStmt, s.Id, id)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
rE, err := r.RowsAffected()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if rE < 1 {
|
|
return fmt.Errorf("Wish claim failed for '%s'", id)
|
|
}
|
|
}
|
|
for _, id := range unclaims {
|
|
r, err := tx.Exec(unclaimStmt, id)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
rE, err := r.RowsAffected()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if rE < 1 {
|
|
return fmt.Errorf("Wish unclaim failed for '%s'", id)
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Undertake or abandon wishes made by other users
|
|
func (s *Session) ClaimWishes(claims, unclaims []string) error {
|
|
if len(claims) < 1 && len(unclaims) < 1 {
|
|
return fmt.Errorf("Attempt to claim/unclaim zero wishes")
|
|
}
|
|
|
|
tx, err := db.Connection.Begin()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = s.executeClaims(tx, claims, unclaims)
|
|
if err != nil {
|
|
rollBackErr := tx.Rollback()
|
|
if rollBackErr != nil {
|
|
return err
|
|
}
|
|
return err
|
|
}
|
|
|
|
err = tx.Commit()
|
|
return err
|
|
}
|
|
|
|
func executeCompletions(tx *sql.Tx, claims []string) error {
|
|
claimStmt := "UPDATE wish SET sent = 1 WHERE id = ?"
|
|
for _, id := range claims {
|
|
r, err := tx.Exec(claimStmt, id)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
rE, err := r.RowsAffected()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if rE < 1 {
|
|
return fmt.Errorf("Wish completion failed for '%s'", id)
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// TODO: User ought not be able to interact with wishes outside their group network
|
|
func (s *Session) CompleteWishes(claims []string) error {
|
|
if len(claims) < 1 {
|
|
return fmt.Errorf("Attempt to complete zero wishes")
|
|
}
|
|
|
|
tx, err := db.Connection.Begin()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = executeCompletions(tx, claims)
|
|
if err != nil {
|
|
rollBackErr := tx.Rollback()
|
|
if rollBackErr != nil {
|
|
return err
|
|
}
|
|
return err
|
|
}
|
|
|
|
err = tx.Commit()
|
|
return err
|
|
}
|
|
|
|
func (u *Session) SuggestWishForUser(otherUserReference string, wishName string) error {
|
|
otherUser, err := GetUserByReference(otherUserReference)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
stmt := "INSERT INTO wish (name, recipient_id, creator_id) VALUES (?, ?, ?)"
|
|
_, err = db.Connection.Exec(stmt, wishName, otherUser.Id, u.Id)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (s *Session) RecindWishesForUser(ids ...string) error {
|
|
if len(ids) < 1 {
|
|
return fmt.Errorf("Attempt to remove zero wishes")
|
|
}
|
|
|
|
tx, err := db.Connection.Begin()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = s.deleteWishes(tx, ids)
|
|
if err != nil {
|
|
rollBackErr := tx.Rollback()
|
|
if rollBackErr != nil {
|
|
return err
|
|
}
|
|
return err
|
|
}
|
|
|
|
err = tx.Commit()
|
|
return err
|
|
}
|