diff --git a/briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/testdata/DeterministicTestDataCreatorImpl.kt b/briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/testdata/DeterministicTestDataCreatorImpl.kt index a681e897b3d616c6570ddf87ca6471880ada1036..4c3ab340fe68d608959058af0dd8589462b31dd8 100644 --- a/briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/testdata/DeterministicTestDataCreatorImpl.kt +++ b/briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/testdata/DeterministicTestDataCreatorImpl.kt @@ -43,12 +43,14 @@ import org.briarproject.bramble.api.properties.TransportPropertyManager import org.briarproject.bramble.api.sync.Group import org.briarproject.bramble.api.sync.GroupFactory import org.briarproject.bramble.api.sync.GroupId -import org.briarproject.bramble.api.sync.Message +import org.briarproject.bramble.api.sync.MessageId import org.briarproject.bramble.api.system.Clock import org.briarproject.briar.api.autodelete.AutoDeleteConstants import org.briarproject.briar.api.avatar.AvatarManager import org.briarproject.briar.api.avatar.AvatarMessageEncoder import org.briarproject.briar.api.conversation.ConversationManager +import org.briarproject.briar.api.forum.ForumFactory +import org.briarproject.briar.api.forum.ForumManager import org.briarproject.briar.api.messaging.MessagingManager import org.briarproject.briar.api.messaging.PrivateMessageFactory import org.briarproject.briar.api.privategroup.GroupMessageFactory @@ -58,6 +60,12 @@ import org.briarproject.briar.api.privategroup.PrivateGroupManager import org.briarproject.briar.api.test.TestAvatarCreator import org.briarproject.briar.desktop.GroupCountHelper import org.briarproject.briar.desktop.attachment.media.ImageCompressor +import org.briarproject.briar.desktop.testdata.conversation.Direction +import org.briarproject.briar.desktop.testdata.conversation.Message +import org.briarproject.briar.desktop.testdata.conversation.conversations +import org.briarproject.briar.desktop.testdata.forum.Post +import org.briarproject.briar.desktop.testdata.forum.PostAuthor +import org.briarproject.briar.desktop.testdata.forum.forums import org.briarproject.briar.desktop.utils.KLoggerUtils.i import org.briarproject.briar.desktop.utils.KLoggerUtils.w import java.io.IOException @@ -82,6 +90,8 @@ class DeterministicTestDataCreatorImpl @Inject internal constructor( private val contactManager: ContactManager, private val privateGroupManager: PrivateGroupManager, private val privateGroupFactory: PrivateGroupFactory, + private val forumManager: ForumManager, + private val forumFactory: ForumFactory, private val transportPropertyManager: TransportPropertyManager, private val conversationManager: ConversationManager, private val messagingManager: MessagingManager, @@ -141,6 +151,8 @@ class DeterministicTestDataCreatorImpl @Inject internal constructor( for (privateGroup in privateGroups) { createRandomPrivateGroupMessages(privateGroup, contacts, numPrivateGroupPosts) } + + createForums() } @Throws(DbException::class) @@ -297,7 +309,7 @@ class DeterministicTestDataCreatorImpl @Inject internal constructor( LOG.w(e) {} return } ?: return - val m: Message = try { + val m = try { avatarMessageEncoder.encodeUpdateMessage(groupId, 0, "image/jpeg", `is`).first } catch (e: IOException) { throw DbException(e) @@ -341,7 +353,7 @@ class DeterministicTestDataCreatorImpl @Inject internal constructor( private fun createPrivateMessage( contactId: ContactId, groupId: GroupId, - message: org.briarproject.briar.desktop.testdata.Message + message: Message ) { val timestamp = message.date.toEpochSecond(ZoneOffset.UTC) * 1000 val text = message.text @@ -427,4 +439,33 @@ class DeterministicTestDataCreatorImpl @Inject internal constructor( ) { // TODO } + + private fun createForums() { + for (f in forums.forums) { + // create forum + val forum = forumManager.addForum(f.name) + + val members = f.members.associateWith { + if (it is PostAuthor.RemoteAuthor) authorFactory.createLocalAuthor(it.name) + else identityManager.localAuthor + } + // todo: create real contact to also share forum! + + // add posts + fun addPost(post: Post, parentId: MessageId?) { + val m = forumManager.createLocalPost( + forum.id, + post.text, + post.date.toEpochSecond(ZoneOffset.UTC) * 1000, + parentId, + members[post.author]!! + ) + // todo: add non-local posts using incoming message via some contact this forum is shared with + forumManager.addLocalPost(m) + post.replies.forEach { addPost(it, m.message.id) } + } + f.posts.forEach { addPost(it, null) } + } + LOG.i { "Created ${forums.forums.size} forums." } + } } diff --git a/briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/testdata/TestDeterministicData.kt b/briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/testdata/TestDeterministicData.kt new file mode 100644 index 0000000000000000000000000000000000000000..8249d89353513576ba9fa8abf2b97090e275d419 --- /dev/null +++ b/briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/testdata/TestDeterministicData.kt @@ -0,0 +1,43 @@ +/* + * Briar Desktop + * Copyright (C) 2021-2022 The Briar Project + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +package org.briarproject.briar.desktop.testdata + +import org.briarproject.briar.desktop.testdata.conversation.conversations +import org.briarproject.briar.desktop.testdata.forum.Post +import org.briarproject.briar.desktop.testdata.forum.PostAuthor +import org.briarproject.briar.desktop.testdata.forum.forums + +fun main() { + for (conversation in conversations.persons) { + println("conversation with: ${conversation.name}") // NON-NLS + for (message in conversation.messages) { + println(" ${message.direction} ${message.text} ${message.read} ${message.date}") + } + } + + for (forum in forums.forums) { + println("Forum: ${forum.name}") // NON-NLS + fun printPost(post: Post, level: Int) { + val name = if (post.author is PostAuthor.RemoteAuthor) post.author.name else "me" + println("|".repeat(level) + "+ ${post.date} - $name: ${post.text}") + post.replies.forEach { printPost(it, level + 1) } + } + forum.posts.forEach { printPost(it, 0) } + } +} diff --git a/briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/testdata/Conversations.kt b/briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/testdata/conversation/Conversations.kt similarity index 94% rename from briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/testdata/Conversations.kt rename to briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/testdata/conversation/Conversations.kt index c157180f38094eb3c910b68378e65f01a52f169c..2734f8b52b207d6014b1ea46166e0db332978668 100644 --- a/briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/testdata/Conversations.kt +++ b/briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/testdata/conversation/Conversations.kt @@ -16,7 +16,7 @@ * along with this program. If not, see <https://www.gnu.org/licenses/>. */ -package org.briarproject.briar.desktop.testdata +package org.briarproject.briar.desktop.testdata.conversation import java.time.LocalDateTime diff --git a/briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/testdata/ConversationsData.kt b/briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/testdata/conversation/ConversationsData.kt similarity index 98% rename from briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/testdata/ConversationsData.kt rename to briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/testdata/conversation/ConversationsData.kt index 76ac296831ecf9377d9f145a561f2debfc6567b4..b3d4da40ee14a77e5963eb23aa5f7462c85a1a90 100644 --- a/briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/testdata/ConversationsData.kt +++ b/briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/testdata/conversation/ConversationsData.kt @@ -15,8 +15,9 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <https://www.gnu.org/licenses/>. */ +@file:Suppress("nls") -package org.briarproject.briar.desktop.testdata +package org.briarproject.briar.desktop.testdata.conversation import java.time.LocalDateTime.of as dt diff --git a/briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/testdata/ConversationsDsl.kt b/briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/testdata/conversation/ConversationsDsl.kt similarity index 91% rename from briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/testdata/ConversationsDsl.kt rename to briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/testdata/conversation/ConversationsDsl.kt index cf44f9f9da8a11e25a45cc44c9dcf7c1d50046ff..e27bb923cfc21eca18e1252aacd1832b4eeb3d19 100644 --- a/briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/testdata/ConversationsDsl.kt +++ b/briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/testdata/conversation/ConversationsDsl.kt @@ -16,10 +16,10 @@ * along with this program. If not, see <https://www.gnu.org/licenses/>. */ -package org.briarproject.briar.desktop.testdata +package org.briarproject.briar.desktop.testdata.conversation -import org.briarproject.briar.desktop.testdata.Direction.INCOMING -import org.briarproject.briar.desktop.testdata.Direction.OUTGOING +import org.briarproject.briar.desktop.testdata.conversation.Direction.INCOMING +import org.briarproject.briar.desktop.testdata.conversation.Direction.OUTGOING import java.time.LocalDateTime import java.time.format.DateTimeFormatter diff --git a/briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/testdata/TestListConversationData.kt b/briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/testdata/forum/Forums.kt similarity index 57% rename from briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/testdata/TestListConversationData.kt rename to briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/testdata/forum/Forums.kt index 89cf0ab89af3b0468d9461dd89175db9d12e467f..05909ed261086eef2d026f78eb6018e4dbe8e892 100644 --- a/briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/testdata/TestListConversationData.kt +++ b/briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/testdata/forum/Forums.kt @@ -16,13 +16,32 @@ * along with this program. If not, see <https://www.gnu.org/licenses/>. */ -package org.briarproject.briar.desktop.testdata +package org.briarproject.briar.desktop.testdata.forum -fun main(args: Array<String>) { - for (conversation in conversations.persons) { - println("conversation with: ${conversation.name}") - for (message in conversation.messages) { - println(" ${message.direction} ${message.text} ${message.read} ${message.date}") - } - } +import java.time.LocalDateTime + +data class Forums( + val forums: List<Forum> +) + +data class Forum( + val name: String, + var members: List<PostAuthor>, + var posts: List<Post>, +) + +data class Post( + val author: PostAuthor, + val text: String, + val date: LocalDateTime, + val replies: List<Post>, +) + +sealed interface PostAuthor { + object Me : PostAuthor + + data class RemoteAuthor( + val name: String, + val sharedWith: Boolean, // todo: not supported yet + ) : PostAuthor } diff --git a/briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/testdata/forum/ForumsData.kt b/briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/testdata/forum/ForumsData.kt new file mode 100644 index 0000000000000000000000000000000000000000..8db914762cfe76d1d976c050a1dcd29313f10166 --- /dev/null +++ b/briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/testdata/forum/ForumsData.kt @@ -0,0 +1,126 @@ +/* + * Briar Desktop + * Copyright (C) 2021-2022 The Briar Project + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ +@file:Suppress("nls") + +package org.briarproject.briar.desktop.testdata.forum + +import java.time.LocalDateTime + +val forums = forums { + forum { + name = "Briar Friends" + + val me = myself() + val anna = member("Anna", sharedForum = true) + val paul = member("Paul") + val claudia = member("Claudia", sharedForum = true) + + post { + author = anna + text = "Hi everybody!" + + post { + author = paul + text = "Hey Anna! It's me, Paul \uD83D\uDC4Bï¸" + + post { + author = anna + text = "Hi Paul! Nice to have you around!" + } + + post { + author = paul + text = "Yes indeed. Thanks for sharing the forum with me! \uD83D\uDC99\uD83E\uDD17ï¸ï¸" + } + } + + post { + author = me + text = "Hi Anna! Where can I see who else is in here?" + + post { + author = anna + text = "Right now it's only Paul, you and me. " + + "But it's actually not possible to have a list of all members of a forum, " + + "since every person in the forum could share it with any of their contacts." + + post { + author = me + text = "Oh, that's a bit unexpected!ï¸ï¸" + } + + post { + author = claudia + text = "That's actually how Paul slipped me in here. Hello everyone!ï¸ï¸" + + post { + author = paul + text = "ï¸ï¸\uD83D\uDE08ï¸" + } + } + } + } + } + + post { + author = anna + text = "What do you think about Briar?" + } + } + + forum { + name = "Let's try forums" + + val me = myself() + val brian = member("Brian", sharedForum = true) + val claudia = member("Claudia", sharedForum = true) + val claudia2 = member("Claudia") + + post { + author = brian + text = "I've just started and shared this forum using Briar Desktop, " + + "did everything work as expected?" + date = LocalDateTime.of(2022, 11, 28, 16, 12, 38) + + post { + author = me + text = "Wow nice, yes, everything seems to work!" + + post { + author = brian + text = "Perfect, that's amazing!" + } + } + + post { + author = claudia + text = "Hey people! That's so exciting that forums work on Briar Desktop now, too!" + + post { + author = claudia2 + text = "And it is fully compatible with Briar Android as well! I'm writing this on my phone just now." + + post { + author = me + text = "Oh hi, can you introduce me to your Briar account on the phone, please?" + } + } + } + } + } +} diff --git a/briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/testdata/forum/ForumsDsl.kt b/briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/testdata/forum/ForumsDsl.kt new file mode 100644 index 0000000000000000000000000000000000000000..44d9a52a7bfaaf519ec9313d95eb6e868d19c867 --- /dev/null +++ b/briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/testdata/forum/ForumsDsl.kt @@ -0,0 +1,140 @@ +/* + * Briar Desktop + * Copyright (C) 2021-2022 The Briar Project + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +package org.briarproject.briar.desktop.testdata.forum + +import java.time.LocalDateTime +import java.time.format.DateTimeFormatter +import kotlin.random.Random + +@DslMarker +annotation class PostsDsl + +/** + * Define a list of forums. + */ +fun forums(block: ForumsBuilder.() -> Unit) = ForumsBuilder().apply(block).build() + +@PostsDsl +class ForumsBuilder { + + private val forums = mutableListOf<Forum>() + + /** + * Add a new forum to the forum list. + */ + fun forum(block: ForumBuilder.() -> Unit) { + forums.add(ForumBuilder().apply(block).build()) + } + + fun build() = Forums(forums) +} + +@PostsDsl +class ForumBuilder : PostHierarchyBuilder() { + + /** + * The name of the forum. + * Needs to be explicitly set. + */ + lateinit var name: String + + private var members = mutableListOf<PostAuthor>(PostAuthor.Me) + override var lastReplySent: LocalDateTime = LocalDateTime.now() + + /** + * Create and return a new member for this forum. + * You can use the return value as the `author` of a [post]. + */ + fun member(name: String, sharedForum: Boolean = false) = + PostAuthor.RemoteAuthor(name, sharedForum).also { members.add(it) } + + /** + * Reference to the local author. + * You can use this as the `author` of a [post]. + */ + fun myself() = PostAuthor.Me + + fun build(): Forum { + check(this::name.isInitialized) { "A forum needs a name to be valid." } // NON-NLS + return Forum(name, members, posts) + } +} + +@PostsDsl +class PostBuilder(parentPostSent: LocalDateTime) : PostHierarchyBuilder() { + + /** + * The author of the post. + * You have to create authors using `member` in a forum. + * If not set, defaults to the local author. + */ + var author: PostAuthor = PostAuthor.Me + + /** + * The text of the post. + * Needs to be explicitly set. + */ + lateinit var text: String + + private var formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss") + private var _date = parentPostSent.addRandomDelay() + + /** + * The date of the post. + * Can be set to a [String] matching the format `yyyy-MM-dd HH:mm:ss` + * or to a [LocalDateTime] object. + * + * If not set, defaults to [LocalDateTime.now] for the first post in a forum, + * and to a random time between zero and five minutes + * after the last post in the corresponding thread for all subsequent ones. + */ + var date: Any = "" + set(value) { + if (value is String) { + _date = LocalDateTime.parse(value, formatter) + } else if (value is LocalDateTime) { + _date = value + } + lastReplySent = _date + } + + override var lastReplySent: LocalDateTime = _date + + fun build(): Post { + check(this::text.isInitialized) { "A forum post needs to contain a text to be valid." } // NON-NLS + return Post(author, text, _date, posts) + } +} + +@PostsDsl +abstract class PostHierarchyBuilder { + protected val posts = mutableListOf<Post>() + protected abstract var lastReplySent: LocalDateTime + + /** + * Add a new post to the forum or a new reply to the enclosing post. + */ + fun post(block: PostBuilder.() -> Unit) { + val post = PostBuilder(lastReplySent).apply(block).build() + posts.add(post) + lastReplySent = post.date + } +} + +private fun LocalDateTime.addRandomDelay() = plusSeconds(Random.nextLong(5 * 60))