add transaction handle

Signed-off-by: GnomeZworc <nicolas.boufidjeline@g3e.fr>
This commit is contained in:
GnomeZworc 2026-06-13 14:06:39 +02:00
commit 5f6b13ce78
Signed by: nicolas.boufideline
GPG key ID: 4406BBBF8845D632
3 changed files with 356 additions and 0 deletions

View file

@ -0,0 +1,188 @@
package handler
import (
"encoding/json"
"errors"
"net/http"
"strconv"
"git.g3e.fr/H6N/account/internal/store"
"github.com/jackc/pgx/v5"
)
type TransactionHandler struct {
store *store.Store
}
func NewTransactionHandler(s *store.Store) *TransactionHandler {
return &TransactionHandler{store: s}
}
func (h *TransactionHandler) RegisterRoutes(mux *http.ServeMux) {
mux.HandleFunc("GET /accounts/{id}/transactions", h.listForAccount)
mux.HandleFunc("POST /transactions", h.create)
mux.HandleFunc("GET /transactions/{id}", h.get)
mux.HandleFunc("PUT /transactions/{id}", h.update)
mux.HandleFunc("DELETE /transactions/{id}", h.delete)
mux.HandleFunc("PATCH /transactions/{id}/validate", h.validate)
}
func (h *TransactionHandler) listForAccount(w http.ResponseWriter, r *http.Request) {
accountID, err := parseID(r)
if err != nil {
writeError(w, http.StatusBadRequest, "invalid account id")
return
}
f := store.AccountTransactionFilters{
Validated: parseBoolParam(r, "validated"),
Pending: parseBoolParam(r, "pending"),
From: parseStringParam(r, "from"),
To: parseStringParam(r, "to"),
}
txs, err := h.store.ListAccountTransactions(r.Context(), accountID, f)
if err != nil {
writeError(w, http.StatusInternalServerError, "failed to list transactions")
return
}
writeJSON(w, http.StatusOK, txs)
}
func (h *TransactionHandler) get(w http.ResponseWriter, r *http.Request) {
id, err := parseTxID(r)
if err != nil {
writeError(w, http.StatusBadRequest, "invalid id")
return
}
tx, err := h.store.GetTransaction(r.Context(), id)
if errors.Is(err, pgx.ErrNoRows) {
writeError(w, http.StatusNotFound, "transaction not found")
return
}
if err != nil {
writeError(w, http.StatusInternalServerError, "failed to get transaction")
return
}
writeJSON(w, http.StatusOK, tx)
}
func (h *TransactionHandler) create(w http.ResponseWriter, r *http.Request) {
var p store.CreateTransactionParams
if err := json.NewDecoder(r.Body).Decode(&p); err != nil {
writeError(w, http.StatusBadRequest, "invalid request body")
return
}
if p.Label == "" {
writeError(w, http.StatusBadRequest, "label is required")
return
}
if p.Date == "" {
writeError(w, http.StatusBadRequest, "date is required")
return
}
tx, err := h.store.CreateTransaction(r.Context(), p)
if err != nil {
writeError(w, http.StatusInternalServerError, "failed to create transaction")
return
}
writeJSON(w, http.StatusCreated, tx)
}
func (h *TransactionHandler) update(w http.ResponseWriter, r *http.Request) {
id, err := parseTxID(r)
if err != nil {
writeError(w, http.StatusBadRequest, "invalid id")
return
}
var p store.CreateTransactionParams
if err := json.NewDecoder(r.Body).Decode(&p); err != nil {
writeError(w, http.StatusBadRequest, "invalid request body")
return
}
if p.Label == "" {
writeError(w, http.StatusBadRequest, "label is required")
return
}
tx, err := h.store.UpdateTransaction(r.Context(), id, p)
if errors.Is(err, pgx.ErrNoRows) {
writeError(w, http.StatusNotFound, "transaction not found")
return
}
if err != nil {
writeError(w, http.StatusInternalServerError, "failed to update transaction")
return
}
writeJSON(w, http.StatusOK, tx)
}
func (h *TransactionHandler) delete(w http.ResponseWriter, r *http.Request) {
id, err := parseTxID(r)
if err != nil {
writeError(w, http.StatusBadRequest, "invalid id")
return
}
if err := h.store.DeleteTransaction(r.Context(), id); err != nil {
writeError(w, http.StatusInternalServerError, "failed to delete transaction")
return
}
w.WriteHeader(http.StatusNoContent)
}
func (h *TransactionHandler) validate(w http.ResponseWriter, r *http.Request) {
id, err := parseTxID(r)
if err != nil {
writeError(w, http.StatusBadRequest, "invalid id")
return
}
var body struct {
Validated bool `json:"validated"`
}
if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
writeError(w, http.StatusBadRequest, "invalid request body")
return
}
tx, err := h.store.SetValidated(r.Context(), id, body.Validated)
if errors.Is(err, pgx.ErrNoRows) {
writeError(w, http.StatusNotFound, "transaction not found")
return
}
if err != nil {
writeError(w, http.StatusInternalServerError, "failed to update transaction")
return
}
writeJSON(w, http.StatusOK, tx)
}
func parseTxID(r *http.Request) (int64, error) {
v, err := strconv.ParseInt(r.PathValue("id"), 10, 64)
return v, err
}
func parseIntParam(r *http.Request, key string) *int32 {
v := r.URL.Query().Get(key)
if v == "" {
return nil
}
n, err := strconv.Atoi(v)
if err != nil {
return nil
}
i := int32(n)
return &i
}
func parseBoolParam(r *http.Request, key string) *bool {
v := r.URL.Query().Get(key)
if v == "" {
return nil
}
b := v == "true"
return &b
}
func parseStringParam(r *http.Request, key string) *string {
v := r.URL.Query().Get(key)
if v == "" {
return nil
}
return &v
}