Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

User-installed commands #1223

Merged
merged 6 commits into from
Oct 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 50 additions & 1 deletion include/dpp/appcommand.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
*
************************************************************************************/
#pragma once
#include <dpp/integration.h>
#include <dpp/export.h>
#include <dpp/snowflake.h>
#include <dpp/managed.h>
Expand Down Expand Up @@ -773,6 +774,26 @@ enum interaction_type {
it_modal_submit = 5,
};

/*
* @brief Context type where the interaction can be used or triggered from, e.g. guild, user etc
*/
enum interaction_context_type {
/**
* @brief Interaction can be used within servers
*/
itc_guild = 0,

/**
* @brief Interaction can be used within DMs with the app's bot user
*/
itc_bot_dm = 1,

/**
* @brief Interaction can be used within Group DMs and DMs other than the app's bot user
*/
itc_private_channel = 2,
};

/**
* @brief Right-click context menu types
*/
Expand Down Expand Up @@ -952,6 +973,16 @@ class DPP_EXPORT interaction : public managed, public json_interface<interaction
virtual json to_json_impl(bool with_id = false) const;

public:
/**
* @brief Context where the interaction was triggered from
*/
std::map<application_integration_types, snowflake> authorizing_integration_owners;

/**
* @brief Context where the interaction was triggered from
*/
std::optional<interaction_context_type> context;

/**
* @brief ID of the application this interaction is for.
*/
Expand Down Expand Up @@ -1420,12 +1451,22 @@ class DPP_EXPORT slashcommand : public managed, public json_interface<slashcomma
*/
permission default_member_permissions;

/**
* @brief Installation contexts where the command is available, only for globally-scoped commands. Defaults to your app's configured contexts
*/
std::vector<application_integration_types> integration_types;

/**
* @brief Interaction context(s) where the command can be used, only for globally-scoped commands. By default, all interaction context types included for new commands.
*/
std::vector<interaction_context_type> contexts;

/**
* @brief True if this command should be allowed in a DM
* D++ defaults this to false. Cannot be set to true in a guild
* command, only a global command.
*/
bool dm_permission;
[[deprecated("Use contexts instead.")]] bool dm_permission;

/**
* @brief Indicates whether the command is [age-restricted](https://discord.com/developers/docs/interactions/application-commands#agerestricted-commands).
Expand Down Expand Up @@ -1543,6 +1584,14 @@ class DPP_EXPORT slashcommand : public managed, public json_interface<slashcomma
*/
slashcommand& set_application_id(snowflake i);

/**
* @brief Set the interaction contexts for the command
*
* @param contexts the contexts to set
* @return slashcommand& reference to self for chaining of calls
*/
slashcommand& set_interaction_contexts(std::vector<interaction_context_type> contexts);

/**
* @brief Adds a permission to the command
*
Expand Down
15 changes: 15 additions & 0 deletions include/dpp/application.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
************************************************************************************/

#pragma once
#include <dpp/integration.h>
#include <dpp/export.h>
#include <dpp/snowflake.h>
#include <dpp/managed.h>
Expand All @@ -30,6 +31,8 @@
#include <dpp/permissions.h>
#include <dpp/json_fwd.h>
#include <dpp/json_interface.h>
#include <map>
#include <optional>

