Skip to content

Commit

Permalink
Merge pull request #25 from moslehazizi/ft/auth
Browse files Browse the repository at this point in the history
Add login user api
  • Loading branch information
moslehazizi authored Jan 9, 2024
2 parents b4d6d91 + 3350b4e commit 6f6effd
Show file tree
Hide file tree
Showing 16 changed files with 130 additions and 87 deletions.
30 changes: 24 additions & 6 deletions api/server.go
Original file line number Diff line number Diff line change
@@ -1,42 +1,60 @@
package api

import (
"fmt"
"net/http"

"github.com/gin-gonic/gin"
db "github.com/moslehazizi/Elyasam_Restaurant/db/sqlc"
"github.com/moslehazizi/Elyasam_Restaurant/token"
"github.com/moslehazizi/Elyasam_Restaurant/util"
)

type Server struct {
store db.Store
store db.Store
tokenMaker token.Maker
router *gin.Engine
router *gin.Engine
config util.Config
}

var externalAPIResponse string
var externalAPIResponseJson map[string]interface{}

func NewServer(store db.Store) *Server {
server := &Server{store: store}
func NewServer(config util.Config, store db.Store) (*Server, error) {
tokenMaker, err := token.NewPasetoMaker(config.TokenSymmetricKey)
if err != nil {
return nil, fmt.Errorf("cannot create token maker: %w", err)
}

server := &Server{
config: config,
store: store,
tokenMaker: tokenMaker,
}

server.setupRouter()
return server, nil
}

func (server *Server) setupRouter() {
router := gin.Default()

router.Use(corsMiddleware())

router.GET("/shop", server.getLanding)
router.GET("/shop/detail/:id", server.getServiceById)
//router.GET("/user", server.getUser)

router.POST("post/category", server.postCategory)
router.POST("post/service/:id", server.postService)
router.POST("post/sliderImage", server.postSliderImage)
router.POST("post/discountOffer", server.PostDiscountOffer)

router.POST("post/user", server.createUser)
router.POST("post/user/login", server.loginUser)

router.PUT("put/service/:id", server.putService)

server.router = router
return server
}

// Start run the HTTP server on a specific address
Expand Down
119 changes: 72 additions & 47 deletions api/user.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package api

import (
"database/sql"
"net/http"
"time"

Expand All @@ -26,6 +27,16 @@ type createUserResponse struct {
CreatedAt time.Time `json:"created_at"`
}

func newUserResponse(user db.User) userResponse {
return userResponse{
Phonenumber: user.PhoneNumber,
FirstName: user.FirstName,
LastName: user.LastName,
Email: user.Email,
CreatedAt: user.CreatedAt,
}
}

func (server *Server) createUser(c *gin.Context) {
var req createUserRequest
if err := c.ShouldBindJSON(&req); err != nil {
Expand Down Expand Up @@ -62,55 +73,69 @@ func (server *Server) createUser(c *gin.Context) {
return
}

res := createUserResponse{
PhoneNumber: user.PhoneNumber,
FirstName: user.FirstName,
LastName: user.LastName,
Email: user.Email,
}
res := newUserResponse(user)

c.JSON(http.StatusOK, gin.H{
"response": res})
}

// type getUserRequest struct {
// PhoneNumber string `json:"phone_number" binding:"required"`
// Password string `json:"hashed_password" binding:"required"`
// }

// func (server *Server) getUser(c *gin.Context) {
// var req getUserRequest
// if err := c.ShouldBindJSON(&req); err != nil {
// c.JSON(http.StatusBadRequest, errorResponse(err))
// return
// }

// hashedPassword, err := util.HashPassword(req.Password)

// if err != nil {
// c.JSON(http.StatusNotFound, errorResponse(err))
// return
// }

// arg := db.GetUserParams{
// PhoneNumber: req.PhoneNumber,
// HashedPassword: hashedPassword,
// }

// user, err := server.store.GetUser(c, arg)

// if hashedPassword != user.HashedPassword {
// c.JSON(http.StatusNotFound, errorResponse(err))
// return
// }

// if err != nil {
// if err == sql.ErrNoRows {
// c.JSON(http.StatusNotFound, errorResponse(err))
// return
// }
// c.JSON(http.StatusInternalServerError, errorResponse(err))
// return
// }
// c.JSON(http.StatusOK, user)
// }
type loginUserRequest struct {
Phonenumber string `json:"phone_number" binding:"required"`
Password string `json:"password" binding:"required,min=6"`
}

type userResponse struct {
ID int64 `json:"id"`
Phonenumber string `json:"phone_number"`
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
Email string `json:"email"`
CreatedAt time.Time `json:"created_at"`
}

type loginUserResponse struct {
AccessToken string `json:"access_token"`
User userResponse `json:"user"`
}



func (server *Server) loginUser(c *gin.Context) {
var req loginUserRequest

if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, errorResponse(err))
return
}

user, err := server.store.GetUser(c, req.Phonenumber)
if err != nil {
if err == sql.ErrNoRows {
c.JSON(http.StatusNotFound, errorResponse(err))
return
}
c.JSON(http.StatusInternalServerError, errorResponse(err))
return
}

err = util.CheckPassword(req.Password, user.HashedPassword)
if err != nil {
c.JSON(http.StatusUnauthorized, errorResponse(err))
return
}

accessToken, err := server.tokenMaker.CreateToken(
user.PhoneNumber,
server.config.AccessTokenDuration,
)
if err != nil {
c.JSON(http.StatusInternalServerError, errorResponse(err))
return
}

rsp := loginUserResponse{
AccessToken: accessToken,
User: newUserResponse(user),
}
c.JSON(http.StatusOK, rsp)
}
4 changes: 3 additions & 1 deletion app.env
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
DB_DRIVER=postgres
DB_SOURCE=postgres://mosleh:1234@localhost:5432/Elyasam_Restaurant?sslmode=disable
SERVER_ADDRESS=0.0.0.0:8080
SERVER_ADDRESS=0.0.0.0:8080
TOKEN_SYMMETRIC_KEY=12345678901234567890123456789012
ACCESS_TOKEN_DURATION=15m
3 changes: 1 addition & 2 deletions db/query/user.sql
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,5 @@ INSERT INTO users(

-- name: GetUser :one
SELECT * FROM users
WHERE phone_number = $1 AND
hashed_password = $2
WHERE phone_number = $1
LIMIT 1;
2 changes: 1 addition & 1 deletion db/sqlc/category.sql.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion db/sqlc/comment.sql.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion db/sqlc/db.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion db/sqlc/discount_offer.sql.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion db/sqlc/models.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions db/sqlc/querier.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion db/sqlc/service.sql.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion db/sqlc/slider_image.sql.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 4 additions & 10 deletions db/sqlc/user.sql.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 1 addition & 6 deletions db/sqlc/user_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,7 @@ func TestCreateUser(t *testing.T) {
func TestGetUser(t *testing.T) {
user_1 := createRandomUser(t)

arg := GetUserParams{
PhoneNumber: user_1.PhoneNumber,
HashedPassword: user_1.HashedPassword,
}

user_2, err := testQueries.GetUser(context.Background(), arg)
user_2, err := testQueries.GetUser(context.Background(), user_1.PhoneNumber)

require.NoError(t, err)
require.NotEmpty(t, user_2)
Expand Down
6 changes: 5 additions & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,11 @@ func main() {
log.Fatal("Connot connect to the database:", err)
}
store := db.NewStore(conn)
server := api.NewServer(store)
server, err := api.NewServer(config, store)
if err != nil {
log.Fatal("cannot create server:", err)
}

err = server.Start(config.ServerAddress)
if err != nil {
log.Fatal("connot start server:", err)
Expand Down
16 changes: 11 additions & 5 deletions util/config.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
package util

import "github.com/spf13/viper"
import (
"time"

"github.com/spf13/viper"
)

// Config stores all configuration of the application.
// The values are read from viper from a config file or enviroment variables.
type Config struct {
DBDriver string `mapstructure:"DB_DRIVER"`
DBSource string `mapstructure:"DB_SOURCE"`
ServerAddress string `mapstructure:"SERVER_ADDRESS"`
DBDriver string `mapstructure:"DB_DRIVER"`
DBSource string `mapstructure:"DB_SOURCE"`
ServerAddress string `mapstructure:"SERVER_ADDRESS"`
TokenSymmetricKey string `mapstructure:"TOKEN_SYMMETRIC_KEY"`
AccessTokenDuration time.Duration `mapstructure:"ACCESS_TOKEN_DURATION"`
}

// LoadConfig reads configurations from file or enviroment variables.
Expand All @@ -25,4 +31,4 @@ func LoadConfig(path string) (config Config, err error) {

err = viper.Unmarshal(&config)
return
}
}

0 comments on commit 6f6effd

Please sign in to comment.