From 050b01a3ead4a9a0662a9f002065b8e2e8dec39b Mon Sep 17 00:00:00 2001 From: Tam Nguyen <98732550+softTam@users.noreply.github.com> Date: Fri, 30 Jun 2023 17:32:31 +0000 Subject: [PATCH 01/23] Added sendMessage in Kotlin folder --- kotlin/sendMessage/Index.kt | 0 kotlin/sendMessage/README.md | 0 kotlin/sendMessage/functions/sendEmailMailgun.kt | 0 kotlin/sendMessage/functions/sendMessageDiscordWebhook.kt | 0 kotlin/sendMessage/functions/sendSMSTwilio.kt | 0 kotlin/sendMessage/functions/sendTweet.kt | 0 6 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 kotlin/sendMessage/Index.kt create mode 100644 kotlin/sendMessage/README.md create mode 100644 kotlin/sendMessage/functions/sendEmailMailgun.kt create mode 100644 kotlin/sendMessage/functions/sendMessageDiscordWebhook.kt create mode 100644 kotlin/sendMessage/functions/sendSMSTwilio.kt create mode 100644 kotlin/sendMessage/functions/sendTweet.kt diff --git a/kotlin/sendMessage/Index.kt b/kotlin/sendMessage/Index.kt new file mode 100644 index 00000000..e69de29b diff --git a/kotlin/sendMessage/README.md b/kotlin/sendMessage/README.md new file mode 100644 index 00000000..e69de29b diff --git a/kotlin/sendMessage/functions/sendEmailMailgun.kt b/kotlin/sendMessage/functions/sendEmailMailgun.kt new file mode 100644 index 00000000..e69de29b diff --git a/kotlin/sendMessage/functions/sendMessageDiscordWebhook.kt b/kotlin/sendMessage/functions/sendMessageDiscordWebhook.kt new file mode 100644 index 00000000..e69de29b diff --git a/kotlin/sendMessage/functions/sendSMSTwilio.kt b/kotlin/sendMessage/functions/sendSMSTwilio.kt new file mode 100644 index 00000000..e69de29b diff --git a/kotlin/sendMessage/functions/sendTweet.kt b/kotlin/sendMessage/functions/sendTweet.kt new file mode 100644 index 00000000..e69de29b From d396222ec7b99eb00e51fd0b9760a0e7015d5809 Mon Sep 17 00:00:00 2001 From: jamesrcramos <76936793+jamesrcramos@users.noreply.github.com> Date: Thu, 6 Jul 2023 18:40:18 +0000 Subject: [PATCH 02/23] Added function headers to Index.kt file --- kotlin/sendMessage/Index.kt | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/kotlin/sendMessage/Index.kt b/kotlin/sendMessage/Index.kt index e69de29b..87228224 100644 --- a/kotlin/sendMessage/Index.kt +++ b/kotlin/sendMessage/Index.kt @@ -0,0 +1,24 @@ + + +fun sendEmailMailgun(variables: map, email: string, message: string, subject: string): RuntimeResponse{ + return res.json(mapOf( + "success" to true, + "message" to "You called sendEmailMailgun",)) +} + +fun sendMessageDiscordWebhook(variables: map, message: string): RuntimeResponse{ + return res.json(mapOf( + "success" to true, + "message" to "You called sendMessageDiscordWebhook")) +} + +fun sendSmsTwilio(variables: map, phoneNumber: string, message: string): RuntimeResponse{ + return res.json(mapOf( + "success" to true, + "message" to "You called sendSmsTwilio")) + +fun sendTweet(variables: map, message: string): RuntimeResponse{ + return res.json(mapOf( + "success" to true, + "message" to "You called sendTweet")) +} From 1f00f036fabdcf739a91481487a03aa69b3b44b0 Mon Sep 17 00:00:00 2001 From: Tam Nguyen <98732550+softTam@users.noreply.github.com> Date: Thu, 6 Jul 2023 18:58:55 +0000 Subject: [PATCH 03/23] Added main function, no input validator --- kotlin/sendMessage/Index-scratch.kt | 66 +++++++++++++++++++ kotlin/sendMessage/Index.kt | 59 +++++++++++++++++ .../sendMessage/functions/sendEmailMailgun.kt | 0 .../functions/sendMessageDiscordWebhook.kt | 0 kotlin/sendMessage/functions/sendSMSTwilio.kt | 0 kotlin/sendMessage/functions/sendTweet.kt | 0 6 files changed, 125 insertions(+) create mode 100644 kotlin/sendMessage/Index-scratch.kt delete mode 100644 kotlin/sendMessage/functions/sendEmailMailgun.kt delete mode 100644 kotlin/sendMessage/functions/sendMessageDiscordWebhook.kt delete mode 100644 kotlin/sendMessage/functions/sendSMSTwilio.kt delete mode 100644 kotlin/sendMessage/functions/sendTweet.kt diff --git a/kotlin/sendMessage/Index-scratch.kt b/kotlin/sendMessage/Index-scratch.kt new file mode 100644 index 00000000..dac78500 --- /dev/null +++ b/kotlin/sendMessage/Index-scratch.kt @@ -0,0 +1,66 @@ +//import things here +import com.google.gson.Gson +import com.google.gson.JsonSyntaxException +import io.openruntimes.kotlin.RuntimeRequest +import io.openruntimes.kotlin.RuntimeResponse +import java.io.BufferedReader +import java.io.IOException +import java.io.InputStreamReader +import java.io.OutputStream +import java.net.HttpURLConnection +import java.net.URL + +// fun sendEmailMailgun(variables: mutableMap, email: String, message: String, subject: String): RuntimeResponse +// { +// /*** Send email using Mailgun ***/ +// if (email.equals("") || message.equals("") || subject.equals("") +// { +// throw Exception("Missing email, message or subject") +// } + +// domain = variables["MAILGUN_DOMAIN"] +// api_key = variables["MAILGUN_API_KEY"] + +// if (domain.equals("")) +// throw Exception("Missing Mailgun domain") +// if (api_key.equals("")): +// throw Exception("Missing Mailgun API key") + +// try +// { + +// } +// catch (e: Exception) +// { + +// } +// } + +@Throws(Exception::class) +suspend fun main(req: RuntimeRequest, res: RuntimeResponse): RuntimeResponse +{ + //Start easy with Discord, assume no exceptions + var variables = req["VARIABLES"] + var webhook = variables["DISCORD_WEBHOOK_URL"] + var payload = req["payload"] + var type = payload["type"] + var message = payload["message"] + + //1. Open connection + val url = URL(webhook) + val conn: HttpURLConnection = url.openConnection() as HttpURLConnection + //2. Make a POST request + conn.requestMethod = "POST" + conn.addRequestProperty("Content-Type", "application/json") + conn.doOutput = true + //3. Parse/Handle the response (in progress...) + + //4. Clode connection and return message + conn.disconnect() + return res.json(mapOf( + "message" to "Test Part 3", + "success" to true, + "variabled" to req.variables, + "payload:))" to req.payload + )) +} \ No newline at end of file diff --git a/kotlin/sendMessage/Index.kt b/kotlin/sendMessage/Index.kt index e69de29b..de4ba477 100644 --- a/kotlin/sendMessage/Index.kt +++ b/kotlin/sendMessage/Index.kt @@ -0,0 +1,59 @@ +import com.google.gson.Gson +import com.google.gson.JsonSyntaxException +import io.openruntimes.kotlin.RuntimeRequest +import io.openruntimes.kotlin.RuntimeResponse +import java.io.BufferedReader +import java.io.IOException +import java.io.InputStreamReader +import java.io.OutputStream +import java.net.HttpURLConnection +import java.net.URL + +@Throws(Exception::class) +suspend fun main(req: RuntimeRequest, res: RuntimeResponse): RuntimeResponse +{ + var result: Map + try + { + //Convert JSON string "payload" to a map "payloadMap" + val payloadMap = Gson().fromJson>( + req.payload.ifBlank { "{}" }, + Map::class.java) + val payloadType = payloadMap["type"] + val message = payloadMap["message"] + + if (payloadType == "Email") + { + val receiver = payloadMap["receiver"] + val subject = payloadMap["subject"] + result = sendEmailMailgun(req.variables, receiver, message, subject) + } + else if (payloadType == "SMS") + { + val receiver = payloadMap["receiver"] + val result = sendSMSTwilio(req.variables, receiver, message) + } + else if (payloadType == "Discord") + { + result = sendMessageDiscord(req.variables, message) + } + else if (payloadType == "Twitter") + { + result = sendTweet(req.variables, message) + } + else + { + result = mapOf("success" to false, + "message" to "Invalid Type") + } + } + catch (e: Exception) + { + return res.json(mapOf( + "success" to false, + "message" to e.message, + )) + } + + return res.json(result) +} \ No newline at end of file diff --git a/kotlin/sendMessage/functions/sendEmailMailgun.kt b/kotlin/sendMessage/functions/sendEmailMailgun.kt deleted file mode 100644 index e69de29b..00000000 diff --git a/kotlin/sendMessage/functions/sendMessageDiscordWebhook.kt b/kotlin/sendMessage/functions/sendMessageDiscordWebhook.kt deleted file mode 100644 index e69de29b..00000000 diff --git a/kotlin/sendMessage/functions/sendSMSTwilio.kt b/kotlin/sendMessage/functions/sendSMSTwilio.kt deleted file mode 100644 index e69de29b..00000000 diff --git a/kotlin/sendMessage/functions/sendTweet.kt b/kotlin/sendMessage/functions/sendTweet.kt deleted file mode 100644 index e69de29b..00000000 From af23ab66da3854132920e143ac7d79a672f9bdb6 Mon Sep 17 00:00:00 2001 From: Tam Nguyen <98732550+softTam@users.noreply.github.com> Date: Thu, 6 Jul 2023 20:15:42 +0000 Subject: [PATCH 04/23] Fixed syntax errors; working main and helper fnctions --- kotlin/sendMessage/Index-scratch.kt | 74 +++++++++++++------------- kotlin/sendMessage/Index.kt | 82 +++++++++++++---------------- kotlin/sendMessage/deps.gradle | 3 ++ 3 files changed, 77 insertions(+), 82 deletions(-) create mode 100644 kotlin/sendMessage/deps.gradle diff --git a/kotlin/sendMessage/Index-scratch.kt b/kotlin/sendMessage/Index-scratch.kt index dac78500..ab375bdb 100644 --- a/kotlin/sendMessage/Index-scratch.kt +++ b/kotlin/sendMessage/Index-scratch.kt @@ -1,14 +1,14 @@ -//import things here -import com.google.gson.Gson -import com.google.gson.JsonSyntaxException -import io.openruntimes.kotlin.RuntimeRequest -import io.openruntimes.kotlin.RuntimeResponse -import java.io.BufferedReader -import java.io.IOException -import java.io.InputStreamReader -import java.io.OutputStream -import java.net.HttpURLConnection -import java.net.URL +// //import things here +// import com.google.gson.Gson +// import com.google.gson.JsonSyntaxException +// import io.openruntimes.kotlin.RuntimeRequest +// import io.openruntimes.kotlin.RuntimeResponse +// import java.io.BufferedReader +// import java.io.IOException +// import java.io.InputStreamReader +// import java.io.OutputStream +// import java.net.HttpURLConnection +// import java.net.URL // fun sendEmailMailgun(variables: mutableMap, email: String, message: String, subject: String): RuntimeResponse // { @@ -36,31 +36,31 @@ import java.net.URL // } // } -@Throws(Exception::class) -suspend fun main(req: RuntimeRequest, res: RuntimeResponse): RuntimeResponse -{ - //Start easy with Discord, assume no exceptions - var variables = req["VARIABLES"] - var webhook = variables["DISCORD_WEBHOOK_URL"] - var payload = req["payload"] - var type = payload["type"] - var message = payload["message"] +// @Throws(Exception::class) +// suspend fun main(req: RuntimeRequest, res: RuntimeResponse): RuntimeResponse +// { +// //Start easy with Discord, assume no exceptions +// var variables = req["VARIABLES"] +// var webhook = variables["DISCORD_WEBHOOK_URL"] +// var payload = req["payload"] +// var type = payload["type"] +// var message = payload["message"] - //1. Open connection - val url = URL(webhook) - val conn: HttpURLConnection = url.openConnection() as HttpURLConnection - //2. Make a POST request - conn.requestMethod = "POST" - conn.addRequestProperty("Content-Type", "application/json") - conn.doOutput = true - //3. Parse/Handle the response (in progress...) +// //1. Open connection +// val url = URL(webhook) +// val conn: HttpURLConnection = url.openConnection() as HttpURLConnection +// //2. Make a POST request +// conn.requestMethod = "POST" +// conn.addRequestProperty("Content-Type", "application/json") +// conn.doOutput = true +// //3. Parse/Handle the response (in progress...) - //4. Clode connection and return message - conn.disconnect() - return res.json(mapOf( - "message" to "Test Part 3", - "success" to true, - "variabled" to req.variables, - "payload:))" to req.payload - )) -} \ No newline at end of file +// //4. Clode connection and return message +// conn.disconnect() +// return res.json(mapOf( +// "message" to "Test Part 3", +// "success" to true, +// "variabled" to req.variables, +// "payload:))" to req.payload +// )) +// } \ No newline at end of file diff --git a/kotlin/sendMessage/Index.kt b/kotlin/sendMessage/Index.kt index ce60f46b..01e637b6 100644 --- a/kotlin/sendMessage/Index.kt +++ b/kotlin/sendMessage/Index.kt @@ -1,4 +1,3 @@ - import com.google.gson.Gson import com.google.gson.JsonSyntaxException import io.openruntimes.kotlin.RuntimeRequest @@ -10,66 +9,60 @@ import java.io.OutputStream import java.net.HttpURLConnection import java.net.URL -fun sendEmailMailgun(variables: map, email: string, message: string, subject: string): RuntimeResponse{ - return res.json(mapOf( - "success" to true, - "message" to "You called sendEmailMailgun",)) +fun sendEmailMailgun(variables: Map, email: String?, message: String?, subject: String?): Map{ + return mapOf("success" to true, + "message" to "You called sendEmailMailgun") } -fun sendMessageDiscordWebhook(variables: map, message: string): RuntimeResponse{ - return res.json(mapOf( - "success" to true, - "message" to "You called sendMessageDiscordWebhook")) +fun sendMessageDiscordWebhook(variables: Map, message: String?): Map{ + return mapOf("success" to true, + "message" to "You called sendMessageDiscordWebhook") } -fun sendSmsTwilio(variables: map, phoneNumber: string, message: string): RuntimeResponse{ - return res.json(mapOf( - "success" to true, - "message" to "You called sendSmsTwilio")) - -fun sendTweet(variables: map, message: string): RuntimeResponse{ - return res.json(mapOf( - "success" to true, - "message" to "You called sendTweet")) +fun sendSmsTwilio(variables: Map, receiver: String?, message: String?): Map{ + return mapOf("success" to true, + "message" to "You called sendSmsTwilio") } +fun sendTweet(variables: Map, message: String?): Map{ + return mapOf("success" to true, + "message" to "You called sendTweet") +} @Throws(Exception::class) -suspend fun main(req: RuntimeRequest, res: RuntimeResponse): RuntimeResponse +fun main(req: RuntimeRequest, res: RuntimeResponse): RuntimeResponse { - var result: Map + var result: Map = mapOf("" to "") try { - //Convert JSON string "payload" to a map "payloadMap" + //Convert JSON String "payload" to a Map "payloadMap" val payloadMap = Gson().fromJson>( req.payload.ifBlank { "{}" }, Map::class.java) val payloadType = payloadMap["type"] val message = payloadMap["message"] - if (payloadType == "Email") - { - val receiver = payloadMap["receiver"] - val subject = payloadMap["subject"] - result = sendEmailMailgun(req.variables, receiver, message, subject) - } - else if (payloadType == "SMS") - { - val receiver = payloadMap["receiver"] - val result = sendSMSTwilio(req.variables, receiver, message) - } - else if (payloadType == "Discord") + when (payloadType) { - result = sendMessageDiscord(req.variables, message) - } - else if (payloadType == "Twitter") - { - result = sendTweet(req.variables, message) - } - else - { - result = mapOf("success" to false, - "message" to "Invalid Type") + "Email" -> { + val receiver = payloadMap["receiver"] + val subject = payloadMap["subject"] + result = sendEmailMailgun(req.variables, receiver, message, subject) + } + "SMS" -> { + val receiver = payloadMap["receiver"] + result = sendSmsTwilio(req.variables, receiver, message) + } + "Discord" -> { + result = sendMessageDiscordWebhook(req.variables, message) + } + "Twitter" -> { + result = sendTweet(req.variables, message) + } + else -> { + result = mapOf("success" to false, + "message" to "Invalid Type") + } } } catch (e: Exception) @@ -79,6 +72,5 @@ suspend fun main(req: RuntimeRequest, res: RuntimeResponse): RuntimeResponse "message" to e.message, )) } - return res.json(result) -} +} \ No newline at end of file diff --git a/kotlin/sendMessage/deps.gradle b/kotlin/sendMessage/deps.gradle new file mode 100644 index 00000000..a2e7f58b --- /dev/null +++ b/kotlin/sendMessage/deps.gradle @@ -0,0 +1,3 @@ +dependencies { + implementation 'com.google.code.gson:gson:2.9.0' +} \ No newline at end of file From a34f7023431ee375f677464bfe924cf25f91d29c Mon Sep 17 00:00:00 2001 From: Tam Nguyen <98732550+softTam@users.noreply.github.com> Date: Fri, 7 Jul 2023 03:05:56 +0000 Subject: [PATCH 05/23] Added sendMessageDiscordWebhook function --- kotlin/sendMessage/Index-scratch.kt | 66 ------------------------ kotlin/sendMessage/Index.kt | 4 +- kotlin/sendMessage/sendMessageDiscord.kt | 25 +++++++++ 3 files changed, 27 insertions(+), 68 deletions(-) delete mode 100644 kotlin/sendMessage/Index-scratch.kt create mode 100644 kotlin/sendMessage/sendMessageDiscord.kt diff --git a/kotlin/sendMessage/Index-scratch.kt b/kotlin/sendMessage/Index-scratch.kt deleted file mode 100644 index ab375bdb..00000000 --- a/kotlin/sendMessage/Index-scratch.kt +++ /dev/null @@ -1,66 +0,0 @@ -// //import things here -// import com.google.gson.Gson -// import com.google.gson.JsonSyntaxException -// import io.openruntimes.kotlin.RuntimeRequest -// import io.openruntimes.kotlin.RuntimeResponse -// import java.io.BufferedReader -// import java.io.IOException -// import java.io.InputStreamReader -// import java.io.OutputStream -// import java.net.HttpURLConnection -// import java.net.URL - -// fun sendEmailMailgun(variables: mutableMap, email: String, message: String, subject: String): RuntimeResponse -// { -// /*** Send email using Mailgun ***/ -// if (email.equals("") || message.equals("") || subject.equals("") -// { -// throw Exception("Missing email, message or subject") -// } - -// domain = variables["MAILGUN_DOMAIN"] -// api_key = variables["MAILGUN_API_KEY"] - -// if (domain.equals("")) -// throw Exception("Missing Mailgun domain") -// if (api_key.equals("")): -// throw Exception("Missing Mailgun API key") - -// try -// { - -// } -// catch (e: Exception) -// { - -// } -// } - -// @Throws(Exception::class) -// suspend fun main(req: RuntimeRequest, res: RuntimeResponse): RuntimeResponse -// { -// //Start easy with Discord, assume no exceptions -// var variables = req["VARIABLES"] -// var webhook = variables["DISCORD_WEBHOOK_URL"] -// var payload = req["payload"] -// var type = payload["type"] -// var message = payload["message"] - -// //1. Open connection -// val url = URL(webhook) -// val conn: HttpURLConnection = url.openConnection() as HttpURLConnection -// //2. Make a POST request -// conn.requestMethod = "POST" -// conn.addRequestProperty("Content-Type", "application/json") -// conn.doOutput = true -// //3. Parse/Handle the response (in progress...) - -// //4. Clode connection and return message -// conn.disconnect() -// return res.json(mapOf( -// "message" to "Test Part 3", -// "success" to true, -// "variabled" to req.variables, -// "payload:))" to req.payload -// )) -// } \ No newline at end of file diff --git a/kotlin/sendMessage/Index.kt b/kotlin/sendMessage/Index.kt index 01e637b6..cf97e7db 100644 --- a/kotlin/sendMessage/Index.kt +++ b/kotlin/sendMessage/Index.kt @@ -15,8 +15,8 @@ fun sendEmailMailgun(variables: Map, email: String?, message: St } fun sendMessageDiscordWebhook(variables: Map, message: String?): Map{ - return mapOf("success" to true, - "message" to "You called sendMessageDiscordWebhook") + return mapOf("success" to true, + "message" to "You called sendMessageDiscordWebhook") } fun sendSmsTwilio(variables: Map, receiver: String?, message: String?): Map{ diff --git a/kotlin/sendMessage/sendMessageDiscord.kt b/kotlin/sendMessage/sendMessageDiscord.kt new file mode 100644 index 00000000..7bc1d82c --- /dev/null +++ b/kotlin/sendMessage/sendMessageDiscord.kt @@ -0,0 +1,25 @@ +fun sendMessageDiscordWebhook(variables: Map, message: String?): Map{ + val webhook = variables["DISCORD_WEBHOOK_URL"] + + val url = URL(webhook) + val conn: HttpURLConnection = url.openConnection() as HttpURLConnection + val body = "{\"content\":\"$message\"}" + conn.addRequestProperty("Content-Type", "application/json") + conn.requestMethod = "POST" + conn.doOutput = true + val os: OutputStream = conn.outputStream + val input: ByteArray = body.toByteArray(Charsets.UTF_8) + println(input) + os.write(input) + val responseCode: Int = conn.responseCode // To Check for 200 + os.close() + conn.disconnect() + if (responseCode / 100 == 2) { //HTTP code of 2xx means success (most of the time) + return mapOf("success" to true, + "message" to "You called sendMessageDiscordWebhook") + } + else { + return mapOf("success" to false, + "message" to conn.getResponseMessage()) + } +} \ No newline at end of file From 5d0b5ac6b6cfe5a9bcf9330382762bc0360ea90d Mon Sep 17 00:00:00 2001 From: jamesrcramos <76936793+jamesrcramos@users.noreply.github.com> Date: Fri, 7 Jul 2023 23:45:52 +0000 Subject: [PATCH 06/23] Added unfinished sendEmailMailgun.kt file; troubleshoot authentication to complete --- kotlin/sendMessage/sendEmailMailgun.kt | 77 ++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 kotlin/sendMessage/sendEmailMailgun.kt diff --git a/kotlin/sendMessage/sendEmailMailgun.kt b/kotlin/sendMessage/sendEmailMailgun.kt new file mode 100644 index 00000000..d2ae2c23 --- /dev/null +++ b/kotlin/sendMessage/sendEmailMailgun.kt @@ -0,0 +1,77 @@ +import java.util.Base64 + +fun sendEmailMailgun(variables: Map, email: String?, message: String?, subject: String?): Map{ + try { + if (email.isNullOrEmpty() || message.isNullOrEmpty() || subject.isNullOrEmpty()){ + throw Exception("Missing email, message, or subject") + } + } catch (e: Exception) { + println(e.message) + return mapOf("success" to false, + "message" to "sendEmailMailgun failed") + } + + val domain = variables["MAILGUN_DOMAIN"] + val apiKey = variables["MAILGUN_API_KEY"] + + try { + if (domain.isNullOrEmpty()){ + throw Exception("Missing Mailgun domain") + } + } catch (e: Exception) { + println(e.message) + return mapOf("success" to false, + "message" to "sendEmailMailgun failed") + } + + try { + if (apiKey.isNullOrEmpty()){ + throw Exception("Missing Mailgun API key") + } + } catch (e: Exception) { + println(e.message) + return mapOf("success" to false, + "message" to "sendEmailMailgun failed") + } + + try { + // URL for the Mailgun API endpoint + val url = URL({"https://api.mailgun.net/v3/$domain/messages"}) + + // authentication + val auth = "api:$apiKey" + + // initializing data to send + val email_data = "{\"from\":\"$domain\", \"to\":\"$email\", \"subject\":\"$subject\", \"text\":\"$message\"}" + + // opening the HTTP connection + val connection = url.openConnection() as HttpURLConnection + connection.doOutput = true + connection.requestMethod = "POST" + // setting request headers + authenticating the HTTP connection + connection.addRequestProperty("Authorization", "Basic " + Base64.getEncoder().encodeToString(auth.toByteArray())) + connection.addRequestProperty("Content-Type", "application/json") + + // make POST request + val outputStream: OutputStream = connection.outputStream + outputStream.write(email_data.toByteArray(Charsets.UTF_8)) + outputStream.flush() + + // check status of response + val responseCode = connection.responseCode + if (responseCode != HttpURLConnection.HTTP_OK) { + throw Exception("$responseCode") + } + + // housekeeping ; closing the open connection + outputSream.close() + connection.disconnect() + } catch (e: Exception) { + println(e.message) + return mapOf("success" to false, + "message" to "sendEmailMailgun failed") + } + + return mapOf("success" to true, + "message" to "You called sendEmailMailgun") +} \ No newline at end of file From 7a60348e95459e4cf79a9f255273c49a179af425 Mon Sep 17 00:00:00 2001 From: Arturo Date: Sat, 8 Jul 2023 00:04:10 +0000 Subject: [PATCH 07/23] Added sendMessageSMS kotlin file; in progress --- kotlin/sendMessage/sendMessageSMS | 55 +++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 kotlin/sendMessage/sendMessageSMS diff --git a/kotlin/sendMessage/sendMessageSMS b/kotlin/sendMessage/sendMessageSMS new file mode 100644 index 00000000..ed236eae --- /dev/null +++ b/kotlin/sendMessage/sendMessageSMS @@ -0,0 +1,55 @@ +import java.net.URLEncoder + +fun sendSmsTwilio(variables: Map, receiver: String?, message: String?): Map{ + + val accountID = variables.get("TWILIO_ACCOUNT_SID") + val auth_token = variables.get("TWILIO_AUTH_TOKEN") + val sender = variables.get("TWILIO_SENDER") + + + if (accountID == null || accountID.isEmpty()) { + return mapOf("success" to false, "message" to "Account ID is not set") + } + + if (auth_token == null || auth_token.isEmpty()) { + return mapOf("success" to false, "message" to "Auth token is not set") + } + + if (sender == null || sender.isEmpty()) { + return mapOf("success" to false, "message" to "Sender is not set") + } + + try { + val url = URL("https://api.twilio.com/2010-04-01/Accounts/$accountID/Messages.json") + val connection = url.openConnection() as HttpURLConnection + connection.doOutput = true + connection.requestMethod = "POST" + connection.setRequestProperty("Content-Type", "application/json") + connection.setRequestProperty("Authorization", "Basic ${URLEncoder.encode(auth_token, "UTF-8")}") + + + val postData = "{\"From\": \"$sender\", \"To\": \"$receiver\", \"Body\": \"$message\"}" + + + println(postData) + + val outputStream = connection.outputStream + outputStream.write(postData.toByteArray(Charsets.UTF_8)) + + val responseCode: Int = connection.responseCode + val responseMessage = connection.responseMessage + + outputStream.close() + connection.disconnect() + + if (responseCode != 200) { + return mapOf("success" to false, "message" to "Error: #$responseCode - > $responseMessage") + } + + return mapOf("success" to true, "message" to "Message sent!") + } catch (e: Exception) { + return mapOf("success" to false, "message" to "Error: ${e.message}") + } + + return mapOf("success" to true, "message" to "Message sent!") +} From cbc5ec560a71069b84548640283a9aa27cb03140 Mon Sep 17 00:00:00 2001 From: Arturo Date: Sat, 8 Jul 2023 00:08:08 +0000 Subject: [PATCH 08/23] Added sendMessageTwitter kotlin file; in progress --- kotlin/sendMessage/sendMessageTwitter.kt | 54 ++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 kotlin/sendMessage/sendMessageTwitter.kt diff --git a/kotlin/sendMessage/sendMessageTwitter.kt b/kotlin/sendMessage/sendMessageTwitter.kt new file mode 100644 index 00000000..df9a8d13 --- /dev/null +++ b/kotlin/sendMessage/sendMessageTwitter.kt @@ -0,0 +1,54 @@ +import java.net.URLEncoder + + +fun sendTweet(variables: Map, message: String?): Map { + val apiKey = variables["TWITTER_API_KEY"] + val apiSecret = variables["TWITTER_API_KEY_SECRET"] + val accessToken = variables["TWITTER_ACCESS_TOKEN"] + val accessTokenSecret = variables["TWITTER_ACCESS_TOKEN_SECRET"] + + if (apiKey.isNullOrEmpty()) { + return mapOf("success" to false, "message" to "Api Key is not set") + } + + if (apiSecret.isNullOrEmpty()) { + return mapOf("success" to false, "message" to "Api Secret is not set") + } + + if (accessToken.isNullOrEmpty()) { + return mapOf("success" to false, "message" to "Access Token is not set") + } + + if (accessTokenSecret.isNullOrEmpty()) { + return mapOf("success" to false, "message" to "Access Token Secret is not set") + } + + try { + val url = URL("https://api.twitter.com/1.1/statuses/update.json?") + val connection = url.openConnection() as HttpURLConnection + connection.doOutput = true + connection.requestMethod = "POST" + connection.setRequestProperty("Authorization", "Bearer ${URLEncoder.encode(accessToken, "UTF-8")}") + connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded") + connection.setRequestProperty("Accept", "application/json") + + val requestBody = "status=${URLEncoder.encode(message, "UTF-8")}" + + val outputStream = connection.outputStream + outputStream.write(requestBody.toByteArray(Charsets.UTF_8)) + outputStream.close() + + val responseCode = connection.responseCode + val responseMessage = connection.responseMessage + + if (responseCode != HttpURLConnection.HTTP_OK) { + return mapOf("success" to false, "message" to "Error: #$responseCode - > $responseMessage") + } + + connection.disconnect() + + return mapOf("success" to true, "message" to "Tweet sent!") + } catch (e: Exception) { + return mapOf("success" to false, "message" to "An unexpected error occurred: ${e.message}") + } +} \ No newline at end of file From a99371c69696d87d881e0d44374ce9f3749d1360 Mon Sep 17 00:00:00 2001 From: Arturo Date: Mon, 10 Jul 2023 02:04:34 +0000 Subject: [PATCH 09/23] Completed sendMessageSMS & error handling on main --- kotlin/sendMessage/Index.kt | 58 ++++++++++++++--------- kotlin/sendMessage/sendMessageSMS | 55 --------------------- kotlin/sendMessage/sendMessageSMS.kt | 71 ++++++++++++++++++++++++++++ 3 files changed, 107 insertions(+), 77 deletions(-) delete mode 100644 kotlin/sendMessage/sendMessageSMS create mode 100644 kotlin/sendMessage/sendMessageSMS.kt diff --git a/kotlin/sendMessage/Index.kt b/kotlin/sendMessage/Index.kt index cf97e7db..5241882b 100644 --- a/kotlin/sendMessage/Index.kt +++ b/kotlin/sendMessage/Index.kt @@ -30,47 +30,61 @@ fun sendTweet(variables: Map, message: String?): Map = mapOf("" to "") - try - { - //Convert JSON String "payload" to a Map "payloadMap" +fun main(req: RuntimeRequest, res: RuntimeResponse): RuntimeResponse { + var result: Map = emptyMap() + try { val payloadMap = Gson().fromJson>( req.payload.ifBlank { "{}" }, - Map::class.java) + Map::class.java + ) val payloadType = payloadMap["type"] val message = payloadMap["message"] - when (payloadType) - { + result = when (payloadType) { "Email" -> { val receiver = payloadMap["receiver"] val subject = payloadMap["subject"] - result = sendEmailMailgun(req.variables, receiver, message, subject) + sendEmailMailgun(req.variables, receiver, message, subject) } "SMS" -> { val receiver = payloadMap["receiver"] - result = sendSmsTwilio(req.variables, receiver, message) + sendSmsTwilio(req.variables, receiver, message) } "Discord" -> { - result = sendMessageDiscordWebhook(req.variables, message) + sendMessageDiscordWebhook(req.variables, message) } "Twitter" -> { - result = sendTweet(req.variables, message) + sendTweet(req.variables, message) } else -> { - result = mapOf("success" to false, - "message" to "Invalid Type") + mapOf( + "success" to false, + "message" to "Invalid Type" + ) } } + } catch (e: JsonSyntaxException) { // if payload is not a valid JSON or does not match the expected structure it will catch that + return res.json( + mapOf( + "success" to false, + "message" to "Invalid JSON payload" + ) + ) + } catch (e: IOException) { // if there is an issue with reading the payload from the request or writting the response it catches that + return res.json( + mapOf( + "success" to false, + "message" to "I/O error occurred" + ) + ) + } catch (e: Exception) { // if any other unhandled exception occurrs this catches that + return res.json( + mapOf( + "success" to false, + "message" to e.message + ) + ) } - catch (e: Exception) - { - return res.json(mapOf( - "success" to false, - "message" to e.message, - )) - } + return res.json(result) } \ No newline at end of file diff --git a/kotlin/sendMessage/sendMessageSMS b/kotlin/sendMessage/sendMessageSMS deleted file mode 100644 index ed236eae..00000000 --- a/kotlin/sendMessage/sendMessageSMS +++ /dev/null @@ -1,55 +0,0 @@ -import java.net.URLEncoder - -fun sendSmsTwilio(variables: Map, receiver: String?, message: String?): Map{ - - val accountID = variables.get("TWILIO_ACCOUNT_SID") - val auth_token = variables.get("TWILIO_AUTH_TOKEN") - val sender = variables.get("TWILIO_SENDER") - - - if (accountID == null || accountID.isEmpty()) { - return mapOf("success" to false, "message" to "Account ID is not set") - } - - if (auth_token == null || auth_token.isEmpty()) { - return mapOf("success" to false, "message" to "Auth token is not set") - } - - if (sender == null || sender.isEmpty()) { - return mapOf("success" to false, "message" to "Sender is not set") - } - - try { - val url = URL("https://api.twilio.com/2010-04-01/Accounts/$accountID/Messages.json") - val connection = url.openConnection() as HttpURLConnection - connection.doOutput = true - connection.requestMethod = "POST" - connection.setRequestProperty("Content-Type", "application/json") - connection.setRequestProperty("Authorization", "Basic ${URLEncoder.encode(auth_token, "UTF-8")}") - - - val postData = "{\"From\": \"$sender\", \"To\": \"$receiver\", \"Body\": \"$message\"}" - - - println(postData) - - val outputStream = connection.outputStream - outputStream.write(postData.toByteArray(Charsets.UTF_8)) - - val responseCode: Int = connection.responseCode - val responseMessage = connection.responseMessage - - outputStream.close() - connection.disconnect() - - if (responseCode != 200) { - return mapOf("success" to false, "message" to "Error: #$responseCode - > $responseMessage") - } - - return mapOf("success" to true, "message" to "Message sent!") - } catch (e: Exception) { - return mapOf("success" to false, "message" to "Error: ${e.message}") - } - - return mapOf("success" to true, "message" to "Message sent!") -} diff --git a/kotlin/sendMessage/sendMessageSMS.kt b/kotlin/sendMessage/sendMessageSMS.kt new file mode 100644 index 00000000..1e3ecdd5 --- /dev/null +++ b/kotlin/sendMessage/sendMessageSMS.kt @@ -0,0 +1,71 @@ +import java.io.IOException +import java.io.OutputStreamWriter +import java.net.HttpURLConnection +import java.net.URL +import java.nio.charset.StandardCharsets +import java.util.Base64 +import java.util.Map + + +fun sendSmsTwilio(variables: Map, receiver: String?, message: String?): Map{ + + val accountID = variables.get("TWILIO_ACCOUNT_SID") // Acount SID from Twilio + val authToken = variables.get("TWILIO_AUTH_TOKEN") // Auth Token from Twilio + val sender = variables.get("TWILIO_SENDER") // Sender Phone Number from Twilio | Mandatory format: +# ### ### #### (all together) + + + if (accountID.isNullOrEmpty()) { + return mapOf("success" to false, "message" to "Account ID is not set") + } + + if (authToken.isNullOrEmpty()) { + return mapOf("success" to false, "message" to "Auth token is not set") + } + + if (sender.isNullOrEmpty()) { + return mapOf("success" to false, "message" to "Sender is not set") + } + + if (receiver.isNullOrEmpty()) { + return mapOf("success" to false, "message" to "Receiver is not set") + } + if (message.isNullOrEmpty()) { + return mapOf("success" to false, "message" to "Message is not set") + } + + + try { + val urlString= "https://api.twilio.com/2010-04-01/Accounts/$accountID/Messages.json" + val url = URL(urlString) + val connection = url.openConnection() as HttpURLConnection + connection.requestMethod = "POST" + connection.doOutput = true + + val authString = "$accountID:$authToken " + val authEncoded = Base64.getEncoder().encodeToString(authString.toByteArray(StandardCharsets.UTF_8)) + connection.setRequestProperty("Authorization", "Basic $authEncoded") + + val postData = "To=$receiver&From=$sender&Body=$message" + + val outputStreamWriter = OutputStreamWriter(connection.outputStream) + outputStreamWriter.write(postData) + outputStreamWriter.flush() + + + val responseCode = connection.responseCode + val responseMessage = connection.responseMessage + + connection.disconnect() + + if (responseCode != HttpURLConnection.HTTP_CREATED) { // HttpURLConnection.HTTP_CREATED = 201 Created + return mapOf("success" to false, "message" to "Error: #$responseCode - > $responseMessage") + } + + return mapOf("success" to true, "message" to "Message sent!") + + } catch (e: IllegalArgumentException) { // if variable receiver is set to "invalid" + return mapOf("success" to false, "message" to "Error: ${e.message}") + } catch (e: IOException) { // if network-related issues such as failure to establish a connection or send the HTTP request to the Twilio APi this will catch it + return mapOf("success" to false, "message" to "Error: ${e.message}") + } +} From 51fdeb12813a37bcf36b6739b5cd410702fe17db Mon Sep 17 00:00:00 2001 From: jamesrcramos <76936793+jamesrcramos@users.noreply.github.com> Date: Mon, 10 Jul 2023 21:23:12 +0000 Subject: [PATCH 10/23] Created working version of Mailgun implementation --- kotlin/sendMessage/Index.kt | 3 ++ kotlin/sendMessage/sendEmailMailgun.kt | 53 ++++++++++++++++---------- 2 files changed, 36 insertions(+), 20 deletions(-) diff --git a/kotlin/sendMessage/Index.kt b/kotlin/sendMessage/Index.kt index 5241882b..925f4c36 100644 --- a/kotlin/sendMessage/Index.kt +++ b/kotlin/sendMessage/Index.kt @@ -8,12 +8,15 @@ import java.io.InputStreamReader import java.io.OutputStream import java.net.HttpURLConnection import java.net.URL +import java.util.Base64 +import java.nio.charset.StandardCharsets fun sendEmailMailgun(variables: Map, email: String?, message: String?, subject: String?): Map{ return mapOf("success" to true, "message" to "You called sendEmailMailgun") } + fun sendMessageDiscordWebhook(variables: Map, message: String?): Map{ return mapOf("success" to true, "message" to "You called sendMessageDiscordWebhook") diff --git a/kotlin/sendMessage/sendEmailMailgun.kt b/kotlin/sendMessage/sendEmailMailgun.kt index d2ae2c23..9cacf9e4 100644 --- a/kotlin/sendMessage/sendEmailMailgun.kt +++ b/kotlin/sendMessage/sendEmailMailgun.kt @@ -1,6 +1,8 @@ import java.util.Base64 +import java.nio.charset.StandardCharsets fun sendEmailMailgun(variables: Map, email: String?, message: String?, subject: String?): Map{ + // validating email, message, and subject arguments try { if (email.isNullOrEmpty() || message.isNullOrEmpty() || subject.isNullOrEmpty()){ throw Exception("Missing email, message, or subject") @@ -8,12 +10,14 @@ fun sendEmailMailgun(variables: Map, email: String?, message: St } catch (e: Exception) { println(e.message) return mapOf("success" to false, - "message" to "sendEmailMailgun failed") + "message" to "sendEmailMailgun failed") } + // initializing variables needed for HTTP request val domain = variables["MAILGUN_DOMAIN"] val apiKey = variables["MAILGUN_API_KEY"] - + + // validating Mailgun domain try { if (domain.isNullOrEmpty()){ throw Exception("Missing Mailgun domain") @@ -21,9 +25,10 @@ fun sendEmailMailgun(variables: Map, email: String?, message: St } catch (e: Exception) { println(e.message) return mapOf("success" to false, - "message" to "sendEmailMailgun failed") + "message" to "sendEmailMailgun failed") } - + + // validating Mailgun API key try { if (apiKey.isNullOrEmpty()){ throw Exception("Missing Mailgun API key") @@ -31,47 +36,55 @@ fun sendEmailMailgun(variables: Map, email: String?, message: St } catch (e: Exception) { println(e.message) return mapOf("success" to false, - "message" to "sendEmailMailgun failed") + "message" to "sendEmailMailgun failed") } + // making the HTTP POST request try { // URL for the Mailgun API endpoint - val url = URL({"https://api.mailgun.net/v3/$domain/messages"}) + val url = URL("https://api.mailgun.net/v3/$domain/messages") // authentication val auth = "api:$apiKey" + val authEncoded = Base64.getEncoder().encodeToString(auth.toByteArray(StandardCharsets.UTF_8)) // initializing data to send - val email_data = "{\"from\":\"$domain\", \"to\":\"$email\", \"subject\":\"$subject\", \"text\":\"$message\"}" - - // opening the HTTP connection + //val emailData = "{\"from\":\"$domain\", \"to\":\"$email\", \"subject\":\"$subject\", \"text\":\"$message\"}" + val emailData = "from=&to=$email&subject=$subject&text=$message" + + // opening the HTTP connection val connection = url.openConnection() as HttpURLConnection connection.doOutput = true connection.requestMethod = "POST" + // setting request headers + authenticating the HTTP connection - connection.addRequestProperty("Authorization", "Basic " + Base64.getEncoder().encodeToString(auth.toByteArray())) - connection.addRequestProperty("Content-Type", "application/json") + connection.addRequestProperty("Authorization", "Basic $authEncoded") - // make POST request + // making POST request + // val outputStreamWriter = OutputStreamWriter(connection.outputStream) + // outputStreamWriter.write(emailData) + // outputStreamWriter.flush() val outputStream: OutputStream = connection.outputStream - outputStream.write(email_data.toByteArray(Charsets.UTF_8)) + outputStream.write(emailData.toByteArray(Charsets.UTF_8)) outputStream.flush() - // check status of response + // checking status of response val responseCode = connection.responseCode + val responseMessage = connection.responseMessage + println(responseMessage) if (responseCode != HttpURLConnection.HTTP_OK) { throw Exception("$responseCode") } - + // housekeeping ; closing the open connection - outputSream.close() + //outputStreamWriter.close() connection.disconnect() + } catch (e: Exception) { println(e.message) return mapOf("success" to false, - "message" to "sendEmailMailgun failed") + "message" to "sendEmailMailgun failed") } - return mapOf("success" to true, - "message" to "You called sendEmailMailgun") -} \ No newline at end of file + "message" to "You called sendEmailMailgun") +} From c3feaff1fbe3053639a6f9b56d93d508bb0ee568 Mon Sep 17 00:00:00 2001 From: jamesrcramos <76936793+jamesrcramos@users.noreply.github.com> Date: Tue, 11 Jul 2023 17:40:40 +0000 Subject: [PATCH 11/23] Improved function formatting and return statements --- kotlin/sendMessage/Index.kt | 7 ++ kotlin/sendMessage/sendEmailMailgun.kt | 100 +++++++------------------ 2 files changed, 33 insertions(+), 74 deletions(-) diff --git a/kotlin/sendMessage/Index.kt b/kotlin/sendMessage/Index.kt index 925f4c36..7f33f67a 100644 --- a/kotlin/sendMessage/Index.kt +++ b/kotlin/sendMessage/Index.kt @@ -11,6 +11,13 @@ import java.net.URL import java.util.Base64 import java.nio.charset.StandardCharsets +fun getErrorResponseWithMessage(message: String? = "Some error occurred"): Map { + return mapOf{ + "success" to false, + "message" to message.toString() + } +} + fun sendEmailMailgun(variables: Map, email: String?, message: String?, subject: String?): Map{ return mapOf("success" to true, "message" to "You called sendEmailMailgun") diff --git a/kotlin/sendMessage/sendEmailMailgun.kt b/kotlin/sendMessage/sendEmailMailgun.kt index 9cacf9e4..f0b3cef9 100644 --- a/kotlin/sendMessage/sendEmailMailgun.kt +++ b/kotlin/sendMessage/sendEmailMailgun.kt @@ -2,89 +2,41 @@ import java.util.Base64 import java.nio.charset.StandardCharsets fun sendEmailMailgun(variables: Map, email: String?, message: String?, subject: String?): Map{ - // validating email, message, and subject arguments - try { - if (email.isNullOrEmpty() || message.isNullOrEmpty() || subject.isNullOrEmpty()){ - throw Exception("Missing email, message, or subject") - } - } catch (e: Exception) { - println(e.message) - return mapOf("success" to false, - "message" to "sendEmailMailgun failed") + if (email.isNullOrEmpty() || message.isNullOrEmpty() || subject.isNullOrEmpty()){ + return getErrorResponseWithMessage("Missing email, message, or subject") } - // initializing variables needed for HTTP request val domain = variables["MAILGUN_DOMAIN"] val apiKey = variables["MAILGUN_API_KEY"] - // validating Mailgun domain - try { - if (domain.isNullOrEmpty()){ - throw Exception("Missing Mailgun domain") - } - } catch (e: Exception) { - println(e.message) - return mapOf("success" to false, - "message" to "sendEmailMailgun failed") + if (domain.isNullOrEmpty()){ + return getErrorResponseWithMessage("Missing Mailgun domain") } - - // validating Mailgun API key - try { - if (apiKey.isNullOrEmpty()){ - throw Exception("Missing Mailgun API key") - } - } catch (e: Exception) { - println(e.message) - return mapOf("success" to false, - "message" to "sendEmailMailgun failed") + if (apiKey.isNullOrEmpty()){ + return getErrorResponseWithMessage("Missing Mailgun API key") } - // making the HTTP POST request - try { - // URL for the Mailgun API endpoint - val url = URL("https://api.mailgun.net/v3/$domain/messages") - - // authentication - val auth = "api:$apiKey" - val authEncoded = Base64.getEncoder().encodeToString(auth.toByteArray(StandardCharsets.UTF_8)) - - // initializing data to send - //val emailData = "{\"from\":\"$domain\", \"to\":\"$email\", \"subject\":\"$subject\", \"text\":\"$message\"}" - val emailData = "from=&to=$email&subject=$subject&text=$message" - - // opening the HTTP connection - val connection = url.openConnection() as HttpURLConnection - connection.doOutput = true - connection.requestMethod = "POST" - - // setting request headers + authenticating the HTTP connection - connection.addRequestProperty("Authorization", "Basic $authEncoded") - - // making POST request - // val outputStreamWriter = OutputStreamWriter(connection.outputStream) - // outputStreamWriter.write(emailData) - // outputStreamWriter.flush() - val outputStream: OutputStream = connection.outputStream - outputStream.write(emailData.toByteArray(Charsets.UTF_8)) - outputStream.flush() - - // checking status of response - val responseCode = connection.responseCode - val responseMessage = connection.responseMessage - println(responseMessage) - if (responseCode != HttpURLConnection.HTTP_OK) { - throw Exception("$responseCode") - } - - // housekeeping ; closing the open connection - //outputStreamWriter.close() - connection.disconnect() - - } catch (e: Exception) { - println(e.message) - return mapOf("success" to false, - "message" to "sendEmailMailgun failed") + val url = URL("https://api.mailgun.net/v3/$domain/messages") + val auth = "api:$apiKey" + val authEncoded = Base64.getEncoder().encodeToString(auth.toByteArray(StandardCharsets.UTF_8)) + val emailData = "from=&to=$email&subject=$subject&text=$message" + + val connection = url.openConnection() as HttpURLConnection + connection.doOutput = true + connection.requestMethod = "POST" + connection.addRequestProperty("Authorization", "Basic $authEncoded") + + val outputStream: OutputStream = connection.outputStream + outputStream.write(emailData.toByteArray(Charsets.UTF_8)) + outputStream.flush() + + val responseCode = connection.responseCode + val responseMessage = connection.responseMessage + connection.disconnect() + if (responseCode != HttpURLConnection.HTTP_OK) { + return getErrorResponseWithMessage("$responseCode - $responseMessage") } + return mapOf("success" to true, "message" to "You called sendEmailMailgun") } From c5e7e39a68f9f8992226e4a3409a0364f7e4ee3c Mon Sep 17 00:00:00 2001 From: Tam Nguyen <98732550+softTam@users.noreply.github.com> Date: Tue, 11 Jul 2023 18:21:04 +0000 Subject: [PATCH 12/23] Draft. Commit for the purpose of pulling from origin --- kotlin/sendMessage/Index.kt | 157 +++++++++++++++++- kotlin/sendMessage/deps.gradle | 1 + kotlin/sendMessage/sendMessageDiscord.kt | 25 --- .../sendEmailMailgun.kt | 0 .../sendMessageHelper/sendMessageDiscord.kt | 41 +++++ .../sendMessageSMS.kt | 0 .../sendMessageTwitter.kt | 21 ++- 7 files changed, 210 insertions(+), 35 deletions(-) delete mode 100644 kotlin/sendMessage/sendMessageDiscord.kt rename kotlin/{sendMessage => sendMessageHelper}/sendEmailMailgun.kt (100%) create mode 100644 kotlin/sendMessageHelper/sendMessageDiscord.kt rename kotlin/{sendMessage => sendMessageHelper}/sendMessageSMS.kt (100%) rename kotlin/{sendMessage => sendMessageHelper}/sendMessageTwitter.kt (67%) diff --git a/kotlin/sendMessage/Index.kt b/kotlin/sendMessage/Index.kt index 5241882b..09a3fa8e 100644 --- a/kotlin/sendMessage/Index.kt +++ b/kotlin/sendMessage/Index.kt @@ -8,6 +8,26 @@ import java.io.InputStreamReader import java.io.OutputStream import java.net.HttpURLConnection import java.net.URL +import java.nio.charset.StandardCharsets +import java.util.Base64 +import java.io.OutputStreamWriter +//Tweeter deps below +import com.chromasgaming.ktweet.constants.VERSION +import com.chromasgaming.ktweet.models.* +// import com.chromasgaming.ktweet.models.Tweet +import com.chromasgaming.ktweet.oauth.SignatureBuilder +import com.chromasgaming.ktweet.oauth.buildSignature +import kotlinx.coroutines.runBlocking +import kotlinx.serialization.ExperimentalSerializationApi +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test + +fun getErrorResponseWithMessage(message: String? = "Some error occurred"): Map { + return mapOf( + "success" to false, + "message" to message.toString() + ) +} fun sendEmailMailgun(variables: Map, email: String?, message: String?, subject: String?): Map{ return mapOf("success" to true, @@ -15,18 +35,143 @@ fun sendEmailMailgun(variables: Map, email: String?, message: St } fun sendMessageDiscordWebhook(variables: Map, message: String?): Map{ - return mapOf("success" to true, - "message" to "You called sendMessageDiscordWebhook") + val webhook = variables["DISCORD_WEBHOOK_URL"]?:"" + + try { + if (webhook.isEmpty() || webhook.trim().isEmpty()) { + return getErrorResponseWithMessage("Payload doesn't contain a Discord Webhook URL") + } + + // println(webhook) //************ */ + val url = URL(webhook) + + val conn: HttpURLConnection = url.openConnection() as HttpURLConnection + val body = "{\"content\":\"$message\"}" + conn.addRequestProperty("Content-Type", "application/json") + conn.requestMethod = "POST" + conn.doOutput = true + + val os: OutputStream = conn.outputStream + val input: ByteArray = body.toByteArray(Charsets.UTF_8) + // println(input) //********** */ + os.write(input) + + val responseCode: Int = conn.responseCode // To Check for 200 + // println(responseCode) //************ */ + os.close() + conn.disconnect() + if (responseCode / 100 == 2) { //HTTP code of 2xx means success (most of the time) + return mapOf("success" to true, + "message" to "You called sendMessageDiscordWebhook") + } + else { + return getErrorResponseWithMessage(conn.getResponseMessage()) + // return mapOf("success" to false, + // "message" to conn.getResponseMessage()) + } + + } catch (e: IllegalArgumentException) { // if variable receiver is set to "invalid" + // println("First was executed") + return getErrorResponseWithMessage(e.message) + // return mapOf("success" to false, "message" to "Error: ${e.message}") + } catch (e: IOException) { // if network-related issues such as failure to establish a connection or send the HTTP request to the Twilio APi this will catch it + // println("Second was executed") + return getErrorResponseWithMessage(e.message) + // return mapOf("success" to false, "message" to "Error: ${e.message}") + } } fun sendSmsTwilio(variables: Map, receiver: String?, message: String?): Map{ - return mapOf("success" to true, - "message" to "You called sendSmsTwilio") + + val accountID = variables.get("TWILIO_ACCOUNT_SID") // Acount SID from Twilio + val authToken = variables.get("TWILIO_AUTH_TOKEN") // Auth Token from Twilio + val sender = variables.get("TWILIO_SENDER") // Sender Phone Number from Twilio | Mandatory format: +# ### ### #### (all together) + + + if (accountID.isNullOrEmpty()) { + return mapOf("success" to false, "message" to "Account ID is not set") + } + + if (authToken.isNullOrEmpty()) { + return mapOf("success" to false, "message" to "Auth token is not set") + } + + if (sender.isNullOrEmpty()) { + return mapOf("success" to false, "message" to "Sender is not set") + } + + if (receiver.isNullOrEmpty()) { + return mapOf("success" to false, "message" to "Receiver is not set") + } + if (message.isNullOrEmpty()) { + return mapOf("success" to false, "message" to "Message is not set") + } + + + try { + val urlString= "https://api.twilio.com/2010-04-01/Accounts/$accountID/Messages.json" + val url = URL(urlString) + val connection = url.openConnection() as HttpURLConnection + connection.requestMethod = "POST" + connection.doOutput = true + + val authString = "$accountID:$authToken " + val authEncoded = Base64.getEncoder().encodeToString(authString.toByteArray(StandardCharsets.UTF_8)) + connection.setRequestProperty("Authorization", "Basic $authEncoded") + + val postData = "To=$receiver&From=$sender&Body=$message" + + val outputStreamWriter = OutputStreamWriter(connection.outputStream) + outputStreamWriter.write(postData) + outputStreamWriter.flush() + + + val responseCode = connection.responseCode + val responseMessage = connection.responseMessage + + connection.disconnect() + + if (responseCode != HttpURLConnection.HTTP_CREATED) { // HttpURLConnection.HTTP_CREATED = 201 Created + return mapOf("success" to false, "message" to "Error: #$responseCode - > $responseMessage") + } + + return mapOf("success" to true, "message" to "Message sent!") + + } catch (e: IllegalArgumentException) { // if variable receiver is set to "invalid" + return mapOf("success" to false, "message" to "Error: ${e.message}") + } catch (e: IOException) { // if network-related issues such as failure to establish a connection or send the HTTP request to the Twilio APi this will catch it + return mapOf("success" to false, "message" to "Error: ${e.message}") + } } fun sendTweet(variables: Map, message: String?): Map{ - return mapOf("success" to true, - "message" to "You called sendTweet") + val apiKey = variables["TWITTER_API_KEY"] + val apiSecret = variables["TWITTER_API_KEY_SECRET"] + val accessToken = variables["TWITTER_ACCESS_TOKEN"] + val accessTokenSecret = variables["TWITTER_ACCESS_TOKEN_SECRET"] + + var post: ManageTweets + manageTweets = ManageTweetsAPI() + + signatureBuilder = SignatureBuilder.Builder() + .oauthConsumerKey(apiKey) + .oauthConsumerSecret(apiSecret) + .accessToken(accessToken) + .accessTokenSecret(accessTokenSecret) + .build() + + authorizationHeaderString = buildSignature( + "POST", + signatureBuilder, + "$VERSION/tweets", + emptyMap() + ) + + val tweet = Tweet(message) + post = manageTweets.create(tweet, authorizationHeaderString) + /*How can I use to check if the request was sucessful??? + Seems like it's a JSON object; represents the body response*/ + return mapOf("success" to true, "message" to post.text) } @Throws(Exception::class) diff --git a/kotlin/sendMessage/deps.gradle b/kotlin/sendMessage/deps.gradle index a2e7f58b..3ab72166 100644 --- a/kotlin/sendMessage/deps.gradle +++ b/kotlin/sendMessage/deps.gradle @@ -1,3 +1,4 @@ dependencies { implementation 'com.google.code.gson:gson:2.9.0' + implementation("com.chromasgaming:ktweet:1.3.0") } \ No newline at end of file diff --git a/kotlin/sendMessage/sendMessageDiscord.kt b/kotlin/sendMessage/sendMessageDiscord.kt deleted file mode 100644 index 7bc1d82c..00000000 --- a/kotlin/sendMessage/sendMessageDiscord.kt +++ /dev/null @@ -1,25 +0,0 @@ -fun sendMessageDiscordWebhook(variables: Map, message: String?): Map{ - val webhook = variables["DISCORD_WEBHOOK_URL"] - - val url = URL(webhook) - val conn: HttpURLConnection = url.openConnection() as HttpURLConnection - val body = "{\"content\":\"$message\"}" - conn.addRequestProperty("Content-Type", "application/json") - conn.requestMethod = "POST" - conn.doOutput = true - val os: OutputStream = conn.outputStream - val input: ByteArray = body.toByteArray(Charsets.UTF_8) - println(input) - os.write(input) - val responseCode: Int = conn.responseCode // To Check for 200 - os.close() - conn.disconnect() - if (responseCode / 100 == 2) { //HTTP code of 2xx means success (most of the time) - return mapOf("success" to true, - "message" to "You called sendMessageDiscordWebhook") - } - else { - return mapOf("success" to false, - "message" to conn.getResponseMessage()) - } -} \ No newline at end of file diff --git a/kotlin/sendMessage/sendEmailMailgun.kt b/kotlin/sendMessageHelper/sendEmailMailgun.kt similarity index 100% rename from kotlin/sendMessage/sendEmailMailgun.kt rename to kotlin/sendMessageHelper/sendEmailMailgun.kt diff --git a/kotlin/sendMessageHelper/sendMessageDiscord.kt b/kotlin/sendMessageHelper/sendMessageDiscord.kt new file mode 100644 index 00000000..0eb9a96c --- /dev/null +++ b/kotlin/sendMessageHelper/sendMessageDiscord.kt @@ -0,0 +1,41 @@ +fun sendMessageDiscordWebhook(variables: Map, message: String?): Map{ + val webhook = variables["DISCORD_WEBHOOK_URL"]?:"" + + try { + if (webhook.isEmpty() || webhook.trim().isEmpty()) { + return getErrorResponseWithMessage(res, "Payload doesn't contain a Discord Webhook URL") + } + + val url = URL(webhook) + + val conn: HttpURLConnection = url.openConnection() as HttpURLConnection + val body = "{\"content\":\"$message\"}" + // conn.addRequestProperty("Content-Type", "application/json") + conn.requestMethod = "POST" + conn.doOutput = true + + val os: OutputStream = conn.outputStream + val input: ByteArray = body.toByteArray(Charsets.UTF_8) + // println(input) + os.write(input) + + val responseCode: Int = conn.responseCode // To Check for 200 + os.close() + conn.disconnect() + if (responseCode / 100 == 2) { //HTTP code of 2xx means success (most of the time) + return mapOf("success" to true, + "message" to "You called sendMessageDiscordWebhook") + } + else { + return getErrorResponseWithMessage(res, conn.getResponseMessage()) + // return mapOf("success" to false, + // "message" to conn.getResponseMessage()) + } + } catch (e: IllegalArgumentException) { // if variable receiver is set to "invalid" + return getErrorResponseWithMessage(res, e.message) + // return mapOf("success" to false, "message" to "Error: ${e.message}") + } catch (e: IOException) { // if network-related issues such as failure to establish a connection or send the HTTP request to the Twilio APi this will catch it + return getErrorResponseWithMessage(res, e.message) + // return mapOf("success" to false, "message" to "Error: ${e.message}") + } +} \ No newline at end of file diff --git a/kotlin/sendMessage/sendMessageSMS.kt b/kotlin/sendMessageHelper/sendMessageSMS.kt similarity index 100% rename from kotlin/sendMessage/sendMessageSMS.kt rename to kotlin/sendMessageHelper/sendMessageSMS.kt diff --git a/kotlin/sendMessage/sendMessageTwitter.kt b/kotlin/sendMessageHelper/sendMessageTwitter.kt similarity index 67% rename from kotlin/sendMessage/sendMessageTwitter.kt rename to kotlin/sendMessageHelper/sendMessageTwitter.kt index df9a8d13..ec10d060 100644 --- a/kotlin/sendMessage/sendMessageTwitter.kt +++ b/kotlin/sendMessageHelper/sendMessageTwitter.kt @@ -1,5 +1,18 @@ import java.net.URLEncoder +import com.chromasgaming.ktweet.api //for creating a Tweet post +import com.chromasgaming.ktweet.models //for creating a Tweet object +tweet: Tweet = Tweet(message) +authorizationHeaderString: String = + +/* Authorization reference: + header 'Authorization: OAuth oauth_consumer_key="CONSUMER_API_KEY", + oauth_nonce="OAUTH_NONCE", + oauth_signature="OAUTH_SIGNATURE", + oauth_signature_method="HMAC-SHA1", + oauth_timestamp="OAUTH_TIMESTAMP", + oauth_token="ACCESS_TOKEN", + oauth_version="1.0"' */ fun sendTweet(variables: Map, message: String?): Map { val apiKey = variables["TWITTER_API_KEY"] @@ -8,19 +21,19 @@ fun sendTweet(variables: Map, message: String?): Map Date: Tue, 11 Jul 2023 19:38:47 +0000 Subject: [PATCH 13/23] Moved sendEmail function to Index.kt and minor syntax improvements and fixes --- kotlin/sendMessage/Index.kt | 69 +++++++++++++-------- sendMessageFunctions/sendEmailMailgun.kt | 42 +++++++++++++ sendMessageFunctions/sendMessageDiscord.kt | 25 ++++++++ sendMessageFunctions/sendMessageSMS.kt | 71 ++++++++++++++++++++++ sendMessageFunctions/sendMessageTwitter.kt | 54 ++++++++++++++++ 5 files changed, 236 insertions(+), 25 deletions(-) create mode 100644 sendMessageFunctions/sendEmailMailgun.kt create mode 100644 sendMessageFunctions/sendMessageDiscord.kt create mode 100644 sendMessageFunctions/sendMessageSMS.kt create mode 100644 sendMessageFunctions/sendMessageTwitter.kt diff --git a/kotlin/sendMessage/Index.kt b/kotlin/sendMessage/Index.kt index 7f33f67a..588a5762 100644 --- a/kotlin/sendMessage/Index.kt +++ b/kotlin/sendMessage/Index.kt @@ -12,18 +12,52 @@ import java.util.Base64 import java.nio.charset.StandardCharsets fun getErrorResponseWithMessage(message: String? = "Some error occurred"): Map { - return mapOf{ + return mapOf( "success" to false, "message" to message.toString() - } + ) } fun sendEmailMailgun(variables: Map, email: String?, message: String?, subject: String?): Map{ + if (email.isNullOrEmpty() || message.isNullOrEmpty() || subject.isNullOrEmpty()){ + return getErrorResponseWithMessage("Missing email, message, or subject") + } + + val domain = variables["MAILGUN_DOMAIN"] + val apiKey = variables["MAILGUN_API_KEY"] + + if (domain.isNullOrEmpty()){ + return getErrorResponseWithMessage("Missing Mailgun domain") + } + if (apiKey.isNullOrEmpty()){ + return getErrorResponseWithMessage("Missing Mailgun API key") + } + + val url = URL("https://api.mailgun.net/v3/$domain/messages") + val auth = "api:$apiKey" + val authEncoded = Base64.getEncoder().encodeToString(auth.toByteArray(StandardCharsets.UTF_8)) + val emailData = "from=&to=$email&subject=$subject&text=$message" + + val connection = url.openConnection() as HttpURLConnection + connection.doOutput = true + connection.requestMethod = "POST" + connection.addRequestProperty("Authorization", "Basic $authEncoded") + + val outputStream: OutputStream = connection.outputStream + outputStream.write(emailData.toByteArray(Charsets.UTF_8)) + outputStream.flush() + + val responseCode = connection.responseCode + val responseMessage = connection.responseMessage + connection.disconnect() + if (responseCode != HttpURLConnection.HTTP_OK) { + return getErrorResponseWithMessage("$responseCode - $responseMessage") + } + return mapOf("success" to true, - "message" to "You called sendEmailMailgun") + "message" to "You called sendEmailMailgun") } - fun sendMessageDiscordWebhook(variables: Map, message: String?): Map{ return mapOf("success" to true, "message" to "You called sendMessageDiscordWebhook") @@ -73,27 +107,12 @@ fun main(req: RuntimeRequest, res: RuntimeResponse): RuntimeResponse { ) } } - } catch (e: JsonSyntaxException) { // if payload is not a valid JSON or does not match the expected structure it will catch that - return res.json( - mapOf( - "success" to false, - "message" to "Invalid JSON payload" - ) - ) - } catch (e: IOException) { // if there is an issue with reading the payload from the request or writting the response it catches that - return res.json( - mapOf( - "success" to false, - "message" to "I/O error occurred" - ) - ) - } catch (e: Exception) { // if any other unhandled exception occurrs this catches that - return res.json( - mapOf( - "success" to false, - "message" to e.message - ) - ) + } catch (e: JsonSyntaxException) { // if the payload is not a valid JSON or does not match the expected structure + result = getErrorResponseWithMessage("Invalid JSON payload") + } catch (e: IOException) { // if there is an issue with reading the payload from the request or writting the response + result = getErrorResponseWithMessage("I/O error occurred") + } catch (e: Exception) { + result = getErrorResponseWithMessage("$e.message") } return res.json(result) diff --git a/sendMessageFunctions/sendEmailMailgun.kt b/sendMessageFunctions/sendEmailMailgun.kt new file mode 100644 index 00000000..f0b3cef9 --- /dev/null +++ b/sendMessageFunctions/sendEmailMailgun.kt @@ -0,0 +1,42 @@ +import java.util.Base64 +import java.nio.charset.StandardCharsets + +fun sendEmailMailgun(variables: Map, email: String?, message: String?, subject: String?): Map{ + if (email.isNullOrEmpty() || message.isNullOrEmpty() || subject.isNullOrEmpty()){ + return getErrorResponseWithMessage("Missing email, message, or subject") + } + + val domain = variables["MAILGUN_DOMAIN"] + val apiKey = variables["MAILGUN_API_KEY"] + + if (domain.isNullOrEmpty()){ + return getErrorResponseWithMessage("Missing Mailgun domain") + } + if (apiKey.isNullOrEmpty()){ + return getErrorResponseWithMessage("Missing Mailgun API key") + } + + val url = URL("https://api.mailgun.net/v3/$domain/messages") + val auth = "api:$apiKey" + val authEncoded = Base64.getEncoder().encodeToString(auth.toByteArray(StandardCharsets.UTF_8)) + val emailData = "from=&to=$email&subject=$subject&text=$message" + + val connection = url.openConnection() as HttpURLConnection + connection.doOutput = true + connection.requestMethod = "POST" + connection.addRequestProperty("Authorization", "Basic $authEncoded") + + val outputStream: OutputStream = connection.outputStream + outputStream.write(emailData.toByteArray(Charsets.UTF_8)) + outputStream.flush() + + val responseCode = connection.responseCode + val responseMessage = connection.responseMessage + connection.disconnect() + if (responseCode != HttpURLConnection.HTTP_OK) { + return getErrorResponseWithMessage("$responseCode - $responseMessage") + } + + return mapOf("success" to true, + "message" to "You called sendEmailMailgun") +} diff --git a/sendMessageFunctions/sendMessageDiscord.kt b/sendMessageFunctions/sendMessageDiscord.kt new file mode 100644 index 00000000..7bc1d82c --- /dev/null +++ b/sendMessageFunctions/sendMessageDiscord.kt @@ -0,0 +1,25 @@ +fun sendMessageDiscordWebhook(variables: Map, message: String?): Map{ + val webhook = variables["DISCORD_WEBHOOK_URL"] + + val url = URL(webhook) + val conn: HttpURLConnection = url.openConnection() as HttpURLConnection + val body = "{\"content\":\"$message\"}" + conn.addRequestProperty("Content-Type", "application/json") + conn.requestMethod = "POST" + conn.doOutput = true + val os: OutputStream = conn.outputStream + val input: ByteArray = body.toByteArray(Charsets.UTF_8) + println(input) + os.write(input) + val responseCode: Int = conn.responseCode // To Check for 200 + os.close() + conn.disconnect() + if (responseCode / 100 == 2) { //HTTP code of 2xx means success (most of the time) + return mapOf("success" to true, + "message" to "You called sendMessageDiscordWebhook") + } + else { + return mapOf("success" to false, + "message" to conn.getResponseMessage()) + } +} \ No newline at end of file diff --git a/sendMessageFunctions/sendMessageSMS.kt b/sendMessageFunctions/sendMessageSMS.kt new file mode 100644 index 00000000..1e3ecdd5 --- /dev/null +++ b/sendMessageFunctions/sendMessageSMS.kt @@ -0,0 +1,71 @@ +import java.io.IOException +import java.io.OutputStreamWriter +import java.net.HttpURLConnection +import java.net.URL +import java.nio.charset.StandardCharsets +import java.util.Base64 +import java.util.Map + + +fun sendSmsTwilio(variables: Map, receiver: String?, message: String?): Map{ + + val accountID = variables.get("TWILIO_ACCOUNT_SID") // Acount SID from Twilio + val authToken = variables.get("TWILIO_AUTH_TOKEN") // Auth Token from Twilio + val sender = variables.get("TWILIO_SENDER") // Sender Phone Number from Twilio | Mandatory format: +# ### ### #### (all together) + + + if (accountID.isNullOrEmpty()) { + return mapOf("success" to false, "message" to "Account ID is not set") + } + + if (authToken.isNullOrEmpty()) { + return mapOf("success" to false, "message" to "Auth token is not set") + } + + if (sender.isNullOrEmpty()) { + return mapOf("success" to false, "message" to "Sender is not set") + } + + if (receiver.isNullOrEmpty()) { + return mapOf("success" to false, "message" to "Receiver is not set") + } + if (message.isNullOrEmpty()) { + return mapOf("success" to false, "message" to "Message is not set") + } + + + try { + val urlString= "https://api.twilio.com/2010-04-01/Accounts/$accountID/Messages.json" + val url = URL(urlString) + val connection = url.openConnection() as HttpURLConnection + connection.requestMethod = "POST" + connection.doOutput = true + + val authString = "$accountID:$authToken " + val authEncoded = Base64.getEncoder().encodeToString(authString.toByteArray(StandardCharsets.UTF_8)) + connection.setRequestProperty("Authorization", "Basic $authEncoded") + + val postData = "To=$receiver&From=$sender&Body=$message" + + val outputStreamWriter = OutputStreamWriter(connection.outputStream) + outputStreamWriter.write(postData) + outputStreamWriter.flush() + + + val responseCode = connection.responseCode + val responseMessage = connection.responseMessage + + connection.disconnect() + + if (responseCode != HttpURLConnection.HTTP_CREATED) { // HttpURLConnection.HTTP_CREATED = 201 Created + return mapOf("success" to false, "message" to "Error: #$responseCode - > $responseMessage") + } + + return mapOf("success" to true, "message" to "Message sent!") + + } catch (e: IllegalArgumentException) { // if variable receiver is set to "invalid" + return mapOf("success" to false, "message" to "Error: ${e.message}") + } catch (e: IOException) { // if network-related issues such as failure to establish a connection or send the HTTP request to the Twilio APi this will catch it + return mapOf("success" to false, "message" to "Error: ${e.message}") + } +} diff --git a/sendMessageFunctions/sendMessageTwitter.kt b/sendMessageFunctions/sendMessageTwitter.kt new file mode 100644 index 00000000..df9a8d13 --- /dev/null +++ b/sendMessageFunctions/sendMessageTwitter.kt @@ -0,0 +1,54 @@ +import java.net.URLEncoder + + +fun sendTweet(variables: Map, message: String?): Map { + val apiKey = variables["TWITTER_API_KEY"] + val apiSecret = variables["TWITTER_API_KEY_SECRET"] + val accessToken = variables["TWITTER_ACCESS_TOKEN"] + val accessTokenSecret = variables["TWITTER_ACCESS_TOKEN_SECRET"] + + if (apiKey.isNullOrEmpty()) { + return mapOf("success" to false, "message" to "Api Key is not set") + } + + if (apiSecret.isNullOrEmpty()) { + return mapOf("success" to false, "message" to "Api Secret is not set") + } + + if (accessToken.isNullOrEmpty()) { + return mapOf("success" to false, "message" to "Access Token is not set") + } + + if (accessTokenSecret.isNullOrEmpty()) { + return mapOf("success" to false, "message" to "Access Token Secret is not set") + } + + try { + val url = URL("https://api.twitter.com/1.1/statuses/update.json?") + val connection = url.openConnection() as HttpURLConnection + connection.doOutput = true + connection.requestMethod = "POST" + connection.setRequestProperty("Authorization", "Bearer ${URLEncoder.encode(accessToken, "UTF-8")}") + connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded") + connection.setRequestProperty("Accept", "application/json") + + val requestBody = "status=${URLEncoder.encode(message, "UTF-8")}" + + val outputStream = connection.outputStream + outputStream.write(requestBody.toByteArray(Charsets.UTF_8)) + outputStream.close() + + val responseCode = connection.responseCode + val responseMessage = connection.responseMessage + + if (responseCode != HttpURLConnection.HTTP_OK) { + return mapOf("success" to false, "message" to "Error: #$responseCode - > $responseMessage") + } + + connection.disconnect() + + return mapOf("success" to true, "message" to "Tweet sent!") + } catch (e: Exception) { + return mapOf("success" to false, "message" to "An unexpected error occurred: ${e.message}") + } +} \ No newline at end of file From d4dca46724ab4ead9e204dd2d97c04964d7da98b Mon Sep 17 00:00:00 2001 From: Tam Nguyen <98732550+softTam@users.noreply.github.com> Date: Wed, 12 Jul 2023 05:15:20 +0000 Subject: [PATCH 14/23] Added sendTweet. Got 401 - Unauthorized error. --- kotlin/sendMessage/Index.kt | 133 ++++++++++++++++-------------------- 1 file changed, 58 insertions(+), 75 deletions(-) diff --git a/kotlin/sendMessage/Index.kt b/kotlin/sendMessage/Index.kt index acabd569..459dc39a 100644 --- a/kotlin/sendMessage/Index.kt +++ b/kotlin/sendMessage/Index.kt @@ -10,6 +10,19 @@ import java.net.HttpURLConnection import java.net.URL import java.util.Base64 import java.nio.charset.StandardCharsets +import java.io.OutputStreamWriter +import com.chromasgaming.ktweet.models.ManageTweets +import com.chromasgaming.ktweet.models.Tweet +import com.chromasgaming.ktweet.oauth.SignatureBuilder +import com.chromasgaming.ktweet.oauth.buildSignature +import com.chromasgaming.ktweet.config.ClientConfig + +fun getErrorResponseWithMessage(message: String? = "Some error occurred"): Map { + return mapOf( + "success" to false, + "message" to message.toString() + ) +} fun sendEmailMailgun(variables: Map, email: String?, message: String?, subject: String?): Map{ return mapOf("success" to true, @@ -49,112 +62,82 @@ fun sendMessageDiscordWebhook(variables: Map, message: String?): } else { return getErrorResponseWithMessage(conn.getResponseMessage()) - // return mapOf("success" to false, - // "message" to conn.getResponseMessage()) } } catch (e: IllegalArgumentException) { // if variable receiver is set to "invalid" - // println("First was executed") return getErrorResponseWithMessage(e.message) - // return mapOf("success" to false, "message" to "Error: ${e.message}") } catch (e: IOException) { // if network-related issues such as failure to establish a connection or send the HTTP request to the Twilio APi this will catch it - // println("Second was executed") return getErrorResponseWithMessage(e.message) - // return mapOf("success" to false, "message" to "Error: ${e.message}") } } fun sendSmsTwilio(variables: Map, receiver: String?, message: String?): Map{ + return mapOf("success" to true, + "message" to "You called sendEmailMailgun") +} - val accountID = variables.get("TWILIO_ACCOUNT_SID") // Acount SID from Twilio - val authToken = variables.get("TWILIO_AUTH_TOKEN") // Auth Token from Twilio - val sender = variables.get("TWILIO_SENDER") // Sender Phone Number from Twilio | Mandatory format: +# ### ### #### (all together) +fun sendTweet(variables: Map, message: String?): Map { + val apiKey = variables["TWITTER_API_KEY"]?:"" + val apiSecret = variables["TWITTER_API_KEY_SECRET"]?:"" + val accessToken = variables["TWITTER_ACCESS_TOKEN"]?:"" + val accessTokenSecret = variables["TWITTER_ACCESS_TOKEN_SECRET"]?:"" - - if (accountID.isNullOrEmpty()) { - return mapOf("success" to false, "message" to "Account ID is not set") + if (apiKey.isNullOrEmpty()) { + return getErrorResponseWithMessage("Payload doesn't contain an API key (i.e. consumer key)") } - if (authToken.isNullOrEmpty()) { - return mapOf("success" to false, "message" to "Auth token is not set") + if (apiSecret.isNullOrEmpty()) { + return getErrorResponseWithMessage("Payload doesn't contain an API key Secret (i.e. consumer secret)") } - if (sender.isNullOrEmpty()) { - return mapOf("success" to false, "message" to "Sender is not set") + if (accessToken.isNullOrEmpty()) { + return getErrorResponseWithMessage("Payload doesn't contain an access token") } - if (receiver.isNullOrEmpty()) { - return mapOf("success" to false, "message" to "Receiver is not set") + if (accessTokenSecret.isNullOrEmpty()) { + return getErrorResponseWithMessage("Payload doesn't contain an an access token secret") } - if (message.isNullOrEmpty()) { - return mapOf("success" to false, "message" to "Message is not set") - } - - - try { - val urlString= "https://api.twilio.com/2010-04-01/Accounts/$accountID/Messages.json" - val url = URL(urlString) - val connection = url.openConnection() as HttpURLConnection - connection.requestMethod = "POST" - connection.doOutput = true - - val authString = "$accountID:$authToken " - val authEncoded = Base64.getEncoder().encodeToString(authString.toByteArray(StandardCharsets.UTF_8)) - connection.setRequestProperty("Authorization", "Basic $authEncoded") - - val postData = "To=$receiver&From=$sender&Body=$message" - - val outputStreamWriter = OutputStreamWriter(connection.outputStream) - outputStreamWriter.write(postData) - outputStreamWriter.flush() - - - val responseCode = connection.responseCode - val responseMessage = connection.responseMessage - - connection.disconnect() - - if (responseCode != HttpURLConnection.HTTP_CREATED) { // HttpURLConnection.HTTP_CREATED = 201 Created - return mapOf("success" to false, "message" to "Error: #$responseCode - > $responseMessage") - } - return mapOf("success" to true, "message" to "Message sent!") - - } catch (e: IllegalArgumentException) { // if variable receiver is set to "invalid" - return mapOf("success" to false, "message" to "Error: ${e.message}") - } catch (e: IOException) { // if network-related issues such as failure to establish a connection or send the HTTP request to the Twilio APi this will catch it - return mapOf("success" to false, "message" to "Error: ${e.message}") - } -} - -fun sendTweet(variables: Map, message: String?): Map{ - val apiKey = variables["TWITTER_API_KEY"] - val apiSecret = variables["TWITTER_API_KEY_SECRET"] - val accessToken = variables["TWITTER_ACCESS_TOKEN"] - val accessTokenSecret = variables["TWITTER_ACCESS_TOKEN_SECRET"] - - var post: ManageTweets - manageTweets = ManageTweetsAPI() - - signatureBuilder = SignatureBuilder.Builder() + val signatureBuilder: SignatureBuilder = SignatureBuilder.Builder() .oauthConsumerKey(apiKey) .oauthConsumerSecret(apiSecret) .accessToken(accessToken) .accessTokenSecret(accessTokenSecret) .build() - authorizationHeaderString = buildSignature( + val authorizationHeaderString: String = buildSignature( "POST", signatureBuilder, - "$VERSION/tweets", + "2/tweets", emptyMap() ) + // println(authorizationHeaderString) + + val urlString = "https://api.twitter.com/2/tweets" + val url = URL(urlString) + val connection = url.openConnection() as HttpURLConnection + connection.requestMethod = "POST" + connection.doOutput = true + + connection.setRequestProperty("Authorization", "$authorizationHeaderString") + // connection.setRequestProperty("Content-Type", "application/json") + + val postData = "text=$message" + // println(postData) + + val outputStreamWriter = OutputStreamWriter(connection.outputStream) + outputStreamWriter.write(postData) + outputStreamWriter.flush() + + val responseCode = connection.responseCode + val responseMessage = connection.responseMessage + + connection.disconnect() - val tweet = Tweet(message) - post = manageTweets.create(tweet, authorizationHeaderString) - /*How can I use to check if the request was sucessful??? - Seems like it's a JSON object; represents the body response*/ - return mapOf("success" to true, "message" to post.text) + if (responseCode != HttpURLConnection.HTTP_CREATED) { // HttpURLConnection.HTTP_CREATED = 201 Created + return getErrorResponseWithMessage("Error: #$responseCode - > $responseMessage") + } + return mapOf("success" to true, "message" to "You called sendTweet") } @Throws(Exception::class) From 6818141ada99a4c0742f2413f3ee6bab4344076a Mon Sep 17 00:00:00 2001 From: Tam Nguyen <98732550+softTam@users.noreply.github.com> Date: Wed, 12 Jul 2023 05:34:34 +0000 Subject: [PATCH 15/23] Deleted all helper files. --- kotlin/sendMessageHelper/sendEmailMailgun.kt | 42 ----------- .../sendMessageHelper/sendMessageDiscord.kt | 41 ----------- kotlin/sendMessageHelper/sendMessageSMS.kt | 71 ------------------- .../sendMessageHelper/sendMessageTwitter.kt | 67 ----------------- sendMessageFunctions/sendEmailMailgun.kt | 42 ----------- sendMessageFunctions/sendMessageDiscord.kt | 25 ------- sendMessageFunctions/sendMessageSMS.kt | 71 ------------------- sendMessageFunctions/sendMessageTwitter.kt | 54 -------------- 8 files changed, 413 deletions(-) delete mode 100644 kotlin/sendMessageHelper/sendEmailMailgun.kt delete mode 100644 kotlin/sendMessageHelper/sendMessageDiscord.kt delete mode 100644 kotlin/sendMessageHelper/sendMessageSMS.kt delete mode 100644 kotlin/sendMessageHelper/sendMessageTwitter.kt delete mode 100644 sendMessageFunctions/sendEmailMailgun.kt delete mode 100644 sendMessageFunctions/sendMessageDiscord.kt delete mode 100644 sendMessageFunctions/sendMessageSMS.kt delete mode 100644 sendMessageFunctions/sendMessageTwitter.kt diff --git a/kotlin/sendMessageHelper/sendEmailMailgun.kt b/kotlin/sendMessageHelper/sendEmailMailgun.kt deleted file mode 100644 index f0b3cef9..00000000 --- a/kotlin/sendMessageHelper/sendEmailMailgun.kt +++ /dev/null @@ -1,42 +0,0 @@ -import java.util.Base64 -import java.nio.charset.StandardCharsets - -fun sendEmailMailgun(variables: Map, email: String?, message: String?, subject: String?): Map{ - if (email.isNullOrEmpty() || message.isNullOrEmpty() || subject.isNullOrEmpty()){ - return getErrorResponseWithMessage("Missing email, message, or subject") - } - - val domain = variables["MAILGUN_DOMAIN"] - val apiKey = variables["MAILGUN_API_KEY"] - - if (domain.isNullOrEmpty()){ - return getErrorResponseWithMessage("Missing Mailgun domain") - } - if (apiKey.isNullOrEmpty()){ - return getErrorResponseWithMessage("Missing Mailgun API key") - } - - val url = URL("https://api.mailgun.net/v3/$domain/messages") - val auth = "api:$apiKey" - val authEncoded = Base64.getEncoder().encodeToString(auth.toByteArray(StandardCharsets.UTF_8)) - val emailData = "from=&to=$email&subject=$subject&text=$message" - - val connection = url.openConnection() as HttpURLConnection - connection.doOutput = true - connection.requestMethod = "POST" - connection.addRequestProperty("Authorization", "Basic $authEncoded") - - val outputStream: OutputStream = connection.outputStream - outputStream.write(emailData.toByteArray(Charsets.UTF_8)) - outputStream.flush() - - val responseCode = connection.responseCode - val responseMessage = connection.responseMessage - connection.disconnect() - if (responseCode != HttpURLConnection.HTTP_OK) { - return getErrorResponseWithMessage("$responseCode - $responseMessage") - } - - return mapOf("success" to true, - "message" to "You called sendEmailMailgun") -} diff --git a/kotlin/sendMessageHelper/sendMessageDiscord.kt b/kotlin/sendMessageHelper/sendMessageDiscord.kt deleted file mode 100644 index 0eb9a96c..00000000 --- a/kotlin/sendMessageHelper/sendMessageDiscord.kt +++ /dev/null @@ -1,41 +0,0 @@ -fun sendMessageDiscordWebhook(variables: Map, message: String?): Map{ - val webhook = variables["DISCORD_WEBHOOK_URL"]?:"" - - try { - if (webhook.isEmpty() || webhook.trim().isEmpty()) { - return getErrorResponseWithMessage(res, "Payload doesn't contain a Discord Webhook URL") - } - - val url = URL(webhook) - - val conn: HttpURLConnection = url.openConnection() as HttpURLConnection - val body = "{\"content\":\"$message\"}" - // conn.addRequestProperty("Content-Type", "application/json") - conn.requestMethod = "POST" - conn.doOutput = true - - val os: OutputStream = conn.outputStream - val input: ByteArray = body.toByteArray(Charsets.UTF_8) - // println(input) - os.write(input) - - val responseCode: Int = conn.responseCode // To Check for 200 - os.close() - conn.disconnect() - if (responseCode / 100 == 2) { //HTTP code of 2xx means success (most of the time) - return mapOf("success" to true, - "message" to "You called sendMessageDiscordWebhook") - } - else { - return getErrorResponseWithMessage(res, conn.getResponseMessage()) - // return mapOf("success" to false, - // "message" to conn.getResponseMessage()) - } - } catch (e: IllegalArgumentException) { // if variable receiver is set to "invalid" - return getErrorResponseWithMessage(res, e.message) - // return mapOf("success" to false, "message" to "Error: ${e.message}") - } catch (e: IOException) { // if network-related issues such as failure to establish a connection or send the HTTP request to the Twilio APi this will catch it - return getErrorResponseWithMessage(res, e.message) - // return mapOf("success" to false, "message" to "Error: ${e.message}") - } -} \ No newline at end of file diff --git a/kotlin/sendMessageHelper/sendMessageSMS.kt b/kotlin/sendMessageHelper/sendMessageSMS.kt deleted file mode 100644 index 1e3ecdd5..00000000 --- a/kotlin/sendMessageHelper/sendMessageSMS.kt +++ /dev/null @@ -1,71 +0,0 @@ -import java.io.IOException -import java.io.OutputStreamWriter -import java.net.HttpURLConnection -import java.net.URL -import java.nio.charset.StandardCharsets -import java.util.Base64 -import java.util.Map - - -fun sendSmsTwilio(variables: Map, receiver: String?, message: String?): Map{ - - val accountID = variables.get("TWILIO_ACCOUNT_SID") // Acount SID from Twilio - val authToken = variables.get("TWILIO_AUTH_TOKEN") // Auth Token from Twilio - val sender = variables.get("TWILIO_SENDER") // Sender Phone Number from Twilio | Mandatory format: +# ### ### #### (all together) - - - if (accountID.isNullOrEmpty()) { - return mapOf("success" to false, "message" to "Account ID is not set") - } - - if (authToken.isNullOrEmpty()) { - return mapOf("success" to false, "message" to "Auth token is not set") - } - - if (sender.isNullOrEmpty()) { - return mapOf("success" to false, "message" to "Sender is not set") - } - - if (receiver.isNullOrEmpty()) { - return mapOf("success" to false, "message" to "Receiver is not set") - } - if (message.isNullOrEmpty()) { - return mapOf("success" to false, "message" to "Message is not set") - } - - - try { - val urlString= "https://api.twilio.com/2010-04-01/Accounts/$accountID/Messages.json" - val url = URL(urlString) - val connection = url.openConnection() as HttpURLConnection - connection.requestMethod = "POST" - connection.doOutput = true - - val authString = "$accountID:$authToken " - val authEncoded = Base64.getEncoder().encodeToString(authString.toByteArray(StandardCharsets.UTF_8)) - connection.setRequestProperty("Authorization", "Basic $authEncoded") - - val postData = "To=$receiver&From=$sender&Body=$message" - - val outputStreamWriter = OutputStreamWriter(connection.outputStream) - outputStreamWriter.write(postData) - outputStreamWriter.flush() - - - val responseCode = connection.responseCode - val responseMessage = connection.responseMessage - - connection.disconnect() - - if (responseCode != HttpURLConnection.HTTP_CREATED) { // HttpURLConnection.HTTP_CREATED = 201 Created - return mapOf("success" to false, "message" to "Error: #$responseCode - > $responseMessage") - } - - return mapOf("success" to true, "message" to "Message sent!") - - } catch (e: IllegalArgumentException) { // if variable receiver is set to "invalid" - return mapOf("success" to false, "message" to "Error: ${e.message}") - } catch (e: IOException) { // if network-related issues such as failure to establish a connection or send the HTTP request to the Twilio APi this will catch it - return mapOf("success" to false, "message" to "Error: ${e.message}") - } -} diff --git a/kotlin/sendMessageHelper/sendMessageTwitter.kt b/kotlin/sendMessageHelper/sendMessageTwitter.kt deleted file mode 100644 index ec10d060..00000000 --- a/kotlin/sendMessageHelper/sendMessageTwitter.kt +++ /dev/null @@ -1,67 +0,0 @@ -import java.net.URLEncoder -import com.chromasgaming.ktweet.api //for creating a Tweet post -import com.chromasgaming.ktweet.models //for creating a Tweet object - -tweet: Tweet = Tweet(message) -authorizationHeaderString: String = - -/* Authorization reference: - header 'Authorization: OAuth oauth_consumer_key="CONSUMER_API_KEY", - oauth_nonce="OAUTH_NONCE", - oauth_signature="OAUTH_SIGNATURE", - oauth_signature_method="HMAC-SHA1", - oauth_timestamp="OAUTH_TIMESTAMP", - oauth_token="ACCESS_TOKEN", - oauth_version="1.0"' */ - -fun sendTweet(variables: Map, message: String?): Map { - val apiKey = variables["TWITTER_API_KEY"] - val apiSecret = variables["TWITTER_API_KEY_SECRET"] - val accessToken = variables["TWITTER_ACCESS_TOKEN"] - val accessTokenSecret = variables["TWITTER_ACCESS_TOKEN_SECRET"] - - if (apiKey.isNullOrEmpty()) { - return getErrorResponseWithMessage("Api Key is not set") - } - - if (apiSecret.isNullOrEmpty()) { - return getErrorResponseWithMessage("Api Secret is not set") - } - - if (accessToken.isNullOrEmpty()) { - return getErrorResponseWithMessage("Access Token is not set") - } - - if (accessTokenSecret.isNullOrEmpty()) { - return getErrorResponseWithMessage("Access Token Secret is not set") - } - - try { - val url = URL("https://api.twitter.com/1.1/statuses/update.json?") - val connection = url.openConnection() as HttpURLConnection - connection.doOutput = true - connection.requestMethod = "POST" - connection.setRequestProperty("Authorization", "Bearer ${URLEncoder.encode(accessToken, "UTF-8")}") - connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded") - connection.setRequestProperty("Accept", "application/json") - - val requestBody = "status=${URLEncoder.encode(message, "UTF-8")}" - - val outputStream = connection.outputStream - outputStream.write(requestBody.toByteArray(Charsets.UTF_8)) - outputStream.close() - - val responseCode = connection.responseCode - val responseMessage = connection.responseMessage - - if (responseCode != HttpURLConnection.HTTP_OK) { - return mapOf("success" to false, "message" to "Error: #$responseCode - > $responseMessage") - } - - connection.disconnect() - - return mapOf("success" to true, "message" to "Tweet sent!") - } catch (e: Exception) { - return mapOf("success" to false, "message" to "An unexpected error occurred: ${e.message}") - } -} \ No newline at end of file diff --git a/sendMessageFunctions/sendEmailMailgun.kt b/sendMessageFunctions/sendEmailMailgun.kt deleted file mode 100644 index f0b3cef9..00000000 --- a/sendMessageFunctions/sendEmailMailgun.kt +++ /dev/null @@ -1,42 +0,0 @@ -import java.util.Base64 -import java.nio.charset.StandardCharsets - -fun sendEmailMailgun(variables: Map, email: String?, message: String?, subject: String?): Map{ - if (email.isNullOrEmpty() || message.isNullOrEmpty() || subject.isNullOrEmpty()){ - return getErrorResponseWithMessage("Missing email, message, or subject") - } - - val domain = variables["MAILGUN_DOMAIN"] - val apiKey = variables["MAILGUN_API_KEY"] - - if (domain.isNullOrEmpty()){ - return getErrorResponseWithMessage("Missing Mailgun domain") - } - if (apiKey.isNullOrEmpty()){ - return getErrorResponseWithMessage("Missing Mailgun API key") - } - - val url = URL("https://api.mailgun.net/v3/$domain/messages") - val auth = "api:$apiKey" - val authEncoded = Base64.getEncoder().encodeToString(auth.toByteArray(StandardCharsets.UTF_8)) - val emailData = "from=&to=$email&subject=$subject&text=$message" - - val connection = url.openConnection() as HttpURLConnection - connection.doOutput = true - connection.requestMethod = "POST" - connection.addRequestProperty("Authorization", "Basic $authEncoded") - - val outputStream: OutputStream = connection.outputStream - outputStream.write(emailData.toByteArray(Charsets.UTF_8)) - outputStream.flush() - - val responseCode = connection.responseCode - val responseMessage = connection.responseMessage - connection.disconnect() - if (responseCode != HttpURLConnection.HTTP_OK) { - return getErrorResponseWithMessage("$responseCode - $responseMessage") - } - - return mapOf("success" to true, - "message" to "You called sendEmailMailgun") -} diff --git a/sendMessageFunctions/sendMessageDiscord.kt b/sendMessageFunctions/sendMessageDiscord.kt deleted file mode 100644 index 7bc1d82c..00000000 --- a/sendMessageFunctions/sendMessageDiscord.kt +++ /dev/null @@ -1,25 +0,0 @@ -fun sendMessageDiscordWebhook(variables: Map, message: String?): Map{ - val webhook = variables["DISCORD_WEBHOOK_URL"] - - val url = URL(webhook) - val conn: HttpURLConnection = url.openConnection() as HttpURLConnection - val body = "{\"content\":\"$message\"}" - conn.addRequestProperty("Content-Type", "application/json") - conn.requestMethod = "POST" - conn.doOutput = true - val os: OutputStream = conn.outputStream - val input: ByteArray = body.toByteArray(Charsets.UTF_8) - println(input) - os.write(input) - val responseCode: Int = conn.responseCode // To Check for 200 - os.close() - conn.disconnect() - if (responseCode / 100 == 2) { //HTTP code of 2xx means success (most of the time) - return mapOf("success" to true, - "message" to "You called sendMessageDiscordWebhook") - } - else { - return mapOf("success" to false, - "message" to conn.getResponseMessage()) - } -} \ No newline at end of file diff --git a/sendMessageFunctions/sendMessageSMS.kt b/sendMessageFunctions/sendMessageSMS.kt deleted file mode 100644 index 1e3ecdd5..00000000 --- a/sendMessageFunctions/sendMessageSMS.kt +++ /dev/null @@ -1,71 +0,0 @@ -import java.io.IOException -import java.io.OutputStreamWriter -import java.net.HttpURLConnection -import java.net.URL -import java.nio.charset.StandardCharsets -import java.util.Base64 -import java.util.Map - - -fun sendSmsTwilio(variables: Map, receiver: String?, message: String?): Map{ - - val accountID = variables.get("TWILIO_ACCOUNT_SID") // Acount SID from Twilio - val authToken = variables.get("TWILIO_AUTH_TOKEN") // Auth Token from Twilio - val sender = variables.get("TWILIO_SENDER") // Sender Phone Number from Twilio | Mandatory format: +# ### ### #### (all together) - - - if (accountID.isNullOrEmpty()) { - return mapOf("success" to false, "message" to "Account ID is not set") - } - - if (authToken.isNullOrEmpty()) { - return mapOf("success" to false, "message" to "Auth token is not set") - } - - if (sender.isNullOrEmpty()) { - return mapOf("success" to false, "message" to "Sender is not set") - } - - if (receiver.isNullOrEmpty()) { - return mapOf("success" to false, "message" to "Receiver is not set") - } - if (message.isNullOrEmpty()) { - return mapOf("success" to false, "message" to "Message is not set") - } - - - try { - val urlString= "https://api.twilio.com/2010-04-01/Accounts/$accountID/Messages.json" - val url = URL(urlString) - val connection = url.openConnection() as HttpURLConnection - connection.requestMethod = "POST" - connection.doOutput = true - - val authString = "$accountID:$authToken " - val authEncoded = Base64.getEncoder().encodeToString(authString.toByteArray(StandardCharsets.UTF_8)) - connection.setRequestProperty("Authorization", "Basic $authEncoded") - - val postData = "To=$receiver&From=$sender&Body=$message" - - val outputStreamWriter = OutputStreamWriter(connection.outputStream) - outputStreamWriter.write(postData) - outputStreamWriter.flush() - - - val responseCode = connection.responseCode - val responseMessage = connection.responseMessage - - connection.disconnect() - - if (responseCode != HttpURLConnection.HTTP_CREATED) { // HttpURLConnection.HTTP_CREATED = 201 Created - return mapOf("success" to false, "message" to "Error: #$responseCode - > $responseMessage") - } - - return mapOf("success" to true, "message" to "Message sent!") - - } catch (e: IllegalArgumentException) { // if variable receiver is set to "invalid" - return mapOf("success" to false, "message" to "Error: ${e.message}") - } catch (e: IOException) { // if network-related issues such as failure to establish a connection or send the HTTP request to the Twilio APi this will catch it - return mapOf("success" to false, "message" to "Error: ${e.message}") - } -} diff --git a/sendMessageFunctions/sendMessageTwitter.kt b/sendMessageFunctions/sendMessageTwitter.kt deleted file mode 100644 index df9a8d13..00000000 --- a/sendMessageFunctions/sendMessageTwitter.kt +++ /dev/null @@ -1,54 +0,0 @@ -import java.net.URLEncoder - - -fun sendTweet(variables: Map, message: String?): Map { - val apiKey = variables["TWITTER_API_KEY"] - val apiSecret = variables["TWITTER_API_KEY_SECRET"] - val accessToken = variables["TWITTER_ACCESS_TOKEN"] - val accessTokenSecret = variables["TWITTER_ACCESS_TOKEN_SECRET"] - - if (apiKey.isNullOrEmpty()) { - return mapOf("success" to false, "message" to "Api Key is not set") - } - - if (apiSecret.isNullOrEmpty()) { - return mapOf("success" to false, "message" to "Api Secret is not set") - } - - if (accessToken.isNullOrEmpty()) { - return mapOf("success" to false, "message" to "Access Token is not set") - } - - if (accessTokenSecret.isNullOrEmpty()) { - return mapOf("success" to false, "message" to "Access Token Secret is not set") - } - - try { - val url = URL("https://api.twitter.com/1.1/statuses/update.json?") - val connection = url.openConnection() as HttpURLConnection - connection.doOutput = true - connection.requestMethod = "POST" - connection.setRequestProperty("Authorization", "Bearer ${URLEncoder.encode(accessToken, "UTF-8")}") - connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded") - connection.setRequestProperty("Accept", "application/json") - - val requestBody = "status=${URLEncoder.encode(message, "UTF-8")}" - - val outputStream = connection.outputStream - outputStream.write(requestBody.toByteArray(Charsets.UTF_8)) - outputStream.close() - - val responseCode = connection.responseCode - val responseMessage = connection.responseMessage - - if (responseCode != HttpURLConnection.HTTP_OK) { - return mapOf("success" to false, "message" to "Error: #$responseCode - > $responseMessage") - } - - connection.disconnect() - - return mapOf("success" to true, "message" to "Tweet sent!") - } catch (e: Exception) { - return mapOf("success" to false, "message" to "An unexpected error occurred: ${e.message}") - } -} \ No newline at end of file From b535124a1e7b001370bebc784c79cc498ea6af2d Mon Sep 17 00:00:00 2001 From: jamesrcramos <76936793+jamesrcramos@users.noreply.github.com> Date: Wed, 12 Jul 2023 17:59:01 +0000 Subject: [PATCH 16/23] Removed messages from return statements --- kotlin/sendMessage/Index.kt | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/kotlin/sendMessage/Index.kt b/kotlin/sendMessage/Index.kt index 8480c92d..2a2864b0 100644 --- a/kotlin/sendMessage/Index.kt +++ b/kotlin/sendMessage/Index.kt @@ -60,8 +60,7 @@ fun sendEmailMailgun(variables: Map, email: String?, message: St return getErrorResponseWithMessage("$responseCode - $responseMessage") } - return mapOf("success" to true, - "message" to "You called sendEmailMailgun") + return mapOf("success" to true) } fun sendMessageDiscordWebhook(variables: Map, message: String?): Map { @@ -91,8 +90,7 @@ fun sendMessageDiscordWebhook(variables: Map, message: String?): os.close() conn.disconnect() if (responseCode / 100 == 2) { //HTTP code of 2xx means success (most of the time) - return mapOf("success" to true, - "message" to "You called sendMessageDiscordWebhook") + return mapOf("success" to true) } else { return getErrorResponseWithMessage(conn.getResponseMessage()) @@ -149,17 +147,16 @@ fun sendSmsTwilio(variables: Map, receiver: String?, message: St outputStreamWriter.write(postData) outputStreamWriter.flush() - val responseCode = connection.responseCode val responseMessage = connection.responseMessage connection.disconnect() if (responseCode != HttpURLConnection.HTTP_CREATED) { // HttpURLConnection.HTTP_CREATED = 201 Created - return mapOf("success" to false, "message" to "Error: #$responseCode - > $responseMessage") + return getErrorResponseWithMessage("Error: #$responseCode - > $responseMessage") } - return mapOf("success" to true, "message" to "Message sent!") + return mapOf("success" to true) } catch (e: IllegalArgumentException) { // if variable receiver is set to "invalid" return getErrorResponseWithMessage("Error: ${e.message}") @@ -229,7 +226,7 @@ fun sendTweet(variables: Map, message: String?): Map $responseMessage") } - return mapOf("success" to true, "message" to "You called sendTweet") + return mapOf("success" to true) } @Throws(Exception::class) From 5344941cb3b7faf1d6fae01915b6bd536be49f38 Mon Sep 17 00:00:00 2001 From: Arturo Date: Wed, 12 Jul 2023 19:56:33 +0000 Subject: [PATCH 17/23] Added READ.me file --- kotlin/sendMessage/README.md | 206 +++++++++++++++++++++++++++++++++++ 1 file changed, 206 insertions(+) diff --git a/kotlin/sendMessage/README.md b/kotlin/sendMessage/README.md index e69de29b..8c5b73d6 100644 --- a/kotlin/sendMessage/README.md +++ b/kotlin/sendMessage/README.md @@ -0,0 +1,206 @@ + +# SendMessage() + + + +A Kotlin Cloud Function for sending a message using a specific channel to a receiver + + + +Supported channels are `SMS`, `Email` , and `Discord`. + + + +_SMS Example payload_ + + + +```json + +{ "type": "SMS", "receiver": "+123456789", "message": "Programming is fun!" } + +``` + + + +_Email Example payload_ + + + +```json + +{ + +"type": "Email", + +"receiver": "hello@example.com", + +"message": "Programming is fun!", + +"subject": "Programming is funny!" + +} + +``` + + + +_Discord Example payload_ + + + +```json + +{ + +"type": "Discord", + +"message": "Hi" + +} + +``` + + + +_Successful function response:_ + + + +```json + +{ + +"success": true + +} + +``` + + + +_Error function response:_ + + + +```json + +{ + +"success": false, + +"message": "Failed to send message,check webhook URL" + +} + +``` + + + +## 📝 Variables + + + +List of variables used by this cloud function: + + + +Mailgun + + + +- **MAILGUN_API_KEY** - API Key for Mailgun + +- **MAILGUN_DOMAIN** - Domain Name from Mailgun + + + +Discord + + + +- **DISCORD_WEBHOOK_URL** - Webhook URL for Discord + + + +Twilio + + + +- **TWILIO_ACCOUNT_SID** - Acount SID from Twilio + +- **TWILIO_AUTH_TOKEN** - Auth Token from Twilio + +- **TWILIO_SENDER** - Sender Phone Number from Twilio + + + +## 🚀 Deployment + + + +1. Clone this repository, and enter this function folder: + + + +``` + +$ git clone https://github.com/open-runtimes/examples.git && cd examples + +$ cd kotlin/sendMessage + +``` + + + +2. Enter this function folder and build the code: + + + +```bash + +docker run --rm --interactive --tty --volume $PWD:/usr/code openruntimes/kotlin:v1.6.0 sh /usr/local/src/build.kotlin + +``` + + + +As a result, a `kotlin.tar.gz` file will be generated. + + + +3. Start the Open Runtime: + + + +```bash + +docker run -p 3000:3000 -e INTERNAL_RUNTIME_KEY=secret-key -e INTERNAL_RUNTIME_ENTRYPOINT=main.kt --rm --interactive --tty --volume $PWD/kotlin.tar.gz:/tmp/kotlin.tar.gz:ro openruntimes/kotlin:v1.6.0 sh /usr/local/src/start.kotlin + +``` + + + +Your function is now listening on port `3000`, and you can execute it by sending `POST` request with appropriate authorization headers. To learn more about runtime, you can visit Kotlin runtime [README](https://github.com/open-runtimes/open-runtimes/tree/main/runtimes/kotlin-1.6/example). + + + +4. Curl Command ( Email ) + + + +```bash + +curl -X POST http://localhost:3000/ -d '{"variables": {"MAILGUN_API_KEY":"YOUR_MAILGUN_API_KEY","MAILGUN_DOMAIN":"YOUR_MAILGUN_DOMAIN"},"payload": "{\"type\": \"Email\",\"receiver\": \"hello@example.com\",\"message\": \"Programming is fun!\",\"subject\": \"Programming is funny!\"}"}' -H "X-Internal-Challenge: secret-key" -H "Content-Type: application/json" + +``` + + + +## 📝 Notes + + + +- This function is designed for use with Appwrite Cloud Functions. You can learn more about it in [Appwrite docs](https://appwrite.io/docs/functions). +READ.me.md +Displaying READ.me.md. \ No newline at end of file From d83e34648e90f53cc6f47b745dd2b55b57671e56 Mon Sep 17 00:00:00 2001 From: Tam Nguyen <98732550+softTam@users.noreply.github.com> Date: Wed, 12 Jul 2023 21:47:18 +0000 Subject: [PATCH 18/23] Suncessfully implemented sendTweet() function --- kotlin/sendMessage/Index.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kotlin/sendMessage/Index.kt b/kotlin/sendMessage/Index.kt index 8480c92d..37a7455c 100644 --- a/kotlin/sendMessage/Index.kt +++ b/kotlin/sendMessage/Index.kt @@ -212,9 +212,9 @@ fun sendTweet(variables: Map, message: String?): Map Date: Wed, 12 Jul 2023 23:08:59 +0000 Subject: [PATCH 19/23] Updated README.md file with Twitter option. --- kotlin/sendMessage/README.md | 392 +++++++++++++++++------------------ 1 file changed, 186 insertions(+), 206 deletions(-) diff --git a/kotlin/sendMessage/README.md b/kotlin/sendMessage/README.md index 8c5b73d6..d62e8da0 100644 --- a/kotlin/sendMessage/README.md +++ b/kotlin/sendMessage/README.md @@ -1,206 +1,186 @@ - -# SendMessage() - - - -A Kotlin Cloud Function for sending a message using a specific channel to a receiver - - - -Supported channels are `SMS`, `Email` , and `Discord`. - - - -_SMS Example payload_ - - - -```json - -{ "type": "SMS", "receiver": "+123456789", "message": "Programming is fun!" } - -``` - - - -_Email Example payload_ - - - -```json - -{ - -"type": "Email", - -"receiver": "hello@example.com", - -"message": "Programming is fun!", - -"subject": "Programming is funny!" - -} - -``` - - - -_Discord Example payload_ - - - -```json - -{ - -"type": "Discord", - -"message": "Hi" - -} - -``` - - - -_Successful function response:_ - - - -```json - -{ - -"success": true - -} - -``` - - - -_Error function response:_ - - - -```json - -{ - -"success": false, - -"message": "Failed to send message,check webhook URL" - -} - -``` - - - -## 📝 Variables - - - -List of variables used by this cloud function: - - - -Mailgun - - - -- **MAILGUN_API_KEY** - API Key for Mailgun - -- **MAILGUN_DOMAIN** - Domain Name from Mailgun - - - -Discord - - - -- **DISCORD_WEBHOOK_URL** - Webhook URL for Discord - - - -Twilio - - - -- **TWILIO_ACCOUNT_SID** - Acount SID from Twilio - -- **TWILIO_AUTH_TOKEN** - Auth Token from Twilio - -- **TWILIO_SENDER** - Sender Phone Number from Twilio - - - -## 🚀 Deployment - - - -1. Clone this repository, and enter this function folder: - - - -``` - -$ git clone https://github.com/open-runtimes/examples.git && cd examples - -$ cd kotlin/sendMessage - -``` - - - -2. Enter this function folder and build the code: - - - -```bash - -docker run --rm --interactive --tty --volume $PWD:/usr/code openruntimes/kotlin:v1.6.0 sh /usr/local/src/build.kotlin - -``` - - - -As a result, a `kotlin.tar.gz` file will be generated. - - - -3. Start the Open Runtime: - - - -```bash - -docker run -p 3000:3000 -e INTERNAL_RUNTIME_KEY=secret-key -e INTERNAL_RUNTIME_ENTRYPOINT=main.kt --rm --interactive --tty --volume $PWD/kotlin.tar.gz:/tmp/kotlin.tar.gz:ro openruntimes/kotlin:v1.6.0 sh /usr/local/src/start.kotlin - -``` - - - -Your function is now listening on port `3000`, and you can execute it by sending `POST` request with appropriate authorization headers. To learn more about runtime, you can visit Kotlin runtime [README](https://github.com/open-runtimes/open-runtimes/tree/main/runtimes/kotlin-1.6/example). - - - -4. Curl Command ( Email ) - - - -```bash - -curl -X POST http://localhost:3000/ -d '{"variables": {"MAILGUN_API_KEY":"YOUR_MAILGUN_API_KEY","MAILGUN_DOMAIN":"YOUR_MAILGUN_DOMAIN"},"payload": "{\"type\": \"Email\",\"receiver\": \"hello@example.com\",\"message\": \"Programming is fun!\",\"subject\": \"Programming is funny!\"}"}' -H "X-Internal-Challenge: secret-key" -H "Content-Type: application/json" - -``` - - - -## 📝 Notes - - - -- This function is designed for use with Appwrite Cloud Functions. You can learn more about it in [Appwrite docs](https://appwrite.io/docs/functions). -READ.me.md -Displaying READ.me.md. \ No newline at end of file + +# SendMessage() + + A Kotlin Cloud Function for sending a message using a specific channel to a receiver + + + +Supported channels are `SMS`, `Email` , `Disocrd`, and `Twitter`. + + + +_SMS Example payload_ + + + +```json +{ + "type": "SMS", + "receiver": "+123456789", + "message": "Programming is fun!" +} +``` + + + +_Email Example payload_ + + + +```json +{ + "type": "Email", + "receiver": "hello@example.com", + "message": "Programming is fun!", + "subject": "Programming is funny!" +} +``` + + + +_Discord Example payload_ + + + +```json + +{ + "type": "Discord", + "message": "Hi" +} +``` + +Twitter Example payload_ + + + +```json +{ + "type": "Twitter", + "message": "Programming is fun!" +} +``` + + + +_Successful function response:_ + + + +```json +{ + "success": true +} +``` + + + +_Error function response:_ + + + +```json +{ + "success": false, + "message": "Failed to send message,check webhook URL" +} +``` + +## 📝 Variables + + + +List of variables used by this cloud function: + + + +Mailgun + + + +- **MAILGUN_API_KEY** - API Key for Mailgun +- **MAILGUN_DOMAIN** - Domain Name from Mailgun + + + +Discord + + + +- **DISCORD_WEBHOOK_URL** - Webhook URL for Discord + + + +Twilio + + + +- **TWILIO_ACCOUNT_SID** - Acount SID from Twilio +- **TWILIO_AUTH_TOKEN** - Auth Token from Twilio +- **TWILIO_SENDER** - Sender Phone Number from Twilio + +Twitter +- **TWITTER_API_KEY** - API Key for Twitter +- **TWITTER_API_KEY_SECRET** - API Key Secret for Twitter +- **TWITTER_ACCESS_TOKEN** - Access Token from Twitter +- **TWITTER_ACCESS_TOKEN_SECRET** - Access Token Secret from Twitter + + +## 🚀 Deployment + + + +1. Clone this repository, and enter this function folder: + + + +``` +$ git clone https://github.com/open-runtimes/examples.git && cd examples +$ cd kotlin/send_message +``` + + + +2. Enter this function folder and build the code: + + + +```bash +docker run --rm --interactive --tty --volume $PWD:/usr/code openruntimes/kotlin:v1.6.0 sh /usr/local/src/build.kotlin +``` + + + +As a result, a `kotlin.tar.gz` file will be generated. + + + +3. Start the Open Runtime: + + + +```bash +docker run -p 3000:3000 -e INTERNAL_RUNTIME_KEY=secret-key -e INTERNAL_RUNTIME_ENTRYPOINT=main.kt --rm --interactive --tty --volume $PWD/kotlin.tar.gz:/tmp/kotlin.tar.gz:ro openruntimes/kotlin:v1.6.0 sh /usr/local/src/start.kotlin +``` + + + +Your function is now listening on port `3000`, and you can execute it by sending `POST` request with appropriate authorization headers. To learn more about runtime, you can visit Kotlin runtime [README](https://github.com/open-runtimes/open-runtimes/tree/main/runtimes/kotlin-1.6/example). + + + +4. Curl Command ( Email ) + + + +```bash +curl -X POST http://localhost:3000/ -d '{"variables": {"MAILGUN_API_KEY":"YOUR_MAILGUN_API_KEY","MAILGUN_DOMAIN":"YOUR_MAILGUN_DOMAIN"},"payload": "{\"type\": \"Email\",\"receiver\": \"hello@example.com\",\"message\": \"Programming is fun!\",\"subject\": \"Programming is funny!\"}"}' -H "X-Internal-Challenge: secret-key" -H "Content-Type: application/json" +``` + + + +## 📝 Notes + + + +- This function is designed for use with Appwrite Cloud Functions. You can learn more about it in [Appwrite docs](https://appwrite.io/docs/functions). From 562a787b31a02564cfd66c6dba31bb08ab67be38 Mon Sep 17 00:00:00 2001 From: Tam Nguyen <98732550+softTam@users.noreply.github.com> Date: Thu, 13 Jul 2023 00:09:03 +0000 Subject: [PATCH 20/23] Added more input validation. Ensured consistency in stylyes. Moved Index.kt into src folder. --- kotlin/sendMessage/README.md | 10 +-- kotlin/sendMessage/deps.gradle | 2 +- kotlin/sendMessage/{ => src}/Index.kt | 121 +++++++++++++++----------- 3 files changed, 76 insertions(+), 57 deletions(-) rename kotlin/sendMessage/{ => src}/Index.kt (72%) diff --git a/kotlin/sendMessage/README.md b/kotlin/sendMessage/README.md index d62e8da0..ab627f78 100644 --- a/kotlin/sendMessage/README.md +++ b/kotlin/sendMessage/README.md @@ -50,7 +50,7 @@ _Discord Example payload_ } ``` -Twitter Example payload_ +_Twitter Example payload_ @@ -146,7 +146,7 @@ $ cd kotlin/send_message ```bash -docker run --rm --interactive --tty --volume $PWD:/usr/code openruntimes/kotlin:v1.6.0 sh /usr/local/src/build.kotlin +docker run -e INTERNAL_RUNTIME_ENTRYPOINT=Index.kt --rm --interactive --tty --volume $PWD:/usr/code openruntimes/kotlin:v2-1.6 sh /usr/local/src/build.sh ``` @@ -155,12 +155,12 @@ As a result, a `kotlin.tar.gz` file will be generated. -3. Start the Open Runtime: +3. Spin-up open-runtime: ```bash -docker run -p 3000:3000 -e INTERNAL_RUNTIME_KEY=secret-key -e INTERNAL_RUNTIME_ENTRYPOINT=main.kt --rm --interactive --tty --volume $PWD/kotlin.tar.gz:/tmp/kotlin.tar.gz:ro openruntimes/kotlin:v1.6.0 sh /usr/local/src/start.kotlin +docker run -p 3000:3000 -e INTERNAL_RUNTIME_KEY=secret-key --rm --interactive --tty --volume $PWD/code.tar.gz:/tmp/code.tar.gz:ro openruntimes/kotlin:v2-1.6 sh /usr/local/src/start.sh ``` @@ -169,7 +169,7 @@ Your function is now listening on port `3000`, and you can execute it by sending -4. Curl Command ( Email ) +4. In new terminal window, execute the function. Example curl command (Email): diff --git a/kotlin/sendMessage/deps.gradle b/kotlin/sendMessage/deps.gradle index 3ab72166..ef01f0f4 100644 --- a/kotlin/sendMessage/deps.gradle +++ b/kotlin/sendMessage/deps.gradle @@ -1,4 +1,4 @@ dependencies { implementation 'com.google.code.gson:gson:2.9.0' - implementation("com.chromasgaming:ktweet:1.3.0") + implementation 'com.chromasgaming:ktweet:1.3.0' } \ No newline at end of file diff --git a/kotlin/sendMessage/Index.kt b/kotlin/sendMessage/src/Index.kt similarity index 72% rename from kotlin/sendMessage/Index.kt rename to kotlin/sendMessage/src/Index.kt index edd425b5..d2adc3f5 100644 --- a/kotlin/sendMessage/Index.kt +++ b/kotlin/sendMessage/src/Index.kt @@ -14,6 +14,8 @@ import java.nio.charset.StandardCharsets import com.chromasgaming.ktweet.oauth.SignatureBuilder import com.chromasgaming.ktweet.oauth.buildSignature + + fun getErrorResponseWithMessage(message: String? = "Some error occurred"): Map { return mapOf( "success" to false, @@ -21,13 +23,15 @@ fun getErrorResponseWithMessage(message: String? = "Some error occurred"): Map, email: String?, message: String?, subject: String?): Map{ if (email.isNullOrEmpty() || message.isNullOrEmpty() || subject.isNullOrEmpty()){ return getErrorResponseWithMessage("Missing email, message, or subject") } - val domain = variables["MAILGUN_DOMAIN"] - val apiKey = variables["MAILGUN_API_KEY"] + val domain = variables["MAILGUN_DOMAIN"]?:"" + val apiKey = variables["MAILGUN_API_KEY"]?:"" if (domain.isNullOrEmpty()){ return getErrorResponseWithMessage("Missing Mailgun domain") @@ -36,73 +40,84 @@ fun sendEmailMailgun(variables: Map, email: String?, message: St return getErrorResponseWithMessage("Missing Mailgun API key") } - val url = URL("https://api.mailgun.net/v3/$domain/messages") - val auth = "api:$apiKey" - val authEncoded = Base64.getEncoder().encodeToString(auth.toByteArray(StandardCharsets.UTF_8)) - val emailData = "from=&to=$email&subject=$subject&text=$message" - - val connection = url.openConnection() as HttpURLConnection - connection.doOutput = true - connection.requestMethod = "POST" - connection.addRequestProperty("Authorization", "Basic $authEncoded") - - val outputStream: OutputStream = connection.outputStream - outputStream.write(emailData.toByteArray(Charsets.UTF_8)) - outputStream.flush() - - val responseCode = connection.responseCode - val responseMessage = connection.responseMessage - connection.disconnect() - if (responseCode != HttpURLConnection.HTTP_OK) { - return getErrorResponseWithMessage("$responseCode - $responseMessage") + try { + val url = URL("https://api.mailgun.net/v3/$domain/messages") + val auth = "api:$apiKey" + val authEncoded = Base64.getEncoder().encodeToString(auth.toByteArray(StandardCharsets.UTF_8)) + val emailData = "from=&to=$email&subject=$subject&text=$message" + + val connection = url.openConnection() as HttpURLConnection + connection.doOutput = true + connection.requestMethod = "POST" + connection.addRequestProperty("Authorization", "Basic $authEncoded") + + val outputStream: OutputStream = connection.outputStream + outputStream.write(emailData.toByteArray(Charsets.UTF_8)) + outputStream.flush() + + val responseCode = connection.responseCode + val responseMessage = connection.responseMessage + connection.disconnect() + if (responseCode != HttpURLConnection.HTTP_OK) { + return getErrorResponseWithMessage("Error: $responseCode -> $responseMessage") + } + return mapOf("success" to true) + + } catch (e: IllegalArgumentException) { // if variable receiver is set to "invalid" + return getErrorResponseWithMessage("Error: ${e.message}") + } catch (e: IOException) { // if network-related issues such as failure to establish a connection or send the HTTP request to the Twilio APi this will catch it + return getErrorResponseWithMessage("Error: ${e.message}") } - - return mapOf("success" to true) } + + fun sendMessageDiscordWebhook(variables: Map, message: String?): Map { + if (message.isNullOrEmpty()) { + return getErrorResponseWithMessage("No message provided") + } + val webhook = variables["DISCORD_WEBHOOK_URL"]?:"" + if (webhook.isNullOrEmpty()) { + return getErrorResponseWithMessage("Payload doesn't contain a Discord Webhook URL") + } try { - if (webhook.isEmpty() || webhook.trim().isEmpty()) { - return getErrorResponseWithMessage("Payload doesn't contain a Discord Webhook URL") - } - val url = URL(webhook) - val conn: HttpURLConnection = url.openConnection() as HttpURLConnection + val connection: HttpURLConnection = url.openConnection() as HttpURLConnection val body = "{\"content\":\"$message\"}" - conn.addRequestProperty("Content-Type", "application/json") - conn.requestMethod = "POST" - conn.doOutput = true + connection.addRequestProperty("Content-Type", "application/json") + connection.requestMethod = "POST" + connection.doOutput = true - val os: OutputStream = conn.outputStream + val outputStream: OutputStream = connection.outputStream val input: ByteArray = body.toByteArray(Charsets.UTF_8) - os.write(input) + outputStream.write(input) - val responseCode: Int = conn.responseCode - val responseMessage = conn.responseMessage + val responseCode: Int = connection.responseCode + val responseMessage = connection.responseMessage - os.close() - conn.disconnect() + outputStream.close() + connection.disconnect() if (responseCode / 100 != 2) { // 201 - CREATED or 204 - Successful but no content return getErrorResponseWithMessage("Error: #$responseCode - > $responseMessage") } return mapOf("success" to true) - } catch (e: IllegalArgumentException) { // if variable receiver is set to "invalid" - return getErrorResponseWithMessage(e.message) + } catch (e: IllegalArgumentException) { + return getErrorResponseWithMessage("Error: ${e.message}") } catch (e: IOException) { // if network-related issues such as failure to establish a connection or send the HTTP request to the Twilio APi this will catch it - return getErrorResponseWithMessage(e.message) + return getErrorResponseWithMessage("Error: ${e.message}") } } fun sendSmsTwilio(variables: Map, receiver: String?, message: String?): Map{ - val accountID = variables.get("TWILIO_ACCOUNT_SID") // Acount SID from Twilio - val authToken = variables.get("TWILIO_AUTH_TOKEN") // Auth Token from Twilio - val sender = variables.get("TWILIO_SENDER") // Sender Phone Number from Twilio | Mandatory format: +# ### ### #### (all together) + val accountID = variables["TWILIO_ACCOUNT_SID"]?:"" // Acount SID from Twilio + val authToken = variables["TWILIO_AUTH_TOKEN"]?:"" // Auth Token from Twilio + val sender = variables["TWILIO_SENDER"]?:"" // Sender Phone Number from Twilio | Mandatory format: +# ### ### #### (all together) if (accountID.isNullOrEmpty()) { @@ -114,15 +129,15 @@ fun sendSmsTwilio(variables: Map, receiver: String?, message: St } if (sender.isNullOrEmpty()) { - return getErrorResponseWithMessage("Sender is not set") + return getErrorResponseWithMessage("Missing Twilio sender") } if (receiver.isNullOrEmpty()) { - return getErrorResponseWithMessage("Receiver is not set") + return getErrorResponseWithMessage("No phone number provided") } if (message.isNullOrEmpty()) { - return getErrorResponseWithMessage("Message is not set") + return getErrorResponseWithMessage("No message provided") } @@ -162,25 +177,29 @@ fun sendSmsTwilio(variables: Map, receiver: String?, message: St } fun sendTweet(variables: Map, message: String?): Map { + if (message.isNullOrEmpty()) { + return getErrorResponseWithMessage("No message provided") + } + val apiKey = variables["TWITTER_API_KEY"]?:"" val apiSecret = variables["TWITTER_API_KEY_SECRET"]?:"" val accessToken = variables["TWITTER_ACCESS_TOKEN"]?:"" val accessTokenSecret = variables["TWITTER_ACCESS_TOKEN_SECRET"]?:"" if (apiKey.isNullOrEmpty()) { - return getErrorResponseWithMessage("Payload doesn't contain an API key (i.e. consumer key)") + return getErrorResponseWithMessage("Missing Twitter API key (i.e. consumer key)") } if (apiSecret.isNullOrEmpty()) { - return getErrorResponseWithMessage("Payload doesn't contain an API key Secret (i.e. consumer secret)") + return getErrorResponseWithMessage("Missing Twitter API key secret (i.e. consumer secret)") } if (accessToken.isNullOrEmpty()) { - return getErrorResponseWithMessage("Payload doesn't contain an access token") + return getErrorResponseWithMessage("Missing Twitter access token") } if (accessTokenSecret.isNullOrEmpty()) { - return getErrorResponseWithMessage("Payload doesn't contain an an access token secret") + return getErrorResponseWithMessage("Missing Twitter access token secret") } try { @@ -207,7 +226,7 @@ fun sendTweet(variables: Map, message: String?): Map Date: Thu, 13 Jul 2023 00:49:22 +0000 Subject: [PATCH 21/23] Fixed READ.me file --- kotlin/sendMessage/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kotlin/sendMessage/README.md b/kotlin/sendMessage/README.md index ab627f78..6fab7f36 100644 --- a/kotlin/sendMessage/README.md +++ b/kotlin/sendMessage/README.md @@ -136,7 +136,7 @@ Twitter ``` $ git clone https://github.com/open-runtimes/examples.git && cd examples -$ cd kotlin/send_message +$ cd kotlin/sendMessage ``` @@ -151,7 +151,7 @@ docker run -e INTERNAL_RUNTIME_ENTRYPOINT=Index.kt --rm --interactive --tty --vo -As a result, a `kotlin.tar.gz` file will be generated. +As a result, a `code.tar.gz` file will be generated. From 57c23b11c00bd5e774a2cb10dea5be69681ed6e6 Mon Sep 17 00:00:00 2001 From: Arturo Date: Thu, 13 Jul 2023 01:33:31 +0000 Subject: [PATCH 22/23] Fix: wrong path declared in READ.me file --- kotlin/sendMessage/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kotlin/sendMessage/README.md b/kotlin/sendMessage/README.md index 6fab7f36..42459d5e 100644 --- a/kotlin/sendMessage/README.md +++ b/kotlin/sendMessage/README.md @@ -146,7 +146,7 @@ $ cd kotlin/sendMessage ```bash -docker run -e INTERNAL_RUNTIME_ENTRYPOINT=Index.kt --rm --interactive --tty --volume $PWD:/usr/code openruntimes/kotlin:v2-1.6 sh /usr/local/src/build.sh +docker run -e INTERNAL_RUNTIME_ENTRYPOINT=src/Index.kt --rm --interactive --tty --volume $PWD:/usr/code openruntimes/kotlin:v2-1.6 sh /usr/local/src/build.sh ``` From 0e251e16f4cccc7a899f3b7a3ad6175ca512d064 Mon Sep 17 00:00:00 2001 From: Arturo Date: Tue, 25 Jul 2023 23:10:33 +0000 Subject: [PATCH 23/23] Minimized the number of newlines * Index.kt * README.md --- kotlin/sendMessage/README.md | 66 +-------------------------------- kotlin/sendMessage/src/Index.kt | 7 +--- 2 files changed, 2 insertions(+), 71 deletions(-) diff --git a/kotlin/sendMessage/README.md b/kotlin/sendMessage/README.md index 42459d5e..d8b23a89 100644 --- a/kotlin/sendMessage/README.md +++ b/kotlin/sendMessage/README.md @@ -1,18 +1,11 @@ - # SendMessage() - A Kotlin Cloud Function for sending a message using a specific channel to a receiver - - +A Kotlin Cloud Function for sending a message using a specific channel to a receiver Supported channels are `SMS`, `Email` , `Disocrd`, and `Twitter`. - - _SMS Example payload_ - - ```json { "type": "SMS", @@ -21,12 +14,8 @@ _SMS Example payload_ } ``` - - _Email Example payload_ - - ```json { "type": "Email", @@ -36,12 +25,8 @@ _Email Example payload_ } ``` - - _Discord Example payload_ - - ```json { @@ -52,8 +37,6 @@ _Discord Example payload_ _Twitter Example payload_ - - ```json { "type": "Twitter", @@ -61,24 +44,16 @@ _Twitter Example payload_ } ``` - - _Successful function response:_ - - ```json { "success": true } ``` - - _Error function response:_ - - ```json { "success": false, @@ -88,33 +63,19 @@ _Error function response:_ ## 📝 Variables - - List of variables used by this cloud function: - - Mailgun - - - **MAILGUN_API_KEY** - API Key for Mailgun - **MAILGUN_DOMAIN** - Domain Name from Mailgun - - Discord - - - **DISCORD_WEBHOOK_URL** - Webhook URL for Discord - - Twilio - - - **TWILIO_ACCOUNT_SID** - Acount SID from Twilio - **TWILIO_AUTH_TOKEN** - Auth Token from Twilio - **TWILIO_SENDER** - Sender Phone Number from Twilio @@ -125,62 +86,37 @@ Twitter - **TWITTER_ACCESS_TOKEN** - Access Token from Twitter - **TWITTER_ACCESS_TOKEN_SECRET** - Access Token Secret from Twitter - ## 🚀 Deployment - - 1. Clone this repository, and enter this function folder: - - ``` $ git clone https://github.com/open-runtimes/examples.git && cd examples $ cd kotlin/sendMessage ``` - - 2. Enter this function folder and build the code: - - ```bash docker run -e INTERNAL_RUNTIME_ENTRYPOINT=src/Index.kt --rm --interactive --tty --volume $PWD:/usr/code openruntimes/kotlin:v2-1.6 sh /usr/local/src/build.sh ``` - - As a result, a `code.tar.gz` file will be generated. - - 3. Spin-up open-runtime: - - ```bash docker run -p 3000:3000 -e INTERNAL_RUNTIME_KEY=secret-key --rm --interactive --tty --volume $PWD/code.tar.gz:/tmp/code.tar.gz:ro openruntimes/kotlin:v2-1.6 sh /usr/local/src/start.sh ``` - - Your function is now listening on port `3000`, and you can execute it by sending `POST` request with appropriate authorization headers. To learn more about runtime, you can visit Kotlin runtime [README](https://github.com/open-runtimes/open-runtimes/tree/main/runtimes/kotlin-1.6/example). - - 4. In new terminal window, execute the function. Example curl command (Email): - - ```bash curl -X POST http://localhost:3000/ -d '{"variables": {"MAILGUN_API_KEY":"YOUR_MAILGUN_API_KEY","MAILGUN_DOMAIN":"YOUR_MAILGUN_DOMAIN"},"payload": "{\"type\": \"Email\",\"receiver\": \"hello@example.com\",\"message\": \"Programming is fun!\",\"subject\": \"Programming is funny!\"}"}' -H "X-Internal-Challenge: secret-key" -H "Content-Type: application/json" ``` - - ## 📝 Notes - - - This function is designed for use with Appwrite Cloud Functions. You can learn more about it in [Appwrite docs](https://appwrite.io/docs/functions). diff --git a/kotlin/sendMessage/src/Index.kt b/kotlin/sendMessage/src/Index.kt index d2adc3f5..2d649721 100644 --- a/kotlin/sendMessage/src/Index.kt +++ b/kotlin/sendMessage/src/Index.kt @@ -14,8 +14,6 @@ import java.nio.charset.StandardCharsets import com.chromasgaming.ktweet.oauth.SignatureBuilder import com.chromasgaming.ktweet.oauth.buildSignature - - fun getErrorResponseWithMessage(message: String? = "Some error occurred"): Map { return mapOf( "success" to false, @@ -23,8 +21,6 @@ fun getErrorResponseWithMessage(message: String? = "Some error occurred"): Map, email: String?, message: String?, subject: String?): Map{ if (email.isNullOrEmpty() || message.isNullOrEmpty() || subject.isNullOrEmpty()){ return getErrorResponseWithMessage("Missing email, message, or subject") @@ -36,6 +32,7 @@ fun sendEmailMailgun(variables: Map, email: String?, message: St if (domain.isNullOrEmpty()){ return getErrorResponseWithMessage("Missing Mailgun domain") } + if (apiKey.isNullOrEmpty()){ return getErrorResponseWithMessage("Missing Mailgun API key") } @@ -70,8 +67,6 @@ fun sendEmailMailgun(variables: Map, email: String?, message: St } } - - fun sendMessageDiscordWebhook(variables: Map, message: String?): Map { if (message.isNullOrEmpty()) { return getErrorResponseWithMessage("No message provided")