I have a Telegram bot which sends users' answers to Google Sheets columns, including the Google Drive link to the file they attach (pygsheets and pydrive libraries used). The table looks like that.
There are two scenarios whether the user sends a voice message or an audio. Everything works fine till the bot is used simultaneously by several users. The users' inputs overlay and the table becomes a mess. I want the bot to work with each user independently.
In Stack (here, here, here) I read that I need to get rid of the global variables and use OOP and classes but I have no idea how it should be implemented. Also I saw that dictionaries might be useful so that the user's id becomes a key (here, here).
Could you please help me with the code? I'm not really a developer, this is a part of my study project. Here is the beginning and the end of the scenario when the user chooses to send a pre-recorded audio:
import telebot
from telebot import types
import pygsheets
import config
from datetime import datetime
import pytz
from twython import Twython, TwythonError
from pydrive.auth import GoogleAuth
from pydrive.drive import GoogleDrive
import requests
import json
import re
settings = Twython(config.TOKEN, config.table_name, config.client_secret, \
config.sheet_1, config.sheet_2, config.folderName, config.credentials)
bot = telebot.TeleBot(config.TOKEN)
# Google Drive authentification
gauth = GoogleAuth()
gauth.LoadCredentialsFile(config.credentials)
if gauth.credentials is None:
gauth.LocalWebserverAuth()
elif gauth.access_token_expired:
gauth.Refresh()
else:
gauth.Authorize()
gauth.SaveCredentialsFile(config.credentials)
drive = GoogleDrive(gauth)
# Setting the folder name where to upload users' attachments
folders = drive.ListFile({
'q': "title='" + config.folderName + "' and mimeType='application/vnd.google-apps.folder' and trashed=false"
}).GetList()
# Connecting to the table and its worksheets
gc = pygsheets.authorize(client_secret=config.client_secret)
sh = gc.open(config.table_name)
no_voice_sheet = sh.worksheet('title', config.sheet_1)
# Defining the variable to save users' answers
no_voice_answers = []
@bot.message_handler(commands=['start'])
def greeting(message):
markup = types.ReplyKeyboardMarkup(resize_keyboard=True)
button1 = types.KeyboardButton('Record now')
button2 = types.KeyboardButton('Already recorded')
markup.add(button1, button2)
bot.send_message(message.from_user.id, f'''Hi, this is a bot of our team! To erase the entered answers and start over, write /reset. \n
Do you want to _record now_, or it's _already recorded_?''', \
reply_markup=markup, parse_mode='Markdown')
bot.register_next_step_handler(message, voice_or_audio)
@bot.message_handler(content_type=['voice', 'text', 'audio', 'location'])
def voice_or_audio(message):
if (message.text == 'Record now'):
markup = types.ReplyKeyboardRemove(selective=False)
bot.send_message(message.from_user.id, f'''Time to record! ''', reply_markup=markup, parse_mode='Markdown')
bot.register_next_step_handler(message, get_voice) # Voice scenario starts
elif (message.text == 'Already recorded'):
markup = types.ReplyKeyboardRemove(selective=False)
bot.send_message(message.from_user.id, f'''Then let's fill in some info beforehand. \n
Write your email''' \
, reply_markup=markup, parse_mode='Markdown')
bot.register_next_step_handler(message, get_mail) # Audio scenario starts
else:
bot.send_message(message.from_user.id, 'Choose one of the options.')
greeting(message)
# Pre-recorded audio scenario
def get_mail(message):
global no_voice_answers
if message.content_type == 'text' and bool(re.search(r"^[\w\.\+\-]+\@[\w]+\.[a-z]{2,3}$", message.text.lower())):
no_voice_answers.append(message.text.lower())
bot.send_message(message.from_user.id, 'Great! When was the story recoded? (format: *02.02.2022, 02:00*)' , parse_mode='Markdown')
bot.register_next_step_handler(message, get_datetime)
elif message.text == '/reset':
no_voice_answers.clear()
greeting(message)
else:
bot.send_message(message.from_user.id, 'Check if the email is correct.')
bot.register_next_step_handler(message, get_mail)
def get_datetime(message):
global no_voice_answers
f = '%d.%m.%Y, %H:%M'
if message.text == '/reset':
no_voice_answers.clear()
greeting(message)
else:
try:
res = datetime.strptime(message.text, f)
if res < datetime.today():
no_voice_answers.append(message.text)
bot.send_message(message.from_user.id, f'''To put your sound on the map, we'll need coordinates. For example, *50.450441, 30.523550* \n
If you're where the sound was recorded, feel free to send your location''', \
parse_mode='Markdown')
bot.register_next_step_handler(message, get_coordinates)
else:
bot.send_message(message.from_user.id, 'Was your file recorded in the future? ')
bot.register_next_step_handler(message, get_datetime)
except:
bot.send_message(message.from_user.id, 'Is the format correct?')
bot.register_next_step_handler(message, get_datetime)
# Some more steps here to get to the final step
def get_file(message):
global no_voice_answers
global no_voice_sheet
if message.content_type == 'audio':
utc_time = datetime.fromtimestamp(message.date)
perm = pytz.timezone('Asia/Yekaterinburg')
perm_time = str(utc_time.astimezone(perm))
no_voice_answers.append(perm_time)
file_name = message.audio.file_name
file_info = bot.get_file(message.audio.file_id)
downloaded_file = bot.download_file(file_info.file_path)
with open(file_name, 'wb') as new_file:
new_file.write(downloaded_file)
new_file.close()
for folder in folders:
if folder['title'] == config.folderName:
file = drive.CreateFile({'parents': [{'id': folder['id']}]})
file.SetContentFile(file_name)
file.Upload()
access_token = gauth.credentials.access_token
file_id = file['id']
url = 'https://www.googleapis.com/drive/v3/files/' + file_id + '/permissions?supportsAllDrives=true'
headers = {'Authorization': 'Bearer ' + access_token, 'Content-Type': 'application/json'}
payload = {'type': 'anyone', 'value': 'anyone', 'role': 'reader'}
res = requests.post(url, data=json.dumps(payload), headers=headers)
no_voice_link = file['alternateLink']
no_voice_answers.append(no_voice_link)
no_voice_sheet.append_table(no_voice_answers)
no_voice_answers.clear()
bot.send_message(message.from_user.id, f'''Thank you! Your story will soon appear on the map \n
To upload one more story, write /start.''')
elif message.text == '/reset':
no_voice_answers.clear()
greeting(message)
else:
bot.send_message(message.from_user.id, 'Seems like you are uploading the wrong file.')
bot.register_next_step_handler(message, get_file)
bot.polling(none_stop=True)
If there's any necessary information I didn't provide, please let me know. Code solutions would be highly appreciated.