refactor: export full Gregorian range, add timezone fallback, cleanup rate limit, configurable schema path

- GenerateMonthlyReport now takes explicit Gregorian start/end range,
  computed via monthGregorianRange, so Jalali/Hijri months spanning
  two Gregorian months are fully covered in exports.
- Added loadLocation helper (UTC fallback on error) and replaced all
  11 ignored-error call sites in handlers + export.
- Added periodicCleanup goroutine in NewHandler to prevent unbounded
  growth of the rateLimit map.
- schemaPath is now read from SCHEMA_PATH env var (init), defaulting
  to /app/db/schema.sql.
- Migrated sendDayView to use sendOrEdit helper, removing duplicated
  send/edit branching.
- Removed dead code: userYearMonthToGregorian (unused), the old
  startOffset function (replaced).
- Updated README with calendar docs, new env vars, full project tree.
- Updated .env.example and docker-compose.yml with SCHEMA_PATH.
- Simplified Makefile: added fmt, tidy, check, run-dev targets;
  removed broken Make-glob prerequisite pattern.
This commit is contained in:
2026-06-24 11:21:54 +03:30
parent f89f5607aa
commit d8599657f4
8 changed files with 193 additions and 122 deletions

View File

@@ -22,7 +22,7 @@ var themes = map[string]themeColors{
"catppuccin": {headerFill: "B48DED", border: "D9D0E8", totalFill: "F0E8FC"},
}
func GenerateMonthlyReport(store *db.Store, userID int64, timezone, accent, calendar string, year int, month time.Month) ([]byte, error) {
func GenerateMonthlyReport(store *db.Store, userID int64, timezone, accent, calendar string, calYear, calMonth int, start, end time.Time) ([]byte, error) {
theme, ok := themes[accent]
if !ok {
theme = themes["ocean"]
@@ -76,16 +76,7 @@ func GenerateMonthlyReport(store *db.Store, userID int64, timezone, accent, cale
Alignment: &excelize.Alignment{Horizontal: "center", Vertical: "center"},
})
var jy, jm int
switch calendar {
case "jalali":
jy, jm, _ = gregorianToJalali(year, int(month), 1)
case "hijri":
jy, jm, _ = gregorianToHijri(year, int(month), 1)
default:
jy, jm = year, int(month)
}
monthName := formatMonthTitle(calendar, jy, jm)
monthName := formatMonthTitle(calendar, calYear, calMonth)
f.SetCellValue(sheet, "A1", fmt.Sprintf("Work Time Report - %s", monthName))
f.MergeCell(sheet, "A1", "F1")
f.SetCellStyle(sheet, "A1", "F1", titleStyle)
@@ -106,16 +97,11 @@ func GenerateMonthlyReport(store *db.Store, userID int64, timezone, accent, cale
f.SetColWidth(sheet, "E", "E", 10)
f.SetColWidth(sheet, "F", "F", 10)
loc, err := time.LoadLocation(timezone)
if err != nil {
loc = time.UTC
}
loc := loadLocation(timezone)
row := 3
firstDay := time.Date(year, month, 1, 0, 0, 0, 0, loc)
lastDay := firstDay.AddDate(0, 1, -1)
userDays, err := store.GetUserDaysInRange(userID, firstDay.Format("2006-01-02"), lastDay.Format("2006-01-02"))
userDays, err := store.GetUserDaysInRange(userID, start.Format("2006-01-02"), end.Format("2006-01-02"))
if err != nil {
return nil, err
}
@@ -127,7 +113,7 @@ func GenerateMonthlyReport(store *db.Store, userID int64, timezone, accent, cale
var totalWork, totalBreak int64
for d := firstDay; !d.After(lastDay); d = d.AddDate(0, 0, 1) {
for d := start; !d.After(end); d = d.AddDate(0, 0, 1) {
dateStr := d.Format("2006-01-02")
displayDate := formatDateForCalendar(dateStr, calendar)