Compare commits

..

No commits in common. "67ea7cb20fbb14416febd4bc869245c5bbe40e28" and "305beabacb6615da5f4c8b0577f3131c2ec542a3" have entirely different histories.

10 changed files with 13 additions and 896 deletions

View File

@ -260,82 +260,3 @@ func (server *Server) getUserReviewByLocation(ctx *gin.Context) {
Images: images,
})
}
type getLocationReviewGradesReq struct {
LocationID int32 `uri:"location_id" binding:"required"`
}
type locationReviewGradesGroup struct {
AvgTasteGrade *float64 `json:"avg_taste_grade"`
TasteGradeCount int64 `json:"taste_grade_count"`
AvgComfortGrade *float64 `json:"avg_comfort_grade"`
ComfortGradeCount int64 `json:"comfort_grade_count"`
AvgCleanlinessGrade *float64 `json:"avg_cleanliness_grade"`
CleanlinessGradeCount int64 `json:"cleanliness_grade_count"`
AvgServiceGrade *float64 `json:"avg_service_grade"`
ServiceGradeCount int64 `json:"service_grade_count"`
AvgFacilitiesGrade *float64 `json:"avg_facilities_grade"`
FacilitiesGradeCount int64 `json:"facilities_grade_count"`
}
type getLocationReviewGradesRes struct {
CriticsGrades locationReviewGradesGroup `json:"critics_grades"`
UsersGrades locationReviewGradesGroup `json:"users_grades"`
}
func nullableFloat(v pgtype.Float8) *float64 {
if !v.Valid {
return nil
}
return &v.Float64
}
// @Summary Get aggregated review grades for a location
// @Tags reviews
// @Produce json
// @Param location_id path int true "Location ID"
// @Success 200 {object} getLocationReviewGradesRes
// @Failure 400 {object} map[string]any
// @Failure 500 {object} map[string]any
// @Router /location/{location_id}/reviews/grades [get]
func (server *Server) getLocationReviewGrades(ctx *gin.Context) {
var req getLocationReviewGradesReq
if err := ctx.ShouldBindUri(&req); err != nil {
ctx.JSON(http.StatusBadRequest, ValidationErrorResponse(err))
return
}
grades, err := server.Store.GetLocationReviewGrades(ctx, req.LocationID)
if err != nil {
ctx.JSON(http.StatusInternalServerError, ErrorResponse(err, "Something went wrong while trying to retrieve review grades"))
return
}
ctx.JSON(http.StatusOK, getLocationReviewGradesRes{
CriticsGrades: locationReviewGradesGroup{
AvgTasteGrade: nullableFloat(grades.CriticAvgTasteGrade),
TasteGradeCount: grades.CriticTasteGradeCount,
AvgComfortGrade: nullableFloat(grades.CriticAvgComfortGrade),
ComfortGradeCount: grades.CriticComfortGradeCount,
AvgCleanlinessGrade: nullableFloat(grades.CriticAvgCleanlinessGrade),
CleanlinessGradeCount: grades.CriticCleanlinessGradeCount,
AvgServiceGrade: nullableFloat(grades.CriticAvgServiceGrade),
ServiceGradeCount: grades.CriticServiceGradeCount,
AvgFacilitiesGrade: nullableFloat(grades.CriticAvgFacilitiesGrade),
FacilitiesGradeCount: grades.CriticFacilitiesGradeCount,
},
UsersGrades: locationReviewGradesGroup{
AvgTasteGrade: nullableFloat(grades.UserAvgTasteGrade),
TasteGradeCount: grades.UserTasteGradeCount,
AvgComfortGrade: nullableFloat(grades.UserAvgComfortGrade),
ComfortGradeCount: grades.UserComfortGradeCount,
AvgCleanlinessGrade: nullableFloat(grades.UserAvgCleanlinessGrade),
CleanlinessGradeCount: grades.UserCleanlinessGradeCount,
AvgServiceGrade: nullableFloat(grades.UserAvgServiceGrade),
ServiceGradeCount: grades.UserServiceGradeCount,
AvgFacilitiesGrade: nullableFloat(grades.UserAvgFacilitiesGrade),
FacilitiesGradeCount: grades.UserFacilitiesGradeCount,
},
})
}

View File

