From f490fd33fe3b903d3ddd450126d3fef52e87847f Mon Sep 17 00:00:00 2001 From: Ruslan <79337999+ruslan-ilesik@users.noreply.github.com> Date: Fri, 15 Sep 2023 14:33:16 -0400 Subject: [PATCH 1/2] Created get_url methods for message, channel and user. (#855) --- include/dpp/channel.h | 7 +++ include/dpp/message.h | 7 +++ include/dpp/user.h | 7 +++ include/dpp/utility.h | 39 ++++++++++++++++ src/dpp/channel.cpp | 4 ++ src/dpp/message.cpp | 4 ++ src/dpp/user.cpp | 4 ++ src/dpp/utility.cpp | 25 ++++++++++ src/unittest/test.cpp | 106 ++++++++++++++++++++++++++++++++++++++++++ src/unittest/test.h | 7 +++ 10 files changed, 210 insertions(+) diff --git a/include/dpp/channel.h b/include/dpp/channel.h index d14037bc0d..afa09823d9 100644 --- a/include/dpp/channel.h +++ b/include/dpp/channel.h @@ -609,6 +609,13 @@ class DPP_EXPORT channel : public managed, public json_interface { */ std::string get_icon_url(uint16_t size = 0, const image_type format = i_png) const; + /** + * @brief Returns string of URL to channel + * + * @return string of URL to channel + */ + std::string get_url() const; + /** * @brief Returns true if the channel is NSFW gated * diff --git a/include/dpp/message.h b/include/dpp/message.h index ed7137eeeb..422722fb0c 100644 --- a/include/dpp/message.h +++ b/include/dpp/message.h @@ -1555,6 +1555,13 @@ struct DPP_EXPORT message : public managed { * @return true if message has remixed attachment */ bool has_remix_attachment() const; + + /** + * @brief Returns URL to message + * + * @return string of URL to message + */ + std::string get_url() const; }; /** A group of messages */ diff --git a/include/dpp/user.h b/include/dpp/user.h index 4595c8e9c8..71c0978e7e 100644 --- a/include/dpp/user.h +++ b/include/dpp/user.h @@ -164,6 +164,13 @@ class DPP_EXPORT user : public managed, public json_interface { */ std::string get_mention() const; + /** + * @brief Returns URL to user + * + * @return string of URL to user + */ + std::string get_url() const; + /** * @brief Return true if user has the active Developer badge * diff --git a/include/dpp/utility.h b/include/dpp/utility.h index 59093a9099..487a90d1de 100644 --- a/include/dpp/utility.h +++ b/include/dpp/utility.h @@ -130,6 +130,11 @@ namespace dpp { */ inline const std::string cdn_host = "https://cdn.discordapp.com"; + /** + * @brief The base URL for message/user/channel links. + */ + inline const std::string url_host = "https://discord.com"; + /** * @brief Callback for the results of a command executed via dpp::utility::exec */ @@ -531,6 +536,40 @@ namespace dpp { */ std::string DPP_EXPORT role_mention(const snowflake& id); + /** + * @brief Create a URL for message. + * @param guild_id The ID of the guild where message is written. + * @param channel_id The ID of the channel where message is written. + * @param message_id The ID of the message. + * @return std::string The URL to message or empty string if any of ids is 0. + */ + std::string DPP_EXPORT message_url(const snowflake& guild_id, const snowflake& channel_id, const snowflake& message_id); + + /** + * @brief Create a URL for message. + * @param guild_id The ID of the guild where channel is located. + * @param channel_id The ID of the channel. + * @return std::string The URL to message or empty string if any of ids is 0. + */ + std::string DPP_EXPORT channel_url(const snowflake& guild_id, const snowflake& channel_id); + + /** + * @brief Create a URL for message. + * @param guild_id The ID of the guild where thread is located. + * @param thread_id The ID of the thread. + * @return std::string The URL to message or empty string if any of ids is 0. + */ + std::string DPP_EXPORT thread_url(const snowflake& guild_id, const snowflake& thread_id); + + /** + * @brief Create a URL for message. + * @param user_id The ID of the guild where thread is located. + * @return std::string The URL to message or empty string if id is 0. + */ + std::string DPP_EXPORT user_url(const snowflake& user_id); + + + #ifdef _DOXYGEN_ /** * @brief Get the mime type for an image type. diff --git a/src/dpp/channel.cpp b/src/dpp/channel.cpp index 021428d17e..ddbdc35dd8 100644 --- a/src/dpp/channel.cpp +++ b/src/dpp/channel.cpp @@ -636,6 +636,10 @@ std::string channel::get_icon_url(uint16_t size, const image_type format) const } } +std::string channel::get_url() const{ + return utility::channel_url(guild_id, id); +} + channel_type channel::get_type() const { return static_cast(flags & CHANNEL_TYPE_MASK); } diff --git a/src/dpp/message.cpp b/src/dpp/message.cpp index e1fb150570..9e08c62d8d 100644 --- a/src/dpp/message.cpp +++ b/src/dpp/message.cpp @@ -1126,6 +1126,10 @@ bool message::has_remix_attachment() const { }); } +std::string message::get_url() const { + return utility::message_url(guild_id, channel_id, id); +} + sticker::sticker() : managed(0), pack_id(0), type(st_standard), format_type(sf_png), available(true), guild_id(0), sort_value(0) { } diff --git a/src/dpp/user.cpp b/src/dpp/user.cpp index 05a7726b44..d40b5eb401 100644 --- a/src/dpp/user.cpp +++ b/src/dpp/user.cpp @@ -130,6 +130,10 @@ std::string user::get_mention() const { return utility::user_mention(id); } +std::string user::get_url() const{ + return utility::user_url(id); +} + bool user::is_active_developer() const { return this->flags & u_active_developer; } diff --git a/src/dpp/utility.cpp b/src/dpp/utility.cpp index 657a034d4d..cd922b1c46 100644 --- a/src/dpp/utility.cpp +++ b/src/dpp/utility.cpp @@ -550,6 +550,31 @@ namespace dpp { return "<@&" + std::to_string(id) + ">"; } + std::string message_url(const snowflake& guild_id, const snowflake& channel_id, const snowflake& message_id){ + if (guild_id.empty() || channel_id.empty() || message_id.empty()) { + return ""; + } + return url_host + "/channels/" + std::to_string(guild_id) + "/" + std::to_string(channel_id) + "/" + std::to_string(message_id); + } + + std::string channel_url(const snowflake& guild_id, const snowflake& channel_id){ + if (guild_id.empty() || channel_id.empty()) { + return ""; + } + return url_host + "/channels/" + std::to_string(guild_id) + "/" + std::to_string(channel_id); + } + + std::string thread_url(const snowflake& guild_id, const snowflake& thread_id){ + return channel_url(guild_id, thread_id); + }; + + std::string user_url(const snowflake& user_id){ + if (user_id.empty()) { + return ""; + } + return url_host + "/users/" + std::to_string(user_id); + }; + template std::enable_if_t, std::string> mime_type(T type) { static constexpr auto get_image_mime = [](image_type t) constexpr noexcept { diff --git a/src/unittest/test.cpp b/src/unittest/test.cpp index 63ee11aa82..f3adb662f9 100644 --- a/src/unittest/test.cpp +++ b/src/unittest/test.cpp @@ -343,6 +343,14 @@ Markdown lol \\|\\|spoiler\\|\\| \\~\\~strikethrough\\~\\~ \\`small \\*code\\* b set_test(USER_GET_CREATION_TIME, false); set_test(USER_GET_CREATION_TIME, (uint64_t)user1.get_creation_time() == 1465312605); + + set_test(USER_GET_URL, false); + + dpp::user user2; + set_test(USER_GET_URL, + user1.get_url() == dpp::utility::url_host + "/users/189759562910400512" && + user2.get_url() == "" + ); } { // avatar size function @@ -422,6 +430,48 @@ Markdown lol \\|\\|spoiler\\|\\| \\~\\~strikethrough\\~\\~ \\`small \\*code\\* b set_test(EMOJI_GET_URL, emoji.get_url() == dpp::utility::cdn_host + "/emojis/825407338755653641.png"); } + { // message methods + dpp::message m; + m.guild_id = 825407338755653642; + m.channel_id = 956230231277072415; + m.id = 1151617986541666386; + + dpp::message m2; + m2.guild_id = 825407338755653642; + m2.channel_id = 956230231277072415; + + dpp::message m3; + m3.guild_id = 825407338755653642; + m3.id = 1151617986541666386; + + dpp::message m4; + m4.channel_id = 956230231277072415; + m4.id = 1151617986541666386; + + dpp::message m5; + m5.guild_id = 825407338755653642; + + dpp::message m6; + m6.channel_id = 956230231277072415; + + dpp::message m7; + m7.id = 1151617986541666386; + + dpp::message m8; + + set_test(MESSAGE_GET_URL, false); + set_test(MESSAGE_GET_URL, + m.get_url() == dpp::utility::url_host + "/channels/825407338755653642/956230231277072415/1151617986541666386" && + m2.get_url() == "" && + m3.get_url() == "" && + m4.get_url() == "" && + m5.get_url() == "" && + m6.get_url() == "" && + m7.get_url() == "" && + m8.get_url() == "" + ); + } + { // channel methods set_test(CHANNEL_SET_TYPE, false); dpp::channel c; @@ -435,6 +485,24 @@ Markdown lol \\|\\|spoiler\\|\\| \\~\\~strikethrough\\~\\~ \\`small \\*code\\* b set_test(CHANNEL_GET_MENTION, false); c.id = 825411707521728511; set_test(CHANNEL_GET_MENTION, c.get_mention() == "<#825411707521728511>"); + + set_test(CHANNEL_GET_URL, false); + c.guild_id = 825407338755653642; + + dpp::channel c2; + c2.id = 825411707521728511; + + dpp::channel c3; + c3.guild_id = 825407338755653642; + + dpp::channel c4; + + set_test(CHANNEL_GET_URL, + c.get_url() == dpp::utility::url_host + "/channels/825407338755653642/825411707521728511" && + c2.get_url() == "" && + c3.get_url() == "" && + c4.get_url() == "" + ); } { // utility methods @@ -507,6 +575,44 @@ Markdown lol \\|\\|spoiler\\|\\| \\~\\~strikethrough\\~\\~ \\`small \\*code\\* b emoji_mention3 == ":white_check_mark:" && emoji_mention4 == ":white_check_mark:" ); + + set_test(UTILITY_USER_URL, false); + auto user_url = dpp::utility::user_url(123); + set_test(UTILITY_USER_URL, + user_url == dpp::utility::url_host + "/users/123" && + dpp::utility::user_url(0) == "" + ); + + set_test(UTILITY_MESSAGE_URL, false); + auto message_url = dpp::utility::message_url(1,2,3); + set_test(UTILITY_MESSAGE_URL, + message_url == dpp::utility::url_host+ "/channels/1/2/3" && + dpp::utility::message_url(0,2,3) == "" && + dpp::utility::message_url(1,0,3) == "" && + dpp::utility::message_url(1,2,0) == "" && + dpp::utility::message_url(0,0,3) == "" && + dpp::utility::message_url(0,2,0) == "" && + dpp::utility::message_url(1,0,0) == "" && + dpp::utility::message_url(0,0,0) == "" + ); + + set_test(UTILITY_CHANNEL_URL, false); + auto channel_url = dpp::utility::channel_url(1,2); + set_test(UTILITY_CHANNEL_URL, + channel_url == dpp::utility::url_host+ "/channels/1/2" && + dpp::utility::channel_url(0,2) == "" && + dpp::utility::channel_url(1,0) == "" && + dpp::utility::channel_url(0,0) == "" + ); + + set_test(UTILITY_THREAD_URL, false); + auto thread_url = dpp::utility::thread_url(1,2); + set_test(UTILITY_THREAD_URL, + thread_url == dpp::utility::url_host+ "/channels/1/2" && + dpp::utility::thread_url(0,2) == "" && + dpp::utility::thread_url(1,0) == "" && + dpp::utility::thread_url(0,0) == "" + ); } #ifndef _WIN32 diff --git a/src/unittest/test.h b/src/unittest/test.h index 9bd88d29b2..865a2abb47 100644 --- a/src/unittest/test.h +++ b/src/unittest/test.h @@ -169,11 +169,14 @@ DPP_TEST(USER_GET, "cluster::user_get", tf_online); DPP_TEST(USER_GET_FLAGS, "cluster::user_get flag parsing", tf_online); DPP_TEST(MEMBER_GET, "cluster::guild_get_member", tf_online); DPP_TEST(USER_GET_MENTION, "user::get_mention", tf_offline); +DPP_TEST(USER_GET_URL, "user::get_url", tf_offline); DPP_TEST(USER_FORMAT_USERNAME, "user::format_username", tf_offline); DPP_TEST(USER_GET_CREATION_TIME, "user::get_creation_time", tf_offline); DPP_TEST(USER_GET_AVATAR_URL, "user::get_avatar_url", tf_offline); DPP_TEST(CHANNEL_SET_TYPE, "channel::set_type", tf_offline); DPP_TEST(CHANNEL_GET_MENTION, "channel::get_mention", tf_offline); +DPP_TEST(CHANNEL_GET_URL, "channel::get_url", tf_offline); +DPP_TEST(MESSAGE_GET_URL,"message::get_url",tf_offline); DPP_TEST(UTILITY_GUILD_NAVIGATION, "utility::guild_navigation", tf_offline); DPP_TEST(UTILITY_ICONHASH, "utility::iconhash", tf_offline); DPP_TEST(UTILITY_MAKE_URL_PARAMETERS, "utility::make_url_parameters", tf_offline); @@ -185,6 +188,10 @@ DPP_TEST(UTILITY_CHANNEL_MENTION, "utility::channel_mention", tf_offline); DPP_TEST(UTILITY_USER_MENTION, "utility::user_mention", tf_offline); DPP_TEST(UTILITY_ROLE_MENTION, "utility::role_mention", tf_offline); DPP_TEST(UTILITY_EMOJI_MENTION, "utility::emoji_mention", tf_offline); +DPP_TEST(UTILITY_USER_URL, "utility::user_url", tf_offline); +DPP_TEST(UTILITY_MESSAGE_URL, "utility::message_url", tf_offline); +DPP_TEST(UTILITY_CHANNEL_URL, "utility::channel_url", tf_offline); +DPP_TEST(UTILITY_THREAD_URL, "utility::thread_url", tf_offline); DPP_TEST(UTILITY_AVATAR_SIZE, "utility::avatar_size", tf_offline); DPP_TEST(UTILITY_CDN_ENDPOINT_URL_HASH, "utility::cdn_endpoint_url_hash", tf_offline); DPP_TEST(STICKER_GET_URL, "sticker::get_url aka utility::cdn_endpoint_url_sticker", tf_offline); From 4f18eb85d2b70dd60ea40918edd24c26b737f71e Mon Sep 17 00:00:00 2001 From: Brain Date: Sat, 16 Sep 2023 16:49:08 +0100 Subject: [PATCH 2/2] ci: remove ninja for all but windows, for us it is slower than make -j2 (#857) --- .github/workflows/ci.yml | 30 +++++++++++++++--------------- cmake/ARM64ToolChain.cmake | 2 +- cmake/ARMv7ToolChain.cmake | 2 +- src/unittest/test.h | 4 ++-- 4 files changed, 19 insertions(+), 19 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3be606ec8d..51349a730b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -45,15 +45,15 @@ jobs: uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 - name: Install apt packages - run: sudo sed -i 's/azure\.//' /etc/apt/sources.list && sudo apt update && sudo apt install ${{ matrix.cfg.cpp-version }} ninja-build libsodium-dev libopus-dev zlib1g-dev rpm + run: sudo sed -i 's/azure\.//' /etc/apt/sources.list && sudo apt update && sudo apt install ${{ matrix.cfg.cpp-version }} libsodium-dev libopus-dev zlib1g-dev rpm - name: Generate CMake - run: mkdir build && cd build && cmake -G Ninja -DDPP_NO_VCPKG=ON -DAVX_TYPE=T_fallback -DCMAKE_BUILD_TYPE=Release .. + run: mkdir build && cd build && cmake -DDPP_NO_VCPKG=ON -DAVX_TYPE=T_fallback -DCMAKE_BUILD_TYPE=Release .. env: CXX: ${{matrix.cfg.cpp-version}} - name: Build Project - run: cd build && ninja + run: cd build && make -j2 - name: Run unit tests run: cd build/library && ./unittest @@ -87,15 +87,15 @@ jobs: uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 - name: Install apt packages - run: sudo sed -i 's/azure\.//' /etc/apt/sources.list && sudo apt update && sudo apt install ${{ matrix.cfg.cpp-version }} ninja-build libsodium-dev libopus-dev zlib1g-dev rpm + run: sudo sed -i 's/azure\.//' /etc/apt/sources.list && sudo apt update && sudo apt install ${{ matrix.cfg.cpp-version }} libsodium-dev libopus-dev zlib1g-dev rpm - name: Generate CMake - run: mkdir build && cd build && cmake -G Ninja -DDPP_NO_VCPKG=ON -DAVX_TYPE=T_fallback -DCMAKE_BUILD_TYPE=Release ${{matrix.cfg.cmake-flags}} .. + run: mkdir build && cd build && cmake -DDPP_NO_VCPKG=ON -DAVX_TYPE=T_fallback -DCMAKE_BUILD_TYPE=Release ${{matrix.cfg.cmake-flags}} .. env: CXX: ${{matrix.cfg.cpp-version}} - name: Build Project - run: cd build && ninja + run: cd build && make -j2 - name: Package distributable if: ${{ matrix.cfg.cpp-version == 'g++-10' }} @@ -128,15 +128,15 @@ jobs: uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 - name: Install homebrew packages - run: brew install cmake ninja libsodium opus openssl + run: brew install cmake make libsodium opus openssl - name: Generate CMake - run: mkdir build && cd build && cmake -DDPP_NO_VCPKG=ON -DCMAKE_BUILD_TYPE=Release -DDPP_CORO=ON -DAVX_TYPE=T_fallback -G Ninja .. + run: mkdir build && cd build && cmake -DDPP_NO_VCPKG=ON -DCMAKE_BUILD_TYPE=Release -DDPP_CORO=ON -DAVX_TYPE=T_fallback .. env: DONT_RUN_VCPKG: true - name: Build Project - run: cd build && ninja + run: cd build && make -j2 env: DONT_RUN_VCPKG: true @@ -186,7 +186,7 @@ jobs: DONT_RUN_VCPKG: true - name: Build Project - run: cmake --build main/build --target dpp --config ${{matrix.cfg.config}} + run: cmake --build main/build --target dpp --config ${{matrix.cfg.config}} --parallel 2 env: DONT_RUN_VCPKG: true @@ -227,16 +227,16 @@ jobs: uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 - name: Install Packages - run: sudo sed -i 's/azure\.//' /etc/apt/sources.list && sudo apt update && sudo apt install cmake ninja-build rpm + run: sudo sed -i 's/azure\.//' /etc/apt/sources.list && sudo apt update && sudo apt install cmake rpm - name: Generate CMakeFiles - run: mkdir build && cd build && sudo cmake ${{matrix.cfg.cmake-options}} -DDPP_NO_VCPKG=ON -DCMAKE_BUILD_TYPE=Release -DAVX_TYPE=T_fallback -G Ninja .. + run: mkdir build && cd build && sudo cmake ${{matrix.cfg.cmake-options}} -DDPP_NO_VCPKG=ON -DCMAKE_BUILD_TYPE=Release -DAVX_TYPE=T_fallback .. - name: Compile Source - run: cd build && sudo ninja + run: cd build && sudo make -j2 - name: Package Distributable - run: cd build && cpack --verbose + run: cd build && sudo cpack --verbose || cat /home/runner/work/DPP/DPP/build/_CPack_Packages/Linux/DEB/PreinstallOutput.log - name: Upload Binaries (DEB) uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2 @@ -260,7 +260,7 @@ jobs: # uses: vmactions/freebsd-vm@v0.1.5 # with: # usesh: true -# prepare: pkg install -y openssl-devel gcc gmake ninja cmake git +# prepare: pkg install -y openssl-devel gcc gmake cmake git # run: | # pwd # ls -lah diff --git a/cmake/ARM64ToolChain.cmake b/cmake/ARM64ToolChain.cmake index 7c09aa4503..8087e3f375 100644 --- a/cmake/ARM64ToolChain.cmake +++ b/cmake/ARM64ToolChain.cmake @@ -47,6 +47,6 @@ EXECUTE_PROCESS(COMMAND sudo mv TMPFILE /etc/apt/sources.list) EXECUTE_PROCESS(COMMAND sudo dpkg --add-architecture arm64) EXECUTE_PROCESS(COMMAND sudo apt-add-repository -y ppa:canonical-kernel-team/ppa) EXECUTE_PROCESS(COMMAND sudo apt update) -EXECUTE_PROCESS(COMMAND sudo apt install -y cmake ninja-build gcc-8-aarch64-linux-gnu g++-8-aarch64-linux-gnu libc6-dev-arm64-cross zlib1g-dev:arm64 libssl-dev:arm64 libopus-dev:arm64 libsodium-dev:arm64) +EXECUTE_PROCESS(COMMAND sudo apt install -y cmake gcc-8-aarch64-linux-gnu g++-8-aarch64-linux-gnu libc6-dev-arm64-cross zlib1g-dev:arm64 libssl-dev:arm64 libopus-dev:arm64 libsodium-dev:arm64) EXECUTE_PROCESS(COMMAND sudo mv /usr/lib/aarch64-linux-gnu/pkgconfig/libsodium.pc /usr/lib/pkgconfig/) diff --git a/cmake/ARMv7ToolChain.cmake b/cmake/ARMv7ToolChain.cmake index e5daa0cab8..7b9bacf3bc 100644 --- a/cmake/ARMv7ToolChain.cmake +++ b/cmake/ARMv7ToolChain.cmake @@ -46,6 +46,6 @@ EXECUTE_PROCESS(COMMAND printf "deb [arch=amd64] http://archive.ubuntu.com/ubunt EXECUTE_PROCESS(COMMAND sudo mv TMPFILE /etc/apt/sources.list) EXECUTE_PROCESS(COMMAND sudo dpkg --add-architecture armhf) EXECUTE_PROCESS(COMMAND sudo apt update) -EXECUTE_PROCESS(COMMAND sudo apt install -y cmake ninja-build gcc-8-arm-linux-gnueabihf g++-8-arm-linux-gnueabihf zlib1g-dev:armhf libssl-dev:armhf libopus-dev:armhf libsodium-dev:armhf) +EXECUTE_PROCESS(COMMAND sudo apt install -y cmake gcc-8-arm-linux-gnueabihf g++-8-arm-linux-gnueabihf zlib1g-dev:armhf libssl-dev:armhf libopus-dev:armhf libsodium-dev:armhf) EXECUTE_PROCESS(COMMAND sudo mv /usr/lib/arm-linux-gnueabihf/pkgconfig/libsodium.pc /usr/lib/pkgconfig/) diff --git a/src/unittest/test.h b/src/unittest/test.h index 865a2abb47..96d531e0a4 100644 --- a/src/unittest/test.h +++ b/src/unittest/test.h @@ -93,8 +93,6 @@ DPP_TEST(MESSAGERECEIVE, "Receipt of a created message", tf_online); DPP_TEST(MESSAGEFILE, "Message attachment send and check", tf_online); DPP_TEST(CACHE, "Test guild cache", tf_online); DPP_TEST(USERCACHE, "Test user cache", tf_online); -DPP_TEST(VOICECONN, "Connect to voice channel", tf_online); -DPP_TEST(VOICESEND, "Send audio to voice channel", tf_online); DPP_TEST(REACT, "React to a message", tf_online); DPP_TEST(REACTEVENT, "Reaction event", tf_online); DPP_TEST(GUILDCREATE, "Receive guild create event", tf_online); @@ -221,6 +219,8 @@ DPP_TEST(INVITE_DELETE, "cluster::invite_delete", tf_online); /* Extended set -- Less important, skipped on the master branch due to rate limits and GitHub actions limitations*/ /* To execute, run unittests with "full" command line argument */ +DPP_TEST(VOICECONN, "Connect to voice channel", tf_online | tf_extended); +DPP_TEST(VOICESEND, "Send audio to voice channel", tf_online | tf_extended); // udp unreliable on gitbub DPP_TEST(MESSAGEPIN, "Pinning a channel message", tf_online | tf_extended); DPP_TEST(MESSAGEUNPIN, "Unpinning a channel message", tf_online | tf_extended);