aboutsummaryrefslogtreecommitdiff
path: root/central/src/main/java/moe/yuuta/dn42peering/asn/IASNHttpServiceImpl.java
diff options
context:
space:
mode:
Diffstat (limited to 'central/src/main/java/moe/yuuta/dn42peering/asn/IASNHttpServiceImpl.java')
-rw-r--r--central/src/main/java/moe/yuuta/dn42peering/asn/IASNHttpServiceImpl.java168
1 files changed, 168 insertions, 0 deletions
diff --git a/central/src/main/java/moe/yuuta/dn42peering/asn/IASNHttpServiceImpl.java b/central/src/main/java/moe/yuuta/dn42peering/asn/IASNHttpServiceImpl.java
new file mode 100644
index 0000000..b2105a4
--- /dev/null
+++ b/central/src/main/java/moe/yuuta/dn42peering/asn/IASNHttpServiceImpl.java
@@ -0,0 +1,168 @@
+package moe.yuuta.dn42peering.asn;
+
+import io.vertx.core.*;
+import io.vertx.core.buffer.Buffer;
+import io.vertx.core.http.HttpHeaders;
+import io.vertx.core.impl.logging.Logger;
+import io.vertx.core.impl.logging.LoggerFactory;
+import io.vertx.core.json.JsonObject;
+import io.vertx.ext.mail.MailClient;
+import io.vertx.ext.mail.MailConfig;
+import io.vertx.ext.mail.MailMessage;
+import io.vertx.ext.mail.MailResult;
+import io.vertx.ext.web.RoutingContext;
+import io.vertx.ext.web.api.service.ServiceRequest;
+import io.vertx.ext.web.api.service.ServiceResponse;
+import io.vertx.ext.web.common.template.TemplateEngine;
+import io.vertx.ext.web.templ.freemarker.FreeMarkerTemplateEngine;
+import moe.yuuta.dn42peering.jaba.Pair;
+import moe.yuuta.dn42peering.portal.FormException;
+import moe.yuuta.dn42peering.portal.HTTPException;
+import moe.yuuta.dn42peering.portal.RenderingUtils;
+import moe.yuuta.dn42peering.whois.IWhoisService;
+import moe.yuuta.dn42peering.whois.WhoisObject;
+import org.apache.commons.text.RandomStringGenerator;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import java.util.*;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+class IASNHttpServiceImpl implements IASNHttpService {
+ private final Logger logger = LoggerFactory.getLogger(getClass().getSimpleName());
+
+ private final IASNService asnService;
+ private final IWhoisService whoisService;
+ private final MailClient mailClient;
+ private final JsonObject mailConfig;
+ private final TemplateEngine templateEngine;
+
+ // Testing API
+ public IASNHttpServiceImpl(@Nonnull IASNService asnService,
+ @Nonnull IWhoisService whoisService,
+ @Nonnull MailClient mailClient,
+ @Nonnull JsonObject mailConfig,
+ @Nonnull TemplateEngine templateEngine) {
+ this.asnService = asnService;
+ this.whoisService = whoisService;
+ this.mailClient = mailClient;
+ this.mailConfig = mailConfig;
+ this.templateEngine = templateEngine;
+ }
+
+ public IASNHttpServiceImpl(@Nonnull Vertx vertx) {
+ this.asnService = IASNService.createProxy(vertx, IASNService.ADDRESS);
+ this.whoisService = IWhoisService.createProxy(vertx, IWhoisService.ADDRESS);
+ mailConfig = vertx.getOrCreateContext().config().getJsonObject("mail");
+ mailClient = MailClient.create(vertx, new MailConfig(mailConfig));
+ templateEngine = FreeMarkerTemplateEngine.create(vertx, "ftlh");
+ }
+
+ @Override
+ public void index(@Nonnull ServiceRequest context, @Nonnull Handler<AsyncResult<ServiceResponse>> handler) {
+ renderIndex(null, null, handler);
+ }
+
+ @Override
+ public void register(@Nonnull JsonObject parameters,
+ @Nonnull ServiceRequest context,
+ @Nonnull Handler<AsyncResult<ServiceResponse>> handler) {
+ final String upperASN = parameters.getString("asn").toUpperCase();
+ // Start: Check if the ASN exists.
+ Future.<Void>future(f -> asnService.exists(upperASN, true, true, ar -> {
+ if (ar.succeeded()) {
+ if (ar.result()) {
+ f.fail(new FormException("This ASN exists in our records. Please login instead of registering."));
+ } else {
+ f.complete();
+ }
+ } else {
+ f.fail(ar.cause());
+ }
+ }))
+ // Lookup ASN
+ .<WhoisObject>compose(exists ->
+ Future.future(f -> whoisService.query(upperASN, f)))
+ // Lookup emails
+ .<List<String>>compose(asnLookup -> {
+ if (asnLookup == null) {
+ return Future.failedFuture(new FormException("The ASN is not found in the DN42 registry."));
+ } else {
+ return Future.future(f -> asnService.lookupEmails(asnLookup, ar -> {
+ if (ar.succeeded()) {
+ if (ar.result().isEmpty()) {
+ f.fail(new FormException("The tech-c contact for this ASN does not have emails."));
+ } else {
+ f.complete(ar.result());
+ }
+ } else {
+ f.fail(ar.cause());
+ }
+ }));
+ }
+ })
+ // Generate random password and register.
+ .<Pair<String /* Random password */, List<String> /* Emails */>>compose(emails -> Future.future(f -> {
+ final String randomPassword = new RandomStringGenerator.Builder()
+ .withinRange('a', 'z')
+ .build()
+ .generate(15);
+ asnService.registerOrChangePassword(upperASN, randomPassword, ar -> {
+ if (ar.succeeded()) {
+ f.complete(new Pair<>(randomPassword, emails));
+ } else {
+ f.fail(ar.cause());
+ }
+ });
+ }))
+ // Send mails.
+ .compose(pair -> CompositeFuture.any(Stream.of(pair.b)
+ .map(mail -> new MailMessage()
+ .setFrom(mailConfig.getString("from"))
+ .setTo(mail)
+ .setText(String.format("Hi %s! Welcome to dn42 peering! Your peering initial password is %s. Make sure to change it.",
+ upperASN,
+ pair.a))
+ .setSubject("Peering initial password"))
+ .map(message -> Future.<MailResult>future(f -> mailClient.sendMail(message, f)))
+ .collect(Collectors.toList())))
+ // Render HTML or report errors
+ .onSuccess(res -> {
+ // Get MailResult's out of the future.
+ final List<MailResult> sendRes = res.list();
+ renderSuccess(sendRes, handler);
+ })
+ .onFailure(err -> {
+ if (err instanceof HTTPException) {
+ handler.handle(Future.succeededFuture(new ServiceResponse(((HTTPException) err).code, null, null, null)));
+ } else if (err instanceof FormException) {
+ renderIndex(Arrays.asList(((FormException) err).errors.clone()),
+ upperASN,
+ handler);
+ } else {
+ logger.error(String.format("Cannot register ASN %s.", upperASN), err);
+ handler.handle(Future.failedFuture(err));
+ }
+ });
+ }
+
+ private void renderIndex(@Nullable List<String> errors,
+ @Nullable String asn,
+ @Nonnull Handler<AsyncResult<ServiceResponse>> handler) {
+ final Map<String, Object> root = new HashMap<>();
+ root.put("input_asn", asn == null ? "" : asn);
+ root.put("errors", errors);
+ templateEngine.render(root, "asn/index.ftlh", RenderingUtils.getGeneralRenderingHandler(handler));
+ }
+
+ private void renderSuccess(@Nonnull List<MailResult> sendRes,
+ @Nonnull Handler<AsyncResult<ServiceResponse>> handler) {
+ final Map<String, Object> root = new HashMap<>();
+ root.put("emails", sendRes.stream()
+ .filter(Objects::nonNull) // Nulls mean failures.
+ .flatMap(res -> res.getRecipients().stream())
+ .collect(Collectors.toList()));
+ templateEngine.render(root, "asn/success.ftlh", RenderingUtils.getGeneralRenderingHandler(handler));
+ }
+}