Skip to content

Commit

Permalink
✨ feat: add Slack4j #4
Browse files Browse the repository at this point in the history
  • Loading branch information
pnguyen215 committed Jun 9, 2024
1 parent d34ab73 commit e655aa3
Show file tree
Hide file tree
Showing 9 changed files with 502 additions and 3 deletions.
133 changes: 133 additions & 0 deletions plugin/src/main/groovy/org/bot4j/slack/common/Slack4j.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
package org.bot4j.slack.common;

import kong.unirest.HttpResponse;
import kong.unirest.JsonNode;
import kong.unirest.Unirest;
import org.bot4j.slack.model.onlyrd.AbstractSlackClass;
import org.unify4j.common.*;
import org.unify4j.model.builder.HttpStatusBuilder;
import org.unify4j.model.builder.HttpWrapBuilder;
import org.unify4j.model.c.HttpHeaders;
import org.unify4j.model.c.MediaType;
import org.unify4j.model.enums.AuthType;
import org.unify4j.model.response.WrapResponse;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CompletableFuture;

public class Slack4j extends AbstractSlackClass {
protected Slack4j(Builder builder) {
super(builder);
}

@Override
public Slack4j requestId(String value) {
if (this.options == null) {
return this;
}
this.options.setRequestId(value);
return this;
}

@Override
public WrapResponse<?> verify() {
if (String4j.isEmpty(this.token)) {
return new HttpWrapBuilder<>().badRequest("Token is required").build();
}
if (String4j.isEmpty(this.channel)) {
return new HttpWrapBuilder<>().badRequest("Channel is required").build();
}
if (Collection4j.isEmptyMap(this.message)) {
return new HttpWrapBuilder<>().badRequest("Body message is required").build();
}
return new HttpWrapBuilder<>().ok(null).build();
}

@Override
public Map<String, String> headers() {
Auth4j auth4j = new Auth4j.Builder().type(AuthType.BEARER).token(this.token).build();
Map<String, String> headers = auth4j.getHeaders();
if (Collection4j.isEmptyMap(headers)) {
return headers;
}
headers.put(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON.getName());
return headers;
}

@Override
public Map<String, Object> messageBody() {
Map<String, Object> request = this.message;
if (Collection4j.isEmptyMap(request)) {
request = new HashMap<>();
}
request.put("channel", this.channel);
return request;
}

@Override
public WrapResponse<?> sendMessage() {
if (this.connections.isSkip()) {
return new HttpWrapBuilder<>().notImplemented("Oops! Slack4j unavailable").build();
}
WrapResponse<?> verified = this.verify();
if (!verified.isSuccess()) {
return verified;
}
String url = String.format("%s/chat.postMessage", this.baseURL);
Map<String, Object> request = this.messageBody();
Map<String, String> headers = this.headers();
if (this.connections.isDebugging()) {
logger.debug("Slack4j, request_id: {} sending message on URL: {}", this.options.getRequestId(), url);
logger.debug("Slack4j, request_id: {} sending request body: {}", this.options.getRequestId(), Json4j.toJson(request));
logger.debug("Slack4j, request_id: {} sending request header: {}", this.options.getRequestId(), headers.toString());
}
try {
HttpResponse<JsonNode> caller = Unirest.post(url).headers(headers).body(request).asJson();
WrapResponse<Object> response = new HttpWrapBuilder<>()
.statusCode(caller.getStatus())
.requestId(this.options.getRequestId())
.body(Json4j.translate(caller))
.total(1)
.build();
if (Object4j.allNotNull(caller.getBody())) {
String message = Json4j.readIf(caller.getBody().toString(), "$.error");
response.setMessage(message);
}
return response;
} catch (Exception e) {
return new HttpWrapBuilder<>()
.statusCode(HttpStatusBuilder.INTERNAL_SERVER_ERROR)
.errors(e)
.requestId(this.options.getRequestId())
.build();
}
}

@Override
public CompletableFuture<WrapResponse<?>> sendMessageAsync() {
return CompletableFuture.supplyAsync(this::sendMessage);
}

@Override
public void sendMessageSilent() {
CompletableFuture.runAsync(this::sendMessage);
}

@Override
public void sendMessageWait() {
this.sendMessageAsync().join();
}

public static class Builder extends AbstractSlackClass.Builder<Builder> {
@Override
public Slack4j build() {
return new Slack4j(this);
}

@Override
protected Builder self() {
return this;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package org.bot4j.slack.model.builder;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import org.bot4j.slack.model.options.SlackConnections;

import java.io.Serializable;

@JsonIgnoreProperties(ignoreUnknown = true)
public class SlackConnectionBuilder implements Serializable {
public SlackConnectionBuilder() {
super();
}

private boolean debugging = false; // enable to trace log as debug mode
private boolean skip = false; // skipping the action for sending message
private boolean retry = false; // enable retry REST HTTP Telegram API when sending message got failure
private int maxRetries = 2; // retry no. times when sending message, default is 2 times

public SlackConnectionBuilder debugging(boolean value) {
this.debugging = value;
return this;
}

public SlackConnectionBuilder skip(boolean value) {
this.skip = value;
return this;
}

public SlackConnectionBuilder retry(boolean value) {
this.retry = value;
return this;
}

public SlackConnectionBuilder maxRetries(int value) {
this.maxRetries = value;
return this;
}

public SlackConnections build() {
SlackConnections e = new SlackConnections();
e.setDebugging(debugging);
e.setSkip(skip);
e.setRetry(retry);
e.setMaxRetries(maxRetries);
return e;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package org.bot4j.slack.model.builder;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import org.bot4j.slack.model.options.SlackOptions;
import org.unify4j.common.UniqueId4j;

import java.io.Serializable;

@JsonIgnoreProperties(ignoreUnknown = true)
public class SlackOptionBuilder implements Serializable {
public SlackOptionBuilder() {
super();
this.requestId = String.valueOf(UniqueId4j.getUniqueId19());
}

private String requestId;

public SlackOptionBuilder requestId(String value) {
this.requestId = value;
return this;
}

public SlackOptions build() {
SlackOptions e = new SlackOptions();
e.setRequestId(this.requestId);
return e;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
package org.bot4j.slack.model.onlyrd;

import org.bot4j.slack.model.builder.SlackConnectionBuilder;
import org.bot4j.slack.model.builder.SlackOptionBuilder;
import org.bot4j.slack.model.options.SlackConnections;
import org.bot4j.slack.model.options.SlackOptions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.unify4j.model.response.WrapResponse;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CompletableFuture;

public abstract class AbstractSlackClass {
protected final String baseURL = "https://slack.com/api";
protected String token;
protected String channel;
protected Map<String, Object> message;
protected Logger logger;
protected SlackOptions options;
protected SlackConnections connections;

protected AbstractSlackClass(Builder<?> builder) {
this.token = builder.token;
this.channel = builder.channel;
this.message = builder.message;
this.logger = builder.logger;
this.options = builder.options != null ? builder.options : new SlackOptions();
this.connections = builder.connections != null ? builder.connections : new SlackConnections();
}

public abstract AbstractSlackClass requestId(String value);

public abstract WrapResponse<?> verify();

public abstract Map<String, String> headers();

public abstract Map<String, Object> messageBody();

public abstract WrapResponse<?> sendMessage();

public abstract CompletableFuture<WrapResponse<?>> sendMessageAsync();

public abstract void sendMessageSilent();

public abstract void sendMessageWait();

public static abstract class Builder<T> {
private String token;
private String channel;
private Map<String, Object> message;
private Logger logger = LoggerFactory.getLogger(getClass());
private SlackOptions options;
private SlackConnections connections;

public abstract AbstractSlackClass build();

protected abstract T self();

public T token(String token) {
this.token = token;
return this.self();
}

public T channel(String channel) {
this.channel = channel;
return this.self();
}

public T message(Map<String, Object> message) {
this.message = message;
return this.self();
}

public T appendMessage(String key, Object value) {
if (this.message == null) {
this.message = new HashMap<>();
}
this.message.put(key, value);
return this.message(this.message);
}

public T logger(Logger logger) {
this.logger = logger == null ? LoggerFactory.getLogger(getClass()) : logger;
return this.self();
}

public T logger(Class<?> logger) {
return this.logger(LoggerFactory.getLogger(logger));
}

public T options(SlackOptions options) {
this.options = options;
return this.self();
}

public T options(SlackOptionBuilder builder) {
return this.options(builder.build());
}

public T connection(SlackConnections connections) {
this.connections = connections;
return this.self();
}

public T connection(SlackConnectionBuilder builder) {
return this.connection(builder.build());
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package org.bot4j.slack.model.options;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;

import java.io.Serializable;

@JsonIgnoreProperties(ignoreUnknown = true)
@JsonInclude(JsonInclude.Include.NON_NULL)
public class SlackConnections implements Serializable {
public SlackConnections() {
super();
}

private boolean debugging = false; // enable to trace log as debug mode
private boolean skip = false; // skipping the action for sending message
private boolean retry = false; // enable retry REST HTTP Telegram API when sending message got failure
private int maxRetries = 2; // retry no. times when sending message, default is 2 times

public boolean isDebugging() {
return debugging;
}

public void setDebugging(boolean debugging) {
this.debugging = debugging;
}

public boolean isSkip() {
return skip;
}

public void setSkip(boolean skip) {
this.skip = skip;
}

public boolean isRetry() {
return retry;
}

public void setRetry(boolean retry) {
this.retry = retry;
}

public int getMaxRetries() {
return maxRetries;
}

public void setMaxRetries(int maxRetries) {
this.maxRetries = maxRetries;
}

@Override
public String toString() {
return String.format("Slack connections { debugging: %s, skip: %s, retry: %s, max_retries: %d }",
this.debugging, this.skip, this.retry, this.maxRetries);
}
}
Loading

0 comments on commit e655aa3

Please sign in to comment.