feat: multi-delete

This commit is contained in:
Teajey 2024-05-08 00:43:55 +12:00
parent 73e64f096d
commit 51c33543e8
Signed by: Teajey
GPG Key ID: 970E790FE834A713
6 changed files with 126 additions and 54 deletions

View File

@ -32,15 +32,11 @@ func (ctx *Context) WishlistDelete(w http.ResponseWriter, r *http.Request) {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
target := r.Form.Get("gift_id")
if target == "" {
http.Error(w, "Gift ID not provided"+target, http.StatusBadRequest)
return
}
err := user.RemoveGift(target)
targets := r.Form["gift"]
err := user.RemoveGifts(targets...)
if err != nil {
log.Printf("Failed to remove gift: %s\n", err)
http.Error(w, "Failed to remove gift.", http.StatusInternalServerError)
log.Printf("Failed to remove gifts: %s\n", err)
http.Error(w, "Failed to remove gifts.", http.StatusInternalServerError)
return
}
http.Redirect(w, r, "/", http.StatusSeeOther)

View File

@ -8,6 +8,7 @@ import (
)
type HomeProps struct {
Username string
Gifts []db.Gift
Reference string
}
@ -19,6 +20,6 @@ func (ctx *Context) Home(w http.ResponseWriter, r *http.Request) {
http.Error(w, "An error occurred while fetching your wishlist :(", http.StatusInternalServerError)
return
}
p := HomeProps{Gifts: gifts, Reference: user.Reference}
p := HomeProps{Username: user.Name, Gifts: gifts, Reference: user.Reference}
templates.Execute(w, "home.gotmpl", p)
}

View File

