def test_combined_duration_string_parsing(self): for duration_string, added_delta in self.COMBINED_DURATION_STRINGS: timezone_aware_now = datetime.now(timezone.utc) self.assertAlmostEqual( parse_duration(duration_string).timestamp(), (timezone_aware_now + added_delta).timestamp(), places=-1 # Being off by < 10 seconds is acceptable )
def post(self, json_data): """ Create and save a new reminder. Data must be provided as JSON. API key must be provided as header. """ duration = json_data["duration"] try: remind_at = parse_duration(duration) except ValueError: return jsonify({ "success": False, "error_message": "An invalid duration was given." }) # Get all of the user's active reminders user_id_filter = {"user_id": json_data["user_id"]} active_reminders = self.db.run( self.db.query(self.table_name).filter(user_id_filter)) # Find all the friendly ID's that are currently in use for this user. taken_ids = (rem["friendly_id"] for rem in active_reminders) # Search for the smallest available friendly ID friendly_id = 0 while str(friendly_id) in taken_ids: friendly_id += 1 # Set up the data to be inserted to the table reminder_data = { "user_id": json_data["user_id"], "content": json_data["content"], "remind_at": remind_at, "channel_id": json_data["channel_id"], "friendly_id": str(friendly_id) } # Insert the data and get the generated ID reminder_id = self.db.insert(self.table_name, reminder_data)["generated_keys"][0] # Create the JSON response data response = {"reminder": {"id": reminder_id, **reminder_data}} return jsonify({"success": True, **response})
def patch(self, json_data): """ Update the duration or content of a user's reminder. Data must be provided as JSON. API key must be provided as header. """ reminder = self._get_full_reminder(json_data["user_id"], json_data["friendly_id"]) if not reminder: return jsonify({ "success": False, "error_message": "Reminder could not be found." }) if "duration" in json_data: duration = json_data["duration"] # Attempt to update the duration, but return if it's invalid. try: reminder["remind_at"] = parse_duration(duration) except ValueError: return jsonify({ "success": False, "error_message": "An invalid duration was given." }) if "content" in json_data: reminder["content"] = json_data["content"] # Update the reminder with the new information update_result = self.db.run( self.db.query(self.table_name).update(reminder)) # Make sure something actually changed if not update_result["replaced"]: return jsonify({ "success": False, "error_message": "Nothing was changed." }) return jsonify({"success": True, "reminder": reminder})
def patch(self, data): expand = data.get("expand") update_collection = {"id": data["id"]} if "reason" in data: update_collection["reason"] = data["reason"] if "active" in data: update_collection["active"] = data["active"] update_collection["closed"] = not data["active"] if "duration" in data: duration_str = data["duration"] if duration_str is None: update_collection["expires_at"] = None else: try: update_collection["expires_at"] = parse_duration( duration_str) except ValueError: return self.error(ErrorCodes.incorrect_parameters, "Invalid duration format.") query_update = self.db.query(self.table_name).update(update_collection) result_update = self.db.run(query_update) if not result_update["replaced"]: return jsonify({ "success": False, "error_message": "Unknown infraction / nothing was changed." }) # return the updated infraction query = self.db.query(self.table_name).get(data["id"]) \ .merge(_merge_expand_users(self, expand)) \ .merge(_merge_active_check()) \ .without(*EXCLUDED_FIELDS).default(None) infraction = self.db.run(query) return jsonify({"infraction": infraction, "success": True})
def post(self, json_data): """ Imprisons a user in superstar-prison. If a forced_nick was provided by the caller, the method will force this nick. If not, a random superstar 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.get("user_id") duration = json_data.get("duration") forced_nick = json_data.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 })
def post(self, data): deactivate_infraction_query = None infraction_type = data["type"] user_id = data["user_id"] actor_id = data["actor_id"] reason = data["reason"] duration_str = data.get("duration") expand = data.get("expand") hidden = data.get("hidden") expires_at = None inserted_at = datetime.datetime.now(tz=datetime.timezone.utc) if infraction_type not in INFRACTION_TYPES: return self.error(ErrorCodes.incorrect_parameters, "Invalid infraction type.") # Hidden warnings are notes. elif infraction_type == "warning" and hidden is True: infraction_type = "note" # check if the user already has an active infraction of this type # if so, we need to disable that infraction and create a new infraction if INFRACTION_TYPES[infraction_type].timed_infraction: active_infraction_query = \ self.db.query(self.table_name).merge(_merge_active_check()) \ .filter({"user_id": user_id, "type": infraction_type, "active": True}) \ .limit(1).nth(0).default(None) active_infraction = self.db.run(active_infraction_query) if active_infraction: deactivate_infraction_query = \ self.db.query(self.table_name) \ .get(active_infraction["id"]) \ .update({"active": False, "closed": True}) if duration_str: try: expires_at = parse_duration(duration_str) except ValueError: return self.error(ErrorCodes.incorrect_parameters, "Invalid duration format.") infraction_insert_doc = { "actor_id": actor_id, "user_id": user_id, "type": infraction_type, "reason": reason, "inserted_at": inserted_at, "expires_at": expires_at, "hidden": hidden } infraction_id = self.db.insert( self.table_name, infraction_insert_doc)["generated_keys"][0] if deactivate_infraction_query: self.db.run(deactivate_infraction_query) query = self.db.query(self.table_name).get(infraction_id) \ .merge(_merge_expand_users(self, expand)) \ .merge(_merge_active_check()) \ .without(*EXCLUDED_FIELDS).default(None) return jsonify({"infraction": self.db.run(query)})
def test_valid_unit_without_digits_raises_valueerror(self): with self.assertRaises(ValueError): parse_duration('s')
def test_unknown_char_raises_valueerror(self): with self.assertRaises(ValueError): parse_duration('12l')
def test_empty_duration_raises_valueerror(self): with self.assertRaises(ValueError): parse_duration('')