(FEAT): Added errors to each of the handlers.
I think this is really the only place we need them. For now at least.
This commit is contained in:
parent
6b030adf02
commit
1e6a06e8ed
@ -6,6 +6,7 @@ import (
|
|||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
domain "github.com/haydenhargreaves/Potion/internal/domain/server"
|
domain "github.com/haydenhargreaves/Potion/internal/domain/server"
|
||||||
|
"github.com/haydenhargreaves/Potion/internal/templates/components"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GoogleLogin directs the user to Googles select user login page. Once the user has selected an
|
// GoogleLogin directs the user to Googles select user login page. Once the user has selected an
|
||||||
@ -21,8 +22,6 @@ func GoogleLogin(ctx *gin.Context) {
|
|||||||
// account. They will be directed here and a JWT is generated. This JWT is stored in the users
|
// account. They will be directed here and a JWT is generated. This JWT is stored in the users
|
||||||
// cookies and will be used by protected routes to validate their login status.
|
// cookies and will be used by protected routes to validate their login status.
|
||||||
//
|
//
|
||||||
// TODO: This route does not do the proper handling, need to work on the redirection or handling.
|
|
||||||
//
|
|
||||||
// We do not need to return all of this data, it is just for testing.
|
// We do not need to return all of this data, it is just for testing.
|
||||||
func GoogleCallback(ctx *gin.Context) {
|
func GoogleCallback(ctx *gin.Context) {
|
||||||
deps := ctx.MustGet("deps").(*domain.InjectedDependencies)
|
deps := ctx.MustGet("deps").(*domain.InjectedDependencies)
|
||||||
@ -32,15 +31,11 @@ func GoogleCallback(ctx *gin.Context) {
|
|||||||
code string = ctx.Query("code")
|
code string = ctx.Query("code")
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO: Do something real, not just return data
|
if jwt, err := deps.AuthService.GoogleAuthSuccess(state, code); err != nil {
|
||||||
if jwt, dbUser, googleUserInfo, err := deps.AuthService.GoogleAuthSuccess(state, code); err != nil {
|
components.RenderErrorBanner(ctx, err.Error())
|
||||||
ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||||
} else {
|
} else {
|
||||||
domain.SetCookie(ctx, "jwt_token", jwt, time.Hour*24*7)
|
domain.SetCookie(ctx, "jwt_token", jwt, time.Hour*24*7)
|
||||||
// ctx.JSON(http.StatusOK, gin.H{"jwt": jwt, "googleUserInfo": googleUserInfo, "dbUser": dbUser})
|
|
||||||
_ = dbUser
|
|
||||||
_ = googleUserInfo
|
|
||||||
|
|
||||||
ctx.Redirect(http.StatusSeeOther, "/")
|
ctx.Redirect(http.StatusSeeOther, "/")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -24,6 +24,7 @@ func EngagementViewRecipe(ctx *gin.Context) {
|
|||||||
|
|
||||||
if !domain.IsLoggedIn(ctx) || user == nil {
|
if !domain.IsLoggedIn(ctx) || user == nil {
|
||||||
if _, err := deps.EngagementService.ViewRecipe(recipeId); err != nil {
|
if _, err := deps.EngagementService.ViewRecipe(recipeId); err != nil {
|
||||||
|
components.RenderErrorBanner(ctx, err.Error())
|
||||||
ctx.JSON(http.StatusInternalServerError, gin.H{
|
ctx.JSON(http.StatusInternalServerError, gin.H{
|
||||||
"status": http.StatusInternalServerError,
|
"status": http.StatusInternalServerError,
|
||||||
"message": err.Error(),
|
"message": err.Error(),
|
||||||
@ -37,6 +38,7 @@ func EngagementViewRecipe(ctx *gin.Context) {
|
|||||||
|
|
||||||
// We caught nil already, we can assume the user exists
|
// We caught nil already, we can assume the user exists
|
||||||
if _, err := deps.EngagementService.UserViewRecipe(user.Id, recipeId); err != nil {
|
if _, err := deps.EngagementService.UserViewRecipe(user.Id, recipeId); err != nil {
|
||||||
|
components.RenderErrorBanner(ctx, err.Error())
|
||||||
ctx.JSON(http.StatusInternalServerError, gin.H{
|
ctx.JSON(http.StatusInternalServerError, gin.H{
|
||||||
"status": http.StatusInternalServerError,
|
"status": http.StatusInternalServerError,
|
||||||
"message": err.Error(),
|
"message": err.Error(),
|
||||||
@ -61,6 +63,7 @@ func EngagementShareRecipe(ctx *gin.Context) {
|
|||||||
|
|
||||||
if !domain.IsLoggedIn(ctx) || user == nil {
|
if !domain.IsLoggedIn(ctx) || user == nil {
|
||||||
if _, err := deps.EngagementService.ShareRecipe(recipeId); err != nil {
|
if _, err := deps.EngagementService.ShareRecipe(recipeId); err != nil {
|
||||||
|
components.RenderErrorBanner(ctx, err.Error())
|
||||||
ctx.JSON(http.StatusInternalServerError, gin.H{
|
ctx.JSON(http.StatusInternalServerError, gin.H{
|
||||||
"status": http.StatusInternalServerError,
|
"status": http.StatusInternalServerError,
|
||||||
"message": err.Error(),
|
"message": err.Error(),
|
||||||
@ -72,6 +75,7 @@ func EngagementShareRecipe(ctx *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if _, err := deps.EngagementService.UserShareRecipe(user.Id, recipeId); err != nil {
|
if _, err := deps.EngagementService.UserShareRecipe(user.Id, recipeId); err != nil {
|
||||||
|
components.RenderErrorBanner(ctx, err.Error())
|
||||||
ctx.JSON(http.StatusInternalServerError, gin.H{
|
ctx.JSON(http.StatusInternalServerError, gin.H{
|
||||||
"status": http.StatusInternalServerError,
|
"status": http.StatusInternalServerError,
|
||||||
"message": err.Error(),
|
"message": err.Error(),
|
||||||
@ -133,6 +137,7 @@ func EngagementMakeRecipe(ctx *gin.Context) {
|
|||||||
recipeId, _ := strconv.Atoi(id)
|
recipeId, _ := strconv.Atoi(id)
|
||||||
|
|
||||||
if _, err := deps.EngagementService.UserMakeRecipe(user.Id, recipeId); err != nil {
|
if _, err := deps.EngagementService.UserMakeRecipe(user.Id, recipeId); err != nil {
|
||||||
|
components.RenderErrorBanner(ctx, err.Error())
|
||||||
ctx.JSON(http.StatusInternalServerError, gin.H{
|
ctx.JSON(http.StatusInternalServerError, gin.H{
|
||||||
"status": http.StatusInternalServerError,
|
"status": http.StatusInternalServerError,
|
||||||
"message": err.Error(),
|
"message": err.Error(),
|
||||||
|
|||||||
@ -10,6 +10,7 @@ import (
|
|||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
domainRecipe "github.com/haydenhargreaves/Potion/internal/domain/recipe"
|
domainRecipe "github.com/haydenhargreaves/Potion/internal/domain/recipe"
|
||||||
domain "github.com/haydenhargreaves/Potion/internal/domain/server"
|
domain "github.com/haydenhargreaves/Potion/internal/domain/server"
|
||||||
|
"github.com/haydenhargreaves/Potion/internal/templates/components"
|
||||||
templates "github.com/haydenhargreaves/Potion/internal/templates/pages"
|
templates "github.com/haydenhargreaves/Potion/internal/templates/pages"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -24,6 +25,7 @@ func CreateRecipe(ctx *gin.Context) {
|
|||||||
|
|
||||||
recipe, err := deps.RecipeService.CreateRecipe(ctx)
|
recipe, err := deps.RecipeService.CreateRecipe(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
components.RenderErrorBanner(ctx, err.Error())
|
||||||
ctx.String(http.StatusOK, CREATE_ERROR_HTML, err.Error())
|
ctx.String(http.StatusOK, CREATE_ERROR_HTML, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -89,6 +91,7 @@ func SearchRecipes(ctx *gin.Context) {
|
|||||||
// We don't care about favorite status, so use false
|
// We don't care about favorite status, so use false
|
||||||
recipes, err := deps.RecipeService.SearchRecipes(filters, userId, false)
|
recipes, err := deps.RecipeService.SearchRecipes(filters, userId, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
components.RenderErrorBanner(ctx, err.Error())
|
||||||
ctx.JSON(http.StatusOK, gin.H{"error": err.Error()})
|
ctx.JSON(http.StatusOK, gin.H{"error": err.Error()})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,6 +129,7 @@ func SearchRecipesFavorites(ctx *gin.Context) {
|
|||||||
// TODO: Error here if they're not logged in?
|
// TODO: Error here if they're not logged in?
|
||||||
// Get user data (they should be logged in)
|
// Get user data (they should be logged in)
|
||||||
if !domain.IsLoggedIn(ctx) {
|
if !domain.IsLoggedIn(ctx) {
|
||||||
|
components.RenderErrorBanner(ctx, "User is not logged in. User will be nil.")
|
||||||
ctx.JSON(http.StatusOK, gin.H{"error": "User is not logged in. User will be nil."})
|
ctx.JSON(http.StatusOK, gin.H{"error": "User is not logged in. User will be nil."})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,6 +137,7 @@ func SearchRecipesFavorites(ctx *gin.Context) {
|
|||||||
|
|
||||||
recipes, err := deps.RecipeService.SearchRecipes(filters, &userId, true)
|
recipes, err := deps.RecipeService.SearchRecipes(filters, &userId, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
components.RenderErrorBanner(ctx, err.Error())
|
||||||
ctx.JSON(http.StatusOK, gin.H{"error": err.Error()})
|
ctx.JSON(http.StatusOK, gin.H{"error": err.Error()})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import (
|
|||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
domain "github.com/haydenhargreaves/Potion/internal/domain/server"
|
domain "github.com/haydenhargreaves/Potion/internal/domain/server"
|
||||||
|
"github.com/haydenhargreaves/Potion/internal/templates/components"
|
||||||
)
|
)
|
||||||
|
|
||||||
func GetUserRecipes(ctx *gin.Context) {
|
func GetUserRecipes(ctx *gin.Context) {
|
||||||
@ -21,6 +22,7 @@ func GetUserRecipes(ctx *gin.Context) {
|
|||||||
|
|
||||||
// Ensure logged in
|
// Ensure logged in
|
||||||
if !domain.IsLoggedIn(ctx) || user == nil {
|
if !domain.IsLoggedIn(ctx) || user == nil {
|
||||||
|
components.RenderErrorBanner(ctx, "User is not authorized to access this endpoint. Please login to continue.")
|
||||||
ctx.JSON(http.StatusUnauthorized, gin.H{
|
ctx.JSON(http.StatusUnauthorized, gin.H{
|
||||||
"status": http.StatusUnauthorized,
|
"status": http.StatusUnauthorized,
|
||||||
"message": "User is not authorized to access this endpoint. Please login to continue.",
|
"message": "User is not authorized to access this endpoint. Please login to continue.",
|
||||||
@ -31,6 +33,7 @@ func GetUserRecipes(ctx *gin.Context) {
|
|||||||
|
|
||||||
recipes, err := deps.RecipeService.GetUserRecipes(user.Id)
|
recipes, err := deps.RecipeService.GetUserRecipes(user.Id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
components.RenderErrorBanner(ctx, fmt.Sprintf("Could not get user recipes. %s", err.Error()))
|
||||||
ctx.JSON(http.StatusBadRequest, gin.H{
|
ctx.JSON(http.StatusBadRequest, gin.H{
|
||||||
"status": http.StatusBadRequest,
|
"status": http.StatusBadRequest,
|
||||||
"message": fmt.Sprintf("Could not get user recipes. %s", err.Error()),
|
"message": fmt.Sprintf("Could not get user recipes. %s", err.Error()),
|
||||||
@ -59,6 +62,7 @@ func GetUserFavoriteRecipes(ctx *gin.Context) {
|
|||||||
|
|
||||||
// Ensure logged in
|
// Ensure logged in
|
||||||
if !domain.IsLoggedIn(ctx) || user == nil {
|
if !domain.IsLoggedIn(ctx) || user == nil {
|
||||||
|
components.RenderErrorBanner(ctx, "User is not authorized to access this endpoint. Please login to continue.")
|
||||||
ctx.JSON(http.StatusUnauthorized, gin.H{
|
ctx.JSON(http.StatusUnauthorized, gin.H{
|
||||||
"status": http.StatusUnauthorized,
|
"status": http.StatusUnauthorized,
|
||||||
"message": "User is not authorized to access this endpoint. Please login to continue.",
|
"message": "User is not authorized to access this endpoint. Please login to continue.",
|
||||||
@ -69,9 +73,10 @@ func GetUserFavoriteRecipes(ctx *gin.Context) {
|
|||||||
|
|
||||||
recipes, err := deps.RecipeService.GetUserFavoriteRecipes(user.Id)
|
recipes, err := deps.RecipeService.GetUserFavoriteRecipes(user.Id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
components.RenderErrorBanner(ctx, fmt.Sprintf("Could not get favorite recipes. %s", err.Error()))
|
||||||
ctx.JSON(http.StatusBadRequest, gin.H{
|
ctx.JSON(http.StatusBadRequest, gin.H{
|
||||||
"status": http.StatusBadRequest,
|
"status": http.StatusBadRequest,
|
||||||
"message": fmt.Sprintf("Could not get user recipes. %s", err.Error()),
|
"message": fmt.Sprintf("Could not get favorite recipes. %s", err.Error()),
|
||||||
"recipes": nil,
|
"recipes": nil,
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
|
|||||||
@ -60,48 +60,48 @@ func (s *AuthService) GetGoogleAuthUrl() string {
|
|||||||
|
|
||||||
// GoogleAuthSuccess accepts the data from the Google login endpoint and uses it to fetch the users
|
// GoogleAuthSuccess accepts the data from the Google login endpoint and uses it to fetch the users
|
||||||
// data. The data is then used to log the user in or create an account.
|
// data. The data is then used to log the user in or create an account.
|
||||||
func (s *AuthService) GoogleAuthSuccess(state, code string) (string, domain.User, domain.GoogleUserInfo, error) {
|
func (s *AuthService) GoogleAuthSuccess(state, code string) (string, error) {
|
||||||
// Ensure the state matches, prevents M.I.T.M. attacks
|
// Ensure the state matches, prevents M.I.T.M. attacks
|
||||||
if state != "randomstate" {
|
if state != "randomstate" {
|
||||||
return "", domain.User{}, domain.GoogleUserInfo{}, fmt.Errorf("States don't match, received %s", state)
|
return "", fmt.Errorf("States don't match, received %s", state)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get access token from Google
|
// Get access token from Google
|
||||||
token, err := auth.GoogleAuthConfig.Exchange(context.Background(), code)
|
token, err := auth.GoogleAuthConfig.Exchange(context.Background(), code)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", domain.User{}, domain.GoogleUserInfo{}, fmt.Errorf("Code exchange failed: %s", err.Error())
|
return "", fmt.Errorf("Code exchange failed: %s", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use the access token to get user data
|
// Use the access token to get user data
|
||||||
googleUserInfo, err := auth.GetUserData(token.AccessToken)
|
googleUserInfo, err := auth.GetUserData(token.AccessToken)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", domain.User{}, domain.GoogleUserInfo{}, err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attempt to get the user, user is nil when they don't exit
|
// Attempt to get the user, user is nil when they don't exit
|
||||||
user, err := s.userRepository.GetGoogleUser(googleUserInfo.Id)
|
user, err := s.userRepository.GetGoogleUser(googleUserInfo.Id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", domain.User{}, domain.GoogleUserInfo{}, fmt.Errorf("Failed to get db user: %s", err)
|
return "", fmt.Errorf("Failed to get db user: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// A user was found
|
// A user was found
|
||||||
if user != nil {
|
if user != nil {
|
||||||
jwt, err := generateJwt(user.Id, user.Email, s.jwtSecret)
|
jwt, err := generateJwt(user.Id, user.Email, s.jwtSecret)
|
||||||
return jwt, *user, googleUserInfo, err
|
return jwt, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// user did not exist, need to create one
|
// user did not exist, need to create one
|
||||||
newUser, err := s.userRepository.CreateGoogleUser(&googleUserInfo, token.RefreshToken)
|
newUser, err := s.userRepository.CreateGoogleUser(&googleUserInfo, token.RefreshToken)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", domain.User{}, domain.GoogleUserInfo{}, fmt.Errorf("Repository failed to create user: %s", err.Error())
|
return "", fmt.Errorf("Repository failed to create user: %s", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
jwt, err := generateJwt(newUser.Id, newUser.Email, s.jwtSecret)
|
jwt, err := generateJwt(newUser.Id, newUser.Email, s.jwtSecret)
|
||||||
return jwt, newUser, googleUserInfo, err
|
return jwt, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// generateJwt requires user data and returns a JSON web token which can be stored in the browsers
|
// generateJwt requires user data and returns a JSON web token which can be stored in the browsers
|
||||||
// cookies. This token is used to log a user into the application and allow access to protected
|
// cookies. This token is used to log a user into the application and allow access to protected
|
||||||
// routes.
|
// routes.
|
||||||
func generateJwt(userId int, email string, jwtSecret []byte) (string, error) {
|
func generateJwt(userId int, email string, jwtSecret []byte) (string, error) {
|
||||||
expiration := time.Now().Add(7 * 24 * time.Hour)
|
expiration := time.Now().Add(7 * 24 * time.Hour)
|
||||||
|
|||||||
@ -1,10 +1,6 @@
|
|||||||
package domain
|
package domain
|
||||||
|
|
||||||
import (
|
|
||||||
domain "github.com/haydenhargreaves/Potion/internal/domain/user"
|
|
||||||
)
|
|
||||||
|
|
||||||
type AuthService interface {
|
type AuthService interface {
|
||||||
GetGoogleAuthUrl() string
|
GetGoogleAuthUrl() string
|
||||||
GoogleAuthSuccess(state, code string) (string, domain.User, domain.GoogleUserInfo, error)
|
GoogleAuthSuccess(state, code string) (string, error)
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user