(REFACTOR): Working on dependency injection.
However, everything seems really slow now... 950ms for a page request? Something is wrong, just not sure what yet.
This commit is contained in:
parent
1e4cf8f922
commit
aad4640527
@ -1,50 +1,47 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
domain "github.com/haydenhargreaves/Potion/internal/domain/server"
|
||||
"github.com/haydenhargreaves/Potion/internal/templates/components"
|
||||
)
|
||||
|
||||
// GoogleLogin directs the user to Googles select user login page. Once the user has selected an
|
||||
// account, they will be directed to the GoogleCallback handler where the main logic resides.
|
||||
func GoogleLogin(ctx *gin.Context) {
|
||||
deps := ctx.MustGet("deps").(*domain.InjectedDependencies)
|
||||
url := deps.AuthService.GetGoogleAuthUrl()
|
||||
|
||||
ctx.Redirect(http.StatusSeeOther, url)
|
||||
}
|
||||
//
|
||||
// DEPRECATED: As of September 4th, 2025.
|
||||
// func GoogleLogin(ctx *gin.Context) {
|
||||
// deps := ctx.MustGet("deps").(*domain.InjectedDependencies)
|
||||
// url := deps.AuthService.GetGoogleAuthUrl()
|
||||
//
|
||||
// ctx.Redirect(http.StatusSeeOther, url)
|
||||
// }
|
||||
|
||||
// GoogleCallback is the callback handler when the user successfully logs in with their Google
|
||||
// account. They will be directed here and a JWT is generated. This JWT is stored in the users
|
||||
// cookies and will be used by protected routes to validate their login status.
|
||||
//
|
||||
// We do not need to return all of this data, it is just for testing.
|
||||
func GoogleCallback(ctx *gin.Context) {
|
||||
deps := ctx.MustGet("deps").(*domain.InjectedDependencies)
|
||||
|
||||
var (
|
||||
state string = ctx.Query("state")
|
||||
code string = ctx.Query("code")
|
||||
)
|
||||
|
||||
if jwt, err := deps.AuthService.GoogleAuthSuccess(state, code); err != nil {
|
||||
components.RenderErrorBanner(ctx, err.Error())
|
||||
ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
} else {
|
||||
domain.SetCookie(ctx, "jwt_token", jwt, time.Hour*24*7)
|
||||
ctx.Redirect(http.StatusSeeOther, "/")
|
||||
}
|
||||
}
|
||||
//
|
||||
// DEPRECATED: As of September 4th, 2025.
|
||||
// func GoogleCallback(ctx *gin.Context) {
|
||||
// deps := ctx.MustGet("deps").(*domain.InjectedDependencies)
|
||||
//
|
||||
// var (
|
||||
// state string = ctx.Query("state")
|
||||
// code string = ctx.Query("code")
|
||||
// )
|
||||
//
|
||||
// if jwt, err := deps.AuthService.GoogleAuthSuccess(state, code); err != nil {
|
||||
// components.RenderErrorBanner(ctx, err.Error())
|
||||
// ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
// } else {
|
||||
// domain.SetCookie(ctx, "jwt_token", jwt, time.Hour*24*7)
|
||||
// ctx.Redirect(http.StatusSeeOther, "/")
|
||||
// }
|
||||
// }
|
||||
|
||||
// Logout removes the token from the user's browser. Effectively "logging them out." Routes that
|
||||
// require authentication will require the user to sign back in before accessing them again.
|
||||
// This route will direct the user back to the home page.
|
||||
func Logout(ctx *gin.Context) {
|
||||
domain.SetCookie(ctx, "jwt_token", "", -1)
|
||||
domain.SetCookie(ctx, "search-filters", "", -1)
|
||||
ctx.Redirect(http.StatusSeeOther, domain.WEB_HOME)
|
||||
}
|
||||
//
|
||||
// DEPRECATED: As of September 4th, 2025.
|
||||
// func Logout(ctx *gin.Context) {
|
||||
// domain.SetCookie(ctx, "jwt_token", "", -1)
|
||||
// domain.SetCookie(ctx, "search-filters", "", -1)
|
||||
// ctx.Redirect(http.StatusSeeOther, domain.WEB_HOME)
|
||||
// }
|
||||
|
||||
@ -1,148 +1,142 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
// DEPRECATED: As of September 4th, 2025.
|
||||
// func EngagementViewRecipe(ctx *gin.Context) {
|
||||
// deps := ctx.MustGet("deps").(*domain.InjectedDependencies)
|
||||
// recipeId, _ := strconv.Atoi(ctx.Param("id"))
|
||||
//
|
||||
// // Ensure user is logged in with a valid account
|
||||
// user := deps.UserService.GetAuthenicatedUser(ctx)
|
||||
// if user == nil {
|
||||
// // Log (stale) user out
|
||||
// domain.SetCookie(ctx, "jwt_token", "", -1)
|
||||
// domain.SetCookie(ctx, "search-filters", "", -1)
|
||||
// }
|
||||
//
|
||||
// if !domain.IsLoggedIn(ctx) || user == nil {
|
||||
// if _, err := deps.EngagementService.ViewRecipe(recipeId); err != nil {
|
||||
// components.RenderErrorBanner(ctx, err.Error())
|
||||
// ctx.JSON(http.StatusInternalServerError, gin.H{
|
||||
// "status": http.StatusInternalServerError,
|
||||
// "message": err.Error(),
|
||||
// })
|
||||
// } else {
|
||||
// ctx.Header("HX-Redirect", fmt.Sprintf(domain.WEB_RECIPE, recipeId))
|
||||
// ctx.Status(http.StatusOK)
|
||||
// }
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// // We caught nil already, we can assume the user exists
|
||||
// if _, err := deps.EngagementService.UserViewRecipe(user.Id, recipeId); err != nil {
|
||||
// components.RenderErrorBanner(ctx, err.Error())
|
||||
// ctx.JSON(http.StatusInternalServerError, gin.H{
|
||||
// "status": http.StatusInternalServerError,
|
||||
// "message": err.Error(),
|
||||
// })
|
||||
// } else {
|
||||
// ctx.Header("HX-Redirect", fmt.Sprintf(domain.WEB_RECIPE, recipeId))
|
||||
// ctx.Status(http.StatusOK)
|
||||
// }
|
||||
// }
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
domain "github.com/haydenhargreaves/Potion/internal/domain/server"
|
||||
"github.com/haydenhargreaves/Potion/internal/templates/components"
|
||||
)
|
||||
// DEPRECATED: As of September 4th, 2025.
|
||||
// func EngagementShareRecipe(ctx *gin.Context) {
|
||||
// deps := ctx.MustGet("deps").(*domain.InjectedDependencies)
|
||||
// recipeId, _ := strconv.Atoi(ctx.Param("id"))
|
||||
//
|
||||
// // Ensure user is logged in with a valid account
|
||||
// user := deps.UserService.GetAuthenicatedUser(ctx)
|
||||
// if user == nil {
|
||||
// // Log (stale) user out
|
||||
// domain.SetCookie(ctx, "jwt_token", "", -1)
|
||||
// domain.SetCookie(ctx, "search-filters", "", -1)
|
||||
// }
|
||||
//
|
||||
// if !domain.IsLoggedIn(ctx) || user == nil {
|
||||
// if _, err := deps.EngagementService.ShareRecipe(recipeId); err != nil {
|
||||
// components.RenderErrorBanner(ctx, err.Error())
|
||||
// ctx.JSON(http.StatusInternalServerError, gin.H{
|
||||
// "status": http.StatusInternalServerError,
|
||||
// "message": err.Error(),
|
||||
// })
|
||||
// } else {
|
||||
// ctx.Status(http.StatusNoContent)
|
||||
// }
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// if _, err := deps.EngagementService.UserShareRecipe(user.Id, recipeId); err != nil {
|
||||
// components.RenderErrorBanner(ctx, err.Error())
|
||||
// ctx.JSON(http.StatusInternalServerError, gin.H{
|
||||
// "status": http.StatusInternalServerError,
|
||||
// "message": err.Error(),
|
||||
// })
|
||||
// } else {
|
||||
// ctx.Status(http.StatusNoContent)
|
||||
// }
|
||||
// }
|
||||
|
||||
func EngagementViewRecipe(ctx *gin.Context) {
|
||||
deps := ctx.MustGet("deps").(*domain.InjectedDependencies)
|
||||
recipeId, _ := strconv.Atoi(ctx.Param("id"))
|
||||
// DEPRECATED: As of September 4th, 2025.
|
||||
// func EngagementFavoriteRecipe(ctx *gin.Context) {
|
||||
// deps := ctx.MustGet("deps").(*domain.InjectedDependencies)
|
||||
//
|
||||
// // Ensure user is logged in with a valid account
|
||||
// user := deps.UserService.GetAuthenicatedUser(ctx)
|
||||
// if user == nil {
|
||||
// // Log (stale) user out
|
||||
// domain.SetCookie(ctx, "jwt_token", "", -1)
|
||||
// domain.SetCookie(ctx, "search-filters", "", -1)
|
||||
// }
|
||||
//
|
||||
// if !domain.IsLoggedIn(ctx) || user == nil {
|
||||
// ctx.Header("HX-Redirect", domain.WEB_LOGIN)
|
||||
// ctx.Status(http.StatusOK)
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// id := ctx.Param("id")
|
||||
// recipeId, _ := strconv.Atoi(id)
|
||||
//
|
||||
// if _, err := deps.EngagementService.UserFavoriteRecipe(user.Id, recipeId); err != nil {
|
||||
// components.RenderErrorBanner(ctx, fmt.Sprintf("Something went wrong. %s.", err.Error()))
|
||||
// ctx.JSON(http.StatusInternalServerError, gin.H{
|
||||
// "status": http.StatusInternalServerError,
|
||||
// "message": err.Error(),
|
||||
// })
|
||||
// } else {
|
||||
// ctx.Status(http.StatusNoContent)
|
||||
// }
|
||||
// }
|
||||
|
||||
// Ensure user is logged in with a valid account
|
||||
user := deps.UserService.GetAuthenicatedUser(ctx)
|
||||
if user == nil {
|
||||
// Log (stale) user out
|
||||
domain.SetCookie(ctx, "jwt_token", "", -1)
|
||||
domain.SetCookie(ctx, "search-filters", "", -1)
|
||||
}
|
||||
|
||||
if !domain.IsLoggedIn(ctx) || user == nil {
|
||||
if _, err := deps.EngagementService.ViewRecipe(recipeId); err != nil {
|
||||
components.RenderErrorBanner(ctx, err.Error())
|
||||
ctx.JSON(http.StatusInternalServerError, gin.H{
|
||||
"status": http.StatusInternalServerError,
|
||||
"message": err.Error(),
|
||||
})
|
||||
} else {
|
||||
ctx.Header("HX-Redirect", fmt.Sprintf(domain.WEB_RECIPE, recipeId))
|
||||
ctx.Status(http.StatusOK)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// We caught nil already, we can assume the user exists
|
||||
if _, err := deps.EngagementService.UserViewRecipe(user.Id, recipeId); err != nil {
|
||||
components.RenderErrorBanner(ctx, err.Error())
|
||||
ctx.JSON(http.StatusInternalServerError, gin.H{
|
||||
"status": http.StatusInternalServerError,
|
||||
"message": err.Error(),
|
||||
})
|
||||
} else {
|
||||
ctx.Header("HX-Redirect", fmt.Sprintf(domain.WEB_RECIPE, recipeId))
|
||||
ctx.Status(http.StatusOK)
|
||||
}
|
||||
}
|
||||
|
||||
func EngagementShareRecipe(ctx *gin.Context) {
|
||||
deps := ctx.MustGet("deps").(*domain.InjectedDependencies)
|
||||
recipeId, _ := strconv.Atoi(ctx.Param("id"))
|
||||
|
||||
// Ensure user is logged in with a valid account
|
||||
user := deps.UserService.GetAuthenicatedUser(ctx)
|
||||
if user == nil {
|
||||
// Log (stale) user out
|
||||
domain.SetCookie(ctx, "jwt_token", "", -1)
|
||||
domain.SetCookie(ctx, "search-filters", "", -1)
|
||||
}
|
||||
|
||||
if !domain.IsLoggedIn(ctx) || user == nil {
|
||||
if _, err := deps.EngagementService.ShareRecipe(recipeId); err != nil {
|
||||
components.RenderErrorBanner(ctx, err.Error())
|
||||
ctx.JSON(http.StatusInternalServerError, gin.H{
|
||||
"status": http.StatusInternalServerError,
|
||||
"message": err.Error(),
|
||||
})
|
||||
} else {
|
||||
ctx.Status(http.StatusNoContent)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if _, err := deps.EngagementService.UserShareRecipe(user.Id, recipeId); err != nil {
|
||||
components.RenderErrorBanner(ctx, err.Error())
|
||||
ctx.JSON(http.StatusInternalServerError, gin.H{
|
||||
"status": http.StatusInternalServerError,
|
||||
"message": err.Error(),
|
||||
})
|
||||
} else {
|
||||
ctx.Status(http.StatusNoContent)
|
||||
}
|
||||
}
|
||||
|
||||
func EngagementFavoriteRecipe(ctx *gin.Context) {
|
||||
deps := ctx.MustGet("deps").(*domain.InjectedDependencies)
|
||||
|
||||
// Ensure user is logged in with a valid account
|
||||
user := deps.UserService.GetAuthenicatedUser(ctx)
|
||||
if user == nil {
|
||||
// Log (stale) user out
|
||||
domain.SetCookie(ctx, "jwt_token", "", -1)
|
||||
domain.SetCookie(ctx, "search-filters", "", -1)
|
||||
}
|
||||
|
||||
if !domain.IsLoggedIn(ctx) || user == nil {
|
||||
ctx.Header("HX-Redirect", domain.WEB_LOGIN)
|
||||
ctx.Status(http.StatusOK)
|
||||
return
|
||||
}
|
||||
|
||||
id := ctx.Param("id")
|
||||
recipeId, _ := strconv.Atoi(id)
|
||||
|
||||
if _, err := deps.EngagementService.UserFavoriteRecipe(user.Id, recipeId); err != nil {
|
||||
components.RenderErrorBanner(ctx, fmt.Sprintf("Something went wrong. %s.", err.Error()))
|
||||
ctx.JSON(http.StatusInternalServerError, gin.H{
|
||||
"status": http.StatusInternalServerError,
|
||||
"message": err.Error(),
|
||||
})
|
||||
} else {
|
||||
ctx.Status(http.StatusNoContent)
|
||||
}
|
||||
}
|
||||
|
||||
func EngagementMakeRecipe(ctx *gin.Context) {
|
||||
deps := ctx.MustGet("deps").(*domain.InjectedDependencies)
|
||||
|
||||
// Ensure user is logged in with a valid account
|
||||
user := deps.UserService.GetAuthenicatedUser(ctx)
|
||||
if user == nil {
|
||||
// Log (stale) user out
|
||||
domain.SetCookie(ctx, "jwt_token", "", -1)
|
||||
domain.SetCookie(ctx, "search-filters", "", -1)
|
||||
}
|
||||
|
||||
if !domain.IsLoggedIn(ctx) || user == nil {
|
||||
ctx.Header("HX-Redirect", domain.WEB_LOGIN)
|
||||
ctx.Status(http.StatusOK)
|
||||
return
|
||||
}
|
||||
|
||||
id := ctx.Param("id")
|
||||
recipeId, _ := strconv.Atoi(id)
|
||||
|
||||
if _, err := deps.EngagementService.UserMakeRecipe(user.Id, recipeId); err != nil {
|
||||
components.RenderErrorBanner(ctx, err.Error())
|
||||
ctx.JSON(http.StatusInternalServerError, gin.H{
|
||||
"status": http.StatusInternalServerError,
|
||||
"message": err.Error(),
|
||||
})
|
||||
} else {
|
||||
ctx.Status(http.StatusNoContent)
|
||||
}
|
||||
}
|
||||
// DEPRECATED: As of September 4th, 2025.
|
||||
// func EngagementMakeRecipe(ctx *gin.Context) {
|
||||
// deps := ctx.MustGet("deps").(*domain.InjectedDependencies)
|
||||
//
|
||||
// // Ensure user is logged in with a valid account
|
||||
// user := deps.UserService.GetAuthenicatedUser(ctx)
|
||||
// if user == nil {
|
||||
// // Log (stale) user out
|
||||
// domain.SetCookie(ctx, "jwt_token", "", -1)
|
||||
// domain.SetCookie(ctx, "search-filters", "", -1)
|
||||
// }
|
||||
//
|
||||
// if !domain.IsLoggedIn(ctx) || user == nil {
|
||||
// ctx.Header("HX-Redirect", domain.WEB_LOGIN)
|
||||
// ctx.Status(http.StatusOK)
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// id := ctx.Param("id")
|
||||
// recipeId, _ := strconv.Atoi(id)
|
||||
//
|
||||
// if _, err := deps.EngagementService.UserMakeRecipe(user.Id, recipeId); err != nil {
|
||||
// components.RenderErrorBanner(ctx, err.Error())
|
||||
// ctx.JSON(http.StatusInternalServerError, gin.H{
|
||||
// "status": http.StatusInternalServerError,
|
||||
// "message": err.Error(),
|
||||
// })
|
||||
// } else {
|
||||
// ctx.Status(http.StatusNoContent)
|
||||
// }
|
||||
// }
|
||||
|
||||
@ -1,306 +1,296 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
// DEPRECATED: As of September 4th, 2025.
|
||||
// func LoginPage(ctx *gin.Context) {
|
||||
// title := "Potion - Login"
|
||||
// page := pages.LoginPage()
|
||||
//
|
||||
// ctx.HTML(http.StatusOK, "", layouts.AppLayout(title, page))
|
||||
// }
|
||||
|
||||
"github.com/a-h/templ"
|
||||
"github.com/gin-gonic/gin"
|
||||
domainRecipe "github.com/haydenhargreaves/Potion/internal/domain/recipe"
|
||||
domain "github.com/haydenhargreaves/Potion/internal/domain/server"
|
||||
domainServer "github.com/haydenhargreaves/Potion/internal/domain/server"
|
||||
"github.com/haydenhargreaves/Potion/internal/templates/components"
|
||||
layouts "github.com/haydenhargreaves/Potion/internal/templates/layouts"
|
||||
pages "github.com/haydenhargreaves/Potion/internal/templates/pages"
|
||||
templates "github.com/haydenhargreaves/Potion/internal/templates/pages"
|
||||
)
|
||||
// DEPRECATED: As of September 4th, 2025.
|
||||
// func HomePage(ctx *gin.Context) {
|
||||
// deps := ctx.MustGet("deps").(*domainServer.InjectedDependencies)
|
||||
//
|
||||
// loggedIn := domain.IsLoggedIn(ctx)
|
||||
//
|
||||
// // Ensure user is logged in with a valid account
|
||||
// if user := deps.UserService.GetAuthenicatedUser(ctx); user == nil {
|
||||
// // Log (stale) user out
|
||||
// domain.SetCookie(ctx, "jwt_token", "", -1)
|
||||
// domain.SetCookie(ctx, "search-filters", "", -1)
|
||||
// loggedIn = false
|
||||
// }
|
||||
//
|
||||
// var page templ.Component
|
||||
// if loggedIn {
|
||||
// userId := ctx.MustGet("userId").(int)
|
||||
// madeRecipes, err := deps.RecipeService.GetUserMadeRecipes(userId, 6)
|
||||
// if err != nil {
|
||||
// components.RenderErrorBanner(ctx, fmt.Sprintf("Error getting made recipes. %s\n", err.Error()))
|
||||
// ctx.JSON(http.StatusInternalServerError, gin.H{
|
||||
// "status": http.StatusInternalServerError,
|
||||
// "message": fmt.Sprintf("Error getting made recipes. %s\n", err.Error()),
|
||||
// })
|
||||
// return
|
||||
// }
|
||||
// viewedRecipes, err := deps.RecipeService.GetUserViewedRecipes(userId, 6)
|
||||
// if err != nil {
|
||||
// components.RenderErrorBanner(ctx, fmt.Sprintf("Error getting viewed recipes. %s\n", err.Error()))
|
||||
// ctx.JSON(http.StatusInternalServerError, gin.H{
|
||||
// "status": http.StatusInternalServerError,
|
||||
// "message": fmt.Sprintf("Error getting viewed recipes. %s\n", err.Error()),
|
||||
// })
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// // Get the recipe of the week
|
||||
// recipeOfTheWeek, err := deps.RecipeService.GetRecipeOfTheWeek(&userId)
|
||||
// if err != nil {
|
||||
// components.RenderErrorBanner(ctx, fmt.Sprintf("Error getting recipe of the week. %s\n", err.Error()))
|
||||
// ctx.JSON(http.StatusInternalServerError, gin.H{
|
||||
// "status": http.StatusInternalServerError,
|
||||
// "message": fmt.Sprintf("Error getting recipe of the week. %s\n", err.Error()),
|
||||
// })
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// if bytes, err := ctx.Cookie("search-filters"); err != nil {
|
||||
// fmt.Printf("ERROR: Failed to get search-filter cookie. %s\n", err.Error())
|
||||
// page = templates.HomePage(true, viewedRecipes, madeRecipes, recipeOfTheWeek, nil)
|
||||
// } else {
|
||||
// var filters domainRecipe.SearchFilters
|
||||
// if err := json.Unmarshal([]byte(bytes), &filters); err != nil {
|
||||
// fmt.Printf("ERROR: Failed to unmarshal search-filter cookie. %s\n", err.Error())
|
||||
// page = templates.HomePage(true, viewedRecipes, madeRecipes, recipeOfTheWeek, nil)
|
||||
// } else {
|
||||
// page = templates.HomePage(true, viewedRecipes, madeRecipes, recipeOfTheWeek, &filters)
|
||||
// }
|
||||
// }
|
||||
// } else {
|
||||
// // Get the recipe of the week
|
||||
// recipeOfTheWeek, err := deps.RecipeService.GetRecipeOfTheWeek(nil)
|
||||
// if err != nil {
|
||||
// components.RenderErrorBanner(ctx, fmt.Sprintf("Error getting recipe of the week. %s\n", err.Error()))
|
||||
// ctx.JSON(http.StatusInternalServerError, gin.H{
|
||||
// "status": http.StatusInternalServerError,
|
||||
// "message": fmt.Sprintf("Error getting recipe of the week. %s\n", err.Error()),
|
||||
// })
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// if bytes, err := ctx.Cookie("search-filters"); err != nil {
|
||||
// fmt.Printf("ERROR: Failed to get search-filter cookie. %s\n", err.Error())
|
||||
// page = templates.HomePage(false, nil, nil, recipeOfTheWeek, nil)
|
||||
// } else {
|
||||
// var filters domainRecipe.SearchFilters
|
||||
// if err := json.Unmarshal([]byte(bytes), &filters); err != nil {
|
||||
// fmt.Printf("ERROR: Failed to unmarshal search-filter cookie. %s\n", err.Error())
|
||||
// page = templates.HomePage(false, nil, nil, recipeOfTheWeek, nil)
|
||||
// } else {
|
||||
// page = templates.HomePage(false, nil, nil, recipeOfTheWeek, &filters)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// title := "Potion - Home"
|
||||
//
|
||||
// ctx.HTML(http.StatusOK, "", layouts.AppLayout(title, page))
|
||||
// }
|
||||
|
||||
func LoginPage(ctx *gin.Context) {
|
||||
title := "Potion - Login"
|
||||
page := pages.LoginPage()
|
||||
// DEPRECATED: As of September 4th, 2025.
|
||||
// func FavoritesPage(ctx *gin.Context) {
|
||||
// // If not logged in, direct to the login page
|
||||
// if !domainServer.IsLoggedIn(ctx) {
|
||||
// ctx.Redirect(http.StatusSeeOther, domainServer.WEB_LOGIN)
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// title := "Potion - Favorites"
|
||||
// var page templ.Component
|
||||
//
|
||||
// // Get filters from cookies
|
||||
// if bytes, err := ctx.Cookie("search-filters"); err != nil {
|
||||
// fmt.Printf("ERROR: Failed to get search-filter cookie. %s\n", err.Error())
|
||||
// page = pages.FavoritesPage(nil)
|
||||
// } else {
|
||||
// var filters domainRecipe.SearchFilters
|
||||
// if err := json.Unmarshal([]byte(bytes), &filters); err != nil {
|
||||
// fmt.Printf("ERROR: Failed to unmarshal search-filter cookie. %s\n", err.Error())
|
||||
// page = pages.FavoritesPage(nil)
|
||||
// } else {
|
||||
// page = pages.FavoritesPage(&filters)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// ctx.HTML(http.StatusOK, "", layouts.AppLayout(title, page))
|
||||
// }
|
||||
//
|
||||
// func CreatePage(ctx *gin.Context) {
|
||||
// deps := ctx.MustGet("deps").(*domainServer.InjectedDependencies)
|
||||
//
|
||||
// // If not logged in, direct to the login page
|
||||
// if !domainServer.IsLoggedIn(ctx) {
|
||||
// ctx.Redirect(http.StatusSeeOther, domainServer.WEB_LOGIN)
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// // Ensure user is logged in with a valid account
|
||||
// if user := deps.UserService.GetAuthenicatedUser(ctx); user == nil {
|
||||
// // Log (stale) user out
|
||||
// domain.SetCookie(ctx, "jwt_token", "", -1)
|
||||
// domain.SetCookie(ctx, "search-filters", "", -1)
|
||||
//
|
||||
// ctx.Redirect(http.StatusSeeOther, domainServer.WEB_LOGIN)
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// title := "Potion - Create"
|
||||
// page := pages.CreatePage()
|
||||
//
|
||||
// ctx.HTML(http.StatusOK, "", layouts.AppLayout(title, page))
|
||||
// }
|
||||
|
||||
ctx.HTML(http.StatusOK, "", layouts.AppLayout(title, page))
|
||||
}
|
||||
// DEPRECATED: As of September 4th, 2025.
|
||||
// func ProfilePage(ctx *gin.Context) {
|
||||
// // If not logged in, direct to the login page
|
||||
// if !domainServer.IsLoggedIn(ctx) {
|
||||
// ctx.Redirect(http.StatusSeeOther, domainServer.WEB_LOGIN)
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// // Else, get the user data
|
||||
// deps := ctx.MustGet("deps").(*domainServer.InjectedDependencies)
|
||||
// user := deps.UserService.GetAuthenicatedUser(ctx)
|
||||
// if user == nil {
|
||||
// // User is failing to be found, direct to the login page
|
||||
// ctx.Redirect(http.StatusSeeOther, domainServer.WEB_LOGIN)
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// recipes, err := deps.RecipeService.GetUserRecipes(user.Id)
|
||||
// if err != nil {
|
||||
// components.RenderErrorBanner(ctx, fmt.Sprintf("Error getting recipes. %s\n", err.Error()))
|
||||
// ctx.JSON(http.StatusInternalServerError, gin.H{
|
||||
// "status": http.StatusInternalServerError,
|
||||
// "message": fmt.Sprintf("Error getting recipes. %s\n", err.Error()),
|
||||
// })
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// favorites, err := deps.RecipeService.GetUserFavoriteRecipes(user.Id)
|
||||
// if err != nil {
|
||||
// components.RenderErrorBanner(ctx, fmt.Sprintf("Error getting favorite recipes. %s\n", err.Error()))
|
||||
// ctx.JSON(http.StatusInternalServerError, gin.H{
|
||||
// "status": http.StatusInternalServerError,
|
||||
// "message": fmt.Sprintf("Error getting favorite recipes. %s\n", err.Error()),
|
||||
// })
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// // Get the engagement data, not sure what will happen when errors occur
|
||||
// engagements, err := deps.EngagementService.GetUserEngagement(user.Id, 6)
|
||||
// if err != nil {
|
||||
// components.RenderErrorBanner(ctx, fmt.Sprintf("Error getting user engagements. %s\n", err.Error()))
|
||||
// ctx.JSON(http.StatusInternalServerError, gin.H{
|
||||
// "status": http.StatusInternalServerError,
|
||||
// "message": fmt.Sprintf("Error getting user engagements. %s\n", err.Error()),
|
||||
// })
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// title := "Potion - Profile"
|
||||
// page := pages.ProfilePage(*user, recipes, favorites, engagements)
|
||||
//
|
||||
// ctx.HTML(http.StatusOK, "", layouts.AppLayout(title, page))
|
||||
// }
|
||||
|
||||
func HomePage(ctx *gin.Context) {
|
||||
deps := ctx.MustGet("deps").(*domainServer.InjectedDependencies)
|
||||
// DEPRECATED: As of September 4th, 2025.
|
||||
// func ListPage(ctx *gin.Context) {
|
||||
// title := "Potion - Shopping List"
|
||||
// page := pages.ListPage()
|
||||
//
|
||||
// ctx.HTML(http.StatusOK, "", layouts.AppLayout(title, page))
|
||||
// }
|
||||
|
||||
loggedIn := domain.IsLoggedIn(ctx)
|
||||
// DEPRECATED: As of September 4th, 2025.
|
||||
// func RecipePage(ctx *gin.Context) {
|
||||
// // Call recipe service to get via ID
|
||||
// deps := ctx.MustGet("deps").(*domainServer.InjectedDependencies)
|
||||
// id := ctx.Param("id")
|
||||
//
|
||||
// // Parse ID
|
||||
// parsed, err := strconv.Atoi(id)
|
||||
// if err != nil {
|
||||
// components.RenderErrorBanner(ctx, fmt.Sprintf("ERROR: %s", err.Error()))
|
||||
// ctx.JSON(400, err.Error())
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// // Get signed in user, if they exist
|
||||
// var userId *int = nil
|
||||
// var loggedIn = domainServer.IsLoggedIn(ctx)
|
||||
//
|
||||
// // Ensure user is logged in with a valid account
|
||||
// if user := deps.UserService.GetAuthenicatedUser(ctx); user == nil {
|
||||
// // Log (stale) user out
|
||||
// domain.SetCookie(ctx, "jwt_token", "", -1)
|
||||
// domain.SetCookie(ctx, "search-filters", "", -1)
|
||||
// loggedIn = false
|
||||
// }
|
||||
//
|
||||
// if loggedIn {
|
||||
// storeId := ctx.MustGet("userId").(int)
|
||||
// userId = &storeId
|
||||
// }
|
||||
//
|
||||
// // Get recipe
|
||||
// recipe, err := deps.RecipeService.GetRecipe(parsed, userId)
|
||||
// if err != nil {
|
||||
// components.RenderErrorBanner(ctx, fmt.Sprintf("ERROR: %s", err.Error()))
|
||||
// ctx.JSON(400, err.Error())
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// // Get user (owner)
|
||||
// user, err := deps.UserService.GetUser(recipe.UserId)
|
||||
// if err != nil {
|
||||
// components.RenderErrorBanner(ctx, fmt.Sprintf("ERROR: %s", err.Error()))
|
||||
// ctx.JSON(400, err.Error())
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// title := "Potion - View Recipe"
|
||||
// page := pages.RecipePage(*recipe, *user, loggedIn, deps.EnvironmentConfig.Domain)
|
||||
//
|
||||
// ctx.HTML(http.StatusOK, "", layouts.AppLayout(title, page))
|
||||
// }
|
||||
//
|
||||
// func SearchPage(ctx *gin.Context) {
|
||||
// var page templ.Component
|
||||
// // Get filters from cookies
|
||||
// if bytes, err := ctx.Cookie("search-filters"); err != nil {
|
||||
// fmt.Printf("ERROR: Failed to get search-filter cookie. %s\n", err.Error())
|
||||
// page = pages.SearchPage(nil, false)
|
||||
// } else {
|
||||
// var filters domainRecipe.SearchFilters
|
||||
// if err := json.Unmarshal([]byte(bytes), &filters); err != nil {
|
||||
// fmt.Printf("ERROR: Failed to unmarshal search-filter cookie. %s\n", err.Error())
|
||||
// page = pages.SearchPage(nil, false)
|
||||
// } else {
|
||||
// page = pages.SearchPage(&filters, true)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// title := "Potion - Recipe Search"
|
||||
//
|
||||
// ctx.HTML(http.StatusOK, "", layouts.AppLayout(title, page))
|
||||
// }
|
||||
|
||||
// Ensure user is logged in with a valid account
|
||||
if user := deps.UserService.GetAuthenicatedUser(ctx); user == nil {
|
||||
// Log (stale) user out
|
||||
domain.SetCookie(ctx, "jwt_token", "", -1)
|
||||
domain.SetCookie(ctx, "search-filters", "", -1)
|
||||
loggedIn = false
|
||||
}
|
||||
|
||||
var page templ.Component
|
||||
if loggedIn {
|
||||
userId := ctx.MustGet("userId").(int)
|
||||
madeRecipes, err := deps.RecipeService.GetUserMadeRecipes(userId, 6)
|
||||
if err != nil {
|
||||
components.RenderErrorBanner(ctx, fmt.Sprintf("Error getting made recipes. %s\n", err.Error()))
|
||||
ctx.JSON(http.StatusInternalServerError, gin.H{
|
||||
"status": http.StatusInternalServerError,
|
||||
"message": fmt.Sprintf("Error getting made recipes. %s\n", err.Error()),
|
||||
})
|
||||
return
|
||||
}
|
||||
viewedRecipes, err := deps.RecipeService.GetUserViewedRecipes(userId, 6)
|
||||
if err != nil {
|
||||
components.RenderErrorBanner(ctx, fmt.Sprintf("Error getting viewed recipes. %s\n", err.Error()))
|
||||
ctx.JSON(http.StatusInternalServerError, gin.H{
|
||||
"status": http.StatusInternalServerError,
|
||||
"message": fmt.Sprintf("Error getting viewed recipes. %s\n", err.Error()),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// Get the recipe of the week
|
||||
recipeOfTheWeek, err := deps.RecipeService.GetRecipeOfTheWeek(&userId)
|
||||
if err != nil {
|
||||
components.RenderErrorBanner(ctx, fmt.Sprintf("Error getting recipe of the week. %s\n", err.Error()))
|
||||
ctx.JSON(http.StatusInternalServerError, gin.H{
|
||||
"status": http.StatusInternalServerError,
|
||||
"message": fmt.Sprintf("Error getting recipe of the week. %s\n", err.Error()),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if bytes, err := ctx.Cookie("search-filters"); err != nil {
|
||||
fmt.Printf("ERROR: Failed to get search-filter cookie. %s\n", err.Error())
|
||||
page = templates.HomePage(true, viewedRecipes, madeRecipes, recipeOfTheWeek, nil)
|
||||
} else {
|
||||
var filters domainRecipe.SearchFilters
|
||||
if err := json.Unmarshal([]byte(bytes), &filters); err != nil {
|
||||
fmt.Printf("ERROR: Failed to unmarshal search-filter cookie. %s\n", err.Error())
|
||||
page = templates.HomePage(true, viewedRecipes, madeRecipes, recipeOfTheWeek, nil)
|
||||
} else {
|
||||
page = templates.HomePage(true, viewedRecipes, madeRecipes, recipeOfTheWeek, &filters)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Get the recipe of the week
|
||||
recipeOfTheWeek, err := deps.RecipeService.GetRecipeOfTheWeek(nil)
|
||||
if err != nil {
|
||||
components.RenderErrorBanner(ctx, fmt.Sprintf("Error getting recipe of the week. %s\n", err.Error()))
|
||||
ctx.JSON(http.StatusInternalServerError, gin.H{
|
||||
"status": http.StatusInternalServerError,
|
||||
"message": fmt.Sprintf("Error getting recipe of the week. %s\n", err.Error()),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if bytes, err := ctx.Cookie("search-filters"); err != nil {
|
||||
fmt.Printf("ERROR: Failed to get search-filter cookie. %s\n", err.Error())
|
||||
page = templates.HomePage(false, nil, nil, recipeOfTheWeek, nil)
|
||||
} else {
|
||||
var filters domainRecipe.SearchFilters
|
||||
if err := json.Unmarshal([]byte(bytes), &filters); err != nil {
|
||||
fmt.Printf("ERROR: Failed to unmarshal search-filter cookie. %s\n", err.Error())
|
||||
page = templates.HomePage(false, nil, nil, recipeOfTheWeek, nil)
|
||||
} else {
|
||||
page = templates.HomePage(false, nil, nil, recipeOfTheWeek, &filters)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
title := "Potion - Home"
|
||||
|
||||
ctx.HTML(http.StatusOK, "", layouts.AppLayout(title, page))
|
||||
}
|
||||
|
||||
func FavoritesPage(ctx *gin.Context) {
|
||||
// If not logged in, direct to the login page
|
||||
if !domainServer.IsLoggedIn(ctx) {
|
||||
ctx.Redirect(http.StatusSeeOther, domainServer.WEB_LOGIN)
|
||||
return
|
||||
}
|
||||
|
||||
title := "Potion - Favorites"
|
||||
var page templ.Component
|
||||
|
||||
// Get filters from cookies
|
||||
if bytes, err := ctx.Cookie("search-filters"); err != nil {
|
||||
fmt.Printf("ERROR: Failed to get search-filter cookie. %s\n", err.Error())
|
||||
page = pages.FavoritesPage(nil)
|
||||
} else {
|
||||
var filters domainRecipe.SearchFilters
|
||||
if err := json.Unmarshal([]byte(bytes), &filters); err != nil {
|
||||
fmt.Printf("ERROR: Failed to unmarshal search-filter cookie. %s\n", err.Error())
|
||||
page = pages.FavoritesPage(nil)
|
||||
} else {
|
||||
page = pages.FavoritesPage(&filters)
|
||||
}
|
||||
}
|
||||
|
||||
ctx.HTML(http.StatusOK, "", layouts.AppLayout(title, page))
|
||||
}
|
||||
|
||||
func CreatePage(ctx *gin.Context) {
|
||||
deps := ctx.MustGet("deps").(*domainServer.InjectedDependencies)
|
||||
|
||||
// If not logged in, direct to the login page
|
||||
if !domainServer.IsLoggedIn(ctx) {
|
||||
ctx.Redirect(http.StatusSeeOther, domainServer.WEB_LOGIN)
|
||||
return
|
||||
}
|
||||
|
||||
// Ensure user is logged in with a valid account
|
||||
if user := deps.UserService.GetAuthenicatedUser(ctx); user == nil {
|
||||
// Log (stale) user out
|
||||
domain.SetCookie(ctx, "jwt_token", "", -1)
|
||||
domain.SetCookie(ctx, "search-filters", "", -1)
|
||||
|
||||
ctx.Redirect(http.StatusSeeOther, domainServer.WEB_LOGIN)
|
||||
return
|
||||
}
|
||||
|
||||
title := "Potion - Create"
|
||||
page := pages.CreatePage()
|
||||
|
||||
ctx.HTML(http.StatusOK, "", layouts.AppLayout(title, page))
|
||||
}
|
||||
|
||||
func ProfilePage(ctx *gin.Context) {
|
||||
// If not logged in, direct to the login page
|
||||
if !domainServer.IsLoggedIn(ctx) {
|
||||
ctx.Redirect(http.StatusSeeOther, domainServer.WEB_LOGIN)
|
||||
return
|
||||
}
|
||||
|
||||
// Else, get the user data
|
||||
deps := ctx.MustGet("deps").(*domainServer.InjectedDependencies)
|
||||
user := deps.UserService.GetAuthenicatedUser(ctx)
|
||||
if user == nil {
|
||||
// User is failing to be found, direct to the login page
|
||||
ctx.Redirect(http.StatusSeeOther, domainServer.WEB_LOGIN)
|
||||
return
|
||||
}
|
||||
|
||||
recipes, err := deps.RecipeService.GetUserRecipes(user.Id)
|
||||
if err != nil {
|
||||
components.RenderErrorBanner(ctx, fmt.Sprintf("Error getting recipes. %s\n", err.Error()))
|
||||
ctx.JSON(http.StatusInternalServerError, gin.H{
|
||||
"status": http.StatusInternalServerError,
|
||||
"message": fmt.Sprintf("Error getting recipes. %s\n", err.Error()),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
favorites, err := deps.RecipeService.GetUserFavoriteRecipes(user.Id)
|
||||
if err != nil {
|
||||
components.RenderErrorBanner(ctx, fmt.Sprintf("Error getting favorite recipes. %s\n", err.Error()))
|
||||
ctx.JSON(http.StatusInternalServerError, gin.H{
|
||||
"status": http.StatusInternalServerError,
|
||||
"message": fmt.Sprintf("Error getting favorite recipes. %s\n", err.Error()),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// Get the engagement data, not sure what will happen when errors occur
|
||||
engagements, err := deps.EngagementService.GetUserEngagement(user.Id, 6)
|
||||
if err != nil {
|
||||
components.RenderErrorBanner(ctx, fmt.Sprintf("Error getting user engagements. %s\n", err.Error()))
|
||||
ctx.JSON(http.StatusInternalServerError, gin.H{
|
||||
"status": http.StatusInternalServerError,
|
||||
"message": fmt.Sprintf("Error getting user engagements. %s\n", err.Error()),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
title := "Potion - Profile"
|
||||
page := pages.ProfilePage(*user, recipes, favorites, engagements)
|
||||
|
||||
ctx.HTML(http.StatusOK, "", layouts.AppLayout(title, page))
|
||||
}
|
||||
|
||||
func ListPage(ctx *gin.Context) {
|
||||
title := "Potion - Shopping List"
|
||||
page := pages.ListPage()
|
||||
|
||||
ctx.HTML(http.StatusOK, "", layouts.AppLayout(title, page))
|
||||
}
|
||||
|
||||
func RecipePage(ctx *gin.Context) {
|
||||
// Call recipe service to get via ID
|
||||
deps := ctx.MustGet("deps").(*domainServer.InjectedDependencies)
|
||||
id := ctx.Param("id")
|
||||
|
||||
// Parse ID
|
||||
parsed, err := strconv.Atoi(id)
|
||||
if err != nil {
|
||||
components.RenderErrorBanner(ctx, fmt.Sprintf("ERROR: %s", err.Error()))
|
||||
ctx.JSON(400, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// Get signed in user, if they exist
|
||||
var userId *int = nil
|
||||
var loggedIn = domainServer.IsLoggedIn(ctx)
|
||||
|
||||
// Ensure user is logged in with a valid account
|
||||
if user := deps.UserService.GetAuthenicatedUser(ctx); user == nil {
|
||||
// Log (stale) user out
|
||||
domain.SetCookie(ctx, "jwt_token", "", -1)
|
||||
domain.SetCookie(ctx, "search-filters", "", -1)
|
||||
loggedIn = false
|
||||
}
|
||||
|
||||
if loggedIn {
|
||||
storeId := ctx.MustGet("userId").(int)
|
||||
userId = &storeId
|
||||
}
|
||||
|
||||
// Get recipe
|
||||
recipe, err := deps.RecipeService.GetRecipe(parsed, userId)
|
||||
if err != nil {
|
||||
components.RenderErrorBanner(ctx, fmt.Sprintf("ERROR: %s", err.Error()))
|
||||
ctx.JSON(400, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// Get user (owner)
|
||||
user, err := deps.UserService.GetUser(recipe.UserId)
|
||||
if err != nil {
|
||||
components.RenderErrorBanner(ctx, fmt.Sprintf("ERROR: %s", err.Error()))
|
||||
ctx.JSON(400, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
title := "Potion - View Recipe"
|
||||
page := pages.RecipePage(*recipe, *user, loggedIn, deps.EnvironmentConfig.Domain)
|
||||
|
||||
ctx.HTML(http.StatusOK, "", layouts.AppLayout(title, page))
|
||||
}
|
||||
|
||||
func SearchPage(ctx *gin.Context) {
|
||||
var page templ.Component
|
||||
// Get filters from cookies
|
||||
if bytes, err := ctx.Cookie("search-filters"); err != nil {
|
||||
fmt.Printf("ERROR: Failed to get search-filter cookie. %s\n", err.Error())
|
||||
page = pages.SearchPage(nil, false)
|
||||
} else {
|
||||
var filters domainRecipe.SearchFilters
|
||||
if err := json.Unmarshal([]byte(bytes), &filters); err != nil {
|
||||
fmt.Printf("ERROR: Failed to unmarshal search-filter cookie. %s\n", err.Error())
|
||||
page = pages.SearchPage(nil, false)
|
||||
} else {
|
||||
page = pages.SearchPage(&filters, true)
|
||||
}
|
||||
}
|
||||
|
||||
title := "Potion - Recipe Search"
|
||||
|
||||
ctx.HTML(http.StatusOK, "", layouts.AppLayout(title, page))
|
||||
}
|
||||
|
||||
func NotFoundPage(ctx *gin.Context) {
|
||||
title := "Potion - Not Found"
|
||||
page := pages.NotFoundPage()
|
||||
|
||||
ctx.HTML(http.StatusOK, "", layouts.AppLayout(title, page))
|
||||
}
|
||||
// DEPRECATED: As of September 4th, 2025.
|
||||
// func NotFoundPage(ctx *gin.Context) {
|
||||
// title := "Potion - Not Found"
|
||||
// page := pages.NotFoundPage()
|
||||
//
|
||||
// ctx.HTML(http.StatusOK, "", layouts.AppLayout(title, page))
|
||||
// }
|
||||
|
||||
@ -1,147 +1,136 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
// DEPRECATED: As of September 4th, 2025.
|
||||
// const CREATE_ERROR_HTML = `
|
||||
// <p id="response" class="text-sm text-red-500 px-4 py-1 bg-red-100 rounded-full w-fit">
|
||||
// Uh oh! Something went wrong when creating your recipe. Please try again. %s
|
||||
// </p>
|
||||
// `
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
domainRecipe "github.com/haydenhargreaves/Potion/internal/domain/recipe"
|
||||
domain "github.com/haydenhargreaves/Potion/internal/domain/server"
|
||||
"github.com/haydenhargreaves/Potion/internal/templates/components"
|
||||
templates "github.com/haydenhargreaves/Potion/internal/templates/pages"
|
||||
)
|
||||
|
||||
const CREATE_ERROR_HTML = `
|
||||
<p id="response" class="text-sm text-red-500 px-4 py-1 bg-red-100 rounded-full w-fit">
|
||||
Uh oh! Something went wrong when creating your recipe. Please try again. %s
|
||||
</p>
|
||||
`
|
||||
|
||||
func CreateRecipe(ctx *gin.Context) {
|
||||
deps := ctx.MustGet("deps").(*domain.InjectedDependencies)
|
||||
|
||||
recipe, err := deps.RecipeService.CreateRecipe(ctx)
|
||||
if err != nil {
|
||||
components.RenderErrorBanner(ctx, err.Error())
|
||||
ctx.String(http.StatusOK, CREATE_ERROR_HTML, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// Send HTMX redirection
|
||||
url := fmt.Sprintf(domain.WEB_RECIPE, recipe.Id)
|
||||
ctx.Header("HX-Redirect", url)
|
||||
ctx.Status(http.StatusCreated)
|
||||
}
|
||||
// DEPRECATED: As of September 4th, 2025.
|
||||
// func CreateRecipe(ctx *gin.Context) {
|
||||
// deps := ctx.MustGet("deps").(*domain.InjectedDependencies)
|
||||
//
|
||||
// recipe, err := deps.RecipeService.CreateRecipe(ctx)
|
||||
// if err != nil {
|
||||
// components.RenderErrorBanner(ctx, err.Error())
|
||||
// ctx.String(http.StatusOK, CREATE_ERROR_HTML, err.Error())
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// // Send HTMX redirection
|
||||
// url := fmt.Sprintf(domain.WEB_RECIPE, recipe.Id)
|
||||
// ctx.Header("HX-Redirect", url)
|
||||
// ctx.Status(http.StatusCreated)
|
||||
// }
|
||||
|
||||
// toBits converts an array of stringified numbers into a single summed value
|
||||
func toBits(arr []string) (bits int) {
|
||||
for _, x := range arr {
|
||||
num, _ := strconv.Atoi(x)
|
||||
bits += num
|
||||
}
|
||||
return
|
||||
}
|
||||
//
|
||||
// DEPRECATED: As of September 4th, 2025.
|
||||
// func toBits(arr []string) (bits int) {
|
||||
// for _, x := range arr {
|
||||
// num, _ := strconv.Atoi(x)
|
||||
// bits += num
|
||||
// }
|
||||
// return
|
||||
// }
|
||||
|
||||
// TODO: I don't love doing all of this here, but it seems to be the only way to get it to work...
|
||||
func SearchRecipes(ctx *gin.Context) {
|
||||
deps := ctx.MustGet("deps").(*domain.InjectedDependencies)
|
||||
// DEPRECATED: As of September 4th, 2025.
|
||||
// func SearchRecipes(ctx *gin.Context) {
|
||||
// deps := ctx.MustGet("deps").(*domain.InjectedDependencies)
|
||||
//
|
||||
// // create filters
|
||||
// filters := domainRecipe.SearchFilters{
|
||||
// Search: ctx.PostForm("search"), // string, search query for titles
|
||||
// MealType: toBits(ctx.PostFormArray("meal")),
|
||||
// Time: toBits(ctx.PostFormArray("time")),
|
||||
// Difficulty: toBits(ctx.PostFormArray("difficulty")),
|
||||
// ServingSize: toBits(ctx.PostFormArray("serving")),
|
||||
// }
|
||||
//
|
||||
// // Set the filters into the cookies, so they can be reloaded
|
||||
// if bytes, err := json.Marshal(filters); err == nil {
|
||||
// domain.SetCookie(ctx, "search-filters", string(bytes), time.Hour*24)
|
||||
// // ctx.SetCookie(
|
||||
// // "search-filters",
|
||||
// // string(bytes),
|
||||
// // int(time.Now().Add(24*time.Hour).Sub(time.Now()).Seconds()),
|
||||
// // "/",
|
||||
// // true,
|
||||
// // )
|
||||
// }
|
||||
//
|
||||
// redirect := ctx.PostForm("redirect")
|
||||
// if redirect == "true" {
|
||||
// ctx.Header("HX-Redirect", domain.WEB_SEARCH)
|
||||
// ctx.Status(http.StatusOK)
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// // Get user if logged in, so we can get favorite status
|
||||
// var userId *int = nil
|
||||
// if domain.IsLoggedIn(ctx) {
|
||||
// id := ctx.MustGet("userId").(int)
|
||||
// userId = &id
|
||||
// }
|
||||
//
|
||||
// // TODO: Not sure if we need to ensure the user is valid here
|
||||
//
|
||||
// // We don't care about favorite status, so use false
|
||||
// recipes, err := deps.RecipeService.SearchRecipes(filters, userId, false)
|
||||
// if err != nil {
|
||||
// components.RenderErrorBanner(ctx, err.Error())
|
||||
// ctx.JSON(http.StatusOK, gin.H{"error": err.Error()})
|
||||
// }
|
||||
//
|
||||
// // Render content as the response
|
||||
// ctx.Status(200)
|
||||
// templates.ResultList(recipes).Render(ctx.Request.Context(), ctx.Writer)
|
||||
// }
|
||||
|
||||
// create filters
|
||||
filters := domainRecipe.SearchFilters{
|
||||
Search: ctx.PostForm("search"), // string, search query for titles
|
||||
MealType: toBits(ctx.PostFormArray("meal")),
|
||||
Time: toBits(ctx.PostFormArray("time")),
|
||||
Difficulty: toBits(ctx.PostFormArray("difficulty")),
|
||||
ServingSize: toBits(ctx.PostFormArray("serving")),
|
||||
}
|
||||
|
||||
// Set the filters into the cookies, so they can be reloaded
|
||||
if bytes, err := json.Marshal(filters); err == nil {
|
||||
domain.SetCookie(ctx, "search-filters", string(bytes), time.Hour*24)
|
||||
// ctx.SetCookie(
|
||||
// "search-filters",
|
||||
// string(bytes),
|
||||
// int(time.Now().Add(24*time.Hour).Sub(time.Now()).Seconds()),
|
||||
// "/",
|
||||
// "", // TODO: Need an actual domain
|
||||
// false, // TODO: True in prod
|
||||
// true,
|
||||
// )
|
||||
}
|
||||
|
||||
redirect := ctx.PostForm("redirect")
|
||||
if redirect == "true" {
|
||||
ctx.Header("HX-Redirect", domain.WEB_SEARCH)
|
||||
ctx.Status(http.StatusOK)
|
||||
return
|
||||
}
|
||||
|
||||
// Get user if logged in, so we can get favorite status
|
||||
var userId *int = nil
|
||||
if domain.IsLoggedIn(ctx) {
|
||||
id := ctx.MustGet("userId").(int)
|
||||
userId = &id
|
||||
}
|
||||
|
||||
// TODO: Not sure if we need to ensure the user is valid here
|
||||
|
||||
// We don't care about favorite status, so use false
|
||||
recipes, err := deps.RecipeService.SearchRecipes(filters, userId, false)
|
||||
if err != nil {
|
||||
components.RenderErrorBanner(ctx, err.Error())
|
||||
ctx.JSON(http.StatusOK, gin.H{"error": err.Error()})
|
||||
}
|
||||
|
||||
// Render content as the response
|
||||
ctx.Status(200)
|
||||
templates.ResultList(recipes).Render(ctx.Request.Context(), ctx.Writer)
|
||||
}
|
||||
|
||||
func SearchRecipesFavorites(ctx *gin.Context) {
|
||||
deps := ctx.MustGet("deps").(*domain.InjectedDependencies)
|
||||
|
||||
// create filters
|
||||
filters := domainRecipe.SearchFilters{
|
||||
Search: ctx.PostForm("search"), // string, search query for titles
|
||||
MealType: toBits(ctx.PostFormArray("meal")),
|
||||
Time: toBits(ctx.PostFormArray("time")),
|
||||
Difficulty: toBits(ctx.PostFormArray("difficulty")),
|
||||
ServingSize: toBits(ctx.PostFormArray("serving")),
|
||||
}
|
||||
|
||||
// Set the filters into the cookies, so they can be reloaded
|
||||
if bytes, err := json.Marshal(filters); err == nil {
|
||||
domain.SetCookie(ctx, "search-filters", string(bytes), time.Hour*24)
|
||||
// ctx.SetCookie(
|
||||
// "search-filters",
|
||||
// string(bytes),
|
||||
// int(time.Now().Add(24*time.Hour).Sub(time.Now()).Seconds()),
|
||||
// "/",
|
||||
// "", // TODO: Need an actual domain
|
||||
// false, // TODO: True in prod
|
||||
// true,
|
||||
// )
|
||||
}
|
||||
|
||||
// TODO: Error here if they're not logged in?
|
||||
// Get user data (they should be logged in)
|
||||
if !domain.IsLoggedIn(ctx) {
|
||||
components.RenderErrorBanner(ctx, "User is not logged in. User will be nil.")
|
||||
ctx.JSON(http.StatusOK, gin.H{"error": "User is not logged in. User will be nil."})
|
||||
}
|
||||
|
||||
userId := ctx.MustGet("userId").(int)
|
||||
|
||||
recipes, err := deps.RecipeService.SearchRecipes(filters, &userId, true)
|
||||
if err != nil {
|
||||
components.RenderErrorBanner(ctx, err.Error())
|
||||
ctx.JSON(http.StatusOK, gin.H{"error": err.Error()})
|
||||
}
|
||||
|
||||
// Render content as the response
|
||||
ctx.Status(200)
|
||||
templates.FavoriteList(recipes).Render(ctx.Request.Context(), ctx.Writer)
|
||||
}
|
||||
// DEPRECATED: As of September 4th, 2025.
|
||||
// func SearchRecipesFavorites(ctx *gin.Context) {
|
||||
// deps := ctx.MustGet("deps").(*domain.InjectedDependencies)
|
||||
//
|
||||
// // create filters
|
||||
// filters := domainRecipe.SearchFilters{
|
||||
// Search: ctx.PostForm("search"), // string, search query for titles
|
||||
// MealType: toBits(ctx.PostFormArray("meal")),
|
||||
// Time: toBits(ctx.PostFormArray("time")),
|
||||
// Difficulty: toBits(ctx.PostFormArray("difficulty")),
|
||||
// ServingSize: toBits(ctx.PostFormArray("serving")),
|
||||
// }
|
||||
//
|
||||
// // Set the filters into the cookies, so they can be reloaded
|
||||
// if bytes, err := json.Marshal(filters); err == nil {
|
||||
// domain.SetCookie(ctx, "search-filters", string(bytes), time.Hour*24)
|
||||
// // ctx.SetCookie(
|
||||
// // "search-filters",
|
||||
// // string(bytes),
|
||||
// // int(time.Now().Add(24*time.Hour).Sub(time.Now()).Seconds()),
|
||||
// // "/",
|
||||
// // "", // TODO: Need an actual domain
|
||||
// // false, // TODO: True in prod
|
||||
// // true,
|
||||
// // )
|
||||
// }
|
||||
//
|
||||
// // TODO: Error here if they're not logged in?
|
||||
// // Get user data (they should be logged in)
|
||||
// if !domain.IsLoggedIn(ctx) {
|
||||
// components.RenderErrorBanner(ctx, "User is not logged in. User will be nil.")
|
||||
// ctx.JSON(http.StatusOK, gin.H{"error": "User is not logged in. User will be nil."})
|
||||
// }
|
||||
//
|
||||
// userId := ctx.MustGet("userId").(int)
|
||||
//
|
||||
// recipes, err := deps.RecipeService.SearchRecipes(filters, &userId, true)
|
||||
// if err != nil {
|
||||
// components.RenderErrorBanner(ctx, err.Error())
|
||||
// ctx.JSON(http.StatusOK, gin.H{"error": err.Error()})
|
||||
// }
|
||||
//
|
||||
// // Render content as the response
|
||||
// ctx.Status(200)
|
||||
// templates.FavoriteList(recipes).Render(ctx.Request.Context(), ctx.Writer)
|
||||
// }
|
||||
|
||||
@ -1,76 +1,71 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
// DEPRECATED: As of September 4th, 2025.
|
||||
// const TAG_HTML = `
|
||||
// <li
|
||||
// hx-post="%s"
|
||||
// hx-trigger="click"
|
||||
// hx-target="#tag-list"
|
||||
// hx-swap="innerHTML"
|
||||
// hx-include="#tag-list"
|
||||
// hx-vals='{"target": "%s"}'
|
||||
// class="flex text-xs items-center bg-blue-100 w-fit px-2 py-1 rounded-full gap-x-1 select-none cursor-pointer hover:bg-blue-200 duration-300">
|
||||
// × %s
|
||||
// </li>
|
||||
// `
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
domain "github.com/haydenhargreaves/Potion/internal/domain/server"
|
||||
)
|
||||
// DEPRECATED: As of September 4th, 2025.
|
||||
// const TAG_LIST_HTML = `
|
||||
// <input
|
||||
// hx-swap-oob="outerHTML"
|
||||
// type="hidden"
|
||||
// name="tags"
|
||||
// id="tags"
|
||||
// value="%s"
|
||||
// />
|
||||
// `
|
||||
|
||||
const TAG_HTML = `
|
||||
<li
|
||||
hx-post="%s"
|
||||
hx-trigger="click"
|
||||
hx-target="#tag-list"
|
||||
hx-swap="innerHTML"
|
||||
hx-include="#tag-list"
|
||||
hx-vals='{"target": "%s"}'
|
||||
class="flex text-xs items-center bg-blue-100 w-fit px-2 py-1 rounded-full gap-x-1 select-none cursor-pointer hover:bg-blue-200 duration-300">
|
||||
× %s
|
||||
</li>
|
||||
`
|
||||
// DEPRECATED: As of September 4th, 2025.
|
||||
// func NewTag(ctx *gin.Context) {
|
||||
// tag := strings.ToLower(ctx.PostForm("tag"))
|
||||
// tags := strings.Split(ctx.PostForm("tags"), ",")
|
||||
//
|
||||
// tags = append([]string{tag}, tags...)
|
||||
//
|
||||
// var html string
|
||||
// var cleaned_tags []string
|
||||
// for _, tag := range tags {
|
||||
// if tag != "" {
|
||||
// html += fmt.Sprintf(TAG_HTML, domain.STATE_TAGS_DELETE, tag, tag)
|
||||
//
|
||||
// // Ensure that the list provided does not contain blank spaces.
|
||||
// // This is another measure to ensure this state is bulletproof.
|
||||
// cleaned_tags = append(cleaned_tags, tag)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // Execute OOB swap for the tags
|
||||
// html += fmt.Sprintf(TAG_LIST_HTML, strings.Join(cleaned_tags, ","))
|
||||
//
|
||||
// ctx.String(http.StatusOK, html)
|
||||
// }
|
||||
|
||||
const TAG_LIST_HTML = `
|
||||
<input
|
||||
hx-swap-oob="outerHTML"
|
||||
type="hidden"
|
||||
name="tags"
|
||||
id="tags"
|
||||
value="%s"
|
||||
/>
|
||||
`
|
||||
|
||||
func NewTag(ctx *gin.Context) {
|
||||
tag := strings.ToLower(ctx.PostForm("tag"))
|
||||
tags := strings.Split(ctx.PostForm("tags"), ",")
|
||||
|
||||
tags = append([]string{tag}, tags...)
|
||||
|
||||
var html string
|
||||
var cleaned_tags []string
|
||||
for _, tag := range tags {
|
||||
if tag != "" {
|
||||
html += fmt.Sprintf(TAG_HTML, domain.STATE_TAGS_DELETE, tag, tag)
|
||||
|
||||
// Ensure that the list provided does not contain blank spaces.
|
||||
// This is another measure to ensure this state is bulletproof.
|
||||
cleaned_tags = append(cleaned_tags, tag)
|
||||
}
|
||||
}
|
||||
|
||||
// Execute OOB swap for the tags
|
||||
html += fmt.Sprintf(TAG_LIST_HTML, strings.Join(cleaned_tags, ","))
|
||||
|
||||
ctx.String(http.StatusOK, html)
|
||||
}
|
||||
|
||||
func DeleteTag(ctx *gin.Context) {
|
||||
tags := strings.Split(ctx.PostForm("tags"), ",")
|
||||
target := ctx.PostForm("target")
|
||||
|
||||
var html string
|
||||
var new_tags []string
|
||||
for _, tag := range tags {
|
||||
if tag != target && tag != "" {
|
||||
html += fmt.Sprintf(TAG_HTML, domain.STATE_TAGS_DELETE ,tag, tag)
|
||||
new_tags = append(new_tags, tag)
|
||||
}
|
||||
}
|
||||
|
||||
// Execute OOB swap for the tags
|
||||
html += fmt.Sprintf(TAG_LIST_HTML, strings.Join(new_tags, ","))
|
||||
|
||||
ctx.String(http.StatusOK, html)
|
||||
}
|
||||
// DEPRECATED: As of September 4th, 2025.
|
||||
// func DeleteTag(ctx *gin.Context) {
|
||||
// tags := strings.Split(ctx.PostForm("tags"), ",")
|
||||
// target := ctx.PostForm("target")
|
||||
//
|
||||
// var html string
|
||||
// var new_tags []string
|
||||
// for _, tag := range tags {
|
||||
// if tag != target && tag != "" {
|
||||
// html += fmt.Sprintf(TAG_HTML, domain.STATE_TAGS_DELETE ,tag, tag)
|
||||
// new_tags = append(new_tags, tag)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // Execute OOB swap for the tags
|
||||
// html += fmt.Sprintf(TAG_LIST_HTML, strings.Join(new_tags, ","))
|
||||
//
|
||||
// ctx.String(http.StatusOK, html)
|
||||
// }
|
||||
|
||||
@ -1,90 +1,83 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
// DEPRECATED: As of September 4th, 2025.
|
||||
// func GetUserRecipes(ctx *gin.Context) {
|
||||
// deps := ctx.MustGet("deps").(*domain.InjectedDependencies)
|
||||
//
|
||||
// // Ensure user is logged in with a valid account
|
||||
// user := deps.UserService.GetAuthenicatedUser(ctx)
|
||||
// if user == nil {
|
||||
// // Log (stale) user out
|
||||
// domain.SetCookie(ctx, "jwt_token", "", -1)
|
||||
// domain.SetCookie(ctx, "search-filters", "", -1)
|
||||
// }
|
||||
//
|
||||
// // Ensure logged in
|
||||
// if !domain.IsLoggedIn(ctx) || user == nil {
|
||||
// components.RenderErrorBanner(ctx, "User is not authorized to access this endpoint. Please login to continue.")
|
||||
// ctx.JSON(http.StatusUnauthorized, gin.H{
|
||||
// "status": http.StatusUnauthorized,
|
||||
// "message": "User is not authorized to access this endpoint. Please login to continue.",
|
||||
// "recipes": nil,
|
||||
// })
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// recipes, err := deps.RecipeService.GetUserRecipes(user.Id)
|
||||
// if err != nil {
|
||||
// components.RenderErrorBanner(ctx, fmt.Sprintf("Could not get user recipes. %s", err.Error()))
|
||||
// ctx.JSON(http.StatusBadRequest, gin.H{
|
||||
// "status": http.StatusBadRequest,
|
||||
// "message": fmt.Sprintf("Could not get user recipes. %s", err.Error()),
|
||||
// "recipes": nil,
|
||||
// })
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// ctx.JSON(http.StatusOK, gin.H{
|
||||
// "status": http.StatusOK,
|
||||
// "message": "User recipes successfully retrieved.",
|
||||
// "recipes": recipes,
|
||||
// })
|
||||
// }
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
domain "github.com/haydenhargreaves/Potion/internal/domain/server"
|
||||
"github.com/haydenhargreaves/Potion/internal/templates/components"
|
||||
)
|
||||
|
||||
func GetUserRecipes(ctx *gin.Context) {
|
||||
deps := ctx.MustGet("deps").(*domain.InjectedDependencies)
|
||||
|
||||
// Ensure user is logged in with a valid account
|
||||
user := deps.UserService.GetAuthenicatedUser(ctx)
|
||||
if user == nil {
|
||||
// Log (stale) user out
|
||||
domain.SetCookie(ctx, "jwt_token", "", -1)
|
||||
domain.SetCookie(ctx, "search-filters", "", -1)
|
||||
}
|
||||
|
||||
// Ensure logged in
|
||||
if !domain.IsLoggedIn(ctx) || user == nil {
|
||||
components.RenderErrorBanner(ctx, "User is not authorized to access this endpoint. Please login to continue.")
|
||||
ctx.JSON(http.StatusUnauthorized, gin.H{
|
||||
"status": http.StatusUnauthorized,
|
||||
"message": "User is not authorized to access this endpoint. Please login to continue.",
|
||||
"recipes": nil,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
recipes, err := deps.RecipeService.GetUserRecipes(user.Id)
|
||||
if err != nil {
|
||||
components.RenderErrorBanner(ctx, fmt.Sprintf("Could not get user recipes. %s", err.Error()))
|
||||
ctx.JSON(http.StatusBadRequest, gin.H{
|
||||
"status": http.StatusBadRequest,
|
||||
"message": fmt.Sprintf("Could not get user recipes. %s", err.Error()),
|
||||
"recipes": nil,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
ctx.JSON(http.StatusOK, gin.H{
|
||||
"status": http.StatusOK,
|
||||
"message": "User recipes successfully retrieved.",
|
||||
"recipes": recipes,
|
||||
})
|
||||
}
|
||||
|
||||
func GetUserFavoriteRecipes(ctx *gin.Context) {
|
||||
deps := ctx.MustGet("deps").(*domain.InjectedDependencies)
|
||||
|
||||
// Ensure user is logged in with a valid account
|
||||
user := deps.UserService.GetAuthenicatedUser(ctx)
|
||||
if user == nil {
|
||||
// Log (stale) user out
|
||||
domain.SetCookie(ctx, "jwt_token", "", -1)
|
||||
domain.SetCookie(ctx, "search-filters", "", -1)
|
||||
}
|
||||
|
||||
// Ensure logged in
|
||||
if !domain.IsLoggedIn(ctx) || user == nil {
|
||||
components.RenderErrorBanner(ctx, "User is not authorized to access this endpoint. Please login to continue.")
|
||||
ctx.JSON(http.StatusUnauthorized, gin.H{
|
||||
"status": http.StatusUnauthorized,
|
||||
"message": "User is not authorized to access this endpoint. Please login to continue.",
|
||||
"recipes": nil,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
recipes, err := deps.RecipeService.GetUserFavoriteRecipes(user.Id)
|
||||
if err != nil {
|
||||
components.RenderErrorBanner(ctx, fmt.Sprintf("Could not get favorite recipes. %s", err.Error()))
|
||||
ctx.JSON(http.StatusBadRequest, gin.H{
|
||||
"status": http.StatusBadRequest,
|
||||
"message": fmt.Sprintf("Could not get favorite recipes. %s", err.Error()),
|
||||
"recipes": nil,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
ctx.JSON(http.StatusOK, gin.H{
|
||||
"status": http.StatusOK,
|
||||
"message": "User recipes successfully retrieved.",
|
||||
"recipes": recipes,
|
||||
})
|
||||
}
|
||||
// DEPRECATED: As of September 4th, 2025.
|
||||
// func GetUserFavoriteRecipes(ctx *gin.Context) {
|
||||
// deps := ctx.MustGet("deps").(*domain.InjectedDependencies)
|
||||
//
|
||||
// // Ensure user is logged in with a valid account
|
||||
// user := deps.UserService.GetAuthenicatedUser(ctx)
|
||||
// if user == nil {
|
||||
// // Log (stale) user out
|
||||
// domain.SetCookie(ctx, "jwt_token", "", -1)
|
||||
// domain.SetCookie(ctx, "search-filters", "", -1)
|
||||
// }
|
||||
//
|
||||
// // Ensure logged in
|
||||
// if !domain.IsLoggedIn(ctx) || user == nil {
|
||||
// components.RenderErrorBanner(ctx, "User is not authorized to access this endpoint. Please login to continue.")
|
||||
// ctx.JSON(http.StatusUnauthorized, gin.H{
|
||||
// "status": http.StatusUnauthorized,
|
||||
// "message": "User is not authorized to access this endpoint. Please login to continue.",
|
||||
// "recipes": nil,
|
||||
// })
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// recipes, err := deps.RecipeService.GetUserFavoriteRecipes(user.Id)
|
||||
// if err != nil {
|
||||
// components.RenderErrorBanner(ctx, fmt.Sprintf("Could not get favorite recipes. %s", err.Error()))
|
||||
// ctx.JSON(http.StatusBadRequest, gin.H{
|
||||
// "status": http.StatusBadRequest,
|
||||
// "message": fmt.Sprintf("Could not get favorite recipes. %s", err.Error()),
|
||||
// "recipes": nil,
|
||||
// })
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// ctx.JSON(http.StatusOK, gin.H{
|
||||
// "status": http.StatusOK,
|
||||
// "message": "User recipes successfully retrieved.",
|
||||
// "recipes": recipes,
|
||||
// })
|
||||
// }
|
||||
|
||||
45
internal/app/server/auth_handler.go
Normal file
45
internal/app/server/auth_handler.go
Normal file
@ -0,0 +1,45 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
domain "github.com/haydenhargreaves/Potion/internal/domain/server"
|
||||
"github.com/haydenhargreaves/Potion/internal/templates/components"
|
||||
)
|
||||
|
||||
// GoogleLogin directs the user to Googles select user login page. Once the user has selected an
|
||||
// account, they will be directed to the GoogleCallback handler where the main logic resides.
|
||||
func (s *Server) GoogleLoginHandler(ctx *gin.Context) {
|
||||
url := s.deps.AuthService.GetGoogleAuthUrl()
|
||||
ctx.Redirect(http.StatusSeeOther, url)
|
||||
}
|
||||
|
||||
// GoogleCallback is the callback handler when the user successfully logs in with their Google
|
||||
// account. They will be directed here and a JWT is generated. This JWT is stored in the users
|
||||
// cookies and will be used by protected routes to validate their login status.
|
||||
func (s *Server) GoogleCallbackHandler(ctx *gin.Context) {
|
||||
var (
|
||||
state string = ctx.Query("state")
|
||||
code string = ctx.Query("code")
|
||||
)
|
||||
|
||||
if jwt, err := s.deps.AuthService.GoogleAuthSuccess(state, code); err != nil {
|
||||
components.RenderErrorBanner(ctx, err.Error())
|
||||
ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
} else {
|
||||
s.SetCookie(ctx, "jwt_token", jwt, time.Hour*24*7)
|
||||
ctx.Redirect(http.StatusSeeOther, "/")
|
||||
}
|
||||
}
|
||||
|
||||
// Logout removes the token from the user's browser. Effectively "logging them out." Routes that
|
||||
// require authentication will require the user to sign back in before accessing them again.
|
||||
// This route will direct the user back to the home page.
|
||||
func (s *Server) LogoutHandler(ctx *gin.Context) {
|
||||
s.SetCookie(ctx, "jwt_token", "", -1)
|
||||
s.SetCookie(ctx, "search-filters", "", -1)
|
||||
ctx.Redirect(http.StatusSeeOther, domain.WEB_HOME)
|
||||
}
|
||||
|
||||
53
internal/app/server/cookies.go
Normal file
53
internal/app/server/cookies.go
Normal file
@ -0,0 +1,53 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// SetCookie sets a cookie value with a duration provided. This function handles setting the security
|
||||
// configuration as well as the domain. These values are based on the EnvironmentConfig, therefore
|
||||
// the value should be set. Nothing is returned by this function, but the cookie will be set.
|
||||
//
|
||||
// This function can also be used to clear cookies, if a blank value ("") and invalid duration (-1)
|
||||
// is provided.
|
||||
//
|
||||
// If 0 is provided as the duration, then a session cookie is created, which will be cleared when
|
||||
// the browser is closed.
|
||||
func (s *Server) SetCookie(ctx *gin.Context, name, value string, duration time.Duration) {
|
||||
var (
|
||||
path string = "/"
|
||||
httpOnly bool = true
|
||||
maxAge int
|
||||
secure bool
|
||||
domain string
|
||||
)
|
||||
|
||||
if duration < 0 {
|
||||
// Delete the cookie
|
||||
maxAge = -1
|
||||
} else if duration == 0 {
|
||||
// Session cookie, clears when browser is closed
|
||||
maxAge = 0
|
||||
} else {
|
||||
// Normal calculation
|
||||
maxAge = int(time.Now().Add(duration).Sub(time.Now()).Seconds())
|
||||
}
|
||||
|
||||
if s.deps.EnvironmentConfig.Environment == "prod" {
|
||||
secure = true
|
||||
domain = s.deps.EnvironmentConfig.Domain
|
||||
|
||||
} else if s.deps.EnvironmentConfig.Environment == "dev" {
|
||||
secure = false
|
||||
domain = s.deps.EnvironmentConfig.Domain
|
||||
|
||||
} else {
|
||||
// Defaults
|
||||
secure = false
|
||||
domain = ""
|
||||
}
|
||||
|
||||
ctx.SetCookie(name, value, maxAge, path, domain, secure, httpOnly)
|
||||
}
|
||||
142
internal/app/server/engagement_handler.go
Normal file
142
internal/app/server/engagement_handler.go
Normal file
@ -0,0 +1,142 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
domain "github.com/haydenhargreaves/Potion/internal/domain/server"
|
||||
"github.com/haydenhargreaves/Potion/internal/templates/components"
|
||||
)
|
||||
|
||||
func (s *Server) EngagementViewRecipeHandler(ctx *gin.Context) {
|
||||
recipeId, _ := strconv.Atoi(ctx.Param("id"))
|
||||
|
||||
// Ensure user is logged in with a valid account
|
||||
user := s.deps.UserService.GetAuthenicatedUser(ctx)
|
||||
if user == nil {
|
||||
// Log (stale) user out
|
||||
s.SetCookie(ctx, "jwt_token", "", -1)
|
||||
s.SetCookie(ctx, "search-filters", "", -1)
|
||||
}
|
||||
|
||||
if !domain.IsLoggedIn(ctx) || user == nil {
|
||||
if _, err := s.deps.EngagementService.ViewRecipe(recipeId); err != nil {
|
||||
components.RenderErrorBanner(ctx, err.Error())
|
||||
ctx.JSON(http.StatusInternalServerError, gin.H{
|
||||
"status": http.StatusInternalServerError,
|
||||
"message": err.Error(),
|
||||
})
|
||||
} else {
|
||||
ctx.Header("HX-Redirect", fmt.Sprintf(domain.WEB_RECIPE, recipeId))
|
||||
ctx.Status(http.StatusOK)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// We caught nil already, we can assume the user exists
|
||||
if _, err := s.deps.EngagementService.UserViewRecipe(user.Id, recipeId); err != nil {
|
||||
components.RenderErrorBanner(ctx, err.Error())
|
||||
ctx.JSON(http.StatusInternalServerError, gin.H{
|
||||
"status": http.StatusInternalServerError,
|
||||
"message": err.Error(),
|
||||
})
|
||||
} else {
|
||||
ctx.Header("HX-Redirect", fmt.Sprintf(domain.WEB_RECIPE, recipeId))
|
||||
ctx.Status(http.StatusOK)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) EngagementShareRecipeHandler(ctx *gin.Context) {
|
||||
recipeId, _ := strconv.Atoi(ctx.Param("id"))
|
||||
|
||||
// Ensure user is logged in with a valid account
|
||||
user := s.deps.UserService.GetAuthenicatedUser(ctx)
|
||||
if user == nil {
|
||||
// Log (stale) user out
|
||||
s.SetCookie(ctx, "jwt_token", "", -1)
|
||||
s.SetCookie(ctx, "search-filters", "", -1)
|
||||
}
|
||||
|
||||
if !domain.IsLoggedIn(ctx) || user == nil {
|
||||
if _, err := s.deps.EngagementService.ShareRecipe(recipeId); err != nil {
|
||||
components.RenderErrorBanner(ctx, err.Error())
|
||||
ctx.JSON(http.StatusInternalServerError, gin.H{
|
||||
"status": http.StatusInternalServerError,
|
||||
"message": err.Error(),
|
||||
})
|
||||
} else {
|
||||
ctx.Status(http.StatusNoContent)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if _, err := s.deps.EngagementService.UserShareRecipe(user.Id, recipeId); err != nil {
|
||||
components.RenderErrorBanner(ctx, err.Error())
|
||||
ctx.JSON(http.StatusInternalServerError, gin.H{
|
||||
"status": http.StatusInternalServerError,
|
||||
"message": err.Error(),
|
||||
})
|
||||
} else {
|
||||
ctx.Status(http.StatusNoContent)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) EngagementFavoriteRecipeHandler(ctx *gin.Context) {
|
||||
// Ensure user is logged in with a valid account
|
||||
user := s.deps.UserService.GetAuthenicatedUser(ctx)
|
||||
if user == nil {
|
||||
// Log (stale) user out
|
||||
s.SetCookie(ctx, "jwt_token", "", -1)
|
||||
s.SetCookie(ctx, "search-filters", "", -1)
|
||||
}
|
||||
|
||||
if !domain.IsLoggedIn(ctx) || user == nil {
|
||||
ctx.Header("HX-Redirect", domain.WEB_LOGIN)
|
||||
ctx.Status(http.StatusOK)
|
||||
return
|
||||
}
|
||||
|
||||
id := ctx.Param("id")
|
||||
recipeId, _ := strconv.Atoi(id)
|
||||
|
||||
if _, err := s.deps.EngagementService.UserFavoriteRecipe(user.Id, recipeId); err != nil {
|
||||
components.RenderErrorBanner(ctx, fmt.Sprintf("Something went wrong. %s.", err.Error()))
|
||||
ctx.JSON(http.StatusInternalServerError, gin.H{
|
||||
"status": http.StatusInternalServerError,
|
||||
"message": err.Error(),
|
||||
})
|
||||
} else {
|
||||
ctx.Status(http.StatusNoContent)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) EngagementMakeRecipeHandler(ctx *gin.Context) {
|
||||
// Ensure user is logged in with a valid account
|
||||
user := s.deps.UserService.GetAuthenicatedUser(ctx)
|
||||
if user == nil {
|
||||
// Log (stale) user out
|
||||
s.SetCookie(ctx, "jwt_token", "", -1)
|
||||
s.SetCookie(ctx, "search-filters", "", -1)
|
||||
}
|
||||
|
||||
if !domain.IsLoggedIn(ctx) || user == nil {
|
||||
ctx.Header("HX-Redirect", domain.WEB_LOGIN)
|
||||
ctx.Status(http.StatusOK)
|
||||
return
|
||||
}
|
||||
|
||||
id := ctx.Param("id")
|
||||
recipeId, _ := strconv.Atoi(id)
|
||||
|
||||
if _, err := s.deps.EngagementService.UserMakeRecipe(user.Id, recipeId); err != nil {
|
||||
components.RenderErrorBanner(ctx, err.Error())
|
||||
ctx.JSON(http.StatusInternalServerError, gin.H{
|
||||
"status": http.StatusInternalServerError,
|
||||
"message": err.Error(),
|
||||
})
|
||||
} else {
|
||||
ctx.Status(http.StatusNoContent)
|
||||
}
|
||||
}
|
||||
@ -13,12 +13,14 @@ import (
|
||||
|
||||
// DepedencyInjectionMiddleware injects the dependencies into the context set. This is a middleware
|
||||
// that is used to apply the required services.
|
||||
func DepedencyInjectionMiddleware(deps *domain.InjectedDependencies) gin.HandlerFunc {
|
||||
return func(ctx *gin.Context) {
|
||||
ctx.Set("deps", deps)
|
||||
ctx.Next()
|
||||
}
|
||||
}
|
||||
//
|
||||
// DEPRECATED: As of September 4th, 2025.
|
||||
// func DepedencyInjectionMiddleware(deps *domain.InjectedDependencies) gin.HandlerFunc {
|
||||
// return func(ctx *gin.Context) {
|
||||
// ctx.Set("deps", deps)
|
||||
// ctx.Next()
|
||||
// }
|
||||
// }
|
||||
|
||||
// JwtAuthMiddleWare handles collection the JWT from the browser's cookies and setting the
|
||||
// appropriate data. If the data is not found, this middleware will do effectively nothing, by not
|
||||
|
||||
298
internal/app/server/page_handler.go
Normal file
298
internal/app/server/page_handler.go
Normal file
@ -0,0 +1,298 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/a-h/templ"
|
||||
"github.com/gin-gonic/gin"
|
||||
domainRecipe "github.com/haydenhargreaves/Potion/internal/domain/recipe"
|
||||
domain "github.com/haydenhargreaves/Potion/internal/domain/server"
|
||||
"github.com/haydenhargreaves/Potion/internal/templates/components"
|
||||
layouts "github.com/haydenhargreaves/Potion/internal/templates/layouts"
|
||||
pages "github.com/haydenhargreaves/Potion/internal/templates/pages"
|
||||
)
|
||||
|
||||
func (s *Server) LoginPageHandler(ctx *gin.Context) {
|
||||
title := "Potion - Login"
|
||||
page := pages.LoginPage()
|
||||
|
||||
ctx.HTML(http.StatusOK, "", layouts.AppLayout(title, page))
|
||||
}
|
||||
|
||||
func (s *Server) HomePageHandler(ctx *gin.Context) {
|
||||
loggedIn := domain.IsLoggedIn(ctx)
|
||||
|
||||
// Ensure user is logged in with a valid account
|
||||
if user := s.deps.UserService.GetAuthenicatedUser(ctx); user == nil {
|
||||
// Log (stale) user out
|
||||
s.SetCookie(ctx, "jwt_token", "", -1)
|
||||
s.SetCookie(ctx, "search-filters", "", -1)
|
||||
loggedIn = false
|
||||
}
|
||||
|
||||
var page templ.Component
|
||||
if loggedIn {
|
||||
userId := ctx.MustGet("userId").(int)
|
||||
madeRecipes, err := s.deps.RecipeService.GetUserMadeRecipes(userId, 6)
|
||||
if err != nil {
|
||||
components.RenderErrorBanner(ctx, fmt.Sprintf("Error getting made recipes. %s\n", err.Error()))
|
||||
ctx.JSON(http.StatusInternalServerError, gin.H{
|
||||
"status": http.StatusInternalServerError,
|
||||
"message": fmt.Sprintf("Error getting made recipes. %s\n", err.Error()),
|
||||
})
|
||||
return
|
||||
}
|
||||
viewedRecipes, err := s.deps.RecipeService.GetUserViewedRecipes(userId, 6)
|
||||
if err != nil {
|
||||
components.RenderErrorBanner(ctx, fmt.Sprintf("Error getting viewed recipes. %s\n", err.Error()))
|
||||
ctx.JSON(http.StatusInternalServerError, gin.H{
|
||||
"status": http.StatusInternalServerError,
|
||||
"message": fmt.Sprintf("Error getting viewed recipes. %s\n", err.Error()),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// Get the recipe of the week
|
||||
recipeOfTheWeek, err := s.deps.RecipeService.GetRecipeOfTheWeek(&userId)
|
||||
if err != nil {
|
||||
components.RenderErrorBanner(ctx, fmt.Sprintf("Error getting recipe of the week. %s\n", err.Error()))
|
||||
ctx.JSON(http.StatusInternalServerError, gin.H{
|
||||
"status": http.StatusInternalServerError,
|
||||
"message": fmt.Sprintf("Error getting recipe of the week. %s\n", err.Error()),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if bytes, err := ctx.Cookie("search-filters"); err != nil {
|
||||
fmt.Printf("ERROR: Failed to get search-filter cookie. %s\n", err.Error())
|
||||
page = pages.HomePage(true, viewedRecipes, madeRecipes, recipeOfTheWeek, nil)
|
||||
} else {
|
||||
var filters domainRecipe.SearchFilters
|
||||
if err := json.Unmarshal([]byte(bytes), &filters); err != nil {
|
||||
fmt.Printf("ERROR: Failed to unmarshal search-filter cookie. %s\n", err.Error())
|
||||
page = pages.HomePage(true, viewedRecipes, madeRecipes, recipeOfTheWeek, nil)
|
||||
} else {
|
||||
page = pages.HomePage(true, viewedRecipes, madeRecipes, recipeOfTheWeek, &filters)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Get the recipe of the week
|
||||
recipeOfTheWeek, err := s.deps.RecipeService.GetRecipeOfTheWeek(nil)
|
||||
if err != nil {
|
||||
components.RenderErrorBanner(ctx, fmt.Sprintf("Error getting recipe of the week. %s\n", err.Error()))
|
||||
ctx.JSON(http.StatusInternalServerError, gin.H{
|
||||
"status": http.StatusInternalServerError,
|
||||
"message": fmt.Sprintf("Error getting recipe of the week. %s\n", err.Error()),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if bytes, err := ctx.Cookie("search-filters"); err != nil {
|
||||
fmt.Printf("ERROR: Failed to get search-filter cookie. %s\n", err.Error())
|
||||
page = pages.HomePage(false, nil, nil, recipeOfTheWeek, nil)
|
||||
} else {
|
||||
var filters domainRecipe.SearchFilters
|
||||
if err := json.Unmarshal([]byte(bytes), &filters); err != nil {
|
||||
fmt.Printf("ERROR: Failed to unmarshal search-filter cookie. %s\n", err.Error())
|
||||
page = pages.HomePage(false, nil, nil, recipeOfTheWeek, nil)
|
||||
} else {
|
||||
page = pages.HomePage(false, nil, nil, recipeOfTheWeek, &filters)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
title := "Potion - Home"
|
||||
|
||||
ctx.HTML(http.StatusOK, "", layouts.AppLayout(title, page))
|
||||
}
|
||||
|
||||
func (s *Server) FavoritesPageHandler(ctx *gin.Context) {
|
||||
// If not logged in, direct to the login page
|
||||
if !domain.IsLoggedIn(ctx) {
|
||||
ctx.Redirect(http.StatusSeeOther, domain.WEB_LOGIN)
|
||||
return
|
||||
}
|
||||
|
||||
title := "Potion - Favorites"
|
||||
var page templ.Component
|
||||
|
||||
// Get filters from cookies
|
||||
if bytes, err := ctx.Cookie("search-filters"); err != nil {
|
||||
fmt.Printf("ERROR: Failed to get search-filter cookie. %s\n", err.Error())
|
||||
page = pages.FavoritesPage(nil)
|
||||
} else {
|
||||
var filters domainRecipe.SearchFilters
|
||||
if err := json.Unmarshal([]byte(bytes), &filters); err != nil {
|
||||
fmt.Printf("ERROR: Failed to unmarshal search-filter cookie. %s\n", err.Error())
|
||||
page = pages.FavoritesPage(nil)
|
||||
} else {
|
||||
page = pages.FavoritesPage(&filters)
|
||||
}
|
||||
}
|
||||
|
||||
ctx.HTML(http.StatusOK, "", layouts.AppLayout(title, page))
|
||||
}
|
||||
|
||||
func (s *Server) CreatePageHandler(ctx *gin.Context) {
|
||||
// If not logged in, direct to the login page
|
||||
if !domain.IsLoggedIn(ctx) {
|
||||
ctx.Redirect(http.StatusSeeOther, domain.WEB_LOGIN)
|
||||
return
|
||||
}
|
||||
|
||||
// Ensure user is logged in with a valid account
|
||||
if user := s.deps.UserService.GetAuthenicatedUser(ctx); user == nil {
|
||||
// Log (stale) user out
|
||||
s.SetCookie(ctx, "jwt_token", "", -1)
|
||||
s.SetCookie(ctx, "search-filters", "", -1)
|
||||
|
||||
ctx.Redirect(http.StatusSeeOther, domain.WEB_LOGIN)
|
||||
return
|
||||
}
|
||||
|
||||
title := "Potion - Create"
|
||||
page := pages.CreatePage()
|
||||
|
||||
ctx.HTML(http.StatusOK, "", layouts.AppLayout(title, page))
|
||||
}
|
||||
|
||||
func (s *Server) ProfilePageHandler(ctx *gin.Context) {
|
||||
// If not logged in, direct to the login page
|
||||
if !domain.IsLoggedIn(ctx) {
|
||||
ctx.Redirect(http.StatusSeeOther, domain.WEB_LOGIN)
|
||||
return
|
||||
}
|
||||
|
||||
// Else, get the user data
|
||||
user := s.deps.UserService.GetAuthenicatedUser(ctx)
|
||||
if user == nil {
|
||||
// User is failing to be found, direct to the login page
|
||||
ctx.Redirect(http.StatusSeeOther, domain.WEB_LOGIN)
|
||||
return
|
||||
}
|
||||
|
||||
recipes, err := s.deps.RecipeService.GetUserRecipes(user.Id)
|
||||
if err != nil {
|
||||
components.RenderErrorBanner(ctx, fmt.Sprintf("Error getting recipes. %s\n", err.Error()))
|
||||
ctx.JSON(http.StatusInternalServerError, gin.H{
|
||||
"status": http.StatusInternalServerError,
|
||||
"message": fmt.Sprintf("Error getting recipes. %s\n", err.Error()),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
favorites, err := s.deps.RecipeService.GetUserFavoriteRecipes(user.Id)
|
||||
if err != nil {
|
||||
components.RenderErrorBanner(ctx, fmt.Sprintf("Error getting favorite recipes. %s\n", err.Error()))
|
||||
ctx.JSON(http.StatusInternalServerError, gin.H{
|
||||
"status": http.StatusInternalServerError,
|
||||
"message": fmt.Sprintf("Error getting favorite recipes. %s\n", err.Error()),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// Get the engagement data, not sure what will happen when errors occur
|
||||
engagements, err := s.deps.EngagementService.GetUserEngagement(user.Id, 6)
|
||||
if err != nil {
|
||||
components.RenderErrorBanner(ctx, fmt.Sprintf("Error getting user engagements. %s\n", err.Error()))
|
||||
ctx.JSON(http.StatusInternalServerError, gin.H{
|
||||
"status": http.StatusInternalServerError,
|
||||
"message": fmt.Sprintf("Error getting user engagements. %s\n", err.Error()),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
title := "Potion - Profile"
|
||||
page := pages.ProfilePage(*user, recipes, favorites, engagements)
|
||||
|
||||
ctx.HTML(http.StatusOK, "", layouts.AppLayout(title, page))
|
||||
}
|
||||
|
||||
func (s *Server) ListPageHandler(ctx *gin.Context) {
|
||||
title := "Potion - Shopping List"
|
||||
page := pages.ListPage()
|
||||
|
||||
ctx.HTML(http.StatusOK, "", layouts.AppLayout(title, page))
|
||||
}
|
||||
|
||||
func (s *Server) RecipePageHandler(ctx *gin.Context) {
|
||||
// Call recipe service to get via ID
|
||||
id := ctx.Param("id")
|
||||
|
||||
// Parse ID
|
||||
parsed, err := strconv.Atoi(id)
|
||||
if err != nil {
|
||||
components.RenderErrorBanner(ctx, fmt.Sprintf("ERROR: %s", err.Error()))
|
||||
ctx.JSON(400, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// Get signed in user, if they exist
|
||||
var userId *int = nil
|
||||
var loggedIn = domain.IsLoggedIn(ctx)
|
||||
|
||||
// Ensure user is logged in with a valid account
|
||||
if user := s.deps.UserService.GetAuthenicatedUser(ctx); user == nil {
|
||||
// Log (stale) user out
|
||||
s.SetCookie(ctx, "jwt_token", "", -1)
|
||||
s.SetCookie(ctx, "search-filters", "", -1)
|
||||
loggedIn = false
|
||||
}
|
||||
|
||||
if loggedIn {
|
||||
storeId := ctx.MustGet("userId").(int)
|
||||
userId = &storeId
|
||||
}
|
||||
|
||||
// Get recipe
|
||||
recipe, err := s.deps.RecipeService.GetRecipe(parsed, userId)
|
||||
if err != nil {
|
||||
components.RenderErrorBanner(ctx, fmt.Sprintf("ERROR: %s", err.Error()))
|
||||
ctx.JSON(400, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// Get user (owner)
|
||||
user, err := s.deps.UserService.GetUser(recipe.UserId)
|
||||
if err != nil {
|
||||
components.RenderErrorBanner(ctx, fmt.Sprintf("ERROR: %s", err.Error()))
|
||||
ctx.JSON(400, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
title := "Potion - View Recipe"
|
||||
page := pages.RecipePage(*recipe, *user, loggedIn, s.deps.EnvironmentConfig.Domain)
|
||||
|
||||
ctx.HTML(http.StatusOK, "", layouts.AppLayout(title, page))
|
||||
}
|
||||
|
||||
func (s *Server) SearchPageHandler(ctx *gin.Context) {
|
||||
var page templ.Component
|
||||
// Get filters from cookies
|
||||
if bytes, err := ctx.Cookie("search-filters"); err != nil {
|
||||
fmt.Printf("ERROR: Failed to get search-filter cookie. %s\n", err.Error())
|
||||
page = pages.SearchPage(nil, false)
|
||||
} else {
|
||||
var filters domainRecipe.SearchFilters
|
||||
if err := json.Unmarshal([]byte(bytes), &filters); err != nil {
|
||||
fmt.Printf("ERROR: Failed to unmarshal search-filter cookie. %s\n", err.Error())
|
||||
page = pages.SearchPage(nil, false)
|
||||
} else {
|
||||
page = pages.SearchPage(&filters, true)
|
||||
}
|
||||
}
|
||||
|
||||
title := "Potion - Recipe Search"
|
||||
|
||||
ctx.HTML(http.StatusOK, "", layouts.AppLayout(title, page))
|
||||
}
|
||||
|
||||
func (s *Server) NotFoundPageHandler(ctx *gin.Context) {
|
||||
title := "Potion - Not Found"
|
||||
page := pages.NotFoundPage()
|
||||
|
||||
ctx.HTML(http.StatusOK, "", layouts.AppLayout(title, page))
|
||||
}
|
||||
121
internal/app/server/recipe_handler.go
Normal file
121
internal/app/server/recipe_handler.go
Normal file
@ -0,0 +1,121 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
domainRecipe "github.com/haydenhargreaves/Potion/internal/domain/recipe"
|
||||
domain "github.com/haydenhargreaves/Potion/internal/domain/server"
|
||||
"github.com/haydenhargreaves/Potion/internal/templates/components"
|
||||
templates "github.com/haydenhargreaves/Potion/internal/templates/pages"
|
||||
)
|
||||
|
||||
const CREATE_ERROR_HTML = `
|
||||
<p id="response" class="text-sm text-red-500 px-4 py-1 bg-red-100 rounded-full w-fit">
|
||||
Uh oh! Something went wrong when creating your recipe. Please try again. %s
|
||||
</p>
|
||||
`
|
||||
|
||||
func (s *Server) CreateRecipeHandler(ctx *gin.Context) {
|
||||
recipe, err := s.deps.RecipeService.CreateRecipe(ctx)
|
||||
if err != nil {
|
||||
components.RenderErrorBanner(ctx, err.Error())
|
||||
ctx.String(http.StatusOK, CREATE_ERROR_HTML, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// Send HTMX redirection
|
||||
url := fmt.Sprintf(domain.WEB_RECIPE, recipe.Id)
|
||||
ctx.Header("HX-Redirect", url)
|
||||
ctx.Status(http.StatusCreated)
|
||||
}
|
||||
|
||||
// toBits converts an array of stringified numbers into a single summed value
|
||||
func toBits(arr []string) (bits int) {
|
||||
for _, x := range arr {
|
||||
num, _ := strconv.Atoi(x)
|
||||
bits += num
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// TODO: (7/06/2025) I don't love doing all of this here, but it seems to be the only way to get it to work...
|
||||
func (s *Server) SearchRecipesHandler(ctx *gin.Context) {
|
||||
// create filters
|
||||
filters := domainRecipe.SearchFilters{
|
||||
Search: ctx.PostForm("search"), // string, search query for titles
|
||||
MealType: toBits(ctx.PostFormArray("meal")),
|
||||
Time: toBits(ctx.PostFormArray("time")),
|
||||
Difficulty: toBits(ctx.PostFormArray("difficulty")),
|
||||
ServingSize: toBits(ctx.PostFormArray("serving")),
|
||||
}
|
||||
|
||||
// Set the filters into the cookies, so they can be reloaded
|
||||
if bytes, err := json.Marshal(filters); err == nil {
|
||||
s.SetCookie(ctx, "search-filters", string(bytes), time.Hour*24)
|
||||
}
|
||||
|
||||
redirect := ctx.PostForm("redirect")
|
||||
if redirect == "true" {
|
||||
ctx.Header("HX-Redirect", domain.WEB_SEARCH)
|
||||
ctx.Status(http.StatusOK)
|
||||
return
|
||||
}
|
||||
|
||||
// Get user if logged in, so we can get favorite status
|
||||
var userId *int = nil
|
||||
if domain.IsLoggedIn(ctx) {
|
||||
id := ctx.MustGet("userId").(int)
|
||||
userId = &id
|
||||
}
|
||||
|
||||
// TODO: Not sure if we need to ensure the user is valid here
|
||||
|
||||
// We don't care about favorite status, so use false
|
||||
recipes, err := s.deps.RecipeService.SearchRecipes(filters, userId, false)
|
||||
if err != nil {
|
||||
components.RenderErrorBanner(ctx, err.Error())
|
||||
ctx.JSON(http.StatusOK, gin.H{"error": err.Error()})
|
||||
}
|
||||
|
||||
// Render content as the response
|
||||
ctx.Status(200)
|
||||
templates.ResultList(recipes).Render(ctx.Request.Context(), ctx.Writer)
|
||||
}
|
||||
|
||||
func (s *Server) SearchRecipesFavoritesHandler(ctx *gin.Context) {
|
||||
// create filters
|
||||
filters := domainRecipe.SearchFilters{
|
||||
Search: ctx.PostForm("search"), // string, search query for titles
|
||||
MealType: toBits(ctx.PostFormArray("meal")),
|
||||
Time: toBits(ctx.PostFormArray("time")),
|
||||
Difficulty: toBits(ctx.PostFormArray("difficulty")),
|
||||
ServingSize: toBits(ctx.PostFormArray("serving")),
|
||||
}
|
||||
|
||||
// Set the filters into the cookies, so they can be reloaded
|
||||
if bytes, err := json.Marshal(filters); err == nil {
|
||||
s.SetCookie(ctx, "search-filters", string(bytes), time.Hour*24)
|
||||
}
|
||||
|
||||
if !domain.IsLoggedIn(ctx) {
|
||||
components.RenderErrorBanner(ctx, "User is not logged in. User will be nil.")
|
||||
ctx.JSON(http.StatusOK, gin.H{"error": "User is not logged in. User will be nil."})
|
||||
}
|
||||
|
||||
userId := ctx.MustGet("userId").(int)
|
||||
|
||||
recipes, err := s.deps.RecipeService.SearchRecipes(filters, &userId, true)
|
||||
if err != nil {
|
||||
components.RenderErrorBanner(ctx, err.Error())
|
||||
ctx.JSON(http.StatusOK, gin.H{"error": err.Error()})
|
||||
}
|
||||
|
||||
// Render content as the response
|
||||
ctx.Status(200)
|
||||
templates.FavoriteList(recipes).Render(ctx.Request.Context(), ctx.Writer)
|
||||
}
|
||||
@ -9,7 +9,6 @@ import (
|
||||
"github.com/a-h/templ/examples/integration-gin/gintemplrenderer"
|
||||
"github.com/gin-contrib/cors"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/haydenhargreaves/Potion/internal/app/handlers"
|
||||
"github.com/haydenhargreaves/Potion/internal/app/service"
|
||||
domain "github.com/haydenhargreaves/Potion/internal/domain/server"
|
||||
"github.com/haydenhargreaves/Potion/internal/infrastructure/auth"
|
||||
@ -23,6 +22,7 @@ type Server struct {
|
||||
Router *gin.Engine
|
||||
config cors.Config
|
||||
DB *sql.DB
|
||||
deps domain.InjectedDependencies
|
||||
}
|
||||
|
||||
// Init initializes the server with the provided port. CORS settings are defined here.
|
||||
@ -53,6 +53,7 @@ func (s *Server) Start() {
|
||||
s.Router.Run(fmt.Sprintf(":%d", s.port))
|
||||
}
|
||||
|
||||
// TODO: (9/4/2025) Abstract these functions and cleanup. This is fucking messy...
|
||||
func (s *Server) Setup() *Server {
|
||||
// SETUP THE ENVIRONMENT CONFIGURATION
|
||||
cfg, err := domain.LoadEnvironment()
|
||||
@ -109,7 +110,7 @@ func (s *Server) Setup() *Server {
|
||||
recipeService := service.NewRecipeService(recipeRepo, engagementRepo)
|
||||
engagementService := service.NewEngagementService(engagementRepo, recipeRepo)
|
||||
|
||||
deps := &domain.InjectedDependencies{
|
||||
s.deps = domain.InjectedDependencies{
|
||||
UserService: userService,
|
||||
AuthService: authService,
|
||||
RecipeService: recipeService,
|
||||
@ -119,7 +120,6 @@ func (s *Server) Setup() *Server {
|
||||
|
||||
// Apply middleware
|
||||
s.Router.Use(RecoveryMiddleware())
|
||||
s.Router.Use(DepedencyInjectionMiddleware(deps))
|
||||
s.Router.Use(JwtAuthMiddleWare(jwtSecret))
|
||||
|
||||
// Redirect index to home page: Update this as needed
|
||||
@ -138,44 +138,41 @@ func (s *Server) Setup() *Server {
|
||||
|
||||
// API router endpoints
|
||||
router_api.GET("/", func(ctx *gin.Context) { ctx.JSON(200, gin.H{"message": "Server is active."}) })
|
||||
router_api.GET("/tmp", func(ctx *gin.Context) {
|
||||
deps := ctx.MustGet("deps").(*domain.InjectedDependencies)
|
||||
ctx.JSON(200, gin.H{"config": deps.EnvironmentConfig})
|
||||
})
|
||||
|
||||
// WEB router endpoints
|
||||
router_web.GET("/", func(ctx *gin.Context) { ctx.Redirect(http.StatusSeeOther, domain.WEB_HOME) })
|
||||
router_web.GET("/login", handlers.LoginPage)
|
||||
router_web.GET("/home", handlers.HomePage)
|
||||
router_web.GET("/favorites", handlers.FavoritesPage)
|
||||
router_web.GET("/create", handlers.CreatePage)
|
||||
router_web.GET("/profile", handlers.ProfilePage)
|
||||
router_web.GET("/list", handlers.ListPage)
|
||||
router_web.GET("/recipe/:id", handlers.RecipePage)
|
||||
router_web.GET("/search", handlers.SearchPage)
|
||||
router_web.GET("/404", handlers.NotFoundPage)
|
||||
router_web.GET("/login", s.LoginPageHandler)
|
||||
router_web.GET("/home", s.HomePageHandler)
|
||||
router_web.GET("/favorites", s.FavoritesPageHandler)
|
||||
router_web.GET("/create", s.CreatePageHandler)
|
||||
router_web.GET("/profile", s.ProfilePageHandler)
|
||||
router_web.GET("/list", s.ListPageHandler)
|
||||
router_web.GET("/recipe/:id", s.RecipePageHandler)
|
||||
router_web.GET("/search", s.SearchPageHandler)
|
||||
router_web.GET("/404", s.NotFoundPageHandler)
|
||||
|
||||
// WEB state endpoints
|
||||
router_state.POST("/tags", handlers.NewTag)
|
||||
router_state.POST("/tags/delete", handlers.DeleteTag)
|
||||
router_state.POST("/tags", s.NewTagHandler)
|
||||
router_state.POST("/tags/delete", s.DeleteTagHandler)
|
||||
|
||||
// Authentication
|
||||
router_api.GET("/auth/login", handlers.GoogleLogin)
|
||||
router_api.GET("/auth/callback", handlers.GoogleCallback)
|
||||
router_api.GET("/auth/logout", handlers.Logout)
|
||||
router_api.GET("/auth/login", s.GoogleLoginHandler)
|
||||
router_api.GET("/auth/callback", s.GoogleCallbackHandler)
|
||||
router_api.GET("/auth/logout", s.LogoutHandler)
|
||||
|
||||
// Recipe endpoints
|
||||
router_api.POST("/recipe", handlers.CreateRecipe)
|
||||
router_api.POST("/recipe/search", handlers.SearchRecipes)
|
||||
router_api.POST("/recipe/search/favorites", handlers.SearchRecipesFavorites)
|
||||
router_api.GET("/user/recipes", handlers.GetUserRecipes)
|
||||
router_api.GET("/user/favorites", handlers.GetUserFavoriteRecipes)
|
||||
router_api.POST("/recipe", s.CreateRecipeHandler)
|
||||
router_api.POST("/recipe/search", s.SearchRecipesHandler)
|
||||
router_api.POST("/recipe/search/favorites", s.SearchRecipesFavoritesHandler)
|
||||
|
||||
router_api.GET("/user/recipes", s.GetUserFavoriteRecipesHandler)
|
||||
router_api.GET("/user/favorites", s.GetUserFavoriteRecipesHandler)
|
||||
|
||||
// Engagement endpoints
|
||||
router_api.POST("/engagement/view/:id", handlers.EngagementViewRecipe)
|
||||
router_api.POST("/engagement/share/:id", handlers.EngagementShareRecipe)
|
||||
router_api.POST("/engagement/favorite/:id", handlers.EngagementFavoriteRecipe)
|
||||
router_api.POST("/engagement/make/:id", handlers.EngagementMakeRecipe)
|
||||
router_api.POST("/engagement/view/:id", s.EngagementViewRecipeHandler)
|
||||
router_api.POST("/engagement/share/:id", s.EngagementShareRecipeHandler)
|
||||
router_api.POST("/engagement/favorite/:id", s.EngagementFavoriteRecipeHandler)
|
||||
router_api.POST("/engagement/make/:id", s.EngagementMakeRecipeHandler)
|
||||
|
||||
// Catch un-routed URLS
|
||||
s.Router.NoRoute(func(ctx *gin.Context) {
|
||||
|
||||
76
internal/app/server/state_handler.go
Normal file
76
internal/app/server/state_handler.go
Normal file
@ -0,0 +1,76 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
domain "github.com/haydenhargreaves/Potion/internal/domain/server"
|
||||
)
|
||||
|
||||
const TAG_HTML = `
|
||||
<li
|
||||
hx-post="%s"
|
||||
hx-trigger="click"
|
||||
hx-target="#tag-list"
|
||||
hx-swap="innerHTML"
|
||||
hx-include="#tag-list"
|
||||
hx-vals='{"target": "%s"}'
|
||||
class="flex text-xs items-center bg-blue-100 w-fit px-2 py-1 rounded-full gap-x-1 select-none cursor-pointer hover:bg-blue-200 duration-300">
|
||||
× %s
|
||||
</li>
|
||||
`
|
||||
|
||||
const TAG_LIST_HTML = `
|
||||
<input
|
||||
hx-swap-oob="outerHTML"
|
||||
type="hidden"
|
||||
name="tags"
|
||||
id="tags"
|
||||
value="%s"
|
||||
/>
|
||||
`
|
||||
|
||||
func (s *Server) NewTagHandler(ctx *gin.Context) {
|
||||
tag := strings.ToLower(ctx.PostForm("tag"))
|
||||
tags := strings.Split(ctx.PostForm("tags"), ",")
|
||||
|
||||
tags = append([]string{tag}, tags...)
|
||||
|
||||
var html string
|
||||
var cleaned_tags []string
|
||||
for _, tag := range tags {
|
||||
if tag != "" {
|
||||
html += fmt.Sprintf(TAG_HTML, domain.STATE_TAGS_DELETE, tag, tag)
|
||||
|
||||
// Ensure that the list provided does not contain blank spaces.
|
||||
// This is another measure to ensure this state is bulletproof.
|
||||
cleaned_tags = append(cleaned_tags, tag)
|
||||
}
|
||||
}
|
||||
|
||||
// Execute OOB swap for the tags
|
||||
html += fmt.Sprintf(TAG_LIST_HTML, strings.Join(cleaned_tags, ","))
|
||||
|
||||
ctx.String(http.StatusOK, html)
|
||||
}
|
||||
|
||||
func (s *Server) DeleteTagHandler(ctx *gin.Context) {
|
||||
tags := strings.Split(ctx.PostForm("tags"), ",")
|
||||
target := ctx.PostForm("target")
|
||||
|
||||
var html string
|
||||
var new_tags []string
|
||||
for _, tag := range tags {
|
||||
if tag != target && tag != "" {
|
||||
html += fmt.Sprintf(TAG_HTML, domain.STATE_TAGS_DELETE, tag, tag)
|
||||
new_tags = append(new_tags, tag)
|
||||
}
|
||||
}
|
||||
|
||||
// Execute OOB swap for the tags
|
||||
html += fmt.Sprintf(TAG_LIST_HTML, strings.Join(new_tags, ","))
|
||||
|
||||
ctx.String(http.StatusOK, html)
|
||||
}
|
||||
87
internal/app/server/user_handler.go
Normal file
87
internal/app/server/user_handler.go
Normal file
@ -0,0 +1,87 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
domain "github.com/haydenhargreaves/Potion/internal/domain/server"
|
||||
"github.com/haydenhargreaves/Potion/internal/templates/components"
|
||||
)
|
||||
|
||||
func (s *Server) GetUserRecipesHandler(ctx *gin.Context) {
|
||||
// Ensure user is logged in with a valid account
|
||||
user := s.deps.UserService.GetAuthenicatedUser(ctx)
|
||||
if user == nil {
|
||||
// Log (stale) user out
|
||||
s.SetCookie(ctx, "jwt_token", "", -1)
|
||||
s.SetCookie(ctx, "search-filters", "", -1)
|
||||
}
|
||||
|
||||
// Ensure logged in
|
||||
if !domain.IsLoggedIn(ctx) || user == nil {
|
||||
components.RenderErrorBanner(ctx, "User is not authorized to access this endpoint. Please login to continue.")
|
||||
ctx.JSON(http.StatusUnauthorized, gin.H{
|
||||
"status": http.StatusUnauthorized,
|
||||
"message": "User is not authorized to access this endpoint. Please login to continue.",
|
||||
"recipes": nil,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
recipes, err := s.deps.RecipeService.GetUserRecipes(user.Id)
|
||||
if err != nil {
|
||||
components.RenderErrorBanner(ctx, fmt.Sprintf("Could not get user recipes. %s", err.Error()))
|
||||
ctx.JSON(http.StatusBadRequest, gin.H{
|
||||
"status": http.StatusBadRequest,
|
||||
"message": fmt.Sprintf("Could not get user recipes. %s", err.Error()),
|
||||
"recipes": nil,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
ctx.JSON(http.StatusOK, gin.H{
|
||||
"status": http.StatusOK,
|
||||
"message": "User recipes successfully retrieved.",
|
||||
"recipes": recipes,
|
||||
})
|
||||
}
|
||||
|
||||
func (s *Server) GetUserFavoriteRecipesHandler(ctx *gin.Context) {
|
||||
// Ensure user is logged in with a valid account
|
||||
user := s.deps.UserService.GetAuthenicatedUser(ctx)
|
||||
if user == nil {
|
||||
// Log (stale) user out
|
||||
s.SetCookie(ctx, "jwt_token", "", -1)
|
||||
s.SetCookie(ctx, "search-filters", "", -1)
|
||||
}
|
||||
|
||||
// Ensure logged in
|
||||
if !domain.IsLoggedIn(ctx) || user == nil {
|
||||
components.RenderErrorBanner(ctx, "User is not authorized to access this endpoint. Please login to continue.")
|
||||
ctx.JSON(http.StatusUnauthorized, gin.H{
|
||||
"status": http.StatusUnauthorized,
|
||||
"message": "User is not authorized to access this endpoint. Please login to continue.",
|
||||
"recipes": nil,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
recipes, err := s.deps.RecipeService.GetUserFavoriteRecipes(user.Id)
|
||||
if err != nil {
|
||||
components.RenderErrorBanner(ctx, fmt.Sprintf("Could not get favorite recipes. %s", err.Error()))
|
||||
ctx.JSON(http.StatusBadRequest, gin.H{
|
||||
"status": http.StatusBadRequest,
|
||||
"message": fmt.Sprintf("Could not get favorite recipes. %s", err.Error()),
|
||||
"recipes": nil,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
ctx.JSON(http.StatusOK, gin.H{
|
||||
"status": http.StatusOK,
|
||||
"message": "User recipes successfully retrieved.",
|
||||
"recipes": recipes,
|
||||
})
|
||||
|
||||
}
|
||||
@ -3,7 +3,6 @@ package domain
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
@ -132,41 +131,43 @@ func LoadEnvironment() (*EnvironmentConfig, error) {
|
||||
//
|
||||
// If 0 is provided as the duration, then a session cookie is created, which will be cleared when
|
||||
// the browser is closed.
|
||||
func SetCookie(ctx *gin.Context, name, value string, duration time.Duration) {
|
||||
deps := ctx.MustGet("deps").(*InjectedDependencies)
|
||||
|
||||
var (
|
||||
path string = "/"
|
||||
httpOnly bool = true
|
||||
maxAge int
|
||||
secure bool
|
||||
domain string
|
||||
)
|
||||
|
||||
if duration < 0 {
|
||||
// Delete the cookie
|
||||
maxAge = -1
|
||||
} else if duration == 0 {
|
||||
// Session cookie, clears when browser is closed
|
||||
maxAge = 0
|
||||
} else {
|
||||
// Normal calculation
|
||||
maxAge = int(time.Now().Add(duration).Sub(time.Now()).Seconds())
|
||||
}
|
||||
|
||||
if deps.EnvironmentConfig.Environment == "prod" {
|
||||
secure = true
|
||||
domain = deps.EnvironmentConfig.Domain
|
||||
|
||||
} else if deps.EnvironmentConfig.Environment == "dev" {
|
||||
secure = false
|
||||
domain = deps.EnvironmentConfig.Domain
|
||||
|
||||
} else {
|
||||
// Defaults
|
||||
secure = false
|
||||
domain = ""
|
||||
}
|
||||
|
||||
ctx.SetCookie(name, value, maxAge, path, domain, secure, httpOnly)
|
||||
}
|
||||
//
|
||||
// DEPRECATED: As of September 4th, 2025.
|
||||
// func SetCookie(ctx *gin.Context, name, value string, duration time.Duration) {
|
||||
// deps := ctx.MustGet("deps").(*InjectedDependencies)
|
||||
//
|
||||
// var (
|
||||
// path string = "/"
|
||||
// httpOnly bool = true
|
||||
// maxAge int
|
||||
// secure bool
|
||||
// domain string
|
||||
// )
|
||||
//
|
||||
// if duration < 0 {
|
||||
// // Delete the cookie
|
||||
// maxAge = -1
|
||||
// } else if duration == 0 {
|
||||
// // Session cookie, clears when browser is closed
|
||||
// maxAge = 0
|
||||
// } else {
|
||||
// // Normal calculation
|
||||
// maxAge = int(time.Now().Add(duration).Sub(time.Now()).Seconds())
|
||||
// }
|
||||
//
|
||||
// if deps.EnvironmentConfig.Environment == "prod" {
|
||||
// secure = true
|
||||
// domain = deps.EnvironmentConfig.Domain
|
||||
//
|
||||
// } else if deps.EnvironmentConfig.Environment == "dev" {
|
||||
// secure = false
|
||||
// domain = deps.EnvironmentConfig.Domain
|
||||
//
|
||||
// } else {
|
||||
// // Defaults
|
||||
// secure = false
|
||||
// domain = ""
|
||||
// }
|
||||
//
|
||||
// ctx.SetCookie(name, value, maxAge, path, domain, secure, httpOnly)
|
||||
// }
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user