feat: add Telegram bot with notifications and scheduler
This commit is contained in:
@@ -23,8 +23,8 @@ func NewHabitRepository(db *sqlx.DB) *HabitRepository {
|
||||
|
||||
func (r *HabitRepository) Create(habit *model.Habit) error {
|
||||
query := `
|
||||
INSERT INTO habits (user_id, name, description, color, icon, frequency, target_days, target_count)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
|
||||
INSERT INTO habits (user_id, name, description, color, icon, frequency, target_days, target_count, reminder_time)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
|
||||
RETURNING id, created_at, updated_at`
|
||||
|
||||
targetDays := pq.Array(habit.TargetDays)
|
||||
@@ -41,6 +41,7 @@ func (r *HabitRepository) Create(habit *model.Habit) error {
|
||||
habit.Frequency,
|
||||
targetDays,
|
||||
habit.TargetCount,
|
||||
habit.ReminderTime,
|
||||
).Scan(&habit.ID, &habit.CreatedAt, &habit.UpdatedAt)
|
||||
}
|
||||
|
||||
@@ -49,13 +50,13 @@ func (r *HabitRepository) GetByID(id, userID int64) (*model.Habit, error) {
|
||||
var targetDays pq.Int64Array
|
||||
|
||||
query := `
|
||||
SELECT id, user_id, name, description, color, icon, frequency, target_days, target_count, is_archived, created_at, updated_at
|
||||
SELECT id, user_id, name, description, color, icon, frequency, target_days, target_count, reminder_time, is_archived, created_at, updated_at
|
||||
FROM habits WHERE id = $1 AND user_id = $2`
|
||||
|
||||
err := r.db.QueryRow(query, id, userID).Scan(
|
||||
&habit.ID, &habit.UserID, &habit.Name, &habit.Description,
|
||||
&habit.Color, &habit.Icon, &habit.Frequency, &targetDays,
|
||||
&habit.TargetCount, &habit.IsArchived, &habit.CreatedAt, &habit.UpdatedAt,
|
||||
&habit.TargetCount, &habit.ReminderTime, &habit.IsArchived, &habit.CreatedAt, &habit.UpdatedAt,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
@@ -69,13 +70,14 @@ func (r *HabitRepository) GetByID(id, userID int64) (*model.Habit, error) {
|
||||
for i, v := range targetDays {
|
||||
habit.TargetDays[i] = int(v)
|
||||
}
|
||||
habit.ProcessForJSON()
|
||||
|
||||
return &habit, nil
|
||||
}
|
||||
|
||||
func (r *HabitRepository) ListByUser(userID int64, includeArchived bool) ([]model.Habit, error) {
|
||||
query := `
|
||||
SELECT id, user_id, name, description, color, icon, frequency, target_days, target_count, is_archived, created_at, updated_at
|
||||
SELECT id, user_id, name, description, color, icon, frequency, target_days, target_count, reminder_time, is_archived, created_at, updated_at
|
||||
FROM habits WHERE user_id = $1`
|
||||
|
||||
if !includeArchived {
|
||||
@@ -97,7 +99,7 @@ func (r *HabitRepository) ListByUser(userID int64, includeArchived bool) ([]mode
|
||||
if err := rows.Scan(
|
||||
&habit.ID, &habit.UserID, &habit.Name, &habit.Description,
|
||||
&habit.Color, &habit.Icon, &habit.Frequency, &targetDays,
|
||||
&habit.TargetCount, &habit.IsArchived, &habit.CreatedAt, &habit.UpdatedAt,
|
||||
&habit.TargetCount, &habit.ReminderTime, &habit.IsArchived, &habit.CreatedAt, &habit.UpdatedAt,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -106,6 +108,49 @@ func (r *HabitRepository) ListByUser(userID int64, includeArchived bool) ([]mode
|
||||
for i, v := range targetDays {
|
||||
habit.TargetDays[i] = int(v)
|
||||
}
|
||||
habit.ProcessForJSON()
|
||||
|
||||
habits = append(habits, habit)
|
||||
}
|
||||
|
||||
return habits, nil
|
||||
}
|
||||
|
||||
func (r *HabitRepository) GetHabitsWithReminder(reminderTime string, weekday int) ([]model.Habit, error) {
|
||||
query := `
|
||||
SELECT h.id, h.user_id, h.name, h.description, h.color, h.icon, h.frequency, h.target_days, h.target_count, h.reminder_time, h.is_archived, h.created_at, h.updated_at
|
||||
FROM habits h
|
||||
JOIN users u ON h.user_id = u.id
|
||||
WHERE h.reminder_time = $1
|
||||
AND h.is_archived = false
|
||||
AND (h.frequency = 'daily' OR $2 = ANY(h.target_days))
|
||||
AND u.telegram_chat_id IS NOT NULL
|
||||
AND u.notifications_enabled = true`
|
||||
|
||||
rows, err := r.db.Query(query, reminderTime, weekday)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var habits []model.Habit
|
||||
for rows.Next() {
|
||||
var habit model.Habit
|
||||
var targetDays pq.Int64Array
|
||||
|
||||
if err := rows.Scan(
|
||||
&habit.ID, &habit.UserID, &habit.Name, &habit.Description,
|
||||
&habit.Color, &habit.Icon, &habit.Frequency, &targetDays,
|
||||
&habit.TargetCount, &habit.ReminderTime, &habit.IsArchived, &habit.CreatedAt, &habit.UpdatedAt,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
habit.TargetDays = make([]int, len(targetDays))
|
||||
for i, v := range targetDays {
|
||||
habit.TargetDays[i] = int(v)
|
||||
}
|
||||
habit.ProcessForJSON()
|
||||
|
||||
habits = append(habits, habit)
|
||||
}
|
||||
@@ -117,8 +162,8 @@ func (r *HabitRepository) Update(habit *model.Habit) error {
|
||||
query := `
|
||||
UPDATE habits
|
||||
SET name = $2, description = $3, color = $4, icon = $5, frequency = $6,
|
||||
target_days = $7, target_count = $8, is_archived = $9, updated_at = CURRENT_TIMESTAMP
|
||||
WHERE id = $1 AND user_id = $10
|
||||
target_days = $7, target_count = $8, reminder_time = $9, is_archived = $10, updated_at = CURRENT_TIMESTAMP
|
||||
WHERE id = $1 AND user_id = $11
|
||||
RETURNING updated_at`
|
||||
|
||||
return r.db.QueryRow(query,
|
||||
@@ -130,6 +175,7 @@ func (r *HabitRepository) Update(habit *model.Habit) error {
|
||||
habit.Frequency,
|
||||
pq.Array(habit.TargetDays),
|
||||
habit.TargetCount,
|
||||
habit.ReminderTime,
|
||||
habit.IsArchived,
|
||||
habit.UserID,
|
||||
).Scan(&habit.UpdatedAt)
|
||||
@@ -208,6 +254,13 @@ func (r *HabitRepository) GetUserLogsForDate(userID int64, date time.Time) ([]mo
|
||||
return logs, nil
|
||||
}
|
||||
|
||||
func (r *HabitRepository) IsHabitCompletedToday(habitID, userID int64) (bool, error) {
|
||||
today := time.Now().Format("2006-01-02")
|
||||
var count int
|
||||
err := r.db.Get(&count, `SELECT COUNT(*) FROM habit_logs WHERE habit_id = $1 AND user_id = $2 AND date = $3`, habitID, userID, today)
|
||||
return count > 0, err
|
||||
}
|
||||
|
||||
func (r *HabitRepository) GetStats(habitID, userID int64) (*model.HabitStats, error) {
|
||||
stats := &model.HabitStats{HabitID: habitID}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user