5.0.8: часовой пояс, разблокировка по удалению задачи
All checks were successful
Build and Push Docker Image / build-and-push (push) Successful in 1m21s

This commit is contained in:
poignatov
2026-02-09 15:47:57 +03:00
parent 1fe3819be6
commit 72da547b80
3 changed files with 106 additions and 37 deletions

View File

@@ -1 +1 @@
5.0.6
5.0.8

View File

@@ -3886,8 +3886,14 @@ func (a *App) syncFitbitDataForAllUsers() error {
log.Printf("Syncing Fitbit data for %d users", len(userIDs))
// Синхронизируем данные за сегодня для каждого пользователя
today := time.Now()
// Синхронизируем данные за сегодня для каждого пользователя (в настроенном часовом поясе)
timezoneStr := getEnv("TIMEZONE", "UTC")
loc, err := time.LoadLocation(timezoneStr)
if err != nil {
log.Printf("Warning: Invalid timezone '%s': %v. Using UTC for Fitbit sync.", timezoneStr, err)
loc = time.UTC
}
today := time.Now().In(loc)
for _, userID := range userIDs {
if err := a.syncFitbitData(userID, today); err != nil {
log.Printf("Failed to sync Fitbit data for user_id=%d: %v", userID, err)
@@ -4062,8 +4068,9 @@ func main() {
// Логируем параметры подключения к БД (без пароля)
log.Printf("Database connection parameters: host=%s port=%s user=%s dbname=%s", dbHost, dbPort, dbUser, dbName)
dsn := fmt.Sprintf("host=%s port=%s user=%s password=%s dbname=%s sslmode=disable",
dbHost, dbPort, dbUser, dbPassword, dbName)
timezoneStr := getEnv("TIMEZONE", "UTC")
dsn := fmt.Sprintf("host=%s port=%s user=%s password=%s dbname=%s sslmode=disable options='-c timezone=%s'",
dbHost, dbPort, dbUser, dbPassword, dbName, timezoneStr)
var db *sql.DB
var err error
@@ -4832,8 +4839,14 @@ func (a *App) processTelegramMessage(fullText string, entities []TelegramEntity,
}
processedText := strings.Join(cleanedLines, "\n")
// Используем текущее время в формате ISO 8601 (UTC)
createdDate := time.Now().UTC().Format(time.RFC3339)
// Используем текущее время в формате ISO 8601 в настроенном часовом поясе
timezoneStr := getEnv("TIMEZONE", "UTC")
loc, err := time.LoadLocation(timezoneStr)
if err != nil {
log.Printf("Warning: Invalid timezone '%s': %v. Using UTC instead.", timezoneStr, err)
loc = time.UTC
}
createdDate := time.Now().In(loc).Format(time.RFC3339)
// Вставляем данные в БД только если есть nodes
if len(scoreNodes) > 0 {
@@ -4929,8 +4942,14 @@ func (a *App) processMessageInternal(rawText string, sendToTelegram bool, userID
// Формируем Markdown (Legacy) контент: заменяем ** на *
markdownText := strings.ReplaceAll(rawText, "**", "*")
// Используем текущее время
createdDate := time.Now().UTC().Format(time.RFC3339)
// Используем текущее время в настроенном часовом поясе
timezoneStr := getEnv("TIMEZONE", "UTC")
loc, err := time.LoadLocation(timezoneStr)
if err != nil {
log.Printf("Warning: Invalid timezone '%s': %v. Using UTC instead.", timezoneStr, err)
loc = time.UTC
}
createdDate := time.Now().In(loc).Format(time.RFC3339)
// Вставляем данные в БД только если есть nodes
if len(nodes) > 0 {
@@ -6696,8 +6715,13 @@ func (a *App) getFullStatisticsHandler(w http.ResponseWriter, r *http.Request) {
return
}
// Получаем ISO год и неделю для текущей даты
now := time.Now()
// Получаем ISO год и неделю для текущей даты (в настроенном часовом поясе)
timezoneStr := getEnv("TIMEZONE", "UTC")
loc, locErr := time.LoadLocation(timezoneStr)
if locErr != nil {
loc = time.UTC
}
now := time.Now().In(loc)
_, currentWeekInt := now.ISOWeek()
currentYearInt := now.Year()
@@ -6849,10 +6873,10 @@ func (a *App) getFullStatisticsHandler(w http.ResponseWriter, r *http.Request) {
normalizedScore = math.Min(totalScore, maxGoalScore)
}
_, weekISO := time.Now().ISOWeek()
_, weekISO := now.ISOWeek()
item := FullStatisticsItem{
ProjectName: projectName,
ReportYear: time.Now().Year(),
ReportYear: now.Year(),
ReportWeek: weekISO,
TotalScore: totalScore,
NormalizedTotalScore: normalizedScore,
@@ -6892,7 +6916,7 @@ func (a *App) getTodayEntriesHandler(w http.ResponseWriter, r *http.Request) {
projectFilter = &projectName
}
// Получаем дату из query string (формат: YYYY-MM-DD), если не указана - используем сегодня
// Получаем дату из query string (формат: YYYY-MM-DD), если не указана - используем сегодня в настроенном часовом поясе
dateParam := r.URL.Query().Get("date")
var targetDate time.Time
if dateParam != "" {
@@ -6904,7 +6928,13 @@ func (a *App) getTodayEntriesHandler(w http.ResponseWriter, r *http.Request) {
}
targetDate = parsedDate
} else {
targetDate = time.Now()
timezoneStr := getEnv("TIMEZONE", "UTC")
loc, locErr := time.LoadLocation(timezoneStr)
if locErr != nil {
log.Printf("Warning: Invalid timezone '%s': %v. Using UTC for today entries.", timezoneStr, locErr)
loc = time.UTC
}
targetDate = time.Now().In(loc)
}
// Запрос для получения entries с nodes за указанный день
@@ -10758,8 +10788,14 @@ func (a *App) fitbitSyncHandler(w http.ResponseWriter, r *http.Request) {
return
}
// Синхронизируем данные за сегодня
err := a.syncFitbitData(userID, time.Now())
// Синхронизируем данные за сегодня (в настроенном часовом поясе)
timezoneStr := getEnv("TIMEZONE", "UTC")
loc, locErr := time.LoadLocation(timezoneStr)
if locErr != nil {
log.Printf("Warning: Invalid timezone '%s': %v. Using UTC for Fitbit sync.", timezoneStr, locErr)
loc = time.UTC
}
err := a.syncFitbitData(userID, time.Now().In(loc))
if err != nil {
log.Printf("Fitbit sync error: %v", err)
sendErrorWithCORS(w, fmt.Sprintf("Sync failed: %v", err), http.StatusInternalServerError)
@@ -10788,10 +10824,15 @@ func (a *App) getFitbitStatsHandler(w http.ResponseWriter, r *http.Request) {
return
}
// Получаем дату из query параметра (по умолчанию сегодня)
// Получаем дату из query параметра (по умолчанию сегодня в настроенном часовом поясе)
dateStr := r.URL.Query().Get("date")
if dateStr == "" {
dateStr = time.Now().Format("2006-01-02")
timezoneStr := getEnv("TIMEZONE", "UTC")
loc, locErr := time.LoadLocation(timezoneStr)
if locErr != nil {
loc = time.UTC
}
dateStr = time.Now().In(loc).Format("2006-01-02")
}
var steps, floors, azm sql.NullInt64
@@ -11084,7 +11125,8 @@ func (a *App) checkWishlistUnlock(itemID int, userID int) (bool, error) {
} else if err != nil {
return false, err
} else {
conditionMet = completed > 0
// Задача существует и не удалена — условие не выполнено
conditionMet = false
}
} else if scoreConditionID.Valid {
@@ -11472,8 +11514,9 @@ func (a *App) getWishlistItemsWithConditions(userID int, includeCompleted bool)
completedBool := true
condition.TaskCompleted = &completedBool
} else if err == nil {
conditionMet = completed > 0
completedBool := conditionMet
// Задача существует и не удалена — условие не выполнено
conditionMet = false
completedBool := false
condition.TaskCompleted = &completedBool
}
}
@@ -11538,7 +11581,8 @@ func (a *App) getWishlistItemsWithConditions(userID int, includeCompleted bool)
completedBool := true
condition.TaskCompleted = &completedBool
} else if err == nil {
completedBool := completed > 0
// Задача существует и не удалена — условие не выполнено
completedBool := false
condition.TaskCompleted = &completedBool
}
}
@@ -12381,9 +12425,14 @@ func (a *App) getWishlistItemHandler(w http.ResponseWriter, r *http.Request) {
condition.TaskID = &taskIDVal
var taskCompleted int
err := a.DB.QueryRow(`SELECT completed FROM tasks WHERE id = $1 AND user_id = $2 AND deleted = FALSE`, taskID.Int64, conditionOwnerID).Scan(&taskCompleted)
if err == nil {
isCompleted := taskCompleted > 0
condition.TaskCompleted = &isCompleted
if err == sql.ErrNoRows {
// Задача удалена или не существует — условие выполнено
t := true
condition.TaskCompleted = &t
} else if err == nil {
// Задача существует и не удалена — условие не выполнено
f := false
condition.TaskCompleted = &f
}
}
if taskNextShowAt.Valid {
@@ -12777,9 +12826,14 @@ func (a *App) updateWishlistHandler(w http.ResponseWriter, r *http.Request) {
condition.TaskID = &taskIDVal
var taskCompleted int
err := a.DB.QueryRow(`SELECT completed FROM tasks WHERE id = $1 AND user_id = $2 AND deleted = FALSE`, taskID.Int64, conditionOwnerID).Scan(&taskCompleted)
if err == nil {
isCompleted := taskCompleted > 0
condition.TaskCompleted = &isCompleted
if err == sql.ErrNoRows {
// Задача удалена или не существует — условие выполнено
t := true
condition.TaskCompleted = &t
} else if err == nil {
// Задача существует и не удалена — условие не выполнено
f := false
condition.TaskCompleted = &f
}
}
} else if scoreConditionID.Valid {
@@ -14917,15 +14971,20 @@ func (a *App) getWishlistItemsByBoard(boardID int, userID int) ([]WishlistItem,
if taskName.Valid {
condition.TaskName = &taskName.String
}
// Проверяем выполнена ли задача для владельца условия
// Условие выполнено, если задача удалена или не существует
if taskID.Valid {
taskIDVal := int(taskID.Int64)
condition.TaskID = &taskIDVal
var taskCompleted int
err := a.DB.QueryRow(`SELECT completed FROM tasks WHERE id = $1 AND user_id = $2 AND deleted = FALSE`, taskID.Int64, conditionOwnerID).Scan(&taskCompleted)
if err == nil {
isCompleted := taskCompleted > 0
condition.TaskCompleted = &isCompleted
if err == sql.ErrNoRows {
// Задача удалена или не существует — условие выполнено
t := true
condition.TaskCompleted = &t
} else if err == nil {
// Задача существует и не удалена — условие не выполнено
f := false
condition.TaskCompleted = &f
}
}
} else if scoreConditionID.Valid {
@@ -15803,8 +15862,13 @@ func (a *App) proxyImageHandler(w http.ResponseWriter, r *http.Request) {
// getWeeklyStatsDataForUserAndWeek получает данные о проектах для конкретного пользователя и недели
func (a *App) getWeeklyStatsDataForUserAndWeek(userID int, year int, week int) (*WeeklyStatsResponse, error) {
// Определяем, является ли это текущей неделей
now := time.Now()
// Определяем, является ли это текущей неделей (в настроенном часовом поясе)
timezoneStr := getEnv("TIMEZONE", "UTC")
loc, locErr := time.LoadLocation(timezoneStr)
if locErr != nil {
loc = time.UTC
}
now := time.Now().In(loc)
currentYear, currentWeek := now.ISOWeek()
isCurrentWeek := year == currentYear && week == currentWeek
@@ -16000,7 +16064,12 @@ func (a *App) getTrackingStatsHandler(w http.ResponseWriter, r *http.Request) {
weekStr := r.URL.Query().Get("week")
var year, week int
now := time.Now()
timezoneStr := getEnv("TIMEZONE", "UTC")
loc, locErr := time.LoadLocation(timezoneStr)
if locErr != nil {
loc = time.UTC
}
now := time.Now().In(loc)
if yearStr == "" || weekStr == "" {
// Если не указаны - текущая неделя

View File

@@ -1,6 +1,6 @@
{
"name": "play-life-web",
"version": "5.0.6",
"version": "5.0.8",
"type": "module",
"scripts": {
"dev": "vite",