From efd93f099e43d65c2d095e414d4cbf01a9c0021b Mon Sep 17 00:00:00 2001 From: Kenneth Date: Fri, 2 Jan 2026 16:57:20 +0000 Subject: [PATCH] feat(backend): add list orgs endpoint --- .../internal/drexa/api_integration_test.go | 16 +++++++ apps/backend/internal/drexa/server.go | 3 +- apps/backend/internal/organization/http.go | 46 +++++++++++++++++++ apps/backend/internal/user/http.go | 9 ++-- 4 files changed, 69 insertions(+), 5 deletions(-) create mode 100644 apps/backend/internal/organization/http.go diff --git a/apps/backend/internal/drexa/api_integration_test.go b/apps/backend/internal/drexa/api_integration_test.go index bee98dc..73accb7 100644 --- a/apps/backend/internal/drexa/api_integration_test.go +++ b/apps/backend/internal/drexa/api_integration_test.go @@ -171,6 +171,22 @@ func TestRegistrationFlow(t *testing.T) { } }) + t.Run("users/me/organizations", func(t *testing.T) { + var orgs []struct { + ID string `json:"id"` + Kind string `json:"kind"` + Name string `json:"name"` + Slug string `json:"slug"` + } + doJSON(t, s.app, http.MethodGet, "/api/users/me/organizations", reg.AccessToken, nil, http.StatusOK, &orgs) + if len(orgs) != 1 { + t.Fatalf("expected 1 organization, got %d", len(orgs)) + } + if orgs[0].Kind != string(organization.KindPersonal) { + t.Fatalf("unexpected organization kind: %q", orgs[0].Kind) + } + }) + t.Run("accounts/:id", func(t *testing.T) { var got struct { ID string `json:"id"` diff --git a/apps/backend/internal/drexa/server.go b/apps/backend/internal/drexa/server.go index 06aa06d..62703a5 100644 --- a/apps/backend/internal/drexa/server.go +++ b/apps/backend/internal/drexa/server.go @@ -124,8 +124,9 @@ func NewServer(c Config) (*Server, error) { api := app.Group("/api") auth.NewHTTPHandler(authService, organizationService, db, cookieConfig).RegisterRoutes(api) registration.NewHTTPHandler(registrationService, authService, db, cookieConfig).RegisterRoutes(api) - user.NewHTTPHandler(userService, db, authMiddleware).RegisterRoutes(api) + usersAPI := user.NewHTTPHandler(userService, db, authMiddleware).RegisterRoutes(api) account.NewHTTPHandler(accountService, db, authMiddleware).RegisterRoutes(api) + organization.NewHTTPHandler(organizationService, db, authMiddleware).RegisterRoutes(usersAPI) orgAPI := api.Group("/:orgSlug", authMiddleware, organization.NewMiddleware(organizationService, accountService, db)) diff --git a/apps/backend/internal/organization/http.go b/apps/backend/internal/organization/http.go new file mode 100644 index 0000000..45093b1 --- /dev/null +++ b/apps/backend/internal/organization/http.go @@ -0,0 +1,46 @@ +package organization + +import ( + "github.com/get-drexa/drexa/internal/httperr" + "github.com/get-drexa/drexa/internal/reqctx" + "github.com/get-drexa/drexa/internal/user" + "github.com/gofiber/fiber/v2" + "github.com/uptrace/bun" +) + +type HTTPHandler struct { + service *Service + db *bun.DB + authMiddleware fiber.Handler +} + +func NewHTTPHandler(service *Service, db *bun.DB, authMiddleware fiber.Handler) *HTTPHandler { + return &HTTPHandler{service: service, db: db, authMiddleware: authMiddleware} +} + +func (h *HTTPHandler) RegisterRoutes(users fiber.Router) { + users.Get("/me/organizations", h.listAuthenticatedUserOrganizations) +} + +// listAuthenticatedUserOrganizations returns the organizations the current user is a member of +// @Summary List current user's organizations +// @Description Retrieve the organizations the authenticated user belongs to +// @Tags users +// @Produce json +// @Security BearerAuth +// @Success 200 {array} Organization "Array of organizations" +// @Failure 401 {string} string "Not authenticated" +// @Router /users/me/organizations [get] +func (h *HTTPHandler) listAuthenticatedUserOrganizations(c *fiber.Ctx) error { + u, _ := reqctx.AuthenticatedUser(c).(*user.User) + if u == nil { + return c.SendStatus(fiber.StatusUnauthorized) + } + + orgs, err := h.service.ListOrganizationsForUser(c.Context(), h.db, u.ID) + if err != nil { + return httperr.Internal(err) + } + + return c.JSON(orgs) +} diff --git a/apps/backend/internal/user/http.go b/apps/backend/internal/user/http.go index 40cec46..9674013 100644 --- a/apps/backend/internal/user/http.go +++ b/apps/backend/internal/user/http.go @@ -16,10 +16,11 @@ func NewHTTPHandler(service *Service, db *bun.DB, authMiddleware fiber.Handler) return &HTTPHandler{service: service, db: db, authMiddleware: authMiddleware} } -func (h *HTTPHandler) RegisterRoutes(api fiber.Router) { - user := api.Group("/users") - user.Use(h.authMiddleware) - user.Get("/me", h.getAuthenticatedUser) +func (h *HTTPHandler) RegisterRoutes(api fiber.Router) fiber.Router { + users := api.Group("/users") + users.Use(h.authMiddleware) + users.Get("/me", h.getAuthenticatedUser) + return users } // getAuthenticatedUser returns the currently authenticated user