From 56b6b07456408377d897c159f865d8d40a8a7761 Mon Sep 17 00:00:00 2001 From: Miuna <809711+Mishura4@users.noreply.github.com> Date: Wed, 1 May 2024 03:30:39 -0400 Subject: [PATCH] fix: fix human_readable for good (#1135) --- include/dpp/restresults.h | 2 +- src/dpp/cluster/confirmation.cpp | 127 ++++++++++--------------------- src/unittest/test.cpp | 17 +++++ 3 files changed, 57 insertions(+), 89 deletions(-) diff --git a/include/dpp/restresults.h b/include/dpp/restresults.h index ec52ca1b71..3dd0ebb69c 100644 --- a/include/dpp/restresults.h +++ b/include/dpp/restresults.h @@ -220,7 +220,7 @@ struct DPP_EXPORT error_detail { /** * @brief Object field index */ - int index = 0; + DPP_DEPRECATED("index is unused and will be removed in a future version") int index = 0; }; /** diff --git a/src/dpp/cluster/confirmation.cpp b/src/dpp/cluster/confirmation.cpp index 83f8d712bb..0589705752 100644 --- a/src/dpp/cluster/confirmation.cpp +++ b/src/dpp/cluster/confirmation.cpp @@ -74,22 +74,39 @@ bool confirmation_callback_t::is_error() const { namespace { -std::vector find_errors_in_array(const std::string& obj, size_t index, const std::string& current_field, json::iterator begin, json::iterator end) { +std::vector find_errors_in_object(const std::string& obj, const std::string& current_field, const json &j) { std::vector ret; - for (auto it = begin; it != end; ++it) { - if (auto errors = it->find("_errors"); errors != it->end()) { - for (auto errordetails = errors->begin(); errordetails != errors->end(); ++errordetails) { - error_detail detail; - detail.code = (*errordetails)["code"].get(); - detail.reason = (*errordetails)["message"].get(); - detail.field = current_field + it.key(); - detail.object = obj; - detail.index = index; - ret.emplace_back(detail); + if (auto errors = j.find("_errors"); errors != j.end()) { + for (const json& errordetails : *errors) { + error_detail detail; + detail.code = errordetails["code"].get(); + detail.reason = errordetails["message"].get(); + detail.field = current_field; + detail.object = obj; + ret.emplace_back(detail); + } + } else { + for (auto it = j.begin(); it != j.end(); ++it) { + std::vector sub_errors; + std::string field; + + if (obj.empty()) { + field = current_field; + } else if (isdigit(*current_field.c_str())) { + /* An element of an array, e.g. an element of a slash command vector for global_bulk_slash_command_create */ + field = obj; + field += '['; + field += current_field; + field += ']'; + } else { + /* A field of an object, e.g. message.content too long */ + field = obj; + field += '.'; + field += current_field; } - } else { // subobject has errors - auto sub_errors = find_errors_in_array(obj, index, current_field + it.key() + ".", it->begin(), it->end()); + + sub_errors = find_errors_in_object(field, it.key(), *it); if (!sub_errors.empty()) { ret.reserve(ret.capacity() + sub_errors.size()); @@ -111,77 +128,14 @@ error_info confirmation_callback_t::get_error() const { set_string_not_null(&j, "message", e.message); json& errors = j["errors"]; for (auto obj = errors.begin(); obj != errors.end(); ++obj) { + std::vector sub_errors; + std::string field = isdigit(*obj.key().c_str()) ? "[" + obj.key() + "]" : obj.key(); - /* Arrays in the error report are numerically indexed with a number in a string. Ugh. */ - if (isdigit(*(obj.key().c_str()))) { - /* An array of error messages */ - int array_index = std::atoll(obj.key().c_str()); - for (auto index = obj->begin(); index != obj->end(); ++index) { - if (index->find("_errors") != index->end()) { - /* A single object where one or more fields generated an error */ - for (auto errordetails = (*index)["_errors"].begin(); errordetails != (*index)["_errors"].end(); ++errordetails) { - error_detail detail; - detail.code = (*errordetails)["code"].get(); - detail.reason = (*errordetails)["message"].get(); - detail.object.clear(); - detail.field = obj.key(); - detail.index = array_index; - e.errors.emplace_back(detail); - } - } else { - /* An object where one or more fields within it generated an error, e.g. slash command */ - for (auto fields = index->begin(); fields != index->end(); ++fields) { - if (fields->find("_errors") != fields->end()) { - for (auto errordetails = (*fields)["_errors"].begin(); errordetails != (*fields)["_errors"].end(); ++errordetails) { - error_detail detail; - detail.code = (*errordetails)["code"].get(); - detail.reason = (*errordetails)["message"].get(); - detail.field = fields.key(); - detail.object = obj.key(); - detail.index = array_index; - e.errors.emplace_back(detail); - } - } else { - /* An array of objects where one or more generated an error, e.g. slash command bulk registration */ - for (auto fields2 = fields->begin(); fields2 != fields->end(); ++fields2) { - for (auto errordetails = (*fields2)["_errors"].begin(); errordetails != (*fields2)["_errors"].end(); ++errordetails) { - error_detail detail; - detail.code = (*errordetails)["code"].get(); - detail.reason = (*errordetails)["message"].get(); - detail.field = index.key() + "[" + fields.key() + "]." + fields2.key(); - detail.object = obj.key(); - detail.index = array_index; - e.errors.emplace_back(detail); - } - } - } - } - } - } - - } else if (obj->find("_errors") != obj->end()) { - /* An object of error messages (rare) */ - e.errors.reserve((*obj)["_errors"].size()); - for (auto errordetails = (*obj)["_errors"].begin(); errordetails != (*obj)["_errors"].end(); ++errordetails) { - error_detail detail; - detail.code = (*errordetails)["code"].get(); - detail.reason = (*errordetails)["message"].get(); - detail.object.clear(); - detail.field = obj.key(); - detail.index = 0; - e.errors.emplace_back(detail); - } - } else { - /* An object that has a subobject with errors */ - for (auto index = obj->begin(); index != obj->end(); ++index) { - int array_index = std::atoll(index.key().c_str()); - auto sub_errors = find_errors_in_array(obj.key(), array_index, {}, index->begin(), index->end()); - - if (!sub_errors.empty()) { - e.errors.reserve(e.errors.capacity() + sub_errors.size()); - std::move(sub_errors.begin(), sub_errors.end(), std::back_inserter(e.errors)); - } - } + sub_errors = find_errors_in_object({}, field, *obj); + + if (!sub_errors.empty()) { + e.errors.reserve(e.errors.capacity() + sub_errors.size()); + std::move(sub_errors.begin(), sub_errors.end(), std::back_inserter(e.errors)); } } @@ -191,12 +145,9 @@ error_info confirmation_callback_t::get_error() const { if (error.object.empty()) { /* A singular field with an error in an unnamed object */ e.human_readable += prefix + "- " + error.field + ": " + error.reason + " (" + error.code + ")"; - } else if (isdigit(*(error.object.c_str()))) { - /* An unnamed array of objects where one or more generated an error, e.g. slash command bulk registration */ - e.human_readable += prefix + "- [" + error.object + "]." + error.field + ": " + error.reason + " (" + error.code + ")"; } else { - /* A named array of objects whre a field in the object has an error */ - e.human_readable += prefix + "- " + error.object + "[" + std::to_string(error.index) + "]." + error.field + ": " + error.reason + " (" + error.code + ")"; + /* An object field that caused an error */ + e.human_readable += prefix + "- " + error.object + '.' + error.field + ": " + error.reason + " (" + error.code + ")"; } } diff --git a/src/unittest/test.cpp b/src/unittest/test.cpp index f1a64d2c0e..1b76713535 100644 --- a/src/unittest/test.cpp +++ b/src/unittest/test.cpp @@ -188,6 +188,23 @@ Markdown lol ||spoiler|| ~~strikethrough~~ `small *code* block`\n"; }"; error_message_success = (error_message_success && error_test.get_error().human_readable == "50035: Invalid Form Body - [1].options[1].description: Must be between 1 and 100 in length. (BASE_TYPE_BAD_LENGTH)"); + error_test.http_info.body = "{\ + \"message\": \"Invalid Form Body\",\ + \"code\": 50035,\ + \"errors\": {\ + \"data\": {\ + \"poll\": {\ + \"_errors\": [\ + {\ + \"code\": \"POLL_TYPE_QUESTION_ALLOWS_TEXT_ONLY\",\ + \"message\": \"This poll type cannot include attachments, emoji or stickers with the question\"}\ + ]\ + }\ + }\ + }\ + }"; + error_message_success = (error_message_success && error_test.get_error().human_readable == "50035: Invalid Form Body - data.poll: This poll type cannot include attachments, emoji or stickers with the question (POLL_TYPE_QUESTION_ALLOWS_TEXT_ONLY)"); + set_test(ERRORS, error_message_success); set_test(MD_ESC_1, false);