diff --git a/ballerina/Dependencies.toml b/ballerina/Dependencies.toml index a536a70..cf56ab6 100644 --- a/ballerina/Dependencies.toml +++ b/ballerina/Dependencies.toml @@ -5,7 +5,7 @@ [ballerina] dependencies-toml-version = "2" -distribution-version = "2201.9.0" +distribution-version = "2201.9.1" [[package]] org = "ballerina" @@ -147,6 +147,15 @@ dependencies = [ {org = "ballerina", name = "jballerina.java"} ] +[[package]] +org = "ballerina" +name = "lang.error" +version = "0.0.0" +scope = "testOnly" +dependencies = [ + {org = "ballerina", name = "jballerina.java"} +] + [[package]] org = "ballerina" name = "lang.int" @@ -205,6 +214,9 @@ dependencies = [ {org = "ballerina", name = "lang.value"}, {org = "ballerina", name = "observe"} ] +modules = [ + {org = "ballerina", packageName = "log", moduleName = "log"} +] [[package]] org = "ballerina" @@ -245,6 +257,9 @@ dependencies = [ {org = "ballerina", name = "io"}, {org = "ballerina", name = "jballerina.java"} ] +modules = [ + {org = "ballerina", packageName = "os", moduleName = "os"} +] [[package]] org = "ballerina" @@ -255,6 +270,20 @@ dependencies = [ {org = "ballerina", name = "time"} ] +[[package]] +org = "ballerina" +name = "test" +version = "0.0.0" +scope = "testOnly" +dependencies = [ + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.array"}, + {org = "ballerina", name = "lang.error"} +] +modules = [ + {org = "ballerina", packageName = "test", moduleName = "test"} +] + [[package]] org = "ballerina" name = "time" @@ -293,6 +322,9 @@ version = "4.0.0" dependencies = [ {org = "ballerina", name = "constraint"}, {org = "ballerina", name = "http"}, + {org = "ballerina", name = "log"}, + {org = "ballerina", name = "os"}, + {org = "ballerina", name = "test"}, {org = "ballerina", name = "url"}, {org = "ballerinai", name = "observe"} ] diff --git a/examples/README.md b/examples/README.md new file mode 100644 index 0000000..e3bbf05 --- /dev/null +++ b/examples/README.md @@ -0,0 +1,47 @@ +# Examples + +The `ballerinax/slack` connector provides practical examples illustrating usage in various scenarios, covering use cases like cache management, session management, and rate limiting. + +## Prerequisites + +1. Generate Slack token to authenticate the connector as described in the [Setup guide](https://central.ballerina.io/ballerinax/slack/latest#prerequisites). + +2. For each example, create a `Config.toml` file the related configuration. Here's an example of how your `Config.toml` file should look: + + ```toml + token = "" + ``` + +## Running an Example + +Execute the following commands to build an example from the source: + +- To build an example: + + ```bash + bal build + ``` + +- To run an example: + + ```bash + bal run + ``` + +## Building the Examples with the Local Module + +**Warning**: Due to the absence of support for reading local repositories for single Ballerina files, the Bala of the module is manually written to the central repository as a workaround. Consequently, the bash script may modify your local Ballerina repositories. + +Execute the following commands to build all the examples against the changes you have made to the module locally: + +- To build all the examples: + + ```bash + ./build.sh build + ``` + +- To run all the examples: + + ```bash + ./build.sh run + ``` diff --git a/examples/build.gradle b/examples/build.gradle new file mode 100644 index 0000000..6c50681 --- /dev/null +++ b/examples/build.gradle @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import org.apache.tools.ant.taskdefs.condition.Os + +apply plugin: 'java' + +def graalvmFlag = "" + +task testExamples { + if (project.hasProperty("balGraalVMTest")) { + graalvmFlag = "--graalvm" + } + doLast { + try { + exec { + workingDir project.projectDir + println("Working dir: ${workingDir}") + if (Os.isFamily(Os.FAMILY_WINDOWS)) { + commandLine 'cmd', "/c", "chmod +x ./build.sh && ./build.sh run && exit %%ERRORLEVEL%%" + } else { + commandLine 'sh', "-c", "chmod +x ./build.sh && ./build.sh run" + } + } + } catch (Exception e) { + println("Example Build failed: " + e.message) + throw e + } + } +} + +task buildExamples { + gradle.taskGraph.whenReady { graph -> + if (graph.hasTask(":slack-examples:test")) { + buildExamples.enabled = false + } else { + testExamples.enabled = false + } + } + doLast { + try { + exec { + workingDir project.projectDir + println("Working dir: ${workingDir}") + if (Os.isFamily(Os.FAMILY_WINDOWS)) { + commandLine 'cmd', "/c", "chmod +x ./build.sh && ./build.sh build && exit %%ERRORLEVEL%%" + } else { + commandLine 'sh', "-c", "chmod +x ./build.sh && ./build.sh build" + } + } + } catch (Exception e) { + println("Example Build failed: " + e.message) + throw e + } + } +} + +buildExamples.dependsOn ":slack-ballerina:build" +testExamples.dependsOn ":slack-ballerina:build" + +// TODO: Enable the examples build once https://github.com/ballerina-platform/ballerina-library/issues/6135 is fixed +// test.dependsOn testExamples +// build.dependsOn buildExamples diff --git a/examples/build.sh b/examples/build.sh new file mode 100644 index 0000000..10fe84c --- /dev/null +++ b/examples/build.sh @@ -0,0 +1,63 @@ +#!/bin/bash + +BAL_EXAMPLES_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +BAL_CENTRAL_DIR="$HOME/.ballerina/repositories/central.ballerina.io" +BAL_HOME_DIR="$BAL_EXAMPLES_DIR/../ballerina" + +set -e + +case "$1" in +build) + BAL_CMD="build" + ;; +run) + BAL_CMD="run" + ;; +*) + echo "Invalid command provided: '$1'. Please provide 'build' or 'run' as the command." + exit 1 + ;; +esac + +# Read Ballerina package name +BAL_PACKAGE_NAME=$(awk -F'"' '/^name/ {print $2}' "$BAL_HOME_DIR/Ballerina.toml") + +# Push the package to the local repository +cd "$BAL_HOME_DIR" && + bal pack && + bal push --repository=local + +# Remove the cache directories in the repositories +cacheDirs=$(ls -d $BAL_CENTRAL_DIR/cache-* 2>/dev/null) || true +for dir in "${cacheDirs[@]}"; do + [ -d "$dir" ] && rm -r "$dir" +done +echo "Successfully cleaned the cache directories" + +# Create the package directory in the central repository, this will not be present if no modules are pulled +mkdir -p "$BAL_CENTRAL_DIR/bala/ballerinax/$BAL_PACKAGE_NAME" + +# Update the central repository +BAL_DESTINATION_DIR="$HOME/.ballerina/repositories/central.ballerina.io/bala/ballerinax/$BAL_PACKAGE_NAME" +BAL_SOURCE_DIR="$HOME/.ballerina/repositories/local/bala/ballerinax/$BAL_PACKAGE_NAME" +[ -d "$BAL_DESTINATION_DIR" ] && rm -r "$BAL_DESTINATION_DIR" +[ -d "$BAL_SOURCE_DIR" ] && cp -r "$BAL_SOURCE_DIR" "$BAL_DESTINATION_DIR" +echo "Successfully updated the local central repositories" + +echo "$BAL_DESTINATION_DIR" +echo "$BAL_SOURCE_DIR" + +# Loop through examples in the examples directory +cd "$BAL_EXAMPLES_DIR" +for dir in $(find "$BAL_EXAMPLES_DIR" -type d -maxdepth 1 -mindepth 1); do + # Skip the build directory + if [[ "$dir" == *build ]]; then + continue + fi + (cd "$dir" && bal "$BAL_CMD" --offline && cd ..); +done + +# Remove generated JAR files +find "$BAL_HOME_DIR" -maxdepth 1 -type f -name "*.jar" | while read -r JAR_FILE; do + rm "$JAR_FILE" +done diff --git a/examples/survey-feedback-analysis/.github/README.md b/examples/survey-feedback-analysis/.github/README.md new file mode 120000 index 0000000..8e61c9d --- /dev/null +++ b/examples/survey-feedback-analysis/.github/README.md @@ -0,0 +1 @@ +../Slack survey feedback anaysis.md \ No newline at end of file diff --git a/examples/survey-feedback-analysis/Ballerina.toml b/examples/survey-feedback-analysis/Ballerina.toml new file mode 100644 index 0000000..ab37f21 --- /dev/null +++ b/examples/survey-feedback-analysis/Ballerina.toml @@ -0,0 +1,4 @@ +org = "wso2" +name = "survey_feedback_analysis" +version = "0.1.0" +distribution = "2201.9.0" diff --git a/examples/survey-feedback-analysis/Slack survey feedback anaysis.md b/examples/survey-feedback-analysis/Slack survey feedback anaysis.md new file mode 100644 index 0000000..505570c --- /dev/null +++ b/examples/survey-feedback-analysis/Slack survey feedback anaysis.md @@ -0,0 +1,25 @@ +# Slack survey feedback analysis + +This use case demonstrates how the Slack API can be utilized to perform a company-wide survey by creating a dedicated channel to receive and track feedback replies. + +## Prerequisites + +### 1. Setup Slack account + +Generate Slack token to authenticate the connector as described in the [Setup guide](https://central.ballerina.io/ballerinax/slack/latest#prerequisites). + +### 2. Configuration + +Create a `Config.toml` file in the example root directory, and update your Slack account token as follows: + +```toml +token = "" +``` + +## Run the example + +Execute the following command to run the example: + +```ballerina +bal run +``` diff --git a/examples/survey-feedback-analysis/main.bal b/examples/survey-feedback-analysis/main.bal new file mode 100644 index 0000000..7117e89 --- /dev/null +++ b/examples/survey-feedback-analysis/main.bal @@ -0,0 +1,97 @@ +// Copyright (c) 2024 WSO2 LLC. (http://www.wso2.org). +// +// WSO2 LLC. licenses this file to you under the Apache License, +// Version 2.0 (the "License"); you may not use this file except +// in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +import ballerina/io; +import ballerina/log; +import ballerinax/slack; + +configurable string token = ?; + +string channelName = "survey-coordination"; +string surveyRequestMessage = "Reply to this survey message to give input on the company"; + +type MessagesItem record { + string text; + string thread_ts; + string ts; + string 'type; + string user; + string parent_user_id?; + string last_read?; + int reply_count?; + boolean subscribed?; + int unread_count?; +}; + +type Response_metadata record { + string next_cursor; +}; + +type RepliesResponse record { + boolean has_more; + MessagesItem[] messages; + boolean ok; + Response_metadata response_metadata; +}; + +final slack:Client slack = check new ({ + auth: { + token + } +}); + +public function main() returns error? { + + // Create a new channel for the survey + json|error createChannelResponse = check slack->/conversations\.create.post({name: channelName}); + if createChannelResponse is error { + log:printError("Error creating the survey conversation: ", createChannelResponse); + return; + } + + // Post a message to the conversation created and get the timestamp of the message + json|error sendMsgResponse = slack->/chat\.postMessage.post({channel: channelName, text: surveyRequestMessage}); + if sendMsgResponse is error { + log:printError("Error posting the survey message: ", sendMsgResponse); + return; + } + string messageTimestamp = check sendMsgResponse.message.ts; + + // Check for replies to the survey message + json|error repliesResponse = slack->/conversations\.replies({channel: channelName, ts: messageTimestamp}); + if repliesResponse is error { + log:printError("Error getting replies to the survey message: ", repliesResponse); + return; + } + + RepliesResponse|error replies = repliesResponse.cloneWithType(); + if replies is error { + log:printError("Error mapping the JSON response to the RepliesResponse type: ", replies); + return; + } + + // Get the messages from the replies + MessagesItem[] messages = replies.messages; + + // Print the survey responses + io:println("Replies to the survey message:"); + io:println("-----------------------------"); + int counter = 1; + foreach MessagesItem message in messages { + io:println(string `Reply ${counter}: ${message.text}`); + counter += 1; + } +}