Files
mule-image/sidecar/handlers_countries.go
dtoro ba5684d120 feat(countries): replace Map view with browse-by-country (like Tags)
Removes the maplibre-gl Map view and adds "Countries" as a sixth
TagCategory, reusing the existing /tags/[category]/[[value]] browse
machinery instead of a bespoke map UI. Backed by a new self-contained
sidecar endpoint that aggregates photos.photo_country with BasePath
scoping, mirroring handleLabels/handleScopedCounts.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-06-30 21:25:24 +02:00

71 lines
2.0 KiB
Go

package main
import (
"net/http"
"github.com/gin-gonic/gin"
"gorm.io/gorm"
)
// PpCountry is the country aggregation row returned to the client: a
// 2-letter ISO 3166-1 code, the user-scoped photo count, and a representative
// thumb hash for the sidebar row.
type PpCountry struct {
Code string `json:"Code"`
PhotoCount int `json:"PhotoCount"`
Thumb string `json:"Thumb"`
}
// handleCountries aggregates photos.photo_country directly against
// PhotoPrism's DB (no upstream proxy needed — this is a simple GROUP BY)
// and scopes the result to the caller's BasePath, mirroring handleLabels.
//
// Route: GET /api/sidecar/countries (behind requireSession, ppDb != nil)
func handleCountries(ppDb *gorm.DB) gin.HandlerFunc {
return func(c *gin.Context) {
basePath := ctxBasePath(c)
type countryStat struct {
Code string `gorm:"column:code"`
Cnt int64 `gorm:"column:cnt"`
ThumbHash string `gorm:"column:thumb_hash"`
}
var stats []countryStat
query := ppDb.Table("photos p").
Select(`p.photo_country AS code,
COUNT(DISTINCT p.id) AS cnt,
COALESCE(MIN(f.file_hash), '') AS thumb_hash`).
Joins(`LEFT JOIN files f ON f.photo_uid = p.photo_uid
AND f.file_primary = 1
AND f.file_missing = 0`).
Where("p.deleted_at IS NULL").
Where("p.photo_country != '' AND p.photo_country != 'zz'")
if basePath != "" {
prefix := basePath + "/%"
query = query.Where("(p.photo_path = ? OR p.photo_path LIKE ?)", basePath, prefix)
}
if err := query.
Group("p.photo_country").
Having("cnt > 0").
Order("cnt DESC").
Scan(&stats).Error; err != nil {
c.JSON(http.StatusBadGateway, gin.H{"error": "country stats query failed"})
return
}
out := make([]PpCountry, 0, len(stats))
for _, s := range stats {
out = append(out, PpCountry{
Code: s.Code,
PhotoCount: int(s.Cnt),
Thumb: s.ThumbHash,
})
}
c.JSON(http.StatusOK, out)
}
}