namespace dpp {

Expand Down Expand Up @@ -209,6 +212,13 @@ class DPP_EXPORT app_team {
snowflake owner_user_id;
};

/**
* * @brief Configuration object for an app installation
* */
struct integration_configuration {
std::optional<application_install_params> oauth2_install_params;
};

/**
* @brief The application class represents details of a bot application
*/
Expand Down Expand Up @@ -357,6 +367,11 @@ class DPP_EXPORT application : public managed, public json_interface<application
*/
application_install_params install_params;

/**
* @brief Default scopes and permissions for each supported installation context
*/
std::map<application_integration_types, integration_configuration> integration_types_config;

/**
* @brief The application's default custom authorization link, if enabled.
*/
Expand Down
14 changes: 14 additions & 0 deletions include/dpp/integration.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,20 @@

namespace dpp {

/**
* @brief Where an app can be installed, also called its supported installation contexts.
*/
enum application_integration_types {
/**
* @brief Installable to servers
*/
ait_guild_install = 0,
/**
* @brief Installable to users
*/
ait_user_install = 1,
};

/**
* @brief Integration types
*/
Expand Down
44 changes: 43 additions & 1 deletion include/dpp/message.h
Original file line number Diff line number Diff line change
Expand Up @@ -2010,6 +2010,43 @@ namespace cache_policy {

};

/**
* @brief Metadata about the interaction, including the source of the interaction and relevant server and user IDs.
*/
struct DPP_EXPORT interaction_metadata_type {

/**
* @brief ID of the interaction
*/
snowflake id;

/**
* @brief User who triggered the interaction
*/
uint8_t type;

/**
* @brief User who triggered the interaction
*/
user usr;

/**
* @brief ID of the original response message, present only on follow-up messages
*/
snowflake original_response_message_id;

/**
* @brief ID of the message that contained interactive component, present only on messages created from component interactions
*/
snowflake interacted_message_id;

// FIXME: Add this field sometime
/**
* @brief Metadata for the interaction that was used to open the modal, present only on modal submit interactions
*/
// interaction_metadata_type triggering_interaction_metadata;
};

/**
* @brief Message Reference type
*/
Expand Down Expand Up @@ -2192,7 +2229,7 @@ struct DPP_EXPORT message : public managed, json_interface<message> {
/**
* @brief Reference to an interaction
*/
struct message_interaction_struct {
DPP_DEPRECATED("Use interaction_metadata instead.") struct message_interaction_struct{
/**
* @brief ID of the interaction.
*/
Expand All @@ -2214,6 +2251,11 @@ struct DPP_EXPORT message : public managed, json_interface<message> {
user usr;
} interaction;

/**
* @brief Sent if the message is sent as a result of an interaction
*/
interaction_metadata_type interaction_metadata;

/**
* @brief Allowed mentions details
*/
Expand Down
20 changes: 20 additions & 0 deletions src/dpp/application.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,28 @@
************************************************************************************/
#include <dpp/application.h>
#include <dpp/discordevents.h>
#include <dpp/integration.h>
#include <dpp/json.h>

namespace dpp {

using json = nlohmann::json;

void from_json(const json &j, application_integration_types& out) {
out = static_cast<dpp::application_integration_types>(j.get<int>());
}

void from_json(const json &j, application_install_params& out) {
out.permissions = j.at("permissions").get<uint64_t>();
j.at("scopes").get_to(out.scopes);
}

void from_json(const json &j, integration_configuration& out) {
if (auto it = j.find("oauth2_install_params"); it != j.end()) {
it->get_to(out.oauth2_install_params.value());
}
}

application::application() : managed(0), bot_public(false), bot_require_code_grant(false), guild_id(0), primary_sku_id(0), flags(0)
{
}
Expand Down Expand Up @@ -116,6 +132,10 @@ application& application::fill_from_json_impl(nlohmann::json* j) {
}
}

if (auto it = j->find("integration_types_config"); it != j->end()) {
it->get_to(this->integration_types_config);
}

set_string_not_null(j, "custom_install_url", custom_install_url);

// TODO: Investigate https://discord.com/developers/docs/resources/application#application-resource when v11 releases. See if the variables below are documented.
Expand Down
15 changes: 13 additions & 2 deletions src/dpp/message.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -649,14 +649,20 @@ std::optional<uint32_t> poll::get_vote_count(uint32_t answer_id) const noexcept
return 0;
}


void from_json(const json& j, interaction_metadata_type& i) {
i.id = snowflake_not_null(&j, "id");
i.interacted_message_id = snowflake_not_null(&j, "interacted_message_id");
i.original_response_message_id = snowflake_not_null(&j, "original_response_message_id");
i.type = j["type"];
i.usr = j["usr"];
}

embed::~embed() = default;

embed::embed() : timestamp(0) {
}

message::message() : managed(0), channel_id(0), guild_id(0), sent(0), edited(0), webhook_id(0),
message::message() : managed(0), channel_id(0), guild_id(0), sent(0), edited(0), webhook_id(0), interaction_metadata{},
owner(nullptr), type(mt_default), flags(0), pinned(false), tts(false), mention_everyone(false)
{
message_reference.channel_id = 0;
Expand Down Expand Up @@ -1330,6 +1336,11 @@ message& message::fill_from_json(json* d, cache_policy_t cp) {
this->author = *authoruser;
}
}

if (auto it = d->find("interaction_medata"); it != d->end()) {
it->get_to(this->interaction_metadata);
}

if (d->find("interaction") != d->end()) {
json& inter = (*d)["interaction"];
interaction.id = snowflake_not_null(&inter, "id");
Expand Down
33 changes: 32 additions & 1 deletion src/dpp/slashcommand.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@
#include <dpp/json.h>
#include <dpp/stringops.h>
#include <dpp/cache.h>
#include <iostream>
#include <algorithm>
#include <iterator>

namespace dpp {

Expand Down Expand Up @@ -73,6 +74,14 @@ slashcommand& slashcommand::fill_from_json_impl(nlohmann::json* j) {

type = (slashcommand_contextmenu_type)int8_not_null(j, "type");
set_object_array_not_null<command_option>(j, "options", options); // command_option fills recursive

if (auto it = j->find("integration_types"); it != j->end()) {
it->get_to(this->integration_types);
}

if (auto it = j->find("contexts"); it != j->end()) {
it->get_to(this->contexts);
}
return *this;
}

Expand Down Expand Up @@ -251,6 +260,15 @@ void to_json(json& j, const slashcommand& p) {
}
}

if (p.integration_types.size()) {
j["integration_types"] = p.integration_types;
}

// TODO: Maybe a std::optional is better to differentiate
if (p.contexts.size()) {
j["contexts"] = p.contexts;
}

// DEPRECATED
// j["default_permission"] = p.default_permission;
j["application_id"] = std::to_string(p.application_id);
Expand Down Expand Up @@ -293,6 +311,11 @@ slashcommand& slashcommand::set_application_id(snowflake i) {
return *this;
}

slashcommand& slashcommand::set_interaction_contexts(std::vector<interaction_context_type> contexts) {
this->contexts = std::move(contexts);
return *this;
}

slashcommand& slashcommand::add_permission(const command_permission& p) {
this->permissions.emplace_back(p);
return *this;
Expand Down Expand Up @@ -727,6 +750,14 @@ void from_json(const nlohmann::json& j, interaction& i) {
}
}

if (auto it = j.find("context"); it != j.end()) {
i.context = static_cast<interaction_context_type>(*it);
}

if (auto it = j.find("authorizing_integration_owners"); it != j.end()) {
it->get_to(i.authorizing_integration_owners);
}

if(j.contains("entitlements")) {
for (auto& entitle : j["entitlements"]) {
i.entitlements.emplace_back(entitlement().fill_from_json(const_cast<json*>(&entitle)));
Expand Down
Loading