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.analysis.JDBCPoolDataSource;
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 org.skife.jdbi.v2.DBI;
import org.skife.jdbi.v2.Handle;
import javax.annotation.PostConstruct;
import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static com.google.common.io.ByteStreams.toByteArray;
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 java.nio.charset.StandardCharsets.UTF_8;
import static javax.ws.rs.core.HttpHeaders.CONTENT_TYPE;
import static org.rakam.ui.ScheduledTaskUIHttpService.getResourceFiles;
@IgnoreApi
@Path("/ui/custom-event-mapper")
@Api(value = "/ui/custom-event-mapper")
public class CustomEventMapperUIHttpService
extends HttpService
{
@GET
@ApiOperation(value = "List custom event mapper", response = Integer.class)
@Path("/list")
public List<UIEventMapper> list()
{
List<String> resourceFiles;
try {
resourceFiles = getResourceFiles("custom-event-mapper");
}
catch (IOException e) {
throw new RakamException("Unable to read files", INTERNAL_SERVER_ERROR);
}
return resourceFiles.stream().flatMap(e -> {
UIEventMapper resource;
try {
URL config = getClass().getResource("/custom-event-mapper/" + e + "/config.json");
byte[] script = toByteArray(getClass().getResource("/custom-event-mapper/" + e + "/script.js").openStream());
resource = JsonHelper.read(toByteArray(config.openStream()), UIEventMapper.class);
resource.script = new String(script, UTF_8);
resource.image = "/ui/custom-event-mapper/image/" + e;
}
catch (IOException ex) {
return Stream.of();
}
return Stream.of(resource);
}).collect(Collectors.toList());
}
@GET
@ApiOperation(value = "List custom event mappers", response = Integer.class)
@Path("/image/*")
public void image(RakamHttpRequest request)
{
String substring = request.path().substring("/ui/custom-event-mapper/image".length() + 1);
if (!substring.matches("^[A-Za-z0-9-]+$")) {
throw new RakamException(FORBIDDEN);
}
URL resource = getClass().getResource("/custom-event-mapper/" + substring + "/image.png");
if (resource == null) {
throw new RakamException(NOT_FOUND);
}
byte[] script;
try {
script = 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;
@JsonCreator
public Parameter(
@ApiParam("type") FieldType type,
@ApiParam("placeholder") String placeholder,
@ApiParam("description") String description,
@ApiParam(value = "value", required = false) Object value)
{
this.type = type;
this.placeholder = placeholder;
this.description = description;
this.value = value;
}
}
public static class UIEventMapper
{
public final String name;
public String image;
public final String description;
public String script;
public final Map<String, Parameter> parameters;
@JsonCreator
public UIEventMapper(@ApiParam("name") String name,
@ApiParam(value = "image", required = false) String image,
@ApiParam(value = "description", required = false) String description,
@ApiParam(value = "code", required = false) String code,
@ApiParam("parameters") Map<String, Parameter> parameters)
{
this.name = name;
this.image = image;
this.description = description;
this.script = code;
this.parameters = parameters;
}
}
}