Skip to content

Commit

Permalink
fix merge
Browse files Browse the repository at this point in the history
  • Loading branch information
braindigitalis committed May 1, 2024
2 parents d6a1fdc + 56b6b07 commit c10975d
Show file tree
Hide file tree
Showing 3 changed files with 154 additions and 95 deletions.
2 changes: 1 addition & 1 deletion include/dpp/restresults.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};

/**
Expand Down
133 changes: 41 additions & 92 deletions src/dpp/cluster/confirmation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,22 +74,39 @@ bool confirmation_callback_t::is_error() const {

namespace {

std::vector<error_detail> find_errors_in_array(const std::string& obj, size_t index, const std::string& current_field, json::iterator begin, json::iterator end) {
std::vector<error_detail> find_errors_in_object(const std::string& obj, const std::string& current_field, const json &j) {
std::vector<error_detail> 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<std::string>();
detail.reason = (*errordetails)["message"].get<std::string>();
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<std::string>();
detail.reason = errordetails["message"].get<std::string>();
detail.field = current_field;
detail.object = obj;
ret.emplace_back(detail);
}
} else {
for (auto it = j.begin(); it != j.end(); ++it) {
std::vector<error_detail> 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());
Expand All @@ -110,80 +127,15 @@ error_info confirmation_callback_t::get_error() const {
set_int32_not_null(&j, "code", e.code);
set_string_not_null(&j, "message", e.message);
json& errors = j["errors"];
if (errors.is_object() || errors.is_array()) {
for (auto obj = errors.begin(); obj != errors.end(); ++obj) {

/* 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<std::string>();
detail.reason = (*errordetails)["message"].get<std::string>();
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<std::string>();
detail.reason = (*errordetails)["message"].get<std::string>();
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<std::string>();
detail.reason = (*errordetails)["message"].get<std::string>();
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<std::string>();
detail.reason = (*errordetails)["message"].get<std::string>();
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));
}
}
}
for (auto obj = errors.begin(); obj != errors.end(); ++obj) {
std::vector<error_detail> sub_errors;
std::string field = isdigit(*obj.key().c_str()) ? "<array>[" + obj.key() + "]" : obj.key();

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));
}
}

Expand All @@ -193,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 + "- <array>[" + 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 + ")";
}
}

Expand Down
114 changes: 112 additions & 2 deletions src/unittest/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 - <array>[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);
Expand Down Expand Up @@ -977,7 +994,7 @@ Markdown lol \\|\\|spoiler\\|\\| \\~\\~strikethrough\\~\\~ \\`small \\*code\\* b
return;
}
g.remove_icon();
bot.guild_edit(g, [&bot](const dpp::confirmation_callback_t &result) {
bot.guild_edit(g, [](const dpp::confirmation_callback_t &result) {
if (result.is_error()) {
set_status(GUILD_EDIT, ts_failed, "guild_edit 2 errored:\n" + result.get_error().human_readable);
return;
Expand Down Expand Up @@ -2076,7 +2093,7 @@ Markdown lol \\|\\|spoiler\\|\\| \\~\\~strikethrough\\~\\~ \\`small \\*code\\* b
}
});
}

set_test(THREAD_CREATE, false);
if (!offline) {
bot.thread_create("thread test", TEST_TEXT_CHANNEL_ID, 60, dpp::channel_type::CHANNEL_PUBLIC_THREAD, true, 60, [&](const dpp::confirmation_callback_t &event) {
Expand All @@ -2088,6 +2105,99 @@ Markdown lol \\|\\|spoiler\\|\\| \\~\\~strikethrough\\~\\~ \\`small \\*code\\* b
});
}

start_test(POLL_CREATE);
if (!offline) {
dpp::message poll_msg{};

poll_msg.set_poll(dpp::poll{}
.set_question("hello!")
.add_answer("one", dpp::unicode_emoji::one)
.add_answer("two", dpp::unicode_emoji::two)
.add_answer("three", dpp::unicode_emoji::three)
.add_answer("four")
.set_duration(48)
.set_allow_multiselect(true)
).set_channel_id(TEST_TEXT_CHANNEL_ID);

bot.message_create(poll_msg, [&bot, poll_msg](const dpp::confirmation_callback_t& result) {
if (result.is_error()) {
set_status(POLL_CREATE, ts_failed, result.get_error().human_readable);
return;
}

const dpp::message& m = std::get<dpp::message>(result.value);

if (!m.attached_poll.has_value()) {
set_status(POLL_CREATE, ts_failed, "poll missing in received message");
return;
}

if (m.attached_poll->find_answer(std::numeric_limits<uint32_t>::max()) != nullptr) {
set_status(POLL_CREATE, ts_failed, "poll::find_answer failed to return nullptr");
return;
}

std::array<bool, 4> correct = {false, false, false, false};
int i = 0;
for (const auto& [_, answer] : m.attached_poll->answers) {
if (m.attached_poll->find_answer(answer.id) != &answer.media) {
set_status(POLL_CREATE, ts_failed, "poll::find_answer failed to return valid answer");
return;
}
if (answer.media.text == "one" && answer.media.emoji.name == dpp::unicode_emoji::one) {
if (correct[i]) {
set_status(POLL_CREATE, ts_failed, "poll answer found twice");
return;
}
correct[i] = true;
}
if (answer.media.text == "two" && answer.media.emoji.name == dpp::unicode_emoji::two) {
if (correct[i]) {
set_status(POLL_CREATE, ts_failed, "poll answer found twice");
return;
}
correct[i] = true;
}
if (answer.media.text == "three" && answer.media.emoji.name == dpp::unicode_emoji::three) {
if (correct[i]) {
set_status(POLL_CREATE, ts_failed, "poll answer found twice");
return;
}
correct[i] = true;
}
if (answer.media.text == "four" && answer.media.emoji.name.empty()) {
if (correct[i]) {
set_status(POLL_CREATE, ts_failed, "poll answer found twice");
return;
}
correct[i] = true;
bot.poll_get_answer_voters(m, answer.id, 0, 100, [m, &bot](const dpp::confirmation_callback_t& result) {
if (result.is_error()) {
set_status(POLL_CREATE, ts_failed, "poll_get_answer_voters: " + result.get_error().human_readable);
return;
}

start_test(POLL_END);
bot.poll_end(m, [message_id = m.id, channel_id = m.channel_id, &bot](const dpp::confirmation_callback_t& result) {
if (result.is_error()) {
set_status(POLL_END, ts_failed, result.get_error().human_readable);
return;
}
set_status(POLL_END, ts_success);
bot.message_delete(message_id, channel_id);
});
});
}
++i;
}
if (correct == std::array<bool, 4>{true, true, true, true}) {
set_status(POLL_CREATE, ts_success);
} else {
set_status(POLL_CREATE, ts_failed, "failed to find the submitted answers");
}
});
}

set_test(MEMBER_GET, false);
if (!offline) {
bot.guild_get_member(TEST_GUILD_ID, TEST_USER_ID, [](const dpp::confirmation_callback_t &event){
Expand Down

0 comments on commit c10975d

Please sign in to comment.