mirror of
https://github.com/sismics/docs.git
synced 2024-11-17 11:47:56 +01:00
#243: call webhooks
This commit is contained in:
parent
dfdd5f8d20
commit
884239bc26
@ -117,6 +117,11 @@
|
|||||||
<artifactId>javax.mail</artifactId>
|
<artifactId>javax.mail</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.squareup.okhttp3</groupId>
|
||||||
|
<artifactId>okhttp</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!-- Only there to read old index and rebuild them -->
|
<!-- Only there to read old index and rebuild them -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.lucene</groupId>
|
<groupId>org.apache.lucene</groupId>
|
||||||
|
@ -36,6 +36,10 @@ public class WebhookDao {
|
|||||||
sb.append(" from T_WEBHOOK w ");
|
sb.append(" from T_WEBHOOK w ");
|
||||||
|
|
||||||
// Add search criterias
|
// Add search criterias
|
||||||
|
if (criteria.getEvent() != null) {
|
||||||
|
criteriaList.add("w.WHK_EVENT_C = :event");
|
||||||
|
parameterMap.put("event", criteria.getEvent().name());
|
||||||
|
}
|
||||||
criteriaList.add("w.WHK_DELETEDATE_D is null");
|
criteriaList.add("w.WHK_DELETEDATE_D is null");
|
||||||
|
|
||||||
if (!criteriaList.isEmpty()) {
|
if (!criteriaList.isEmpty()) {
|
||||||
|
@ -1,9 +1,24 @@
|
|||||||
package com.sismics.docs.core.dao.criteria;
|
package com.sismics.docs.core.dao.criteria;
|
||||||
|
|
||||||
|
import com.sismics.docs.core.constant.WebhookEvent;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Webhook criteria.
|
* Webhook criteria.
|
||||||
*
|
*
|
||||||
* @author bgamard
|
* @author bgamard
|
||||||
*/
|
*/
|
||||||
public class WebhookCriteria {
|
public class WebhookCriteria {
|
||||||
|
/**
|
||||||
|
* Webhook event.
|
||||||
|
*/
|
||||||
|
private WebhookEvent event;
|
||||||
|
|
||||||
|
public WebhookEvent getEvent() {
|
||||||
|
return event;
|
||||||
|
}
|
||||||
|
|
||||||
|
public WebhookCriteria setEvent(WebhookEvent event) {
|
||||||
|
this.event = event;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,103 @@
|
|||||||
|
package com.sismics.docs.core.listener.async;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
import com.google.common.eventbus.AllowConcurrentEvents;
|
||||||
|
import com.google.common.eventbus.Subscribe;
|
||||||
|
import com.sismics.docs.core.constant.WebhookEvent;
|
||||||
|
import com.sismics.docs.core.dao.WebhookDao;
|
||||||
|
import com.sismics.docs.core.dao.criteria.WebhookCriteria;
|
||||||
|
import com.sismics.docs.core.dao.dto.WebhookDto;
|
||||||
|
import com.sismics.docs.core.event.*;
|
||||||
|
import com.sismics.docs.core.util.TransactionUtil;
|
||||||
|
import okhttp3.*;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listener for triggering webhooks.
|
||||||
|
*
|
||||||
|
* @author bgamard
|
||||||
|
*/
|
||||||
|
public class WebhookAsyncListener {
|
||||||
|
/**
|
||||||
|
* Logger.
|
||||||
|
*/
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(WebhookAsyncListener.class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* OkHttp client.
|
||||||
|
*/
|
||||||
|
private static final OkHttpClient client = new OkHttpClient();
|
||||||
|
public static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
@AllowConcurrentEvents
|
||||||
|
public void on(final DocumentCreatedAsyncEvent event) {
|
||||||
|
triggerWebhook(WebhookEvent.DOCUMENT_CREATED, event.getDocument().getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
@AllowConcurrentEvents
|
||||||
|
public void on(final DocumentUpdatedAsyncEvent event) {
|
||||||
|
triggerWebhook(WebhookEvent.DOCUMENT_UPDATED, event.getDocumentId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
@AllowConcurrentEvents
|
||||||
|
public void on(final DocumentDeletedAsyncEvent event) {
|
||||||
|
triggerWebhook(WebhookEvent.DOCUMENT_UPDATED, event.getDocumentId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
@AllowConcurrentEvents
|
||||||
|
public void on(final FileCreatedAsyncEvent event) {
|
||||||
|
triggerWebhook(WebhookEvent.FILE_CREATED, event.getFile().getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
@AllowConcurrentEvents
|
||||||
|
public void on(final FileUpdatedAsyncEvent event) {
|
||||||
|
triggerWebhook(WebhookEvent.FILE_UPDATED, event.getFile().getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
@AllowConcurrentEvents
|
||||||
|
public void on(final FileDeletedAsyncEvent event) {
|
||||||
|
triggerWebhook(WebhookEvent.FILE_DELETED, event.getFile().getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trigger the webhooks for the specified event.
|
||||||
|
*
|
||||||
|
* @param event Event
|
||||||
|
* @param id ID
|
||||||
|
*/
|
||||||
|
private void triggerWebhook(WebhookEvent event, String id) {
|
||||||
|
List<String> webhookUrlList = Lists.newArrayList();
|
||||||
|
|
||||||
|
TransactionUtil.handle(() -> {
|
||||||
|
WebhookDao webhookDao = new WebhookDao();
|
||||||
|
List<WebhookDto> webhookDtoList = webhookDao.findByCriteria(new WebhookCriteria().setEvent(event), null);
|
||||||
|
for (WebhookDto webhookDto : webhookDtoList) {
|
||||||
|
webhookUrlList.add(webhookDto.getUrl());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
RequestBody body = RequestBody.create(JSON, "{\"event\": \"" + event.name() + "\", \"id\": \"" + id + "\"}");
|
||||||
|
|
||||||
|
for (String webhookUrl : webhookUrlList) {
|
||||||
|
Request request = new Request.Builder()
|
||||||
|
.url(webhookUrl)
|
||||||
|
.post(body)
|
||||||
|
.build();
|
||||||
|
try (Response response = client.newCall(request).execute()) {
|
||||||
|
log.info("Successfully called the webhook at: " + webhookUrl + " - " + response.code());
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("Error calling the webhook at: " + webhookUrl, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -145,6 +145,7 @@ public class AppContext {
|
|||||||
asyncEventBus.register(new RebuildIndexAsyncListener());
|
asyncEventBus.register(new RebuildIndexAsyncListener());
|
||||||
asyncEventBus.register(new AclCreatedAsyncListener());
|
asyncEventBus.register(new AclCreatedAsyncListener());
|
||||||
asyncEventBus.register(new AclDeletedAsyncListener());
|
asyncEventBus.register(new AclDeletedAsyncListener());
|
||||||
|
asyncEventBus.register(new WebhookAsyncListener());
|
||||||
|
|
||||||
mailEventBus = newAsyncEventBus();
|
mailEventBus = newAsyncEventBus();
|
||||||
mailEventBus.register(new PasswordLostAsyncListener());
|
mailEventBus.register(new PasswordLostAsyncListener());
|
||||||
|
@ -67,6 +67,7 @@ public class WebhookResource extends BaseResource {
|
|||||||
* Add a webhook.
|
* Add a webhook.
|
||||||
*
|
*
|
||||||
* @api {put} /webhook Add a webhook
|
* @api {put} /webhook Add a webhook
|
||||||
|
* @apiDescription Each time the specified event is raised, the webhook URL will be POST-ed with the following JSON payload: {"event": "Event name", "id": "ID of the document or file"}
|
||||||
* @apiName PutWebhook
|
* @apiName PutWebhook
|
||||||
* @apiWebhook Webhook
|
* @apiWebhook Webhook
|
||||||
* @apiParam {String="DOCUMENT_CREATED","DOCUMENT_UPDATED","DOCUMENT_DELETED","FILE_CREATED","FILE_UPDATED","FILE_DELETED"} event Event
|
* @apiParam {String="DOCUMENT_CREATED","DOCUMENT_UPDATED","DOCUMENT_DELETED","FILE_CREATED","FILE_UPDATED","FILE_DELETED"} event Event
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package com.sismics.docs.rest;
|
package com.sismics.docs.rest;
|
||||||
|
|
||||||
|
import com.sismics.docs.rest.resource.ThirdPartyWebhookResource;
|
||||||
import com.sismics.util.filter.TokenBasedSecurityFilter;
|
import com.sismics.util.filter.TokenBasedSecurityFilter;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@ -8,6 +9,7 @@ import javax.json.JsonArray;
|
|||||||
import javax.json.JsonObject;
|
import javax.json.JsonObject;
|
||||||
import javax.ws.rs.client.Entity;
|
import javax.ws.rs.client.Entity;
|
||||||
import javax.ws.rs.core.Form;
|
import javax.ws.rs.core.Form;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -24,6 +26,10 @@ public class TestWebhookResource extends BaseJerseyTest {
|
|||||||
// Login admin
|
// Login admin
|
||||||
String adminToken = clientUtil.login("admin", "admin", false);
|
String adminToken = clientUtil.login("admin", "admin", false);
|
||||||
|
|
||||||
|
// Login webhook1
|
||||||
|
clientUtil.createUser("webhook1");
|
||||||
|
String webhook1Token = clientUtil.login("webhook1");
|
||||||
|
|
||||||
// Get all webhooks
|
// Get all webhooks
|
||||||
JsonObject json = target().path("/webhook")
|
JsonObject json = target().path("/webhook")
|
||||||
.request()
|
.request()
|
||||||
@ -37,7 +43,21 @@ public class TestWebhookResource extends BaseJerseyTest {
|
|||||||
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, adminToken)
|
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, adminToken)
|
||||||
.put(Entity.form(new Form()
|
.put(Entity.form(new Form()
|
||||||
.param("event", "DOCUMENT_CREATED")
|
.param("event", "DOCUMENT_CREATED")
|
||||||
.param("url", "https://www.sismics.com")), JsonObject.class);
|
.param("url", "http://localhost:" + getPort() + "/docs/thirdpartywebhook")), JsonObject.class);
|
||||||
|
|
||||||
|
// Create a document
|
||||||
|
json = target().path("/document").request()
|
||||||
|
.cookie(TokenBasedSecurityFilter.COOKIE_NAME, webhook1Token)
|
||||||
|
.put(Entity.form(new Form()
|
||||||
|
.param("title", "Webhook document 1")
|
||||||
|
.param("language", "eng")
|
||||||
|
.param("create_date", Long.toString(new Date().getTime()))), JsonObject.class);
|
||||||
|
String document1Id = json.getString("id");
|
||||||
|
|
||||||
|
// Check the webhook payload
|
||||||
|
JsonObject payload = ThirdPartyWebhookResource.getLastPayload();
|
||||||
|
Assert.assertEquals("DOCUMENT_CREATED", payload.getString("event"));
|
||||||
|
Assert.assertEquals(document1Id, payload.getString("id"));
|
||||||
|
|
||||||
// Get all webhooks
|
// Get all webhooks
|
||||||
json = target().path("/webhook")
|
json = target().path("/webhook")
|
||||||
@ -49,7 +69,7 @@ public class TestWebhookResource extends BaseJerseyTest {
|
|||||||
JsonObject webhook = webhooks.getJsonObject(0);
|
JsonObject webhook = webhooks.getJsonObject(0);
|
||||||
String webhookId = webhook.getString("id");
|
String webhookId = webhook.getString("id");
|
||||||
Assert.assertEquals("DOCUMENT_CREATED", webhook.getString("event"));
|
Assert.assertEquals("DOCUMENT_CREATED", webhook.getString("event"));
|
||||||
Assert.assertEquals("https://www.sismics.com", webhook.getString("url"));
|
Assert.assertEquals("http://localhost:" + getPort() + "/docs/thirdpartywebhook", webhook.getString("url"));
|
||||||
Assert.assertNotNull(webhook.getJsonNumber("create_date"));
|
Assert.assertNotNull(webhook.getJsonNumber("create_date"));
|
||||||
|
|
||||||
// Delete a webhook
|
// Delete a webhook
|
||||||
|
@ -0,0 +1,34 @@
|
|||||||
|
package com.sismics.docs.rest.resource;
|
||||||
|
|
||||||
|
import javax.json.JsonObject;
|
||||||
|
import javax.ws.rs.POST;
|
||||||
|
import javax.ws.rs.Path;
|
||||||
|
import javax.ws.rs.core.Response;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Webhook REST resources.
|
||||||
|
*
|
||||||
|
* @author bgamard
|
||||||
|
*/
|
||||||
|
@Path("/thirdpartywebhook")
|
||||||
|
public class ThirdPartyWebhookResource extends BaseResource {
|
||||||
|
/**
|
||||||
|
* Last payload received.
|
||||||
|
*/
|
||||||
|
private static JsonObject lastPayload;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a webhook.
|
||||||
|
*
|
||||||
|
* @return Response
|
||||||
|
*/
|
||||||
|
@POST
|
||||||
|
public Response webhook(JsonObject request) {
|
||||||
|
lastPayload = request;
|
||||||
|
return Response.ok().build();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static JsonObject getLastPayload() {
|
||||||
|
return lastPayload;
|
||||||
|
}
|
||||||
|
}
|
7
pom.xml
7
pom.xml
@ -48,6 +48,7 @@
|
|||||||
<com.icegreen.greenmail.version>1.5.7</com.icegreen.greenmail.version>
|
<com.icegreen.greenmail.version>1.5.7</com.icegreen.greenmail.version>
|
||||||
<com.sun.mail.javax.mail.version>1.5.6</com.sun.mail.javax.mail.version>
|
<com.sun.mail.javax.mail.version>1.5.6</com.sun.mail.javax.mail.version>
|
||||||
<org.jsoup.jsoup.version>1.11.2</org.jsoup.jsoup.version>
|
<org.jsoup.jsoup.version>1.11.2</org.jsoup.jsoup.version>
|
||||||
|
<com.squareup.okhttp3.okhttp.version>3.11.0</com.squareup.okhttp3.okhttp.version>
|
||||||
|
|
||||||
<org.eclipse.jetty.jetty-server.version>9.3.11.v20160721</org.eclipse.jetty.jetty-server.version>
|
<org.eclipse.jetty.jetty-server.version>9.3.11.v20160721</org.eclipse.jetty.jetty-server.version>
|
||||||
<org.eclipse.jetty.jetty-webapp.version>9.3.11.v20160721</org.eclipse.jetty.jetty-webapp.version>
|
<org.eclipse.jetty.jetty-webapp.version>9.3.11.v20160721</org.eclipse.jetty.jetty-webapp.version>
|
||||||
@ -224,6 +225,12 @@
|
|||||||
<version>${org.jsoup.jsoup.version}</version>
|
<version>${org.jsoup.jsoup.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.squareup.okhttp3</groupId>
|
||||||
|
<artifactId>okhttp</artifactId>
|
||||||
|
<version>${com.squareup.okhttp3.okhttp.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>log4j</groupId>
|
<groupId>log4j</groupId>
|
||||||
<artifactId>log4j</artifactId>
|
<artifactId>log4j</artifactId>
|
||||||
|
Loading…
Reference in New Issue
Block a user