Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
2169a3e
fix bot syntax and token)
ashat1701 Apr 21, 2019
7f6a4d1
Try to up flask server..
Apr 23, 2019
a3e52c8
fix server
Apr 23, 2019
df9fba6
fix server
Apr 23, 2019
c153972
fix http server and add command to start
ashat1701 Apr 23, 2019
4814ec3
move http server to another project
ashat1701 Apr 23, 2019
4ca78e0
add login handler
Apr 23, 2019
6acb685
fix handlers with beta version of API
Apr 23, 2019
9077ab4
fix singleton
Apr 23, 2019
c40f3c0
fix login handler
Apr 23, 2019
ecd6e83
Google API docs lied)
Apr 23, 2019
e040b65
fix chat_id to str
Apr 23, 2019
e2ff912
fix base64
Apr 23, 2019
006e1d4
fix json and db
ashat1701 Apr 24, 2019
1d013c6
fix auth
Apr 24, 2019
bb22231
add handlers for db
Apr 24, 2019
c9b248f
fix tuple
Apr 24, 2019
f9b0f59
fix db
ashat1701 Apr 24, 2019
dfeb649
fix start_callback
Apr 24, 2019
7373216
fix start_callback
Apr 24, 2019
826cb7b
fix start_callback
Apr 24, 2019
436d205
fix start_callback
Apr 24, 2019
b1cf811
add menu
Apr 24, 2019
29f806f
fix menu
ashat1701 Apr 24, 2019
735068a
another fix menu
ashat1701 Apr 24, 2019
8029862
Add logout and today_tasks handler
Apr 25, 2019
aaf021b
fix echo_callback
Apr 25, 2019
1602dc2
temp fix
Apr 25, 2019
de38d71
naming fix
Apr 25, 2019
042658b
naming fix
Apr 25, 2019
bc257c8
db fix
Apr 25, 2019
f498571
db fix
Apr 25, 2019
e092259
db fix
ashat1701 Apr 25, 2019
f06bdcb
fix gcalendar
Apr 25, 2019
13dccad
fix req
ashat1701 Apr 25, 2019
1ec3812
fix gapi req
ashat1701 Apr 25, 2019
a1aaafc
fix gapi req
Apr 25, 2019
eba23fb
fix some bugs
ashat1701 Apr 25, 2019
248254b
fix some bugs
Apr 25, 2019
2c56512
fix some bugs
ashat1701 Apr 25, 2019
f9ceb16
fix some st
Apr 25, 2019
f2b123f
fix some st
ashat1701 Apr 26, 2019
10ae967
add events handler
ashat1701 Apr 27, 2019
b709421
fix gcalendar
Apr 27, 2019
dcee55e
add daily announcment
Apr 27, 2019
c7fee95
fix some shit
Apr 27, 2019
cdddc9b
fix some shi
ashat1701 Apr 27, 2019
9f57a9a
fix some bugs
Apr 27, 2019
ce71076
Reformat code
ashat1701 May 19, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
137 changes: 137 additions & 0 deletions callbacks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
import datetime

import dateutil.parser
import pytz
import telegram

import database
import gauth
import gcalendar


def get_menu():
buttons = [["/plan", "/get_today_tasks"], ["/logout"]]
reply_markup = telegram.ReplyKeyboardMarkup(buttons, resize_keyboard=True)
return reply_markup


def text_callback(update, context):
reply_markup = telegram.ReplyKeyboardMarkup([["/cancel"]], resize_keyboard=True)
if "state" in context.user_data:
if context.user_data["state"] == "summary":
context.user_data["state"] = "date"
context.user_data["summary"] = update.message.text
context.bot.send_message(chat_id=update.message.chat_id, text="Введите дату в формате ГГГГ-ММ-ДД",
reply_markup=reply_markup)
elif context.user_data["state"] == "date":
context.user_data["state"] = "time"
# TODO: check if it is correct date
context.user_data["date"] = update.message.text
context.bot.send_message(chat_id=update.message.chat_id, text="Введите время события",
reply_markup=reply_markup)
elif context.user_data["state"] == "time":
gcalendar.set_new_task(update.message.chat_id, update.message.text, context.user_data["date"],
context.user_data["summary"])
context.bot.send_message(chat_id=update.message.chat_id, text="Задача успешно добавлена",
reply_markup=get_menu())
else:
context.bot.send_message(chat_id=update.message.chat_id, text="Команда не распознана", reply_markup=get_menu())


def plan_callback(update, context):
context.user_data["state"] = "summary"
reply_markup = telegram.ReplyKeyboardMarkup([["/cancel"]], resize_keyboard=True)
context.bot.send_message(chat_id=update.message.chat_id, text="Введите текст для задачи.",
reply_markup=reply_markup)


def back_callback(update, context):
pass


