add get recent locations rating

This commit is contained in:
nochill 2023-09-14 22:51:01 +07:00
parent 06d1284bbe
commit d1e5e7deb7
10 changed files with 151 additions and 10 deletions

View File

@ -110,6 +110,26 @@ func (server *Server) getListLocations(ctx *gin.Context) {
ctx.JSON(http.StatusOK, locations) ctx.JSON(http.StatusOK, locations)
} }
type getListRecentLocationsWithRatingsReq struct {
Page int32 `form:"page_size" binding:"required,min=1"`
}
func (server *Server) getListRecentLocationsWithRatings(ctx *gin.Context) {
var req getListRecentLocationsWithRatingsReq
if err := ctx.ShouldBindQuery(&req); err != nil {
ctx.JSON(http.StatusBadRequest, ValidationErrorResponse(err))
return
}
locations, err := server.Store.GetListRecentLocationsWithRatings(ctx, req.Page)
if err != nil {
ctx.JSON(http.StatusInternalServerError, ErrorResponse(err, "Something went wrong"))
return
}
ctx.JSON(http.StatusOK, locations)
}
type getLocationReq struct { type getLocationReq struct {
ID int32 `uri:"location_id" binding:"required"` ID int32 `uri:"location_id" binding:"required"`
} }

19
api/middleware.go Normal file
View File

@ -0,0 +1,19 @@
package api
import "github.com/gin-gonic/gin"
func CORSMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
c.Writer.Header().Set("Access-Control-Allow-Credentials", "true")
c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With")
c.Writer.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS, GET, PUT")
if c.Request.Method == "OPTIONS" {
c.AbortWithStatus(204)
return
}
c.Next()
}
}

View File

