github.com/weplanx/server@v0.2.6-0.20240318110640-f7e75155779a/api/lark/service.go (about) 1 package lark 2 3 import ( 4 "context" 5 "crypto/aes" 6 "crypto/cipher" 7 "crypto/sha256" 8 "encoding/base64" 9 "fmt" 10 "github.com/bytedance/sonic" 11 "github.com/cloudwego/hertz/pkg/common/errors" 12 "github.com/imroc/req/v3" 13 "github.com/weplanx/go/locker" 14 "github.com/weplanx/go/passport" 15 "github.com/weplanx/go/sessions" 16 "github.com/weplanx/server/api/index" 17 "github.com/weplanx/server/common" 18 "github.com/weplanx/server/model" 19 "go.mongodb.org/mongo-driver/bson" 20 "go.mongodb.org/mongo-driver/bson/primitive" 21 "go.mongodb.org/mongo-driver/mongo" 22 "strings" 23 "time" 24 ) 25 26 type Service struct { 27 *common.Inject 28 Sessions *sessions.Service 29 Locker *locker.Locker 30 Passport *passport.Passport 31 IndexX *index.Service 32 } 33 34 var client = req.C(). 35 SetBaseURL("https://open.feishu.cn/open-apis"). 36 SetJsonMarshal(sonic.Marshal). 37 SetJsonUnmarshal(sonic.Unmarshal). 38 SetTimeout(time.Second * 5) 39 40 func (x *Service) Decrypt(encrypt string, key string) (string, error) { 41 buf, err := base64.StdEncoding.DecodeString(encrypt) 42 if err != nil { 43 return "", fmt.Errorf("base64StdEncode Error[%v]", err) 44 } 45 if len(buf) < aes.BlockSize { 46 return "", errors.NewPublic("cipher too short") 47 } 48 keyBs := sha256.Sum256([]byte(key)) 49 block, err := aes.NewCipher(keyBs[:sha256.Size]) 50 if err != nil { 51 return "", fmt.Errorf("AESNewCipher Error[%v]", err) 52 } 53 iv := buf[:aes.BlockSize] 54 buf = buf[aes.BlockSize:] 55 if len(buf)%aes.BlockSize != 0 { 56 return "", errors.NewPublic("ciphertext is not a multiple of the block size") 57 } 58 mode := cipher.NewCBCDecrypter(block, iv) 59 mode.CryptBlocks(buf, buf) 60 n := strings.Index(string(buf), "{") 61 if n == -1 { 62 n = 0 63 } 64 m := strings.LastIndex(string(buf), "}") 65 if m == -1 { 66 m = len(buf) - 1 67 } 68 return string(buf[n : m+1]), nil 69 } 70 71 func (x *Service) GetTenantAccessToken(ctx context.Context) (token string, err error) { 72 key := fmt.Sprintf(`%s:%s`, "lark", "tenant_access_token") 73 var exists int64 74 if exists, err = x.RDb.Exists(ctx, key).Result(); err != nil { 75 return 76 } 77 if exists == 0 { 78 var result struct { 79 Code uint64 `json:"code"` 80 Msg string `json:"msg"` 81 TenantAccessToken string `json:"tenant_access_token"` 82 Expire int64 `json:"expire"` 83 } 84 if _, err = client.R(). 85 SetContext(ctx). 86 SetBody(M{ 87 "app_id": x.V.LarkAppId, 88 "app_secret": x.V.LarkAppSecret, 89 }). 90 SetSuccessResult(&result). 91 Post("/auth/v3/tenant_access_token/internal"); err != nil { 92 return 93 } 94 if err = x.RDb.Set(ctx, key, 95 result.TenantAccessToken, 96 time.Second*time.Duration(result.Expire)).Err(); err != nil { 97 return 98 } 99 } 100 return x.RDb.Get(ctx, key).Result() 101 } 102 103 func (x *Service) GetUserAccessToken(ctx context.Context, code string) (_ model.UserLark, err error) { 104 var token string 105 if token, err = x.GetTenantAccessToken(ctx); err != nil { 106 return 107 } 108 var result struct { 109 Code uint64 `json:"code"` 110 Msg string `json:"msg"` 111 Data model.UserLark `json:"data"` 112 } 113 if _, err = client.R(). 114 SetContext(ctx). 115 SetBearerAuthToken(token). 116 SetBody(map[string]interface{}{ 117 "grant_type": "authorization_code", 118 "code": code, 119 }). 120 SetSuccessResult(&result). 121 Post("/authen/v1/access_token"); err != nil { 122 return 123 } 124 if result.Code != 0 { 125 err = errors.NewPublic(result.Msg) 126 return 127 } 128 return result.Data, nil 129 } 130 131 func (x *Service) Link(ctx context.Context, userId string, data model.UserLark) (_ *mongo.UpdateResult, err error) { 132 id, _ := primitive.ObjectIDFromHex(userId) 133 return x.Db.Collection("users").UpdateOne(ctx, 134 bson.M{"_id": id}, 135 bson.M{"$set": bson.M{"lark": data}}, 136 ) 137 } 138 139 type LoginResult struct { 140 User model.User 141 AccessToken string 142 } 143 144 func (x *Service) Login(ctx context.Context, openId string) (r *LoginResult, err error) { 145 r = new(LoginResult) 146 if r.User, err = x.IndexX.Logining(ctx, bson.M{"lark.open_id": openId, "status": true}); err != nil { 147 return 148 } 149 150 if err = x.Db.Collection("users"). 151 FindOne(ctx, bson.M{"lark.open_id": openId, "status": true}).Decode(&r.User); err != nil { 152 if err == mongo.ErrNoDocuments { 153 err = common.ErrLoginNotExists 154 return 155 } 156 return 157 } 158 userId := r.User.ID.Hex() 159 if r.AccessToken, err = x.IndexX.CreateAccessToken(ctx, userId); err != nil { 160 return 161 } 162 return 163 } 164 165 func (x *Service) CreateTask(ctx context.Context) (result M, err error) { 166 var token string 167 if token, err = x.GetTenantAccessToken(ctx); err != nil { 168 return 169 } 170 body := `{}` 171 if _, err = client.R(). 172 SetContext(ctx). 173 SetBearerAuthToken(token). 174 SetBody(body). 175 SetSuccessResult(&result). 176 Post("/task/v1/tasks"); err != nil { 177 return 178 } 179 return 180 } 181 182 func (x *Service) GetTasks(ctx context.Context) (result M, err error) { 183 var token string 184 if token, err = x.GetTenantAccessToken(ctx); err != nil { 185 return 186 } 187 if _, err = client.R(). 188 SetContext(ctx). 189 SetBearerAuthToken(token). 190 SetSuccessResult(&result). 191 Get("/task/v1/tasks"); err != nil { 192 return 193 } 194 return 195 }