mirror of
https://gitlab.com/questable/questable_bot
synced 2025-07-06 20:16:54 +02:00
Compare commits
No commits in common. "master" and "1.0.1" have entirely different histories.
29
README.md
29
README.md
@ -1,30 +1,3 @@
|
|||||||
# 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`.
|
|
324
bot.py
Executable file → Normal file
324
bot.py
Executable file → Normal file
@ -9,8 +9,6 @@ from telegram.ext import Updater, CommandHandler, MessageHandler, Filters, \
|
|||||||
RegexHandler
|
RegexHandler
|
||||||
import signal
|
import signal
|
||||||
import sys
|
import sys
|
||||||
import re
|
|
||||||
import button_groups
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import config
|
import config
|
||||||
@ -22,22 +20,17 @@ logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - \
|
|||||||
%(message)s', level=logging.INFO)
|
%(message)s', level=logging.INFO)
|
||||||
|
|
||||||
|
|
||||||
def escape_html(message):
|
|
||||||
return re.sub("<", "<",
|
|
||||||
re.sub("&", "&", message))
|
|
||||||
|
|
||||||
|
|
||||||
def start(bot, update):
|
def start(bot, update):
|
||||||
chat_id = update.message.chat_id
|
chat_id = update.message.chat_id
|
||||||
if update.message.chat.type == "private":
|
|
||||||
name = str(update.message.from_user.first_name)
|
name = str(update.message.from_user.first_name)
|
||||||
if update.message.from_user.last_name:
|
if update.message.from_user.last_name:
|
||||||
name += " " + str(update.message.from_user.last_name)
|
name += " " + str(update.message.from_user.last_name)
|
||||||
else:
|
|
||||||
name = update.message.chat.title
|
|
||||||
text = f"Hello {name}!\n" + \
|
text = f"Hello {name}!\n" + \
|
||||||
"Welcome to Questable. To get started, check /help."
|
"Welcome to Questable. To get started, check /help."
|
||||||
custom_keyboard = button_groups.main
|
custom_keyboard = [
|
||||||
|
['Add Quest', 'Add Side Quest'],
|
||||||
|
['List Quests', 'List Side Quests']
|
||||||
|
]
|
||||||
reply_markup = telegram.ReplyKeyboardMarkup(custom_keyboard)
|
reply_markup = telegram.ReplyKeyboardMarkup(custom_keyboard)
|
||||||
bot.send_message(chat_id=chat_id, text=text, reply_markup=reply_markup)
|
bot.send_message(chat_id=chat_id, text=text, reply_markup=reply_markup)
|
||||||
|
|
||||||
@ -68,10 +61,7 @@ def add_quest(bot, update, player, type="quest"):
|
|||||||
chat_id = update.message.chat_id
|
chat_id = update.message.chat_id
|
||||||
text = ("What shall the name of " +
|
text = ("What shall the name of " +
|
||||||
{"quest": "Quest", "side_quest": "Side Quest"}[type] + " be?")
|
{"quest": "Quest", "side_quest": "Side Quest"}[type] + " be?")
|
||||||
if update.message.chat.type == "private":
|
|
||||||
reply_markup = telegram.ReplyKeyboardRemove()
|
reply_markup = telegram.ReplyKeyboardRemove()
|
||||||
else:
|
|
||||||
reply_markup = telegram.ForceReply()
|
|
||||||
bot.send_message(chat_id=chat_id, text=text, reply_markup=reply_markup)
|
bot.send_message(chat_id=chat_id, text=text, reply_markup=reply_markup)
|
||||||
|
|
||||||
|
|
||||||
@ -90,7 +80,7 @@ def add_name(bot, update, player, type, qid):
|
|||||||
|
|
||||||
chat_id = update.message.chat_id
|
chat_id = update.message.chat_id
|
||||||
text = "How difficult is it?"
|
text = "How difficult is it?"
|
||||||
custom_keyboard = button_groups.difficulty
|
custom_keyboard = [["Low", "Medium", "High"]]
|
||||||
reply_markup = telegram.ReplyKeyboardMarkup(custom_keyboard)
|
reply_markup = telegram.ReplyKeyboardMarkup(custom_keyboard)
|
||||||
bot.send_message(chat_id=chat_id, text=text, reply_markup=reply_markup)
|
bot.send_message(chat_id=chat_id, text=text, reply_markup=reply_markup)
|
||||||
|
|
||||||
@ -98,11 +88,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 in ["low", "📙 low", "l"]:
|
if message == "low":
|
||||||
diff = 1
|
diff = 1
|
||||||
elif message in ["medium", "📘 medium", "m"]:
|
elif message == "medium":
|
||||||
diff = 2
|
diff = 2
|
||||||
elif message in ["high", "📗 high", "h"]:
|
elif message == "high":
|
||||||
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")
|
||||||
@ -121,7 +111,7 @@ def add_diff(bot, update, player, type, qid):
|
|||||||
x.update_db()
|
x.update_db()
|
||||||
|
|
||||||
text = "How important is it?"
|
text = "How important is it?"
|
||||||
custom_keyboard = button_groups.importance
|
custom_keyboard = [["Low", "Medium", "High"]]
|
||||||
reply_markup = telegram.ReplyKeyboardMarkup(custom_keyboard)
|
reply_markup = telegram.ReplyKeyboardMarkup(custom_keyboard)
|
||||||
bot.send_message(chat_id=chat_id, text=text, reply_markup=reply_markup)
|
bot.send_message(chat_id=chat_id, text=text, reply_markup=reply_markup)
|
||||||
|
|
||||||
@ -129,11 +119,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 in ["low", "🔹 low", "l"]:
|
if message == "low":
|
||||||
imp = 1
|
imp = 1
|
||||||
elif message in ["medium", "🔸 medium", "m"]:
|
elif message == "medium":
|
||||||
imp = 2
|
imp = 2
|
||||||
elif message in ["high", "🔺 high", "h"]:
|
elif message == "high":
|
||||||
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")
|
||||||
@ -151,32 +141,31 @@ def add_imp(bot, update, player, type, qid):
|
|||||||
x.imp = imp
|
x.imp = imp
|
||||||
x.update_db()
|
x.update_db()
|
||||||
|
|
||||||
text = {"quest": "Quest", "side_quest": "Side Quest"}[type] + " Added!"
|
text = "Quest Added!"
|
||||||
bot.send_message(chat_id=chat_id, text=text)
|
bot.send_message(chat_id=chat_id, text=text)
|
||||||
send_status(bot, update, player)
|
send_status(bot, update, player)
|
||||||
|
|
||||||
|
|
||||||
def send_status(bot, update, player, prefix=""):
|
def send_status(bot, update, player, prefix=""):
|
||||||
if update.message.chat.type == "private":
|
|
||||||
name = str(update.message.from_user.first_name)
|
name = str(update.message.from_user.first_name)
|
||||||
if update.message.from_user.last_name:
|
if update.message.from_user.last_name:
|
||||||
name += " " + str(update.message.from_user.last_name)
|
name += " " + str(update.message.from_user.last_name)
|
||||||
else:
|
|
||||||
name = update.message.chat.title
|
|
||||||
name = escape_html(name)
|
|
||||||
points = player.get_points()
|
points = player.get_points()
|
||||||
total_quests = len(player.get_quests(None))
|
total_quests = len(player.get_quests(None))
|
||||||
completed_quests = len(player.get_quests(1))
|
completed_quests = len(player.get_quests(1))
|
||||||
total_side_quests = len(player.get_side_quests(None))
|
total_side_quests = len(player.get_side_quests(None))
|
||||||
completed_side_quests = len(player.get_side_quests(1))
|
completed_side_quests = len(player.get_side_quests(1))
|
||||||
|
|
||||||
text = (prefix + f'<b>👤 {name}</b>\n'
|
text = (f'<b>{name}</b>\n\n' + prefix +
|
||||||
f'<b>🔥 XP:</b> {points}\n'
|
f'<b>🔥 XP:</b> {points}\n'
|
||||||
f'<b>⭐️ Quests:</b> {completed_quests}/{total_quests}\n'
|
f'<b>⭐️ Quests:</b> {completed_quests}/{total_quests}\n'
|
||||||
f'<b>💠 Side Quests:</b> {completed_side_quests}/'
|
f'<b>💠 Side Quests:</b> {completed_side_quests}/'
|
||||||
f'{total_side_quests}\n')
|
f'{total_side_quests}\n')
|
||||||
chat_id = update.message.chat_id
|
chat_id = update.message.chat_id
|
||||||
custom_keyboard = button_groups.main
|
custom_keyboard = [
|
||||||
|
['Add Quest', 'Add Side Quest'],
|
||||||
|
['List Quests', 'List Side Quests']
|
||||||
|
]
|
||||||
reply_markup = telegram.ReplyKeyboardMarkup(custom_keyboard)
|
reply_markup = telegram.ReplyKeyboardMarkup(custom_keyboard)
|
||||||
bot.send_message(chat_id=chat_id, text=text, reply_markup=reply_markup,
|
bot.send_message(chat_id=chat_id, text=text, reply_markup=reply_markup,
|
||||||
parse_mode="HTML")
|
parse_mode="HTML")
|
||||||
@ -198,27 +187,21 @@ def list_quests(bot, update, player, type):
|
|||||||
raise ValueError('Not quest or side_quest')
|
raise ValueError('Not quest or side_quest')
|
||||||
if len(x) == 0:
|
if len(x) == 0:
|
||||||
text = ("<b>You have completed every " +
|
text = ("<b>You have completed every " +
|
||||||
{"quest": "quest", "side_quest": "side quest"}[type] +
|
{"quest": "Quests", "side_quest": "Side Quests"}[type] +
|
||||||
" ever known to me.</b>")
|
" ever known to me.</b>")
|
||||||
else:
|
else:
|
||||||
text = ("<b>" + {"quest": "📖", "side_quest": "📒"}[type] +
|
text = "<b>List of " + {"quest": "Quests", "side_quest":
|
||||||
" List of " + {"quest": "Quests", "side_quest":
|
"Side Quests"}[type] + "</b>\n"
|
||||||
"Side Quests"}[type] + "</b>")
|
|
||||||
x.sort(key=lambda i: (i.imp, -i.QID), reverse=True)
|
x.sort(key=lambda i: (i.imp, -i.QID), reverse=True)
|
||||||
imp = 3
|
|
||||||
for i in x:
|
|
||||||
if i.imp <= imp:
|
|
||||||
text += "\n\n<b>📌 " + ["Low", "Medium", "High"][i.imp-1]
|
|
||||||
text += "</b>"
|
|
||||||
imp = i.imp - 1
|
|
||||||
if type == "quest":
|
if type == "quest":
|
||||||
|
for i in x:
|
||||||
text += f"\n/Q_{i.QID} {i.name}"
|
text += f"\n/Q_{i.QID} {i.name}"
|
||||||
else:
|
else:
|
||||||
|
for i in x:
|
||||||
text += f"\n/SQ_{i.QID} {i.name}"
|
text += f"\n/SQ_{i.QID} {i.name}"
|
||||||
|
|
||||||
chat_id = update.message.chat_id
|
chat_id = update.message.chat_id
|
||||||
bot.send_message(chat_id=chat_id, text=text, parse_mode="HTML",
|
bot.send_message(chat_id=chat_id, text=text, parse_mode="HTML")
|
||||||
disable_web_page_preview=True)
|
|
||||||
|
|
||||||
|
|
||||||
def quest(bot, update, player, qid, type):
|
def quest(bot, update, player, qid, type):
|
||||||
@ -237,8 +220,7 @@ def quest(bot, update, player, qid, type):
|
|||||||
text = ("<b>🗺 " + {"quest": "Quest", "side_quest": "Side Quest"}[type]
|
text = ("<b>🗺 " + {"quest": "Quest", "side_quest": "Side Quest"}[type]
|
||||||
+ f":</b> {x.name}"
|
+ f":</b> {x.name}"
|
||||||
"\n<b>📌 Priority:</b> " + ["Low", "Medium", "High"][x.imp-1]
|
"\n<b>📌 Priority:</b> " + ["Low", "Medium", "High"][x.imp-1]
|
||||||
+ "\n<b>" + ["📙", "📘", "📗"][x.diff-1] + " Difficulty:</b> "
|
+ "\n<b>📘 Difficulty:</b> " + ["Low", "Medium", "High"][x.diff-1]
|
||||||
+ ["Low", "Medium", "High"][x.diff-1]
|
|
||||||
+ "\n<b>" + ["❎", "✅"][x.state] + " Status:</b> "
|
+ "\n<b>" + ["❎", "✅"][x.state] + " Status:</b> "
|
||||||
+ ["Incomplete", "Complete"][x.state])
|
+ ["Incomplete", "Complete"][x.state])
|
||||||
|
|
||||||
@ -248,7 +230,13 @@ def quest(bot, update, player, qid, type):
|
|||||||
elif x.state == 0:
|
elif x.state == 0:
|
||||||
state = {"quest": "eq", "side_quest": "esq"}[type]
|
state = {"quest": "eq", "side_quest": "esq"}[type]
|
||||||
player.set_state(state, qid)
|
player.set_state(state, qid)
|
||||||
custom_keyboard = button_groups.quests(type)
|
custom_keyboard = [
|
||||||
|
["Mark as done"],
|
||||||
|
["Edit Name", "Change Priority"],
|
||||||
|
["Change Difficulty", "Delete " +
|
||||||
|
{"quest": "Quest", "side_quest": "Side Quest"}[type]],
|
||||||
|
["Back"]]
|
||||||
|
|
||||||
reply_markup = telegram.ReplyKeyboardMarkup(custom_keyboard)
|
reply_markup = telegram.ReplyKeyboardMarkup(custom_keyboard)
|
||||||
chat_id = update.message.chat_id
|
chat_id = update.message.chat_id
|
||||||
bot.send_message(chat_id=chat_id, text=text, parse_mode="HTML",
|
bot.send_message(chat_id=chat_id, text=text, parse_mode="HTML",
|
||||||
@ -256,7 +244,7 @@ def quest(bot, update, player, qid, type):
|
|||||||
|
|
||||||
|
|
||||||
def quest_handling(bot, update, db):
|
def quest_handling(bot, update, db):
|
||||||
text = update.message.text.lower().split("@")[0].split("_")
|
text = update.message.text.lower().split("_")
|
||||||
chat_id = update.message.chat_id
|
chat_id = update.message.chat_id
|
||||||
player = questable.player(db, chat_id)
|
player = questable.player(db, chat_id)
|
||||||
drop_state(bot, update, player)
|
drop_state(bot, update, player)
|
||||||
@ -283,7 +271,10 @@ def mark_as_done(bot, update, player, qid, type):
|
|||||||
player.set_state('none', 0)
|
player.set_state('none', 0)
|
||||||
send_status(bot, update, player, f"<b>🌟 Earned {points} XP</b>\n\n")
|
send_status(bot, update, player, f"<b>🌟 Earned {points} XP</b>\n\n")
|
||||||
chat_id = update.message.chat_id
|
chat_id = update.message.chat_id
|
||||||
custom_keyboard = button_groups.main
|
custom_keyboard = [
|
||||||
|
['Add Quest', 'Add Side Quest'],
|
||||||
|
['List Quests', 'List Side Quests']
|
||||||
|
]
|
||||||
reply_markup = telegram.ReplyKeyboardMarkup(custom_keyboard)
|
reply_markup = telegram.ReplyKeyboardMarkup(custom_keyboard)
|
||||||
bot.send_animation(chat_id=chat_id, animation=random.choice(config.gifs),
|
bot.send_animation(chat_id=chat_id, animation=random.choice(config.gifs),
|
||||||
reply_markup=reply_markup)
|
reply_markup=reply_markup)
|
||||||
@ -302,31 +293,20 @@ def edit_quest(bot, update, player, qid, target, type):
|
|||||||
|
|
||||||
if target == "name":
|
if target == "name":
|
||||||
x.name = message
|
x.name = message
|
||||||
text = "<b>☑️ Updated Name</b>"
|
text = "<b>Updated Name</b>"
|
||||||
elif target == "imp":
|
elif target == "imp" or target == "diff":
|
||||||
message = message.lower()
|
message = message.lower()
|
||||||
if message in ["low", "🔹 low", "l"]:
|
if message != "low" and message != "medium" and message != "high":
|
||||||
x.imp = 1
|
|
||||||
elif message in ["medium", "🔸 medium", "m"]:
|
|
||||||
x.imp = 2
|
|
||||||
elif message in ["high", "🔺 high", "h"]:
|
|
||||||
x.imp = 3
|
|
||||||
else:
|
|
||||||
bot.send_message(chat_id=chat_id, text="Invalid Option")
|
bot.send_message(chat_id=chat_id, text="Invalid Option")
|
||||||
return
|
return
|
||||||
text = "<b>☑️ Updated Priority</b>"
|
else:
|
||||||
|
num = {"low": 1, "medium": 2, "high": 3}[message]
|
||||||
|
if target == "imp":
|
||||||
|
x.imp = num
|
||||||
|
text = "<b>Updated Priority</b>"
|
||||||
elif target == "diff":
|
elif target == "diff":
|
||||||
message = message.lower()
|
x.diff = num
|
||||||
if message in ["low", "📙 low", "l"]:
|
text = "<b>Updated Difficulty</b>"
|
||||||
x.diff = 1
|
|
||||||
elif message in ["medium", "📘 medium", "m"]:
|
|
||||||
x.diff = 2
|
|
||||||
elif message in ["high", "📗 high", "h"]:
|
|
||||||
x.diff = 3
|
|
||||||
else:
|
|
||||||
bot.send_message(chat_id=chat_id, text="Invalid Option")
|
|
||||||
return
|
|
||||||
text = "<b>☑️ Updated Difficulty</b>"
|
|
||||||
|
|
||||||
x.update_db()
|
x.update_db()
|
||||||
if type == "quest":
|
if type == "quest":
|
||||||
@ -334,11 +314,11 @@ def edit_quest(bot, update, player, qid, target, type):
|
|||||||
elif type == "side_quest":
|
elif type == "side_quest":
|
||||||
player.set_state('esq', qid)
|
player.set_state('esq', qid)
|
||||||
custom_keyboard = [
|
custom_keyboard = [
|
||||||
["✅ Mark as done"],
|
["Mark as done"],
|
||||||
["📝 Edit Name", "⚠️ Change Priority"],
|
["Edit Name", "Change Priority"],
|
||||||
["📚 Change Difficulty", "🗑 Delete " +
|
["Change Difficulty", "Delete " +
|
||||||
{"quest": "Quest", "side_quest": "Side Quest"}[type]],
|
{"quest": "Quest", "side_quest": "Side Quest"}[type]],
|
||||||
["⬅️ Back"]]
|
["Back"]]
|
||||||
reply_markup = telegram.ReplyKeyboardMarkup(custom_keyboard)
|
reply_markup = telegram.ReplyKeyboardMarkup(custom_keyboard)
|
||||||
bot.send_message(chat_id=chat_id, text=text, reply_markup=reply_markup,
|
bot.send_message(chat_id=chat_id, text=text, reply_markup=reply_markup,
|
||||||
parse_mode="HTML")
|
parse_mode="HTML")
|
||||||
@ -357,15 +337,16 @@ def drop_state(bot, update, player):
|
|||||||
x = questable.get_side_quest(player.DB, player.CHAT_ID, state["extra"])
|
x = questable.get_side_quest(player.DB, player.CHAT_ID, state["extra"])
|
||||||
x.delete_from_db()
|
x.delete_from_db()
|
||||||
player.set_state('none', 0)
|
player.set_state('none', 0)
|
||||||
else:
|
|
||||||
player.set_state('none', 0)
|
|
||||||
|
|
||||||
|
|
||||||
def help_command(bot, update, db):
|
def help_command(bot, update, db):
|
||||||
player = questable.player(db, update.message.chat_id)
|
player = questable.player(db, update.message.chat_id)
|
||||||
drop_state(bot, update, player)
|
drop_state(bot, update, player)
|
||||||
chat_id = update.message.chat_id
|
chat_id = update.message.chat_id
|
||||||
custom_keyboard = button_groups.main
|
custom_keyboard = [
|
||||||
|
['Add Quest', 'Add Side Quest'],
|
||||||
|
['List Quests', 'List Side Quests']
|
||||||
|
]
|
||||||
text = ("*Questable Bot*\n\nQuestable is an RPG-like bot for maintaining "
|
text = ("*Questable Bot*\n\nQuestable is an RPG-like bot for maintaining "
|
||||||
"events in real life. _Main Tasks_ are _Quests_ while _other "
|
"events in real life. _Main Tasks_ are _Quests_ while _other "
|
||||||
"tasks_ are _Side Quests._ You can use the bot to maintain a "
|
"tasks_ are _Side Quests._ You can use the bot to maintain a "
|
||||||
@ -373,8 +354,7 @@ def help_command(bot, update, db):
|
|||||||
"Quests you get XP based on how difficult and important the "
|
"Quests you get XP based on how difficult and important the "
|
||||||
"Quest/Side Quest was. Quests/Side Quests can be added and "
|
"Quest/Side Quest was. Quests/Side Quests can be added and "
|
||||||
"modified later.\n\n To get more help check "
|
"modified later.\n\n To get more help check "
|
||||||
"[Extended Help](https://questable.webionite.com/help/) or "
|
"[Extended Help](https://webionite.com/questable/). In case, of "
|
||||||
"[this video](https://t.me/quadnite/25). In case, of "
|
|
||||||
"bugs/feedback/more help, contact @ceda\\_ei or join the "
|
"bugs/feedback/more help, contact @ceda\\_ei or join the "
|
||||||
"[group](https://t.me/questable).")
|
"[group](https://t.me/questable).")
|
||||||
reply_markup = telegram.ReplyKeyboardMarkup(custom_keyboard)
|
reply_markup = telegram.ReplyKeyboardMarkup(custom_keyboard)
|
||||||
@ -382,74 +362,6 @@ def help_command(bot, update, db):
|
|||||||
reply_markup=reply_markup)
|
reply_markup=reply_markup)
|
||||||
|
|
||||||
|
|
||||||
def rate_command(bot, update, db):
|
|
||||||
player = questable.player(db, update.message.chat_id)
|
|
||||||
drop_state(bot, update, player)
|
|
||||||
chat_id = update.message.chat_id
|
|
||||||
custom_keyboard = button_groups.main
|
|
||||||
text = ("[Vote for us on Telegram Directory!](https://t.me/tgdrbot?"
|
|
||||||
"start=questable_bot)\n\n"
|
|
||||||
"Telegram Directory is a website that helps you discover top "
|
|
||||||
"telegram channels, bots and groups.")
|
|
||||||
reply_markup = telegram.ReplyKeyboardMarkup(custom_keyboard)
|
|
||||||
bot.send_message(chat_id=chat_id, text=text, parse_mode="Markdown",
|
|
||||||
reply_markup=reply_markup)
|
|
||||||
|
|
||||||
|
|
||||||
def tokens(bot, update):
|
|
||||||
custom_keyboard = button_groups.tokens
|
|
||||||
reply_markup = telegram.ReplyKeyboardMarkup(custom_keyboard)
|
|
||||||
reply_text = ("Tokens are used to authenticate external "
|
|
||||||
"applications. This only provides access to "
|
|
||||||
"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,
|
|
||||||
reply_markup=reply_markup, parse_mode="markdown",
|
|
||||||
disable_web_page_preview=True)
|
|
||||||
|
|
||||||
|
|
||||||
def add_token(bot, update, player):
|
|
||||||
custom_keyboard = button_groups.main
|
|
||||||
reply_markup = telegram.ReplyKeyboardMarkup(custom_keyboard)
|
|
||||||
if len(player.get_tokens()) < 3:
|
|
||||||
reply_text = player.add_token()
|
|
||||||
else:
|
|
||||||
reply_text = "Maximum number of tokens reached."
|
|
||||||
bot.send_message(chat_id=player.CHAT_ID, text=reply_text,
|
|
||||||
reply_markup=reply_markup)
|
|
||||||
|
|
||||||
|
|
||||||
def delete_token(bot, update, player):
|
|
||||||
tokens = player.get_tokens()
|
|
||||||
custom_keyboard = list(map(lambda x: [x], tokens))
|
|
||||||
reply_markup = telegram.ReplyKeyboardMarkup(custom_keyboard)
|
|
||||||
reply_text = "Choose token to remove."
|
|
||||||
player.set_state("rt")
|
|
||||||
bot.send_message(chat_id=update.message.chat_id, text=reply_text,
|
|
||||||
reply_markup=reply_markup)
|
|
||||||
|
|
||||||
|
|
||||||
def delete_token_rt(bot, update, player):
|
|
||||||
player.delete_token(update.message.text.lower())
|
|
||||||
custom_keyboard = button_groups.main
|
|
||||||
reply_markup = telegram.ReplyKeyboardMarkup(custom_keyboard)
|
|
||||||
reply_text = "Token has been removed."
|
|
||||||
player.set_state("none")
|
|
||||||
bot.send_message(chat_id=player.CHAT_ID, text=reply_text,
|
|
||||||
reply_markup=reply_markup)
|
|
||||||
|
|
||||||
|
|
||||||
def list_tokens(bot, update, player):
|
|
||||||
custom_keyboard = button_groups.main
|
|
||||||
reply_markup = telegram.ReplyKeyboardMarkup(custom_keyboard)
|
|
||||||
reply_text = "📋 List of tokens\n\n"
|
|
||||||
reply_text += "\n".join(player.get_tokens())
|
|
||||||
bot.send_message(chat_id=update.message.chat_id, text=reply_text,
|
|
||||||
reply_markup=reply_markup)
|
|
||||||
|
|
||||||
|
|
||||||
def message_handling(bot, update, db):
|
def message_handling(bot, update, db):
|
||||||
text = update.message.text.lower()
|
text = update.message.text.lower()
|
||||||
player = questable.player(db, update.message.chat_id)
|
player = questable.player(db, update.message.chat_id)
|
||||||
@ -467,31 +379,18 @@ def message_handling(bot, update, db):
|
|||||||
# eqn / esqn: Edit Quest / Side Quest Name
|
# eqn / esqn: Edit Quest / Side Quest Name
|
||||||
# eqi / esqi: Edit Quest / Side Quest Importance
|
# eqi / esqi: Edit Quest / Side Quest Importance
|
||||||
# eqd / esqd: Edit Quest / Side Quest Difficulty
|
# eqd / esqd: Edit Quest / Side Quest Difficulty
|
||||||
# rt: Remove token
|
|
||||||
|
|
||||||
if state["state"] == "none":
|
if state["state"] == "none":
|
||||||
if text in ["add quest", "❇️ add quest", "aq"]:
|
if text == "add quest":
|
||||||
add_quest(bot, update, player)
|
add_quest(bot, update, player)
|
||||||
elif text in ["add side quest", "📯 add side quest", "asq"]:
|
elif text == "add side quest":
|
||||||
add_quest(bot, update, player, "side_quest")
|
add_quest(bot, update, player, "side_quest")
|
||||||
elif text in ["list quests", "📜 list quests", "lq"]:
|
elif text == "list quests":
|
||||||
list_quests(bot, update, player, "quest")
|
list_quests(bot, update, player, "quest")
|
||||||
elif text in ["list side quests", "📃 list side quests", "lsq"]:
|
elif text == "list side quests":
|
||||||
list_quests(bot, update, player, "side_quest")
|
list_quests(bot, update, player, "side_quest")
|
||||||
elif text in ["tokens", "🔑 tokens", "t"]:
|
|
||||||
tokens(bot, update)
|
|
||||||
elif text in ["list tokens", "📋 list tokens", "lt"]:
|
|
||||||
list_tokens(bot, update, player)
|
|
||||||
elif text in ["generate token", "🔑 generate token", "gt"]:
|
|
||||||
add_token(bot, update, player)
|
|
||||||
elif text in ["delete token", "🧹 delete token", "dt"]:
|
|
||||||
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":
|
drop_state(bot, update, player)
|
||||||
send_status(bot, update, player)
|
send_status(bot, update, player)
|
||||||
|
|
||||||
elif state["state"] == "aq":
|
elif state["state"] == "aq":
|
||||||
@ -513,81 +412,78 @@ 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 in ["back", "⬅️ back", "b"]:
|
if text == "back":
|
||||||
player.set_state('none', 0)
|
player.set_state('none', 0)
|
||||||
send_status(bot, update, player)
|
send_status(bot, update, player)
|
||||||
elif text in ["mark as done", "✅ mark as done", "mad"]:
|
elif text == "mark as done":
|
||||||
mark_as_done(bot, update, player, state["extra"], "quest")
|
mark_as_done(bot, update, player, state["extra"], "quest")
|
||||||
elif text in ["edit name", "📝 edit name", "en"]:
|
elif text == "edit name":
|
||||||
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 in ["change priority", "⚠️ change priority", "cp"]:
|
elif text == "change priority":
|
||||||
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 = [["Low", "Medium", "High"]]
|
||||||
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 in ["change difficulty", "📚 change difficulty", "cd"]:
|
elif text == "change difficulty":
|
||||||
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 = [["Low", "Medium", "High"]]
|
||||||
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 in ["delete quest", "🗑 delete quest", "dq"]:
|
elif text == "delete quest":
|
||||||
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)
|
||||||
prefix = f"<b>Quest {quest.name} has been deleted</b>\n\n"
|
prefix = f"<b>Quest {quest.name} has been deleted</b>\n\n"
|
||||||
send_status(bot, update, player, prefix=prefix)
|
send_status(bot, update, player, prefix=prefix)
|
||||||
else:
|
else:
|
||||||
if update.message.chat.type == "private":
|
|
||||||
drop_state(bot, update, player)
|
drop_state(bot, update, player)
|
||||||
send_status(bot, update, player)
|
send_status(bot, update, player)
|
||||||
|
|
||||||
elif state["state"] == "esq":
|
elif state["state"] == "esq":
|
||||||
if text in ["back", "⬅️ back", "b"]:
|
if text == "back":
|
||||||
player.set_state('none', 0)
|
player.set_state('none', 0)
|
||||||
send_status(bot, update, player)
|
send_status(bot, update, player)
|
||||||
elif text in ["mark as done", "✅ mark as done", "mad"]:
|
elif text == "mark as done":
|
||||||
mark_as_done(bot, update, player, state["extra"], "side_quest")
|
mark_as_done(bot, update, player, state["extra"], "side_quest")
|
||||||
elif text in ["edit name", "📝 edit name", "en"]:
|
elif text == "edit name":
|
||||||
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 in ["change priority", "⚠️ change priority", "cp"]:
|
elif text == "change priority":
|
||||||
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 = [["Low", "Medium", "High"]]
|
||||||
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 in ["change difficulty", "📚 change difficulty", "cd"]:
|
elif text == "change difficulty":
|
||||||
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 = [["Low", "Medium", "High"]]
|
||||||
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 in ["delete side quest", "🗑 delete side quest", "dsq"]:
|
elif text == "delete side quest":
|
||||||
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)
|
||||||
prefix = f"<b>Side Quest {sq.name} has been deleted</b>\n\n"
|
prefix = f"<b>Side Quest {sq.name} has been deleted</b>\n\n"
|
||||||
send_status(bot, update, player, prefix=prefix)
|
send_status(bot, update, player, prefix=prefix)
|
||||||
else:
|
else:
|
||||||
if update.message.chat.type == "private":
|
|
||||||
drop_state(bot, update, player)
|
drop_state(bot, update, player)
|
||||||
send_status(bot, update, player)
|
send_status(bot, update, player)
|
||||||
|
|
||||||
elif state["state"] == "bo":
|
elif state["state"] == "bo":
|
||||||
if text == "back" or update.message.chat.type == "private":
|
|
||||||
player.set_state('none', 0)
|
player.set_state('none', 0)
|
||||||
send_status(bot, update, player)
|
send_status(bot, update, player)
|
||||||
|
|
||||||
@ -609,10 +505,7 @@ def message_handling(bot, update, db):
|
|||||||
elif state["state"] == "esqd":
|
elif state["state"] == "esqd":
|
||||||
edit_quest(bot, update, player, state["extra"], "diff", "side_quest")
|
edit_quest(bot, update, player, state["extra"], "diff", "side_quest")
|
||||||
|
|
||||||
elif state["state"] == "rt":
|
|
||||||
delete_token_rt(bot, update, player)
|
|
||||||
else:
|
else:
|
||||||
if update.message.chat.type == "private":
|
|
||||||
drop_state(bot, update, player)
|
drop_state(bot, update, player)
|
||||||
send_status(bot, update, player)
|
send_status(bot, update, player)
|
||||||
|
|
||||||
@ -622,32 +515,55 @@ def sigterm_handler(signal, frame, db):
|
|||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
|
|
||||||
signal.signal(signal.SIGTERM, lambda x, y: sigterm_handler(x, y, db))
|
|
||||||
|
|
||||||
# Set up database and tables
|
|
||||||
db = sqlite3.connect("questable.db", check_same_thread=False)
|
db = sqlite3.connect("questable.db", check_same_thread=False)
|
||||||
cursor = db.cursor()
|
cursor = db.cursor()
|
||||||
with open('schema.sql') as f:
|
signal.signal(signal.SIGTERM, lambda x, y: sigterm_handler(x, y, db))
|
||||||
cursor.executescript(f.read())
|
|
||||||
|
# Set up tables
|
||||||
|
queries = [
|
||||||
|
("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 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));"),
|
||||||
|
]
|
||||||
|
for query in queries:
|
||||||
|
cursor.execute(query)
|
||||||
db.commit()
|
db.commit()
|
||||||
|
|
||||||
updater = Updater(token=config.api_key, use_context=False)
|
updater = Updater(token=config.api_key)
|
||||||
dispatcher = updater.dispatcher
|
dispatcher = updater.dispatcher
|
||||||
|
|
||||||
dispatcher.add_handler(CommandHandler('start', start))
|
start_handler = CommandHandler('start', start)
|
||||||
dispatcher.add_handler(CommandHandler('me', lambda x, y: me_handler(x, y, db)))
|
dispatcher.add_handler(start_handler)
|
||||||
dispatcher.add_handler(CommandHandler('rate', lambda x, y:
|
|
||||||
rate_command(x, y, db)))
|
me = CommandHandler('me', lambda x, y: me_handler(x, y, db))
|
||||||
dispatcher.add_handler(CommandHandler('cancel', lambda x, y: me_handler(x, y,
|
dispatcher.add_handler(me)
|
||||||
db)))
|
|
||||||
dispatcher.add_handler(CommandHandler('help', lambda x, y: help_command(x, y,
|
cancel = CommandHandler('cancel', lambda x, y: me_handler(x, y, db))
|
||||||
db)))
|
dispatcher.add_handler(cancel)
|
||||||
dispatcher.add_handler(RegexHandler(r"/[Ss]?[Qq]_\d+", lambda x, y:
|
|
||||||
quest_handling(x, y, db)))
|
help_h = CommandHandler('help', lambda x, y: help_command(x, y, db))
|
||||||
dispatcher.add_handler(MessageHandler(Filters.command, lambda x, y:
|
dispatcher.add_handler(help_h)
|
||||||
message_handling(x, y, db)))
|
|
||||||
dispatcher.add_handler(MessageHandler(Filters.text, lambda x, y:
|
handler = MessageHandler(Filters.text, lambda x, y: message_handling(x, y, db))
|
||||||
message_handling(x, y, db)))
|
dispatcher.add_handler(handler)
|
||||||
|
|
||||||
|
quest_handler = RegexHandler(r"/[Ss]?[Qq]_\d+", lambda x, y:
|
||||||
|
quest_handling(x, y, db))
|
||||||
|
dispatcher.add_handler(quest_handler)
|
||||||
|
|
||||||
|
unknown = MessageHandler(Filters.command, lambda x, y: message_handling(x, y,
|
||||||
|
db))
|
||||||
|
dispatcher.add_handler(unknown)
|
||||||
|
|
||||||
if config.update_method == "polling":
|
if config.update_method == "polling":
|
||||||
updater.start_polling()
|
updater.start_polling()
|
||||||
|
@ -1,23 +0,0 @@
|
|||||||
main = [
|
|
||||||
['❇️ Add Quest', '📯 Add Side Quest'],
|
|
||||||
['📜 List Quests', '📃 List Side Quests'],
|
|
||||||
['🏅 Player Status', '🔑 Tokens']
|
|
||||||
]
|
|
||||||
|
|
||||||
importance = [["🔹 Low", "🔸 Medium", "🔺 High"]]
|
|
||||||
difficulty = [["📙 Low", "📘 Medium", "📗 High"]]
|
|
||||||
|
|
||||||
|
|
||||||
def quests(cat):
|
|
||||||
return [
|
|
||||||
["✅ Mark as done"],
|
|
||||||
["📝 Edit Name", "⚠️ Change Priority"],
|
|
||||||
["📚 Change Difficulty", "🗑 Delete " +
|
|
||||||
{"quest": "Quest", "side_quest": "Side Quest"}[cat]],
|
|
||||||
["⬅️ Back"]]
|
|
||||||
|
|
||||||
|
|
||||||
tokens = [
|
|
||||||
["📋 List tokens"],
|
|
||||||
["🔑 Generate token", "🧹 Delete token"]
|
|
||||||
]
|
|
@ -1,4 +0,0 @@
|
|||||||
_400 = {"error": "insufficient parameters"}
|
|
||||||
_400_bv = {"error": "bad values"}
|
|
||||||
_401 = {"error": "invalid token"}
|
|
||||||
_404 = {"error": "The quest/side quest doesn't exist"}
|
|
62
questable.py
62
questable.py
@ -1,6 +1,3 @@
|
|||||||
import uuid
|
|
||||||
|
|
||||||
|
|
||||||
class base_quest():
|
class base_quest():
|
||||||
TABLE = None
|
TABLE = None
|
||||||
|
|
||||||
@ -9,7 +6,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 = int(qid)
|
self.QID = qid
|
||||||
self.imp = imp
|
self.imp = imp
|
||||||
self.diff = diff
|
self.diff = diff
|
||||||
self.state = state
|
self.state = state
|
||||||
@ -44,9 +41,6 @@ class base_quest():
|
|||||||
cursor.execute(query, (self.CHAT_ID, self.QID))
|
cursor.execute(query, (self.CHAT_ID, self.QID))
|
||||||
self.DB.commit()
|
self.DB.commit()
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return f"{self.QID}: {self.name}"
|
|
||||||
|
|
||||||
|
|
||||||
class quest(base_quest):
|
class quest(base_quest):
|
||||||
TABLE = "quests"
|
TABLE = "quests"
|
||||||
@ -156,57 +150,3 @@ class player():
|
|||||||
q = side_quest(self.DB, *row)
|
q = side_quest(self.DB, *row)
|
||||||
quests.append(q)
|
quests.append(q)
|
||||||
return quests
|
return quests
|
||||||
|
|
||||||
def get_quest(self, qid):
|
|
||||||
cursor = self.DB.cursor()
|
|
||||||
query = ('SELECT chat_id, qid, name, importance, difficulty, '
|
|
||||||
'state FROM quests WHERE chat_id = ? AND qid = ?')
|
|
||||||
cursor.execute(query, (self.CHAT_ID, qid))
|
|
||||||
row = cursor.fetchone()
|
|
||||||
if row is None:
|
|
||||||
return False
|
|
||||||
else:
|
|
||||||
return quest(self.DB, *row)
|
|
||||||
|
|
||||||
def get_side_quest(self, qid):
|
|
||||||
cursor = self.DB.cursor()
|
|
||||||
query = ('SELECT chat_id, qid, name, importance, difficulty, '
|
|
||||||
'state FROM side_quests WHERE chat_id = ? AND qid = ?')
|
|
||||||
cursor.execute(query, (self.CHAT_ID, qid))
|
|
||||||
row = cursor.fetchone()
|
|
||||||
if row is None:
|
|
||||||
return False
|
|
||||||
else:
|
|
||||||
return side_quest(self.DB, *row)
|
|
||||||
|
|
||||||
def get_tokens(self):
|
|
||||||
cursor = self.DB.cursor()
|
|
||||||
query = ('SELECT token FROM tokens WHERE chat_id=?')
|
|
||||||
cursor.execute(query, (self.CHAT_ID,))
|
|
||||||
tokens = list(map(lambda x: x[0], cursor))
|
|
||||||
return tokens
|
|
||||||
|
|
||||||
def add_token(self):
|
|
||||||
cursor = self.DB.cursor()
|
|
||||||
token = str(uuid.uuid4())
|
|
||||||
query = ('INSERT INTO tokens(chat_id, token) values(?, ?)')
|
|
||||||
cursor.execute(query, (self.CHAT_ID, token))
|
|
||||||
self.DB.commit()
|
|
||||||
return token
|
|
||||||
|
|
||||||
def delete_token(self, token):
|
|
||||||
cursor = self.DB.cursor()
|
|
||||||
query = ('DELETE FROM tokens WHERE chat_id = ? AND token = ?')
|
|
||||||
cursor.execute(query, (self.CHAT_ID, token))
|
|
||||||
self.DB.commit()
|
|
||||||
|
|
||||||
|
|
||||||
def get_player_from_token(db, token):
|
|
||||||
cursor = db.cursor()
|
|
||||||
query = "SELECT chat_id FROM tokens WHERE token=?"
|
|
||||||
cursor.execute(query, (token,))
|
|
||||||
chat_id = cursor.fetchone()
|
|
||||||
if chat_id is None:
|
|
||||||
return False
|
|
||||||
else:
|
|
||||||
return player(db, chat_id[0])
|
|
||||||
|
39
schema.sql
39
schema.sql
@ -1,39 +0,0 @@
|
|||||||
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 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
|
|
||||||
);
|
|
375
server.py
375
server.py
@ -1,375 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
|
|
||||||
import questable
|
|
||||||
import sqlite3
|
|
||||||
import errors
|
|
||||||
from flask import Flask, jsonify, request, redirect
|
|
||||||
from flask_cors import CORS
|
|
||||||
|
|
||||||
app = Flask(__name__)
|
|
||||||
CORS(app)
|
|
||||||
db = sqlite3.connect("questable.db", check_same_thread=False)
|
|
||||||
|
|
||||||
|
|
||||||
# Returns the player object if valid token
|
|
||||||
def get_player(db):
|
|
||||||
try:
|
|
||||||
token = request.values['token']
|
|
||||||
except (AttributeError):
|
|
||||||
return False
|
|
||||||
except (KeyError):
|
|
||||||
return False
|
|
||||||
return questable.get_player_from_token(db, token)
|
|
||||||
|
|
||||||
|
|
||||||
# /auth.
|
|
||||||
def auth(db):
|
|
||||||
if get_player(db) is False:
|
|
||||||
return jsonify({"success": False})
|
|
||||||
else:
|
|
||||||
return jsonify({"success": True})
|
|
||||||
|
|
||||||
|
|
||||||
app.add_url_rule('/auth', '/auth', lambda: auth(db), methods=['GET'])
|
|
||||||
|
|
||||||
|
|
||||||
# /player
|
|
||||||
def player(db):
|
|
||||||
player = get_player(db)
|
|
||||||
if player is False:
|
|
||||||
return jsonify(errors._401), 401
|
|
||||||
noq = len(player.get_quests(None))
|
|
||||||
nosq = len(player.get_side_quests(None))
|
|
||||||
return jsonify({
|
|
||||||
"xp": player.get_points(),
|
|
||||||
"quests_completed": noq - len(player.get_quests()),
|
|
||||||
"total_quests": noq,
|
|
||||||
"side_quests_completed": nosq - len(player.get_side_quests()),
|
|
||||||
"total_side_quests": nosq,
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
app.add_url_rule('/player', '/player', lambda: player(db), methods=['GET'])
|
|
||||||
|
|
||||||
|
|
||||||
def dictify_quest(quest):
|
|
||||||
return {
|
|
||||||
"id": quest.QID,
|
|
||||||
"name": quest.name,
|
|
||||||
"difficulty": quest.diff,
|
|
||||||
"priority": quest.imp,
|
|
||||||
"state": [False, True][quest.state]
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
# /get_quests
|
|
||||||
def get_quests(db):
|
|
||||||
player = get_player(db)
|
|
||||||
if player is False:
|
|
||||||
return jsonify(errors._401), 401
|
|
||||||
quests = list(map(dictify_quest, player.get_quests()))
|
|
||||||
return jsonify(quests)
|
|
||||||
|
|
||||||
|
|
||||||
app.add_url_rule('/get_quests', '/get_quests', lambda: get_quests(db),
|
|
||||||
methods=['GET'])
|
|
||||||
|
|
||||||
|
|
||||||
# /get_side_quests
|
|
||||||
def get_side_quests(db):
|
|
||||||
player = get_player(db)
|
|
||||||
if player is False:
|
|
||||||
return jsonify(errors._401), 401
|
|
||||||
side_quests = list(map(dictify_quest, player.get_side_quests()))
|
|
||||||
return jsonify(side_quests)
|
|
||||||
|
|
||||||
|
|
||||||
app.add_url_rule('/get_side_quests', '/get_side_quests',
|
|
||||||
lambda: get_side_quests(db), methods=['GET'])
|
|
||||||
|
|
||||||
|
|
||||||
# /get_quest
|
|
||||||
def get_quest(db):
|
|
||||||
player = get_player(db)
|
|
||||||
if player is False:
|
|
||||||
return jsonify(errors._401), 401
|
|
||||||
try:
|
|
||||||
qid = request.values['id']
|
|
||||||
except(KeyError):
|
|
||||||
return jsonify(errors._400), 400
|
|
||||||
|
|
||||||
quest = player.get_quest(qid)
|
|
||||||
if quest is False:
|
|
||||||
return jsonify(errors._404), 404
|
|
||||||
|
|
||||||
return jsonify(dictify_quest(quest))
|
|
||||||
|
|
||||||
|
|
||||||
app.add_url_rule('/get_quest', '/get_quest', lambda: get_quest(db),
|
|
||||||
methods=['GET'])
|
|
||||||
|
|
||||||
|
|
||||||
# /get_side_quest
|
|
||||||
def get_side_quest(db):
|
|
||||||
player = get_player(db)
|
|
||||||
if player is False:
|
|
||||||
return jsonify(errors._401), 401
|
|
||||||
try:
|
|
||||||
qid = request.values['id']
|
|
||||||
except(KeyError):
|
|
||||||
return jsonify(errors._400), 400
|
|
||||||
|
|
||||||
side_quest = player.get_side_quest(qid)
|
|
||||||
|
|
||||||
if side_quest is False:
|
|
||||||
return jsonify(errors._404), 404
|
|
||||||
|
|
||||||
return jsonify(dictify_quest(side_quest))
|
|
||||||
|
|
||||||
|
|
||||||
app.add_url_rule('/get_side_quest', '/get_side_quest',
|
|
||||||
lambda: get_side_quest(db), methods=['GET'])
|
|
||||||
|
|
||||||
|
|
||||||
# /add_quest
|
|
||||||
def add_quest(db):
|
|
||||||
player = get_player(db)
|
|
||||||
if player is False:
|
|
||||||
return jsonify(errors._401), 401
|
|
||||||
|
|
||||||
x = player.get_quests(None)
|
|
||||||
if len(x) == 0:
|
|
||||||
qid = 1
|
|
||||||
else:
|
|
||||||
x.sort(key=lambda i: i.QID, reverse=True)
|
|
||||||
qid = x[0].QID + 1
|
|
||||||
|
|
||||||
try:
|
|
||||||
name = request.values['name']
|
|
||||||
imp = int(request.values['priority'])
|
|
||||||
diff = int(request.values['difficulty'])
|
|
||||||
except (KeyError):
|
|
||||||
return jsonify(errors._400), 400
|
|
||||||
except (ValueError):
|
|
||||||
return jsonify(errors._400_bv), 400
|
|
||||||
|
|
||||||
if imp not in [1, 2, 3] or diff not in [1, 2, 3]:
|
|
||||||
return jsonify(errors._400_bv), 400
|
|
||||||
|
|
||||||
quest = questable.add_quest(db, player.CHAT_ID, qid, name, imp, diff, 0)
|
|
||||||
return jsonify(dictify_quest(quest))
|
|
||||||
|
|
||||||
|
|
||||||
app.add_url_rule('/add_quest', '/add_quest', lambda: add_quest(db),
|
|
||||||
methods=['POST'])
|
|
||||||
|
|
||||||
|
|
||||||
# /add_side_quest
|
|
||||||
def add_side_quest(db):
|
|
||||||
player = get_player(db)
|
|
||||||
if player is False:
|
|
||||||
return jsonify(errors._401), 401
|
|
||||||
|
|
||||||
x = player.get_side_quests(None)
|
|
||||||
if len(x) == 0:
|
|
||||||
qid = 1
|
|
||||||
else:
|
|
||||||
x.sort(key=lambda i: i.QID, reverse=True)
|
|
||||||
qid = x[0].QID + 1
|
|
||||||
|
|
||||||
try:
|
|
||||||
name = request.values['name']
|
|
||||||
imp = int(request.values['priority'])
|
|
||||||
diff = int(request.values['difficulty'])
|
|
||||||
except (KeyError):
|
|
||||||
return jsonify(errors._400), 400
|
|
||||||
except (ValueError):
|
|
||||||
return jsonify(errors._400_bv), 400
|
|
||||||
|
|
||||||
if imp not in [1, 2, 3] or diff not in [1, 2, 3]:
|
|
||||||
return jsonify(errors._400_bv), 400
|
|
||||||
|
|
||||||
quest = questable.add_side_quest(db, player.CHAT_ID, qid, name, imp,
|
|
||||||
diff, 0)
|
|
||||||
return jsonify(dictify_quest(quest))
|
|
||||||
|
|
||||||
|
|
||||||
app.add_url_rule('/add_side_quest', '/add_side_quest',
|
|
||||||
lambda: add_side_quest(db), methods=['POST'])
|
|
||||||
|
|
||||||
|
|
||||||
# /update_quest
|
|
||||||
def update_quest(db):
|
|
||||||
player = get_player(db)
|
|
||||||
if player is False:
|
|
||||||
return jsonify(errors._401), 401
|
|
||||||
try:
|
|
||||||
qid = request.values['id']
|
|
||||||
except(KeyError):
|
|
||||||
return jsonify(errors._400), 400
|
|
||||||
|
|
||||||
available_keys = [i for i in ['name', 'difficulty', 'priority', 'state']
|
|
||||||
if i in request.values.keys()]
|
|
||||||
if len(available_keys) == 0:
|
|
||||||
return jsonify(errors._400), 400
|
|
||||||
quest = questable.get_quest(db, player.CHAT_ID, qid)
|
|
||||||
|
|
||||||
if quest is False:
|
|
||||||
return jsonify(errors._404), 404
|
|
||||||
|
|
||||||
if quest.state == 1:
|
|
||||||
return jsonify(dictify_quest(quest))
|
|
||||||
|
|
||||||
for i in available_keys:
|
|
||||||
try:
|
|
||||||
if i == "name":
|
|
||||||
quest.name = request.values["name"]
|
|
||||||
elif i == "difficulty":
|
|
||||||
diff = int(request.values["difficulty"])
|
|
||||||
if diff in [1, 2, 3]:
|
|
||||||
quest.diff = diff
|
|
||||||
else:
|
|
||||||
return jsonify(errors._400_bv), 400
|
|
||||||
elif i == "priority":
|
|
||||||
imp = int(request.values["priority"])
|
|
||||||
if imp in [1, 2, 3]:
|
|
||||||
quest.imp = imp
|
|
||||||
else:
|
|
||||||
return jsonify(errors._400_bv), 400
|
|
||||||
elif i == "state":
|
|
||||||
state = (True if str(request.values['state']).lower()
|
|
||||||
in ["1", "true"] else False)
|
|
||||||
if state is True:
|
|
||||||
quest.state = 1
|
|
||||||
else:
|
|
||||||
return jsonify(errors._400_bv), 400
|
|
||||||
except (ValueError):
|
|
||||||
return jsonify(errors._400_bv), 400
|
|
||||||
|
|
||||||
if quest.state == 1:
|
|
||||||
points = 55 + 10*quest.imp + 15*quest.diff
|
|
||||||
player.add_points(points)
|
|
||||||
|
|
||||||
quest.update_db()
|
|
||||||
return jsonify(dictify_quest(quest))
|
|
||||||
|
|
||||||
|
|
||||||
app.add_url_rule('/update_quest', '/update_quest', lambda: update_quest(db),
|
|
||||||
methods=['POST'])
|
|
||||||
|
|
||||||
|
|
||||||
# /update_side_quest
|
|
||||||
def update_side_quest(db):
|
|
||||||
player = get_player(db)
|
|
||||||
if player is False:
|
|
||||||
return jsonify(errors._401), 401
|
|
||||||
try:
|
|
||||||
qid = request.values['id']
|
|
||||||
except(KeyError):
|
|
||||||
return jsonify(errors._400), 400
|
|
||||||
|
|
||||||
available_keys = [i for i in ['name', 'difficulty', 'priority', 'state']
|
|
||||||
if i in request.values.keys()]
|
|
||||||
if len(available_keys) == 0:
|
|
||||||
return jsonify(errors._400), 400
|
|
||||||
quest = questable.get_side_quest(db, player.CHAT_ID, qid)
|
|
||||||
|
|
||||||
if quest is False:
|
|
||||||
return jsonify(errors._404), 404
|
|
||||||
|
|
||||||
if quest.state == 1:
|
|
||||||
return jsonify(dictify_quest(quest))
|
|
||||||
|
|
||||||
for i in available_keys:
|
|
||||||
try:
|
|
||||||
if i == "name":
|
|
||||||
quest.name = request.values["name"]
|
|
||||||
elif i == "difficulty":
|
|
||||||
diff = int(request.values["difficulty"])
|
|
||||||
if diff in [1, 2, 3]:
|
|
||||||
quest.diff = diff
|
|
||||||
else:
|
|
||||||
return jsonify(errors._400_bv), 400
|
|
||||||
elif i == "priority":
|
|
||||||
imp = int(request.values["priority"])
|
|
||||||
if imp in [1, 2, 3]:
|
|
||||||
quest.imp = imp
|
|
||||||
else:
|
|
||||||
return jsonify(errors._400_bv), 400
|
|
||||||
elif i == "state":
|
|
||||||
state = (True if str(request.values['state']).lower()
|
|
||||||
in ["1", "true"] else False)
|
|
||||||
if state is True:
|
|
||||||
quest.state = 1
|
|
||||||
else:
|
|
||||||
return jsonify(errors._400_bv), 400
|
|
||||||
except (ValueError):
|
|
||||||
return jsonify(errors._400_bv), 400
|
|
||||||
|
|
||||||
if quest.state == 1:
|
|
||||||
points = 10*quest.imp + 15*quest.diff
|
|
||||||
player.add_points(points)
|
|
||||||
|
|
||||||
quest.update_db()
|
|
||||||
return jsonify(dictify_quest(quest))
|
|
||||||
|
|
||||||
|
|
||||||
app.add_url_rule('/update_side_quest', '/update_side_quest',
|
|
||||||
lambda: update_side_quest(db), methods=['POST'])
|
|
||||||
|
|
||||||
|
|
||||||
# /delete_quest
|
|
||||||
def delete_quest(db):
|
|
||||||
player = get_player(db)
|
|
||||||
if player is False:
|
|
||||||
return jsonify(errors._401), 401
|
|
||||||
try:
|
|
||||||
qid = request.values['id']
|
|
||||||
except(KeyError):
|
|
||||||
return jsonify(errors._400), 400
|
|
||||||
|
|
||||||
try:
|
|
||||||
quest = questable.get_quest(db, player.CHAT_ID, qid)
|
|
||||||
except Exception:
|
|
||||||
return jsonify(errors._404), 404
|
|
||||||
|
|
||||||
if quest.state == 1:
|
|
||||||
return jsonify({"success": False})
|
|
||||||
|
|
||||||
quest.delete_from_db()
|
|
||||||
return jsonify({"success": True})
|
|
||||||
|
|
||||||
|
|
||||||
app.add_url_rule('/delete_quest', '/delete_quest',
|
|
||||||
lambda: delete_quest(db), methods=['DELETE'])
|
|
||||||
|
|
||||||
|
|
||||||
# /delete_side_quest
|
|
||||||
def delete_side_quest(db):
|
|
||||||
player = get_player(db)
|
|
||||||
if player is False:
|
|
||||||
return jsonify(errors._401), 401
|
|
||||||
try:
|
|
||||||
qid = request.values['id']
|
|
||||||
except(KeyError):
|
|
||||||
return jsonify(errors._400), 400
|
|
||||||
|
|
||||||
try:
|
|
||||||
side_quest = questable.get_side_quest(db, player.CHAT_ID, qid)
|
|
||||||
except Exception:
|
|
||||||
return jsonify(errors._404), 404
|
|
||||||
|
|
||||||
if side_quest.state == 1:
|
|
||||||
return jsonify({"success": False})
|
|
||||||
|
|
||||||
side_quest.delete_from_db()
|
|
||||||
return jsonify({"success": True})
|
|
||||||
|
|
||||||
|
|
||||||
app.add_url_rule('/delete_side_quest', '/delete_side_quest',
|
|
||||||
lambda: delete_side_quest(db), methods=['DELETE'])
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/')
|
|
||||||
def redirect_to_docs():
|
|
||||||
return redirect("https://questable.webionite.com/api", code=301)
|
|
Loading…
x
Reference in New Issue
Block a user