Skip to content

Commit 3f9e1e7

Browse files
committed
Release candidate for 1.5.x
1 parent a044b22 commit 3f9e1e7

File tree

204 files changed

+695
-524
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

204 files changed

+695
-524
lines changed

README.md

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ Add the package to your `Package.swift` dependencies:
3333

3434
```swift
3535
dependencies: [
36-
.package(url: "git@github.com:appwrite/sdk-for-swift.git", from: "5.0.0-rc.4"),
36+
.package(url: "git@github.com:appwrite/sdk-for-swift.git", from: "5.0.0-rc.5"),
3737
],
3838
```
3939

@@ -77,9 +77,11 @@ let users = Users(client)
7777

7878
do {
7979
let user = try await users.create(
80-
userId: ID.unique(),
81-
email: "email@example.com",
82-
password: "password"
80+
userId: ID.unique(),
81+
email: "email@example.com",
82+
phone: "+123456789",
83+
password: "password",
84+
name: "Walter O'Brien"
8385
)
8486
print(String(describing: user.toMap()))
8587
} catch {
@@ -103,9 +105,11 @@ func main() {
103105

104106
do {
105107
let user = try await users.create(
106-
userId: ID.unique(),
107-
email: "email@example.com",
108-
password: "password"
108+
userId: ID.unique(),
109+
email: "email@example.com",
110+
phone: "+123456789",
111+
password: "password",
112+
name: "Walter O'Brien"
109113
)
110114
print(String(describing: user.toMap()))
111115
} catch {

Sources/Appwrite/Client.swift

Lines changed: 78 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ open class Client {
2121
"x-sdk-name": "Swift",
2222
"x-sdk-platform": "server",
2323
"x-sdk-language": "swift",
24-
"x-sdk-version": "5.0.0-rc.4",
24+
"x-sdk-version": "5.0.0-rc.5",
2525
"x-appwrite-response-format": "1.5.0"
2626
]
2727

@@ -31,6 +31,8 @@ open class Client {
3131

3232
internal var http: HTTPClient
3333

34+
internal var httpForRedirect: HTTPClient
35+
3436
private static let boundaryChars = "abcdefghijklmnopqrstuvwxyz1234567890"
3537

3638
private static let boundary = randomBoundary()
@@ -41,25 +43,21 @@ open class Client {
4143

4244
public init() {
4345
http = Client.createHTTP()
46+
httpForRedirect = Client.createHTTP(redirectConfiguration: .disallow)
4447
addUserAgentHeader()
4548
addOriginHeader()
4649
}
4750

4851
private static func createHTTP(
4952
selfSigned: Bool = false,
50-
maxRedirects: Int = 5,
51-
alloweRedirectCycles: Bool = false,
53+
redirectConfiguration: HTTPClient.Configuration.RedirectConfiguration = .follow(max: 5, allowCycles: false),
5254
connectTimeout: TimeAmount = .seconds(30),
5355
readTimeout: TimeAmount = .seconds(30)
5456
) -> HTTPClient {
5557
let timeout = HTTPClient.Configuration.Timeout(
5658
connect: connectTimeout,
5759
read: readTimeout
5860
)
59-
let redirect = HTTPClient.Configuration.RedirectConfiguration.follow(
60-
max: 5,
61-
allowCycles: false
62-
)
6361
var tls = TLSConfiguration
6462
.makeClientConfiguration()
6563

@@ -71,7 +69,7 @@ open class Client {
7169
eventLoopGroupProvider: eventLoopGroupProvider,
7270
configuration: HTTPClient.Configuration(
7371
tlsConfiguration: tls,
74-
redirectConfiguration: redirect,
72+
redirectConfiguration: redirectConfiguration,
7573
timeout: timeout,
7674
decompression: .enabled(limit: .none)
7775
)
@@ -82,6 +80,7 @@ open class Client {
8280
deinit {
8381
do {
8482
try http.syncShutdown()
83+
try httpForRedirect.syncShutdown()
8584
} catch {
8685
print(error)
8786
}
@@ -160,21 +159,6 @@ open class Client {
160159
return self
161160
}
162161

163-
///
164-
/// Set ForwardedFor
165-
///
166-
/// The IP address of the client that made the request
167-
///
168-
/// @param String value
169-
///
170-
/// @return Client
171-
///
172-
open func setForwardedFor(_ value: String) -> Client {
173-
config["forwardedfor"] = value
174-
_ = addHeader(key: "X-Forwarded-For", value: value)
175-
return self
176-
}
177-
178162
///
179163
/// Set ForwardedUserAgent
180164
///
@@ -291,6 +275,74 @@ open class Client {
291275
sink: ((ByteBuffer) -> Void)? = nil,
292276
converter: ((Any) -> T)? = nil
293277
) async throws -> T {
278+
let request = try prepareRequest(
279+
method: method,
280+
path: path,
281+
headers: headers,
282+
params: params
283+
)
284+
285+
return try await execute(request, converter: converter)
286+
}
287+
288+
///
289+
/// Make an redirect API call
290+
///
291+
/// @param String method
292+
/// @param String path
293+
/// @param Dictionary<String, Any?> params
294+
/// @param Dictionary<String, String> headers
295+
/// @return String
296+
/// @throws Exception
297+
///
298+
open func redirect(
299+
method: String,
300+
path: String = "",
301+
headers: [String: String] = [:],
302+
params: [String: Any?] = [:]
303+
) async throws -> String? {
304+
let request = try prepareRequest(
305+
method: method,
306+
path: path,
307+
headers: headers,
308+
params: params
309+
)
310+
311+
let response = try await httpForRedirect.execute(
312+
request,
313+
timeout: .seconds(30)
314+
)
315+
316+
if response.status.code >= 400 {
317+
var message = ""
318+
var data = try await response.body.collect(upTo: Int.max)
319+
var type = ""
320+
321+
do {
322+
let dict = try JSONSerialization.jsonObject(with: data) as? [String: Any]
323+
324+
message = dict?["message"] as? String ?? response.status.reasonPhrase
325+
type = dict?["type"] as? String ?? ""
326+
} catch {
327+
message = data.readString(length: data.readableBytes)!
328+
}
329+
330+
throw AppwriteError(
331+
message: message,
332+
code: Int(response.status.code),
333+
type: type
334+
)
335+
}
336+
337+
return response.headers["location"].first
338+
}
339+
340+
private func prepareRequest(
341+
method: String,
342+
path: String = "",
343+
headers: [String: String] = [:],
344+
params: [String: Any?] = [:]
345+
) throws -> HTTPClientRequest {
294346
let validParams = params.filter { $0.value != nil }
295347

296348
let queryParameters = method == "GET" && !validParams.isEmpty
@@ -307,13 +359,11 @@ open class Client {
307359

308360
request.addDomainCookies()
309361

310-
if "GET" == method {
311-
return try await execute(request, converter: converter)
362+
if "GET" != method {
363+
try buildBody(for: &request, with: validParams)
312364
}
313365

314-
try buildBody(for: &request, with: validParams)
315-
316-
return try await execute(request, withSink: sink, converter: converter)
366+
return request
317367
}
318368

319369
private func buildBody(
@@ -329,7 +379,6 @@ open class Client {
329379

330380
private func execute<T>(
331381
_ request: HTTPClientRequest,
332-
withSink bufferSink: ((ByteBuffer) -> Void)? = nil,
333382
converter: ((Any) -> T)? = nil
334383
) async throws -> T {
335384
let response = try await http.execute(

Sources/Appwrite/Services/Account.swift

Lines changed: 64 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -404,7 +404,7 @@ open class Account: Service {
404404
/// @throws Exception
405405
/// @return array
406406
///
407-
open func create2FAChallenge(
407+
open func createChallenge(
408408
factor: AppwriteEnums.AuthenticationFactor
409409
) async throws -> AppwriteModels.MfaChallenge {
410410
let apiPath: String = "/account/mfa/challenge"
@@ -1220,42 +1220,36 @@ open class Account: Service {
12201220
/// @param AppwriteEnums.OAuthProvider provider
12211221
/// @param String success
12221222
/// @param String failure
1223-
/// @param Bool token
12241223
/// @param [String] scopes
12251224
/// @throws Exception
12261225
/// @return array
12271226
///
1228-
@available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *)
12291227
open func createOAuth2Session(
12301228
provider: AppwriteEnums.OAuthProvider,
12311229
success: String? = nil,
12321230
failure: String? = nil,
1233-
token: Bool? = nil,
12341231
scopes: [String]? = nil
1235-
) async throws -> Bool {
1232+
) async throws -> String? {
12361233
let apiPath: String = "/account/sessions/oauth2/{provider}"
12371234
.replacingOccurrences(of: "{provider}", with: provider.rawValue)
12381235

12391236
let apiParams: [String: Any?] = [
12401237
"success": success,
12411238
"failure": failure,
1242-
"token": token,
12431239
"scopes": scopes,
12441240
"project": client.config["project"]
12451241
]
12461242

1247-
let query = "?\(client.parametersToQueryString(params: apiParams))"
1248-
let url = URL(string: client.endPoint + apiPath + query)!
1249-
let callbackScheme = "appwrite-callback-\(client.config["project"] ?? "")"
1250-
1251-
_ = try await withCheckedThrowingContinuation { continuation in
1252-
WebAuthComponent.authenticate(url: url, callbackScheme: callbackScheme) { result in
1253-
continuation.resume(with: result)
1254-
}
1255-
}
1256-
1257-
return true
1243+
let apiHeaders: [String: String] = [
1244+
"content-type": "application/json"
1245+
]
12581246

1247+
return try await client.redirect(
1248+
method: "GET",
1249+
path: apiPath,
1250+
headers: apiHeaders,
1251+
params: apiParams
1252+
)
12591253
}
12601254

12611255
///
@@ -1560,6 +1554,59 @@ open class Account: Service {
15601554
)
15611555
}
15621556

1557+
///
1558+
/// Create OAuth2 token
1559+
///
1560+
/// Allow the user to login to their account using the OAuth2 provider of their
1561+
/// choice. Each OAuth2 provider should be enabled from the Appwrite console
1562+
/// first. Use the success and failure arguments to provide a redirect URL's
1563+
/// back to your app when login is completed.
1564+
///
1565+
/// If authentication succeeds, `userId` and `secret` of a token will be
1566+
/// appended to the success URL as query parameters. These can be used to
1567+
/// create a new session using the [Create
1568+
/// session](https://appwrite.io/docs/references/cloud/client-web/account#createSession)
1569+
/// endpoint.
1570+
///
1571+
/// A user is limited to 10 active sessions at a time by default. [Learn more
1572+
/// about session
1573+
/// limits](https://appwrite.io/docs/authentication-security#limits).
1574+
///
1575+
/// @param AppwriteEnums.OAuthProvider provider
1576+
/// @param String success
1577+
/// @param String failure
1578+
/// @param [String] scopes
1579+
/// @throws Exception
1580+
/// @return array
1581+
///
1582+
open func createOAuth2Token(
1583+
provider: AppwriteEnums.OAuthProvider,
1584+
success: String? = nil,
1585+
failure: String? = nil,
1586+
scopes: [String]? = nil
1587+
) async throws -> String? {
1588+
let apiPath: String = "/account/tokens/oauth2/{provider}"
1589+
.replacingOccurrences(of: "{provider}", with: provider.rawValue)
1590+
1591+
let apiParams: [String: Any?] = [
1592+
"success": success,
1593+
"failure": failure,
1594+
"scopes": scopes,
1595+
"project": client.config["project"]
1596+
]
1597+
1598+
let apiHeaders: [String: String] = [
1599+
"content-type": "application/json"
1600+
]
1601+
1602+
return try await client.redirect(
1603+
method: "GET",
1604+
path: apiPath,
1605+
headers: apiHeaders,
1606+
params: apiParams
1607+
)
1608+
}
1609+
15631610
///
15641611
/// Create phone token
15651612
///

0 commit comments

Comments
 (0)