Skip to content

Commit ec017f8

Browse files
committed
feat(db-repository): implement create message in MessageLifecycleRepository
- Wire MessageLifecycleRepository into MessagingController for sending messages - Replace direct MessageStore calls with repository.create() in sendMessage() - Add DefaultMessageLifecycleRepository implementing create() with legacy adapter logic - Add messageLifecycleRepository, messageDataMapper, and messageIdLegacyEntityIdFactory dependencies - Convert domain Message to legacy DTO, save to outbox folder, and initialize outbox state - Add MessageLifecycleRepository registration in MailMessageModule - Add feature.mail.message.api dependency to legacy core GG-ID: c-639ad93 GG-Parent: c-be36e42
1 parent 472f05f commit ec017f8

21 files changed

Lines changed: 876 additions & 68 deletions

File tree

‎app-common/src/main/kotlin/net/thunderbird/app/common/feature/mail/message/MailMessageModule.kt‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import com.fsck.k9.mail.Message
55
import com.fsck.k9.mail.Part
66
import com.fsck.k9.mailstore.DefaultAttachmentViewInfoMapper
77
import com.fsck.k9.ui.helper.SizeFormatter
8+
import net.thunderbird.app.common.feature.mail.message.data.repository.DefaultMessageLifecycleRepository
89
import net.thunderbird.app.common.feature.mail.message.data.repository.DefaultMessageQueryRepository
910
import net.thunderbird.app.common.feature.mail.message.list.LegacyUpdateSortCriteria
1011
import net.thunderbird.app.common.feature.mail.message.mapper.AttachmentResolver
@@ -18,6 +19,7 @@ import net.thunderbird.feature.mail.message.LegacyMessageIdFactory
1819
import net.thunderbird.feature.mail.message.LegacyThreadIdFactory
1920
import net.thunderbird.feature.mail.message.MessageId
2021
import net.thunderbird.feature.mail.message.ThreadId
22+
import net.thunderbird.feature.mail.message.domain.MessageLifecycleRepository
2123
import net.thunderbird.feature.mail.message.domain.MessageQueryRepository
2224
import net.thunderbird.feature.mail.message.list.domain.model.SortCriteria
2325
import net.thunderbird.feature.mail.message.list.extension.toSortType
@@ -75,4 +77,16 @@ internal val mailMessageModule = module {
7577
folderIdLegacyEntityIdFactory = get<LegacyEntityIdFactory<FolderId>>(named(ByteRepresentation.FOLDERS)),
7678
)
7779
}
80+
81+
single<MessageLifecycleRepository> {
82+
DefaultMessageLifecycleRepository(
83+
logger = get(),
84+
messageStoreManager = get(),
85+
saveMessageDataCreator = get(),
86+
messageMapper = get(),
87+
messageIdLegacyEntityIdFactory = get<LegacyEntityIdFactory<MessageId>>(named(ByteRepresentation.MESSAGE)),
88+
folderIdLegacyEntityIdFactory = get<LegacyEntityIdFactory<FolderId>>(named(ByteRepresentation.FOLDERS)),
89+
outboxFolderManager = get(),
90+
)
91+
}
7892
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
package net.thunderbird.app.common.feature.mail.message.data.repository
2+
3+
import app.k9mail.legacy.mailstore.ListenableMessageStore
4+
import app.k9mail.legacy.mailstore.MessageStoreManager
5+
import app.k9mail.legacy.mailstore.SaveMessageData
6+
import com.fsck.k9.mailstore.SaveMessageDataCreator
7+
import kotlinx.coroutines.CoroutineDispatcher
8+
import kotlinx.coroutines.Dispatchers
9+
import kotlinx.coroutines.withContext
10+
import net.thunderbird.app.common.feature.mail.message.domain.model.LegacyMessageSource
11+
import net.thunderbird.components.core.outcome.Outcome
12+
import net.thunderbird.core.architecture.model.LegacyEntityIdFactory
13+
import net.thunderbird.core.logging.Logger
14+
import net.thunderbird.feature.account.AccountId
15+
import net.thunderbird.feature.mail.folder.FolderId
16+
import net.thunderbird.feature.mail.folder.api.OutboxFolderManager
17+
import net.thunderbird.feature.mail.message.Message
18+
import net.thunderbird.feature.mail.message.MessageDownloadState
19+
import net.thunderbird.feature.mail.message.MessageId
20+
import net.thunderbird.feature.mail.message.MessageServerId
21+
import net.thunderbird.feature.mail.message.domain.MessageLifecycleError
22+
import net.thunderbird.feature.mail.message.domain.MessageLifecycleRepository
23+
import net.thunderbird.feature.mail.message.mapper.MessageDataMapper
24+
import com.fsck.k9.mail.Message as LegacyMessageDto
25+
import com.fsck.k9.mail.MessageDownloadState as LegacyMessageDownloadState
26+
27+
private const val LOG_ID = "[repository][message-lifecycle]"
28+
29+
class DefaultMessageLifecycleRepository(
30+
private val logger: Logger,
31+
private val messageStoreManager: MessageStoreManager,
32+
private val saveMessageDataCreator: SaveMessageDataCreator,
33+
private val messageMapper: MessageDataMapper<LegacyMessageDto>,
34+
private val messageIdLegacyEntityIdFactory: LegacyEntityIdFactory<MessageId>,
35+
private val folderIdLegacyEntityIdFactory: LegacyEntityIdFactory<FolderId>,
36+
private val outboxFolderManager: OutboxFolderManager,
37+
private val ioDispatcher: CoroutineDispatcher = Dispatchers.IO,
38+
) : MessageLifecycleRepository {
39+
override suspend fun create(
40+
message: Message,
41+
accountId: AccountId,
42+
folderId: FolderId?,
43+
): Outcome<MessageId, MessageLifecycleError> = withContext(ioDispatcher) {
44+
logger.debug {
45+
"$LOG_ID creating new message in folder '${folderId ?: "<outbox-id>"}' for account '$accountId'"
46+
}
47+
logger.verbose { "$LOG_ID message = $message" }
48+
val messageData = message.toSaveMessageData()
49+
val messageStore = messageStoreManager.getMessageStore(accountId)
50+
val legacyFolderId = if (folderId == null) {
51+
outboxFolderManager.getOutboxFolderId(accountId)
52+
} else {
53+
folderIdLegacyEntityIdFactory.toLegacyId(folderId)
54+
}
55+
logger.verbose { "$LOG_ID assigning message to folder id = $legacyFolderId" }
56+
57+
val messageServerId = message.serverId
58+
val messageId = if (messageServerId == null) {
59+
createLocalMessage(messageStore, legacyFolderId, messageData)
60+
} else {
61+
createRemoteMessage(messageStore, legacyFolderId, messageServerId, messageData)
62+
}
63+
logger.verbose { "$LOG_ID message created successfully. MessageId = $messageId" }
64+
Outcome.success(messageId)
65+
}
66+
67+
override suspend fun update(
68+
message: Message,
69+
accountId: AccountId,
70+
): Outcome<MessageId, MessageLifecycleError> {
71+
TODO("Not yet implemented")
72+
}
73+
74+
override suspend fun move(
75+
messageId: MessageId,
76+
destinationFolderId: FolderId,
77+
): Outcome<MessageId, MessageLifecycleError> {
78+
TODO("Not yet implemented")
79+
}
80+
81+
override suspend fun copy(
82+
messageId: MessageId,
83+
destinationFolderId: FolderId,
84+
): Outcome<MessageId, MessageLifecycleError> {
85+
TODO("Not yet implemented")
86+
}
87+
88+
override suspend fun destroy(
89+
serverIds: List<MessageServerId>,
90+
folderId: FolderId,
91+
accountId: AccountId,
92+
): Outcome<Unit, MessageLifecycleError> {
93+
TODO("Not yet implemented")
94+
}
95+
96+
private fun createLocalMessage(
97+
messageStore: ListenableMessageStore,
98+
legacyFolderId: Long,
99+
messageData: SaveMessageData,
100+
): MessageId {
101+
logger.verbose { "$LOG_ID creating local message in folder id '$legacyFolderId'" }
102+
val legacyMessageId = messageStore.saveLocalMessage(
103+
folderId = legacyFolderId,
104+
messageData = messageData,
105+
existingMessageId = null,
106+
)
107+
return messageIdLegacyEntityIdFactory.of(legacyMessageId)
108+
}
109+
110+
private fun createRemoteMessage(
111+
messageStore: ListenableMessageStore,
112+
legacyFolderId: Long,
113+
messageServerId: MessageServerId,
114+
messageData: SaveMessageData,
115+
): MessageId {
116+
logger.verbose { "$LOG_ID creating remote message in folder id '$legacyFolderId'" }
117+
val legacyMessageId = messageStore.saveRemoteMessage(
118+
folderId = legacyFolderId,
119+
messageData = messageData,
120+
messageServerId = messageServerId.value,
121+
)
122+
return messageIdLegacyEntityIdFactory.of(legacyMessageId)
123+
}
124+
125+
private fun MessageDownloadState.toLegacyDownloadState(): LegacyMessageDownloadState = when (this) {
126+
MessageDownloadState.ENVELOPE -> LegacyMessageDownloadState.ENVELOPE
127+
MessageDownloadState.PARTIAL -> LegacyMessageDownloadState.PARTIAL
128+
MessageDownloadState.FULL -> LegacyMessageDownloadState.FULL
129+
}
130+
131+
private suspend fun Message.toSaveMessageData(): SaveMessageData {
132+
val downloadState = downloadState.toLegacyDownloadState()
133+
return when (val source = source) {
134+
is LegacyMessageSource -> {
135+
logger.verbose {
136+
"$LOG_ID convert message -> save message data using message source ($source)"
137+
}
138+
saveMessageDataCreator.createSaveMessageData(
139+
source.message,
140+
downloadState,
141+
envelope.subject,
142+
)
143+
}
144+
145+
else -> {
146+
logger.verbose { "$LOG_ID convert message -> save message data using message mapper" }
147+
saveMessageDataCreator.createSaveMessageData(messageMapper.toDto(this), downloadState)
148+
}
149+
}
150+
}
151+
}

0 commit comments

Comments
 (0)