fix: improve Todoist user info API call with better logging and error handling
All checks were successful
Build and Push Docker Image / build-and-push (push) Successful in 6s
All checks were successful
Build and Push Docker Image / build-and-push (push) Successful in 6s
This commit is contained in:
@@ -5848,38 +5848,76 @@ func getTodoistUserInfo(accessToken string) (struct {
|
|||||||
Email string
|
Email string
|
||||||
}
|
}
|
||||||
|
|
||||||
req, err := http.NewRequest("POST", "https://api.todoist.com/sync/v9/sync", strings.NewReader("sync_token=*&resource_types=[\"user\"]"))
|
// Формируем правильный запрос к Sync API
|
||||||
|
data := url.Values{}
|
||||||
|
data.Set("sync_token", "*")
|
||||||
|
data.Set("resource_types", `["user"]`)
|
||||||
|
|
||||||
|
req, err := http.NewRequest("POST", "https://api.todoist.com/sync/v9/sync", strings.NewReader(data.Encode()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.Printf("Todoist API: failed to create request: %v", err)
|
||||||
return userInfo, err
|
return userInfo, err
|
||||||
}
|
}
|
||||||
req.Header.Set("Authorization", "Bearer "+accessToken)
|
req.Header.Set("Authorization", "Bearer "+accessToken)
|
||||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||||
req.Header.Set("User-Agent", "PlayLife")
|
req.Header.Set("User-Agent", "PlayLife")
|
||||||
|
|
||||||
|
log.Printf("Todoist API: requesting user info from sync/v9/sync")
|
||||||
|
|
||||||
client := &http.Client{Timeout: 10 * time.Second}
|
client := &http.Client{Timeout: 10 * time.Second}
|
||||||
resp, err := client.Do(req)
|
resp, err := client.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.Printf("Todoist API: request failed: %v", err)
|
||||||
return userInfo, fmt.Errorf("failed to get user info: %w", err)
|
return userInfo, fmt.Errorf("failed to get user info: %w", err)
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
bodyBytes, _ := io.ReadAll(resp.Body)
|
||||||
|
log.Printf("Todoist API: response status=%d, body=%s", resp.StatusCode, string(bodyBytes))
|
||||||
|
|
||||||
if resp.StatusCode != http.StatusOK {
|
if resp.StatusCode != http.StatusOK {
|
||||||
body, _ := io.ReadAll(resp.Body)
|
return userInfo, fmt.Errorf("get user info failed (status %d): %s", resp.StatusCode, string(bodyBytes))
|
||||||
return userInfo, fmt.Errorf("get user info failed: %s", string(body))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var result struct {
|
// Парсим ответ - в Sync API user может быть объектом или массивом
|
||||||
User struct {
|
var result map[string]interface{}
|
||||||
ID int64 `json:"id"`
|
if err := json.Unmarshal(bodyBytes, &result); err != nil {
|
||||||
Email string `json:"email"`
|
log.Printf("Todoist API: failed to parse JSON: %v, body: %s", err, string(bodyBytes))
|
||||||
} `json:"user"`
|
|
||||||
}
|
|
||||||
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
|
|
||||||
return userInfo, fmt.Errorf("failed to decode user info: %w", err)
|
return userInfo, fmt.Errorf("failed to decode user info: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
userInfo.ID = result.User.ID
|
log.Printf("Todoist API: parsed response keys: %v", getMapKeys(result))
|
||||||
userInfo.Email = result.User.Email
|
|
||||||
|
// Проверяем разные варианты структуры ответа
|
||||||
|
if userObj, ok := result["user"].(map[string]interface{}); ok {
|
||||||
|
// Один объект user
|
||||||
|
if id, ok := userObj["id"].(float64); ok {
|
||||||
|
userInfo.ID = int64(id)
|
||||||
|
}
|
||||||
|
if email, ok := userObj["email"].(string); ok {
|
||||||
|
userInfo.Email = email
|
||||||
|
}
|
||||||
|
} else if usersArr, ok := result["user"].([]interface{}); ok && len(usersArr) > 0 {
|
||||||
|
// Массив users, берем первый
|
||||||
|
if userObj, ok := usersArr[0].(map[string]interface{}); ok {
|
||||||
|
if id, ok := userObj["id"].(float64); ok {
|
||||||
|
userInfo.ID = int64(id)
|
||||||
|
}
|
||||||
|
if email, ok := userObj["email"].(string); ok {
|
||||||
|
userInfo.Email = email
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.Printf("Todoist API: user not found in response, available keys: %v", getMapKeys(result))
|
||||||
|
return userInfo, fmt.Errorf("user not found in response")
|
||||||
|
}
|
||||||
|
|
||||||
|
if userInfo.ID == 0 || userInfo.Email == "" {
|
||||||
|
log.Printf("Todoist API: incomplete user info: ID=%d, Email=%s", userInfo.ID, userInfo.Email)
|
||||||
|
return userInfo, fmt.Errorf("incomplete user info: ID=%d, Email=%s", userInfo.ID, userInfo.Email)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("Todoist API: successfully got user info: ID=%d, Email=%s", userInfo.ID, userInfo.Email)
|
||||||
return userInfo, nil
|
return userInfo, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user