-
Notifications
You must be signed in to change notification settings - Fork 0
/
tgtgtgbot.py
269 lines (231 loc) · 11.4 KB
/
tgtgtgbot.py
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
import logging
import logging.handlers
import time
import json
import sqlite3
from telegram import Update # https://github.com/python-telegram-bot/python-telegram-bot
from telegram.ext import filters, MessageHandler, ApplicationBuilder, ContextTypes, CommandHandler
from tgtg import TgtgClient # https://github.com/ahivert/tgtg-python
from sqlite3 import Error
from tgtg import TgtgAPIError, TgtgPollingError, TgtgLoginError
from requests.exceptions import ConnectionError
from email_validator import validate_email, EmailNotValidError # https://github.com/JoshData/python-email-validator
log_handler = logging.handlers.TimedRotatingFileHandler('tgtgtgbot.log', when='midnight')
formatter = logging.Formatter(
'%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
formatter.converter = time.localtime
log_handler.setFormatter(formatter)
logger = logging.getLogger()
logger.addHandler(log_handler)
logger.setLevel(logging.INFO)
async def command_help(update: Update, context: ContextTypes.DEFAULT_TYPE):
await context.bot.send_message(chat_id=update.effective_chat.id,
text='/help - this help\n'
'/start - start conversation\n'
'/email - register too good to go email\n'
'/pause - pause subscription\n'
'/resume - resume subscription\n'
'/info - show subscription info (TODO)\n'
'/delete - delete my subscription\n')
async def command_start(update: Update, context: ContextTypes.DEFAULT_TYPE):
user_first_name = update.effective_chat.first_name
user_is_bot = update.effective_user.is_bot
if user_is_bot:
await context.bot.send_message(chat_id=update.effective_chat.id,
text='Sorry, no bots allowed')
else:
# check status of this user and initiate registering
userid_tg = update.effective_chat.id
con = db_connection()
cursor = con.cursor()
cursor.execute(f"""SELECT * FROM users WHERE userid_tg={userid_tg}""")
result = cursor.fetchall()
if len(result) == 0:
# create row in dbase
cursor.execute(f"""INSERT INTO users (userid_tg, pause, sent_deals) VALUES ({userid_tg}, 0, '[]');""")
con.commit()
await context.bot.send_message(
chat_id=update.effective_chat.id,
text=f'Welcome {user_first_name},\n'
f'To access your Too Good To Go account please send us your email associated with Too Good To Go '
f'with the command: /email <your email>'
)
else:
await context.bot.send_message(
chat_id=update.effective_chat.id,
text=f'Welcome back {user_first_name}'
)
con.close()
async def command_pause(update: Update, context: ContextTypes.DEFAULT_TYPE):
# set pause flag in database for this user
con = db_connection()
cursor = con.cursor()
cursor.execute(f"""UPDATE users SET pause=1 WHERE userid_tg={update.effective_chat.id}""")
con.commit()
con.close()
await context.bot.send_message(chat_id=update.effective_chat.id,
text="Your subscription has been paused.\n"
"Reactivate your subscription with the command /resume")
async def command_resume(update: Update, context: ContextTypes.DEFAULT_TYPE):
# reset pause flag in database for this user
con = db_connection()
cursor = con.cursor()
cursor.execute(f"""UPDATE users SET pause=0 WHERE userid_tg={update.effective_chat.id}""")
cursor.execute(f"""UPDATE users SET sent_deals='[]' WHERE userid_tg={update.effective_chat.id}""")
con.commit()
con.close()
await context.bot.send_message(chat_id=update.effective_chat.id,
text="Your subscription has been resumed.\n"
"Pause your subscription with the command /pause")
async def command_info(update: Update, context: ContextTypes.DEFAULT_TYPE):
# show info for this user
con = db_connection()
cursor = con.cursor()
cursor.execute(f"""SELECT * FROM users WHERE userid_tg={update.effective_chat.id}""")
user = cursor.fetchall()[0]
con.close()
await context.bot.send_message(chat_id=update.effective_chat.id,
text=f"info: {user[0]}")
async def command_delete(update: Update, context: ContextTypes.DEFAULT_TYPE):
# remove this user from the database
con = db_connection()
cursor = con.cursor()
cursor.execute(f"""DELETE FROM users WHERE userid_tg={update.effective_chat.id}""")
con.commit()
con.close()
await context.bot.send_message(chat_id=update.effective_chat.id,
text='Your data is deleted.\n'
'To subscribe again type /start')
async def command_email(update: Update, context: ContextTypes.DEFAULT_TYPE):
# register user with tgtg api
user_tgtg_email = "".join(context.args)
# validate email
try:
v = validate_email(user_tgtg_email)
user_tgtg_email = v["email"]
await context.bot.send_message(chat_id=update.effective_chat.id,
text='An email is sent to you.\n'
'To confirm your registration please click on the link provided.\n'
'IMPORTANT! Do not click on the link on the same device that has '
'the Too Good To Go app')
try:
client = TgtgClient(email=user_tgtg_email)
credentials = client.get_credentials()
# store credentials
con = db_connection()
cursor = con.cursor()
cursor.execute(f"""UPDATE users SET
tgtg_accesstoken="{credentials['access_token']}",
tgtg_refreshtoken="{credentials['refresh_token']}",
tgtg_userid="{credentials['user_id']}",
tgtg_cookie="{credentials['cookie']}"
WHERE userid_tg={update.effective_chat.id};""")
con.commit()
con.close()
await context.bot.send_message(chat_id=update.effective_chat.id,
text='Your Too Good To Go access is registered with me\n'
'When your favorite deals are available I wll sent you a message.')
except TgtgPollingError as e:
logging.info(str(e))
except EmailNotValidError as e:
logging.info(f'{e}: {user_tgtg_email}')
await context.bot.send_message(chat_id=update.effective_chat.id,
text=str(e) + '\nPlease try again')
async def echo(update: Update, context: ContextTypes.DEFAULT_TYPE):
await context.bot.send_message(chat_id=update.effective_chat.id,
text='Type /help for an overview of all commands')
def db_connection():
conn = None
try:
conn = sqlite3.connect('tgtgtgbot.sqlite')
cursor = conn.cursor()
cursor.execute("""
CREATE TABLE IF NOT EXISTS users
([userid_tg] INTEGER,
[tgtg_accesstoken] TEXT,
[tgtg_refreshtoken] TEXT,
[tgtg_userid] TEXT,
[tgtg_cookie] TEXT,
[pause] INTEGER,
[last_seen] INTEGER,
[sent_deals] TEXT)
""")
conn.commit()
except Error as e:
logging.error(e)
return conn
def retrieve_active_user_list(conn):
cursor = conn.cursor()
cursor.execute("""SELECT * FROM users WHERE pause=0 AND tgtg_cookie IS NOT NULL;""")
return cursor.fetchall()
def update_sent_deals(conn, telegram_user_id, message_sent_lst):
cursor = conn.cursor()
msl_json = json.dumps(message_sent_lst)
cursor.execute(f"""UPDATE users SET sent_deals='{msl_json}' where userid_tg={telegram_user_id};""")
conn.commit()
async def job_tgtg(context: ContextTypes.DEFAULT_TYPE):
dbconn = db_connection()
active_user_list = retrieve_active_user_list(dbconn)
logging.info(f'processing {len(active_user_list)} toogoodtogo user(s)')
for user in active_user_list:
update_user_flag = False
sent_deals = [] if not user[7] else json.loads(user[7])
tgtg_client = TgtgClient(access_token=user[1],
refresh_token=user[2],
user_id=user[3],
cookie=user[4],)
try:
items = tgtg_client.get_items()
except (TgtgAPIError, ConnectionError, TgtgLoginError, TgtgPollingError) as e:
logging.error(e)
time.sleep(10)
continue
for item in items:
if item['items_available'] and item['in_sales_window']:
if item['item']['item_id'] not in sent_deals:
message = f'{item["store"]["store_name"]} ' \
f'{item["store"]["store_location"]["address"]["address_line"]} ' \
f'{item["item"]["name"]} ' \
f'{item["items_available"]}\n' \
f'https://share.toogoodtogo.com/item/{item["item"]["item_id"]}/'
await context.bot.send_message(chat_id=user[0], text=message)
sent_deals.append(item['item']['item_id'])
update_user_flag = True
elif item['item']['item_id'] in sent_deals:
sent_deals.remove(item['item']['item_id'])
update_user_flag = True
if update_user_flag:
update_sent_deals(dbconn, user[0], sent_deals)
dbconn.close()
if __name__ == '__main__':
with open('telegram_bot_token.txt', 'r') as tbt_file:
telegram_bot_token = json.load(tbt_file)
application = ApplicationBuilder().token(telegram_bot_token["telegram_bot_token"]).build()
job_queue = application.job_queue
help_handler = CommandHandler('help', command_help)
start_handler = CommandHandler('start', command_start)
pause_handler = CommandHandler('pause', command_pause)
resume_handler = CommandHandler('resume', command_resume)
status_handler = CommandHandler('info', command_info)
delete_handler = CommandHandler('delete', command_delete)
email_handler = CommandHandler('email', command_email)
echo_handler = MessageHandler(filters.TEXT & (~filters.COMMAND), echo)
application.add_handler(help_handler)
application.add_handler(start_handler)
application.add_handler(pause_handler)
application.add_handler(resume_handler)
application.add_handler(status_handler)
application.add_handler(delete_handler)
application.add_handler(email_handler)
application.add_handler(echo_handler)
job_tgtg = job_queue.run_repeating(job_tgtg, interval=300, first=10)
application.run_polling()
'''
application.run_webhook(
listen='0.0.0.0',
port=eval(telegram_bot_token["telegram_webhook_port"]),
secret_token=telegram_bot_token["telegram_secret_token"],
webhook_url=telegram_bot_token["telegram_webhook_url"] + ':' + telegram_bot_token["telegram_webhook_port"]
)
'''