Skip to content

Commit

Permalink
User-installed commands (#1223)
Browse files Browse the repository at this point in the history
  • Loading branch information
braindigitalis authored Oct 21, 2024
2 parents 4906105 + 09e8e02 commit 7a0e5f2
Show file tree
Hide file tree
Showing 7 changed files with 187 additions and 5 deletions.
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

0 comments on commit 7a0e5f2

Please sign in to comment.