🔀 Merge branch 'release/v82'
[Sone.git] / src / main / kotlin / net / pterodactylus / sone / text / SoneMentionDetector.kt
1 /**
2  * Sone - SoneMentionDetector.kt - Copyright Â© 2019–2020 David â€˜Bombe’ Roden
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16  */
17
18 package net.pterodactylus.sone.text
19
20 import com.google.common.eventbus.*
21 import net.pterodactylus.sone.core.event.*
22 import net.pterodactylus.sone.data.*
23 import net.pterodactylus.sone.database.*
24 import net.pterodactylus.sone.utils.*
25 import javax.inject.*
26
27 /**
28  * Listens to [NewPostFoundEvent]s and [NewPostReplyFoundEvent], parses the
29  * texts and emits a [MentionOfLocalSoneFoundEvent] if a [SoneTextParser]
30  * finds a [SonePart] that points to a local [Sone].
31  */
32 class SoneMentionDetector @Inject constructor(private val eventBus: EventBus, private val soneTextParser: SoneTextParser, private val postReplyProvider: PostReplyProvider) {
33
34         @Subscribe
35         fun onNewPost(newPostFoundEvent: NewPostFoundEvent) {
36                 newPostFoundEvent.post.let { post ->
37                         post.sone.isLocal.onFalse {
38                                 if (post.text.hasLinksToLocalSones()) {
39                                         mentionedPosts += post
40                                         eventBus.post(MentionOfLocalSoneFoundEvent(post))
41                                 }
42                         }
43                 }
44         }
45
46         @Subscribe
47         fun onNewPostReply(event: NewPostReplyFoundEvent) {
48                 event.postReply.let { postReply ->
49                         postReply.sone.isLocal.onFalse {
50                                 if (postReply.text.hasLinksToLocalSones()) {
51                                         postReply.post
52                                                         .also { mentionedPosts += it }
53                                                         .let(::MentionOfLocalSoneFoundEvent)
54                                                         ?.also(eventBus::post)
55                                 }
56                         }
57                 }
58         }
59
60         @Subscribe
61         fun onPostRemoved(event: PostRemovedEvent) {
62                 unmentionPost(event.post)
63         }
64
65         @Subscribe
66         fun onPostMarkedKnown(event: MarkPostKnownEvent) {
67                 unmentionPost(event.post)
68         }
69
70         @Subscribe
71         fun onReplyRemoved(event: PostReplyRemovedEvent) {
72                 event.postReply.post.let {
73                         if ((!it.text.hasLinksToLocalSones() || it.isKnown) && (it.replies.filterNot { it == event.postReply }.none { it.text.hasLinksToLocalSones() && !it.isKnown })) {
74                                 unmentionPost(it)
75                         }
76                 }
77         }
78
79         private fun unmentionPost(post: Post) {
80                 if (post in mentionedPosts) {
81                         eventBus.post(MentionOfLocalSoneRemovedEvent(post))
82                         mentionedPosts -= post
83                 }
84         }
85
86         private val mentionedPosts = mutableSetOf<Post>()
87
88         private fun String.hasLinksToLocalSones() = soneTextParser.parse(this, null)
89                         .filterIsInstance<SonePart>()
90                         .any { it.sone.isLocal }
91
92         private val Post.replies get() = postReplyProvider.getReplies(id)
93
94 }