@ -35,10 +35,13 @@ func NewServer(config util.Config, store db.Store) (*Server, error) {
func (server *Server) getRoutes() { func (server *Server) getRoutes() {
router := gin.Default() router := gin.Default()
router.Use(CORSMiddleware())
router.POST("/user/signup", server.createUser) router.POST("/user/signup", server.createUser)
// LOCATION // LOCATION
router.POST("/locations", server.createLocation) router.POST("/locations", server.createLocation)
router.GET("/recent-locations/ratings", server.getListRecentLocationsWithRatings)
router.GET("/locations", server.getListLocations) router.GET("/locations", server.getListLocations)
router.GET("/location/:location_id", server.getLocation) router.GET("/location/:location_id", server.getLocation)

View File

@ -8,3 +8,6 @@ id,address,name,submitted_by,thumbnail,regency_id,google_maps_link,approved_by
7#Jl. P. Mangkubumi No.72A Cokrodiningratan Kec. Jetis#Hotel Tentrem Yogyakarta#1#https://cdn.discordapp.com/attachments/743422487882104837/1150987888553623653/image.png#3471#https://www.google.com/maps?q=Hotel+Tentrem+Yogyakarta&source=lmns&entry=mc&bih=1115&biw=2124&hl=en-US&sa=X&ved=2ahUKEwjjl-HHiKSBAxUu5jgGHTU3BiwQ0pQJKAJ6BAgBEAY#1 7#Jl. P. Mangkubumi No.72A Cokrodiningratan Kec. Jetis#Hotel Tentrem Yogyakarta#1#https://cdn.discordapp.com/attachments/743422487882104837/1150987888553623653/image.png#3471#https://www.google.com/maps?q=Hotel+Tentrem+Yogyakarta&source=lmns&entry=mc&bih=1115&biw=2124&hl=en-US&sa=X&ved=2ahUKEwjjl-HHiKSBAxUu5jgGHTU3BiwQ0pQJKAJ6BAgBEAY#1
8#Moluo Kec.Kwandang#Pulau Saronde Gorontalo#1#https://dynamic-media-cdn.tripadvisor.com/media/photo-o/0d/ec/58/21/saronde-island-a-place.jpg?w=700&h=-1&s=1#7505#https://www.google.com/maps/place/Pulau+Saronde+Gorontalo/@0.9263376,122.8613201,17z/data=!3m1!4b1!4m6!3m5!1s0x32795bf34dff4467:0xa8beb2a832ae8176!8m2!3d0.9263376!4d122.863895!16s%2Fg%2F11l241cc1d?hl=id&entry=ttu#1 8#Moluo Kec.Kwandang#Pulau Saronde Gorontalo#1#https://dynamic-media-cdn.tripadvisor.com/media/photo-o/0d/ec/58/21/saronde-island-a-place.jpg?w=700&h=-1&s=1#7505#https://www.google.com/maps/place/Pulau+Saronde+Gorontalo/@0.9263376,122.8613201,17z/data=!3m1!4b1!4m6!3m5!1s0x32795bf34dff4467:0xa8beb2a832ae8176!8m2!3d0.9263376!4d122.863895!16s%2Fg%2F11l241cc1d?hl=id&entry=ttu#1
9#Dusun Katiet Desa Bosua Kecamatan Sipora#Pantai Katiet#1#https://dynamic-media-cdn.tripadvisor.com/media/photo-o/1a/d7/fe/f4/mentawai-islands.jpg?w=500&h=-1&s=1#1301#https://www.google.com/maps/place/Katiet,+Bosua,+Sipora+Selatan,+Mentawai+Islands+Regency,+West+Sumatra/@-2.375793,99.848187,15z/data=!3m1!4b1!4m6!3m5!1s0x2fd27efa8363912f:0x8c9c19bd76cba179!8m2!3d-2.375793!4d99.848187!16s%2Fg%2F1tcwz0mt?hl=en-US&entry=ttu#1 9#Dusun Katiet Desa Bosua Kecamatan Sipora#Pantai Katiet#1#https://dynamic-media-cdn.tripadvisor.com/media/photo-o/1a/d7/fe/f4/mentawai-islands.jpg?w=500&h=-1&s=1#1301#https://www.google.com/maps/place/Katiet,+Bosua,+Sipora+Selatan,+Mentawai+Islands+Regency,+West+Sumatra/@-2.375793,99.848187,15z/data=!3m1!4b1!4m6!3m5!1s0x2fd27efa8363912f:0x8c9c19bd76cba179!8m2!3d-2.375793!4d99.848187!16s%2Fg%2F1tcwz0mt?hl=en-US&entry=ttu#1
10#Pulau Padar#Pulau Padar#2#https://dynamic-media-cdn.tripadvisor.com/media/photo-o/18/4e/11/f3/padar-island.jpg?w=800&h=-1&s=1#5315#https://www.google.com/maps/place/Pulau+Padar/@-8.6554183,119.570686,14.83z/data=!4m6!3m5!1s0x2db4f84ff6cd01ab:0xf7e6fd33b692a898!8m2!3d-8.6489909!4d119.5832593!16s%2Fg%2F121d16wd?entry=ttu#1
11#Jl. Ahmad Yani 18, Kel. Kelimutu, Kec. Ende Tengah#Sari rasa#3#https://cdn.discordapp.com/attachments/743422487882104837/1151903310295601172/image.png#5315#https://www.google.com/maps/place/Rumah+Makan+Cha+Cha/@-8.6153697,120.4652533,21z/data=!4m6!3m5!1s0x2db37469e54c0dd3:0x36ac988c726ed544!8m2!3d-8.6153631!4d120.465275!16s%2Fg%2F11bwpclp91?entry=ttu#1
12#Danau Sentani#Danau Sentani#3#https://dynamic-media-cdn.tripadvisor.com/media/photo-o/1a/c7/e8/17/20190630-143008-largejpg.jpg?w=800&h=-1&s=1#9403#https://www.google.com/maps/place/Danau+Sentani/@-2.639976,140.3889748,12.46z/data=!4m7!3m6!1s0x686cf33c72660fbf:0x7e5c1e7d20d930d7!4b1!8m2!3d-2.6133004!4d140.518734!16s%2Fm%2F0tkjf6v?entry=ttu#1
1 id,address,name,submitted_by,thumbnail,regency_id,google_maps_link,approved_by
8 7#Jl. P. Mangkubumi No.72A Cokrodiningratan Kec. Jetis#Hotel Tentrem Yogyakarta#1#https://cdn.discordapp.com/attachments/743422487882104837/1150987888553623653/image.png#3471#https://www.google.com/maps?q=Hotel+Tentrem+Yogyakarta&source=lmns&entry=mc&bih=1115&biw=2124&hl=en-US&sa=X&ved=2ahUKEwjjl-HHiKSBAxUu5jgGHTU3BiwQ0pQJKAJ6BAgBEAY#1
9 8#Moluo Kec.Kwandang#Pulau Saronde Gorontalo#1#https://dynamic-media-cdn.tripadvisor.com/media/photo-o/0d/ec/58/21/saronde-island-a-place.jpg?w=700&h=-1&s=1#7505#https://www.google.com/maps/place/Pulau+Saronde+Gorontalo/@0.9263376,122.8613201,17z/data=!3m1!4b1!4m6!3m5!1s0x32795bf34dff4467:0xa8beb2a832ae8176!8m2!3d0.9263376!4d122.863895!16s%2Fg%2F11l241cc1d?hl=id&entry=ttu#1
10 9#Dusun Katiet Desa Bosua Kecamatan Sipora#Pantai Katiet#1#https://dynamic-media-cdn.tripadvisor.com/media/photo-o/1a/d7/fe/f4/mentawai-islands.jpg?w=500&h=-1&s=1#1301#https://www.google.com/maps/place/Katiet,+Bosua,+Sipora+Selatan,+Mentawai+Islands+Regency,+West+Sumatra/@-2.375793,99.848187,15z/data=!3m1!4b1!4m6!3m5!1s0x2fd27efa8363912f:0x8c9c19bd76cba179!8m2!3d-2.375793!4d99.848187!16s%2Fg%2F1tcwz0mt?hl=en-US&entry=ttu#1
11 10#Pulau Padar#Pulau Padar#2#https://dynamic-media-cdn.tripadvisor.com/media/photo-o/18/4e/11/f3/padar-island.jpg?w=800&h=-1&s=1#5315#https://www.google.com/maps/place/Pulau+Padar/@-8.6554183,119.570686,14.83z/data=!4m6!3m5!1s0x2db4f84ff6cd01ab:0xf7e6fd33b692a898!8m2!3d-8.6489909!4d119.5832593!16s%2Fg%2F121d16wd?entry=ttu#1
12 11#Jl. Ahmad Yani 18, Kel. Kelimutu, Kec. Ende Tengah#Sari rasa#3#https://cdn.discordapp.com/attachments/743422487882104837/1151903310295601172/image.png#5315#https://www.google.com/maps/place/Rumah+Makan+Cha+Cha/@-8.6153697,120.4652533,21z/data=!4m6!3m5!1s0x2db37469e54c0dd3:0x36ac988c726ed544!8m2!3d-8.6153631!4d120.465275!16s%2Fg%2F11bwpclp91?entry=ttu#1
13 12#Danau Sentani#Danau Sentani#3#https://dynamic-media-cdn.tripadvisor.com/media/photo-o/1a/c7/e8/17/20190630-143008-largejpg.jpg?w=800&h=-1&s=1#9403#https://www.google.com/maps/place/Danau+Sentani/@-2.639976,140.3889748,12.46z/data=!4m7!3m6!1s0x686cf33c72660fbf:0x7e5c1e7d20d930d7!4b1!8m2!3d-2.6133004!4d140.518734!16s%2Fm%2F0tkjf6v?entry=ttu#1

View File

@ -1,2 +1,4 @@
id,username,password id,username,password
1,user123,password 1,user123,password
2,critics,password
3,plebs,password
1 id username password
2 1 user123 password
3 2 critics password
4 3 plebs password

View File

@ -79,6 +79,21 @@ func (mr *MockStoreMockRecorder) GetListLocations(arg0 interface{}) *gomock.Call
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetListLocations", reflect.TypeOf((*MockStore)(nil).GetListLocations), arg0) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetListLocations", reflect.TypeOf((*MockStore)(nil).GetListLocations), arg0)
} }
// GetListRecentLocationsWithRatings mocks base method.
func (m *MockStore) GetListRecentLocationsWithRatings(arg0 context.Context, arg1 int32) ([]db.GetListRecentLocationsWithRatingsRow, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetListRecentLocationsWithRatings", arg0, arg1)
ret0, _ := ret[0].([]db.GetListRecentLocationsWithRatingsRow)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetListRecentLocationsWithRatings indicates an expected call of GetListRecentLocationsWithRatings.
func (mr *MockStoreMockRecorder) GetListRecentLocationsWithRatings(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetListRecentLocationsWithRatings", reflect.TypeOf((*MockStore)(nil).GetListRecentLocationsWithRatings), arg0, arg1)
}
// GetLocation mocks base method. // GetLocation mocks base method.
func (m *MockStore) GetLocation(arg0 context.Context, arg1 int32) (db.Location, error) { func (m *MockStore) GetLocation(arg0 context.Context, arg1 int32) (db.Location, error) {
m.ctrl.T.Helper() m.ctrl.T.Helper()

View File

@ -1,6 +1,23 @@
-- name: GetListLocations :many -- name: GetListLocations :many
SELECT * FROM locations; SELECT * FROM locations;
-- name: GetListRecentLocationsWithRatings :many
SELECT
l.id,
name,
thumbnail,
re.regency_name,
(SELECT COALESCE(SUM(score), -1) from reviews re where re.is_from_critic = true and re.location_id = l.id) as critic_score,
(SELECT COUNT(id) from reviews re where re.is_from_critic = true and re.location_id = l.id) as critic_count,
(SELECT COALESCE(SUM(score), -1) from reviews re where re.is_from_critic = false and re.location_id = l.id) as user_score,
(SELECT COUNT(id) from reviews re where re.is_from_critic = false and re.location_id = l.id) as user_count
FROM locations l
JOIN regencies re on re.id = l.regency_id
WHERE approved_by IS NOT NULL
ORDER BY l.created_at ASC
LIMIT $1;
-- name: GetLocation :one -- name: GetLocation :one
SELECT * FROM locations SELECT * FROM locations
WHERE id = $1; WHERE id = $1;

View File

@ -82,6 +82,66 @@ func (q *Queries) GetListLocations(ctx context.Context) ([]Location, error) {
return items, nil return items, nil
} }
const getListRecentLocationsWithRatings = `-- name: GetListRecentLocationsWithRatings :many
SELECT
l.id,
name,
thumbnail,
re.regency_name,
(SELECT COALESCE(SUM(score), -1) from reviews re where re.is_from_critic = true and re.location_id = l.id) as critic_score,
(SELECT COUNT(id) from reviews re where re.is_from_critic = true and re.location_id = l.id) as critic_count,
(SELECT COALESCE(SUM(score), -1) from reviews re where re.is_from_critic = false and re.location_id = l.id) as user_score,
(SELECT COUNT(id) from reviews re where re.is_from_critic = false and re.location_id = l.id) as user_count
FROM locations l
JOIN regencies re on re.id = l.regency_id
WHERE approved_by IS NOT NULL
ORDER BY l.created_at ASC
LIMIT $1
`
type GetListRecentLocationsWithRatingsRow struct {
ID int32 `json:"id"`
Name string `json:"name"`
Thumbnail sql.NullString `json:"thumbnail"`
RegencyName sql.NullString `json:"regency_name"`
CriticScore interface{} `json:"critic_score"`
CriticCount int64 `json:"critic_count"`
UserScore interface{} `json:"user_score"`
UserCount int64 `json:"user_count"`
}
func (q *Queries) GetListRecentLocationsWithRatings(ctx context.Context, limit int32) ([]GetListRecentLocationsWithRatingsRow, error) {
rows, err := q.db.QueryContext(ctx, getListRecentLocationsWithRatings, limit)
if err != nil {
return nil, err
}
defer rows.Close()
items := []GetListRecentLocationsWithRatingsRow{}
for rows.Next() {
var i GetListRecentLocationsWithRatingsRow
if err := rows.Scan(
&i.ID,
&i.Name,
&i.Thumbnail,
&i.RegencyName,
&i.CriticScore,
&i.CriticCount,
&i.UserScore,
&i.UserCount,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getLocation = `-- name: GetLocation :one const getLocation = `-- name: GetLocation :one
SELECT id, address, name, google_maps_link, submitted_by, total_visited, thumbnail, regency_id, is_deleted, created_at, updated_at, approved_by, approved_at FROM locations SELECT id, address, name, google_maps_link, submitted_by, total_visited, thumbnail, regency_id, is_deleted, created_at, updated_at, approved_by, approved_at FROM locations
WHERE id = $1 WHERE id = $1

View File

@ -173,14 +173,15 @@ type Region struct {
} }
type Review struct { type Review struct {
ID int32 `json:"id"` ID int32 `json:"id"`
SubmittedBy int32 `json:"submitted_by"` SubmittedBy int32 `json:"submitted_by"`
Comments string `json:"comments"` Comments string `json:"comments"`
Score int16 `json:"score"` Score int16 `json:"score"`
IsHided sql.NullBool `json:"is_hided"` IsFromCritic bool `json:"is_from_critic"`
LocationID int32 `json:"location_id"` IsHided sql.NullBool `json:"is_hided"`
CreatedAt sql.NullTime `json:"created_at"` LocationID int32 `json:"location_id"`
UpdatedAt sql.NullTime `json:"updated_at"` CreatedAt sql.NullTime `json:"created_at"`
UpdatedAt sql.NullTime `json:"updated_at"`
} }
type Tag struct { type Tag struct {

View File

@ -12,6 +12,7 @@ type Querier interface {
CreateLocation(ctx context.Context, arg CreateLocationParams) error CreateLocation(ctx context.Context, arg CreateLocationParams) error
CreateUser(ctx context.Context, arg CreateUserParams) (User, error) CreateUser(ctx context.Context, arg CreateUserParams) (User, error)
GetListLocations(ctx context.Context) ([]Location, error) GetListLocations(ctx context.Context) ([]Location, error)
GetListRecentLocationsWithRatings(ctx context.Context, limit int32) ([]GetListRecentLocationsWithRatingsRow, error)
GetLocation(ctx context.Context, id int32) (Location, error) GetLocation(ctx context.Context, id int32) (Location, error)
UpdatePassword(ctx context.Context, arg UpdatePasswordParams) error UpdatePassword(ctx context.Context, arg UpdatePasswordParams) error
UpdateUser(ctx context.Context, arg UpdateUserParams) (User, error) UpdateUser(ctx context.Context, arg UpdateUserParams) (User, error)