def cancel_callback(update, context):
context.user_data.clear()
context.bot.send_message(chat_id=update.message.chat_id, text="Выберете команду", reply_markup=get_menu())


def logout_callback(update, context):
db = database.Database()
chat_id = update.message.chat_id
db.delete_cred(chat_id)
start_callback(update, context)


def get_today_tasks_callback(update, context):
chat_id = update.message.chat_id
db = database.Database()
if db.is_auth(chat_id):
response = gcalendar.get_today_tasks_list(chat_id)
if not response:
context.bot.send_message(chat_id=chat_id, text="Ваш день сегодня свободен. Везет же)",
reply_markup=get_menu())
else:
text = "События на сегодня: \n"
counter = 1
for event in response:
text = text + str(counter) + ". " + event["start"].get("dateTime", event['start'].get('date')) + "\n"
text = text + event["summary"] + "\n"
counter += 1
context.bot.send_message(chat_id=chat_id, text=text, reply_markup=get_menu())
else:
reply_markup = telegram.ReplyKeyboardMarkup([["/login"]], resize_keyboard=True)
context.bot.send_message(chat_id=chat_id, text="Вам необходимо войти в аккаунт. Используйте /login",
reply_markup=reply_markup)


def login_callback(update, context):
db = database.Database()
chat_id = update.message.chat_id
if db.is_auth(chat_id):
context.bot.send_message(chat_id=chat_id, text="Вы уже вошли в свой аккаунт.", reply_markup=get_menu())
else:
googleAuth = gauth.GoogleAuth(chat_id)
reply_markup = telegram.ReplyKeyboardMarkup([["/login"]], resize_keyboard=True)
# TODO : strange behavior with /login twice
context.bot.send_message(chat_id=chat_id, text=googleAuth.generate_url(), reply_markup=reply_markup)


def start_callback(update, context):
args = "".join(context.args)
if args == "":
reply_markup = telegram.ReplyKeyboardMarkup([["/login"]], resize_keyboard=True)
context.bot.send_message(chat_id=int(update.message.chat_id),
text="Здравствуйте! Вам нужно войти в свой аккаунт Google для использования этого бота",
reply_markup=reply_markup)
else:
db = database.Database()
chat_id = args
if db.is_auth(chat_id):
context.bot.send_message(chat_id=int(chat_id), text="Вы успешно вошли в аккаунт", reply_markup=get_menu())
context.job_queue.run_daily(daily_announce, datetime.time(hour=8, minute=0, second=0,
tzinfo=pytz.timezone("Europe/Moscow")))
else:
reply_markup = telegram.ReplyKeyboardMarkup([["/login"]], resize_keyboard=True)
context.bot.send_message(chat_id=int(chat_id), text="Вам необходимо войти в аккаунт. Используйте /login",
reply_markup=reply_markup)


def daily_announce(bot, job):
# TODO: Repeating code
chat_id = job.context
db = database.Database()
if db.is_auth(chat_id):
bot.send_message(chat_id=chat_id, text="Доброе утро!")
response = gcalendar.get_today_tasks_list(chat_id)
if not response:
bot.send_message(chat_id=chat_id, text="Ваш день сегодня свободен. Везет же)",
reply_markup=get_menu())
else:
text = "События на сегодня: \n"
counter = 1
# TODO: add enumerate
for event in response:
date = dateutil.parser.parse(event["start"].get("dateTime", event['start'].get('date')))
text = text + str(counter) + ". {}:{}".format(date.time().hour, date.time().minute) + + "\n"
text = text + event["summary"] + "\n"
counter += 1
bot.send_message(chat_id=chat_id, text=text, reply_markup=get_menu())
40 changes: 40 additions & 0 deletions database.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import logging
import os

import psycopg2
from psycopg2.extras import RealDictCursor


class Database:
__instance = None

def __new__(cls, *args, **kwargs):
if cls.__instance is None:
cls.__instance = super().__new__(cls, *args, **kwargs)
DATABASE_URL = os.environ['DATABASE_URL']
try:
cls.__instance.conn = psycopg2.connect(DATABASE_URL, sslmode='require')
except ConnectionError:
logging.error("No database in DATABASE_URL environ")
return cls.__instance

def get_cred(self, chat_id):
cursor = self.conn.cursor(cursor_factory=RealDictCursor)
cursor.execute("SELECT * FROM auth WHERE chat_id = %s", (str(chat_id),))
return cursor.fetchall()[0]

def is_auth(self, chat_id):
cursor = self.conn.cursor(cursor_factory=RealDictCursor)
cursor.execute("SELECT chat_id FROM auth WHERE chat_id = %s", (str(chat_id),))
if cursor.fetchone() is not None:
cursor.close()
return True
else:
cursor.close()
return False

