122 lines
2.8 KiB
Go
122 lines
2.8 KiB
Go
package service
|
|
|
|
import (
|
|
"archive/zip"
|
|
"bytes"
|
|
"encoding/json"
|
|
"fmt"
|
|
"time"
|
|
|
|
"gpt-plus/internal/db"
|
|
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
type authFile struct {
|
|
OpenAIAPIKey string `json:"OPENAI_API_KEY"`
|
|
AccessToken string `json:"access_token"`
|
|
IDToken string `json:"id_token"`
|
|
LastRefresh string `json:"last_refresh"`
|
|
RefreshToken string `json:"refresh_token"`
|
|
Tokens authTokens `json:"tokens"`
|
|
}
|
|
|
|
type authTokens struct {
|
|
AccessToken string `json:"access_token"`
|
|
AccountID string `json:"account_id"`
|
|
IDToken string `json:"id_token"`
|
|
LastRefresh string `json:"last_refresh"`
|
|
RefreshToken string `json:"refresh_token"`
|
|
}
|
|
|
|
func buildAuthFile(acct *db.Account) *authFile {
|
|
now := time.Now().UTC().Format("2006-01-02T15:04:05Z")
|
|
token := acct.AccessToken
|
|
if acct.WorkspaceToken != "" {
|
|
token = acct.WorkspaceToken
|
|
}
|
|
accountID := acct.AccountID
|
|
if acct.TeamWorkspaceID != "" {
|
|
accountID = acct.TeamWorkspaceID
|
|
}
|
|
return &authFile{
|
|
AccessToken: token,
|
|
IDToken: acct.IDToken,
|
|
LastRefresh: now,
|
|
RefreshToken: acct.RefreshToken,
|
|
Tokens: authTokens{
|
|
AccessToken: token,
|
|
AccountID: accountID,
|
|
IDToken: acct.IDToken,
|
|
LastRefresh: now,
|
|
RefreshToken: acct.RefreshToken,
|
|
},
|
|
}
|
|
}
|
|
|
|
// ExportAccounts exports accounts as auth.json files.
|
|
// If multiple files, returns a zip archive.
|
|
func ExportAccounts(d *gorm.DB, ids []uint, note string) ([]byte, string, error) {
|
|
var accounts []db.Account
|
|
d.Where("id IN ?", ids).Find(&accounts)
|
|
|
|
if len(accounts) == 0 {
|
|
return nil, "", fmt.Errorf("未找到账号")
|
|
}
|
|
|
|
// Collect all files to export
|
|
type exportFile struct {
|
|
Name string
|
|
Data []byte
|
|
}
|
|
var files []exportFile
|
|
|
|
for _, acct := range accounts {
|
|
auth := buildAuthFile(&acct)
|
|
data, _ := json.MarshalIndent(auth, "", " ")
|
|
files = append(files, exportFile{
|
|
Name: acct.Email + ".auth.json",
|
|
Data: data,
|
|
})
|
|
|
|
// If team_owner, also export sub-accounts
|
|
if acct.Plan == "team_owner" {
|
|
var subs []db.Account
|
|
d.Where("parent_id = ?", acct.ID).Find(&subs)
|
|
for _, sub := range subs {
|
|
subAuth := buildAuthFile(&sub)
|
|
subData, _ := json.MarshalIndent(subAuth, "", " ")
|
|
files = append(files, exportFile{
|
|
Name: sub.Email + ".auth.json",
|
|
Data: subData,
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
// Single file — return directly
|
|
if len(files) == 1 {
|
|
return files[0].Data, files[0].Name, nil
|
|
}
|
|
|
|
// Multiple files — zip archive
|
|
var buf bytes.Buffer
|
|
zw := zip.NewWriter(&buf)
|
|
for _, f := range files {
|
|
w, err := zw.Create(f.Name)
|
|
if err != nil {
|
|
return nil, "", err
|
|
}
|
|
w.Write(f.Data)
|
|
}
|
|
zw.Close()
|
|
|
|
ts := time.Now().Format("20060102_150405")
|
|
filename := fmt.Sprintf("export_%s_%s.zip", note, ts)
|
|
if note == "" {
|
|
filename = fmt.Sprintf("export_%s.zip", ts)
|
|
}
|
|
|
|
return buf.Bytes(), filename, nil
|
|
}
|