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

feat: add support for user apps #1304

Merged
merged 12 commits into from
Oct 21, 2024
2 changes: 1 addition & 1 deletion .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ updates:
- package-ecosystem: "docker"
directory: "/"
schedule:
interval: "daily"
interval: "monthly"
target-branch: "dev"

- package-ecosystem: github-actions
Expand Down
2 changes: 1 addition & 1 deletion doxygen-awesome-css
73 changes: 73 additions & 0 deletions 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 @@ -1194,6 +1225,30 @@ class DPP_EXPORT interaction : public managed, public json_interface<interaction
* is not for a command.
*/
std::string get_command_name() const;

/**
* @brief Get the user who installed the application for a given type.
* @param type Type of installation for the command, e.g. dpp::ait_guild_install or
* dpp::ait_user_install.
* @return The snowflake of the user. In the event this type is not allowed for the
* given command, this will return a default-initialised snowflake with value 0.
*/
dpp::snowflake get_authorizing_integration_owner(application_integration_types type) const;

/**
* @brief Returns true if this interaction occurred as a user-app interaction, e.g.
* within a DM or group DM, added to the user not a guild.
* @return true if a user-app interaction
*/
bool is_user_app_interaction() const;

/**
* @brief Returns true if this interaction occurred as a guild-invited interaction, e.g.
* within a guild's channel, or a DM of a user in that guild.
* @return true if a guild interaction
*/
bool is_guild_interaction() const;

};

/**
Expand Down Expand Up @@ -1420,6 +1475,16 @@ 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
Expand Down Expand Up @@ -1543,6 +1608,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
braindigitalis marked this conversation as resolved.
Show resolved Hide resolved
* */
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
42 changes: 42 additions & 0 deletions 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 @@ -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
19 changes: 19 additions & 0 deletions src/dpp/application.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,21 @@ 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 +131,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
Loading
Loading