package org.rakam.ui;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.google.common.base.Throwables;
import com.google.common.io.ByteStreams;
import io.netty.buffer.Unpooled;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.HttpHeaders;
import org.rakam.collection.FieldType;
import org.rakam.server.http.HttpService;
import org.rakam.server.http.RakamHttpRequest;
import org.rakam.server.http.annotations.Api;
import org.rakam.server.http.annotations.ApiOperation;
import org.rakam.server.http.annotations.ApiParam;
import org.rakam.server.http.annotations.IgnoreApi;
import org.rakam.util.JsonHelper;
import org.rakam.util.RakamException;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import java.io.IOException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static com.google.common.net.HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN;
import static com.google.common.net.HttpHeaders.CACHE_CONTROL;
import static io.netty.handler.codec.http.HttpResponseStatus.FORBIDDEN;
import static io.netty.handler.codec.http.HttpResponseStatus.INTERNAL_SERVER_ERROR;
import static io.netty.handler.codec.http.HttpResponseStatus.NOT_FOUND;
import static io.netty.handler.codec.http.HttpResponseStatus.OK;
import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;
import static javax.ws.rs.core.HttpHeaders.CONTENT_TYPE;
import static org.rakam.ui.ScheduledTaskUIHttpService.getResourceFiles;
@IgnoreApi
@Path("/ui/webhook")
@Api(value = "/ui/webhook")
public class WebHookUIHttpService
extends HttpService
{
@GET
@ApiOperation(value = "List webhooks", response = Integer.class)
@Path("/list")
public List<UIWebHook> list()
{
List<String> resourceFiles;
try {
resourceFiles = getResourceFiles("webhook");
}
catch (IOException e) {
throw new RakamException("Unable to read files", INTERNAL_SERVER_ERROR);
}
return resourceFiles.stream().flatMap(e -> {
UIWebHook resource;
try {
URL config = getClass().getResource("/webhook/" + e + "/config.json");
byte[] script = ByteStreams.toByteArray(getClass().getResource("/webhook/" + e + "/script.js").openStream());
String test = null;
try {
test = new String(ByteStreams.toByteArray(getClass()
.getResource("/webhook/" + e + "/test.txt").openStream()),
StandardCharsets.UTF_8);
}
catch (Exception e1) {
test = null;
}
resource = JsonHelper.read(ByteStreams.toByteArray(config.openStream()), UIWebHook.class);
resource.script = new String(script, StandardCharsets.UTF_8);
resource.testCode = test;
resource.image = "/ui/webhook/image/" + e;
}
catch (IOException ex) {
return Stream.of();
}
return Stream.of(resource);
}).collect(Collectors.toList());
}
@GET
@ApiOperation(value = "Show webhook images", response = Integer.class)
@Path("/image/*")
public void image(RakamHttpRequest request)
{
String substring = request.path().substring("/ui/webhook/image".length() + 1);
if (!substring.matches("^[A-Za-z0-9-]+$")) {
throw new RakamException(FORBIDDEN);
}
URL resource = getClass().getResource("/webhook/" + substring + "/image.png");
if (resource == null) {
throw new RakamException(NOT_FOUND);
}
byte[] script;
try {
script = ByteStreams.toByteArray(resource.openStream());
}
catch (IOException e) {
throw Throwables.propagate(e);
}
DefaultFullHttpResponse resp = new DefaultFullHttpResponse(HTTP_1_1, OK, Unpooled.wrappedBuffer(script));
resp.headers().add(ACCESS_CONTROL_ALLOW_ORIGIN, "*");
resp.headers().add(CACHE_CONTROL, "private, max-age=86400");
HttpHeaders.setContentLength(resp, script.length);
resp.headers().set(CONTENT_TYPE, "image/png");
request.response(resp).end();
}
public static class Parameter
{
public final FieldType type;
public final String placeholder;
public final String description;
public final Object value;
public final boolean hidden;
public final boolean required;
@JsonCreator
public Parameter(
@ApiParam("type") FieldType type,
@ApiParam("placeholder") String placeholder,
@ApiParam("description") String description,
@ApiParam(value = "value", required = false) Object value,
@ApiParam(value = "hidden", required = false) Boolean hidden,
@ApiParam(value = "required", required = false) Boolean required)
{
this.type = type;
this.placeholder = placeholder;
this.description = description;
this.value = value;
this.hidden = Boolean.TRUE.equals(hidden);
this.required = Boolean.TRUE.equals(required);
}
}
public static class UIWebHook
{
public final String name;
public String image;
public final String description;
public String script;
public final Map<String, Parameter> parameters;
public String testCode;
@JsonCreator
public UIWebHook(@ApiParam("name") String name,
@ApiParam(value = "image", required = false) String image,
@ApiParam("description") String description,
@ApiParam(value = "script", required = false) String script,
@ApiParam(value = "testCode", required = false) String testCode,
@ApiParam("parameters") Map<String, Parameter> parameters)
{
this.name = name;
this.image = image;
this.description = description;
this.testCode = testCode;
this.script = script;
this.parameters = parameters;
}
}
}