feat: add /setcalendar command, store tests, and improve error handling
All checks were successful
CI / build (push) Successful in 48s
All checks were successful
CI / build (push) Successful in 48s
- Add /setcalendar command for calendar type parity (Settings UI) - Add 17 store tests covering all repository methods - Add handler tests for formatDuration, fmtHHMM, fmtDDHHMM - Add domain tests for BurnoutLevel.String, NavMonth, FormatSalary - Fix silent error discarding in save* helpers (log write failures) - Fix computeAndAwardXP error handling instead of discarding - Wrap critical store.go SQL errors with fmt.Errorf context - Update README commands table with /setcalendar
This commit is contained in:
@@ -600,6 +600,48 @@ func (h *Handler) processTimezoneInput(ctx context.Context, msg *models.Message,
|
||||
fmt.Sprintf("Timezone set to %s (current time: %s)", text, now.Format(domain.TimeLayout)), &backKB)
|
||||
}
|
||||
|
||||
func (h *Handler) handleSetCalendar(ctx context.Context, msg *models.Message, user *domain.User) {
|
||||
args := strings.TrimSpace(strings.TrimPrefix(msg.Text, "/setcalendar"))
|
||||
if args == "" {
|
||||
h.promptForInput(ctx, msg.Chat.ID, 0, user.ID, PendingCalendar,
|
||||
fmt.Sprintf("Current calendar: %s\n\nValid options: gregorian, jalali, hijri", user.Calendar), nil)
|
||||
return
|
||||
}
|
||||
args = strings.ToLower(args)
|
||||
valid := map[string]bool{"gregorian": true, "jalali": true, "hijri": true}
|
||||
if !valid[args] {
|
||||
h.sendText(ctx, msg.Chat.ID, "Invalid calendar. Valid options: gregorian, jalali, hijri")
|
||||
return
|
||||
}
|
||||
h.saveCalendar(ctx, msg.Chat.ID, user, args)
|
||||
}
|
||||
|
||||
func (h *Handler) processCalendarInput(ctx context.Context, msg *models.Message, user *domain.User, pi *PendingInput, text string) {
|
||||
text = strings.ToLower(strings.TrimSpace(text))
|
||||
valid := map[string]bool{"gregorian": true, "jalali": true, "hijri": true}
|
||||
if !valid[text] {
|
||||
h.editText(ctx, msg.Chat.ID, pi.MsgID,
|
||||
"Invalid calendar. Valid options: gregorian, jalali, hijri", &models.InlineKeyboardMarkup{
|
||||
InlineKeyboard: [][]models.InlineKeyboardButton{
|
||||
{{Text: "Try again", CallbackData: "caltype"}},
|
||||
{{Text: "Cancel", CallbackData: "back_settings"}},
|
||||
},
|
||||
})
|
||||
return
|
||||
}
|
||||
h.saveCalendar(ctx, msg.Chat.ID, user, text)
|
||||
backKB := settingsBackKeyboard()
|
||||
h.editText(ctx, msg.Chat.ID, pi.MsgID,
|
||||
fmt.Sprintf("Calendar set to %s", text), &backKB)
|
||||
}
|
||||
|
||||
func (h *Handler) saveCalendar(_ context.Context, _ int64, user *domain.User, cal string) {
|
||||
user.Calendar = cal
|
||||
if err := h.Repo.UpdateUser(user); err != nil {
|
||||
slog.Error("save calendar failed", "user_id", user.ID, "error", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (h *Handler) processBreakInput(ctx context.Context, msg *models.Message, user *domain.User, pi *PendingInput, text string) {
|
||||
mins, err := strconv.Atoi(text)
|
||||
if err != nil || mins < 0 || mins > domain.MaxBreakThresholdMins {
|
||||
@@ -684,15 +726,20 @@ func (h *Handler) saveRate(ctx context.Context, chatID int64, user *domain.User,
|
||||
func (h *Handler) saveCurrency(_ context.Context, _ int64, user *domain.User, currency string) {
|
||||
st, err := h.Repo.GetOrCreateSettings(user.ID)
|
||||
if err != nil {
|
||||
slog.Error("save currency: get settings failed", "user_id", user.ID, "error", err)
|
||||
return
|
||||
}
|
||||
st.Currency = currency
|
||||
h.Repo.UpdateSettings(st)
|
||||
if err := h.Repo.UpdateSettings(st); err != nil {
|
||||
slog.Error("save currency: update settings failed", "user_id", user.ID, "error", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (h *Handler) saveTimezone(_ context.Context, _ int64, user *domain.User, tz string) {
|
||||
user.Timezone = tz
|
||||
h.Repo.UpdateUser(user)
|
||||
if err := h.Repo.UpdateUser(user); err != nil {
|
||||
slog.Error("save timezone failed", "user_id", user.ID, "error", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (h *Handler) saveBreakThreshold(_ context.Context, _ int64, user *domain.User, mins int) {
|
||||
@@ -700,10 +747,13 @@ func (h *Handler) saveBreakThreshold(_ context.Context, _ int64, user *domain.Us
|
||||
today := time.Now().In(loc).Format(domain.DateLayout)
|
||||
day, err := h.Repo.GetOrCreateDay(user.ID, today)
|
||||
if err != nil {
|
||||
slog.Error("save break threshold: get day failed", "user_id", user.ID, "error", err)
|
||||
return
|
||||
}
|
||||
day.MinBreakThreshold = int64(mins) * 60
|
||||
h.Repo.UpdateDay(day)
|
||||
if err := h.Repo.UpdateDay(day); err != nil {
|
||||
slog.Error("save break threshold: update day failed", "user_id", user.ID, "error", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (h *Handler) saveUsername(_ context.Context, _ int64, user *domain.User, name string) {
|
||||
@@ -712,7 +762,9 @@ func (h *Handler) saveUsername(_ context.Context, _ int64, user *domain.User, na
|
||||
return
|
||||
}
|
||||
user.Username = name
|
||||
h.Repo.UpdateUser(user)
|
||||
if err := h.Repo.UpdateUser(user); err != nil {
|
||||
slog.Error("save username failed", "user_id", user.ID, "error", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (h *Handler) validateAndSaveReportTime(_ context.Context, _ int64, user *domain.User, timeStr string) error {
|
||||
|
||||
Reference in New Issue
Block a user