forked from Ivasoft/mattermost-mobile
iOS Share Extension fix post and dm/gm list (#2659)
* MM-14629 DMs and GMs for the iOS extension to match sidebar * MM-14631 ios extension logging and fix race condition to post after uploading
This commit is contained in:
@@ -21,13 +21,16 @@
|
||||
#import "RNNotifications.h"
|
||||
#import <UploadAttachments/UploadAttachments-Swift.h>
|
||||
#import <UserNotifications/UserNotifications.h>
|
||||
#import <os/log.h>
|
||||
|
||||
@implementation AppDelegate
|
||||
|
||||
NSString* const NotificationClearAction = @"clear";
|
||||
|
||||
-(void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)(void))completionHandler {
|
||||
os_log(OS_LOG_DEFAULT, "Mattermost will attach session from handleEventsForBackgroundURLSession!! identifier=%{public}@", identifier);
|
||||
[[UploadSession shared] attachSessionWithIdentifier:identifier completionHandler:completionHandler];
|
||||
os_log(OS_LOG_DEFAULT, "Mattermost session ATTACHED from handleEventsForBackgroundURLSession!! identifier=%{public}@", identifier);
|
||||
}
|
||||
|
||||
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
|
||||
@@ -58,6 +61,9 @@ NSString* const NotificationClearAction = @"clear";
|
||||
[[RCCManager sharedInstance] initBridgeWithBundleURL:jsCodeLocation launchOptions:launchOptions];
|
||||
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error: nil];
|
||||
|
||||
os_log(OS_LOG_DEFAULT, "Mattermost started!!");
|
||||
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
||||
@@ -26,21 +26,16 @@
|
||||
-(NSDictionary *)getChannelById:(NSString *)channelId {
|
||||
NSDictionary *channelsStore = [self.entities objectForKey:@"channels"];
|
||||
NSDictionary *channels = [channelsStore objectForKey:@"channels"];
|
||||
NSDictionary *channel = channels[channelId];
|
||||
|
||||
for (NSString * key in channels) {
|
||||
NSDictionary *channel = channels[key];
|
||||
NSString *channel_id = [channel objectForKey:@"id"];
|
||||
if ([channel_id isEqualToString:channelId]) {
|
||||
return channel;
|
||||
}
|
||||
}
|
||||
|
||||
return nil;
|
||||
return channel;
|
||||
}
|
||||
|
||||
-(NSDictionary *)getChannelsBySections:(NSString *)forTeamId {
|
||||
NSDictionary *channelsStore = [self.entities objectForKey:@"channels"];
|
||||
NSString *currentUserId = [self getCurrentUserId];
|
||||
NSString *currentChannelId = [self getCurrentChannelId];
|
||||
NSDictionary *preferences = [self getMyPreferences];
|
||||
NSDictionary *channels = [channelsStore objectForKey:@"channels"];
|
||||
NSMutableDictionary *channelsInTeam = [[NSMutableDictionary alloc] init];
|
||||
NSMutableArray *publicChannels = [[NSMutableArray alloc] init];
|
||||
@@ -66,13 +61,17 @@
|
||||
// direct message
|
||||
NSString *otherUserId = [self getOtherUserIdFromChannel:currentUserId withChannelName:[channel objectForKey:@"name"]];
|
||||
NSDictionary *otherUser = [self getUserById:otherUserId];
|
||||
if (otherUser) {
|
||||
NSNumber *delete_at = [otherUser objectForKey:@"delete_at"] ?: 0;
|
||||
if (otherUser && [self isDirectChannelVisible:preferences otherUserId:otherUserId] && ![self isAutoClosed:preferences channel:channel currentChannelId:currentChannelId channelArchivedAt:delete_at]) {
|
||||
[channel setObject:[self displayUserName:otherUser] forKey:@"display_name"];
|
||||
[directChannels addObject:channel];
|
||||
}
|
||||
} else {
|
||||
[channel setObject:[self completeDirectGroupInfo:key] forKey:@"display_name"];
|
||||
[directChannels addObject:channel];
|
||||
NSNumber *delete_at = [channel objectForKey:@"delete_at"] ?: 0;
|
||||
if ([self isGroupChannelVisible:preferences channelId:key] && ![self isAutoClosed:preferences channel:channel currentChannelId:currentChannelId channelArchivedAt:delete_at]) {
|
||||
[channel setObject:[self completeDirectGroupInfo:key] forKey:@"display_name"];
|
||||
[directChannels addObject:channel];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -89,8 +88,6 @@
|
||||
return [self getChannelById:currentChannelId];
|
||||
}
|
||||
|
||||
|
||||
|
||||
-(NSString *)getCurrentChannelId {
|
||||
return [[self.entities objectForKey:@"channels"] objectForKey:@"currentChannelId"];
|
||||
}
|
||||
@@ -236,27 +233,22 @@
|
||||
}
|
||||
|
||||
-(NSString *)getOtherUserIdFromChannel:(NSString *)currentUserId withChannelName:(NSString *)channelName {
|
||||
NSArray *ids = [channelName componentsSeparatedByString:@"_"];
|
||||
if ([ids[0] isEqualToString:currentUserId]) {
|
||||
return ids[2];
|
||||
}
|
||||
|
||||
return ids[0];
|
||||
NSArray *ids = [channelName componentsSeparatedByString:@"_"];
|
||||
NSString *user1 = ids[0];
|
||||
NSString *user2 = ids[2];
|
||||
if (user1 != nil && [user1 isEqualToString:currentUserId]) {
|
||||
return user2;
|
||||
}
|
||||
|
||||
return user1;
|
||||
}
|
||||
|
||||
-(NSDictionary *)getUserById:(NSString *)userId {
|
||||
NSDictionary *usersStore = [self.entities objectForKey:@"users"];
|
||||
NSDictionary *users = [usersStore objectForKey:@"profiles"];
|
||||
NSDictionary *user = [users objectForKey:userId];
|
||||
|
||||
for (NSString* key in users) {
|
||||
NSDictionary *user = [users objectForKey:key];
|
||||
NSString *user_id = [user objectForKey:@"id"];
|
||||
if ([user_id isEqualToString:userId]) {
|
||||
return user;
|
||||
}
|
||||
}
|
||||
|
||||
return nil;
|
||||
return user;
|
||||
}
|
||||
|
||||
-(NSString *)getUserFullName:(NSDictionary*) user {
|
||||
@@ -300,4 +292,100 @@
|
||||
return [array sortedArrayUsingDescriptors:sortDescriptor];
|
||||
}
|
||||
|
||||
-(BOOL)isAutoClosed:(NSDictionary*)preferences channel:(NSDictionary *)channel currentChannelId:(NSString *)currentChannelId channelArchivedAt:(NSNumber *)channelArchivedAt {
|
||||
NSNumber *cutoff = [NSNumber numberWithLongLong:([[NSDate date] timeIntervalSince1970] * 1000 - (7 * 24 * 60 * 60 * 1000))];
|
||||
NSString *channelId = [channel objectForKey:@"id"];
|
||||
|
||||
NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
|
||||
numberFormatter.numberStyle = NSNumberFormatterNoStyle;
|
||||
|
||||
NSDictionary *viewTimePref = [preferences objectForKey:[NSString stringWithFormat:@"channel_approximate_view_time--%@", channelId]];
|
||||
NSNumber *viewTime = 0;
|
||||
if (viewTimePref != nil) {
|
||||
viewTime = [numberFormatter numberFromString:[viewTimePref objectForKey:@"value"]];
|
||||
}
|
||||
|
||||
if ([viewTime doubleValue] > [cutoff doubleValue]) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
// If chhannel is archived we cannot post to it
|
||||
if ([channelArchivedAt doubleValue] > 0.0) {
|
||||
return YES;
|
||||
}
|
||||
|
||||
NSDictionary *config = [self getConfig];
|
||||
if (![[config objectForKey:@"CloseUnusedDirectMessages"] isEqualToString:@"true"] || [self isFavoriteChannel:channelId]) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
NSDictionary *autoClosePref = [preferences objectForKey:@"sidebar_settings--close_unused_direct_messages"];
|
||||
|
||||
if (autoClosePref == nil || [[autoClosePref objectForKey:@"value"] isEqualToString:@"after_seven_days"]) {
|
||||
NSNumber *lastChannelPostAt = [self lastChannelPostActivity:channelId];
|
||||
if ([lastChannelPostAt doubleValue] > [cutoff doubleValue]) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
NSDictionary *openTimePref = [preferences objectForKey:[NSString stringWithFormat:@"channel_open_time--%@", channelId]];
|
||||
NSNumber *openTime = 0;
|
||||
if (openTimePref != nil) {
|
||||
openTime = [numberFormatter numberFromString:[openTimePref objectForKey:@"value"]];
|
||||
}
|
||||
|
||||
if ([openTime doubleValue] > [cutoff doubleValue]) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
NSNumber *lastActivity = [channel objectForKey:@"last_post_at"];
|
||||
return [lastActivity doubleValue] == 0.0 || [lastActivity doubleValue] < [cutoff doubleValue];
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
-(BOOL)isFavoriteChannel:(NSString *)channelId {
|
||||
NSDictionary *preferences = [self getMyPreferences];
|
||||
NSDictionary *favoritePref = [preferences objectForKey:[NSString stringWithFormat:@"favorite_channel--%@", channelId]];
|
||||
return favoritePref != nil && [[favoritePref objectForKey:@"value"] isEqualToString:@"true"];
|
||||
}
|
||||
|
||||
-(NSNumber *)lastChannelPostActivity:(NSString *)channelId {
|
||||
NSDictionary *allPosts = [[self.entities objectForKey:@"posts"] objectForKey:@"posts"];
|
||||
NSDictionary *postsInChannels = [[self.entities objectForKey:@"posts"] objectForKey:@"postsInChannel"];
|
||||
NSArray *postInChannel = [postsInChannels objectForKey:channelId];
|
||||
|
||||
if (postInChannel != nil && [postInChannel count] > 0) {
|
||||
NSString *postId = [postInChannel lastObject];
|
||||
NSDictionary *post = [allPosts objectForKey:postId];
|
||||
if (post != nil) {
|
||||
return [post objectForKey:@"create_at"];
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
-(BOOL)isDirectChannelVisible:(NSDictionary *)preferences otherUserId:(NSString *) otherUserId {
|
||||
NSDictionary *dmPref = [preferences objectForKey:[NSString stringWithFormat:@"direct_channel_show--%@", otherUserId]];
|
||||
if (dmPref != nil) {
|
||||
NSString *value = [dmPref objectForKey:@"value"];
|
||||
if (value != nil) {
|
||||
return [value isEqualToString:@"true"];
|
||||
}
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
-(BOOL)isGroupChannelVisible:(NSDictionary *)preferences channelId:(NSString *) channelId {
|
||||
NSDictionary *gmPref = [preferences objectForKey:[NSString stringWithFormat:@"group_channel_show--%@", channelId]];
|
||||
if (gmPref != nil) {
|
||||
NSString *value = [gmPref objectForKey:@"value"];
|
||||
if (value != nil) {
|
||||
return [value isEqualToString:@"true"];
|
||||
}
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import UIKit
|
||||
import os.log
|
||||
|
||||
@objc @objcMembers public class UploadSession: NSObject, URLSessionDataDelegate {
|
||||
public class var shared :UploadSession {
|
||||
@@ -33,6 +34,11 @@ import UIKit
|
||||
request.setValue("Bearer \(sessionToken!)", forHTTPHeaderField: "Authorization")
|
||||
request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
|
||||
request.httpBody = try? JSONSerialization.data(withJSONObject: jsonObject, options: .prettyPrinted)
|
||||
|
||||
if #available(iOS 12.0, *) {
|
||||
os_log(OSLogType.default, "Mattermost will post identifier=%{public}@", identifier)
|
||||
}
|
||||
|
||||
URLSession(configuration: .ephemeral).dataTask(with: request).resume()
|
||||
|
||||
UploadSessionManager.shared.removeUploadSessionData(identifier: identifier)
|
||||
@@ -42,6 +48,9 @@ import UIKit
|
||||
|
||||
public func attachSession(identifier: String, completionHandler: @escaping () -> Void) {
|
||||
self.completionHandler = completionHandler
|
||||
if #available(iOS 12.0, *) {
|
||||
os_log(OSLogType.default, "Mattermost Attached session with completionHandler identifier=%{public}@", identifier)
|
||||
}
|
||||
let sessionConfig = URLSessionConfiguration.background(withIdentifier: identifier)
|
||||
sessionConfig.sharedContainerIdentifier = APP_GROUP_ID
|
||||
if #available(iOS 11.0, *) {
|
||||
@@ -59,9 +68,12 @@ import UIKit
|
||||
}
|
||||
|
||||
self.session = URLSession(configuration: sessionConfig, delegate: self, delegateQueue: nil)
|
||||
if #available(iOS 12.0, *) {
|
||||
os_log(OSLogType.default, "Mattermost Session created identifier=%{public}@", identifier)
|
||||
}
|
||||
return self.session!
|
||||
}
|
||||
|
||||
|
||||
public func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
|
||||
// here we should get the file Id and update it in the session
|
||||
guard let identifier = session.configuration.identifier else {return}
|
||||
@@ -74,6 +86,9 @@ import UIKit
|
||||
UploadSessionManager.shared.appendCompletedUploadToSession(identifier: identifier, fileId: fileId)
|
||||
}
|
||||
} catch {
|
||||
if #available(iOS 12.0, *) {
|
||||
os_log(OSLogType.default, "Mattermost Failed to receive data identifier=%{public}@ error=%{public}", identifier, error.localizedDescription)
|
||||
}
|
||||
print("MMLOG: Failed to get the file upload response %@", error.localizedDescription)
|
||||
}
|
||||
|
||||
@@ -84,19 +99,28 @@ import UIKit
|
||||
let identifier = session.configuration.identifier!
|
||||
guard let sessionData = UploadSessionManager.shared.getUploadSessionData(identifier: identifier) else {return}
|
||||
if sessionData.fileIds.count == sessionData.totalFiles {
|
||||
if #available(iOS 12.0, *) {
|
||||
os_log(OSLogType.default, "Mattermost did complete upload identifier=%{public}@", identifier)
|
||||
}
|
||||
ProcessInfo().performExpiringActivity(withReason: "Need to post the message") { (expires) in
|
||||
self.createPost(identifier: identifier)
|
||||
self.createPost(identifier: session.configuration.identifier!)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func urlSessionDidFinishEvents(forBackgroundURLSession session: URLSession) {
|
||||
DispatchQueue.main.async {
|
||||
|
||||
if #available(iOS 12.0, *) {
|
||||
os_log(OSLogType.default, "Mattermost urlSessionDidFinishEvents identifier=%{public}@", session.configuration.identifier ?? "no identifier")
|
||||
}
|
||||
|
||||
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + Double(Int64(1.0*Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC), execute: {
|
||||
if self.completionHandler != nil {
|
||||
if #available(iOS 12.0, *) {
|
||||
os_log(OSLogType.default, "Mattermost CALLED COMPLETIONHANDLER")
|
||||
}
|
||||
self.completionHandler!()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user