Gitea-Helpdesk/src/main/java/io/gitlab/jfronny/gitea/helpdesk/web/WebInterface.java

128 lines
5.2 KiB
Java

package io.gitlab.jfronny.gitea.helpdesk.web;
import io.gitlab.jfronny.commons.StringFormatter;
import io.gitlab.jfronny.gitea.helpdesk.Config;
import io.gitlab.jfronny.gitea.helpdesk.Main;
import io.gitlab.jfronny.gitea.helpdesk.db.DBInterface;
import io.gitlab.jfronny.gitea.helpdesk.gitea.GiteaInterface;
import net.freeutils.httpserver.HTTPServer;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.util.Map;
public class WebInterface implements AutoCloseable {
public static final String THEME = Main.getResource("web/theme.css");
private static final String TEMPLATE = Main.getResource("web/template.html");
private static final String ISSUE_MISSING_REPO = page("issue/missing_repo.html");
private static final String ISSUE_SUCCESS = page("issue/success.html");
private static final String UNSUBSCRIBE_MISSING_ID = page("unsubscribe/missing_id.html");
private static final String UNSUBSCRIBE_FAILURE = page("unsubscribe/failure.html");
private static final String UNSUBSCRIBE_SUCCESS = page("unsubscribe/success.html");
private static final String CLOSE_MISSING_ID = page("close/missing_id.html");
private static final String CLOSE_FAILURE = page("close/failure.html");
private static final String CLOSE_SUCCESS = page("close/success.html");
private static String page(String path) {
return TEMPLATE.formatted(Main.getResource("web/" + path));
}
private final HTTPServer server;
private final Config.Web web;
public WebInterface(Config.Web web, String address, DBInterface db, GiteaInterface gitea) throws IOException {
server = new HTTPServer(web.port);
this.web = web;
HTTPServer.VirtualHost host = server.getVirtualHost(null);
host.addContext("/unsubscribe", (req, resp) -> {
String id = req.getParams().get("id");
if (id == null) {
resp.send(404, UNSUBSCRIBE_MISSING_ID);
} else {
try {
db.removeSubscription(id);
resp.send(202, UNSUBSCRIBE_SUCCESS);
} catch (Throwable e) {
resp.send(500, UNSUBSCRIBE_FAILURE.formatted(escapeHTML(StringFormatter.toString(e))));
}
}
return 0;
});
host.addContext("/close", ((req, resp) -> {
String id = req.getParams().get("id");
if (id == null) {
resp.send(404, CLOSE_MISSING_ID);
} else {
try {
db.getSubscription(id).ifPresentOrElse(sub -> {
try {
gitea.closeIssue(sub.repoOwner(), sub.repo(), sub.issue());
resp.send(202, CLOSE_SUCCESS);
} catch (IOException e) {
throw new UncheckedIOException(e);
} catch (URISyntaxException e) {
throw new RuntimeException(e);
}
}, () -> {
try {
resp.send(404, CLOSE_MISSING_ID);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
});
} catch (Throwable e) {
resp.send(500, CLOSE_FAILURE.formatted(escapeHTML(StringFormatter.toString(e))));
}
}
return 0;
}));
String[] addr = address.split("@");
host.addContext("/issue", (req, resp) -> {
Map<String, String> params = req.getParams();
String owner = params.get("owner");
String repo = params.get("repo");
if (owner == null || repo == null || owner.contains("+") || repo.contains("+")) {
resp.send(404, ISSUE_MISSING_REPO);
} else {
String mail = "mailto:create+" + addr[0] + '+' + owner + '+' + repo;
resp.send(200, ISSUE_SUCCESS.formatted(escapeHTML(mail)));
}
return 0;
});
host.addContext("/theme.css", (req, resp) -> {
byte[] content = THEME.getBytes(StandardCharsets.UTF_8);
resp.sendHeaders(200, content.length, -1, "W/\"" + Integer.toHexString(THEME.hashCode()) + "\"", "text/css; charset=utf-8", null);
resp.getBody().write(content);
return 0;
});
server.start();
}
@Override
public void close() {
server.stop();
}
public static String escapeHTML(String s) {
StringBuilder out = new StringBuilder();
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (c > 127 || c == '"' || c == '\'' || c == '<' || c == '>' || c == '&') {
out.append("&#");
out.append((int) c);
out.append(';');
} else if (c == '\n') {
out.append("<br>\n");
} else {
out.append(c);
}
}
return out.toString();
}
public String getAddress() {
return web.publicAddress;
}
}