diff --git a/README.md b/README.md index 90f49f345..3077775b1 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ To get started with SwiftyDropbox, we recommend you add it to your project using platform :ios, '8.0' use_frameworks! - pod 'SwiftyDropbox', :git => 'git@github.com:dropbox/SwiftyDropbox.git', :tag => '0.6' + pod 'SwiftyDropbox', :git => 'git@github.com:dropbox/SwiftyDropbox.git', :tag => '0.7' ``` 1. From the project directory, install the SwiftyDropbox SDK with: diff --git a/Source/Client.swift b/Source/Client.swift index d71074ec1..2c4df77e1 100644 --- a/Source/Client.swift +++ b/Source/Client.swift @@ -5,13 +5,13 @@ public class Box { public let unboxed : T init (_ v : T) { self.unboxed = v } } -public enum CallError : CustomStringConvertible { +public enum CallError : CustomStringConvertible { case InternalServerError(Int, String?, String?) case BadInputError(String?, String?) case RateLimitError case HTTPError(Int?, String?, String?) - case RouteError(Box, String?) - + case RouteError(Box, String?) + case OSError(ErrorType?) public var description : String { switch self { @@ -57,6 +57,11 @@ public enum CallError : CustomStringConvertible { } ret += "API route error - handle programmatically" return ret + case let .OSError(err): + if let e = err { + return "\(e)" + } + return "An unknown system error" } } } @@ -92,46 +97,53 @@ public class BabelRequest { let responseSerializer : RType let request : Alamofire.Request - init(client: BabelClient, - host: String, - route: String, + init(request: Alamofire.Request, responseSerializer: RType, - errorSerializer: EType, - requestEncoder: (URLRequestConvertible, [String: AnyObject]?) -> (NSMutableURLRequest, NSError?)) { + errorSerializer: EType) + { self.errorSerializer = errorSerializer self.responseSerializer = responseSerializer - let url = "\(client.baseHosts[host]!)\(route)" - self.request = client.manager.request(.POST, url, parameters: [:], encoding: ParameterEncoding.Custom(requestEncoder)) + self.request = request } - func handleResponseError(response: NSHTTPURLResponse?, data: NSData) -> CallError { + func handleResponseError(response: NSHTTPURLResponse?, data: NSData?, error: ErrorType?) -> CallError { let requestId = response?.allHeaderFields["X-Dropbox-Request-Id"] as? String if let code = response?.statusCode { switch code { case 500...599: - let message = utf8Decode(data) + var message = "" + if let d = data { + message = utf8Decode(d) + } return .InternalServerError(code, message, requestId) case 400: - let message = utf8Decode(data) + var message = "" + if let d = data { + message = utf8Decode(d) + } return .BadInputError(message, requestId) case 429: return .RateLimitError case 403, 404, 409: - let json = parseJSON(data) + let json = parseJSON(data!) switch json { case .Dictionary(let d): return .RouteError(Box(self.errorSerializer.deserialize(d["error"]!)), requestId) default: fatalError("Failed to parse error type") } - + case 200: + return .OSError(error) default: return .HTTPError(code, "An error occurred.", requestId) } } else { - let message = utf8Decode(data) + var message = "" + if let d = data { + message = utf8Decode(d) + } return .HTTPError(nil, message, requestId) } } @@ -140,13 +152,17 @@ public class BabelRequest { /// An "rpc-style" request public class BabelRpcRequest : BabelRequest { init(client: BabelClient, host: String, route: String, params: JSON, responseSerializer: RType, errorSerializer: EType) { - super.init( client: client, host: host, route: route, responseSerializer: responseSerializer, errorSerializer: errorSerializer, - requestEncoder: ({ convertible, _ in - let mutableRequest = convertible.URLRequest.copy() as! NSMutableURLRequest - mutableRequest.addValue("application/json", forHTTPHeaderField: "Content-Type") - mutableRequest.HTTPBody = dumpJSON(params) - return (mutableRequest, nil) - })) + let url = "\(client.baseHosts[host]!)\(route)" + let headers = ["Content-Type": "application/json"] + + let request = client.manager.request(.POST, url, parameters: [:], headers: headers, encoding: ParameterEncoding.Custom {(convertible, _) in + let mutableRequest = convertible.URLRequest.copy() as! NSMutableURLRequest + mutableRequest.HTTPBody = dumpJSON(params) + return (mutableRequest, nil) + }) + super.init(request: request, + responseSerializer: responseSerializer, + errorSerializer: errorSerializer) } /// Called when a request completes. @@ -157,7 +173,7 @@ public class BabelRpcRequest : B (request, response, dataObj, error) -> Void in let data = dataObj! if error != nil { - completionHandler(nil, self.handleResponseError(response, data: data)) + completionHandler(nil, self.handleResponseError(response, data: data, error: error)) } else { completionHandler(self.responseSerializer.deserialize(parseJSON(data)), nil) } @@ -166,23 +182,47 @@ public class BabelRpcRequest : B } } +public enum BabelUploadBody { + case Data(NSData) + case File(NSURL) + case Stream(NSInputStream) +} + public class BabelUploadRequest : BabelRequest { - init(client: BabelClient, host: String, route: String, params: JSON, body: NSData, responseSerializer: RType, errorSerializer: EType) { - super.init( client: client, host: host, route: route, responseSerializer: responseSerializer, errorSerializer: errorSerializer, - requestEncoder: ({ convertible, _ in - let mutableRequest = convertible.URLRequest.copy() as! NSMutableURLRequest - mutableRequest.addValue("application/octet-stream", forHTTPHeaderField: "Content-Type") - mutableRequest.HTTPBody = body + + init( + client: BabelClient, + host: String, + route: String, + params: JSON, + responseSerializer: RType, errorSerializer: EType, + body: BabelUploadBody) { + let url = "\(client.baseHosts[host]!)\(route)" + var headers = [ + "Content-Type": "application/octet-stream", + ] if let data = dumpJSON(params) { let value = asciiEscape(utf8Decode(data)) - mutableRequest.addValue(value, forHTTPHeaderField: "Dropbox-Api-Arg") + headers["Dropbox-Api-Arg"] = value } - return (mutableRequest, nil) - })) + let request : Alamofire.Request + + switch body { + case let .Data(data): + request = client.manager.upload(.POST, url, headers: headers, data: data) + case let .File(file): + request = client.manager.upload(.POST, url, headers: headers, file: file) + case let .Stream(stream): + request = client.manager.upload(.POST, url, headers: headers, stream: stream) + } + super.init(request: request, + responseSerializer: responseSerializer, + errorSerializer: errorSerializer) } + - /// Called as the upload progresses. + /// Called as the upload progresses. /// /// :param: closure /// a callback taking three arguments (`bytesWritten`, `totalBytesWritten`, `totalBytesExpectedToWrite`) @@ -202,7 +242,7 @@ public class BabelUploadRequest (request, response, dataObj, error) -> Void in let data = dataObj! if error != nil { - completionHandler(nil, self.handleResponseError(response, data: data)) + completionHandler(nil, self.handleResponseError(response, data: data, error: error)) } else { completionHandler(self.responseSerializer.deserialize(parseJSON(data)), nil) } @@ -213,17 +253,32 @@ public class BabelUploadRequest } public class BabelDownloadRequest : BabelRequest { - init(client: BabelClient, host: String, route: String, params: JSON, responseSerializer: RType, errorSerializer: EType) { - super.init( client: client, host: host, route: route, responseSerializer: responseSerializer, errorSerializer: errorSerializer, - requestEncoder: ({ convertible, _ in - let mutableRequest = convertible.URLRequest.copy() as! NSMutableURLRequest - if let data = dumpJSON(params) { - let value = asciiEscape(utf8Decode(data)) - mutableRequest.addValue(value, forHTTPHeaderField: "Dropbox-Api-Arg") - } - - return (mutableRequest, nil) - })) + var urlPath : NSURL? + init(client: BabelClient, host: String, route: String, params: JSON, responseSerializer: RType, errorSerializer: EType, destination: (NSURL, NSHTTPURLResponse) -> NSURL) { + let url = "\(client.baseHosts[host]!)\(route)" + var headers = [String : String]() + urlPath = nil + + if let data = dumpJSON(params) { + let value = asciiEscape(utf8Decode(data)) + headers["Dropbox-Api-Arg"] = value + } + + + + + weak var _self : BabelDownloadRequest! + + let dest : (NSURL, NSHTTPURLResponse) -> NSURL = { url, resp in + let ret = destination(url, resp) + _self.urlPath = ret + return ret + } + + let request = client.manager.download(.POST, url, headers: headers, destination: dest) + + super.init(request: request, responseSerializer: responseSerializer, errorSerializer: errorSerializer) + _self = self } /// Called as the download progresses @@ -241,18 +296,20 @@ public class BabelDownloadRequest?) -> Void) -> Self { + public func response(completionHandler: ( (RType.ValueType, NSURL)?, CallError?) -> Void) -> Self { + self.request.validate().response { (request, response, dataObj, error) -> Void in - let data = dataObj! + let data = NSData(contentsOfURL: self.urlPath!)! + if error != nil { - completionHandler(nil, self.handleResponseError(response, data: data)) + completionHandler(nil, self.handleResponseError(response, data: data, error: error)) } else { let result = response!.allHeaderFields["Dropbox-Api-Result"] as! String let resultData = result.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)! let resultObject = self.responseSerializer.deserialize(parseJSON(resultData)) - completionHandler( (resultObject, data), nil) + completionHandler( (resultObject, self.urlPath!), nil) } } return self diff --git a/Source/Files.swift b/Source/Files.swift index 4fc17445e..f9da55602 100644 --- a/Source/Files.swift +++ b/Source/Files.swift @@ -208,7 +208,7 @@ public class Files { /// The GetMetadataError union /// /// - Path - public enum GetMetadataError : CustomStringConvertible { + public enum GetMetadataError: CustomStringConvertible { case Path(Files.LookupError) public var description : String { return "\(prepareJSONForSerialization(GetMetadataErrorSerializer().serialize(self)))" @@ -363,7 +363,7 @@ public class Files { /// - Path /// - Other: /// An unspecified error. - public enum ListFolderError : CustomStringConvertible { + public enum ListFolderError: CustomStringConvertible { case Path(Files.LookupError) case Other public var description : String { @@ -442,7 +442,7 @@ public class Files { /// Indicates that the cursor has been invalidated. Call `list_folder` to /// obtain a new cursor. /// - Other - public enum ListFolderContinueError : CustomStringConvertible { + public enum ListFolderContinueError: CustomStringConvertible { case Path(Files.LookupError) case Reset case Other @@ -526,7 +526,7 @@ public class Files { /// - Path /// - Other: /// An unspecified error. - public enum DownloadError : CustomStringConvertible { + public enum DownloadError: CustomStringConvertible { case Path(Files.LookupError) case Other public var description : String { @@ -648,7 +648,7 @@ public class Files { /// Unable to save the uploaded contents to a file. /// - Other: /// An unspecified error. - public enum UploadError : CustomStringConvertible { + public enum UploadError: CustomStringConvertible { case Path(Files.UploadWriteFailed) case Other public var description : String { @@ -733,7 +733,7 @@ public class Files { /// been closed (i.e. committed). /// - Other: /// An unspecified error. - public enum UploadSessionLookupError : CustomStringConvertible { + public enum UploadSessionLookupError: CustomStringConvertible { case NotFound case IncorrectOffset(Files.UploadSessionOffsetError) case Closed @@ -794,7 +794,7 @@ public class Files { /// Unable to save the uploaded contents to a file. /// - Other: /// An unspecified error. - public enum UploadSessionFinishError : CustomStringConvertible { + public enum UploadSessionFinishError: CustomStringConvertible { case LookupFailed(Files.UploadSessionLookupError) case Path(Files.WriteError) case Other @@ -937,7 +937,7 @@ public class Files { /// autorename strategy is to append the string "conflicted copy" to the /// file name. For example, "document.txt" might become "document /// (conflicted copy).txt" or "document (Panda's conflicted copy).txt". - public enum WriteMode : CustomStringConvertible { + public enum WriteMode: CustomStringConvertible { case Add case Overwrite case Update(String) @@ -1092,7 +1092,7 @@ public class Files { /// Search file and folder names as well as file contents. /// - DeletedFilename: /// Search for deleted file and folder names. - public enum SearchMode : CustomStringConvertible { + public enum SearchMode: CustomStringConvertible { case Filename case FilenameAndContent case DeletedFilename @@ -1209,7 +1209,7 @@ public class Files { /// This item was matched based on its file contents. /// - Both: /// This item was matched based on both its contents and its file name. - public enum SearchMatchType : CustomStringConvertible { + public enum SearchMatchType: CustomStringConvertible { case Filename case Content case Both @@ -1342,7 +1342,7 @@ public class Files { /// - Path /// - Other: /// An unspecified error. - public enum SearchError : CustomStringConvertible { + public enum SearchError: CustomStringConvertible { case Path(Files.LookupError) case Other public var description : String { @@ -1397,7 +1397,7 @@ public class Files { /// example, sometimes there are legal restrictions due to copyright /// claims. /// - Other - public enum LookupError : CustomStringConvertible { + public enum LookupError: CustomStringConvertible { case MalformedPath(String?) case NotFound case NotFile @@ -1478,7 +1478,7 @@ public class Files { /// - DisallowedName: /// Dropbox will not save the file or folder because it of its name. /// - Other - public enum WriteError : CustomStringConvertible { + public enum WriteError: CustomStringConvertible { case MalformedPath(String?) case Conflict(Files.WriteConflictError) case NoWritePermission @@ -1556,7 +1556,7 @@ public class Files { /// There's a file at an ancestor path, so we couldn't create the required /// parent folders. /// - Other - public enum WriteConflictError : CustomStringConvertible { + public enum WriteConflictError: CustomStringConvertible { case File case Folder case FileAncestor @@ -1643,7 +1643,7 @@ public class Files { /// The CreateFolderError union /// /// - Path - public enum CreateFolderError : CustomStringConvertible { + public enum CreateFolderError: CustomStringConvertible { case Path(Files.WriteError) public var description : String { return "\(prepareJSONForSerialization(CreateFolderErrorSerializer().serialize(self)))" @@ -1712,7 +1712,7 @@ public class Files { /// - PathLookup /// - PathWrite /// - Other - public enum DeleteError : CustomStringConvertible { + public enum DeleteError: CustomStringConvertible { case PathLookup(Files.LookupError) case PathWrite(Files.WriteError) case Other @@ -1812,7 +1812,7 @@ public class Files { /// The operation would involve more than 10,000 files and folders. /// - Other: /// An unspecified error. - public enum RelocationError : CustomStringConvertible { + public enum RelocationError: CustomStringConvertible { case FromLookup(Files.LookupError) case FromWrite(Files.WriteError) case To(Files.WriteError) @@ -1900,7 +1900,7 @@ public class Files { /// 640 by 480 px. /// - W1024h768: /// 1024 by 768 - public enum ThumbnailSize : CustomStringConvertible { + public enum ThumbnailSize: CustomStringConvertible { case W32h32 case W64h64 case W128h128 @@ -1963,7 +1963,7 @@ public class Files { /// /// - Jpeg /// - Png - public enum ThumbnailFormat : CustomStringConvertible { + public enum ThumbnailFormat: CustomStringConvertible { case Jpeg case Png public var description : String { @@ -2057,7 +2057,7 @@ public class Files { /// The image cannot be converted to a thumbnail. /// - ConversionError: /// An error occurs during thumbnail conversion. - public enum ThumbnailError : CustomStringConvertible { + public enum ThumbnailError: CustomStringConvertible { case Path(Files.LookupError) case UnsupportedExtension case UnsupportedImage @@ -2160,7 +2160,7 @@ public class Files { /// The file extension is not supported preview generation. /// - UnsupportedContent: /// The file content is not supported for preview generation. - public enum PreviewError : CustomStringConvertible { + public enum PreviewError: CustomStringConvertible { case Path(Files.LookupError) case InProgress case UnsupportedExtension @@ -2256,7 +2256,7 @@ public class Files { /// /// - Path /// - Other - public enum ListRevisionsError : CustomStringConvertible { + public enum ListRevisionsError: CustomStringConvertible { case Path(Files.LookupError) case Other public var description : String { @@ -2381,7 +2381,7 @@ public class Files { /// - InvalidRevision: /// The revision is invalid. It may point to a different file. /// - Other - public enum RestoreError : CustomStringConvertible { + public enum RestoreError: CustomStringConvertible { case PathLookup(Files.LookupError) case PathWrite(Files.WriteError) case InvalidRevision @@ -2489,9 +2489,12 @@ extension BabelClient { /// The path of the file to download. /// :param: rev /// Optional revision, taken from the corresponding `Metadata` field. - public func filesDownload(path path: String, rev: String? = nil) -> BabelDownloadRequest { + /// :param: destination + /// A closure used to compute the destination,given the temporary + /// file location and the response + public func filesDownload(path path: String, rev: String? = nil, destination: (NSURL, NSHTTPURLResponse) -> NSURL) -> BabelDownloadRequest { let request = Files.DownloadArg(path: path, rev: rev) - return BabelDownloadRequest(client: self, host: "content", route: "/files/download", params: Files.DownloadArgSerializer().serialize(request), responseSerializer: Files.FileMetadataSerializer(), errorSerializer: Files.DownloadErrorSerializer()) + return BabelDownloadRequest(client: self, host: "content", route: "/files/download", params: Files.DownloadArgSerializer().serialize(request), responseSerializer: Files.FileMetadataSerializer(), errorSerializer: Files.DownloadErrorSerializer(), destination: destination) } /// Upload sessions allow you to upload a single file using multiple /// requests. This call starts a new upload session with the given data. @@ -2500,9 +2503,31 @@ extension BabelClient { /// Dropbox. /// /// :param: body - /// The binary payload to upload + /// The file to upload, as an NSData object public func filesUploadSessionStart(body body: NSData) -> BabelUploadRequest { - return BabelUploadRequest(client: self, host: "content", route: "/files/upload_session/start", params: Serialization._VoidSerializer.serialize(), body: body, responseSerializer: Files.UploadSessionStartResultSerializer(), errorSerializer: Serialization._VoidSerializer) + return BabelUploadRequest(client: self, host: "content", route: "/files/upload_session/start", params: Serialization._VoidSerializer.serialize(), responseSerializer: Files.UploadSessionStartResultSerializer(), errorSerializer: Serialization._VoidSerializer, body: .Data(body)) + } + /// Upload sessions allow you to upload a single file using multiple + /// requests. This call starts a new upload session with the given data. + /// You can then use :route:`upload_session/append` to add more data and + /// :route:`upload_session/finish` to save all the data to a file in + /// Dropbox. + /// + /// :param: body + /// The file to upload, as an NSURL object + public func filesUploadSessionStart(body body: NSURL) -> BabelUploadRequest { + return BabelUploadRequest(client: self, host: "content", route: "/files/upload_session/start", params: Serialization._VoidSerializer.serialize(), responseSerializer: Files.UploadSessionStartResultSerializer(), errorSerializer: Serialization._VoidSerializer, body: .File(body)) + } + /// Upload sessions allow you to upload a single file using multiple + /// requests. This call starts a new upload session with the given data. + /// You can then use :route:`upload_session/append` to add more data and + /// :route:`upload_session/finish` to save all the data to a file in + /// Dropbox. + /// + /// :param: body + /// The file to upload, as an NSInputStream object + public func filesUploadSessionStart(body body: NSInputStream) -> BabelUploadRequest { + return BabelUploadRequest(client: self, host: "content", route: "/files/upload_session/start", params: Serialization._VoidSerializer.serialize(), responseSerializer: Files.UploadSessionStartResultSerializer(), errorSerializer: Serialization._VoidSerializer, body: .Stream(body)) } /// Append more data to an upload session. /// @@ -2513,10 +2538,38 @@ extension BabelClient { /// make sure upload data isn't lost or duplicated in the event of a /// network error. /// :param: body - /// The binary payload to upload + /// The file to upload, as an NSData object public func filesUploadSessionAppend(sessionId sessionId: String, offset: UInt64, body: NSData) -> BabelUploadRequest { let request = Files.UploadSessionCursor(sessionId: sessionId, offset: offset) - return BabelUploadRequest(client: self, host: "content", route: "/files/upload_session/append", params: Files.UploadSessionCursorSerializer().serialize(request), body: body, responseSerializer: Serialization._VoidSerializer, errorSerializer: Files.UploadSessionLookupErrorSerializer()) + return BabelUploadRequest(client: self, host: "content", route: "/files/upload_session/append", params: Files.UploadSessionCursorSerializer().serialize(request), responseSerializer: Serialization._VoidSerializer, errorSerializer: Files.UploadSessionLookupErrorSerializer(), body: .Data(body)) + } + /// Append more data to an upload session. + /// + /// :param: sessionId + /// The upload session ID (returned by `upload_session/start`). + /// :param: offset + /// The amount of data that has been uploaded so far. We use this to + /// make sure upload data isn't lost or duplicated in the event of a + /// network error. + /// :param: body + /// The file to upload, as an NSURL object + public func filesUploadSessionAppend(sessionId sessionId: String, offset: UInt64, body: NSURL) -> BabelUploadRequest { + let request = Files.UploadSessionCursor(sessionId: sessionId, offset: offset) + return BabelUploadRequest(client: self, host: "content", route: "/files/upload_session/append", params: Files.UploadSessionCursorSerializer().serialize(request), responseSerializer: Serialization._VoidSerializer, errorSerializer: Files.UploadSessionLookupErrorSerializer(), body: .File(body)) + } + /// Append more data to an upload session. + /// + /// :param: sessionId + /// The upload session ID (returned by `upload_session/start`). + /// :param: offset + /// The amount of data that has been uploaded so far. We use this to + /// make sure upload data isn't lost or duplicated in the event of a + /// network error. + /// :param: body + /// The file to upload, as an NSInputStream object + public func filesUploadSessionAppend(sessionId sessionId: String, offset: UInt64, body: NSInputStream) -> BabelUploadRequest { + let request = Files.UploadSessionCursor(sessionId: sessionId, offset: offset) + return BabelUploadRequest(client: self, host: "content", route: "/files/upload_session/append", params: Files.UploadSessionCursorSerializer().serialize(request), responseSerializer: Serialization._VoidSerializer, errorSerializer: Files.UploadSessionLookupErrorSerializer(), body: .Stream(body)) } /// Finish an upload session and save the uploaded data to the given file /// path. @@ -2526,10 +2579,36 @@ extension BabelClient { /// :param: commit /// Contains the path and other optional modifiers for the commit. /// :param: body - /// The binary payload to upload + /// The file to upload, as an NSData object public func filesUploadSessionFinish(cursor cursor: Files.UploadSessionCursor, commit: Files.CommitInfo, body: NSData) -> BabelUploadRequest { let request = Files.UploadSessionFinishArg(cursor: cursor, commit: commit) - return BabelUploadRequest(client: self, host: "content", route: "/files/upload_session/finish", params: Files.UploadSessionFinishArgSerializer().serialize(request), body: body, responseSerializer: Files.FileMetadataSerializer(), errorSerializer: Files.UploadSessionFinishErrorSerializer()) + return BabelUploadRequest(client: self, host: "content", route: "/files/upload_session/finish", params: Files.UploadSessionFinishArgSerializer().serialize(request), responseSerializer: Files.FileMetadataSerializer(), errorSerializer: Files.UploadSessionFinishErrorSerializer(), body: .Data(body)) + } + /// Finish an upload session and save the uploaded data to the given file + /// path. + /// + /// :param: cursor + /// Contains the upload session ID and the offset. + /// :param: commit + /// Contains the path and other optional modifiers for the commit. + /// :param: body + /// The file to upload, as an NSURL object + public func filesUploadSessionFinish(cursor cursor: Files.UploadSessionCursor, commit: Files.CommitInfo, body: NSURL) -> BabelUploadRequest { + let request = Files.UploadSessionFinishArg(cursor: cursor, commit: commit) + return BabelUploadRequest(client: self, host: "content", route: "/files/upload_session/finish", params: Files.UploadSessionFinishArgSerializer().serialize(request), responseSerializer: Files.FileMetadataSerializer(), errorSerializer: Files.UploadSessionFinishErrorSerializer(), body: .File(body)) + } + /// Finish an upload session and save the uploaded data to the given file + /// path. + /// + /// :param: cursor + /// Contains the upload session ID and the offset. + /// :param: commit + /// Contains the path and other optional modifiers for the commit. + /// :param: body + /// The file to upload, as an NSInputStream object + public func filesUploadSessionFinish(cursor cursor: Files.UploadSessionCursor, commit: Files.CommitInfo, body: NSInputStream) -> BabelUploadRequest { + let request = Files.UploadSessionFinishArg(cursor: cursor, commit: commit) + return BabelUploadRequest(client: self, host: "content", route: "/files/upload_session/finish", params: Files.UploadSessionFinishArgSerializer().serialize(request), responseSerializer: Files.FileMetadataSerializer(), errorSerializer: Files.UploadSessionFinishErrorSerializer(), body: .Stream(body)) } /// Create a new file with the contents provided in the request. /// @@ -2552,10 +2631,62 @@ extension BabelClient { /// `true`, this tells the clients that this modification shouldn't /// result in a user notification. /// :param: body - /// The binary payload to upload + /// The file to upload, as an NSData object public func filesUpload(path path: String, mode: Files.WriteMode = .Add, autorename: Bool = false, clientModified: NSDate? = nil, mute: Bool = false, body: NSData) -> BabelUploadRequest { let request = Files.CommitInfo(path: path, mode: mode, autorename: autorename, clientModified: clientModified, mute: mute) - return BabelUploadRequest(client: self, host: "content", route: "/files/upload", params: Files.CommitInfoSerializer().serialize(request), body: body, responseSerializer: Files.FileMetadataSerializer(), errorSerializer: Files.UploadErrorSerializer()) + return BabelUploadRequest(client: self, host: "content", route: "/files/upload", params: Files.CommitInfoSerializer().serialize(request), responseSerializer: Files.FileMetadataSerializer(), errorSerializer: Files.UploadErrorSerializer(), body: .Data(body)) + } + /// Create a new file with the contents provided in the request. + /// + /// :param: path + /// Path in the user's Dropbox to save the file. + /// :param: mode + /// Selects what to do if the file already exists. + /// :param: autorename + /// If there's a conflict, as determined by `mode`, have the Dropbox + /// server try to autorename the file to avoid conflict. + /// :param: clientModified + /// The value to store as the `client_modified` timestamp. Dropbox + /// automatically records the time at which the file was written to + /// the Dropbox servers. It can also record an additional timestamp, + /// provided by Dropbox desktop clients, mobile clients, and API apps + /// of when the file was actually created or modified. + /// :param: mute + /// Normally, users are made aware of any file modifications in their + /// Dropbox account via notifications in the client software. If + /// `true`, this tells the clients that this modification shouldn't + /// result in a user notification. + /// :param: body + /// The file to upload, as an NSURL object + public func filesUpload(path path: String, mode: Files.WriteMode = .Add, autorename: Bool = false, clientModified: NSDate? = nil, mute: Bool = false, body: NSURL) -> BabelUploadRequest { + let request = Files.CommitInfo(path: path, mode: mode, autorename: autorename, clientModified: clientModified, mute: mute) + return BabelUploadRequest(client: self, host: "content", route: "/files/upload", params: Files.CommitInfoSerializer().serialize(request), responseSerializer: Files.FileMetadataSerializer(), errorSerializer: Files.UploadErrorSerializer(), body: .File(body)) + } + /// Create a new file with the contents provided in the request. + /// + /// :param: path + /// Path in the user's Dropbox to save the file. + /// :param: mode + /// Selects what to do if the file already exists. + /// :param: autorename + /// If there's a conflict, as determined by `mode`, have the Dropbox + /// server try to autorename the file to avoid conflict. + /// :param: clientModified + /// The value to store as the `client_modified` timestamp. Dropbox + /// automatically records the time at which the file was written to + /// the Dropbox servers. It can also record an additional timestamp, + /// provided by Dropbox desktop clients, mobile clients, and API apps + /// of when the file was actually created or modified. + /// :param: mute + /// Normally, users are made aware of any file modifications in their + /// Dropbox account via notifications in the client software. If + /// `true`, this tells the clients that this modification shouldn't + /// result in a user notification. + /// :param: body + /// The file to upload, as an NSInputStream object + public func filesUpload(path path: String, mode: Files.WriteMode = .Add, autorename: Bool = false, clientModified: NSDate? = nil, mute: Bool = false, body: NSInputStream) -> BabelUploadRequest { + let request = Files.CommitInfo(path: path, mode: mode, autorename: autorename, clientModified: clientModified, mute: mute) + return BabelUploadRequest(client: self, host: "content", route: "/files/upload", params: Files.CommitInfoSerializer().serialize(request), responseSerializer: Files.FileMetadataSerializer(), errorSerializer: Files.UploadErrorSerializer(), body: .Stream(body)) } /// Searches for files and folders. /// @@ -2630,9 +2761,12 @@ extension BabelClient { /// better for screenshots and digital arts. /// :param: size /// The size for the thumbnail image. - public func filesGetThumbnail(path path: String, format: Files.ThumbnailFormat = .Jpeg, size: Files.ThumbnailSize = .W64h64) -> BabelDownloadRequest { + /// :param: destination + /// A closure used to compute the destination,given the temporary + /// file location and the response + public func filesGetThumbnail(path path: String, format: Files.ThumbnailFormat = .Jpeg, size: Files.ThumbnailSize = .W64h64, destination: (NSURL, NSHTTPURLResponse) -> NSURL) -> BabelDownloadRequest { let request = Files.ThumbnailArg(path: path, format: format, size: size) - return BabelDownloadRequest(client: self, host: "content", route: "/files/get_thumbnail", params: Files.ThumbnailArgSerializer().serialize(request), responseSerializer: Files.FileMetadataSerializer(), errorSerializer: Files.ThumbnailErrorSerializer()) + return BabelDownloadRequest(client: self, host: "content", route: "/files/get_thumbnail", params: Files.ThumbnailArgSerializer().serialize(request), responseSerializer: Files.FileMetadataSerializer(), errorSerializer: Files.ThumbnailErrorSerializer(), destination: destination) } /// Get a preview for a file. Currently previews are only generated for the /// files with the following extensions: .doc, .docx, .docm, .ppt, .pps, @@ -2642,9 +2776,12 @@ extension BabelClient { /// The path of the file to preview. /// :param: rev /// Optional revision, taken from the corresponding `Metadata` field. - public func filesGetPreview(path path: String, rev: String? = nil) -> BabelDownloadRequest { + /// :param: destination + /// A closure used to compute the destination,given the temporary + /// file location and the response + public func filesGetPreview(path path: String, rev: String? = nil, destination: (NSURL, NSHTTPURLResponse) -> NSURL) -> BabelDownloadRequest { let request = Files.PreviewArg(path: path, rev: rev) - return BabelDownloadRequest(client: self, host: "content", route: "/files/get_preview", params: Files.PreviewArgSerializer().serialize(request), responseSerializer: Files.FileMetadataSerializer(), errorSerializer: Files.PreviewErrorSerializer()) + return BabelDownloadRequest(client: self, host: "content", route: "/files/get_preview", params: Files.PreviewArgSerializer().serialize(request), responseSerializer: Files.FileMetadataSerializer(), errorSerializer: Files.PreviewErrorSerializer(), destination: destination) } /// Return revisions of a file /// diff --git a/Source/Sharing.swift b/Source/Sharing.swift index 17c95eec1..872cdb9d5 100644 --- a/Source/Sharing.swift +++ b/Source/Sharing.swift @@ -23,7 +23,7 @@ public class Sharing { /// access the link. Login is required. /// - Other: /// An unknown restriction is in place. - public enum Visibility : CustomStringConvertible { + public enum Visibility: CustomStringConvertible { case Public case TeamOnly case Password @@ -290,7 +290,7 @@ public class Sharing { /// /// - Path /// - Other - public enum GetSharedLinksError : CustomStringConvertible { + public enum GetSharedLinksError: CustomStringConvertible { case Path(String?) case Other public var description : String { @@ -336,7 +336,7 @@ public class Sharing { /// Assume pending uploads are files. /// - Folder: /// Assume pending uploads are folders. - public enum PendingUploadMode : CustomStringConvertible { + public enum PendingUploadMode: CustomStringConvertible { case File case Folder public var description : String { @@ -424,7 +424,7 @@ public class Sharing { /// /// - Path /// - Other - public enum CreateSharedLinkError : CustomStringConvertible { + public enum CreateSharedLinkError: CustomStringConvertible { case Path(Files.LookupError) case Other public var description : String { @@ -475,7 +475,7 @@ public class Sharing { /// The member can only view the shared folder. /// - Other: /// An unknown access type. - public enum AccessType : CustomStringConvertible { + public enum AccessType: CustomStringConvertible { case Owner case Editor case Viewer @@ -535,7 +535,7 @@ public class Sharing { /// Links can only be shared among members of the shared folder. /// - Other: /// An unknown shared link policy. - public enum SharedLinkPolicy : CustomStringConvertible { + public enum SharedLinkPolicy: CustomStringConvertible { case All case MembersOnly case Other @@ -966,7 +966,7 @@ public class Sharing { /// The folder is a team shared folder and the user cannot access it. /// - IsAppFolder: /// The folder is an app folder and cannot be shared. - public enum SharedFolderAccessError : CustomStringConvertible { + public enum SharedFolderAccessError: CustomStringConvertible { case InvalidId case NotMember case HasLeft diff --git a/Source/Users.swift b/Source/Users.swift index 2f29d74d9..4eb026fca 100644 --- a/Source/Users.swift +++ b/Source/Users.swift @@ -40,7 +40,7 @@ public class Users { /// - NoAccount: /// The specified `GetAccountArg.account_id` does not exist. /// - Unknown - public enum GetAccountError : CustomStringConvertible { + public enum GetAccountError: CustomStringConvertible { case NoAccount case Unknown public var description : String { @@ -86,7 +86,7 @@ public class Users { /// The Dropbox Pro account type. /// - Business: /// The Dropbox for Business account type. - public enum AccountType : CustomStringConvertible { + public enum AccountType: CustomStringConvertible { case Basic case Pro case Business @@ -429,7 +429,7 @@ public class Users { /// - Team: /// The user shares space with other members of their team. /// - Other - public enum SpaceAllocation : CustomStringConvertible { + public enum SpaceAllocation: CustomStringConvertible { case Individual(Users.IndividualSpaceAllocation) case Team(Users.TeamSpaceAllocation) case Other diff --git a/SwiftyDropbox.podspec b/SwiftyDropbox.podspec index 1a297b51e..a09874d17 100644 --- a/SwiftyDropbox.podspec +++ b/SwiftyDropbox.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "SwiftyDropbox" - s.version = "0.6" + s.version = "0.7" s.summary = "Dropbox Swift SDK for APIv2" s.homepage = "https://dropbox.com/developers/" s.license = "MIT"