feat: 添加联系我们配置接口和字典配置缓存

1. 新增DictionaryItem字典配置结构体
2. 添加字典配置缓存及失效逻辑
3. 实现联系我们接口的业务逻辑和测试用例
4. 注册联系我们API路由
5. 集成字典配置到admin内部客户端
6. 处理字典配置更新的kafka事件
This commit is contained in:
Austin
2026-09-21 13:11:42 +08:00
parent c891afba73
commit 7829990180
8 changed files with 196 additions and 0 deletions
+66
View File
@@ -8266,3 +8266,69 @@ func TestIMMessageTypeDraftyEntities(t *testing.T) {
}
}
}
type testDictionaryStore struct {
items []types.DictionaryItem
err error
}
func (s *testDictionaryStore) Get(_ string) ([]types.DictionaryItem, error) {
if s.err != nil {
return nil, s.err
}
return s.items, nil
}
func TestServeIMContactUs(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
expectIMBearer(t, ctrl, "token-1", 7, 42)
oldDict := store.DictionaryConfig
defer func() { store.DictionaryConfig = oldDict }()
store.DictionaryConfig = &testDictionaryStore{items: []types.DictionaryItem{
{Label: "客服邮箱", Value: "support@example.com", Sort: 10},
{Label: "客服电话", Value: "+86 400-000-0000", Sort: 20},
}}
req := httptest.NewRequest(http.MethodGet, "/v1/im/contact-us", nil)
req.Header.Set("Authorization", "Bearer token-1")
rec := httptest.NewRecorder()
serveIMContactUs(rec, req)
if rec.Code != http.StatusOK {
t.Fatalf("status: got %d body=%s", rec.Code, rec.Body.String())
}
resp := decodeIMHTTPResponse(t, rec)
items, ok := resp.Data.(map[string]any)["items"].([]any)
if !ok || len(items) != 2 {
t.Fatalf("unexpected items: %#v", resp.Data)
}
if items[0].(map[string]any)["label"] != "客服邮箱" || items[1].(map[string]any)["value"] != "+86 400-000-0000" {
t.Fatalf("item mismatch: %#v", items)
}
store.DictionaryConfig = &testDictionaryStore{err: types.ErrUnsupported}
rec = httptest.NewRecorder()
serveIMContactUs(rec, req)
if rec.Code != http.StatusOK {
t.Fatalf("unsupported status: got %d body=%s", rec.Code, rec.Body.String())
}
resp = decodeIMHTTPResponse(t, rec)
if listed, ok := resp.Data.(map[string]any)["items"].([]any); !ok || len(listed) != 0 {
t.Fatalf("expected empty items, got %#v", resp.Data)
}
store.DictionaryConfig = &testDictionaryStore{err: types.ErrInternal}
rec = httptest.NewRecorder()
serveIMContactUs(rec, req)
if rec.Code != http.StatusInternalServerError {
t.Fatalf("error status: got %d body=%s", rec.Code, rec.Body.String())
}
req = httptest.NewRequest(http.MethodPost, "/v1/im/contact-us", nil)
req.Header.Set("Authorization", "Bearer token-1")
rec = httptest.NewRecorder()
serveIMContactUs(rec, req)
if rec.Code != http.StatusMethodNotAllowed {
t.Fatalf("method status: got %d body=%s", rec.Code, rec.Body.String())
}
}