retrieve blocklist on bind
This commit is contained in:
parent
6b232f7a5a
commit
20962554a4
|
@ -2,7 +2,7 @@
|
||||||
"formatVersion": 1,
|
"formatVersion": 1,
|
||||||
"database": {
|
"database": {
|
||||||
"version": 1,
|
"version": 1,
|
||||||
"identityHash": "d16845c3eb73e5fdbc9902903b74428a",
|
"identityHash": "aa5e73a1cf9ba959e118f66b89b9d227",
|
||||||
"entities": [
|
"entities": [
|
||||||
{
|
{
|
||||||
"tableName": "account",
|
"tableName": "account",
|
||||||
|
@ -1066,7 +1066,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"tableName": "roster",
|
"tableName": "roster",
|
||||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `accountId` INTEGER NOT NULL, `address` TEXT NOT NULL, `subscription` TEXT, `ask` INTEGER NOT NULL, `name` TEXT, FOREIGN KEY(`accountId`) REFERENCES `account`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `accountId` INTEGER NOT NULL, `address` TEXT NOT NULL, `subscription` TEXT, `isPendingOut` INTEGER NOT NULL, `name` TEXT, FOREIGN KEY(`accountId`) REFERENCES `account`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"fieldPath": "id",
|
"fieldPath": "id",
|
||||||
|
@ -1093,8 +1093,8 @@
|
||||||
"notNull": false
|
"notNull": false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldPath": "ask",
|
"fieldPath": "isPendingOut",
|
||||||
"columnName": "ask",
|
"columnName": "isPendingOut",
|
||||||
"affinity": "INTEGER",
|
"affinity": "INTEGER",
|
||||||
"notNull": true
|
"notNull": true
|
||||||
},
|
},
|
||||||
|
@ -1195,7 +1195,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, 'd16845c3eb73e5fdbc9902903b74428a')"
|
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'aa5e73a1cf9ba959e118f66b89b9d227')"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -67,6 +67,10 @@ public class Element {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public <E extends Extension> boolean hasExtension(final Class<E> clazz) {
|
||||||
|
return Iterables.any(this.children, clazz::isInstance);
|
||||||
|
}
|
||||||
|
|
||||||
public <E extends Extension> E getExtension(final Class<E> clazz) {
|
public <E extends Extension> E getExtension(final Class<E> clazz) {
|
||||||
final var extension = Iterables.find(this.children, clazz::isInstance);
|
final var extension = Iterables.find(this.children, clazz::isInstance);
|
||||||
if (extension == null) {
|
if (extension == null) {
|
||||||
|
|
|
@ -6,6 +6,7 @@ import androidx.room.Room;
|
||||||
import androidx.room.RoomDatabase;
|
import androidx.room.RoomDatabase;
|
||||||
import androidx.room.TypeConverters;
|
import androidx.room.TypeConverters;
|
||||||
import im.conversations.android.database.dao.AccountDao;
|
import im.conversations.android.database.dao.AccountDao;
|
||||||
|
import im.conversations.android.database.dao.BlockingDao;
|
||||||
import im.conversations.android.database.dao.MessageDao;
|
import im.conversations.android.database.dao.MessageDao;
|
||||||
import im.conversations.android.database.dao.PresenceDao;
|
import im.conversations.android.database.dao.PresenceDao;
|
||||||
import im.conversations.android.database.dao.RosterDao;
|
import im.conversations.android.database.dao.RosterDao;
|
||||||
|
@ -74,4 +75,6 @@ public abstract class ConversationsDatabase extends RoomDatabase {
|
||||||
public abstract MessageDao messageDao();
|
public abstract MessageDao messageDao();
|
||||||
|
|
||||||
public abstract RosterDao rosterDao();
|
public abstract RosterDao rosterDao();
|
||||||
|
|
||||||
|
public abstract BlockingDao blockingDao();
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
package im.conversations.android.database.dao;
|
||||||
|
|
||||||
|
import androidx.room.Dao;
|
||||||
|
import androidx.room.Insert;
|
||||||
|
import androidx.room.Query;
|
||||||
|
import androidx.room.Transaction;
|
||||||
|
import com.google.common.collect.Collections2;
|
||||||
|
import im.conversations.android.database.entity.BlockedItemEntity;
|
||||||
|
import im.conversations.android.database.model.Account;
|
||||||
|
import im.conversations.android.xmpp.model.blocking.Item;
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
@Dao
|
||||||
|
public abstract class BlockingDao {
|
||||||
|
|
||||||
|
@Insert
|
||||||
|
abstract void insert(Collection<BlockedItemEntity> entities);
|
||||||
|
|
||||||
|
@Query("DELETE FROM blocked WHERE accountId=:account")
|
||||||
|
abstract void clear(final long account);
|
||||||
|
|
||||||
|
@Transaction
|
||||||
|
public void setBlocklist(final Account account, final Collection<Item> blockedItems) {
|
||||||
|
final var entities =
|
||||||
|
Collections2.transform(blockedItems, i -> BlockedItemEntity.of(account.id, i));
|
||||||
|
clear(account.id);
|
||||||
|
insert(entities);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,32 +1,56 @@
|
||||||
package im.conversations.android.database.dao;
|
package im.conversations.android.database.dao;
|
||||||
|
|
||||||
|
import static androidx.room.OnConflictStrategy.REPLACE;
|
||||||
|
|
||||||
import androidx.room.Dao;
|
import androidx.room.Dao;
|
||||||
import androidx.room.Insert;
|
import androidx.room.Insert;
|
||||||
import androidx.room.Query;
|
import androidx.room.Query;
|
||||||
import androidx.room.Transaction;
|
import androidx.room.Transaction;
|
||||||
|
import eu.siacs.conversations.xmpp.Jid;
|
||||||
import im.conversations.android.database.entity.RosterItemEntity;
|
import im.conversations.android.database.entity.RosterItemEntity;
|
||||||
import im.conversations.android.database.model.Account;
|
import im.conversations.android.database.model.Account;
|
||||||
|
import im.conversations.android.xmpp.model.roster.Item;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
@Dao
|
@Dao
|
||||||
public abstract class RosterDao {
|
public abstract class RosterDao {
|
||||||
|
|
||||||
@Insert
|
@Insert(onConflict = REPLACE)
|
||||||
protected abstract void insert(Collection<RosterItemEntity> rosterItems);
|
protected abstract long insert(RosterItemEntity rosterItem);
|
||||||
|
|
||||||
@Query("DELETE FROM roster WHERE accountId=:account")
|
@Query("DELETE FROM roster WHERE accountId=:account")
|
||||||
protected abstract void clear(final long account);
|
protected abstract void clear(final long account);
|
||||||
|
|
||||||
|
@Query("DELETE FROM roster WHERE accountId=:account AND address=:address")
|
||||||
|
protected abstract void delete(final long account, final Jid address);
|
||||||
|
|
||||||
@Query("UPDATE account SET rosterVersion=:version WHERE id=:account")
|
@Query("UPDATE account SET rosterVersion=:version WHERE id=:account")
|
||||||
protected abstract void setRosterVersion(final long account, final String version);
|
protected abstract void setRosterVersion(final long account, final String version);
|
||||||
|
|
||||||
@Transaction
|
@Transaction
|
||||||
public void setRoster(
|
public void set(
|
||||||
final Account account,
|
final Account account, final String version, final Collection<Item> rosterItems) {
|
||||||
final String version,
|
|
||||||
final Collection<RosterItemEntity> rosterItems) {
|
|
||||||
clear(account.id);
|
clear(account.id);
|
||||||
insert(rosterItems);
|
for (final Item item : rosterItems) {
|
||||||
|
final long id = insert(RosterItemEntity.of(account.id, item));
|
||||||
|
// TODO insert groups
|
||||||
|
}
|
||||||
|
setRosterVersion(account.id, version);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void update(
|
||||||
|
final Account account, final String version, final Collection<Item> updates) {
|
||||||
|
for (final Item item : updates) {
|
||||||
|
final Item.Subscription subscription = item.getSubscription();
|
||||||
|
if (subscription == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (subscription == Item.Subscription.REMOVE) {
|
||||||
|
delete(account.id, item.getJid());
|
||||||
|
}
|
||||||
|
final RosterItemEntity entity = RosterItemEntity.of(account.id, item);
|
||||||
|
final long id = insert(entity);
|
||||||
|
}
|
||||||
setRosterVersion(account.id, version);
|
setRosterVersion(account.id, version);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,8 @@ import androidx.room.Entity;
|
||||||
import androidx.room.ForeignKey;
|
import androidx.room.ForeignKey;
|
||||||
import androidx.room.Index;
|
import androidx.room.Index;
|
||||||
import androidx.room.PrimaryKey;
|
import androidx.room.PrimaryKey;
|
||||||
|
import eu.siacs.conversations.xmpp.Jid;
|
||||||
|
import im.conversations.android.xmpp.model.blocking.Item;
|
||||||
|
|
||||||
@Entity(
|
@Entity(
|
||||||
tableName = "blocked",
|
tableName = "blocked",
|
||||||
|
@ -26,5 +28,12 @@ public class BlockedItemEntity {
|
||||||
|
|
||||||
@NonNull public Long accountId;
|
@NonNull public Long accountId;
|
||||||
|
|
||||||
@NonNull public String address;
|
@NonNull public Jid address;
|
||||||
|
|
||||||
|
public static BlockedItemEntity of(final long accountId, final Item item) {
|
||||||
|
final var entity = new BlockedItemEntity();
|
||||||
|
entity.accountId = accountId;
|
||||||
|
entity.address = item.getJid();
|
||||||
|
return entity;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,10 +5,8 @@ import androidx.room.Entity;
|
||||||
import androidx.room.ForeignKey;
|
import androidx.room.ForeignKey;
|
||||||
import androidx.room.Index;
|
import androidx.room.Index;
|
||||||
import androidx.room.PrimaryKey;
|
import androidx.room.PrimaryKey;
|
||||||
import com.google.common.collect.Collections2;
|
|
||||||
import eu.siacs.conversations.xmpp.Jid;
|
import eu.siacs.conversations.xmpp.Jid;
|
||||||
import im.conversations.android.xmpp.model.roster.Item;
|
import im.conversations.android.xmpp.model.roster.Item;
|
||||||
import java.util.Collection;
|
|
||||||
|
|
||||||
@Entity(
|
@Entity(
|
||||||
tableName = "roster",
|
tableName = "roster",
|
||||||
|
@ -47,9 +45,4 @@ public class RosterItemEntity {
|
||||||
entity.name = item.getItemName();
|
entity.name = item.getItemName();
|
||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Collection<RosterItemEntity> of(
|
|
||||||
final long accountId, final Collection<Item> items) {
|
|
||||||
return Collections2.transform(items, i -> of(accountId, i));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,8 +7,6 @@ import eu.siacs.conversations.xml.Element;
|
||||||
import im.conversations.android.annotation.XmlElement;
|
import im.conversations.android.annotation.XmlElement;
|
||||||
import im.conversations.android.annotation.XmlPackage;
|
import im.conversations.android.annotation.XmlPackage;
|
||||||
import im.conversations.android.xmpp.model.Extension;
|
import im.conversations.android.xmpp.model.Extension;
|
||||||
import im.conversations.android.xmpp.model.roster.Item;
|
|
||||||
import im.conversations.android.xmpp.model.roster.Query;
|
|
||||||
import java.lang.reflect.Constructor;
|
import java.lang.reflect.Constructor;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
@ -18,8 +16,15 @@ import java.util.Map;
|
||||||
|
|
||||||
public final class Extensions {
|
public final class Extensions {
|
||||||
|
|
||||||
|
// TODO these two maps can easily be generated by an annotation processor
|
||||||
private static final List<Class<? extends Extension>> ELEMENTS =
|
private static final List<Class<? extends Extension>> ELEMENTS =
|
||||||
Arrays.asList(Query.class, Item.class);
|
Arrays.asList(
|
||||||
|
im.conversations.android.xmpp.model.roster.Query.class,
|
||||||
|
im.conversations.android.xmpp.model.roster.Item.class,
|
||||||
|
im.conversations.android.xmpp.model.blocking.Item.class,
|
||||||
|
im.conversations.android.xmpp.model.blocking.Block.class,
|
||||||
|
im.conversations.android.xmpp.model.blocking.Blocklist.class,
|
||||||
|
im.conversations.android.xmpp.model.blocking.Unblock.class);
|
||||||
|
|
||||||
private static final Map<Id, Class<? extends Extension>> EXTENSION_CLASS_MAP;
|
private static final Map<Id, Class<? extends Extension>> EXTENSION_CLASS_MAP;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
package im.conversations.android.xmpp.model.blocking;
|
||||||
|
|
||||||
|
import eu.siacs.conversations.xml.Namespace;
|
||||||
|
import im.conversations.android.annotation.XmlElement;
|
||||||
|
import im.conversations.android.xmpp.model.Extension;
|
||||||
|
|
||||||
|
@XmlElement
|
||||||
|
public class Block extends Extension {
|
||||||
|
|
||||||
|
public Block() {
|
||||||
|
super("block", Namespace.BLOCKING);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
package im.conversations.android.xmpp.model.blocking;
|
||||||
|
|
||||||
|
import eu.siacs.conversations.xml.Namespace;
|
||||||
|
import im.conversations.android.annotation.XmlElement;
|
||||||
|
import im.conversations.android.xmpp.model.Extension;
|
||||||
|
|
||||||
|
@XmlElement
|
||||||
|
public class Blocklist extends Extension {
|
||||||
|
public Blocklist() {
|
||||||
|
super("blocklist", Namespace.BLOCKING);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
package im.conversations.android.xmpp.model.blocking;
|
||||||
|
|
||||||
|
import eu.siacs.conversations.xml.Namespace;
|
||||||
|
import eu.siacs.conversations.xmpp.Jid;
|
||||||
|
import im.conversations.android.annotation.XmlElement;
|
||||||
|
import im.conversations.android.xmpp.model.Extension;
|
||||||
|
|
||||||
|
@XmlElement
|
||||||
|
public class Item extends Extension {
|
||||||
|
|
||||||
|
public Item() {
|
||||||
|
super("item", Namespace.BLOCKING);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Jid getJid() {
|
||||||
|
return getAttributeAsJid("jid");
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
package im.conversations.android.xmpp.model.blocking;
|
||||||
|
|
||||||
|
import eu.siacs.conversations.xml.Namespace;
|
||||||
|
import im.conversations.android.annotation.XmlElement;
|
||||||
|
import im.conversations.android.xmpp.model.Extension;
|
||||||
|
|
||||||
|
@XmlElement
|
||||||
|
public class Unblock extends Extension {
|
||||||
|
|
||||||
|
public Unblock() {
|
||||||
|
super("unblock", Namespace.BLOCKING);
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,10 +7,11 @@ import com.google.common.collect.Collections2;
|
||||||
import eu.siacs.conversations.Config;
|
import eu.siacs.conversations.Config;
|
||||||
import eu.siacs.conversations.xmpp.Jid;
|
import eu.siacs.conversations.xmpp.Jid;
|
||||||
import eu.siacs.conversations.xmpp.stanzas.IqPacket;
|
import eu.siacs.conversations.xmpp.stanzas.IqPacket;
|
||||||
import im.conversations.android.database.entity.RosterItemEntity;
|
|
||||||
import im.conversations.android.xmpp.XmppConnection;
|
import im.conversations.android.xmpp.XmppConnection;
|
||||||
|
import im.conversations.android.xmpp.model.blocking.Blocklist;
|
||||||
import im.conversations.android.xmpp.model.roster.Item;
|
import im.conversations.android.xmpp.model.roster.Item;
|
||||||
import im.conversations.android.xmpp.model.roster.Query;
|
import im.conversations.android.xmpp.model.roster.Query;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
public class BindProcessor extends AbstractBaseProcessor implements Consumer<Jid> {
|
public class BindProcessor extends AbstractBaseProcessor implements Consumer<Jid> {
|
||||||
|
@ -36,6 +37,9 @@ public class BindProcessor extends AbstractBaseProcessor implements Consumer<Jid
|
||||||
|
|
||||||
fetchRoster();
|
fetchRoster();
|
||||||
|
|
||||||
|
// TODO check feature
|
||||||
|
fetchBlocklist();
|
||||||
|
|
||||||
// TODO fetch bookmarks
|
// TODO fetch bookmarks
|
||||||
|
|
||||||
// TODO send initial presence
|
// TODO send initial presence
|
||||||
|
@ -61,7 +65,7 @@ public class BindProcessor extends AbstractBaseProcessor implements Consumer<Jid
|
||||||
if (result.getType() != IqPacket.TYPE.RESULT) {
|
if (result.getType() != IqPacket.TYPE.RESULT) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final Query query = result.getExtension(Query.class);
|
final var query = result.getExtension(Query.class);
|
||||||
if (query == null) {
|
if (query == null) {
|
||||||
// No query in result means further modifications are sent via pushes
|
// No query in result means further modifications are sent via pushes
|
||||||
return;
|
return;
|
||||||
|
@ -75,8 +79,30 @@ public class BindProcessor extends AbstractBaseProcessor implements Consumer<Jid
|
||||||
final var validItems =
|
final var validItems =
|
||||||
Collections2.filter(
|
Collections2.filter(
|
||||||
items,
|
items,
|
||||||
i -> i != null && Item.RESULT_SUBSCRIPTIONS.contains(i.getSubscription()));
|
i ->
|
||||||
final var entities = RosterItemEntity.of(account.id, validItems);
|
Item.RESULT_SUBSCRIPTIONS.contains(i.getSubscription())
|
||||||
database.rosterDao().setRoster(account, version, entities);
|
&& Objects.nonNull(i.getJid()));
|
||||||
|
database.rosterDao().set(account, version, validItems);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void fetchBlocklist() {
|
||||||
|
final IqPacket iqPacket = new IqPacket(IqPacket.TYPE.GET);
|
||||||
|
iqPacket.addChild(new Blocklist());
|
||||||
|
connection.sendIqPacket(iqPacket, this::handleFetchBlocklistResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleFetchBlocklistResult(final IqPacket result) {
|
||||||
|
if (result.getType() != IqPacket.TYPE.RESULT) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final var blocklist = result.getExtension(Blocklist.class);
|
||||||
|
if (blocklist == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final var account = getAccount();
|
||||||
|
final var items =
|
||||||
|
blocklist.getExtensions(im.conversations.android.xmpp.model.blocking.Item.class);
|
||||||
|
final var filteredItems = Collections2.filter(items, i -> Objects.nonNull(i.getJid()));
|
||||||
|
getDatabase().blockingDao().setBlocklist(account, filteredItems);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,32 @@
|
||||||
package im.conversations.android.xmpp.processor;
|
package im.conversations.android.xmpp.processor;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import com.google.common.base.Preconditions;
|
||||||
import eu.siacs.conversations.xmpp.stanzas.IqPacket;
|
import eu.siacs.conversations.xmpp.stanzas.IqPacket;
|
||||||
import im.conversations.android.xmpp.XmppConnection;
|
import im.conversations.android.xmpp.XmppConnection;
|
||||||
|
import im.conversations.android.xmpp.model.roster.Query;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
public class IqProcessor implements Consumer<IqPacket> {
|
public class IqProcessor extends AbstractBaseProcessor implements Consumer<IqPacket> {
|
||||||
|
|
||||||
public IqProcessor(final Context context, final XmppConnection connection) {}
|
public IqProcessor(final Context context, final XmppConnection connection) {
|
||||||
|
super(context, connection);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void accept(final IqPacket packet) {}
|
public void accept(final IqPacket packet) {
|
||||||
|
final IqPacket.TYPE type = packet.getType();
|
||||||
|
Preconditions.checkArgument(
|
||||||
|
Arrays.asList(IqPacket.TYPE.GET, IqPacket.TYPE.SET).contains(type));
|
||||||
|
if (type == IqPacket.TYPE.SET
|
||||||
|
&& connection.fromAccount(packet)
|
||||||
|
&& packet.hasExtension(Query.class)) {
|
||||||
|
handleRosterPush(packet.getExtension(Query.class));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleRosterPush(final Query query) {
|
||||||
|
final String version = query.getVersion();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue