(FEAT): Implemented API for the share engagement.
This includes user and no user routes! Now wired to the frontend, however, it will still create an engagement even if it fails...
This commit is contained in:
parent
e4c1a575be
commit
2a33edc8f6
@ -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