fix: resolve golangci-lint violations (errcheck, unused, gosimple, ineffassign)

errcheck: add proper error handling with slog.Error for tx.Rollback, key generation, and s3/dav operations. Add nolint comments for intentionally discarded DB scan errors and HTTP write errors.
unused: remove dead code (svcRow type, processImage, nonDepositPaymentType, generateSecureCode, colorBold, nGreen, nRed)
gosimple S1021: merge var declaration with assignment in manage.go
ineffassign: remove dead assignments in settings.go, till.go, images.go

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
2026-07-09 18:53:51 +01:00
co-authored by Sisyphus
parent b26bf14419
commit ed9cb1489c
34 changed files with 766 additions and 345 deletions
+68 -32
View File
@@ -15,6 +15,7 @@ import (
"fmt"
"github.com/jackc/pgx/v5"
"log"
"log/slog"
"net/http"
"strings"
"time"
@@ -43,7 +44,11 @@ func UserCancelBookingHandler(w http.ResponseWriter, r *http.Request) {
http.Error(w, "Internal server error", http.StatusInternalServerError)
return
}
defer tx.Rollback(r.Context())
defer func() {
if err := tx.Rollback(r.Context()); err != nil {
slog.Error("failed to rollback transaction", "err", err)
}
}()
// Get current status before updating
var originalStatus string
@@ -166,7 +171,11 @@ func AdminCancelBookingHandler(w http.ResponseWriter, r *http.Request) {
http.Error(w, "Internal server error", http.StatusInternalServerError)
return
}
defer tx.Rollback(r.Context())
defer func() {
if err := tx.Rollback(r.Context()); err != nil {
slog.Error("failed to rollback transaction", "err", err)
}
}()
// Get current status and user ID — use FOR UPDATE to lock the row so
// the refund and status change are atomic.
@@ -289,7 +298,7 @@ func AdminCancelBookingHandler(w http.ResponseWriter, r *http.Request) {
resp["refund_failed"] = true
resp["warning"] = "Booking was cancelled but refund processing failed — please process refund manually or retry"
}
json.NewEncoder(w).Encode(resp)
_ = json.NewEncoder(w).Encode(resp)
return
}
@@ -445,13 +454,15 @@ func AdminCreateBookingForUserHandler(w http.ResponseWriter, r *http.Request) {
// Get deposit info
var depositRequired bool
var preStartPaid float64
db.Conn.QueryRow(r.Context(), `SELECT deposit_required FROM bookings WHERE id = $1`, existingID).Scan(&depositRequired)
db.Conn.QueryRow(r.Context(), `SELECT COALESCE(SUM(amount), 0) FROM payments WHERE booking_id = $1 AND payment_type IN ('deposit', 'full') AND status = 'completed'`, existingID).Scan(&preStartPaid)
//nolint:errcheck // zero value is acceptable fallback on scan failure
_ = db.Conn.QueryRow(r.Context(), `SELECT deposit_required FROM bookings WHERE id = $1`, existingID).Scan(&depositRequired)
//nolint:errcheck // zero value is acceptable fallback on scan failure
_ = db.Conn.QueryRow(r.Context(), `SELECT COALESCE(SUM(amount), 0) FROM payments WHERE booking_id = $1 AND payment_type IN ('deposit', 'full') AND status = 'completed'`, existingID).Scan(&preStartPaid)
populateDepositFields(&existingBooking, depositRequired, preStartPaid)
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(existingBooking)
_ = json.NewEncoder(w).Encode(existingBooking)
return
}
}
@@ -644,8 +655,7 @@ func AdminCreateBookingForUserHandler(w http.ResponseWriter, r *http.Request) {
if !req.OutOfHours {
// Check if there's an exceptional hours entry that makes this time unavailable
var isClosed bool
var checkErr error
checkErr = db.Conn.QueryRow(r.Context(), `
checkErr := db.Conn.QueryRow(r.Context(), `
SELECT EXISTS (
SELECT 1 FROM exceptional_working_hours ewh
JOIN exceptional_group_applications ega ON ewh.group_id = ega.group_id
@@ -698,7 +708,11 @@ func AdminCreateBookingForUserHandler(w http.ResponseWriter, r *http.Request) {
http.Error(w, "Internal server error", http.StatusInternalServerError)
return
}
defer tx.Rollback(r.Context())
defer func() {
if err := tx.Rollback(r.Context()); err != nil {
slog.Error("failed to rollback transaction", "err", err)
}
}()
// Evict any pending_release bookings that overlap this slot.
if _, evictErr := EvictPendingReleaseOverlapping(r.Context(), tx, req.StartTime, newEnd); evictErr != nil {
@@ -1240,7 +1254,11 @@ func DeleteEditRequestHandler(w http.ResponseWriter, r *http.Request) {
http.Error(w, "Internal server error", http.StatusInternalServerError)
return
}
defer tx.Rollback(r.Context())
defer func() {
if err := tx.Rollback(r.Context()); err != nil {
slog.Error("failed to rollback transaction", "err", err)
}
}()
// Delete the edit request for this booking
res, err := tx.Exec(r.Context(), `
@@ -1361,11 +1379,13 @@ func RequestEditHandler(w http.ResponseWriter, r *http.Request) {
// Query payment and timing info (used for validation AND auto-approval later)
var hasPayments bool
hoursUntilCurrent := currentStartTime.Sub(clock.Now()).Hours()
db.Conn.QueryRow(r.Context(), "SELECT EXISTS(SELECT 1 FROM payments WHERE booking_id = $1 AND status = 'completed')", bookingID).Scan(&hasPayments)
//nolint:errcheck // zero value is acceptable fallback on scan failure
_ = db.Conn.QueryRow(r.Context(), "SELECT EXISTS(SELECT 1 FROM payments WHERE booking_id = $1 AND status = 'completed')", bookingID).Scan(&hasPayments)
// Check if booking has discounts (affects auto-approval decisions)
var hasDiscounts bool
db.Conn.QueryRow(r.Context(), "SELECT EXISTS(SELECT 1 FROM booking_discounts WHERE booking_id = $1)", bookingID).Scan(&hasDiscounts)
//nolint:errcheck // zero value is acceptable fallback on scan failure
_ = db.Conn.QueryRow(r.Context(), "SELECT EXISTS(SELECT 1 FROM booking_discounts WHERE booking_id = $1)", bookingID).Scan(&hasDiscounts)
if req.NewStartTime != nil && !req.NewStartTime.Equal(currentStartTime) {
if hasPayments && hoursUntilCurrent < 72 {
@@ -1412,7 +1432,11 @@ func RequestEditHandler(w http.ResponseWriter, r *http.Request) {
http.Error(w, "Internal server error", http.StatusInternalServerError)
return
}
defer tx.Rollback(r.Context())
defer func() {
if err := tx.Rollback(r.Context()); err != nil {
slog.Error("failed to rollback transaction", "err", err)
}
}()
// Delete any existing edit request for this booking (upsert behavior)
_, err = tx.Exec(r.Context(), `
@@ -1574,7 +1598,7 @@ func RequestEditHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(map[string]any{
_ = json.NewEncoder(w).Encode(map[string]any{
"auto_approved": true,
"edit_request": editReq,
})
@@ -1591,6 +1615,7 @@ func RequestEditHandler(w http.ResponseWriter, r *http.Request) {
var durationMinutes int
if len(req.NewServices) > 0 {
//nolint:errcheck // zero value is acceptable fallback on scan failure
_ = tx.QueryRow(r.Context(), `
SELECT COALESCE(SUM(dur), 60) FROM (
SELECT s.duration_minutes AS dur
@@ -1603,6 +1628,7 @@ func RequestEditHandler(w http.ResponseWriter, r *http.Request) {
) sub
`, req.NewServices).Scan(&durationMinutes)
} else {
//nolint:errcheck // zero value is acceptable fallback on scan failure
_ = tx.QueryRow(r.Context(), `
SELECT total_duration_minutes FROM bookings WHERE id = $1
`, bookingID).Scan(&durationMinutes)
@@ -1668,7 +1694,7 @@ func RequestEditHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusCreated)
json.NewEncoder(w).Encode(editReq)
_ = json.NewEncoder(w).Encode(editReq)
}
// AdminListEditRequestsHandler returns all edit requests
@@ -1691,7 +1717,8 @@ func AdminListEditRequestsHandler(w http.ResponseWriter, r *http.Request) {
var total int
// Count query (no ORDER BY needed).
db.Conn.QueryRow(r.Context(), "SELECT COUNT(*) FROM booking_edit_requests").Scan(&total)
//nolint:errcheck // zero value is acceptable fallback on scan failure
_ = db.Conn.QueryRow(r.Context(), "SELECT COUNT(*) FROM booking_edit_requests").Scan(&total)
rows, err := db.Conn.Query(r.Context(), baseQuery, args...)
if err != nil {
@@ -1747,7 +1774,7 @@ func AdminListEditRequestsHandler(w http.ResponseWriter, r *http.Request) {
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(map[string]any{
_ = json.NewEncoder(w).Encode(map[string]any{
"requests": requests,
"total": total,
})
@@ -1773,7 +1800,11 @@ func AdminApproveEditRequestHandler(w http.ResponseWriter, r *http.Request) {
http.Error(w, "Internal server error", http.StatusInternalServerError)
return
}
defer tx.Rollback(r.Context())
defer func() {
if err := tx.Rollback(r.Context()); err != nil {
slog.Error("failed to rollback transaction", "err", err)
}
}()
// Get the edit request
var bookingID string
@@ -2058,7 +2089,11 @@ func AdminRejectEditRequestHandler(w http.ResponseWriter, r *http.Request) {
http.Error(w, "Internal server error", http.StatusInternalServerError)
return
}
defer tx.Rollback(r.Context())
defer func() {
if err := tx.Rollback(r.Context()); err != nil {
slog.Error("failed to rollback transaction", "err", err)
}
}()
// Delete the edit request
_, err = tx.Exec(r.Context(), `
@@ -2153,7 +2188,7 @@ func GetMyEditRequestHandler(w http.ResponseWriter, r *http.Request) {
if errors.Is(err, pgx.ErrNoRows) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(map[string]any{
_ = json.NewEncoder(w).Encode(map[string]any{
"edit_request": nil,
})
return
@@ -2172,7 +2207,7 @@ func GetMyEditRequestHandler(w http.ResponseWriter, r *http.Request) {
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(map[string]any{
_ = json.NewEncoder(w).Encode(map[string]any{
"edit_request": enriched,
})
}
@@ -2236,7 +2271,7 @@ func GetMyEditRequestsHandler(w http.ResponseWriter, r *http.Request) {
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(map[string]any{
_ = json.NewEncoder(w).Encode(map[string]any{
"edit_requests": enrichedRequests,
})
}
@@ -2293,7 +2328,7 @@ func AdminListAllEditRequestsHandler(w http.ResponseWriter, r *http.Request) {
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(map[string]any{
_ = json.NewEncoder(w).Encode(map[string]any{
"edit_requests": enrichedRequests,
})
}
@@ -2335,16 +2370,17 @@ func AdminGetBookingEditRequestHandler(w http.ResponseWriter, r *http.Request) {
editReq.NewServices = newServices
enriched, err := buildEnrichedEditRequest(r.Context(), &editReq)
if err != nil {
log.Printf("Failed to build enriched edit request: %v", err)
http.Error(w, "Internal server error", http.StatusInternalServerError)
return
}
if err != nil {
log.Printf("Failed to build enriched edit request: %v", err)
http.Error(w, "Internal server error", http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(map[string]any{
"edit_request": enriched,
})
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
_ = json.NewEncoder(w).Encode(map[string]any{
"edit_request": enriched,
})
}
// ========================================