diff --git a/src/androidTest/java/im/conversations/android/xmpp/TransformationTest.java b/src/androidTest/java/im/conversations/android/xmpp/TransformationTest.java index 32a7c1671..e0d70aea8 100644 --- a/src/androidTest/java/im/conversations/android/xmpp/TransformationTest.java +++ b/src/androidTest/java/im/conversations/android/xmpp/TransformationTest.java @@ -9,8 +9,10 @@ import eu.siacs.conversations.xmpp.Jid; import im.conversations.android.IDs; import im.conversations.android.database.ConversationsDatabase; import im.conversations.android.database.entity.AccountEntity; +import im.conversations.android.database.model.Modification; import im.conversations.android.transformer.Transformation; import im.conversations.android.transformer.Transformer; +import im.conversations.android.xmpp.model.correction.Replace; import im.conversations.android.xmpp.model.jabber.Body; import im.conversations.android.xmpp.model.reactions.Reaction; import im.conversations.android.xmpp.model.reactions.Reactions; @@ -77,4 +79,73 @@ public class TransformationTest { Assert.assertEquals("Y", onlyReaction.reaction); Assert.assertEquals(REMOTE, onlyReaction.reactionBy); } + + @Test + public void correctionBeforeOriginal() { + + final var messageCorrection = new Message(); + messageCorrection.setId("2"); + messageCorrection.setTo(ACCOUNT); + messageCorrection.setFrom(REMOTE.withResource("junit")); + messageCorrection.addExtension(new Body()).setContent("Hi example!"); + messageCorrection.addExtension(new Replace()).setId("1"); + + this.transformer.transform( + Transformation.of(messageCorrection, Instant.now(), REMOTE, "stanza-a", null)); + + // the correction should not show up as a message + Assert.assertEquals(0, database.messageDao().getMessages(1L).size()); + + final var messageWithTypo = new Message(); + messageWithTypo.setId("1"); + messageWithTypo.setTo(ACCOUNT); + messageWithTypo.setFrom(REMOTE.withResource("junit")); + messageWithTypo.addExtension(new Body()).setContent("Hii example!"); + + this.transformer.transform( + Transformation.of(messageWithTypo, Instant.now(), REMOTE, "stanza-b", null)); + + final var messages = database.messageDao().getMessages(1L); + + Assert.assertEquals(1, messages.size()); + + final var message = Iterables.getOnlyElement(messages); + final var onlyContent = Iterables.getOnlyElement(message.contents); + Assert.assertEquals(Modification.EDIT, message.modification); + Assert.assertEquals("Hi example!", onlyContent.body); + } + + @Test + public void correctionAfterOriginal() { + + final var messageWithTypo = new Message(); + messageWithTypo.setId("1"); + messageWithTypo.setTo(ACCOUNT); + messageWithTypo.setFrom(REMOTE.withResource("junit")); + messageWithTypo.addExtension(new Body()).setContent("Hii example!"); + + this.transformer.transform( + Transformation.of(messageWithTypo, Instant.now(), REMOTE, "stanza-a", null)); + + Assert.assertEquals(1, database.messageDao().getMessages(1L).size()); + + final var messageCorrection = new Message(); + messageCorrection.setId("2"); + messageCorrection.setTo(ACCOUNT); + messageCorrection.setFrom(REMOTE.withResource("junit")); + messageCorrection.addExtension(new Body()).setContent("Hi example!"); + messageCorrection.addExtension(new Replace()).setId("1"); + + this.transformer.transform( + Transformation.of(messageCorrection, Instant.now(), REMOTE, "stanza-b", null)); + + final var messages = database.messageDao().getMessages(1L); + + Assert.assertEquals(1, messages.size()); + + final var message = Iterables.getOnlyElement(messages); + final var onlyContent = Iterables.getOnlyElement(message.contents); + Assert.assertEquals(Modification.EDIT, message.modification); + Assert.assertEquals("Hi example!", onlyContent.body); + } } diff --git a/src/main/java/im/conversations/android/database/dao/MessageDao.java b/src/main/java/im/conversations/android/database/dao/MessageDao.java index a769c043a..e414f642b 100644 --- a/src/main/java/im/conversations/android/database/dao/MessageDao.java +++ b/src/main/java/im/conversations/android/database/dao/MessageDao.java @@ -82,23 +82,27 @@ public abstract class MessageDao { "Found stub for stanzaId '{}' and messageId '{}'", transformation.stanzaId, transformation.messageId); - final long messageVersionId = + final long originalVersionId = insert( MessageVersionEntity.of( messageIdentifier.id, - Modification.ORIGINAl, + Modification.ORIGINAL, transformation)); final MessageEntity updatedEntity = MessageEntity.of(chatIdentifier.id, transformation); updatedEntity.id = messageIdentifier.id; - updatedEntity.latestVersion = messageVersionId; + updatedEntity.latestVersion = getLatestVersion(messageIdentifier.id); + LOGGER.info( + "Created original version {} and updated latest version to {}", + originalVersionId, + updatedEntity.latestVersion); update(updatedEntity); return new MessageIdentifier( updatedEntity.id, transformation.stanzaId, transformation.messageId, transformation.fromBare(), - messageVersionId); + originalVersionId); } else { throw new IllegalStateException( String.format( @@ -114,7 +118,7 @@ public abstract class MessageDao { final long messageVersionId = insert( MessageVersionEntity.of( - messageEntityId, Modification.ORIGINAl, transformation)); + messageEntityId, Modification.ORIGINAL, transformation)); setLatestMessageId(messageEntityId, messageVersionId); return new MessageIdentifier( messageEntityId, @@ -206,7 +210,7 @@ public abstract class MessageDao { @Query( "SELECT id FROM message_version WHERE messageEntityId=:messageEntityId ORDER BY (CASE" - + " modification WHEN 'ORIGINAL' THEN 0 ELSE 1 END),receivedAt DESC LIMIT 1") + + " modification WHEN 'ORIGINAL' THEN 1 ELSE 0 END),receivedAt DESC LIMIT 1") abstract Long getLatestVersion(long messageEntityId); @Query( diff --git a/src/main/java/im/conversations/android/database/model/Modification.java b/src/main/java/im/conversations/android/database/model/Modification.java index c2c3bf7a0..e5bc2709f 100644 --- a/src/main/java/im/conversations/android/database/model/Modification.java +++ b/src/main/java/im/conversations/android/database/model/Modification.java @@ -1,7 +1,7 @@ package im.conversations.android.database.model; public enum Modification { - ORIGINAl, + ORIGINAL, EDIT, // XEP-0308: Last Message Correction RETRACTION, // XEP-0424: Message Retraction MODERATION // XEP-0425: Message Moderation diff --git a/src/main/java/im/conversations/android/xmpp/model/correction/Replace.java b/src/main/java/im/conversations/android/xmpp/model/correction/Replace.java index 9febd8779..508603cda 100644 --- a/src/main/java/im/conversations/android/xmpp/model/correction/Replace.java +++ b/src/main/java/im/conversations/android/xmpp/model/correction/Replace.java @@ -1,5 +1,6 @@ package im.conversations.android.xmpp.model.correction; +import androidx.annotation.NonNull; import com.google.common.base.Strings; import eu.siacs.conversations.xml.Namespace; import im.conversations.android.annotation.XmlElement; @@ -15,4 +16,8 @@ public class Replace extends Extension { public String getId() { return Strings.emptyToNull(this.getAttribute("id")); } + + public void setId(@NonNull final String id) { + this.setAttribute("id", id); + } }