(DB/FEAT): Began the implementation of the user engagement! #18
@ -129,15 +129,21 @@ func RecipePage(ctx *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add engagement
|
// Add engagement
|
||||||
if user != nil {
|
if loggedIn {
|
||||||
if _, err = deps.EngagementService.UserViewRecipe(user.Id, recipe.Id); err != nil {
|
fmt.Println("CALLING USER VIEW")
|
||||||
|
if _, err = deps.EngagementService.UserViewRecipe(*userId, recipe.Id); err != nil {
|
||||||
|
fmt.Printf("ERROR: %s\n", err.Error())
|
||||||
|
ctx.JSON(400, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fmt.Println("CALLING VIEW")
|
||||||
|
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())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// TODO: Need handling for anon viewing of the recipe
|
|
||||||
// I also do not really like that this runs on refresh, might need some better handling
|
|
||||||
|
|
||||||
title := "Potion - View Recipe"
|
title := "Potion - View Recipe"
|
||||||
page := pages.RecipePage(*recipe, *user, loggedIn)
|
page := pages.RecipePage(*recipe, *user, loggedIn)
|
||||||
|
|||||||
@ -25,6 +25,20 @@ func NewEngagementService(engagementRepository domain.EngagementRepository, reci
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ViewRecipe 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) ViewRecipe(recipeId int) (domain.Engagement, error) {
|
||||||
|
recipe, err := s.recipeRepository.GetRecipe(recipeId, nil)
|
||||||
|
if err != nil {
|
||||||
|
return domain.Engagement{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
message := fmt.Sprintf("Viewed \"%s\"", recipe.Title)
|
||||||
|
|
||||||
|
return s.engagementRepository.AddEntityEngagement(recipeId, message, domain.EngagementViewed)
|
||||||
|
}
|
||||||
|
|
||||||
// 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.
|
||||||
|
|||||||
@ -3,6 +3,8 @@ package domain
|
|||||||
type EngagementRepository interface {
|
type EngagementRepository interface {
|
||||||
AddUserEngagement(userId int, message string, engagementType EngagementType) (Engagement, error)
|
AddUserEngagement(userId int, message string, engagementType EngagementType) (Engagement, error)
|
||||||
AddUserEntityEngagement(userId, entityId int, message string, engagementType EngagementType) (Engagement, error)
|
AddUserEntityEngagement(userId, entityId int, message string, engagementType EngagementType) (Engagement, error)
|
||||||
|
AddEngagement(message string, engagementType EngagementType) (Engagement, error)
|
||||||
|
AddEntityEngagement(entityId int, message string, engagementType EngagementType) (Engagement, error)
|
||||||
GetUserEngagement(userId, limit int) ([]Engagement, error)
|
GetUserEngagement(userId, limit int) ([]Engagement, error)
|
||||||
UserFavoriteRecipeToggle(userId, recipeId int) (bool, error)
|
UserFavoriteRecipeToggle(userId, recipeId int) (bool, error)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
package domain
|
package domain
|
||||||
|
|
||||||
type EngagementService interface {
|
type EngagementService interface {
|
||||||
|
ViewRecipe(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)
|
||||||
|
|||||||
@ -44,12 +44,13 @@ func (r *EngagementRepository) AddUserEngagement(userId int, message string, eng
|
|||||||
`
|
`
|
||||||
|
|
||||||
var engagement domain.Engagement
|
var engagement domain.Engagement
|
||||||
|
var engUserId sql.NullInt32
|
||||||
if err := tx.QueryRow(query, engagementType, message, userId, time.Now()).Scan(
|
if err := tx.QueryRow(query, engagementType, message, userId, time.Now()).Scan(
|
||||||
&engagement.Id,
|
&engagement.Id,
|
||||||
&engagement.Type,
|
&engagement.Type,
|
||||||
&engagement.Message,
|
&engagement.Message,
|
||||||
&engagement.Entity,
|
&engagement.Entity,
|
||||||
&engagement.UserId,
|
&engUserId,
|
||||||
&engagement.Created,
|
&engagement.Created,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
tx.Rollback()
|
tx.Rollback()
|
||||||
@ -61,10 +62,15 @@ func (r *EngagementRepository) AddUserEngagement(userId int, message string, eng
|
|||||||
return domain.Engagement{}, err
|
return domain.Engagement{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Is user is valid
|
||||||
|
if engUserId.Valid {
|
||||||
|
engagement.UserId = int(engUserId.Int32)
|
||||||
|
}
|
||||||
|
|
||||||
return engagement, nil
|
return engagement, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddUserEngagement creates an engagement record in the database with the user ID provided. This
|
// AddUserEntityEngagement creates an engagement record in the database with the user ID provided. This
|
||||||
// function requires an entity ID as it should be used when there is a reference to external an
|
// function requires an entity ID as it should be used when there is a reference to external an
|
||||||
// entity. The message should be provided, but a blank string ("") is acceptable. The engagement
|
// entity. The message should be provided, but a blank string ("") is acceptable. The engagement
|
||||||
// type parameter determines the labeling of the engagement in the database. Any errors will be
|
// type parameter determines the labeling of the engagement in the database. Any errors will be
|
||||||
@ -87,12 +93,13 @@ func (r *EngagementRepository) AddUserEntityEngagement(userId, entityId int, mes
|
|||||||
`
|
`
|
||||||
|
|
||||||
var engagement domain.Engagement
|
var engagement domain.Engagement
|
||||||
|
var engUserId sql.NullInt32
|
||||||
if err := tx.QueryRow(query, engagementType, message, entityId, userId, time.Now()).Scan(
|
if err := tx.QueryRow(query, engagementType, message, entityId, userId, time.Now()).Scan(
|
||||||
&engagement.Id,
|
&engagement.Id,
|
||||||
&engagement.Type,
|
&engagement.Type,
|
||||||
&engagement.Message,
|
&engagement.Message,
|
||||||
&engagement.Entity,
|
&engagement.Entity,
|
||||||
&engagement.UserId,
|
&engUserId,
|
||||||
&engagement.Created,
|
&engagement.Created,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
tx.Rollback()
|
tx.Rollback()
|
||||||
@ -104,6 +111,133 @@ func (r *EngagementRepository) AddUserEntityEngagement(userId, entityId int, mes
|
|||||||
return domain.Engagement{}, err
|
return domain.Engagement{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Is user is valid
|
||||||
|
if engUserId.Valid {
|
||||||
|
engagement.UserId = int(engUserId.Int32)
|
||||||
|
}
|
||||||
|
|
||||||
|
return engagement, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddEngagement creates an engagement record in the database without any user. This function does
|
||||||
|
// not accept an entity ID as it should be used when there is no need to reference an entity or user.
|
||||||
|
// The message should be provided, but a blank string ("") is acceptable. The engagement type
|
||||||
|
// parameter determines the labeling of the engagement in the database. Any errors will be bubbled
|
||||||
|
// to the caller.
|
||||||
|
//
|
||||||
|
// List of allowed engagements: viewed, shared
|
||||||
|
func (r *EngagementRepository) AddEngagement(message string, engagementType domain.EngagementType) (domain.Engagement, error) {
|
||||||
|
// Prevent invalid engagement types
|
||||||
|
switch engagementType {
|
||||||
|
case domain.EngagementViewed:
|
||||||
|
case domain.EngagementShared:
|
||||||
|
break
|
||||||
|
case domain.EngagementMade:
|
||||||
|
case domain.EngagementLiked:
|
||||||
|
case domain.EngagementReviewed:
|
||||||
|
case domain.EngagementRated:
|
||||||
|
return domain.Engagement{}, fmt.Errorf("Attempting to use disallowed anonymous engagement type.")
|
||||||
|
}
|
||||||
|
|
||||||
|
tx, err := r.db.Begin()
|
||||||
|
if err != nil {
|
||||||
|
tx.Rollback()
|
||||||
|
return domain.Engagement{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
query := `
|
||||||
|
INSERT INTO Engagements (
|
||||||
|
type, message, entity, userid, created
|
||||||
|
) VALUES (
|
||||||
|
$1, $2, NULL, NULL, $3
|
||||||
|
) RETURNING *;
|
||||||
|
`
|
||||||
|
|
||||||
|
var engagement domain.Engagement
|
||||||
|
var userId sql.NullInt32
|
||||||
|
if err := tx.QueryRow(query, engagementType, message, time.Now()).Scan(
|
||||||
|
&engagement.Id,
|
||||||
|
&engagement.Type,
|
||||||
|
&engagement.Message,
|
||||||
|
&engagement.Entity,
|
||||||
|
&userId,
|
||||||
|
&engagement.Created,
|
||||||
|
); err != nil {
|
||||||
|
tx.Rollback()
|
||||||
|
return domain.Engagement{}, fmt.Errorf("Failed to insert engagement into database. %s", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := tx.Commit(); err != nil {
|
||||||
|
tx.Rollback()
|
||||||
|
return domain.Engagement{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Is user is valid
|
||||||
|
if userId.Valid {
|
||||||
|
engagement.UserId = int(userId.Int32)
|
||||||
|
}
|
||||||
|
|
||||||
|
return engagement, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddEntityEngagement creates an engagement record in the database without any user. This function
|
||||||
|
// requires an entity ID as it should be used when there is a reference to external an entity.
|
||||||
|
// The message should be provided, but a blank string ("") is acceptable. The engagement type
|
||||||
|
// parameter determines the labeling of the engagement in the database. Any errors will be
|
||||||
|
// bubbled to the caller.
|
||||||
|
//
|
||||||
|
// List of allowed engagements: viewed, shared
|
||||||
|
func (r *EngagementRepository) AddEntityEngagement(entityId int, message string, engagementType domain.EngagementType) (domain.Engagement, error) {
|
||||||
|
// Prevent invalid engagement types
|
||||||
|
switch engagementType {
|
||||||
|
case domain.EngagementViewed:
|
||||||
|
case domain.EngagementShared:
|
||||||
|
break
|
||||||
|
case domain.EngagementMade:
|
||||||
|
case domain.EngagementLiked:
|
||||||
|
case domain.EngagementReviewed:
|
||||||
|
case domain.EngagementRated:
|
||||||
|
return domain.Engagement{}, fmt.Errorf("Attempting to use disallowed anonymous engagement type.")
|
||||||
|
}
|
||||||
|
|
||||||
|
tx, err := r.db.Begin()
|
||||||
|
if err != nil {
|
||||||
|
tx.Rollback()
|
||||||
|
return domain.Engagement{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
query := `
|
||||||
|
INSERT INTO Engagements (
|
||||||
|
type, message, entity, userid, created
|
||||||
|
) VALUES (
|
||||||
|
$1, $2, $3, NULL, $4
|
||||||
|
) RETURNING *;
|
||||||
|
`
|
||||||
|
|
||||||
|
var engagement domain.Engagement
|
||||||
|
var userId sql.NullInt32
|
||||||
|
if err := tx.QueryRow(query, engagementType, message, entityId, time.Now()).Scan(
|
||||||
|
&engagement.Id,
|
||||||
|
&engagement.Type,
|
||||||
|
&engagement.Message,
|
||||||
|
&engagement.Entity,
|
||||||
|
&userId,
|
||||||
|
&engagement.Created,
|
||||||
|
); err != nil {
|
||||||
|
tx.Rollback()
|
||||||
|
return domain.Engagement{}, fmt.Errorf("Failed to insert engagement into database. %s", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := tx.Commit(); err != nil {
|
||||||
|
tx.Rollback()
|
||||||
|
return domain.Engagement{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Is user is valid
|
||||||
|
if userId.Valid {
|
||||||
|
engagement.UserId = int(userId.Int32)
|
||||||
|
}
|
||||||
|
|
||||||
return engagement, nil
|
return engagement, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,18 +266,24 @@ func (r *EngagementRepository) GetUserEngagement(userId, limit int) ([]domain.En
|
|||||||
var engagements []domain.Engagement
|
var engagements []domain.Engagement
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var engagement domain.Engagement
|
var engagement domain.Engagement
|
||||||
|
var engUserId sql.NullInt32
|
||||||
if err := rows.Scan(
|
if err := rows.Scan(
|
||||||
&engagement.Id,
|
&engagement.Id,
|
||||||
&engagement.Type,
|
&engagement.Type,
|
||||||
&engagement.Message,
|
&engagement.Message,
|
||||||
&engagement.Entity,
|
&engagement.Entity,
|
||||||
&engagement.UserId,
|
&engUserId,
|
||||||
&engagement.Created,
|
&engagement.Created,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
tx.Rollback()
|
tx.Rollback()
|
||||||
return []domain.Engagement{}, fmt.Errorf("Failed to scan user engagement. %s", err.Error())
|
return []domain.Engagement{}, fmt.Errorf("Failed to scan user engagement. %s", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add user if valid
|
||||||
|
if engUserId.Valid {
|
||||||
|
engagement.UserId = int(engUserId.Int32)
|
||||||
|
}
|
||||||
|
|
||||||
engagements = append(engagements, engagement)
|
engagements = append(engagements, engagement)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user