feat: Initialize backend API server with S2A proxy, mail service management, team processing, and add frontend email configuration page.
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
@@ -361,10 +362,84 @@ func handleMailServices(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
func handleTestMailService(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPost {
|
||||
api.Error(w, http.StatusMethodNotAllowed, "仅支持 POST")
|
||||
return
|
||||
}
|
||||
|
||||
var req struct {
|
||||
Name string `json:"name"`
|
||||
APIBase string `json:"api_base"`
|
||||
APIToken string `json:"api_token"`
|
||||
Domain string `json:"domain"`
|
||||
}
|
||||
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
api.Error(w, http.StatusBadRequest, "解析请求失败")
|
||||
return
|
||||
}
|
||||
|
||||
logger.Info(fmt.Sprintf("测试邮箱服务: %s (%s)", req.Name, req.Domain), "", "mail")
|
||||
logger.Info(fmt.Sprintf("API Base: %s", req.APIBase), "", "mail")
|
||||
|
||||
// 创建测试请求
|
||||
testEmail := "test@" + req.Domain
|
||||
payload := map[string]interface{}{
|
||||
"list": []map[string]string{
|
||||
{"email": testEmail, "password": "TestPass123#"},
|
||||
},
|
||||
}
|
||||
jsonData, _ := json.Marshal(payload)
|
||||
|
||||
apiURL := req.APIBase + "/api/public/addUser"
|
||||
httpReq, err := http.NewRequest("POST", apiURL, bytes.NewBuffer(jsonData))
|
||||
if err != nil {
|
||||
logger.Error(fmt.Sprintf("创建请求失败: %v", err), "", "mail")
|
||||
api.Error(w, http.StatusInternalServerError, "创建请求失败")
|
||||
return
|
||||
}
|
||||
|
||||
httpReq.Header.Set("Authorization", req.APIToken)
|
||||
httpReq.Header.Set("Content-Type", "application/json")
|
||||
|
||||
client := &http.Client{Timeout: 10 * time.Second}
|
||||
resp, err := client.Do(httpReq)
|
||||
if err != nil {
|
||||
logger.Error(fmt.Sprintf("请求失败: %v", err), "", "mail")
|
||||
api.Error(w, http.StatusBadGateway, fmt.Sprintf("连接失败: %v", err))
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
bodyBytes, _ := io.ReadAll(resp.Body)
|
||||
bodyStr := string(bodyBytes)
|
||||
|
||||
logger.Info(fmt.Sprintf("响应状态: %d", resp.StatusCode), "", "mail")
|
||||
logger.Info(fmt.Sprintf("响应内容: %s", bodyStr), "", "mail")
|
||||
|
||||
// 解析响应
|
||||
var result struct {
|
||||
Code int `json:"code"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
if err := json.Unmarshal(bodyBytes, &result); err != nil {
|
||||
logger.Error(fmt.Sprintf("解析响应失败: %v", err), "", "mail")
|
||||
api.Error(w, http.StatusInternalServerError, "解析响应失败")
|
||||
return
|
||||
}
|
||||
|
||||
// 判断结果
|
||||
if result.Code == 200 || strings.Contains(result.Message, "exist") {
|
||||
logger.Success(fmt.Sprintf("邮箱服务测试成功: %s", req.Name), "", "mail")
|
||||
api.Success(w, map[string]interface{}{
|
||||
"connected": true,
|
||||
"message": "邮箱服务测试成功",
|
||||
"message": "邮箱服务连接成功",
|
||||
"response": result,
|
||||
})
|
||||
} else {
|
||||
logger.Error(fmt.Sprintf("邮箱服务测试失败: %s - %s", req.Name, result.Message), "", "mail")
|
||||
api.Error(w, http.StatusBadRequest, fmt.Sprintf("API 错误: %s", result.Message))
|
||||
}
|
||||
}
|
||||
|
||||
func handleGetOwners(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
@@ -258,6 +258,7 @@ func processSingleTeam(idx int, req TeamProcessRequest) TeamProcessResult {
|
||||
if owner.AccountID != "" {
|
||||
// 直接使用数据库中存储的 account_id
|
||||
teamID = owner.AccountID
|
||||
inviter.SetAccountID(teamID) // 必须设置到 inviter 中
|
||||
logger.Info(fmt.Sprintf("%s 使用已存储的 Team ID: %s", logPrefix, teamID), owner.Email, "team")
|
||||
} else {
|
||||
// 如果没有存储,才请求 API 获取
|
||||
|
||||
@@ -54,6 +54,11 @@ func NewWithProxy(accessToken, proxy string) *TeamInviter {
|
||||
}
|
||||
}
|
||||
|
||||
// SetAccountID 手动设置 account_id(当已有存储值时使用)
|
||||
func (t *TeamInviter) SetAccountID(accountID string) {
|
||||
t.accountID = accountID
|
||||
}
|
||||
|
||||
// GetAccountID 获取 Team 的 account_id (workspace_id)
|
||||
func (t *TeamInviter) GetAccountID() (string, error) {
|
||||
req, _ := http.NewRequest("GET", "https://chatgpt.com/backend-api/accounts/check/v4-2023-04-27", nil)
|
||||
|
||||
@@ -76,6 +76,7 @@ export default function EmailConfig() {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
name: service.name,
|
||||
api_base: service.apiBase,
|
||||
api_token: service.apiToken,
|
||||
domain: service.domain,
|
||||
|
||||
Reference in New Issue
Block a user