mirror of
https://github.com/brian8544/turtle-wow.git
synced 2025-01-05 22:34:35 +00:00
1207 lines
32 KiB
C++
1207 lines
32 KiB
C++
/************************************************************************************
|
|
*
|
|
* D++, A Lightweight C++ library for Discord
|
|
*
|
|
* Copyright 2021 Craig Edwards and D++ contributors
|
|
* (https://github.com/brainboxdotcc/DPP/graphs/contributors)
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*
|
|
************************************************************************************/
|
|
#include <dpp/message.h>
|
|
#include <dpp/user.h>
|
|
#include <dpp/channel.h>
|
|
#include <dpp/guild.h>
|
|
#include <dpp/cache.h>
|
|
#include <dpp/nlohmann/json.hpp>
|
|
#include <dpp/discordevents.h>
|
|
#include <dpp/stringops.h>
|
|
#include <dpp/exception.h>
|
|
#include <dpp/cluster.h>
|
|
|
|
using json = nlohmann::json;
|
|
|
|
namespace dpp {
|
|
|
|
component::component() :
|
|
type(cot_action_row), label(""), style(cos_primary), custom_id(""),
|
|
min_values(-1), max_values(-1), min_length(0), max_length(0), disabled(false), required(false)
|
|
{
|
|
emoji.animated = false;
|
|
emoji.id = 0;
|
|
emoji.name = "";
|
|
}
|
|
|
|
|
|
component& component::fill_from_json(nlohmann::json* j) {
|
|
type = static_cast<component_type>(int8_not_null(j, "type"));
|
|
if (type == cot_action_row) {
|
|
for (json sub_component : (*j)["components"]) {
|
|
dpp::component new_component;
|
|
new_component.fill_from_json(&sub_component);
|
|
components.emplace_back(new_component);
|
|
}
|
|
} else if (type == cot_button) {
|
|
label = string_not_null(j, "label");
|
|
style = static_cast<component_style>(int8_not_null(j, "style"));
|
|
custom_id = string_not_null(j, "custom_id");
|
|
disabled = bool_not_null(j, "disabled");
|
|
if (j->contains("emoji")) {
|
|
json emo = (*j)["emoji"];
|
|
emoji.id = snowflake_not_null(&emo, "id");
|
|
emoji.name = string_not_null(&emo, "name");
|
|
emoji.animated = bool_not_null(&emo, "animated");
|
|
}
|
|
} else if (type == cot_selectmenu) {
|
|
label = "";
|
|
custom_id = string_not_null(j, "custom_id");
|
|
disabled = bool_not_null(j, "disabled");
|
|
if (j->contains("options")) {
|
|
for(json opt : (*j)["options"]) {
|
|
options.push_back(dpp::select_option().fill_from_json(&opt));
|
|
}
|
|
}
|
|
} else if (type == cot_text) {
|
|
custom_id = string_not_null(j, "custom_id");
|
|
type = (component_type)int8_not_null(j, "type");
|
|
required = bool_not_null(j, "required");
|
|
json v = (*j)["value"];
|
|
if (!v.is_null() && v.is_number_integer()) {
|
|
value = v.get<int64_t>();
|
|
} else if (!v.is_null() && v.is_number_float()) {
|
|
value = v.get<double>();
|
|
} else if (!v.is_null() && v.is_string()) {
|
|
value = v.get<std::string>();
|
|
}
|
|
} else if (type == cot_user_selectmenu || type == cot_role_selectmenu || type == cot_mentionable_selectmenu) {
|
|
custom_id = string_not_null(j, "custom_id");
|
|
disabled = bool_not_null(j, "disabled");
|
|
} else if (type == cot_channel_selectmenu) {
|
|
custom_id = string_not_null(j, "custom_id");
|
|
disabled = bool_not_null(j, "disabled");
|
|
if (j->contains("channel_types")) {
|
|
for (json &ct : (*j)["channel_types"]) {
|
|
if (ct.is_number_integer()) {
|
|
channel_types.push_back(ct.get<dpp::channel_type>());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
component& component::add_component(const component& c)
|
|
{
|
|
set_type(cot_action_row);
|
|
components.emplace_back(c);
|
|
return *this;
|
|
}
|
|
|
|
component& component::add_channel_type(uint8_t ct) {
|
|
if (type == cot_action_row) {
|
|
set_type(cot_channel_selectmenu);
|
|
}
|
|
channel_types.push_back(ct);
|
|
return *this;
|
|
}
|
|
|
|
component& component::set_type(component_type ct)
|
|
{
|
|
type = ct;
|
|
if (type == cot_text || type == cot_button) {
|
|
label = dpp::utility::utf8substr(label, 0, 80);
|
|
} else if (type == cot_selectmenu) {
|
|
label = dpp::utility::utf8substr(label, 0, 100);
|
|
}
|
|
if(type == cot_text) {
|
|
placeholder = dpp::utility::utf8substr(placeholder, 0, 100);
|
|
} else if (type == cot_selectmenu || type == cot_user_selectmenu || type == cot_role_selectmenu || type == cot_mentionable_selectmenu || type == cot_channel_selectmenu) {
|
|
placeholder = dpp::utility::utf8substr(placeholder, 0, 150);
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
component& component::set_label(const std::string &l)
|
|
{
|
|
if (type == cot_action_row) {
|
|
set_type(cot_button);
|
|
}
|
|
if (type == cot_text || type == cot_button) {
|
|
label = dpp::utility::utf8substr(l, 0, 80);
|
|
} else if (type == cot_selectmenu) {
|
|
label = dpp::utility::utf8substr(l, 0, 100);
|
|
} else {
|
|
label = l;
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
component& component::set_default_value(const std::string &val)
|
|
{
|
|
if (type == cot_action_row) {
|
|
set_type(cot_text);
|
|
}
|
|
value = dpp::utility::utf8substr(val, 0, 4000);
|
|
return *this;
|
|
}
|
|
|
|
component& component::set_style(component_style cs)
|
|
{
|
|
set_type(cot_button);
|
|
style = cs;
|
|
return *this;
|
|
}
|
|
|
|
component& component::set_text_style(text_style_type ts)
|
|
{
|
|
set_type(cot_text);
|
|
text_style = ts;
|
|
return *this;
|
|
}
|
|
|
|
component& component::set_url(const std::string& u)
|
|
{
|
|
set_type(cot_button);
|
|
set_style(cos_link);
|
|
url = utility::utf8substr(u, 0, 512);
|
|
return *this;
|
|
}
|
|
|
|
component& component::set_id(const std::string &id)
|
|
{
|
|
if (type == cot_action_row) {
|
|
set_type(cot_button);
|
|
}
|
|
custom_id = utility::utf8substr(id, 0, 100);
|
|
return *this;
|
|
}
|
|
|
|
component& component::set_disabled(bool disable)
|
|
{
|
|
if (type == cot_action_row) {
|
|
set_type(cot_button);
|
|
}
|
|
disabled = disable;
|
|
return *this;
|
|
}
|
|
|
|
component& component::set_required(bool require)
|
|
{
|
|
if (type == cot_action_row) {
|
|
set_type(cot_button);
|
|
}
|
|
required = require;
|
|
return *this;
|
|
}
|
|
|
|
component& component::set_emoji(const std::string& name, dpp::snowflake id, bool animated)
|
|
{
|
|
if (type == cot_action_row) {
|
|
set_type(cot_button);
|
|
}
|
|
this->emoji.id = id;
|
|
this->emoji.name = name;
|
|
this->emoji.animated = animated;
|
|
return *this;
|
|
}
|
|
|
|
component& component::set_min_length(uint32_t min_l)
|
|
{
|
|
min_length = min_l;
|
|
return *this;
|
|
}
|
|
|
|
component& component::set_max_length(uint32_t max_l)
|
|
{
|
|
max_length = max_l;
|
|
return *this;
|
|
}
|
|
|
|
void to_json(json& j, const attachment& a) {
|
|
if (a.id) {
|
|
j["id"] = a.id;
|
|
}
|
|
if (a.size) {
|
|
j["size"] = a.size;
|
|
}
|
|
if (!a.filename.empty()) {
|
|
j["filename"] = a.filename;
|
|
}
|
|
if (!a.url.empty()) {
|
|
j["url"] = a.url;
|
|
}
|
|
j["ephemeral"] = a.ephemeral;
|
|
}
|
|
|
|
void to_json(json& j, const component& cp) {
|
|
j["type"] = cp.type;
|
|
if (cp.type == cot_text) {
|
|
j["label"] = cp.label;
|
|
j["required"] = cp.required;
|
|
j["style"] = int(cp.text_style);
|
|
if (std::holds_alternative<std::string>(cp.value) && !std::get<std::string>(cp.value).empty()) {
|
|
j["value"] = std::get<std::string>(cp.value);
|
|
}
|
|
if (!cp.custom_id.empty()) {
|
|
j["custom_id"] = cp.custom_id;
|
|
}
|
|
if (!cp.placeholder.empty()) {
|
|
j["placeholder"] = cp.placeholder;
|
|
}
|
|
if (cp.min_length > 0) {
|
|
j["min_length"] = cp.min_length;
|
|
}
|
|
if (cp.max_length > 0) {
|
|
j["max_length"] = cp.max_length;
|
|
}
|
|
}
|
|
if (cp.type == cot_button) {
|
|
j["label"] = cp.label;
|
|
j["style"] = int(cp.style);
|
|
if (cp.type == cot_button && cp.style != cos_link && !cp.custom_id.empty()) {
|
|
/* Links cannot have a custom id */
|
|
j["custom_id"] = cp.custom_id;
|
|
}
|
|
if (cp.type == cot_button && cp.style == cos_link && !cp.url.empty()) {
|
|
j["url"] = cp.url;
|
|
}
|
|
j["disabled"] = cp.disabled;
|
|
|
|
if (cp.emoji.id || !cp.emoji.name.empty()) {
|
|
j["emoji"] = {};
|
|
j["emoji"]["animated"] = cp.emoji.animated;
|
|
}
|
|
if (cp.emoji.id) {
|
|
j["emoji"]["id"] = std::to_string(cp.emoji.id);
|
|
}
|
|
if (!cp.emoji.name.empty()) {
|
|
j["emoji"]["name"] = cp.emoji.name;
|
|
}
|
|
} else if (cp.type == cot_selectmenu) {
|
|
j["custom_id"] = cp.custom_id;
|
|
j["disabled"] = cp.disabled;
|
|
if (!cp.placeholder.empty()) {
|
|
j["placeholder"] = cp.placeholder;
|
|
}
|
|
if (cp.min_values >= 0) {
|
|
j["min_values"] = cp.min_values;
|
|
}
|
|
if (cp.max_values >= 0) {
|
|
j["max_values"] = cp.max_values;
|
|
}
|
|
j["options"] = json::array();
|
|
for (auto opt : cp.options) {
|
|
json o;
|
|
if (!opt.description.empty()) {
|
|
o["description"] = opt.description;
|
|
}
|
|
if (!opt.label.empty()) {
|
|
o["label"] = opt.label;
|
|
}
|
|
if (!opt.value.empty()) {
|
|
o["value"] = opt.value;
|
|
}
|
|
if (opt.is_default) {
|
|
o["default"] = true;
|
|
}
|
|
if (!opt.emoji.name.empty()) {
|
|
o["emoji"] = json::object();
|
|
o["emoji"]["name"] = opt.emoji.name;
|
|
if (opt.emoji.id) {
|
|
o["emoji"]["id"] = std::to_string(opt.emoji.id);
|
|
}
|
|
if (opt.emoji.animated) {
|
|
o["emoji"]["animated"] = true;
|
|
}
|
|
}
|
|
j["options"].push_back(o);
|
|
}
|
|
} else if (cp.type == cot_user_selectmenu || cp.type == cot_role_selectmenu || cp.type == cot_mentionable_selectmenu) {
|
|
j["custom_id"] = cp.custom_id;
|
|
j["disabled"] = cp.disabled;
|
|
if (!cp.placeholder.empty()) {
|
|
j["placeholder"] = cp.placeholder;
|
|
}
|
|
if (cp.min_values >= 0) {
|
|
j["min_values"] = cp.min_values;
|
|
}
|
|
if (cp.max_values >= 0) {
|
|
j["max_values"] = cp.max_values;
|
|
}
|
|
} else if (cp.type == cot_channel_selectmenu) {
|
|
j["custom_id"] = cp.custom_id;
|
|
j["disabled"] = cp.disabled;
|
|
if (!cp.placeholder.empty()) {
|
|
j["placeholder"] = cp.placeholder;
|
|
}
|
|
if (cp.min_values >= 0) {
|
|
j["min_values"] = cp.min_values;
|
|
}
|
|
if (cp.max_values >= 0) {
|
|
j["max_values"] = cp.max_values;
|
|
}
|
|
if (!cp.channel_types.empty()) {
|
|
j["channel_types"] = json::array();
|
|
for (auto &type : cp.channel_types) {
|
|
j["channel_types"].push_back(type);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
select_option::select_option() : is_default(false) {
|
|
}
|
|
|
|
select_option::select_option(const std::string &_label, const std::string &_value, const std::string &_description) : label(_label), value(_value), description(_description), is_default(false) {
|
|
}
|
|
|
|
select_option& select_option::set_label(const std::string &l) {
|
|
label = dpp::utility::utf8substr(l, 0, 100);
|
|
return *this;
|
|
}
|
|
|
|
select_option& select_option::set_default(bool def) {
|
|
is_default = def;
|
|
return *this;
|
|
}
|
|
|
|
select_option& select_option::set_value(const std::string &v) {
|
|
value = dpp::utility::utf8substr(v, 0, 100);
|
|
return *this;
|
|
}
|
|
|
|
select_option& select_option::set_description(const std::string &d) {
|
|
description = dpp::utility::utf8substr(d, 0, 100);
|
|
return *this;
|
|
}
|
|
|
|
select_option& select_option::set_emoji(const std::string &n, dpp::snowflake id, bool animated) {
|
|
emoji.name = n;
|
|
emoji.id = id;
|
|
emoji.animated = animated;
|
|
return *this;
|
|
}
|
|
|
|
select_option& select_option::set_animated(bool anim) {
|
|
emoji.animated = anim;
|
|
return *this;
|
|
}
|
|
|
|
select_option& select_option::fill_from_json(nlohmann::json* j) {
|
|
label = string_not_null(j, "label");
|
|
value = string_not_null(j, "value");
|
|
description = string_not_null(j, "description");
|
|
if (j->contains("emoji")) {
|
|
const json& emoj = (*j)["emoji"];
|
|
emoji.animated = bool_not_null(&emoj, "animated");
|
|
emoji.name = string_not_null(&emoj, "name");
|
|
emoji.id = snowflake_not_null(&emoj, "id");
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
component& component::set_placeholder(const std::string &_placeholder) {
|
|
if(type == cot_text) {
|
|
placeholder = dpp::utility::utf8substr(_placeholder, 0, 100);
|
|
} else if (type == cot_selectmenu || type == cot_user_selectmenu || type == cot_role_selectmenu || type == cot_mentionable_selectmenu || type == cot_channel_selectmenu) {
|
|
placeholder = dpp::utility::utf8substr(_placeholder, 0, 150);
|
|
} else {
|
|
placeholder = _placeholder;
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
component& component::set_min_values(uint32_t _min_values) {
|
|
min_values = _min_values;
|
|
return *this;
|
|
}
|
|
|
|
component& component::set_max_values(uint32_t _max_values) {
|
|
max_values = _max_values;
|
|
return *this;
|
|
}
|
|
|
|
component& component::add_select_option(const select_option &option) {
|
|
if (options.size() <= 25) {
|
|
options.emplace_back(option);
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
embed::~embed() = default;
|
|
|
|
embed::embed() : timestamp(0), color(0) {
|
|
}
|
|
|
|
message::message() : managed(0), channel_id(0), guild_id(0), sent(0), edited(0), webhook_id(0),
|
|
owner(nullptr), type(mt_default), flags(0), pinned(false), tts(false), mention_everyone(false)
|
|
{
|
|
message_reference.channel_id = 0;
|
|
message_reference.guild_id = 0;
|
|
message_reference.message_id = 0;
|
|
message_reference.fail_if_not_exists = false;
|
|
interaction.id = 0;
|
|
interaction.type = interaction_type::it_ping;
|
|
interaction.usr.id = 0;
|
|
allowed_mentions.parse_users = false;
|
|
allowed_mentions.parse_everyone = false;
|
|
allowed_mentions.parse_roles = false;
|
|
allowed_mentions.replied_user = false;
|
|
|
|
}
|
|
|
|
message::message(class cluster* o) : message() {
|
|
owner = o;
|
|
}
|
|
|
|
message& message::set_reference(snowflake _message_id, snowflake _guild_id, snowflake _channel_id, bool fail_if_not_exists) {
|
|
message_reference.channel_id = _channel_id;
|
|
message_reference.guild_id = _guild_id;
|
|
message_reference.message_id = _message_id;
|
|
message_reference.fail_if_not_exists = fail_if_not_exists;
|
|
return *this;
|
|
}
|
|
|
|
message& message::set_allowed_mentions(bool _parse_users, bool _parse_roles, bool _parse_everyone, bool _replied_user, const std::vector<snowflake> &users, const std::vector<snowflake> &roles) {
|
|
allowed_mentions.parse_users = _parse_users;
|
|
allowed_mentions.parse_everyone = _parse_everyone;
|
|
allowed_mentions.parse_roles = _parse_roles;
|
|
allowed_mentions.replied_user = _replied_user;
|
|
allowed_mentions.users = users;
|
|
allowed_mentions.roles = roles;
|
|
return *this;
|
|
}
|
|
|
|
message::message(snowflake _channel_id, const std::string &_content, message_type t) : message() {
|
|
channel_id = _channel_id;
|
|
content = utility::utf8substr(_content, 0, 4000);
|
|
type = t;
|
|
}
|
|
|
|
message& message::add_component(const component& c)
|
|
{
|
|
components.emplace_back(c);
|
|
return *this;
|
|
}
|
|
|
|
message& message::add_embed(const embed& e)
|
|
{
|
|
embeds.emplace_back(e);
|
|
return *this;
|
|
}
|
|
|
|
message& message::set_flags(uint16_t f)
|
|
{
|
|
flags = f;
|
|
return *this;
|
|
}
|
|
|
|
message& message::set_type(message_type t)
|
|
{
|
|
type = t;
|
|
return *this;
|
|
}
|
|
|
|
message& message::set_filename(const std::string &fn)
|
|
{
|
|
if (filename.empty()) {
|
|
filename.push_back(fn);
|
|
} else {
|
|
filename[filename.size() - 1] = fn;
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
message& message::set_file_content(const std::string &fc)
|
|
{
|
|
if (filecontent.empty()) {
|
|
filecontent.push_back(fc);
|
|
} else {
|
|
filecontent[filecontent.size() - 1] = fc;
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
message& message::add_file(const std::string &fn, const std::string &fc) {
|
|
filecontent.push_back(fc);
|
|
filename.push_back(fn);
|
|
return *this;
|
|
}
|
|
|
|
message& message::set_content(const std::string &c)
|
|
{
|
|
content = utility::utf8substr(c, 0, 4000);
|
|
return *this;
|
|
}
|
|
|
|
message& message::set_channel_id(snowflake _channel_id) {
|
|
channel_id = _channel_id;
|
|
return *this;
|
|
}
|
|
|
|
message& message::set_guild_id(snowflake _guild_id) {
|
|
guild_id = _guild_id;
|
|
return *this;
|
|
}
|
|
|
|
message::message(const std::string &_content, message_type t) : message() {
|
|
content = utility::utf8substr(_content, 0, 4000);
|
|
type = t;
|
|
}
|
|
|
|
message::message(snowflake _channel_id, const embed& _embed) : message() {
|
|
channel_id = _channel_id;
|
|
embeds.emplace_back(_embed);
|
|
}
|
|
|
|
embed::embed(json* j) : embed() {
|
|
title = string_not_null(j, "title");
|
|
type = string_not_null(j, "type");
|
|
description = string_not_null(j, "description");
|
|
url = string_not_null(j, "url");
|
|
timestamp = ts_not_null(j, "timestamp");
|
|
color = int32_not_null(j, "color");
|
|
if (j->contains("footer")) {
|
|
dpp::embed_footer f;
|
|
json& fj = (*j)["footer"];
|
|
f.text = string_not_null(&fj, "text");
|
|
f.icon_url = string_not_null(&fj, "icon_url");
|
|
f.proxy_url = string_not_null(&fj, "proxy_url");
|
|
footer = f;
|
|
}
|
|
std::vector<std::string> type_list = { "image", "video", "thumbnail" };
|
|
for (auto& s : type_list) {
|
|
if (j->contains(s)) {
|
|
embed_image curr;
|
|
json& fi = (*j)[s];
|
|
curr.url = string_not_null(&fi, "url");
|
|
curr.height = string_not_null(&fi, "height");
|
|
curr.width = string_not_null(&fi, "width");
|
|
curr.proxy_url = string_not_null(&fi, "proxy_url");
|
|
if (s == "image") {
|
|
image = curr;
|
|
} else if (s == "video") {
|
|
video = curr;
|
|
} else if (s == "thumbnail") {
|
|
thumbnail = curr;
|
|
}
|
|
}
|
|
}
|
|
if (j->contains("provider")) {
|
|
json &p = (*j)["provider"];
|
|
dpp::embed_provider pr;
|
|
pr.name = string_not_null(&p, "name");
|
|
pr.url = string_not_null(&p, "url");
|
|
provider = pr;
|
|
}
|
|
if (j->contains("author")) {
|
|
json &a = (*j)["author"];
|
|
dpp::embed_author au;
|
|
au.name = string_not_null(&a, "name");
|
|
au.url = string_not_null(&a, "url");
|
|
au.icon_url = string_not_null(&a, "icon_url");
|
|
au.proxy_icon_url = string_not_null(&a, "proxy_icon_url");
|
|
author = au;
|
|
}
|
|
if (j->contains("fields")) {
|
|
json &fl = (*j)["fields"];
|
|
for (auto & field : fl) {
|
|
embed_field f;
|
|
f.name = string_not_null(&field, "name");
|
|
f.value = string_not_null(&field, "value");
|
|
f.is_inline = bool_not_null(&field, "inline");
|
|
fields.push_back(f);
|
|
}
|
|
}
|
|
}
|
|
|
|
embed& embed::add_field(const std::string& name, const std::string &value, bool is_inline) {
|
|
if (fields.size() < 25) {
|
|
embed_field f;
|
|
f.name = utility::utf8substr(name, 0, 256);
|
|
f.value = utility::utf8substr(value, 0, 1024);
|
|
f.is_inline = is_inline;
|
|
fields.push_back(f);
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
embed& embed::set_author(const embed_author& a)
|
|
{
|
|
author = a;
|
|
return *this;
|
|
}
|
|
|
|
embed& embed::set_timestamp(time_t tstamp)
|
|
{
|
|
timestamp = tstamp;
|
|
return *this;
|
|
}
|
|
|
|
embed& embed::set_author(const std::string& name, const std::string& url, const std::string& icon_url) {
|
|
dpp::embed_author a;
|
|
a.name = utility::utf8substr(name, 0, 256);
|
|
a.url = url;
|
|
a.icon_url = icon_url;
|
|
author = a;
|
|
return *this;
|
|
}
|
|
|
|
embed& embed::set_footer(const embed_footer& f) {
|
|
footer = f;
|
|
return *this;
|
|
}
|
|
|
|
embed& embed::set_footer(const std::string& text, const std::string& icon_url) {
|
|
dpp::embed_footer f;
|
|
f.set_text(text);
|
|
f.set_icon(icon_url);
|
|
footer = f;
|
|
return *this;
|
|
}
|
|
|
|
embed& embed::set_provider(const std::string& name, const std::string& url) {
|
|
dpp::embed_provider p;
|
|
p.name = utility::utf8substr(name, 0, 256);
|
|
p.url = url;
|
|
provider = p;
|
|
return *this;
|
|
}
|
|
|
|
embed& embed::set_image(const std::string& url) {
|
|
dpp::embed_image i;
|
|
i.url = url;
|
|
image = i;
|
|
return *this;
|
|
}
|
|
|
|
embed& embed::set_video(const std::string& url) {
|
|
dpp::embed_image v;
|
|
v.url = url;
|
|
video = v;
|
|
return *this;
|
|
}
|
|
|
|
embed& embed::set_thumbnail(const std::string& url) {
|
|
dpp::embed_image t;
|
|
t.url = url;
|
|
thumbnail = t;
|
|
return *this;
|
|
}
|
|
|
|
embed& embed::set_title(const std::string &text) {
|
|
title = utility::utf8substr(text, 0, 256);
|
|
return *this;
|
|
}
|
|
|
|
embed& embed::set_description(const std::string &text) {
|
|
description = utility::utf8substr(text, 0, 4096);
|
|
return *this;
|
|
}
|
|
|
|
embed& embed::set_color(uint32_t col) {
|
|
// Mask off alpha, as discord doesn't use it
|
|
color = col & 0x00FFFFFF;
|
|
return *this;
|
|
}
|
|
|
|
embed& embed::set_url(const std::string &u) {
|
|
url = u;
|
|
return *this;
|
|
}
|
|
|
|
embed_footer& embed_footer::set_text(const std::string& t){
|
|
text = utility::utf8substr(t, 0, 2048);
|
|
return *this;
|
|
}
|
|
|
|
embed_footer& embed_footer::set_icon(const std::string& i){
|
|
icon_url = i;
|
|
return *this;
|
|
}
|
|
|
|
embed_footer& embed_footer::set_proxy(const std::string& p){
|
|
proxy_url = p;
|
|
return *this;
|
|
}
|
|
|
|
reaction::reaction() {
|
|
count = 0;
|
|
me = false;
|
|
emoji_id = 0;
|
|
}
|
|
|
|
reaction::reaction(json* j) {
|
|
count = (*j)["count"];
|
|
me = (*j)["me"];
|
|
json emoji = (*j)["emoji"];
|
|
emoji_id = snowflake_not_null(&emoji, "id");
|
|
emoji_name = string_not_null(&emoji, "name");
|
|
}
|
|
|
|
attachment::attachment(struct message* o)
|
|
: id(0)
|
|
, size(0)
|
|
, width(0)
|
|
, height(0)
|
|
, ephemeral(false)
|
|
, owner(o)
|
|
{
|
|
}
|
|
|
|
attachment::attachment(struct message* o, json *j) : attachment(o) {
|
|
this->id = snowflake_not_null(j, "id");
|
|
this->size = (*j)["size"];
|
|
this->filename = (*j)["filename"].get<std::string>();;
|
|
this->description = string_not_null(j, "description");
|
|
this->url = (*j)["url"].get<std::string>();;
|
|
this->proxy_url = (*j)["proxy_url"].get<std::string>();;
|
|
this->width = int32_not_null(j, "width");
|
|
this->height = int32_not_null(j, "height");
|
|
this->content_type = string_not_null(j, "content_type");
|
|
this->ephemeral = bool_not_null(j, "ephemeral");
|
|
}
|
|
|
|
void attachment::download(http_completion_event callback) const {
|
|
/* Download attachment if there is one attached to this object */
|
|
if (owner == nullptr || owner->owner == nullptr) {
|
|
throw dpp::logic_exception("attachment has no owning message/cluster");
|
|
}
|
|
if (callback && this->id && !this->url.empty()) {
|
|
owner->owner->request(this->url, dpp::m_get, callback);
|
|
}
|
|
}
|
|
|
|
std::string message::build_json(bool with_id, bool is_interaction_response) const {
|
|
/* This is the basics. once it works, expand on it. */
|
|
json j({
|
|
{"channel_id", channel_id},
|
|
{"tts", tts},
|
|
{"nonce", nonce},
|
|
{"flags", flags},
|
|
{"type", type},
|
|
{"content", content}
|
|
});
|
|
|
|
if (with_id) {
|
|
j["id"] = std::to_string(id);
|
|
}
|
|
|
|
if(!author.username.empty()) {
|
|
/* Used for webhooks */
|
|
j["username"] = author.username;
|
|
}
|
|
|
|
/* Populate message reference */
|
|
if (message_reference.channel_id || message_reference.guild_id || message_reference.message_id) {
|
|
j["message_reference"] = json::object();
|
|
if (message_reference.channel_id) {
|
|
j["message_reference"]["channel_id"] = std::to_string(message_reference.channel_id);
|
|
}
|
|
if (message_reference.guild_id) {
|
|
j["message_reference"]["guild_id"] = std::to_string(message_reference.guild_id);
|
|
}
|
|
if (message_reference.message_id) {
|
|
j["message_reference"]["message_id"] = std::to_string(message_reference.message_id);
|
|
}
|
|
j["message_reference"]["fail_if_not_exists"] = message_reference.fail_if_not_exists;
|
|
}
|
|
|
|
j["allowed_mentions"] = json::object();
|
|
j["allowed_mentions"]["parse"] = json::array();
|
|
if (allowed_mentions.parse_everyone || allowed_mentions.parse_roles || allowed_mentions.parse_users || allowed_mentions.replied_user || allowed_mentions.users.size() || allowed_mentions.roles.size()) {
|
|
if (allowed_mentions.parse_everyone) {
|
|
j["allowed_mentions"]["parse"].push_back("everyone");
|
|
}
|
|
if (allowed_mentions.parse_roles) {
|
|
j["allowed_mentions"]["parse"].push_back("roles");
|
|
}
|
|
if (allowed_mentions.parse_users) {
|
|
j["allowed_mentions"]["parse"].push_back("users");
|
|
}
|
|
if (!allowed_mentions.replied_user) {
|
|
j["allowed_mentions"]["replied_user"] = false;
|
|
} else {
|
|
j["allowed_mentions"]["replied_user"] = true;
|
|
}
|
|
if (allowed_mentions.users.size()) {
|
|
j["allowed_mentions"]["users"] = json::array();
|
|
for (auto& user : allowed_mentions.users) {
|
|
j["allowed_mentions"]["users"].push_back(std::to_string(user));
|
|
}
|
|
}
|
|
if (allowed_mentions.roles.size()) {
|
|
j["allowed_mentions"]["roles"] = json::array();
|
|
for (auto& role : allowed_mentions.roles) {
|
|
j["allowed_mentions"]["roles"].push_back(std::to_string(role));
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
j["components"] = json::array();
|
|
for (auto & component : components) {
|
|
json n;
|
|
n["type"] = cot_action_row;
|
|
n["components"] = {};
|
|
for (auto & subcomponent : component.components) {
|
|
json sn = subcomponent;
|
|
n["components"].push_back(sn);
|
|
}
|
|
j["components"].push_back(n);
|
|
}
|
|
|
|
j["attachments"] = json::array();
|
|
for (auto& attachment : attachments) {
|
|
json a = attachment;
|
|
j["attachments"].push_back(a);
|
|
}
|
|
|
|
j["embeds"] = json::array();
|
|
for (auto& embed : embeds) {
|
|
json e;
|
|
if (!embed.description.empty())
|
|
e["description"] = embed.description;
|
|
if (!embed.title.empty())
|
|
e["title"] = embed.title;
|
|
if (!embed.url.empty())
|
|
e["url"] = embed.url;
|
|
e["color"] = embed.color;
|
|
if (embed.footer.has_value()) {
|
|
e["footer"]["text"] = embed.footer->text;
|
|
e["footer"]["icon_url"] = embed.footer->icon_url;
|
|
}
|
|
if (embed.image.has_value()) {
|
|
e["image"]["url"] = embed.image->url;
|
|
}
|
|
if (embed.thumbnail.has_value()) {
|
|
e["thumbnail"]["url"] = embed.thumbnail->url;
|
|
}
|
|
if (embed.author.has_value()) {
|
|
e["author"]["name"] = embed.author->name;
|
|
e["author"]["url"] = embed.author->url;
|
|
e["author"]["icon_url"] = embed.author->icon_url;
|
|
}
|
|
if (embed.fields.size()) {
|
|
e["fields"] = json();
|
|
for (auto& field : embed.fields) {
|
|
json f({ {"name", field.name}, {"value", field.value}, {"inline", field.is_inline} });
|
|
e["fields"].push_back(f);
|
|
}
|
|
}
|
|
if (embed.timestamp) {
|
|
e["timestamp"] = ts_to_string(embed.timestamp);
|
|
}
|
|
|
|
j["embeds"].push_back(e);
|
|
}
|
|
|
|
return j.dump();
|
|
}
|
|
|
|
bool message::is_crossposted() const {
|
|
return flags & m_crossposted;
|
|
}
|
|
|
|
bool message::is_crosspost() const {
|
|
return flags & m_is_crosspost;
|
|
}
|
|
|
|
bool message::is_dm() const {
|
|
return guild_id.empty();
|
|
}
|
|
|
|
bool message::suppress_embeds() const {
|
|
return flags & m_suppress_embeds;
|
|
}
|
|
|
|
bool message::is_source_message_deleted() const {
|
|
return flags & m_source_message_deleted;
|
|
}
|
|
|
|
bool message::is_urgent() const {
|
|
return flags & m_urgent;
|
|
}
|
|
|
|
bool message::has_thread() const {
|
|
return flags & m_has_thread;
|
|
}
|
|
|
|
bool message::is_ephemeral() const {
|
|
return flags & m_ephemeral;
|
|
}
|
|
|
|
bool message::is_loading() const {
|
|
return flags & m_loading;
|
|
}
|
|
|
|
bool message::is_thread_mention_failed() const {
|
|
return flags & m_thread_mention_failed;
|
|
}
|
|
|
|
message::~message() = default;
|
|
|
|
|
|
message& message::fill_from_json(json* d, cache_policy_t cp) {
|
|
this->id = snowflake_not_null(d, "id");
|
|
this->channel_id = snowflake_not_null(d, "channel_id");
|
|
this->guild_id = snowflake_not_null(d, "guild_id");
|
|
/* We didn't get a guild id. See if we can find one in the channel */
|
|
if (guild_id.empty() && !channel_id.empty()) {
|
|
dpp::channel* c = dpp::find_channel(this->channel_id);
|
|
if (c) {
|
|
this->guild_id = c->guild_id;
|
|
}
|
|
}
|
|
this->flags = int16_not_null(d, "flags");
|
|
this->type = static_cast<message_type>(int8_not_null(d, "type"));
|
|
this->author = user();
|
|
/* May be null, if its null cache it from the partial */
|
|
if (d->find("author") != d->end()) {
|
|
json &j_author = (*d)["author"];
|
|
if (cp.user_policy == dpp::cp_none) {
|
|
/* User caching off! Allocate a temp user to be deleted in destructor */
|
|
this->author.fill_from_json(&j_author);
|
|
} else {
|
|
/* User caching on - aggressive or lazy - create a cached user entry */
|
|
user* authoruser = find_user(snowflake_not_null(&j_author, "id"));
|
|
if (!authoruser) {
|
|
/* User does not exist yet, cache the partial as a user record */
|
|
authoruser = new user();
|
|
authoruser->fill_from_json(&j_author);
|
|
get_user_cache()->store(authoruser);
|
|
}
|
|
this->author = *authoruser;
|
|
}
|
|
}
|
|
if (d->find("interaction") != d->end()) {
|
|
json& inter = (*d)["interaction"];
|
|
interaction.id = snowflake_not_null(&inter, "id");
|
|
interaction.name = string_not_null(&inter, "name");
|
|
interaction.type = int8_not_null(&inter, "type");
|
|
if (inter.contains("user") && !inter["user"].is_null()) from_json(inter["user"], interaction.usr);
|
|
}
|
|
if (d->find("sticker_items") != d->end()) {
|
|
json &sub = (*d)["sticker_items"];
|
|
for (auto & sticker_raw : sub) {
|
|
stickers.emplace_back(dpp::sticker().fill_from_json(&sticker_raw));
|
|
}
|
|
}
|
|
if (d->find("mentions") != d->end()) {
|
|
json &sub = (*d)["mentions"];
|
|
for (auto & m : sub) {
|
|
dpp::user u = dpp::user().fill_from_json(&m);
|
|
dpp::guild_member gm = dpp::guild_member().fill_from_json(static_cast<json*>(&m["member"]), this->guild_id, u.id);
|
|
mentions.push_back({u, gm});
|
|
}
|
|
}
|
|
if (d->find("mention_roles") != d->end()) {
|
|
for (auto & m : (*d)["mention_roles"]) {
|
|
try {
|
|
snowflake rid = std::stoull(static_cast<const std::string&>(m));
|
|
mention_roles.push_back(rid);
|
|
} catch (const std::exception&) {}
|
|
}
|
|
}
|
|
if (d->find("mention_channels") != d->end()) {
|
|
json &sub = (*d)["mention_channels"];
|
|
for (auto & m : sub) {
|
|
mention_channels.emplace_back(dpp::channel().fill_from_json(&m));
|
|
}
|
|
}
|
|
/* Fill in member record, cache uncached ones */
|
|
guild* g = find_guild(this->guild_id);
|
|
this->member = {};
|
|
if (g && d->find("member") != d->end()) {
|
|
json& mi = (*d)["member"];
|
|
snowflake uid = snowflake_not_null(&(mi["user"]), "id");
|
|
if (!uid && author.id) {
|
|
uid = author.id;
|
|
}
|
|
if (cp.user_policy == dpp::cp_none) {
|
|
/* User caching off! Just fill in directly but dont store member to guild */
|
|
this->member.fill_from_json(&mi, g->id, uid);
|
|
} else {
|
|
/* User caching on, lazy or aggressive - cache the member information */
|
|
auto thismember = g->members.find(uid);
|
|
if (thismember == g->members.end()) {
|
|
if (!uid.empty() && author.id) {
|
|
guild_member gm;
|
|
gm.fill_from_json(&mi, g->id, uid);
|
|
g->members[author.id] = gm;
|
|
this->member = gm;
|
|
}
|
|
} else {
|
|
/* Update roles etc */
|
|
this->member = thismember->second;
|
|
if (author.id) {
|
|
this->member.fill_from_json(&mi, g->id, author.id);
|
|
g->members[author.id] = this->member;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (d->find("embeds") != d->end()) {
|
|
json & el = (*d)["embeds"];
|
|
for (auto& e : el) {
|
|
this->embeds.emplace_back(embed(&e));
|
|
}
|
|
}
|
|
if (d->find("components") != d->end()) {
|
|
json & el = (*d)["components"];
|
|
for (auto& e : el) {
|
|
this->components.emplace_back(component().fill_from_json(&e));
|
|
}
|
|
}
|
|
this->content = string_not_null(d, "content");
|
|
this->sent = ts_not_null(d, "timestamp");
|
|
this->edited = ts_not_null(d, "edited_timestamp");
|
|
this->tts = bool_not_null(d, "tts");
|
|
this->mention_everyone = bool_not_null(d, "mention_everyone");
|
|
if (d->find("reactions") != d->end()) {
|
|
json & el = (*d)["reactions"];
|
|
for (auto& e : el) {
|
|
this->reactions.emplace_back(reaction(&e));
|
|
}
|
|
}
|
|
if (((*d)["nonce"]).is_string()) {
|
|
this->nonce = string_not_null(d, "nonce");
|
|
} else {
|
|
this->nonce = std::to_string(snowflake_not_null(d, "nonce"));
|
|
}
|
|
this->pinned = bool_not_null(d, "pinned");
|
|
this->webhook_id = snowflake_not_null(d, "webhook_id");
|
|
for (auto& e : (*d)["attachments"]) {
|
|
this->attachments.emplace_back(attachment(this, &e));
|
|
}
|
|
if (d->find("message_reference") != d->end()) {
|
|
json& mr = (*d)["message_reference"];
|
|
message_reference.channel_id = snowflake_not_null(&mr, "channel_id");
|
|
message_reference.guild_id = snowflake_not_null(&mr, "guild_id");
|
|
message_reference.message_id = snowflake_not_null(&mr, "message_id");
|
|
message_reference.fail_if_not_exists = bool_not_null(&mr, "fail_if_not_exists");
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
sticker::sticker() : managed(0), pack_id(0), type(st_standard), format_type(sf_png), available(true), guild_id(0), sort_value(0) {
|
|
}
|
|
|
|
sticker& sticker::fill_from_json(nlohmann::json* j) {
|
|
this->id = snowflake_not_null(j, "id");
|
|
this->pack_id = snowflake_not_null(j, "pack_id");
|
|
this->name = string_not_null(j, "name");
|
|
this->description = string_not_null(j, "description");
|
|
this->tags = string_not_null(j, "tags");
|
|
this->asset = string_not_null(j, "asset");
|
|
this->guild_id = snowflake_not_null(j, "guild_id");
|
|
this->type = static_cast<sticker_type>(int8_not_null(j, "type"));
|
|
this->format_type = static_cast<sticker_format>(int8_not_null(j, "format_type"));
|
|
this->available = bool_not_null(j, "available");
|
|
this->sort_value = int8_not_null(j, "sort_value");
|
|
if (j->contains("user")) {
|
|
sticker_user.fill_from_json(&((*j)["user"]));
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
std::string sticker::build_json(bool with_id) const {
|
|
json j;
|
|
|
|
if (with_id) {
|
|
j["id"] = std::to_string(this->id);
|
|
}
|
|
j["pack_id"] = std::to_string(this->pack_id);
|
|
if (this->guild_id) {
|
|
j["guild_id"] = std::to_string(this->guild_id);
|
|
}
|
|
j["name"] = this->name;
|
|
j["description"] = this->description;
|
|
if (!this->tags.empty()) {
|
|
j["tags"] = this->tags;
|
|
}
|
|
if (!this->asset.empty()) {
|
|
j["asset"] = this->asset;
|
|
}
|
|
j["type"] = this->type;
|
|
j["format_type"] = this->format_type;
|
|
j["available"] = this->available;
|
|
j["sort_value"] = this->sort_value;
|
|
|
|
return j.dump();
|
|
}
|
|
|
|
sticker_pack::sticker_pack() : managed(0), sku_id(0), cover_sticker_id(0), banner_asset_id(0) {
|
|
}
|
|
|
|
sticker_pack& sticker_pack::fill_from_json(nlohmann::json* j) {
|
|
this->id = snowflake_not_null(j, "id");
|
|
this->sku_id = snowflake_not_null(j, "sku_id");
|
|
this->cover_sticker_id = snowflake_not_null(j, "cover_sticker_id");
|
|
this->banner_asset_id = snowflake_not_null(j, "banner_asset_id");
|
|
this->name = string_not_null(j, "name");
|
|
this->description = string_not_null(j, "description");
|
|
if (j->contains("stickers")) {
|
|
json & sl = (*j)["stickers"];
|
|
for (auto& s : sl) {
|
|
this->stickers[snowflake_not_null(&s, "id")] = sticker().fill_from_json(&s);
|
|
}
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
std::string sticker_pack::build_json(bool with_id) const {
|
|
json j;
|
|
if (with_id) {
|
|
j["id"] = std::to_string(this->id);
|
|
}
|
|
if (sku_id) {
|
|
j["sku_id"] = std::to_string(sku_id);
|
|
}
|
|
if (cover_sticker_id) {
|
|
j["cover_sticker_id"] = std::to_string(cover_sticker_id);
|
|
}
|
|
if (banner_asset_id) {
|
|
j["banner_asset_id"] = std::to_string(banner_asset_id);
|
|
}
|
|
j["name"] = name;
|
|
j["description"] = description;
|
|
j["stickers"] = json::array();
|
|
for (auto& s : stickers) {
|
|
j["stickers"].push_back(json::parse(s.second.build_json(with_id)));
|
|
}
|
|
return j.dump();
|
|
}
|
|
|
|
std::string sticker::get_url(bool accept_lottie) const {
|
|
if (this->format_type == sticker_format::sf_lottie && !accept_lottie) {
|
|
return std::string();
|
|
} else {
|
|
return utility::cdn_host + "/stickers/" + std::to_string(this->id) + (this->format_type == sticker_format::sf_lottie ? ".json" : ".png");
|
|
}
|
|
}
|
|
|
|
sticker& sticker::set_filename(const std::string &fn) {
|
|
filename = fn;
|
|
return *this;
|
|
}
|
|
|
|
sticker& sticker::set_file_content(const std::string &fc) {
|
|
filecontent = fc;
|
|
return *this;
|
|
}
|
|
|
|
|
|
};
|