From c0237983945a462d7b3d1fc07ee3b674727e6fb1 Mon Sep 17 00:00:00 2001 From: Umesh Bhatt Date: Thu, 18 Sep 2025 18:30:25 +0530 Subject: [PATCH 1/3] Implemented createSms method and tested successfully --- Makefile | 4 + examples/messaging/messages/createSms.cpp | 32 ++++++ include/classes/Messaging.hpp | 130 +++++++++++++--------- src/services/Messaging.cpp | 77 +++++++++++++ 4 files changed, 193 insertions(+), 50 deletions(-) create mode 100644 examples/messaging/messages/createSms.cpp diff --git a/Makefile b/Makefile index 6d49cc2..e69bc96 100644 --- a/Makefile +++ b/Makefile @@ -284,6 +284,10 @@ listProviderLogs: $(SRCS) $(EXAMPLES_DIR)/messaging/messages/listProviderLogs.cp @mkdir -p ./$(TESTS_DIR) $(CXX) $(CXXFLAGS) -o ./$(TESTS_DIR)/listProviderLogs $(SRCS) $(EXAMPLES_DIR)/messaging/messages/listProviderLogs.cpp $(LDFLAGS) +createSms: $(SRCS) $(EXAMPLES_DIR)/messaging/messages/createSms.cpp + @mkdir -p ./$(TESTS_DIR) + $(CXX) $(CXXFLAGS) -o ./$(TESTS_DIR)/createSms $(SRCS) $(EXAMPLES_DIR)/messaging/messages/createSms.cpp $(LDFLAGS) + # Messaging - Topics getTopic: $(SRCS) $(EXAMPLES_DIR)/messaging/topics/getTopic.cpp @mkdir -p ./$(TESTS_DIR) diff --git a/examples/messaging/messages/createSms.cpp b/examples/messaging/messages/createSms.cpp new file mode 100644 index 0000000..12d03a7 --- /dev/null +++ b/examples/messaging/messages/createSms.cpp @@ -0,0 +1,32 @@ +#include "Appwrite.hpp" +#include + +int main() { + std::string projectId = ""; + std::string apiKey = ""; + + Appwrite appwrite(projectId, apiKey); + + std::string messageId = "67b30694016a7eb8"; + std::string subject = "Hello from C++ Appwrite SDK!"; + std::string content = + "Testing SMS message creation with topics, users, and targets."; + + std::vector topics = {}; + std::vector users = {}; + std::vector targets = {}; + + std::string scheduled_at = "2025-09-27 18:00:00.000"; + bool draft = true; + + try { + std::string response = appwrite.getMessaging().createSms( + messageId, content, topics, users, targets, draft, scheduled_at); + std::cout << "SMS Message Created!\nResponse: " << response + << std::endl; + } catch (const AppwriteException &ex) { + std::cerr << "Exception: " << ex.what() << std::endl; + } + + return 0; +} \ No newline at end of file diff --git a/include/classes/Messaging.hpp b/include/classes/Messaging.hpp index f2eef99..a79ca7b 100644 --- a/include/classes/Messaging.hpp +++ b/include/classes/Messaging.hpp @@ -150,30 +150,56 @@ class Messaging { * @param targets List of target recipients (e.g., email:userId) (optional). * @return JSON response. */ - std::string createMessage(const std::string& messageId, - const std::string& subject, - const std::string& content, - const std::vector& topics = {}, - const std::vector& targets = {}); + std::string createMessage(const std::string &messageId, + const std::string &subject, + const std::string &content, + const std::vector &topics = {}, + const std::vector &targets = {}); - /** - * @brief Updates an existing push notification message. - * - * Modifies the title and body of an existing push message. + /** + * @brief Create a new sms message. + * + * @param messageId Unique ID for the message. + * @param content SMS Content. + * @param topics List of topic IDs (optional). + * @param users List of User IDs (optional). + * @param targets List of target IDs (optional). + * @param draft If true, saves the message as a draft. + * @param scheduled_at Scheduled delivery time for message. + * @return JSON response. + */ + std::string createSms(const std::string &messageId, + const std::string &content, + const std::vector &topics = {}, + const std::vector &users = {}, + const std::vector &targets = {}, + bool draft = false, + const std::string &scheduled_at = ""); + + /** + * @brief Updates an existing push notification + * message. * - * @param messageId The ID of the message to update. - * @param title New title of the push notification. - * @param body New body content of the push notification. - * @param topicId List of topic IDs to update the message. - * @param userId List of user IDs to update the message. + * Modifies the title and body of an existing push + * message. + * + * @param messageId The ID of the message to + * update. + * @param title New title of the push + * notification. + * @param body New body content of the push + * notification. + * @param topicId List of topic IDs to update the + * message. + * @param userId List of user IDs to update the + * message. * @return JSON response - */ + */ std::string updatePush(const std::string &messageId, - const std::string &title, - const std::string &body, - const std::vector &topicId = {}, - const std::vector &userId = {}); - + const std::string &title, const std::string &body, + const std::vector &topicId = {}, + const std::vector &userId = {}); + /** * @brief List all providers. * @param queries Optional query filters @@ -189,79 +215,83 @@ class Messaging { */ std::string listProviderLogs(const std::string &providerId, Queries &queries); - + /** - * @brief Create a new Firebase Cloud Messaging provider. + * @brief Create a new Firebase Cloud Messaging + * provider. * @param providerId A unique Id for the provider. * @param name provider name. - * @param service_account_json FCM service account JSON.. - * @param enabled Whether the provider should be active immediately after creation. + * @param service_account_json FCM service account + * JSON.. + * @param enabled Whether the provider should be + * active immediately after creation. * @return JSON response. - */ + */ std::string createFcmProvider(std::string &providerId, std::string name, std::string service_account_json, bool enabled); - + /** * @brief Delete a provider. * @param providerId ID of the provider * @return JSON response */ std::string deleteProvider(const std::string &providerId); - + /** * @brief Get a specific provider by ID. * @param providerId ID of the provider * @return JSON string of the provider details */ std::string getProvider(const std::string &providerId); - + /** - * @brief List all message logs with optional filters. + * @brief List all message logs with optional + * filters. * @param messageId ID of the message * @param queries Query parameters for filtering * @return JSON string of messageLog list */ std::string listMessageLogs(const std::string &messageId, Queries &queries); - - /** + + /** * @brief Delete a message by its ID. * @param messageId ID of the message. * @return JSON response. */ std::string deleteMessages(const std::string &messageId); - - /** + + /** * @brief Update an email message by its ID. * @class updateEmail - * - * This method belongs to the updateEmail class and provides the functionality - * to update the subject and content of an existing email message via the - * Appwrite Messaging API. - * + * + * This method belongs to the updateEmail class + * and provides the functionality to update the + * subject and content of an existing email + * message via the Appwrite Messaging API. + * * @param messageId Unique message identifier * @param subject New subject of the email - * @param content Updated content/body of the email + * @param content Updated content/body of the + * email * @return JSON response string from the server - * @throws AppwriteException if parameters are invalid or request fails - */ - std::string updateEmail( - const std::string& messageId, - const std::string& subject, - const std::string& content - ); - + * @throws AppwriteException if parameters are + * invalid or request fails + */ + std::string updateEmail(const std::string &messageId, + const std::string &subject, + const std::string &content); /** * @brief List all targets for a given message. * @param messageId ID of the message. * @param queries Optional query filters. * @return JSON response. - */ - std::string listTargets(const std::string &messageId, + */ + std::string listTargets(const std::string &messageId, const std::vector &queries = {}); - + private: std::string projectId; ///< Project ID std::string apiKey; ///< API Key diff --git a/src/services/Messaging.cpp b/src/services/Messaging.cpp index e74c2d3..7d9f13c 100644 --- a/src/services/Messaging.cpp +++ b/src/services/Messaging.cpp @@ -468,6 +468,83 @@ std::string Messaging::createMessage(const std::string& messageId, } } +// Added method to create a new SMS message +std::string Messaging::createSms(const std::string &messageId, + const std::string &content, + const std::vector &topics, + const std::vector &users, + const std::vector &targets, + bool draft, const std::string &scheduled_at) { + if (messageId.empty()) { + throw AppwriteException("Missing required parameter: 'messageId'"); + } + + if (content.empty()) { + throw AppwriteException("Missing required parameter: 'content'"); + } + + std::string payload = + R"({"messageId":")" + Utils::escapeJsonString(messageId) + + R"(","content":")" + Utils::escapeJsonString(content) + R"(")"; + + if (!topics.empty()) { + payload += R"(,"topics":[)"; + for (size_t i = 0; i < topics.size(); ++i) { + payload += "\"" + Utils::escapeJsonString(topics[i]) + "\""; + if (i != topics.size() - 1) + payload += ","; + } + payload += "]"; + } + + if (!users.empty()) { + payload += R"(,"users":[)"; + for (size_t i = 0; i < users.size(); ++i) { + payload += "\"" + Utils::escapeJsonString(users[i]) + "\""; + if (i != users.size() - 1) + payload += ","; + } + payload += "]"; + } + + if (!targets.empty()) { + payload += R"(,"targets":[)"; + for (size_t i = 0; i < targets.size(); ++i) { + payload += "\"" + Utils::escapeJsonString(targets[i]) + "\""; + if (i != targets.size() - 1) + payload += ","; + } + payload += "]"; + } + + payload += std::string(R"(,"draft":)") + (draft ? "true" : "false"); + + if (!scheduled_at.empty()) { + payload += R"(,"scheduledAt":")" + + Utils::escapeJsonString(scheduled_at) + "\""; + } + + payload += "}"; + + std::string url = Config::API_BASE_URL + "/messaging/messages/sms"; + + std::vector headers = Config::getHeaders(projectId); + headers.push_back("X-Appwrite-Key: " + apiKey); + headers.push_back("Content-Type: application/json"); + + std::string response; + + int statusCode = Utils::postRequest(url, payload, headers, response); + + if (statusCode == HttpStatus::CREATED || statusCode == HttpStatus::OK) { + return response; + } else { + throw AppwriteException( + "Error creating a new sms message. Status code: " + + std::to_string(statusCode) + "\n\nResponse: " + response); + } +} + std::string Messaging::updateEmail( const std::string& messageId, const std::string& subject, From 108ead25d1823ed0d99a49b925bdd3dd40533883 Mon Sep 17 00:00:00 2001 From: Umesh Bhatt Date: Thu, 18 Sep 2025 22:39:28 +0530 Subject: [PATCH 2/3] fix: formatted code using clang-format --- include/classes/Messaging.hpp | 31 +++---- src/services/Messaging.cpp | 154 ++++++++++++++++++---------------- 2 files changed, 96 insertions(+), 89 deletions(-) diff --git a/include/classes/Messaging.hpp b/include/classes/Messaging.hpp index a79ca7b..5935241 100644 --- a/include/classes/Messaging.hpp +++ b/include/classes/Messaging.hpp @@ -116,30 +116,31 @@ class Messaging { const std::string &name, const std::string &targetId, const std::string &subscriberId); - /** + /** * @brief Creates a new push notification message. - * - * Sends a push notification to specified users, topics, or both. + * + * Sends a push notification to specified users, topics, or both. * * @param messageId A unique Id for the message. * @param title Title of the push notification. * @param body Body content of the push notification. - * @param topicId A list of topic IDs to which the notification should be sent. - * @param userId A list of user IDs to which the notification should be sent. + * @param topicId A list of topic IDs to which the notification should be + * sent. + * @param userId A list of user IDs to which the notification should be + * sent. * @param draft If true, saves the message as a draft. - * + * * @return JSON response. - */ + */ std::string createPush(const std::string &messageId, - const std::string &title, - const std::string &body, - const std::vector &topicId= {}, - const std::vector &userId = {}, - bool draft = false); - - /** + const std::string &title, const std::string &body, + const std::vector &topicId = {}, + const std::vector &userId = {}, + bool draft = false); + + /** * @brief Create a new email message. - * + * * Sends a new email message to specific topics and/or target recipients. * At least one of `topics` or `targets` must be provided. * diff --git a/src/services/Messaging.cpp b/src/services/Messaging.cpp index 7d9f13c..5e40659 100644 --- a/src/services/Messaging.cpp +++ b/src/services/Messaging.cpp @@ -249,7 +249,6 @@ std::string Messaging::listSubscribers(const std::string &topicId, std::string url = Config::API_BASE_URL + "/messaging/topics/" + topicId + "/subscribers" + queries.to_string(); - std::vector headers = Config::getHeaders(projectId); headers.push_back("X-Appwrite-Key: " + apiKey); @@ -342,11 +341,11 @@ std::string Messaging::createSubscribers(const std::string &topicId, } std::string Messaging::createPush(const std::string &messageId, - const std::string &title, - const std::string &body, - const std::vector &topicId, - const std::vector &userId, - bool draft){ + const std::string &title, + const std::string &body, + const std::vector &topicId, + const std::vector &userId, + bool draft) { if (messageId.empty()) { throw AppwriteException("Missing required parameter: 'messageId'"); } @@ -361,58 +360,57 @@ std::string Messaging::createPush(const std::string &messageId, if (topicId.empty()) { throw AppwriteException("Missing required parameter: 'topicId'"); - } + } if (userId.empty()) { throw AppwriteException("Missing required parameter: 'userId'"); } - + std::string topicIdJson = "["; for (size_t i = 0; i < topicId.size(); ++i) { topicIdJson += "\"" + Utils::escapeJsonString(topicId[i]) + "\""; - if (i < topicId.size() - 1) topicIdJson += ","; + if (i < topicId.size() - 1) + topicIdJson += ","; } topicIdJson += "]"; - + std::string userIdJson = "["; for (size_t i = 0; i < userId.size(); ++i) { userIdJson += "\"" + Utils::escapeJsonString(userId[i]) + "\""; - if (i < userId.size() - 1) userIdJson += ","; + if (i < userId.size() - 1) + userIdJson += ","; } userIdJson += "]"; - - + std::string url = Config::API_BASE_URL + "/messaging/messages/push"; std::string payload = R"({"messageId":")" + Utils::escapeJsonString(messageId) + - R"(","title":")" + Utils::escapeJsonString(title) + - R"(","body":")" + Utils::escapeJsonString(body) + - R"(","topicId":)" + topicIdJson + - R"(,"userId":)" + userIdJson + - R"(,"draft":)" + (draft ? "true" : "false") + - "}"; + R"(","title":")" + Utils::escapeJsonString(title) + R"(","body":")" + + Utils::escapeJsonString(body) + R"(","topicId":)" + topicIdJson + + R"(,"userId":)" + userIdJson + R"(,"draft":)" + + (draft ? "true" : "false") + "}"; std::vector headers = Config::getHeaders(projectId); headers.push_back("X-Appwrite-Key: " + apiKey); - headers.push_back("Content-Type: application/json"); - + headers.push_back("Content-Type: application/json"); + std::string response; int statusCode = Utils::postRequest(url, payload, headers, response); - if (statusCode == HttpStatus::CREATED) { - return response; - } else { - throw AppwriteException( - "Error fetching topic. Status code: " + std::to_string(statusCode) + - "\n\nResponse: " + response); - } + if (statusCode == HttpStatus::CREATED) { + return response; + } else { + throw AppwriteException( + "Error fetching topic. Status code: " + std::to_string(statusCode) + + "\n\nResponse: " + response); + } } -std::string Messaging::createMessage(const std::string& messageId, - const std::string& subject, - const std::string& content, - const std::vector& topics, - const std::vector& targets) { +std::string Messaging::createMessage(const std::string &messageId, + const std::string &subject, + const std::string &content, + const std::vector &topics, + const std::vector &targets) { if (messageId.empty()) { throw AppwriteException("Missing required parameter: 'messageId'"); } @@ -423,18 +421,21 @@ std::string Messaging::createMessage(const std::string& messageId, throw AppwriteException("Missing required parameter: 'content'"); } if (topics.empty() && targets.empty()) { - throw AppwriteException("At least one of 'topics' or 'targets' must be provided"); + throw AppwriteException( + "At least one of 'topics' or 'targets' must be provided"); } - std::string payload = R"({"messageId":")" + Utils::escapeJsonString(messageId) + - R"(","subject":")" + Utils::escapeJsonString(subject) + - R"(","content":")" + Utils::escapeJsonString(content) + R"(")"; + std::string payload = + R"({"messageId":")" + Utils::escapeJsonString(messageId) + + R"(","subject":")" + Utils::escapeJsonString(subject) + + R"(","content":")" + Utils::escapeJsonString(content) + R"(")"; if (!topics.empty()) { payload += R"(,"topics":[)"; for (size_t i = 0; i < topics.size(); ++i) { payload += "\"" + Utils::escapeJsonString(topics[i]) + "\""; - if (i != topics.size() - 1) payload += ","; + if (i != topics.size() - 1) + payload += ","; } payload += "]"; } @@ -443,7 +444,8 @@ std::string Messaging::createMessage(const std::string& messageId, payload += R"(,"targets":[)"; for (size_t i = 0; i < targets.size(); ++i) { payload += "\"" + Utils::escapeJsonString(targets[i]) + "\""; - if (i != targets.size() - 1) payload += ","; + if (i != targets.size() - 1) + payload += ","; } payload += "]"; } @@ -464,7 +466,8 @@ std::string Messaging::createMessage(const std::string& messageId, return response; } else { throw AppwriteException("Error creating email message. Status code: " + - std::to_string(statusCode) + "\n\nResponse: " + response); + std::to_string(statusCode) + + "\n\nResponse: " + response); } } @@ -545,11 +548,9 @@ std::string Messaging::createSms(const std::string &messageId, } } -std::string Messaging::updateEmail( - const std::string& messageId, - const std::string& subject, - const std::string& content -) { +std::string Messaging::updateEmail(const std::string &messageId, + const std::string &subject, + const std::string &content) { if (messageId.empty()) { throw AppwriteException("Missing required parameter: 'messageId'"); } @@ -560,10 +561,12 @@ std::string Messaging::updateEmail( throw AppwriteException("Missing required parameter: 'content'"); } - std::string url = Config::API_BASE_URL + "/messaging/messages/email/" + Utils::urlEncode(messageId); + std::string url = Config::API_BASE_URL + "/messaging/messages/email/" + + Utils::urlEncode(messageId); std::string payload = R"({"subject":")" + Utils::escapeJsonString(subject) + - R"(","content":")" + Utils::escapeJsonString(content) + R"("})"; + R"(","content":")" + + Utils::escapeJsonString(content) + R"("})"; std::vector headers = Config::getHeaders(projectId); headers.push_back("X-Appwrite-Key: " + apiKey); @@ -575,7 +578,8 @@ std::string Messaging::updateEmail( if (statusCode == HttpStatus::OK) { return response; } else { - throw AppwriteException("Error updating message. Status code: " + std::to_string(statusCode) + + throw AppwriteException("Error updating message. Status code: " + + std::to_string(statusCode) + "\n\nResponse: " + response); } } @@ -608,37 +612,38 @@ std::string Messaging::updatePush(const std::string &messageId, std::string topicIdJson = "["; for (size_t i = 0; i < topicId.size(); ++i) { topicIdJson += "\"" + Utils::escapeJsonString(topicId[i]) + "\""; - if (i < topicId.size() - 1) topicIdJson += ","; + if (i < topicId.size() - 1) + topicIdJson += ","; } topicIdJson += "]"; - + std::string userIdJson = "["; for (size_t i = 0; i < userId.size(); ++i) { userIdJson += "\"" + Utils::escapeJsonString(userId[i]) + "\""; - if (i < userId.size() - 1) userIdJson += ","; + if (i < userId.size() - 1) + userIdJson += ","; } userIdJson += "]"; - - std::string url = Config::API_BASE_URL + "/messaging/messages/push/" + messageId; - std::string payload = - R"({"title":")" + Utils::escapeJsonString(title) + - R"(","body":")" + Utils::escapeJsonString(body) + - R"(","topicId":)" + topicIdJson + - R"(,"userId":)" + userIdJson + - "}"; + + std::string url = + Config::API_BASE_URL + "/messaging/messages/push/" + messageId; + std::string payload = R"({"title":")" + Utils::escapeJsonString(title) + + R"(","body":")" + Utils::escapeJsonString(body) + + R"(","topicId":)" + topicIdJson + R"(,"userId":)" + + userIdJson + "}"; std::vector headers = Config::getHeaders(projectId); headers.push_back("X-Appwrite-Key: " + apiKey); headers.push_back("Content-Type: application/json"); std::string response; - - int statusCode = Utils::patchRequest(url, payload, headers, response); + + int statusCode = Utils::patchRequest(url, payload, headers, response); if (statusCode == HttpStatus::OK) { return response; } else { - throw AppwriteException( - "Error updating push message. Status code: " + std::to_string(statusCode) + - "\n\nResponse: " + response); + throw AppwriteException("Error updating push message. Status code: " + + std::to_string(statusCode) + + "\n\nResponse: " + response); } } @@ -759,7 +764,9 @@ std::string Messaging::listMessageLogs(const std::string &messageId, if (statusCode == HttpStatus::OK) { return response; } else { - throw AppwriteException("Error listing message logs. Status code: " +std::to_string(statusCode) + "\nResponse: " + response); + throw AppwriteException("Error listing message logs. Status code: " + + std::to_string(statusCode) + + "\nResponse: " + response); } } @@ -781,13 +788,14 @@ std::string Messaging::deleteMessages(const std::string &messageId) { } } -std::string Messaging::listTargets(const std::string &messageId, +std::string Messaging::listTargets(const std::string &messageId, const std::vector &queries) { if (messageId.empty()) { throw AppwriteException("Missing required parameter: 'messageId'"); } - - std::string url = Config::API_BASE_URL + "/messaging/messages/" + messageId + "/targets"; + + std::string url = + Config::API_BASE_URL + "/messaging/messages/" + messageId + "/targets"; std::string queryParam = ""; if (!queries.empty()) { queryParam += "?queries[]=" + Utils::urlEncode(queries[0]); @@ -795,22 +803,20 @@ std::string Messaging::listTargets(const std::string &messageId, queryParam += "&queries[]=" + Utils::urlEncode(queries[i]); } } - + url += queryParam; - + std::vector headers = Config::getHeaders(projectId); headers.push_back("X-Appwrite-Key: " + apiKey); std::string response; int statusCode = Utils::getRequest(url, headers, response); - if (statusCode == HttpStatus::OK) { return response; } else { - throw AppwriteException("Error updating message. Status code: " + std::to_string(statusCode) + + throw AppwriteException("Error updating message. Status code: " + + std::to_string(statusCode) + "\n\nResponse: " + response); } } - - From aa0bfc3539675c26c9c34a936da74f25080bc336 Mon Sep 17 00:00:00 2001 From: Umesh Bhatt Date: Sat, 20 Sep 2025 14:24:26 +0530 Subject: [PATCH 3/3] changed hardcoded time to local time --- examples/messaging/messages/createSms.cpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/examples/messaging/messages/createSms.cpp b/examples/messaging/messages/createSms.cpp index 12d03a7..ad687b9 100644 --- a/examples/messaging/messages/createSms.cpp +++ b/examples/messaging/messages/createSms.cpp @@ -1,4 +1,5 @@ #include "Appwrite.hpp" +#include #include int main() { @@ -7,7 +8,7 @@ int main() { Appwrite appwrite(projectId, apiKey); - std::string messageId = "67b30694016a7eb8"; + std::string messageId = "6b309k4016e14b8"; std::string subject = "Hello from C++ Appwrite SDK!"; std::string content = "Testing SMS message creation with topics, users, and targets."; @@ -16,7 +17,18 @@ int main() { std::vector users = {}; std::vector targets = {}; - std::string scheduled_at = "2025-09-27 18:00:00.000"; + auto now = std::chrono::system_clock::now(); + auto future_time = now + std::chrono::minutes(5); + auto time_t = std::chrono::system_clock::to_time_t(future_time); + auto ms = std::chrono::duration_cast( + future_time.time_since_epoch()) % + 1000; + + std::stringstream ss; + ss << std::put_time(std::gmtime(&time_t), "%Y-%m-%dT%H:%M:%S"); + ss << "." << std::setfill('0') << std::setw(3) << ms.count() << "+00:00"; + std::string scheduled_at = ss.str(); + bool draft = true; try {