From 57f0c997e3d33a6715ca3d4ce100969fbe53c08d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaros=C5=82aw=20Zywert?= Date: Sun, 5 May 2024 22:01:32 +0200 Subject: [PATCH] Include holidays in summary and calendar (#10) --- CHANGELOG.md | 9 ++++- gojira/calendar.go | 24 +++++++++--- gojira/cli.go | 20 +++++++++- gojira/gojira.go | 2 + gojira/hoilidays.go | 92 +++++++++++++++++++++++++++++++++++++++++++++ gojira/summary.go | 2 +- 6 files changed, 139 insertions(+), 10 deletions(-) create mode 100644 gojira/hoilidays.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 51e4549..013d630 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), ## [Unreleased] +## [0.7.0] - 2024-05-05 +### Added +- Fetch national holidays from [date.nager.at](https://date.nager.at) if LC_TIME is present in environment. Holidays will be marked on calendar and excluded from month summary. + ## [0.6.0] - 2024-03-30 ### Changed - Replace [manifoldco/promptui](https://github.com/charmbracelet/huh) with [charmbracelet/huh](https://github.com/charmbracelet/huh) due to lack of maintainer @@ -96,7 +100,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), ### Added - Initial release of gojira -[Unreleased]: https://github.com/jzyinq/gojira/compare/0.6.0...master +[Unreleased]: https://github.com/jzyinq/gojira/compare/0.7.0...master +[0.7.0]: https://github.com/jzyinq/gojira/compare/0.6.0...0.7.0 [0.6.0]: https://github.com/jzyinq/gojira/compare/0.5.4...0.6.0 [0.5.4]: https://github.com/jzyinq/gojira/compare/0.5.3...0.5.4 [0.5.3]: https://github.com/jzyinq/gojira/compare/0.5.2...0.5.3 @@ -109,4 +114,4 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), [0.2.2]: https://github.com/jzyinq/gojira/compare/0.2.1...0.2.2 [0.2.1]: https://github.com/jzyinq/gojira/compare/0.2.0...0.2.1 [0.2.0]: https://github.com/jzyinq/gojira/compare/0.1.0...0.2.0 -[0.1.0]: https://github.com/jzyinq/gojira/tree/0.1.0 \ No newline at end of file +[0.1.0]: https://github.com/jzyinq/gojira/tree/0.1.0 diff --git a/gojira/calendar.go b/gojira/calendar.go index 00c791b..3d2172f 100644 --- a/gojira/calendar.go +++ b/gojira/calendar.go @@ -35,21 +35,29 @@ func NewCalendar() *Calendar { } func (c *Calendar) update() { + c.setDate() + c.setWeekdays() + c.setDays() +} + +func (c *Calendar) setDate() { c.day = app.time.Day() c.month = app.time.Month() c.year = app.time.Year() - c.Clear() - - t := time.Date(c.year, c.month, 1, 0, 0, 0, 0, time.Local) - daysInMonth := time.Date(c.year, c.month+1, 0, 0, 0, 0, 0, time.Local).Day() +} - // Weekdays +func (c *Calendar) setWeekdays() { weekdays := []string{"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"} for i, day := range weekdays { c.SetCell(0, i, tview.NewTableCell(day)) } +} + +func (c *Calendar) setDays() { + c.Clear() + t := time.Date(c.year, c.month, 1, 0, 0, 0, 0, time.Local) + daysInMonth := time.Date(c.year, c.month+1, 0, 0, 0, 0, 0, time.Local).Day() - // Days week := 1 for i := 1; i <= daysInMonth; i++ { dayOfWeek := int(t.Weekday()) - 1 // Weekday() returns 1 (Monday) to 7 (Sunday) @@ -63,6 +71,7 @@ func (c *Calendar) update() { if calendarDay.Before(time.Now().Local()) { cell.SetBackgroundColor(tcell.ColorGray) } + if len(app.workLogs.logs) > 0 { worklogs, err := app.workLogs.LogsOnDate(&calendarDay) if err != nil { @@ -78,6 +87,9 @@ func (c *Calendar) update() { } } } + if app.holidays.IsHoliday(&calendarDay) { + cell.SetTextColor(tcell.ColorRed) + } if i == c.day { cell.SetTextColor(tcell.ColorWhite) cell.SetBackgroundColor(tcell.ColorDimGray) diff --git a/gojira/cli.go b/gojira/cli.go index 6f7f633..2b06a3d 100644 --- a/gojira/cli.go +++ b/gojira/cli.go @@ -26,7 +26,25 @@ var WorklogsCommand = &cli.Command{ Usage: "Edit your today's work log", Action: func(c *cli.Context) error { newUi() - loadWorklogs() + var wg sync.WaitGroup + wg.Add(1) + go func() { + defer wg.Done() + loadWorklogs() + }() + wg.Add(1) + go func() { + defer wg.Done() + countryCode, err := GetCountryFromLCTime(os.Getenv("LC_TIME")) + if err != nil { + logrus.Error("getting country code from LC_TIME failed:" + err.Error()) + } + app.holidays, err = NewHolidays(countryCode) + if err != nil { + logrus.Error("fetching national holidays failed:" + err.Error()) + } + }() + wg.Wait() err := app.ui.app.Run() if err != nil { return err diff --git a/gojira/gojira.go b/gojira/gojira.go index 5d23d6a..a7bbbdd 100644 --- a/gojira/gojira.go +++ b/gojira/gojira.go @@ -12,6 +12,7 @@ type gojira struct { cli *cli.App ui *UserInteface time *time.Time + holidays *Holidays workLogs Worklogs workLogsIssues WorklogsIssues } @@ -31,6 +32,7 @@ func Run() { logrus.Infof("current time %s", appTimer) app.ui = &UserInteface{} app.time = &appTimer + app.holidays = &Holidays{} app.cli = &cli.App{ Name: "gojira", Usage: `quickly log time to jira/tempo through cli. diff --git a/gojira/hoilidays.go b/gojira/hoilidays.go new file mode 100644 index 0000000..dc1694d --- /dev/null +++ b/gojira/hoilidays.go @@ -0,0 +1,92 @@ +package gojira + +import ( + "encoding/json" + "fmt" + "github.com/sirupsen/logrus" + "net/http" + "regexp" + "time" +) + +type Holiday struct { + Date string `json:"date"` + LocalName string `json:"localName"` + Name string `json:"name"` + CountryCode string `json:"countryCode"` +} + +type Holidays []Holiday + +func (h *Holidays) GetHolidaysForMonth(month time.Month) Holidays { + var holidaysForMonth Holidays + for _, holiday := range *h { + t, err := time.Parse("2006-01-02", holiday.Date) + if err != nil { + fmt.Println(err) + continue + } + if t.Month() == month { + holidaysForMonth = append(holidaysForMonth, holiday) + } + } + return holidaysForMonth +} + +func (h *Holidays) IsHoliday(t *time.Time) bool { + for _, holiday := range *h { + t2, err := time.Parse("2006-01-02", holiday.Date) + if err != nil { + fmt.Println(err) + continue + } + if t2.Equal(*t) { + return true + } + } + return false +} + +func (h *Holiday) GetTime() (*time.Time, error) { + t, err := time.Parse("2006-01-02", h.Date) + if err != nil { + return nil, err + } + return &t, nil +} + +func getHolidaysForCountry(countryCode string) (*Holidays, error) { + url := fmt.Sprintf("https://date.nager.at/api/v3/PublicHolidays/2024/%s", countryCode) + logrus.Infof("fetching holidays from url: %s", url) + resp, err := http.Get(url) //nolint:gosec + if err != nil { + logrus.Error("could not fetch holidays from url: ", url) + return nil, err + } + defer resp.Body.Close() + var holidays Holidays + err = json.NewDecoder(resp.Body).Decode(&holidays) + if err != nil { + return nil, err + } + return &holidays, nil +} + +func NewHolidays(countryCode string) (*Holidays, error) { + holidays, err := getHolidaysForCountry(countryCode) + if err != nil { + logrus.Error(err) + return &Holidays{}, err + } + + return holidays, nil +} + +func GetCountryFromLCTime(timeString string) (string, error) { + r, _ := regexp.Compile("([A-Z]{2})") + match := r.FindString(timeString) + if match == "" { + return "", fmt.Errorf("could not parse country from LC_TIME") + } + return match, nil +} diff --git a/gojira/summary.go b/gojira/summary.go index 14cf41b..1519077 100644 --- a/gojira/summary.go +++ b/gojira/summary.go @@ -41,7 +41,7 @@ func workingHoursInMonthToPresentDay(year int, month time.Month) int { totalWorkHours := 0 for t.Month() == month && t.Before(time.Now().Local()) { - if t.Weekday() != time.Saturday && t.Weekday() != time.Sunday { + if t.Weekday() != time.Saturday && t.Weekday() != time.Sunday && !app.holidays.IsHoliday(&t) { totalWorkHours += 8 } t = t.AddDate(0, 0, 1)