| 122 | } |
| 123 | |
| 124 | func (p *provider) getUserIDByEmail(ctx context.Context, email string) (id string, rerr error) { |
| 125 | if id, ok := userIDCache.Get(email); ok { |
| 126 | return id, nil |
| 127 | } |
| 128 | if t, ok := notFoundUserCache.Peek(email); ok { |
| 129 | return "", errors.Errorf("user wasn't found at %v with errcode 46004", t) |
| 130 | } |
| 131 | |
| 132 | defer func() { |
| 133 | // errcode 46004 means user not found. |
| 134 | // we consider the error to be permanent and won't retry |
| 135 | // for the email for the next 12 hours. |
| 136 | if rerr != nil && strings.Contains(rerr.Error(), "errcode 46004") { |
| 137 | notFoundUserCache.Add(email, time.Now()) |
| 138 | } |
| 139 | }() |
| 140 | |
| 141 | url, err := url.Parse("https://qyapi.weixin.qq.com/cgi-bin/user/get_userid_by_email") |
| 142 | if err != nil { |
| 143 | return "", errors.Wrapf(err, "failed to parse url") |
| 144 | } |
| 145 | |
| 146 | requestBody, err := json.Marshal(struct { |
| 147 | Email string `json:"email"` |
| 148 | EmailType int `json:"email_type"` |
| 149 | }{ |
| 150 | Email: email, |
| 151 | EmailType: 2, |
| 152 | }) |
| 153 | if err != nil { |
| 154 | return "", errors.Wrapf(err, "failed to marshal request body") |
| 155 | } |
| 156 | |
| 157 | resp, err := p.do(ctx, http.MethodPost, url, requestBody) |
| 158 | if err != nil { |
| 159 | return "", errors.Wrapf(err, "failed to get user id") |
| 160 | } |
| 161 | |
| 162 | var payload struct { |
| 163 | UserID string `json:"userid"` |
| 164 | } |
| 165 | if err := json.Unmarshal(resp, &payload); err != nil { |
| 166 | return "", errors.Wrapf(err, "failed to unmarshal payload for get user id by email") |
| 167 | } |
| 168 | |
| 169 | userIDCache.Add(email, payload.UserID) |
| 170 | |
| 171 | return payload.UserID, nil |
| 172 | } |
| 173 | |
| 174 | // https://developer.work.weixin.qq.com/document/path/90236 |
| 175 | func (p *provider) sendMessage(ctx context.Context, userIDs []string, markdown *WebhookMarkdown) error { |