diff --git a/api/location.go b/api/location.go index 7a3837b..58f4025 100755 --- a/api/location.go +++ b/api/location.go @@ -1,6 +1,7 @@ package api import ( + "encoding/json" "fmt" "net/http" "os" @@ -23,6 +24,7 @@ type createLocationReq struct { RegencyID int16 `form:"regency_id" binding:"required,number"` LocationType string `form:"location_type" binding:"required"` Amenities string `form:"amenities"` + RestaurantMenu string `form:"restaurant_menu"` GoogleMapsLink string `form:"google_maps_link"` } @@ -72,6 +74,22 @@ func (server *Server) createLocation(ctx *gin.Context) { } } + var amenities pgtype.Text + if req.Amenities != "" { + var parsed []map[string][]string + if err := json.Unmarshal([]byte(req.Amenities), &parsed); err == nil { + amenities = pgtype.Text{Valid: true, String: req.Amenities} + } + } + + var restaurantMenu pgtype.Text + if req.RestaurantMenu != "" { + var parsed []map[string]any + if err := json.Unmarshal([]byte(req.RestaurantMenu), &parsed); err == nil { + restaurantMenu = pgtype.Text{Valid: true, String: req.RestaurantMenu} + } + } + arg := db.CreateLocationTxParams{ Address: req.Address, Name: req.Name, @@ -81,7 +99,8 @@ func (server *Server) createLocation(ctx *gin.Context) { IsDeleted: false, ApprovedBy: pgtype.Int4{Int32: 0, Valid: false}, GoogleMapsLink: pgtype.Text{Valid: len(req.GoogleMapsLink) > 0, String: req.GoogleMapsLink}, - Amenities: req.Amenities, + Amenities: amenities, + RestaurantMenu: restaurantMenu, Thumbnail: tempImg, } @@ -92,9 +111,12 @@ func (server *Server) createLocation(ctx *gin.Context) { return } + } else { + ctx.JSON(http.StatusBadRequest, ErrorResponse(fmt.Errorf("thumbnail is required"), "")) + return } - ctx.Writer.WriteHeader(http.StatusOK) + ctx.Writer.WriteHeader(http.StatusNoContent) } @@ -158,6 +180,14 @@ func (server *Server) getTopListLocations(ctx *gin.Context) { return } + cacheKey := fmt.Sprintf("cache:top_locations:%d:%d:%d:%d", + req.Page, req.PageSize, req.OrderBy, req.RegionType) + + if cached, err := server.Redis.Get(ctx, cacheKey).Result(); err == nil { + ctx.Data(http.StatusOK, "application/json", []byte(cached)) + return + } + switch req.OrderBy { case 1: orderby = "iq2.avg_bayes" @@ -180,6 +210,9 @@ func (server *Server) getTopListLocations(ctx *gin.Context) { return } + if data, err := json.Marshal(locations); err == nil { + server.Redis.Set(ctx, cacheKey, data, 5*time.Minute) + } ctx.JSON(http.StatusOK, locations) // str, err := ctx.Cookie("kek123429") diff --git a/api/middleware.go b/api/middleware.go index 8f7a3e8..510537f 100755 --- a/api/middleware.go +++ b/api/middleware.go @@ -5,6 +5,7 @@ import ( "git.nochill.in/nochill/hiling_go/util/token" "github.com/gin-gonic/gin" + "github.com/redis/go-redis/v9" ) // func CORSMiddleware() gin.HandlerFunc { @@ -27,7 +28,7 @@ const ( authorizationPayloadKey = "authorization_payload" ) -func authMiddleware(tokenMaker token.Maker) gin.HandlerFunc { +func authMiddleware(tokenMaker token.Maker, redisClient *redis.Client) gin.HandlerFunc { return func(ctx *gin.Context) { str, err := ctx.Cookie("paseto") @@ -37,14 +38,19 @@ func authMiddleware(tokenMaker token.Maker) gin.HandlerFunc { } payload, err := tokenMaker.VerifyToken(str) - if err != nil { ctx.AbortWithStatusJSON(http.StatusInternalServerError, ErrorResponse(err, "Something went wrong while try to verify token")) return } - ctx.Set(authorizationPayloadKey, payload) + _, err = redisClient.Get(ctx, "blacklist:"+str).Result() + if err == nil { + ctx.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"message": "Token has been revoked"}) + return + } + // redis.Nil = key not found (not blacklisted); other errors = Redis down → fail-open + ctx.Set(authorizationPayloadKey, payload) ctx.Next() } } diff --git a/api/region.go b/api/region.go index 194de1e..416d609 100755 --- a/api/region.go +++ b/api/region.go @@ -1,7 +1,9 @@ package api import ( + "encoding/json" "net/http" + "time" "github.com/gin-gonic/gin" ) @@ -12,12 +14,21 @@ import ( // @Success 200 {array} map[string]any // @Router /regions [get] func (server *Server) getListRegions(ctx *gin.Context) { + const key = "cache:regions" + + if cached, err := server.Redis.Get(ctx, key).Result(); err == nil { + ctx.Data(http.StatusOK, "application/json", []byte(cached)) + return + } + regions, err := server.Store.GetListRegions(ctx) if err != nil { ctx.JSON(http.StatusInternalServerError, ErrorResponse(err, "Something went wrong while try to get regions")) return } - + if data, err := json.Marshal(regions); err == nil { + server.Redis.Set(ctx, key, data, 24*time.Hour) + } ctx.JSON(http.StatusOK, regions) } @@ -27,12 +38,21 @@ func (server *Server) getListRegions(ctx *gin.Context) { // @Success 200 {array} map[string]any // @Router /region/provinces [get] func (server *Server) getListProvinces(ctx *gin.Context) { - provinces, err := server.Store.GetListProvinces(ctx) - if err != nil { - ctx.JSON(http.StatusInternalServerError, ErrorResponse(err, "Something went wrong while try to get regions")) + const key = "cache:provinces" + + if cached, err := server.Redis.Get(ctx, key).Result(); err == nil { + ctx.Data(http.StatusOK, "application/json", []byte(cached)) return } + provinces, err := server.Store.GetListProvinces(ctx) + if err != nil { + ctx.JSON(http.StatusInternalServerError, ErrorResponse(err, "Something went wrong while try to get provinces")) + return + } + if data, err := json.Marshal(provinces); err == nil { + server.Redis.Set(ctx, key, data, 24*time.Hour) + } ctx.JSON(http.StatusOK, provinces) } @@ -42,11 +62,20 @@ func (server *Server) getListProvinces(ctx *gin.Context) { // @Success 200 {array} map[string]any // @Router /region/regencies [get] func (server *Server) getListRegencies(ctx *gin.Context) { - regencies, err := server.Store.GetListRegencies(ctx) - if err != nil { - ctx.JSON(http.StatusInternalServerError, ErrorResponse(err, "Something went wrong while try to get regions")) + const key = "cache:regencies" + + if cached, err := server.Redis.Get(ctx, key).Result(); err == nil { + ctx.Data(http.StatusOK, "application/json", []byte(cached)) return } + regencies, err := server.Store.GetListRegencies(ctx) + if err != nil { + ctx.JSON(http.StatusInternalServerError, ErrorResponse(err, "Something went wrong while try to get regencies")) + return + } + if data, err := json.Marshal(regencies); err == nil { + server.Redis.Set(ctx, key, data, 24*time.Hour) + } ctx.JSON(http.StatusOK, regencies) } diff --git a/api/server.go b/api/server.go index b32da25..5bf3875 100755 --- a/api/server.go +++ b/api/server.go @@ -1,6 +1,7 @@ package api import ( + "context" "fmt" db "git.nochill.in/nochill/hiling_go/db/repository" @@ -10,6 +11,7 @@ import ( "github.com/gin-contrib/cors" "github.com/gin-gonic/gin" "github.com/meilisearch/meilisearch-go" + "github.com/redis/go-redis/v9" swaggerFiles "github.com/swaggo/files" ginSwagger "github.com/swaggo/gin-swagger" ) @@ -21,6 +23,7 @@ type Server struct { Router *gin.Engine MeilisearchClient *meilisearch.Client R2 *cloudfare.R2Client + Redis *redis.Client } func NewServer(config util.Config, store db.Store) (*Server, error) { @@ -45,12 +48,18 @@ func NewServer(config util.Config, store db.Store) (*Server, error) { return nil, fmt.Errorf("cannot create R2 client: %w", err) } + redisClient := redis.NewClient(&redis.Options{Addr: config.RedisAddress}) + if _, err := redisClient.Ping(context.Background()).Result(); err != nil { + return nil, fmt.Errorf("cannot connect to redis: %w", err) + } + server := &Server{ Config: config, Store: store, TokenMaker: tokenMaker, MeilisearchClient: meiliClient, R2: r2Client, + Redis: redisClient, } server.getRoutes() @@ -69,13 +78,11 @@ func (server *Server) getRoutes() { router.POST("/user/signup", server.createUser) router.POST("/user/login", server.login) - router.POST("/user/logout", server.logout) router.GET("/regions", server.getListRegions) router.GET("/region/provinces", server.getListProvinces) router.GET("/region/regencies", server.getListRegencies) // LOCATION - router.POST("/locations", server.createLocation) router.GET("/locations/recent", server.getListRecentLocationsWithRatings) router.GET("/locations/top-ratings", server.getTopListLocations) router.GET("/locations", server.getListLocations) @@ -95,7 +102,9 @@ func (server *Server) getRoutes() { router.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler)) // REQUIRE AUTH TOKEN - authRoutes := router.Use(authMiddleware(server.TokenMaker)) + authRoutes := router.Use(authMiddleware(server.TokenMaker, server.Redis)) + authRoutes.POST("/location", server.createLocation) + authRoutes.POST("/user/logout", server.logout) authRoutes.POST("/review/location", server.createReview) authRoutes.POST("/review/location/images", server.uploadReviewImages) authRoutes.PATCH("/user", server.updateUser) diff --git a/api/user.go b/api/user.go index f2957b7..a10e023 100755 --- a/api/user.go +++ b/api/user.go @@ -360,17 +360,17 @@ func (server *Server) login(ctx *gin.Context) { // @Summary Logout // @Tags auth +// @Security CookieAuth // @Success 204 // @Router /user/logout [post] func (server *Server) logout(ctx *gin.Context) { - ctx.SetCookie( - "paseto", - "", - -1, - "/", - "", - false, - true, - ) + payload := ctx.MustGet(authorizationPayloadKey).(*token.Payload) + rawToken, _ := ctx.Cookie("paseto") + + if ttl := time.Until(payload.ExpiredAt); ttl > 0 { + server.Redis.Set(ctx, "blacklist:"+rawToken, "1", ttl) + } + + ctx.SetCookie("paseto", "", -1, "/", "", false, true) ctx.Writer.WriteHeader(http.StatusNoContent) } diff --git a/db/csv_seeder/reviews.csv b/db/csv_seeder/reviews.csv index 27eb164..bdd6c33 100755 --- a/db/csv_seeder/reviews.csv +++ b/db/csv_seeder/reviews.csv @@ -1,16 +1,16 @@ -id,submitted_by,is_from_critic,comments,score,is_hided,location_id -1#1#false#I recently had the opportunity to visit a breathtaking beach that left me in awe. Nestled between rolling waves and golden sands, this hidden gem is a true paradise for beach lovers and nature enthusiasts alike.From the moment I set foot on the powdery shoreline, I was captivated by the crystal-clear azure waters that stretched as far as the eye could see. The gentle caress of the ocean breeze and the soothing sound of waves crashing created an instant sense of relaxation.One of the most remarkable features of this beach is its untouched beauty. The absence of crowds and commercialization allowed for an authentic and serene experience. I was able to walk along the shoreline, feeling the soft sand beneath my feet, and listen to the symphony of seagulls above. It was a refreshing escape from the hustle and bustle of daily life.#8#false#8 -2#2#true#I recently had the opportunity to visit a breathtaking beach that left me in awe. Nestled between rolling waves and golden sands, this hidden gem is a true paradise for beach lovers and nature enthusiasts alike.From the moment I set foot on the powdery shoreline, I was captivated by the crystal-clear azure waters that stretched as far as the eye could see. The gentle caress of the ocean breeze and the soothing sound of waves crashing created an instant sense of relaxation.One of the most remarkable features of this beach is its untouched beauty. The absence of crowds and commercialization allowed for an authentic and serene experience. I was able to walk along the shoreline, feeling the soft sand beneath my feet, and listen to the symphony of seagulls above. It was a refreshing escape from the hustle and bustle of daily life.#8#false#1 -3#2#true#I recently had the opportunity to visit a breathtaking beach that left me in awe. Nestled between rolling waves and golden sands, this hidden gem is a true paradise for beach lovers and nature enthusiasts alike.From the moment I set foot on the powdery shoreline, I was captivated by the crystal-clear azure waters that stretched as far as the eye could see. The gentle caress of the ocean breeze and the soothing sound of waves crashing created an instant sense of relaxation.One of the most remarkable features of this beach is its untouched beauty. The absence of crowds and commercialization allowed for an authentic and serene experience. I was able to walk along the shoreline, feeling the soft sand beneath my feet, and listen to the symphony of seagulls above. It was a refreshing escape from the hustle and bustle of daily life.#8#false#1 -4#1#false#I recently had the opportunity to visit a breathtaking beach that left me in awe. Nestled between rolling waves and golden sands, this hidden gem is a true paradise for beach lovers and nature enthusiasts alike.From the moment I set foot on the powdery shoreline, I was captivated by the crystal-clear azure waters that stretched as far as the eye could see. The gentle caress of the ocean breeze and the soothing sound of waves crashing created an instant sense of relaxation.One of the most remarkable features of this beach is its untouched beauty. The absence of crowds and commercialization allowed for an authentic and serene experience. I was able to walk along the shoreline, feeling the soft sand beneath my feet, and listen to the symphony of seagulls above. It was a refreshing escape from the hustle and bustle of daily life.#8#false#2 -5#3#false#I recently had the opportunity to visit a breathtaking beach that left me in awe. Nestled between rolling waves and golden sands, this hidden gem is a true paradise for beach lovers and nature enthusiasts alike.From the moment I set foot on the powdery shoreline, I was captivated by the crystal-clear azure waters that stretched as far as the eye could see. The gentle caress of the ocean breeze and the soothing sound of waves crashing created an instant sense of relaxation.One of the most remarkable features of this beach is its untouched beauty. The absence of crowds and commercialization allowed for an authentic and serene experience. I was able to walk along the shoreline, feeling the soft sand beneath my feet, and listen to the symphony of seagulls above. It was a refreshing escape from the hustle and bustle of daily life.#8#false#3 -6#2#true#I recently had the opportunity to visit a breathtaking beach that left me in awe. Nestled between rolling waves and golden sands, this hidden gem is a true paradise for beach lovers and nature enthusiasts alike.From the moment I set foot on the powdery shoreline, I was captivated by the crystal-clear azure waters that stretched as far as the eye could see. The gentle caress of the ocean breeze and the soothing sound of waves crashing created an instant sense of relaxation.One of the most remarkable features of this beach is its untouched beauty. The absence of crowds and commercialization allowed for an authentic and serene experience. I was able to walk along the shoreline, feeling the soft sand beneath my feet, and listen to the symphony of seagulls above. It was a refreshing escape from the hustle and bustle of daily life.#8#false#9 -7#3#false#I recently had the opportunity to visit a breathtaking beach that left me in awe. Nestled between rolling waves and golden sands, this hidden gem is a true paradise for beach lovers and nature enthusiasts alike.From the moment I set foot on the powdery shoreline, I was captivated by the crystal-clear azure waters that stretched as far as the eye could see. The gentle caress of the ocean breeze and the soothing sound of waves crashing created an instant sense of relaxation.One of the most remarkable features of this beach is its untouched beauty. The absence of crowds and commercialization allowed for an authentic and serene experience. I was able to walk along the shoreline, feeling the soft sand beneath my feet, and listen to the symphony of seagulls above. It was a refreshing escape from the hustle and bustle of daily life.#8#false#8 -8#2#true#I recently had the opportunity to visit a breathtaking beach that left me in awe. Nestled between rolling waves and golden sands, this hidden gem is a true paradise for beach lovers and nature enthusiasts alike.From the moment I set foot on the powdery shoreline, I was captivated by the crystal-clear azure waters that stretched as far as the eye could see. The gentle caress of the ocean breeze and the soothing sound of waves crashing created an instant sense of relaxation.One of the most remarkable features of this beach is its untouched beauty. The absence of crowds and commercialization allowed for an authentic and serene experience. I was able to walk along the shoreline, feeling the soft sand beneath my feet, and listen to the symphony of seagulls above. It was a refreshing escape from the hustle and bustle of daily life.#8#false#9 -9#2#true#I recently had the opportunity to visit a breathtaking beach that left me in awe. Nestled between rolling waves and golden sands, this hidden gem is a true paradise for beach lovers and nature enthusiasts alike.From the moment I set foot on the powdery shoreline, I was captivated by the crystal-clear azure waters that stretched as far as the eye could see. The gentle caress of the ocean breeze and the soothing sound of waves crashing created an instant sense of relaxation.One of the most remarkable features of this beach is its untouched beauty. The absence of crowds and commercialization allowed for an authentic and serene experience. I was able to walk along the shoreline, feeling the soft sand beneath my feet, and listen to the symphony of seagulls above. It was a refreshing escape from the hustle and bustle of daily life.#8#false#4 -10#3#false#I recently had the opportunity to visit a breathtaking beach that left me in awe. Nestled between rolling waves and golden sands, this hidden gem is a true paradise for beach lovers and nature enthusiasts alike.From the moment I set foot on the powdery shoreline, I was captivated by the crystal-clear azure waters that stretched as far as the eye could see. The gentle caress of the ocean breeze and the soothing sound of waves crashing created an instant sense of relaxation.One of the most remarkable features of this beach is its untouched beauty. The absence of crowds and commercialization allowed for an authentic and serene experience. I was able to walk along the shoreline, feeling the soft sand beneath my feet, and listen to the symphony of seagulls above. It was a refreshing escape from the hustle and bustle of daily life.#8#false#4 -11#2#true#I recently had the opportunity to visit a breathtaking beach that left me in awe. Nestled between rolling waves and golden sands, this hidden gem is a true paradise for beach lovers and nature enthusiasts alike.From the moment I set foot on the powdery shoreline, I was captivated by the crystal-clear azure waters that stretched as far as the eye could see. The gentle caress of the ocean breeze and the soothing sound of waves crashing created an instant sense of relaxation.One of the most remarkable features of this beach is its untouched beauty. The absence of crowds and commercialization allowed for an authentic and serene experience. I was able to walk along the shoreline, feeling the soft sand beneath my feet, and listen to the symphony of seagulls above. It was a refreshing escape from the hustle and bustle of daily life.#8#false#2 -12#2#true#I recently had the opportunity to visit a breathtaking beach that left me in awe. Nestled between rolling waves and golden sands, this hidden gem is a true paradise for beach lovers and nature enthusiasts alike.From the moment I set foot on the powdery shoreline, I was captivated by the crystal-clear azure waters that stretched as far as the eye could see. The gentle caress of the ocean breeze and the soothing sound of waves crashing created an instant sense of relaxation.One of the most remarkable features of this beach is its untouched beauty. The absence of crowds and commercialization allowed for an authentic and serene experience. I was able to walk along the shoreline, feeling the soft sand beneath my feet, and listen to the symphony of seagulls above. It was a refreshing escape from the hustle and bustle of daily life.#8#false#1 -13#1#false#I recently had the opportunity to visit a breathtaking beach that left me in awe. Nestled between rolling waves and golden sands, this hidden gem is a true paradise for beach lovers and nature enthusiasts alike.From the moment I set foot on the powdery shoreline, I was captivated by the crystal-clear azure waters that stretched as far as the eye could see. The gentle caress of the ocean breeze and the soothing sound of waves crashing created an instant sense of relaxation.One of the most remarkable features of this beach is its untouched beauty. The absence of crowds and commercialization allowed for an authentic and serene experience. I was able to walk along the shoreline, feeling the soft sand beneath my feet, and listen to the symphony of seagulls above. It was a refreshing escape from the hustle and bustle of daily life.#8#false#8 -14#1#false#I recently had the opportunity to visit a breathtaking beach that left me in awe. Nestled between rolling waves and golden sands, this hidden gem is a true paradise for beach lovers and nature enthusiasts alike.From the moment I set foot on the powdery shoreline, I was captivated by the crystal-clear azure waters that stretched as far as the eye could see. The gentle caress of the ocean breeze and the soothing sound of waves crashing created an instant sense of relaxation.One of the most remarkable features of this beach is its untouched beauty. The absence of crowds and commercialization allowed for an authentic and serene experience. I was able to walk along the shoreline, feeling the soft sand beneath my feet, and listen to the symphony of seagulls above. It was a refreshing escape from the hustle and bustle of daily life.#8#false#8 -15#1#false#I recently had the opportunity to visit a breathtaking beach that left me in awe. Nestled between rolling waves and golden sands, this hidden gem is a true paradise for beach lovers and nature enthusiasts alike.From the moment I set foot on the powdery shoreline, I was captivated by the crystal-clear azure waters that stretched as far as the eye could see. The gentle caress of the ocean breeze and the soothing sound of waves crashing created an instant sense of relaxation.One of the most remarkable features of this beach is its untouched beauty. The absence of crowds and commercialization allowed for an authentic and serene experience. I was able to walk along the shoreline, feeling the soft sand beneath my feet, and listen to the symphony of seagulls above. It was a refreshing escape from the hustle and bustle of daily life.#8#false#8 \ No newline at end of file +id,title,submitted_by,is_from_critic,comments,score,is_hided,location_id +1#review title#1#false#I recently had the opportunity to visit a breathtaking beach that left me in awe. Nestled between rolling waves and golden sands, this hidden gem is a true paradise for beach lovers and nature enthusiasts alike.From the moment I set foot on the powdery shoreline, I was captivated by the crystal-clear azure waters that stretched as far as the eye could see. The gentle caress of the ocean breeze and the soothing sound of waves crashing created an instant sense of relaxation.One of the most remarkable features of this beach is its untouched beauty. The absence of crowds and commercialization allowed for an authentic and serene experience. I was able to walk along the shoreline, feeling the soft sand beneath my feet, and listen to the symphony of seagulls above. It was a refreshing escape from the hustle and bustle of daily life.#8#false#8 +2#review title#2#true#I recently had the opportunity to visit a breathtaking beach that left me in awe. Nestled between rolling waves and golden sands, this hidden gem is a true paradise for beach lovers and nature enthusiasts alike.From the moment I set foot on the powdery shoreline, I was captivated by the crystal-clear azure waters that stretched as far as the eye could see. The gentle caress of the ocean breeze and the soothing sound of waves crashing created an instant sense of relaxation.One of the most remarkable features of this beach is its untouched beauty. The absence of crowds and commercialization allowed for an authentic and serene experience. I was able to walk along the shoreline, feeling the soft sand beneath my feet, and listen to the symphony of seagulls above. It was a refreshing escape from the hustle and bustle of daily life.#8#false#1 +3#review title#2#true#I recently had the opportunity to visit a breathtaking beach that left me in awe. Nestled between rolling waves and golden sands, this hidden gem is a true paradise for beach lovers and nature enthusiasts alike.From the moment I set foot on the powdery shoreline, I was captivated by the crystal-clear azure waters that stretched as far as the eye could see. The gentle caress of the ocean breeze and the soothing sound of waves crashing created an instant sense of relaxation.One of the most remarkable features of this beach is its untouched beauty. The absence of crowds and commercialization allowed for an authentic and serene experience. I was able to walk along the shoreline, feeling the soft sand beneath my feet, and listen to the symphony of seagulls above. It was a refreshing escape from the hustle and bustle of daily life.#8#false#1 +4#review title#1#false#I recently had the opportunity to visit a breathtaking beach that left me in awe. Nestled between rolling waves and golden sands, this hidden gem is a true paradise for beach lovers and nature enthusiasts alike.From the moment I set foot on the powdery shoreline, I was captivated by the crystal-clear azure waters that stretched as far as the eye could see. The gentle caress of the ocean breeze and the soothing sound of waves crashing created an instant sense of relaxation.One of the most remarkable features of this beach is its untouched beauty. The absence of crowds and commercialization allowed for an authentic and serene experience. I was able to walk along the shoreline, feeling the soft sand beneath my feet, and listen to the symphony of seagulls above. It was a refreshing escape from the hustle and bustle of daily life.#8#false#2 +5#review title#3#false#I recently had the opportunity to visit a breathtaking beach that left me in awe. Nestled between rolling waves and golden sands, this hidden gem is a true paradise for beach lovers and nature enthusiasts alike.From the moment I set foot on the powdery shoreline, I was captivated by the crystal-clear azure waters that stretched as far as the eye could see. The gentle caress of the ocean breeze and the soothing sound of waves crashing created an instant sense of relaxation.One of the most remarkable features of this beach is its untouched beauty. The absence of crowds and commercialization allowed for an authentic and serene experience. I was able to walk along the shoreline, feeling the soft sand beneath my feet, and listen to the symphony of seagulls above. It was a refreshing escape from the hustle and bustle of daily life.#8#false#3 +6#review title#2#true#I recently had the opportunity to visit a breathtaking beach that left me in awe. Nestled between rolling waves and golden sands, this hidden gem is a true paradise for beach lovers and nature enthusiasts alike.From the moment I set foot on the powdery shoreline, I was captivated by the crystal-clear azure waters that stretched as far as the eye could see. The gentle caress of the ocean breeze and the soothing sound of waves crashing created an instant sense of relaxation.One of the most remarkable features of this beach is its untouched beauty. The absence of crowds and commercialization allowed for an authentic and serene experience. I was able to walk along the shoreline, feeling the soft sand beneath my feet, and listen to the symphony of seagulls above. It was a refreshing escape from the hustle and bustle of daily life.#8#false#9 +7#review title#3#false#I recently had the opportunity to visit a breathtaking beach that left me in awe. Nestled between rolling waves and golden sands, this hidden gem is a true paradise for beach lovers and nature enthusiasts alike.From the moment I set foot on the powdery shoreline, I was captivated by the crystal-clear azure waters that stretched as far as the eye could see. The gentle caress of the ocean breeze and the soothing sound of waves crashing created an instant sense of relaxation.One of the most remarkable features of this beach is its untouched beauty. The absence of crowds and commercialization allowed for an authentic and serene experience. I was able to walk along the shoreline, feeling the soft sand beneath my feet, and listen to the symphony of seagulls above. It was a refreshing escape from the hustle and bustle of daily life.#8#false#8 +8#review title#2#true#I recently had the opportunity to visit a breathtaking beach that left me in awe. Nestled between rolling waves and golden sands, this hidden gem is a true paradise for beach lovers and nature enthusiasts alike.From the moment I set foot on the powdery shoreline, I was captivated by the crystal-clear azure waters that stretched as far as the eye could see. The gentle caress of the ocean breeze and the soothing sound of waves crashing created an instant sense of relaxation.One of the most remarkable features of this beach is its untouched beauty. The absence of crowds and commercialization allowed for an authentic and serene experience. I was able to walk along the shoreline, feeling the soft sand beneath my feet, and listen to the symphony of seagulls above. It was a refreshing escape from the hustle and bustle of daily life.#8#false#9 +9#review title#2#true#I recently had the opportunity to visit a breathtaking beach that left me in awe. Nestled between rolling waves and golden sands, this hidden gem is a true paradise for beach lovers and nature enthusiasts alike.From the moment I set foot on the powdery shoreline, I was captivated by the crystal-clear azure waters that stretched as far as the eye could see. The gentle caress of the ocean breeze and the soothing sound of waves crashing created an instant sense of relaxation.One of the most remarkable features of this beach is its untouched beauty. The absence of crowds and commercialization allowed for an authentic and serene experience. I was able to walk along the shoreline, feeling the soft sand beneath my feet, and listen to the symphony of seagulls above. It was a refreshing escape from the hustle and bustle of daily life.#8#false#4 +10#review title#3#false#I recently had the opportunity to visit a breathtaking beach that left me in awe. Nestled between rolling waves and golden sands, this hidden gem is a true paradise for beach lovers and nature enthusiasts alike.From the moment I set foot on the powdery shoreline, I was captivated by the crystal-clear azure waters that stretched as far as the eye could see. The gentle caress of the ocean breeze and the soothing sound of waves crashing created an instant sense of relaxation.One of the most remarkable features of this beach is its untouched beauty. The absence of crowds and commercialization allowed for an authentic and serene experience. I was able to walk along the shoreline, feeling the soft sand beneath my feet, and listen to the symphony of seagulls above. It was a refreshing escape from the hustle and bustle of daily life.#8#false#4 +11#review title#2#true#I recently had the opportunity to visit a breathtaking beach that left me in awe. Nestled between rolling waves and golden sands, this hidden gem is a true paradise for beach lovers and nature enthusiasts alike.From the moment I set foot on the powdery shoreline, I was captivated by the crystal-clear azure waters that stretched as far as the eye could see. The gentle caress of the ocean breeze and the soothing sound of waves crashing created an instant sense of relaxation.One of the most remarkable features of this beach is its untouched beauty. The absence of crowds and commercialization allowed for an authentic and serene experience. I was able to walk along the shoreline, feeling the soft sand beneath my feet, and listen to the symphony of seagulls above. It was a refreshing escape from the hustle and bustle of daily life.#8#false#2 +12#review title#2#true#I recently had the opportunity to visit a breathtaking beach that left me in awe. Nestled between rolling waves and golden sands, this hidden gem is a true paradise for beach lovers and nature enthusiasts alike.From the moment I set foot on the powdery shoreline, I was captivated by the crystal-clear azure waters that stretched as far as the eye could see. The gentle caress of the ocean breeze and the soothing sound of waves crashing created an instant sense of relaxation.One of the most remarkable features of this beach is its untouched beauty. The absence of crowds and commercialization allowed for an authentic and serene experience. I was able to walk along the shoreline, feeling the soft sand beneath my feet, and listen to the symphony of seagulls above. It was a refreshing escape from the hustle and bustle of daily life.#8#false#1 +13#review title#1#false#I recently had the opportunity to visit a breathtaking beach that left me in awe. Nestled between rolling waves and golden sands, this hidden gem is a true paradise for beach lovers and nature enthusiasts alike.From the moment I set foot on the powdery shoreline, I was captivated by the crystal-clear azure waters that stretched as far as the eye could see. The gentle caress of the ocean breeze and the soothing sound of waves crashing created an instant sense of relaxation.One of the most remarkable features of this beach is its untouched beauty. The absence of crowds and commercialization allowed for an authentic and serene experience. I was able to walk along the shoreline, feeling the soft sand beneath my feet, and listen to the symphony of seagulls above. It was a refreshing escape from the hustle and bustle of daily life.#8#false#8 +14#review title#1#false#I recently had the opportunity to visit a breathtaking beach that left me in awe. Nestled between rolling waves and golden sands, this hidden gem is a true paradise for beach lovers and nature enthusiasts alike.From the moment I set foot on the powdery shoreline, I was captivated by the crystal-clear azure waters that stretched as far as the eye could see. The gentle caress of the ocean breeze and the soothing sound of waves crashing created an instant sense of relaxation.One of the most remarkable features of this beach is its untouched beauty. The absence of crowds and commercialization allowed for an authentic and serene experience. I was able to walk along the shoreline, feeling the soft sand beneath my feet, and listen to the symphony of seagulls above. It was a refreshing escape from the hustle and bustle of daily life.#8#false#8 +15#review title#1#false#I recently had the opportunity to visit a breathtaking beach that left me in awe. Nestled between rolling waves and golden sands, this hidden gem is a true paradise for beach lovers and nature enthusiasts alike.From the moment I set foot on the powdery shoreline, I was captivated by the crystal-clear azure waters that stretched as far as the eye could see. The gentle caress of the ocean breeze and the soothing sound of waves crashing created an instant sense of relaxation.One of the most remarkable features of this beach is its untouched beauty. The absence of crowds and commercialization allowed for an authentic and serene experience. I was able to walk along the shoreline, feeling the soft sand beneath my feet, and listen to the symphony of seagulls above. It was a refreshing escape from the hustle and bustle of daily life.#8#false#8 \ No newline at end of file diff --git a/db/repository/locations.go b/db/repository/locations.go index d4762b3..0709dcd 100755 --- a/db/repository/locations.go +++ b/db/repository/locations.go @@ -286,7 +286,7 @@ type CreateLocationParams struct { GoogleMapsLink pgtype.Text `json:"google_maps_link"` IsDeleted bool `json:"is_deleted"` ApprovedBy pgtype.Int4 `json:"approved_by"` - Amenities string `json:"amenities"` + Amenities pgtype.Text `json:"amenities"` } func (q *Queries) CreateLocation(ctx context.Context, arg CreateLocationParams) (int32, error) { diff --git a/db/repository/menu_items.go b/db/repository/menu_items.go new file mode 100644 index 0000000..b1e5675 --- /dev/null +++ b/db/repository/menu_items.go @@ -0,0 +1,46 @@ +package db + +import ( + "context" +) + +const createMenuItems = `-- name: CreateMenuItems :exec +INSERT INTO menu_items( + location_id, + name, + price, + category, + description, + is_available, + submitted_by +) values ( + $1, $2, $3, $4, $5, $6, $7 +) +RETURNING id +` + +type CreateMenuItemsParams struct { + LocationID int32 `json:"location_id"` + Name string `json:"name"` + Price int32 `json:"price"` + Category string `json:"category"` + Description string `json:"description"` + IsAvailable bool `json:"is_available"` + SubmittedBy int32 `json:"submitted_by"` +} + +func (q *Queries) CreateMenuItems(ctx context.Context, arg CreateMenuItemsParams) (int32, error) { + row := q.db.QueryRow(ctx, createMenuItems, + arg.LocationID, + arg.Name, + arg.Price, + arg.Category, + arg.Description, + arg.IsAvailable, + arg.SubmittedBy, + ) + + var i int32 + err := row.Scan(&i) + return i, err +} diff --git a/db/repository/tx_location.go b/db/repository/tx_location.go index a7b1f30..d42b435 100755 --- a/db/repository/tx_location.go +++ b/db/repository/tx_location.go @@ -2,6 +2,7 @@ package db import ( "context" + "encoding/json" "github.com/jackc/pgx/v5/pgtype" ) @@ -12,7 +13,8 @@ type CreateLocationTxParams struct { SubmittedBy int32 `json:"submitted_by"` LocationType LocationType `json:"location_type"` RegencyID int16 `json:"regency_id"` - Amenities string `json:"amenities"` + Amenities pgtype.Text `json:"amenities"` + RestaurantMenu pgtype.Text `json:"restaurant_menu"` GoogleMapsLink pgtype.Text `json:"google_maps_link"` IsDeleted bool `json:"is_deleted"` ApprovedBy pgtype.Int4 `json:"approved_by"` @@ -35,6 +37,33 @@ func (store *SQLStore) CreateLocationTx(ctx context.Context, arg CreateLocationT Amenities: arg.Amenities, }) + if arg.LocationType == LocationTypeCulinary && arg.RestaurantMenu.Valid { + type menuItemInput struct { + Name string `json:"name"` + Price int32 `json:"price"` + Category string `json:"category"` + Description string `json:"description"` + } + var items []menuItemInput + if err := json.Unmarshal([]byte(arg.RestaurantMenu.String), &items); err != nil { + return err + } + for _, item := range items { + _, err := q.CreateMenuItems(ctx, CreateMenuItemsParams{ + LocationID: location_id, + Name: item.Name, + Price: item.Price, + Category: item.Category, + Description: item.Description, + IsAvailable: true, + SubmittedBy: arg.SubmittedBy, + }) + if err != nil { + return err + } + } + } + if err != nil { return err } diff --git a/dev.env.example b/dev.env.example index 9897e7e..db7a17b 100755 --- a/dev.env.example +++ b/dev.env.example @@ -11,4 +11,6 @@ SERVER_ADDRESS = 0.0.0.0:8888 TOKEN_SYMMETRIC_KEY= TOKEN_DURATION = 1024h COOKIE_DURATION = # in seconds -REFRESH_TOKEN_DURATION = 1024h \ No newline at end of file +REFRESH_TOKEN_DURATION = 1024h + +REDIS_ADDRESS = localhost:6379 \ No newline at end of file diff --git a/docs/docs.go b/docs/docs.go index e0ed6e9..5c335bc 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -964,6 +964,11 @@ const docTemplate = `{ }, "/user/logout": { "post": { + "security": [ + { + "CookieAuth": [] + } + ], "tags": [ "auth" ], diff --git a/docs/swagger.json b/docs/swagger.json index 17ce6b9..f179ccb 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -958,6 +958,11 @@ }, "/user/logout": { "post": { + "security": [ + { + "CookieAuth": [] + } + ], "tags": [ "auth" ], diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 7c49e70..02dc102 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -696,6 +696,8 @@ paths: responses: "204": description: No Content + security: + - CookieAuth: [] summary: Logout tags: - auth diff --git a/go.mod b/go.mod index d3a3e3f..06c255b 100755 --- a/go.mod +++ b/go.mod @@ -45,6 +45,7 @@ require ( github.com/aws/aws-sdk-go-v2/service/sts v1.41.10 // indirect github.com/aws/smithy-go v1.24.2 // indirect github.com/bytedance/sonic v1.10.2 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect github.com/chenzhuoyu/iasm v0.9.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect @@ -66,7 +67,7 @@ require ( github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/compress v1.15.6 // indirect - github.com/klauspost/cpuid/v2 v2.2.6 // indirect + github.com/klauspost/cpuid/v2 v2.2.10 // indirect github.com/leodido/go-urn v1.2.4 // indirect github.com/magiconair/properties v1.8.7 // indirect github.com/mailru/easyjson v0.7.7 // indirect @@ -77,6 +78,7 @@ require ( github.com/pelletier/go-toml/v2 v2.1.1 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/redis/go-redis/v9 v9.20.0 // indirect github.com/spf13/afero v1.9.5 // indirect github.com/spf13/cast v1.5.1 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect @@ -90,6 +92,7 @@ require ( github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasthttp v1.37.1-0.20220607072126-8a320890c08d // indirect github.com/yiplee/nap v1.0.1 // indirect + go.uber.org/atomic v1.11.0 // indirect golang.org/x/arch v0.7.0 // indirect golang.org/x/mod v0.17.0 // indirect golang.org/x/net v0.38.0 // indirect diff --git a/go.sum b/go.sum index 4b5ffc5..b04e730 100755 --- a/go.sum +++ b/go.sum @@ -96,6 +96,8 @@ github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ github.com/bytedance/sonic v1.10.2 h1:GQebETVBxYB7JGWJtLBi07OVzWwt+8dWA00gEVW2ZFE= github.com/bytedance/sonic v1.10.2/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d h1:77cEq6EriyTZ0g/qfRdp61a3Uu/AWrgIq2s0ClJV1g0= @@ -251,6 +253,8 @@ github.com/klauspost/compress v1.15.6/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHU github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.2.6 h1:ndNyv040zDGIDh8thGkXYjnFtiN02M1PVVF+JE/48xc= github.com/klauspost/cpuid/v2 v2.2.6/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE= +github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= @@ -300,6 +304,8 @@ github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qR github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/redis/go-redis/v9 v9.20.0 h1:WnQYxLkgO2xiXTCJY0ldIiI8dNqCDlQAG+AtaH7a2a0= +github.com/redis/go-redis/v9 v9.20.0/go.mod h1:v/M13XI1PVCDcm01VtPFOADfZtHf8YW3baQf57KlIkA= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= @@ -366,6 +372,8 @@ go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= +go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU= go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= diff --git a/util/config.go b/util/config.go index d3c1c54..f42ce1e 100755 --- a/util/config.go +++ b/util/config.go @@ -22,6 +22,7 @@ type Config struct { R2SecretAccessKey string `mapstructure:"R2_SECRET_ACCESS_KEY"` R2BucketName string `mapstructure:"R2_BUCKET_NAME"` R2PublicApiID string `mapstructure:"R2_PUBLIC_API_ID"` + RedisAddress string `mapstructure:"REDIS_ADDRESS"` } func LoadConfig(path string) (config Config, err error) {