Files
mira/backend/internal/calendar/provider.go
Cauê Faleiros 8c7e5fbbe4
All checks were successful
CI / backend (push) Successful in 13m19s
CI / frontend (push) Successful in 11m3s
CI / docker (push) Successful in 1m58s
first commit
2026-06-03 16:31:42 -03:00

137 lines
3.2 KiB
Go

package calendar
import (
"context"
"encoding/json"
"fmt"
"net/http"
"strings"
"time"
)
type Holiday struct {
Date string `json:"date"`
Name string `json:"name"`
Type string `json:"type"`
}
type Provider interface {
NationalHolidays(ctx context.Context, year int) ([]Holiday, error)
}
type CommemorativeProvider interface {
CommemorativeDates(ctx context.Context, year int) ([]ExternalCommemorativeDate, error)
}
type ExternalCommemorativeDate struct {
Date string
Name string
Description string
SourceID string
}
type BrasilAPIProvider struct {
baseURL string
client *http.Client
}
type FeriadosBrasilProvider struct {
baseURL string
client *http.Client
}
func NewFeriadosBrasilProvider() FeriadosBrasilProvider {
return FeriadosBrasilProvider{
baseURL: "https://raw.githubusercontent.com/joaopbini/feriados-brasil/master/dados/comemorativas/json",
client: &http.Client{
Timeout: 10 * time.Second,
},
}
}
type feriadosBrasilCommemorativeDate struct {
ID string `json:"id"`
Data string `json:"data"`
Nome string `json:"nome"`
Tipo string `json:"tipo"`
Descricao string `json:"descricao"`
UF string `json:"uf"`
CodigoIBGE *int `json:"codigo_ibge"`
}
func (p FeriadosBrasilProvider) CommemorativeDates(ctx context.Context, year int) ([]ExternalCommemorativeDate, error) {
url := fmt.Sprintf("%s/%d.json", p.baseURL, year)
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
if err != nil {
return nil, err
}
resp, err := p.client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("feriados-brasil returned status %d", resp.StatusCode)
}
var records []feriadosBrasilCommemorativeDate
if err := json.NewDecoder(resp.Body).Decode(&records); err != nil {
return nil, err
}
dates := make([]ExternalCommemorativeDate, 0, len(records))
for _, record := range records {
if strings.ToUpper(strings.TrimSpace(record.Tipo)) != "COMEMORATIVA" {
continue
}
parsed, err := time.Parse("02/01/2006", strings.TrimSpace(record.Data))
if err != nil {
continue
}
dates = append(dates, ExternalCommemorativeDate{
Date: parsed.Format("2006-01-02"),
Name: strings.TrimSpace(record.Nome),
Description: strings.TrimSpace(record.Descricao),
SourceID: strings.TrimSpace(record.ID),
})
}
return dates, nil
}
func NewBrasilAPIProvider(baseURL string) BrasilAPIProvider {
return BrasilAPIProvider{
baseURL: baseURL,
client: &http.Client{
Timeout: 10 * time.Second,
},
}
}
func (p BrasilAPIProvider) NationalHolidays(ctx context.Context, year int) ([]Holiday, error) {
url := fmt.Sprintf("%s/api/feriados/v1/%d", p.baseURL, year)
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
if err != nil {
return nil, err
}
resp, err := p.client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("brasilapi returned status %d", resp.StatusCode)
}
var holidays []Holiday
if err := json.NewDecoder(resp.Body).Decode(&holidays); err != nil {
return nil, err
}
return holidays, nil
}