1 package net.pterodactylus.sone.web.ajax
3 import com.fasterxml.jackson.databind.JsonNode
4 import com.fasterxml.jackson.databind.ObjectMapper
5 import net.pterodactylus.sone.core.ElementLoader
6 import net.pterodactylus.sone.core.LinkedElement
7 import net.pterodactylus.sone.data.Post
8 import net.pterodactylus.sone.data.PostReply
9 import net.pterodactylus.sone.data.Sone
10 import net.pterodactylus.sone.data.SoneOptions
11 import net.pterodactylus.sone.freenet.L10nFilter
12 import net.pterodactylus.sone.template.SoneAccessor
13 import net.pterodactylus.sone.text.TimeTextConverter
14 import net.pterodactylus.sone.utils.jsonObject
15 import net.pterodactylus.sone.utils.toArray
16 import net.pterodactylus.sone.web.WebInterface
17 import net.pterodactylus.sone.web.page.FreenetRequest
18 import java.text.SimpleDateFormat
21 * The “get status” AJAX handler returns all information that is necessary to
22 * update the web interface in real-time.
24 class GetStatusAjaxPage(webInterface: WebInterface, private val elementLoader: ElementLoader, private val timeTextConverter: TimeTextConverter, private val l10nFilter: L10nFilter):
25 JsonPage("getStatus.ajax", webInterface) {
27 private val dateFormatter = SimpleDateFormat("MMM d, yyyy, HH:mm:ss")
29 override fun createJsonObject(request: FreenetRequest) =
30 (webInterface.getCurrentSoneWithoutCreatingSession(request.toadletContext) as Sone?).let { currentSone ->
31 createSuccessJsonObject().apply {
32 this["loggedIn"] = currentSone != null
33 this["options"] = currentSone?.options?.toJsonOptions() ?: jsonObject {}
34 this["notificationHash"] = webInterface.getNotifications(currentSone).sortedBy { it.createdTime }.hashCode()
35 this["sones"] = request.httpRequest.getParam("soneIds").split(',').map { webInterface.core.getSone(it).orNull() }.plus(currentSone).filterNotNull().toJsonSones()
36 this["newPosts"] = webInterface.getNewPosts(currentSone).toJsonPosts()
37 this["newReplies"] = webInterface.getNewReplies(currentSone).toJsonReplies()
38 this["linkedElements"] = request.httpRequest.getParam("elements", "[]").asJson().map(JsonNode::asText).map(elementLoader::loadElement).toJsonElements()
42 private operator fun JsonReturnObject.set(key: String, value: JsonNode) = put(key, value)
43 private operator fun JsonReturnObject.set(key: String, value: Int) = put(key, value)
44 private operator fun JsonReturnObject.set(key: String, value: Boolean) = put(key, value)
46 private fun String.asJson() = ObjectMapper().readTree(this).asIterable()
48 override fun needsFormPassword() = false
49 override fun requiresLogin() = false
51 private fun SoneOptions.toJsonOptions() = jsonObject {
52 put("ShowNotification/NewSones", isShowNewSoneNotifications)
53 put("ShowNotification/NewPosts", isShowNewPostNotifications)
54 put("ShowNotification/NewReplies", isShowNewReplyNotifications)
57 private fun Iterable<Sone>.toJsonSones() = map { sone ->
60 put("name", SoneAccessor.getNiceName(sone))
61 put("local", sone.isLocal)
62 put("status", sone.status.name)
63 put("modified", webInterface.core.isModifiedSone(sone))
64 put("locked", webInterface.core.isLocked(sone))
65 put("lastUpdatedUnknown", sone.time == 0L)
66 synchronized(dateFormatter) {
67 put("lastUpdated", dateFormatter.format(sone.time))
69 put("lastUpdatedText", timeTextConverter.getTimeText(sone.time).l10nText.let { l10nFilter.format(null, it, emptyMap()) })
73 private fun Iterable<Post>.toJsonPosts() = map { post ->
76 put("sone", post.sone.id)
77 put("time", post.time)
78 put("recipient", post.recipientId.orNull())
82 private fun Iterable<PostReply>.toJsonReplies() = map { reply ->
85 put("sone", reply.sone.id)
86 put("post", reply.postId)
87 put("postSone", reply.post.get().sone.id)
91 private fun Iterable<LinkedElement>.toJsonElements() = map { (link, failed, loading) ->
94 put("loading", loading)