Fred
Fred is a Java Framework for Building Slack Bots.
Current Version: 1.0.2
Installation
To add a dependency using Maven, use the following:
<dependency>
<groupId>com.clivern</groupId>
<artifactId>fred</artifactId>
<version>1.0.2</version>
</dependency>
To add a dependency using Gradle, use the following:
dependencies {
compile 'com.clivern:fred:1.0.2'
}
To add a dependency using Scala SBT, use the following:
libraryDependencies += "com.clivern" % "fred" % "1.0.2"
Usage
After adding the package as a dependency, Please read the following steps:
Basic Configurations
In order to cofigure the package create config.properties
file with the following data
client_id=Application Client ID
client_secret=Application Client Secret
scope=Application Scope
redirect_uri=Oauth Secured URL
state_type=State Type (for example. vary)
state=State Key
team=Slack Team Name
verification_token=Verification Token Goes Here
logging_level=tarce or debug or info or warning or error
logging_file_path=src/main/java/resources/
logging_file_format=current_date or app
logging_log_type=file or console or both
logging_current_date_format=yyyy-MM-dd
logging_append=true or false
logging_buffered=true or false
Build Oauth Redirect URL
Create a route to return the Oauth redirect URL like the following:
import com.clivern.fred.util.*;
import com.mashape.unirest.http.exceptions.UnirestException;
Config config = new Config();
config.loadPropertiesFile("config.properties");
config.configLogger();
Oauth oauth = new Oauth(config, log);
return "<a href='" + oauth.getRedirectURL() + "'>Auth</a>";
So let's say we use Spark Java Framework for our bot, Our route and callback will look like the following:
import static spark.Spark.*;
import com.clivern.fred.util.*;
import com.mashape.unirest.http.exceptions.UnirestException;
public class Main {
public static void main(String[] args) throws UnirestException
{
get("/", (request, response) -> {
Config config = new Config();
config.loadPropertiesFile("config.properties");
config.configLogger();
Oauth oauth = new Oauth(config);
return "<a href='" + oauth.getRedirectURL() + "'>Auth</a>";
});
}
}
Build Oauth Webhook
In order to verify the incoming user token and fetch the access token for that user, We will build and a route that do these tasks and we already provided this URL in the config.properties
file as redirect_uri
:
import static spark.Spark.*;
import com.clivern.fred.util.*;
import com.mashape.unirest.http.exceptions.UnirestException;
String code = // Get code query parameter value from the current URL
String state = // Get state query parameter value from the current URL
String error = // Get error query parameter value from the current URL
Config config = new Config();
config.loadPropertiesFile("config.properties");
config.configLogger();
Oauth oauth = new Oauth(config);
Boolean status = oauth.issueToken(code, state, error);
Boolean fetch = oauth.fetchAccessToken();
if( status && fetch ){
return "State: " + oauth.getState() + "<br/>" +
"Client ID: " + oauth.getClientId() + "<br/>" +
"Client Secret: " + oauth.getClientSecret() + "<br/>" +
"Scope: " + oauth.getScope() + "<br/>" +
"Redirect Uri: " + oauth.getRedirectUri() + "<br/>" +
"State Type: " + oauth.getStateType() + "<br/>" +
"Team: " + oauth.getTeam() + "<br/>" +
"Incoming Code: " + oauth.getIncomingCode() + "<br/>" +
"Incoming State: " + oauth.getIncomingState() + "<br/>" +
"Incoming Error: " + oauth.getIncomingError() + "<br/>" +
"Incoming Access Token: " + oauth.getIncomingAccessToken() + "<br/>" +
"Incoming Scope: " + oauth.getIncomingScope() + "<br/>" +
"Incoming User ID: " + oauth.getIncomingUserId() + "<br/>" +
"Incoming Team Name: " + oauth.getIncomingTeamName() + "<br/>" +
"Incoming Team ID: " + oauth.getIncomingTeamId() + "<br/>" +
"Incoming Webhook URL: " + oauth.getIncomingWebhookUrl() + "<br/>" +
"Incoming Webhook Channel: " + oauth.getIncomingWebhookChannel() + "<br/>" +
"Incoming Webhook Config URL: " + oauth.getIncomingWebhookConfigUrl() + "<br/>" +
"Incoming Bot User ID: " + oauth.getIncomingBotUserId() + "<br/>" +
"Incoming Bot Access Token: " + oauth.getIncomingBotAccessToken() + "<br/>";
}else{
return "Error";
}
So let's say we use Spark Java Framework for our bot, Our route and callback will look like the following:
import static spark.Spark.*;
import com.clivern.fred.util.*;
import com.mashape.unirest.http.exceptions.UnirestException;
public class Main {
public static void main(String[] args) throws UnirestException
{
get("/", (request, response) -> {
Config config = new Config();
config.loadPropertiesFile("config.properties");
config.configLogger();
Oauth oauth = new Oauth(config);
return "<a href='" + oauth.getRedirectURL() + "'>Auth</a>";
});
get("/oauth", (request, response) -> {
Config config = new Config();
config.loadPropertiesFile("config.properties");
config.configLogger();
Oauth oauth = new Oauth(config);
Boolean status = oauth.issueToken(
( request.queryParams("code") != null ) ? request.queryParams("code") : "",
( request.queryParams("state") != null ) ? request.queryParams("state") : "",
( request.queryParams("error") != null ) ? request.queryParams("error") : ""
);
Boolean fetch = oauth.fetchAccessToken();
if( status && fetch ){
return "State: " + oauth.getState() + "<br/>" +
"Client ID: " + oauth.getClientId() + "<br/>" +
"Client Secret: " + oauth.getClientSecret() + "<br/>" +
"Scope: " + oauth.getScope() + "<br/>" +
"Redirect Uri: " + oauth.getRedirectUri() + "<br/>" +
"State Type: " + oauth.getStateType() + "<br/>" +
"Team: " + oauth.getTeam() + "<br/>" +
"Incoming Code: " + oauth.getIncomingCode() + "<br/>" +
"Incoming State: " + oauth.getIncomingState() + "<br/>" +
"Incoming Error: " + oauth.getIncomingError() + "<br/>" +
"Incoming Access Token: " + oauth.getIncomingAccessToken() + "<br/>" +
"Incoming Scope: " + oauth.getIncomingScope() + "<br/>" +
"Incoming User ID: " + oauth.getIncomingUserId() + "<br/>" +
"Incoming Team Name: " + oauth.getIncomingTeamName() + "<br/>" +
"Incoming Team ID: " + oauth.getIncomingTeamId() + "<br/>" +
"Incoming Webhook URL: " + oauth.getIncomingWebhookUrl() + "<br/>" +
"Incoming Webhook Channel: " + oauth.getIncomingWebhookChannel() + "<br/>" +
"Incoming Webhook Config URL: " + oauth.getIncomingWebhookConfigUrl() + "<br/>" +
"Incoming Bot User ID: " + oauth.getIncomingBotUserId() + "<br/>" +
"Incoming Bot Access Token: " + oauth.getIncomingBotAccessToken() + "<br/>";
}else{
return "Error";
}
});
}
}
Build Slash Commands
Slash Command enable users to interact with your app from within Slack. We will have two tasks to do:
- First to Create the Commnad on Slack Application and Configure its
Request URL
(The URL that slack will POST the command data once used by any user). - Build a New Route (Accept POST Requests) to handle all Incoming Requests from Slack.
So Lets Start by the Easy Part Creating Commands On Slack App
:
- Please visit Your Apps Page from Slack.
- Open You App Settings Page (By clicking on the App).
- Go to
Slash Commands
From Side Menu UnderFeatures
. - Then Click to
Create New Command
. A Command Form Will Open To be Filled. - Set the Commnad for example
/fred
. - Set
Request URL
to you Application URL Handling Slack Commands for examplehttps://b2f78bbb.ngrok.io/commands
. - Set Short Description for example
Launch The Rocket!
. - Set Usage Hint
- And Finally Set to
Escape channels, users, and links sent to your app
or Not and ClickSave
.
Then Let's Build Our Route
That will Accept and Process All Incoming Requests from Slack for example https://b2f78bbb.ngrok.io/commands
. Our route and callback will look like the following Using Spark Java Framework:
import static spark.Spark.*;
import java.util.HashMap;
import java.util.Map;
import com.clivern.fred.util.*;
import com.clivern.fred.sender.BaseSender;
import com.mashape.unirest.http.exceptions.UnirestException;
import com.clivern.fred.receiver.BaseReceiver;
import com.clivern.fred.receiver.command.Command;
public class Main {
public static void main(String[] args) throws UnirestException
{
post("/commands", (request, response) -> {
Config config = new Config();
config.loadPropertiesFile("config.properties");
config.configLogger();
BaseReceiver baseReceiver = new BaseReceiver(config);
// Build Our First Command (/fred Command)
Command fredCommand = new Command("/fred", false, (ct) -> "You Typed -> " + ct.getText() + " To /fred");
// Build Another Command (/frog Command)
Command frogCommand = new Command("/frog", false, (ct) -> "You Typed -> " + ct.getText() + " To /frog");
// Pass Commands To The Receiver
baseReceiver.setCommand("/fred", fredCommand);
baseReceiver.setCommand("/frog", frogCommand);
// Check If Incoming Data Related to Any Configured Command (/fred or /frog)
if( baseReceiver.commandExists(request.queryParams("command")) ){
Map<String, String> incomingData = new HashMap<String, String>();
incomingData.put("channel_name", request.queryParams("channel_name"));
incomingData.put("user_id", request.queryParams("user_id"));
incomingData.put("user_name", request.queryParams("user_name"));
incomingData.put("trigger_id", request.queryParams("trigger_id"));
incomingData.put("team_domain", request.queryParams("team_domain"));
incomingData.put("team_id", request.queryParams("team_id"));
incomingData.put("text", request.queryParams("text"));
incomingData.put("channel_id", request.queryParams("channel_id"));
incomingData.put("command", request.queryParams("command"));
incomingData.put("token", request.queryParams("token"));
incomingData.put("response_url", request.queryParams("response_url"));
return baseReceiver.callCurrentCommand(request.queryParams("command"), incomingData);
}
return "Command Not Configured In App!";
});
}
}
Now You Finished, Just go to Slack Messaging and Interact With You Commands. Type /fred Hello World
and You will Get You Typed -> Hello World To /fred
.
Listen To Slack Events
Slack Event API allows your app to be notified of events in Slack (for example, when a user adds a reaction or creates a file) at a URL you choose.
Let's discuss how to implement this using Fred
.
Misc
Todo & Contributing
In case you want to share some love, Show your awesomeness in the following sub-packages:
-
๐ Config and Oauthcom.clivern.fred.util
. -
๐ Slash Commandscom.clivern.fred.receiver
. -
๐ฅ Web APIcom.clivern.fred.sender
. -
๐ฅ Events APIcom.clivern.fred.event
. -
๐ Add More Test Cases. -
๐ Add More Docs. -
๐ Update and Fix Code Docs and Remove Line32-38
inmaven-push.gradle
. -
๐ Add Examples & Write Tutorials.
And then please do the following:
- Fork the master branch.
- Create a feature branch
git branch my-feature
. - Move to your branch
git checkout my-feature
. - Do Your Changes.
- It will be great if you write some tests to your feature and check
./gradlew test
but not required ;). - Track the changes
git add --all
. - Commit your changes
git commit -m 'new awesome feature'
. - Push to your newly created branch
git push origin my-feature
. - Create a new Pull Request.
Tutorials & Examples
For almost all supported features you can take a look at
examples/
folder for working examples.
Changelog
Version 1.0.2:
Update logging package.
Update Configurations.
Version 1.0.1:
Add Java 8 Support.
Version 1.0.0:
Initial Release.
Acknowledgements
ยฉ 2017, Clivern. Released under The Apache Software License, Version 2.0.
Fred is authored and maintained by @clivern.