From 6c5fbc6de5644ba5a42f9ec1d858ab1806630b32 Mon Sep 17 00:00:00 2001 From: Michael Kirk Date: Tue, 18 Sep 2018 15:17:27 -0600 Subject: [PATCH] Update existing contact offers in place WIP: migration / autoincrement logic TODO: -[x] contact offer -[ ] verify all paths that utilized timestampForSorting, e.g. make sure SN appear before the message they affect, etc. -[x] Monotonic ID -[x] New extension which sorts by id -[x] Migration -[ ] batch migration? fixup contact offers --- Signal.xcodeproj/project.pbxproj | 4 +- .../Models/OWSContactOffersInteraction.h | 10 +++ .../Models/OWSContactOffersInteraction.m | 20 ++++++ SignalMessaging/utils/ThreadUtil.m | 70 +++++++++---------- 4 files changed, 64 insertions(+), 40 deletions(-) diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index d5a6e4503..050d186f9 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -444,8 +444,8 @@ 4C63CC00210A620B003AE45C /* SignalTSan.supp in Resources */ = {isa = PBXBuildFile; fileRef = 4C63CBFF210A620B003AE45C /* SignalTSan.supp */; }; 4C6F527C20FFE8400097DEEE /* SignalUBSan.supp in Resources */ = {isa = PBXBuildFile; fileRef = 4C6F527B20FFE8400097DEEE /* SignalUBSan.supp */; }; 4C858A52212DC5E1001B45D3 /* UIImage+OWS.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C858A51212DC5E1001B45D3 /* UIImage+OWS.swift */; }; - 4C948FF72146EB4800349F0D /* BlockListCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C948FF62146EB4800349F0D /* BlockListCache.swift */; }; 4C858A562130CBEC001B45D3 /* OWS110SortIdMigration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C858A552130CBEC001B45D3 /* OWS110SortIdMigration.swift */; }; + 4C948FF72146EB4800349F0D /* BlockListCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C948FF62146EB4800349F0D /* BlockListCache.swift */; }; 4CA5F793211E1F06008C2708 /* Toast.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CA5F792211E1F06008C2708 /* Toast.swift */; }; 4CB5F26720F6E1E2004D1B42 /* MenuActionsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CFF4C0920F55BBA005DA313 /* MenuActionsViewController.swift */; }; 4CB5F26920F7D060004D1B42 /* MessageActions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CB5F26820F7D060004D1B42 /* MessageActions.swift */; }; @@ -1136,8 +1136,8 @@ 4C63CBFF210A620B003AE45C /* SignalTSan.supp */ = {isa = PBXFileReference; lastKnownFileType = text; path = SignalTSan.supp; sourceTree = ""; }; 4C6F527B20FFE8400097DEEE /* SignalUBSan.supp */ = {isa = PBXFileReference; lastKnownFileType = text; path = SignalUBSan.supp; sourceTree = ""; }; 4C858A51212DC5E1001B45D3 /* UIImage+OWS.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIImage+OWS.swift"; sourceTree = ""; }; - 4C948FF62146EB4800349F0D /* BlockListCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlockListCache.swift; sourceTree = ""; }; 4C858A552130CBEC001B45D3 /* OWS110SortIdMigration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OWS110SortIdMigration.swift; sourceTree = ""; }; + 4C948FF62146EB4800349F0D /* BlockListCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlockListCache.swift; sourceTree = ""; }; 4CA5F792211E1F06008C2708 /* Toast.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Toast.swift; sourceTree = ""; }; 4CB5F26820F7D060004D1B42 /* MessageActions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageActions.swift; sourceTree = ""; }; 4CC0B59B20EC5F2E00CF6EE0 /* ConversationConfigurationSyncOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConversationConfigurationSyncOperation.swift; sourceTree = ""; }; diff --git a/SignalMessaging/Models/OWSContactOffersInteraction.h b/SignalMessaging/Models/OWSContactOffersInteraction.h index 2f3878123..d6f1ebd3b 100644 --- a/SignalMessaging/Models/OWSContactOffersInteraction.h +++ b/SignalMessaging/Models/OWSContactOffersInteraction.h @@ -4,6 +4,8 @@ #import +@class YapDatabaseReadWriteTransaction; + NS_ASSUME_NONNULL_BEGIN @interface OWSContactOffersInteraction : TSInteraction @@ -11,6 +13,9 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic, readonly) BOOL hasBlockOffer; @property (nonatomic, readonly) BOOL hasAddToContactsOffer; @property (nonatomic, readonly) BOOL hasAddToProfileWhitelistOffer; + +// TODO - remove this recipientId param +// it's redundant with the interaction's TSContactThread @property (nonatomic, readonly) NSString *recipientId; - (instancetype)initInteractionWithTimestamp:(uint64_t)timestamp inThread:(TSThread *)thread NS_UNAVAILABLE; @@ -24,6 +29,11 @@ NS_ASSUME_NONNULL_BEGIN hasAddToProfileWhitelistOffer:(BOOL)hasAddToProfileWhitelistOffer recipientId:(NSString *)recipientId NS_DESIGNATED_INITIALIZER; +- (void)updateHasBlockOffer:(BOOL)hasBlockOffer + hasAddToContactsOffer:(BOOL)hasAddToContactsOffer + hasAddToProfileWhitelistOffer:(BOOL)hasAddToProfileWhitelistOffer + transaction:(YapDatabaseReadWriteTransaction *)transaction; + @end NS_ASSUME_NONNULL_END diff --git a/SignalMessaging/Models/OWSContactOffersInteraction.m b/SignalMessaging/Models/OWSContactOffersInteraction.m index 6be86f2e1..7fa484f19 100644 --- a/SignalMessaging/Models/OWSContactOffersInteraction.m +++ b/SignalMessaging/Models/OWSContactOffersInteraction.m @@ -6,6 +6,14 @@ NS_ASSUME_NONNULL_BEGIN +@interface OWSContactOffersInteraction () + +@property (nonatomic) BOOL hasBlockOffer; +@property (nonatomic) BOOL hasAddToContactsOffer; +@property (nonatomic) BOOL hasAddToProfileWhitelistOffer; + +@end + @implementation OWSContactOffersInteraction - (instancetype)initWithCoder:(NSCoder *)coder @@ -52,6 +60,18 @@ NS_ASSUME_NONNULL_BEGIN return OWSInteractionType_Offer; } +- (void)updateHasBlockOffer:(BOOL)hasBlockOffer + hasAddToContactsOffer:(BOOL)hasAddToContactsOffer + hasAddToProfileWhitelistOffer:(BOOL)hasAddToProfileWhitelistOffer + transaction:(YapDatabaseReadWriteTransaction *)transaction +{ + [self applyChangeToSelfAndLatestCopy:transaction + changeBlock:^(OWSContactOffersInteraction *offers) { + offers.hasBlockOffer = hasBlockOffer; + offers.hasAddToContactsOffer = hasAddToContactsOffer; + offers.hasAddToProfileWhitelistOffer = hasAddToProfileWhitelistOffer; + }]; +} @end NS_ASSUME_NONNULL_END diff --git a/SignalMessaging/utils/ThreadUtil.m b/SignalMessaging/utils/ThreadUtil.m index 1d0d7cf70..bf42211c3 100644 --- a/SignalMessaging/utils/ThreadUtil.m +++ b/SignalMessaging/utils/ThreadUtil.m @@ -255,7 +255,6 @@ NS_ASSUME_NONNULL_BEGIN #pragma mark - Dynamic Interactions -// MJK TODO - dynamic interactions + (ThreadDynamicInteractions *)ensureDynamicInteractionsForThread:(TSThread *)thread contactsManager:(OWSContactsManager *)contactsManager blockingManager:(OWSBlockingManager *)blockingManager @@ -464,53 +463,48 @@ NS_ASSUME_NONNULL_BEGIN = (shouldHaveBlockOffer || shouldHaveAddToContactsOffer || shouldHaveAddToProfileWhitelistOffer); if (isContactThread) { TSContactThread *contactThread = (TSContactThread *)thread; + // MJK only place where `hasDismissedOffers` is read if (contactThread.hasDismissedOffers) { shouldHaveContactOffers = NO; } } - // We want the offers to be the first interactions in their - // conversation's timeline, so we back-date them to slightly before - // the first message - or at an aribtrary old timestamp if the - // conversation has no messages. - uint64_t contactOffersTimestamp = [NSDate ows_millisecondTimeStamp]; - - // If the contact offers' properties have changed, discard the current - // one and create a new one. - if (existingContactOffers) { - if (existingContactOffers.hasBlockOffer != shouldHaveBlockOffer - || existingContactOffers.hasAddToContactsOffer != shouldHaveAddToContactsOffer - || existingContactOffers.hasAddToProfileWhitelistOffer != shouldHaveAddToProfileWhitelistOffer) { - OWSLogInfo(@"Removing stale contact offers: %@ (%llu)", - existingContactOffers.uniqueId, - existingContactOffers.timestampForSorting); - // Preserve the timestamp of the existing "contact offers" so that - // we replace it in the same position in the timeline. - contactOffersTimestamp = existingContactOffers.timestamp; - [existingContactOffers removeWithTransaction:transaction]; - existingContactOffers = nil; - } - } - if (existingContactOffers && !shouldHaveContactOffers) { OWSLogInfo(@"Removing contact offers: %@ (%llu)", existingContactOffers.uniqueId, existingContactOffers.timestampForSorting); [existingContactOffers removeWithTransaction:transaction]; - } else if (!existingContactOffers && shouldHaveContactOffers) { - NSString *recipientId = ((TSContactThread *)thread).contactIdentifier; - - TSInteraction *offersMessage = - [[OWSContactOffersInteraction alloc] initContactOffersWithTimestamp:contactOffersTimestamp - thread:thread - hasBlockOffer:shouldHaveBlockOffer - hasAddToContactsOffer:shouldHaveAddToContactsOffer - hasAddToProfileWhitelistOffer:shouldHaveAddToProfileWhitelistOffer - recipientId:recipientId]; - [offersMessage saveWithTransaction:transaction]; - - OWSLogInfo( - @"Creating contact offers: %@ (%llu)", offersMessage.uniqueId, offersMessage.timestampForSorting); + } else if (shouldHaveContactOffers) { + if (existingContactOffers) { + // If the contact offers' properties have changed, update them + if (existingContactOffers.hasBlockOffer != shouldHaveBlockOffer + || existingContactOffers.hasAddToContactsOffer != shouldHaveAddToContactsOffer + || existingContactOffers.hasAddToProfileWhitelistOffer != shouldHaveAddToProfileWhitelistOffer) { + OWSLogInfo(@"Updating stale contact offers: %@ (%llu)", + existingContactOffers.uniqueId, + existingContactOffers.timestampForSorting); + + [existingContactOffers updateHasBlockOffer:shouldHaveBlockOffer + hasAddToContactsOffer:shouldHaveAddToContactsOffer + hasAddToProfileWhitelistOffer:shouldHaveAddToProfileWhitelistOffer + transaction:transaction]; + } + } else { + NSString *recipientId = ((TSContactThread *)thread).contactIdentifier; + + // TODO MJK - remove this timestamp + TSInteraction *offersMessage = [[OWSContactOffersInteraction alloc] + initContactOffersWithTimestamp:[NSDate ows_millisecondTimeStamp] + thread:thread + hasBlockOffer:shouldHaveBlockOffer + hasAddToContactsOffer:shouldHaveAddToContactsOffer + hasAddToProfileWhitelistOffer:shouldHaveAddToProfileWhitelistOffer + recipientId:recipientId]; + [offersMessage saveWithTransaction:transaction]; + + OWSLogInfo( + @"Creating contact offers: %@ (%llu)", offersMessage.uniqueId, offersMessage.timestampForSorting); + } } [self ensureUnreadIndicator:result