1
0
mirror of https://gitlab.com/questable/questable_bot synced 2025-07-12 06:56:53 +02:00

Compare commits

...

10 Commits
2.0 ... master

Author SHA1 Message Date
6116594eb4 [fix] Re-order dispatchers so that /s?q_\d* commands work 2021-04-24 12:43:22 +05:30
1f0a05ca9d Allows CORS 2019-05-31 10:41:28 +05:30
d2b70dacd8 Update README. 2019-05-21 16:27:47 +05:30
c5b7eba052 Update README. 2019-05-21 16:24:41 +05:30
1cc0743061 Add client list in tokens. 2019-05-21 16:04:06 +05:30
514117a079 Convert qid to int 2019-05-21 13:28:59 +05:30
ac3e09fb19 Fix state being True even if it is false. 2019-05-21 13:15:25 +05:30
3604248a83 Fix typo 2019-05-13 19:48:44 +05:30
0ab2fa5b6b Add ls to list both quests and side quests 2019-05-11 12:29:21 +05:30
0a41d3d868 Add initial shortcuts 2019-04-13 00:55:56 +05:30
5 changed files with 118 additions and 48 deletions

View File

@ -1,3 +1,30 @@
# Questable # Questable
A game-like To-Do List Telegram Bot A game-like To-Do List Telegram Bot.
Source code for [Questable Bot](https://t.me/questable_bot) and the relevant
[API](https://api.questable.webionite.com/)
# Self Hosting
+ Clone the repository.
+ `git clone https://gitlab.com/questable/questable_bot.git`
+ `cd questable`
## Telegram Bot
+ Install the dependencies
+ `pip3 install python-telegram-bot`
+ Copy `sample.config.py` to `config.py` and edit it accordingly.
+ Run the bot
+ `python3 bot.py`
## Questable API Server
+ Install the dependencies
+ `pip3 install Flask flask_cors`
+ Install `gunicorn`
+ `pip3 install gunicorn`
+ Run `gunicorn3 -b 127.0.0.1:5000 server:app`. Change port if you want to run
gunicorn on a different port.
+ Set up a reverse proxy from your webserver to `localhost:5000`.

83
bot.py
View File

@ -98,11 +98,11 @@ def add_name(bot, update, player, type, qid):
def add_diff(bot, update, player, type, qid): def add_diff(bot, update, player, type, qid):
message = update.message.text.lower() message = update.message.text.lower()
chat_id = update.message.chat_id chat_id = update.message.chat_id
if message == "low" or message == "📙 low": if message in ["low", "📙 low", "l"]:
diff = 1 diff = 1
elif message == "medium" or message == "📘 medium": elif message in ["medium", "📘 medium", "m"]:
diff = 2 diff = 2
elif message == "high" or message == "📗 high": elif message in ["high", "📗 high", "h"]:
diff = 3 diff = 3
else: else:
bot.send_message(chat_id=chat_id, text="Invalid Option") bot.send_message(chat_id=chat_id, text="Invalid Option")
@ -129,11 +129,11 @@ def add_diff(bot, update, player, type, qid):
def add_imp(bot, update, player, type, qid): def add_imp(bot, update, player, type, qid):
message = update.message.text.lower() message = update.message.text.lower()
chat_id = update.message.chat_id chat_id = update.message.chat_id
if message == "low" or message == "🔹 low": if message in ["low", "🔹 low", "l"]:
imp = 1 imp = 1
elif message == "medium" or message == "🔸 medium": elif message in ["medium", "🔸 medium", "m"]:
imp = 2 imp = 2
elif message == "high" or message == "🔺 high": elif message in ["high", "🔺 high", "h"]:
imp = 3 imp = 3
else: else:
bot.send_message(chat_id=chat_id, text="Invalid Option") bot.send_message(chat_id=chat_id, text="Invalid Option")
@ -305,11 +305,11 @@ def edit_quest(bot, update, player, qid, target, type):
text = "<b>☑️ Updated Name</b>" text = "<b>☑️ Updated Name</b>"
elif target == "imp": elif target == "imp":
message = message.lower() message = message.lower()
if message == "low" or message == "🔹 low": if message in ["low", "🔹 low", "l"]:
x.imp = 1 x.imp = 1
elif message == "medium" or message == "🔸 medium": elif message in ["medium", "🔸 medium", "m"]:
x.imp = 2 x.imp = 2
elif message == "high" or message == "🔺 high": elif message in ["high", "🔺 high", "h"]:
x.imp = 3 x.imp = 3
else: else:
bot.send_message(chat_id=chat_id, text="Invalid Option") bot.send_message(chat_id=chat_id, text="Invalid Option")
@ -317,11 +317,11 @@ def edit_quest(bot, update, player, qid, target, type):
text = "<b>☑️ Updated Priority</b>" text = "<b>☑️ Updated Priority</b>"
elif target == "diff": elif target == "diff":
message = message.lower() message = message.lower()
if message == "low" or message == "📙 low": if message in ["low", "📙 low", "l"]:
x.diff = 1 x.diff = 1
elif message == "medium" or message == "📘 medium": elif message in ["medium", "📘 medium", "m"]:
x.diff = 2 x.diff = 2
elif message == "high" or message == "📗 high": elif message in ["high", "📗 high", "h"]:
x.diff = 3 x.diff = 3
else: else:
bot.send_message(chat_id=chat_id, text="Invalid Option") bot.send_message(chat_id=chat_id, text="Invalid Option")
@ -401,9 +401,13 @@ def tokens(bot, update):
reply_markup = telegram.ReplyKeyboardMarkup(custom_keyboard) reply_markup = telegram.ReplyKeyboardMarkup(custom_keyboard)
reply_text = ("Tokens are used to authenticate external " reply_text = ("Tokens are used to authenticate external "
"applications. This only provides access to " "applications. This only provides access to "
"Questable data.") "Questable data.\n"
"\nOfficial clients are:\n"
"[Questable CLI](https://gitlab.com/questable/questable-cli)"
)
bot.send_message(chat_id=update.message.chat_id, text=reply_text, bot.send_message(chat_id=update.message.chat_id, text=reply_text,
reply_markup=reply_markup) reply_markup=reply_markup, parse_mode="markdown",
disable_web_page_preview=True)
def add_token(bot, update, player): def add_token(bot, update, player):
@ -466,24 +470,25 @@ def message_handling(bot, update, db):
# rt: Remove token # rt: Remove token
if state["state"] == "none": if state["state"] == "none":
if text == "add quest" or text == "❇️ add quest": if text in ["add quest", "❇️ add quest", "aq"]:
add_quest(bot, update, player) add_quest(bot, update, player)
elif text == "add side quest" or text == "📯 add side quest": elif text in ["add side quest", "📯 add side quest", "asq"]:
add_quest(bot, update, player, "side_quest") add_quest(bot, update, player, "side_quest")
elif text == "list quests" or text == "📜 list quests": elif text in ["list quests", "📜 list quests", "lq"]:
list_quests(bot, update, player, "quest") list_quests(bot, update, player, "quest")
elif text == "list side quests" or text == "📃 list side quests": elif text in ["list side quests", "📃 list side quests", "lsq"]:
list_quests(bot, update, player, "side_quest") list_quests(bot, update, player, "side_quest")
elif text == "tokens" or text == "🔑 tokens": elif text in ["tokens", "🔑 tokens", "t"]:
tokens(bot, update) tokens(bot, update)
elif text == "list tokens" or text == "📋 list tokens": elif text in ["list tokens", "📋 list tokens", "lt"]:
list_tokens(bot, update, player) list_tokens(bot, update, player)
elif text in ["generate token", "🔑 generate token", "gt"]:
elif text == "generate token" or text == "🔑 generate token":
add_token(bot, update, player) add_token(bot, update, player)
elif text in ["delete token", "🧹 delete token", "dt"]:
elif text == "delete token" or text == "🧹 delete token":
delete_token(bot, update, player) delete_token(bot, update, player)
elif text == "ls":
list_quests(bot, update, player, "side_quest")
list_quests(bot, update, player, "quest")
else: else:
if update.message.chat.type == "private": if update.message.chat.type == "private":
@ -508,32 +513,32 @@ def message_handling(bot, update, db):
add_imp(bot, update, player, "side_quest", state["extra"]) add_imp(bot, update, player, "side_quest", state["extra"])
elif state["state"] == "eq": elif state["state"] == "eq":
if text == "back" or text == "⬅️ back": if text in ["back", "⬅️ back", "b"]:
player.set_state('none', 0) player.set_state('none', 0)
send_status(bot, update, player) send_status(bot, update, player)
elif text == "mark as done" or text == "✅ mark as done": elif text in ["mark as done", "✅ mark as done", "mad"]:
mark_as_done(bot, update, player, state["extra"], "quest") mark_as_done(bot, update, player, state["extra"], "quest")
elif text == "edit name" or text == "📝 edit name": elif text in ["edit name", "📝 edit name", "en"]:
player.set_state('eqn', state["extra"]) player.set_state('eqn', state["extra"])
text = "What shall the new name of the Quest be?" text = "What shall the new name of the Quest be?"
reply_markup = telegram.ReplyKeyboardRemove() reply_markup = telegram.ReplyKeyboardRemove()
bot.send_message(chat_id=player.CHAT_ID, text=text, bot.send_message(chat_id=player.CHAT_ID, text=text,
reply_markup=reply_markup) reply_markup=reply_markup)
elif text == "change priority" or text == "⚠️ change priority": elif text in ["change priority", "⚠️ change priority", "cp"]:
player.set_state('eqi', state["extra"]) player.set_state('eqi', state["extra"])
text = "How important is it?" text = "How important is it?"
custom_keyboard = button_groups.importance custom_keyboard = button_groups.importance
reply_markup = telegram.ReplyKeyboardMarkup(custom_keyboard) reply_markup = telegram.ReplyKeyboardMarkup(custom_keyboard)
bot.send_message(chat_id=player.CHAT_ID, text=text, bot.send_message(chat_id=player.CHAT_ID, text=text,
reply_markup=reply_markup) reply_markup=reply_markup)
elif text == "change difficulty" or text == "📚 change difficulty": elif text in ["change difficulty", "📚 change difficulty", "cd"]:
player.set_state('eqd', state["extra"]) player.set_state('eqd', state["extra"])
text = "How difficult is it?" text = "How difficult is it?"
custom_keyboard = button_groups.difficulty custom_keyboard = button_groups.difficulty
reply_markup = telegram.ReplyKeyboardMarkup(custom_keyboard) reply_markup = telegram.ReplyKeyboardMarkup(custom_keyboard)
bot.send_message(chat_id=player.CHAT_ID, text=text, bot.send_message(chat_id=player.CHAT_ID, text=text,
reply_markup=reply_markup) reply_markup=reply_markup)
elif text == "delete quest" or text == "🗑 delete quest": elif text in ["delete quest", "🗑 delete quest", "dq"]:
quest = questable.get_quest(db, player.CHAT_ID, state["extra"]) quest = questable.get_quest(db, player.CHAT_ID, state["extra"])
quest.delete_from_db() quest.delete_from_db()
drop_state(bot, update, player) drop_state(bot, update, player)
@ -545,32 +550,32 @@ def message_handling(bot, update, db):
send_status(bot, update, player) send_status(bot, update, player)
elif state["state"] == "esq": elif state["state"] == "esq":
if text == "back" or text == "⬅️ back": if text in ["back", "⬅️ back", "b"]:
player.set_state('none', 0) player.set_state('none', 0)
send_status(bot, update, player) send_status(bot, update, player)
elif text == "mark as done" or text == "✅ mark as done": elif text in ["mark as done", "✅ mark as done", "mad"]:
mark_as_done(bot, update, player, state["extra"], "side_quest") mark_as_done(bot, update, player, state["extra"], "side_quest")
elif text == "edit name" or text == "📝 edit name": elif text in ["edit name", "📝 edit name", "en"]:
player.set_state('esqn', state["extra"]) player.set_state('esqn', state["extra"])
text = "What shall the new name of the Side Quest be?" text = "What shall the new name of the Side Quest be?"
reply_markup = telegram.ReplyKeyboardRemove() reply_markup = telegram.ReplyKeyboardRemove()
bot.send_message(chat_id=player.CHAT_ID, text=text, bot.send_message(chat_id=player.CHAT_ID, text=text,
reply_markup=reply_markup) reply_markup=reply_markup)
elif text == "change priority" or text == "⚠️ change priority": elif text in ["change priority", "⚠️ change priority", "cp"]:
player.set_state('esqi', state["extra"]) player.set_state('esqi', state["extra"])
text = "How important is it?" text = "How important is it?"
custom_keyboard = button_groups.importance custom_keyboard = button_groups.importance
reply_markup = telegram.ReplyKeyboardMarkup(custom_keyboard) reply_markup = telegram.ReplyKeyboardMarkup(custom_keyboard)
bot.send_message(chat_id=player.CHAT_ID, text=text, bot.send_message(chat_id=player.CHAT_ID, text=text,
reply_markup=reply_markup) reply_markup=reply_markup)
elif text == "change difficulty" or text == "📚 change difficulty": elif text in ["change difficulty", "📚 change difficulty", "cd"]:
player.set_state('esqd', state["extra"]) player.set_state('esqd', state["extra"])
text = "How difficult is it?" text = "How difficult is it?"
custom_keyboard = button_groups.difficulty custom_keyboard = button_groups.difficulty
reply_markup = telegram.ReplyKeyboardMarkup(custom_keyboard) reply_markup = telegram.ReplyKeyboardMarkup(custom_keyboard)
bot.send_message(chat_id=player.CHAT_ID, text=text, bot.send_message(chat_id=player.CHAT_ID, text=text,
reply_markup=reply_markup) reply_markup=reply_markup)
elif text == "delete side quest" or text == "🗑 delete side quest": elif text in ["delete side quest", "🗑 delete side quest", "dsq"]:
sq = questable.get_side_quest(db, player.CHAT_ID, state["extra"]) sq = questable.get_side_quest(db, player.CHAT_ID, state["extra"])
sq.delete_from_db() sq.delete_from_db()
drop_state(bot, update, player) drop_state(bot, update, player)
@ -626,7 +631,7 @@ with open('schema.sql') as f:
cursor.executescript(f.read()) cursor.executescript(f.read())
db.commit() db.commit()
updater = Updater(token=config.api_key) updater = Updater(token=config.api_key, use_context=False)
dispatcher = updater.dispatcher dispatcher = updater.dispatcher
dispatcher.add_handler(CommandHandler('start', start)) dispatcher.add_handler(CommandHandler('start', start))
@ -637,12 +642,12 @@ dispatcher.add_handler(CommandHandler('cancel', lambda x, y: me_handler(x, y,
db))) db)))
dispatcher.add_handler(CommandHandler('help', lambda x, y: help_command(x, y, dispatcher.add_handler(CommandHandler('help', lambda x, y: help_command(x, y,
db))) db)))
dispatcher.add_handler(MessageHandler(Filters.text, lambda x, y:
message_handling(x, y, db)))
dispatcher.add_handler(RegexHandler(r"/[Ss]?[Qq]_\d+", lambda x, y: dispatcher.add_handler(RegexHandler(r"/[Ss]?[Qq]_\d+", lambda x, y:
quest_handling(x, y, db))) quest_handling(x, y, db)))
dispatcher.add_handler(MessageHandler(Filters.command, lambda x, y: dispatcher.add_handler(MessageHandler(Filters.command, lambda x, y:
message_handling(x, y, db))) message_handling(x, y, db)))
dispatcher.add_handler(MessageHandler(Filters.text, lambda x, y:
message_handling(x, y, db)))
if config.update_method == "polling": if config.update_method == "polling":
updater.start_polling() updater.start_polling()

