mirror of
https://github.com/taigrr/wtf
synced 2025-01-18 04:03:14 -08:00
[modules] Add new covid tracker module (#1037)
* Add draft of covid module * Work on pointers * Add country stats * Remove recovered, stays at 0 * Handle response code * One struct for both * List of countries * Add test * Add test for countries * Fix typos * Format numbers based on language/locale
This commit is contained in:
parent
d7da659b8b
commit
2f2df04478
@ -13,6 +13,7 @@ import (
|
|||||||
"github.com/wtfutil/wtf/modules/circleci"
|
"github.com/wtfutil/wtf/modules/circleci"
|
||||||
"github.com/wtfutil/wtf/modules/clocks"
|
"github.com/wtfutil/wtf/modules/clocks"
|
||||||
"github.com/wtfutil/wtf/modules/cmdrunner"
|
"github.com/wtfutil/wtf/modules/cmdrunner"
|
||||||
|
"github.com/wtfutil/wtf/modules/covid"
|
||||||
"github.com/wtfutil/wtf/modules/cryptoexchanges/bittrex"
|
"github.com/wtfutil/wtf/modules/cryptoexchanges/bittrex"
|
||||||
"github.com/wtfutil/wtf/modules/cryptoexchanges/blockfolio"
|
"github.com/wtfutil/wtf/modules/cryptoexchanges/blockfolio"
|
||||||
"github.com/wtfutil/wtf/modules/cryptoexchanges/cryptolive"
|
"github.com/wtfutil/wtf/modules/cryptoexchanges/cryptolive"
|
||||||
@ -137,6 +138,9 @@ func MakeWidget(
|
|||||||
case "clocks":
|
case "clocks":
|
||||||
settings := clocks.NewSettingsFromYAML(moduleName, moduleConfig, config)
|
settings := clocks.NewSettingsFromYAML(moduleName, moduleConfig, config)
|
||||||
widget = clocks.NewWidget(tviewApp, settings)
|
widget = clocks.NewWidget(tviewApp, settings)
|
||||||
|
case "covid":
|
||||||
|
settings := covid.NewSettingsFromYAML(moduleName, moduleConfig, config)
|
||||||
|
widget = covid.NewWidget(tviewApp, settings)
|
||||||
case "cmdrunner":
|
case "cmdrunner":
|
||||||
settings := cmdrunner.NewSettingsFromYAML(moduleName, moduleConfig, config)
|
settings := cmdrunner.NewSettingsFromYAML(moduleName, moduleConfig, config)
|
||||||
widget = cmdrunner.NewWidget(tviewApp, settings)
|
widget = cmdrunner.NewWidget(tviewApp, settings)
|
||||||
|
14
modules/covid/cases.go
Normal file
14
modules/covid/cases.go
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
package covid
|
||||||
|
|
||||||
|
// Cases holds the latest cases
|
||||||
|
type Cases struct {
|
||||||
|
Latest Latest `json:"latest"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Latest holds the number of global confirmed cases and deaths due to Covid
|
||||||
|
type Latest struct {
|
||||||
|
Confirmed int `json:"confirmed"`
|
||||||
|
Deaths int `json:"deaths"`
|
||||||
|
// Not currently used but holds information about the country
|
||||||
|
Locations []interface{} `json:"locations,omitempty"`
|
||||||
|
}
|
58
modules/covid/client.go
Normal file
58
modules/covid/client.go
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
package covid
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/wtfutil/wtf/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
const covidTrackerAPIURL = "https://coronavirus-tracker-api.herokuapp.com/v2/"
|
||||||
|
|
||||||
|
// LatestCases queries the /latest endpoint, does not take any query parameters
|
||||||
|
func LatestCases() (*Cases, error) {
|
||||||
|
latestURL := covidTrackerAPIURL + "latest"
|
||||||
|
resp, err := http.Get(latestURL)
|
||||||
|
if resp.StatusCode != 200 {
|
||||||
|
return nil, fmt.Errorf(resp.Status)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer func() { _ = resp.Body.Close() }()
|
||||||
|
|
||||||
|
var latestGlobalCases Cases
|
||||||
|
err = utils.ParseJSON(&latestGlobalCases, resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &latestGlobalCases, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// LatestCountryCases queries the /locations endpoint, takes a query parameter: the country code
|
||||||
|
func (widget *Widget) LatestCountryCases(countries []interface{}) ([]*Cases, error) {
|
||||||
|
countriesCovidData := []*Cases{}
|
||||||
|
for _, name := range countries {
|
||||||
|
countryURL := covidTrackerAPIURL + "locations?source=jhu&country_code=" + name.(string)
|
||||||
|
resp, err := http.Get(countryURL)
|
||||||
|
if resp.StatusCode != 200 {
|
||||||
|
return nil, fmt.Errorf(resp.Status)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer func() { _ = resp.Body.Close() }()
|
||||||
|
|
||||||
|
var latestCountryCases Cases
|
||||||
|
err = utils.ParseJSON(&latestCountryCases, resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// add stats for each country to the slice
|
||||||
|
countriesCovidData = append(countriesCovidData, &latestCountryCases)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return countriesCovidData, nil
|
||||||
|
}
|
31
modules/covid/client_test.go
Normal file
31
modules/covid/client_test.go
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
package covid
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestLatestCases(t *testing.T) {
|
||||||
|
latestCasesToAssert, err := LatestCases()
|
||||||
|
if err != nil {
|
||||||
|
t.Error("LatestCases() returned an error")
|
||||||
|
}
|
||||||
|
if latestCasesToAssert.Latest.Confirmed == 0 {
|
||||||
|
t.Error("LatestCases() should return a non 0 integer")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (widget *Widget) TestCountryCases(t *testing.T) {
|
||||||
|
countryList := []string{"US", "FR"}
|
||||||
|
c := make([]interface{}, len(countryList))
|
||||||
|
for i, v := range countryList {
|
||||||
|
c[i] = v
|
||||||
|
}
|
||||||
|
latestCountryCasesToAssert, err := widget.LatestCountryCases(c)
|
||||||
|
if err != nil {
|
||||||
|
t.Error("LatestCountryCases() returned an error")
|
||||||
|
}
|
||||||
|
if len(latestCountryCasesToAssert) == 0 {
|
||||||
|
t.Error("LatestCountryCases() should not be empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
31
modules/covid/settings.go
Normal file
31
modules/covid/settings.go
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
package covid
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/olebedev/config"
|
||||||
|
"github.com/wtfutil/wtf/cfg"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
defaultFocusable = false
|
||||||
|
defaultTitle = "Covid tracker"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Settings is the struct for this module's settings
|
||||||
|
type Settings struct {
|
||||||
|
*cfg.Common
|
||||||
|
|
||||||
|
countries []interface{} `help:"Countries (codes) from which to retrieve stats."`
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewSettingsFromYAML returns the settings from the config yaml file
|
||||||
|
func NewSettingsFromYAML(name string, ymlConfig *config.Config, globalConfig *config.Config) *Settings {
|
||||||
|
|
||||||
|
settings := Settings{
|
||||||
|
Common: cfg.NewCommonSettingsFromModule(name, defaultTitle, defaultFocusable, ymlConfig, globalConfig),
|
||||||
|
|
||||||
|
// List of countries to retrieve stats from
|
||||||
|
countries: ymlConfig.UList("countries"),
|
||||||
|
}
|
||||||
|
|
||||||
|
return &settings
|
||||||
|
}
|
87
modules/covid/widget.go
Normal file
87
modules/covid/widget.go
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
package covid
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/rivo/tview"
|
||||||
|
"github.com/wtfutil/wtf/view"
|
||||||
|
|
||||||
|
"golang.org/x/text/language"
|
||||||
|
"golang.org/x/text/message"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Widget is the struct that defines this module widget
|
||||||
|
type Widget struct {
|
||||||
|
view.TextWidget
|
||||||
|
|
||||||
|
settings *Settings
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewWidget creates a new widget for this module
|
||||||
|
func NewWidget(app *tview.Application, settings *Settings) *Widget {
|
||||||
|
widget := &Widget{
|
||||||
|
TextWidget: view.NewTextWidget(app, nil, settings.Common),
|
||||||
|
|
||||||
|
settings: settings,
|
||||||
|
}
|
||||||
|
|
||||||
|
widget.View.SetScrollable(true)
|
||||||
|
|
||||||
|
return widget
|
||||||
|
}
|
||||||
|
|
||||||
|
// Refresh checks if this module widget is disabled
|
||||||
|
func (widget *Widget) Refresh() {
|
||||||
|
if widget.Disabled() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
widget.Redraw(widget.content)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render renders this module widget
|
||||||
|
func (widget *Widget) Render() {
|
||||||
|
widget.Redraw(widget.content)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Display stats based on the user's locale
|
||||||
|
func (widget *Widget) displayStats(cases int) string {
|
||||||
|
prntr := message.NewPrinter(language.English)
|
||||||
|
str := fmt.Sprintf("%s", prntr.Sprintf("%d", cases))
|
||||||
|
|
||||||
|
return str
|
||||||
|
}
|
||||||
|
|
||||||
|
func (widget *Widget) content() (string, string, bool) {
|
||||||
|
title := defaultTitle
|
||||||
|
if widget.CommonSettings().Title != "" {
|
||||||
|
title = widget.CommonSettings().Title
|
||||||
|
}
|
||||||
|
|
||||||
|
cases, err := LatestCases()
|
||||||
|
var covidStats string
|
||||||
|
if err != nil {
|
||||||
|
widget.err = err
|
||||||
|
} else {
|
||||||
|
// Display global stats
|
||||||
|
covidStats = fmt.Sprintf("[%s]Global[white]\n", widget.settings.Colors.Subheading)
|
||||||
|
covidStats += fmt.Sprintf("%s: %s\n", "Confirmed", widget.displayStats(cases.Latest.Confirmed))
|
||||||
|
covidStats += fmt.Sprintf("%s: %s\n", "Deaths", widget.displayStats(cases.Latest.Deaths))
|
||||||
|
}
|
||||||
|
// Retrieve country stats if country codes are set in the config
|
||||||
|
if len(widget.settings.countries) > 0 {
|
||||||
|
countryCases, err := widget.LatestCountryCases(widget.settings.countries)
|
||||||
|
if err != nil {
|
||||||
|
widget.err = err
|
||||||
|
} else {
|
||||||
|
for i, name := range countryCases {
|
||||||
|
covidStats += fmt.Sprintf("[%s]Country[white]: %s\n", widget.settings.Colors.Subheading, widget.settings.countries[i])
|
||||||
|
covidStats += fmt.Sprintf("%s: %s\n", "Confirmed", widget.displayStats(name.Latest.Confirmed))
|
||||||
|
covidStats += fmt.Sprintf("%s: %s\n", "Deaths", widget.displayStats(name.Latest.Deaths))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return title, covidStats, true
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user