@@ -352,6 +352,8 @@ type Task struct {
SubtasksCount int ` json:"subtasks_count" `
HasProgression bool ` json:"has_progression" `
AutoComplete bool ` json:"auto_complete" `
DefaultAutoComplete bool ` json:"default_auto_complete" `
DefaultProgress * float64 ` json:"default_progress,omitempty" `
DraftProgressionValue * float64 ` json:"draft_progression_value,omitempty" `
DraftSubtasksCount * int ` json:"draft_subtasks_count,omitempty" `
}
@@ -421,9 +423,11 @@ type TaskRequest struct {
RepetitionDate * string ` json:"repetition_date,omitempty" `
WishlistID * int ` json:"wishlist_id,omitempty" `
RewardPolicy * string ` json:"reward_policy,omitempty" ` // "personal" или "general" для задач, связанных с желаниями
GroupName * string ` json:"group_name,omitempty" ` // Название группы задачи
Rewards [ ] RewardRequest ` json:"rewards ,omitempty"`
Subtask s [ ] SubtaskRequest ` json:"subtask s,omitempty" `
GroupName * string ` json:"group_name,omitempty" ` // Название группы задачи
DefaultAutoComplete * bool ` json:"default_auto_complete ,omitempty"`
DefaultProgres s * float64 ` json:"default_progres s,omitempty" `
Rewards [ ] RewardRequest ` json:"rewards,omitempty" `
Subtasks [ ] SubtaskRequest ` json:"subtasks,omitempty" `
// Test-specific fields
IsTest bool ` json:"is_test,omitempty" `
WordsCount * int ` json:"words_count,omitempty" `
@@ -3398,9 +3402,9 @@ func (a *App) getDraftPendingScores(userID int) (map[int]float64, error) {
// Получаем все драфты с auto_complete=true для пользователя
// Включаем progression_base из задачи для расчёта score
query := `
SELECT
SELECT
td.task_id,
td.progression_value,
COALESCE( td.progression_value, t.default_progress, t.progression_base),
t.progression_base
FROM task_drafts td
JOIN tasks t ON td.task_id = t.id
@@ -3528,13 +3532,78 @@ func (a *App) getDraftPendingScores(userID int) (map[int]float64, error) {
subtaskRows . Close ( )
}
// Также учитываем задачи с default_auto_complete=true без драфта
defaultRows , defaultErr := a . DB . Query ( `
SELECT t.id, COALESCE(t.default_progress, t.progression_base), t.progression_base
FROM tasks t
WHERE t.user_id = $1
AND t.default_auto_complete = TRUE
AND t.deleted = FALSE
AND NOT EXISTS (SELECT 1 FROM task_drafts td WHERE td.task_id = t.id)
AND (t.next_show_at IS NULL OR t.next_show_at <= NOW())
` , userID )
if defaultErr != nil {
log . Printf ( "Error querying default_auto_complete tasks for pending scores: %v" , defaultErr )
} else {
defer defaultRows . Close ( )
for defaultRows . Next ( ) {
var taskID int
var progressionValue sql . NullFloat64
var progressionBase sql . NullFloat64
if err := defaultRows . Scan ( & taskID , & progressionValue , & progressionBase ) ; err != nil {
log . Printf ( "Error scanning default_auto_complete task for pending: %v" , err )
continue
}
var progressionValuePtr * float64
if progressionValue . Valid {
progressionValuePtr = & progressionValue . Float64
}
var progressionBasePtr * float64
if progressionBase . Valid {
progressionBasePtr = & progressionBase . Float64
}
rewardRows , err := a . DB . Query ( `
SELECT rc.project_id, rc.value, rc.use_progression
FROM reward_configs rc
WHERE rc.task_id = $1
` , taskID )
if err != nil {
log . Printf ( "Error querying rewards for default_auto_complete pending: %v" , err )
continue
}
for rewardRows . Next ( ) {
var projectID int
var rewardValue float64
var useProgression bool
if err := rewardRows . Scan ( & projectID , & rewardValue , & useProgression ) ; err != nil {
log . Printf ( "Error scanning reward for default_auto_complete pending: %v" , err )
continue
}
reward := Reward {
Value : rewardValue ,
UseProgression : useProgression ,
}
score := calculateRewardScore ( reward , progressionValuePtr , progressionBasePtr )
scores [ projectID ] += score
}
rewardRows . Close ( )
}
}
return scores , nil
}
// getAutoCompleteDraftEntries возвращает драфты с auto_complete=true как TodayEntry для отображения в списке записей
func ( a * App ) getAutoCompleteDraftEntries ( userID int ) ( [ ] TodayEntry , error ) {
rows , err := a . DB . Query ( `
SELECT td.task_id, t.name, COALESCE(t.reward_message, ''), td.progression_value, t.progression_base
SELECT td.task_id, t.name, COALESCE(t.reward_message, ''), COALESCE( td.progression_value, t.default_progress, t.progression_base), t.progression_base
FROM task_drafts td
JOIN tasks t ON td.task_id = t.id
WHERE td.user_id = $1 AND td.auto_complete = TRUE AND t.deleted = FALSE
@@ -3746,6 +3815,99 @@ func (a *App) getAutoCompleteDraftEntries(userID int) ([]TodayEntry, error) {
return nil , fmt . Errorf ( "error iterating auto complete draft rows: %w" , err )
}
// Также добавляем задачи с default_auto_complete=true без драфта
defaultRows , defaultErr := a . DB . Query ( `
SELECT t.id, t.name, COALESCE(t.reward_message, ''), COALESCE(t.default_progress, t.progression_base), t.progression_base
FROM tasks t
WHERE t.user_id = $1
AND t.default_auto_complete = TRUE
AND t.deleted = FALSE
AND NOT EXISTS (SELECT 1 FROM task_drafts td WHERE td.task_id = t.id)
AND (t.next_show_at IS NULL OR t.next_show_at <= NOW())
ORDER BY t.id
` , userID )
if defaultErr != nil {
log . Printf ( "Error querying default_auto_complete tasks for preview: %v" , defaultErr )
} else {
defer defaultRows . Close ( )
for defaultRows . Next ( ) {
var taskID int
var taskName string
var rewardMessageStr string
var progressionValue sql . NullFloat64
var progressionBase sql . NullFloat64
if err := defaultRows . Scan ( & taskID , & taskName , & rewardMessageStr , & progressionValue , & progressionBase ) ; err != nil {
log . Printf ( "Error scanning default_auto_complete task row: %v" , err )
continue
}
var progressionValuePtr * float64
if progressionValue . Valid {
progressionValuePtr = & progressionValue . Float64
}
var progressionBasePtr * float64
if progressionBase . Valid {
progressionBasePtr = & progressionBase . Float64
}
// Получаем ноды (reward_configs) для задачи
rewardRows , err := a . DB . Query ( `
SELECT rc.position, p.name AS project_name, rc.value, rc.use_progression
FROM reward_configs rc
JOIN projects p ON rc.project_id = p.id
WHERE rc.task_id = $1
ORDER BY rc.position
` , taskID )
if err != nil {
log . Printf ( "Error querying rewards for default_auto_complete task %d: %v" , taskID , err )
continue
}
nodes := make ( [ ] TodayEntryNode , 0 )
for rewardRows . Next ( ) {
var position int
var projectName string
var rewardValue float64
var useProgression bool
if err := rewardRows . Scan ( & position , & projectName , & rewardValue , & useProgression ) ; err != nil {
log . Printf ( "Error scanning reward row for default_auto_complete: %v" , err )
continue
}
reward := Reward {
Value : rewardValue ,
UseProgression : useProgression ,
}
score := calculateRewardScore ( reward , progressionValuePtr , progressionBasePtr )
nodes = append ( nodes , TodayEntryNode {
ProjectName : projectName ,
Score : score ,
Index : position ,
} )
}
rewardRows . Close ( )
var entryText string
if rewardMessageStr != "" {
entryText = strings . ReplaceAll ( rewardMessageStr , "$name" , taskName )
} else {
entryText = taskName
}
taskIDCopy := taskID
entries = append ( entries , TodayEntry {
IsDraft : true ,
TaskID : & taskIDCopy ,
Text : entryText ,
Nodes : nodes ,
} )
}
}
return entries , nil
}
@@ -4618,6 +4780,60 @@ func (a *App) startEndOfDayTaskScheduler() {
log . Printf ( "Task %d executed successfully at end of day" , taskInfo . TaskID )
}
}
// Выполняем задачи с default_auto_complete=true, у которых нет драфта вообще
// (если есть драфт — пользователь уже взаимодействовал с задачей и она обработана выше или отменена)
defaultRows , defaultErr := a . DB . Query ( `
SELECT t.id, t.user_id, COALESCE(t.default_progress, t.progression_base) as progress_value
FROM tasks t
WHERE t.default_auto_complete = TRUE
AND t.deleted = FALSE
AND NOT EXISTS (SELECT 1 FROM task_drafts td WHERE td.task_id = t.id)
AND (t.next_show_at IS NULL OR t.next_show_at <= NOW())
` )
if defaultErr != nil {
log . Printf ( "Error querying default_auto_complete tasks: %v" , defaultErr )
} else {
defer defaultRows . Close ( )
defaultTasks := make ( [ ] struct {
TaskID int
UserID int
ProgressValue * float64
} , 0 )
for defaultRows . Next ( ) {
var taskID , userID int
var progressValue sql . NullFloat64
if err := defaultRows . Scan ( & taskID , & userID , & progressValue ) ; err != nil {
log . Printf ( "Error scanning default_auto_complete task: %v" , err )
continue
}
var progVal * float64
if progressValue . Valid {
progVal = & progressValue . Float64
}
defaultTasks = append ( defaultTasks , struct {
TaskID int
UserID int
ProgressValue * float64
} { TaskID : taskID , UserID : userID , ProgressValue : progVal } )
}
for _ , taskInfo := range defaultTasks {
req := CompleteTaskRequest {
Value : taskInfo . ProgressValue ,
ChildrenTaskIDs : [ ] int { } ,
}
err := a . executeTask ( taskInfo . TaskID , taskInfo . UserID , req )
if err != nil {
log . Printf ( "Error executing default_auto_complete task %d at end of day: %v" , taskInfo . TaskID , err )
} else {
log . Printf ( "Default auto-complete task %d executed successfully at end of day" , taskInfo . TaskID )
}
}
}
} )
if err != nil {
@@ -8577,6 +8793,8 @@ func (a *App) fetchTasksForUser(userID int) ([]Task, error) {
t.repetition_period::text,
t.repetition_date,
t.progression_base,
t.default_auto_complete,
t.default_progress,
t.wishlist_id,
t.config_id,
t.purchase_config_id,
@@ -8636,6 +8854,8 @@ func (a *App) fetchTasksForUser(userID int) ([]Task, error) {
var repetitionPeriod sql . NullString
var repetitionDate sql . NullString
var progressionBase sql . NullFloat64
var defaultAutoComplete bool
var defaultProgress sql . NullFloat64
var wishlistID sql . NullInt64
var configID sql . NullInt64
var purchaseConfigID sql . NullInt64
@@ -8656,6 +8876,8 @@ func (a *App) fetchTasksForUser(userID int) ([]Task, error) {
& repetitionPeriod ,
& repetitionDate ,
& progressionBase ,
& defaultAutoComplete ,
& defaultProgress ,
& wishlistID ,
& configID ,
& purchaseConfigID ,
@@ -8691,6 +8913,10 @@ func (a *App) fetchTasksForUser(userID int) ([]Task, error) {
} else {
task . HasProgression = false
}
task . DefaultAutoComplete = defaultAutoComplete
if defaultProgress . Valid {
task . DefaultProgress = & defaultProgress . Float64
}
if wishlistID . Valid {
wishlistIDInt := int ( wishlistID . Int64 )
task . WishlistID = & wishlistIDInt
@@ -8794,6 +9020,7 @@ func (a *App) getTaskDetailHandler(w http.ResponseWriter, r *http.Request) {
var task Task
var rewardMessage sql . NullString
var progressionBase sql . NullFloat64
var defaultProgress sql . NullFloat64
var lastCompletedAt sql . NullString
var nextShowAt sql . NullString
var repetitionPeriod sql . NullString
@@ -8808,18 +9035,20 @@ func (a *App) getTaskDetailHandler(w http.ResponseWriter, r *http.Request) {
var repetitionPeriodStr string
var repetitionDateStr string
err = a . DB . QueryRow ( `
SELECT id, name, completed, last_completed_at, next_show_at, reward_message, progression_base,
SELECT id, name, completed, last_completed_at, next_show_at, reward_message, progression_base,
CASE WHEN repetition_period IS NULL THEN '' ELSE repetition_period::text END as repetition_period,
COALESCE(repetition_date, '') as repetition_date,
wishlist_id,
config_id,
purchase_config_id,
reward_policy,
group_name
group_name,
default_auto_complete,
default_progress
FROM tasks
WHERE id = $1 AND user_id = $2 AND deleted = FALSE
` , taskID , userID ) . Scan (
& task . ID , & task . Name , & task . Completed , & lastCompletedAt , & nextShowAt , & rewardMessage , & progressionBase , & repetitionPeriodStr , & repetitionDateStr , & wishlistID , & configID , & purchaseConfigID , & rewardPolicy , & groupName ,
& task . ID , & task . Name , & task . Completed , & lastCompletedAt , & nextShowAt , & rewardMessage , & progressionBase , & repetitionPeriodStr , & repetitionDateStr , & wishlistID , & configID , & purchaseConfigID , & rewardPolicy , & groupName , & task . DefaultAutoComplete , & defaultProgress ,
)
log . Printf ( "Scanned repetition_period for task %d: String='%s', repetition_date='%s'" , taskID , repetitionPeriodStr , repetitionDateStr )
@@ -8852,6 +9081,9 @@ func (a *App) getTaskDetailHandler(w http.ResponseWriter, r *http.Request) {
if progressionBase . Valid {
task . ProgressionBase = & progressionBase . Float64
}
if defaultProgress . Valid {
task . DefaultProgress = & defaultProgress . Float64
}
if lastCompletedAt . Valid {
task . LastCompletedAt = & lastCompletedAt . String
}
@@ -9392,6 +9624,16 @@ func (a *App) createTaskHandler(w http.ResponseWriter, r *http.Request) {
if req . ProgressionBase != nil {
progressionBase = sql . NullFloat64 { Float64 : * req . ProgressionBase , Valid : true }
}
var defaultProgressValue sql . NullFloat64
if req . DefaultProgress != nil {
defaultProgressValue = sql . NullFloat64 { Float64 : * req . DefaultProgress , Valid : true }
} else if req . ProgressionBase != nil {
defaultProgressValue = sql . NullFloat64 { Float64 : * req . ProgressionBase , Valid : true }
}
defaultAutoCompleteValue := false
if req . DefaultAutoComplete != nil {
defaultAutoCompleteValue = * req . DefaultAutoComplete
}
if req . RepetitionPeriod != nil && strings . TrimSpace ( * req . RepetitionPeriod ) != "" {
repetitionPeriod = sql . NullString { String : strings . TrimSpace ( * req . RepetitionPeriod ) , Valid : true }
log . Printf ( "Creating task with repetition_period: %s" , repetitionPeriod . String )
@@ -9449,11 +9691,11 @@ func (a *App) createTaskHandler(w http.ResponseWriter, r *http.Request) {
now := time . Now ( ) . In ( loc )
insertSQL = `
INSERT INTO tasks (user_id, name, reward_message, progression_base, repetition_period, repetition_date, next_show_at, completed, deleted, wishlist_id, reward_policy, group_name)
VALUES ($1, $2, $3, $4, $5::INTERVAL, NULL, $6 , 0, FALSE, $7 , $8 , $9 )
INSERT INTO tasks (user_id, name, reward_message, progression_base, default_progress, default_auto_complete, repetition_period, repetition_date, next_show_at, completed, deleted, wishlist_id, reward_policy, group_name)
VALUES ($1, $2, $3, $4, $5, $6, $7 ::INTERVAL, NULL, $8 , 0, FALSE, $9 , $10 , $11 )
RETURNING id
`
insertArgs = [ ] interface { } { userID , strings . TrimSpace ( req . Name ) , rewardMessage , progressionBase , repetitionPeriodValue , now , wishlistIDValue , rewardPolicyValue , req . GroupName }
insertArgs = [ ] interface { } { userID , strings . TrimSpace ( req . Name ) , rewardMessage , progressionBase , defaultProgressValue , defaultAutoCompleteValue , repetitionPeriodValue , now , wishlistIDValue , rewardPolicyValue , req . GroupName }
} else if repetitionDate . Valid {
// Вычисляем next_show_at для задачи с repetition_date
@@ -9468,18 +9710,18 @@ func (a *App) createTaskHandler(w http.ResponseWriter, r *http.Request) {
nextShowAt := calculateNextShowAtFromRepetitionDate ( repetitionDate . String , time . Now ( ) . In ( loc ) )
if nextShowAt != nil {
insertSQL = `
INSERT INTO tasks (user_id, name, reward_message, progression_base, repetition_period, repetition_date, next_show_at, completed, deleted, wishlist_id, reward_policy, group_name)
VALUES ($1, $2, $3, $4, NULL, $5 , $6 , 0, FALSE, $7 , $8 , $9 )
INSERT INTO tasks (user_id, name, reward_message, progression_base, default_progress, default_auto_complete, repetition_period, repetition_date, next_show_at, completed, deleted, wishlist_id, reward_policy, group_name)
VALUES ($1, $2, $3, $4, $5, $6, NULL, $7 , $8 , 0, FALSE, $9 , $10 , $11 )
RETURNING id
`
insertArgs = [ ] interface { } { userID , strings . TrimSpace ( req . Name ) , rewardMessage , progressionBase , repetitionDate . String , nextShowAt , wishlistIDValue , rewardPolicyValue , req . GroupName }
insertArgs = [ ] interface { } { userID , strings . TrimSpace ( req . Name ) , rewardMessage , progressionBase , defaultProgressValue , defaultAutoCompleteValue , repetitionDate . String , nextShowAt , wishlistIDValue , rewardPolicyValue , req . GroupName }
} else {
insertSQL = `
INSERT INTO tasks (user_id, name, reward_message, progression_base, repetition_period, repetition_date, completed, deleted, wishlist_id, reward_policy, group_name)
VALUES ($1, $2, $3, $4, NULL, $5 , 0, FALSE, $6 , $7 , $8 )
INSERT INTO tasks (user_id, name, reward_message, progression_base, default_progress, default_auto_complete, repetition_period, repetition_date, completed, deleted, wishlist_id, reward_policy, group_name)
VALUES ($1, $2, $3, $4, $5, $6, NULL, $7 , 0, FALSE, $8 , $9 , $10 )
RETURNING id
`
insertArgs = [ ] interface { } { userID , strings . TrimSpace ( req . Name ) , rewardMessage , progressionBase , repetitionDate . String , wishlistIDValue , rewardPolicyValue , req . GroupName }
insertArgs = [ ] interface { } { userID , strings . TrimSpace ( req . Name ) , rewardMessage , progressionBase , defaultProgressValue , defaultAutoCompleteValue , repetitionDate . String , wishlistIDValue , rewardPolicyValue , req . GroupName }
}
} else {
// Получаем часовой пояс для задач без повторения
@@ -9492,11 +9734,11 @@ func (a *App) createTaskHandler(w http.ResponseWriter, r *http.Request) {
now := time . Now ( ) . In ( loc )
insertSQL = `
INSERT INTO tasks (user_id, name, reward_message, progression_base, repetition_period, repetition_date, next_show_at, completed, deleted, wishlist_id, reward_policy, group_name)
VALUES ($1, $2, $3, $4, NULL, NULL, $5 , 0, FALSE, $6 , $7 , $8 )
INSERT INTO tasks (user_id, name, reward_message, progression_base, default_progress, default_auto_complete, repetition_period, repetition_date, next_show_at, completed, deleted, wishlist_id, reward_policy, group_name)
VALUES ($1, $2, $3, $4, $5, $6, NULL, NULL, $7 , 0, FALSE, $8 , $9 , $10 )
RETURNING id
`
insertArgs = [ ] interface { } { userID , strings . TrimSpace ( req . Name ) , rewardMessage , progressionBase , now , wishlistIDValue , rewardPolicyValue , req . GroupName }
insertArgs = [ ] interface { } { userID , strings . TrimSpace ( req . Name ) , rewardMessage , progressionBase , defaultProgressValue , defaultAutoCompleteValue , now , wishlistIDValue , rewardPolicyValue , req . GroupName }
}
err = tx . QueryRow ( insertSQL , insertArgs ... ) . Scan ( & taskID )
@@ -9714,13 +9956,14 @@ func (a *App) createTaskHandler(w http.ResponseWriter, r *http.Request) {
var lastCompletedAt sql . NullString
var createdRepetitionPeriod sql . NullString
var createdRepetitionDate sql . NullString
var createdDefaultProgress sql . NullFloat64
err = a . DB . QueryRow ( `
SELECT id, name, completed, last_completed_at, reward_message, progression_base, repetition_period::text, repetition_date
SELECT id, name, completed, last_completed_at, reward_message, progression_base, default_progress, default_auto_complete, repetition_period::text, repetition_date
FROM tasks
WHERE id = $1
` , taskID ) . Scan (
& createdTask . ID , & createdTask . Name , & createdTask . Completed ,
& lastCompletedAt , & rewardMessage , & progressionBase , & createdRepetitionPeriod , & createdRepetitionDate ,
& lastCompletedAt , & rewardMessage , & progressionBase , & createdDefaultProgress , & createdTask . DefaultAutoComplete , & createdRepetitionPeriod, & createdRepetitionDate ,
)
if err != nil {
@@ -9735,6 +9978,9 @@ func (a *App) createTaskHandler(w http.ResponseWriter, r *http.Request) {
if progressionBase . Valid {
createdTask . ProgressionBase = & progressionBase . Float64
}
if createdDefaultProgress . Valid {
createdTask . DefaultProgress = & createdDefaultProgress . Float64
}
if lastCompletedAt . Valid {
createdTask . LastCompletedAt = & lastCompletedAt . String
}
@@ -9873,6 +10119,16 @@ func (a *App) updateTaskHandler(w http.ResponseWriter, r *http.Request) {
if req . ProgressionBase != nil {
progressionBase = sql . NullFloat64 { Float64 : * req . ProgressionBase , Valid : true }
}
var defaultProgressValue sql . NullFloat64
if req . DefaultProgress != nil {
defaultProgressValue = sql . NullFloat64 { Float64 : * req . DefaultProgress , Valid : true }
} else if req . ProgressionBase != nil {
defaultProgressValue = sql . NullFloat64 { Float64 : * req . ProgressionBase , Valid : true }
}
defaultAutoCompleteValue := false
if req . DefaultAutoComplete != nil {
defaultAutoCompleteValue = * req . DefaultAutoComplete
}
if req . RepetitionPeriod != nil && strings . TrimSpace ( * req . RepetitionPeriod ) != "" {
repetitionPeriod = sql . NullString { String : strings . TrimSpace ( * req . RepetitionPeriod ) , Valid : true }
log . Printf ( "Updating task %d with repetition_period: %s" , taskID , repetitionPeriod . String )
@@ -9913,24 +10169,24 @@ func (a *App) updateTaskHandler(w http.ResponseWriter, r *http.Request) {
if repetitionPeriod . Valid {
updateSQL = `
UPDATE tasks
SET name = $1, reward_message = $2, progression_base = $3, repetition_period = $4 ::INTERVAL, repetition_date = NULL, wishlist_id = $5 , reward_policy = $6 , group_name = $7
WHERE id = $8
SET name = $1, reward_message = $2, progression_base = $3, default_progress = $4, default_auto_complete = $5, repetition_period = $6 ::INTERVAL, repetition_date = NULL, wishlist_id = $7 , reward_policy = $8 , group_name = $9
WHERE id = $10
`
updateArgs = [ ] interface { } { strings . TrimSpace ( req . Name ) , rewardMessage , progressionBase , repetitionPeriod . String , newWishlistID , rewardPolicyValue , req . GroupName , taskID }
updateArgs = [ ] interface { } { strings . TrimSpace ( req . Name ) , rewardMessage , progressionBase , defaultProgressValue , defaultAutoCompleteValue , repetitionPeriod . String , newWishlistID , rewardPolicyValue , req . GroupName , taskID }
} else if repetitionDate . Valid {
updateSQL = `
UPDATE tasks
SET name = $1, reward_message = $2, progression_base = $3, repetition_period = NULL, repetition_date = $4 , wishlist_id = $5 , reward_policy = $6 , group_name = $7
WHERE id = $8
SET name = $1, reward_message = $2, progression_base = $3, default_progress = $4, default_auto_complete = $5, repetition_period = NULL, repetition_date = $6 , wishlist_id = $7 , reward_policy = $8 , group_name = $9
WHERE id = $10
`
updateArgs = [ ] interface { } { strings . TrimSpace ( req . Name ) , rewardMessage , progressionBase , repetitionDate . String , newWishlistID , rewardPolicyValue , req . GroupName , taskID }
updateArgs = [ ] interface { } { strings . TrimSpace ( req . Name ) , rewardMessage , progressionBase , defaultProgressValue , defaultAutoCompleteValue , repetitionDate . String , newWishlistID , rewardPolicyValue , req . GroupName , taskID }
} else {
updateSQL = `
UPDATE tasks
SET name = $1, reward_message = $2, progression_base = $3, repetition_period = NULL, repetition_date = NULL, wishlist_id = $4 , reward_policy = $5 , group_name = $6
WHERE id = $7
SET name = $1, reward_message = $2, progression_base = $3, default_progress = $4, default_auto_complete = $5, repetition_period = NULL, repetition_date = NULL, wishlist_id = $6 , reward_policy = $7 , group_name = $8
WHERE id = $9
`
updateArgs = [ ] interface { } { strings . TrimSpace ( req . Name ) , rewardMessage , progressionBase , newWishlistID , rewardPolicyValue , req . GroupName , taskID }
updateArgs = [ ] interface { } { strings . TrimSpace ( req . Name ) , rewardMessage , progressionBase , defaultProgressValue , defaultAutoCompleteValue , newWishlistID , rewardPolicyValue , req . GroupName , taskID }
}
_ , err = tx . Exec ( updateSQL , updateArgs ... )
@@ -10345,13 +10601,14 @@ func (a *App) updateTaskHandler(w http.ResponseWriter, r *http.Request) {
var lastCompletedAt sql . NullString
var updatedRepetitionPeriod sql . NullString
var updatedRepetitionDate sql . NullString
var updatedDefaultProgress sql . NullFloat64
err = a . DB . QueryRow ( `
SELECT id, name, completed, last_completed_at, reward_message, progression_base, repetition_period::text, repetition_date
SELECT id, name, completed, last_completed_at, reward_message, progression_base, default_progress, default_auto_complete, repetition_period::text, repetition_date
FROM tasks
WHERE id = $1
` , taskID ) . Scan (
& updatedTask . ID , & updatedTask . Name , & updatedTask . Completed ,
& lastCompletedAt , & rewardMessage , & progressionBase , & updatedRepetitionPeriod , & updatedRepetitionDate ,
& lastCompletedAt , & rewardMessage , & progressionBase , & updatedDefaultProgress , & updatedTask . DefaultAutoComplete , & updatedRepetitionPeriod, & updatedRepetitionDate ,
)
if err != nil {
@@ -10366,6 +10623,9 @@ func (a *App) updateTaskHandler(w http.ResponseWriter, r *http.Request) {
if progressionBase . Valid {
updatedTask . ProgressionBase = & progressionBase . Float64
}
if updatedDefaultProgress . Valid {
updatedTask . DefaultProgress = & updatedDefaultProgress . Float64
}
if lastCompletedAt . Valid {
updatedTask . LastCompletedAt = & lastCompletedAt . String
}
@@ -10422,17 +10682,17 @@ func (a *App) saveTaskDraftHandler(w http.ResponseWriter, r *http.Request) {
return
}
// Если авто-выполнение включено и progression_value не задан — подставляем progression_base задачи
// Если авто-выполнение включено и progression_value не задан — подставляем default_progress или progression_base задачи
if req . AutoComplete != nil && * req . AutoComplete && req . ProgressionValue == nil &&
( req . ClearProgressionValue == nil || ! * req . ClearProgressionValue ) {
var taskProgressionBase sql . NullFloat64
if pbErr := a . DB . QueryRow ( "SELECT progression_base FROM tasks WHERE id = $1" , taskID ) . Scan ( & taskProgressionBase ) ; pbErr != nil {
log . Printf ( "Error fetching task progression_base : %v" , pbErr )
sendErrorWithCORS ( w , fmt . Sprintf ( "Error fetching task progression_base : %v" , pbErr ) , http . StatusInternalServerError )
var taskDefault Progress sql . NullFloat64
if pbErr := a . DB . QueryRow ( "SELECT COALESCE(default_progress, progression_base) FROM tasks WHERE id = $1" , taskID ) . Scan ( & taskDefault Progress ) ; pbErr != nil {
log . Printf ( "Error fetching task default_ progress: %v" , pbErr )
sendErrorWithCORS ( w , fmt . Sprintf ( "Error fetching task default_ progress: %v" , pbErr ) , http . StatusInternalServerError )
return
}
if taskProgressionBase . Valid {
req . ProgressionValue = & taskProgressionBase . Float64
if taskDefault Progress . Valid {
req . ProgressionValue = & taskDefault Progress . Float64
}
}
@@ -10669,6 +10929,8 @@ func (a *App) copyTaskHandler(w http.ResponseWriter, r *http.Request) {
var name string
var rewardMessage sql . NullString
var progressionBase sql . NullFloat64
var copyDefaultProgress sql . NullFloat64
var copyDefaultAutoComplete bool
var repetitionPeriodStr string
var repetitionDateStr string
var wishlistID sql . NullInt64
@@ -10678,13 +10940,13 @@ func (a *App) copyTaskHandler(w http.ResponseWriter, r *http.Request) {
var ownerID int
err = a . DB . QueryRow ( `
SELECT user_id, name, reward_message, progression_base,
SELECT user_id, name, reward_message, progression_base, default_progress, default_auto_complete,
CASE WHEN repetition_period IS NULL THEN '' ELSE repetition_period::text END,
COALESCE(repetition_date, ''),
wishlist_id, config_id, purchase_config_id, group_name
FROM tasks
WHERE id = $1 AND deleted = FALSE
` , taskID ) . Scan ( & ownerID , & name , & rewardMessage , & progressionBase ,
` , taskID ) . Scan ( & ownerID , & name , & rewardMessage , & progressionBase , & copyDefaultProgress , & copyDefaultAutoComplete ,
& repetitionPeriodStr , & repetitionDateStr , & wishlistID , & configID , & purchaseConfigID , & groupName )
if err == sql . ErrNoRows || ownerID != userID {
@@ -10734,31 +10996,31 @@ func (a *App) copyTaskHandler(w http.ResponseWriter, r *http.Request) {
if repetitionPeriodValue != nil {
err = tx . QueryRow ( `
INSERT INTO tasks (user_id, name, reward_message, progression_base, repetition_period, repetition_date, next_show_at, completed, deleted, group_name)
VALUES ($1, $2, $3, $4, $5::INTERVAL, NULL, $6 , 0, FALSE, $7 )
INSERT INTO tasks (user_id, name, reward_message, progression_base, default_progress, default_auto_complete, repetition_period, repetition_date, next_show_at, completed, deleted, group_name)
VALUES ($1, $2, $3, $4, $5, $6, $7 ::INTERVAL, NULL, $8 , 0, FALSE, $9 )
RETURNING id
` , userID , name , rewardMessage , progressionBase , repetitionPeriodValue , now , groupName ) . Scan ( & newTaskID )
` , userID , name , rewardMessage , progressionBase , copyDefaultProgress , copyDefaultAutoComplete , repetitionPeriodValue , now , groupName ) . Scan ( & newTaskID )
} else if repetitionDateValue != nil {
nextShowAt := calculateNextShowAtFromRepetitionDate ( repetitionDateStr , now )
if nextShowAt != nil {
err = tx . QueryRow ( `
INSERT INTO tasks (user_id, name, reward_message, progression_base, repetition_period, repetition_date, next_show_at, completed, deleted, group_name)
VALUES ($1, $2, $3, $4, NULL, $5 , $6 , 0, FALSE, $7 )
INSERT INTO tasks (user_id, name, reward_message, progression_base, default_progress, default_auto_complete, repetition_period, repetition_date, next_show_at, completed, deleted, group_name)
VALUES ($1, $2, $3, $4, $5, $6, NULL, $7 , $8 , 0, FALSE, $9 )
RETURNING id
` , userID , name , rewardMessage , progressionBase , repetitionDateValue , nextShowAt , groupName ) . Scan ( & newTaskID )
` , userID , name , rewardMessage , progressionBase , copyDefaultProgress , copyDefaultAutoComplete , repetitionDateValue , nextShowAt , groupName ) . Scan ( & newTaskID )
} else {
err = tx . QueryRow ( `
INSERT INTO tasks (user_id, name, reward_message, progression_base, repetition_period, repetition_date, completed, deleted, group_name)
VALUES ($1, $2, $3, $4, NULL, $5 , 0, FALSE, $6 )
INSERT INTO tasks (user_id, name, reward_message, progression_base, default_progress, default_auto_complete, repetition_period, repetition_date, completed, deleted, group_name)
VALUES ($1, $2, $3, $4, $5, $6, NULL, $7 , 0, FALSE, $8 )
RETURNING id
` , userID , name , rewardMessage , progressionBase , repetitionDateValue , groupName ) . Scan ( & newTaskID )
` , userID , name , rewardMessage , progressionBase , copyDefaultProgress , copyDefaultAutoComplete , repetitionDateValue , groupName ) . Scan ( & newTaskID )
}
} else {
err = tx . QueryRow ( `
INSERT INTO tasks (user_id, name, reward_message, progression_base, repetition_period, repetition_date, next_show_at, completed, deleted, group_name)
VALUES ($1, $2, $3, $4, NULL, NULL, $5 , 0, FALSE, $6 )
INSERT INTO tasks (user_id, name, reward_message, progression_base, default_progress, default_auto_complete, repetition_period, repetition_date, next_show_at, completed, deleted, group_name)
VALUES ($1, $2, $3, $4, $5, $6, NULL, NULL, $7 , 0, FALSE, $8 )
RETURNING id
` , userID , name , rewardMessage , progressionBase , now , groupName ) . Scan ( & newTaskID )
` , userID , name , rewardMessage , progressionBase , copyDefaultProgress , copyDefaultAutoComplete , now , groupName ) . Scan ( & newTaskID )
}
if err != nil {
@@ -11406,16 +11668,16 @@ func (a *App) completeTaskAtEndOfDayHandler(w http.ResponseWriter, r *http.Reque
autoCompleteTrue := true
req . AutoComplete = & autoCompleteTrue
// Если progression_value не задан — подставляем progression_base задачи
// Если progression_value не задан — подставляем default_progress или progression_base задачи
if req . ProgressionValue == nil && ( req . ClearProgressionValue == nil || ! * req . ClearProgressionValue ) {
var taskProgressionBase sql . NullFloat64
if pbErr := a . DB . QueryRow ( "SELECT progression_base FROM tasks WHERE id = $1" , taskID ) . Scan ( & taskProgressionBase ) ; pbErr != nil {
log . Printf ( "Error fetching task progression_base : %v" , pbErr )
sendErrorWithCORS ( w , fmt . Sprintf ( "Error fetching task progression_base : %v" , pbErr ) , http . StatusInternalServerError )
var taskDefault Progress sql . NullFloat64
if pbErr := a . DB . QueryRow ( "SELECT COALESCE(default_progress, progression_base) FROM tasks WHERE id = $1" , taskID ) . Scan ( & taskDefault Progress ) ; pbErr != nil {
log . Printf ( "Error fetching task default_ progress: %v" , pbErr )
sendErrorWithCORS ( w , fmt . Sprintf ( "Error fetching task default_ progress: %v" , pbErr ) , http . StatusInternalServerError )
return
}
if taskProgressionBase . Valid {
req . ProgressionValue = & taskProgressionBase . Float64
if taskDefault Progress . Valid {
req . ProgressionValue = & taskDefault Progress . Float64
}
}