Skip to content

Commit

Permalink
feat: Chat supports batch import of JSON and XLSX (#338)
Browse files Browse the repository at this point in the history
* fix: default verifyCode type and admin register user

* fix: default verifyCode type and admin register user

* fix: default verifyCode type and admin register user

* fix: default verifyCode type and admin register user

* fate: batch import

* fate: batch import

* fate: batch import

* fate: batch import

* fate: batch import

* fate: batch import

* fate: batch import
  • Loading branch information
withchao authored Dec 25, 2023
1 parent a32cec0 commit 5fb01e1
Show file tree
Hide file tree
Showing 14 changed files with 611 additions and 24 deletions.
2 changes: 2 additions & 0 deletions deployments/helm-charts/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ config:
withStack: false

secret: openIM123
chatSecret: openIM123

tokenPolicy:
expire: 86400

Expand Down
3 changes: 2 additions & 1 deletion deployments/templates/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,8 @@ log:
withStack: false # Whether to include stack trace in logs

# Secret key for secure communication
secret: openIM123 # SECRET, Secret key for encryption and secure communication
secret: openIM123 # SECRET, Secret OpenIM key for encryption and secure communication
chatSecret: openIM123 # ChatSecret, ChatSecret chat key for encryption and secure communication

# Token policy configuration
tokenPolicy:
Expand Down
16 changes: 11 additions & 5 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ require (
github.com/OpenIMSDK/tools v0.0.17
github.com/go-zookeeper/zk v1.0.3
github.com/redis/go-redis/v9 v9.1.0
github.com/xuri/excelize/v2 v2.8.0
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
)

Expand Down Expand Up @@ -66,27 +67,32 @@ require (
github.com/mattn/go-isatty v0.0.19 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe // indirect
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect
github.com/pelletier/go-toml/v2 v2.0.8 // indirect
github.com/richardlehane/mscfb v1.0.4 // indirect
github.com/richardlehane/msoleps v1.0.3 // indirect
github.com/tjfoc/gmsm v1.3.2 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.11 // indirect
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
github.com/xdg-go/scram v1.1.2 // indirect
github.com/xdg-go/stringprep v1.0.4 // indirect
github.com/xuri/efp v0.0.0-20230802181842-ad255f2331ca // indirect
github.com/xuri/nfp v0.0.0-20230819163627-dc951e3ffe1a // indirect
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect
go.mongodb.org/mongo-driver v1.12.0 // indirect
go.uber.org/atomic v1.9.0 // indirect
go.uber.org/multierr v1.7.0 // indirect
go.uber.org/zap v1.24.0 // indirect
golang.org/x/arch v0.3.0 // indirect
golang.org/x/crypto v0.11.0 // indirect
golang.org/x/image v0.9.0 // indirect
golang.org/x/net v0.12.0 // indirect
golang.org/x/crypto v0.12.0 // indirect
golang.org/x/image v0.11.0 // indirect
golang.org/x/net v0.14.0 // indirect
golang.org/x/sync v0.3.0 // indirect
golang.org/x/sys v0.10.0 // indirect
golang.org/x/text v0.11.0 // indirect
golang.org/x/sys v0.11.0 // indirect
golang.org/x/text v0.12.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 // indirect
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
Expand Down
34 changes: 24 additions & 10 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,8 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw=
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe h1:iruDEfMl2E6fbMZ9s0scYfZQ84/6SPL6zC8ACM2oIL0=
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=
Expand All @@ -151,6 +153,11 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/redis/go-redis/v9 v9.1.0 h1:137FnGdk+EQdCbye1FW+qOEcY5S+SpY9T0NiuqvtfMY=
github.com/redis/go-redis/v9 v9.1.0/go.mod h1:urWj3He21Dj5k4TK1y59xH8Uj6ATueP8AH1cY3lZl4c=
github.com/richardlehane/mscfb v1.0.4 h1:WULscsljNPConisD5hR0+OyZjwK46Pfyr6mPu5ZawpM=
github.com/richardlehane/mscfb v1.0.4/go.mod h1:YzVpcZg9czvAuhk9T+a3avCpcFPMUWm7gK3DypaEsUk=
github.com/richardlehane/msoleps v1.0.1/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg=
github.com/richardlehane/msoleps v1.0.3 h1:aznSZzrwYRl3rLKRT3gUk9am7T/mLNSnJINvN0AQoVM=
github.com/richardlehane/msoleps v1.0.3/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
Expand Down Expand Up @@ -181,6 +188,12 @@ github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY=
github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4=
github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8=
github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM=
github.com/xuri/efp v0.0.0-20230802181842-ad255f2331ca h1:uvPMDVyP7PXMMioYdyPH+0O+Ta/UO1WFfNYMO3Wz0eg=
github.com/xuri/efp v0.0.0-20230802181842-ad255f2331ca/go.mod h1:ybY/Jr0T0GTCnYjKqmdwxyxn2BQf2RcQIIvex5QldPI=
github.com/xuri/excelize/v2 v2.8.0 h1:Vd4Qy809fupgp1v7X+nCS/MioeQmYVVzi495UCTqB7U=
github.com/xuri/excelize/v2 v2.8.0/go.mod h1:6iA2edBTKxKbZAa7X5bDhcCg51xdOn1Ar5sfoXRGrQg=
github.com/xuri/nfp v0.0.0-20230819163627-dc951e3ffe1a h1:Mw2VNrNNNjDtw68VsEj2+st+oCSn4Uz7vZw6TbhcV1o=
github.com/xuri/nfp v0.0.0-20230819163627-dc951e3ffe1a/go.mod h1:WwHg+CVyzlv/TX9xqBFXEZAuxOPxn2k1GNHwG41IIUQ=
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d h1:splanxYIlg+5LfHAM6xpdFEAYOk8iySO56hMFq6uLyA=
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
Expand Down Expand Up @@ -208,10 +221,10 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I=
golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA=
golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio=
golang.org/x/image v0.9.0 h1:QrzfX26snvCM20hIhBwuHI/ThTg18b/+kcKdXHvnR+g=
golang.org/x/image v0.9.0/go.mod h1:jtrku+n79PfroUbvDdeUWMAI+heR786BofxrbiSF+J0=
golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk=
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
golang.org/x/image v0.11.0 h1:ds2RoQvBvYTiJkwpSFDwCcDFNX7DqjL2WsUgTNk0Ooo=
golang.org/x/image v0.11.0/go.mod h1:bglhjqbqVuEb9e9+eNR45Jfu7D+T4Qan+NhQk8Ck2P8=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
Expand All @@ -228,8 +241,8 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ=
golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50=
golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA=
golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14=
golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
Expand All @@ -253,13 +266,14 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA=
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM=
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.9.0/go.mod h1:M6DEAAIenWoTxdKrOltXcmDY3rSplQUkrvaDU5FcQyo=
golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
Expand All @@ -269,8 +283,8 @@ golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4=
golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc=
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
Expand Down
212 changes: 212 additions & 0 deletions internal/api/admin.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,17 @@
package api

import (
"context"
"crypto/md5"
"encoding/hex"
"fmt"
"github.com/OpenIMSDK/chat/pkg/common/apicall"
"github.com/OpenIMSDK/chat/pkg/common/apistruct"
"github.com/OpenIMSDK/chat/pkg/common/config"
constant2 "github.com/OpenIMSDK/chat/pkg/common/constant"
"github.com/OpenIMSDK/chat/pkg/common/mctx"
"github.com/OpenIMSDK/chat/pkg/common/xlsx"
"github.com/OpenIMSDK/chat/pkg/common/xlsx/model"
"github.com/OpenIMSDK/chat/pkg/proto/admin"
"github.com/OpenIMSDK/chat/pkg/proto/chat"
"github.com/OpenIMSDK/protocol/constant"
Expand All @@ -32,6 +39,11 @@ import (
"github.com/OpenIMSDK/tools/utils"
"github.com/gin-gonic/gin"
"google.golang.org/grpc"
"net"
"net/http"
"strconv"
"strings"
"time"
)

func NewAdmin(chatConn, adminConn grpc.ClientConnInterface) *AdminApi {
Expand Down Expand Up @@ -387,3 +399,203 @@ func (o *AdminApi) SearchLogs(c *gin.Context) {
func (o *AdminApi) DeleteLogs(c *gin.Context) {
a2r.Call(chat.ChatClient.DeleteLogs, o.chatClient, c)
}

func (o *AdminApi) getClientIP(c *gin.Context) (string, error) {
if config.Config.ProxyHeader == "" {
ip, _, err := net.SplitHostPort(c.Request.RemoteAddr)
return ip, err
}
ip := c.Request.Header.Get(config.Config.ProxyHeader)
if ip == "" {
return "", errs.ErrInternalServer.Wrap()
}
if ip := net.ParseIP(ip); ip == nil {
return "", errs.ErrInternalServer.Wrap(fmt.Sprintf("parse proxy ip header %s failed", ip))
}
return ip, nil
}

func (o *AdminApi) checkSecretAdmin(c *gin.Context, secret string) error {
if _, ok := c.Get(constant2.RpcOpUserID); ok {
return nil
}
if config.Config.ChatSecret == "" {
return errs.ErrNoPermission.Wrap("not config chat secret")
}
if config.Config.ChatSecret != secret {
return errs.ErrNoPermission.Wrap("secret error")
}
SetToken(c, config.GetDefaultIMAdmin(), constant2.AdminUser)
return nil
}

func (o *AdminApi) ImportUserByXlsx(c *gin.Context) {
defer log.ZDebug(c, "ImportUserByXlsx return")
formFile, err := c.FormFile("data")
if err != nil {
apiresp.GinError(c, err)
return
}
ip, err := o.getClientIP(c)
if err != nil {
apiresp.GinError(c, err)
return
}
secret := c.PostForm("secret")
if err := o.checkSecretAdmin(c, secret); err != nil {
apiresp.GinError(c, err)
return
}
file, err := formFile.Open()
if err != nil {
apiresp.GinError(c, err)
return
}
defer file.Close()
var users []model.User
if err := xlsx.ParseAll(file, &users); err != nil {
apiresp.GinError(c, errs.ErrArgs.Wrap("xlsx file parse error "+err.Error()))
return
}
us, err := o.xlsx2user(users)
if err != nil {
apiresp.GinError(c, err)
return
}
imToken, err := o.imApiCaller.ImAdminTokenWithDefaultAdmin(c)
if err != nil {
apiresp.GinError(c, err)
return
}

ctx := mctx.WithAdminUser(mctx.WithApiToken(c, imToken))
apiresp.GinError(c, o.registerChatUser(ctx, ip, us))
}

func (o *AdminApi) ImportUserByJson(c *gin.Context) {
var req struct {
Secret string `json:"secret"`
Users []*chat.RegisterUserInfo `json:"users"`
}
if err := c.BindJSON(&req); err != nil {
apiresp.GinError(c, err)
return
}
ip, err := o.getClientIP(c)
if err != nil {
apiresp.GinError(c, err)
return
}
if err := o.checkSecretAdmin(c, req.Secret); err != nil {
apiresp.GinError(c, err)
return
}
imToken, err := o.imApiCaller.ImAdminTokenWithDefaultAdmin(c)
if err != nil {
apiresp.GinError(c, err)
return
}
ctx := mctx.WithAdminUser(mctx.WithApiToken(c, imToken))
apiresp.GinError(c, o.registerChatUser(ctx, ip, req.Users))
}

func (o *AdminApi) xlsx2user(users []model.User) ([]*chat.RegisterUserInfo, error) {
chatUsers := make([]*chat.RegisterUserInfo, len(users))
for i, info := range users {
if info.Nickname == "" {
return nil, errs.ErrArgs.Wrap("nickname is empty")
}
if info.AreaCode == "" || info.PhoneNumber == "" {
return nil, errs.ErrArgs.Wrap("areaCode or phoneNumber is empty")
}
if info.Password == "" {
return nil, errs.ErrArgs.Wrap("password is empty")
}
if !strings.HasPrefix(info.AreaCode, "+") {
return nil, errs.ErrArgs.Wrap("areaCode format error")
}
if _, err := strconv.ParseUint(info.AreaCode[1:], 10, 16); err != nil {
return nil, errs.ErrArgs.Wrap("areaCode format error")
}
gender, _ := strconv.Atoi(info.Gender)
chatUsers[i] = &chat.RegisterUserInfo{
UserID: info.UserID,
Nickname: info.Nickname,
FaceURL: info.FaceURL,
Birth: o.xlsxBirth(info.Birth).UnixMilli(),
Gender: int32(gender),
AreaCode: info.AreaCode,
PhoneNumber: info.PhoneNumber,
Email: info.Email,
Account: info.Account,
Password: utils.Md5(info.Password),
}
}
return chatUsers, nil
}

func (o *AdminApi) xlsxBirth(s string) time.Time {
if s == "" {
return time.Now()
}
var separator byte
for _, b := range []byte(s) {
if b < '0' || b > '9' {
separator = b
}
}
arr := strings.Split(s, string([]byte{separator}))
if len(arr) != 3 {
return time.Now()
}
year, _ := strconv.Atoi(arr[0])
month, _ := strconv.Atoi(arr[1])
day, _ := strconv.Atoi(arr[2])
t := time.Date(year, time.Month(month), day, 0, 0, 0, 0, time.Local)
if t.Before(time.Date(1900, 0, 0, 0, 0, 0, 0, time.Local)) {
return time.Now()
}
return t
}

func (o *AdminApi) registerChatUser(ctx context.Context, ip string, users []*chat.RegisterUserInfo) error {
if len(users) == 0 {
return errs.ErrArgs.Wrap("users is empty")
}
for _, info := range users {
respRegisterUser, err := o.chatClient.RegisterUser(ctx, &chat.RegisterUserReq{Ip: ip, User: info, Platform: constant.AdminPlatformID})
if err != nil {
return err
}
userInfo := &sdkws.UserInfo{
UserID: respRegisterUser.UserID,
Nickname: info.Nickname,
FaceURL: info.FaceURL,
}
if err = o.imApiCaller.RegisterUser(ctx, []*sdkws.UserInfo{userInfo}); err != nil {
return err
}
if resp, err := o.adminClient.FindDefaultFriend(ctx, &admin.FindDefaultFriendReq{}); err == nil {
_ = o.imApiCaller.ImportFriend(ctx, respRegisterUser.UserID, resp.UserIDs)
}
if resp, err := o.adminClient.FindDefaultGroup(ctx, &admin.FindDefaultGroupReq{}); err == nil {
_ = o.imApiCaller.InviteToGroup(ctx, respRegisterUser.UserID, resp.GroupIDs)
}
}
return nil
}

func (o *AdminApi) BatchImportTemplate(c *gin.Context) {
md5Sum := md5.Sum(config.ImportTemplate)
md5Val := hex.EncodeToString(md5Sum[:])
if c.GetHeader("If-None-Match") == md5Val {
c.Status(http.StatusNotModified)
return
}
c.Header("Content-Disposition", "attachment; filename=template.xlsx")
c.Header("Content-Transfer-Encoding", "binary")
c.Header("Content-Description", "File Transfer")
c.Header("Content-Length", strconv.Itoa(len(config.ImportTemplate)))
c.Header("ETag", md5Val)
c.Data(http.StatusOK, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", config.ImportTemplate)
}
Loading

0 comments on commit 5fb01e1

Please sign in to comment.