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 }