feat(api): Add compatibility layer for API v1

This commit is contained in:
2026-02-22 18:39:14 +03:00
parent 82f252f32f
commit ad1a9364b8
6 changed files with 8624 additions and 10 deletions
+102 -2
View File
@@ -26,8 +26,9 @@ type httpError struct {
}
type Services struct {
PrayerProvider PrayerProvider
LocationProvider LocationProvider
PrayerProvider PrayerProvider
LocationProvider LocationProvider
LegacyLocationProvider LegacyLocationProvider
}
type PrayerProvider interface {
@@ -40,6 +41,11 @@ type LocationProvider interface {
SearchLocationsByCoords(ctx context.Context, coords prayer.Coordinates) ([]prayer.Location, error)
}
type LegacyLocationProvider interface {
SearchLocations(ctx context.Context, query string) ([]prayer.LegacyLocation, error)
GetLocationByID(ctx context.Context, id int) (prayer.LegacyLocation, error)
}
func New(services Services) *fiber.App {
app := fiber.New(fiber.Config{
Immutable: true,
@@ -192,6 +198,74 @@ func New(services Services) *fiber.App {
})
})
app.Get("/api/diyanet/search", func(ctx fiber.Ctx) error {
q := strings.TrimSpace(ctx.Query("q"))
if q == "" {
return fmt.Errorf("missing query parameter q: %w", fiber.ErrBadRequest)
}
locations, err := services.LegacyLocationProvider.SearchLocations(ctx.Context(), q)
if err != nil {
return fmt.Errorf("failed to search legacy diyanet locations: %w", err)
}
resp := make([]fiber.Map, 0, len(locations))
for _, location := range locations {
resp = append(resp, fiber.Map{
"id": location.ID,
"country": location.Country,
"city": location.City,
"region": location.Region,
})
}
ctx.Response().Header.Set(fiber.HeaderCacheControl, "max-age=86400")
return ctx.JSON(resp)
})
app.Get("/api/diyanet/prayertimes", func(ctx fiber.Ctx) error {
if services.LegacyLocationProvider == nil {
return fmt.Errorf("legacy location provider is not configured: %w", fiber.ErrNotFound)
}
locationIDText := strings.TrimSpace(ctx.Query("location_id"))
if locationIDText == "" {
return fmt.Errorf("missing query parameter location_id: %w", fiber.ErrBadRequest)
}
locationID, err := strconv.Atoi(locationIDText)
if err != nil {
return fmt.Errorf("failed to parse location_id query parameter: %w", errors.Join(fiber.ErrBadRequest, err))
}
legacyLocation, err := services.LegacyLocationProvider.GetLocationByID(ctx.Context(), locationID)
if err != nil {
return fmt.Errorf("failed to resolve location by location_id: %w", errors.Join(fiber.ErrNotFound, err))
}
result, err := services.PrayerProvider.GetByCoords(ctx.Context(), prayer.Coordinates{
Latitude: legacyLocation.Latitude,
Longitude: legacyLocation.Longitude,
})
if err != nil {
return fmt.Errorf("failed to fetch prayer times for location_id: %w", err)
}
location := result.Location
location.ID = legacyLocation.ID
if strings.TrimSpace(legacyLocation.Timezone) != "" {
location.Timezone = legacyLocation.Timezone
}
mapped, err := mapPrayerTimesForLegacyResponse(result.Times, location)
if err != nil {
return fmt.Errorf("failed to map legacy prayer times response: %w", err)
}
ctx.Response().Header.Set(fiber.HeaderCacheControl, "max-age=86400")
return ctx.JSON(mapped)
})
app.Use("/", static.New("", static.Config{FS: templates.FS()}))
return app
@@ -293,3 +367,29 @@ func loadTimezone(name string) (*time.Location, error) {
return loc, nil
}
func mapPrayerTimesForLegacyResponse(times []prayer.Times, location prayer.Location) ([]fiber.Map, error) {
tz := time.UTC
if strings.TrimSpace(location.Timezone) != "" {
loadedTZ, err := loadTimezone(location.Timezone)
if err != nil {
return nil, fmt.Errorf("failed to load location timezone: %w", err)
}
tz = loadedTZ
}
out := make([]fiber.Map, 0, len(times))
for _, item := range times {
out = append(out, fiber.Map{
"date": item.Date.In(tz).Format(time.RFC3339),
"fajr": formatHHMM(item.Fajr, tz),
"sun": formatHHMM(item.Sunrise, tz),
"dhuhr": formatHHMM(item.Dhuhr, tz),
"asr": formatHHMM(item.Asr, tz),
"maghrib": formatHHMM(item.Maghrib, tz),
"isha": formatHHMM(item.Isha, tz),
})
}
return out, nil
}