Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 61 additions & 14 deletions backend/internal/handler/clerk.go
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
package handler

import (
"errors"
"log/slog"
"net/http"

"github.com/generate/selfserve/config"
"github.com/generate/selfserve/internal/errs"
"github.com/generate/selfserve/internal/models"
storage "github.com/generate/selfserve/internal/service/storage/postgres"
"github.com/generate/selfserve/internal/utils"
"github.com/gofiber/fiber/v2"
svix "github.com/svix/svix-webhooks/go"
)

type ClerkWebHookHandler struct {
UsersRepository storage.UsersRepository
WebhookVerifier WebhookVerifier
UsersRepository storage.UsersRepository
HotelsRepository storage.HotelsRepository
WebhookVerifier WebhookVerifier
}

type WebhookVerifier interface {
Expand All @@ -24,34 +28,77 @@ func NewWebhookVerifier(cfg *config.Config) (WebhookVerifier, error) {
return svix.NewWebhook(cfg.Clerk.WebhookSignature)
}

func NewClerkWebHookHandler(userRepo storage.UsersRepository, WebhookVerifier WebhookVerifier) *ClerkWebHookHandler {
return &ClerkWebHookHandler{UsersRepository: userRepo, WebhookVerifier: WebhookVerifier}
func NewClerkWebHookHandler(userRepo storage.UsersRepository, hotelsRepo storage.HotelsRepository, webhookVerifier WebhookVerifier) *ClerkWebHookHandler {
return &ClerkWebHookHandler{
UsersRepository: userRepo,
HotelsRepository: hotelsRepo,
WebhookVerifier: webhookVerifier,
}
}

func (h *ClerkWebHookHandler) CreateUser(c *fiber.Ctx) error {
func (h *ClerkWebHookHandler) verifySvix(c *fiber.Ctx) error {
headers := http.Header{}
headers.Set("svix-id", c.Get("svix-id"))
headers.Set("svix-timestamp", c.Get("svix-timestamp"))
headers.Set("svix-signature", c.Get("svix-signature"))

err := h.WebhookVerifier.Verify(c.Body(), headers)
if err != nil {
if err := h.WebhookVerifier.Verify(c.Body(), headers); err != nil {
return errs.Unauthorized()
}
return nil
}

func (h *ClerkWebHookHandler) CreateOrgMembership(c *fiber.Ctx) error {
if err := h.verifySvix(c); err != nil {
return err
}

var CreateUserRequest models.CreateUserWebhook
if err := c.BodyParser(&CreateUserRequest); err != nil {
var payload models.CreateUserOrgMembershipWebhook
if err := c.BodyParser(&payload); err != nil {
return errs.InvalidJSON()
}
clerkUser := &CreateUserRequest.ClerkUser
if err := ValidateCreateUserClerk(clerkUser); err != nil {

hotel, err := h.HotelsRepository.FindByID(c.Context(), payload.Data.Organization.ID)
if err != nil {
if errors.Is(err, errs.ErrNotFoundInDB) {
return errs.NotFound("hotel", "id", payload.Data.Organization.ID)
}
return errs.InternalServerError()
}

userData := &payload.Data.PublicUserData
_, err = h.UsersRepository.InsertUser(c.Context(), ReformatOrgMembershipUserData(userData, hotel.ID))
if err != nil {
return errs.InternalServerError()
}

return c.SendStatus(fiber.StatusOK)
}

// When a new org is created in Clerk, we create a corresponding hotel in our DB
func (h *ClerkWebHookHandler) OrgCreated(c *fiber.Ctx) error {
if err := h.verifySvix(c); err != nil {
return err
}

res, err := h.UsersRepository.InsertUser(c.Context(), ReformatUserData(clerkUser))
var payload models.CreateOrgWebhook
if err := c.BodyParser(&payload); err != nil {
return errs.InvalidJSON()
}

hotel, err := h.HotelsRepository.InsertHotel(c.Context(), &models.CreateHotelRequest{
ID: payload.Data.ID,
Name: payload.Data.Name,
})
if err != nil {
if errors.Is(err, errs.ErrAlreadyExistsInDB) {
return c.SendStatus(fiber.StatusOK)
}
return errs.InternalServerError()
}

return c.JSON(res)
if err := utils.UpdateOrgMetadata(c.Context(), payload.Data.ID, hotel.ID); err != nil {
slog.Error("failed to update org metadata", "clerk_org_id", payload.Data.ID, "error", err)
}

return c.SendStatus(fiber.StatusOK)
}
8 changes: 3 additions & 5 deletions backend/internal/handler/hotels.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ import (
"context"
"errors"
"log/slog"
"strings"

"github.com/generate/selfserve/internal/errs"
"github.com/generate/selfserve/internal/httpx"
"github.com/generate/selfserve/internal/models"
"github.com/gofiber/fiber/v2"
"github.com/google/uuid"
)

// HotelRepository defines methods for hotel data access
Expand Down Expand Up @@ -40,10 +40,8 @@ func NewHotelsHandler(repo HotelsRepository) *HotelsHandler {
func (h *HotelsHandler) GetHotelByID(c *fiber.Ctx) error {
idParam := c.Params("id")

// Validate UUID
_, err := uuid.Parse(idParam)
if err != nil {
return errs.BadRequest("invalid hotel id format")
if strings.TrimSpace(idParam) == "" {
return errs.BadRequest("hotel id is required")
}

// Fetch hotel
Expand Down
Loading
Loading