예제 #1
0
 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
         )
예제 #2
0
    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})
예제 #3
0
    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})
예제 #4
0
    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})
예제 #5
0
    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
        })
예제 #6
0
    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)})
예제 #7
0
 def test_valid_unit_without_digits_raises_valueerror(self):
     with self.assertRaises(ValueError):
         parse_duration('s')
예제 #8
0
 def test_unknown_char_raises_valueerror(self):
     with self.assertRaises(ValueError):
         parse_duration('12l')
예제 #9
0
 def test_empty_duration_raises_valueerror(self):
     with self.assertRaises(ValueError):
         parse_duration('')