Skip to content

Commit

Permalink
feat: add ParseFileTransferable protocol for direct file uploads (#410)
Browse files Browse the repository at this point in the history
* feat: add ParseFileTransferable protocol for direct uploads to file storage

* nit
  • Loading branch information
cbaker6 authored Sep 13, 2022
1 parent 378b81a commit 9ab5271
Show file tree
Hide file tree
Showing 13 changed files with 154 additions and 26 deletions.
7 changes: 6 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
# Parse-Swift Changelog

### main
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/4.10.0...main)
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/4.12.0...main)
* _Contributing to this repo? Add info about your change here to be included in the next release_

### 4.12.0
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/4.11.0...4.12.0)

__New features__
- Add the ParseFileTransferable protocol for overriding the default transfer behavior for ParseFile's. Allows for direct uploads to other file storage
providers ([#408](https://github.com/parse-community/Parse-Swift/pull/408)), thanks to [Corey Baker](https://github.com/cbaker6).
- Add the become method to ParseInstallation which allows any ParseInstallation to be copied to the current installation. This method can be used to migrate any ParseInstallation to the current installation in the Swift SDK ([#407](https://github.com/parse-community/Parse-Swift/pull/407)), thanks to [Corey Baker](https://github.com/cbaker6).

__Fixes__
Expand Down
20 changes: 20 additions & 0 deletions ParseSwift.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,14 @@
704C886D28BE69A8008E6B01 /* ParseConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 704C886B28BE69A8008E6B01 /* ParseConfiguration.swift */; };
704C886E28BE69A8008E6B01 /* ParseConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 704C886B28BE69A8008E6B01 /* ParseConfiguration.swift */; };
704C886F28BE69A8008E6B01 /* ParseConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 704C886B28BE69A8008E6B01 /* ParseConfiguration.swift */; };
704E781728CFD8A00075F952 /* ParseFileTransferable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 704E781628CFD8A00075F952 /* ParseFileTransferable.swift */; };
704E781828CFD8A00075F952 /* ParseFileTransferable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 704E781628CFD8A00075F952 /* ParseFileTransferable.swift */; };
704E781928CFD8A00075F952 /* ParseFileTransferable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 704E781628CFD8A00075F952 /* ParseFileTransferable.swift */; };
704E781A28CFD8A00075F952 /* ParseFileTransferable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 704E781628CFD8A00075F952 /* ParseFileTransferable.swift */; };
704E781C28CFFAF80075F952 /* ParseFileDefaultTransfer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 704E781B28CFFAF80075F952 /* ParseFileDefaultTransfer.swift */; };
704E781D28CFFAF80075F952 /* ParseFileDefaultTransfer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 704E781B28CFFAF80075F952 /* ParseFileDefaultTransfer.swift */; };
704E781E28CFFAF80075F952 /* ParseFileDefaultTransfer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 704E781B28CFFAF80075F952 /* ParseFileDefaultTransfer.swift */; };
704E781F28CFFAF80075F952 /* ParseFileDefaultTransfer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 704E781B28CFFAF80075F952 /* ParseFileDefaultTransfer.swift */; };
705025992842FD3B008D6624 /* ParseCLPTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 705025982842FD3B008D6624 /* ParseCLPTests.swift */; };
7050259A2842FD3B008D6624 /* ParseCLPTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 705025982842FD3B008D6624 /* ParseCLPTests.swift */; };
7050259B2842FD3B008D6624 /* ParseCLPTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 705025982842FD3B008D6624 /* ParseCLPTests.swift */; };
Expand Down Expand Up @@ -1234,6 +1242,8 @@
7045769726BD917500F86F71 /* Query+async.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Query+async.swift"; sourceTree = "<group>"; };
7045769C26BD934000F86F71 /* ParseFile+async.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ParseFile+async.swift"; sourceTree = "<group>"; };
704C886B28BE69A8008E6B01 /* ParseConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseConfiguration.swift; sourceTree = "<group>"; };
704E781628CFD8A00075F952 /* ParseFileTransferable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseFileTransferable.swift; sourceTree = "<group>"; };
704E781B28CFFAF80075F952 /* ParseFileDefaultTransfer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseFileDefaultTransfer.swift; sourceTree = "<group>"; };
705025982842FD3B008D6624 /* ParseCLPTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseCLPTests.swift; sourceTree = "<group>"; };
7050259C2843F0CF008D6624 /* ParseSchemaAsyncTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseSchemaAsyncTests.swift; sourceTree = "<group>"; };
705025A02843F0E7008D6624 /* ParseSchemaCombineTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseSchemaCombineTests.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1790,6 +1800,7 @@
703B090626BD9764005A112F /* ParseCloud+async.swift */,
7044C17425C4ECFF0011F6E7 /* ParseCloud+combine.swift */,
70647E9B259E3A9A004C1004 /* ParseEncodable.swift */,
704E781628CFD8A00075F952 /* ParseFileTransferable.swift */,
70CE0AB6285A83B100DAEA86 /* ParseHookable.swift */,
70385E752858E1000084D306 /* ParseHookFunctionable.swift */,
70CE0AC0285FD59B00DAEA86 /* ParseHookFunctionable+async.swift */,
Expand Down Expand Up @@ -2124,6 +2135,7 @@
F97B45C124D9C6F200F4A88B /* ParseFile.swift */,
7045769C26BD934000F86F71 /* ParseFile+async.swift */,
7044C19025C4F5B60011F6E7 /* ParseFile+combine.swift */,
704E781B28CFFAF80075F952 /* ParseFileDefaultTransfer.swift */,
F97B45BC24D9C6F200F4A88B /* ParseGeoPoint.swift */,
70F79A182639CE6F00731C46 /* ParseHealth.swift */,
703B08FC26BD953B005A112F /* ParseHealth+async.swift */,
Expand Down Expand Up @@ -2707,6 +2719,7 @@
705025E628514F36008D6624 /* ParsePushPayloadAny.swift in Sources */,
709A148228395ED100BF85E5 /* ParseSchema+async.swift in Sources */,
705025D1284CFCDE008D6624 /* ParsePushAppleAlert.swift in Sources */,
704E781C28CFFAF80075F952 /* ParseFileDefaultTransfer.swift in Sources */,
7045769826BD917500F86F71 /* Query+async.swift in Sources */,
703B094E26BF47E3005A112F /* ParseTwitter+combine.swift in Sources */,
70386A3825D998D90048EC1B /* ParseLDAP.swift in Sources */,
Expand Down Expand Up @@ -2765,6 +2778,7 @@
707A3C2025B14BD0000D215C /* ParseApple.swift in Sources */,
703B095D26BF481F005A112F /* ParseFacebook+async.swift in Sources */,
709A147D283949D100BF85E5 /* ParseSchema.swift in Sources */,
704E781728CFD8A00075F952 /* ParseFileTransferable.swift in Sources */,
F97B462224D9C6F200F4A88B /* ParseKeyValueStore.swift in Sources */,
703B090226BD9652005A112F /* ParseAnalytics+async.swift in Sources */,
703B093F26BF47AC005A112F /* ParseApple+async.swift in Sources */,
Expand Down Expand Up @@ -3016,6 +3030,7 @@
705025E728514F36008D6624 /* ParsePushPayloadAny.swift in Sources */,
709A148328395ED100BF85E5 /* ParseSchema+async.swift in Sources */,
705025D2284CFCDE008D6624 /* ParsePushAppleAlert.swift in Sources */,
704E781D28CFFAF80075F952 /* ParseFileDefaultTransfer.swift in Sources */,
703B094F26BF47E3005A112F /* ParseTwitter+combine.swift in Sources */,
70386A3925D998D90048EC1B /* ParseLDAP.swift in Sources */,
700395F325A171320052CB31 /* LiveQueryable.swift in Sources */,
Expand Down Expand Up @@ -3074,6 +3089,7 @@
703B095E26BF481F005A112F /* ParseFacebook+async.swift in Sources */,
F97B462324D9C6F200F4A88B /* ParseKeyValueStore.swift in Sources */,
709A147E283949D100BF85E5 /* ParseSchema.swift in Sources */,
704E781828CFD8A00075F952 /* ParseFileTransferable.swift in Sources */,
703B090326BD9652005A112F /* ParseAnalytics+async.swift in Sources */,
703B094026BF47AC005A112F /* ParseApple+async.swift in Sources */,
F97B45E724D9C6F200F4A88B /* Query.swift in Sources */,
Expand Down Expand Up @@ -3457,6 +3473,7 @@
705025E928514F36008D6624 /* ParsePushPayloadAny.swift in Sources */,
709A148528395ED100BF85E5 /* ParseSchema+async.swift in Sources */,
705025D4284CFCDE008D6624 /* ParsePushAppleAlert.swift in Sources */,
704E781F28CFFAF80075F952 /* ParseFileDefaultTransfer.swift in Sources */,
7045769B26BD917500F86F71 /* Query+async.swift in Sources */,
703B095126BF47E3005A112F /* ParseTwitter+combine.swift in Sources */,
70386A3B25D998D90048EC1B /* ParseLDAP.swift in Sources */,
Expand Down Expand Up @@ -3515,6 +3532,7 @@
703B096026BF481F005A112F /* ParseFacebook+async.swift in Sources */,
F97B462124D9C6F200F4A88B /* ParseStorage.swift in Sources */,
709A1480283949D100BF85E5 /* ParseSchema.swift in Sources */,
704E781A28CFD8A00075F952 /* ParseFileTransferable.swift in Sources */,
703B090526BD9652005A112F /* ParseAnalytics+async.swift in Sources */,
703B094226BF47AC005A112F /* ParseApple+async.swift in Sources */,
F97B466724D9C88600F4A88B /* SecureStorage.swift in Sources */,
Expand Down Expand Up @@ -3643,6 +3661,7 @@
705025E828514F36008D6624 /* ParsePushPayloadAny.swift in Sources */,
709A148428395ED100BF85E5 /* ParseSchema+async.swift in Sources */,
705025D3284CFCDE008D6624 /* ParsePushAppleAlert.swift in Sources */,
704E781E28CFFAF80075F952 /* ParseFileDefaultTransfer.swift in Sources */,
7045769A26BD917500F86F71 /* Query+async.swift in Sources */,
703B095026BF47E3005A112F /* ParseTwitter+combine.swift in Sources */,
70386A3A25D998D90048EC1B /* ParseLDAP.swift in Sources */,
Expand Down Expand Up @@ -3701,6 +3720,7 @@
703B095F26BF481F005A112F /* ParseFacebook+async.swift in Sources */,
F97B462024D9C6F200F4A88B /* ParseStorage.swift in Sources */,
709A147F283949D100BF85E5 /* ParseSchema.swift in Sources */,
704E781928CFD8A00075F952 /* ParseFileTransferable.swift in Sources */,
703B090426BD9652005A112F /* ParseAnalytics+async.swift in Sources */,
703B094126BF47AC005A112F /* ParseApple+async.swift in Sources */,
F97B466624D9C88600F4A88B /* SecureStorage.swift in Sources */,
Expand Down
4 changes: 2 additions & 2 deletions Sources/ParseSwift/Documentation.docc/ParseSwift.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ To learn how to use or experiment with ParseSwift, you can run and edit the [Par
### Configure SDK

- ``ParseSwift/initialize(configuration:)``
- ``ParseSwift/initialize(applicationId:clientKey:masterKey:serverURL:liveQueryServerURL:allowingCustomObjectIds:usingTransactions:usingEqualQueryConstraint:usingPostForQuery:keyValueStore:requestCachePolicy:cacheMemoryCapacity:cacheDiskCapacity:usingDataProtectionKeychain:deletingKeychainIfNeeded:httpAdditionalHeaders:maxConnectionAttempts:authentication:)``
- ``ParseSwift/initialize(applicationId:clientKey:masterKey:serverURL:liveQueryServerURL:allowingCustomObjectIds:usingTransactions:usingEqualQueryConstraint:usingPostForQuery:keyValueStore:requestCachePolicy:cacheMemoryCapacity:cacheDiskCapacity:migratingFromObjcSDK:usingDataProtectionKeychain:deletingKeychainIfNeeded:httpAdditionalHeaders:maxConnectionAttempts:authentication:)``
- ``ParseSwift/initialize(applicationId:clientKey:masterKey:serverURL:liveQueryServerURL:allowingCustomObjectIds:usingTransactions:usingEqualQueryConstraint:usingPostForQuery:keyValueStore:requestCachePolicy:cacheMemoryCapacity:cacheDiskCapacity:usingDataProtectionKeychain:deletingKeychainIfNeeded:httpAdditionalHeaders:maxConnectionAttempts:parseFileTransfer:authentication:)``
- ``ParseSwift/initialize(applicationId:clientKey:masterKey:serverURL:liveQueryServerURL:allowingCustomObjectIds:usingTransactions:usingEqualQueryConstraint:usingPostForQuery:keyValueStore:requestCachePolicy:cacheMemoryCapacity:cacheDiskCapacity:migratingFromObjcSDK:usingDataProtectionKeychain:deletingKeychainIfNeeded:httpAdditionalHeaders:maxConnectionAttempts:parseFileTransfer:authentication:)``
- ``ParseSwift/configuration``
- ``ParseSwift/setAccessGroup(_:synchronizeAcrossDevices:)``
- ``ParseSwift/updateAuthentication(_:)``
Expand Down
33 changes: 20 additions & 13 deletions Sources/ParseSwift/Extensions/URLSession.swift
Original file line number Diff line number Diff line change
Expand Up @@ -226,15 +226,21 @@ internal extension URLSession {
) {
var task: URLSessionTask?
if let data = data {
task = uploadTask(with: request, from: data) { (responseData, urlResponse, responseError) in
task = ParseSwift
.configuration
.parseFileTransfer
.upload(with: request, from: data) { (responseData, urlResponse, responseError) in
completion(self.makeResult(request: request,
responseData: responseData,
urlResponse: urlResponse,
responseError: responseError,
mapper: mapper))
}
} else if let file = file {
task = uploadTask(with: request, fromFile: file) { (responseData, urlResponse, responseError) in
task = ParseSwift
.configuration
.parseFileTransfer
.upload(with: request, fromFile: file) { (responseData, urlResponse, responseError) in
completion(self.makeResult(request: request,
responseData: responseData,
urlResponse: urlResponse,
Expand All @@ -244,19 +250,20 @@ internal extension URLSession {
} else {
completion(.failure(ParseError(code: .unknownError, message: "data and file both cannot be nil")))
}
if let task = task {
#if compiler(>=5.5.2) && canImport(_Concurrency)
Task {
await Parse.sessionDelegate.delegates.updateUpload(task, callback: progress)
await Parse.sessionDelegate.delegates.updateTask(task, queue: notificationQueue)
task.resume()
}
#else
Parse.sessionDelegate.uploadDelegates[task] = progress
Parse.sessionDelegate.taskCallbackQueues[task] = notificationQueue
guard let task = task else {
return
}
#if compiler(>=5.5.2) && canImport(_Concurrency)
Task {
await Parse.sessionDelegate.delegates.updateUpload(task, callback: progress)
await Parse.sessionDelegate.delegates.updateTask(task, queue: notificationQueue)
task.resume()
#endif
}
#else
Parse.sessionDelegate.uploadDelegates[task] = progress
Parse.sessionDelegate.taskCallbackQueues[task] = notificationQueue
task.resume()
#endif
}

func downloadTask<U>(
Expand Down
2 changes: 1 addition & 1 deletion Sources/ParseSwift/Objects/ParseObject.swift
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,7 @@ public extension ParseObject {
/**
Set the value of a specific `KeyPath` on a `ParseObject`.
- parameter key: The `KeyPath` of the value to set.
- parameter to: The value to set the `KeyPath` to.
- parameter value: The value to set the `KeyPath` to.
- returns: The updated `ParseObject`.
- important: This method should be used when updating a `ParseObject` that has already been saved to
a Parse Server. You can also use this method on a new `ParseObject`'s that has not been saved to a Parse Server
Expand Down
12 changes: 12 additions & 0 deletions Sources/ParseSwift/Parse.swift
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,10 @@ public func initialize(configuration: ParseConfiguration) {
- parameter httpAdditionalHeaders: A dictionary of additional headers to send with requests. See Apple's
[documentation](https://developer.apple.com/documentation/foundation/urlsessionconfiguration/1411532-httpadditionalheaders)
for more info.
- parameter maxConnectionAttempts: Maximum number of times to try to connect to Parse Server.
Defaults to 5.
- parameter parseFileTransfer: Override the default transfer behavior for `ParseFile`'s.
Allows for direct uploads to other file storage providers.
- parameter authentication: A callback block that will be used to receive/accept/decline network challenges.
Defaults to `nil` in which the SDK will use the default OS authentication methods for challenges.
It should have the following argument signature: `(challenge: URLAuthenticationChallenge,
Expand Down Expand Up @@ -234,6 +238,7 @@ public func initialize(
deletingKeychainIfNeeded: Bool = false,
httpAdditionalHeaders: [AnyHashable: Any]? = nil,
maxConnectionAttempts: Int = 5,
parseFileTransfer: ParseFileTransferable? = nil,
authentication: ((URLAuthenticationChallenge,
(URLSession.AuthChallengeDisposition,
URLCredential?) -> Void) -> Void)? = nil
Expand All @@ -255,6 +260,7 @@ public func initialize(
deletingKeychainIfNeeded: deletingKeychainIfNeeded,
httpAdditionalHeaders: httpAdditionalHeaders,
maxConnectionAttempts: maxConnectionAttempts,
parseFileTransfer: parseFileTransfer,
authentication: authentication)
initialize(configuration: configuration)
}
Expand Down Expand Up @@ -292,6 +298,10 @@ public func initialize(
- parameter httpAdditionalHeaders: A dictionary of additional headers to send with requests. See Apple's
[documentation](https://developer.apple.com/documentation/foundation/urlsessionconfiguration/1411532-httpadditionalheaders)
for more info.
- parameter maxConnectionAttempts: Maximum number of times to try to connect to Parse Server.
Defaults to 5.
- parameter parseFileTransfer: Override the default transfer behavior for `ParseFile`'s.
Allows for direct uploads to other file storage providers.
- parameter authentication: A callback block that will be used to receive/accept/decline network challenges.
Defaults to `nil` in which the SDK will use the default OS authentication methods for challenges.
It should have the following argument signature: `(challenge: URLAuthenticationChallenge,
Expand Down Expand Up @@ -323,6 +333,7 @@ public func initialize(
deletingKeychainIfNeeded: Bool = false,
httpAdditionalHeaders: [AnyHashable: Any]? = nil,
maxConnectionAttempts: Int = 5,
parseFileTransfer: ParseFileTransferable? = nil,
authentication: ((URLAuthenticationChallenge,
(URLSession.AuthChallengeDisposition,
URLCredential?) -> Void) -> Void)? = nil
Expand All @@ -344,6 +355,7 @@ public func initialize(
deletingKeychainIfNeeded: deletingKeychainIfNeeded,
httpAdditionalHeaders: httpAdditionalHeaders,
maxConnectionAttempts: maxConnectionAttempts,
parseFileTransfer: parseFileTransfer,
authentication: authentication)
configuration.isMigratingFromObjcSDK = migratingFromObjcSDK
initialize(configuration: configuration)
Expand Down
2 changes: 1 addition & 1 deletion Sources/ParseSwift/ParseConstants.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import Foundation

enum ParseConstants {
static let sdk = "swift"
static let version = "4.11.0"
static let version = "4.12.0"
static let fileManagementDirectory = "parse/"
static let fileManagementPrivateDocumentsDirectory = "Private Documents/"
static let fileManagementLibraryDirectory = "Library/"
Expand Down
Loading

0 comments on commit 9ab5271

Please sign in to comment.