@ -91,7 +91,6 @@ func (server *Server) getRoutes() {
router.GET("/location/tags/:location_id", server.getTagsByLocation)
router.GET("/location/reviews", server.getListLocationReviews)
router.GET("/location/:location_id/review/:review_id", server.getReview)
router.GET("/location/grades/:location_id", server.getLocationReviewGrades)
router.GET("/locations/search", server.searchLocations)
router.POST("/location/:location_id/visit", server.recordLocationVisit)

BIN
db/.DS_Store vendored

Binary file not shown.

View File

@ -1,16 +1,13 @@
id,address,name,google_maps_link,location_type,submitted_by,thumbnail,regency_id,is_deleted,created_at,updated_at,approved_by,approved_at,amenities,business_hours
1,Jalan Raya Beside the bridge Ubud,Murni's Warung,"https://www.google.com/maps/place/Murni's+Warung/@-8.5048696,115.2553417,19z/data=!4m6!3m5!1s0x2dd23d3e0ffaa071:0xf2fa69b4cb211e41!8m2!3d-8.5051184!4d115.2547196!16s%2Fg%2F1tdsmcq7?entry=ttu",culinary,1,https://cdn.discordapp.com/attachments/743422487882104837/1150972798320267304/image.png,5104,false,2026-04-12 23:50:04.608443,2026-04-12 23:50:04.608443,1,,,
2,Jl.Taman Wijaya Kusuma Ps. Baru Kecamatan Sawah Besar,Masjid Istiqlal,"https://www.google.com/maps/place/Masjid+Istiqlal/@-6.1703155,106.8308434,19z/data=!4m15!1m7!3m6!1s0x2e69f5ce68b5e01d:0xcafaf042d5840c6c!2sMasjid+Istiqlal!8m2!3d-6.17017!4d106.83139!16zL20vMDRzam1q!3m6!1s0x2e69f5ce68b5e01d:0xcafaf042d5840c6c!8m2!3d-6.17017!4d106.83139!15sCg9tYXNqaWQgaXN0aXFsYWxaESIPbWFzamlkIGlzdGlxbGFskgEGbW9zcXVl4AEA!16zL20vMDRzam1q?entry=ttu",other,1,https://dynamic-media-cdn.tripadvisor.com/media/photo-o/04/11/31/33/istiqlal-mosque-mesjid.jpg?w=500&h=-1&s=1,3173,false,2026-04-12 23:50:04.608443,2026-04-12 23:50:04.608443,1,,,
3,Jl. Mayjend Sungkono no. 89,Hotel Ciputra World Surabaya,"https://www.google.com/maps/place/Ciputra+World+Hotel+Surabaya/@-7.2923061,112.7191552,15z/data=!4m2!3m1!1s0x0:0x736a9c49dcc2ac42?sa=X&ved=2ahUKEwjJlbf8gqSBAxWtzzgGHUIkBFYQ_BJ6BAgVEAA&ved=2ahUKEwjJlbf8gqSBAxWtzzgGHUIkBFYQ_BJ6BAgjEAc",accommodation,1,https://lh5.googleusercontent.com/p/AF1QipOvHDO-M6riRoqBrWU3MskhwL_bue8JmN9faq7Q=w500-h500-k-no,3578,false,2026-04-12 23:50:04.608443,2026-04-12 23:50:04.608443,1,,,
4,Jl. Taman Safari No.101 . B Cibeureum Kec. Cisarua,Club Huis,"https://www.google.com/maps/place/Club+Huis/@-6.7027857,106.9453741,17z/data=!3m1!4b1!4m6!3m5!1s0x2e69b679d7a09e01:0xf9fc2df396f09977!8m2!3d-6.7027857!4d106.947949!16s%2Fg%2F11c57lh8ky?entry=ttu",recreation,1,https://media-cdn.tripadvisor.com/media/photo-o/0d/6a/5d/63/our-peaceful-backyard.jpg,3201,false,2026-04-12 23:50:04.608443,2026-04-12 23:50:04.608443,1,,,
5,Desa Tambakrejo Kecamatan Sumbermanjing Wetan,Pulau Sempu,"https://www.google.com/maps/place/Pulau+Sempu/@-8.446621,112.6746143,14z/data=!3m1!4b1!4m6!3m5!1s0x2dd60120edbc901f:0x8efd89687a308993!8m2!3d-8.4428564!4d112.6973355!16s%2Fm%2F0r8k540?entry=ttu",recreation,1,https://dynamic-media-cdn.tripadvisor.com/media/photo-o/11/3b/06/a5/pulau-sempu.jpg?w=500&h=-1&s=1,3507,false,2026-04-12 23:50:04.608443,2026-04-12 23:50:04.608443,1,,,
6,Jl. Bukit Golf I BSD Sektor VI Lengkong Karya Kec. Serpong Utara,Damai Indah Golf,"https://www.google.com/maps/place/Damai+Indah+Golf+-+BSD+Course/@-6.2815644,106.6496566,17z/data=!3m1!4b1!4m6!3m5!1s0x2e69fb152983d973:0x89e58e219f8b93ef!8m2!3d-6.2815644!4d106.6522315!16s%2Fg%2F11c54c9r94?entry=ttu",recreation,1,https://lh3.googleusercontent.com/p/AF1QipN5Z-0J6vIfIO6gqPO0z5HDWlNKqp0t816XIJPS=s680-w500-h500,3674,false,2026-04-12 23:50:04.608443,2026-04-12 23:50:04.608443,1,,,
7,Jl. P. Mangkubumi No.72A Cokrodiningratan Kec. Jetis,Hotel Tentrem Yogyakarta,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,accommodation,1,https://cdn.discordapp.com/attachments/743422487882104837/1150987888553623653/image.png,3471,false,2026-04-12 23:50:04.608443,2026-04-12 23:50:04.608443,1,,,
8,Moluo Kec.Kwandang,Pulau Saronde Gorontalo,"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",recreation,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,false,2026-04-12 23:50:04.608443,2026-04-12 23:50:04.608443,1,,,
9,Dusun Katiet Desa Bosua Kecamatan Sipora,Pantai Katiet,"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",recreation,1,https://dynamic-media-cdn.tripadvisor.com/media/photo-o/1a/d7/fe/f4/mentawai-islands.jpg?w=500&h=-1&s=1,1301,false,2026-04-12 23:50:04.608443,2026-04-12 23:50:04.608443,1,,,
10,Pulau Padar,Pulau Padar,"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",recreation,2,https://dynamic-media-cdn.tripadvisor.com/media/photo-o/18/4e/11/f3/padar-island.jpg?w=800&h=-1&s=1,5315,false,2026-04-12 23:50:04.608443,2026-04-12 23:50:04.608443,1,,,
11,"Jl. Ahmad Yani 18, Kel. Kelimutu, Kec. Ende Tengah",Sari rasa,"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",culinary,3,https://cdn.discordapp.com/attachments/743422487882104837/1151903310295601172/image.png,5315,false,2026-04-12 23:50:04.608443,2026-04-12 23:50:04.608443,1,,,
12,Danau Sentani,Danau Sentani,"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",recreation,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,false,2026-04-12 23:50:04.608443,2026-04-12 23:50:04.608443,1,,,
19,natohentoahe,aosenhatohe,aoeaoeaoe,mall,4,,1112,false,2026-06-01 09:19:04.996652,2026-06-01 09:19:04.996652,,,"[{""Food & Beverages"": [""Solaria"", ""J.CO Donuts"", ""Pizza Hut"", ""Chatime""]}, {""Fashion"": [""Pull&Bear"", ""Nevada""]}, {""Sports"": [""Reebok"", ""Puma"", ""Nike"", ""Mills""]}, {""Health & Beauty"": [""The Body Shop"", ""Miniso"", ""Innisfree""]}]",
20,aoeaoeaoeoae,aoeaoe,aoeaoeoaeaoe,culinary,4,,1118,false,2026-06-06 23:29:37.459913,2026-06-06 23:29:37.459913,,,,
21,aotehsnatohesntaho,aoedhnaohesnth,aoeaoeaoeaoeaoe,culinary,4,,1409,false,2026-06-11 12:52:23.675860,2026-06-11 12:52:23.675860,1,,"[{""Facilities"": [""Live Music"", ""Outdoor Seating""]}, {""Services"": [""Parking"", ""Takeout""]}, {""Food Options"": [""Vegetarian"", ""Vegan""]}]","[{""day"": ""Sunday"", ""closed"": true}, {""day"": ""Monday"", ""closed"": true}, {""day"": ""Tuesday"", ""open"": ""09:00"", ""close"": ""21:00""}, {""day"": ""Wednesday"", ""open"": ""09:00"", ""close"": ""21:00""}, {""day"": ""Thursday"", ""open"": ""09:00"", ""close"": ""21:00""}, {""day"": ""Friday"", ""open"": ""09:00"", ""close"": ""21:00""}, {""day"": ""Saturday"", ""open"": ""09:00"", ""close"": ""21:00""}]"
id,location_type,address,name,submitted_by,thumbnail,regency_id,google_maps_link,approved_by,is_deleted
1#culinary#Jalan Raya Beside the bridge Ubud#Murnis Warung#1#https://cdn.discordapp.com/attachments/743422487882104837/1150972798320267304/image.png#5104#https://www.google.com/maps/place/Murni's+Warung/@-8.5048696,115.2553417,19z/data=!4m6!3m5!1s0x2dd23d3e0ffaa071:0xf2fa69b4cb211e41!8m2!3d-8.5051184!4d115.2547196!16s%2Fg%2F1tdsmcq7?entry=ttu#1#false
2#other#Jl.Taman Wijaya Kusuma Ps. Baru Kecamatan Sawah Besar#Masjid Istiqlal#1#https://dynamic-media-cdn.tripadvisor.com/media/photo-o/04/11/31/33/istiqlal-mosque-mesjid.jpg?w=500&h=-1&s=1#3173#https://www.google.com/maps/place/Masjid+Istiqlal/@-6.1703155,106.8308434,19z/data=!4m15!1m7!3m6!1s0x2e69f5ce68b5e01d:0xcafaf042d5840c6c!2sMasjid+Istiqlal!8m2!3d-6.17017!4d106.83139!16zL20vMDRzam1q!3m6!1s0x2e69f5ce68b5e01d:0xcafaf042d5840c6c!8m2!3d-6.17017!4d106.83139!15sCg9tYXNqaWQgaXN0aXFsYWxaESIPbWFzamlkIGlzdGlxbGFskgEGbW9zcXVl4AEA!16zL20vMDRzam1q?entry=ttu#1#false
3#accommodation#Jl. Mayjend Sungkono no. 89#Hotel Ciputra World Surabaya#1#https://lh5.googleusercontent.com/p/AF1QipOvHDO-M6riRoqBrWU3MskhwL_bue8JmN9faq7Q=w500-h500-k-no#3578#https://www.google.com/maps/place/Ciputra+World+Hotel+Surabaya/@-7.2923061,112.7191552,15z/data=!4m2!3m1!1s0x0:0x736a9c49dcc2ac42?sa=X&ved=2ahUKEwjJlbf8gqSBAxWtzzgGHUIkBFYQ_BJ6BAgVEAA&ved=2ahUKEwjJlbf8gqSBAxWtzzgGHUIkBFYQ_BJ6BAgjEAc#1#false
4#recreation#Jl. Taman Safari No.101 . B Cibeureum Kec. Cisarua#Club Huis#1#https://media-cdn.tripadvisor.com/media/photo-o/0d/6a/5d/63/our-peaceful-backyard.jpg#3201#https://www.google.com/maps/place/Club+Huis/@-6.7027857,106.9453741,17z/data=!3m1!4b1!4m6!3m5!1s0x2e69b679d7a09e01:0xf9fc2df396f09977!8m2!3d-6.7027857!4d106.947949!16s%2Fg%2F11c57lh8ky?entry=ttu#1#false
5#recreation#Desa Tambakrejo Kecamatan Sumbermanjing Wetan#Pulau Sempu#1#https://dynamic-media-cdn.tripadvisor.com/media/photo-o/11/3b/06/a5/pulau-sempu.jpg?w=500&h=-1&s=1#3507#https://www.google.com/maps/place/Pulau+Sempu/@-8.446621,112.6746143,14z/data=!3m1!4b1!4m6!3m5!1s0x2dd60120edbc901f:0x8efd89687a308993!8m2!3d-8.4428564!4d112.6973355!16s%2Fm%2F0r8k540?entry=ttu#1#false
6#recreation#Jl. Bukit Golf I BSD Sektor VI Lengkong Karya Kec. Serpong Utara#Damai Indah Golf#1#https://lh3.googleusercontent.com/p/AF1QipN5Z-0J6vIfIO6gqPO0z5HDWlNKqp0t816XIJPS=s680-w500-h500#3674#https://www.google.com/maps/place/Damai+Indah+Golf+-+BSD+Course/@-6.2815644,106.6496566,17z/data=!3m1!4b1!4m6!3m5!1s0x2e69fb152983d973:0x89e58e219f8b93ef!8m2!3d-6.2815644!4d106.6522315!16s%2Fg%2F11c54c9r94?entry=ttu#1#false
7#accommodation#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#false
8#recreation#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#false
9#recreation#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#false
10#recreation#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#false
11#culinary#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#false
12#recreation#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#false
1 id id,location_type,address,name,submitted_by,thumbnail,regency_id,google_maps_link,approved_by,is_deleted address name google_maps_link location_type submitted_by thumbnail regency_id is_deleted created_at updated_at approved_by approved_at amenities business_hours
2 1 1#culinary#Jalan Raya Beside the bridge Ubud#Murni’s Warung#1#https://cdn.discordapp.com/attachments/743422487882104837/1150972798320267304/image.png#5104#https://www.google.com/maps/place/Murni's+Warung/@-8.5048696,115.2553417,19z/data=!4m6!3m5!1s0x2dd23d3e0ffaa071:0xf2fa69b4cb211e41!8m2!3d-8.5051184!4d115.2547196!16s%2Fg%2F1tdsmcq7?entry=ttu#1#false Jalan Raya Beside the bridge Ubud Murni's Warung https://www.google.com/maps/place/Murni's+Warung/@-8.5048696,115.2553417,19z/data=!4m6!3m5!1s0x2dd23d3e0ffaa071:0xf2fa69b4cb211e41!8m2!3d-8.5051184!4d115.2547196!16s%2Fg%2F1tdsmcq7?entry=ttu culinary 1 https://cdn.discordapp.com/attachments/743422487882104837/1150972798320267304/image.png 5104 false 2026-04-12 23:50:04.608443 2026-04-12 23:50:04.608443 1
3 2 2#other#Jl.Taman Wijaya Kusuma Ps. Baru Kecamatan Sawah Besar#Masjid Istiqlal#1#https://dynamic-media-cdn.tripadvisor.com/media/photo-o/04/11/31/33/istiqlal-mosque-mesjid.jpg?w=500&h=-1&s=1#3173#https://www.google.com/maps/place/Masjid+Istiqlal/@-6.1703155,106.8308434,19z/data=!4m15!1m7!3m6!1s0x2e69f5ce68b5e01d:0xcafaf042d5840c6c!2sMasjid+Istiqlal!8m2!3d-6.17017!4d106.83139!16zL20vMDRzam1q!3m6!1s0x2e69f5ce68b5e01d:0xcafaf042d5840c6c!8m2!3d-6.17017!4d106.83139!15sCg9tYXNqaWQgaXN0aXFsYWxaESIPbWFzamlkIGlzdGlxbGFskgEGbW9zcXVl4AEA!16zL20vMDRzam1q?entry=ttu#1#false Jl.Taman Wijaya Kusuma Ps. Baru Kecamatan Sawah Besar Masjid Istiqlal https://www.google.com/maps/place/Masjid+Istiqlal/@-6.1703155,106.8308434,19z/data=!4m15!1m7!3m6!1s0x2e69f5ce68b5e01d:0xcafaf042d5840c6c!2sMasjid+Istiqlal!8m2!3d-6.17017!4d106.83139!16zL20vMDRzam1q!3m6!1s0x2e69f5ce68b5e01d:0xcafaf042d5840c6c!8m2!3d-6.17017!4d106.83139!15sCg9tYXNqaWQgaXN0aXFsYWxaESIPbWFzamlkIGlzdGlxbGFskgEGbW9zcXVl4AEA!16zL20vMDRzam1q?entry=ttu other 1 https://dynamic-media-cdn.tripadvisor.com/media/photo-o/04/11/31/33/istiqlal-mosque-mesjid.jpg?w=500&h=-1&s=1 3173 false 2026-04-12 23:50:04.608443 2026-04-12 23:50:04.608443 1
4 3 3#accommodation#Jl. Mayjend Sungkono no. 89#Hotel Ciputra World Surabaya#1#https://lh5.googleusercontent.com/p/AF1QipOvHDO-M6riRoqBrWU3MskhwL_bue8JmN9faq7Q=w500-h500-k-no#3578#https://www.google.com/maps/place/Ciputra+World+Hotel+Surabaya/@-7.2923061,112.7191552,15z/data=!4m2!3m1!1s0x0:0x736a9c49dcc2ac42?sa=X&ved=2ahUKEwjJlbf8gqSBAxWtzzgGHUIkBFYQ_BJ6BAgVEAA&ved=2ahUKEwjJlbf8gqSBAxWtzzgGHUIkBFYQ_BJ6BAgjEAc#1#false Jl. Mayjend Sungkono no. 89 Hotel Ciputra World Surabaya https://www.google.com/maps/place/Ciputra+World+Hotel+Surabaya/@-7.2923061,112.7191552,15z/data=!4m2!3m1!1s0x0:0x736a9c49dcc2ac42?sa=X&ved=2ahUKEwjJlbf8gqSBAxWtzzgGHUIkBFYQ_BJ6BAgVEAA&ved=2ahUKEwjJlbf8gqSBAxWtzzgGHUIkBFYQ_BJ6BAgjEAc accommodation 1 https://lh5.googleusercontent.com/p/AF1QipOvHDO-M6riRoqBrWU3MskhwL_bue8JmN9faq7Q=w500-h500-k-no 3578 false 2026-04-12 23:50:04.608443 2026-04-12 23:50:04.608443 1
5 4 4#recreation#Jl. Taman Safari No.101 . B Cibeureum Kec. Cisarua#Club Huis#1#https://media-cdn.tripadvisor.com/media/photo-o/0d/6a/5d/63/our-peaceful-backyard.jpg#3201#https://www.google.com/maps/place/Club+Huis/@-6.7027857,106.9453741,17z/data=!3m1!4b1!4m6!3m5!1s0x2e69b679d7a09e01:0xf9fc2df396f09977!8m2!3d-6.7027857!4d106.947949!16s%2Fg%2F11c57lh8ky?entry=ttu#1#false Jl. Taman Safari No.101 . B Cibeureum Kec. Cisarua Club Huis https://www.google.com/maps/place/Club+Huis/@-6.7027857,106.9453741,17z/data=!3m1!4b1!4m6!3m5!1s0x2e69b679d7a09e01:0xf9fc2df396f09977!8m2!3d-6.7027857!4d106.947949!16s%2Fg%2F11c57lh8ky?entry=ttu recreation 1 https://media-cdn.tripadvisor.com/media/photo-o/0d/6a/5d/63/our-peaceful-backyard.jpg 3201 false 2026-04-12 23:50:04.608443 2026-04-12 23:50:04.608443 1
6 5 5#recreation#Desa Tambakrejo Kecamatan Sumbermanjing Wetan#Pulau Sempu#1#https://dynamic-media-cdn.tripadvisor.com/media/photo-o/11/3b/06/a5/pulau-sempu.jpg?w=500&h=-1&s=1#3507#https://www.google.com/maps/place/Pulau+Sempu/@-8.446621,112.6746143,14z/data=!3m1!4b1!4m6!3m5!1s0x2dd60120edbc901f:0x8efd89687a308993!8m2!3d-8.4428564!4d112.6973355!16s%2Fm%2F0r8k540?entry=ttu#1#false Desa Tambakrejo Kecamatan Sumbermanjing Wetan Pulau Sempu https://www.google.com/maps/place/Pulau+Sempu/@-8.446621,112.6746143,14z/data=!3m1!4b1!4m6!3m5!1s0x2dd60120edbc901f:0x8efd89687a308993!8m2!3d-8.4428564!4d112.6973355!16s%2Fm%2F0r8k540?entry=ttu recreation 1 https://dynamic-media-cdn.tripadvisor.com/media/photo-o/11/3b/06/a5/pulau-sempu.jpg?w=500&h=-1&s=1 3507 false 2026-04-12 23:50:04.608443 2026-04-12 23:50:04.608443 1
7 6 6#recreation#Jl. Bukit Golf I BSD Sektor VI Lengkong Karya Kec. Serpong Utara#Damai Indah Golf#1#https://lh3.googleusercontent.com/p/AF1QipN5Z-0J6vIfIO6gqPO0z5HDWlNKqp0t816XIJPS=s680-w500-h500#3674#https://www.google.com/maps/place/Damai+Indah+Golf+-+BSD+Course/@-6.2815644,106.6496566,17z/data=!3m1!4b1!4m6!3m5!1s0x2e69fb152983d973:0x89e58e219f8b93ef!8m2!3d-6.2815644!4d106.6522315!16s%2Fg%2F11c54c9r94?entry=ttu#1#false Jl. Bukit Golf I BSD Sektor VI Lengkong Karya Kec. Serpong Utara Damai Indah Golf https://www.google.com/maps/place/Damai+Indah+Golf+-+BSD+Course/@-6.2815644,106.6496566,17z/data=!3m1!4b1!4m6!3m5!1s0x2e69fb152983d973:0x89e58e219f8b93ef!8m2!3d-6.2815644!4d106.6522315!16s%2Fg%2F11c54c9r94?entry=ttu recreation 1 https://lh3.googleusercontent.com/p/AF1QipN5Z-0J6vIfIO6gqPO0z5HDWlNKqp0t816XIJPS=s680-w500-h500 3674 false 2026-04-12 23:50:04.608443 2026-04-12 23:50:04.608443 1
8 7 7#accommodation#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#false Jl. P. Mangkubumi No.72A Cokrodiningratan Kec. Jetis Hotel Tentrem Yogyakarta 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 accommodation 1 https://cdn.discordapp.com/attachments/743422487882104837/1150987888553623653/image.png 3471 false 2026-04-12 23:50:04.608443 2026-04-12 23:50:04.608443 1
9 8 8#recreation#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#false Moluo Kec.Kwandang Pulau Saronde Gorontalo 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 recreation 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 false 2026-04-12 23:50:04.608443 2026-04-12 23:50:04.608443 1
10 9 9#recreation#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#false Dusun Katiet Desa Bosua Kecamatan Sipora Pantai Katiet 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 recreation 1 https://dynamic-media-cdn.tripadvisor.com/media/photo-o/1a/d7/fe/f4/mentawai-islands.jpg?w=500&h=-1&s=1 1301 false 2026-04-12 23:50:04.608443 2026-04-12 23:50:04.608443 1
11 10 10#recreation#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#false Pulau Padar Pulau Padar 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 recreation 2 https://dynamic-media-cdn.tripadvisor.com/media/photo-o/18/4e/11/f3/padar-island.jpg?w=800&h=-1&s=1 5315 false 2026-04-12 23:50:04.608443 2026-04-12 23:50:04.608443 1
12 11 11#culinary#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#false Jl. Ahmad Yani 18, Kel. Kelimutu, Kec. Ende Tengah Sari rasa 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 culinary 3 https://cdn.discordapp.com/attachments/743422487882104837/1151903310295601172/image.png 5315 false 2026-04-12 23:50:04.608443 2026-04-12 23:50:04.608443 1
13 12 12#recreation#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#false Danau Sentani Danau Sentani 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 recreation 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 false 2026-04-12 23:50:04.608443 2026-04-12 23:50:04.608443 1
19 natohentoahe aosenhatohe aoeaoeaoe mall 4 1112 false 2026-06-01 09:19:04.996652 2026-06-01 09:19:04.996652 [{"Food & Beverages": ["Solaria", "J.CO Donuts", "Pizza Hut", "Chatime"]}, {"Fashion": ["Pull&Bear", "Nevada"]}, {"Sports": ["Reebok", "Puma", "Nike", "Mills"]}, {"Health & Beauty": ["The Body Shop", "Miniso", "Innisfree"]}]
20 aoeaoeaoeoae aoeaoe aoeaoeoaeaoe culinary 4 1118 false 2026-06-06 23:29:37.459913 2026-06-06 23:29:37.459913
21 aotehsnatohesntaho aoedhnaohesnth aoeaoeaoeaoeaoe culinary 4 1409 false 2026-06-11 12:52:23.675860 2026-06-11 12:52:23.675860 1 [{"Facilities": ["Live Music", "Outdoor Seating"]}, {"Services": ["Parking", "Takeout"]}, {"Food Options": ["Vegetarian", "Vegan"]}] [{"day": "Sunday", "closed": true}, {"day": "Monday", "closed": true}, {"day": "Tuesday", "open": "09:00", "close": "21:00"}, {"day": "Wednesday", "open": "09:00", "close": "21:00"}, {"day": "Thursday", "open": "09:00", "close": "21:00"}, {"day": "Friday", "open": "09:00", "close": "21:00"}, {"day": "Saturday", "open": "09:00", "close": "21:00"}]

View File

@ -338,21 +338,6 @@ func (mr *MockStoreMockRecorder) GetLocationLifetimeVisits(ctx, locationID any)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLocationLifetimeVisits", reflect.TypeOf((*MockStore)(nil).GetLocationLifetimeVisits), ctx, locationID)
}
// GetLocationReviewGrades mocks base method.
func (m *MockStore) GetLocationReviewGrades(ctx context.Context, locationID int32) (db.GetLocationReviewGradesRow, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetLocationReviewGrades", ctx, locationID)
ret0, _ := ret[0].(db.GetLocationReviewGradesRow)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetLocationReviewGrades indicates an expected call of GetLocationReviewGrades.
func (mr *MockStoreMockRecorder) GetLocationReviewGrades(ctx, locationID any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLocationReviewGrades", reflect.TypeOf((*MockStore)(nil).GetLocationReviewGrades), ctx, locationID)
}
// GetLocationTag mocks base method.
func (m *MockStore) GetLocationTag(ctx context.Context, targetID int32) ([]string, error) {
m.ctrl.T.Helper()

View File

@ -146,84 +146,6 @@ func (q *Queries) GetReviewByLocationAndId(ctx context.Context, arg GetReviewByL
return i, err
}
type GetLocationReviewGradesRow struct {
CriticAvgTasteGrade pgtype.Float8 `json:"critic_avg_taste_grade"`
CriticTasteGradeCount int64 `json:"critic_taste_grade_count"`
CriticAvgComfortGrade pgtype.Float8 `json:"critic_avg_comfort_grade"`
CriticComfortGradeCount int64 `json:"critic_comfort_grade_count"`
CriticAvgCleanlinessGrade pgtype.Float8 `json:"critic_avg_cleanliness_grade"`
CriticCleanlinessGradeCount int64 `json:"critic_cleanliness_grade_count"`
CriticAvgServiceGrade pgtype.Float8 `json:"critic_avg_service_grade"`
CriticServiceGradeCount int64 `json:"critic_service_grade_count"`
CriticAvgFacilitiesGrade pgtype.Float8 `json:"critic_avg_facilities_grade"`
CriticFacilitiesGradeCount int64 `json:"critic_facilities_grade_count"`
UserAvgTasteGrade pgtype.Float8 `json:"user_avg_taste_grade"`
UserTasteGradeCount int64 `json:"user_taste_grade_count"`
UserAvgComfortGrade pgtype.Float8 `json:"user_avg_comfort_grade"`
UserComfortGradeCount int64 `json:"user_comfort_grade_count"`
UserAvgCleanlinessGrade pgtype.Float8 `json:"user_avg_cleanliness_grade"`
UserCleanlinessGradeCount int64 `json:"user_cleanliness_grade_count"`
UserAvgServiceGrade pgtype.Float8 `json:"user_avg_service_grade"`
UserServiceGradeCount int64 `json:"user_service_grade_count"`
UserAvgFacilitiesGrade pgtype.Float8 `json:"user_avg_facilities_grade"`
UserFacilitiesGradeCount int64 `json:"user_facilities_grade_count"`
}
const getLocationReviewGrades = `
SELECT
AVG(re.taste_grade) FILTER (WHERE re.is_from_critic = true)::float8 AS critic_avg_taste_grade,
COUNT(re.taste_grade) FILTER (WHERE re.is_from_critic = true) AS critic_taste_grade_count,
AVG(re.comfort_grade) FILTER (WHERE re.is_from_critic = true)::float8 AS critic_avg_comfort_grade,
COUNT(re.comfort_grade) FILTER (WHERE re.is_from_critic = true) AS critic_comfort_grade_count,
AVG(re.cleanliness_grade) FILTER (WHERE re.is_from_critic = true)::float8 AS critic_avg_cleanliness_grade,
COUNT(re.cleanliness_grade) FILTER (WHERE re.is_from_critic = true) AS critic_cleanliness_grade_count,
AVG(re.service_grade) FILTER (WHERE re.is_from_critic = true)::float8 AS critic_avg_service_grade,
COUNT(re.service_grade) FILTER (WHERE re.is_from_critic = true) AS critic_service_grade_count,
AVG(re.facilities_grade) FILTER (WHERE re.is_from_critic = true)::float8 AS critic_avg_facilities_grade,
COUNT(re.facilities_grade) FILTER (WHERE re.is_from_critic = true) AS critic_facilities_grade_count,
AVG(re.taste_grade) FILTER (WHERE re.is_from_critic = false)::float8 AS user_avg_taste_grade,
COUNT(re.taste_grade) FILTER (WHERE re.is_from_critic = false) AS user_taste_grade_count,
AVG(re.comfort_grade) FILTER (WHERE re.is_from_critic = false)::float8 AS user_avg_comfort_grade,
COUNT(re.comfort_grade) FILTER (WHERE re.is_from_critic = false) AS user_comfort_grade_count,
AVG(re.cleanliness_grade) FILTER (WHERE re.is_from_critic = false)::float8 AS user_avg_cleanliness_grade,
COUNT(re.cleanliness_grade) FILTER (WHERE re.is_from_critic = false) AS user_cleanliness_grade_count,
AVG(re.service_grade) FILTER (WHERE re.is_from_critic = false)::float8 AS user_avg_service_grade,
COUNT(re.service_grade) FILTER (WHERE re.is_from_critic = false) AS user_service_grade_count,
AVG(re.facilities_grade) FILTER (WHERE re.is_from_critic = false)::float8 AS user_avg_facilities_grade,
COUNT(re.facilities_grade) FILTER (WHERE re.is_from_critic = false) AS user_facilities_grade_count
FROM reviews re
WHERE re.location_id = $1 AND re.is_hided = false;
`
func (q *Queries) GetLocationReviewGrades(ctx context.Context, locationID int32) (GetLocationReviewGradesRow, error) {
row := q.db.QueryRow(ctx, getLocationReviewGrades, locationID)
var i GetLocationReviewGradesRow
err := row.Scan(
&i.CriticAvgTasteGrade,
&i.CriticTasteGradeCount,
&i.CriticAvgComfortGrade,
&i.CriticComfortGradeCount,
&i.CriticAvgCleanlinessGrade,
&i.CriticCleanlinessGradeCount,
&i.CriticAvgServiceGrade,
&i.CriticServiceGradeCount,
&i.CriticAvgFacilitiesGrade,
&i.CriticFacilitiesGradeCount,
&i.UserAvgTasteGrade,
&i.UserTasteGradeCount,
&i.UserAvgComfortGrade,
&i.UserComfortGradeCount,
&i.UserAvgCleanlinessGrade,
&i.UserCleanlinessGradeCount,
&i.UserAvgServiceGrade,
&i.UserServiceGradeCount,
&i.UserAvgFacilitiesGrade,
&i.UserFacilitiesGradeCount,
)
return i, err
}
func (q *Queries) GetListLocationReviews(ctx context.Context, arg GetListLocationReviewsParams) ([]GetListLocationReviewsRow, error) {
rows, err := q.db.Query(ctx, getListLocationReviews, arg.LocationID, arg.IsCritics, arg.Limit, arg.Offset)
if err != nil {

View File

@ -29,7 +29,6 @@ type Store interface {
RecordLocationVisit(ctx context.Context, locationID int32) error
GetLocationLifetimeVisits(ctx context.Context, locationID int32) (int64, error)
GetTrendingLocations(ctx context.Context, arg GetTrendingLocationsParams) ([]GetTrendingLocationsRow, error)
GetLocationReviewGrades(ctx context.Context, locationID int32) (GetLocationReviewGradesRow, error)
}
type SQLStore struct {

View File

@ -258,88 +258,6 @@ const docTemplate = `{
}
}
},
"/location/{location_id}/reviews/grades": {
"get": {
"produces": [
"application/json"
],
"tags": [
"reviews"
],
"summary": "Get aggregated review grades for a location",
"parameters": [
{
"type": "integer",
"description": "Location ID",
"name": "location_id",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/api.getLocationReviewGradesRes"
}
},
"400": {
"description": "Bad Request",
"schema": {
"type": "object",
"additionalProperties": true
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"type": "object",
"additionalProperties": true
}
}
}
}
},
"/location/{location_id}/visit": {
"post": {
"description": "Increments today's visit bucket. A single client (IP) is rate-limited to one visit per location per 30 minutes via Redis to deter trivial F5 inflation.",
"produces": [
"application/json"
],
"tags": [
"locations"
],
"summary": "Record a page visit for a location",
"parameters": [
{
"type": "integer",
"description": "Location ID",
"name": "location_id",
"in": "path",
"required": true
}
],
"responses": {
"204": {
"description": "No Content"
},
"400": {
"description": "Bad Request",
"schema": {
"type": "object",
"additionalProperties": true
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"type": "object",
"additionalProperties": true
}
}
}
}
},
"/locations": {
"get": {
"produces": [
@ -438,12 +356,6 @@ const docTemplate = `{
"name": "amenities",
"in": "formData"
},
{
"type": "string",
"description": "Business hours JSON: [{\\",
"name": "business_hours",
"in": "formData"
},
{
"type": "string",
"description": "Google Maps link",
@ -624,104 +536,6 @@ const docTemplate = `{
}
}
},
"/locations/trending": {
"get": {
"description": "Ranks approved, non-deleted locations by total page-visits in the trailing window.",
"produces": [
"application/json"
],
"tags": [
"locations"
],
"summary": "Trending locations",
"parameters": [
{
"type": "string",
"description": "Window: week | month | 3month | semester | year",
"name": "window",
"in": "query",
"required": true
},
{
"type": "integer",
"description": "Page (min 1)",
"name": "page",
"in": "query",
"required": true
},
{
"type": "integer",
"description": "Page size (1-50)",
"name": "page_size",
"in": "query",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": true
}
}
},
"400": {
"description": "Bad Request",
"schema": {
"type": "object",
"additionalProperties": true
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"type": "object",
"additionalProperties": true
}
}
}
}
},
"/menu-items": {
"get": {
"produces": [
"application/json"
],
"tags": [
"menu"
],
"summary": "Get menu items",
"parameters": [
{
"type": "integer",
"description": "Filter by location ID (omit for all)",
"name": "location_id",
"in": "query"
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/db.GetMenuItemsRow"
}
}
},
"400": {
"description": "Bad Request",
"schema": {
"type": "object",
"additionalProperties": true
}
}
}
}
},
"/news-events": {
"get": {
"produces": [
@ -1373,84 +1187,6 @@ const docTemplate = `{
"type": "string"
}
}
},
"api.getLocationReviewGradesRes": {
"type": "object",
"properties": {
"critics_grades": {
"$ref": "#/definitions/api.locationReviewGradesGroup"
},
"users_grades": {
"$ref": "#/definitions/api.locationReviewGradesGroup"
}
}
},
"api.locationReviewGradesGroup": {
"type": "object",
"properties": {
"avg_cleanliness_grade": {
"type": "number"
},
"avg_comfort_grade": {
"type": "number"
},
"avg_facilities_grade": {
"type": "number"
},
"avg_service_grade": {
"type": "number"
},
"avg_taste_grade": {
"type": "number"
},
"cleanliness_grade_count": {
"type": "integer"
},
"comfort_grade_count": {
"type": "integer"
},
"facilities_grade_count": {
"type": "integer"
},
"service_grade_count": {
"type": "integer"
},
"taste_grade_count": {
"type": "integer"
}
}
},
"db.GetMenuItemsRow": {
"type": "object",
"properties": {
"avg_score": {
"type": "number"
},
"category": {
"type": "string"
},
"description": {
"type": "string"
},
"id": {
"type": "integer"
},
"is_available": {
"type": "boolean"
},
"location_id": {
"type": "integer"
},
"name": {
"type": "string"
},
"price": {
"type": "integer"
},
"submitted_by": {
"type": "integer"
}
}
}
},
"securityDefinitions": {

View File

@ -252,88 +252,6 @@
}
}
},
"/location/{location_id}/reviews/grades": {
"get": {
"produces": [
"application/json"
],
"tags": [
"reviews"
],
"summary": "Get aggregated review grades for a location",
"parameters": [
{
"type": "integer",
"description": "Location ID",
"name": "location_id",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/api.getLocationReviewGradesRes"
}
},
"400": {
"description": "Bad Request",
"schema": {
"type": "object",
"additionalProperties": true
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"type": "object",
"additionalProperties": true
}
}
}
}
},
"/location/{location_id}/visit": {
"post": {
"description": "Increments today's visit bucket. A single client (IP) is rate-limited to one visit per location per 30 minutes via Redis to deter trivial F5 inflation.",
"produces": [
"application/json"
],
"tags": [
"locations"
],
"summary": "Record a page visit for a location",
"parameters": [
{
"type": "integer",
"description": "Location ID",
"name": "location_id",
"in": "path",
"required": true
}
],
"responses": {
"204": {
"description": "No Content"
},
"400": {
"description": "Bad Request",
"schema": {
"type": "object",
"additionalProperties": true
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"type": "object",
"additionalProperties": true
}
}
}
}
},
"/locations": {
"get": {
"produces": [
@ -432,12 +350,6 @@
"name": "amenities",
"in": "formData"
},
{
"type": "string",
"description": "Business hours JSON: [{\\",
"name": "business_hours",
"in": "formData"
},
{
"type": "string",
"description": "Google Maps link",
@ -618,104 +530,6 @@
}
}
},
"/locations/trending": {
"get": {
"description": "Ranks approved, non-deleted locations by total page-visits in the trailing window.",
"produces": [
"application/json"
],
"tags": [
"locations"
],
"summary": "Trending locations",
"parameters": [
{
"type": "string",
"description": "Window: week | month | 3month | semester | year",
"name": "window",
"in": "query",
"required": true
},
{
"type": "integer",
"description": "Page (min 1)",
"name": "page",
"in": "query",
"required": true
},
{
"type": "integer",
"description": "Page size (1-50)",
"name": "page_size",
"in": "query",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": true
}
}
},
"400": {
"description": "Bad Request",
"schema": {
"type": "object",
"additionalProperties": true
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"type": "object",
"additionalProperties": true
}
}
}
}
},
"/menu-items": {
"get": {
"produces": [
"application/json"
],
"tags": [
"menu"
],
"summary": "Get menu items",
"parameters": [
{
"type": "integer",
"description": "Filter by location ID (omit for all)",
"name": "location_id",
"in": "query"
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/db.GetMenuItemsRow"
}
}
},
"400": {
"description": "Bad Request",
"schema": {
"type": "object",
"additionalProperties": true
}
}
}
}
},
"/news-events": {
"get": {
"produces": [
@ -1367,84 +1181,6 @@
"type": "string"
}
}
},
"api.getLocationReviewGradesRes": {
"type": "object",
"properties": {
"critics_grades": {
"$ref": "#/definitions/api.locationReviewGradesGroup"
},
"users_grades": {
"$ref": "#/definitions/api.locationReviewGradesGroup"
}
}
},
"api.locationReviewGradesGroup": {
"type": "object",
"properties": {
"avg_cleanliness_grade": {
"type": "number"
},
"avg_comfort_grade": {
"type": "number"
},
"avg_facilities_grade": {
"type": "number"
},
"avg_service_grade": {
"type": "number"
},
"avg_taste_grade": {
"type": "number"
},
"cleanliness_grade_count": {
"type": "integer"
},
"comfort_grade_count": {
"type": "integer"
},
"facilities_grade_count": {
"type": "integer"
},
"service_grade_count": {
"type": "integer"
},
"taste_grade_count": {
"type": "integer"
}
}
},
"db.GetMenuItemsRow": {
"type": "object",
"properties": {
"avg_score": {
"type": "number"
},
"category": {
"type": "string"
},
"description": {
"type": "string"
},
"id": {
"type": "integer"
},
"is_available": {
"type": "boolean"
},
"location_id": {
"type": "integer"
},
"name": {
"type": "string"
},
"price": {
"type": "integer"
},
"submitted_by": {
"type": "integer"
}
}
}
},
"securityDefinitions": {

View File

@ -58,57 +58,6 @@ definitions:
- password
- username
type: object
api.getLocationReviewGradesRes:
properties:
critics_grades:
$ref: '#/definitions/api.locationReviewGradesGroup'
users_grades:
$ref: '#/definitions/api.locationReviewGradesGroup'
type: object
api.locationReviewGradesGroup:
properties:
avg_cleanliness_grade:
type: number
avg_comfort_grade:
type: number
avg_facilities_grade:
type: number
avg_service_grade:
type: number
avg_taste_grade:
type: number
cleanliness_grade_count:
type: integer
comfort_grade_count:
type: integer
facilities_grade_count:
type: integer
service_grade_count:
type: integer
taste_grade_count:
type: integer
type: object
db.GetMenuItemsRow:
properties:
avg_score:
type: number
category:
type: string
description:
type: string
id:
type: integer
is_available:
type: boolean
location_id:
type: integer
name:
type: string
price:
type: integer
submitted_by:
type: integer
type: object
host: localhost:8888
info:
contact: {}
@ -215,62 +164,6 @@ paths:
summary: Get a single review
tags:
- reviews
/location/{location_id}/reviews/grades:
get:
parameters:
- description: Location ID
in: path
name: location_id
required: true
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/api.getLocationReviewGradesRes'
"400":
description: Bad Request
schema:
additionalProperties: true
type: object
"500":
description: Internal Server Error
schema:
additionalProperties: true
type: object
summary: Get aggregated review grades for a location
tags:
- reviews
/location/{location_id}/visit:
post:
description: Increments today's visit bucket. A single client (IP) is rate-limited
to one visit per location per 30 minutes via Redis to deter trivial F5 inflation.
parameters:
- description: Location ID
in: path
name: location_id
required: true
type: integer
produces:
- application/json
responses:
"204":
description: No Content
"400":
description: Bad Request
schema:
additionalProperties: true
type: object
"500":
description: Internal Server Error
schema:
additionalProperties: true
type: object
summary: Record a page visit for a location
tags:
- locations
/location/reviews:
get:
parameters:
@ -400,10 +293,6 @@ paths:
in: formData
name: amenities
type: string
- description: 'Business hours JSON: [{\'
in: formData
name: business_hours
type: string
- description: Google Maps link
in: formData
name: google_maps_link
@ -527,73 +416,6 @@ paths:
summary: Top-rated locations
tags:
- locations
/locations/trending:
get:
description: Ranks approved, non-deleted locations by total page-visits in the
trailing window.
parameters:
- description: 'Window: week | month | 3month | semester | year'
in: query
name: window
required: true
type: string
- description: Page (min 1)
in: query
name: page
required: true
type: integer
- description: Page size (1-50)
in: query
name: page_size
required: true
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
items:
additionalProperties: true
type: object
type: array
"400":
description: Bad Request
schema:
additionalProperties: true
type: object
"500":
description: Internal Server Error
schema:
additionalProperties: true
type: object
summary: Trending locations
tags:
- locations
/menu-items:
get:
parameters:
- description: Filter by location ID (omit for all)
in: query
name: location_id
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
items:
$ref: '#/definitions/db.GetMenuItemsRow'
type: array
"400":
description: Bad Request
schema:
additionalProperties: true
type: object
summary: Get menu items
tags:
- menu
/news-events:
get:
parameters: