1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
| import logging
import sqlite3
import asyncio
import re
from datetime import datetime, timedelta
from aiogram import Bot, Dispatcher, types
from aiogram.contrib.fsm_storage.memory import MemoryStorage
from aiogram.dispatcher import FSMContext
from aiogram.dispatcher.filters import Text
from aiogram.dispatcher.filters.state import State, StatesGroup
from aiogram.types import ParseMode
from aiogram.utils import executor
logging.basicConfig(level=logging.INFO)
bot_token = 'token'
bot = Bot(token=bot_token)
storage = MemoryStorage()
dp = Dispatcher(bot, storage=storage)
db = sqlite3.connect('main3.db')
class Pet(StatesGroup):
waiting_for_pet_choice = State()
waiting_for_steps_number = State()
waiting_for_next_action = State()
waiting_for_steps_choice = State()
waiting_for_reminder_time = State()
waiting_for_new_steps_number = State()
class PetAction(StatesGroup):
waiting_for_action_choice = State()
waiting_for_walk_time = State()
@dp.message_handler(commands=['start'])
async def welcome(message: types.Message):
await message.answer('Добро пожаловать на наш бот!\n'
'Пожалуйста, выберите животное для отслеживания:', reply_markup=types.ReplyKeyboardMarkup(
keyboard=[
[types.KeyboardButton(text='Собака'), types.KeyboardButton(text='Кот')],
[types.KeyboardButton(text='Кролик'), types.KeyboardButton(text='Попугай')],
[types.KeyboardButton(text='Myself')],
],
resize_keyboard=True
))
await Pet.waiting_for_pet_choice.set()
@dp.message_handler(Text(equals=['Собака', 'Кот', 'Кролик', 'Попугай']), state=Pet.waiting_for_pet_choice)
async def choose_pet(message: types.Message, state: FSMContext):
async with state.proxy() as data:
data['pet'] = message.text
await message.answer(f"Вы выбрали {message.text}!\n"
"Пожалуйста, введите количество шагов, которые вы сделали сегодня:")
await Pet.waiting_for_steps_number.set()
@dp.message_handler(Text(equals=['Myself']), state=Pet.waiting_for_pet_choice)
async def choose_myself(message: types.Message, state: FSMContext):
async with state.proxy() as data:
data['pet'] = 'Myself'
await message.answer("You have chosen to track yourself!\n"
"Пожалуйста, введите количество шагов, которые вы сделали сегодня:")
await Pet.waiting_for_steps_number.set()
@dp.message_handler(lambda message: not message.text.isdigit(), state=Pet.waiting_for_steps_number)
async def process_steps_invalid(message: types.Message):
await message.answer("Напишите количество шагов числом.")
@dp.message_handler(lambda message: message.text.isdigit(), state=Pet.waiting_for_steps_number)
async def process_steps(message: types.Message, state: FSMContext):
async with state.proxy() as data:
data['steps'] = int(message.text)
data['username'] = message.from_user.username
data['date'] = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
pet = data['pet']
steps = data['steps']
username = data['username']
date = data['date']
cursor = db.cursor()
cursor.execute("INSERT INTO pet_tracker (pet, steps, username, date) VALUES (?, ?, ?, ?)", (pet, steps, username, date))
db.commit()
await message.answer(f"Отлично! Вы покормили {pet} {steps} шагами.\n"
"Что бы вы хотели сделать дальше?", reply_markup=types.ReplyKeyboardMarkup(
keyboard=[
[types.KeyboardButton(text='Проверить прогресс'), types.KeyboardButton(text='Установить напоминание')],
[types.KeyboardButton(text='Поменять питомца'), types.KeyboardButton(text='Выйти')]
],
resize_keyboard=True
))
await Pet.waiting_for_next_action.set()
@dp.message_handler(Text(equals=['Проверить прогресс']), state=Pet.waiting_for_next_action)
async def check_progress(message: types.Message, state: FSMContext):
async with state.proxy() as data:
pet = data['pet']
cursor = db.cursor()
cursor.execute("SELECT sum(steps) FROM pet_tracker WHERE pet=?", (pet,))
result = cursor.fetchone()[0]
if result is not None:
await message.answer(f"Вы прошли {result} шагов.")
else:
await message.answer("Вы еще не зарегистрировали ни одного шага для своего питомца.")
@dp.message_handler(Text(equals=['Установить напоминание']), state=Pet.waiting_for_next_action)
async def set_reminder(message: types.Message, state: FSMContext):
async with state.proxy() as data:
pet = data['pet']
reminder_time = datetime.now() + timedelta(hours=24)
reminder_text = f"Не забудьте сегодня покормить {pet}!"
await bot.send_message(chat_id=message.chat.id, text=reminder_text, parse_mode=ParseMode.MARKDOWN)
await message.answer(f"Для вас было установлено напоминание о необходимости зарегистрировать шаги завтра.")
await state.finish()
@dp.message_handler(Text(equals=['Поменять питомца']), state=Pet.waiting_for_next_action)
async def change_pet(message: types.Message, state: FSMContext):
await message.answer('Пожалуйста, выберите животное:', reply_markup=types.ReplyKeyboardMarkup(
keyboard=[
[types.KeyboardButton(text='Собака'), types.KeyboardButton(text='Кот')],
[types.KeyboardButton(text='Кролик'), types.KeyboardButton(text='Попугай')],
],
resize_keyboard=True
))
await Pet.waiting_for_pet_choice.set()
@dp.message_handler(Text(equals=['Выйти']), state=Pet.waiting_for_next_action)
async def exit(message: types.Message, state: FSMContext):
await message.answer('Прощайте!')
await state.finish()
await message.answer("Что бы вы хотели сделать дальше?", reply_markup=types.ReplyKeyboardMarkup(
keyboard=[
[types.KeyboardButton(text='Шаги в журнале'), types.KeyboardButton(text='Проверить прогресс')],
[types.KeyboardButton(text='Отправить напоминание'), types.KeyboardButton(text='Поменять питомца')],
[types.KeyboardButton(text='Выйти')],
[types.KeyboardButton(text='Редактировать запись'), types.KeyboardButton(text='Удалить запись')],
],
resize_keyboard=True
))
await Pet.next()
@dp.message_handler(Text(equals=['Проверить прогресс']), state=Pet.waiting_for_steps_choice)
async def check_progress(message: types.Message, state: FSMContext):
async with state.proxy() as data:
pet = data['pet']
cursor = db.cursor()
cursor.execute("SELECT sum(steps) FROM pet_tracker WHERE pet=?", (pet,))
total_steps = cursor.fetchone()[0]
await message.answer(f"У вас всего {total_steps} шагов.")
@dp.message_handler(Text(equals=['Отправить напоминание']), state=Pet.waiting_for_steps_choice)
async def set_reminder(message: types.Message, state: FSMContext):
async with state.proxy() as data:
await message.answer(f"Когда вы хотите получать напоминание о необходимости обновить количество шагов?")
await Pet.waiting_for_reminder_time.set()
@dp.message_handler(lambda message: not message.text.isdigit(), state=Pet.waiting_for_reminder_time)
async def process_reminder_invalid(message: types.Message):
await message.answer("Введите число.")
@dp.message_handler(lambda message: message.text.isdigit(), state=Pet.waiting_for_reminder_time)
async def process_reminder(message: types.Message, state: FSMContext):
async with state.proxy() as data:
data['reminder_time'] = int(message.text)
pet = data['pet']
reminder_time = data['reminder_time']
reminder_datetime = datetime.now() + timedelta(hours=reminder_time)
reminder_text = f"Не забудьте покормить своего питомца шагами!"
await bot.send_message(chat_id=message.chat.id, text=reminder_text, reply_at=reminder_datetime)
await message.answer(f"Мы напомним вам через {reminder_time} часов.")
await state.finish()
@dp.message_handler(Text(equals=['Редактировать запись']), state=Pet.waiting_for_steps_choice)
async def edit_entry(message: types.Message, state: FSMContext):
async with state.proxy() as data:
pet = data['pet']
cursor = db.cursor()
cursor.execute("SELECT steps FROM pet_tracker WHERE pet=? AND username=?", (pet, message.from_user.username))
row = cursor.fetchone()
if not row:
await message.answer("Вы еще не зарегистрировали ни одного шага.")
await state.finish()
return
current_steps = row[0]
await message.answer(f"Вы сделали {current_steps} шагов сегодня.\n"
"Пожалуйста, введите новое уоличество шагов:")
await Pet.waiting_for_new_steps_number.set()
@dp.message_handler(lambda message: not message.text.isdigit(), state=Pet.waiting_for_new_steps_number)
async def process_new_steps_invalid(message: types.Message):
await message.answer("Введите число.")
@dp.message_handler(Text(equals=['Редактировать запись']), state=Pet.waiting_for_steps_choice)
async def edit_entry(message: types.Message, state: FSMContext):
async with state.proxy() as data:
pet = data['pet']
cursor = db.cursor()
cursor.execute("SELECT steps FROM pet_tracker WHERE pet=? AND username=?", (pet, message.from_user.username))
row = cursor.fetchone()
if not row:
await message.answer("Вы еще не зарегистрировали шаги.")
await state.finish()
return
current_steps = row[0]
await message.answer(f"Вы сделали {current_steps} шагов сегодня.\n"
"Пожалуйста, введите новое количество шагов:")
await Pet.waiting_for_new_steps_number.set()
@dp.message_handler(lambda message: message.text.isdigit(), state=Pet.waiting_for_new_steps_number)
async def process_new_steps(message: types.Message, state: FSMContext):
async with state.proxy() as data:
data['new_steps'] = int(message.text)
pet = data['pet']
cursor = db.cursor()
cursor.execute("UPDATE pet_tracker SET steps=? WHERE pet=? AND username=?",
(data['new_steps'], pet, message.from_user.username))
db.commit()
await message.answer(f"Количество шагов было обновлено: {data['new_steps']}.\n"
"Что бы вы хотели сделать дальше?",
reply_markup=types.ReplyKeyboardMarkup(
keyboard=[
[types.KeyboardButton(text='Поменять питомца'), types.KeyboardButton(text='Готово')],
],
resize_keyboard=True
))
await Pet.waiting_for_next_action.set()
@dp.message_handler(Text(equals=['Проверить прогресс', 'Отправить напоминание', 'Поменять питомца']), state=Pet.waiting_for_next_action)
async def process_next_action(message: types.Message, state: FSMContext):
async with state.proxy() as data:
data['next_action'] = message.text
next_action = data['next_action']
if next_action == 'Проверить прогресс':
cursor = db.cursor()
cursor.execute("SELECT sum(steps) FROM pet_tracker WHERE pet=?", (data['pet'],))
result = cursor.fetchone()
total_steps = result[0] if result[0] is not None else 0
await message.answer(f"Вы зарегистрировали {total_steps} шагов.")
elif next_action == 'Отправить напоминание':
await message.answer("В какое время вы хотите получать напоминание? (Пожалуйста, введите в формате ЧЧ:ММ, 24-часовые часы)")
await Pet.waiting_for_reminder_time.set()
elif next_action == 'Поменять питомца':
await message.answer('Выберите питомца:', reply_markup=types.ReplyKeyboardMarkup(
keyboard=[
[types.KeyboardButton(text='Собака'), types.KeyboardButton(text='Кот')],
[types.KeyboardButton(text='Кролик'), types.KeyboardButton(text='Кролик')],
],
resize_keyboard=True
))
await Pet.waiting_for_pet_choice.set()
@dp.message_handler(lambda message: not re.match(r'^\d{2}:\d{2}$', message.text), state=Pet.waiting_for_reminder_time)
async def process_reminder_time_invalid(message: types.Message):
await message.answer("Invalid format. Please enter time in HH:MM format, 24-hour clock.")
@dp.message_handler(lambda message: re.match(r'^\d{2}:\d{2}$', message.text), state=Pet.waiting_for_reminder_time)
async def process_reminder_time(message: types.Message, state: FSMContext):
async with state.proxy() as data:
data['reminder_time'] = message.text
reminder_time = data['reminder_time']
await message.answer(f"Мы будем напоминать в {reminder_time} каждый день.")
await state.finish()
async def send_reminder():
while True:
await asyncio.sleep(60)
cursor = db.cursor()
cursor.execute("SELECT DISTINCT username FROM pet_tracker")
result = cursor.fetchall()
for row in result:
username = row[0]
cursor.execute("SELECT pet, sum(steps) FROM pet_tracker WHERE username=? GROUP BY pet", (username,))
result = cursor.fetchall()
for row in result:
pet = row[0]
total_steps = row[1]
if total_steps == 0:
continue
cursor.execute("SELECT reminder_time FROM user_settings WHERE username=? AND pet=?", (username, pet))
result = cursor.fetchone()
if result is None or result[0] is None:
continue
reminder_time = result[0]
now = datetime.now()
if now.strftime('%H:%M') == reminder_time:
await bot.send_message(chat_id=username, text=f"Не забульте написать количество шагов за сегодня!")
if __name__ == '__main__':
executor.start_polling(dp, skip_updates=True)
db.execute("CREATE TABLE IF NOT EXISTS pet_tracker (pet text, steps integer, username text, date text)")
db.execute("CREATE TABLE IF NOT EXISTS user_settings (username text, pet text, reminder_time text)")
db.commit()
loop = asyncio.get_event_loop() |