From 831c121983ff722f47796c5d4341418431967002 Mon Sep 17 00:00:00 2001 From: nochill Date: Wed, 13 Sep 2023 21:42:31 +0700 Subject: [PATCH] add locations endpoint and fix some tests --- api/location.go | 120 +++++++++++++++++++++++++++++++++ api/server.go | 17 +++-- api/test/location_test.go | 31 +++++++++ api/test/user_test.go | 10 +-- api/user.go | 2 +- db/sqlc/test/locations_test.go | 41 +++++++++++ db/sqlc/test/users_test.go | 2 +- 7 files changed, 210 insertions(+), 13 deletions(-) create mode 100644 api/location.go create mode 100644 api/test/location_test.go create mode 100644 db/sqlc/test/locations_test.go diff --git a/api/location.go b/api/location.go new file mode 100644 index 0000000..3923068 --- /dev/null +++ b/api/location.go @@ -0,0 +1,120 @@ +package api + +import ( + "database/sql" + "fmt" + "net/http" + "os" + "path/filepath" + "time" + + db "git.nochill.in/nochill/hiling_go/db/sqlc" + "git.nochill.in/nochill/hiling_go/util" + "github.com/gin-gonic/gin" + "github.com/lib/pq" +) + +type createLocationReq struct { + Address string `form:"address" binding:"required"` + Name string `form:"name" binding:"required"` + SubmittedBy int32 `form:"submitted_by" binding:"required,number"` + RegencyID int16 `form:"regency_id" binding:"required,number"` + GoogleMapsLink string `form:"google_maps_link"` +} + +func (server *Server) createLocation(ctx *gin.Context) { + var req createLocationReq + var imgPath string + + var thumbnail, _ = ctx.FormFile("thumbnail") + + if err := ctx.Bind(&req); err != nil { + ctx.JSON(http.StatusBadRequest, ValidationErrorResponse(err)) + return + } + + if thumbnail != nil { + img := thumbnail + fileExt := filepath.Ext(img.Filename) + now := time.Now() + dir := fmt.Sprintf("public/upload/images/locations/%s/thumbnail", req.Name) + osFilename := fmt.Sprintf("%s%s%s", util.RandomString(5), fmt.Sprintf("%v", now.Unix()), fileExt) + imgPath = fmt.Sprintf("%s%s", dir, osFilename) + + if _, err := os.Stat(dir); os.IsNotExist(err) { + os.Mkdir(dir, 0775) + } + + if err := ctx.SaveUploadedFile(img, imgPath); err != nil { + ctx.JSON(http.StatusInternalServerError, ErrorResponse(err, "Error while try to save thumbnail image")) + return + } + } + + arg := db.CreateLocationParams{ + Address: req.Address, + Name: req.Name, + SubmittedBy: req.SubmittedBy, + RegencyID: req.RegencyID, + GoogleMapsLink: sql.NullString{Valid: len(req.GoogleMapsLink) > 0, String: req.GoogleMapsLink}, + } + + err := server.Store.CreateLocation(ctx, arg) + if err != nil { + if pqErr, ok := err.(*pq.Error); ok { + ctx.JSON(http.StatusConflict, ErrorResponse(err, fmt.Sprintf("Something went wrong, code: %s", pqErr.Code.Name()))) + return + } + ctx.JSON(http.StatusInternalServerError, ErrorResponse(err, "Something went wrong")) + return + } + + ctx.Writer.WriteHeader(http.StatusOK) + +} + +type getListLocationsReq struct { + Page int32 `form:"page" binding:"required,min=1"` + PageSize int32 `form:"page_size" binding:"required,min=5"` +} + +func (server *Server) getListLocations(ctx *gin.Context) { + var req getListLocationsReq + if err := ctx.ShouldBindQuery(&req); err != nil { + ctx.JSON(http.StatusBadRequest, ValidationErrorResponse(err)) + return + } + + arg := db.GetListLocationsParams{ + Limit: req.PageSize, + Offset: (req.Page - 1) * req.PageSize, + } + + locations, err := server.Store.GetListLocations(ctx, arg) + if err != nil { + ctx.JSON(http.StatusInternalServerError, ErrorResponse(err, "Something went wrong")) + return + } + + ctx.JSON(http.StatusOK, locations) +} + +type getLocationReq struct { + ID int32 `uri:"location_id" binding:"required"` +} + +func (server *Server) getLocation(ctx *gin.Context) { + var req getLocationReq + if err := ctx.ShouldBindUri(&req); err != nil { + ctx.JSON(http.StatusBadRequest, ValidationErrorResponse(err)) + return + } + + location, err := server.Store.GetLocation(ctx, req.ID) + if err != nil { + ctx.JSON(http.StatusInternalServerError, ErrorResponse(err, "Something went wrong")) + return + } + + ctx.JSON(http.StatusOK, location) +} diff --git a/api/server.go b/api/server.go index 0c2d2f0..1100fb4 100644 --- a/api/server.go +++ b/api/server.go @@ -10,9 +10,9 @@ import ( ) type Server struct { - config util.Config - store db.Store - tokenMaker token.Maker + Config util.Config + Store db.Store + TokenMaker token.Maker Router *gin.Engine } @@ -23,9 +23,9 @@ func NewServer(config util.Config, store db.Store) (*Server, error) { } server := &Server{ - config: config, - store: store, - tokenMaker: tokenMaker, + Config: config, + Store: store, + TokenMaker: tokenMaker, } server.getRoutes() @@ -37,6 +37,11 @@ func (server *Server) getRoutes() { router.POST("/user/signup", server.createUser) + // LOCATION + router.POST("/locations", server.createLocation) + router.GET("/locations", server.getListLocations) + router.GET("/location/:location_id", server.getLocation) + server.Router = router } diff --git a/api/test/location_test.go b/api/test/location_test.go new file mode 100644 index 0000000..74015aa --- /dev/null +++ b/api/test/location_test.go @@ -0,0 +1,31 @@ +package api_test + +import ( + "database/sql" + "testing" + + db "git.nochill.in/nochill/hiling_go/db/sqlc" + "git.nochill.in/nochill/hiling_go/util" + "go.uber.org/mock/gomock" +) + +func TestGetListLocationsAPI(t *testing.T) { + +} + +func TestCreateLocationAPI(t *testing.T) { + _ = db.CreateLocationParams{ + Address: util.RandomString(10), + Name: util.RandomString(10), + SubmittedBy: int32(util.RandomInt(0, 10)), + RegencyID: 1305, + GoogleMapsLink: sql.NullString{Valid: true, String: util.RandomString(10)}, + } + + t.Run("OK", func(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + // store := mockdb.MockStore + }) +} diff --git a/api/test/user_test.go b/api/test/user_test.go index 81689c2..e27d519 100644 --- a/api/test/user_test.go +++ b/api/test/user_test.go @@ -22,10 +22,10 @@ func TestSignupAPI(t *testing.T) { defer ctrl.Finish() store := mockdb.NewMockStore(ctrl) - store.EXPECT(). - CreateUser(gomock.Any(), gomock.Any()). - Times(1). - Return(user, nil) + // store.EXPECT(). + // CreateUser(gomock.Any(), gomock.Any()). + // Times(1). + // Return(user, nil) server := newTestServer(t, store) recorder := httptest.NewRecorder() @@ -56,5 +56,5 @@ func createUser(t *testing.T) (user db.User, password string) { Password: hashedPassword, } - return + return user, passw } diff --git a/api/user.go b/api/user.go index f531489..ffa72c8 100644 --- a/api/user.go +++ b/api/user.go @@ -51,7 +51,7 @@ func (server *Server) createUser(ctx *gin.Context) { Password: hashedPassword, } - user, err := server.store.CreateUser(ctx, arg) + user, err := server.Store.CreateUser(ctx, arg) if err != nil { if pqErr, ok := err.(*pq.Error); ok { switch pqErr.Code.Name() { diff --git a/db/sqlc/test/locations_test.go b/db/sqlc/test/locations_test.go new file mode 100644 index 0000000..a133d17 --- /dev/null +++ b/db/sqlc/test/locations_test.go @@ -0,0 +1,41 @@ +package db_test + +import ( + "context" + "database/sql" + "testing" + + db "git.nochill.in/nochill/hiling_go/db/sqlc" + "git.nochill.in/nochill/hiling_go/util" + "github.com/stretchr/testify/require" +) + +func TestGetLocationsList(t *testing.T) { + arg := db.GetListLocationsParams{ + Limit: 10, + Offset: 0, + } + + locations, err := testQueries.GetListLocations(context.Background(), arg) + require.NoError(t, err) + require.NotEmpty(t, locations) +} + +func TestGetLocation(t *testing.T) { + location, err := testQueries.GetLocation(context.Background(), 1) + require.NoError(t, err) + require.NotEmpty(t, location) +} + +func TestCreateLocation(t *testing.T) { + arg := db.CreateLocationParams{ + Address: util.RandomString(12), + Name: util.RandomString(10), + SubmittedBy: 1, + RegencyID: 1305, + GoogleMapsLink: sql.NullString{Valid: true, String: util.RandomString(10)}, + } + + err := testQueries.CreateLocation(context.Background(), arg) + require.NoError(t, err) +} diff --git a/db/sqlc/test/users_test.go b/db/sqlc/test/users_test.go index c5fc044..4659173 100644 --- a/db/sqlc/test/users_test.go +++ b/db/sqlc/test/users_test.go @@ -11,7 +11,7 @@ import ( func TestCreateUser(t *testing.T) { arg := db.CreateUserParams{ - Username: util.RandomString(10), + Username: util.RandomString(7), Password: util.RandomString(10), }