Files
geo/server/internal/tenant/app/enterprise_site_wordpress_test.go
T
root c7bad83496
Frontend CI / Frontend (push) Successful in 4m17s
Backend CI / Backend (push) Failing after 6m42s
feat(enterprise-site): add WordPress support and scheduled auto-publish to sites
Add WordPress as an enterprise-site CMS type alongside pbootcms, and let
schedule tasks auto-publish generated articles to enterprise sites.

- WordPress connection/publisher service and tests; register wordpress
  media platform and relax cms_type CHECK constraint
- New publish_enterprise_site_targets JSONB column on schedule_tasks with
  array type constraint; thread targets through scheduler dispatch,
  prompt/KOL generation, and worker
- Admin UI: enterprise-site targets in generate/schedule/publish flows,
  KOL package form, MediaView, and i18n strings

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-09 19:44:24 +08:00

166 lines
5.6 KiB
Go

package app
import (
"context"
"encoding/base64"
"encoding/json"
"fmt"
"net/http"
"net/http/httptest"
"strings"
"testing"
)
func TestWordPressPublisherCategoriesUsesRESTAPIAndBasicAuth(t *testing.T) {
const username = "editor@example.com"
const applicationPassword = "abcd efgh ijkl mnop"
var gotAuth string
var gotPath string
var gotQuery string
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
gotAuth = r.Header.Get("Authorization")
gotPath = r.URL.Path
gotQuery = r.URL.RawQuery
w.Header().Set("Content-Type", "application/json")
w.Header().Set("X-WP-TotalPages", "1")
_, _ = w.Write([]byte(`[
{"id": 12, "name": "案例", "slug": "case", "parent": 0, "count": 3, "link": "https://example.test/category/case/"}
]`))
}))
defer server.Close()
publisher := newWordPressPublisher(server.Client())
items, raw, err := publisher.Categories(context.Background(), enterpriseSiteCredential{
SiteURL: server.URL,
AppID: username,
Secret: applicationPassword,
})
if err != nil {
t.Fatalf("sync wordpress categories: %v", err)
}
wantAuth := "Basic " + base64.StdEncoding.EncodeToString([]byte(username+":"+applicationPassword))
if gotAuth != wantAuth {
t.Fatalf("authorization = %q, want %q", gotAuth, wantAuth)
}
if gotPath != "/index.php" {
t.Fatalf("path = %q, want wordpress categories endpoint", gotPath)
}
if !strings.Contains(gotQuery, "rest_route=%2Fwp%2Fv2%2Fcategories") ||
!strings.Contains(gotQuery, "per_page=100") ||
!strings.Contains(gotQuery, "hide_empty=false") {
t.Fatalf("query = %q, want wordpress rest_route, per_page and hide_empty", gotQuery)
}
if len(items) != 1 || items[0].RemoteID != "12" || items[0].Name != "案例" {
t.Fatalf("items = %#v, want parsed wordpress category", items)
}
if len(raw) != 1 || raw[0]["slug"] != "case" {
t.Fatalf("raw = %#v, want preserved category payload", raw)
}
}
func TestWordPressPublisherPingReturnsSafeRawSummary(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
switch {
case strings.Contains(r.URL.RawQuery, "rest_route=%2Fwp%2Fv2%2Fusers%2Fme"):
_, _ = w.Write([]byte(`{"id": 7, "name": "admin", "email": "admin@example.test", "capabilities": {"administrator": true}}`))
default:
_, _ = w.Write([]byte(`{"name": "Example", "home": "https://example.test", "routes": {"/wp/v2/users/me": {"sensitive": true}}}`))
}
}))
defer server.Close()
publisher := newWordPressPublisher(server.Client())
capability, raw, err := publisher.Ping(context.Background(), enterpriseSiteCredential{
SiteURL: server.URL,
AppID: "editor",
Secret: "application-password",
})
if err != nil {
t.Fatalf("ping wordpress: %v", err)
}
if capability.SiteName == nil || *capability.SiteName != "Example" || !capability.APIAuth {
t.Fatalf("capability = %#v, want sanitized wordpress capability", capability)
}
if raw["api_auth"] != true || raw["authenticated"] != true {
t.Fatalf("raw = %#v, want safe auth summary", raw)
}
if _, ok := raw["routes"]; ok {
t.Fatalf("raw leaked wordpress index routes: %#v", raw)
}
if user, ok := raw["authenticated_user"].(map[string]any); ok || user != nil {
t.Fatalf("raw leaked authenticated user body: %#v", raw)
}
if strings.Contains(fmt.Sprintf("%v", raw), "admin@example.test") {
t.Fatalf("raw leaked authenticated user email: %#v", raw)
}
}
func TestWordPressPublisherPublishCreatesPost(t *testing.T) {
var gotPath string
var gotQuery string
var gotPayload map[string]any
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
gotPath = r.URL.Path
gotQuery = r.URL.RawQuery
if r.Method != http.MethodPost {
t.Fatalf("method = %s, want POST", r.Method)
}
if _, _, ok := r.BasicAuth(); !ok {
t.Fatalf("missing basic auth")
}
if err := json.NewDecoder(r.Body).Decode(&gotPayload); err != nil {
t.Fatalf("decode request body: %v", err)
}
w.Header().Set("Content-Type", "application/json")
_, _ = w.Write([]byte(`{"id": 88, "link": "https://example.test/post/88/", "status": "publish"}`))
}))
defer server.Close()
publisher := newWordPressPublisher(server.Client())
result, raw, err := publisher.Publish(context.Background(), enterpriseSiteCredential{
SiteURL: server.URL,
AppID: "editor",
Secret: "application-password",
}, cmsPublishRequest{
Title: "测试标题",
ContentHTML: "<p>正文</p>",
CategoryID: "12",
Description: "摘要",
PublishType: "draft",
})
if err != nil {
t.Fatalf("publish wordpress post: %v", err)
}
if gotPath != "/index.php" {
t.Fatalf("path = %q, want wordpress posts endpoint", gotPath)
}
if !strings.Contains(gotQuery, "rest_route=%2Fwp%2Fv2%2Fposts") {
t.Fatalf("query = %q, want wordpress posts rest_route", gotQuery)
}
if gotPayload == nil {
t.Fatalf("missing request payload")
}
if gotPayload["title"] != "测试标题" || gotPayload["content"] != "<p>正文</p>" || gotPayload["status"] != "draft" {
t.Fatalf("payload = %#v, want wordpress post body", gotPayload)
}
categories, ok := gotPayload["categories"].([]any)
if !ok || len(categories) != 1 {
t.Fatalf("categories = %#v, want [12]", gotPayload["categories"])
}
categoryID, ok := categories[0].(float64)
if !ok || categoryID != 12 {
t.Fatalf("category id = %#v, want 12", categories[0])
}
if result.RemoteID != "88" || result.URL != "https://example.test/post/88/" {
t.Fatalf("result = %#v, want wordpress post result", result)
}
if raw["id"] != int64(88) {
t.Fatalf("raw = %#v, want saved wordpress response", raw)
}
}