mirror of
https://gitlab.com/foxixus/neomovies-api.git
synced 2025-10-28 01:48:51 +05:00
Add Google OAuth
This commit is contained in:
@@ -3,6 +3,8 @@ package handlers
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"time"
|
||||
"strings"
|
||||
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
|
||||
@@ -16,9 +18,7 @@ type AuthHandler struct {
|
||||
}
|
||||
|
||||
func NewAuthHandler(authService *services.AuthService) *AuthHandler {
|
||||
return &AuthHandler{
|
||||
authService: authService,
|
||||
}
|
||||
return &AuthHandler{authService: authService}
|
||||
}
|
||||
|
||||
func (h *AuthHandler) Register(w http.ResponseWriter, r *http.Request) {
|
||||
@@ -36,11 +36,7 @@ func (h *AuthHandler) Register(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusCreated)
|
||||
json.NewEncoder(w).Encode(models.APIResponse{
|
||||
Success: true,
|
||||
Data: response,
|
||||
Message: "User registered successfully",
|
||||
})
|
||||
json.NewEncoder(w).Encode(models.APIResponse{Success: true, Data: response, Message: "User registered successfully"})
|
||||
}
|
||||
|
||||
func (h *AuthHandler) Login(w http.ResponseWriter, r *http.Request) {
|
||||
@@ -52,21 +48,82 @@ func (h *AuthHandler) Login(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
response, err := h.authService.Login(req)
|
||||
if err != nil {
|
||||
// Определяем правильный статус код в зависимости от ошибки
|
||||
statusCode := http.StatusBadRequest
|
||||
if err.Error() == "Account not activated. Please verify your email." {
|
||||
statusCode = http.StatusForbidden // 403 для неверифицированного email
|
||||
statusCode = http.StatusForbidden
|
||||
}
|
||||
http.Error(w, err.Error(), statusCode)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(models.APIResponse{
|
||||
Success: true,
|
||||
Data: response,
|
||||
Message: "Login successful",
|
||||
})
|
||||
json.NewEncoder(w).Encode(models.APIResponse{Success: true, Data: response, Message: "Login successful"})
|
||||
}
|
||||
|
||||
func (h *AuthHandler) GoogleLogin(w http.ResponseWriter, r *http.Request) {
|
||||
state := generateState()
|
||||
http.SetCookie(w, &http.Cookie{Name: "oauth_state", Value: state, HttpOnly: true, Path: "/", Expires: time.Now().Add(10 * time.Minute)})
|
||||
url, err := h.authService.GetGoogleLoginURL(state)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
http.Redirect(w, r, url, http.StatusFound)
|
||||
}
|
||||
|
||||
func (h *AuthHandler) GoogleCallback(w http.ResponseWriter, r *http.Request) {
|
||||
q := r.URL.Query()
|
||||
state := q.Get("state")
|
||||
code := q.Get("code")
|
||||
preferJSON := q.Get("response") == "json" || strings.Contains(r.Header.Get("Accept"), "application/json")
|
||||
cookie, _ := r.Cookie("oauth_state")
|
||||
if cookie == nil || cookie.Value != state || code == "" {
|
||||
if preferJSON {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
json.NewEncoder(w).Encode(models.APIResponse{Success: false, Message: "invalid oauth state"})
|
||||
return
|
||||
}
|
||||
redirectURL, ok := h.authService.BuildFrontendRedirect("", "invalid_state")
|
||||
if ok {
|
||||
http.Redirect(w, r, redirectURL, http.StatusFound)
|
||||
return
|
||||
}
|
||||
http.Error(w, "invalid oauth state", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
resp, err := h.authService.HandleGoogleCallback(r.Context(), code)
|
||||
if err != nil {
|
||||
if preferJSON {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
json.NewEncoder(w).Encode(models.APIResponse{Success: false, Message: err.Error()})
|
||||
return
|
||||
}
|
||||
redirectURL, ok := h.authService.BuildFrontendRedirect("", "auth_failed")
|
||||
if ok {
|
||||
http.Redirect(w, r, redirectURL, http.StatusFound)
|
||||
return
|
||||
}
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if preferJSON {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(models.APIResponse{Success: true, Data: resp, Message: "Login successful"})
|
||||
return
|
||||
}
|
||||
|
||||
redirectURL, ok := h.authService.BuildFrontendRedirect(resp.Token, "")
|
||||
if ok {
|
||||
http.Redirect(w, r, redirectURL, http.StatusFound)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(models.APIResponse{Success: true, Data: resp, Message: "Login successful"})
|
||||
}
|
||||
|
||||
func (h *AuthHandler) GetProfile(w http.ResponseWriter, r *http.Request) {
|
||||
@@ -83,10 +140,7 @@ func (h *AuthHandler) GetProfile(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(models.APIResponse{
|
||||
Success: true,
|
||||
Data: user,
|
||||
})
|
||||
json.NewEncoder(w).Encode(models.APIResponse{Success: true, Data: user})
|
||||
}
|
||||
|
||||
func (h *AuthHandler) UpdateProfile(w http.ResponseWriter, r *http.Request) {
|
||||
@@ -102,7 +156,6 @@ func (h *AuthHandler) UpdateProfile(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
// Удаляем поля, которые нельзя обновлять через этот эндпоинт
|
||||
delete(updates, "password")
|
||||
delete(updates, "email")
|
||||
delete(updates, "_id")
|
||||
@@ -115,14 +168,9 @@ func (h *AuthHandler) UpdateProfile(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(models.APIResponse{
|
||||
Success: true,
|
||||
Data: user,
|
||||
Message: "Profile updated successfully",
|
||||
})
|
||||
json.NewEncoder(w).Encode(models.APIResponse{Success: true, Data: user, Message: "Profile updated successfully"})
|
||||
}
|
||||
|
||||
// Удаление аккаунта
|
||||
func (h *AuthHandler) DeleteAccount(w http.ResponseWriter, r *http.Request) {
|
||||
userID, ok := middleware.GetUserIDFromContext(r.Context())
|
||||
if !ok {
|
||||
@@ -136,12 +184,9 @@ func (h *AuthHandler) DeleteAccount(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(models.APIResponse{
|
||||
Success: true,
|
||||
Message: "Account deleted successfully",
|
||||
})
|
||||
json.NewEncoder(w).Encode(models.APIResponse{Success: true, Message: "Account deleted successfully"})
|
||||
}
|
||||
// Подтверждение email
|
||||
|
||||
func (h *AuthHandler) VerifyEmail(w http.ResponseWriter, r *http.Request) {
|
||||
var req models.VerifyEmailRequest
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
@@ -159,7 +204,6 @@ func (h *AuthHandler) VerifyEmail(w http.ResponseWriter, r *http.Request) {
|
||||
json.NewEncoder(w).Encode(response)
|
||||
}
|
||||
|
||||
// Повторная отправка кода верификации
|
||||
func (h *AuthHandler) ResendVerificationCode(w http.ResponseWriter, r *http.Request) {
|
||||
var req models.ResendCodeRequest
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
@@ -175,4 +219,7 @@ func (h *AuthHandler) ResendVerificationCode(w http.ResponseWriter, r *http.Requ
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(response)
|
||||
}
|
||||
}
|
||||
|
||||
// helpers
|
||||
func generateState() string { return uuidNew() }
|
||||
Reference in New Issue
Block a user