@@ -295,9 +295,28 @@ func (c *Client) SavePreparedRecipe(ctx context.Context, title, markdown string,
return response.RecipeID, nil
}
+// SaveRecipeDraft logs in when needed and saves a reviewed URL import draft.
+func (c *Client) SaveRecipeDraft(ctx context.Context, draftID, markdown string, portions int) (string, error) {
+ body, err := json.Marshal(recipeContentRequest{Description: markdown, Portions: portions})
+ if err != nil {
+ return "", fmt.Errorf("encode Cooked recipe draft save request: %w", err)
+ }
+
+ var response saveRecipeResponse
+ decodeSave := func(decoder *json.Decoder) error {
+ return decoder.Decode(&response)
+ }
+ path := "/api/extract/" + url.PathEscape(draftID) + "/save"
+ if err := c.doAuthenticated(ctx, http.MethodPost, path, body, decodeSave); err != nil {
+ return "", err
+ }
+
+ return response.RecipeID, nil
+}
+
// UpdateRecipeContent logs in when needed and updates an existing recipe's content.
func (c *Client) UpdateRecipeContent(ctx context.Context, recipeID, markdown string, portions int) error {
- body, err := json.Marshal(updateRecipeContentRequest{Description: markdown, Portions: portions})
+ body, err := json.Marshal(recipeContentRequest{Description: markdown, Portions: portions})
if err != nil {
return fmt.Errorf("encode Cooked recipe update request: %w", err)
}
@@ -516,7 +535,7 @@ type savePreparedRecipeRequest struct {
Portions int `json:"portions"`
}
-type updateRecipeContentRequest struct {
+type recipeContentRequest struct {
Description string `json:"description"`
Portions int `json:"portions"`
}
@@ -144,6 +144,25 @@ func TestSavePreparedRecipeACIDRecipesSave2And9And13SavesMarkdownAsDescription(t
}
}
+// recipes.SAVE.7 recipes.SAVE.9 recipes.SAVE.13
+func TestSaveRecipeDraftACIDRecipesSave7And9And13SavesReviewedExtractionDraft(t *testing.T) {
+ var saveCalls int
+ client, closeServer := newTestClient(t, saveRecipeDraftTestHandler(t, &saveCalls))
+ defer closeServer()
+
+ recipeID, err := client.SaveRecipeDraft(context.Background(), "draft/with space", "# Pasta\n\n1. Boil pasta.", 4)
+ if err != nil {
+ t.Fatalf("SaveRecipeDraft() error = %v", err)
+ }
+
+ if saveCalls != 1 {
+ t.Fatalf("save calls = %d, want 1", saveCalls)
+ }
+ if recipeID != "recipe-1" {
+ t.Fatalf("recipe ID = %q, want recipe-1", recipeID)
+ }
+}
+
func TestUpdateRecipeContentACIDRecipesSave8And9And13UpdatesExistingRecipe(t *testing.T) {
var updateCalls int
client, closeServer := newTestClient(t, updateRecipeContentTestHandler(t, &updateCalls))
@@ -492,6 +511,25 @@ func savePreparedRecipeTestHandler(t *testing.T, saveCalls *int) http.HandlerFun
}
}
+func saveRecipeDraftTestHandler(t *testing.T, saveCalls *int) http.HandlerFunc {
+ t.Helper()
+
+ return func(w http.ResponseWriter, r *http.Request) {
+ switch r.URL.EscapedPath() {
+ case "/api/public/login":
+ writeLoginResponse(t, w)
+ case "/api/extract/draft%2Fwith%20space/save":
+ requireMethod(t, r, http.MethodPost, "save recipe draft")
+ requireSessionCookie(t, r)
+ requireRecipeContentRequest(t, r, "draft save")
+ (*saveCalls)++
+ writeJSON(t, w, saveRecipeResponse{RecipeID: "recipe-1"})
+ default:
+ t.Fatalf("unexpected path %s", r.URL.EscapedPath())
+ }
+ }
+}
+
func updateRecipeContentTestHandler(t *testing.T, updateCalls *int) http.HandlerFunc {
t.Helper()
@@ -502,7 +540,7 @@ func updateRecipeContentTestHandler(t *testing.T, updateCalls *int) http.Handler
case "/api/recipe/recipe%2Fwith%20space/content":
requireMethod(t, r, http.MethodPost, "update recipe content")
requireSessionCookie(t, r)
- requireUpdateRecipeContentRequest(t, r)
+ requireRecipeContentRequest(t, r, "update")
(*updateCalls)++
w.WriteHeader(http.StatusNoContent)
default:
@@ -760,18 +798,18 @@ func requireSavePreparedRecipeRequest(t *testing.T, r *http.Request) {
}
}
-func requireUpdateRecipeContentRequest(t *testing.T, r *http.Request) {
+func requireRecipeContentRequest(t *testing.T, r *http.Request, description string) {
t.Helper()
- var request updateRecipeContentRequest
+ var request recipeContentRequest
if err := json.NewDecoder(r.Body).Decode(&request); err != nil {
- t.Fatalf("decode update recipe content request: %v", err)
+ t.Fatalf("decode %s recipe content request: %v", description, err)
}
if request.Description != "# Pasta\n\n1. Boil pasta." {
- t.Fatalf("update description = %q, want markdown", request.Description)
+ t.Fatalf("%s description = %q, want markdown", description, request.Description)
}
if request.Portions != 4 {
- t.Fatalf("update portions = %d, want 4", request.Portions)
+ t.Fatalf("%s portions = %d, want 4", description, request.Portions)
}
}