package handler import ( "encoding/json" "errors" "net/http" "git.g3e.fr/H6N/account/internal/store" "github.com/jackc/pgx/v5" ) type AccountHandler struct { store *store.Store } func NewAccountHandler(s *store.Store) *AccountHandler { return &AccountHandler{store: s} } func (h *AccountHandler) RegisterRoutes(mux *http.ServeMux) { // Comptes maîtres mux.HandleFunc("GET /accounts", h.list) mux.HandleFunc("POST /accounts", h.create) mux.HandleFunc("GET /accounts/{id}", h.get) mux.HandleFunc("PUT /accounts/{id}", h.update) mux.HandleFunc("DELETE /accounts/{id}", h.delete) // Enveloppes (sous-comptes) mux.HandleFunc("GET /accounts/{id}/envelopes", h.listEnvelopes) mux.HandleFunc("POST /accounts/{id}/envelopes", h.createEnvelope) mux.HandleFunc("PUT /envelopes/{id}", h.updateEnvelope) mux.HandleFunc("DELETE /envelopes/{id}", h.deleteEnvelope) } // --- Comptes maîtres --- func (h *AccountHandler) list(w http.ResponseWriter, r *http.Request) { ownerID, ok := requireOwner(w, r) if !ok { return } accounts, err := h.store.ListAccounts(r.Context(), ownerID) if err != nil { writeError(w, http.StatusInternalServerError, "failed to list accounts") return } writeJSON(w, http.StatusOK, accounts) } func (h *AccountHandler) get(w http.ResponseWriter, r *http.Request) { ownerID, ok := requireOwner(w, r) if !ok { return } id, err := parseID(r) if err != nil { writeError(w, http.StatusBadRequest, "invalid id") return } if err := h.store.VerifyAccountOwner(r.Context(), id, ownerID); errors.Is(err, pgx.ErrNoRows) { writeError(w, http.StatusNotFound, "account not found") return } else if err != nil { writeError(w, http.StatusInternalServerError, "failed to get account") return } account, err := h.store.GetAccountWithEnvelopes(r.Context(), id) if errors.Is(err, pgx.ErrNoRows) { writeError(w, http.StatusNotFound, "account not found") return } if err != nil { writeError(w, http.StatusInternalServerError, "failed to get account") return } writeJSON(w, http.StatusOK, account) } func (h *AccountHandler) create(w http.ResponseWriter, r *http.Request) { ownerID, ok := requireOwner(w, r) if !ok { return } var p store.CreateAccountParams if err := json.NewDecoder(r.Body).Decode(&p); err != nil { writeError(w, http.StatusBadRequest, "invalid request body") return } if p.Nom == "" || p.Type == "" { writeError(w, http.StatusBadRequest, "nom and type are required") return } account, err := h.store.CreateAccount(r.Context(), p, ownerID) if err != nil { writeError(w, http.StatusInternalServerError, "failed to create account") return } writeJSON(w, http.StatusCreated, account) } func (h *AccountHandler) update(w http.ResponseWriter, r *http.Request) { ownerID, ok := requireOwner(w, r) if !ok { return } id, err := parseID(r) if err != nil { writeError(w, http.StatusBadRequest, "invalid id") return } var p store.CreateAccountParams if err := json.NewDecoder(r.Body).Decode(&p); err != nil { writeError(w, http.StatusBadRequest, "invalid request body") return } account, err := h.store.UpdateAccount(r.Context(), id, p, ownerID) if errors.Is(err, pgx.ErrNoRows) { writeError(w, http.StatusNotFound, "account not found") return } if err != nil { writeError(w, http.StatusInternalServerError, "failed to update account") return } writeJSON(w, http.StatusOK, account) } func (h *AccountHandler) delete(w http.ResponseWriter, r *http.Request) { ownerID, ok := requireOwner(w, r) if !ok { return } id, err := parseID(r) if err != nil { writeError(w, http.StatusBadRequest, "invalid id") return } if err := h.store.DeleteAccount(r.Context(), id, ownerID); err != nil { writeError(w, http.StatusInternalServerError, "failed to delete account") return } w.WriteHeader(http.StatusNoContent) } // --- Enveloppes --- func (h *AccountHandler) listEnvelopes(w http.ResponseWriter, r *http.Request) { ownerID, ok := requireOwner(w, r) if !ok { return } id, err := parseID(r) if err != nil { writeError(w, http.StatusBadRequest, "invalid id") return } if err := h.store.VerifyAccountOwner(r.Context(), id, ownerID); errors.Is(err, pgx.ErrNoRows) { writeError(w, http.StatusNotFound, "account not found") return } else if err != nil { writeError(w, http.StatusInternalServerError, "failed to verify account") return } envelopes, err := h.store.ListEnvelopes(r.Context(), id) if err != nil { writeError(w, http.StatusInternalServerError, "failed to list envelopes") return } writeJSON(w, http.StatusOK, envelopes) } func (h *AccountHandler) createEnvelope(w http.ResponseWriter, r *http.Request) { ownerID, ok := requireOwner(w, r) if !ok { return } masterID, err := parseID(r) if err != nil { writeError(w, http.StatusBadRequest, "invalid id") return } var p store.CreateEnvelopeParams if err := json.NewDecoder(r.Body).Decode(&p); err != nil { writeError(w, http.StatusBadRequest, "invalid request body") return } if p.Nom == "" { writeError(w, http.StatusBadRequest, "nom is required") return } envelope, err := h.store.CreateEnvelope(r.Context(), masterID, p, ownerID) if errors.Is(err, pgx.ErrNoRows) { writeError(w, http.StatusNotFound, "account not found") return } if errors.Is(err, store.ErrMasterIsSubAccount) { writeError(w, http.StatusBadRequest, "account cannot itself be an envelope") return } if err != nil { writeError(w, http.StatusInternalServerError, "failed to create envelope") return } writeJSON(w, http.StatusCreated, envelope) } func (h *AccountHandler) updateEnvelope(w http.ResponseWriter, r *http.Request) { ownerID, ok := requireOwner(w, r) if !ok { return } id, err := parseID(r) if err != nil { writeError(w, http.StatusBadRequest, "invalid id") return } var p store.CreateEnvelopeParams if err := json.NewDecoder(r.Body).Decode(&p); err != nil { writeError(w, http.StatusBadRequest, "invalid request body") return } envelope, err := h.store.UpdateEnvelope(r.Context(), id, p, ownerID) if errors.Is(err, pgx.ErrNoRows) { writeError(w, http.StatusNotFound, "envelope not found") return } if err != nil { writeError(w, http.StatusInternalServerError, "failed to update envelope") return } writeJSON(w, http.StatusOK, envelope) } func (h *AccountHandler) deleteEnvelope(w http.ResponseWriter, r *http.Request) { ownerID, ok := requireOwner(w, r) if !ok { return } id, err := parseID(r) if err != nil { writeError(w, http.StatusBadRequest, "invalid id") return } if err := h.store.DeleteAccount(r.Context(), id, ownerID); err != nil { writeError(w, http.StatusInternalServerError, "failed to delete envelope") return } w.WriteHeader(http.StatusNoContent) }