1// Copyright 2018-present 650 Industries. All rights reserved. 2 3#import "EXScopedNotificationsUtils.h" 4 5@implementation EXScopedNotificationsUtils 6 7+ (BOOL)shouldNotificationRequest:(UNNotificationRequest *)request beHandledByExperience:(NSString *)scopeKey 8{ 9 NSString *notificationScopeKey = request.content.userInfo[@"experienceId"]; 10 if (!notificationScopeKey) { 11 return true; 12 } 13 return [notificationScopeKey isEqual:scopeKey]; 14} 15 16+ (BOOL)shouldNotification:(UNNotification *)notification beHandledByExperience:(NSString *)scopeKey 17{ 18 return [EXScopedNotificationsUtils shouldNotificationRequest:notification.request beHandledByExperience:scopeKey]; 19} 20 21+ (NSString *)scopedIdentifierFromId:(NSString *)unscopedId forExperience:(NSString *)scopeKey 22{ 23 NSString *scope = [EXScopedNotificationsUtils escapedString:scopeKey]; 24 NSString *escapedCategoryId = [EXScopedNotificationsUtils escapedString:unscopedId]; 25 return [NSString stringWithFormat:@"%@/%@", scope, escapedCategoryId]; 26} 27 28+ (BOOL)isId:(NSString *)identifier scopedByExperience:(NSString *)scopeKey 29{ 30 NSString *scopeFromCategoryId = [EXScopedNotificationsUtils getScopeAndIdentifierFromScopedIdentifier:identifier].scopeKey; 31 return [scopeFromCategoryId isEqualToString:scopeKey]; 32} 33 34+ (ScopedIdentifierComponents)getScopeAndIdentifierFromScopedIdentifier:(NSString *)scopedIdentifier 35{ 36 NSString *scope = @""; 37 NSString *identifier = @""; 38 NSString *pattern = @"^" 39 "((?:[^/\\\\]|\\\\[/\\\\])*)" // escaped scope key 40 "/" // delimiter 41 "((?:[^/\\\\]|\\\\[/\\\\])*)" // escaped original category identifier 42 "$"; 43 NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:pattern 44 options:0 45 error:nil]; 46 NSTextCheckingResult *match = [regex firstMatchInString:scopedIdentifier 47 options:0 48 range:NSMakeRange(0, scopedIdentifier.length)]; 49 if (!match) { 50 // No delimiter found, so no scope associated with this identifier 51 identifier = scopedIdentifier; 52 } else { 53 scope = [scopedIdentifier substringWithRange:[match rangeAtIndex:1]]; 54 identifier = [scopedIdentifier substringWithRange:[match rangeAtIndex:2]]; 55 } 56 ScopedIdentifierComponents components; 57 components.scopeKey = [EXScopedNotificationsUtils unescapedString:scope]; 58 components.identifier = [EXScopedNotificationsUtils unescapedString:identifier]; 59 return components; 60} 61 62+ (NSString *)escapedString:(NSString*)string 63{ 64 return [[string stringByReplacingOccurrencesOfString:@"\\" withString:@"\\\\"] 65 stringByReplacingOccurrencesOfString:@"/" withString:@"\\/"]; 66} 67 68+ (NSString *)unescapedString:(NSString*)string 69{ 70 return [[string stringByReplacingOccurrencesOfString:@"\\/" withString:@"/"] 71 stringByReplacingOccurrencesOfString:@"\\\\" withString:@"\\"]; 72} 73 74# pragma mark Legacy notification category scoping 75 76+ (BOOL)isLegacyCategoryId:(NSString *)scopedCategoryId scopedByScopeKey:(NSString *)scopeKey 77{ 78 NSString* legacyScopingPrefix = [NSString stringWithFormat:@"%@-", scopeKey]; 79 return [scopedCategoryId hasPrefix:legacyScopingPrefix]; 80} 81 82// legacy categories were stored under an unescaped experienceId 83+ (NSString *)unscopedLegacyCategoryIdentifierWithId:(NSString *)scopedCategoryId 84 forScopeKey:(NSString *)scopeKey 85{ 86 NSString* legacyScopingPrefix = [NSString stringWithFormat:@"%@-", scopeKey]; 87 return [scopedCategoryId stringByReplacingOccurrencesOfString:legacyScopingPrefix 88 withString:@"" 89 options:NSAnchoredSearch 90 range:NSMakeRange(0, [scopedCategoryId length])]; 91} 92 93@end 94