// handleViewMealPlan handles HTTP requests for the meal plan viewer. func handleViewMealPlan(w http.ResponseWriter, r *http.Request) { mpID, ok := getUint64Var(r, "mealplanid") if !ok { httpError(w, BadRequestError) return } var mp *mpdata.MealPlan err := mpdb.WithConnection(func(db *sql.DB) (err error) { return mpdb.WithTransaction(db, func(tx *sql.Tx) (err error) { mp, err = mpdb.GetMealPlan(tx, mpID) return err }) }) if err != nil { serverError(w, err) return } if mp == nil { httpError(w, NotFoundError) return } renderTemplate(w, "view-mp.html", mp) }
// handleEditMealForm handles HTTP requests for the "edit meal" form. func handleEditMealForm(w http.ResponseWriter, r *http.Request) { mealID, ok := getUint64Var(r, "mealid") if !ok { httpError(w, BadRequestError) return } var mt mpdata.MealWithTags err := mpdb.WithConnection(func(db *sql.DB) (err error) { return mpdb.WithTransaction(db, func(tx *sql.Tx) (err error) { mt, err = mpdb.GetMealWithTags(tx, mealID) return err }) }) if err != nil { serverError(w, err) return } if mt.Meal == nil { httpError(w, NotFoundError) return } renderTemplate(w, "edit-meal-form.html", mt) }
// handleAddMealAction handles HTTP requests for submission of the "new meal" // form. func handleAddMealAction(w http.ResponseWriter, r *http.Request) { // Parse the POST request body err := r.ParseForm() if err != nil { serverError(w, err) return } // Create a MealWithTags value from the form fields mt := mpdata.MealWithTags{ Meal: &mpdata.Meal{ Name: r.FormValue("name"), RecipeURL: r.FormValue("recipe"), Favourite: r.FormValue("favourite") != "", }, Tags: r.Form["tags"], } // Add the record to the database err = mpdb.WithConnection(func(db *sql.DB) (err error) { return mpdb.WithTransaction(db, func(tx *sql.Tx) (err error) { return mpdb.AddMealWithTags(tx, mt) }) }) if err != nil { serverError(w, err) return } // Redirect to list of meals redirect(w, http.StatusSeeOther, "/meals?highlight="+strconv.FormatUint(mt.Meal.ID, 10)) }
// fetchMealPlans handles an API call to return a list of meal plans that // overlap with a specified inclusive date range. Expected parameters: from, to. // Returns: an array of meal plan objects. func fetchMealPlans(params url.Values) (response JSONResponse) { from, err := time.Parse(mpdata.JSONDateFormat, params.Get("from")) if err != nil { return JSONResponse{Error: "Invalid or missing 'from' parameter"} } to, err := time.Parse(mpdata.JSONDateFormat, params.Get("to")) if err != nil { return JSONResponse{Error: "Invalid or missing 'to' parameter"} } var mps []*mpdata.MealPlan err = mpdb.WithConnection(func(db *sql.DB) (err error) { return mpdb.WithTransaction(db, func(tx *sql.Tx) (err error) { mps, err = mpdb.ListMealPlansBetween(tx, from, to) return err }) }) if err != nil { log.Printf("Database error: %s\n", err.Error()) return JSONResponse{Error: "Database error"} } return JSONResponse{Success: mps} }
// fetchSuggestions handles an API call to generate suggestions for a given date. // Expected parameters: date. Returns: an array of suggestion objects. func fetchSuggestions(params url.Values) (response JSONResponse) { mpID, err := strconv.ParseUint(params.Get("mealplanid"), 10, 64) if err != nil { return JSONResponse{Error: "Invalid or missing 'mealplanid' parameter"} } dateServed, err := time.Parse(mpdata.JSONDateFormat, params.Get("date")) if err != nil { return JSONResponse{Error: "Invalid or missing 'date' parameter"} } var suggs []*mpdata.Suggestion err = mpdb.WithConnection(func(db *sql.DB) (err error) { return mpdb.WithTransaction(db, func(tx *sql.Tx) (err error) { suggs, err = mpdb.GenerateSuggestions(tx, mpID, dateServed) return err }) }) if err != nil { log.Printf("Database error: %s\n", err.Error()) return JSONResponse{Error: "Database error"} } return JSONResponse{Success: suggs} }
// fetchMealList handles an API call to fetch a list of all meals in the // database. Expected parameters: none. Returns: an array of meal/tags objects. func fetchMealList(params url.Values) (response JSONResponse) { query := params.Get("query") var words []string if query != "" { words = wordRegexp.FindAllString(query, -1) } var mts []mpdata.MealWithTags err := mpdb.WithConnection(func(db *sql.DB) (err error) { return mpdb.WithTransaction(db, func(tx *sql.Tx) (err error) { if query == "" { mts, err = mpdb.ListMealsWithTags(tx, true) } else { mts, err = mpdb.SearchMealsWithTags(tx, words, true) } return err }) }) if err != nil { log.Printf("Database error: %s\n", err.Error()) return JSONResponse{Error: "Database error"} } return JSONResponse{Success: mts} }
// handleDeleteMealPlanAction handles HTTP requests for submission of the // meal plan deletion form. func handleDeleteMealPlanAction(w http.ResponseWriter, r *http.Request) { mpID, ok := getUint64Var(r, "mealplanid") if !ok { httpError(w, BadRequestError) return } err := mpdb.WithConnection(func(db *sql.DB) (err error) { return mpdb.WithTransaction(db, func(tx *sql.Tx) (err error) { err = mpdb.DeleteServings(tx, mpID) if err != nil { return err } return mpdb.DeleteMealPlan(tx, mpID) }) }) if err != nil { serverError(w, err) return } redirect(w, http.StatusSeeOther, "/mealplans") }
// handleDeleteMealPlanForm handles HTTP requests for the meal plan deletion // confirmation page. func handleDeleteMealPlanForm(w http.ResponseWriter, r *http.Request) { mpID, ok := getUint64Var(r, "mealplanid") if !ok { httpError(w, BadRequestError) return } var mp *mpdata.MealPlan var numServings int err := mpdb.WithConnection(func(db *sql.DB) (err error) { return mpdb.WithTransaction(db, func(tx *sql.Tx) (err error) { mp, err = mpdb.GetMealPlan(tx, mpID) if err != nil { return err } numServings, err = mpdb.CountServings(tx, mpID) return err }) }) if err != nil { serverError(w, err) return } if mp == nil { httpError(w, NotFoundError) return } renderTemplate(w, "delete-mp-form.html", deleteMPData{mp, numServings}) }
// handleCreateMealPlanAction handles HTTP requests for the submission of the // meal plan creation form. func handleCreateMealPlanAction(w http.ResponseWriter, r *http.Request) { // Parse the POST request body err := r.ParseForm() if err != nil { serverError(w, err) return } startDate, err := time.Parse(mpdata.DatepickerDateFormat, r.FormValue("start")) if err != nil { httpError(w, BadRequestError) return } endDate, err := time.Parse(mpdata.DatepickerDateFormat, r.FormValue("end")) if err != nil { httpError(w, BadRequestError) return } if startDate.After(endDate) { httpError(w, BadRequestError) return } auto := r.FormValue("auto") == "true" // Create a MealPlan object mp := &mpdata.MealPlan{ StartDate: startDate, EndDate: endDate, } err = mpdb.WithConnection(func(db *sql.DB) (err error) { return mpdb.WithTransaction(db, func(tx *sql.Tx) (err error) { // Add mp to the database err = mpdb.AddMealPlan(tx, mp) if err != nil { return err } // Optionally fill the meal plan automatically if auto { err = mpdb.AutoFillMealPlan(tx, mp) if err != nil { return err } } return nil }) }) if err != nil { serverError(w, err) return } redirect(w, http.StatusSeeOther, "/mealplans/"+strconv.FormatUint(mp.ID, 10)+"/edit") }
// fetchServings handles an API call to list all the servings for a given meal // plan. Expected parameters: mealplanid. Returns: an array of // fetchServingsRecord objects. func fetchServings(params url.Values) (response JSONResponse) { mpID, err := strconv.ParseUint(params.Get("mealplanid"), 10, 64) if err != nil { return JSONResponse{Error: "Invalid or missing 'mealplanid' parameter"} } var results []*fetchServingsRecord err = mpdb.WithConnection(func(db *sql.DB) (err error) { return mpdb.WithTransaction(db, func(tx *sql.Tx) (err error) { mps, err := mpdb.GetMealPlanWithServings(tx, mpID) if err != nil { return err } if mps.MealPlan == nil { return nil } for _, date := range mps.MealPlan.Days() { ts := &fetchServingsRecord{ Date: date.Format(mpdata.JSONDateFormat), } for _, serving := range mps.Servings { if serving.Date == date { ts.HasMeal = true ts.MealID = serving.MealID meal, err := mpdb.GetMeal(tx, serving.MealID) if err != nil { return err } if meal == nil { log.Printf("Warning: meal plan %d -> serving %s points to nonexistent meal %d\n", mpID, date.Format("2006-01-02"), serving.MealID) ts.MealName = "???" } else { ts.MealName = meal.Name } break } } results = append(results, ts) } return err }) }) if err != nil { log.Printf("Database error: %s\n", err.Error()) return JSONResponse{Error: "Database error"} } return JSONResponse{Success: results} }
// fetchAllTags handles an API call to obtain a list of all tags present in the // database, without duplicates and in alphabetical order. Expected parameters: // none. Returns: an array of tags. func fetchAllTags(params url.Values) (response JSONResponse) { var tags []string err := mpdb.WithConnection(func(db *sql.DB) (err error) { return mpdb.WithTransaction(db, func(tx *sql.Tx) (err error) { tags, err = mpdb.ListAllTags(tx, true) return err }) }) if err != nil { log.Printf("Database error: %s\n", err.Error()) return JSONResponse{Error: "Database error"} } return JSONResponse{Success: tags} }
// handleEditMealAction handles HTTP requests for submission of the "edit meal" // form. func handleEditMealAction(w http.ResponseWriter, r *http.Request) { // Get the meal ID from the URL mealID, ok := getUint64Var(r, "mealid") if !ok { httpError(w, BadRequestError) return } // Parse the POST request body err := r.ParseForm() if err != nil { serverError(w, err) return } // Create a MealWithTags value from the form fields mt := mpdata.MealWithTags{ Meal: &mpdata.Meal{ ID: mealID, Name: r.FormValue("name"), RecipeURL: r.FormValue("recipe"), Favourite: r.FormValue("favourite") != "", }, Tags: r.Form["tags"], } // Update the database record err = mpdb.WithConnection(func(db *sql.DB) (err error) { return mpdb.WithTransaction(db, func(tx *sql.Tx) (err error) { return mpdb.UpdateMealWithTags(tx, mt) }) }) if err != nil { serverError(w, err) return } // Redirect to list of meals redirect(w, http.StatusSeeOther, "/meals?highlight="+strconv.FormatUint(mealID, 10)) }
// updateServing implements an API call to update a meal serving for a meal // plan with a new meal ID, removing the old serving if it already exists. // Expected parameters: mealplanid, date, mealid. Returns: nothing. func updateServing(params url.Values) (response JSONResponse) { mpID, err := strconv.ParseUint(params.Get("mealplanid"), 10, 64) if err != nil { return JSONResponse{Error: "Invalid or missing 'mealplanid' parameter"} } dateServed, err := time.Parse(mpdata.JSONDateFormat, params.Get("date")) if err != nil { return JSONResponse{Error: "Invalid or missing 'date' parameter"} } mealID, err := strconv.ParseUint(params.Get("mealid"), 10, 64) if err != nil { return JSONResponse{Error: "Invalid or missing 'mealid' parameter"} } err = mpdb.WithConnection(func(db *sql.DB) (err error) { return mpdb.WithTransaction(db, func(tx *sql.Tx) (err error) { err = mpdb.DeleteServing(tx, mpID, dateServed) if err != nil { return err } s := &mpdata.Serving{ MealPlanID: mpID, Date: dateServed, MealID: mealID, } return mpdb.AddServing(tx, s) }) }) if err != nil { log.Printf("Database error: %s\n", err.Error()) return JSONResponse{Error: "Database error"} } return JSONResponse{Success: nil} }
// toggleFavourite implements an API call to toggle the "favourite" status of // a given meal. Expected paramaters: mealid. Returns: the updated "favourite" // status of the meal. func toggleFavourite(params url.Values) (response JSONResponse) { mealID, err := strconv.ParseUint(params.Get("mealid"), 10, 64) if err != nil { return JSONResponse{Error: "Invalid or missing 'mealid' parameter"} } var isFavourite bool err = mpdb.WithConnection(func(db *sql.DB) (err error) { return mpdb.WithTransaction(db, func(tx *sql.Tx) (err error) { isFavourite, err = mpdb.ToggleFavourite(tx, mealID) return err }) }) if err != nil { log.Printf("Database error: %s\n", err.Error()) return JSONResponse{Error: "Database error"} } return JSONResponse{Success: isFavourite} }
// updateNotes implements an API call to update the notes associated with a // meal plan. Expected parameters: mealplanid, notes. Returns: nothing. func updateNotes(params url.Values) (response JSONResponse) { mpID, err := strconv.ParseUint(params.Get("mealplanid"), 10, 64) if err != nil { return JSONResponse{Error: "Invalid or missing 'mealplanid' parameter"} } notes := params.Get("notes") if err != nil { return JSONResponse{Error: "Invalid or missing 'notes' parameter"} } err = mpdb.WithConnection(func(db *sql.DB) (err error) { return mpdb.WithTransaction(db, func(tx *sql.Tx) (err error) { return mpdb.UpdateNotes(tx, mpID, notes) }) }) if err != nil { log.Printf("Database error: %s\n", err.Error()) return JSONResponse{Error: "Database error"} } return JSONResponse{Success: nil} }
// deleteMeal handles an API call to delete a meal. Expected parameters: mealid. // Returns: nothing. func deleteMeal(params url.Values) (response JSONResponse) { mealID, err := strconv.ParseUint(params.Get("mealid"), 10, 64) if err != nil { return JSONResponse{Error: "Invalid or missing 'mealid' parameter"} } err = mpdb.WithConnection(func(db *sql.DB) (err error) { return mpdb.WithTransaction(db, func(tx *sql.Tx) (err error) { err = mpdb.DeleteServingsOf(tx, mealID) if err != nil { return err } return mpdb.DeleteMealWithTags(tx, mealID) }) }) if err != nil { log.Printf("Database error: %s\n", err.Error()) return JSONResponse{Error: "Database error"} } return JSONResponse{Success: nil} }