diff --git a/play-life-backend/main.go b/play-life-backend/main.go index ed0b56f..49c5ab9 100644 --- a/play-life-backend/main.go +++ b/play-life-backend/main.go @@ -5848,38 +5848,76 @@ func getTodoistUserInfo(accessToken string) (struct { 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 { + log.Printf("Todoist API: failed to create request: %v", err) return userInfo, err } req.Header.Set("Authorization", "Bearer "+accessToken) req.Header.Set("Content-Type", "application/x-www-form-urlencoded") req.Header.Set("User-Agent", "PlayLife") + log.Printf("Todoist API: requesting user info from sync/v9/sync") + client := &http.Client{Timeout: 10 * time.Second} resp, err := client.Do(req) if err != nil { + log.Printf("Todoist API: request failed: %v", err) return userInfo, fmt.Errorf("failed to get user info: %w", err) } 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 { - body, _ := io.ReadAll(resp.Body) - return userInfo, fmt.Errorf("get user info failed: %s", string(body)) + return userInfo, fmt.Errorf("get user info failed (status %d): %s", resp.StatusCode, string(bodyBytes)) } - var result struct { - User struct { - ID int64 `json:"id"` - Email string `json:"email"` - } `json:"user"` - } - if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { + // Парсим ответ - в Sync API user может быть объектом или массивом + var result map[string]interface{} + if err := json.Unmarshal(bodyBytes, &result); err != nil { + log.Printf("Todoist API: failed to parse JSON: %v, body: %s", err, string(bodyBytes)) return userInfo, fmt.Errorf("failed to decode user info: %w", err) } - userInfo.ID = result.User.ID - userInfo.Email = result.User.Email + log.Printf("Todoist API: parsed response keys: %v", getMapKeys(result)) + + // Проверяем разные варианты структуры ответа + 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 }