diff --git a/main_dc/yalarba/api_tp/internal/handlers/oauth.go b/main_dc/yalarba/api_tp/internal/handlers/oauth.go deleted file mode 100644 index ade44be..0000000 --- a/main_dc/yalarba/api_tp/internal/handlers/oauth.go +++ /dev/null @@ -1,130 +0,0 @@ -// handlers/oauth.go -package handlers - -import ( - "encoding/json" - "net/http" - "api_tp/internal/config" - "api_tp/internal/models" - "api_tp/internal/utils" - - "golang.org/x/oauth2" - "gorm.io/gorm" -) - -type OAuthHandler struct { - DB *gorm.DB -} - -type GoogleUserInfo struct { - ID string `json:"id"` - Email string `json:"email"` - Name string `json:"name"` -} - - -func (h *OAuthHandler) GoogleLogin(w http.ResponseWriter, r *http.Request) { - url := config.GoogleOAuthConfig.AuthCodeURL("state") - http.Redirect(w, r, url, http.StatusTemporaryRedirect) -} - -func (h *OAuthHandler) GoogleCallback(w http.ResponseWriter, r *http.Request) { - code := r.URL.Query().Get("code") - - token, err := config.GoogleOAuthConfig.Exchange(r.Context(), code) - if err != nil { - utils.WriteError(w, http.StatusBadRequest, "Failed to exchange token") - return - } - - client := config.GoogleOAuthConfig.Client(r.Context(), token) - resp, err := client.Get("https://www.googleapis.com/oauth2/v2/userinfo") - if err != nil { - utils.WriteError(w, http.StatusBadRequest, "Failed to get user info") - return - } - defer resp.Body.Close() - - var userInfo GoogleUserInfo - if err := json.NewDecoder(resp.Body).Decode(&userInfo); err != nil { - utils.WriteError(w, http.StatusBadRequest, "Failed to decode user info") - return - } - - // Создаем или находим пользователя - user, err := h.findOrCreateOAuthUser("google", userInfo.ID, userInfo.Email, userInfo.Name, token) - if err != nil { - utils.WriteError(w, http.StatusInternalServerError, "Error processing user") - return - } - - jwtToken, err := utils.GenerateJWT(user.ID, user.Email) - if err != nil { - utils.WriteError(w, http.StatusInternalServerError, "Error generating token") - return - } - - // Редирект или возврат токена - utils.WriteJSON(w, http.StatusOK, map[string]interface{}{ - "token": jwtToken, - "user": user, - }) -} - -// Аналогичные методы для Yandex и VK... - -func (h *OAuthHandler) findOrCreateOAuthUser(provider, providerID, email, name string, token *oauth2.Token) (*models.UserT, error) { - var oauthProvider models.OAuthProvider - - err := h.DB.Where("provider = ? AND provider_id = ?", provider, providerID). - Preload("User"). - First(&oauthProvider).Error - - if err == nil { - // Обновляем токены существующей привязки - oauthProvider.AccessToken = token.AccessToken - oauthProvider.RefreshToken = token.RefreshToken - oauthProvider.ExpiresAt = token.Expiry - if err := h.DB.Save(&oauthProvider).Error; err != nil { - return nil, err - } - - var user models.UserT - if err := h.DB.First(&user, oauthProvider.UserID).Error; err != nil { - return nil, err - } - return &user, nil - } - - // Ищем пользователя по email - var user models.UserT - err = h.DB.Where("email = ?", email).First(&user).Error - - if err != nil { - // Создаем нового пользователя - user = models.UserT{ - Email: email, - Name: name, - Password: utils.GenerateRandomPassword(), - } - if err := h.DB.Create(&user).Error; err != nil { - return nil, err - } - } - - // Создаем новую привязку OAuth с токенами - oauthProvider = models.OAuthProvider{ - UserID: user.ID, - Provider: provider, - ProviderID: providerID, - AccessToken: token.AccessToken, - RefreshToken: token.RefreshToken, - ExpiresAt: token.Expiry, - } - - if err := h.DB.Create(&oauthProvider).Error; err != nil { - return nil, err - } - - return &user, nil -} \ No newline at end of file diff --git a/main_dc/yalarba/api_tp/internal/handlers/oauth_VK.go b/main_dc/yalarba/api_tp/internal/handlers/oauth_VK.go deleted file mode 100644 index 6ed24a9..0000000 --- a/main_dc/yalarba/api_tp/internal/handlers/oauth_VK.go +++ /dev/null @@ -1,125 +0,0 @@ -package handlers - -import ( - "encoding/json" - "fmt" - "net/http" - "api_tp/internal/config" - "api_tp/internal/utils" -) - -// VKUserInfo представляет данные пользователя от VK -type VKUserInfo struct { - Response []struct { - ID int `json:"id"` - FirstName string `json:"first_name"` - LastName string `json:"last_name"` - Email string `json:"email"` - Photo string `json:"photo_200"` - } `json:"response"` -} - -// VKEmailResponse представляет ответ с email от VK -type VKEmailResponse struct { - Email string `json:"email"` -} - -// VKLogin initiates VK OAuth flow -func (h *OAuthHandler) VKLogin(w http.ResponseWriter, r *http.Request) { - url := config.VKOAuthConfig.AuthCodeURL("state") - http.Redirect(w, r, url, http.StatusTemporaryRedirect) -} - -// VKCallback handles VK OAuth callback -func (h *OAuthHandler) VKCallback(w http.ResponseWriter, r *http.Request) { - code := r.URL.Query().Get("code") - - token, err := config.VKOAuthConfig.Exchange(r.Context(), code) - if err != nil { - utils.WriteError(w, http.StatusBadRequest, "Failed to exchange token: "+err.Error()) - return - } - - // VK не возвращает email в основном токене, нужно получить его отдельно - email, err := h.getVKEmail(token.AccessToken) - if err != nil { - utils.WriteError(w, http.StatusBadRequest, "Failed to get email from VK: "+err.Error()) - return - } - - client := config.VKOAuthConfig.Client(r.Context(), token) - - // Получаем основную информацию о пользователе - userInfoURL := fmt.Sprintf("https://api.vk.com/method/users.get?fields=photo_200,email&v=5.131&access_token=%s", token.AccessToken) - resp, err := client.Get(userInfoURL) - if err != nil { - utils.WriteError(w, http.StatusBadRequest, "Failed to get user info: "+err.Error()) - return - } - defer resp.Body.Close() - - var vkUserInfo VKUserInfo - if err := json.NewDecoder(resp.Body).Decode(&vkUserInfo); err != nil { - utils.WriteError(w, http.StatusBadRequest, "Failed to decode user info: "+err.Error()) - return - } - - if len(vkUserInfo.Response) == 0 { - utils.WriteError(w, http.StatusBadRequest, "No user data received from VK") - return - } - - vkUser := vkUserInfo.Response[0] - userID := fmt.Sprintf("%d", vkUser.ID) - name := vkUser.FirstName + " " + vkUser.LastName - - // Используем email из отдельного запроса - if email == "" && vkUser.Email != "" { - email = vkUser.Email - } - - // Если email все еще пустой, создаем временный - if email == "" { - email = fmt.Sprintf("vk_%s@temp.vk", userID) - } - - // Создаем или находим пользователя - user, err := h.findOrCreateOAuthUser("vk", userID, email, name, token) - if err != nil { - utils.WriteError(w, http.StatusInternalServerError, "Error processing user: "+err.Error()) - return - } - - jwtToken, err := utils.GenerateJWT(user.ID, user.Email) - if err != nil { - utils.WriteError(w, http.StatusInternalServerError, "Error generating token: "+err.Error()) - return - } - - h.handleOAuthSuccess(w, r, jwtToken, user) -} - -// getVKEmail получает email из VK OAuth -func (h *OAuthHandler) getVKEmail(accessToken string) (string, error) { - // VK возвращает email в ответе на запрос токена, но если его нет, - // можно попробовать получить через API - emailURL := fmt.Sprintf("https://api.vk.com/method/account.getProfileInfo?v=5.131&access_token=%s", accessToken) - - resp, err := http.Get(emailURL) - if err != nil { - return "", err - } - defer resp.Body.Close() - - var emailResp struct { - Response struct { - Email string `json:"email"` - } `json:"response"` - } - - if err := json.NewDecoder(resp.Body).Decode(&emailResp); err != nil { - return "", err - } - - return emailResp.Response.Email, nil -} \ No newline at end of file diff --git a/main_dc/yalarba/api_tp/internal/handlers/oauth_yandex.go b/main_dc/yalarba/api_tp/internal/handlers/oauth_yandex.go deleted file mode 100644 index 3a2ddc9..0000000 --- a/main_dc/yalarba/api_tp/internal/handlers/oauth_yandex.go +++ /dev/null @@ -1,100 +0,0 @@ -package handlers - -import ( - "encoding/json" - "net/http" - "api_tp/internal/config" - "api_tp/internal/models" - "api_tp/internal/utils" - - "golang.org/x/oauth2" -) - -type YandexUserInfo struct { - ID string `json:"id"` - Login string `json:"login"` - Email string `json:"default_email"` - DisplayName string `json:"display_name"` - FirstName string `json:"first_name"` - LastName string `json:"last_name"` - RealName string `json:"real_name"` - IsAvatarEmpty bool `json:"is_avatar_empty"` -} - -// YandexLogin initiates Yandex OAuth flow -func (h *OAuthHandler) YandexLogin(w http.ResponseWriter, r *http.Request) { - url := config.YandexOAuthConfig.AuthCodeURL("state", oauth2.AccessTypeOffline) - http.Redirect(w, r, url, http.StatusTemporaryRedirect) -} - -// YandexCallback handles Yandex OAuth callback -func (h *OAuthHandler) YandexCallback(w http.ResponseWriter, r *http.Request) { - code := r.URL.Query().Get("code") - state := r.URL.Query().Get("state") - - if state != "state" { - utils.WriteError(w, http.StatusBadRequest, "Invalid state parameter") - return - } - - token, err := config.YandexOAuthConfig.Exchange(r.Context(), code) - if err != nil { - utils.WriteError(w, http.StatusBadRequest, "Failed to exchange token: "+err.Error()) - return - } - - client := config.YandexOAuthConfig.Client(r.Context(), token) - - // Получаем информацию о пользователе - resp, err := client.Get("https://login.yandex.ru/info?format=json") - if err != nil { - utils.WriteError(w, http.StatusBadRequest, "Failed to get user info: "+err.Error()) - return - } - defer resp.Body.Close() - - var userInfo YandexUserInfo - if err := json.NewDecoder(resp.Body).Decode(&userInfo); err != nil { - utils.WriteError(w, http.StatusBadRequest, "Failed to decode user info: "+err.Error()) - return - } - - // Формируем имя пользователя - name := h.getYandexUserName(userInfo) - - // Создаем или находим пользователя - user, err := h.findOrCreateOAuthUser("yandex", userInfo.ID, userInfo.Email, name, token) - if err != nil { - utils.WriteError(w, http.StatusInternalServerError, "Error processing user: "+err.Error()) - return - } - - jwtToken, err := utils.GenerateJWT(user.ID, user.Email) - if err != nil { - utils.WriteError(w, http.StatusInternalServerError, "Error generating token: "+err.Error()) - return - } - - h.handleOAuthSuccess(w, r, jwtToken, user) -} - -func (h *OAuthHandler) handleOAuthSuccess(w http.ResponseWriter, r *http.Request, jwtToken string, user *models.UserT) { - panic("unimplemented") -} - -// getYandexUserName формирует имя пользователя из данных Yandex -func (h *OAuthHandler) getYandexUserName(userInfo YandexUserInfo) string { - if userInfo.RealName != "" { - return userInfo.RealName - } - if userInfo.DisplayName != "" { - return userInfo.DisplayName - } - if userInfo.FirstName != "" && userInfo.LastName != "" { - return userInfo.FirstName + " " + userInfo.LastName - } - if userInfo.FirstName != "" { - return userInfo.FirstName - } - return userInfo.Login -} diff --git a/main_dc/yalarba/api_tp/internal/models/contacts.go b/main_dc/yalarba/api_tp/internal/models/contacts.go deleted file mode 100644 index 2578c48..0000000 --- a/main_dc/yalarba/api_tp/internal/models/contacts.go +++ /dev/null @@ -1,21 +0,0 @@ -package models - -import ( - "time" - - "gorm.io/gorm" -) - -type Contact struct { - ID uint `json:"id" gorm:"primarykey"` - UserId uint - CreatedAt time.Time `json:"created_at"` - UpdatedAt time.Time `json:"updated_at"` - DeletedAt gorm.DeletedAt `json:"deleted_at,omitempty" gorm:"index"` - - FirstName string - LastName string - PhoneNumbers map[string]string - SocialLinks map[string]string - Emails map[string]string -} diff --git a/main_dc/yalarba/api_tp/internal/models/o_auth_provider.go b/main_dc/yalarba/api_tp/internal/models/o_auth_provider.go deleted file mode 100644 index d24020d..0000000 --- a/main_dc/yalarba/api_tp/internal/models/o_auth_provider.go +++ /dev/null @@ -1,20 +0,0 @@ -package models - -import ( - "time" - - "gorm.io/gorm" -) - -type OAuthProvider struct { - ID uint `json:"id" gorm:"primaryKey"` - UserID uint `json:"user_id" gorm:"not null;index:idx_user_provider"` // Уникальный индекс с провайдером - Provider string `json:"provider" gorm:"not null;index:idx_user_provider;size:50"` // Ограничение длины - ProviderID string `json:"provider_id" gorm:"not null;uniqueIndex:uix_provider_id"` // Уникальный идентификатор - AccessToken string `json:"access_token"` - RefreshToken string `json:"refresh_token"` - ExpiresAt time.Time `json:"expires_at"` - CreatedAt time.Time `json:"created_at"` - UpdatedAt time.Time `json:"updated_at"` // Добавлено для отслеживания изменений - DeletedAt gorm.DeletedAt `json:"deleted_at" gorm:"index"` -} diff --git a/main_dc/yalarba/api_tp/internal/server/server.go b/main_dc/yalarba/api_tp/internal/server/server.go index cfb9cbe..923feb5 100644 --- a/main_dc/yalarba/api_tp/internal/server/server.go +++ b/main_dc/yalarba/api_tp/internal/server/server.go @@ -56,7 +56,6 @@ func (s *Server) setupUserRoutes(r chi.Router, db *gorm.DB) { userHandler := handlers.NewUserHandler(userService) authHandler := &handlers.AuthHandler{DB: db} - oauthHandler := &handlers.OAuthHandler{DB: db} // Публичные маршруты r.Route("/auth", func(r chi.Router) { @@ -64,13 +63,6 @@ func (s *Server) setupUserRoutes(r chi.Router, db *gorm.DB) { r.Post("/login", authHandler.Login) r.Get("/check", s.healthCheck) - // OAuth routes - r.Get("/google", oauthHandler.GoogleLogin) - r.Get("/google/callback", oauthHandler.GoogleCallback) - r.Get("/yandex", oauthHandler.YandexLogin) - r.Get("/yandex/callback", oauthHandler.YandexCallback) - r.Get("/vk", oauthHandler.VKLogin) - r.Get("/vk/callback", oauthHandler.VKCallback) }) // Защищенные маршруты diff --git a/main_dc/yalarba/api_tp/internal/utils/oauth_utils.go b/main_dc/yalarba/api_tp/internal/utils/oauth_utils.go deleted file mode 100644 index a0648ac..0000000 --- a/main_dc/yalarba/api_tp/internal/utils/oauth_utils.go +++ /dev/null @@ -1,78 +0,0 @@ -// utils/oauth_utils.go -package utils - -import ( - "crypto/rand" - "fmt" - "api_tp/internal/models" - - "golang.org/x/oauth2" - "gorm.io/gorm" -) - -type OAuthHandler struct { - DB *gorm.DB -} - -// GenerateState generates a random state string for OAuth -func GenerateState() string { - b := make([]byte, 16) - rand.Read(b) - return fmt.Sprintf("%x", b) -} - -func (h *OAuthHandler) findOrCreateOAuthUser(provider, providerID, email, name string, token *oauth2.Token) (*models.UserT, error) { - var oauthProvider models.OAuthProvider - - err := h.DB.Where("provider = ? AND provider_id = ?", provider, providerID). - Preload("User"). - First(&oauthProvider).Error - - if err == nil { - // Обновляем токены существующей привязки - oauthProvider.AccessToken = token.AccessToken - oauthProvider.RefreshToken = token.RefreshToken - oauthProvider.ExpiresAt = token.Expiry - if err := h.DB.Save(&oauthProvider).Error; err != nil { - return nil, err - } - - var user models.UserT - if err := h.DB.First(&user, oauthProvider.UserID).Error; err != nil { - return nil, err - } - return &user, nil - } - - // Ищем пользователя по email - var user models.UserT - err = h.DB.Where("email = ?", email).First(&user).Error - - if err != nil { - // Создаем нового пользователя - user = models.UserT{ - Email: email, - Name: name, - Password: GenerateRandomPassword(), - } - if err := h.DB.Create(&user).Error; err != nil { - return nil, err - } - } - - // Создаем новую привязку OAuth с токенами - oauthProvider = models.OAuthProvider{ - UserID: user.ID, - Provider: provider, - ProviderID: providerID, - AccessToken: token.AccessToken, - RefreshToken: token.RefreshToken, - ExpiresAt: token.Expiry, - } - - if err := h.DB.Create(&oauthProvider).Error; err != nil { - return nil, err - } - - return &user, nil -} diff --git a/main_dc/yalarba/api_tp/pkg/database/postgres.go b/main_dc/yalarba/api_tp/pkg/database/postgres.go index 8c26fe6..fb2ad23 100644 --- a/main_dc/yalarba/api_tp/pkg/database/postgres.go +++ b/main_dc/yalarba/api_tp/pkg/database/postgres.go @@ -32,7 +32,6 @@ func autoMigrate(db *gorm.DB) error { // автоматические миграции GORM return db.AutoMigrate( &models.UserT{}, - &models.OAuthProvider{}, // другие модели... ) } \ No newline at end of file