remove fallback body when rendering

This commit is contained in:
Daniel Gultsch 2023-03-30 18:49:04 +02:00
parent 1b3c7b6a42
commit 4f654044b4
No known key found for this signature in database
GPG key ID: F43D18AD2A0982C2
11 changed files with 126 additions and 12 deletions

View file

@ -2,7 +2,7 @@
"formatVersion": 1, "formatVersion": 1,
"database": { "database": {
"version": 1, "version": 1,
"identityHash": "cc15c6de66482506c7f895ccaff971b4", "identityHash": "a4cee026f132d06fdad6ff6db418d041",
"entities": [ "entities": [
{ {
"tableName": "account", "tableName": "account",
@ -1665,7 +1665,7 @@
}, },
{ {
"tableName": "message", "tableName": "message",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `chatId` INTEGER NOT NULL, `receivedAt` INTEGER, `sentAt` INTEGER, `outgoing` INTEGER NOT NULL, `toBare` TEXT, `toResource` TEXT, `fromBare` TEXT, `fromResource` TEXT, `occupantId` TEXT, `senderIdentity` TEXT, `messageId` TEXT, `stanzaId` TEXT, `stanzaIdVerified` INTEGER NOT NULL, `latestVersion` INTEGER, `acknowledged` INTEGER NOT NULL, `inReplyToMessageId` TEXT, `inReplyToStanzaId` TEXT, `inReplyToMessageEntityId` INTEGER, FOREIGN KEY(`chatId`) REFERENCES `chat`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`latestVersion`) REFERENCES `message_version`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`inReplyToMessageEntityId`) REFERENCES `message`(`id`) ON UPDATE NO ACTION ON DELETE SET NULL )", "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `chatId` INTEGER NOT NULL, `receivedAt` INTEGER, `sentAt` INTEGER, `outgoing` INTEGER NOT NULL, `toBare` TEXT, `toResource` TEXT, `fromBare` TEXT, `fromResource` TEXT, `occupantId` TEXT, `senderIdentity` TEXT, `messageId` TEXT, `stanzaId` TEXT, `stanzaIdVerified` INTEGER NOT NULL, `latestVersion` INTEGER, `acknowledged` INTEGER NOT NULL, `inReplyToMessageId` TEXT, `inReplyToStanzaId` TEXT, `inReplyToMessageEntityId` INTEGER, `inReplyToFallbackStart` INTEGER NOT NULL, `inReplyToFallbackEnd` INTEGER NOT NULL, FOREIGN KEY(`chatId`) REFERENCES `chat`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`latestVersion`) REFERENCES `message_version`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`inReplyToMessageEntityId`) REFERENCES `message`(`id`) ON UPDATE NO ACTION ON DELETE SET NULL )",
"fields": [ "fields": [
{ {
"fieldPath": "id", "fieldPath": "id",
@ -1780,6 +1780,18 @@
"columnName": "inReplyToMessageEntityId", "columnName": "inReplyToMessageEntityId",
"affinity": "INTEGER", "affinity": "INTEGER",
"notNull": false "notNull": false
},
{
"fieldPath": "inReplyToFallbackStart",
"columnName": "inReplyToFallbackStart",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "inReplyToFallbackEnd",
"columnName": "inReplyToFallbackEnd",
"affinity": "INTEGER",
"notNull": true
} }
], ],
"primaryKey": { "primaryKey": {
@ -2681,7 +2693,7 @@
"views": [], "views": [],
"setupQueries": [ "setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'cc15c6de66482506c7f895ccaff971b4')" "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'a4cee026f132d06fdad6ff6db418d041')"
] ]
} }
} }

View file

