Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Implement GET endpoint to fetch URLs for a given user and admin access #60

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
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
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -195,4 +195,8 @@ fabric.properties
/events.db
/events.db.wal
/duckdb-driver
/GeoLite2-City.mmdb
/GeoLite2-City.mmdb

index.html.fiber.gz
script.js.fiber.gz
style.css.fiber.gz
25 changes: 22 additions & 3 deletions src/controllers/urls.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,17 @@ package controllers

import (
"errors"
"github.com/gofiber/fiber/v2"
"github.com/samber/lo"
"gorm.io/gorm"
"math"
"math/rand"
"onepixel_backend/src/db"
"onepixel_backend/src/db/models"
"onepixel_backend/src/utils"
"onepixel_backend/src/utils/applogger"
"sync"

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why the juggling of imports? needed?

Copy link
Author

@rahul-MyGit rahul-MyGit Aug 4, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whenever I save this file, it automatically juggles. As there are no spaces between them, it's prolly done by go itself.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah ok that's fine then

"github.com/gofiber/fiber/v2"
"github.com/samber/lo"
"gorm.io/gorm"
)

// the current max length of the short url
Expand Down Expand Up @@ -160,3 +161,21 @@ func (c *UrlsController) CreateUrlGroup(groupName string, userId uint64) (urlGro
return

}

func (c *UrlsController) GetAllUrls(userId *uint64) ([]models.Url, error) {
var urls []models.Url
query := c.db

if userId != nil {
query = query.Where("creator_id = ?", *userId)
}

res := query.Find(&urls)
if res.Error != nil {
applogger.Error("Failed to fetch URLs from database", "user_id", userId, "error", res.Error)
return nil, res.Error
}

applogger.Info("Successfully fetched URLs", "user_id", userId, "url_count", len(urls))
return urls, nil
}
14 changes: 12 additions & 2 deletions src/controllers/users.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@ package controllers

import (
"errors"
"github.com/google/uuid"
"gorm.io/gorm"
"onepixel_backend/src/config"
"onepixel_backend/src/db"
"onepixel_backend/src/db/models"
"onepixel_backend/src/security"
"onepixel_backend/src/utils/applogger"
"sync"

"github.com/google/uuid"
"gorm.io/gorm"
)

type AuthError struct {
Expand Down Expand Up @@ -106,3 +107,12 @@ func (c *UsersController) VerifyEmailAndPassword(email string, password string)
}
return user, nil
}

func (c *UrlsController) GetUrlsByUserId(userId uint64) ([]models.Url, error) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getting URLs should not be happening in Users controller, it should happen in Urls Controller only

var urls []models.Url
res := c.db.Where("creator_id =?", userId).Find(&urls)
if res.Error != nil {
return nil, res.Error
}
return urls, nil
}
8 changes: 8 additions & 0 deletions src/dtos/url_dtos.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,11 @@ func CreateUrlResponse(url *models.Url) UrlResponse {
CreatorID: url.CreatorID,
}
}

func CreateUrlsResponse(urls []models.Url) []UrlResponse {
response := make([]UrlResponse, len(urls))
for i, url := range urls {
response[i] = CreateUrlResponse(&url)
}
return response
}
53 changes: 52 additions & 1 deletion src/routes/api/urls.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import (
"onepixel_backend/src/security"
"onepixel_backend/src/server/parsers"
"onepixel_backend/src/server/validators"
"onepixel_backend/src/utils/applogger"
"strconv"

"github.com/gofiber/fiber/v2"
)
Expand All @@ -22,6 +24,7 @@ func UrlsRoute() func(router fiber.Router) {

return func(router fiber.Router) {
router.Get("/", getAllUrls)
router.Get("/admin", security.MandatoryAdminApiKeyAuthMiddleware, getAllUrlsAdmin)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i was preferring not to have /admin/urls or /urls/admin separately but simply use the /urls endpoint with the X-API-Key to work for admins.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure I'll do that

router.Post("/", security.MandatoryJwtAuthMiddleware, createRandomUrl)
router.Put("/:shortcode", security.MandatoryJwtAuthMiddleware, createSpecificUrl)
}
Expand All @@ -38,7 +41,13 @@ func UrlsRoute() func(router fiber.Router) {
// @Router /urls [get]
// @security BearerToken
func getAllUrls(ctx *fiber.Ctx) error {
return ctx.SendString("GetAllUsers")
user := ctx.Locals(config.LOCALS_USER).(*models.User)

urls, err := urlsController.GetUrlsByUserId(user.ID)
if err != nil {
return ctx.Status(fiber.StatusInternalServerError).JSON(dtos.CreateErrorResponse(fiber.StatusInternalServerError, "Failed to fetch URLs"))
}
return ctx.Status(fiber.StatusOK).JSON(dtos.CreateUrlsResponse(urls))
}

// createRandomUrl
Expand Down Expand Up @@ -137,3 +146,45 @@ func createGroupedRandomUrl(ctx *fiber.Ctx) error {
func createGroupedSpecificUrl(ctx *fiber.Ctx) error {
return ctx.SendString("createGroupedSpecificUrl")
}

// getAllUrlsAdmin
//
// @Summary Get all URLs (admin only)
// @Description Get all URLs with optional user ID filter (admin access required)
// @Tags admin, urls
// @Accept json
// @Produce json
// @Param X-API-Key header string true "Admin API Key"
// @Param userid query string false "Filter URLs by user ID"
// @Success 200 {array} dtos.UrlResponse
// @Failure 400 {object} dtos.ErrorResponse "Invalid user ID"
// @Failure 401 {object} dtos.ErrorResponse "Unauthorized"
// @Failure 500 {object} dtos.ErrorResponse "Failed to fetch URLs"
// @Router /urls/admin [get]
// @Security ApiKeyAuth
func getAllUrlsAdmin(ctx *fiber.Ctx) error {
userIdStr := ctx.Query("userid")

var userId *uint64
if userIdStr != "" {
parsedId, err := strconv.ParseUint(userIdStr, 10, 64)
if err != nil {
applogger.Error("Invalid user ID in admin URL request", "user_id", userIdStr, "error", err)
return ctx.Status(fiber.StatusBadRequest).JSON(fiber.Map{
"message": "Invalid user ID",
})
}
userId = &parsedId
}

urls, err := urlsController.GetAllUrls(userId)
if err != nil {
applogger.Error("Failed to fetch URL in admin request", "user_id", userId, "error", err)
return ctx.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
"message": "Failed to fetch URLs",
})
}

applogger.Info("Admin fetched URLs", "user_id", userId, "url_count", len(urls))
return ctx.Status(fiber.StatusOK).JSON(dtos.CreateUrlsResponse(urls))
}