diff options
author | 2018-04-20 22:12:03 +0200 | |
---|---|---|
committer | 2018-04-20 22:12:03 +0200 | |
commit | 35e0f4466677602e9ec6db614e8ea881dbf656cb (patch) | |
tree | 43ebdcc530b57211e45e4fe96bb2811e334640f0 /pysite/views/api/bot | |
parent | Added image URLs for each of these famous rappers. (#55) (diff) |
[#1eeu1] Hiphopify (#54)
* Changed the dev-mode logic to be the same as prod for creating new tables if they don't exist. Also added a new feature where a table can be initialized with data if you create a JSON file in the pysite/database/table_init/ folder and fill it with a list of dicts where each dict represents a row in your table. Included a hiphoppers json so that I can actually test if it works in production. It will only init the table if the table is empty.
* Not sure if this will solve it, but I think so.
* Renamed the tables and primary keys, and alphabetized the dict. Now complies with the gdudes holy wishes.
* Almost done with the initial build for this. Implemented GET and DELETE, in order to finish POST I need to expand the database.py interface class.
* Alphabetized database convenience wrappers.
* Fixed a few typehints and added the sample convenience wrapper to the database class.
* Finishing up the POST method and adding a duration parser to the utils folder so we can handle strings like 2w3d and turn them into a timestamp.
* Fixed API blueprint loading, which was broken by the setup method in the DBMixIn. I'd forgotten to remove the check for table_name attribute. Also adde some logging and got the DELETE route working.
* Added timezone-sensitivity to the duration parser so it will work with rethink. renamed the json and fixed some bugs in the hiphopify API.
* Added a utility to test if rdb timestamps are expired, and only returning data from the GET calls if it isn't expired.
* changed some log wording
* Setting up Lil Joseph as default image. Adding some rappers to the list.
* Adding a bunch of logging
* These tests no longer apply. New tests must be written in the long run, removing them for now.
* Addressing review comments left by Volcyy
* Fixed misleading comment.
Diffstat (limited to 'pysite/views/api/bot')
-rw-r--r-- | pysite/views/api/bot/hiphopify.py | 178 |
1 files changed, 178 insertions, 0 deletions
diff --git a/pysite/views/api/bot/hiphopify.py b/pysite/views/api/bot/hiphopify.py new file mode 100644 index 00000000..7ebf47e1 --- /dev/null +++ b/pysite/views/api/bot/hiphopify.py @@ -0,0 +1,178 @@ +# coding=utf-8 +import datetime +import logging + +from flask import jsonify +from schema import Optional, Schema + +from pysite.base_route import APIView +from pysite.constants import ValidationTypes +from pysite.decorators import api_key, api_params +from pysite.mixins import DBMixin +from pysite.utils.time import is_expired, parse_duration + +log = logging.getLogger(__name__) + +GET_SCHEMA = Schema([ + { + "user_id": str + } +]) + +POST_SCHEMA = Schema([ + { + "user_id": str, + "duration": str, + Optional("forced_nick"): str + } +]) + +DELETE_SCHEMA = Schema([ + { + "user_id": str + } +]) + + +class HiphopifyView(APIView, DBMixin): + path = "/hiphopify" + name = "hiphopify" + prison_table = "hiphopify" + name_table = "hiphopify_namelist" + + @api_key + @api_params(schema=GET_SCHEMA, validation_type=ValidationTypes.params) + def get(self, params=None): + """ + Check if the user is currently in hiphop-prison. + + If user is currently servin' his sentence in the big house, + return the name stored in the forced_nick column of prison_table. + + If user cannot be found in prison, or + if his sentence has expired, return nothing. + + Data must be provided as params. + API key must be provided as header. + """ + + user_id = params[0].get("user_id") + + log.debug(f"Checking if user ({user_id}) is permitted to change their nickname.") + data = self.db.get(self.prison_table, user_id) or {} + + if data and data.get("end_timestamp"): + log.trace("User exists in the prison_table.") + end_time = data.get("end_timestamp") + if is_expired(end_time): + log.trace("...But their sentence has already expired.") + data = {} # Return nothing if the sentence has expired. + + return jsonify(data) + + @api_key + @api_params(schema=POST_SCHEMA, validation_type=ValidationTypes.json) + def post(self, json_data): + """ + Imprisons a user in hiphop-prison. + + If a forced_nick was provided by the caller, the method will force + this nick. If not, a random hiphop nick will be selected from the + name_table. + + Data must be provided as JSON. + API key must be provided as header. + """ + + user_id = json_data[0].get("user_id") + duration = json_data[0].get("duration") + forced_nick = json_data[0].get("forced_nick") + + log.debug(f"Attempting to imprison user ({user_id}).") + + # Get random name and picture if no forced_nick was provided. + if not forced_nick: + log.trace("No forced_nick provided. Fetching a random rapper name and image.") + rapper_data = self.db.sample(self.name_table, 1)[0] + forced_nick = rapper_data.get('name') + + # If forced nick was provided, try to look up the forced_nick in the database. + # If a match cannot be found, just default to Lil' Jon for the image. + else: + log.trace(f"Forced nick provided ({forced_nick}). Trying to match it with the database.") + rapper_data = ( + self.db.get(self.name_table, forced_nick) + or self.db.get(self.name_table, "Lil' Joseph") + ) + + image_url = rapper_data.get('image_url') + log.trace(f"Using the nickname {forced_nick} and the image_url {image_url}.") + + # Convert duration to valid timestamp + try: + log.trace("Parsing the duration and converting it to a timestamp") + end_timestamp = parse_duration(duration) + except ValueError: + log.warning(f"The duration could not be parsed, or was invalid. The duration was '{duration}'.") + return jsonify({ + "success": False, + "error_message": "Invalid duration" + }) + + log.debug("Everything seems to be in order, inserting the data into the prison_table.") + self.db.insert( + self.prison_table, + { + "user_id": user_id, + "end_timestamp": end_timestamp, + "forced_nick": forced_nick + }, + conflict="update" # If it exists, update it. + ) + + return jsonify({ + "success": True, + "end_timestamp": end_timestamp, + "forced_nick": forced_nick, + "image_url": image_url + }) + + @api_key + @api_params(schema=DELETE_SCHEMA, validation_type=ValidationTypes.json) + def delete(self, json_data): + """ + Releases a user from hiphop-prison. + + Data must be provided as JSON. + API key must be provided as header. + """ + + user_id = json_data[0].get("user_id") + + log.debug(f"Attempting to release user ({user_id}) from hiphop-prison.") + prisoner_data = self.db.get(self.prison_table, user_id) + sentence_expired = None + + log.trace(f"Checking if the user ({user_id}) is currently in hiphop-prison.") + if prisoner_data and prisoner_data.get("end_datetime"): + sentence_expired = datetime.datetime.now() > prisoner_data.get("end_datetime") + + if prisoner_data and not sentence_expired: + log.debug("User is currently in hiphop-prison. Deleting the record and releasing the prisoner.") + self.db.delete( + self.prison_table, + user_id + ) + return jsonify({"success": True}) + elif not prisoner_data: + log.warning(f"User ({user_id}) is not currently in hiphop-prison.") + return jsonify({ + "success": False, + "error_message": "User is not currently in hiphop-prison!" + }) + elif sentence_expired: + log.warning(f"User ({user_id}) was in hiphop-prison, but has already been released.") + return jsonify({ + "success": False, + "error_message": "User has already been released from hiphop-prison!" + }) |