diff --git a/ios/Mattermost.xcodeproj/project.pbxproj b/ios/Mattermost.xcodeproj/project.pbxproj index d1ccb0588..0667576d4 100644 --- a/ios/Mattermost.xcodeproj/project.pbxproj +++ b/ios/Mattermost.xcodeproj/project.pbxproj @@ -62,6 +62,8 @@ 7F43D6061F6BF9EB001FC614 /* libPods-Mattermost.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F43D6051F6BF9EB001FC614 /* libPods-Mattermost.a */; }; 7F43D63F1F6BFA19001FC614 /* libBVLinearGradient.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 37D8FEC21E80B5230091F3BD /* libBVLinearGradient.a */; }; 7F43D6401F6BFA82001FC614 /* libRCTPushNotification.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F63D2811E6C957C001FAE12 /* libRCTPushNotification.a */; }; + 7F50C96A203C6E80007CA374 /* SessionManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 7F50C969203C6E80007CA374 /* SessionManager.m */; }; + 7F50C96B203C6E80007CA374 /* SessionManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 7F50C969203C6E80007CA374 /* SessionManager.m */; }; 7F6877B31E7836070094B63F /* libToolTipMenu.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F6877B01E7835E50094B63F /* libToolTipMenu.a */; }; 7F6C47A51FE87E8C00F5A912 /* PerformRequests.m in Sources */ = {isa = PBXBuildFile; fileRef = 7F6C47A41FE87E8C00F5A912 /* PerformRequests.m */; }; 7F7D7F98201645E100D31155 /* libReactNativePermissions.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F7D7F87201645D300D31155 /* libReactNativePermissions.a */; }; @@ -693,6 +695,8 @@ 7F380D0A1FDB28160061AAD2 /* MattermostShare.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = MattermostShare.entitlements; sourceTree = ""; }; 7F43D5DF1F6BF994001FC614 /* libRNSVG.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libRNSVG.a; path = "../../../../../../../Library/Developer/Xcode/DerivedData/Mattermost-czlinsdviifujheezzjvmisotjrm/Build/Products/Debug-iphonesimulator/libRNSVG.a"; sourceTree = ""; }; 7F43D6051F6BF9EB001FC614 /* libPods-Mattermost.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = "libPods-Mattermost.a"; path = "../../../../../../../Library/Developer/Xcode/DerivedData/Mattermost-czlinsdviifujheezzjvmisotjrm/Build/Products/Debug-iphonesimulator/libPods-Mattermost.a"; sourceTree = ""; }; + 7F50C968203C6E80007CA374 /* SessionManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SessionManager.h; sourceTree = ""; }; + 7F50C969203C6E80007CA374 /* SessionManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SessionManager.m; sourceTree = ""; }; 7F63D27B1E6C957C001FAE12 /* RCTPushNotification.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTPushNotification.xcodeproj; path = "../node_modules/react-native/Libraries/PushNotificationIOS/RCTPushNotification.xcodeproj"; sourceTree = ""; }; 7F63D2C21E6DD98A001FAE12 /* Mattermost.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; name = Mattermost.entitlements; path = Mattermost/Mattermost.entitlements; sourceTree = ""; }; 7F6877AA1E7835E50094B63F /* ToolTipMenu.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = ToolTipMenu.xcodeproj; path = "../node_modules/react-native-tooltip/ToolTipMenu.xcodeproj"; sourceTree = ""; }; @@ -1286,6 +1290,8 @@ 7FFE32A21FD9CB650038C7A0 /* Info.plist */, 7F6C47A31FE87E8C00F5A912 /* PerformRequests.h */, 7F6C47A41FE87E8C00F5A912 /* PerformRequests.m */, + 7F50C968203C6E80007CA374 /* SessionManager.h */, + 7F50C969203C6E80007CA374 /* SessionManager.m */, ); path = MattermostShare; sourceTree = ""; @@ -2341,6 +2347,7 @@ 13B07FC11A68108700A75B9A /* main.m in Sources */, 7FF7BE6D1FDEE5E8005E55FE /* MattermostBucket.m in Sources */, 7FEB10981F6101710039A015 /* BlurAppScreen.m in Sources */, + 7F50C96A203C6E80007CA374 /* SessionManager.m in Sources */, 7FEB109D1F61019C0039A015 /* MattermostManaged.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -2349,6 +2356,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 7F50C96B203C6E80007CA374 /* SessionManager.m in Sources */, 7FF7BE6E1FDEE5E8005E55FE /* MattermostBucket.m in Sources */, 7FF7BE2C1FDEE4AE005E55FE /* MattermostManaged.m in Sources */, 7FFE329E1FD9CB650038C7A0 /* ShareViewController.m in Sources */, diff --git a/ios/Mattermost/AppDelegate.m b/ios/Mattermost/AppDelegate.m index 1f7db23b9..49c3c621e 100644 --- a/ios/Mattermost/AppDelegate.m +++ b/ios/Mattermost/AppDelegate.m @@ -19,6 +19,7 @@ #import "Orientation.h" #import "RCCManager.h" #import "RNNotifications.h" +#import "SessionManager.h" @implementation AppDelegate @@ -78,4 +79,9 @@ [RNNotifications handleActionWithIdentifier:identifier forRemoteNotification:userInfo withResponseInfo:responseInfo completionHandler:completionHandler]; } +-(void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(nonnull NSString *)identifier completionHandler:(nonnull void (^)(void))completionHandler { + [SessionManager sharedSession].savedCompletionHandler = completionHandler; + [[SessionManager sharedSession] createSessionForRequestRequest:identifier]; +} + @end diff --git a/ios/MattermostShare/PerformRequests.h b/ios/MattermostShare/PerformRequests.h index 471c90213..748f887ae 100644 --- a/ios/MattermostShare/PerformRequests.h +++ b/ios/MattermostShare/PerformRequests.h @@ -1,11 +1,3 @@ -// -// PerformRequests.h -// MattermostShare -// -// Created by Elias Nahum on 12/18/17. -// Copyright © 2017 Facebook. All rights reserved. -// - #import #import "MattermostBucket.h" diff --git a/ios/MattermostShare/PerformRequests.m b/ios/MattermostShare/PerformRequests.m index 8cc3639b9..3d582406d 100644 --- a/ios/MattermostShare/PerformRequests.m +++ b/ios/MattermostShare/PerformRequests.m @@ -1,14 +1,6 @@ -// -// PerformRequests.m -// MattermostShare -// -// Created by Elias Nahum on 12/18/17. -// Copyright © 2017 Facebook. All rights reserved. -// - #import "PerformRequests.h" #import "MattermostBucket.h" -#import "ShareViewController.h" +#import "SessionManager.h" @implementation PerformRequests @@ -141,7 +133,7 @@ } - (void) cleanUpTempFiles { - NSURL *tmpDirectoryURL = [ShareViewController tempContainerURL:self.appGroupId]; + NSURL *tmpDirectoryURL = [[SessionManager sharedSession] tempContainerURL:self.appGroupId]; if (tmpDirectoryURL == nil) { return; } diff --git a/ios/MattermostShare/SessionManager.h b/ios/MattermostShare/SessionManager.h new file mode 100644 index 000000000..53823aed1 --- /dev/null +++ b/ios/MattermostShare/SessionManager.h @@ -0,0 +1,15 @@ +#import +#import "MattermostBucket.h" + +@interface SessionManager : NSObject +@property (nonatomic, copy) void (^savedCompletionHandler)(void); +@property MattermostBucket *bucket; + + ++(instancetype)sharedSession; +-(NSString *)getAppGroupIdFromRequestIdentifier:(NSString *) requestWithGroup; +-(NSURLSession *)createSessionForRequestRequest:(NSString *)requestId; +-(void)setDataForRequest:(NSDictionary *)data forRequestWithGroup:(NSString *)requestId; +-(void)createPostForRequest:(NSString *)requestId; +-(NSURL*)tempContainerURL:(NSString*)appGroupId; +@end diff --git a/ios/MattermostShare/SessionManager.m b/ios/MattermostShare/SessionManager.m new file mode 100644 index 000000000..ae0e82387 --- /dev/null +++ b/ios/MattermostShare/SessionManager.m @@ -0,0 +1,218 @@ +#import "SessionManager.h" +#import "MattermostBucket.h" + +@implementation SessionManager ++ (instancetype)sharedSession { + static id sharedMyManager = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sharedMyManager = [[self alloc] init]; + }); + return sharedMyManager; +} + +- (instancetype)init { + self = [super init]; + if (self) { + self.bucket = [[MattermostBucket alloc] init]; + } + return self; +} + +-(NSString *)getAppGroupIdFromRequestIdentifier:(NSString *) requestWithGroup { + return [requestWithGroup componentsSeparatedByString:@"|"][1]; +} + +-(void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session { + if (self.savedCompletionHandler) { + self.savedCompletionHandler(); + self.savedCompletionHandler = nil; + } +} + +-(void)URLSession:(NSURLSession *)session task:(NSURLSessionDataTask *)task didCompleteWithError:(nullable NSError *)error { + NSString *requestWithGroup = [[session configuration] identifier]; + + if(error != nil) { + NSLog(@"ERROR %@", [error userInfo]); + NSLog(@"invalidating session %@", requestWithGroup); + [session invalidateAndCancel]; + } else if (requestWithGroup != nil) { + NSString *appGroupId = [self getAppGroupIdFromRequestIdentifier:requestWithGroup]; + NSURL *requestUrl = [[task originalRequest] URL]; + + NSDictionary *data = [self getDataForRequest:requestWithGroup]; + NSArray *files = [data objectForKey:@"files"]; + NSMutableArray *fileIds = [data objectForKey:@"file_ids"]; + + if ([[requestUrl absoluteString] containsString:@"files"] && + [files count] == [fileIds count]) { + [self sendPostRequestForId:requestWithGroup]; + [[self.bucket bucketByName:appGroupId] removeObjectForKey:requestWithGroup]; + } + } +} + +-(void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data { + NSString *requestWithGroup = [[session configuration] identifier]; + NSURL *requestUrl = [[dataTask originalRequest] URL]; + + if ([[requestUrl absoluteString] containsString:@"files"]) { + NSString *appGroupId = [self getAppGroupIdFromRequestIdentifier:requestWithGroup]; + NSError *error; + NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error]; + if (error == nil && json != nil) { + NSArray *fileInfos = [json objectForKey:@"file_infos"]; + NSDictionary *dataFromBucket = [self getDataForRequest:requestWithGroup]; + NSMutableDictionary *data = [dataFromBucket mutableCopy]; + NSMutableArray *fileIds = [[data objectForKey:@"file_ids"] mutableCopy]; + if (fileIds == nil && data != nil) { + fileIds = [[NSMutableArray alloc] init]; + } + + for (id file in fileInfos) { + [fileIds addObject:[file objectForKey:@"id"]]; + NSString * filename = [file objectForKey:@"name"]; + NSLog(@"got file id %@ %@", [file objectForKey:@"id"], filename); + NSURL *tempContainerURL = [self tempContainerURL:appGroupId]; + NSURL *destinationURL = [tempContainerURL URLByAppendingPathComponent: filename]; + [[NSFileManager defaultManager] removeItemAtURL:destinationURL error:nil]; + } + [data setObject:fileIds forKey:@"file_ids"]; + [self setDataForRequest:data forRequestWithGroup:requestWithGroup]; + } + } +} + +-(void)setDataForRequest:(NSDictionary *)data forRequestWithGroup:(NSString *)requestWithGroup { + NSString *appGroupId = [self getAppGroupIdFromRequestIdentifier:requestWithGroup]; + [[self.bucket bucketByName:appGroupId] setObject:data forKey:requestWithGroup]; +} + +-(NSDictionary *)getDataForRequest:(NSString *)requestWithGroup { + NSString *appGroupId = [self getAppGroupIdFromRequestIdentifier:requestWithGroup]; + return [[self.bucket bucketByName:appGroupId] objectForKey:requestWithGroup]; +} + +-(NSURLSession *)createSessionForRequestRequest:(NSString *)requestWithGroup { + NSString *appGroupId = [self getAppGroupIdFromRequestIdentifier:requestWithGroup]; + NSURLSessionConfiguration* config = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:requestWithGroup]; + config.sharedContainerIdentifier = appGroupId; + return [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:nil]; +} + +-(NSDictionary *)getCredentialsForRequest:(NSString *)requestWithGroup { + NSString * appGroupId = [self getAppGroupIdFromRequestIdentifier:requestWithGroup]; + NSString *entitiesString = [self.bucket readFromFile:@"entities" appGroupId:appGroupId]; + NSData *entitiesData = [entitiesString dataUsingEncoding:NSUTF8StringEncoding]; + NSError *error; + NSDictionary *entities = [NSJSONSerialization JSONObjectWithData:entitiesData options:NSJSONReadingMutableContainers error:&error]; + if (error != nil) { + return nil; + } + return [[entities objectForKey:@"general"] objectForKey:@"credentials"]; +} + +-(void)createPostForRequest:(NSString *)requestWithGroup { + NSDictionary *data = [self getDataForRequest:requestWithGroup]; + NSDictionary *post = [data objectForKey:@"post"]; + NSArray *files = [data objectForKey:@"files"]; + + if (files != nil && [files count] > 0) { + NSString *channelId = [post objectForKey:@"channel_id"]; + NSDictionary *credentials = [self getCredentialsForRequest:requestWithGroup]; + NSString *appGroupId = [self getAppGroupIdFromRequestIdentifier:requestWithGroup]; + + if (credentials == nil) { + return; + } + + NSString *serverUrl = [credentials objectForKey:@"url"]; + NSString *token = [credentials objectForKey:@"token"]; + NSURLSession *session = [self createSessionForRequestRequest:requestWithGroup]; + + for (id file in files) { + NSURL *filePath = [NSURL fileURLWithPath:[file objectForKey:@"filePath"]]; + NSString *fileName = [file objectForKey:@"filename"]; + + NSError *err; + NSURL *tempContainerURL = [self tempContainerURL:appGroupId]; + NSURL *destinationURL = [tempContainerURL URLByAppendingPathComponent: fileName]; + BOOL bVal = [[NSFileManager defaultManager] copyItemAtURL:filePath toURL:destinationURL error:&err]; + + NSCharacterSet *allowedCharacters = [NSCharacterSet URLQueryAllowedCharacterSet]; + NSString *encodedFilename = [[file objectForKey:@"filename"] stringByAddingPercentEncodingWithAllowedCharacters:allowedCharacters]; + NSString *url = [serverUrl stringByAppendingString:@"/api/v4/files"]; + NSString *queryString = [NSString stringWithFormat:@"?channel_id=%@&filename=%@", channelId, encodedFilename]; + NSURL *filesUrl = [NSURL URLWithString:[url stringByAppendingString:queryString]]; + NSMutableURLRequest *uploadRequest = [NSMutableURLRequest requestWithURL:filesUrl cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:120.0]; + [uploadRequest setHTTPMethod:@"POST"]; + [uploadRequest setValue:[@"Bearer " stringByAppendingString:token] forHTTPHeaderField:@"Authorization"]; + [uploadRequest setValue:@"application/json" forHTTPHeaderField:@"Accept"]; + + NSURLSessionUploadTask *task = [session uploadTaskWithRequest:uploadRequest fromFile:destinationURL]; + NSLog(@"Executing file request %@", fileName); + [task resume]; + } + } else { + [self sendPostRequestForId:requestWithGroup]; + } +} + +-(void)sendPostRequestForId:(NSString *)requestWithGroup { + NSDictionary *data = [self getDataForRequest:requestWithGroup]; + NSDictionary *credentials = [self getCredentialsForRequest:requestWithGroup]; + + if (credentials == nil) { + return; + } + + NSString *serverUrl = [credentials objectForKey:@"url"]; + NSString *token = [credentials objectForKey:@"token"]; + NSMutableDictionary *post = [[data objectForKey:@"post"] mutableCopy]; + NSArray *fileIds = [data objectForKey:@"file_ids"]; + + if (fileIds != nil && [fileIds count] > 0) { + [post setObject:fileIds forKey:@"file_ids"]; + } + + NSError *error; + NSData *postData = [NSJSONSerialization dataWithJSONObject:post options:NSJSONWritingPrettyPrinted error:&error]; + + if (error == nil) { + NSString* postAsString = [[NSString alloc] initWithData:postData encoding:NSUTF8StringEncoding]; + + NSURL *createUrl = [NSURL URLWithString:[serverUrl stringByAppendingString:@"/api/v4/posts"]]; + + NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:createUrl cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:5.0]; + [request setHTTPMethod:@"POST"]; + [request setValue:[@"Bearer " stringByAppendingString:token] forHTTPHeaderField:@"Authorization"]; + [request setValue:@"application/json" forHTTPHeaderField:@"Accept"]; + [request setValue:@"application/json; charset=utf-8" forHTTPHeaderField:@"Content-Type"]; + [request setHTTPBody:[postAsString dataUsingEncoding:NSUTF8StringEncoding]]; + + NSURLSessionConfiguration* config = [NSURLSessionConfiguration ephemeralSessionConfiguration]; + NSURLSession *createSession = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:nil]; + NSURLSessionDataTask *createTask = [createSession dataTaskWithRequest:request]; + NSLog(@"Executing post request"); + [createTask resume]; + } +} + +-(NSURL*)tempContainerURL:(NSString*)appGroupId { + NSFileManager *manager = [NSFileManager defaultManager]; + NSURL *containerURL = [manager containerURLForSecurityApplicationGroupIdentifier:appGroupId]; + NSURL *tempDirectoryURL = [containerURL URLByAppendingPathComponent:@"shareTempItems"]; + if (![manager fileExistsAtPath:[tempDirectoryURL path]]) { + NSError *err; + [manager createDirectoryAtURL:tempDirectoryURL withIntermediateDirectories:YES attributes:nil error:&err]; + if (err) { + return nil; + } + } + + return tempDirectoryURL; +} + + +@end diff --git a/ios/MattermostShare/ShareViewController.h b/ios/MattermostShare/ShareViewController.h index ade93ce22..390c05d41 100644 --- a/ios/MattermostShare/ShareViewController.h +++ b/ios/MattermostShare/ShareViewController.h @@ -2,5 +2,4 @@ #import "React/RCTBridgeModule.h" @interface ShareViewController : UIViewController -+ (NSURL*) tempContainerURL: (NSString*)appGroupId; @end diff --git a/ios/MattermostShare/ShareViewController.m b/ios/MattermostShare/ShareViewController.m index c3699f174..ff9797715 100644 --- a/ios/MattermostShare/ShareViewController.m +++ b/ios/MattermostShare/ShareViewController.m @@ -2,6 +2,7 @@ #import #import #import "PerformRequests.h" +#import "SessionManager.h" NSExtensionContext* extensionContext; @@ -49,12 +50,24 @@ RCT_REMAP_METHOD(getOrientation, RCT_EXPORT_METHOD(close:(NSDictionary *)data appGroupId:(NSString *)appGroupId) { if (data != nil) { - NSDictionary *post = [data objectForKey:@"post"]; - NSArray *files = [data objectForKey:@"files"]; NSString *requestId = [data objectForKey:@"requestId"]; - NSLog(@"Call createPost"); - PerformRequests *request = [[PerformRequests alloc] initWithPost:post withFiles:files forRequestId:requestId inAppGroupId:appGroupId inContext:extensionContext]; - [request createPost]; + NSString *useBackgroundUpload = [data objectForKey:@"useBackgroundUpload"]; + BOOL isBackgroundUpload = useBackgroundUpload ? [useBackgroundUpload boolValue] : NO; + + if (isBackgroundUpload) { + NSString *requestWithGroup = [NSString stringWithFormat:@"%@|%@", requestId, appGroupId]; + [[SessionManager sharedSession] setDataForRequest:data forRequestWithGroup:requestWithGroup]; + [[SessionManager sharedSession] createPostForRequest:requestWithGroup]; + + [extensionContext completeRequestReturningItems:nil + completionHandler:nil]; + NSLog(@"Extension closed"); + } else { + NSDictionary *post = [data objectForKey:@"post"]; + NSArray *files = [data objectForKey:@"files"]; + PerformRequests *request = [[PerformRequests alloc] initWithPost:post withFiles:files forRequestId:requestId inAppGroupId:appGroupId inContext:extensionContext]; + [request createPost]; + } } else { [extensionContext completeRequestReturningItems:nil completionHandler:nil]; @@ -152,7 +165,7 @@ typedef void (^ProviderCallback)(NSString *content, NSString *contentType, BOOL } else if ([item isKindOfClass: UIImage.class]) { UIImage *image = (UIImage *)item; NSString *fileName = [NSString stringWithFormat:@"%@.jpg", [[NSUUID UUID] UUIDString]]; - NSURL *tempContainerURL = [ShareViewController tempContainerURL:appGroupId]; + NSURL *tempContainerURL = [[SessionManager sharedSession] tempContainerURL:appGroupId]; if (tempContainerURL == nil){ return callback(nil, nil, NO, nil); } @@ -168,7 +181,7 @@ typedef void (^ProviderCallback)(NSString *content, NSString *contentType, BOOL NSString *fileName = [NSString stringWithFormat:@"%@.jpg", [[NSUUID UUID] UUIDString]]; NSData *data = (NSData *)item; UIImage *image = [UIImage imageWithData:data]; - NSURL *tempContainerURL = [ShareViewController tempContainerURL:appGroupId]; + NSURL *tempContainerURL = [[SessionManager sharedSession] tempContainerURL:appGroupId]; if (tempContainerURL == nil){ return callback(nil, nil, NO, nil); } @@ -255,19 +268,4 @@ typedef void (^ProviderCallback)(NSString *content, NSString *contentType, BOOL callback(nil, nil, NO, nil); } - -+ (NSURL*) tempContainerURL: (NSString*)appGroupId { - NSFileManager *manager = [NSFileManager defaultManager]; - NSURL *containerURL = [manager containerURLForSecurityApplicationGroupIdentifier: appGroupId]; - NSURL *tempDirectoryURL = [containerURL URLByAppendingPathComponent:@"shareTempItems"]; - if (![manager fileExistsAtPath:[tempDirectoryURL path]]) { - NSError *err; - [manager createDirectoryAtURL:tempDirectoryURL withIntermediateDirectories:YES attributes:nil error:&err]; - if (err) { - return nil; - } - } - - return tempDirectoryURL; -} @end diff --git a/share_extension/ios/extension_post.js b/share_extension/ios/extension_post.js index 866f0ff99..91295c0e6 100644 --- a/share_extension/ios/extension_post.js +++ b/share_extension/ios/extension_post.js @@ -24,6 +24,7 @@ import {Client4} from 'mattermost-redux/client'; import {General} from 'mattermost-redux/constants'; import {getChannel} from 'mattermost-redux/selectors/entities/channels'; import {getFormattedFileSize, lookupMimeType} from 'mattermost-redux/utils/file_utils'; +import {isMinimumServerVersion} from 'mattermost-redux/utils/helpers'; import mattermostBucket from 'app/mattermost_bucket'; import {generateId, getAllowedServerMaxFileSize} from 'app/utils/file'; @@ -76,13 +77,16 @@ export default class ExtensionPost extends PureComponent { const {height, width} = Dimensions.get('window'); const isLandscape = width > height; + const entities = props.entities; + + this.useBackgroundUpload = props.authenticated ? isMinimumServerVersion(entities.general.serverVersion, 4, 8) : false; this.state = { - entities: props.entities, + entities, error: null, files: [], isLandscape, - totalSize: 0, + exceededSize: 0, value: '', sending: false, }; @@ -185,17 +189,21 @@ export default class ExtensionPost extends PureComponent { loadData = async () => { const {entities} = this.state; + if (this.props.authenticated) { try { - const {credentials} = entities.general; + const {config, credentials} = entities.general; const {currentUserId} = entities.users; const team = entities.teams.teams[entities.teams.currentTeamId]; let channel = entities.channels.channels[entities.channels.currentChannelId]; const items = await ShareExtension.data(Config.AppGroupId); + const serverMaxFileSize = getAllowedServerMaxFileSize(config); + const maxSize = Math.min(MAX_FILE_SIZE, serverMaxFileSize); const text = []; const urls = []; const files = []; let totalSize = 0; + let exceededSize = false; if (channel.type === General.GM_CHANNEL || channel.type === General.DM_CHANNEL) { channel = getChannel({entities}, channel.id); @@ -217,7 +225,13 @@ export default class ExtensionPost extends PureComponent { const filename = fullPath.replace(/^.*[\\/]/, ''); const extension = filename.split('.').pop(); - totalSize += fileSize.size; + if (this.useBackgroundUpload) { + if (!exceededSize) { + exceededSize = fileSize.size >= maxSize; + } + } else { + totalSize += fileSize.size; + } files.push({ extension, filename, @@ -240,7 +254,12 @@ export default class ExtensionPost extends PureComponent { Client4.setUrl(credentials.url); Client4.setToken(credentials.token); Client4.setUserId(currentUserId); - this.setState({channel, files, team, value, totalSize}); + + if (!this.useBackgroundUpload) { + exceededSize = totalSize >= maxSize; + } + + this.setState({channel, files, team, value, exceededSize}); } catch (error) { this.setState({error}); } @@ -263,7 +282,7 @@ export default class ExtensionPost extends PureComponent { renderBody = (styles) => { const {formatMessage} = this.context.intl; const {authenticated, theme} = this.props; - const {entities, error, sending, totalSize, value} = this.state; + const {entities, error, sending, exceededSize, value} = this.state; const {config} = entities.general; const serverMaxFileSize = getAllowedServerMaxFileSize(config); const maxSize = Math.min(MAX_FILE_SIZE, serverMaxFileSize); @@ -282,7 +301,7 @@ export default class ExtensionPost extends PureComponent { ); } - if (totalSize >= maxSize) { + if (exceededSize) { return ( @@ -563,7 +582,8 @@ export default class ExtensionPost extends PureComponent { const data = { files, post, - requestId: generateId(), + requestId: generateId().replace(/-/g, ''), + useBackgroundUpload: this.useBackgroundUpload, }; this.setState({sending: true});