Files
im_manager/server/internal/logic/sys/im_admin_query_client.go
T

259 lines
6.0 KiB
Go

package sys
import (
"context"
"encoding/json"
"hotgo/internal/dao"
"hotgo/internal/library/imadmin"
"hotgo/internal/library/imtenant"
"hotgo/internal/model/entity"
"net/url"
"strconv"
"strings"
"time"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/os/gtime"
)
type imAdminQueryPage struct {
Items []map[string]any `json:"items"`
Total int `json:"total"`
Page int `json:"page"`
PerPage int `json:"per_page"`
}
func resolveImAdminTenant(ctx context.Context, selectedTenantId int64) (tenant *entity.ImTenant, err error) {
scope, err := resolveImAdminScope(ctx, selectedTenantId)
if err != nil {
return nil, err
}
if err = imtenant.RegistryDB().Model(dao.ImTenant.Table()).Safe().Ctx(ctx).WherePri(scope.TenantId).Scan(&tenant); err != nil {
return nil, gerror.Wrap(err, "获取IM租户失败")
}
if tenant == nil || tenant.Id <= 0 || tenant.Code == "" {
return nil, gerror.New("IM租户不存在或编码为空")
}
return tenant, nil
}
func imAdminQueryList[T any](ctx context.Context, tenant *entity.ImTenant, path string, values url.Values, aliases map[string]string) (list []*T, totalCount int, err error) {
if values == nil {
values = url.Values{}
}
query := values.Encode()
if query != "" {
path += "?" + query
}
var page imAdminQueryPage
if err = imadmin.DefaultClient(ctx).InternalGet(ctx, path, &page); err != nil {
return nil, 0, err
}
normalizeImAdminRows(page.Items, aliases)
if len(page.Items) == 0 {
return []*T{}, page.Total, nil
}
raw, err := json.Marshal(page.Items)
if err != nil {
return nil, 0, gerror.Wrap(err, "转换IM内部查询列表失败")
}
if err = json.Unmarshal(raw, &list); err != nil {
return nil, 0, gerror.Wrap(err, "解析IM内部查询列表失败")
}
fillImTenantFields(tenant, &list)
return list, page.Total, nil
}
func imAdminQueryOne[T any](ctx context.Context, tenant *entity.ImTenant, path string, aliases map[string]string) (res *T, err error) {
row := map[string]any{}
if err = imadmin.DefaultClient(ctx).InternalGet(ctx, path, &row); err != nil {
return nil, err
}
normalizeImAdminRow(row, aliases)
raw, err := json.Marshal(row)
if err != nil {
return nil, gerror.Wrap(err, "转换IM内部查询详情失败")
}
if err = json.Unmarshal(raw, &res); err != nil {
return nil, gerror.Wrap(err, "解析IM内部查询详情失败")
}
fillImTenantFields(tenant, res)
return res, nil
}
func normalizeImAdminRows(rows []map[string]any, aliases map[string]string) {
for _, row := range rows {
normalizeImAdminRow(row, aliases)
}
}
func normalizeImAdminRow(row map[string]any, aliases map[string]string) {
for key, value := range row {
target := snakeToLowerCamel(key)
if aliases != nil {
if alias := aliases[key]; alias != "" {
target = alias
}
}
value = normalizeImAdminValue(target, value)
if target == key {
row[key] = value
continue
}
row[target] = value
delete(row, key)
}
if _, ok := row["authNames"]; !ok {
username, _ := row["username"].(string)
phone, _ := row["phone"].(string)
authNames := username
if phone != "" && phone != username {
if authNames != "" {
authNames += ", "
}
authNames += phone
}
if authNames != "" {
row["authNames"] = authNames
}
}
}
func normalizeImAdminValue(target string, value any) any {
switch target {
case "credentials":
items, ok := value.([]any)
if !ok {
return value
}
parts := make([]string, 0, len(items))
for _, item := range items {
m, ok := item.(map[string]any)
if !ok {
continue
}
method, _ := m["method"].(string)
val, _ := m["value"].(string)
if method == "" && val == "" {
continue
}
text := method
if val != "" {
if text != "" {
text += ":"
}
text += val
}
if done, ok := m["done"].(bool); ok && !done {
text += "(未验证)"
}
parts = append(parts, text)
}
return strings.Join(parts, ", ")
case "profileJson", "trustedJson", "accessJson", "head", "content", "metadata", "atUsers":
return normalizeImAdminJSONString(value)
default:
return value
}
}
func normalizeImAdminJSONString(value any) string {
switch v := value.(type) {
case nil:
return ""
case string:
return v
default:
encoded, err := json.Marshal(v)
if err != nil {
return ""
}
return string(encoded)
}
}
func snakeToLowerCamel(s string) string {
if !strings.Contains(s, "_") {
return s
}
parts := strings.Split(s, "_")
var b strings.Builder
for i, part := range parts {
if part == "" {
continue
}
if i == 0 {
b.WriteString(part)
continue
}
b.WriteString(strings.ToUpper(part[:1]))
if len(part) > 1 {
b.WriteString(part[1:])
}
}
return b.String()
}
func fillImTenantFields(tenant *entity.ImTenant, target any) {
raw, err := json.Marshal(target)
if err != nil {
return
}
var rows []map[string]any
if err = json.Unmarshal(raw, &rows); err == nil {
for _, row := range rows {
row["tenantId"] = tenant.Id
row["tenantName"] = tenant.Name
}
updated, _ := json.Marshal(rows)
_ = json.Unmarshal(updated, target)
return
}
var row map[string]any
if err = json.Unmarshal(raw, &row); err == nil {
row["tenantId"] = tenant.Id
row["tenantName"] = tenant.Name
updated, _ := json.Marshal(row)
_ = json.Unmarshal(updated, target)
}
}
func addPageQuery(values url.Values, page int, perPage int) url.Values {
if values == nil {
values = url.Values{}
}
if page <= 0 {
page = 1
}
if perPage <= 0 {
perPage = 20
}
values.Set("page", intToString(page))
values.Set("per_page", intToString(perPage))
return values
}
func addTimeRangeQuery(values url.Values, prefix string, times []*gtime.Time) {
if len(times) != 2 {
return
}
if times[0] != nil {
values.Set(prefix+"_start", times[0].Time.UTC().Format(time.RFC3339Nano))
}
if times[1] != nil {
values.Set(prefix+"_end", times[1].Time.UTC().Format(time.RFC3339Nano))
}
}
func intToString(v int) string {
return strconvFormatInt(int64(v))
}
func int64ToString(v int64) string {
return strconvFormatInt(v)
}
func strconvFormatInt(v int64) string {
return strconv.FormatInt(v, 10)
}