Skip to content

Commit

Permalink
Implemented user login
Browse files Browse the repository at this point in the history
  • Loading branch information
ayushrakesh committed Oct 11, 2024
1 parent 6af93d9 commit 3fb071a
Show file tree
Hide file tree
Showing 8 changed files with 122 additions and 21 deletions.
2 changes: 1 addition & 1 deletion api/account_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ func TestGetAccountAPI(t *testing.T) {
store := mockdb.NewMockStore(ctrl)
tc.buildStubs(store)

server := NewServer(store)
server := testServer(t, store)
recorder := httptest.NewRecorder()

url := fmt.Sprintf("/accounts/%d", tc.accountID)
Expand Down
16 changes: 16 additions & 0 deletions api/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,26 @@ package api
import (
"os"
"testing"
"time"

db "github.com/ayushrakesh/go-bank/db/sqlc"
"github.com/ayushrakesh/go-bank/util"
"github.com/gin-gonic/gin"
"github.com/stretchr/testify/require"
)

func testServer(t *testing.T, store db.Store) *Server {

config := util.Config{
SymmetricKey: util.RandomString(32),
AccessTokenExpiry: time.Minute,
}

server, err := NewServer(config, store)
require.NoError(t, err)

return server
}
func TestMain(m *testing.M) {

gin.SetMode(gin.TestMode)
Expand Down
33 changes: 27 additions & 6 deletions api/server.go
Original file line number Diff line number Diff line change
@@ -1,38 +1,59 @@
package api

import (
"fmt"

"github.com/ayushrakesh/go-bank/token"

db "github.com/ayushrakesh/go-bank/db/sqlc"
"github.com/ayushrakesh/go-bank/util"
"github.com/gin-gonic/gin"
"github.com/gin-gonic/gin/binding"
"github.com/go-playground/validator/v10"
)

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

func NewServer(store db.Store) *Server {
func NewServer(config util.Config, store db.Store) (*Server, error) {

tokenMaker, err := token.NewPasetoMaker(config.SymmetricKey)
if err != nil {
return nil, fmt.Errorf("cannot create token maker, %w ", err)
}

server := &Server{
store: store,
store: store,
tokenMaker: tokenMaker,
config: config,
}
router := gin.Default()

if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
v.RegisterValidation("currency", validCurrency)
}

server.setupRouter()
return server, nil
}

func (server *Server) setupRouter() {

router := gin.Default()

router.POST("/accounts", server.createAccount)
router.GET("/accounts/:id", server.getAccount)
router.GET("/accounts", server.listAccounts)

router.POST("/transfers", server.createTransfer)

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

server.router = router
return server
}

func (server *Server) Start(address string) error {
Expand Down
71 changes: 63 additions & 8 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 @@ -10,7 +11,7 @@ import (
"github.com/lib/pq"
)

type createUserRes struct {
type userResponse struct {
Username string `json:"username"`
FullName string `json:"full_name"`
Email string `json:"email"`
Expand All @@ -25,6 +26,15 @@ type createUserReq struct {
Password string `json:"password" binding:"required,min=6"`
}

func createUserResponse(user db.User) userResponse {
return userResponse{
Username: user.Username,
FullName: user.FullName,
Email: user.Email,
PasswordChangedAt: user.PasswordChangedAt,
CreatedAt: user.CreatedAt,
}
}
func (server *Server) createUser(ctx *gin.Context) {

var req createUserReq
Expand Down Expand Up @@ -62,12 +72,57 @@ func (server *Server) createUser(ctx *gin.Context) {
return
}

res := createUserRes{
Username: user.Username,
FullName: user.FullName,
Email: user.Email,
PasswordChangedAt: user.PasswordChangedAt,
CreatedAt: user.CreatedAt,
}
res := createUserResponse(user)
ctx.JSON(http.StatusOK, res)
}

type loginUserReq struct {
Username string `json:"username" binding:"required,alphanum"`
Password string `json:"password" binding:"required,min=6"`
}

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

func (server *Server) loginUser(ctx *gin.Context) {
var req loginUserReq

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

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

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

accessToken, err := server.tokenMaker.CreateToken(
user.Username, server.config.AccessTokenExpiry,
)
if err != nil {
ctx.JSON(http.StatusInternalServerError, errorResponse(err))
return
}

rsp := loginUserRes{
AccessToken: accessToken,
User: createUserResponse(user),
}

ctx.JSON(http.StatusOK, rsp)
}
2 changes: 1 addition & 1 deletion api/user_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ func TestCreateUserAPI(t *testing.T) {
store := mockdb.NewMockStore(ctrl)
tc.buildStubs(store)

server := NewServer(store)
server := testServer(t, store)
recorder := httptest.NewRecorder()

// Marshal body data to JSON
Expand Down
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://postgres:postgres@localhost:5432/bank?sslmode=disable
SERVER_ADDRESS=0.0.0.0:8080
SERVER_ADDRESS=0.0.0.0:8080
SYMMETRIC_KEY=12345678901234567890123456789012
ACCESS_TOKEN_DURATION=15m
5 changes: 4 additions & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,10 @@ func main() {

store := db.NewStore(testDB)

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 {
Expand Down
10 changes: 7 additions & 3 deletions util/config.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
package util

import (
"time"

"github.com/spf13/viper"
)

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"`
SymmetricKey string `mapstructure:"SYMMETRIC_KEY"`
AccessTokenExpiry time.Duration `mapstructure:"ACCESS_TOKEN_DURATION"`
}

func LoadConfig(path string) (config Config, errr error) {
Expand Down

0 comments on commit 3fb071a

Please sign in to comment.