From 787aa8a7839dcb32c07a8e2b6d982c7e2cb67244 Mon Sep 17 00:00:00 2001 From: =?utf8?q?David=20=E2=80=98Bombe=E2=80=99=20Roden?= Date: Sat, 1 Apr 2017 11:08:38 +0200 Subject: [PATCH] Replace get status AJAX page with Kotlin version --- .../sone/web/ajax/GetStatusAjaxPage.java | 188 --------------------- .../net/pterodactylus/sone/web/ajax/JsonPage.java | 4 + .../sone/web/ajax/GetStatusAjaxPage.kt | 85 ++++++++++ 3 files changed, 89 insertions(+), 188 deletions(-) delete mode 100644 src/main/java/net/pterodactylus/sone/web/ajax/GetStatusAjaxPage.java create mode 100644 src/main/kotlin/net/pterodactylus/sone/web/ajax/GetStatusAjaxPage.kt diff --git a/src/main/java/net/pterodactylus/sone/web/ajax/GetStatusAjaxPage.java b/src/main/java/net/pterodactylus/sone/web/ajax/GetStatusAjaxPage.java deleted file mode 100644 index 45c1cee..0000000 --- a/src/main/java/net/pterodactylus/sone/web/ajax/GetStatusAjaxPage.java +++ /dev/null @@ -1,188 +0,0 @@ -/* - * Sone - GetStatusAjaxPage.java - Copyright © 2010–2016 David Roden - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package net.pterodactylus.sone.web.ajax; - -import static com.fasterxml.jackson.databind.node.JsonNodeFactory.instance; - -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Date; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import net.pterodactylus.sone.data.Post; -import net.pterodactylus.sone.data.PostReply; -import net.pterodactylus.sone.data.Sone; -import net.pterodactylus.sone.freenet.L10nFilter; -import net.pterodactylus.sone.template.SoneAccessor; -import net.pterodactylus.sone.text.TimeText; -import net.pterodactylus.sone.text.TimeTextConverter; -import net.pterodactylus.sone.web.WebInterface; -import net.pterodactylus.sone.web.page.FreenetRequest; -import net.pterodactylus.util.notify.Notification; - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.node.ArrayNode; -import com.fasterxml.jackson.databind.node.ObjectNode; - -/** - * The “get status” AJAX handler returns all information that is necessary to - * update the web interface in real-time. - * - * @author David ‘Bombe’ Roden - */ -public class GetStatusAjaxPage extends JsonPage { - - /** Date formatter. */ - private static final DateFormat dateFormat = new SimpleDateFormat("MMM d, yyyy, HH:mm:ss"); - private final TimeTextConverter timeTextConverter; - private final L10nFilter l10nFilter; - - /** - * Creates a new “get status” AJAX handler. - * - * @param webInterface - * The Sone web interface - */ - public GetStatusAjaxPage(WebInterface webInterface, TimeTextConverter timeTextConverter, L10nFilter l10nFilter) { - super("getStatus.ajax", webInterface); - this.timeTextConverter = timeTextConverter; - this.l10nFilter = l10nFilter; - } - - /** - * {@inheritDoc} - */ - @Override - protected JsonReturnObject createJsonObject(FreenetRequest request) { - final Sone currentSone = getCurrentSoneWithoutCreatingSession(request.getToadletContext()); - /* load Sones. always return the status of the current Sone. */ - Set sones = new HashSet(Collections.singleton(currentSone)); - String loadSoneIds = request.getHttpRequest().getParam("soneIds"); - if (loadSoneIds.length() > 0) { - String[] soneIds = loadSoneIds.split(","); - for (String soneId : soneIds) { - /* just add it, we skip null further down. */ - sones.add(webInterface.getCore().getSone(soneId).orNull()); - } - } - ArrayNode jsonSones = new ArrayNode(instance); - for (Sone sone : sones) { - if (sone == null) { - continue; - } - jsonSones.add(createJsonSone(sone)); - } - /* load notifications. */ - List notifications = new ArrayList(webInterface.getNotifications(currentSone)); - Collections.sort(notifications, Notification.CREATED_TIME_SORTER); - /* load new posts. */ - Collection newPosts = webInterface.getNewPosts(currentSone); - - ArrayNode jsonPosts = new ArrayNode(instance); - for (Post post : newPosts) { - ObjectNode jsonPost = new ObjectNode(instance); - jsonPost.put("id", post.getId()); - jsonPost.put("sone", post.getSone().getId()); - jsonPost.put("recipient", post.getRecipientId().orNull()); - jsonPost.put("time", post.getTime()); - jsonPosts.add(jsonPost); - } - /* load new replies. */ - Collection newReplies = webInterface.getNewReplies(currentSone); - - ArrayNode jsonReplies = new ArrayNode(instance); - for (PostReply reply : newReplies) { - ObjectNode jsonReply = new ObjectNode(instance); - jsonReply.put("id", reply.getId()); - jsonReply.put("sone", reply.getSone().getId()); - jsonReply.put("post", reply.getPostId()); - jsonReply.put("postSone", reply.getPost().get().getSone().getId()); - jsonReplies.add(jsonReply); - } - return createSuccessJsonObject().put("loggedIn", currentSone != null).put("options", createJsonOptions(currentSone)).put("sones", jsonSones).put("notificationHash", notifications.hashCode()).put("newPosts", jsonPosts).put("newReplies", jsonReplies); - } - - /** - * {@inheritDoc} - */ - @Override - protected boolean needsFormPassword() { - return false; - } - - /** - * {@inheritDoc} - */ - @Override - protected boolean requiresLogin() { - return false; - } - - // - // PRIVATE METHODS - // - - /** - * Creates a JSON object from the given Sone. - * - * @param sone - * The Sone to convert to a JSON object - * @return The JSON representation of the given Sone - */ - private JsonNode createJsonSone(Sone sone) { - ObjectNode jsonSone = new ObjectNode(instance); - jsonSone.put("id", sone.getId()); - jsonSone.put("name", SoneAccessor.getNiceName(sone)); - jsonSone.put("local", sone.isLocal()); - jsonSone.put("status", sone.getStatus().name()); - jsonSone.put("modified", webInterface.getCore().isModifiedSone(sone)); - jsonSone.put("locked", webInterface.getCore().isLocked(sone)); - jsonSone.put("lastUpdatedUnknown", sone.getTime() == 0); - synchronized (dateFormat) { - jsonSone.put("lastUpdated", dateFormat.format(new Date(sone.getTime()))); - } - TimeText timeText = timeTextConverter.getTimeText(sone.getTime()); - jsonSone.put("lastUpdatedText", l10nFilter.format(null, timeText.getL10nText(), Collections.emptyMap())); - return jsonSone; - } - - /** - * Creates a JSON object that contains all options that are currently in - * effect for the given Sone (or overall, if the given Sone is {@code null} - * ). - * - * @param currentSone - * The current Sone (may be {@code null}) - * @return The current options - */ - private static JsonNode createJsonOptions(Sone currentSone) { - ObjectNode options = new ObjectNode(instance); - if (currentSone != null) { - options.put("ShowNotification/NewSones", currentSone.getOptions().isShowNewSoneNotifications()); - options.put("ShowNotification/NewPosts", currentSone.getOptions().isShowNewPostNotifications()); - options.put("ShowNotification/NewReplies", currentSone.getOptions().isShowNewReplyNotifications()); - } - return options; - } - -} diff --git a/src/main/java/net/pterodactylus/sone/web/ajax/JsonPage.java b/src/main/java/net/pterodactylus/sone/web/ajax/JsonPage.java index eee28ec..70ecb2b 100644 --- a/src/main/java/net/pterodactylus/sone/web/ajax/JsonPage.java +++ b/src/main/java/net/pterodactylus/sone/web/ajax/JsonPage.java @@ -27,6 +27,8 @@ import java.net.URI; import java.util.logging.Level; import java.util.logging.Logger; +import javax.annotation.Nonnull; + import net.pterodactylus.sone.data.Sone; import net.pterodactylus.sone.web.WebInterface; import net.pterodactylus.sone.web.page.FreenetPage; @@ -138,6 +140,7 @@ public abstract class JsonPage implements FreenetPage { * * @return A reply signaling success */ + @Nonnull protected static JsonReturnObject createSuccessJsonObject() { return new JsonReturnObject(true); } @@ -149,6 +152,7 @@ public abstract class JsonPage implements FreenetPage { * The error that has occured * @return The JSON object, signalling failure and the error code */ + @Nonnull protected static JsonReturnObject createErrorJsonObject(String error) { return new JsonErrorReturnObject(error); } diff --git a/src/main/kotlin/net/pterodactylus/sone/web/ajax/GetStatusAjaxPage.kt b/src/main/kotlin/net/pterodactylus/sone/web/ajax/GetStatusAjaxPage.kt new file mode 100644 index 0000000..21d296a --- /dev/null +++ b/src/main/kotlin/net/pterodactylus/sone/web/ajax/GetStatusAjaxPage.kt @@ -0,0 +1,85 @@ +package net.pterodactylus.sone.web.ajax + +import com.fasterxml.jackson.databind.JsonNode +import net.pterodactylus.sone.data.Post +import net.pterodactylus.sone.data.PostReply +import net.pterodactylus.sone.data.Sone +import net.pterodactylus.sone.data.SoneOptions +import net.pterodactylus.sone.freenet.L10nFilter +import net.pterodactylus.sone.template.SoneAccessor +import net.pterodactylus.sone.text.TimeTextConverter +import net.pterodactylus.sone.utils.jsonObject +import net.pterodactylus.sone.utils.toArray +import net.pterodactylus.sone.web.WebInterface +import net.pterodactylus.sone.web.page.FreenetRequest +import java.text.SimpleDateFormat + +/** + * The “get status” AJAX handler returns all information that is necessary to + * update the web interface in real-time. + */ +class GetStatusAjaxPage(webInterface: WebInterface, private val timeTextConverter: TimeTextConverter, private val l10nFilter: L10nFilter): + JsonPage("getStatus.ajax", webInterface) { + + private val dateFormatter = SimpleDateFormat("MMM d, yyyy, HH:mm:ss") + + override fun createJsonObject(request: FreenetRequest) = + (webInterface.getCurrentSoneWithoutCreatingSession(request.toadletContext) as Sone?).let { currentSone -> + createSuccessJsonObject().apply { + this["loggedIn"] = currentSone != null + this["options"] = currentSone?.options?.toJsonOptions() ?: jsonObject {} + this["notificationHash"] = webInterface.getNotifications(currentSone).sortedBy { it.createdTime }.hashCode() + this["sones"] = request.httpRequest.getParam("soneIds").split(',').map { webInterface.core.getSone(it).orNull() }.plus(currentSone).filterNotNull().toJsonSones() + this["newPosts"] = webInterface.getNewPosts(currentSone).toJsonPosts() + this["newReplies"] = webInterface.getNewReplies(currentSone).toJsonReplies() + } + } + + private operator fun JsonReturnObject.set(key: String, value: JsonNode) = put(key, value) + private operator fun JsonReturnObject.set(key: String, value: Int) = put(key, value) + private operator fun JsonReturnObject.set(key: String, value: Boolean) = put(key, value) + + override fun needsFormPassword() = false + override fun requiresLogin() = false + + private fun SoneOptions.toJsonOptions() = jsonObject { + put("ShowNotification/NewSones", isShowNewSoneNotifications) + put("ShowNotification/NewPosts", isShowNewPostNotifications) + put("ShowNotification/NewReplies", isShowNewReplyNotifications) + } + + private fun Iterable.toJsonSones() = map { sone -> + jsonObject { + put("id", sone.id) + put("name", SoneAccessor.getNiceName(sone)) + put("local", sone.isLocal) + put("status", sone.status.name) + put("modified", webInterface.core.isModifiedSone(sone)) + put("locked", webInterface.core.isLocked(sone)) + put("lastUpdatedUnknown", sone.time == 0L) + synchronized(dateFormatter) { + put("lastUpdated", dateFormatter.format(sone.time)) + } + put("lastUpdatedText", timeTextConverter.getTimeText(sone.time).l10nText.let { l10nFilter.format(null, it, emptyMap()) }) + } + }.toArray() + + private fun Iterable.toJsonPosts() = map { post -> + jsonObject { + put("id", post.id) + put("sone", post.sone.id) + put("time", post.time) + put("recipient", post.recipientId.orNull()) + } + }.toArray() + + private fun Iterable.toJsonReplies() = map { reply -> + jsonObject { + put("id", reply.id) + put("sone", reply.sone.id) + put("post", reply.postId) + put("postSone", reply.post.get().sone.id) + } + }.toArray() + +} -- 2.7.4