Add login
This commit is contained in:
94
handlers/handler.go
Executable file
94
handlers/handler.go
Executable file
@@ -0,0 +1,94 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"hamster-tycoon/middlewares"
|
||||
"hamster-tycoon/service"
|
||||
"hamster-tycoon/storage/dao"
|
||||
"hamster-tycoon/storage/dao/fake"
|
||||
"hamster-tycoon/storage/dao/postgresql"
|
||||
"hamster-tycoon/storage/validators"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/gin-contrib/cors"
|
||||
"github.com/gin-gonic/gin"
|
||||
"gopkg.in/go-playground/validator.v9"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Mock bool
|
||||
DBConnectionURI string
|
||||
Port int
|
||||
LogLevel string
|
||||
LogFormat string
|
||||
}
|
||||
|
||||
type handlersContext struct {
|
||||
db dao.Database
|
||||
validator *validator.Validate
|
||||
userService *service.UserService
|
||||
}
|
||||
|
||||
func NewRouter(config *Config) *gin.Engine {
|
||||
gin.SetMode(gin.ReleaseMode)
|
||||
|
||||
router := gin.New()
|
||||
router.HandleMethodNotAllowed = true
|
||||
|
||||
router.Use(cors.New(cors.Config{
|
||||
AllowOrigins: []string{"*"},
|
||||
AllowMethods: []string{"*"},
|
||||
AllowHeaders: []string{"*"},
|
||||
ExposeHeaders: []string{"*"},
|
||||
AllowCredentials: true,
|
||||
MaxAge: 12 * time.Hour,
|
||||
}))
|
||||
router.Use(gin.Recovery())
|
||||
router.Use(middlewares.GetLoggerMiddleware())
|
||||
router.Use(middlewares.GetHTTPLoggerMiddleware())
|
||||
|
||||
hc := &handlersContext{}
|
||||
if config.Mock {
|
||||
hc.db = fake.NewDatabaseFake()
|
||||
} else {
|
||||
hc.db = postgresql.NewDatabasePostgreSQL(config.DBConnectionURI)
|
||||
}
|
||||
hc.validator = newValidator()
|
||||
hc.userService = service.NewUserService(hc.db)
|
||||
public := router.Group("/")
|
||||
public.Handle(http.MethodGet, "/_health", hc.GetHealth)
|
||||
|
||||
public.Handle("LOGIN", "/users", hc.ConnectUser)
|
||||
// start: user routes
|
||||
public.Handle(http.MethodGet, "/users", hc.GetAllUsers)
|
||||
public.Handle(http.MethodPost, "/users", hc.CreateUser)
|
||||
public.Handle(http.MethodGet, "/users/:id", hc.GetUser)
|
||||
public.Handle(http.MethodPut, "/users/:id", hc.UpdateUser)
|
||||
public.Handle(http.MethodDelete, "/users/:id", hc.DeleteUser)
|
||||
// end: user routes
|
||||
|
||||
return router
|
||||
}
|
||||
|
||||
func newValidator() *validator.Validate {
|
||||
va := validator.New()
|
||||
|
||||
va.RegisterTagNameFunc(func(fld reflect.StructField) string {
|
||||
name := strings.SplitN(fld.Tag.Get("json"), ",", 2)
|
||||
if len(name) < 1 {
|
||||
return ""
|
||||
}
|
||||
return name[0]
|
||||
})
|
||||
|
||||
for k, v := range validators.CustomValidators {
|
||||
if v.Validator != nil {
|
||||
va.RegisterValidationCtx(k, v.Validator)
|
||||
}
|
||||
}
|
||||
|
||||
return va
|
||||
}
|
||||
12
handlers/health_handler.go
Executable file
12
handlers/health_handler.go
Executable file
@@ -0,0 +1,12 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"hamster-tycoon/utils"
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func (hc *handlersContext) GetHealth(c *gin.Context) {
|
||||
utils.JSON(c.Writer, http.StatusNoContent, nil)
|
||||
}
|
||||
264
handlers/user_handler.go
Executable file
264
handlers/user_handler.go
Executable file
@@ -0,0 +1,264 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"hamster-tycoon/storage/dao"
|
||||
"hamster-tycoon/storage/model"
|
||||
"hamster-tycoon/storage/validators"
|
||||
"hamster-tycoon/utils"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"google.golang.org/api/oauth2/v2"
|
||||
)
|
||||
|
||||
var httpClient = &http.Client{}
|
||||
|
||||
func (hc *handlersContext) GetAllUsers(c *gin.Context) {
|
||||
users, err := hc.db.GetAllUsers()
|
||||
if err != nil {
|
||||
utils.GetLoggerFromCtx(c).WithError(err).Error("error while getting users")
|
||||
utils.JSONErrorWithMessage(c.Writer, model.ErrInternalServer, "Error while getting users")
|
||||
return
|
||||
}
|
||||
utils.JSON(c.Writer, http.StatusOK, users)
|
||||
}
|
||||
|
||||
func (hc *handlersContext) ConnectUser(c *gin.Context) {
|
||||
authorizationHeader := c.GetHeader("Authorization")
|
||||
authorizationHeaderSplitted := strings.Split(authorizationHeader, " ")
|
||||
if len(authorizationHeaderSplitted) != 2 {
|
||||
utils.JSONError(c.Writer, model.ErrBadRequestFormat)
|
||||
return
|
||||
}
|
||||
|
||||
oauth2Service, err := oauth2.New(httpClient)
|
||||
tokenInfoCall := oauth2Service.Tokeninfo()
|
||||
tokenInfoCall.IdToken(authorizationHeaderSplitted[1])
|
||||
tokenInfo, err := tokenInfoCall.Do()
|
||||
if err != nil {
|
||||
utils.GetLogger().WithError(err).Error(err)
|
||||
utils.JSONError(c.Writer, model.ErrBadRequestFormat)
|
||||
return
|
||||
}
|
||||
user, err := hc.userService.GetUserFromGoogleId(tokenInfo.UserId)
|
||||
if err != nil {
|
||||
utils.GetLogger().WithError(err).Error(err)
|
||||
if castedError, ok := err.(*model.APIError); ok {
|
||||
if castedError.Type == model.ErrNotFound.Type {
|
||||
user, err := hc.userService.CreateUserFromGoogleToken(tokenInfo.UserId, tokenInfo.Email)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
utils.JSONError(c.Writer, model.ErrInternalServer)
|
||||
return
|
||||
}
|
||||
utils.JSON(c.Writer, 200, user)
|
||||
return
|
||||
}
|
||||
utils.JSONError(c.Writer, *castedError)
|
||||
return
|
||||
}
|
||||
utils.JSONError(c.Writer, model.ErrInternalServer)
|
||||
return
|
||||
}
|
||||
|
||||
utils.JSON(c.Writer, 200, user)
|
||||
}
|
||||
func (hc *handlersContext) CreateUser(c *gin.Context) {
|
||||
b, err := c.GetRawData()
|
||||
if err != nil {
|
||||
utils.GetLoggerFromCtx(c).WithError(err).Error("error while creating user, read data fail")
|
||||
utils.JSONError(c.Writer, model.ErrInternalServer)
|
||||
return
|
||||
}
|
||||
|
||||
userToCreate := model.UserEditable{}
|
||||
err = json.Unmarshal(b, &userToCreate)
|
||||
if err != nil {
|
||||
utils.JSONError(c.Writer, model.ErrBadRequestFormat)
|
||||
return
|
||||
}
|
||||
|
||||
err = hc.validator.StructCtx(c, userToCreate)
|
||||
if err != nil {
|
||||
utils.JSONError(c.Writer, validators.NewDataValidationAPIError(err))
|
||||
return
|
||||
}
|
||||
|
||||
user := model.User{
|
||||
UserEditable: userToCreate,
|
||||
}
|
||||
|
||||
err = hc.db.CreateUser(&user)
|
||||
if e, ok := err.(*dao.DAOError); ok {
|
||||
switch {
|
||||
case e.Type == dao.ErrTypeDuplicate:
|
||||
utils.JSONErrorWithMessage(c.Writer, model.ErrAlreadyExists, "User already exists")
|
||||
return
|
||||
default:
|
||||
utils.GetLoggerFromCtx(c).WithError(err).WithField("type", e.Type).Error("error CreateUser: Error type not handled")
|
||||
utils.JSONError(c.Writer, model.ErrInternalServer)
|
||||
return
|
||||
}
|
||||
} else if err != nil {
|
||||
utils.GetLoggerFromCtx(c).WithError(err).Error("error while creating user")
|
||||
utils.JSONError(c.Writer, model.ErrInternalServer)
|
||||
return
|
||||
}
|
||||
|
||||
utils.JSON(c.Writer, http.StatusCreated, user)
|
||||
}
|
||||
|
||||
func (hc *handlersContext) GetUser(c *gin.Context) {
|
||||
userID := c.Param("id")
|
||||
|
||||
err := hc.validator.VarCtx(c, userID, "uuid4")
|
||||
if err != nil {
|
||||
utils.JSONError(c.Writer, validators.NewDataValidationAPIError(err))
|
||||
return
|
||||
}
|
||||
|
||||
user, err := hc.db.GetUsersByID(userID)
|
||||
if e, ok := err.(*dao.DAOError); ok {
|
||||
switch {
|
||||
case e.Type == dao.ErrTypeNotFound:
|
||||
utils.JSONErrorWithMessage(c.Writer, model.ErrNotFound, "User not found")
|
||||
return
|
||||
default:
|
||||
utils.GetLoggerFromCtx(c).WithError(err).WithField("type", e.Type).Error("error GetUser: get user error type not handled")
|
||||
utils.JSONError(c.Writer, model.ErrInternalServer)
|
||||
return
|
||||
}
|
||||
} else if err != nil {
|
||||
utils.GetLoggerFromCtx(c).WithError(err).Error("error while get user")
|
||||
utils.JSONError(c.Writer, model.ErrInternalServer)
|
||||
return
|
||||
}
|
||||
|
||||
if user == nil {
|
||||
utils.JSONErrorWithMessage(c.Writer, model.ErrNotFound, "User not found")
|
||||
return
|
||||
}
|
||||
|
||||
utils.JSON(c.Writer, http.StatusOK, user)
|
||||
}
|
||||
|
||||
func (hc *handlersContext) DeleteUser(c *gin.Context) {
|
||||
userID := c.Param("id")
|
||||
|
||||
err := hc.validator.VarCtx(c, userID, "uuid4")
|
||||
if err != nil {
|
||||
utils.JSONError(c.Writer, validators.NewDataValidationAPIError(err))
|
||||
return
|
||||
}
|
||||
|
||||
// check user id given in URL exists
|
||||
_, err = hc.db.GetUsersByID(userID)
|
||||
if e, ok := err.(*dao.DAOError); ok {
|
||||
switch {
|
||||
case e.Type == dao.ErrTypeNotFound:
|
||||
utils.JSONErrorWithMessage(c.Writer, model.ErrNotFound, "User to delete not found")
|
||||
return
|
||||
default:
|
||||
utils.GetLoggerFromCtx(c).WithError(err).WithField("type", e.Type).Error("error DeleteUser: get user error type not handled")
|
||||
utils.JSONError(c.Writer, model.ErrInternalServer)
|
||||
return
|
||||
}
|
||||
} else if err != nil {
|
||||
utils.GetLoggerFromCtx(c).WithError(err).Error("error while get user to delete")
|
||||
utils.JSONError(c.Writer, model.ErrInternalServer)
|
||||
return
|
||||
}
|
||||
|
||||
err = hc.db.DeleteUser(userID)
|
||||
if e, ok := err.(*dao.DAOError); ok {
|
||||
switch {
|
||||
case e.Type == dao.ErrTypeNotFound:
|
||||
utils.JSONErrorWithMessage(c.Writer, model.ErrNotFound, "User to delete not found")
|
||||
return
|
||||
default:
|
||||
utils.GetLoggerFromCtx(c).WithError(err).WithField("type", e.Type).Error("error DeleteUser: Error type not handled")
|
||||
utils.JSONError(c.Writer, model.ErrInternalServer)
|
||||
return
|
||||
}
|
||||
} else if err != nil {
|
||||
utils.GetLoggerFromCtx(c).WithError(err).Error("error while deleting user")
|
||||
utils.JSONError(c.Writer, model.ErrInternalServer)
|
||||
return
|
||||
}
|
||||
|
||||
utils.JSON(c.Writer, http.StatusNoContent, nil)
|
||||
}
|
||||
|
||||
func (hc *handlersContext) UpdateUser(c *gin.Context) {
|
||||
userID := c.Param("id")
|
||||
|
||||
err := hc.validator.VarCtx(c, userID, "uuid4")
|
||||
if err != nil {
|
||||
utils.JSONError(c.Writer, validators.NewDataValidationAPIError(err))
|
||||
return
|
||||
}
|
||||
|
||||
// check user id given in URL exists
|
||||
user, err := hc.db.GetUsersByID(userID)
|
||||
if e, ok := err.(*dao.DAOError); ok {
|
||||
switch {
|
||||
case e.Type == dao.ErrTypeNotFound:
|
||||
utils.JSONErrorWithMessage(c.Writer, model.ErrNotFound, "User to update not found")
|
||||
return
|
||||
default:
|
||||
utils.GetLoggerFromCtx(c).WithError(err).WithField("type", e.Type).Error("deleteUser: get user error type not handled")
|
||||
utils.JSONError(c.Writer, model.ErrInternalServer)
|
||||
return
|
||||
}
|
||||
} else if err != nil {
|
||||
utils.GetLoggerFromCtx(c).WithError(err).Error("error while get user to update")
|
||||
utils.JSONError(c.Writer, model.ErrInternalServer)
|
||||
return
|
||||
}
|
||||
|
||||
// get body and verify data
|
||||
b, err := c.GetRawData()
|
||||
if err != nil {
|
||||
utils.GetLoggerFromCtx(c).WithError(err).Error("error while updating user, read data fail")
|
||||
utils.JSONError(c.Writer, model.ErrInternalServer)
|
||||
return
|
||||
}
|
||||
|
||||
userToUpdate := model.UserEditable{}
|
||||
err = json.Unmarshal(b, &userToUpdate)
|
||||
if err != nil {
|
||||
utils.JSONError(c.Writer, model.ErrBadRequestFormat)
|
||||
return
|
||||
}
|
||||
|
||||
err = hc.validator.StructCtx(c, userToUpdate)
|
||||
if err != nil {
|
||||
utils.JSONError(c.Writer, validators.NewDataValidationAPIError(err))
|
||||
return
|
||||
}
|
||||
|
||||
user.UserEditable = userToUpdate
|
||||
|
||||
// make the update
|
||||
err = hc.db.UpdateUser(user)
|
||||
if e, ok := err.(*dao.DAOError); ok {
|
||||
switch {
|
||||
case e.Type == dao.ErrTypeNotFound:
|
||||
utils.JSONErrorWithMessage(c.Writer, model.ErrNotFound, "User to update not found")
|
||||
return
|
||||
default:
|
||||
utils.GetLoggerFromCtx(c).WithError(err).WithField("type", e.Type).Error("error UpdateUser: Error type not handled")
|
||||
utils.JSONError(c.Writer, model.ErrInternalServer)
|
||||
return
|
||||
}
|
||||
} else if err != nil {
|
||||
utils.GetLoggerFromCtx(c).WithError(err).Error("error while deleting user")
|
||||
utils.JSONError(c.Writer, model.ErrInternalServer)
|
||||
return
|
||||
}
|
||||
|
||||
utils.JSON(c.Writer, http.StatusOK, user)
|
||||
}
|
||||
Reference in New Issue
Block a user