From ffaf60e39854c2bfcedcd6ec934b472ad86515a5 Mon Sep 17 00:00:00 2001 From: Manuel Torres Date: Wed, 14 Jan 2026 16:32:36 -0500 Subject: [PATCH 1/5] missing tests --- backend/internal/handler/requests.go | 88 +++++++++++++++++++ backend/internal/models/requests.go | 27 ++++++ backend/internal/repository/requests.go | 34 +++++++ backend/internal/service/server.go | 6 ++ .../service/storage/postgres/repo_types.go | 10 +++ .../service/storage/postgres/storage.go | 2 + 6 files changed, 167 insertions(+) create mode 100644 backend/internal/handler/requests.go create mode 100644 backend/internal/models/requests.go create mode 100644 backend/internal/repository/requests.go create mode 100644 backend/internal/service/storage/postgres/repo_types.go diff --git a/backend/internal/handler/requests.go b/backend/internal/handler/requests.go new file mode 100644 index 00000000..a4d5999c --- /dev/null +++ b/backend/internal/handler/requests.go @@ -0,0 +1,88 @@ +package handler + +import ( + "strings" + "github.com/generate/selfserve/internal/errs" + "github.com/generate/selfserve/internal/models" + "github.com/generate/selfserve/internal/service/storage/postgres" + "github.com/gofiber/fiber/v2" + "github.com/google/uuid" +) + +type RequestHandler struct { + RequestRepository storage.RequestRepository +} + +func NewRequestHandler(repo storage.RequestRepository) *RequestHandler { + return &RequestHandler{RequestRepository: repo} +} + +// MakeRequest godoc +// @Summary Make a request +// @Description Creates a request with the given data +// @Tags requests +// @Accept json +// @Produce json +// @Param request body models.Request true "Request data" +// @Success 200 {object} models.Request +// @Failure 400 {object} map[string]string +// @Failure 500 {object} map[string]string +// @Router /request [post] +func (r *RequestHandler)MakeRequest(c *fiber.Ctx) error { + var req models.Request + if err := c.BodyParser(&req); err != nil { + return errs.InvalidJSON() + } + + if err := validateRequest(&req); err != nil { + return err + } + + res, err := r.RequestRepository.MakeRequest(c.Context(), &req) + if err != nil { + return errs.InternalServerError() + } + + return c.JSON(res) +} + +func validateRequest(req *models.Request) error { + errors := make(map[string]string) + + if !validUUID(req.HotelID) { + errors["hotel_id"] = "invalid uuid" + } + + if req.GuestID != nil && !validUUID(*req.GuestID) { + errors["guest_id"] = "invalid uuid" + } + if req.Name == "" { + errors["name"] = "must not be an empty string" + } + if req.RequestType == "" { + errors["request_type"] = "must not be an empty string" + } + if req.Status == "" { + errors["status"] = "must not be an empty string" + } + if req.Priority == "" { + errors["priority"] = "must not be an empty string" + } + if req.Notes == "" { + errors["notes"] = "must not be an empty string" + } + + if len(errors) > 0 { + var parts []string + for field, violation := range errors { + parts = append(parts, field+": "+violation) + } + return errs.BadRequest(strings.Join(parts, ", ")) + } + return nil +} + +func validUUID(s string) bool { + _, err := uuid.Parse(s) + return err == nil +} \ No newline at end of file diff --git a/backend/internal/models/requests.go b/backend/internal/models/requests.go new file mode 100644 index 00000000..f755cc83 --- /dev/null +++ b/backend/internal/models/requests.go @@ -0,0 +1,27 @@ +package models + +import "time" + +// pointer fields are for easy handling of optional fields + +type Request struct { + ID string `json:"id" example:"530e8400-e458-41d4-a716-446655440000"` + HotelID string `json:"hotel_id" example:"521e8400-e458-41d4-a716-446655440000"` + GuestID *string `json:"guest_id" example:"521e8417-e458-41d4-a716-446655440990"` + UserID *string `json:"user_id" example:"521po400-e458-41d4-a716-446655440000"` + ReservationID *string `json:"reservation_id" example:"521e8400-e458-41d4-a716-498655440000"` + Name string `json:"name" example:"room cleaning"` + Description *string `json:"description" example:"clean 504"` + RoomID *string `json:"room_id" example:"521e8422-e458-41d4-a716-446655440000"` + RequestCategory *string `json:"request_category" example:"Cleaning"` + RequestType string `json:"request_type" example:"recurring"` + Department *string `json:"department" example:"maintenance"` + Status string `json:"status" example:"assigned"` + Priority string `json:"priority" example:"urgent"` + EstimatedCompletionTime *int `json:"estimated_completion_time" example:"30"` + ScheduledTime *time.Time `json:"scheduled_time" example:"2024-01-01T00:00:00Z"` + CompletedAt *time.Time `json:"completed_at" example:"2024-01-01T00:30:00Z"` + Notes string `json:"notes" example:"No special requests"` + CreatedAt time.Time `json:"created_at" example:"2024-01-02T00:00:00Z"` + UpdatedAt time.Time `json:"updated_at" example:"2024-01-02T00:00:00Z"` +} \ No newline at end of file diff --git a/backend/internal/repository/requests.go b/backend/internal/repository/requests.go new file mode 100644 index 00000000..f4f39ec5 --- /dev/null +++ b/backend/internal/repository/requests.go @@ -0,0 +1,34 @@ +package repository + +import ( + "context" + "github.com/generate/selfserve/internal/models" + "github.com/jackc/pgx/v5/pgxpool" +) + +type RequestRepository struct { + db *pgxpool.Pool +} + +func NewRequestRepo(db *pgxpool.Pool) *RequestRepository { + return &RequestRepository{db: db} +} + +func (r *RequestRepository) MakeRequest(ctx context.Context, req *models.Request) (*models.Request, error) { + err := r.db.QueryRow(ctx, `INSERT INTO requests ( + hotel_id, guest_id, user_id, reservation_id, name, description, + room_id, request_category, request_type, department, status, + priority, estimated_completion_time, scheduled_time, notes + ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15) + RETURNING id, created_at, updated_at + `, req.HotelID, req.GuestID, req.UserID, req.ReservationID, req.Name, + req.Description, req.RoomID, req.RequestCategory, req.RequestType, req.Department, + req.Status, req.Priority, req.EstimatedCompletionTime, + req.ScheduledTime, req.Notes).Scan(&req.ID, &req.CreatedAt, &req.UpdatedAt) + + if (err != nil) { + return nil, err + } + + return req, nil +} diff --git a/backend/internal/service/server.go b/backend/internal/service/server.go index c57f1996..faf5c95d 100644 --- a/backend/internal/service/server.go +++ b/backend/internal/service/server.go @@ -56,6 +56,7 @@ func setupRoutes(app *fiber.App, repo *storage.Repository) { // initialize handler(s) helloHandler := handler.NewHelloHandler() devsHandler := handler.NewDevsHandler(repository.NewDevsRepository(repo.DB)) + reqsHandler := handler.NewRequestHandler(repository.NewRequestRepo(repo.DB)) // API v1 routes api := app.Group("/api/v1") @@ -70,6 +71,11 @@ func setupRoutes(app *fiber.App, repo *storage.Repository) { api.Route("/devs", func(r fiber.Router) { r.Get("/:name", devsHandler.GetMember) }) + + // Request routes + api.Route("/request", func(r fiber.Router) { + r.Post("/", reqsHandler.MakeRequest) + }) } // Initialize Fiber app with middlewares / configs diff --git a/backend/internal/service/storage/postgres/repo_types.go b/backend/internal/service/storage/postgres/repo_types.go new file mode 100644 index 00000000..f3f670a9 --- /dev/null +++ b/backend/internal/service/storage/postgres/repo_types.go @@ -0,0 +1,10 @@ +package storage + +import ( + "context" + "github.com/generate/selfserve/internal/models" +) + +type RequestRepository interface { + MakeRequest(ctx context.Context, req *models.Request) (*models.Request, error) +} diff --git a/backend/internal/service/storage/postgres/storage.go b/backend/internal/service/storage/postgres/storage.go index afc06d6f..dc506602 100644 --- a/backend/internal/service/storage/postgres/storage.go +++ b/backend/internal/service/storage/postgres/storage.go @@ -17,6 +17,7 @@ type DevsRepository interface { type Repository struct { DB *pgxpool.Pool DevsRepository DevsRepository + RequestRepository RequestRepository } // Establishes a sustained connection to the PostgreSQL database / pooling @@ -59,5 +60,6 @@ func NewRepository(config config.DB) (*Repository, error) { return &Repository{ DB: db, DevsRepository: repository.NewDevsRepository(db), + RequestRepository: repository.NewRequestRepo(db), }, nil } From ea35d627a6b922b5049b0f1c908e2a340addcc8b Mon Sep 17 00:00:00 2001 From: Manuel Torres Date: Wed, 14 Jan 2026 18:42:17 -0500 Subject: [PATCH 2/5] tests and swagger testing done --- backend/cmd/server/main.go | 1 + backend/internal/handler/requests.go | 10 +- backend/internal/handler/requests_test.go | 235 ++++++++++++++++++++++ backend/internal/models/requests.go | 13 +- backend/internal/service/server.go | 4 + 5 files changed, 257 insertions(+), 6 deletions(-) create mode 100644 backend/internal/handler/requests_test.go diff --git a/backend/cmd/server/main.go b/backend/cmd/server/main.go index e629ee4a..1380212d 100644 --- a/backend/cmd/server/main.go +++ b/backend/cmd/server/main.go @@ -11,6 +11,7 @@ import ( "github.com/generate/selfserve/config" "github.com/generate/selfserve/internal/service" "github.com/sethvargo/go-envconfig" + _ "github.com/generate/selfserve/docs" ) // @title SelfServe API diff --git a/backend/internal/handler/requests.go b/backend/internal/handler/requests.go index a4d5999c..5e60014d 100644 --- a/backend/internal/handler/requests.go +++ b/backend/internal/handler/requests.go @@ -23,16 +23,17 @@ func NewRequestHandler(repo storage.RequestRepository) *RequestHandler { // @Tags requests // @Accept json // @Produce json -// @Param request body models.Request true "Request data" +// @Param request body models.MakeRequest true "Request data" // @Success 200 {object} models.Request // @Failure 400 {object} map[string]string // @Failure 500 {object} map[string]string // @Router /request [post] func (r *RequestHandler)MakeRequest(c *fiber.Ctx) error { - var req models.Request - if err := c.BodyParser(&req); err != nil { + var incoming models.MakeRequest + if err := c.BodyParser(&incoming); err != nil { return errs.InvalidJSON() } + req := models.Request{MakeRequest: incoming} if err := validateRequest(&req); err != nil { return err @@ -56,6 +57,9 @@ func validateRequest(req *models.Request) error { if req.GuestID != nil && !validUUID(*req.GuestID) { errors["guest_id"] = "invalid uuid" } + if req.UserID != nil && !validUUID(*req.UserID) { + errors["user_id"] = "invalid uuid" + } if req.Name == "" { errors["name"] = "must not be an empty string" } diff --git a/backend/internal/handler/requests_test.go b/backend/internal/handler/requests_test.go new file mode 100644 index 00000000..cb3cb63a --- /dev/null +++ b/backend/internal/handler/requests_test.go @@ -0,0 +1,235 @@ +package handler + +import ( + "bytes" + "context" + "errors" + "io" + "net/http/httptest" + "testing" + + "github.com/generate/selfserve/internal/errs" + "github.com/generate/selfserve/internal/models" + "github.com/gofiber/fiber/v2" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + + +type mockRequestRepository struct { + makeRequestFunc func(ctx context.Context, req *models.Request) (*models.Request, error) +} + +func (m *mockRequestRepository) MakeRequest(ctx context.Context, req *models.Request) (*models.Request, error) { + return m.makeRequestFunc(ctx, req) +} + +func TestRequestHandler_MakeRequest(t *testing.T) { + t.Parallel() + validBody := `{ + "hotel_id": "550e8400-e29b-41d4-a716-446655440000", + "name": "room cleaning", + "request_type": "recurring", + "status": "pending", + "priority": "high", + "notes": "No special requests" + }` + + t.Run("returns 200 on success", func(t *testing.T) { + t.Parallel() + + mock := &mockRequestRepository{ + makeRequestFunc: func(ctx context.Context, req *models.Request) (*models.Request, error) { + req.ID = "generated-uuid" + return req, nil + }, + } + + app := fiber.New() + h := NewRequestHandler(mock) + app.Post("/request", h.MakeRequest) + + req := httptest.NewRequest("POST", "/request", bytes.NewBufferString(validBody)) + req.Header.Set("Content-Type", "application/json") + resp, err := app.Test(req) + require.NoError(t, err) + + assert.Equal(t, 200, resp.StatusCode) + + body, _ := io.ReadAll(resp.Body) + assert.Contains(t, string(body), "generated-uuid") + assert.Contains(t, string(body), "room cleaning") + + }) + + t.Run("returns 200 when optional uuid fields are valid", func(t *testing.T) { + t.Parallel() + + mock := &mockRequestRepository{ + makeRequestFunc: func(ctx context.Context, req *models.Request) (*models.Request, error) { + req.ID = "generated-uuid" + return req, nil + }, + } + + app := fiber.New() + h := NewRequestHandler(mock) + app.Post("/request", h.MakeRequest) + + bodyWithOptionalUUIDs := `{ + "hotel_id": "550e8400-e29b-41d4-a716-446655440000", + "guest_id": "660e8400-e29b-41d4-a716-446655440000", + "user_id": "770e8400-e29b-41d4-a716-446655440000", + "name": "room cleaning", + "request_type": "recurring", + "status": "pending", + "priority": "high", + "notes": "No special requests" + }` + + req := httptest.NewRequest("POST", "/request", bytes.NewBufferString(bodyWithOptionalUUIDs)) + req.Header.Set("Content-Type", "application/json") + resp, err := app.Test(req) + require.NoError(t, err) + + assert.Equal(t, 200, resp.StatusCode) + + body, _ := io.ReadAll(resp.Body) + assert.Contains(t, string(body), "660e8400-e29b-41d4-a716-446655440000") + assert.Contains(t, string(body), "770e8400-e29b-41d4-a716-446655440000") + }) + + t.Run("returns 400 on invalid JSON", func(t *testing.T) { + t.Parallel() + + mock := &mockRequestRepository{ + makeRequestFunc: func(ctx context.Context, req *models.Request) (*models.Request, error) { + return req, nil + }, + } + + app := fiber.New(fiber.Config{ErrorHandler: errs.ErrorHandler}) + h := NewRequestHandler(mock) + app.Post("/request", h.MakeRequest) + + req := httptest.NewRequest("POST", "/request", bytes.NewBufferString(`{invalid json`)) + req.Header.Set("Content-Type", "application/json") + resp, err := app.Test(req) + require.NoError(t, err) + + assert.Equal(t, 400, resp.StatusCode) + }) + + t.Run("returns 400 on missing required fields", func(t *testing.T) { + t.Parallel() + + mock := &mockRequestRepository{ + makeRequestFunc: func(ctx context.Context, req *models.Request) (*models.Request, error) { + return req, nil + }, + } + + app := fiber.New(fiber.Config{ErrorHandler: errs.ErrorHandler}) + h := NewRequestHandler(mock) + app.Post("/request", h.MakeRequest) + + req := httptest.NewRequest("POST", "/request", bytes.NewBufferString(`{}`)) + req.Header.Set("Content-Type", "application/json") + resp, err := app.Test(req) + require.NoError(t, err) + + assert.Equal(t, 400, resp.StatusCode) + + body, _ := io.ReadAll(resp.Body) + assert.Contains(t, string(body), "hotel_id") + assert.Contains(t, string(body), "name") + }) + + t.Run("returns 400 on invalid hotel_id uuid", func(t *testing.T) { + t.Parallel() + + mock := &mockRequestRepository{ + makeRequestFunc: func(ctx context.Context, req *models.Request) (*models.Request, error) { + return req, nil + }, + } + + app := fiber.New(fiber.Config{ErrorHandler: errs.ErrorHandler}) + h := NewRequestHandler(mock) + app.Post("/request", h.MakeRequest) + + invalidUUIDBody := `{ + "hotel_id": "not-a-uuid", + "name": "room cleaning", + "request_type": "recurring", + "status": "pending", + "priority": "high", + "notes": "No special requests" + }` + + req := httptest.NewRequest("POST", "/request", bytes.NewBufferString(invalidUUIDBody)) + req.Header.Set("Content-Type", "application/json") + resp, err := app.Test(req) + require.NoError(t, err) + + assert.Equal(t, 400, resp.StatusCode) + + body, _ := io.ReadAll(resp.Body) + assert.Contains(t, string(body), "hotel_id") + }) + + t.Run("returns 400 on invalid optional guest_id uuid", func(t *testing.T) { + t.Parallel() + + mock := &mockRequestRepository{ + makeRequestFunc: func(ctx context.Context, req *models.Request) (*models.Request, error) { + return req, nil + }, + } + + app := fiber.New(fiber.Config{ErrorHandler: errs.ErrorHandler}) + h := NewRequestHandler(mock) + app.Post("/request", h.MakeRequest) + + invalidGuestIDBody := `{ + "hotel_id": "550e8400-e29b-41d4-a716-446655440000", + "guest_id": "not-a-uuid", + "name": "room cleaning", + "request_type": "recurring", + "status": "pending", + "priority": "high", + "notes": "No special requests" + }` + + req := httptest.NewRequest("POST", "/request", bytes.NewBufferString(invalidGuestIDBody)) + req.Header.Set("Content-Type", "application/json") + resp, err := app.Test(req) + require.NoError(t, err) + + assert.Equal(t, 400, resp.StatusCode) + + body, _ := io.ReadAll(resp.Body) + assert.Contains(t, string(body), "guest_id") + }) + + t.Run("returns 500 on db error", func(t *testing.T) { + t.Parallel() + + mock := &mockRequestRepository{ + makeRequestFunc: func(ctx context.Context, req *models.Request) (*models.Request, error) { + return nil, errors.New("db connection failed") + }, + } + + app := fiber.New(fiber.Config{ErrorHandler: errs.ErrorHandler}) + h := NewRequestHandler(mock) + app.Post("/request", h.MakeRequest) + + req := httptest.NewRequest("POST", "/request", bytes.NewBufferString(validBody)) + req.Header.Set("Content-Type", "application/json") + resp, err := app.Test(req) + require.NoError(t, err) + + assert.Equal(t, 500, resp.StatusCode) + }) +} \ No newline at end of file diff --git a/backend/internal/models/requests.go b/backend/internal/models/requests.go index f755cc83..a838f6a5 100644 --- a/backend/internal/models/requests.go +++ b/backend/internal/models/requests.go @@ -4,11 +4,11 @@ import "time" // pointer fields are for easy handling of optional fields -type Request struct { - ID string `json:"id" example:"530e8400-e458-41d4-a716-446655440000"` +// for post because the ID and timestamps should always be generated +type MakeRequest struct { HotelID string `json:"hotel_id" example:"521e8400-e458-41d4-a716-446655440000"` GuestID *string `json:"guest_id" example:"521e8417-e458-41d4-a716-446655440990"` - UserID *string `json:"user_id" example:"521po400-e458-41d4-a716-446655440000"` + UserID *string `json:"user_id" example:"521ee400-e458-41d4-a716-446655440000"` ReservationID *string `json:"reservation_id" example:"521e8400-e458-41d4-a716-498655440000"` Name string `json:"name" example:"room cleaning"` Description *string `json:"description" example:"clean 504"` @@ -22,6 +22,13 @@ type Request struct { ScheduledTime *time.Time `json:"scheduled_time" example:"2024-01-01T00:00:00Z"` CompletedAt *time.Time `json:"completed_at" example:"2024-01-01T00:30:00Z"` Notes string `json:"notes" example:"No special requests"` +} + + + +type Request struct { + ID string `json:"id" example:"530e8400-e458-41d4-a716-446655440000"` CreatedAt time.Time `json:"created_at" example:"2024-01-02T00:00:00Z"` UpdatedAt time.Time `json:"updated_at" example:"2024-01-02T00:00:00Z"` + MakeRequest } \ No newline at end of file diff --git a/backend/internal/service/server.go b/backend/internal/service/server.go index faf5c95d..e9c35418 100644 --- a/backend/internal/service/server.go +++ b/backend/internal/service/server.go @@ -15,6 +15,7 @@ import ( "github.com/gofiber/fiber/v2/middleware/logger" "github.com/gofiber/fiber/v2/middleware/recover" "github.com/gofiber/fiber/v2/middleware/requestid" + "github.com/generate/selfserve/internal/errs" ) type App struct { @@ -76,6 +77,8 @@ func setupRoutes(app *fiber.App, repo *storage.Repository) { api.Route("/request", func(r fiber.Router) { r.Post("/", reqsHandler.MakeRequest) }) + + } // Initialize Fiber app with middlewares / configs @@ -83,6 +86,7 @@ func setupApp() *fiber.App { app := fiber.New(fiber.Config{ JSONEncoder: json.Marshal, JSONDecoder: json.Unmarshal, + ErrorHandler: errs.ErrorHandler, }) app.Use(recover.New()) app.Use(requestid.New()) From 2555db90e6ae73b68ca3b378b4cf27438898f016 Mon Sep 17 00:00:00 2001 From: Manuel Torres Date: Wed, 14 Jan 2026 18:46:07 -0500 Subject: [PATCH 3/5] added google dependency --- backend/go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/go.mod b/backend/go.mod index 4b912da3..4ebe1170 100644 --- a/backend/go.mod +++ b/backend/go.mod @@ -45,7 +45,7 @@ require ( github.com/andybalholm/brotli v1.2.0 // indirect github.com/goccy/go-json v0.10.5 github.com/gofiber/fiber/v2 v2.52.10 - github.com/google/uuid v1.6.0 // indirect + github.com/google/uuid v1.6.0 github.com/jackc/pgx/v5 v5.8.0 github.com/klauspost/compress v1.18.2 // indirect github.com/mattn/go-colorable v0.1.14 // indirect From 9eb919990253e8043d8871cec533ee95bba440f4 Mon Sep 17 00:00:00 2001 From: Manuel Torres Date: Wed, 14 Jan 2026 22:18:55 -0500 Subject: [PATCH 4/5] fixes + migration --- backend/internal/handler/requests.go | 32 +++++++------------ backend/internal/handler/requests_test.go | 30 ++++++++--------- backend/internal/handler/utils.go | 10 ++++++ backend/internal/models/requests.go | 2 +- backend/internal/repository/requests.go | 8 ++--- backend/internal/service/server.go | 6 ++-- .../service/storage/postgres/repo_types.go | 4 +-- .../service/storage/postgres/storage.go | 4 +-- ...115030809_nullable_notes_request_table.sql | 3 ++ 9 files changed, 52 insertions(+), 47 deletions(-) create mode 100644 backend/internal/handler/utils.go create mode 100644 backend/supabase/migrations/20260115030809_nullable_notes_request_table.sql diff --git a/backend/internal/handler/requests.go b/backend/internal/handler/requests.go index 5e60014d..75e2ee70 100644 --- a/backend/internal/handler/requests.go +++ b/backend/internal/handler/requests.go @@ -2,23 +2,23 @@ package handler import ( "strings" + "github.com/generate/selfserve/internal/errs" "github.com/generate/selfserve/internal/models" - "github.com/generate/selfserve/internal/service/storage/postgres" + storage "github.com/generate/selfserve/internal/service/storage/postgres" "github.com/gofiber/fiber/v2" - "github.com/google/uuid" ) -type RequestHandler struct { - RequestRepository storage.RequestRepository +type RequestsHandler struct { + RequestRepository storage.RequestsRepository } -func NewRequestHandler(repo storage.RequestRepository) *RequestHandler { - return &RequestHandler{RequestRepository: repo} +func NewRequestsHandler(repo storage.RequestsRepository) *RequestsHandler { + return &RequestsHandler{RequestRepository: repo} } -// MakeRequest godoc -// @Summary Make a request +// CreateRequest godoc +// @Summary creates a request // @Description Creates a request with the given data // @Tags requests // @Accept json @@ -28,18 +28,18 @@ func NewRequestHandler(repo storage.RequestRepository) *RequestHandler { // @Failure 400 {object} map[string]string // @Failure 500 {object} map[string]string // @Router /request [post] -func (r *RequestHandler)MakeRequest(c *fiber.Ctx) error { +func (r *RequestsHandler)CreateRequest(c *fiber.Ctx) error { var incoming models.MakeRequest if err := c.BodyParser(&incoming); err != nil { return errs.InvalidJSON() } req := models.Request{MakeRequest: incoming} - if err := validateRequest(&req); err != nil { + if err := validateCreateRequest(&req); err != nil { return err } - res, err := r.RequestRepository.MakeRequest(c.Context(), &req) + res, err := r.RequestRepository.InsertRequest(c.Context(), &req) if err != nil { return errs.InternalServerError() } @@ -47,7 +47,7 @@ func (r *RequestHandler)MakeRequest(c *fiber.Ctx) error { return c.JSON(res) } -func validateRequest(req *models.Request) error { +func validateCreateRequest(req *models.Request) error { errors := make(map[string]string) if !validUUID(req.HotelID) { @@ -72,9 +72,6 @@ func validateRequest(req *models.Request) error { if req.Priority == "" { errors["priority"] = "must not be an empty string" } - if req.Notes == "" { - errors["notes"] = "must not be an empty string" - } if len(errors) > 0 { var parts []string @@ -84,9 +81,4 @@ func validateRequest(req *models.Request) error { return errs.BadRequest(strings.Join(parts, ", ")) } return nil -} - -func validUUID(s string) bool { - _, err := uuid.Parse(s) - return err == nil } \ No newline at end of file diff --git a/backend/internal/handler/requests_test.go b/backend/internal/handler/requests_test.go index cb3cb63a..9257e050 100644 --- a/backend/internal/handler/requests_test.go +++ b/backend/internal/handler/requests_test.go @@ -20,7 +20,7 @@ type mockRequestRepository struct { makeRequestFunc func(ctx context.Context, req *models.Request) (*models.Request, error) } -func (m *mockRequestRepository) MakeRequest(ctx context.Context, req *models.Request) (*models.Request, error) { +func (m *mockRequestRepository) InsertRequest(ctx context.Context, req *models.Request) (*models.Request, error) { return m.makeRequestFunc(ctx, req) } @@ -46,8 +46,8 @@ func TestRequestHandler_MakeRequest(t *testing.T) { } app := fiber.New() - h := NewRequestHandler(mock) - app.Post("/request", h.MakeRequest) + h := NewRequestsHandler(mock) + app.Post("/request", h.CreateRequest) req := httptest.NewRequest("POST", "/request", bytes.NewBufferString(validBody)) req.Header.Set("Content-Type", "application/json") @@ -73,8 +73,8 @@ func TestRequestHandler_MakeRequest(t *testing.T) { } app := fiber.New() - h := NewRequestHandler(mock) - app.Post("/request", h.MakeRequest) + h := NewRequestsHandler(mock) + app.Post("/request", h.CreateRequest) bodyWithOptionalUUIDs := `{ "hotel_id": "550e8400-e29b-41d4-a716-446655440000", @@ -109,8 +109,8 @@ func TestRequestHandler_MakeRequest(t *testing.T) { } app := fiber.New(fiber.Config{ErrorHandler: errs.ErrorHandler}) - h := NewRequestHandler(mock) - app.Post("/request", h.MakeRequest) + h := NewRequestsHandler(mock) + app.Post("/request", h.CreateRequest) req := httptest.NewRequest("POST", "/request", bytes.NewBufferString(`{invalid json`)) req.Header.Set("Content-Type", "application/json") @@ -130,8 +130,8 @@ func TestRequestHandler_MakeRequest(t *testing.T) { } app := fiber.New(fiber.Config{ErrorHandler: errs.ErrorHandler}) - h := NewRequestHandler(mock) - app.Post("/request", h.MakeRequest) + h := NewRequestsHandler(mock) + app.Post("/request", h.CreateRequest) req := httptest.NewRequest("POST", "/request", bytes.NewBufferString(`{}`)) req.Header.Set("Content-Type", "application/json") @@ -155,8 +155,8 @@ func TestRequestHandler_MakeRequest(t *testing.T) { } app := fiber.New(fiber.Config{ErrorHandler: errs.ErrorHandler}) - h := NewRequestHandler(mock) - app.Post("/request", h.MakeRequest) + h := NewRequestsHandler(mock) + app.Post("/request", h.CreateRequest) invalidUUIDBody := `{ "hotel_id": "not-a-uuid", @@ -188,8 +188,8 @@ func TestRequestHandler_MakeRequest(t *testing.T) { } app := fiber.New(fiber.Config{ErrorHandler: errs.ErrorHandler}) - h := NewRequestHandler(mock) - app.Post("/request", h.MakeRequest) + h := NewRequestsHandler(mock) + app.Post("/request", h.CreateRequest) invalidGuestIDBody := `{ "hotel_id": "550e8400-e29b-41d4-a716-446655440000", @@ -222,8 +222,8 @@ func TestRequestHandler_MakeRequest(t *testing.T) { } app := fiber.New(fiber.Config{ErrorHandler: errs.ErrorHandler}) - h := NewRequestHandler(mock) - app.Post("/request", h.MakeRequest) + h := NewRequestsHandler(mock) + app.Post("/request", h.CreateRequest) req := httptest.NewRequest("POST", "/request", bytes.NewBufferString(validBody)) req.Header.Set("Content-Type", "application/json") diff --git a/backend/internal/handler/utils.go b/backend/internal/handler/utils.go new file mode 100644 index 00000000..c490a267 --- /dev/null +++ b/backend/internal/handler/utils.go @@ -0,0 +1,10 @@ +package handler + +import ( + "github.com/google/uuid" +) + +func validUUID(s string) bool { + _, err := uuid.Parse(s) + return err == nil +} \ No newline at end of file diff --git a/backend/internal/models/requests.go b/backend/internal/models/requests.go index a838f6a5..2db4e5f5 100644 --- a/backend/internal/models/requests.go +++ b/backend/internal/models/requests.go @@ -21,7 +21,7 @@ type MakeRequest struct { EstimatedCompletionTime *int `json:"estimated_completion_time" example:"30"` ScheduledTime *time.Time `json:"scheduled_time" example:"2024-01-01T00:00:00Z"` CompletedAt *time.Time `json:"completed_at" example:"2024-01-01T00:30:00Z"` - Notes string `json:"notes" example:"No special requests"` + Notes *string `json:"notes" example:"No special requests"` } diff --git a/backend/internal/repository/requests.go b/backend/internal/repository/requests.go index f4f39ec5..cce9e8b1 100644 --- a/backend/internal/repository/requests.go +++ b/backend/internal/repository/requests.go @@ -6,15 +6,15 @@ import ( "github.com/jackc/pgx/v5/pgxpool" ) -type RequestRepository struct { +type RequestsRepository struct { db *pgxpool.Pool } -func NewRequestRepo(db *pgxpool.Pool) *RequestRepository { - return &RequestRepository{db: db} +func NewRequestsRepo(db *pgxpool.Pool) *RequestsRepository { + return &RequestsRepository{db: db} } -func (r *RequestRepository) MakeRequest(ctx context.Context, req *models.Request) (*models.Request, error) { +func (r *RequestsRepository) InsertRequest(ctx context.Context, req *models.Request) (*models.Request, error) { err := r.db.QueryRow(ctx, `INSERT INTO requests ( hotel_id, guest_id, user_id, reservation_id, name, description, room_id, request_category, request_type, department, status, diff --git a/backend/internal/service/server.go b/backend/internal/service/server.go index e9c35418..47a048c9 100644 --- a/backend/internal/service/server.go +++ b/backend/internal/service/server.go @@ -4,6 +4,7 @@ import ( "net/http" "github.com/generate/selfserve/config" + "github.com/generate/selfserve/internal/errs" "github.com/generate/selfserve/internal/handler" "github.com/generate/selfserve/internal/repository" storage "github.com/generate/selfserve/internal/service/storage/postgres" @@ -15,7 +16,6 @@ import ( "github.com/gofiber/fiber/v2/middleware/logger" "github.com/gofiber/fiber/v2/middleware/recover" "github.com/gofiber/fiber/v2/middleware/requestid" - "github.com/generate/selfserve/internal/errs" ) type App struct { @@ -57,7 +57,7 @@ func setupRoutes(app *fiber.App, repo *storage.Repository) { // initialize handler(s) helloHandler := handler.NewHelloHandler() devsHandler := handler.NewDevsHandler(repository.NewDevsRepository(repo.DB)) - reqsHandler := handler.NewRequestHandler(repository.NewRequestRepo(repo.DB)) + reqsHandler := handler.NewRequestsHandler(repository.NewRequestsRepo(repo.DB)) // API v1 routes api := app.Group("/api/v1") @@ -75,7 +75,7 @@ func setupRoutes(app *fiber.App, repo *storage.Repository) { // Request routes api.Route("/request", func(r fiber.Router) { - r.Post("/", reqsHandler.MakeRequest) + r.Post("/", reqsHandler.CreateRequest) }) diff --git a/backend/internal/service/storage/postgres/repo_types.go b/backend/internal/service/storage/postgres/repo_types.go index f3f670a9..55875641 100644 --- a/backend/internal/service/storage/postgres/repo_types.go +++ b/backend/internal/service/storage/postgres/repo_types.go @@ -5,6 +5,6 @@ import ( "github.com/generate/selfserve/internal/models" ) -type RequestRepository interface { - MakeRequest(ctx context.Context, req *models.Request) (*models.Request, error) +type RequestsRepository interface { + InsertRequest(ctx context.Context, req *models.Request) (*models.Request, error) } diff --git a/backend/internal/service/storage/postgres/storage.go b/backend/internal/service/storage/postgres/storage.go index dc506602..42e0179c 100644 --- a/backend/internal/service/storage/postgres/storage.go +++ b/backend/internal/service/storage/postgres/storage.go @@ -17,7 +17,7 @@ type DevsRepository interface { type Repository struct { DB *pgxpool.Pool DevsRepository DevsRepository - RequestRepository RequestRepository + RequestRepository RequestsRepository } // Establishes a sustained connection to the PostgreSQL database / pooling @@ -60,6 +60,6 @@ func NewRepository(config config.DB) (*Repository, error) { return &Repository{ DB: db, DevsRepository: repository.NewDevsRepository(db), - RequestRepository: repository.NewRequestRepo(db), + RequestRepository: repository.NewRequestsRepo(db), }, nil } diff --git a/backend/supabase/migrations/20260115030809_nullable_notes_request_table.sql b/backend/supabase/migrations/20260115030809_nullable_notes_request_table.sql new file mode 100644 index 00000000..f9d3d9d5 --- /dev/null +++ b/backend/supabase/migrations/20260115030809_nullable_notes_request_table.sql @@ -0,0 +1,3 @@ +-- make notes nullable in the requests table +ALTER TABLE public.requests +ALTER COLUMN notes DROP NOT NULL; \ No newline at end of file From 32d67ccf76c1846a868924e5e4e43b74f193f71b Mon Sep 17 00:00:00 2001 From: Manuel Torres Date: Thu, 15 Jan 2026 12:46:30 -0500 Subject: [PATCH 5/5] Revert "Feat/request post" --- backend/cmd/server/main.go | 1 - backend/go.mod | 2 +- backend/internal/handler/requests.go | 84 ------- backend/internal/handler/requests_test.go | 235 ------------------ backend/internal/handler/utils.go | 10 - backend/internal/models/requests.go | 34 --- backend/internal/repository/requests.go | 34 --- backend/internal/service/server.go | 10 - .../service/storage/postgres/repo_types.go | 10 - .../service/storage/postgres/storage.go | 2 - ...115030809_nullable_notes_request_table.sql | 3 - 11 files changed, 1 insertion(+), 424 deletions(-) delete mode 100644 backend/internal/handler/requests.go delete mode 100644 backend/internal/handler/requests_test.go delete mode 100644 backend/internal/handler/utils.go delete mode 100644 backend/internal/models/requests.go delete mode 100644 backend/internal/repository/requests.go delete mode 100644 backend/internal/service/storage/postgres/repo_types.go delete mode 100644 backend/supabase/migrations/20260115030809_nullable_notes_request_table.sql diff --git a/backend/cmd/server/main.go b/backend/cmd/server/main.go index 1380212d..e629ee4a 100644 --- a/backend/cmd/server/main.go +++ b/backend/cmd/server/main.go @@ -11,7 +11,6 @@ import ( "github.com/generate/selfserve/config" "github.com/generate/selfserve/internal/service" "github.com/sethvargo/go-envconfig" - _ "github.com/generate/selfserve/docs" ) // @title SelfServe API diff --git a/backend/go.mod b/backend/go.mod index 4ebe1170..4b912da3 100644 --- a/backend/go.mod +++ b/backend/go.mod @@ -45,7 +45,7 @@ require ( github.com/andybalholm/brotli v1.2.0 // indirect github.com/goccy/go-json v0.10.5 github.com/gofiber/fiber/v2 v2.52.10 - github.com/google/uuid v1.6.0 + github.com/google/uuid v1.6.0 // indirect github.com/jackc/pgx/v5 v5.8.0 github.com/klauspost/compress v1.18.2 // indirect github.com/mattn/go-colorable v0.1.14 // indirect diff --git a/backend/internal/handler/requests.go b/backend/internal/handler/requests.go deleted file mode 100644 index 75e2ee70..00000000 --- a/backend/internal/handler/requests.go +++ /dev/null @@ -1,84 +0,0 @@ -package handler - -import ( - "strings" - - "github.com/generate/selfserve/internal/errs" - "github.com/generate/selfserve/internal/models" - storage "github.com/generate/selfserve/internal/service/storage/postgres" - "github.com/gofiber/fiber/v2" -) - -type RequestsHandler struct { - RequestRepository storage.RequestsRepository -} - -func NewRequestsHandler(repo storage.RequestsRepository) *RequestsHandler { - return &RequestsHandler{RequestRepository: repo} -} - -// CreateRequest godoc -// @Summary creates a request -// @Description Creates a request with the given data -// @Tags requests -// @Accept json -// @Produce json -// @Param request body models.MakeRequest true "Request data" -// @Success 200 {object} models.Request -// @Failure 400 {object} map[string]string -// @Failure 500 {object} map[string]string -// @Router /request [post] -func (r *RequestsHandler)CreateRequest(c *fiber.Ctx) error { - var incoming models.MakeRequest - if err := c.BodyParser(&incoming); err != nil { - return errs.InvalidJSON() - } - req := models.Request{MakeRequest: incoming} - - if err := validateCreateRequest(&req); err != nil { - return err - } - - res, err := r.RequestRepository.InsertRequest(c.Context(), &req) - if err != nil { - return errs.InternalServerError() - } - - return c.JSON(res) -} - -func validateCreateRequest(req *models.Request) error { - errors := make(map[string]string) - - if !validUUID(req.HotelID) { - errors["hotel_id"] = "invalid uuid" - } - - if req.GuestID != nil && !validUUID(*req.GuestID) { - errors["guest_id"] = "invalid uuid" - } - if req.UserID != nil && !validUUID(*req.UserID) { - errors["user_id"] = "invalid uuid" - } - if req.Name == "" { - errors["name"] = "must not be an empty string" - } - if req.RequestType == "" { - errors["request_type"] = "must not be an empty string" - } - if req.Status == "" { - errors["status"] = "must not be an empty string" - } - if req.Priority == "" { - errors["priority"] = "must not be an empty string" - } - - if len(errors) > 0 { - var parts []string - for field, violation := range errors { - parts = append(parts, field+": "+violation) - } - return errs.BadRequest(strings.Join(parts, ", ")) - } - return nil -} \ No newline at end of file diff --git a/backend/internal/handler/requests_test.go b/backend/internal/handler/requests_test.go deleted file mode 100644 index 9257e050..00000000 --- a/backend/internal/handler/requests_test.go +++ /dev/null @@ -1,235 +0,0 @@ -package handler - -import ( - "bytes" - "context" - "errors" - "io" - "net/http/httptest" - "testing" - - "github.com/generate/selfserve/internal/errs" - "github.com/generate/selfserve/internal/models" - "github.com/gofiber/fiber/v2" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - - -type mockRequestRepository struct { - makeRequestFunc func(ctx context.Context, req *models.Request) (*models.Request, error) -} - -func (m *mockRequestRepository) InsertRequest(ctx context.Context, req *models.Request) (*models.Request, error) { - return m.makeRequestFunc(ctx, req) -} - -func TestRequestHandler_MakeRequest(t *testing.T) { - t.Parallel() - validBody := `{ - "hotel_id": "550e8400-e29b-41d4-a716-446655440000", - "name": "room cleaning", - "request_type": "recurring", - "status": "pending", - "priority": "high", - "notes": "No special requests" - }` - - t.Run("returns 200 on success", func(t *testing.T) { - t.Parallel() - - mock := &mockRequestRepository{ - makeRequestFunc: func(ctx context.Context, req *models.Request) (*models.Request, error) { - req.ID = "generated-uuid" - return req, nil - }, - } - - app := fiber.New() - h := NewRequestsHandler(mock) - app.Post("/request", h.CreateRequest) - - req := httptest.NewRequest("POST", "/request", bytes.NewBufferString(validBody)) - req.Header.Set("Content-Type", "application/json") - resp, err := app.Test(req) - require.NoError(t, err) - - assert.Equal(t, 200, resp.StatusCode) - - body, _ := io.ReadAll(resp.Body) - assert.Contains(t, string(body), "generated-uuid") - assert.Contains(t, string(body), "room cleaning") - - }) - - t.Run("returns 200 when optional uuid fields are valid", func(t *testing.T) { - t.Parallel() - - mock := &mockRequestRepository{ - makeRequestFunc: func(ctx context.Context, req *models.Request) (*models.Request, error) { - req.ID = "generated-uuid" - return req, nil - }, - } - - app := fiber.New() - h := NewRequestsHandler(mock) - app.Post("/request", h.CreateRequest) - - bodyWithOptionalUUIDs := `{ - "hotel_id": "550e8400-e29b-41d4-a716-446655440000", - "guest_id": "660e8400-e29b-41d4-a716-446655440000", - "user_id": "770e8400-e29b-41d4-a716-446655440000", - "name": "room cleaning", - "request_type": "recurring", - "status": "pending", - "priority": "high", - "notes": "No special requests" - }` - - req := httptest.NewRequest("POST", "/request", bytes.NewBufferString(bodyWithOptionalUUIDs)) - req.Header.Set("Content-Type", "application/json") - resp, err := app.Test(req) - require.NoError(t, err) - - assert.Equal(t, 200, resp.StatusCode) - - body, _ := io.ReadAll(resp.Body) - assert.Contains(t, string(body), "660e8400-e29b-41d4-a716-446655440000") - assert.Contains(t, string(body), "770e8400-e29b-41d4-a716-446655440000") - }) - - t.Run("returns 400 on invalid JSON", func(t *testing.T) { - t.Parallel() - - mock := &mockRequestRepository{ - makeRequestFunc: func(ctx context.Context, req *models.Request) (*models.Request, error) { - return req, nil - }, - } - - app := fiber.New(fiber.Config{ErrorHandler: errs.ErrorHandler}) - h := NewRequestsHandler(mock) - app.Post("/request", h.CreateRequest) - - req := httptest.NewRequest("POST", "/request", bytes.NewBufferString(`{invalid json`)) - req.Header.Set("Content-Type", "application/json") - resp, err := app.Test(req) - require.NoError(t, err) - - assert.Equal(t, 400, resp.StatusCode) - }) - - t.Run("returns 400 on missing required fields", func(t *testing.T) { - t.Parallel() - - mock := &mockRequestRepository{ - makeRequestFunc: func(ctx context.Context, req *models.Request) (*models.Request, error) { - return req, nil - }, - } - - app := fiber.New(fiber.Config{ErrorHandler: errs.ErrorHandler}) - h := NewRequestsHandler(mock) - app.Post("/request", h.CreateRequest) - - req := httptest.NewRequest("POST", "/request", bytes.NewBufferString(`{}`)) - req.Header.Set("Content-Type", "application/json") - resp, err := app.Test(req) - require.NoError(t, err) - - assert.Equal(t, 400, resp.StatusCode) - - body, _ := io.ReadAll(resp.Body) - assert.Contains(t, string(body), "hotel_id") - assert.Contains(t, string(body), "name") - }) - - t.Run("returns 400 on invalid hotel_id uuid", func(t *testing.T) { - t.Parallel() - - mock := &mockRequestRepository{ - makeRequestFunc: func(ctx context.Context, req *models.Request) (*models.Request, error) { - return req, nil - }, - } - - app := fiber.New(fiber.Config{ErrorHandler: errs.ErrorHandler}) - h := NewRequestsHandler(mock) - app.Post("/request", h.CreateRequest) - - invalidUUIDBody := `{ - "hotel_id": "not-a-uuid", - "name": "room cleaning", - "request_type": "recurring", - "status": "pending", - "priority": "high", - "notes": "No special requests" - }` - - req := httptest.NewRequest("POST", "/request", bytes.NewBufferString(invalidUUIDBody)) - req.Header.Set("Content-Type", "application/json") - resp, err := app.Test(req) - require.NoError(t, err) - - assert.Equal(t, 400, resp.StatusCode) - - body, _ := io.ReadAll(resp.Body) - assert.Contains(t, string(body), "hotel_id") - }) - - t.Run("returns 400 on invalid optional guest_id uuid", func(t *testing.T) { - t.Parallel() - - mock := &mockRequestRepository{ - makeRequestFunc: func(ctx context.Context, req *models.Request) (*models.Request, error) { - return req, nil - }, - } - - app := fiber.New(fiber.Config{ErrorHandler: errs.ErrorHandler}) - h := NewRequestsHandler(mock) - app.Post("/request", h.CreateRequest) - - invalidGuestIDBody := `{ - "hotel_id": "550e8400-e29b-41d4-a716-446655440000", - "guest_id": "not-a-uuid", - "name": "room cleaning", - "request_type": "recurring", - "status": "pending", - "priority": "high", - "notes": "No special requests" - }` - - req := httptest.NewRequest("POST", "/request", bytes.NewBufferString(invalidGuestIDBody)) - req.Header.Set("Content-Type", "application/json") - resp, err := app.Test(req) - require.NoError(t, err) - - assert.Equal(t, 400, resp.StatusCode) - - body, _ := io.ReadAll(resp.Body) - assert.Contains(t, string(body), "guest_id") - }) - - t.Run("returns 500 on db error", func(t *testing.T) { - t.Parallel() - - mock := &mockRequestRepository{ - makeRequestFunc: func(ctx context.Context, req *models.Request) (*models.Request, error) { - return nil, errors.New("db connection failed") - }, - } - - app := fiber.New(fiber.Config{ErrorHandler: errs.ErrorHandler}) - h := NewRequestsHandler(mock) - app.Post("/request", h.CreateRequest) - - req := httptest.NewRequest("POST", "/request", bytes.NewBufferString(validBody)) - req.Header.Set("Content-Type", "application/json") - resp, err := app.Test(req) - require.NoError(t, err) - - assert.Equal(t, 500, resp.StatusCode) - }) -} \ No newline at end of file diff --git a/backend/internal/handler/utils.go b/backend/internal/handler/utils.go deleted file mode 100644 index c490a267..00000000 --- a/backend/internal/handler/utils.go +++ /dev/null @@ -1,10 +0,0 @@ -package handler - -import ( - "github.com/google/uuid" -) - -func validUUID(s string) bool { - _, err := uuid.Parse(s) - return err == nil -} \ No newline at end of file diff --git a/backend/internal/models/requests.go b/backend/internal/models/requests.go deleted file mode 100644 index 2db4e5f5..00000000 --- a/backend/internal/models/requests.go +++ /dev/null @@ -1,34 +0,0 @@ -package models - -import "time" - -// pointer fields are for easy handling of optional fields - -// for post because the ID and timestamps should always be generated -type MakeRequest struct { - HotelID string `json:"hotel_id" example:"521e8400-e458-41d4-a716-446655440000"` - GuestID *string `json:"guest_id" example:"521e8417-e458-41d4-a716-446655440990"` - UserID *string `json:"user_id" example:"521ee400-e458-41d4-a716-446655440000"` - ReservationID *string `json:"reservation_id" example:"521e8400-e458-41d4-a716-498655440000"` - Name string `json:"name" example:"room cleaning"` - Description *string `json:"description" example:"clean 504"` - RoomID *string `json:"room_id" example:"521e8422-e458-41d4-a716-446655440000"` - RequestCategory *string `json:"request_category" example:"Cleaning"` - RequestType string `json:"request_type" example:"recurring"` - Department *string `json:"department" example:"maintenance"` - Status string `json:"status" example:"assigned"` - Priority string `json:"priority" example:"urgent"` - EstimatedCompletionTime *int `json:"estimated_completion_time" example:"30"` - ScheduledTime *time.Time `json:"scheduled_time" example:"2024-01-01T00:00:00Z"` - CompletedAt *time.Time `json:"completed_at" example:"2024-01-01T00:30:00Z"` - Notes *string `json:"notes" example:"No special requests"` -} - - - -type Request struct { - ID string `json:"id" example:"530e8400-e458-41d4-a716-446655440000"` - CreatedAt time.Time `json:"created_at" example:"2024-01-02T00:00:00Z"` - UpdatedAt time.Time `json:"updated_at" example:"2024-01-02T00:00:00Z"` - MakeRequest -} \ No newline at end of file diff --git a/backend/internal/repository/requests.go b/backend/internal/repository/requests.go deleted file mode 100644 index cce9e8b1..00000000 --- a/backend/internal/repository/requests.go +++ /dev/null @@ -1,34 +0,0 @@ -package repository - -import ( - "context" - "github.com/generate/selfserve/internal/models" - "github.com/jackc/pgx/v5/pgxpool" -) - -type RequestsRepository struct { - db *pgxpool.Pool -} - -func NewRequestsRepo(db *pgxpool.Pool) *RequestsRepository { - return &RequestsRepository{db: db} -} - -func (r *RequestsRepository) InsertRequest(ctx context.Context, req *models.Request) (*models.Request, error) { - err := r.db.QueryRow(ctx, `INSERT INTO requests ( - hotel_id, guest_id, user_id, reservation_id, name, description, - room_id, request_category, request_type, department, status, - priority, estimated_completion_time, scheduled_time, notes - ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15) - RETURNING id, created_at, updated_at - `, req.HotelID, req.GuestID, req.UserID, req.ReservationID, req.Name, - req.Description, req.RoomID, req.RequestCategory, req.RequestType, req.Department, - req.Status, req.Priority, req.EstimatedCompletionTime, - req.ScheduledTime, req.Notes).Scan(&req.ID, &req.CreatedAt, &req.UpdatedAt) - - if (err != nil) { - return nil, err - } - - return req, nil -} diff --git a/backend/internal/service/server.go b/backend/internal/service/server.go index 47a048c9..c57f1996 100644 --- a/backend/internal/service/server.go +++ b/backend/internal/service/server.go @@ -4,7 +4,6 @@ import ( "net/http" "github.com/generate/selfserve/config" - "github.com/generate/selfserve/internal/errs" "github.com/generate/selfserve/internal/handler" "github.com/generate/selfserve/internal/repository" storage "github.com/generate/selfserve/internal/service/storage/postgres" @@ -57,7 +56,6 @@ func setupRoutes(app *fiber.App, repo *storage.Repository) { // initialize handler(s) helloHandler := handler.NewHelloHandler() devsHandler := handler.NewDevsHandler(repository.NewDevsRepository(repo.DB)) - reqsHandler := handler.NewRequestsHandler(repository.NewRequestsRepo(repo.DB)) // API v1 routes api := app.Group("/api/v1") @@ -72,13 +70,6 @@ func setupRoutes(app *fiber.App, repo *storage.Repository) { api.Route("/devs", func(r fiber.Router) { r.Get("/:name", devsHandler.GetMember) }) - - // Request routes - api.Route("/request", func(r fiber.Router) { - r.Post("/", reqsHandler.CreateRequest) - }) - - } // Initialize Fiber app with middlewares / configs @@ -86,7 +77,6 @@ func setupApp() *fiber.App { app := fiber.New(fiber.Config{ JSONEncoder: json.Marshal, JSONDecoder: json.Unmarshal, - ErrorHandler: errs.ErrorHandler, }) app.Use(recover.New()) app.Use(requestid.New()) diff --git a/backend/internal/service/storage/postgres/repo_types.go b/backend/internal/service/storage/postgres/repo_types.go deleted file mode 100644 index 55875641..00000000 --- a/backend/internal/service/storage/postgres/repo_types.go +++ /dev/null @@ -1,10 +0,0 @@ -package storage - -import ( - "context" - "github.com/generate/selfserve/internal/models" -) - -type RequestsRepository interface { - InsertRequest(ctx context.Context, req *models.Request) (*models.Request, error) -} diff --git a/backend/internal/service/storage/postgres/storage.go b/backend/internal/service/storage/postgres/storage.go index 42e0179c..afc06d6f 100644 --- a/backend/internal/service/storage/postgres/storage.go +++ b/backend/internal/service/storage/postgres/storage.go @@ -17,7 +17,6 @@ type DevsRepository interface { type Repository struct { DB *pgxpool.Pool DevsRepository DevsRepository - RequestRepository RequestsRepository } // Establishes a sustained connection to the PostgreSQL database / pooling @@ -60,6 +59,5 @@ func NewRepository(config config.DB) (*Repository, error) { return &Repository{ DB: db, DevsRepository: repository.NewDevsRepository(db), - RequestRepository: repository.NewRequestsRepo(db), }, nil } diff --git a/backend/supabase/migrations/20260115030809_nullable_notes_request_table.sql b/backend/supabase/migrations/20260115030809_nullable_notes_request_table.sql deleted file mode 100644 index f9d3d9d5..00000000 --- a/backend/supabase/migrations/20260115030809_nullable_notes_request_table.sql +++ /dev/null @@ -1,3 +0,0 @@ --- make notes nullable in the requests table -ALTER TABLE public.requests -ALTER COLUMN notes DROP NOT NULL; \ No newline at end of file