Add --hide parameter to removeContact command

This commit is contained in:
AsamK 2023-11-11 11:35:23 +01:00
parent 9f4a2b3e26
commit 7b0744ec75
14 changed files with 96 additions and 35 deletions

View File

@ -193,6 +193,8 @@ public interface Manager extends Closeable {
SendMessageResults sendEndSessionMessage(Set<RecipientIdentifier.Single> recipients) throws IOException; SendMessageResults sendEndSessionMessage(Set<RecipientIdentifier.Single> recipients) throws IOException;
void hideRecipient(RecipientIdentifier.Single recipient);
void deleteRecipient(RecipientIdentifier.Single recipient); void deleteRecipient(RecipientIdentifier.Single recipient);
void deleteContact(RecipientIdentifier.Single recipient); void deleteContact(RecipientIdentifier.Single recipient);

View File

@ -9,7 +9,8 @@ public record Contact(
int messageExpirationTime, int messageExpirationTime,
boolean isBlocked, boolean isBlocked,
boolean isArchived, boolean isArchived,
boolean isProfileSharingEnabled boolean isProfileSharingEnabled,
boolean isHidden
) { ) {
private Contact(final Builder builder) { private Contact(final Builder builder) {
@ -17,9 +18,10 @@ public record Contact(
builder.familyName, builder.familyName,
builder.color, builder.color,
builder.messageExpirationTime, builder.messageExpirationTime,
builder.blocked, builder.isBlocked,
builder.archived, builder.isArchived,
builder.profileSharingEnabled); builder.isProfileSharingEnabled,
builder.isHidden);
} }
public static Builder newBuilder() { public static Builder newBuilder() {
@ -32,9 +34,10 @@ public record Contact(
builder.familyName = copy.familyName(); builder.familyName = copy.familyName();
builder.color = copy.color(); builder.color = copy.color();
builder.messageExpirationTime = copy.messageExpirationTime(); builder.messageExpirationTime = copy.messageExpirationTime();
builder.blocked = copy.isBlocked(); builder.isBlocked = copy.isBlocked();
builder.archived = copy.isArchived(); builder.isArchived = copy.isArchived();
builder.profileSharingEnabled = copy.isProfileSharingEnabled(); builder.isProfileSharingEnabled = copy.isProfileSharingEnabled();
builder.isHidden = copy.isHidden();
return builder; return builder;
} }
@ -59,13 +62,18 @@ public record Contact(
private String familyName; private String familyName;
private String color; private String color;
private int messageExpirationTime; private int messageExpirationTime;
private boolean blocked; private boolean isBlocked;
private boolean archived; private boolean isArchived;
private boolean profileSharingEnabled; private boolean isProfileSharingEnabled;
private boolean isHidden;
private Builder() { private Builder() {
} }
public static Builder newBuilder() {
return new Builder();
}
public Builder withGivenName(final String val) { public Builder withGivenName(final String val) {
givenName = val; givenName = val;
return this; return this;
@ -86,18 +94,23 @@ public record Contact(
return this; return this;
} }
public Builder withBlocked(final boolean val) { public Builder withIsBlocked(final boolean val) {
blocked = val; isBlocked = val;
return this; return this;
} }
public Builder withArchived(final boolean val) { public Builder withIsArchived(final boolean val) {
archived = val; isArchived = val;
return this; return this;
} }
public Builder withProfileSharingEnabled(final boolean val) { public Builder withIsProfileSharingEnabled(final boolean val) {
profileSharingEnabled = val; isProfileSharingEnabled = val;
return this;
}
public Builder withIsHidden(final boolean val) {
isHidden = val;
return this; return this;
} }

View File

@ -20,6 +20,7 @@ public class ContactHelper {
public void setContactName(final RecipientId recipientId, final String givenName, final String familyName) { public void setContactName(final RecipientId recipientId, final String givenName, final String familyName) {
var contact = account.getContactStore().getContact(recipientId); var contact = account.getContactStore().getContact(recipientId);
final var builder = contact == null ? Contact.newBuilder() : Contact.newBuilder(contact); final var builder = contact == null ? Contact.newBuilder() : Contact.newBuilder(contact);
builder.withIsHidden(false);
if (givenName != null) { if (givenName != null) {
builder.withGivenName(givenName); builder.withGivenName(givenName);
} }
@ -43,8 +44,14 @@ public class ContactHelper {
var contact = account.getContactStore().getContact(recipientId); var contact = account.getContactStore().getContact(recipientId);
final var builder = contact == null ? Contact.newBuilder() : Contact.newBuilder(contact); final var builder = contact == null ? Contact.newBuilder() : Contact.newBuilder(contact);
if (blocked) { if (blocked) {
builder.withProfileSharingEnabled(false); builder.withIsProfileSharingEnabled(false);
} }
account.getContactStore().storeContact(recipientId, builder.withBlocked(blocked).build()); account.getContactStore().storeContact(recipientId, builder.withIsBlocked(blocked).build());
}
public void setContactHidden(RecipientId recipientId, boolean hidden) {
var contact = account.getContactStore().getContact(recipientId);
final var builder = contact == null ? Contact.newBuilder() : Contact.newBuilder(contact);
account.getContactStore().storeContact(recipientId, builder.withIsHidden(hidden).build());
} }
} }

View File

@ -78,9 +78,9 @@ public class SendHelper {
Optional<Long> editTargetTimestamp Optional<Long> editTargetTimestamp
) { ) {
var contact = account.getContactStore().getContact(recipientId); var contact = account.getContactStore().getContact(recipientId);
if (contact == null || !contact.isProfileSharingEnabled()) { if (contact == null || !contact.isProfileSharingEnabled() || contact.isHidden()) {
final var contactBuilder = contact == null ? Contact.newBuilder() : Contact.newBuilder(contact); final var contactBuilder = contact == null ? Contact.newBuilder() : Contact.newBuilder(contact);
contact = contactBuilder.withProfileSharingEnabled(true).build(); contact = contactBuilder.withIsProfileSharingEnabled(true).withIsHidden(false).build();
account.getContactStore().storeContact(recipientId, contact); account.getContactStore().storeContact(recipientId, contact);
} }

View File

@ -116,11 +116,13 @@ public class StorageHelper {
final var blocked = contact != null && contact.isBlocked(); final var blocked = contact != null && contact.isBlocked();
final var profileShared = contact != null && contact.isProfileSharingEnabled(); final var profileShared = contact != null && contact.isProfileSharingEnabled();
final var archived = contact != null && contact.isArchived(); final var archived = contact != null && contact.isArchived();
final var hidden = contact != null && contact.isHidden();
final var contactGivenName = contact == null ? null : contact.givenName(); final var contactGivenName = contact == null ? null : contact.givenName();
final var contactFamilyName = contact == null ? null : contact.familyName(); final var contactFamilyName = contact == null ? null : contact.familyName();
if (blocked != contactRecord.isBlocked() if (blocked != contactRecord.isBlocked()
|| profileShared != contactRecord.isProfileSharingEnabled() || profileShared != contactRecord.isProfileSharingEnabled()
|| archived != contactRecord.isArchived() || archived != contactRecord.isArchived()
|| hidden != contactRecord.isHidden()
|| ( || (
contactRecord.getSystemGivenName().isPresent() && !contactRecord.getSystemGivenName() contactRecord.getSystemGivenName().isPresent() && !contactRecord.getSystemGivenName()
.get() .get()
@ -133,9 +135,10 @@ public class StorageHelper {
)) { )) {
logger.debug("Storing new or updated contact {}", recipientId); logger.debug("Storing new or updated contact {}", recipientId);
final var contactBuilder = contact == null ? Contact.newBuilder() : Contact.newBuilder(contact); final var contactBuilder = contact == null ? Contact.newBuilder() : Contact.newBuilder(contact);
final var newContact = contactBuilder.withBlocked(contactRecord.isBlocked()) final var newContact = contactBuilder.withIsBlocked(contactRecord.isBlocked())
.withProfileSharingEnabled(contactRecord.isProfileSharingEnabled()) .withIsProfileSharingEnabled(contactRecord.isProfileSharingEnabled())
.withArchived(contactRecord.isArchived()); .withIsArchived(contactRecord.isArchived())
.withIsHidden(contactRecord.isHidden());
if (contactRecord.getSystemGivenName().isPresent() || contactRecord.getSystemFamilyName().isPresent()) { if (contactRecord.getSystemGivenName().isPresent() || contactRecord.getSystemFamilyName().isPresent()) {
newContact.withGivenName(contactRecord.getSystemGivenName().orElse(null)) newContact.withGivenName(contactRecord.getSystemGivenName().orElse(null))
.withFamilyName(contactRecord.getSystemFamilyName().orElse(null)); .withFamilyName(contactRecord.getSystemFamilyName().orElse(null));

View File

@ -339,8 +339,8 @@ public class SyncHelper {
if (c.getExpirationTimer().isPresent()) { if (c.getExpirationTimer().isPresent()) {
builder.withMessageExpirationTime(c.getExpirationTimer().get()); builder.withMessageExpirationTime(c.getExpirationTimer().get());
} }
builder.withBlocked(c.isBlocked()); builder.withIsBlocked(c.isBlocked());
builder.withArchived(c.isArchived()); builder.withIsArchived(c.isArchived());
account.getContactStore().storeContact(recipientId, builder.build()); account.getContactStore().storeContact(recipientId, builder.build());
if (c.getAvatar().isPresent()) { if (c.getAvatar().isPresent()) {

View File

@ -840,6 +840,15 @@ public class ManagerImpl implements Manager {
} }
} }
@Override
public void hideRecipient(final RecipientIdentifier.Single recipient) {
final var recipientIdOptional = context.getRecipientHelper().resolveRecipientOptional(recipient);
if (recipientIdOptional.isPresent()) {
context.getContactHelper().setContactHidden(recipientIdOptional.get(), true);
account.removeRecipient(recipientIdOptional.get());
}
}
@Override @Override
public void deleteRecipient(final RecipientIdentifier.Single recipient) { public void deleteRecipient(final RecipientIdentifier.Single recipient) {
final var recipientIdOptional = context.getRecipientHelper().resolveRecipientOptional(recipient); final var recipientIdOptional = context.getRecipientHelper().resolveRecipientOptional(recipient);

View File

@ -32,7 +32,7 @@ import java.util.UUID;
public class AccountDatabase extends Database { public class AccountDatabase extends Database {
private static final Logger logger = LoggerFactory.getLogger(AccountDatabase.class); private static final Logger logger = LoggerFactory.getLogger(AccountDatabase.class);
private static final long DATABASE_VERSION = 18; private static final long DATABASE_VERSION = 19;
private AccountDatabase(final HikariDataSource dataSource) { private AccountDatabase(final HikariDataSource dataSource) {
super(logger, DATABASE_VERSION, dataSource); super(logger, DATABASE_VERSION, dataSource);
@ -531,5 +531,13 @@ public class AccountDatabase extends Database {
"""); """);
} }
} }
if (oldVersion < 19) {
logger.debug("Updating database: Adding contact hidden column");
try (final var statement = connection.createStatement()) {
statement.executeUpdate("""
ALTER TABLE recipient ADD COLUMN hidden INTEGER NOT NULL DEFAULT FALSE;
""");
}
}
} }
} }

View File

@ -826,6 +826,7 @@ public class SignalAccount implements Closeable {
contact.messageExpirationTime, contact.messageExpirationTime,
contact.blocked, contact.blocked,
contact.archived, contact.archived,
false,
false)); false));
// Store profile keys only in profile store // Store profile keys only in profile store

View File

@ -44,7 +44,8 @@ public class LegacyRecipientStore2 {
r.contact.messageExpirationTime, r.contact.messageExpirationTime,
r.contact.blocked, r.contact.blocked,
r.contact.archived, r.contact.archived,
r.contact.profileSharingEnabled); r.contact.profileSharingEnabled,
false);
} }
ProfileKey profileKey = null; ProfileKey profileKey = null;

View File

@ -70,6 +70,7 @@ public class RecipientStore implements RecipientIdCreator, RecipientResolver, Re
blocked INTEGER NOT NULL DEFAULT FALSE, blocked INTEGER NOT NULL DEFAULT FALSE,
archived INTEGER NOT NULL DEFAULT FALSE, archived INTEGER NOT NULL DEFAULT FALSE,
profile_sharing INTEGER NOT NULL DEFAULT FALSE, profile_sharing INTEGER NOT NULL DEFAULT FALSE,
hidden INTEGER NOT NULL DEFAULT FALSE,
profile_last_update_timestamp INTEGER NOT NULL DEFAULT 0, profile_last_update_timestamp INTEGER NOT NULL DEFAULT 0,
profile_given_name TEXT, profile_given_name TEXT,
@ -318,9 +319,9 @@ public class RecipientStore implements RecipientIdCreator, RecipientResolver, Re
public List<Pair<RecipientId, Contact>> getContacts() { public List<Pair<RecipientId, Contact>> getContacts() {
final var sql = ( final var sql = (
""" """
SELECT r._id, r.given_name, r.family_name, r.expiration_time, r.profile_sharing, r.color, r.blocked, r.archived SELECT r._id, r.given_name, r.family_name, r.expiration_time, r.profile_sharing, r.color, r.blocked, r.archived, r.hidden
FROM %s r FROM %s r
WHERE (r.number IS NOT NULL OR r.uuid IS NOT NULL) AND %s WHERE (r.number IS NOT NULL OR r.uuid IS NOT NULL) AND %s AND r.hidden = FALSE
""" """
).formatted(TABLE_RECIPIENT, SQL_IS_CONTACT); ).formatted(TABLE_RECIPIENT, SQL_IS_CONTACT);
try (final var connection = database.getConnection()) { try (final var connection = database.getConnection()) {
@ -342,6 +343,7 @@ public class RecipientStore implements RecipientIdCreator, RecipientResolver, Re
final var sqlWhere = new ArrayList<String>(); final var sqlWhere = new ArrayList<String>();
if (onlyContacts) { if (onlyContacts) {
sqlWhere.add("(" + SQL_IS_CONTACT + ")"); sqlWhere.add("(" + SQL_IS_CONTACT + ")");
sqlWhere.add("r.hidden = FALSE");
} }
if (blocked.isPresent()) { if (blocked.isPresent()) {
sqlWhere.add("r.blocked = ?"); sqlWhere.add("r.blocked = ?");
@ -357,7 +359,7 @@ public class RecipientStore implements RecipientIdCreator, RecipientResolver, Re
SELECT r._id, SELECT r._id,
r.number, r.uuid, r.pni, r.username, r.number, r.uuid, r.pni, r.username,
r.profile_key, r.profile_key_credential, r.profile_key, r.profile_key_credential,
r.given_name, r.family_name, r.expiration_time, r.profile_sharing, r.color, r.blocked, r.archived, r.given_name, r.family_name, r.expiration_time, r.profile_sharing, r.color, r.blocked, r.archived, r.hidden,
r.profile_last_update_timestamp, r.profile_given_name, r.profile_family_name, r.profile_about, r.profile_about_emoji, r.profile_avatar_url_path, r.profile_mobile_coin_address, r.profile_unidentified_access_mode, r.profile_capabilities r.profile_last_update_timestamp, r.profile_given_name, r.profile_family_name, r.profile_about, r.profile_about_emoji, r.profile_avatar_url_path, r.profile_mobile_coin_address, r.profile_unidentified_access_mode, r.profile_capabilities
FROM %s r FROM %s r
WHERE (r.number IS NOT NULL OR r.uuid IS NOT NULL) AND %s WHERE (r.number IS NOT NULL OR r.uuid IS NOT NULL) AND %s
@ -962,7 +964,7 @@ public class RecipientStore implements RecipientIdCreator, RecipientResolver, Re
private Contact getContact(final Connection connection, final RecipientId recipientId) throws SQLException { private Contact getContact(final Connection connection, final RecipientId recipientId) throws SQLException {
final var sql = ( final var sql = (
""" """
SELECT r.given_name, r.family_name, r.expiration_time, r.profile_sharing, r.color, r.blocked, r.archived SELECT r.given_name, r.family_name, r.expiration_time, r.profile_sharing, r.color, r.blocked, r.archived, r.hidden
FROM %s r FROM %s r
WHERE r._id = ? AND (%s) WHERE r._id = ? AND (%s)
""" """
@ -1053,7 +1055,8 @@ public class RecipientStore implements RecipientIdCreator, RecipientResolver, Re
resultSet.getInt("expiration_time"), resultSet.getInt("expiration_time"),
resultSet.getBoolean("blocked"), resultSet.getBoolean("blocked"),
resultSet.getBoolean("archived"), resultSet.getBoolean("archived"),
resultSet.getBoolean("profile_sharing")); resultSet.getBoolean("profile_sharing"),
resultSet.getBoolean("hidden"));
} }
private Profile getProfileFromResultSet(ResultSet resultSet) throws SQLException { private Profile getProfileFromResultSet(ResultSet resultSet) throws SQLException {

View File

@ -613,6 +613,9 @@ Remove the info of a given contact
NUMBER:: NUMBER::
Specify the contact phone number. Specify the contact phone number.
*--hide*::
Hide the contact in the contact list, but keep the data.
*--forget*:: *--forget*::
Delete all data associated with this contact, including identity keys and sessions. Delete all data associated with this contact, including identity keys and sessions.

View File

@ -20,7 +20,11 @@ public class RemoveContactCommand implements JsonRpcLocalCommand {
public void attachToSubparser(final Subparser subparser) { public void attachToSubparser(final Subparser subparser) {
subparser.help("Remove the details of a given contact"); subparser.help("Remove the details of a given contact");
subparser.addArgument("recipient").help("Contact number"); subparser.addArgument("recipient").help("Contact number");
subparser.addArgument("--forget") final var mut = subparser.addMutuallyExclusiveGroup();
mut.addArgument("--hide")
.action(Arguments.storeTrue())
.help("Hide the contact in the contact list, but keep the data.");
mut.addArgument("--forget")
.action(Arguments.storeTrue()) .action(Arguments.storeTrue())
.help("Delete all data associated with this contact, including identity keys and sessions."); .help("Delete all data associated with this contact, including identity keys and sessions.");
} }
@ -32,8 +36,11 @@ public class RemoveContactCommand implements JsonRpcLocalCommand {
var recipientString = ns.getString("recipient"); var recipientString = ns.getString("recipient");
var recipient = CommandUtil.getSingleRecipientIdentifier(recipientString, m.getSelfNumber()); var recipient = CommandUtil.getSingleRecipientIdentifier(recipientString, m.getSelfNumber());
var hide = Boolean.TRUE == ns.getBoolean("hide");
var forget = Boolean.TRUE == ns.getBoolean("forget"); var forget = Boolean.TRUE == ns.getBoolean("forget");
if (forget) { if (hide) {
m.hideRecipient(recipient);
} else if (forget) {
m.deleteRecipient(recipient); m.deleteRecipient(recipient);
} else { } else {
m.deleteContact(recipient); m.deleteContact(recipient);

View File

@ -452,6 +452,10 @@ public class DbusManagerImpl implements Manager {
return new SendMessageResults(0, Map.of()); return new SendMessageResults(0, Map.of());
} }
public void hideRecipient(final RecipientIdentifier.Single recipient) {
throw new UnsupportedOperationException();
}
@Override @Override
public void deleteRecipient(final RecipientIdentifier.Single recipient) { public void deleteRecipient(final RecipientIdentifier.Single recipient) {
signal.deleteRecipient(recipient.getIdentifier()); signal.deleteRecipient(recipient.getIdentifier());
@ -653,7 +657,7 @@ public class DbusManagerImpl implements Manager {
} }
return Recipient.newBuilder() return Recipient.newBuilder()
.withAddress(new RecipientAddress(null, n)) .withAddress(new RecipientAddress(null, n))
.withContact(new Contact(contactName, null, null, 0, contactBlocked, false, false)) .withContact(new Contact(contactName, null, null, 0, contactBlocked, false, false, false))
.build(); .build();
}).filter(Objects::nonNull).toList(); }).filter(Objects::nonNull).toList();
} }