diff --git a/backend/internal/models/review.go b/backend/internal/models/review.go new file mode 100644 index 00000000..45d29bc4 --- /dev/null +++ b/backend/internal/models/review.go @@ -0,0 +1,10 @@ +package models + +type Review struct { + UserID string `json:"user_id"` + MediaType string `json:"media_type"` + MediaID string `json:"media_id"` + Rating string `json:"rating"` + Desc *string `json:"desc,omitempty"` + DateTime string `json:"date_time"` +} diff --git a/backend/internal/service/handler/review.go b/backend/internal/service/handler/review.go new file mode 100644 index 00000000..af542e07 --- /dev/null +++ b/backend/internal/service/handler/review.go @@ -0,0 +1,85 @@ +package handler + +import ( + "platnm/internal/storage" + + "github.com/gofiber/fiber/v2" +) + +type ReviewHandler struct { + reviewRepository storage.ReviewRepository +} + +func NewReviewHandler(reviewRepository storage.ReviewRepository) *ReviewHandler { + return &ReviewHandler{ + reviewRepository, + } +} + +func (h *ReviewHandler) GetReviews(c *fiber.Ctx) error { + review, err := h.reviewRepository.GetReviews(c.Context()) + if err != nil { + return err + } + + return c.Status(fiber.StatusOK).JSON(users) +} + +func (h *ReviewHandler) GetReviewById(c *fiber.Ctx, mediaType MediaType) error { + id := c.Params("id") + offset := c.Query("offset", "0") + limit := c.Query("limit", "10") + review, err := h.reviewRepository.GetReviewByID(id, mediaType, c.Context()) + + // Parse offset and limit as integers + offset, err := strconv.Atoi(offsetStr) + if err != nil || offset < 0 { + offset = 0 // Ensure offset is non-negative + } + + limit, err := strconv.Atoi(limitStr) + if err != nil || limit <= 0 { + limit = 10 // Ensure limit is positive + } + + // Fetch the review based on ID and media type + review, err := h.reviewRepository.GetReviewByID(id, mediaType, c.Context(), offset, limit) + if err != nil { + // If error, log it and return 500 + fmt.Println(err.Error(), "from transactions err ") + return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{ + "error": "Unable to retrieve reviews", + }) + } + + // If no review is found, return a 404 status + if review == nil || len(review) == 0 { + return c.Status(fiber.StatusNotFound).JSON(fiber.Map{ + "message": "No reviews found", + }) + } + + // Calculate average rating + var avgRating float64 + for _, r := range review { + avgRating += r.Rating + } + if len(review) > 0 { + avgRating /= float64(len(review)) + } + + // Return the reviews and average rating + response := fiber.Map{ + "avgRating": avgRating, + "reviews": review, + } + + return c.Status(fiber.StatusOK).JSON(response) + + if err != nil { + print(err.Error(), "from transactions err ") + return err + } + + return c.Status(fiber.StatusOK).JSON(review) +} diff --git a/backend/internal/service/handler/user.go b/backend/internal/service/handler/user.go index e3e06639..ff378813 100644 --- a/backend/internal/service/handler/user.go +++ b/backend/internal/service/handler/user.go @@ -27,6 +27,8 @@ func (h *UserHandler) GetUsers(c *fiber.Ctx) error { func (h *UserHandler) GetUserById(c *fiber.Ctx) error { id := c.Params("id") + limitParam := r.URL.Query().Get("limit") + offsetParam := r.URL.Query().Get("offset") user, err := h.userRepository.GetUserByID(id, c.Context()) if err != nil { diff --git a/backend/internal/service/server.go b/backend/internal/service/server.go index 1749125e..21fafe7f 100644 --- a/backend/internal/service/server.go +++ b/backend/internal/service/server.go @@ -36,6 +36,18 @@ func setupRoutes(app *fiber.App, conn *pgxpool.Pool) { r.Get("/", userHandler.GetUsers) r.Get("/:id", userHandler.GetUserById) }) + + reviewHandler := handler.NewReviewHandler(repository.Review) + app.Route("/reviews", func(r fiber.Router) { + r.Get("/album", reviewHandler.GetReviews) + r.Get("/:albumID", reviewHandler.GetReviewsById(MediaType: "album")) + }) + + reviewHandler := handler.NewReviewHandler(repository.Review) + app.Route("/reviews", func(r fiber.Router) { + r.Get("/track", reviewHandler.GetReviews) + r.Get("/:trackID", reviewHandler.GetReviewsById(MediaType: "track")) + }) } func setupApp() *fiber.App { diff --git a/backend/internal/storage/postgres/schema/review.go b/backend/internal/storage/postgres/schema/review.go new file mode 100644 index 00000000..5a7a9765 --- /dev/null +++ b/backend/internal/storage/postgres/schema/review.go @@ -0,0 +1,70 @@ +package user + +import ( + "context" + "platnm/internal/models" + + "github.com/jackc/pgx/v5/pgxpool" +) + +type ReviewRepository struct { + db *pgxpool.Pool +} + +func (r *ReviewRepository) GetReviews(ctx context.Context) ([]*models.Review, error) { + rows, err := r.db.Query(context.Background(), "SELECT user_id, media_id, media_type, desc, rating, date_time FROM review") + if err != nil { + print(err.Error(), "from transactions err ") + return []*models.Review{}, err + } + defer rows.Close() + + var reviews []*models.Review + for rows.Next() { + var review models.Review + var user_id, media_id, media_type, desc, rating, date_time *string + + if err := rows.Scan(&review.UserID, &mediaID, &mediaType, &desc, &rating, &dateTime); err != nil { + print(err.Error(), "from transactions err ") + return review, err + } + + review.UserID = *userID + review.MediaID = *mediaID + review.MediaType = *mediaType + review.Desc = *desc + review.Rating = *rating + review.DateTime = *dateTime + + reviews = append(reviews, &review) + } + + if err := rows.Err(); err != nil { + print(err.Error(), "from transactions err ") + return []*models.Review{}, err + } + + return reviews, nil +} + +func (r *ReviewRepository) GetReviewByID(id string, media_type string, ctx context.Context) (*models.Review, error) { + var review models.Review + if media_type = "album" { + err := r.db.QueryRow(context.Background(), "SELECT user_id, media_id, media_type, desc, rating, date_time FROM review WHERE media_id = $1 and media_type = 'album'", id).Scan(&review.UserID, &mediaID, &mediaType, &desc, &rating, &dateTime) + } else if media_type = "track" { + err := r.db.QueryRow(context.Background(), "SELECT user_id, media_id, media_type, desc, rating, date_time FROM review WHERE media_id = $1 and media_type = 'track'", id).Scan(&review.UserID, &mediaID, &mediaType, &desc, &rating, &dateTime) + } + + if err != nil { + print(err.Error(), "from transactions err ") + return nil, err + } + + return &review, nil +} + +func NewReviewRepository(db *pgxpool.Pool) *ReviewRepository { + return &ReviewRepository{ + db: db, + } +} \ No newline at end of file