♻️ Change dependencies of render filter
[Sone.git] / src / main / kotlin / net / pterodactylus / sone / template / RenderFilter.kt
1 package net.pterodactylus.sone.template
2
3 import net.pterodactylus.sone.database.*
4 import net.pterodactylus.sone.text.*
5 import net.pterodactylus.sone.text.Part
6 import net.pterodactylus.sone.utils.*
7 import net.pterodactylus.util.template.*
8 import java.io.*
9 import java.net.*
10
11 /**
12  * Renders a number of pre-parsed [Part] into a [String].
13  */
14 class RenderFilter(private val soneProvider: SoneProvider, private val soneTextParser: SoneTextParser, htmlFilter: HtmlFilter) : Filter {
15
16         private val templateContextFactory = TemplateContextFactory().apply {
17                 addFilter("html", htmlFilter)
18         }
19
20         override fun format(templateContext: TemplateContext?, data: Any?, parameters: MutableMap<String, Any?>?): Any? {
21                 @Suppress("UNCHECKED_CAST")
22                 val parts = data as? Iterable<Part> ?: return null
23                 val parsedTextWriter = StringWriter()
24                 render(parsedTextWriter, parts)
25                 return parsedTextWriter.toString()
26         }
27
28         private fun render(writer: Writer, parts: Iterable<Part>) {
29                 parts.forEach { render(writer, it) }
30         }
31
32         private fun render(writer: Writer, part: Part) {
33                 @Suppress("UNCHECKED_CAST")
34                 when (part) {
35                         is PlainTextPart -> render(writer, part)
36                         is FreenetLinkPart -> render(writer, part)
37                         is LinkPart -> render(writer, part)
38                         is SonePart -> render(writer, part)
39                         is PostPart -> render(writer, part)
40                         is FreemailPart -> render(writer, part)
41                 }
42         }
43
44         private fun render(writer: Writer, plainTextPart: PlainTextPart) {
45                 val templateContext = templateContextFactory.createTemplateContext()
46                 templateContext.set("text", plainTextPart.text)
47                 plainTextTemplate.render(templateContext, writer)
48         }
49
50         private fun render(writer: Writer, freenetLinkPart: FreenetLinkPart) {
51                 renderLink(writer, "/${freenetLinkPart.link}", freenetLinkPart.text, freenetLinkPart.title, if (freenetLinkPart.trusted) "freenet-trusted" else "freenet")
52         }
53
54         private fun render(writer: Writer, linkPart: LinkPart) {
55                 renderLink(writer, "/external-link/?_CHECKED_HTTP_=${linkPart.link.urlEncode()}", linkPart.text, linkPart.title, "internet")
56         }
57
58         private fun String.urlEncode(): String = URLEncoder.encode(this, "UTF-8")
59
60         private fun render(writer: Writer, sonePart: SonePart) {
61                 if (sonePart.sone.name != null) {
62                         renderLink(writer, "viewSone.html?sone=${sonePart.sone.id}", SoneAccessor.getNiceName(sonePart.sone), SoneAccessor.getNiceName(sonePart.sone), "in-sone")
63                 } else {
64                         renderLink(writer, "/WebOfTrust/ShowIdentity?id=${sonePart.sone.id}", sonePart.sone.id, sonePart.sone.id, "in-sone")
65                 }
66         }
67
68         private fun render(writer: Writer, postPart: PostPart) {
69                 val parserContext = SoneTextParserContext(postPart.post.sone)
70                 val parts = soneTextParser.parse(postPart.post.text, parserContext)
71                 val excerpt = StringBuilder()
72                 for (part in parts) {
73                         excerpt.append(part.text)
74                         if (excerpt.length > 20) {
75                                 val lastSpace = excerpt.lastIndexOf(" ", 20)
76                                 if (lastSpace > -1) {
77                                         excerpt.setLength(lastSpace)
78                                 } else {
79                                         excerpt.setLength(20)
80                                 }
81                                 excerpt.append("…")
82                                 break
83                         }
84                 }
85                 renderLink(writer, "viewPost.html?post=${postPart.post.id}", excerpt.toString(), SoneAccessor.getNiceName(postPart.post.sone), "in-sone")
86         }
87
88         private fun render(writer: Writer, freemailPart: FreemailPart) {
89                 val sone = soneProvider.getSone(freemailPart.identityId)
90                 val soneName = sone?.let(SoneAccessor::getNiceName) ?: freemailPart.identityId
91                 renderLink(writer,
92                                 "/Freemail/NewMessage?to=${freemailPart.identityId}",
93                                 "${freemailPart.emailLocalPart}@$soneName.freemail",
94                                 "$soneName\n${freemailPart.emailLocalPart}@${freemailPart.freemailId}.freemail",
95                                 "in-sone")
96         }
97
98         private fun renderLink(writer: Writer, link: String, text: String, title: String, cssClass: String) {
99                 val templateContext = templateContextFactory.createTemplateContext()
100                 templateContext["cssClass"] = cssClass
101                 templateContext["link"] = link
102                 templateContext["text"] = text
103                 templateContext["title"] = title
104                 linkTemplate.render(templateContext, writer)
105         }
106
107 }
108
109 private val plainTextTemplate = "<%text|html>".asTemplate()
110 private val linkTemplate = "<a class=\"<%cssClass|html>\" href=\"<%link|html>\" title=\"<%title|html>\"><%text|html></a>".asTemplate()