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

Fix jwt generation and verification to include userid #125

Merged
merged 11 commits into from
Oct 4, 2024
129 changes: 71 additions & 58 deletions controllers/url.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,21 @@ func CreateTinyURL(ctx *gin.Context, db *bun.DB) {
return
}

userID, exists := ctx.Get("userID")
if !exists {
ctx.JSON(http.StatusUnauthorized, dtos.URLCreationResponse{
Message: "User not authenticated",
})
return
}

var existingOriginalURL models.Tinyurl
if err := db.NewSelect().Model(&existingOriginalURL).
Where("original_url = ?", body.OriginalUrl).
Where("user_id = ?", body.UserID).
Where("is_deleted = ?", false).
Where("original_url = ? AND user_id = ? AND is_deleted = ?", body.OriginalUrl, userID, false).
Scan(ctx); err == nil {
ctx.JSON(http.StatusOK, dtos.URLCreationResponse{
Message: "Shortened URL already exists",
ShortURL: existingOriginalURL.ShortUrl,
Message: "Shortened URL already exists",
ShortURL: existingOriginalURL.ShortUrl,
CreatedAt: existingOriginalURL.CreatedAt,
})
return
Expand Down Expand Up @@ -76,8 +82,7 @@ func CreateTinyURL(ctx *gin.Context, db *bun.DB) {

count, err := db.NewSelect().
Model(&models.Tinyurl{}).
Where("user_id = ?", body.UserID).
Where("is_deleted = ?", false).
Where("user_id = ? AND is_deleted = ?", userID, false).
Count(ctx)

if err != nil {
Expand All @@ -94,16 +99,21 @@ func CreateTinyURL(ctx *gin.Context, db *bun.DB) {
return
}

body.CreatedAt = time.Now().UTC()
newTinyURL := models.Tinyurl{
OriginalUrl: body.OriginalUrl,
ShortUrl: body.ShortUrl,
UserID: userID.(int64),
CreatedAt: time.Now().UTC(),
}

if _, err := db.NewInsert().Model(&body).Exec(ctx); err != nil {
if _, err := db.NewInsert().Model(&newTinyURL).Exec(ctx); err != nil {
ctx.JSON(http.StatusInternalServerError, dtos.URLCreationResponse{
Message: "Failed to create tiny URL",
})
return
}

if err := utils.IncrementURLCount(body.UserID, db, ctx); err != nil {
if err := utils.IncrementURLCount(userID.(int64), db, ctx); err != nil {
ctx.JSON(http.StatusInternalServerError, dtos.URLCreationResponse{
Message: "Failed to increment URL count: " + err.Error(),
})
Expand All @@ -112,8 +122,7 @@ func CreateTinyURL(ctx *gin.Context, db *bun.DB) {

updatedCount, err := db.NewSelect().
Model(&models.Tinyurl{}).
Where("user_id = ?", body.UserID).
Where("is_deleted = ?", false).
Where("user_id = ? AND is_deleted = ?", userID, false).
Count(ctx)

if err != nil {
Expand All @@ -124,9 +133,9 @@ func CreateTinyURL(ctx *gin.Context, db *bun.DB) {
}

ctx.JSON(http.StatusOK, dtos.URLCreationResponse{
Message: "Tiny URL created successfully",
ShortURL: body.ShortUrl,
URLCount: updatedCount,
Message: "Tiny URL created successfully",
ShortURL: newTinyURL.ShortUrl,
URLCount: updatedCount,
})
}

Expand Down Expand Up @@ -215,51 +224,55 @@ func GetAllURLs(ctx *gin.Context, db *bun.DB) {
}

func DeleteURL(ctx *gin.Context, db *bun.DB) {
id, _ := ctx.Params.Get("id")

var body struct {
UserID int64 `json:"user_id"`
}
if err := ctx.BindJSON(&body); err != nil {
ctx.JSON(http.StatusBadRequest, dtos.UserURLsResponse{
Message: "Invalid Request.",
})
return
}

_, err := db.NewUpdate().Model(&models.Tinyurl{}).Set("is_deleted=?", true).Set("deleted_at=?", time.Now().UTC()).Where("id = ?", id).Exec(ctx)
if err != nil {
ctx.JSON(http.StatusNotFound, dtos.UserURLsResponse{
Message: "No URLs found",
})
return
}


if err := utils.DecrementURLCount(body.UserID, db, ctx); err != nil {
ctx.JSON(http.StatusInternalServerError, dtos.URLCreationResponse{
Message: "Failed to decrement URL count: " + err.Error(),
})
return
}
id, _ := ctx.Params.Get("id")

userID, exists := ctx.Get("userID")
if !exists {
ctx.JSON(http.StatusUnauthorized, dtos.UserURLsResponse{
Message: "User not authenticated",
})
return
}

_, err := db.NewUpdate().
Model(&models.Tinyurl{}).
Set("is_deleted=?", true).
Set("deleted_at=?", time.Now().UTC()).
Where("id = ?", id).
Where("user_id = ?", userID).
Exec(ctx)

if err != nil {
ctx.JSON(http.StatusNotFound, dtos.UserURLsResponse{
Message: "No URLs found",
})
return
}

if err := utils.DecrementURLCount(userID.(int64), db, ctx); err != nil {
ctx.JSON(http.StatusInternalServerError, dtos.URLCreationResponse{
Message: "Failed to decrement URL count: " + err.Error(),
})
return
}

updatedCount, err := db.NewSelect().
Model(&models.Tinyurl{}).
Where("user_id = ?", body.UserID).
Where("is_deleted = ?", false).
Count(ctx)

if err != nil {
ctx.JSON(http.StatusInternalServerError, dtos.URLCreationResponse{
Message: "Failed to fetch updated URL count",
})
return
}

ctx.JSON(http.StatusOK, dtos.URLDeleteResponse{
Message: "URL deleted",
URLCount: updatedCount,
})
Model(&models.Tinyurl{}).
Where("user_id = ?", userID).
Where("is_deleted = ?", false).
Count(ctx)

if err != nil {
ctx.JSON(http.StatusInternalServerError, dtos.URLCreationResponse{
Message: "Failed to fetch updated URL count",
})
return
}

ctx.JSON(http.StatusOK, dtos.URLDeleteResponse{
Message: "URL deleted",
URLCount: updatedCount,
})
}

func GetURLDetails(ctx *gin.Context, db *bun.DB) {
Expand Down
15 changes: 12 additions & 3 deletions middlewares/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,24 @@ func AuthMiddleware() gin.HandlerFunc {

token := tokenCookie.Value

email, err := utils.VerifyToken(token)
claims, err := utils.VerifyToken(token)

if err != nil {
ctx.JSON(http.StatusUnauthorized, gin.H{"message": "Unauthorized"})
ctx.Abort()
return
}

ctx.Set("user", email)
userID, ok := claims["userID"].(float64)

if !ok {
ctx.JSON(http.StatusUnauthorized, gin.H{"message": "Invalid UserID format"})
ctx.Abort()
return
}

ctx.Set("user", claims["email"])
ctx.Set("userID", int64(userID))
ctx.Next()
}
}
}
4 changes: 2 additions & 2 deletions routes/url.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ func TinyURLRoutes(rg *gin.RouterGroup, db *bun.DB) {
redirect.GET("/:shortURL", func(ctx *gin.Context) {
controller.RedirectShortURL(ctx, db)
})
urls.DELETE("/:id", func(ctx *gin.Context) {
urls.DELETE("/:id", middleware.AuthMiddleware(), func(ctx *gin.Context) {
controller.DeleteURL(ctx, db)
})
})
}
27 changes: 24 additions & 3 deletions tests/integration/url_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ import (
func (suite *AppTestSuite) TestCreateTinyURLSuccess() {
// Setup the router and route for creating a tiny URL
router := gin.Default()

router.Use(func(ctx *gin.Context) {
ctx.Set("userID", int64(1))
ctx.Next()
})

router.POST("/v1/tinyurl", func(ctx *gin.Context) {
controller.CreateTinyURL(ctx, suite.db)
})
Expand Down Expand Up @@ -81,14 +87,19 @@ func (suite *AppTestSuite) TestCreateTinyURLEmptyOriginalURL() {
// TestCreateTinyURLCustomShortURL tests the creation of a tiny URL with a custom short URL and expects a successful response.
func (suite *AppTestSuite) TestCreateTinyURLCustomShortURL() {
router := gin.Default()

router.Use(func(ctx *gin.Context) {
ctx.Set("userID", int64(1))
ctx.Next()
})

router.POST("/v1/tinyurl", func(ctx *gin.Context) {
controller.CreateTinyURL(ctx, suite.db)
})

requestBody := map[string]interface{}{
"OriginalUrl": "https://example.com",
"ShortUrl": "short",
"UserId": 1,
}
requestJSON, _ := json.Marshal(requestBody)
req, _ := http.NewRequest("POST", "/v1/tinyurl", bytes.NewBuffer(requestJSON))
Expand All @@ -102,14 +113,19 @@ func (suite *AppTestSuite) TestCreateTinyURLCustomShortURL() {

func (suite *AppTestSuite) TestCreateTinyURLCustomShortURLExists() {
router := gin.Default()

router.Use(func(ctx *gin.Context) {
ctx.Set("userID", int64(1))
ctx.Next()
})

router.POST("/v1/tinyurl", func(ctx *gin.Context) {
controller.CreateTinyURL(ctx, suite.db)
})

requestBody := map[string]interface{}{
"OriginalUrl": "https://rds.com",
"ShortUrl": "37fff",
"UserId": 1,
}
requestJSON, _ := json.Marshal(requestBody)
req, _ := http.NewRequest("POST", "/v1/tinyurl", bytes.NewBuffer(requestJSON))
Expand All @@ -123,6 +139,12 @@ func (suite *AppTestSuite) TestCreateTinyURLCustomShortURLExists() {

func (suite *AppTestSuite) TestCreateTinyURLExistingOriginalURL() {
router := gin.Default()

router.Use(func(ctx *gin.Context) {
ctx.Set("userID", int64(1))
ctx.Next()
})

router.POST("/v1/tinyurl", func(ctx *gin.Context) {
controller.CreateTinyURL(ctx, suite.db)
})
Expand All @@ -131,7 +153,6 @@ func (suite *AppTestSuite) TestCreateTinyURLExistingOriginalURL() {

requestBody := map[string]interface{}{
"OriginalUrl": existingOriginalURL,
"UserId": 1,
}
requestJSON, _ := json.Marshal(requestBody)
req, _ := http.NewRequest("POST", "/v1/tinyurl", bytes.NewBuffer(requestJSON))
Expand Down
Loading
Loading