1.4.5
release-tag / release-image (push) Successful in 3m42s

This commit is contained in:
2026-08-27 06:06:00 +02:00
parent 0b3db9afa8
commit 1decb831d6
30 changed files with 6458 additions and 319 deletions
+12 -10
View File
@@ -239,14 +239,16 @@ func (a *app) handleAIFallback(w http.ResponseWriter, r *http.Request) {
}
type integrationStagingRequest struct {
Source string `json:"source"`
Query string `json:"query"`
Title string `json:"title"`
Text string `json:"text"`
Answer string `json:"answer"`
Categories []string `json:"categories"`
Keywords []string `json:"keywords"`
MinScore *float64 `json:"min_score,omitempty"`
Source string `json:"source"`
Query string `json:"query"`
Title string `json:"title"`
Text string `json:"text"`
Answer string `json:"answer"`
Categories []string `json:"categories"`
Keywords []string `json:"keywords"`
MinScore *float64 `json:"min_score,omitempty"`
IntegrationKey string `json:"integration_key,omitempty"`
Metadata map[string]any `json:"metadata,omitempty"`
}
func integrationBearerAuthorized(r *http.Request) (bool, bool) {
@@ -296,9 +298,9 @@ func (a *app) handleIntegrationStaging(w http.ResponseWriter, r *http.Request) {
if req.MinScore != nil {
minScore = *req.MinScore
}
result, err := a.staging.SaveFromSource(req.Query, req.Source, staging.Draft{
result, err := a.staging.SaveFromIntegration(req.Query, req.Source, staging.Draft{
Title: req.Title, Text: req.Text, Answer: req.Answer, Categories: req.Categories, Keywords: req.Keywords,
}, false, minScore)
}, false, minScore, staging.IntegrationOptions{IntegrationKey: req.IntegrationKey, Metadata: req.Metadata})
if err != nil {
writeError(w, http.StatusBadRequest, err.Error())
return
+35
View File
@@ -424,3 +424,38 @@ func TestEditorBasicAuthDoesNotLeakCredentialsToIntegrationClient(t *testing.T)
t.Fatalf("editor API unexpectedly bypassed basic auth: %d", itemsRR.Code)
}
}
func TestIntegrationDraftWithStableKeyUpdatesInsteadOfDuplicating(t *testing.T) {
t.Setenv("KB_INTEGRATION_TOKEN", "integration-secret")
s, err := store.New(t.TempDir())
if err != nil {
t.Fatal(err)
}
st, err := staging.New(t.TempDir())
if err != nil {
t.Fatal(err)
}
web, _ := fs.Sub(webFS, "web")
h := newApp(s, web).withStaging(st).routes()
post := func(answer string) {
payload := fmt.Sprintf(`{"source":"NeuroForge Research","query":"NVIDIA","title":"NVIDIA","answer":%q,"integration_key":"neuroforge-goal:g1","metadata":{"research_goal_id":"g1"}}`, answer)
req := httptest.NewRequest(http.MethodPost, "/api/integrations/staging", bytes.NewBufferString(payload))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", "Bearer integration-secret")
rr := httptest.NewRecorder()
h.ServeHTTP(rr, req)
if rr.Code != http.StatusCreated {
t.Fatalf("status=%d body=%s", rr.Code, rr.Body.String())
}
}
post("erste Fassung")
post("zweite Fassung")
if st.Count() != 1 {
t.Fatalf("expected one active draft, got %d", st.Count())
}
items, _ := st.List(staging.Query{Page: 1, PageSize: 10})
got, _ := st.Get(items.Items[0].Key)
if got.Document["answer"] != "zweite Fassung" {
t.Fatalf("draft not refreshed: %#v", got.Document)
}
}