package api import ( "encoding/json" "fmt" "net/http" "regexp" "slices" "strings" "time" "github.com/maximotejeda/us_dop_api/domain" "github.com/maximotejeda/us_dop_api/helpers" ) // handler to parse query to the api func (api *API) GetInstitutionHistory(w http.ResponseWriter, r *http.Request) { var ( timeSearch time.Duration historyResult []*domain.History ) err := r.ParseForm() if err != nil { api.log.Error("parsing form ", "error", err) http.Error(w, "parsing form", http.StatusNotFound) } queryP := r.Form timeAmount := queryP.Get("ta") // numeric amount timeFrame := queryP.Get("tf") // minute, hour, day, week, month, now ago until now resType := queryP.Get("format") // can be multiples html or a json inst := queryP.Get("name") resource := queryP.Get("res") inst = strings.ToLower(inst) // match time amount number re := regexp.MustCompile(`[0-9]{1,3}`) // api.log.Info("parsing inst", "name", inst) if timeFrame != "now" { if !re.Match([]byte(timeAmount)) { api.log.Error("matching time", "error", "incorrect time amount") http.Error(w, "incorrect time amount", http.StatusNotFound) return } } timeSearch, err = helpers.ParseTimeAmount(timeFrame, timeAmount) if err != nil { api.log.Error("parsing time ", "error", err) http.Error(w, "incorrect time amount", http.StatusNotFound) return } if timeFrame == "now" { hist, err := api.dolar.GetLatest(inst) //hist, err := api.db.GetLastPrice(inst) if err != nil { api.log.Error("GetLastPrice", "time Frame", "now", "error", err) http.Error(w, "price not found", http.StatusNotFound) return } historyResult = append(historyResult, hist) } else { historyResult, err = api.dolar.GetSince(inst, int64(timeSearch.Minutes())) //historyResult, err = api.db.GetChangeSince(inst, timeSearch) if err != nil { api.log.Error("GetLastPrice", "time Frame", timeFrame, "amount", timeAmount, "error", err) http.Error(w, "price not found for time frame", http.StatusNotFound) return } api.log.Info("resultados", "=", historyResult) } searchRes := SearchResult{ InstRequested: inst, Date: time.Now(), TimeAmount: timeAmount, TimeFrame: timeFrame, Results: historyResult, } // check if we want a json if resType == "html" { switch resource { case "card": err = api.templ.ExecuteTemplate(w, "card-history", searchRes) case "list": // by default we crate simple query // we need a way to distinguish from mixed or more complex query err = api.templ.ExecuteTemplate(w, "list-history", searchRes) case "table": // by default we crate simple query // we need a way to distinguish from mixed or more complex query err = api.templ.ExecuteTemplate(w, "table-history", searchRes) } if err != nil { api.log.Error("History", "error", err) http.Error(w, "history error", http.StatusNotFound) } } else { data, _ := json.Marshal(searchRes) w.Write(data) } } // GetBanks // as bank will only return a list of names // we can assume we need a list of some html to the app func (api *API) GetInstNames(w http.ResponseWriter, r *http.Request) { queryP := r.URL.Query() fType := queryP.Get("format") resource := queryP.Get("res") inst := r.PathValue("inst") w.Header().Set("Etag", "institutions") w.Header().Set("Cache-Control", "max-age=3600") var institutions, err = []string{}, *new(error) switch inst { case "bancos", "banco": inst = "bancos" institutions, err = api.dolar.GetInstByType("bancos") case "caja", "cajas": inst = "cajas" institutions, err = api.dolar.GetInstByType("cajas") case "agente", "agentes": inst = "agentes" institutions, err = api.dolar.GetInstByType("agentes") case "all": bancos, _ := api.dolar.GetInstByType("bancos") cajas, _ := api.dolar.GetInstByType("cajas") agentes, _ := api.dolar.GetInstByType("agentes") inst = "all" institutions = slices.Concat(bancos, cajas, agentes) default: http.NotFound(w, r) return } if err != nil { api.log.Error("GetInstName", "error", err) http.Error(w, "", http.StatusNotFound) } searchResult := SearchResult{ InstRequested: inst, Date: time.Now(), TimeAmount: "none", TimeFrame: "none", } removeDup := map[string]int{} res := []string{} for _, val := range institutions { removeDup[val]++ if removeDup[val] == 1 { res = append(res, val) } } for _, banco := range res { inst := domain.History{} inst.Institution.Name = banco searchResult.Results = append(searchResult.Results, &inst) } api.log.Info("institutions", "list", res) if fType == "html" { switch resource { case "card": err = api.templ.ExecuteTemplate(w, "card", searchResult) case "list": // by default we crate simple query // we need a way to distinguish from mixed or more complex query err = api.templ.ExecuteTemplate(w, "list", searchResult) } if err != nil { api.log.Error("rendering institucion", "tipo", inst, "error", err) } } else { dat, err := json.Marshal(searchResult) if err != nil { fmt.Println(err) } w.Write(dat) } } func (api *API) GetLatestPrice(w http.ResponseWriter, r *http.Request) { inst := r.PathValue("inst") if inst == "" { http.Error(w, "no inst in request", http.StatusNotFound) } price, err := api.dolar.GetLatest(inst) if err != nil { api.log.Error("geting latest price", "error", err) http.NotFound(w, r) } api.templ.ExecuteTemplate(w, "latest-price", price) } func (api *API) GetAllLatestPrice(w http.ResponseWriter, r *http.Request) { bancos, err := api.dolar.GetInstByType("bancos") if err != nil { api.log.Error("geting inst", "error", err) http.NotFound(w, r) } cajas, err := api.dolar.GetInstByType("cajas") if err != nil { api.log.Error("geting inst cajas", "error", err) http.NotFound(w, r) } agentes, err := api.dolar.GetInstByType("agentes") if err != nil { api.log.Error("geting inst agentes", "error", err) http.NotFound(w, r) } instLastPriceList := []*domain.History{} for _, inst := range slices.Concat(bancos, cajas, agentes) { in, err := api.dolar.GetLatest(inst) if err != nil { api.log.Error("geting last price", "error", err) continue } instLastPriceList = append(instLastPriceList, in) } api.templ.ExecuteTemplate(w, "latest-price", instLastPriceList) }