diff --git a/bot.py b/bot.py
old mode 100644
new mode 100755
index 0722cf2..732f4e1
--- a/bot.py
+++ b/bot.py
@@ -10,6 +10,7 @@ from telegram.ext import Updater, CommandHandler, MessageHandler, Filters, \
import signal
import sys
import re
+import button_groups
try:
import config
@@ -28,16 +29,15 @@ def escape_html(message):
def start(bot, update):
chat_id = update.message.chat_id
- name = str(update.message.from_user.first_name)
- if update.message.from_user.last_name:
- name += " " + str(update.message.from_user.last_name)
+ if update.message.chat.type == "private":
+ name = str(update.message.from_user.first_name)
+ if 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" + \
"Welcome to Questable. To get started, check /help."
- custom_keyboard = [
- ['โ๏ธ Add Quest', '๐ฏ Add Side Quest'],
- ['๐ List Quests', '๐ List Side Quests'],
- ['๐
Player Status']
- ]
+ custom_keyboard = button_groups.main
reply_markup = telegram.ReplyKeyboardMarkup(custom_keyboard)
bot.send_message(chat_id=chat_id, text=text, reply_markup=reply_markup)
@@ -68,7 +68,10 @@ def add_quest(bot, update, player, type="quest"):
chat_id = update.message.chat_id
text = ("What shall the name of " +
{"quest": "Quest", "side_quest": "Side Quest"}[type] + " be?")
- reply_markup = telegram.ReplyKeyboardRemove()
+ if update.message.chat.type == "private":
+ reply_markup = telegram.ReplyKeyboardRemove()
+ else:
+ reply_markup = telegram.ForceReply()
bot.send_message(chat_id=chat_id, text=text, reply_markup=reply_markup)
@@ -87,7 +90,7 @@ def add_name(bot, update, player, type, qid):
chat_id = update.message.chat_id
text = "How difficult is it?"
- custom_keyboard = [["๐ Low", "๐ Medium", "๐ High"]]
+ custom_keyboard = button_groups.difficulty
reply_markup = telegram.ReplyKeyboardMarkup(custom_keyboard)
bot.send_message(chat_id=chat_id, text=text, reply_markup=reply_markup)
@@ -118,7 +121,7 @@ def add_diff(bot, update, player, type, qid):
x.update_db()
text = "How important is it?"
- custom_keyboard = [["๐น Low", "๐ธ Medium", "๐บ High"]]
+ custom_keyboard = button_groups.importance
reply_markup = telegram.ReplyKeyboardMarkup(custom_keyboard)
bot.send_message(chat_id=chat_id, text=text, reply_markup=reply_markup)
@@ -154,9 +157,12 @@ def add_imp(bot, update, player, type, qid):
def send_status(bot, update, player, prefix=""):
- name = str(update.message.from_user.first_name)
- if update.message.from_user.last_name:
- name += " " + str(update.message.from_user.last_name)
+ if update.message.chat.type == "private":
+ name = str(update.message.from_user.first_name)
+ if 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()
total_quests = len(player.get_quests(None))
@@ -170,11 +176,7 @@ def send_status(bot, update, player, prefix=""):
f'๐ Side Quests: {completed_side_quests}/'
f'{total_side_quests}\n')
chat_id = update.message.chat_id
- custom_keyboard = [
- ['โ๏ธ Add Quest', '๐ฏ Add Side Quest'],
- ['๐ List Quests', '๐ List Side Quests'],
- ['๐
Player Status']
- ]
+ custom_keyboard = button_groups.main
reply_markup = telegram.ReplyKeyboardMarkup(custom_keyboard)
bot.send_message(chat_id=chat_id, text=text, reply_markup=reply_markup,
parse_mode="HTML")
@@ -246,13 +248,7 @@ def quest(bot, update, player, qid, type):
elif x.state == 0:
state = {"quest": "eq", "side_quest": "esq"}[type]
player.set_state(state, qid)
- custom_keyboard = [
- ["โ
Mark as done"],
- ["๐ Edit Name", "โ ๏ธ Change Priority"],
- ["๐ Change Difficulty", "๐ Delete " +
- {"quest": "Quest", "side_quest": "Side Quest"}[type]],
- ["โฌ
๏ธ Back"]]
-
+ custom_keyboard = button_groups.quests(type)
reply_markup = telegram.ReplyKeyboardMarkup(custom_keyboard)
chat_id = update.message.chat_id
bot.send_message(chat_id=chat_id, text=text, parse_mode="HTML",
@@ -260,7 +256,7 @@ def quest(bot, update, player, qid, type):
def quest_handling(bot, update, db):
- text = update.message.text.lower().split("_")
+ text = update.message.text.lower().split("@")[0].split("_")
chat_id = update.message.chat_id
player = questable.player(db, chat_id)
drop_state(bot, update, player)
@@ -287,11 +283,7 @@ def mark_as_done(bot, update, player, qid, type):
player.set_state('none', 0)
send_status(bot, update, player, f"๐ Earned {points} XP\n\n")
chat_id = update.message.chat_id
- custom_keyboard = [
- ['โ๏ธ Add Quest', '๐ฏ Add Side Quest'],
- ['๐ List Quests', '๐ List Side Quests'],
- ['๐
Player Status']
- ]
+ custom_keyboard = button_groups.main
reply_markup = telegram.ReplyKeyboardMarkup(custom_keyboard)
bot.send_animation(chat_id=chat_id, animation=random.choice(config.gifs),
reply_markup=reply_markup)
@@ -365,17 +357,15 @@ def drop_state(bot, update, player):
x = questable.get_side_quest(player.DB, player.CHAT_ID, state["extra"])
x.delete_from_db()
player.set_state('none', 0)
+ else:
+ player.set_state('none', 0)
def help_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 = [
- ['โ๏ธ Add Quest', '๐ฏ Add Side Quest'],
- ['๐ List Quests', '๐ List Side Quests'],
- ['๐
Player Status']
- ]
+ custom_keyboard = button_groups.main
text = ("*Questable Bot*\n\nQuestable is an RPG-like bot for maintaining "
"events in real life. _Main Tasks_ are _Quests_ while _other "
"tasks_ are _Side Quests._ You can use the bot to maintain a "
@@ -396,11 +386,7 @@ 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 = [
- ['โ๏ธ Add Quest', '๐ฏ Add Side Quest'],
- ['๐ List Quests', '๐ List Side Quests'],
- ['๐
Player Status']
- ]
+ 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 "
@@ -410,6 +396,56 @@ def rate_command(bot, update, db):
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.")
+ bot.send_message(chat_id=update.message.chat_id, text=reply_text,
+ reply_markup=reply_markup)
+
+
+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):
text = update.message.text.lower()
player = questable.player(db, update.message.chat_id)
@@ -427,6 +463,7 @@ def message_handling(bot, update, db):
# eqn / esqn: Edit Quest / Side Quest Name
# eqi / esqi: Edit Quest / Side Quest Importance
# eqd / esqd: Edit Quest / Side Quest Difficulty
+ # rt: Remove token
if state["state"] == "none":
if text == "add quest" or text == "โ๏ธ add quest":
@@ -437,9 +474,20 @@ def message_handling(bot, update, db):
list_quests(bot, update, player, "quest")
elif text == "list side quests" or text == "๐ list side quests":
list_quests(bot, update, player, "side_quest")
+ elif text == "tokens" or text == "๐ tokens":
+ tokens(bot, update)
+ elif text == "list tokens" or text == "๐ list tokens":
+ list_tokens(bot, update, player)
+
+ elif text == "generate token" or text == "๐ generate token":
+ add_token(bot, update, player)
+
+ elif text == "delete token" or text == "๐งน delete token":
+ delete_token(bot, update, player)
+
else:
- drop_state(bot, update, player)
- send_status(bot, update, player)
+ if update.message.chat.type == "private":
+ send_status(bot, update, player)
elif state["state"] == "aq":
add_name(bot, update, player, "quest", state["extra"])
@@ -474,14 +522,14 @@ def message_handling(bot, update, db):
elif text == "change priority" or text == "โ ๏ธ change priority":
player.set_state('eqi', state["extra"])
text = "How important is it?"
- custom_keyboard = [["๐น Low", "๐ธ Medium", "๐บ High"]]
+ custom_keyboard = button_groups.importance
reply_markup = telegram.ReplyKeyboardMarkup(custom_keyboard)
bot.send_message(chat_id=player.CHAT_ID, text=text,
reply_markup=reply_markup)
elif text == "change difficulty" or text == "๐ change difficulty":
player.set_state('eqd', state["extra"])
text = "How difficult is it?"
- custom_keyboard = [["๐ Low", "๐ Medium", "๐ High"]]
+ custom_keyboard = button_groups.difficulty
reply_markup = telegram.ReplyKeyboardMarkup(custom_keyboard)
bot.send_message(chat_id=player.CHAT_ID, text=text,
reply_markup=reply_markup)
@@ -492,8 +540,9 @@ def message_handling(bot, update, db):
prefix = f"Quest {quest.name} has been deleted\n\n"
send_status(bot, update, player, prefix=prefix)
else:
- drop_state(bot, update, player)
- send_status(bot, update, player)
+ if update.message.chat.type == "private":
+ drop_state(bot, update, player)
+ send_status(bot, update, player)
elif state["state"] == "esq":
if text == "back" or text == "โฌ
๏ธ back":
@@ -510,14 +559,14 @@ def message_handling(bot, update, db):
elif text == "change priority" or text == "โ ๏ธ change priority":
player.set_state('esqi', state["extra"])
text = "How important is it?"
- custom_keyboard = [["๐น Low", "๐ธ Medium", "๐บ High"]]
+ custom_keyboard = button_groups.importance
reply_markup = telegram.ReplyKeyboardMarkup(custom_keyboard)
bot.send_message(chat_id=player.CHAT_ID, text=text,
reply_markup=reply_markup)
elif text == "change difficulty" or text == "๐ change difficulty":
player.set_state('esqd', state["extra"])
text = "How difficult is it?"
- custom_keyboard = [["๐ Low", "๐ Medium", "๐ High"]]
+ custom_keyboard = button_groups.difficulty
reply_markup = telegram.ReplyKeyboardMarkup(custom_keyboard)
bot.send_message(chat_id=player.CHAT_ID, text=text,
reply_markup=reply_markup)
@@ -528,12 +577,14 @@ def message_handling(bot, update, db):
prefix = f"Side Quest {sq.name} has been deleted\n\n"
send_status(bot, update, player, prefix=prefix)
else:
- drop_state(bot, update, player)
- send_status(bot, update, player)
+ if update.message.chat.type == "private":
+ drop_state(bot, update, player)
+ send_status(bot, update, player)
elif state["state"] == "bo":
- player.set_state('none', 0)
- send_status(bot, update, player)
+ if text == "back" or update.message.chat.type == "private":
+ player.set_state('none', 0)
+ send_status(bot, update, player)
elif state["state"] == "eqn":
edit_quest(bot, update, player, state["extra"], "name", "quest")
@@ -553,9 +604,12 @@ def message_handling(bot, update, db):
elif state["state"] == "esqd":
edit_quest(bot, update, player, state["extra"], "diff", "side_quest")
+ elif state["state"] == "rt":
+ delete_token_rt(bot, update, player)
else:
- drop_state(bot, update, player)
- send_status(bot, update, player)
+ if update.message.chat.type == "private":
+ drop_state(bot, update, player)
+ send_status(bot, update, player)
def sigterm_handler(signal, frame, db):
@@ -563,28 +617,13 @@ def sigterm_handler(signal, frame, db):
sys.exit(0)
-db = sqlite3.connect("questable.db", check_same_thread=False)
-cursor = db.cursor()
signal.signal(signal.SIGTERM, lambda x, y: sigterm_handler(x, y, db))
-# 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)
+# Set up database and tables
+db = sqlite3.connect("questable.db", check_same_thread=False)
+cursor = db.cursor()
+with open('schema.sql') as f:
+ cursor.executescript(f.read())
db.commit()
updater = Updater(token=config.api_key)
diff --git a/button_groups.py b/button_groups.py
new file mode 100644
index 0000000..b5c5174
--- /dev/null
+++ b/button_groups.py
@@ -0,0 +1,23 @@
+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"]
+ ]
diff --git a/errors.py b/errors.py
new file mode 100644
index 0000000..a0ae6d8
--- /dev/null
+++ b/errors.py
@@ -0,0 +1,4 @@
+_400 = {"error": "insufficient parameters"}
+_400_bv = {"error": "bad values"}
+_401 = {"error": "invalid token"}
+_404 = {"error": "The quest/side quest doesn't exist"}
diff --git a/questable.py b/questable.py
index da5eb7a..895773a 100644
--- a/questable.py
+++ b/questable.py
@@ -1,3 +1,6 @@
+import uuid
+
+
class base_quest():
TABLE = None
@@ -153,3 +156,57 @@ class player():
q = side_quest(self.DB, *row)
quests.append(q)
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])
diff --git a/schema.sql b/schema.sql
new file mode 100644
index 0000000..1c659de
--- /dev/null
+++ b/schema.sql
@@ -0,0 +1,5 @@
+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);
diff --git a/server.py b/server.py
new file mode 100644
index 0000000..f09c88b
--- /dev/null
+++ b/server.py
@@ -0,0 +1,371 @@
+#!/usr/bin/env python3
+
+import questable
+import sqlite3
+import errors
+from flask import Flask, jsonify, request, redirect
+
+app = Flask(__name__)
+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 = bool(request.values["state"])
+ 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 = bool(request.values["state"])
+ 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)