(DB/FEAT): Began the implementation of the user engagement! #18
@ -8,24 +8,55 @@ import (
|
|||||||
domain "github.com/haydenhargreaves/Potion/internal/domain/server"
|
domain "github.com/haydenhargreaves/Potion/internal/domain/server"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
func EngagementViewRecipe(ctx *gin.Context) {
|
func EngagementViewRecipe(ctx *gin.Context) {
|
||||||
deps := ctx.MustGet("deps").(*domain.InjectedDependencies)
|
deps := ctx.MustGet("deps").(*domain.InjectedDependencies)
|
||||||
id := ctx.Param("id")
|
recipeId, _ := strconv.Atoi(ctx.Param("id"))
|
||||||
|
|
||||||
if !domain.IsLoggedIn(ctx) {
|
if !domain.IsLoggedIn(ctx) {
|
||||||
// TODO: Anon view
|
if _, err := deps.EngagementService.ViewRecipe(recipeId); err != nil {
|
||||||
ctx.Status(http.StatusNoContent)
|
ctx.JSON(http.StatusInternalServerError, gin.H{
|
||||||
|
"status": http.StatusInternalServerError,
|
||||||
|
"message": err.Error(),
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
ctx.Status(http.StatusNoContent)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
recipeId, _ := strconv.Atoi(id)
|
|
||||||
userId := ctx.MustGet("userId").(int)
|
userId := ctx.MustGet("userId").(int)
|
||||||
|
|
||||||
if _, err := deps.EngagementService.UserViewRecipe(userId, recipeId); err != nil {
|
if _, err := deps.EngagementService.UserViewRecipe(userId, recipeId); err != nil {
|
||||||
ctx.JSON(http.StatusInternalServerError, gin.H{
|
ctx.JSON(http.StatusInternalServerError, gin.H{
|
||||||
"status": http.StatusInternalServerError,
|
"status": http.StatusInternalServerError,
|
||||||
|
"message": err.Error(),
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
ctx.Status(http.StatusNoContent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func EngagementShareRecipe(ctx *gin.Context) {
|
||||||
|
deps := ctx.MustGet("deps").(*domain.InjectedDependencies)
|
||||||
|
recipeId, _ := strconv.Atoi(ctx.Param("id"))
|
||||||
|
|
||||||
|
if !domain.IsLoggedIn(ctx) {
|
||||||
|
if _, err := deps.EngagementService.ShareRecipe(recipeId); err != nil {
|
||||||
|
ctx.JSON(http.StatusInternalServerError, gin.H{
|
||||||
|
"status": http.StatusInternalServerError,
|
||||||
|
"message": err.Error(),
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
ctx.Status(http.StatusNoContent)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
userId := ctx.MustGet("userId").(int)
|
||||||
|
|
||||||
|
if _, err := deps.EngagementService.UserShareRecipe(userId, recipeId); err != nil {
|
||||||
|
ctx.JSON(http.StatusInternalServerError, gin.H{
|
||||||
|
"status": http.StatusInternalServerError,
|
||||||
"message": err.Error(),
|
"message": err.Error(),
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
@ -48,7 +79,7 @@ func EngagementFavoriteRecipe(ctx *gin.Context) {
|
|||||||
|
|
||||||
if _, err := deps.EngagementService.UserFavoriteRecipe(userId, recipeId); err != nil {
|
if _, err := deps.EngagementService.UserFavoriteRecipe(userId, recipeId); err != nil {
|
||||||
ctx.JSON(http.StatusInternalServerError, gin.H{
|
ctx.JSON(http.StatusInternalServerError, gin.H{
|
||||||
"status": http.StatusInternalServerError,
|
"status": http.StatusInternalServerError,
|
||||||
"message": err.Error(),
|
"message": err.Error(),
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
@ -71,7 +102,7 @@ func EngagementMakeRecipe(ctx *gin.Context) {
|
|||||||
|
|
||||||
if _, err := deps.EngagementService.UserMakeRecipe(userId, recipeId); err != nil {
|
if _, err := deps.EngagementService.UserMakeRecipe(userId, recipeId); err != nil {
|
||||||
ctx.JSON(http.StatusInternalServerError, gin.H{
|
ctx.JSON(http.StatusInternalServerError, gin.H{
|
||||||
"status": http.StatusInternalServerError,
|
"status": http.StatusInternalServerError,
|
||||||
"message": err.Error(),
|
"message": err.Error(),
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -130,14 +130,12 @@ func RecipePage(ctx *gin.Context) {
|
|||||||
|
|
||||||
// Add engagement
|
// Add engagement
|
||||||
if loggedIn {
|
if loggedIn {
|
||||||
fmt.Println("CALLING USER VIEW")
|
|
||||||
if _, err = deps.EngagementService.UserViewRecipe(*userId, recipe.Id); err != nil {
|
if _, err = deps.EngagementService.UserViewRecipe(*userId, recipe.Id); err != nil {
|
||||||
fmt.Printf("ERROR: %s\n", err.Error())
|
fmt.Printf("ERROR: %s\n", err.Error())
|
||||||
ctx.JSON(400, err.Error())
|
ctx.JSON(400, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
fmt.Println("CALLING VIEW")
|
|
||||||
if _, err = deps.EngagementService.ViewRecipe(recipe.Id); err != nil {
|
if _, err = deps.EngagementService.ViewRecipe(recipe.Id); err != nil {
|
||||||
fmt.Printf("ERROR: %s\n", err.Error())
|
fmt.Printf("ERROR: %s\n", err.Error())
|
||||||
ctx.JSON(400, err.Error())
|
ctx.JSON(400, err.Error())
|
||||||
|
|||||||
@ -188,6 +188,7 @@ func (s *Server) Setup() *Server {
|
|||||||
|
|
||||||
// Engagement endpoints
|
// Engagement endpoints
|
||||||
router_api.POST("/engagement/view/:id", handlers.EngagementViewRecipe)
|
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/favorite/:id", handlers.EngagementFavoriteRecipe)
|
||||||
router_api.POST("/engagement/make/:id", handlers.EngagementMakeRecipe)
|
router_api.POST("/engagement/make/:id", handlers.EngagementMakeRecipe)
|
||||||
|
|
||||||
|
|||||||
@ -39,6 +39,20 @@ func (s *EngagementService) ViewRecipe(recipeId int) (domain.Engagement, error)
|
|||||||
return s.engagementRepository.AddEntityEngagement(recipeId, message, domain.EngagementViewed)
|
return s.engagementRepository.AddEntityEngagement(recipeId, message, domain.EngagementViewed)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ShareRecipe requires a user ID and a recipe ID to create an engagement record in the database.
|
||||||
|
// A message will be generated using the recipe data and then used to add a view engagement to the
|
||||||
|
// database.
|
||||||
|
func (s *EngagementService) ShareRecipe(recipeId int) (domain.Engagement, error) {
|
||||||
|
recipe, err := s.recipeRepository.GetRecipe(recipeId, nil)
|
||||||
|
if err != nil {
|
||||||
|
return domain.Engagement{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
message := fmt.Sprintf("Shared \"%s\"", recipe.Title)
|
||||||
|
|
||||||
|
return s.engagementRepository.AddEntityEngagement(recipeId, message, domain.EngagementShared)
|
||||||
|
}
|
||||||
|
|
||||||
// UserViewRecipe requires a user ID and a recipe ID to create an engagement record in the database.
|
// UserViewRecipe requires a user ID and a recipe ID to create an engagement record in the database.
|
||||||
// A message will be generated using the recipe data and then used to add a view engagement to the
|
// A message will be generated using the recipe data and then used to add a view engagement to the
|
||||||
// database.
|
// database.
|
||||||
@ -94,6 +108,20 @@ func (s *EngagementService) UserMakeRecipe(userId, recipeId int) (domain.Engagem
|
|||||||
return s.engagementRepository.AddUserEntityEngagement(userId, recipeId, message, domain.EngagementMade)
|
return s.engagementRepository.AddUserEntityEngagement(userId, recipeId, message, domain.EngagementMade)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UserShareRecipe requires a user ID and a recipe ID to create an engagement record in the database.
|
||||||
|
// A message will be generated using the recipe data and then used to add a make engagement to the
|
||||||
|
// database.
|
||||||
|
func (s *EngagementService) UserShareRecipe(userId, recipeId int) (domain.Engagement, error) {
|
||||||
|
recipe, err := s.recipeRepository.GetRecipe(recipeId, &userId)
|
||||||
|
if err != nil {
|
||||||
|
return domain.Engagement{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
message := fmt.Sprintf("Shared \"%s\"", recipe.Title)
|
||||||
|
|
||||||
|
return s.engagementRepository.AddUserEntityEngagement(userId, recipeId, message, domain.EngagementShared)
|
||||||
|
}
|
||||||
|
|
||||||
// GetUserEngagement returns a list of the users most recent engagement entries. The number of records
|
// GetUserEngagement returns a list of the users most recent engagement entries. The number of records
|
||||||
// is determined by the limit passed into this function. The results are sorted, newest-to-oldest.
|
// is determined by the limit passed into this function. The results are sorted, newest-to-oldest.
|
||||||
func (s *EngagementService) GetUserEngagement(userId, limit int) ([]domain.Engagement, error) {
|
func (s *EngagementService) GetUserEngagement(userId, limit int) ([]domain.Engagement, error) {
|
||||||
|
|||||||
@ -2,8 +2,10 @@ package domain
|
|||||||
|
|
||||||
type EngagementService interface {
|
type EngagementService interface {
|
||||||
ViewRecipe(recipeId int) (Engagement, error)
|
ViewRecipe(recipeId int) (Engagement, error)
|
||||||
|
ShareRecipe(recipeId int) (Engagement, error)
|
||||||
UserViewRecipe(userId, recipeId int) (Engagement, error)
|
UserViewRecipe(userId, recipeId int) (Engagement, error)
|
||||||
UserFavoriteRecipe(userId, recipeId int) (Engagement, error)
|
UserFavoriteRecipe(userId, recipeId int) (Engagement, error)
|
||||||
UserMakeRecipe(userId, recipeId int) (Engagement, error)
|
UserMakeRecipe(userId, recipeId int) (Engagement, error)
|
||||||
|
UserShareRecipe(userId, recipeId int) (Engagement, error)
|
||||||
GetUserEngagement(userId, limit int) ([]Engagement, error)
|
GetUserEngagement(userId, limit int) ([]Engagement, error)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -26,6 +26,7 @@ const API_CREATE_RECIPE = VERSION + API + "/recipe"
|
|||||||
const API_SEARCH_RECIPES = VERSION + API + "/recipe/search"
|
const API_SEARCH_RECIPES = VERSION + API + "/recipe/search"
|
||||||
|
|
||||||
const API_ENGAGEMENT_VIEW = VERSION + API + "/engagement/view/%d"
|
const API_ENGAGEMENT_VIEW = VERSION + API + "/engagement/view/%d"
|
||||||
|
const API_ENGAGEMENT_SHARE = VERSION + API + "/engagement/share/%d"
|
||||||
const API_ENGAGEMENT_FAVORITE = VERSION + API + "/engagement/favorite/%d"
|
const API_ENGAGEMENT_FAVORITE = VERSION + API + "/engagement/favorite/%d"
|
||||||
const API_ENGAGEMENT_MAKE = VERSION + API + "/engagement/make/%d"
|
const API_ENGAGEMENT_MAKE = VERSION + API + "/engagement/make/%d"
|
||||||
|
|
||||||
|
|||||||
@ -189,11 +189,11 @@ templ favoriteButton(favorited bool, id int, loggedIn bool) {
|
|||||||
hx-post={ fmt.Sprintf(domainServer.API_ENGAGEMENT_FAVORITE, id) }
|
hx-post={ fmt.Sprintf(domainServer.API_ENGAGEMENT_FAVORITE, id) }
|
||||||
hx-trigger="click"
|
hx-trigger="click"
|
||||||
hx-swap="none"
|
hx-swap="none"
|
||||||
if loggedIn {
|
if loggedIn {
|
||||||
hx-on:click="favoriteButtonHandler();"
|
hx-on:click="favoriteButtonHandler();"
|
||||||
}
|
}
|
||||||
class="flex items-center justify-center gap-x-1 rounded-lg border border-blue-300 bg-blue-50 text-gray-800 px-6 py-3 flex-grow hover:bg-blue-100 hover:border-blue-500 duration-300"
|
class="flex items-center justify-center gap-x-1 rounded-lg border border-blue-300 bg-blue-50 text-gray-800 px-6 py-3 flex-grow hover:bg-blue-100 hover:border-blue-500 duration-300"
|
||||||
id="favorite-button"
|
id="favorite-button"
|
||||||
>
|
>
|
||||||
<svg class="h-6 text-red-500" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
<svg class="h-6 text-red-500" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
<path
|
<path
|
||||||
@ -208,11 +208,11 @@ templ favoriteButton(favorited bool, id int, loggedIn bool) {
|
|||||||
hx-post={ fmt.Sprintf(domainServer.API_ENGAGEMENT_FAVORITE, id) }
|
hx-post={ fmt.Sprintf(domainServer.API_ENGAGEMENT_FAVORITE, id) }
|
||||||
hx-trigger="click"
|
hx-trigger="click"
|
||||||
hx-swap="none"
|
hx-swap="none"
|
||||||
if loggedIn {
|
if loggedIn {
|
||||||
hx-on:click="favoriteButtonHandler();"
|
hx-on:click="favoriteButtonHandler();"
|
||||||
}
|
}
|
||||||
class="flex items-center justify-center gap-x-1 rounded-lg border border-gray-300 text-gray-800 px-6 py-3 flex-grow hover:bg-gray-50 hover:border-blue-300 duration-300"
|
class="flex items-center justify-center gap-x-1 rounded-lg border border-gray-300 text-gray-800 px-6 py-3 flex-grow hover:bg-gray-50 hover:border-blue-300 duration-300"
|
||||||
id="favorite-button"
|
id="favorite-button"
|
||||||
>
|
>
|
||||||
<svg class="h-6" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
<svg class="h-6" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
<path
|
<path
|
||||||
@ -236,9 +236,9 @@ templ madeButton(id int, loggedIn bool) {
|
|||||||
hx-trigger="click"
|
hx-trigger="click"
|
||||||
hx-swap="none"
|
hx-swap="none"
|
||||||
id="make-button"
|
id="make-button"
|
||||||
if loggedIn {
|
if loggedIn {
|
||||||
hx-on:click="makeButtonHandler();"
|
hx-on:click="makeButtonHandler();"
|
||||||
}
|
}
|
||||||
class="flex items-center justify-center gap-x-1 rounded-lg border border-gray-300 text-gray-800 px-6 py-3 flex-grow hover:bg-gray-50 hover:border-blue-300 duration-300"
|
class="flex items-center justify-center gap-x-1 rounded-lg border border-gray-300 text-gray-800 px-6 py-3 flex-grow hover:bg-gray-50 hover:border-blue-300 duration-300"
|
||||||
>
|
>
|
||||||
<svg
|
<svg
|
||||||
@ -262,10 +262,13 @@ templ madeButton(id int, loggedIn bool) {
|
|||||||
</button>
|
</button>
|
||||||
}
|
}
|
||||||
|
|
||||||
templ shareButton() {
|
templ shareButton(id int) {
|
||||||
<button
|
<button
|
||||||
id="share-button"
|
id="share-button"
|
||||||
onclick="shareButtonHandler();"
|
hx-post={ fmt.Sprintf(domainServer.API_ENGAGEMENT_SHARE, id) }
|
||||||
|
hx-trigger="click"
|
||||||
|
hx-swap="none"
|
||||||
|
hx-on:click="shareButtonHandler();"
|
||||||
class="flex items-center justify-center gap-x-1 rounded-lg border border-gray-300 text-gray-800 px-6 py-3 flex-grow hover:bg-gray-50 hover:border-blue-300 duration-300"
|
class="flex items-center justify-center gap-x-1 rounded-lg border border-gray-300 text-gray-800 px-6 py-3 flex-grow hover:bg-gray-50 hover:border-blue-300 duration-300"
|
||||||
>
|
>
|
||||||
<svg class="h-7" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
<svg class="h-7" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
@ -284,7 +287,7 @@ templ buttonSection(favorited bool, id int, loggedIn bool) {
|
|||||||
<section class="w-full flex flex-col md:flex-row gap-x-4 gap-y-2 py-8 px-4 md:px-8">
|
<section class="w-full flex flex-col md:flex-row gap-x-4 gap-y-2 py-8 px-4 md:px-8">
|
||||||
@favoriteButton(favorited, id, loggedIn)
|
@favoriteButton(favorited, id, loggedIn)
|
||||||
@madeButton(id, loggedIn)
|
@madeButton(id, loggedIn)
|
||||||
@shareButton()
|
@shareButton(id)
|
||||||
</section>
|
</section>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Loading…
x
Reference in New Issue
Block a user