Просмотр исходного кода

feat(api): add force parameter to the feed refresh endpoint

PUT /v1/feeds/{id}/refresh?force=true does what the web UI's forced
refresh already does: it skips the HTTP cache check and reprocesses
entries that are already stored, so changed rewrite or scraper rules
apply to them. Without it, API clients have no way to see the effect of
a rule change until new entries arrive.

The client gains ForceRefreshFeed and ForceRefreshFeedContext.
Dave Marquard 1 неделя назад
Родитель
Сommit
c573f2e0c3
4 измененных файлов с 34 добавлено и 1 удалено
  1. 13 0
      client/client.go
  2. 13 0
      client/client_test.go
  3. 4 0
      internal/api/api_integration_test.go
  4. 4 1
      internal/api/feed_handlers.go

+ 13 - 0
client/client.go

@@ -784,6 +784,19 @@ func (c *Client) RefreshFeedContext(ctx context.Context, feedID int64) error {
 	return err
 }
 
+// ForceRefreshFeed refreshes a feed, bypassing the HTTP cache and reprocessing existing entries.
+func (c *Client) ForceRefreshFeed(feedID int64) error {
+	ctx, cancel := withDefaultTimeout()
+	defer cancel()
+	return c.ForceRefreshFeedContext(ctx, feedID)
+}
+
+// ForceRefreshFeedContext refreshes a feed, bypassing the HTTP cache and reprocessing existing entries.
+func (c *Client) ForceRefreshFeedContext(ctx context.Context, feedID int64) error {
+	_, err := c.request.Put(ctx, fmt.Sprintf("/v1/feeds/%d/refresh?force=true", feedID), nil)
+	return err
+}
+
 // DeleteFeed removes a feed.
 func (c *Client) DeleteFeed(feedID int64) error {
 	ctx, cancel := withDefaultTimeout()

+ 13 - 0
client/client_test.go

@@ -906,6 +906,19 @@ func TestRefreshFeed(t *testing.T) {
 	}
 }
 
+func TestForceRefreshFeed(t *testing.T) {
+	client := NewClientWithOptions(
+		"http://mf",
+		WithHTTPClient(
+			newFakeHTTPClient(t, func(t *testing.T, req *http.Request) *http.Response {
+				expectRequest(t, http.MethodPut, "http://mf/v1/feeds/1/refresh?force=true", nil, req)
+				return jsonResponseFrom(t, http.StatusOK, http.Header{}, nil)
+			})))
+	if err := client.ForceRefreshFeedContext(t.Context(), 1); err != nil {
+		t.Fatalf("Expected no error, got %v", err)
+	}
+}
+
 func TestDeleteFeed(t *testing.T) {
 	client := NewClientWithOptions(
 		"http://mf",

+ 4 - 0
internal/api/api_integration_test.go

@@ -2117,6 +2117,10 @@ func TestRefreshFeedEndpoint(t *testing.T) {
 	if err := regularUserClient.RefreshFeed(feedID); err != nil {
 		t.Fatal(err)
 	}
+
+	if err := regularUserClient.ForceRefreshFeed(feedID); err != nil {
+		t.Fatal(err)
+	}
 }
 
 func TestGetFeedEndpoint(t *testing.T) {

+ 4 - 1
internal/api/feed_handlers.go

@@ -79,7 +79,10 @@ func (h *handler) refreshFeedHandler(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 
-	localizedError := feedHandler.RefreshFeed(h.store, userID, feedID, false)
+	// force=true mirrors the web UI's forced refresh: it bypasses the HTTP cache
+	// and reprocesses (and re-scrapes) entries that are already stored.
+	forceRefresh := request.QueryBoolParam(r, "force", false)
+	localizedError := feedHandler.RefreshFeed(h.store, userID, feedID, forceRefresh)
 	if localizedError != nil {
 		response.JSONServerError(w, r, localizedError.Error())
 		return