0017a32489b0fa24398bb6a95872fa94757e7f09
[Sone.git] / src / main / kotlin / net / pterodactylus / sone / web / ajax / GetStatusAjaxPage.kt
1 package net.pterodactylus.sone.web.ajax
2
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
19 import java.util.TimeZone
20 import javax.inject.Inject
21
22 /**
23  * The “get status” AJAX handler returns all information that is necessary to
24  * update the web interface in real-time.
25  */
26 class GetStatusAjaxPage(webInterface: WebInterface, private val elementLoader: ElementLoader, private val timeTextConverter: TimeTextConverter, private val l10nFilter: L10nFilter, timeZone: TimeZone):
27                 JsonPage("getStatus.ajax", webInterface) {
28
29         @Inject constructor(webInterface: WebInterface, elementLoader: ElementLoader, timeTextConverter: TimeTextConverter, l10nFilter: L10nFilter):
30                         this(webInterface, elementLoader, timeTextConverter, l10nFilter, TimeZone.getDefault())
31
32         private val dateFormatter = SimpleDateFormat("MMM d, yyyy, HH:mm:ss").apply {
33                 this.timeZone = timeZone
34         }
35
36         override fun createJsonObject(request: FreenetRequest) =
37                         getCurrentSone(request.toadletContext, false).let { currentSone ->
38                                 createSuccessJsonObject().apply {
39                                         this["loggedIn"] = currentSone != null
40                                         this["options"] = currentSone?.options?.toJsonOptions() ?: jsonObject {}
41                                         this["notificationHash"] = webInterface.getNotifications(currentSone).sortedBy { it.createdTime }.hashCode()
42                                         this["sones"] = request.httpRequest.getParam("soneIds").split(',').mapNotNull(core::getSone).plus(currentSone).filterNotNull().toJsonSones()
43                                         this["newPosts"] = webInterface.getNewPosts(currentSone).toJsonPosts()
44                                         this["newReplies"] = webInterface.getNewReplies(currentSone).toJsonReplies()
45                                         this["linkedElements"] = request.httpRequest.getParam("elements", "[]").asJson().map(JsonNode::asText).map(elementLoader::loadElement).toJsonElements()
46                                 }
47                         }
48
49         private operator fun JsonReturnObject.set(key: String, value: JsonNode) = put(key, value)
50         private operator fun JsonReturnObject.set(key: String, value: Int) = put(key, value)
51         private operator fun JsonReturnObject.set(key: String, value: Boolean) = put(key, value)
52
53         private fun String.asJson() = ObjectMapper().readTree(this).asIterable()
54
55         override val needsFormPassword = false
56         override val requiresLogin = false
57
58         private fun SoneOptions.toJsonOptions() = jsonObject {
59                 put("ShowNotification/NewSones", isShowNewSoneNotifications)
60                 put("ShowNotification/NewPosts", isShowNewPostNotifications)
61                 put("ShowNotification/NewReplies", isShowNewReplyNotifications)
62         }
63
64         private fun Iterable<Sone>.toJsonSones() = map { sone ->
65                 jsonObject {
66                         put("id", sone.id)
67                         put("name", SoneAccessor.getNiceName(sone))
68                         put("local", sone.isLocal)
69                         put("status", sone.status.name)
70                         put("modified", core.isModifiedSone(sone))
71                         put("locked", core.isLocked(sone))
72                         put("lastUpdatedUnknown", sone.time == 0L)
73                         synchronized(dateFormatter) {
74                                 put("lastUpdated", dateFormatter.format(sone.time))
75                         }
76                         put("lastUpdatedText", timeTextConverter.getTimeText(sone.time).l10nText.let { l10nFilter.format(null, it, emptyMap()) })
77                 }
78         }.toArray()
79
80         private fun Iterable<Post>.toJsonPosts() = map { post ->
81                 jsonObject {
82                         put("id", post.id)
83                         put("sone", post.sone.id)
84                         put("time", post.time)
85                         put("recipient", post.recipientId.orNull())
86                 }
87         }.toArray()
88
89         private fun Iterable<PostReply>.toJsonReplies() = map { reply ->
90                 jsonObject {
91                         put("id", reply.id)
92                         put("sone", reply.sone.id)
93                         put("post", reply.postId)
94                         put("postSone", reply.post.get().sone.id)
95                 }
96         }.toArray()
97
98         private fun Iterable<LinkedElement>.toJsonElements() = map { (link, failed, loading) ->
99                 jsonObject {
100                         put("link", link)
101                         put("loading", loading)
102                         put("failed", failed)
103                 }
104         }.toArray()
105
106 }