@ -26,6 +26,7 @@ import im.conversations.android.database.model.MessageWithContentReactions;
import im.conversations.android.database.model.Modification; import im.conversations.android.database.model.Modification;
import im.conversations.android.transformer.MessageContentWrapper; import im.conversations.android.transformer.MessageContentWrapper;
import im.conversations.android.transformer.MessageTransformation; import im.conversations.android.transformer.MessageTransformation;
import im.conversations.android.xmpp.model.fallback.Body;
import im.conversations.android.xmpp.model.reactions.Reactions; import im.conversations.android.xmpp.model.reactions.Reactions;
import im.conversations.android.xmpp.model.stanza.Message; import im.conversations.android.xmpp.model.stanza.Message;
import java.util.Collection; import java.util.Collection;
@ -442,7 +443,7 @@ public abstract class MessageDao {
+ " c.type IN ('MUC','MUC_PM') THEN (SELECT resource FROM presence WHERE" + " c.type IN ('MUC','MUC_PM') THEN (SELECT resource FROM presence WHERE"
+ " accountId=c.accountId AND address=c.address AND occupantId=m.occupantId LIMIT" + " accountId=c.accountId AND address=c.address AND occupantId=m.occupantId LIMIT"
+ " 1) ELSE NULL END) as occupantResource,modification,latestVersion as" + " 1) ELSE NULL END) as occupantResource,modification,latestVersion as"
+ " version,inReplyToMessageEntityId,encryption,message_version.identityKey,trust,(CASE" + " version,inReplyToMessageEntityId,inReplyToFallbackStart,inReplyToFallbackEnd,encryption,message_version.identityKey,trust,(CASE"
+ " WHEN c.type IN ('MUC','MUC_PM') THEN (SELECT count(distinct(df.feature)) == 2" + " WHEN c.type IN ('MUC','MUC_PM') THEN (SELECT count(distinct(df.feature)) == 2"
+ " FROM disco_item di JOIN disco_feature df ON di.discoId = df.discoId WHERE" + " FROM disco_item di JOIN disco_feature df ON di.discoId = df.discoId WHERE"
+ " di.address=c.address AND df.feature IN('muc_membersonly','muc_nonanonymous'))" + " di.address=c.address AND df.feature IN('muc_membersonly','muc_nonanonymous'))"
@ -472,7 +473,7 @@ public abstract class MessageDao {
+ " c.type IN ('MUC','MUC_PM') THEN (SELECT resource FROM presence WHERE" + " c.type IN ('MUC','MUC_PM') THEN (SELECT resource FROM presence WHERE"
+ " accountId=c.accountId AND address=c.address AND occupantId=m.occupantId LIMIT" + " accountId=c.accountId AND address=c.address AND occupantId=m.occupantId LIMIT"
+ " 1) ELSE NULL END) as occupantResource,modification,latestVersion as" + " 1) ELSE NULL END) as occupantResource,modification,latestVersion as"
+ " version,inReplyToMessageEntityId,encryption,message_version.identityKey,trust,(CASE" + " version,inReplyToMessageEntityId,inReplyToFallbackStart,inReplyToFallbackEnd,encryption,message_version.identityKey,trust,(CASE"
+ " WHEN c.type IN ('MUC','MUC_PM') THEN (SELECT count(distinct(df.feature)) == 2" + " WHEN c.type IN ('MUC','MUC_PM') THEN (SELECT count(distinct(df.feature)) == 2"
+ " FROM disco_item di JOIN disco_feature df ON di.discoId = df.discoId WHERE" + " FROM disco_item di JOIN disco_feature df ON di.discoId = df.discoId WHERE"
+ " di.address=c.address AND df.feature IN('muc_membersonly','muc_nonanonymous'))" + " di.address=c.address AND df.feature IN('muc_membersonly','muc_nonanonymous'))"
@ -493,11 +494,12 @@ public abstract class MessageDao {
public abstract ListenableFuture<Integer> getPosition(final long chatId, final long messageId); public abstract ListenableFuture<Integer> getPosition(final long chatId, final long messageId);
public void setInReplyTo( public void setInReplyTo(
ChatIdentifier chat, final ChatIdentifier chat,
MessageIdentifier messageIdentifier, final MessageIdentifier messageIdentifier,
Message.Type messageType, final Message.Type messageType,
final Jid to, final Jid to,
String inReplyTo) { final String inReplyTo,
final Body fallbackBody) {
if (messageType == Message.Type.GROUPCHAT) { if (messageType == Message.Type.GROUPCHAT) {
final Long messageEntityId = getMessageByStanzaId(chat.id, inReplyTo); final Long messageEntityId = getMessageByStanzaId(chat.id, inReplyTo);
setInReplyToStanzaId(messageIdentifier.id, inReplyTo, messageEntityId); setInReplyToStanzaId(messageIdentifier.id, inReplyTo, messageEntityId);
@ -505,6 +507,12 @@ public abstract class MessageDao {
final Long messageEntityId = getMessageByMessageId(chat.id, to.asBareJid(), inReplyTo); final Long messageEntityId = getMessageByMessageId(chat.id, to.asBareJid(), inReplyTo);
setInReplyToMessageId(messageIdentifier.id, inReplyTo, messageEntityId); setInReplyToMessageId(messageIdentifier.id, inReplyTo, messageEntityId);
} }
final int inReplyToFallbackStart = fallbackBody == null ? 0 : fallbackBody.getStart();
final int inReplyToFallbackEnd = fallbackBody == null ? 0 : fallbackBody.getEnd();
if (inReplyToFallbackStart != 0 || inReplyToFallbackEnd != 0) {
setInReplyToFallback(
messageIdentifier.id, inReplyToFallbackStart, inReplyToFallbackEnd);
}
} }
@Query( @Query(
@ -521,6 +529,13 @@ public abstract class MessageDao {
protected abstract void setInReplyToMessageId( protected abstract void setInReplyToMessageId(
final long id, String messageId, Long inReplyToMessageEntityId); final long id, String messageId, Long inReplyToMessageEntityId);
@Query(
"UPDATE message SET"
+ " inReplyToFallbackStart=:inReplyToFallbackStart,inReplyToFallbackEnd=:inReplyToFallbackEnd"
+ " WHERE id=:id")
protected abstract void setInReplyToFallback(
final long id, final int inReplyToFallbackStart, final int inReplyToFallbackEnd);
@Query( @Query(
"SELECT id FROM message WHERE chatId=:chatId AND fromBare=:fromBare AND" "SELECT id FROM message WHERE chatId=:chatId AND fromBare=:fromBare AND"
+ " messageId=:messageId") + " messageId=:messageId")

View file

@ -71,6 +71,9 @@ public class MessageEntity {
public String inReplyToStanzaId; public String inReplyToStanzaId;
@Nullable public Long inReplyToMessageEntityId; @Nullable public Long inReplyToMessageEntityId;
public int inReplyToFallbackStart;
public int inReplyToFallbackEnd;
public static MessageEntity of(final long chatId, final MessageTransformation transformation) { public static MessageEntity of(final long chatId, final MessageTransformation transformation) {
final var entity = new MessageEntity(); final var entity = new MessageEntity();
entity.chatId = chatId; entity.chatId = chatId;

View file

@ -57,6 +57,8 @@ public final class MessageWithContentReactions
public long version; public long version;
public boolean acknowledged; public boolean acknowledged;
public Long inReplyToMessageEntityId; public Long inReplyToMessageEntityId;
public int inReplyToFallbackStart;
public int inReplyToFallbackEnd;
public Encryption encryption; public Encryption encryption;
public IdentityKey identityKey; public IdentityKey identityKey;
public Trust trust; public Trust trust;
@ -95,8 +97,18 @@ public final class MessageWithContentReactions
} }
public String textContent() { public String textContent() {
final var content = Iterables.getFirst(this.contents, null); final var textContent =
return Strings.nullToEmpty(content == null ? null : content.body); Iterables.getFirst(
Iterables.filter(this.contents, c -> c.type == PartType.TEXT), null);
final var body = Strings.nullToEmpty(textContent == null ? null : textContent.body);
;
if (inReplyToMessageEntityId != null
&& inReplyToFallbackEnd > inReplyToFallbackStart
&& inReplyToFallbackEnd <= body.length()) {
return body.substring(0, inReplyToFallbackStart) + body.substring(inReplyToFallbackEnd);
} else {
return body;
}
} }
public boolean hasPreview() { public boolean hasPreview() {

View file

@ -11,6 +11,7 @@ import im.conversations.android.xmpp.model.Extension;
import im.conversations.android.xmpp.model.axolotl.Encrypted; import im.conversations.android.xmpp.model.axolotl.Encrypted;
import im.conversations.android.xmpp.model.correction.Replace; import im.conversations.android.xmpp.model.correction.Replace;
import im.conversations.android.xmpp.model.error.Error; import im.conversations.android.xmpp.model.error.Error;
import im.conversations.android.xmpp.model.fallback.Fallback;
import im.conversations.android.xmpp.model.jabber.Body; import im.conversations.android.xmpp.model.jabber.Body;
import im.conversations.android.xmpp.model.jabber.Thread; import im.conversations.android.xmpp.model.jabber.Thread;
import im.conversations.android.xmpp.model.markers.Displayed; import im.conversations.android.xmpp.model.markers.Displayed;
@ -42,6 +43,7 @@ public class MessageTransformation extends Transformation {
Replace.class, Replace.class,
Reactions.class, Reactions.class,
Reply.class, Reply.class,
Fallback.class,
Retract.class); Retract.class);
private final BareJid senderIdentity; private final BareJid senderIdentity;

View file

@ -3,6 +3,7 @@ package im.conversations.android.transformer;
import android.content.Context; import android.content.Context;
import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import com.google.common.collect.Iterables;
import im.conversations.android.axolotl.AxolotlService; import im.conversations.android.axolotl.AxolotlService;
import im.conversations.android.database.ConversationsDatabase; import im.conversations.android.database.ConversationsDatabase;
import im.conversations.android.database.model.Account; import im.conversations.android.database.model.Account;
@ -11,11 +12,13 @@ import im.conversations.android.database.model.MessageIdentifier;
import im.conversations.android.database.model.MessageState; import im.conversations.android.database.model.MessageState;
import im.conversations.android.database.model.Modification; import im.conversations.android.database.model.Modification;
import im.conversations.android.database.model.StanzaId; import im.conversations.android.database.model.StanzaId;
import im.conversations.android.xml.Namespace;
import im.conversations.android.xmpp.Range; import im.conversations.android.xmpp.Range;
import im.conversations.android.xmpp.manager.ArchiveManager; import im.conversations.android.xmpp.manager.ArchiveManager;
import im.conversations.android.xmpp.model.DeliveryReceipt; import im.conversations.android.xmpp.model.DeliveryReceipt;
import im.conversations.android.xmpp.model.axolotl.Encrypted; import im.conversations.android.xmpp.model.axolotl.Encrypted;
import im.conversations.android.xmpp.model.correction.Replace; import im.conversations.android.xmpp.model.correction.Replace;
import im.conversations.android.xmpp.model.fallback.Fallback;
import im.conversations.android.xmpp.model.markers.Displayed; import im.conversations.android.xmpp.model.markers.Displayed;
import im.conversations.android.xmpp.model.muc.user.MucUser; import im.conversations.android.xmpp.model.muc.user.MucUser;
import im.conversations.android.xmpp.model.reactions.Reactions; import im.conversations.android.xmpp.model.reactions.Reactions;
@ -205,9 +208,22 @@ public class Transformer {
if (Objects.nonNull(reply) if (Objects.nonNull(reply)
&& Objects.nonNull(reply.getId()) && Objects.nonNull(reply.getId())
&& Objects.nonNull(reply.getTo())) { && Objects.nonNull(reply.getTo())) {
final var fallback =
Iterables.tryFind(
transformation.getExtensions(Fallback.class),
f -> Namespace.REPLY.equals(f.getFor()))
.orNull();
final var fallbackBody = fallback == null ? null : fallback.getBody();
LOGGER.info("fallbacks {}", transformation.getExtensions(Fallback.class));
LOGGER.info("fallback body {}", fallbackBody);
database.messageDao() database.messageDao()
.setInReplyTo( .setInReplyTo(
chat, messageIdentifier, messageType, reply.getTo(), reply.getId()); chat,
messageIdentifier,
messageType,
reply.getTo(),
reply.getId(),
fallbackBody);
} }
return true; return true;
} }

View file

@ -34,6 +34,7 @@ public final class Namespace {
public static final String ENTITY_CAPABILITIES_2 = "urn:xmpp:caps"; public static final String ENTITY_CAPABILITIES_2 = "urn:xmpp:caps";
public static final String EXTERNAL_SERVICE_DISCOVERY = "urn:xmpp:extdisco:2"; public static final String EXTERNAL_SERVICE_DISCOVERY = "urn:xmpp:extdisco:2";
public static final String FAST = "urn:xmpp:fast:0"; public static final String FAST = "urn:xmpp:fast:0";
public static final String FALLBACK = "urn:xmpp:fallback:0";
public static final String FLEXIBLE_OFFLINE_MESSAGE_RETRIEVAL = public static final String FLEXIBLE_OFFLINE_MESSAGE_RETRIEVAL =
"http://jabber.org/protocol/offline"; "http://jabber.org/protocol/offline";
public static final String FORWARD = "urn:xmpp:forward:0"; public static final String FORWARD = "urn:xmpp:forward:0";

View file

@ -24,10 +24,12 @@ import im.conversations.android.xmpp.Range;
import im.conversations.android.xmpp.XmppConnection; import im.conversations.android.xmpp.XmppConnection;
import im.conversations.android.xmpp.model.Extension; import im.conversations.android.xmpp.model.Extension;
import im.conversations.android.xmpp.model.delay.Delay; import im.conversations.android.xmpp.model.delay.Delay;
import im.conversations.android.xmpp.model.fallback.Fallback;
import im.conversations.android.xmpp.model.mam.Fin; import im.conversations.android.xmpp.model.mam.Fin;
import im.conversations.android.xmpp.model.mam.Query; import im.conversations.android.xmpp.model.mam.Query;
import im.conversations.android.xmpp.model.mam.Result; import im.conversations.android.xmpp.model.mam.Result;
import im.conversations.android.xmpp.model.muc.user.MucUser; import im.conversations.android.xmpp.model.muc.user.MucUser;
import im.conversations.android.xmpp.model.reply.Reply;
import im.conversations.android.xmpp.model.rsm.Set; import im.conversations.android.xmpp.model.rsm.Set;
import im.conversations.android.xmpp.model.stanza.Iq; import im.conversations.android.xmpp.model.stanza.Iq;
import im.conversations.android.xmpp.model.stanza.Message; import im.conversations.android.xmpp.model.stanza.Message;
@ -94,6 +96,12 @@ public class ArchiveManager extends AbstractManager {
} }
} }
if (forwardedMessage.hasExtension(Reply.class)) {
LOGGER.info(
"message with reply hasFallback {}",
forwardedMessage.hasExtension(Fallback.class));
}
final var transformation = final var transformation =
this.transformationFactory.create( this.transformationFactory.create(
forwardedMessage, stanzaId, receivedAt, privilegedExtensionBuilder.build()); forwardedMessage, stanzaId, receivedAt, privilegedExtensionBuilder.build());

View file

@ -0,0 +1,20 @@
package im.conversations.android.xmpp.model.fallback;
import im.conversations.android.annotation.XmlElement;
import im.conversations.android.xmpp.model.Extension;
@XmlElement
public class Body extends Extension {
public Body() {
super(Body.class);
}
public int getStart() {
return this.getOptionalIntAttribute("start").or(0);
}
public int getEnd() {
return this.getOptionalIntAttribute("end").or(0);
}
}

View file

@ -0,0 +1,20 @@
package im.conversations.android.xmpp.model.fallback;
import im.conversations.android.annotation.XmlElement;
import im.conversations.android.xmpp.model.Extension;
@XmlElement
public class Fallback extends Extension {
public Fallback() {
super(Fallback.class);
}
public Body getBody() {
return this.getExtension(Body.class);
}
public String getFor() {
return this.getAttribute("for");
}
}

View file

@ -0,0 +1,5 @@
@XmlPackage(namespace = Namespace.FALLBACK)
package im.conversations.android.xmpp.model.fallback;
import im.conversations.android.annotation.XmlPackage;
import im.conversations.android.xml.Namespace;