Improvements for working with conversations

This commit is contained in:
Christian Basler 2018-03-05 10:12:21 +01:00
parent f1403bcd00
commit 81fc50ec37
4 changed files with 30 additions and 9 deletions

View File

@ -815,3 +815,14 @@ class Plaintext private constructor(
} }
} }
data class Conversation(val id: UUID, val subject: String, val messages: List<Plaintext>) {
val participants = messages
.map { it.from }
.filter { it.privateKey == null || it.isChan }
.distinct()
val extract: String by lazy { messages.lastOrNull()?.text ?: "" }
fun hasUnread() = messages.any { it.isUnread() }
}

View File

@ -41,7 +41,7 @@ interface MessageRepository {
* * * *
* @return a distinct list of all conversations that have at least one message with the given label. * @return a distinct list of all conversations that have at least one message with the given label.
*/ */
fun findConversations(label: Label?): List<UUID> fun findConversations(label: Label?, offset: Int = 0, limit: Int = 0): List<UUID>
fun findMessages(label: Label?): List<Plaintext> fun findMessages(label: Label?): List<Plaintext>

View File

@ -16,10 +16,11 @@
package ch.dissem.bitmessage.utils package ch.dissem.bitmessage.utils
import ch.dissem.bitmessage.entity.Conversation
import ch.dissem.bitmessage.entity.Plaintext import ch.dissem.bitmessage.entity.Plaintext
import ch.dissem.bitmessage.entity.valueobject.InventoryVector import ch.dissem.bitmessage.entity.valueobject.InventoryVector
import ch.dissem.bitmessage.entity.valueobject.Label
import ch.dissem.bitmessage.ports.MessageRepository import ch.dissem.bitmessage.ports.MessageRepository
import org.slf4j.LoggerFactory
import java.util.* import java.util.*
import java.util.Collections import java.util.Collections
import java.util.regex.Pattern import java.util.regex.Pattern
@ -30,7 +31,10 @@ import java.util.regex.Pattern.CASE_INSENSITIVE
*/ */
class ConversationService(private val messageRepository: MessageRepository) { class ConversationService(private val messageRepository: MessageRepository) {
private val SUBJECT_PREFIX = Pattern.compile("^(re|fwd?):", CASE_INSENSITIVE) private val SUBJECT_PREFIX = Pattern.compile("^(re|fwd?):\\s*", CASE_INSENSITIVE)
fun findConversations(label: Label?, offset: Int = 0, limit: Int = 0) = messageRepository.findConversations(label, offset, limit)
.map { getConversation(it) }
/** /**
* Retrieve the whole conversation from one single message. If the message isn't part * Retrieve the whole conversation from one single message. If the message isn't part
@ -41,7 +45,7 @@ class ConversationService(private val messageRepository: MessageRepository) {
* * * *
* @return a list of messages that belong to the same conversation. * @return a list of messages that belong to the same conversation.
*/ */
fun getConversation(message: Plaintext): List<Plaintext> { fun getConversation(message: Plaintext): Conversation {
return getConversation(message.conversationId) return getConversation(message.conversationId)
} }
@ -58,7 +62,7 @@ class ConversationService(private val messageRepository: MessageRepository) {
return result return result
} }
fun getConversation(conversationId: UUID): List<Plaintext> { fun getConversation(conversationId: UUID): Conversation {
val messages = sorted(messageRepository.getConversation(conversationId)) val messages = sorted(messageRepository.getConversation(conversationId))
val map = HashMap<InventoryVector, Plaintext>(messages.size) val map = HashMap<InventoryVector, Plaintext>(messages.size)
for (message in messages) { for (message in messages) {
@ -74,7 +78,7 @@ class ConversationService(private val messageRepository: MessageRepository) {
result.add(pos, last) result.add(pos, last)
addAncestors(last, result, messages, map) addAncestors(last, result, messages, map)
} }
return result return Conversation(conversationId, getSubject(result) ?: "", result)
} }
fun getSubject(conversation: List<Plaintext>): String? { fun getSubject(conversation: List<Plaintext>): String? {
@ -109,7 +113,12 @@ class ConversationService(private val messageRepository: MessageRepository) {
return child.parents.firstOrNull { it == item.inventoryVector } != null return child.parents.firstOrNull { it == item.inventoryVector } != null
} }
private fun addAncestors(message: Plaintext, result: LinkedList<Plaintext>, messages: LinkedList<Plaintext>, map: MutableMap<InventoryVector, Plaintext>) { private fun addAncestors(
message: Plaintext,
result: LinkedList<Plaintext>,
messages: LinkedList<Plaintext>,
map: MutableMap<InventoryVector, Plaintext>
) {
for (parentKey in message.parents) { for (parentKey in message.parents) {
map.remove(parentKey)?.let { map.remove(parentKey)?.let {
messages.remove(it) messages.remove(it)

View File

@ -257,18 +257,19 @@ class JdbcMessageRepository(private val config: JdbcConfig) : AbstractMessageRep
} }
} }
override fun findConversations(label: Label?): List<UUID> { override fun findConversations(label: Label?, offset: Int, limit: Int): List<UUID> {
val where = if (label == null) { val where = if (label == null) {
"id NOT IN (SELECT message_id FROM Message_Label)" "id NOT IN (SELECT message_id FROM Message_Label)"
} else { } else {
"id IN (SELECT message_id FROM Message_Label WHERE label_id=${label.id})" "id IN (SELECT message_id FROM Message_Label WHERE label_id=${label.id})"
} }
val limit = if (limit == 0) "" else "LIMIT $limit OFFSET $offset"
val result = LinkedList<UUID>() val result = LinkedList<UUID>()
try { try {
config.getConnection().use { connection -> config.getConnection().use { connection ->
connection.createStatement().use { stmt -> connection.createStatement().use { stmt ->
stmt.executeQuery( stmt.executeQuery(
"SELECT DISTINCT conversation FROM Message WHERE $where").use { rs -> "SELECT DISTINCT conversation FROM Message WHERE $where $limit").use { rs ->
while (rs.next()) { while (rs.next()) {
result.add(rs.getObject(1) as UUID) result.add(rs.getObject(1) as UUID)
} }