Skip to content

Commit ec7813e

Browse files
authored
feat: Add support for file request API (#867)
1 parent fedd778 commit ec7813e

File tree

14 files changed

+922
-70
lines changed

14 files changed

+922
-70
lines changed

BoxSDK.xcodeproj/project.pbxproj

Lines changed: 121 additions & 69 deletions
Large diffs are not rendered by default.

Sources/Client/BoxClient.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ public class BoxClient {
5151
public private(set) lazy var storagePolicies = StoragePoliciesModule(boxClient: self)
5252
/// Provides sign requests functionality.
5353
public private(set) lazy var signRequests = SignRequestsModule(boxClient: self)
54+
/// Provides file requests functionality.
55+
public private(set) lazy var fileRequests = FileRequestsModule(boxClient: self)
5456

5557
/// Provides network communication with the Box APIs.
5658
private var networkAgent: NetworkAgentProtocol
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
//
2+
// FileRequestsModule.swift
3+
// BoxSDK-iOS
4+
//
5+
// Created by Artur Jankowski on 09/08/2022.
6+
// Copyright © 2022 box. All rights reserved.
7+
//
8+
9+
import Foundation
10+
11+
/// Provides management of FileRequests
12+
public class FileRequestsModule {
13+
/// Required for communicating with Box APIs.
14+
weak var boxClient: BoxClient!
15+
// swiftlint:disable:previous implicitly_unwrapped_optional
16+
17+
/// Initializer
18+
///
19+
/// - Parameter boxClient: Required for communicating with Box APIs.
20+
init(boxClient: BoxClient) {
21+
self.boxClient = boxClient
22+
}
23+
24+
/// Retrieves the information about a file request by ID.
25+
///
26+
/// - Parameters:
27+
/// - fileRequestId: The unique identifier that represent a file request.
28+
/// - completion: Returns a FileRequest response object if successful otherwise a BoxSDKError.
29+
public func get(
30+
fileRequestId: String,
31+
completion: @escaping Callback<FileRequest>
32+
) {
33+
boxClient.get(
34+
url: URL.boxAPIEndpoint("/2.0/file_requests/\(fileRequestId)", configuration: boxClient.configuration),
35+
completion: ResponseHandler.default(wrapping: completion)
36+
)
37+
}
38+
39+
/// Updates a file request. This can be used to activate or deactivate a file request.
40+
///
41+
/// - Parameters:
42+
/// - fileRequestId: The unique identifier that represent a file request.
43+
/// - ifMatch: Ensures this item hasn't recently changed before making changes.
44+
/// Pass in the item's last observed `etag` value into this header and the endpoint will fail with a `412 Precondition Failed` if it has changed since. (optional)
45+
/// - updateRequest: The `FileRequestUpdateRequest` object which provides the fields that can be updated.
46+
/// - completion: Returns a FileRequest response object if successful otherwise a BoxSDKError.
47+
public func update(
48+
fileRequestId: String,
49+
ifMatch: String? = nil,
50+
updateRequest: FileRequestUpdateRequest,
51+
completion: @escaping Callback<FileRequest>
52+
) {
53+
var headers: BoxHTTPHeaders = [:]
54+
if let unwrappedIfMatch = ifMatch {
55+
headers[BoxHTTPHeaderKey.ifMatch] = unwrappedIfMatch
56+
}
57+
58+
boxClient.put(
59+
url: URL.boxAPIEndpoint("/2.0/file_requests/\(fileRequestId)", configuration: boxClient.configuration),
60+
httpHeaders: headers,
61+
json: updateRequest.bodyDict,
62+
completion: ResponseHandler.default(wrapping: completion)
63+
)
64+
}
65+
66+
/// Copies an existing file request that is already present on one folder, and applies it to another folder.
67+
///
68+
/// - Parameters:
69+
/// - fileRequestId: The unique identifier that represent a file request.
70+
/// - copyRequest: The `FileRequestCopyRequest` object which provides required and optional fields used when copying, like: folder(required), title(optional), etc.
71+
/// - completion: Returns a FileRequest response object if successful otherwise a BoxSDKError.
72+
public func copy(
73+
fileRequestId: String,
74+
copyRequest: FileRequestCopyRequest,
75+
completion: @escaping Callback<FileRequest>
76+
) {
77+
boxClient.post(
78+
url: URL.boxAPIEndpoint("/2.0/file_requests/\(fileRequestId)/copy", configuration: boxClient.configuration),
79+
json: copyRequest.bodyDict,
80+
completion: ResponseHandler.default(wrapping: completion)
81+
)
82+
}
83+
84+
/// Deletes a file request permanently.
85+
///
86+
/// - Parameters:
87+
/// - fileRequestId: The unique identifier that represent a file request.
88+
/// - completion: Returns response object if successful otherwise a BoxSDKError.
89+
public func delete(
90+
fileRequestId: String,
91+
completion: @escaping Callback<Void>
92+
) {
93+
boxClient.delete(
94+
url: URL.boxAPIEndpoint("/2.0/file_requests/\(fileRequestId)", configuration: boxClient.configuration),
95+
completion: ResponseHandler.default(wrapping: completion)
96+
)
97+
}
98+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
//
2+
// FileRequestCopyRequest.swift
3+
// BoxSDK-iOS
4+
//
5+
// Created by Artur Jankowski on 09/08/2022.
6+
// Copyright © Box. All rights reserved.
7+
//
8+
9+
import Foundation
10+
11+
// The request body to copy a file request.
12+
public struct FileRequestCopyRequest: Encodable {
13+
14+
// MARK: - Properties
15+
16+
/// An optional new title for the file request.
17+
/// This can be used to change the title of the file request.
18+
public let title: String?
19+
/// An optional new description for the file request.
20+
/// This can be used to change the description of the file request.
21+
public let description: String?
22+
/// An optional new status of the file request.
23+
public let status: FileRequestStatus?
24+
/// Whether a file request submitter is required to provide their email address.
25+
/// When this setting is set to true, the Box UI will show an email field on the file request form.
26+
public let isEmailRequired: Bool?
27+
/// Whether a file request submitter is required to provide a description of the files they are submitting.
28+
/// When this setting is set to true, the Box UI will show a description field on the file request form.
29+
public let isDescriptionRequired: Bool?
30+
/// The date after which a file request will no longer accept new submissions.
31+
/// After this date, the `status` will automatically be set to `inactive`.
32+
public let expiresAt: Date?
33+
/// The folder to associate the new file request to.
34+
public let folder: FolderEntity
35+
36+
/// Initializer.
37+
///
38+
/// - Parameters:
39+
/// - title: An optional new title for the file request.
40+
/// - description: An optional new description for the file request.
41+
/// - status: An optional new status of the file request.
42+
/// - isEmailRequired: Whether a file request submitter is required to provide their email address.
43+
/// - isDescriptionRequired: Whether a file request submitter is required to provide a description of the files they are submitting.
44+
/// - expiresAt: The date after which a file request will no longer accept new submissions.
45+
/// - folder: The folder to associate the new file request to.
46+
public init(
47+
title: String? = nil,
48+
description: String? = nil,
49+
status: FileRequestStatus? = nil,
50+
isEmailRequired: Bool? = nil,
51+
isDescriptionRequired: Bool? = nil,
52+
expiresAt: Date? = nil,
53+
folder: FolderEntity
54+
) {
55+
self.title = title
56+
self.description = description
57+
self.status = status
58+
self.isEmailRequired = isEmailRequired
59+
self.isDescriptionRequired = isDescriptionRequired
60+
self.expiresAt = expiresAt
61+
self.folder = folder
62+
}
63+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
//
2+
// FileRequestUpdateRequest.swift
3+
// BoxSDK-iOS
4+
//
5+
// Created by Artur Jankowski on 09/08/2022.
6+
// Copyright © Box. All rights reserved.
7+
//
8+
9+
import Foundation
10+
11+
// The request body to update a file request.
12+
public struct FileRequestUpdateRequest: Encodable {
13+
14+
// MARK: - Properties
15+
16+
/// An optional new title for the file request.
17+
/// This can be used to change the title of the file request.
18+
public let title: String?
19+
/// An optional new description for the file request.
20+
/// This can be used to change the description of the file request.
21+
public let description: String?
22+
/// An optional new status of the file request.
23+
public let status: FileRequestStatus?
24+
/// Whether a file request submitter is required to provide their email address.
25+
/// When this setting is set to true, the Box UI will show an email field on the file request form.
26+
public let isEmailRequired: Bool?
27+
/// Whether a file request submitter is required to provide a description of the files they are submitting.
28+
/// When this setting is set to true, the Box UI will show a description field on the file request form.
29+
public let isDescriptionRequired: Bool?
30+
/// The date after which a file request will no longer accept new submissions.
31+
/// After this date, the `status` will automatically be set to `inactive`.
32+
public let expiresAt: Date?
33+
34+
/// Initializer.
35+
///
36+
/// - Parameters:
37+
/// - title: An optional new title for the file request.
38+
/// - description: An optional new description for the file request.
39+
/// - status: An optional new status of the file request.
40+
/// - isEmailRequired: Whether a file request submitter is required to provide their email address.
41+
/// - isDescriptionRequired: Whether a file request submitter is required to provide a description of the files they are submitting.
42+
/// - expiresAt: The date after which a file request will no longer accept new submissions.
43+
public init(
44+
title: String? = nil,
45+
description: String? = nil,
46+
status: FileRequestStatus? = nil,
47+
isEmailRequired: Bool? = nil,
48+
isDescriptionRequired: Bool? = nil,
49+
expiresAt: Date? = nil
50+
) {
51+
self.title = title
52+
self.description = description
53+
self.status = status
54+
self.isEmailRequired = isEmailRequired
55+
self.isDescriptionRequired = isDescriptionRequired
56+
self.expiresAt = expiresAt
57+
}
58+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
//
2+
// FolderEntity.swift
3+
// BoxSDK-iOS
4+
//
5+
// Created by Artur Jankowski on 09/08/2022.
6+
// Copyright © 2022 box. All rights reserved.
7+
//
8+
9+
import Foundation
10+
11+
/// Represents folder resource
12+
public struct FolderEntity: ResourceTypeEntity {
13+
public private(set) var type: String
14+
public private(set) var id: String
15+
16+
/// Initializer.
17+
///
18+
/// - Parameters:
19+
/// - id: Identifier of the folder.
20+
public init(id: String) {
21+
self.id = id
22+
type = "folder"
23+
}
24+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
//
2+
// ResourceTypeEntity.swift
3+
// BoxSDK-iOS
4+
//
5+
// Created by Artur Jankowski on 09/08/2022.
6+
// Copyright © 2022 box. All rights reserved.
7+
//
8+
9+
import Foundation
10+
11+
/// Represents simple resource type abstraction
12+
public protocol ResourceTypeEntity: Encodable {
13+
/// The resource type of the assiociated object.
14+
var type: String { get }
15+
16+
/// The id of the assiociated object
17+
var id: String { get }
18+
}
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
//
2+
// FileRequest.swift
3+
// BoxSDK-iOS
4+
//
5+
// Created by Artur Jankowski on 09/08/2022.
6+
// Copyright © Box. All rights reserved.
7+
//
8+
9+
import Foundation
10+
11+
/// The status of the file request.
12+
public enum FileRequestStatus: BoxEnum {
13+
/// The file request can accept new submissions.
14+
case active
15+
/// The file request can't accept new submissions, and any visitor to the file request URL will receive a `HTTP 404` status code.
16+
case inactive
17+
/// Custom value for enum values not yet implemented in the SDK
18+
case customValue(String)
19+
20+
public init(_ value: String) {
21+
switch value {
22+
case "active":
23+
self = .active
24+
case "inactive":
25+
self = .inactive
26+
default:
27+
self = .customValue(value)
28+
}
29+
}
30+
31+
public var description: String {
32+
switch self {
33+
case .active:
34+
return "active"
35+
case .inactive:
36+
return "inactive"
37+
case let .customValue(value):
38+
return value
39+
}
40+
}
41+
}
42+
43+
// A standard representation of a file request, as returned from any file request API endpoints by default.
44+
public final class FileRequest: BoxModel {
45+
46+
// MARK: - BoxModel
47+
48+
private static var resourceType: String = "file_request"
49+
/// Box item type
50+
public var type: String
51+
public private(set) var rawData: [String: Any]
52+
53+
// MARK: - Properties
54+
55+
/// The unique identifier for this file request.
56+
public let id: String
57+
/// The title of file request. This is shown in the Box UI to users uploading files.
58+
public let title: String?
59+
/// The optional description of this file request. This is shown in the Box UI to users uploading files.
60+
public let description: String?
61+
/// The status of the file request.
62+
public let status: FileRequestStatus?
63+
/// Whether a file request submitter is required to provide their email address. When this setting is set to true, the Box UI will show an email field on the file request form.
64+
public let isEmailRequired: Bool?
65+
/// Whether a file request submitter is required to provide a description of the files they are submitting.
66+
/// When this setting is set to true, the Box UI will show a description field on the file request form.
67+
public let isDescriptionRequired: Bool?
68+
/// The date after which a file request will no longer accept new submissions. After this date, the `status` will automatically be set to `inactive`.
69+
public let expiresAt: Date?
70+
/// The folder that this file request is associated with. Files submitted through the file request form will be uploaded to this folder.
71+
public let folder: Folder
72+
/// The generated URL for this file request. This URL can be shared with users to let them upload files to the associated folder.
73+
public let url: String?
74+
/// The HTTP `etag` of this file. This can be used in combination with the `If-Match` header when updating a file request.
75+
/// By providing that header, a change will only be performed on the file request if the `etag` on the file request still matches the `etag` provided in the `If-Match` header.
76+
public let etag: String?
77+
/// The user who created this file request.
78+
public let createdBy: User?
79+
/// The date and time when the file request was created.
80+
public let createdAt: Date
81+
/// The user who last modified this file request.
82+
public let updatedBy: User?
83+
/// The date and time when the file request was last updated.
84+
public let updatedAt: Date
85+
86+
/// Initializer.
87+
///
88+
/// - Parameter json: JSON dictionary.
89+
/// - Throws: Decoding error.
90+
public required init(json: [String: Any]) throws {
91+
guard let itemType = json["type"] as? String else {
92+
throw BoxCodingError(message: .typeMismatch(key: "type"))
93+
}
94+
95+
guard itemType == FileRequest.resourceType else {
96+
throw BoxCodingError(message: .valueMismatch(key: "type", value: itemType, acceptedValues: [FileRequest.resourceType]))
97+
}
98+
99+
type = itemType
100+
rawData = json
101+
id = try BoxJSONDecoder.decode(json: json, forKey: "id")
102+
title = try BoxJSONDecoder.optionalDecode(json: json, forKey: "title")
103+
description = try BoxJSONDecoder.optionalDecode(json: json, forKey: "description")
104+
status = try BoxJSONDecoder.optionalDecodeEnum(json: json, forKey: "status")
105+
isEmailRequired = try BoxJSONDecoder.optionalDecode(json: json, forKey: "is_email_required")
106+
isDescriptionRequired = try BoxJSONDecoder.optionalDecode(json: json, forKey: "is_description_required")
107+
expiresAt = try BoxJSONDecoder.optionalDecodeDate(json: json, forKey: "expires_at")
108+
folder = try BoxJSONDecoder.decode(json: json, forKey: "folder")
109+
url = try BoxJSONDecoder.optionalDecode(json: json, forKey: "url")
110+
etag = try BoxJSONDecoder.optionalDecode(json: json, forKey: "etag")
111+
createdBy = try BoxJSONDecoder.optionalDecode(json: json, forKey: "created_by")
112+
createdAt = try BoxJSONDecoder.decodeDate(json: json, forKey: "created_at")
113+
updatedBy = try BoxJSONDecoder.optionalDecode(json: json, forKey: "updated_by")
114+
updatedAt = try BoxJSONDecoder.decodeDate(json: json, forKey: "updated_at")
115+
}
116+
}

0 commit comments

Comments
 (0)