def delete_cred(self, chat_id):
cursor = self.conn.cursor(cursor_factory=RealDictCursor)
cursor.execute("DELETE FROM auth WHERE chat_id = %s", (str(chat_id),))
self.conn.commit()
cursor.close()
19 changes: 19 additions & 0 deletions gauth.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import google_auth_oauthlib.flow


class GoogleAuth:
def __init__(self, chat_id):
self.chat_id = chat_id

def generate_url(self):
flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
'client_secret.json',
scopes=['https://www.googleapis.com/auth/calendar.events'])

flow.redirect_uri = "https://server-for-task-bot.herokuapp.com/login"
state = str(self.chat_id)
authorization_url, st = flow.authorization_url(
access_type='offline',
state=state,
include_granted_scopes='true')
return authorization_url
50 changes: 50 additions & 0 deletions gcalendar.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import datetime
import logging

import google.oauth2.credentials
import googleapiclient.discovery
import pytz

import database


def get_today_tasks_list(chat_id):
db = database.Database()
creds_dict = db.get_cred(chat_id)
del creds_dict["chat_id"]
logging.info("Get new task list request{}".format(creds_dict))
credentials = google.oauth2.credentials.Credentials(**creds_dict)
calendar = googleapiclient.discovery.build("calendar", "v3", credentials=credentials)
# TODO: fix this for other UTC
date = datetime.datetime.now(pytz.timezone('Europe/Moscow'))
today = datetime.datetime.combine(datetime.date(date.year, date.month, date.day), datetime.datetime.min.time())
start_of_day = today.isoformat() + '+03:00'
end = datetime.datetime.combine(datetime.date(date.year, date.month, date.day), datetime.datetime.max.time())
end_of_day = end.isoformat() + '+03:00'
events_result = calendar.events().list(calendarId="primary", singleEvents=True, orderBy='startTime',
timeMin=start_of_day, timeMax=end_of_day).execute()
events = events_result.get('items', [])
if not events:
return False
else:
return events


def set_new_task(chat_id, time, date, summary):
db = database.Database()
creds_dict = db.get_cred(chat_id)
del creds_dict["chat_id"]
credentials = google.oauth2.credentials.Credentials(**creds_dict)
calendar = googleapiclient.discovery.build("calendar", "v3", credentials=credentials)
event = {
'summary': summary,
'start': {
'dateTime': date + "T" + time + ":00+03:00",
'timeZone': 'Europe/Moscow',
},
'end': {
'dateTime': date + "T" + time + ":00+03:00",
'timeZone': 'Europe/Moscow',
},
}
calendar.events().insert(calendarId="primary", body=event).execute()
12 changes: 12 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1 +1,13 @@
python-telegram-bot==12.0.0b1
google-api-python-client
google
google-auth
google-auth-oauthlib
google-auth-httplib2
psycopg2-binary
google
oauth2client
googleapis-common-protos
google-cloud
pytz
python-dateutil
32 changes: 21 additions & 11 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,32 @@
import telegram.ext
import os
import logging
logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
level=logging.INFO)
import os

import telegram.ext

def echo(update, context):
context.bot.send_message(chat_id=update.message.chat_id, text=update.message.text)
from callbacks import text_callback, login_callback, start_callback, logout_callback, get_today_tasks_callback, \
plan_callback, cancel_callback

logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
level=logging.INFO)

TOKEN = os.environ["TOKEN"]
SECRET_CLIENT = os.environ["SECRET_TOKEN"]
with open("client_secret.json", "w") as f:
print(SECRET_CLIENT, file=f)

TOKEN = "820703303:AAHZXbuIVVA4oQm4s6SrxNtV7WX9m1xNGw8"
PORT = int(os.environ.get('PORT', '8443'))
updater = telegram.ext.Updater(token=TOKEN)
updater = telegram.ext.Updater(token=TOKEN, use_context=True)
dispatcher = updater.dispatcher
dispatcher.add_handler(telegram.ext.MessageHandler(telegram.ext.Filters.text, echo))

dispatcher.add_handler(telegram.ext.MessageHandler(telegram.ext.Filters.text, text_callback))
dispatcher.add_handler(telegram.ext.CommandHandler('login', login_callback))
dispatcher.add_handler(telegram.ext.CommandHandler("start", start_callback, pass_args=True))
dispatcher.add_handler(telegram.ext.CommandHandler("logout", logout_callback))
dispatcher.add_handler(telegram.ext.CommandHandler("get_today_tasks", get_today_tasks_callback))
dispatcher.add_handler(telegram.ext.CommandHandler("plan", plan_callback))
dispatcher.add_handler(telegram.ext.CommandHandler("cancel", cancel_callback))
updater.start_webhook(listen="0.0.0.0",
port=PORT,
url_path=TOKEN)
updater.bot.set_webhook("https://yet-another-task-bot.herokuapp.com/" + TOKEN)

updater.idle()
updater.idle()