View File

@ -9,7 +9,7 @@ class base_quest():
self.DB = db self.DB = db
self.CHAT_ID = chat_id self.CHAT_ID = chat_id
self.name = name self.name = name
self.QID = qid self.QID = int(qid)
self.imp = imp self.imp = imp
self.diff = diff self.diff = diff
self.state = state self.state = state

View File

@ -1,5 +1,39 @@
CREATE TABLE IF NOT EXISTS quests(chat_id int NOT NULL, qid int NOT NULL, name varchar(255), difficulty int, importance int, state int DEFAULT 0, UNIQUE(chat_id, qid)); CREATE TABLE IF NOT EXISTS quests(
CREATE TABLE IF NOT EXISTS side_quests(chat_id int NOT NULL, qid int NOT NULL, name varchar(255), difficulty int, importance int, state int DEFAULT 0, UNIQUE(chat_id, qid)); chat_id int NOT NULL,
CREATE TABLE IF NOT EXISTS points(chat_id int PRIMARY KEY, points int); qid int NOT NULL,
CREATE TABLE IF NOT EXISTS state(chat_id int PRIMARY KEY, state varchar(10), extra varchar(10)); name varchar(255),
CREATE TABLE IF NOT EXISTS tokens(chat_id int, token varchar(36) PRIMARY KEY); difficulty int,
importance int,
state int DEFAULT 0,
UNIQUE(chat_id, qid)
);
CREATE TABLE IF NOT EXISTS side_quests(
chat_id int NOT NULL,
qid int NOT NULL,
name varchar(255),
difficulty int,
importance int,
state int DEFAULT 0,
UNIQUE(chat_id, qid)
);
CREATE TABLE IF NOT EXISTS points(
chat_id int PRIMARY KEY,
points int
);
CREATE TABLE IF NOT EXISTS state(
chat_id int PRIMARY KEY,
state varchar(10),
extra varchar(10)
);
CREATE TABLE IF NOT EXISTS tokens(
chat_id int,
token varchar(36) PRIMARY KEY
);

View File

@ -4,8 +4,10 @@ import questable
import sqlite3 import sqlite3
import errors import errors
from flask import Flask, jsonify, request, redirect from flask import Flask, jsonify, request, redirect
from flask_cors import CORS
app = Flask(__name__) app = Flask(__name__)
CORS(app)
db = sqlite3.connect("questable.db", check_same_thread=False) db = sqlite3.connect("questable.db", check_same_thread=False)
@ -235,7 +237,8 @@ def update_quest(db):
else: else:
return jsonify(errors._400_bv), 400 return jsonify(errors._400_bv), 400
elif i == "state": elif i == "state":
state = bool(request.values["state"]) state = (True if str(request.values['state']).lower()
in ["1", "true"] else False)
if state is True: if state is True:
quest.state = 1 quest.state = 1
else: else:
@ -294,7 +297,8 @@ def update_side_quest(db):
else: else:
return jsonify(errors._400_bv), 400 return jsonify(errors._400_bv), 400
elif i == "state": elif i == "state":
state = bool(request.values["state"]) state = (True if str(request.values['state']).lower()
in ["1", "true"] else False)
if state is True: if state is True:
quest.state = 1 quest.state = 1
else: else: