Bump version to 3.4.1 and add version logging on startup
All checks were successful
Build and Push Docker Image / build-and-push (push) Successful in 44s
All checks were successful
Build and Push Docker Image / build-and-push (push) Successful in 44s
This commit is contained in:
@@ -39,6 +39,8 @@ COPY --from=frontend-builder /app/frontend/dist /usr/share/nginx/html
|
||||
# Копируем собранный backend
|
||||
COPY --from=backend-builder /app/backend/main /app/backend/main
|
||||
COPY play-life-backend/admin.html /app/backend/admin.html
|
||||
# Копируем файл версии
|
||||
COPY VERSION /app/VERSION
|
||||
|
||||
# Копируем конфигурацию nginx
|
||||
COPY nginx.conf /etc/nginx/nginx.conf
|
||||
|
||||
@@ -373,6 +373,48 @@ func calculateNextShowAtFromRepetitionDate(repetitionDate string, fromDate time.
|
||||
return &nextDate
|
||||
}
|
||||
|
||||
// calculateNextShowAtFromRepetitionPeriod calculates the next show date by adding repetition_period to fromDate
|
||||
// Format: PostgreSQL INTERVAL string (e.g., "1 day", "2 weeks", "3 months")
|
||||
func calculateNextShowAtFromRepetitionPeriod(repetitionPeriod string, fromDate time.Time) *time.Time {
|
||||
if repetitionPeriod == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
parts := strings.Fields(strings.TrimSpace(repetitionPeriod))
|
||||
if len(parts) < 2 {
|
||||
return nil
|
||||
}
|
||||
|
||||
value, err := strconv.Atoi(parts[0])
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
unit := strings.ToLower(parts[1])
|
||||
|
||||
// Start from fromDate at midnight
|
||||
nextDate := time.Date(fromDate.Year(), fromDate.Month(), fromDate.Day(), 0, 0, 0, 0, fromDate.Location())
|
||||
|
||||
switch unit {
|
||||
case "minute", "minutes":
|
||||
nextDate = nextDate.Add(time.Duration(value) * time.Minute)
|
||||
case "hour", "hours":
|
||||
nextDate = nextDate.Add(time.Duration(value) * time.Hour)
|
||||
case "day", "days":
|
||||
nextDate = nextDate.AddDate(0, 0, value)
|
||||
case "week", "weeks":
|
||||
nextDate = nextDate.AddDate(0, 0, value*7)
|
||||
case "month", "months":
|
||||
nextDate = nextDate.AddDate(0, value, 0)
|
||||
case "year", "years":
|
||||
nextDate = nextDate.AddDate(value, 0, 0)
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
|
||||
return &nextDate
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// Auth types
|
||||
// ============================================
|
||||
@@ -3524,7 +3566,36 @@ func (a *App) startDailyReportScheduler() {
|
||||
// Планировщик будет работать в фоновом режиме
|
||||
}
|
||||
|
||||
// readVersion читает версию из файла VERSION
|
||||
func readVersion() string {
|
||||
// Пробуем разные пути к файлу VERSION
|
||||
paths := []string{
|
||||
"/app/VERSION", // В Docker контейнере
|
||||
"../VERSION", // При запуске из play-life-backend/
|
||||
"../../VERSION", // Альтернативный путь
|
||||
"VERSION", // Текущая директория
|
||||
}
|
||||
|
||||
for _, path := range paths {
|
||||
data, err := os.ReadFile(path)
|
||||
if err == nil {
|
||||
version := strings.TrimSpace(string(data))
|
||||
if version != "" {
|
||||
return version
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
func main() {
|
||||
// Читаем версию приложения
|
||||
version := readVersion()
|
||||
log.Printf("========================================")
|
||||
log.Printf("Play Life Backend v%s", version)
|
||||
log.Printf("========================================")
|
||||
|
||||
// Загружаем переменные окружения из .env файла (если существует)
|
||||
// Сначала пробуем загрузить из корня проекта, затем из текущей директории
|
||||
// Игнорируем ошибку, если файл не найден
|
||||
@@ -6805,12 +6876,28 @@ func (a *App) createTaskHandler(w http.ResponseWriter, r *http.Request) {
|
||||
var insertSQL string
|
||||
var insertArgs []interface{}
|
||||
if repetitionPeriod.Valid {
|
||||
// Вычисляем next_show_at для задачи с repetition_period
|
||||
periodStr := strings.TrimSpace(repetitionPeriod.String)
|
||||
isZeroPeriod := strings.HasPrefix(periodStr, "0 ") || periodStr == "0"
|
||||
var nextShowAt *time.Time
|
||||
if !isZeroPeriod {
|
||||
nextShowAt = calculateNextShowAtFromRepetitionPeriod(repetitionPeriod.String, time.Now())
|
||||
}
|
||||
if nextShowAt != nil {
|
||||
insertSQL = `
|
||||
INSERT INTO tasks (user_id, name, reward_message, progression_base, repetition_period, repetition_date, next_show_at, completed, deleted)
|
||||
VALUES ($1, $2, $3, $4, $5::INTERVAL, NULL, $6, 0, FALSE)
|
||||
RETURNING id
|
||||
`
|
||||
insertArgs = []interface{}{userID, strings.TrimSpace(req.Name), rewardMessage, progressionBase, repetitionPeriodValue, nextShowAt}
|
||||
} else {
|
||||
insertSQL = `
|
||||
INSERT INTO tasks (user_id, name, reward_message, progression_base, repetition_period, repetition_date, completed, deleted)
|
||||
VALUES ($1, $2, $3, $4, $5::INTERVAL, NULL, 0, FALSE)
|
||||
RETURNING id
|
||||
`
|
||||
insertArgs = []interface{}{userID, strings.TrimSpace(req.Name), rewardMessage, progressionBase, repetitionPeriodValue}
|
||||
}
|
||||
} else if repetitionDate.Valid {
|
||||
// Вычисляем next_show_at для задачи с repetition_date
|
||||
nextShowAt := calculateNextShowAtFromRepetitionDate(repetitionDate.String, time.Now())
|
||||
@@ -7062,12 +7149,28 @@ func (a *App) updateTaskHandler(w http.ResponseWriter, r *http.Request) {
|
||||
var updateSQL string
|
||||
var updateArgs []interface{}
|
||||
if repetitionPeriod.Valid {
|
||||
// Вычисляем next_show_at для задачи с repetition_period
|
||||
periodStr := strings.TrimSpace(repetitionPeriod.String)
|
||||
isZeroPeriod := strings.HasPrefix(periodStr, "0 ") || periodStr == "0"
|
||||
var nextShowAt *time.Time
|
||||
if !isZeroPeriod {
|
||||
nextShowAt = calculateNextShowAtFromRepetitionPeriod(repetitionPeriod.String, time.Now())
|
||||
}
|
||||
if nextShowAt != nil {
|
||||
updateSQL = `
|
||||
UPDATE tasks
|
||||
SET name = $1, reward_message = $2, progression_base = $3, repetition_period = $4::INTERVAL, repetition_date = NULL, next_show_at = $5
|
||||
WHERE id = $6
|
||||
`
|
||||
updateArgs = []interface{}{strings.TrimSpace(req.Name), rewardMessage, progressionBase, repetitionPeriod.String, nextShowAt, taskID}
|
||||
} else {
|
||||
updateSQL = `
|
||||
UPDATE tasks
|
||||
SET name = $1, reward_message = $2, progression_base = $3, repetition_period = $4::INTERVAL, repetition_date = NULL, next_show_at = NULL
|
||||
WHERE id = $5
|
||||
`
|
||||
updateArgs = []interface{}{strings.TrimSpace(req.Name), rewardMessage, progressionBase, repetitionPeriod.String, taskID}
|
||||
}
|
||||
} else if repetitionDate.Valid {
|
||||
// Вычисляем next_show_at для задачи с repetition_date
|
||||
nextShowAt := calculateNextShowAtFromRepetitionDate(repetitionDate.String, time.Now())
|
||||
@@ -7706,13 +7809,25 @@ func (a *App) completeTaskHandler(w http.ResponseWriter, r *http.Request) {
|
||||
WHERE id = $1
|
||||
`, taskID)
|
||||
} else {
|
||||
// Обычный период: обновляем счетчик и last_completed_at, сбрасываем next_show_at
|
||||
// Обычный период: обновляем счетчик и last_completed_at, вычисляем next_show_at
|
||||
// next_show_at = last_completed_at + repetition_period
|
||||
now := time.Now()
|
||||
nextShowAt := calculateNextShowAtFromRepetitionPeriod(repetitionPeriod.String, now)
|
||||
if nextShowAt != nil {
|
||||
_, err = a.DB.Exec(`
|
||||
UPDATE tasks
|
||||
SET completed = completed + 1, last_completed_at = NOW(), next_show_at = $2
|
||||
WHERE id = $1
|
||||
`, taskID, nextShowAt)
|
||||
} else {
|
||||
// Если не удалось вычислить дату, обновляем как обычно
|
||||
_, err = a.DB.Exec(`
|
||||
UPDATE tasks
|
||||
SET completed = completed + 1, last_completed_at = NOW(), next_show_at = NULL
|
||||
WHERE id = $1
|
||||
`, taskID)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
_, err = a.DB.Exec(`
|
||||
UPDATE tasks
|
||||
|
||||
Reference in New Issue
Block a user