diff --git a/CHANGELOG.md b/CHANGELOG.md index 12b7396..1f1cc83 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,16 @@ +## 6.0.0 +* Support for Appwrite 0.15 +* **NEW** Phone authentication `account.createPhoneSession()` +* **BREAKING** `Database` -> `Databases` +* **BREAKING** `account.createSession()` -> `account.createEmailSession()` +* **BREAKING** `dateCreated` attribute removed from `Team`, `Execution`, `File` models +* **BREAKING** `dateCreated` and `dateUpdated` attribute removed from `Func`, `Deployment`, `Bucket` models +* **BREAKING** Realtime channels + * collections.[COLLECTION_ID] is now databases.[DATABASE_ID].ollections.[COLLECTION_ID] + * collections.[COLLECTION_ID].documents is now databases.[DATABASE_ID].ollections.[COLLECTION_ID].documents + +**Full Changelog for Appwrite 0.15 can be found here**: https://github.com/appwrite/appwrite/blob/master/CHANGES.md#version-0150 + ## 5.0.0 * Support for Appwrite 0.14 * **BREAKING** `account.delete()` -> `account.updateStatus()` diff --git a/README.md b/README.md index 69d2360..3fb6d2a 100644 --- a/README.md +++ b/README.md @@ -2,12 +2,12 @@ [![pub package](https://img.shields.io/pub/v/appwrite?style=flat-square)](https://pub.dartlang.org/packages/appwrite) ![License](https://img.shields.io/github/license/appwrite/sdk-for-flutter.svg?style=flat-square) -![Version](https://img.shields.io/badge/api%20version-0.14.0-blue.svg?style=flat-square) +![Version](https://img.shields.io/badge/api%20version-0.15.0-blue.svg?style=flat-square) [![Build Status](https://img.shields.io/travis/com/appwrite/sdk-generator?style=flat-square)](https://travis-ci.com/appwrite/sdk-generator) [![Twitter Account](https://img.shields.io/twitter/follow/appwrite?color=00acee&label=twitter&style=flat-square)](https://twitter.com/appwrite) [![Discord](https://img.shields.io/discord/564160730845151244?label=discord&style=flat-square)](https://appwrite.io/discord) -**This SDK is compatible with Appwrite server version 0.14.x. For older versions, please check [previous releases](https://github.com/appwrite/sdk-for-flutter/releases).** +**This SDK is compatible with Appwrite server version 0.15.x. For older versions, please check [previous releases](https://github.com/appwrite/sdk-for-flutter/releases).** Appwrite is an open-source backend as a service server that abstract and simplify complex and repetitive development tasks behind a very simple to use REST API. Appwrite aims to help you develop your apps faster and in a more secure way. Use the Flutter SDK to integrate your app with the Appwrite server to easily start interacting with all of Appwrite backend APIs and tools. For full API documentation and tutorials go to [https://appwrite.io/docs](https://appwrite.io/docs) @@ -21,7 +21,7 @@ Add this to your package's `pubspec.yaml` file: ```yml dependencies: - appwrite: ^5.0.0 + appwrite: ^6.0.0 ``` You can install packages from the command line: @@ -43,11 +43,14 @@ If you are building your Flutter application for multiple devices, you have to f ### Android For **Android** first add your app name and package name, Your package name is generally the **applicationId** in your app-level build.gradle file. By registering your new app platform, you are allowing your app to communicate with the Appwrite API. -In order to capture the Appwrite OAuth callback url, the following activity needs to be added to your [AndroidManifest.xml](https://github.com/appwrite/playground-for-flutter/blob/master/android/app/src/main/AndroidManifest.xml). Be sure to replace the **[PROJECT_ID]** string with your actual Appwrite project ID. You can find your Appwrite project ID in your project settings screen in the console. +In order to capture the Appwrite OAuth callback url, the following activity needs to be added inside the `` tag, along side the existing `` tags in your [AndroidManifest.xml](https://github.com/appwrite/playground-for-flutter/blob/master/android/app/src/main/AndroidManifest.xml). Be sure to replace the **[PROJECT_ID]** string with your actual Appwrite project ID. You can find your Appwrite project ID in your project settings screen in the console. ```xml - - + + .... + + .... + diff --git a/docs/examples/account/create-session.md b/docs/examples/account/create-email-session.md similarity index 90% rename from docs/examples/account/create-session.md rename to docs/examples/account/create-email-session.md index 6233665..6cbb227 100644 --- a/docs/examples/account/create-session.md +++ b/docs/examples/account/create-email-session.md @@ -8,7 +8,7 @@ void main() { // Init SDK .setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint .setProject('5df5acd0d48c2') // Your project ID ; - Future result = account.createSession( + Future result = account.createEmailSession( email: 'email@example.com', password: 'password', ); diff --git a/docs/examples/account/create-phone-session.md b/docs/examples/account/create-phone-session.md new file mode 100644 index 0000000..e1cd25a --- /dev/null +++ b/docs/examples/account/create-phone-session.md @@ -0,0 +1,22 @@ +import 'package:appwrite/appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Account account = Account(client); + + client + .setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + ; + Future result = account.createPhoneSession( + userId: '[USER_ID]', + number: '', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} diff --git a/docs/examples/account/create-phone-verification.md b/docs/examples/account/create-phone-verification.md new file mode 100644 index 0000000..ee16f76 --- /dev/null +++ b/docs/examples/account/create-phone-verification.md @@ -0,0 +1,19 @@ +import 'package:appwrite/appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Account account = Account(client); + + client + .setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + ; + Future result = account.createPhoneVerification(); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} diff --git a/docs/examples/account/update-phone-session.md b/docs/examples/account/update-phone-session.md new file mode 100644 index 0000000..2125266 --- /dev/null +++ b/docs/examples/account/update-phone-session.md @@ -0,0 +1,22 @@ +import 'package:appwrite/appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Account account = Account(client); + + client + .setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + ; + Future result = account.updatePhoneSession( + userId: '[USER_ID]', + secret: '[SECRET]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} diff --git a/docs/examples/account/update-phone-verification.md b/docs/examples/account/update-phone-verification.md new file mode 100644 index 0000000..9ad71fe --- /dev/null +++ b/docs/examples/account/update-phone-verification.md @@ -0,0 +1,22 @@ +import 'package:appwrite/appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Account account = Account(client); + + client + .setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + ; + Future result = account.updatePhoneVerification( + userId: '[USER_ID]', + secret: '[SECRET]', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} diff --git a/docs/examples/account/update-phone.md b/docs/examples/account/update-phone.md new file mode 100644 index 0000000..1269349 --- /dev/null +++ b/docs/examples/account/update-phone.md @@ -0,0 +1,22 @@ +import 'package:appwrite/appwrite.dart'; + +void main() { // Init SDK + Client client = Client(); + Account account = Account(client); + + client + .setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + ; + Future result = account.updatePhone( + number: '', + password: 'password', + ); + + result + .then((response) { + print(response); + }).catchError((error) { + print(error.response); + }); +} diff --git a/docs/examples/database/create-document.md b/docs/examples/databases/create-document.md similarity index 79% rename from docs/examples/database/create-document.md rename to docs/examples/databases/create-document.md index 9027b71..6c4b9b8 100644 --- a/docs/examples/database/create-document.md +++ b/docs/examples/databases/create-document.md @@ -2,13 +2,13 @@ import 'package:appwrite/appwrite.dart'; void main() { // Init SDK Client client = Client(); - Database database = Database(client); + Databases databases = Databases(client, databaseId: '[DATABASE_ID]'); client .setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint .setProject('5df5acd0d48c2') // Your project ID ; - Future result = database.createDocument( + Future result = databases.createDocument( collectionId: '[COLLECTION_ID]', documentId: '[DOCUMENT_ID]', data: {}, diff --git a/docs/examples/database/delete-document.md b/docs/examples/databases/delete-document.md similarity index 78% rename from docs/examples/database/delete-document.md rename to docs/examples/databases/delete-document.md index 94479a0..a57ed8e 100644 --- a/docs/examples/database/delete-document.md +++ b/docs/examples/databases/delete-document.md @@ -2,13 +2,13 @@ import 'package:appwrite/appwrite.dart'; void main() { // Init SDK Client client = Client(); - Database database = Database(client); + Databases databases = Databases(client, databaseId: '[DATABASE_ID]'); client .setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint .setProject('5df5acd0d48c2') // Your project ID ; - Future result = database.deleteDocument( + Future result = databases.deleteDocument( collectionId: '[COLLECTION_ID]', documentId: '[DOCUMENT_ID]', ); diff --git a/docs/examples/database/get-document.md b/docs/examples/databases/get-document.md similarity index 79% rename from docs/examples/database/get-document.md rename to docs/examples/databases/get-document.md index 153ad8e..585ac2b 100644 --- a/docs/examples/database/get-document.md +++ b/docs/examples/databases/get-document.md @@ -2,13 +2,13 @@ import 'package:appwrite/appwrite.dart'; void main() { // Init SDK Client client = Client(); - Database database = Database(client); + Databases databases = Databases(client, databaseId: '[DATABASE_ID]'); client .setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint .setProject('5df5acd0d48c2') // Your project ID ; - Future result = database.getDocument( + Future result = databases.getDocument( collectionId: '[COLLECTION_ID]', documentId: '[DOCUMENT_ID]', ); diff --git a/docs/examples/database/list-documents.md b/docs/examples/databases/list-documents.md similarity index 77% rename from docs/examples/database/list-documents.md rename to docs/examples/databases/list-documents.md index dc6893a..6ac1153 100644 --- a/docs/examples/database/list-documents.md +++ b/docs/examples/databases/list-documents.md @@ -2,13 +2,13 @@ import 'package:appwrite/appwrite.dart'; void main() { // Init SDK Client client = Client(); - Database database = Database(client); + Databases databases = Databases(client, databaseId: '[DATABASE_ID]'); client .setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint .setProject('5df5acd0d48c2') // Your project ID ; - Future result = database.listDocuments( + Future result = databases.listDocuments( collectionId: '[COLLECTION_ID]', ); diff --git a/docs/examples/database/update-document.md b/docs/examples/databases/update-document.md similarity index 78% rename from docs/examples/database/update-document.md rename to docs/examples/databases/update-document.md index 65c23a2..f27139f 100644 --- a/docs/examples/database/update-document.md +++ b/docs/examples/databases/update-document.md @@ -2,16 +2,15 @@ import 'package:appwrite/appwrite.dart'; void main() { // Init SDK Client client = Client(); - Database database = Database(client); + Databases databases = Databases(client, databaseId: '[DATABASE_ID]'); client .setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint .setProject('5df5acd0d48c2') // Your project ID ; - Future result = database.updateDocument( + Future result = databases.updateDocument( collectionId: '[COLLECTION_ID]', documentId: '[DOCUMENT_ID]', - data: {}, ); result diff --git a/lib/appwrite.dart b/lib/appwrite.dart index 9a841b4..e43fb1b 100644 --- a/lib/appwrite.dart +++ b/lib/appwrite.dart @@ -3,14 +3,14 @@ library appwrite; import 'dart:async'; import 'dart:typed_data'; import 'package:flutter/foundation.dart'; -import 'src/chunked_upload_stub.dart' - if (dart.library.io) 'src/chunked_upload_io.dart'; +import 'package:http/http.dart' show MultipartFile; import 'src/enums.dart'; import 'src/client.dart'; import 'src/service.dart'; import 'src/input_file.dart'; import 'models.dart' as models; import 'src/upload_progress.dart'; +import 'src/exception.dart'; export 'src/response.dart'; export 'src/client.dart'; @@ -20,12 +20,11 @@ export 'src/upload_progress.dart'; export 'src/realtime_subscription.dart'; export 'src/realtime_message.dart'; export 'src/input_file.dart'; -export 'package:http/http.dart' show MultipartFile; part 'query.dart'; part 'services/account.dart'; part 'services/avatars.dart'; -part 'services/database.dart'; +part 'services/databases.dart'; part 'services/functions.dart'; part 'services/locale.dart'; part 'services/storage.dart'; diff --git a/lib/services/account.dart b/lib/services/account.dart index 10708c8..d2ead1d 100644 --- a/lib/services/account.dart +++ b/lib/services/account.dart @@ -1,6 +1,5 @@ part of appwrite; - /// The Account service allows you to authenticate and manage a user account. class Account extends Service { Account(Client client): super(client); @@ -13,14 +12,20 @@ class Account extends Service { const String path = '/account'; final Map params = { + + }; final Map headers = { - 'content-type': 'application/json', + 'content-type': 'application/json', + }; final res = await client.call(HttpMethod.get, path: path, params: params, headers: headers); + return models.User.fromMap(res.data); + + } /// Create Account @@ -36,18 +41,24 @@ class Account extends Service { const String path = '/account'; final Map params = { + 'userId': userId, - 'email': email, - 'password': password, - 'name': name, +'email': email, +'password': password, +'name': name, + }; final Map headers = { - 'content-type': 'application/json', + 'content-type': 'application/json', + }; final res = await client.call(HttpMethod.post, path: path, params: params, headers: headers); + return models.User.fromMap(res.data); + + } /// Update Account Email @@ -65,16 +76,22 @@ class Account extends Service { const String path = '/account/email'; final Map params = { + 'email': email, - 'password': password, +'password': password, + }; final Map headers = { - 'content-type': 'application/json', + 'content-type': 'application/json', + }; final res = await client.call(HttpMethod.patch, path: path, params: params, headers: headers); + return models.User.fromMap(res.data); + + } /// Create Account JWT @@ -89,14 +106,20 @@ class Account extends Service { const String path = '/account/jwt'; final Map params = { + + }; final Map headers = { - 'content-type': 'application/json', + 'content-type': 'application/json', + }; final res = await client.call(HttpMethod.post, path: path, params: params, headers: headers); + return models.Jwt.fromMap(res.data); + + } /// Get Account Logs @@ -109,15 +132,21 @@ class Account extends Service { final Map params = { 'limit': limit, - 'offset': offset, +'offset': offset, + + }; final Map headers = { - 'content-type': 'application/json', + 'content-type': 'application/json', + }; final res = await client.call(HttpMethod.get, path: path, params: params, headers: headers); + return models.LogList.fromMap(res.data); + + } /// Update Account Name @@ -128,15 +157,21 @@ class Account extends Service { const String path = '/account/name'; final Map params = { + 'name': name, + }; final Map headers = { - 'content-type': 'application/json', + 'content-type': 'application/json', + }; final res = await client.call(HttpMethod.patch, path: path, params: params, headers: headers); + return models.User.fromMap(res.data); + + } /// Update Account Password @@ -149,16 +184,51 @@ class Account extends Service { const String path = '/account/password'; final Map params = { + 'password': password, - 'oldPassword': oldPassword, +'oldPassword': oldPassword, + }; final Map headers = { - 'content-type': 'application/json', + 'content-type': 'application/json', + }; final res = await client.call(HttpMethod.patch, path: path, params: params, headers: headers); + return models.User.fromMap(res.data); + + + } + + /// Update Account Phone + /// + /// Update currently logged in user account phone number. After changing phone + /// number, the user confirmation status will get reset. A new confirmation SMS + /// is not sent automatically however you can use the phone confirmation + /// endpoint again to send the confirmation SMS. + /// + Future updatePhone({required String number, required String password}) async { + const String path = '/account/phone'; + + final Map params = { + + 'number': number, +'password': password, + + }; + + final Map headers = { + 'content-type': 'application/json', + + }; + + final res = await client.call(HttpMethod.patch, path: path, params: params, headers: headers); + + return models.User.fromMap(res.data); + + } /// Get Account Preferences @@ -169,14 +239,20 @@ class Account extends Service { const String path = '/account/prefs'; final Map params = { + + }; final Map headers = { - 'content-type': 'application/json', + 'content-type': 'application/json', + }; final res = await client.call(HttpMethod.get, path: path, params: params, headers: headers); + return models.Preferences.fromMap(res.data); + + } /// Update Account Preferences @@ -189,15 +265,21 @@ class Account extends Service { const String path = '/account/prefs'; final Map params = { + 'prefs': prefs, + }; final Map headers = { - 'content-type': 'application/json', + 'content-type': 'application/json', + }; final res = await client.call(HttpMethod.patch, path: path, params: params, headers: headers); + return models.User.fromMap(res.data); + + } /// Create Password Recovery @@ -215,16 +297,22 @@ class Account extends Service { const String path = '/account/recovery'; final Map params = { + 'email': email, - 'url': url, +'url': url, + }; final Map headers = { - 'content-type': 'application/json', + 'content-type': 'application/json', + }; final res = await client.call(HttpMethod.post, path: path, params: params, headers: headers); + return models.Token.fromMap(res.data); + + } /// Create Password Recovery (confirmation) @@ -243,18 +331,24 @@ class Account extends Service { const String path = '/account/recovery'; final Map params = { + 'userId': userId, - 'secret': secret, - 'password': password, - 'passwordAgain': passwordAgain, +'secret': secret, +'password': password, +'passwordAgain': passwordAgain, + }; final Map headers = { - 'content-type': 'application/json', + 'content-type': 'application/json', + }; final res = await client.call(HttpMethod.put, path: path, params: params, headers: headers); + return models.Token.fromMap(res.data); + + } /// Get Account Sessions @@ -266,35 +360,20 @@ class Account extends Service { const String path = '/account/sessions'; final Map params = { + + }; final Map headers = { - 'content-type': 'application/json', + 'content-type': 'application/json', + }; final res = await client.call(HttpMethod.get, path: path, params: params, headers: headers); + return models.SessionList.fromMap(res.data); - } - /// Create Account Session - /// - /// Allow the user to login into their account by providing a valid email and - /// password combination. This route will create a new session for the user. - /// - Future createSession({required String email, required String password}) async { - const String path = '/account/sessions'; - final Map params = { - 'email': email, - 'password': password, - }; - - final Map headers = { - 'content-type': 'application/json', - }; - - final res = await client.call(HttpMethod.post, path: path, params: params, headers: headers); - return models.Session.fromMap(res.data); } /// Delete All Account Sessions @@ -306,14 +385,20 @@ class Account extends Service { const String path = '/account/sessions'; final Map params = { + + }; final Map headers = { - 'content-type': 'application/json', + 'content-type': 'application/json', + }; final res = await client.call(HttpMethod.delete, path: path, params: params, headers: headers); + return res.data; + + } /// Create Anonymous Session @@ -329,14 +414,47 @@ class Account extends Service { const String path = '/account/sessions/anonymous'; final Map params = { + + }; final Map headers = { - 'content-type': 'application/json', + 'content-type': 'application/json', + }; final res = await client.call(HttpMethod.post, path: path, params: params, headers: headers); + return models.Session.fromMap(res.data); + + + } + + /// Create Account Session with Email + /// + /// Allow the user to login into their account by providing a valid email and + /// password combination. This route will create a new session for the user. + /// + Future createEmailSession({required String email, required String password}) async { + const String path = '/account/sessions/email'; + + final Map params = { + + 'email': email, +'password': password, + + }; + + final Map headers = { + 'content-type': 'application/json', + + }; + + final res = await client.call(HttpMethod.post, path: path, params: params, headers: headers); + + return models.Session.fromMap(res.data); + + } /// Create Magic URL session @@ -356,17 +474,23 @@ class Account extends Service { const String path = '/account/sessions/magic-url'; final Map params = { + 'userId': userId, - 'email': email, - 'url': url, +'email': email, +'url': url, + }; final Map headers = { - 'content-type': 'application/json', + 'content-type': 'application/json', + }; final res = await client.call(HttpMethod.post, path: path, params: params, headers: headers); + return models.Token.fromMap(res.data); + + } /// Create Magic URL session (confirmation) @@ -387,16 +511,22 @@ class Account extends Service { const String path = '/account/sessions/magic-url'; final Map params = { + 'userId': userId, - 'secret': secret, +'secret': secret, + }; final Map headers = { - 'content-type': 'application/json', + 'content-type': 'application/json', + }; final res = await client.call(HttpMethod.put, path: path, params: params, headers: headers); + return models.Session.fromMap(res.data); + + } /// Create Account Session with OAuth2 @@ -419,12 +549,13 @@ class Account extends Service { final Map params = { 'success': success, - 'failure': failure, - 'scopes': scopes, +'failure': failure, +'scopes': scopes, + + 'project': client.config['project'], }; - final List query = []; params.forEach((key, value) { @@ -447,6 +578,72 @@ class Account extends Service { return client.webAuth(url); + } + + /// Create Phone session + /// + /// Sends the user a SMS with a secret key for creating a session. Use the + /// returned user ID and the secret to submit a request to the [PUT + /// /account/sessions/phone](/docs/client/account#accountUpdatePhoneSession) + /// endpoint to complete the login process. The secret sent to the user's phone + /// is valid for 15 minutes. + /// + Future createPhoneSession({required String userId, required String number}) async { + const String path = '/account/sessions/phone'; + + final Map params = { + + 'userId': userId, +'number': number, + + }; + + final Map headers = { + 'content-type': 'application/json', + + }; + + final res = await client.call(HttpMethod.post, path: path, params: params, headers: headers); + + return models.Token.fromMap(res.data); + + + } + + /// Create Phone session (confirmation) + /// + /// Use this endpoint to complete creating the session with the Magic URL. Both + /// the **userId** and **secret** arguments will be passed as query parameters + /// to the redirect URL you have provided when sending your request to the + /// [POST + /// /account/sessions/magic-url](/docs/client/account#accountCreateMagicURLSession) + /// endpoint. + /// + /// Please note that in order to avoid a [Redirect + /// Attack](https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md) + /// the only valid redirect URLs are the ones from domains you have set when + /// adding your platforms in the console interface. + /// + Future updatePhoneSession({required String userId, required String secret}) async { + const String path = '/account/sessions/phone'; + + final Map params = { + + 'userId': userId, +'secret': secret, + + }; + + final Map headers = { + 'content-type': 'application/json', + + }; + + final res = await client.call(HttpMethod.put, path: path, params: params, headers: headers); + + return models.Session.fromMap(res.data); + + } /// Get Session By ID @@ -458,14 +655,20 @@ class Account extends Service { final String path = '/account/sessions/{sessionId}'.replaceAll('{sessionId}', sessionId); final Map params = { + + }; final Map headers = { - 'content-type': 'application/json', + 'content-type': 'application/json', + }; final res = await client.call(HttpMethod.get, path: path, params: params, headers: headers); + return models.Session.fromMap(res.data); + + } /// Update Session (Refresh Tokens) @@ -478,14 +681,20 @@ class Account extends Service { final String path = '/account/sessions/{sessionId}'.replaceAll('{sessionId}', sessionId); final Map params = { + + }; final Map headers = { - 'content-type': 'application/json', + 'content-type': 'application/json', + }; final res = await client.call(HttpMethod.patch, path: path, params: params, headers: headers); + return models.Session.fromMap(res.data); + + } /// Delete Account Session @@ -499,14 +708,20 @@ class Account extends Service { final String path = '/account/sessions/{sessionId}'.replaceAll('{sessionId}', sessionId); final Map params = { + + }; final Map headers = { - 'content-type': 'application/json', + 'content-type': 'application/json', + }; final res = await client.call(HttpMethod.delete, path: path, params: params, headers: headers); + return res.data; + + } /// Update Account Status @@ -519,14 +734,20 @@ class Account extends Service { const String path = '/account/status'; final Map params = { + + }; final Map headers = { - 'content-type': 'application/json', + 'content-type': 'application/json', + }; final res = await client.call(HttpMethod.patch, path: path, params: params, headers: headers); + return models.User.fromMap(res.data); + + } /// Create Email Verification @@ -538,8 +759,8 @@ class Account extends Service { /// should redirect the user back to your app and allow you to complete the /// verification process by verifying both the **userId** and **secret** /// parameters. Learn more about how to [complete the verification - /// process](/docs/client/account#accountUpdateVerification). The verification - /// link sent to the user's email address is valid for 7 days. + /// process](/docs/client/account#accountUpdateEmailVerification). The + /// verification link sent to the user's email address is valid for 7 days. /// /// Please note that in order to avoid a [Redirect /// Attack](https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md), @@ -551,15 +772,21 @@ class Account extends Service { const String path = '/account/verification'; final Map params = { + 'url': url, + }; final Map headers = { - 'content-type': 'application/json', + 'content-type': 'application/json', + }; final res = await client.call(HttpMethod.post, path: path, params: params, headers: headers); + return models.Token.fromMap(res.data); + + } /// Create Email Verification (confirmation) @@ -573,15 +800,80 @@ class Account extends Service { const String path = '/account/verification'; final Map params = { + 'userId': userId, - 'secret': secret, +'secret': secret, + }; final Map headers = { - 'content-type': 'application/json', + 'content-type': 'application/json', + }; final res = await client.call(HttpMethod.put, path: path, params: params, headers: headers); + return models.Token.fromMap(res.data); + + + } + + /// Create Phone Verification + /// + /// Use this endpoint to send a verification message to your user's phone + /// number to confirm they are the valid owners of that address. The provided + /// secret should allow you to complete the verification process by verifying + /// both the **userId** and **secret** parameters. Learn more about how to + /// [complete the verification + /// process](/docs/client/account#accountUpdatePhoneVerification). The + /// verification link sent to the user's phone number is valid for 15 minutes. + /// + Future createPhoneVerification() async { + const String path = '/account/verification/phone'; + + final Map params = { + + + }; + + final Map headers = { + 'content-type': 'application/json', + + }; + + final res = await client.call(HttpMethod.post, path: path, params: params, headers: headers); + + return models.Token.fromMap(res.data); + + + } + + /// Create Phone Verification (confirmation) + /// + /// Use this endpoint to complete the user phone verification process. Use the + /// **userId** and **secret** that were sent to your user's phone number to + /// verify the user email ownership. If confirmed this route will return a 200 + /// status code. + /// + Future updatePhoneVerification({required String userId, required String secret}) async { + const String path = '/account/verification/phone'; + + final Map params = { + + 'userId': userId, +'secret': secret, + + }; + + final Map headers = { + 'content-type': 'application/json', + + }; + + final res = await client.call(HttpMethod.put, path: path, params: params, headers: headers); + + return models.Token.fromMap(res.data); + + } } \ No newline at end of file diff --git a/lib/services/avatars.dart b/lib/services/avatars.dart index 5ea674f..dff7e2c 100644 --- a/lib/services/avatars.dart +++ b/lib/services/avatars.dart @@ -1,6 +1,5 @@ part of appwrite; - /// The Avatars service aims to help you complete everyday tasks related to /// your app image, icons, and avatars. class Avatars extends Service { @@ -23,13 +22,16 @@ class Avatars extends Service { final Map params = { 'width': width, - 'height': height, - 'quality': quality, +'height': height, +'quality': quality, + + 'project': client.config['project'], }; final res = await client.call(HttpMethod.get, path: path, params: params, responseType: ResponseType.bytes); return res.data; + } /// Get Credit Card Icon @@ -49,13 +51,16 @@ class Avatars extends Service { final Map params = { 'width': width, - 'height': height, - 'quality': quality, +'height': height, +'quality': quality, + + 'project': client.config['project'], }; final res = await client.call(HttpMethod.get, path: path, params: params, responseType: ResponseType.bytes); return res.data; + } /// Get Favicon @@ -69,11 +74,14 @@ class Avatars extends Service { final Map params = { 'url': url, + + 'project': client.config['project'], }; final res = await client.call(HttpMethod.get, path: path, params: params, responseType: ResponseType.bytes); return res.data; + } /// Get Country Flag @@ -93,13 +101,16 @@ class Avatars extends Service { final Map params = { 'width': width, - 'height': height, - 'quality': quality, +'height': height, +'quality': quality, + + 'project': client.config['project'], }; final res = await client.call(HttpMethod.get, path: path, params: params, responseType: ResponseType.bytes); return res.data; + } /// Get Image from URL @@ -120,13 +131,16 @@ class Avatars extends Service { final Map params = { 'url': url, - 'width': width, - 'height': height, +'width': width, +'height': height, + + 'project': client.config['project'], }; final res = await client.call(HttpMethod.get, path: path, params: params, responseType: ResponseType.bytes); return res.data; + } /// Get User Initials @@ -153,15 +167,18 @@ class Avatars extends Service { final Map params = { 'name': name, - 'width': width, - 'height': height, - 'color': color, - 'background': background, +'width': width, +'height': height, +'color': color, +'background': background, + + 'project': client.config['project'], }; final res = await client.call(HttpMethod.get, path: path, params: params, responseType: ResponseType.bytes); return res.data; + } /// Get QR Code @@ -175,13 +192,16 @@ class Avatars extends Service { final Map params = { 'text': text, - 'size': size, - 'margin': margin, - 'download': download, +'size': size, +'margin': margin, +'download': download, + + 'project': client.config['project'], }; final res = await client.call(HttpMethod.get, path: path, params: params, responseType: ResponseType.bytes); return res.data; + } } \ No newline at end of file diff --git a/lib/services/database.dart b/lib/services/database.dart deleted file mode 100644 index 4a75bfd..0000000 --- a/lib/services/database.dart +++ /dev/null @@ -1,120 +0,0 @@ -part of appwrite; - - - /// The Database service allows you to create structured collections of - /// documents, query and filter lists of documents -class Database extends Service { - Database(Client client): super(client); - - /// List Documents - /// - /// Get a list of all the user documents. You can use the query params to - /// filter your results. On admin mode, this endpoint will return a list of all - /// of the project's documents. [Learn more about different API - /// modes](/docs/admin). - /// - Future listDocuments({required String collectionId, List? queries, int? limit, int? offset, String? cursor, String? cursorDirection, List? orderAttributes, List? orderTypes}) async { - final String path = '/database/collections/{collectionId}/documents'.replaceAll('{collectionId}', collectionId); - - final Map params = { - 'queries': queries, - 'limit': limit, - 'offset': offset, - 'cursor': cursor, - 'cursorDirection': cursorDirection, - 'orderAttributes': orderAttributes, - 'orderTypes': orderTypes, - }; - - final Map headers = { - 'content-type': 'application/json', - }; - - final res = await client.call(HttpMethod.get, path: path, params: params, headers: headers); - return models.DocumentList.fromMap(res.data); - } - - /// Create Document - /// - /// Create a new Document. Before using this route, you should create a new - /// collection resource using either a [server - /// integration](/docs/server/database#databaseCreateCollection) API or - /// directly from your database console. - /// - Future createDocument({required String collectionId, required String documentId, required Map data, List? read, List? write}) async { - final String path = '/database/collections/{collectionId}/documents'.replaceAll('{collectionId}', collectionId); - - final Map params = { - 'documentId': documentId, - 'data': data, - 'read': read, - 'write': write, - }; - - final Map headers = { - 'content-type': 'application/json', - }; - - final res = await client.call(HttpMethod.post, path: path, params: params, headers: headers); - return models.Document.fromMap(res.data); - } - - /// Get Document - /// - /// Get a document by its unique ID. This endpoint response returns a JSON - /// object with the document data. - /// - Future getDocument({required String collectionId, required String documentId}) async { - final String path = '/database/collections/{collectionId}/documents/{documentId}'.replaceAll('{collectionId}', collectionId).replaceAll('{documentId}', documentId); - - final Map params = { - }; - - final Map headers = { - 'content-type': 'application/json', - }; - - final res = await client.call(HttpMethod.get, path: path, params: params, headers: headers); - return models.Document.fromMap(res.data); - } - - /// Update Document - /// - /// Update a document by its unique ID. Using the patch method you can pass - /// only specific fields that will get updated. - /// - Future updateDocument({required String collectionId, required String documentId, required Map data, List? read, List? write}) async { - final String path = '/database/collections/{collectionId}/documents/{documentId}'.replaceAll('{collectionId}', collectionId).replaceAll('{documentId}', documentId); - - final Map params = { - 'data': data, - 'read': read, - 'write': write, - }; - - final Map headers = { - 'content-type': 'application/json', - }; - - final res = await client.call(HttpMethod.patch, path: path, params: params, headers: headers); - return models.Document.fromMap(res.data); - } - - /// Delete Document - /// - /// Delete a document by its unique ID. - /// - Future deleteDocument({required String collectionId, required String documentId}) async { - final String path = '/database/collections/{collectionId}/documents/{documentId}'.replaceAll('{collectionId}', collectionId).replaceAll('{documentId}', documentId); - - final Map params = { - }; - - final Map headers = { - 'content-type': 'application/json', - }; - - final res = await client.call(HttpMethod.delete, path: path, params: params, headers: headers); - return res.data; - } -} \ No newline at end of file diff --git a/lib/services/databases.dart b/lib/services/databases.dart new file mode 100644 index 0000000..3101115 --- /dev/null +++ b/lib/services/databases.dart @@ -0,0 +1,127 @@ +part of appwrite; + + /// The Databases service allows you to create structured collections of + /// documents, query and filter lists of documents +class Databases extends Service { + Databases(Client client, {required this.databaseId}): super(client); + String databaseId; + + /// List Documents + Future listDocuments({required String collectionId, List? queries, int? limit, int? offset, String? cursor, String? cursorDirection, List? orderAttributes, List? orderTypes}) async { + final String path = '/databases/{databaseId}/collections/{collectionId}/documents'.replaceAll('{databaseId}', databaseId).replaceAll('{collectionId}', collectionId); + + final Map params = { + 'queries': queries, +'limit': limit, +'offset': offset, +'cursor': cursor, +'cursorDirection': cursorDirection, +'orderAttributes': orderAttributes, +'orderTypes': orderTypes, + + + }; + + final Map headers = { + 'content-type': 'application/json', + + }; + + final res = await client.call(HttpMethod.get, path: path, params: params, headers: headers); + + return models.DocumentList.fromMap(res.data); + + + } + + /// Create Document + Future createDocument({required String collectionId, required String documentId, required Map data, List? read, List? write}) async { + final String path = '/databases/{databaseId}/collections/{collectionId}/documents'.replaceAll('{databaseId}', databaseId).replaceAll('{collectionId}', collectionId); + + final Map params = { + + 'documentId': documentId, +'data': data, +'read': read, +'write': write, + + }; + + final Map headers = { + 'content-type': 'application/json', + + }; + + final res = await client.call(HttpMethod.post, path: path, params: params, headers: headers); + + return models.Document.fromMap(res.data); + + + } + + /// Get Document + Future getDocument({required String collectionId, required String documentId}) async { + final String path = '/databases/{databaseId}/collections/{collectionId}/documents/{documentId}'.replaceAll('{databaseId}', databaseId).replaceAll('{collectionId}', collectionId).replaceAll('{documentId}', documentId); + + final Map params = { + + + }; + + final Map headers = { + 'content-type': 'application/json', + + }; + + final res = await client.call(HttpMethod.get, path: path, params: params, headers: headers); + + return models.Document.fromMap(res.data); + + + } + + /// Update Document + Future updateDocument({required String collectionId, required String documentId, Map? data, List? read, List? write}) async { + final String path = '/databases/{databaseId}/collections/{collectionId}/documents/{documentId}'.replaceAll('{databaseId}', databaseId).replaceAll('{collectionId}', collectionId).replaceAll('{documentId}', documentId); + + final Map params = { + + 'data': data, +'read': read, +'write': write, + + }; + + final Map headers = { + 'content-type': 'application/json', + + }; + + final res = await client.call(HttpMethod.patch, path: path, params: params, headers: headers); + + return models.Document.fromMap(res.data); + + + } + + /// Delete Document + Future deleteDocument({required String collectionId, required String documentId}) async { + final String path = '/databases/{databaseId}/collections/{collectionId}/documents/{documentId}'.replaceAll('{databaseId}', databaseId).replaceAll('{collectionId}', collectionId).replaceAll('{documentId}', documentId); + + final Map params = { + + + }; + + final Map headers = { + 'content-type': 'application/json', + + }; + + final res = await client.call(HttpMethod.delete, path: path, params: params, headers: headers); + + return res.data; + + + } +} \ No newline at end of file diff --git a/lib/services/functions.dart b/lib/services/functions.dart index 37ae4e5..0b99922 100644 --- a/lib/services/functions.dart +++ b/lib/services/functions.dart @@ -1,6 +1,5 @@ part of appwrite; - /// The Functions Service allows you view, create and manage your Cloud /// Functions. class Functions extends Service { @@ -11,14 +10,20 @@ class Functions extends Service { final String path = '/functions/{functionId}/deployments/{deploymentId}/builds/{buildId}'.replaceAll('{functionId}', functionId).replaceAll('{deploymentId}', deploymentId).replaceAll('{buildId}', buildId); final Map params = { + + }; final Map headers = { - 'content-type': 'application/json', + 'content-type': 'application/json', + }; final res = await client.call(HttpMethod.post, path: path, params: params, headers: headers); + return res.data; + + } /// List Executions @@ -33,18 +38,24 @@ class Functions extends Service { final Map params = { 'limit': limit, - 'offset': offset, - 'search': search, - 'cursor': cursor, - 'cursorDirection': cursorDirection, +'offset': offset, +'search': search, +'cursor': cursor, +'cursorDirection': cursorDirection, + + }; final Map headers = { - 'content-type': 'application/json', + 'content-type': 'application/json', + }; final res = await client.call(HttpMethod.get, path: path, params: params, headers: headers); + return models.ExecutionList.fromMap(res.data); + + } /// Create Execution @@ -58,16 +69,22 @@ class Functions extends Service { final String path = '/functions/{functionId}/executions'.replaceAll('{functionId}', functionId); final Map params = { + 'data': data, - 'async': xasync, +'async': xasync, + }; final Map headers = { - 'content-type': 'application/json', + 'content-type': 'application/json', + }; final res = await client.call(HttpMethod.post, path: path, params: params, headers: headers); + return models.Execution.fromMap(res.data); + + } /// Get Execution @@ -78,13 +95,19 @@ class Functions extends Service { final String path = '/functions/{functionId}/executions/{executionId}'.replaceAll('{functionId}', functionId).replaceAll('{executionId}', executionId); final Map params = { + + }; final Map headers = { - 'content-type': 'application/json', + 'content-type': 'application/json', + }; final res = await client.call(HttpMethod.get, path: path, params: params, headers: headers); + return models.Execution.fromMap(res.data); + + } } \ No newline at end of file diff --git a/lib/services/locale.dart b/lib/services/locale.dart index 60add44..fde7a09 100644 --- a/lib/services/locale.dart +++ b/lib/services/locale.dart @@ -1,6 +1,5 @@ part of appwrite; - /// The Locale service allows you to customize your app based on your users' /// location. class Locale extends Service { @@ -19,14 +18,20 @@ class Locale extends Service { const String path = '/locale'; final Map params = { + + }; final Map headers = { - 'content-type': 'application/json', + 'content-type': 'application/json', + }; final res = await client.call(HttpMethod.get, path: path, params: params, headers: headers); + return models.Locale.fromMap(res.data); + + } /// List Continents @@ -38,14 +43,20 @@ class Locale extends Service { const String path = '/locale/continents'; final Map params = { + + }; final Map headers = { - 'content-type': 'application/json', + 'content-type': 'application/json', + }; final res = await client.call(HttpMethod.get, path: path, params: params, headers: headers); + return models.ContinentList.fromMap(res.data); + + } /// List Countries @@ -57,14 +68,20 @@ class Locale extends Service { const String path = '/locale/countries'; final Map params = { + + }; final Map headers = { - 'content-type': 'application/json', + 'content-type': 'application/json', + }; final res = await client.call(HttpMethod.get, path: path, params: params, headers: headers); + return models.CountryList.fromMap(res.data); + + } /// List EU Countries @@ -76,14 +93,20 @@ class Locale extends Service { const String path = '/locale/countries/eu'; final Map params = { + + }; final Map headers = { - 'content-type': 'application/json', + 'content-type': 'application/json', + }; final res = await client.call(HttpMethod.get, path: path, params: params, headers: headers); + return models.CountryList.fromMap(res.data); + + } /// List Countries Phone Codes @@ -95,14 +118,20 @@ class Locale extends Service { const String path = '/locale/countries/phones'; final Map params = { + + }; final Map headers = { - 'content-type': 'application/json', + 'content-type': 'application/json', + }; final res = await client.call(HttpMethod.get, path: path, params: params, headers: headers); + return models.PhoneList.fromMap(res.data); + + } /// List Currencies @@ -115,14 +144,20 @@ class Locale extends Service { const String path = '/locale/currencies'; final Map params = { + + }; final Map headers = { - 'content-type': 'application/json', + 'content-type': 'application/json', + }; final res = await client.call(HttpMethod.get, path: path, params: params, headers: headers); + return models.CurrencyList.fromMap(res.data); + + } /// List Languages @@ -134,13 +169,19 @@ class Locale extends Service { const String path = '/locale/languages'; final Map params = { + + }; final Map headers = { - 'content-type': 'application/json', + 'content-type': 'application/json', + }; final res = await client.call(HttpMethod.get, path: path, params: params, headers: headers); + return models.LanguageList.fromMap(res.data); + + } } \ No newline at end of file diff --git a/lib/services/storage.dart b/lib/services/storage.dart index 9cc4608..2483af8 100644 --- a/lib/services/storage.dart +++ b/lib/services/storage.dart @@ -1,6 +1,5 @@ part of appwrite; - /// The Storage service allows you to manage your project files. class Storage extends Service { Storage(Client client): super(client); @@ -16,19 +15,25 @@ class Storage extends Service { final Map params = { 'search': search, - 'limit': limit, - 'offset': offset, - 'cursor': cursor, - 'cursorDirection': cursorDirection, - 'orderType': orderType, +'limit': limit, +'offset': offset, +'cursor': cursor, +'cursorDirection': cursorDirection, +'orderType': orderType, + + }; final Map headers = { - 'content-type': 'application/json', + 'content-type': 'application/json', + }; final res = await client.call(HttpMethod.get, path: path, params: params, headers: headers); + return models.FileList.fromMap(res.data); + + } /// Create File @@ -55,27 +60,24 @@ class Storage extends Service { Future createFile({required String bucketId, required String fileId, required InputFile file, List? read, List? write, Function(UploadProgress)? onProgress}) async { final String path = '/storage/buckets/{bucketId}/files'.replaceAll('{bucketId}', bucketId); - final Map params = { + final Map params = { + 'fileId': fileId, - 'file': file, - 'read': read, - 'write': write, +'file': file, +'read': read, +'write': write, + }; final Map headers = { - 'content-type': 'multipart/form-data', + 'content-type': 'multipart/form-data', + }; - dynamic res; - if(kIsWeb) { - params['file'] = file.file; - res = await client.call(HttpMethod.post, path: path, params: params, headers: headers); - } else { - String idParamName = ''; - idParamName = 'fileId'; - final paramName = 'file'; - res = await chunkedUpload( - client: client, + String idParamName = ''; + idParamName = 'fileId'; + final paramName = 'file'; + final res = await client.chunkedUpload( path: path, params: params, paramName: paramName, @@ -83,8 +85,10 @@ class Storage extends Service { headers: headers, onProgress: onProgress, ); - } + return models.File.fromMap(res.data); + + } /// Get File @@ -96,14 +100,20 @@ class Storage extends Service { final String path = '/storage/buckets/{bucketId}/files/{fileId}'.replaceAll('{bucketId}', bucketId).replaceAll('{fileId}', fileId); final Map params = { + + }; final Map headers = { - 'content-type': 'application/json', + 'content-type': 'application/json', + }; final res = await client.call(HttpMethod.get, path: path, params: params, headers: headers); + return models.File.fromMap(res.data); + + } /// Update File @@ -115,16 +125,22 @@ class Storage extends Service { final String path = '/storage/buckets/{bucketId}/files/{fileId}'.replaceAll('{bucketId}', bucketId).replaceAll('{fileId}', fileId); final Map params = { + 'read': read, - 'write': write, +'write': write, + }; final Map headers = { - 'content-type': 'application/json', + 'content-type': 'application/json', + }; final res = await client.call(HttpMethod.put, path: path, params: params, headers: headers); + return models.File.fromMap(res.data); + + } /// Delete File @@ -136,14 +152,20 @@ class Storage extends Service { final String path = '/storage/buckets/{bucketId}/files/{fileId}'.replaceAll('{bucketId}', bucketId).replaceAll('{fileId}', fileId); final Map params = { + + }; final Map headers = { - 'content-type': 'application/json', + 'content-type': 'application/json', + }; final res = await client.call(HttpMethod.delete, path: path, params: params, headers: headers); + return res.data; + + } /// Get File for Download @@ -156,11 +178,14 @@ class Storage extends Service { final String path = '/storage/buckets/{bucketId}/files/{fileId}/download'.replaceAll('{bucketId}', bucketId).replaceAll('{fileId}', fileId); final Map params = { + + 'project': client.config['project'], }; final res = await client.call(HttpMethod.get, path: path, params: params, responseType: ResponseType.bytes); return res.data; + } /// Get File Preview @@ -176,21 +201,24 @@ class Storage extends Service { final Map params = { 'width': width, - 'height': height, - 'gravity': gravity, - 'quality': quality, - 'borderWidth': borderWidth, - 'borderColor': borderColor, - 'borderRadius': borderRadius, - 'opacity': opacity, - 'rotation': rotation, - 'background': background, - 'output': output, +'height': height, +'gravity': gravity, +'quality': quality, +'borderWidth': borderWidth, +'borderColor': borderColor, +'borderRadius': borderRadius, +'opacity': opacity, +'rotation': rotation, +'background': background, +'output': output, + + 'project': client.config['project'], }; final res = await client.call(HttpMethod.get, path: path, params: params, responseType: ResponseType.bytes); return res.data; + } /// Get File for View @@ -203,10 +231,13 @@ class Storage extends Service { final String path = '/storage/buckets/{bucketId}/files/{fileId}/view'.replaceAll('{bucketId}', bucketId).replaceAll('{fileId}', fileId); final Map params = { + + 'project': client.config['project'], }; final res = await client.call(HttpMethod.get, path: path, params: params, responseType: ResponseType.bytes); return res.data; + } } \ No newline at end of file diff --git a/lib/services/teams.dart b/lib/services/teams.dart index 656635f..deacc25 100644 --- a/lib/services/teams.dart +++ b/lib/services/teams.dart @@ -1,6 +1,5 @@ part of appwrite; - /// The Teams service allows you to group users of your project and to enable /// them to share read and write access to your project resources class Teams extends Service { @@ -19,19 +18,25 @@ class Teams extends Service { final Map params = { 'search': search, - 'limit': limit, - 'offset': offset, - 'cursor': cursor, - 'cursorDirection': cursorDirection, - 'orderType': orderType, +'limit': limit, +'offset': offset, +'cursor': cursor, +'cursorDirection': cursorDirection, +'orderType': orderType, + + }; final Map headers = { - 'content-type': 'application/json', + 'content-type': 'application/json', + }; final res = await client.call(HttpMethod.get, path: path, params: params, headers: headers); + return models.TeamList.fromMap(res.data); + + } /// Create Team @@ -44,17 +49,23 @@ class Teams extends Service { const String path = '/teams'; final Map params = { + 'teamId': teamId, - 'name': name, - 'roles': roles, +'name': name, +'roles': roles, + }; final Map headers = { - 'content-type': 'application/json', + 'content-type': 'application/json', + }; final res = await client.call(HttpMethod.post, path: path, params: params, headers: headers); + return models.Team.fromMap(res.data); + + } /// Get Team @@ -65,14 +76,20 @@ class Teams extends Service { final String path = '/teams/{teamId}'.replaceAll('{teamId}', teamId); final Map params = { + + }; final Map headers = { - 'content-type': 'application/json', + 'content-type': 'application/json', + }; final res = await client.call(HttpMethod.get, path: path, params: params, headers: headers); + return models.Team.fromMap(res.data); + + } /// Update Team @@ -84,15 +101,21 @@ class Teams extends Service { final String path = '/teams/{teamId}'.replaceAll('{teamId}', teamId); final Map params = { + 'name': name, + }; final Map headers = { - 'content-type': 'application/json', + 'content-type': 'application/json', + }; final res = await client.call(HttpMethod.put, path: path, params: params, headers: headers); + return models.Team.fromMap(res.data); + + } /// Delete Team @@ -104,14 +127,20 @@ class Teams extends Service { final String path = '/teams/{teamId}'.replaceAll('{teamId}', teamId); final Map params = { + + }; final Map headers = { - 'content-type': 'application/json', + 'content-type': 'application/json', + }; final res = await client.call(HttpMethod.delete, path: path, params: params, headers: headers); + return res.data; + + } /// Get Team Memberships @@ -124,19 +153,25 @@ class Teams extends Service { final Map params = { 'search': search, - 'limit': limit, - 'offset': offset, - 'cursor': cursor, - 'cursorDirection': cursorDirection, - 'orderType': orderType, +'limit': limit, +'offset': offset, +'cursor': cursor, +'cursorDirection': cursorDirection, +'orderType': orderType, + + }; final Map headers = { - 'content-type': 'application/json', + 'content-type': 'application/json', + }; final res = await client.call(HttpMethod.get, path: path, params: params, headers: headers); + return models.MembershipList.fromMap(res.data); + + } /// Create Team Membership @@ -161,18 +196,24 @@ class Teams extends Service { final String path = '/teams/{teamId}/memberships'.replaceAll('{teamId}', teamId); final Map params = { + 'email': email, - 'roles': roles, - 'url': url, - 'name': name, +'roles': roles, +'url': url, +'name': name, + }; final Map headers = { - 'content-type': 'application/json', + 'content-type': 'application/json', + }; final res = await client.call(HttpMethod.post, path: path, params: params, headers: headers); + return models.Membership.fromMap(res.data); + + } /// Get Team Membership @@ -184,14 +225,20 @@ class Teams extends Service { final String path = '/teams/{teamId}/memberships/{membershipId}'.replaceAll('{teamId}', teamId).replaceAll('{membershipId}', membershipId); final Map params = { + + }; final Map headers = { - 'content-type': 'application/json', + 'content-type': 'application/json', + }; final res = await client.call(HttpMethod.get, path: path, params: params, headers: headers); + return models.MembershipList.fromMap(res.data); + + } /// Update Membership Roles @@ -204,15 +251,21 @@ class Teams extends Service { final String path = '/teams/{teamId}/memberships/{membershipId}'.replaceAll('{teamId}', teamId).replaceAll('{membershipId}', membershipId); final Map params = { + 'roles': roles, + }; final Map headers = { - 'content-type': 'application/json', + 'content-type': 'application/json', + }; final res = await client.call(HttpMethod.patch, path: path, params: params, headers: headers); + return models.Membership.fromMap(res.data); + + } /// Delete Team Membership @@ -225,14 +278,20 @@ class Teams extends Service { final String path = '/teams/{teamId}/memberships/{membershipId}'.replaceAll('{teamId}', teamId).replaceAll('{membershipId}', membershipId); final Map params = { + + }; final Map headers = { - 'content-type': 'application/json', + 'content-type': 'application/json', + }; final res = await client.call(HttpMethod.delete, path: path, params: params, headers: headers); + return res.data; + + } /// Update Team Membership Status @@ -249,15 +308,21 @@ class Teams extends Service { final String path = '/teams/{teamId}/memberships/{membershipId}/status'.replaceAll('{teamId}', teamId).replaceAll('{membershipId}', membershipId); final Map params = { + 'userId': userId, - 'secret': secret, +'secret': secret, + }; final Map headers = { - 'content-type': 'application/json', + 'content-type': 'application/json', + }; final res = await client.call(HttpMethod.patch, path: path, params: params, headers: headers); + return models.Membership.fromMap(res.data); + + } } \ No newline at end of file diff --git a/lib/src/chunked_upload_io.dart b/lib/src/chunked_upload_io.dart deleted file mode 100644 index dea0315..0000000 --- a/lib/src/chunked_upload_io.dart +++ /dev/null @@ -1,78 +0,0 @@ -import 'client.dart'; -import 'dart:io' as io; -import 'enums.dart'; -import 'package:http/http.dart' as http; -import 'response.dart'; -import 'dart:math'; -import 'input_file.dart'; -import 'exception.dart'; -import 'upload_progress.dart'; - -Future chunkedUpload({ - required Client client, - required String path, - required Map params, - required String paramName, - required String idParamName, - required Map headers, - Function(UploadProgress)? onProgress, -}) async { - InputFile file = params[paramName]; - if (file.path == null) { - throw AppwriteException("File path must be provided for dart:io"); - } - io.File iofile = io.File(file.path!); - final size = await iofile.length(); - - late Response res; - if (size <= Client.CHUNK_SIZE) { - params[paramName] = await http.MultipartFile.fromPath(paramName, file.path!, filename: file.filename); - return client.call( - HttpMethod.post, - path: path, - params: params, - headers: headers, - ); - } - - var offset = 0; - if(idParamName.isNotEmpty && params[idParamName] != 'unique()') { - //make a request to check if a file already exists - try { - res = await client.call( - HttpMethod.get, - path: path + '/' + params[idParamName], - headers: headers, - ); - final int chunksUploaded = res.data['chunksUploaded'] as int; - offset = min(size, chunksUploaded * Client.CHUNK_SIZE); - } on AppwriteException catch (_) {} - } - // read chunk and upload each chunk - final raf = iofile.openSync(mode: io.FileMode.read); - - while (offset < size) { - raf.setPositionSync(offset); - final chunk = raf.readSync(Client.CHUNK_SIZE); - params[paramName] = - http.MultipartFile.fromBytes(paramName, chunk, filename: file.filename); - headers['content-range'] = - 'bytes $offset-${min(((offset + Client.CHUNK_SIZE) - 1), size)}/$size'; - res = await client.call(HttpMethod.post, - path: path, headers: headers, params: params); - offset += Client.CHUNK_SIZE; - if(offset < size) { - headers['x-appwrite-id'] = res.data['\$id']; - } - final progress = UploadProgress( - $id: res.data['\$id'] ?? '', - progress: min(offset-1,size)/size * 100, - sizeUploaded: min(offset-1,size), - chunksTotal: res.data['chunksTotal'] ?? 0, - chunksUploaded: res.data['chunksUploaded'] ?? 0, - ); - onProgress?.call(progress); - } - raf.close(); - return res; -} diff --git a/lib/src/chunked_upload_stub.dart b/lib/src/chunked_upload_stub.dart deleted file mode 100644 index 79ff481..0000000 --- a/lib/src/chunked_upload_stub.dart +++ /dev/null @@ -1,14 +0,0 @@ -import 'response.dart'; -import 'client.dart'; -import 'upload_progress.dart'; - -Future chunkedUpload({ - required Client client, - required String path, - required Map params, - required String paramName, - required String idParamName, - required Map headers, - Function(UploadProgress)? onProgress, -}) => - throw UnsupportedError('Cannot redirect to url without dart:html'); diff --git a/lib/src/client.dart b/lib/src/client.dart index 993e0e2..5483ae8 100644 --- a/lib/src/client.dart +++ b/lib/src/client.dart @@ -3,6 +3,7 @@ import 'client_stub.dart' if (dart.library.html) 'client_browser.dart' if (dart.library.io) 'client_io.dart'; import 'response.dart'; +import 'upload_progress.dart'; abstract class Client { static const int CHUNK_SIZE = 5*1024*1024; @@ -20,6 +21,15 @@ abstract class Client { Future webAuth(Uri url); + Future chunkedUpload({ + required String path, + required Map params, + required String paramName, + required String idParamName, + required Map headers, + Function(UploadProgress)? onProgress, + }); + Client setSelfSigned({bool status = true}); Client setEndpoint(String endPoint); diff --git a/lib/src/client_browser.dart b/lib/src/client_browser.dart index 34d9d79..f700582 100644 --- a/lib/src/client_browser.dart +++ b/lib/src/client_browser.dart @@ -1,4 +1,5 @@ import 'dart:html' as html; +import 'dart:math'; import 'package:flutter/foundation.dart'; import 'package:flutter_web_auth/flutter_web_auth.dart'; import 'package:http/http.dart' as http; @@ -7,7 +8,8 @@ import 'client_mixin.dart'; import 'enums.dart'; import 'exception.dart'; import 'client_base.dart'; - +import 'input_file.dart'; +import 'upload_progress.dart'; import 'response.dart'; ClientBase createClient({ @@ -17,6 +19,7 @@ ClientBase createClient({ ClientBrowser(endPoint: endPoint, selfSigned: selfSigned); class ClientBrowser extends ClientBase with ClientMixin { + static const int CHUNK_SIZE = 5*1024*1024; String _endPoint; Map? _headers; @override @@ -37,8 +40,8 @@ class ClientBrowser extends ClientBase with ClientMixin { .replaceFirst('http://', 'ws://'); _headers = { 'content-type': 'application/json', - 'x-sdk-version': 'appwrite:flutter:5.0.0', - 'X-Appwrite-Response-Format' : '0.14.0', + 'x-sdk-version': 'appwrite:flutter:6.0.0', + 'X-Appwrite-Response-Format' : '0.15.0', }; config = {}; @@ -107,6 +110,73 @@ class ClientBrowser extends ClientBase with ClientMixin { _httpClient.withCredentials = true; } + @override + Future chunkedUpload({ + required String path, + required Map params, + required String paramName, + required String idParamName, + required Map headers, + Function(UploadProgress)? onProgress, + }) async { + InputFile file = params[paramName]; + if (file.bytes == null) { + throw AppwriteException("File bytes must be provided for Flutter web"); + } + + int size = file.bytes!.length; + + late Response res; + if (size <= CHUNK_SIZE) { + params[paramName] = http.MultipartFile.fromBytes(paramName, file.bytes!, filename: file.filename); + return call( + HttpMethod.post, + path: path, + params: params, + headers: headers, + ); + } + + var offset = 0; + if (idParamName.isNotEmpty && params[idParamName] != 'unique()') { + //make a request to check if a file already exists + try { + res = await call( + HttpMethod.get, + path: path + '/' + params[idParamName], + headers: headers, + ); + final int chunksUploaded = res.data['chunksUploaded'] as int; + offset = min(size, chunksUploaded * CHUNK_SIZE); + } on AppwriteException catch (_) {} + } + + while (offset < size) { + var chunk; + final end = min(offset + CHUNK_SIZE-1, size-1); + chunk = file.bytes!.getRange(offset, end).toList(); + params[paramName] = + http.MultipartFile.fromBytes(paramName, chunk, filename: file.filename); + headers['content-range'] = + 'bytes $offset-${min(((offset + CHUNK_SIZE) - 1), size)}/$size'; + res = await call(HttpMethod.post, + path: path, headers: headers, params: params); + offset += CHUNK_SIZE; + if (offset < size) { + headers['x-appwrite-id'] = res.data['\$id']; + } + final progress = UploadProgress( + $id: res.data['\$id'] ?? '', + progress: min(offset - 1, size) / size * 100, + sizeUploaded: min(offset - 1, size), + chunksTotal: res.data['chunksTotal'] ?? 0, + chunksUploaded: res.data['chunksUploaded'] ?? 0, + ); + onProgress?.call(progress); + } + return res; + } + @override Future call( HttpMethod method, { diff --git a/lib/src/client_io.dart b/lib/src/client_io.dart index dfd4618..41cd7aa 100644 --- a/lib/src/client_io.dart +++ b/lib/src/client_io.dart @@ -1,4 +1,5 @@ import 'dart:io'; +import 'dart:math'; import 'package:cookie_jar/cookie_jar.dart'; import 'package:device_info_plus/device_info_plus.dart'; import 'package:http/http.dart' as http; @@ -14,6 +15,8 @@ import 'exception.dart'; import 'interceptor.dart'; import 'response.dart'; import 'package:flutter/foundation.dart'; +import 'input_file.dart'; +import 'upload_progress.dart'; ClientBase createClient({ required String endPoint, @@ -25,6 +28,7 @@ ClientBase createClient({ ); class ClientIO extends ClientBase with ClientMixin { + static const int CHUNK_SIZE = 5*1024*1024; String _endPoint; Map? _headers; @override @@ -55,8 +59,8 @@ class ClientIO extends ClientBase with ClientMixin { .replaceFirst('http://', 'ws://'); _headers = { 'content-type': 'application/json', - 'x-sdk-version': 'appwrite:flutter:5.0.0', - 'X-Appwrite-Response-Format' : '0.14.0', + 'x-sdk-version': 'appwrite:flutter:6.0.0', + 'X-Appwrite-Response-Format' : '0.15.0', }; config = {}; @@ -202,6 +206,102 @@ class ClientIO extends ClientBase with ClientMixin { return response; } + @override + Future chunkedUpload({ + required String path, + required Map params, + required String paramName, + required String idParamName, + required Map headers, + Function(UploadProgress)? onProgress, + }) async { + InputFile file = params[paramName]; + if (file.path == null && file.bytes == null) { + throw AppwriteException("File path or bytes must be provided"); + } + + int size = 0; + if (file.bytes != null) { + size = file.bytes!.length; + } + + File? iofile; + + if (file.path != null) { + iofile = File(file.path!); + size = await iofile.length(); + } + + late Response res; + if (size <= CHUNK_SIZE) { + if (file.path != null) { + params[paramName] = await http.MultipartFile.fromPath( + paramName, file.path!, + filename: file.filename); + } else { + params[paramName] = http.MultipartFile.fromBytes(paramName, file.bytes!, + filename: file.filename); + } + return call( + HttpMethod.post, + path: path, + params: params, + headers: headers, + ); + } + + var offset = 0; + if (idParamName.isNotEmpty && params[idParamName] != 'unique()') { + //make a request to check if a file already exists + try { + res = await call( + HttpMethod.get, + path: path + '/' + params[idParamName], + headers: headers, + ); + final int chunksUploaded = res.data['chunksUploaded'] as int; + offset = min(size, chunksUploaded * CHUNK_SIZE); + } on AppwriteException catch (_) {} + } + + RandomAccessFile? raf; + // read chunk and upload each chunk + if (iofile != null) { + raf = await iofile.open(mode: FileMode.read); + } + + while (offset < size) { + var chunk; + if (file.bytes != null) { + final end = min(offset + CHUNK_SIZE-1, size-1); + chunk = file.bytes!.getRange(offset, end).toList(); + } else { + raf!.setPositionSync(offset); + chunk = raf.readSync(CHUNK_SIZE); + } + params[paramName] = + http.MultipartFile.fromBytes(paramName, chunk, filename: file.filename); + headers['content-range'] = + 'bytes $offset-${min(((offset + CHUNK_SIZE) - 1), size)}/$size'; + res = await call(HttpMethod.post, + path: path, headers: headers, params: params); + offset += CHUNK_SIZE; + if (offset < size) { + headers['x-appwrite-id'] = res.data['\$id']; + } + final progress = UploadProgress( + $id: res.data['\$id'] ?? '', + progress: min(offset - 1, size) / size * 100, + sizeUploaded: min(offset - 1, size), + chunksTotal: res.data['chunksTotal'] ?? 0, + chunksUploaded: res.data['chunksUploaded'] ?? 0, + ); + onProgress?.call(progress); + } + raf?.close(); + return res; + } + @override Future webAuth(Uri url) { return FlutterWebAuth.authenticate( diff --git a/lib/src/input_file.dart b/lib/src/input_file.dart index 1b85e4b..46bdd0a 100644 --- a/lib/src/input_file.dart +++ b/lib/src/input_file.dart @@ -1,9 +1,19 @@ -import 'package:http/http.dart' show MultipartFile; +import 'package:flutter/foundation.dart'; +import 'exception.dart'; class InputFile { - final MultipartFile? file; - final String? path; + late final String? path; + late final List? bytes; final String? filename; + final String? contentType; - InputFile({this.file, this.path, this.filename}); + /// Provide a file, use `path` for IO platforms + /// and provide `bytes` for web platform + InputFile({this.path, this.filename, this.contentType, this.bytes}) { + if (kIsWeb && bytes == null) { + throw AppwriteException('On web `bytes` is required'); + } else if(!kIsWeb && path == null && bytes == null) { + throw AppwriteException('On IO platforms one of `path` or `bytes` is required'); + } + } } diff --git a/lib/src/models/document.dart b/lib/src/models/document.dart index 74adc2e..7051104 100644 --- a/lib/src/models/document.dart +++ b/lib/src/models/document.dart @@ -6,6 +6,10 @@ class Document implements Model { final String $id; /// Collection ID. final String $collection; + /// Document creation date in Unix timestamp. + final int $createdAt; + /// Document update date in Unix timestamp. + final int $updatedAt; /// Document read permissions. final List $read; /// Document write permissions. @@ -15,6 +19,8 @@ class Document implements Model { Document({ required this.$id, required this.$collection, + required this.$createdAt, + required this.$updatedAt, required this.$read, required this.$write, required this.data, @@ -24,6 +30,8 @@ class Document implements Model { return Document( $id: map['\$id'].toString(), $collection: map['\$collection'].toString(), + $createdAt: map['\$createdAt'], + $updatedAt: map['\$updatedAt'], $read: map['\$read'], $write: map['\$write'], data: map, @@ -35,6 +43,8 @@ class Document implements Model { return { "\$id": $id, "\$collection": $collection, + "\$createdAt": $createdAt, + "\$updatedAt": $updatedAt, "\$read": $read, "\$write": $write, "data": data, diff --git a/lib/src/models/execution.dart b/lib/src/models/execution.dart index 7d7ca79..2e9dfbc 100644 --- a/lib/src/models/execution.dart +++ b/lib/src/models/execution.dart @@ -4,12 +4,14 @@ part of appwrite.models; class Execution implements Model { /// Execution ID. final String $id; + /// Execution creation date in Unix timestamp. + final int $createdAt; + /// Execution update date in Unix timestamp. + final int $updatedAt; /// Execution read permissions. final List $read; /// Function ID. final String functionId; - /// The execution creation date in Unix timestamp. - final int dateCreated; /// The trigger that caused the function to execute. Possible values can be: `http`, `schedule`, or `event`. final String trigger; /// The status of the function execution. Possible values can be: `waiting`, `processing`, `completed`, or `failed`. @@ -25,9 +27,10 @@ class Execution implements Model { Execution({ required this.$id, + required this.$createdAt, + required this.$updatedAt, required this.$read, required this.functionId, - required this.dateCreated, required this.trigger, required this.status, required this.statusCode, @@ -39,9 +42,10 @@ class Execution implements Model { factory Execution.fromMap(Map map) { return Execution( $id: map['\$id'].toString(), + $createdAt: map['\$createdAt'], + $updatedAt: map['\$updatedAt'], $read: map['\$read'], functionId: map['functionId'].toString(), - dateCreated: map['dateCreated'], trigger: map['trigger'].toString(), status: map['status'].toString(), statusCode: map['statusCode'], @@ -55,9 +59,10 @@ class Execution implements Model { Map toMap() { return { "\$id": $id, + "\$createdAt": $createdAt, + "\$updatedAt": $updatedAt, "\$read": $read, "functionId": functionId, - "dateCreated": dateCreated, "trigger": trigger, "status": status, "statusCode": statusCode, diff --git a/lib/src/models/file.dart b/lib/src/models/file.dart index ea0ae03..aa86db7 100644 --- a/lib/src/models/file.dart +++ b/lib/src/models/file.dart @@ -6,14 +6,16 @@ class File implements Model { final String $id; /// Bucket ID. final String bucketId; + /// File creation date in Unix timestamp. + final int $createdAt; + /// File update date in Unix timestamp. + final int $updatedAt; /// File read permissions. final List $read; /// File write permissions. final List $write; /// File name. final String name; - /// File creation date in Unix timestamp. - final int dateCreated; /// File MD5 signature. final String signature; /// File mime type. @@ -28,10 +30,11 @@ class File implements Model { File({ required this.$id, required this.bucketId, + required this.$createdAt, + required this.$updatedAt, required this.$read, required this.$write, required this.name, - required this.dateCreated, required this.signature, required this.mimeType, required this.sizeOriginal, @@ -43,10 +46,11 @@ class File implements Model { return File( $id: map['\$id'].toString(), bucketId: map['bucketId'].toString(), + $createdAt: map['\$createdAt'], + $updatedAt: map['\$updatedAt'], $read: map['\$read'], $write: map['\$write'], name: map['name'].toString(), - dateCreated: map['dateCreated'], signature: map['signature'].toString(), mimeType: map['mimeType'].toString(), sizeOriginal: map['sizeOriginal'], @@ -60,10 +64,11 @@ class File implements Model { return { "\$id": $id, "bucketId": bucketId, + "\$createdAt": $createdAt, + "\$updatedAt": $updatedAt, "\$read": $read, "\$write": $write, "name": name, - "dateCreated": dateCreated, "signature": signature, "mimeType": mimeType, "sizeOriginal": sizeOriginal, diff --git a/lib/src/models/membership.dart b/lib/src/models/membership.dart index 7b60411..1805d1f 100644 --- a/lib/src/models/membership.dart +++ b/lib/src/models/membership.dart @@ -4,6 +4,10 @@ part of appwrite.models; class Membership implements Model { /// Membership ID. final String $id; + /// Membership creation date in Unix timestamp. + final int $createdAt; + /// Membership update date in Unix timestamp. + final int $updatedAt; /// User ID. final String userId; /// User name. @@ -25,6 +29,8 @@ class Membership implements Model { Membership({ required this.$id, + required this.$createdAt, + required this.$updatedAt, required this.userId, required this.userName, required this.userEmail, @@ -39,6 +45,8 @@ class Membership implements Model { factory Membership.fromMap(Map map) { return Membership( $id: map['\$id'].toString(), + $createdAt: map['\$createdAt'], + $updatedAt: map['\$updatedAt'], userId: map['userId'].toString(), userName: map['userName'].toString(), userEmail: map['userEmail'].toString(), @@ -55,6 +63,8 @@ class Membership implements Model { Map toMap() { return { "\$id": $id, + "\$createdAt": $createdAt, + "\$updatedAt": $updatedAt, "userId": userId, "userName": userName, "userEmail": userEmail, diff --git a/lib/src/models/session.dart b/lib/src/models/session.dart index 332d8da..ae6ac10 100644 --- a/lib/src/models/session.dart +++ b/lib/src/models/session.dart @@ -4,6 +4,8 @@ part of appwrite.models; class Session implements Model { /// Session ID. final String $id; + /// Session creation date in Unix timestamp. + final int $createdAt; /// User ID. final String userId; /// Session expiration date in Unix timestamp. @@ -53,6 +55,7 @@ class Session implements Model { Session({ required this.$id, + required this.$createdAt, required this.userId, required this.expire, required this.provider, @@ -81,6 +84,7 @@ class Session implements Model { factory Session.fromMap(Map map) { return Session( $id: map['\$id'].toString(), + $createdAt: map['\$createdAt'], userId: map['userId'].toString(), expire: map['expire'], provider: map['provider'].toString(), @@ -111,6 +115,7 @@ class Session implements Model { Map toMap() { return { "\$id": $id, + "\$createdAt": $createdAt, "userId": userId, "expire": expire, "provider": provider, diff --git a/lib/src/models/team.dart b/lib/src/models/team.dart index cd1cd62..dde2e29 100644 --- a/lib/src/models/team.dart +++ b/lib/src/models/team.dart @@ -4,25 +4,29 @@ part of appwrite.models; class Team implements Model { /// Team ID. final String $id; + /// Team creation date in Unix timestamp. + final int $createdAt; + /// Team update date in Unix timestamp. + final int $updatedAt; /// Team name. final String name; - /// Team creation date in Unix timestamp. - final int dateCreated; /// Total number of team members. final int total; Team({ required this.$id, + required this.$createdAt, + required this.$updatedAt, required this.name, - required this.dateCreated, required this.total, }); factory Team.fromMap(Map map) { return Team( $id: map['\$id'].toString(), + $createdAt: map['\$createdAt'], + $updatedAt: map['\$updatedAt'], name: map['name'].toString(), - dateCreated: map['dateCreated'], total: map['total'], ); } @@ -31,8 +35,9 @@ class Team implements Model { Map toMap() { return { "\$id": $id, + "\$createdAt": $createdAt, + "\$updatedAt": $updatedAt, "name": name, - "dateCreated": dateCreated, "total": total, }; } diff --git a/lib/src/models/token.dart b/lib/src/models/token.dart index d353789..729623e 100644 --- a/lib/src/models/token.dart +++ b/lib/src/models/token.dart @@ -4,6 +4,8 @@ part of appwrite.models; class Token implements Model { /// Token ID. final String $id; + /// Token creation date in Unix timestamp. + final int $createdAt; /// User ID. final String userId; /// Token secret key. This will return an empty string unless the response is returned using an API key or as part of a webhook payload. @@ -13,6 +15,7 @@ class Token implements Model { Token({ required this.$id, + required this.$createdAt, required this.userId, required this.secret, required this.expire, @@ -21,6 +24,7 @@ class Token implements Model { factory Token.fromMap(Map map) { return Token( $id: map['\$id'].toString(), + $createdAt: map['\$createdAt'], userId: map['userId'].toString(), secret: map['secret'].toString(), expire: map['expire'], @@ -31,6 +35,7 @@ class Token implements Model { Map toMap() { return { "\$id": $id, + "\$createdAt": $createdAt, "userId": userId, "secret": secret, "expire": expire, diff --git a/lib/src/models/user.dart b/lib/src/models/user.dart index a126d3c..e27668c 100644 --- a/lib/src/models/user.dart +++ b/lib/src/models/user.dart @@ -4,6 +4,10 @@ part of appwrite.models; class User implements Model { /// User ID. final String $id; + /// User creation date in Unix timestamp. + final int $createdAt; + /// User update date in Unix timestamp. + final int $updatedAt; /// User name. final String name; /// User registration date in Unix timestamp. @@ -14,31 +18,43 @@ class User implements Model { final int passwordUpdate; /// User email address. final String email; + /// User phone number in E.164 format. + final String phone; /// Email verification status. final bool emailVerification; + /// Phone verification status. + final bool phoneVerification; /// User preferences as a key-value object final Preferences prefs; User({ required this.$id, + required this.$createdAt, + required this.$updatedAt, required this.name, required this.registration, required this.status, required this.passwordUpdate, required this.email, + required this.phone, required this.emailVerification, + required this.phoneVerification, required this.prefs, }); factory User.fromMap(Map map) { return User( $id: map['\$id'].toString(), + $createdAt: map['\$createdAt'], + $updatedAt: map['\$updatedAt'], name: map['name'].toString(), registration: map['registration'], status: map['status'], passwordUpdate: map['passwordUpdate'], email: map['email'].toString(), + phone: map['phone'].toString(), emailVerification: map['emailVerification'], + phoneVerification: map['phoneVerification'], prefs: Preferences.fromMap(map['prefs']), ); } @@ -47,12 +63,16 @@ class User implements Model { Map toMap() { return { "\$id": $id, + "\$createdAt": $createdAt, + "\$updatedAt": $updatedAt, "name": name, "registration": registration, "status": status, "passwordUpdate": passwordUpdate, "email": email, + "phone": phone, "emailVerification": emailVerification, + "phoneVerification": phoneVerification, "prefs": prefs.toMap(), }; } diff --git a/pubspec.yaml b/pubspec.yaml index fe070d4..8d444dc 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: appwrite -version: 5.0.0 +version: 6.0.0 description: Appwrite is an open-source self-hosted backend server that abstract and simplify complex and repetitive development tasks behind a very simple REST API homepage: https://appwrite.io repository: https://github.com/appwrite/sdk-for-flutter