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)