diff --git a/internal/app/handlers/auth_handler.go b/internal/app/handlers/auth_handler.go index e21d3cf..4fa0a66 100644 --- a/internal/app/handlers/auth_handler.go +++ b/internal/app/handlers/auth_handler.go @@ -36,18 +36,7 @@ func GoogleCallback(ctx *gin.Context) { if jwt, dbUser, googleUserInfo, err := deps.AuthService.GoogleAuthSuccess(state, code); err != nil { ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) } else { - // TODO: Update these values when using a real domain. Maybe an ENV? domain.SetCookie(ctx, "jwt_token", jwt, time.Hour*24*7) - // ctx.SetCookie( - // "jwt_token", - // jwt, - // int(time.Now().Add(7*24*time.Hour).Sub(time.Now()).Seconds()), - // "/", - // "", // TODO: Real live domain - // false, // TODO: True in prod - // true, - // ) - // ctx.JSON(http.StatusOK, gin.H{"jwt": jwt, "googleUserInfo": googleUserInfo, "dbUser": dbUser}) _ = dbUser _ = googleUserInfo @@ -60,11 +49,7 @@ func GoogleCallback(ctx *gin.Context) { // 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) { - // TODO: Use same values as the GoogleCallback function domain.SetCookie(ctx, "jwt_token", "", -1) domain.SetCookie(ctx, "search-filters", "", -1) - // ctx.SetCookie("jwt_token", "", -1, "/", "", false, true) // TODO: Update settings - // ctx.SetCookie("search-filters", "", -1, "/", "", false, true) - ctx.Redirect(http.StatusSeeOther, domain.WEB_HOME) } diff --git a/internal/app/handlers/engagement_handler.go b/internal/app/handlers/engagement_handler.go index 1f80b7b..1c1f00b 100644 --- a/internal/app/handlers/engagement_handler.go +++ b/internal/app/handlers/engagement_handler.go @@ -13,7 +13,15 @@ func EngagementViewRecipe(ctx *gin.Context) { deps := ctx.MustGet("deps").(*domain.InjectedDependencies) recipeId, _ := strconv.Atoi(ctx.Param("id")) - if !domain.IsLoggedIn(ctx) { + // 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 { ctx.JSON(http.StatusInternalServerError, gin.H{ "status": http.StatusInternalServerError, @@ -26,9 +34,8 @@ func EngagementViewRecipe(ctx *gin.Context) { return } - userId := ctx.MustGet("userId").(int) - - if _, err := deps.EngagementService.UserViewRecipe(userId, recipeId); err != nil { + // We caught nil already, we can assume the user exists + if _, err := deps.EngagementService.UserViewRecipe(user.Id, recipeId); err != nil { ctx.JSON(http.StatusInternalServerError, gin.H{ "status": http.StatusInternalServerError, "message": err.Error(), @@ -43,7 +50,15 @@ func EngagementShareRecipe(ctx *gin.Context) { deps := ctx.MustGet("deps").(*domain.InjectedDependencies) recipeId, _ := strconv.Atoi(ctx.Param("id")) - if !domain.IsLoggedIn(ctx) { + // 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 { ctx.JSON(http.StatusInternalServerError, gin.H{ "status": http.StatusInternalServerError, @@ -55,9 +70,7 @@ func EngagementShareRecipe(ctx *gin.Context) { return } - userId := ctx.MustGet("userId").(int) - - if _, err := deps.EngagementService.UserShareRecipe(userId, recipeId); err != nil { + if _, err := deps.EngagementService.UserShareRecipe(user.Id, recipeId); err != nil { ctx.JSON(http.StatusInternalServerError, gin.H{ "status": http.StatusInternalServerError, "message": err.Error(), @@ -70,7 +83,15 @@ func EngagementShareRecipe(ctx *gin.Context) { func EngagementFavoriteRecipe(ctx *gin.Context) { deps := ctx.MustGet("deps").(*domain.InjectedDependencies) - if !domain.IsLoggedIn(ctx) { + // 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 @@ -78,9 +99,8 @@ func EngagementFavoriteRecipe(ctx *gin.Context) { id := ctx.Param("id") recipeId, _ := strconv.Atoi(id) - userId := ctx.MustGet("userId").(int) - if _, err := deps.EngagementService.UserFavoriteRecipe(userId, recipeId); err != nil { + if _, err := deps.EngagementService.UserFavoriteRecipe(user.Id, recipeId); err != nil { ctx.JSON(http.StatusInternalServerError, gin.H{ "status": http.StatusInternalServerError, "message": err.Error(), diff --git a/internal/app/handlers/page_handler.go b/internal/app/handlers/page_handler.go old mode 100644 new mode 100755 index 0f3629e..a29b705 --- a/internal/app/handlers/page_handler.go +++ b/internal/app/handlers/page_handler.go @@ -28,6 +28,14 @@ func HomePage(ctx *gin.Context) { 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) @@ -58,7 +66,18 @@ func HomePage(ctx *gin.Context) { return } - page = templates.HomePage(true, viewedRecipes, madeRecipes, recipeOfTheWeek) + 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) @@ -70,7 +89,18 @@ func HomePage(ctx *gin.Context) { return } - page = templates.HomePage(false, nil, nil, recipeOfTheWeek) + 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" @@ -91,14 +121,14 @@ func FavoritesPage(ctx *gin.Context) { // 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(domainRecipe.SearchFilters{}) + 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(domainRecipe.SearchFilters{}) + page = pages.FavoritesPage(nil) } else { - page = pages.FavoritesPage(filters) + page = pages.FavoritesPage(&filters) } } @@ -106,12 +136,24 @@ func FavoritesPage(ctx *gin.Context) { } 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() @@ -128,6 +170,12 @@ func ProfilePage(ctx *gin.Context) { // 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 { ctx.JSON(http.StatusInternalServerError, gin.H{ @@ -157,7 +205,7 @@ func ProfilePage(ctx *gin.Context) { } title := "Potion - Profile" - page := pages.ProfilePage(user, recipes, favorites, engagements) + page := pages.ProfilePage(*user, recipes, favorites, engagements) ctx.HTML(http.StatusOK, "", layouts.AppLayout(title, page)) } @@ -186,6 +234,15 @@ func RecipePage(ctx *gin.Context) { // 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 @@ -218,14 +275,14 @@ func SearchPage(ctx *gin.Context) { // 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(domainRecipe.SearchFilters{}, false) + 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(domainRecipe.SearchFilters{}, false) + page = pages.SearchPage(nil, false) } else { - page = pages.SearchPage(filters, true) + page = pages.SearchPage(&filters, true) } } diff --git a/internal/app/handlers/recipe_handler.go b/internal/app/handlers/recipe_handler.go index 3a85be0..2d24556 100644 --- a/internal/app/handlers/recipe_handler.go +++ b/internal/app/handlers/recipe_handler.go @@ -84,6 +84,8 @@ func SearchRecipes(ctx *gin.Context) { 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 { diff --git a/internal/app/handlers/user_handler.go b/internal/app/handlers/user_handler.go index c5508bf..e19cd18 100644 --- a/internal/app/handlers/user_handler.go +++ b/internal/app/handlers/user_handler.go @@ -11,8 +11,16 @@ import ( 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) { + if !domain.IsLoggedIn(ctx) || user == nil { ctx.JSON(http.StatusUnauthorized, gin.H{ "status": http.StatusUnauthorized, "message": "User is not authorized to access this endpoint. Please login to continue.", @@ -21,17 +29,7 @@ func GetUserRecipes(ctx *gin.Context) { return } - userId, ok := ctx.MustGet("userId").(int) - if !ok { - ctx.JSON(http.StatusInternalServerError, gin.H{ - "status": http.StatusInternalServerError, - "message": "Unable to access user id from store.", - "recipes": nil, - }) - return - } - - recipes, err := deps.RecipeService.GetUserRecipes(userId) + recipes, err := deps.RecipeService.GetUserRecipes(user.Id) if err != nil { ctx.JSON(http.StatusBadRequest, gin.H{ "status": http.StatusBadRequest, @@ -51,8 +49,16 @@ func GetUserRecipes(ctx *gin.Context) { 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) { + if !domain.IsLoggedIn(ctx) || user == nil { ctx.JSON(http.StatusUnauthorized, gin.H{ "status": http.StatusUnauthorized, "message": "User is not authorized to access this endpoint. Please login to continue.", @@ -61,17 +67,7 @@ func GetUserFavoriteRecipes(ctx *gin.Context) { return } - userId, ok := ctx.MustGet("userId").(int) - if !ok { - ctx.JSON(http.StatusInternalServerError, gin.H{ - "status": http.StatusInternalServerError, - "message": "Unable to access user id from store.", - "recipes": nil, - }) - return - } - - recipes, err := deps.RecipeService.GetUserFavoriteRecipes(userId) + recipes, err := deps.RecipeService.GetUserFavoriteRecipes(user.Id) if err != nil { ctx.JSON(http.StatusBadRequest, gin.H{ "status": http.StatusBadRequest, diff --git a/internal/app/service/user_service.go b/internal/app/service/user_service.go index 96b257d..f49b93e 100644 --- a/internal/app/service/user_service.go +++ b/internal/app/service/user_service.go @@ -25,19 +25,19 @@ func NewUserService(userRepository domain.UserRepository) domain.UserService { // user is actually logged in, if not, a blank user will be returned. To ensure success, call the // `domain.IsLoggedIn()` function first to ensure the user is logged in. If that passes, this // function should yield a result. -func (s *UserService) GetAuthenicatedUser(ctx *gin.Context) domain.User { +func (s *UserService) GetAuthenicatedUser(ctx *gin.Context) *domain.User { val, ok := ctx.Get("userId") if !ok { - return domain.User{} + return nil } id := val.(int) user, err := s.userRepository.GetUser(id) if err != nil { - return domain.User{} + return nil } - return *user + return user } // GetUser will get a user from the database via its ID. This is not related to the Google ID in diff --git a/internal/domain/user/service.go b/internal/domain/user/service.go index 16a7629..ddf835c 100644 --- a/internal/domain/user/service.go +++ b/internal/domain/user/service.go @@ -3,6 +3,6 @@ package domain import "github.com/gin-gonic/gin" type UserService interface { - GetAuthenicatedUser(ctx *gin.Context) User + GetAuthenicatedUser(ctx *gin.Context) *User GetUser(id int) (*User, error) } diff --git a/internal/infrastructure/database/repository/engagement_repository.go b/internal/infrastructure/database/repository/engagement_repository.go index 90e8cac..906bd5e 100644 --- a/internal/infrastructure/database/repository/engagement_repository.go +++ b/internal/infrastructure/database/repository/engagement_repository.go @@ -244,21 +244,14 @@ func (r *EngagementRepository) AddEntityEngagement(entityId int, message string, // 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. func (r *EngagementRepository) GetUserEngagement(userId, limit int) ([]domain.Engagement, error) { - tx, err := r.db.Begin() - if err != nil { - tx.Rollback() - return []domain.Engagement{}, err - } - query := ` SELECT * FROM Engagements WHERE Userid = $1 ORDER BY created DESC LIMIT $2; ` - rows, err := tx.Query(query, userId, limit) + rows, err := r.db.Query(query, userId, limit) if err != nil { - tx.Rollback() return []domain.Engagement{}, fmt.Errorf("Failed to get user engagements. %s", err.Error()) } defer rows.Close() @@ -275,7 +268,6 @@ func (r *EngagementRepository) GetUserEngagement(userId, limit int) ([]domain.En &engUserId, &engagement.Created, ); err != nil { - tx.Rollback() return []domain.Engagement{}, fmt.Errorf("Failed to scan user engagement. %s", err.Error()) } @@ -287,11 +279,6 @@ func (r *EngagementRepository) GetUserEngagement(userId, limit int) ([]domain.En engagements = append(engagements, engagement) } - if err := tx.Commit(); err != nil { - tx.Rollback() - return []domain.Engagement{}, err - } - return engagements, err } @@ -299,12 +286,6 @@ func (r *EngagementRepository) GetUserEngagement(userId, limit int) ([]domain.En // type. The number of records is determined by the limit passed into this function. The results are // sorted, newest-to-oldest. Only results of the provided engagementType will be returned. func (r *EngagementRepository) GetUserEngagementFiltered(userId, limit int, engagementType domain.EngagementType) ([]domain.Engagement, error) { - tx, err := r.db.Begin() - if err != nil { - tx.Rollback() - return []domain.Engagement{}, err - } - query := ` SELECT id, type, message, entity, userid, created FROM ( @@ -319,9 +300,8 @@ func (r *EngagementRepository) GetUserEngagementFiltered(userId, limit int, enga LIMIT $3; ` - rows, err := tx.Query(query, userId, engagementType, limit) + rows, err := r.db.Query(query, userId, engagementType, limit) if err != nil { - tx.Rollback() return []domain.Engagement{}, fmt.Errorf("Failed to get user engagements. %s", err.Error()) } defer rows.Close() @@ -338,7 +318,6 @@ func (r *EngagementRepository) GetUserEngagementFiltered(userId, limit int, enga &engUserId, &engagement.Created, ); err != nil { - tx.Rollback() return []domain.Engagement{}, fmt.Errorf("Failed to scan user engagement. %s", err.Error()) } @@ -350,13 +329,7 @@ func (r *EngagementRepository) GetUserEngagementFiltered(userId, limit int, enga engagements = append(engagements, engagement) } - if err := tx.Commit(); err != nil { - tx.Rollback() - return []domain.Engagement{}, err - } - return engagements, err - } // UserFavoriteRecipeToggle toggles the status of a users favorite of a recipe. If the user has already diff --git a/internal/infrastructure/database/repository/recipe_repository.go b/internal/infrastructure/database/repository/recipe_repository.go index 9a758c9..5a4d437 100644 --- a/internal/infrastructure/database/repository/recipe_repository.go +++ b/internal/infrastructure/database/repository/recipe_repository.go @@ -94,12 +94,6 @@ func (r *RecipeRepository) CreateRecipe(recipe *domain.Recipe) error { // for added safety. The repository will not check for a nil result, instead the service will. Callers // are responsible for protecting against double nil results. Any errors will be bubbled to the caller. func (r *RecipeRepository) GetRecipe(id int, userId *int) (*domain.Recipe, error) { - tx, err := r.db.Begin() - if err != nil { - tx.Rollback() - return nil, err - } - query := ` SELECT id, title, description, instructions, serves, difficulty, duration, category, ingredients, @@ -112,7 +106,7 @@ func (r *RecipeRepository) GetRecipe(id int, userId *int) (*domain.Recipe, error var ingredientBytes []byte var recipe domain.Recipe - if err := tx.QueryRow(query, id).Scan( + if err := r.db.QueryRow(query, id).Scan( &recipe.Id, &recipe.Title, &recipe.Description, @@ -167,11 +161,6 @@ func (r *RecipeRepository) GetRecipe(id int, userId *int) (*domain.Recipe, error recipe.Favorite = false } - if err := tx.Commit(); err != nil { - tx.Rollback() - return nil, err - } - return &recipe, nil } @@ -180,12 +169,6 @@ func (r *RecipeRepository) GetRecipe(id int, userId *int) (*domain.Recipe, error // will. Callers are responsible for protecting against double nil results. Any errors will be bubbled // to the caller. func (r *RecipeRepository) GetRecipes(ids []int, userId *int) ([]domain.Recipe, error) { - tx, err := r.db.Begin() - if err != nil { - tx.Rollback() - return nil, err - } - query := ` SELECT id, title, description, instructions, serves, difficulty, duration, category, ingredients, userid, modified, created @@ -196,9 +179,8 @@ func (r *RecipeRepository) GetRecipes(ids []int, userId *int) ([]domain.Recipe, var recipes []domain.Recipe - rows, err := tx.Query(query, pq.Array(ids)) + rows, err := r.db.Query(query, pq.Array(ids)) if err != nil { - tx.Rollback() return nil, fmt.Errorf("Failed to get recipes. %s", err.Error()) } defer rows.Close() @@ -266,11 +248,6 @@ func (r *RecipeRepository) GetRecipes(ids []int, userId *int) ([]domain.Recipe, recipes = append(recipes, recipe) } - if err := tx.Commit(); err != nil { - tx.Rollback() - return nil, err - } - return recipes, nil } @@ -288,12 +265,6 @@ func isBitActive(bits, pos int) bool { // // TODO: Pagination is required, to provide infinite scroll. func (r *RecipeRepository) SearchRecipes(filters domain.SearchFilters, userId *int, favorites bool) ([]domain.Recipe, error) { - tx, err := r.db.Begin() - if err != nil { - tx.Rollback() - return nil, err - } - // Compute meals type filters (there are 7 bits) var mealConditions []string for i := range 7 { @@ -442,7 +413,7 @@ func (r *RecipeRepository) SearchRecipes(filters domain.SearchFilters, userId *i query += ";" // Execute the query - rows, err := tx.Query(query) + rows, err := r.db.Query(query) if err != nil { return nil, fmt.Errorf("failed to query recipes: %w", err) } @@ -513,11 +484,6 @@ func (r *RecipeRepository) SearchRecipes(filters domain.SearchFilters, userId *i recipes = append(recipes, recipe) } - if err := tx.Commit(); err != nil { - tx.Rollback() - return nil, err - } - return recipes, nil } @@ -584,12 +550,6 @@ func (r *RecipeRepository) CreateRecipeTags(recipe domain.Recipe, tags []string) // authenticated or exists. If nothing is found, a blank slice will be returned. The resulting list // is sorted by the created dates, newest first. Any errors will be bubbled to the caller. func (r *RecipeRepository) GetUserRecipes(id int) ([]domain.Recipe, error) { - tx, err := r.db.Begin() - if err != nil { - tx.Rollback() - return nil, err - } - query := ` SELECT id, title, description, instructions, serves, difficulty, duration, category, ingredients, userid, modified, created @@ -598,7 +558,7 @@ func (r *RecipeRepository) GetUserRecipes(id int) ([]domain.Recipe, error) { ORDER BY created DESC; ` - rows, err := tx.Query(query, id) + rows, err := r.db.Query(query, id) if err != nil { return nil, fmt.Errorf("Failed to query DB for user recipes. %s\n", err.Error()) } @@ -669,11 +629,6 @@ func (r *RecipeRepository) GetUserRecipes(id int) ([]domain.Recipe, error) { recipes = append(recipes, recipe) } - if err := tx.Commit(); err != nil { - tx.Rollback() - return nil, err - } - return recipes, nil } @@ -681,12 +636,6 @@ func (r *RecipeRepository) GetUserRecipes(id int) ([]domain.Recipe, error) { // authenticated or exists. If nothing is found, a blank slice will be returned. The resulting list // is sorted by the created dates, newest first. Any errors will be bubbled to the caller. func (r *RecipeRepository) GetUserFavoriteRecipes(id int) ([]domain.Recipe, error) { - tx, err := r.db.Begin() - if err != nil { - tx.Rollback() - return nil, err - } - query := ` SELECT r.id, r.title, r.description, r.instructions, r.serves, r.difficulty, r.duration, r.category, r.ingredients, r. userid, r.modified, r.created @@ -695,7 +644,7 @@ func (r *RecipeRepository) GetUserFavoriteRecipes(id int) ([]domain.Recipe, erro WHERE f.userid = $1 ORDER BY f.created DESC; ` - rows, err := tx.Query(query, id) + rows, err := r.db.Query(query, id) if err != nil { return nil, fmt.Errorf("Failed to query DB for user recipes. %s\n", err.Error()) } @@ -760,11 +709,6 @@ func (r *RecipeRepository) GetUserFavoriteRecipes(id int) ([]domain.Recipe, erro recipes = append(recipes, recipe) } - if err := tx.Commit(); err != nil { - tx.Rollback() - return nil, err - } - return recipes, nil } @@ -777,12 +721,6 @@ func (r *RecipeRepository) GetRecipeTags(recipe *domain.Recipe) error { return nil } - tx, err := r.db.Begin() - if err != nil { - tx.Rollback() - return err - } - recipe.Tags = []domain.Tag{} query := ` @@ -790,7 +728,7 @@ func (r *RecipeRepository) GetRecipeTags(recipe *domain.Recipe) error { JOIN recipetags rt ON rt.tagid = t.id WHERE rt.recipeid = $1; ` - rows, err := tx.Query(query, recipe.Id) + rows, err := r.db.Query(query, recipe.Id) if err != nil { return fmt.Errorf("Failed to get tags for recipe. %s\n", err.Error()) } @@ -807,11 +745,6 @@ func (r *RecipeRepository) GetRecipeTags(recipe *domain.Recipe) error { recipe.Tags = append(recipe.Tags, tag) } - if err := tx.Commit(); err != nil { - tx.Rollback() - return err - } - return nil } @@ -824,12 +757,6 @@ func (r *RecipeRepository) GetRecipeFavorite(recipe *domain.Recipe, userId int) return nil } - tx, err := r.db.Begin() - if err != nil { - tx.Rollback() - return err - } - query := ` SELECT COUNT(*) FROM favorites @@ -837,8 +764,7 @@ func (r *RecipeRepository) GetRecipeFavorite(recipe *domain.Recipe, userId int) ` var count int - if err := tx.QueryRow(query, recipe.Id, userId).Scan(&count); err != nil { - tx.Rollback() + if err := r.db.QueryRow(query, recipe.Id, userId).Scan(&count); err != nil { return fmt.Errorf("Failed to get recipe favorite. %s", err.Error()) } @@ -852,12 +778,6 @@ func (r *RecipeRepository) GetRecipeFavorite(recipe *domain.Recipe, userId int) // table and return it. If there is no entry, nil will be returned Any errors will be bubbled to // the caller. func (r *RecipeRepository) GetRecipeOfTheWeek(userId *int) (*domain.Recipe, error) { - tx, err := r.db.Begin() - if err != nil { - tx.Rollback() - return nil, err - } - query := ` SELECT r.id, r.title, r.description, r.instructions, r.serves, r.difficulty, r.duration, r.category, @@ -872,7 +792,7 @@ func (r *RecipeRepository) GetRecipeOfTheWeek(userId *int) (*domain.Recipe, erro var ingredientBytes []byte var recipe domain.Recipe - if err := tx.QueryRow(query).Scan( + if err := r.db.QueryRow(query).Scan( &recipe.Id, &recipe.Title, &recipe.Description, @@ -930,10 +850,5 @@ func (r *RecipeRepository) GetRecipeOfTheWeek(userId *int) (*domain.Recipe, erro recipe.Favorite = false } - if err := tx.Commit(); err != nil { - tx.Rollback() - return nil, err - } - return &recipe, nil } diff --git a/internal/infrastructure/database/repository/user_repository.go b/internal/infrastructure/database/repository/user_repository.go index b593d3d..ee198b5 100644 --- a/internal/infrastructure/database/repository/user_repository.go +++ b/internal/infrastructure/database/repository/user_repository.go @@ -77,16 +77,10 @@ func (r *UserRepository) CreateGoogleUser(googleUserInfo *domain.GoogleUserInfo, // function is used when a user logs in with Google to prevent duplicate entries from being made. If // no user is found, this function will return a null pointer but not an error. func (r *UserRepository) GetGoogleUser(googleId string) (*domain.User, error) { - tx, err := r.db.Begin() - if err != nil { - tx.Rollback() - return nil, err - } - var user domain.User query := `SELECT * FROM users WHERE GoogleId = $1` - if err := tx.QueryRow(query, googleId).Scan( + if err := r.db.QueryRow(query, googleId).Scan( &user.Id, &user.GoogleId, &user.Name, @@ -99,12 +93,6 @@ func (r *UserRepository) GetGoogleUser(googleId string) (*domain.User, error) { if err == sql.ErrNoRows { return nil, nil } - tx.Rollback() - return nil, err - } - - if err := tx.Commit(); err != nil { - tx.Rollback() return nil, err } @@ -116,16 +104,10 @@ func (r *UserRepository) GetGoogleUser(googleId string) (*domain.User, error) { // Callers are responsible for protecting against double nil results. Any errors will be bubbled // to the caller. func (r *UserRepository) GetUser(id int) (*domain.User, error) { - tx, err := r.db.Begin() - if err != nil { - tx.Rollback() - return nil, err - } - query := "SELECT * FROM users WHERE id = $1" var user domain.User - if err := tx.QueryRow(query, id).Scan( + if err := r.db.QueryRow(query, id).Scan( &user.Id, &user.GoogleId, &user.Name, @@ -138,15 +120,8 @@ func (r *UserRepository) GetUser(id int) (*domain.User, error) { if err == sql.ErrNoRows { return nil, nil } - tx.Rollback() - return nil, err - } - - if err := tx.Commit(); err != nil { - tx.Rollback() return nil, err } return &user, nil - } diff --git a/internal/templates/components/dropdowns.templ b/internal/templates/components/dropdowns.templ index 2940e38..2ca33b6 100644 --- a/internal/templates/components/dropdowns.templ +++ b/internal/templates/components/dropdowns.templ @@ -20,7 +20,7 @@ templ dropdownButton(content, name, value string, selected bool) { } -templ FilterDropdown(filters domainRecipe.SearchFilters) { +templ FilterDropdown(filters *domainRecipe.SearchFilters) {