@ -120,38 +120,84 @@ func (u *User) AddGift(name string) error {
return nil
}
func (u *User) RemoveGift(id string) error {
func (u *User) deleteGifts(tx *sql.Tx, ids []string) error {
stmt := "DELETE FROM gift WHERE gift.creator_id = ? AND gift.id = ?"
result, err := database.Exec(stmt, u.Id, 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("Gift deletion failed for '%s'", id)
}
}
return nil
}
func (u *User) RemoveGifts(ids ...string) error {
if len(ids) < 1 {
return fmt.Errorf("Attempt to remove zero gifts")
}
tx, err := database.Begin()
if err != nil {
return err
}
affected, _ := result.RowsAffected()
if affected == 0 {
return fmt.Errorf("No gift match.")
err = u.deleteGifts(tx, ids)
if err != nil {
rollBackErr := tx.Rollback()
if rollBackErr != nil {
return err
}
return err
}
return nil
err = tx.Commit()
return err
}
func (u *User) executeClaims(tx *sql.Tx, claims, unclaims []string) error {
claimStmt := "UPDATE gift SET claimant_id = ? WHERE id = ?"
unclaimStmt := "UPDATE gift SET claimant_id = NULL WHERE id = ?"
for _, id := range claims {
_, err := tx.Exec(claimStmt, u.Id, id)
r, err := tx.Exec(claimStmt, u.Id, id)
if err != nil {
return err
}
}
for _, id := range unclaims {
_, err := tx.Exec(unclaimStmt, id)
rE, err := r.RowsAffected()
if err != nil {
return err
}
if rE < 1 {
return fmt.Errorf("Gift 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("Gift unclaim failed for '%s'", id)
}
}
return nil
}
func (u *User) ClaimGifts(claims, unclaims []string) error {
if len(claims) < 1 && len(unclaims) < 1 {
return fmt.Errorf("Attempt to claim/unclaim zero gifts")
}
tx, err := database.Begin()
if err != nil {
return err
@ -159,7 +205,10 @@ func (u *User) ClaimGifts(claims, unclaims []string) error {
err = u.executeClaims(tx, claims, unclaims)
if err != nil {
err = tx.Rollback()
rollBackErr := tx.Rollback()
if rollBackErr != nil {
return err
}
return err
}
@ -170,15 +219,26 @@ func (u *User) ClaimGifts(claims, unclaims []string) error {
func (u *User) executeCompletions(tx *sql.Tx, claims []string) error {
claimStmt := "UPDATE gift SET sent = 1 WHERE id = ?"
for _, id := range claims {
_, err := tx.Exec(claimStmt, id)
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("Gift completion failed for '%s'", id)
}
}
return nil
}
func (u *User) CompleteGifts(claims []string) error {
if len(claims) < 1 {
return fmt.Errorf("Attempt to complete zero gifts")
}
tx, err := database.Begin()
if err != nil {
return err
@ -186,7 +246,10 @@ func (u *User) CompleteGifts(claims []string) error {
err = u.executeCompletions(tx, claims)
if err != nil {
err = tx.Rollback()
rollBackErr := tx.Rollback()
if rollBackErr != nil {
return err
}
return err
}

View File

@ -4,10 +4,18 @@
<head>
<title>Lishwist</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<script>
function someChecked(checkList) {
if (!checkList) {
return
}
return Array.from(checkList).some(({checked}) => checked);
}
</script>
</head>
<body>
{{template "body" .}}
{{template "body" .}}
</body>
</html>

View File

@ -8,34 +8,35 @@
</ul>
</nav>
<h2>{{.Username}}'s list</h2>
<form method="post" action="/{{.UserReference}}/update" autocomplete="off">
<button type="submit" name="mode" value="claim">Claim/Unclaim</button>
<button type="submit" name="mode" value="complete">Complete</button>
<form method="post" action="/{{.UserReference}}/update" autocomplete="off"
onchange="const checked = someChecked(this.unclaimed) || someChecked(this.claimed); this.mode[0].disabled = !checked; this.mode[1].disabled = !checked;">
<button type="submit" name="mode" value="claim" disabled>Claim/Unclaim</button>
<button type="submit" name="mode" value="complete" disabled>Complete</button>
<ul>
{{range .Gifts}}
<li>
<label>
{{if .ClaimantId}}
{{if .ClaimantId}}
{{if eq .ClaimantId $.CurrentUserId}}
<input type="checkbox" name="claimed" value="{{.Id}}" {{if .Sent}}disabled{{end}}>
<input type="checkbox" name="claimed" value="{{.Id}}" {{if .Sent}}disabled{{end}}>
{{else}}
<input type="checkbox" disabled>
<input type="checkbox" disabled>
{{end}}
{{else}}
{{else}}
<input type="checkbox" name="unclaimed" value="{{.Id}}" {{if .Sent}}disabled{{end}}>
{{end}}
{{if .Sent}}
<s>{{.Name}}</s>
{{else}}
{{.Name}}
{{end}}
{{if .ClaimantId}}
{{if eq .ClaimantId $.CurrentUserId}}
<span style="color: blue;">{{if .Sent}}Completed{{else}}Claimed{{end}} by you</span>
{{else}}
<span style="color: red;">{{if .Sent}}Completed{{else}}Claimed{{end}} by {{.ClaimantName}}</span>
{{end}}
{{end}}
{{if .Sent}}
<s>{{.Name}}</s>
{{else}}
{{.Name}}
{{end}}
{{if .ClaimantId}}
{{if eq .ClaimantId $.CurrentUserId}}
<span style="color: blue;">{{if .Sent}}Completed{{else}}Claimed{{end}} by you</span>
{{else}}
<span style="color: red;">{{if .Sent}}Completed{{else}}Claimed{{end}} by {{.ClaimantName}}</span>
{{end}}
{{end}}
</label>
</li>
{{end}}

View File

@ -1,4 +1,5 @@
{{define "body"}}
<p>Logged in as '{{.Username}}'</p>
<form method="post" action="/logout">
<input type="submit" value="Logout">
</form>
@ -10,16 +11,18 @@
</dd>
</dl>
<h2>Your list</h2>
<ul>
{{range .Gifts}}
<li>{{.Name}}
<form method="post" action="wishlist/delete">
<input type="hidden" name="gift_id" value="{{.Id}}">
<input type="submit" value="Delete">
</form>
</li>
{{end}}
</ul>
<form method="post" action="/wishlist/delete" onchange="this.mode.disabled = !someChecked(this.gift)"
autocomplete="off">
<button type="submit" name="mode" value="delete" disabled>Delete</button>
<ul>
{{range .Gifts}}
<li>
<input type="checkbox" name="gift" value="{{.Id}}">
{{.Name}}
</li>
{{end}}
</ul>
</form>
<form method="post" action="/wishlist/add">
<input name="gift_name" required>
<input type="submit">