diff --git a/CHANGELOG.md b/CHANGELOG.md index cdb46c5a..1344896b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,17 @@ # Change Log +## 27.0.0 + +* Breaking: removed `Account.listLogs` and the `Log`, `LogList` models +* Breaking: removed `Client.setDevKey` +* Breaking: SDK now targets Appwrite 2.3 (`X-Appwrite-Response-Format: 2.3.0`) +* Added: `Account.createIdTokenSession` for native Apple and Google sign-in with `IdTokenProvider` enum +* Added: `Account.createRecoveryOTP` and `Account.updateRecoveryOTP` for code-based password recovery +* Added: `Account.createEmailVerificationOTP` and `Account.updateEmailVerificationOTP` +* Added: `kakao` and `tiktok` values to `OAuthProvider` +* Added: `passwordPwned` field on `User` and `providerIdToken` field on `Identity` +* Fixed: empty-string required path parameters are rejected instead of sent to the API + ## 26.2.0 * Added: `DocumentsDB` and `VectorsDB` services for document and vector database access diff --git a/README.md b/README.md index 584d890c..bbc066a7 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-2.0.x-blue.svg?style=flat-square) +![Version](https://img.shields.io/badge/api%20version-2.3.x-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 targets Appwrite server version 2.0.x as shipped on Appwrite Cloud.** Self-hosted releases can lag behind Cloud — if you run an older self-hosted build, use a matching older SDK from [previous releases](https://github.com/appwrite/sdk-for-flutter/releases) when APIs differ. +**This SDK targets Appwrite server version 2.3.x as shipped on Appwrite Cloud.** Self-hosted releases can lag behind Cloud — if you run an older self-hosted build, use a matching older SDK from [previous releases](https://github.com/appwrite/sdk-for-flutter/releases) when APIs differ. Appwrite is an open-source backend as a service server that abstracts and simplifies 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) @@ -19,7 +19,7 @@ Add this to your package's `pubspec.yaml` file: ```yml dependencies: - appwrite: ^26.2.0 + appwrite: ^27.0.0 ``` You can install packages from the command line: diff --git a/docs/examples/account/list-logs.md b/docs/examples/account/create-email-verification-otp.md similarity index 71% rename from docs/examples/account/list-logs.md rename to docs/examples/account/create-email-verification-otp.md index 924470de..941db965 100644 --- a/docs/examples/account/list-logs.md +++ b/docs/examples/account/create-email-verification-otp.md @@ -7,8 +7,7 @@ Client client = Client() Account account = Account(client); -LogList result = await account.listLogs( - queries: [], // optional - total: false, // optional +Token result = await account.createEmailVerificationOTP( + phrase: false, // optional ); ``` diff --git a/docs/examples/account/create-id-token-session.md b/docs/examples/account/create-id-token-session.md new file mode 100644 index 00000000..61f84065 --- /dev/null +++ b/docs/examples/account/create-id-token-session.md @@ -0,0 +1,19 @@ +```dart +import 'package:appwrite/appwrite.dart'; +import 'package:appwrite/enums.dart' as enums; + +Client client = Client() + .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + .setProject(''); // Your project ID + +Account account = Account(client); + +Session result = await account.createIdTokenSession( + provider: enums.IdTokenProvider.apple, + idToken: '', + nonce: '', // optional + accessToken: '', // optional + accessTokenExpiry: 0, // optional + name: '', // optional +); +``` diff --git a/docs/examples/account/create-recovery-otp.md b/docs/examples/account/create-recovery-otp.md new file mode 100644 index 00000000..366469f3 --- /dev/null +++ b/docs/examples/account/create-recovery-otp.md @@ -0,0 +1,14 @@ +```dart +import 'package:appwrite/appwrite.dart'; + +Client client = Client() + .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + .setProject(''); // Your project ID + +Account account = Account(client); + +Token result = await account.createRecoveryOTP( + email: 'email@example.com', + phrase: false, // optional +); +``` diff --git a/docs/examples/account/update-email-verification-otp.md b/docs/examples/account/update-email-verification-otp.md new file mode 100644 index 00000000..52ff4c11 --- /dev/null +++ b/docs/examples/account/update-email-verification-otp.md @@ -0,0 +1,14 @@ +```dart +import 'package:appwrite/appwrite.dart'; + +Client client = Client() + .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + .setProject(''); // Your project ID + +Account account = Account(client); + +Token result = await account.updateEmailVerificationOTP( + userId: '', + secret: '', +); +``` diff --git a/docs/examples/account/update-recovery-otp.md b/docs/examples/account/update-recovery-otp.md new file mode 100644 index 00000000..f7b4a2ef --- /dev/null +++ b/docs/examples/account/update-recovery-otp.md @@ -0,0 +1,15 @@ +```dart +import 'package:appwrite/appwrite.dart'; + +Client client = Client() + .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + .setProject(''); // Your project ID + +Account account = Account(client); + +Token result = await account.updateRecoveryOTP( + userId: '', + secret: '', + password: 'password', +); +``` diff --git a/lib/appwrite.dart b/lib/appwrite.dart index e2826d9f..c80609e3 100644 --- a/lib/appwrite.dart +++ b/lib/appwrite.dart @@ -1,6 +1,6 @@ /// Appwrite Flutter SDK /// -/// This SDK targets Appwrite server version 2.0.x as shipped on Appwrite Cloud. +/// This SDK targets Appwrite server version 2.3.x as shipped on Appwrite Cloud. /// Self-hosted releases can lag behind Cloud — if you run an older self-hosted /// build, use a matching older SDK from /// [previous releases](https://github.com/appwrite/sdk-for-flutter/releases) @@ -13,6 +13,7 @@ import 'dart:typed_data'; import 'dart:convert'; import 'src/enums.dart'; +import 'src/exception.dart'; import 'src/service.dart'; import 'src/input_file.dart'; import 'models.dart' as models; diff --git a/lib/enums.dart b/lib/enums.dart index a9677f03..c73a7c43 100644 --- a/lib/enums.dart +++ b/lib/enums.dart @@ -3,6 +3,7 @@ library appwrite.enums; part 'src/enums/authenticator_type.dart'; part 'src/enums/authentication_factor.dart'; +part 'src/enums/id_token_provider.dart'; part 'src/enums/o_auth_provider.dart'; part 'src/enums/browser.dart'; part 'src/enums/credit_card.dart'; diff --git a/lib/models.dart b/lib/models.dart index d6ee0466..f1fca69d 100644 --- a/lib/models.dart +++ b/lib/models.dart @@ -9,7 +9,6 @@ part 'src/models/document_list.dart'; part 'src/models/presence_list.dart'; part 'src/models/session_list.dart'; part 'src/models/identity_list.dart'; -part 'src/models/log_list.dart'; part 'src/models/file_list.dart'; part 'src/models/team_list.dart'; part 'src/models/membership_list.dart'; @@ -24,7 +23,6 @@ part 'src/models/transaction_list.dart'; part 'src/models/row.dart'; part 'src/models/document.dart'; part 'src/models/presence.dart'; -part 'src/models/log.dart'; part 'src/models/user.dart'; part 'src/models/algo_md5.dart'; part 'src/models/algo_sha.dart'; diff --git a/lib/services/account.dart b/lib/services/account.dart index 41a32f4a..48492bdb 100644 --- a/lib/services/account.dart +++ b/lib/services/account.dart @@ -97,6 +97,12 @@ class Account extends Service { Future getConsent({ required String consentId, }) async { + if (consentId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "consentId"', + ); + } + final String apiPath = '/account/consents/{consentId}'.replaceAll( '{consentId}', consentId, @@ -125,6 +131,12 @@ class Account extends Service { Future deleteConsent({ required String consentId, }) async { + if (consentId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "consentId"', + ); + } + final String apiPath = '/account/consents/{consentId}'.replaceAll( '{consentId}', consentId, @@ -156,6 +168,12 @@ class Account extends Service { List? queries, bool? total, }) async { + if (consentId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "consentId"', + ); + } + final String apiPath = '/account/consents/{consentId}/tokens'.replaceAll( '{consentId}', consentId, @@ -187,6 +205,18 @@ class Account extends Service { required String consentId, required String tokenId, }) async { + if (consentId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "consentId"', + ); + } + + if (tokenId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "tokenId"', + ); + } + final String apiPath = '/account/consents/{consentId}/tokens/{tokenId}' .replaceAll( '{consentId}', @@ -221,6 +251,18 @@ class Account extends Service { required String consentId, required String tokenId, }) async { + if (consentId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "consentId"', + ); + } + + if (tokenId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "tokenId"', + ); + } + final String apiPath = '/account/consents/{consentId}/tokens/{tokenId}' .replaceAll( '{consentId}', @@ -314,6 +356,12 @@ class Account extends Service { Future deleteIdentity({ required String identityId, }) async { + if (identityId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "identityId"', + ); + } + final String apiPath = '/account/identities/{identityId}'.replaceAll( '{identityId}', identityId, @@ -324,6 +372,7 @@ class Account extends Service { final Map apiHeaders = { 'X-Appwrite-Project': client.config['project'] ?? '', 'content-type': 'application/json', + 'accept': 'application/json', }; final res = await client.call( @@ -366,34 +415,6 @@ class Account extends Service { return models.Jwt.fromMap(res.data); } - /// Get the list of latest security activity logs for the currently logged in - /// user. Each log returns user IP address, location and date and time of log. - Future listLogs({ - List? queries, - bool? total, - }) async { - final String apiPath = '/account/logs'; - - final Map apiParams = { - if (queries != null) 'queries': queries, - if (total != null) 'total': total, - }; - - final Map apiHeaders = { - 'X-Appwrite-Project': client.config['project'] ?? '', - 'accept': 'application/json', - }; - - final res = await client.call( - HttpMethod.get, - path: apiPath, - params: apiParams, - headers: apiHeaders, - ); - - return models.LogList.fromMap(res.data); - } - /// Enable or disable MFA on an account. Future updateMFA({ required bool mfa, @@ -567,6 +588,7 @@ class Account extends Service { final Map apiHeaders = { 'X-Appwrite-Project': client.config['project'] ?? '', 'content-type': 'application/json', + 'accept': 'application/json', }; final res = await client.call( @@ -593,6 +615,7 @@ class Account extends Service { final Map apiHeaders = { 'X-Appwrite-Project': client.config['project'] ?? '', 'content-type': 'application/json', + 'accept': 'application/json', }; final res = await client.call( @@ -1146,6 +1169,81 @@ class Account extends Service { return models.Token.fromMap(res.data); } + /// Use this endpoint to send a 6-digit password recovery code to the user's + /// email address. Unlike + /// [createRecovery](https://appwrite.io/docs/references/cloud/client-web/account#createRecovery), + /// this method requires no redirect URL, which makes it suitable for mobile + /// and desktop apps that cannot host a recovery page. Learn more about how to + /// [complete the recovery + /// process](https://appwrite.io/docs/references/cloud/client-web/account#updateRecoveryOTP). + /// The code sent to the user's email address is valid for 15 minutes. + /// + /// Enable the **phrase** parameter to include a randomly generated security + /// phrase in both the email and the response. Showing that phrase in your app + /// lets the user confirm the email genuinely came from your request, which + /// helps protect against phishing. + Future createRecoveryOTP({ + required String email, + bool? phrase, + }) async { + final String apiPath = '/account/recovery/otp'; + + final Map apiParams = { + 'email': email, + if (phrase != null) 'phrase': phrase, + }; + + final Map apiHeaders = { + 'X-Appwrite-Project': client.config['project'] ?? '', + 'content-type': 'application/json', + 'accept': 'application/json', + }; + + final res = await client.call( + HttpMethod.post, + path: apiPath, + params: apiParams, + headers: apiHeaders, + ); + + return models.Token.fromMap(res.data); + } + + /// Use this endpoint to complete the user password recovery process using the + /// 6-digit code that was emailed by + /// [createRecoveryOTP](https://appwrite.io/docs/references/cloud/client-web/account#createRecoveryOTP). + /// Pass the **userId** of the user along with the **secret** code from the + /// email and the new **password** to set. If confirmed, this route will return + /// a 200 status code, the code is consumed and the user's password is updated. + Future updateRecoveryOTP({ + required String userId, + required String secret, + required String password, + }) async { + final String apiPath = '/account/recovery/otp'; + + final Map apiParams = { + 'userId': userId, + 'secret': secret, + 'password': password, + }; + + final Map apiHeaders = { + 'X-Appwrite-Project': client.config['project'] ?? '', + 'content-type': 'application/json', + 'accept': 'application/json', + }; + + final res = await client.call( + HttpMethod.put, + path: apiPath, + params: apiParams, + headers: apiHeaders, + ); + + return models.Token.fromMap(res.data); + } + /// Get the list of active sessions across different devices for the currently /// logged in user. Future listSessions() async { @@ -1178,6 +1276,7 @@ class Account extends Service { final Map apiHeaders = { 'X-Appwrite-Project': client.config['project'] ?? '', 'content-type': 'application/json', + 'accept': 'application/json', }; final res = await client.call( @@ -1251,6 +1350,82 @@ class Account extends Service { return models.Session.fromMap(res.data); } + /// Allow the user to login to their account using an OpenID Connect ID token + /// obtained natively from the OAuth2 provider, for example via Google + /// Credential Manager on Android or Sign in with Apple on iOS. No browser or + /// redirect is involved: the ID token is verified against the provider's + /// published signing keys and a session is created in a single request. + /// + /// Native sign-in is switched on per provider with its nativeEnabled setting. + /// It is independent of the browser-based flow's enabled setting, which has no + /// effect on this endpoint. The token's audience must match the provider's + /// configured client ID or one of its native client IDs; tokens issued for any + /// other client ID are rejected. For Sign in with Apple, register your app's + /// bundle ID as a native client ID. For Google, the web client ID used by + /// Credential Manager is usually the configured client ID; add your Android + /// and iOS client IDs as native client IDs if your app requests tokens for + /// them. + /// + /// Pass the raw nonce used when requesting the ID token so it can be validated + /// against the token's nonce claim. When signing in with Apple, the nonce is + /// required: hash it with SHA-256 before passing it to the Apple SDK, and send + /// the raw value here - Apple tokens requested without a nonce are rejected. + /// For Google the nonce is optional: it is validated whenever the token + /// carries one, and ignored when the provider issued the token without one. + /// Apple only returns the user's name on the first authorization, and never + /// inside the ID token - capture it on the client and pass it via the name + /// parameter. + /// + /// If there is already an active session, the new session will be attached to + /// the logged-in account. If there are no active sessions, the server will + /// attempt to look for a user with the same email address as the verified + /// email received from the provider and attach the new session to the existing + /// user. If no matching user is found - the server will create a new user. + /// + /// This flow does not return provider refresh tokens. You may pass an access + /// token the provider handed your client, along with its lifetime, to store it + /// on the session - but Appwrite cannot renew it once it expires. If your app + /// needs long-lived access to provider APIs, use the browser-based OAuth2 flow + /// instead. + /// + /// A user is limited to 10 active sessions at a time by default. [Learn more + /// about session + /// limits](https://appwrite.io/docs/authentication-security#limits). + Future createIdTokenSession({ + required enums.IdTokenProvider provider, + required String idToken, + String? nonce, + String? accessToken, + int? accessTokenExpiry, + String? name, + }) async { + final String apiPath = '/account/sessions/id-token'; + + final Map apiParams = { + 'provider': provider.value, + 'idToken': idToken, + if (nonce != null) 'nonce': nonce, + if (accessToken != null) 'accessToken': accessToken, + if (accessTokenExpiry != null) 'accessTokenExpiry': accessTokenExpiry, + if (name != null) 'name': name, + }; + + final Map apiHeaders = { + 'X-Appwrite-Project': client.config['project'] ?? '', + 'content-type': 'application/json', + 'accept': 'application/json', + }; + + final res = await client.call( + HttpMethod.post, + path: apiPath, + params: apiParams, + headers: apiHeaders, + ); + + return models.Session.fromMap(res.data); + } + /// Use this endpoint to create a session from token. Provide the **userId** /// and **secret** parameters from the successful response of authentication /// flows initiated by token creation. For example, magic URL and phone login. @@ -1411,6 +1586,12 @@ class Account extends Service { Future getSession({ required String sessionId, }) async { + if (sessionId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "sessionId"', + ); + } + final String apiPath = '/account/sessions/{sessionId}'.replaceAll( '{sessionId}', sessionId, @@ -1439,6 +1620,12 @@ class Account extends Service { Future updateSession({ required String sessionId, }) async { + if (sessionId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "sessionId"', + ); + } + final String apiPath = '/account/sessions/{sessionId}'.replaceAll( '{sessionId}', sessionId, @@ -1470,6 +1657,12 @@ class Account extends Service { Future deleteSession({ required String sessionId, }) async { + if (sessionId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "sessionId"', + ); + } + final String apiPath = '/account/sessions/{sessionId}'.replaceAll( '{sessionId}', sessionId, @@ -1480,6 +1673,7 @@ class Account extends Service { final Map apiHeaders = { 'X-Appwrite-Project': client.config['project'] ?? '', 'content-type': 'application/json', + 'accept': 'application/json', }; final res = await client.call( @@ -1520,7 +1714,10 @@ class Account extends Service { /// target ID (custom or generated using ID.unique()), a device identifier /// (usually a device token), and optionally specify which provider should send /// notifications to this target. The target is automatically linked to the - /// current session and includes device information like brand and model. + /// current session and includes device information like brand and model. A + /// session holds one push target per provider, so if one already exists this + /// endpoint updates and returns that target instead of creating a second one, + /// and a device that rotates its token is never notified twice. Future createPushTarget({ required String targetId, required String identifier, @@ -1559,6 +1756,12 @@ class Account extends Service { required String targetId, required String identifier, }) async { + if (targetId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "targetId"', + ); + } + final String apiPath = '/account/targets/{targetId}/push'.replaceAll( '{targetId}', targetId, @@ -1590,6 +1793,12 @@ class Account extends Service { Future deletePushTarget({ required String targetId, }) async { + if (targetId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "targetId"', + ); + } + final String apiPath = '/account/targets/{targetId}/push'.replaceAll( '{targetId}', targetId, @@ -1600,6 +1809,7 @@ class Account extends Service { final Map apiHeaders = { 'X-Appwrite-Project': client.config['project'] ?? '', 'content-type': 'application/json', + 'accept': 'application/json', }; final res = await client.call( @@ -1709,6 +1919,10 @@ class Account extends Service { /// session](https://appwrite.io/docs/references/cloud/client-web/account#createSession) /// endpoint. /// + /// If there is already an active session, the OAuth2 identity is attached to + /// the logged-in account and that session stays active until the token is + /// exchanged for a new one. + /// /// A user is limited to 10 active sessions at a time by default. [Learn more /// about session /// limits](https://appwrite.io/docs/authentication-security#limits). @@ -1939,6 +2153,77 @@ class Account extends Service { return models.Token.fromMap(res.data); } + /// Use this endpoint to send a 6-digit verification code to the currently + /// logged in user's email address. Unlike + /// [createEmailVerification](https://appwrite.io/docs/references/cloud/client-web/account#createEmailVerification), + /// this method requires no redirect URL, which makes it suitable for mobile + /// and desktop apps that cannot host a verification page. Learn more about how + /// to [complete the verification + /// process](https://appwrite.io/docs/references/cloud/client-web/account#updateEmailVerificationOTP). + /// The code sent to the user's email address is valid for 15 minutes. + /// + /// Enable the **phrase** parameter to include a randomly generated security + /// phrase in both the email and the response. Showing that phrase in your app + /// lets the user confirm the email genuinely came from your request, which + /// helps protect against phishing. + Future createEmailVerificationOTP({ + bool? phrase, + }) async { + final String apiPath = '/account/verifications/email/otp'; + + final Map apiParams = { + if (phrase != null) 'phrase': phrase, + }; + + final Map apiHeaders = { + 'X-Appwrite-Project': client.config['project'] ?? '', + 'content-type': 'application/json', + 'accept': 'application/json', + }; + + final res = await client.call( + HttpMethod.post, + path: apiPath, + params: apiParams, + headers: apiHeaders, + ); + + return models.Token.fromMap(res.data); + } + + /// Use this endpoint to complete the user email verification process using the + /// 6-digit code that was emailed by + /// [createEmailVerificationOTP](https://appwrite.io/docs/references/cloud/client-web/account#createEmailVerificationOTP). + /// Pass the **userId** of the user being verified along with the **secret** + /// code from the email. If confirmed, this route will return a 200 status code + /// and the code is consumed. + Future updateEmailVerificationOTP({ + required String userId, + required String secret, + }) async { + final String apiPath = '/account/verifications/email/otp'; + + final Map apiParams = { + 'userId': userId, + 'secret': secret, + }; + + final Map apiHeaders = { + 'X-Appwrite-Project': client.config['project'] ?? '', + 'content-type': 'application/json', + 'accept': 'application/json', + }; + + final res = await client.call( + HttpMethod.put, + path: apiPath, + params: apiParams, + headers: apiHeaders, + ); + + return models.Token.fromMap(res.data); + } + /// Use this endpoint to send a verification SMS to the currently logged in /// user. This endpoint is meant for use after updating a user's phone number /// using the diff --git a/lib/services/databases.dart b/lib/services/databases.dart index aaa74ff5..f1bb2510 100644 --- a/lib/services/databases.dart +++ b/lib/services/databases.dart @@ -70,6 +70,12 @@ class Databases extends Service { Future getTransaction({ required String transactionId, }) async { + if (transactionId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "transactionId"', + ); + } + final String apiPath = '/databases/transactions/{transactionId}'.replaceAll( '{transactionId}', transactionId, @@ -101,6 +107,12 @@ class Databases extends Service { bool? commit, bool? rollback, }) async { + if (transactionId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "transactionId"', + ); + } + final String apiPath = '/databases/transactions/{transactionId}'.replaceAll( '{transactionId}', transactionId, @@ -134,6 +146,12 @@ class Databases extends Service { Future deleteTransaction({ required String transactionId, }) async { + if (transactionId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "transactionId"', + ); + } + final String apiPath = '/databases/transactions/{transactionId}'.replaceAll( '{transactionId}', transactionId, @@ -144,6 +162,7 @@ class Databases extends Service { final Map apiHeaders = { 'X-Appwrite-Project': client.config['project'] ?? '', 'content-type': 'application/json', + 'accept': 'application/json', }; final res = await client.call( @@ -164,6 +183,12 @@ class Databases extends Service { required String transactionId, List? operations, }) async { + if (transactionId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "transactionId"', + ); + } + final String apiPath = '/databases/transactions/{transactionId}/operations'.replaceAll( '{transactionId}', @@ -203,6 +228,18 @@ class Databases extends Service { bool? total, int? ttl, }) async { + if (databaseId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "databaseId"', + ); + } + + if (collectionId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "collectionId"', + ); + } + final String apiPath = '/databases/{databaseId}/collections/{collectionId}/documents' .replaceAll( @@ -251,6 +288,18 @@ class Databases extends Service { List? permissions, String? transactionId, }) async { + if (databaseId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "databaseId"', + ); + } + + if (collectionId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "collectionId"', + ); + } + final String apiPath = '/databases/{databaseId}/collections/{collectionId}/documents' .replaceAll( @@ -297,6 +346,24 @@ class Databases extends Service { List? queries, String? transactionId, }) async { + if (databaseId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "databaseId"', + ); + } + + if (collectionId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "collectionId"', + ); + } + + if (documentId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "documentId"', + ); + } + final String apiPath = '/databases/{databaseId}/collections/{collectionId}/documents/{documentId}' .replaceAll( @@ -347,6 +414,24 @@ class Databases extends Service { List? permissions, String? transactionId, }) async { + if (databaseId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "databaseId"', + ); + } + + if (collectionId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "collectionId"', + ); + } + + if (documentId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "documentId"', + ); + } + final String apiPath = '/databases/{databaseId}/collections/{collectionId}/documents/{documentId}' .replaceAll( @@ -397,6 +482,24 @@ class Databases extends Service { List? permissions, String? transactionId, }) async { + if (databaseId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "databaseId"', + ); + } + + if (collectionId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "collectionId"', + ); + } + + if (documentId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "documentId"', + ); + } + final String apiPath = '/databases/{databaseId}/collections/{collectionId}/documents/{documentId}' .replaceAll( @@ -444,6 +547,24 @@ class Databases extends Service { required String documentId, String? transactionId, }) async { + if (databaseId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "databaseId"', + ); + } + + if (collectionId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "collectionId"', + ); + } + + if (documentId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "documentId"', + ); + } + final String apiPath = '/databases/{databaseId}/collections/{collectionId}/documents/{documentId}' .replaceAll( @@ -466,6 +587,7 @@ class Databases extends Service { final Map apiHeaders = { 'X-Appwrite-Project': client.config['project'] ?? '', 'content-type': 'application/json', + 'accept': 'application/json', }; final res = await client.call( @@ -491,6 +613,30 @@ class Databases extends Service { double? min, String? transactionId, }) async { + if (databaseId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "databaseId"', + ); + } + + if (collectionId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "collectionId"', + ); + } + + if (documentId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "documentId"', + ); + } + + if (attribute.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "attribute"', + ); + } + final String apiPath = '/databases/{databaseId}/collections/{collectionId}/documents/{documentId}/{attribute}/decrement' .replaceAll( @@ -545,6 +691,30 @@ class Databases extends Service { double? max, String? transactionId, }) async { + if (databaseId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "databaseId"', + ); + } + + if (collectionId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "collectionId"', + ); + } + + if (documentId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "documentId"', + ); + } + + if (attribute.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "attribute"', + ); + } + final String apiPath = '/databases/{databaseId}/collections/{collectionId}/documents/{documentId}/{attribute}/increment' .replaceAll( diff --git a/lib/services/documents_db.dart b/lib/services/documents_db.dart index 0756f7d1..3ca77cdb 100644 --- a/lib/services/documents_db.dart +++ b/lib/services/documents_db.dart @@ -59,6 +59,12 @@ class DocumentsDB extends Service { Future getTransaction({ required String transactionId, }) async { + if (transactionId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "transactionId"', + ); + } + final String apiPath = '/documentsdb/transactions/{transactionId}'.replaceAll( '{transactionId}', @@ -88,6 +94,12 @@ class DocumentsDB extends Service { bool? commit, bool? rollback, }) async { + if (transactionId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "transactionId"', + ); + } + final String apiPath = '/documentsdb/transactions/{transactionId}'.replaceAll( '{transactionId}', @@ -119,6 +131,12 @@ class DocumentsDB extends Service { Future deleteTransaction({ required String transactionId, }) async { + if (transactionId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "transactionId"', + ); + } + final String apiPath = '/documentsdb/transactions/{transactionId}'.replaceAll( '{transactionId}', @@ -130,6 +148,7 @@ class DocumentsDB extends Service { final Map apiHeaders = { 'X-Appwrite-Project': client.config['project'] ?? '', 'content-type': 'application/json', + 'accept': 'application/json', }; final res = await client.call( @@ -147,6 +166,12 @@ class DocumentsDB extends Service { required String transactionId, List? operations, }) async { + if (transactionId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "transactionId"', + ); + } + final String apiPath = '/documentsdb/transactions/{transactionId}/operations'.replaceAll( '{transactionId}', @@ -183,6 +208,18 @@ class DocumentsDB extends Service { bool? total, int? ttl, }) async { + if (databaseId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "databaseId"', + ); + } + + if (collectionId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "collectionId"', + ); + } + final String apiPath = '/documentsdb/{databaseId}/collections/{collectionId}/documents' .replaceAll( @@ -228,6 +265,18 @@ class DocumentsDB extends Service { List? permissions, String? transactionId, }) async { + if (databaseId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "databaseId"', + ); + } + + if (collectionId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "collectionId"', + ); + } + final String apiPath = '/documentsdb/{databaseId}/collections/{collectionId}/documents' .replaceAll( @@ -272,6 +321,18 @@ class DocumentsDB extends Service { required List documents, String? transactionId, }) async { + if (databaseId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "databaseId"', + ); + } + + if (collectionId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "collectionId"', + ); + } + final String apiPath = '/documentsdb/{databaseId}/collections/{collectionId}/documents' .replaceAll( @@ -313,6 +374,24 @@ class DocumentsDB extends Service { List? queries, String? transactionId, }) async { + if (databaseId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "databaseId"', + ); + } + + if (collectionId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "collectionId"', + ); + } + + if (documentId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "documentId"', + ); + } + final String apiPath = '/documentsdb/{databaseId}/collections/{collectionId}/documents/{documentId}' .replaceAll( @@ -360,6 +439,24 @@ class DocumentsDB extends Service { List? permissions, String? transactionId, }) async { + if (databaseId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "databaseId"', + ); + } + + if (collectionId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "collectionId"', + ); + } + + if (documentId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "documentId"', + ); + } + final String apiPath = '/documentsdb/{databaseId}/collections/{collectionId}/documents/{documentId}' .replaceAll( @@ -407,6 +504,24 @@ class DocumentsDB extends Service { List? permissions, String? transactionId, }) async { + if (databaseId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "databaseId"', + ); + } + + if (collectionId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "collectionId"', + ); + } + + if (documentId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "documentId"', + ); + } + final String apiPath = '/documentsdb/{databaseId}/collections/{collectionId}/documents/{documentId}' .replaceAll( @@ -451,6 +566,24 @@ class DocumentsDB extends Service { required String documentId, String? transactionId, }) async { + if (databaseId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "databaseId"', + ); + } + + if (collectionId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "collectionId"', + ); + } + + if (documentId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "documentId"', + ); + } + final String apiPath = '/documentsdb/{databaseId}/collections/{collectionId}/documents/{documentId}' .replaceAll( @@ -473,6 +606,7 @@ class DocumentsDB extends Service { final Map apiHeaders = { 'X-Appwrite-Project': client.config['project'] ?? '', 'content-type': 'application/json', + 'accept': 'application/json', }; final res = await client.call( @@ -495,6 +629,30 @@ class DocumentsDB extends Service { double? min, String? transactionId, }) async { + if (databaseId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "databaseId"', + ); + } + + if (collectionId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "collectionId"', + ); + } + + if (documentId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "documentId"', + ); + } + + if (attribute.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "attribute"', + ); + } + final String apiPath = '/documentsdb/{databaseId}/collections/{collectionId}/documents/{documentId}/{attribute}/decrement' .replaceAll( @@ -546,6 +704,30 @@ class DocumentsDB extends Service { double? max, String? transactionId, }) async { + if (databaseId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "databaseId"', + ); + } + + if (collectionId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "collectionId"', + ); + } + + if (documentId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "documentId"', + ); + } + + if (attribute.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "attribute"', + ); + } + final String apiPath = '/documentsdb/{databaseId}/collections/{collectionId}/documents/{documentId}/{attribute}/increment' .replaceAll( diff --git a/lib/services/functions.dart b/lib/services/functions.dart index fc5f460e..9d40b1d0 100644 --- a/lib/services/functions.dart +++ b/lib/services/functions.dart @@ -13,6 +13,12 @@ class Functions extends Service { List? queries, bool? total, }) async { + if (functionId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "functionId"', + ); + } + final String apiPath = '/functions/{functionId}/executions'.replaceAll( '{functionId}', functionId, @@ -51,6 +57,12 @@ class Functions extends Service { Map? headers, String? scheduledAt, }) async { + if (functionId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "functionId"', + ); + } + final String apiPath = '/functions/{functionId}/executions'.replaceAll( '{functionId}', functionId, @@ -86,6 +98,18 @@ class Functions extends Service { required String functionId, required String executionId, }) async { + if (functionId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "functionId"', + ); + } + + if (executionId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "executionId"', + ); + } + final String apiPath = '/functions/{functionId}/executions/{executionId}' .replaceAll( '{functionId}', diff --git a/lib/services/messaging.dart b/lib/services/messaging.dart index d213b55f..4afbb010 100644 --- a/lib/services/messaging.dart +++ b/lib/services/messaging.dart @@ -12,6 +12,12 @@ class Messaging extends Service { required String subscriberId, required String targetId, }) async { + if (topicId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "topicId"', + ); + } + final String apiPath = '/messaging/topics/{topicId}/subscribers'.replaceAll( '{topicId}', topicId, @@ -43,6 +49,18 @@ class Messaging extends Service { required String topicId, required String subscriberId, }) async { + if (topicId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "topicId"', + ); + } + + if (subscriberId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "subscriberId"', + ); + } + final String apiPath = '/messaging/topics/{topicId}/subscribers/{subscriberId}' .replaceAll( @@ -59,6 +77,7 @@ class Messaging extends Service { final Map apiHeaders = { 'X-Appwrite-Project': client.config['project'] ?? '', 'content-type': 'application/json', + 'accept': 'application/json', }; final res = await client.call( diff --git a/lib/services/organization.dart b/lib/services/organization.dart index 1dd88dac..bbda874a 100644 --- a/lib/services/organization.dart +++ b/lib/services/organization.dart @@ -69,6 +69,12 @@ class Organization extends Service { Future getInstallation({ required String installationId, }) async { + if (installationId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "installationId"', + ); + } + final String apiPath = '/organization/installations/{installationId}'.replaceAll( '{installationId}', @@ -100,6 +106,12 @@ class Organization extends Service { required String installationId, String? authorizationDetails, }) async { + if (installationId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "installationId"', + ); + } + final String apiPath = '/organization/installations/{installationId}'.replaceAll( '{installationId}', @@ -133,6 +145,12 @@ class Organization extends Service { Future deleteInstallation({ required String installationId, }) async { + if (installationId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "installationId"', + ); + } + final String apiPath = '/organization/installations/{installationId}'.replaceAll( '{installationId}', diff --git a/lib/services/presences.dart b/lib/services/presences.dart index f40c07e3..7ce2e633 100644 --- a/lib/services/presences.dart +++ b/lib/services/presences.dart @@ -40,6 +40,12 @@ class Presences extends Service { Future get({ required String presenceId, }) async { + if (presenceId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "presenceId"', + ); + } + final String apiPath = '/presences/{presenceId}'.replaceAll( '{presenceId}', presenceId, @@ -70,6 +76,12 @@ class Presences extends Service { String? expiresAt, Map? metadata, }) async { + if (presenceId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "presenceId"', + ); + } + final String apiPath = '/presences/{presenceId}'.replaceAll( '{presenceId}', presenceId, @@ -108,6 +120,12 @@ class Presences extends Service { List? permissions, bool? purge, }) async { + if (presenceId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "presenceId"', + ); + } + final String apiPath = '/presences/{presenceId}'.replaceAll( '{presenceId}', presenceId, @@ -141,6 +159,12 @@ class Presences extends Service { Future delete({ required String presenceId, }) async { + if (presenceId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "presenceId"', + ); + } + final String apiPath = '/presences/{presenceId}'.replaceAll( '{presenceId}', presenceId, @@ -151,6 +175,7 @@ class Presences extends Service { final Map apiHeaders = { 'X-Appwrite-Project': client.config['project'] ?? '', 'content-type': 'application/json', + 'accept': 'application/json', }; final res = await client.call( diff --git a/lib/services/storage.dart b/lib/services/storage.dart index 77f156dd..52a129a8 100644 --- a/lib/services/storage.dart +++ b/lib/services/storage.dart @@ -13,6 +13,12 @@ class Storage extends Service { String? search, bool? total, }) async { + if (bucketId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "bucketId"', + ); + } + final String apiPath = '/storage/buckets/{bucketId}/files'.replaceAll( '{bucketId}', bucketId, @@ -64,6 +70,12 @@ class Storage extends Service { String? folder, Function(UploadProgress)? onProgress, }) async { + if (bucketId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "bucketId"', + ); + } + final String apiPath = '/storage/buckets/{bucketId}/files'.replaceAll( '{bucketId}', bucketId, @@ -103,6 +115,18 @@ class Storage extends Service { required String bucketId, required String fileId, }) async { + if (bucketId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "bucketId"', + ); + } + + if (fileId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "fileId"', + ); + } + final String apiPath = '/storage/buckets/{bucketId}/files/{fileId}' .replaceAll( '{bucketId}', @@ -138,6 +162,18 @@ class Storage extends Service { String? name, List? permissions, }) async { + if (bucketId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "bucketId"', + ); + } + + if (fileId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "fileId"', + ); + } + final String apiPath = '/storage/buckets/{bucketId}/files/{fileId}' .replaceAll( '{bucketId}', @@ -175,6 +211,18 @@ class Storage extends Service { required String bucketId, required String fileId, }) async { + if (bucketId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "bucketId"', + ); + } + + if (fileId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "fileId"', + ); + } + final String apiPath = '/storage/buckets/{bucketId}/files/{fileId}' .replaceAll( '{bucketId}', @@ -190,6 +238,7 @@ class Storage extends Service { final Map apiHeaders = { 'X-Appwrite-Project': client.config['project'] ?? '', 'content-type': 'application/json', + 'accept': 'application/json', }; final res = await client.call( @@ -210,6 +259,18 @@ class Storage extends Service { required String fileId, String? token, }) async { + if (bucketId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "bucketId"', + ); + } + + if (fileId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "fileId"', + ); + } + final String apiPath = '/storage/buckets/{bucketId}/files/{fileId}/download' .replaceAll( '{bucketId}', @@ -260,6 +321,18 @@ class Storage extends Service { enums.ImageFormat? output, String? token, }) async { + if (bucketId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "bucketId"', + ); + } + + if (fileId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "fileId"', + ); + } + final String apiPath = '/storage/buckets/{bucketId}/files/{fileId}/preview' .replaceAll( '{bucketId}', @@ -308,6 +381,18 @@ class Storage extends Service { required String fileId, String? token, }) async { + if (bucketId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "bucketId"', + ); + } + + if (fileId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "fileId"', + ); + } + final String apiPath = '/storage/buckets/{bucketId}/files/{fileId}/view' .replaceAll( '{bucketId}', diff --git a/lib/services/tables_db.dart b/lib/services/tables_db.dart index d7f23f39..4fdbb987 100644 --- a/lib/services/tables_db.dart +++ b/lib/services/tables_db.dart @@ -61,6 +61,12 @@ class TablesDB extends Service { Future getTransaction({ required String transactionId, }) async { + if (transactionId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "transactionId"', + ); + } + final String apiPath = '/tablesdb/transactions/{transactionId}'.replaceAll( '{transactionId}', transactionId, @@ -89,6 +95,12 @@ class TablesDB extends Service { bool? commit, bool? rollback, }) async { + if (transactionId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "transactionId"', + ); + } + final String apiPath = '/tablesdb/transactions/{transactionId}'.replaceAll( '{transactionId}', transactionId, @@ -119,6 +131,12 @@ class TablesDB extends Service { Future deleteTransaction({ required String transactionId, }) async { + if (transactionId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "transactionId"', + ); + } + final String apiPath = '/tablesdb/transactions/{transactionId}'.replaceAll( '{transactionId}', transactionId, @@ -129,6 +147,7 @@ class TablesDB extends Service { final Map apiHeaders = { 'X-Appwrite-Project': client.config['project'] ?? '', 'content-type': 'application/json', + 'accept': 'application/json', }; final res = await client.call( @@ -146,6 +165,12 @@ class TablesDB extends Service { required String transactionId, List? operations, }) async { + if (transactionId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "transactionId"', + ); + } + final String apiPath = '/tablesdb/transactions/{transactionId}/operations'.replaceAll( '{transactionId}', @@ -182,6 +207,18 @@ class TablesDB extends Service { bool? total, int? ttl, }) async { + if (databaseId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "databaseId"', + ); + } + + if (tableId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "tableId"', + ); + } + final String apiPath = '/tablesdb/{databaseId}/tables/{tableId}/rows' .replaceAll( '{databaseId}', @@ -226,6 +263,18 @@ class TablesDB extends Service { List? permissions, String? transactionId, }) async { + if (databaseId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "databaseId"', + ); + } + + if (tableId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "tableId"', + ); + } + final String apiPath = '/tablesdb/{databaseId}/tables/{tableId}/rows' .replaceAll( '{databaseId}', @@ -268,6 +317,24 @@ class TablesDB extends Service { List? queries, String? transactionId, }) async { + if (databaseId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "databaseId"', + ); + } + + if (tableId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "tableId"', + ); + } + + if (rowId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "rowId"', + ); + } + final String apiPath = '/tablesdb/{databaseId}/tables/{tableId}/rows/{rowId}' .replaceAll( @@ -315,6 +382,24 @@ class TablesDB extends Service { List? permissions, String? transactionId, }) async { + if (databaseId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "databaseId"', + ); + } + + if (tableId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "tableId"', + ); + } + + if (rowId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "rowId"', + ); + } + final String apiPath = '/tablesdb/{databaseId}/tables/{tableId}/rows/{rowId}' .replaceAll( @@ -362,6 +447,24 @@ class TablesDB extends Service { List? permissions, String? transactionId, }) async { + if (databaseId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "databaseId"', + ); + } + + if (tableId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "tableId"', + ); + } + + if (rowId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "rowId"', + ); + } + final String apiPath = '/tablesdb/{databaseId}/tables/{tableId}/rows/{rowId}' .replaceAll( @@ -406,6 +509,24 @@ class TablesDB extends Service { required String rowId, String? transactionId, }) async { + if (databaseId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "databaseId"', + ); + } + + if (tableId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "tableId"', + ); + } + + if (rowId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "rowId"', + ); + } + final String apiPath = '/tablesdb/{databaseId}/tables/{tableId}/rows/{rowId}' .replaceAll( @@ -428,6 +549,7 @@ class TablesDB extends Service { final Map apiHeaders = { 'X-Appwrite-Project': client.config['project'] ?? '', 'content-type': 'application/json', + 'accept': 'application/json', }; final res = await client.call( @@ -450,6 +572,30 @@ class TablesDB extends Service { double? min, String? transactionId, }) async { + if (databaseId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "databaseId"', + ); + } + + if (tableId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "tableId"', + ); + } + + if (rowId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "rowId"', + ); + } + + if (column.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "column"', + ); + } + final String apiPath = '/tablesdb/{databaseId}/tables/{tableId}/rows/{rowId}/{column}/decrement' .replaceAll( @@ -501,6 +647,30 @@ class TablesDB extends Service { double? max, String? transactionId, }) async { + if (databaseId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "databaseId"', + ); + } + + if (tableId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "tableId"', + ); + } + + if (rowId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "rowId"', + ); + } + + if (column.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "column"', + ); + } + final String apiPath = '/tablesdb/{databaseId}/tables/{tableId}/rows/{rowId}/{column}/increment' .replaceAll( diff --git a/lib/services/teams.dart b/lib/services/teams.dart index 99190fc1..99e9d722 100644 --- a/lib/services/teams.dart +++ b/lib/services/teams.dart @@ -72,6 +72,12 @@ class Teams extends Service { Future get({ required String teamId, }) async { + if (teamId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "teamId"', + ); + } + final String apiPath = '/teams/{teamId}'.replaceAll( '{teamId}', teamId, @@ -99,6 +105,12 @@ class Teams extends Service { required String teamId, required String name, }) async { + if (teamId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "teamId"', + ); + } + final String apiPath = '/teams/{teamId}'.replaceAll( '{teamId}', teamId, @@ -129,6 +141,12 @@ class Teams extends Service { Future delete({ required String teamId, }) async { + if (teamId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "teamId"', + ); + } + final String apiPath = '/teams/{teamId}'.replaceAll( '{teamId}', teamId, @@ -139,6 +157,7 @@ class Teams extends Service { final Map apiHeaders = { 'X-Appwrite-Project': client.config['project'] ?? '', 'content-type': 'application/json', + 'accept': 'application/json', }; final res = await client.call( @@ -157,6 +176,12 @@ class Teams extends Service { List? queries, bool? total, }) async { + if (teamId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "teamId"', + ); + } + final String apiPath = '/teams/{teamId}/installations'.replaceAll( '{teamId}', teamId, @@ -191,6 +216,12 @@ class Teams extends Service { required String appId, String? authorizationDetails, }) async { + if (teamId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "teamId"', + ); + } + final String apiPath = '/teams/{teamId}/installations'.replaceAll( '{teamId}', teamId, @@ -224,6 +255,18 @@ class Teams extends Service { required String teamId, required String installationId, }) async { + if (teamId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "teamId"', + ); + } + + if (installationId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "installationId"', + ); + } + final String apiPath = '/teams/{teamId}/installations/{installationId}' .replaceAll( '{teamId}', @@ -260,6 +303,18 @@ class Teams extends Service { required String installationId, String? authorizationDetails, }) async { + if (teamId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "teamId"', + ); + } + + if (installationId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "installationId"', + ); + } + final String apiPath = '/teams/{teamId}/installations/{installationId}' .replaceAll( '{teamId}', @@ -298,6 +353,18 @@ class Teams extends Service { required String teamId, required String installationId, }) async { + if (teamId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "teamId"', + ); + } + + if (installationId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "installationId"', + ); + } + final String apiPath = '/teams/{teamId}/installations/{installationId}' .replaceAll( '{teamId}', @@ -335,6 +402,12 @@ class Teams extends Service { String? search, bool? total, }) async { + if (teamId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "teamId"', + ); + } + final String apiPath = '/teams/{teamId}/memberships'.replaceAll( '{teamId}', teamId, @@ -390,6 +463,12 @@ class Teams extends Service { String? url, String? name, }) async { + if (teamId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "teamId"', + ); + } + final String apiPath = '/teams/{teamId}/memberships'.replaceAll( '{teamId}', teamId, @@ -427,6 +506,18 @@ class Teams extends Service { required String teamId, required String membershipId, }) async { + if (teamId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "teamId"', + ); + } + + if (membershipId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "membershipId"', + ); + } + final String apiPath = '/teams/{teamId}/memberships/{membershipId}' .replaceAll( '{teamId}', @@ -462,6 +553,18 @@ class Teams extends Service { required String membershipId, required List roles, }) async { + if (teamId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "teamId"', + ); + } + + if (membershipId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "membershipId"', + ); + } + final String apiPath = '/teams/{teamId}/memberships/{membershipId}' .replaceAll( '{teamId}', @@ -499,6 +602,18 @@ class Teams extends Service { required String teamId, required String membershipId, }) async { + if (teamId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "teamId"', + ); + } + + if (membershipId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "membershipId"', + ); + } + final String apiPath = '/teams/{teamId}/memberships/{membershipId}' .replaceAll( '{teamId}', @@ -514,6 +629,7 @@ class Teams extends Service { final Map apiHeaders = { 'X-Appwrite-Project': client.config['project'] ?? '', 'content-type': 'application/json', + 'accept': 'application/json', }; final res = await client.call( @@ -538,6 +654,18 @@ class Teams extends Service { required String userId, required String secret, }) async { + if (teamId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "teamId"', + ); + } + + if (membershipId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "membershipId"', + ); + } + final String apiPath = '/teams/{teamId}/memberships/{membershipId}/status' .replaceAll( '{teamId}', @@ -575,6 +703,12 @@ class Teams extends Service { Future getPrefs({ required String teamId, }) async { + if (teamId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "teamId"', + ); + } + final String apiPath = '/teams/{teamId}/prefs'.replaceAll( '{teamId}', teamId, @@ -604,6 +738,12 @@ class Teams extends Service { required String teamId, required Map prefs, }) async { + if (teamId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "teamId"', + ); + } + final String apiPath = '/teams/{teamId}/prefs'.replaceAll( '{teamId}', teamId, diff --git a/lib/services/vectors_db.dart b/lib/services/vectors_db.dart index 08ba3e81..e257b38c 100644 --- a/lib/services/vectors_db.dart +++ b/lib/services/vectors_db.dart @@ -59,6 +59,12 @@ class VectorsDB extends Service { Future getTransaction({ required String transactionId, }) async { + if (transactionId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "transactionId"', + ); + } + final String apiPath = '/vectorsdb/transactions/{transactionId}'.replaceAll( '{transactionId}', transactionId, @@ -87,6 +93,12 @@ class VectorsDB extends Service { bool? commit, bool? rollback, }) async { + if (transactionId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "transactionId"', + ); + } + final String apiPath = '/vectorsdb/transactions/{transactionId}'.replaceAll( '{transactionId}', transactionId, @@ -117,6 +129,12 @@ class VectorsDB extends Service { Future deleteTransaction({ required String transactionId, }) async { + if (transactionId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "transactionId"', + ); + } + final String apiPath = '/vectorsdb/transactions/{transactionId}'.replaceAll( '{transactionId}', transactionId, @@ -127,6 +145,7 @@ class VectorsDB extends Service { final Map apiHeaders = { 'X-Appwrite-Project': client.config['project'] ?? '', 'content-type': 'application/json', + 'accept': 'application/json', }; final res = await client.call( @@ -144,6 +163,12 @@ class VectorsDB extends Service { required String transactionId, List? operations, }) async { + if (transactionId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "transactionId"', + ); + } + final String apiPath = '/vectorsdb/transactions/{transactionId}/operations'.replaceAll( '{transactionId}', @@ -180,6 +205,18 @@ class VectorsDB extends Service { bool? total, int? ttl, }) async { + if (databaseId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "databaseId"', + ); + } + + if (collectionId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "collectionId"', + ); + } + final String apiPath = '/vectorsdb/{databaseId}/collections/{collectionId}/documents' .replaceAll( @@ -225,6 +262,18 @@ class VectorsDB extends Service { List? permissions, String? transactionId, }) async { + if (databaseId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "databaseId"', + ); + } + + if (collectionId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "collectionId"', + ); + } + final String apiPath = '/vectorsdb/{databaseId}/collections/{collectionId}/documents' .replaceAll( @@ -271,6 +320,18 @@ class VectorsDB extends Service { bool? total, int? ttl, }) async { + if (databaseId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "databaseId"', + ); + } + + if (collectionId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "collectionId"', + ); + } + final String apiPath = '/vectorsdb/{databaseId}/collections/{collectionId}/documents/query' .replaceAll( @@ -314,6 +375,24 @@ class VectorsDB extends Service { List? queries, String? transactionId, }) async { + if (databaseId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "databaseId"', + ); + } + + if (collectionId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "collectionId"', + ); + } + + if (documentId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "documentId"', + ); + } + final String apiPath = '/vectorsdb/{databaseId}/collections/{collectionId}/documents/{documentId}' .replaceAll( @@ -361,6 +440,24 @@ class VectorsDB extends Service { List? permissions, String? transactionId, }) async { + if (databaseId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "databaseId"', + ); + } + + if (collectionId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "collectionId"', + ); + } + + if (documentId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "documentId"', + ); + } + final String apiPath = '/vectorsdb/{databaseId}/collections/{collectionId}/documents/{documentId}' .replaceAll( @@ -408,6 +505,24 @@ class VectorsDB extends Service { List? permissions, String? transactionId, }) async { + if (databaseId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "databaseId"', + ); + } + + if (collectionId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "collectionId"', + ); + } + + if (documentId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "documentId"', + ); + } + final String apiPath = '/vectorsdb/{databaseId}/collections/{collectionId}/documents/{documentId}' .replaceAll( @@ -452,6 +567,24 @@ class VectorsDB extends Service { required String documentId, String? transactionId, }) async { + if (databaseId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "databaseId"', + ); + } + + if (collectionId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "collectionId"', + ); + } + + if (documentId.isEmpty) { + throw AppwriteException( + 'Missing required parameter: "documentId"', + ); + } + final String apiPath = '/vectorsdb/{databaseId}/collections/{collectionId}/documents/{documentId}' .replaceAll( @@ -474,6 +607,7 @@ class VectorsDB extends Service { final Map apiHeaders = { 'X-Appwrite-Project': client.config['project'] ?? '', 'content-type': 'application/json', + 'accept': 'application/json', }; final res = await client.call( diff --git a/lib/src/client.dart b/lib/src/client.dart index dbfe4bdf..fedec03c 100644 --- a/lib/src/client.dart +++ b/lib/src/client.dart @@ -79,11 +79,6 @@ abstract class Client { /// The user session to authenticate with. Client setSession(String value); - /// Set DevKey. - /// - /// Your secret dev API key. - Client setDevKey(String value); - /// Set Cookie. /// /// The user cookie to authenticate with. Used by SDKs that forward an incoming Cookie header in server-side runtimes.. diff --git a/lib/src/client_base.dart b/lib/src/client_base.dart index 9e6cf566..36e4bbc9 100644 --- a/lib/src/client_base.dart +++ b/lib/src/client_base.dart @@ -22,10 +22,6 @@ abstract class ClientBase implements Client { @override ClientBase setSession(value); - /// Your secret dev API key - @override - ClientBase setDevKey(value); - /// The user cookie to authenticate with. Used by SDKs that forward an incoming Cookie header in server-side runtimes. @override ClientBase setCookie(value); diff --git a/lib/src/client_browser.dart b/lib/src/client_browser.dart index fdf011c8..d04f9bc6 100644 --- a/lib/src/client_browser.dart +++ b/lib/src/client_browser.dart @@ -40,8 +40,8 @@ class ClientBrowser extends ClientBase with ClientMixin { 'x-sdk-name': 'Flutter', 'x-sdk-platform': 'client', 'x-sdk-language': 'flutter', - 'x-sdk-version': '26.2.0', - 'X-Appwrite-Response-Format': '2.0.0', + 'x-sdk-version': '27.0.0', + 'X-Appwrite-Response-Format': '2.3.0', }; config = {}; @@ -94,14 +94,6 @@ class ClientBrowser extends ClientBase with ClientMixin { return this; } - /// Your secret dev API key - @override - ClientBrowser setDevKey(value) { - config['devKey'] = value; - addHeader('X-Appwrite-Dev-Key', value); - return this; - } - /// The user cookie to authenticate with. Used by SDKs that forward an incoming Cookie header in server-side runtimes. @override ClientBrowser setCookie(value) { @@ -346,21 +338,13 @@ class ClientBrowser extends ClientBase with ClientMixin { }) async { await init(); - // Combine headers to check for dev key - final combinedHeaders = {..._headers!, ...headers}; - - // Only include credentials when dev key is not set - if (combinedHeaders['X-Appwrite-Dev-Key'] == null) { - _httpClient.withCredentials = true; - } else { - _httpClient.withCredentials = false; - } + _httpClient.withCredentials = true; late http.Response res; http.BaseRequest request = prepareRequest( method, uri: Uri.parse(_endPoint + path), - headers: combinedHeaders, + headers: {..._headers!, ...headers}, params: params, ); try { diff --git a/lib/src/client_io.dart b/lib/src/client_io.dart index 3ccefd87..f228d17f 100644 --- a/lib/src/client_io.dart +++ b/lib/src/client_io.dart @@ -59,8 +59,8 @@ class ClientIO extends ClientBase with ClientMixin { 'x-sdk-name': 'Flutter', 'x-sdk-platform': 'client', 'x-sdk-language': 'flutter', - 'x-sdk-version': '26.2.0', - 'X-Appwrite-Response-Format': '2.0.0', + 'x-sdk-version': '27.0.0', + 'X-Appwrite-Response-Format': '2.3.0', }; config = {}; @@ -121,14 +121,6 @@ class ClientIO extends ClientBase with ClientMixin { return this; } - /// Your secret dev API key - @override - ClientIO setDevKey(value) { - config['devKey'] = value; - addHeader('X-Appwrite-Dev-Key', value); - return this; - } - /// The user cookie to authenticate with. Used by SDKs that forward an incoming Cookie header in server-side runtimes. @override ClientIO setCookie(value) { diff --git a/lib/src/enums/id_token_provider.dart b/lib/src/enums/id_token_provider.dart new file mode 100644 index 00000000..4863e845 --- /dev/null +++ b/lib/src/enums/id_token_provider.dart @@ -0,0 +1,12 @@ +part of '../../enums.dart'; + +enum IdTokenProvider { + apple(value: "apple"), + google(value: "google"); + + const IdTokenProvider({required this.value}); + + final String value; + + String toJson() => value; +} diff --git a/lib/src/enums/o_auth_provider.dart b/lib/src/enums/o_auth_provider.dart index 6626f3a0..02b85c7f 100644 --- a/lib/src/enums/o_auth_provider.dart +++ b/lib/src/enums/o_auth_provider.dart @@ -23,6 +23,7 @@ enum OAuthProvider { gitlab(value: "gitlab"), google(value: "google"), huggingface(value: "huggingface"), + kakao(value: "kakao"), keycloak(value: "keycloak"), kick(value: "kick"), linkedin(value: "linkedin"), @@ -38,6 +39,7 @@ enum OAuthProvider { slack(value: "slack"), spotify(value: "spotify"), stripe(value: "stripe"), + tiktok(value: "tiktok"), tradeshift(value: "tradeshift"), tradeshiftBox(value: "tradeshiftBox"), twitch(value: "twitch"), diff --git a/lib/src/models/execution.dart b/lib/src/models/execution.dart index 2b07213b..d4fe5134 100644 --- a/lib/src/models/execution.dart +++ b/lib/src/models/execution.dart @@ -53,7 +53,7 @@ class Execution implements Model { /// Resource errors. Includes the last 4,000 characters. This will return an empty string unless the response is returned using an API key or as part of a webhook payload. final String errors; - /// Resource(function/site) execution duration in seconds. + /// Total time the resource(function/site) took to respond, in seconds. final double duration; /// The scheduled time for execution. If left empty, execution will be queued immediately. diff --git a/lib/src/models/identity.dart b/lib/src/models/identity.dart index 2f32c7f9..7203863d 100644 --- a/lib/src/models/identity.dart +++ b/lib/src/models/identity.dart @@ -32,6 +32,9 @@ class Identity implements Model { /// Identity Provider Refresh Token. final String providerRefreshToken; + /// Identity Provider ID token (JWT) from the most recent native sign-in. Empty for identities created through the browser OAuth2 flow. + final String providerIdToken; + Identity({ required this.$id, required this.$createdAt, @@ -43,6 +46,7 @@ class Identity implements Model { required this.providerAccessToken, required this.providerAccessTokenExpiry, required this.providerRefreshToken, + required this.providerIdToken, }); factory Identity.fromMap( Map map, @@ -58,6 +62,7 @@ class Identity implements Model { providerAccessToken: map['providerAccessToken'].toString(), providerAccessTokenExpiry: map['providerAccessTokenExpiry'].toString(), providerRefreshToken: map['providerRefreshToken'].toString(), + providerIdToken: map['providerIdToken'].toString(), ); } @@ -74,6 +79,7 @@ class Identity implements Model { "providerAccessToken": providerAccessToken, "providerAccessTokenExpiry": providerAccessTokenExpiry, "providerRefreshToken": providerRefreshToken, + "providerIdToken": providerIdToken, }; } } diff --git a/lib/src/models/log.dart b/lib/src/models/log.dart deleted file mode 100644 index 296fe5f8..00000000 --- a/lib/src/models/log.dart +++ /dev/null @@ -1,151 +0,0 @@ -part of '../../models.dart'; - -/// Log -class Log implements Model { - /// Event name. - final String event; - - /// User ID of the actor recorded for this log. During impersonation, this is the original impersonator, not the impersonated target user. - final String userId; - - /// User email of the actor recorded for this log. During impersonation, this is the original impersonator. - final String userEmail; - - /// User name of the actor recorded for this log. During impersonation, this is the original impersonator. - final String userName; - - /// API mode when event triggered. - final String mode; - - /// User type who triggered the audit log. Possible values: user, admin, guest, hidden, keyProject, keyAccount, keyOrganization. - final String userType; - - /// IP session in use when the session was created. - final String ip; - - /// Log creation date in ISO 8601 format. - final String time; - - /// Operating system code name. View list of [available options](https://github.com/appwrite/appwrite/blob/master/docs/lists/os.json). - final String osCode; - - /// Operating system name. - final String osName; - - /// Operating system version. - final String osVersion; - - /// Client type. - final String clientType; - - /// Client code name. View list of [available options](https://github.com/appwrite/appwrite/blob/master/docs/lists/clients.json). - final String clientCode; - - /// Client name. - final String clientName; - - /// Client version. - final String clientVersion; - - /// Client engine name. - final String clientEngine; - - /// Client engine name. - final String clientEngineVersion; - - /// Device name. - final String deviceName; - - /// Device brand name. - final String deviceBrand; - - /// Device model name. - final String deviceModel; - - /// Country two-character ISO 3166-1 alpha code. - final String countryCode; - - /// Country name. - final String countryName; - - Log({ - required this.event, - required this.userId, - required this.userEmail, - required this.userName, - required this.mode, - required this.userType, - required this.ip, - required this.time, - required this.osCode, - required this.osName, - required this.osVersion, - required this.clientType, - required this.clientCode, - required this.clientName, - required this.clientVersion, - required this.clientEngine, - required this.clientEngineVersion, - required this.deviceName, - required this.deviceBrand, - required this.deviceModel, - required this.countryCode, - required this.countryName, - }); - factory Log.fromMap( - Map map, - ) { - return Log( - event: map['event'].toString(), - userId: map['userId'].toString(), - userEmail: map['userEmail'].toString(), - userName: map['userName'].toString(), - mode: map['mode'].toString(), - userType: map['userType'].toString(), - ip: map['ip'].toString(), - time: map['time'].toString(), - osCode: map['osCode'].toString(), - osName: map['osName'].toString(), - osVersion: map['osVersion'].toString(), - clientType: map['clientType'].toString(), - clientCode: map['clientCode'].toString(), - clientName: map['clientName'].toString(), - clientVersion: map['clientVersion'].toString(), - clientEngine: map['clientEngine'].toString(), - clientEngineVersion: map['clientEngineVersion'].toString(), - deviceName: map['deviceName'].toString(), - deviceBrand: map['deviceBrand'].toString(), - deviceModel: map['deviceModel'].toString(), - countryCode: map['countryCode'].toString(), - countryName: map['countryName'].toString(), - ); - } - - @override - Map toMap() { - return { - "event": event, - "userId": userId, - "userEmail": userEmail, - "userName": userName, - "mode": mode, - "userType": userType, - "ip": ip, - "time": time, - "osCode": osCode, - "osName": osName, - "osVersion": osVersion, - "clientType": clientType, - "clientCode": clientCode, - "clientName": clientName, - "clientVersion": clientVersion, - "clientEngine": clientEngine, - "clientEngineVersion": clientEngineVersion, - "deviceName": deviceName, - "deviceBrand": deviceBrand, - "deviceModel": deviceModel, - "countryCode": countryCode, - "countryName": countryName, - }; - } -} diff --git a/lib/src/models/log_list.dart b/lib/src/models/log_list.dart deleted file mode 100644 index 07828c75..00000000 --- a/lib/src/models/log_list.dart +++ /dev/null @@ -1,33 +0,0 @@ -part of '../../models.dart'; - -/// Logs List -class LogList implements Model { - /// Total number of logs that matched your query. - final int total; - - /// List of logs. - final List logs; - - LogList({ - required this.total, - required this.logs, - }); - factory LogList.fromMap( - Map map, - ) { - return LogList( - total: map['total'], - logs: List.from( - map['logs'].map((p) => Log.fromMap(p)), - ), - ); - } - - @override - Map toMap() { - return { - "total": total, - "logs": logs.map((p) => p.toMap()).toList(), - }; - } -} diff --git a/lib/src/models/user.dart b/lib/src/models/user.dart index 8650dfd5..7d58b908 100644 --- a/lib/src/models/user.dart +++ b/lib/src/models/user.dart @@ -59,6 +59,9 @@ class User implements Model { /// Whether the user email is in its canonical form. final bool? emailIsCanonical; + /// Whether the password was found in a known data breach the last time it was checked. Null when the password has never been checked. + final bool? passwordPwned; + /// Phone verification status. final bool phoneVerification; @@ -100,6 +103,7 @@ class User implements Model { this.emailIsDisposable, this.emailIsCorporate, this.emailIsCanonical, + this.passwordPwned, required this.phoneVerification, required this.mfa, required this.prefs, @@ -131,6 +135,7 @@ class User implements Model { emailIsDisposable: map['emailIsDisposable'], emailIsCorporate: map['emailIsCorporate'], emailIsCanonical: map['emailIsCanonical'], + passwordPwned: map['passwordPwned'], phoneVerification: map['phoneVerification'], mfa: map['mfa'], prefs: Preferences.fromMap( @@ -167,6 +172,7 @@ class User implements Model { "emailIsDisposable": emailIsDisposable, "emailIsCorporate": emailIsCorporate, "emailIsCanonical": emailIsCanonical, + "passwordPwned": passwordPwned, "phoneVerification": phoneVerification, "mfa": mfa, "prefs": prefs.toMap(), diff --git a/pubspec.yaml b/pubspec.yaml index a08b4cdb..b04bee5a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: appwrite -version: 26.2.0 +version: 27.0.0 description: Appwrite is an open-source self-hosted backend server that abstracts and simplifies complex and repetitive development tasks behind a very simple REST API homepage: https://appwrite.io repository: https://github.com/appwrite/sdk-for-flutter diff --git a/test/services/account_test.dart b/test/services/account_test.dart index 00c1e68e..ef1bc31b 100644 --- a/test/services/account_test.dart +++ b/test/services/account_test.dart @@ -303,20 +303,6 @@ void main() { expect(response, isA()); }); - test('test method listLogs()', () async { - final Map data = { - 'total': 5, - 'logs': [], - }; - - when( - client.call(HttpMethod.get), - ).thenAnswer((_) async => Response(data: data)); - - final response = await account.listLogs(); - expect(response, isA()); - }); - test('test method updateMFA()', () async { final Map data = { '\$id': "5e5ea5c16897e", @@ -878,6 +864,48 @@ void main() { expect(response, isA()); }); + test('test method createRecoveryOTP()', () async { + final Map data = { + '\$id': "bb8ea5c16897e", + '\$createdAt': "2020-10-15T06:38:00.000+00:00", + 'userId': "5e5ea5c168bb8", + 'secret': "", + 'expire': "2020-10-15T06:38:00.000+00:00", + 'phrase': "Golden Fox", + }; + + when( + client.call(HttpMethod.post), + ).thenAnswer((_) async => Response(data: data)); + + final response = await account.createRecoveryOTP( + email: "email@example.com", + ); + expect(response, isA()); + }); + + test('test method updateRecoveryOTP()', () async { + final Map data = { + '\$id': "bb8ea5c16897e", + '\$createdAt': "2020-10-15T06:38:00.000+00:00", + 'userId': "5e5ea5c168bb8", + 'secret': "", + 'expire': "2020-10-15T06:38:00.000+00:00", + 'phrase': "Golden Fox", + }; + + when( + client.call(HttpMethod.put), + ).thenAnswer((_) async => Response(data: data)); + + final response = await account.updateRecoveryOTP( + userId: "", + secret: "", + password: "password", + ); + expect(response, isA()); + }); + test('test method listSessions()', () async { final Map data = { 'total': 5, @@ -987,6 +1015,50 @@ void main() { expect(response, isA()); }); + test('test method createIdTokenSession()', () async { + final Map data = { + '\$id': "5e5ea5c16897e", + '\$createdAt': "2020-10-15T06:38:00.000+00:00", + '\$updatedAt': "2020-10-15T06:38:00.000+00:00", + 'userId': "5e5bb8c16897e", + 'expire': "2020-10-15T06:38:00.000+00:00", + 'provider': "email", + 'providerUid': "user@example.com", + 'providerAccessToken': "MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3", + 'providerAccessTokenExpiry': "2020-10-15T06:38:00.000+00:00", + 'providerRefreshToken': "MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3", + 'ip': "127.0.0.1", + 'osCode': "Mac", + 'osName': "Mac", + 'osVersion': "Mac", + 'clientType': "browser", + 'clientCode': "CM", + 'clientName': "Chrome Mobile iOS", + 'clientVersion': "84.0", + 'clientEngine': "WebKit", + 'clientEngineVersion': "605.1.15", + 'deviceName': "smartphone", + 'deviceBrand': "Google", + 'deviceModel': "Nexus 5", + 'countryCode': "US", + 'countryName': "United States", + 'current': true, + 'factors': [], + 'secret': "5e5bb8c16897e", + 'mfaUpdatedAt': "2020-10-15T06:38:00.000+00:00", + }; + + when( + client.call(HttpMethod.post), + ).thenAnswer((_) async => Response(data: data)); + + final response = await account.createIdTokenSession( + provider: enums.IdTokenProvider.apple, + idToken: "", + ); + expect(response, isA()); + }); + test('test method updateMagicURLSession()', () async { final Map data = { '\$id': "5e5ea5c16897e", @@ -1470,6 +1542,45 @@ void main() { expect(response, isA()); }); + test('test method createEmailVerificationOTP()', () async { + final Map data = { + '\$id': "bb8ea5c16897e", + '\$createdAt': "2020-10-15T06:38:00.000+00:00", + 'userId': "5e5ea5c168bb8", + 'secret': "", + 'expire': "2020-10-15T06:38:00.000+00:00", + 'phrase': "Golden Fox", + }; + + when( + client.call(HttpMethod.post), + ).thenAnswer((_) async => Response(data: data)); + + final response = await account.createEmailVerificationOTP(); + expect(response, isA()); + }); + + test('test method updateEmailVerificationOTP()', () async { + final Map data = { + '\$id': "bb8ea5c16897e", + '\$createdAt': "2020-10-15T06:38:00.000+00:00", + 'userId': "5e5ea5c168bb8", + 'secret': "", + 'expire': "2020-10-15T06:38:00.000+00:00", + 'phrase': "Golden Fox", + }; + + when( + client.call(HttpMethod.put), + ).thenAnswer((_) async => Response(data: data)); + + final response = await account.updateEmailVerificationOTP( + userId: "", + secret: "", + ); + expect(response, isA()); + }); + test('test method createPhoneVerification()', () async { final Map data = { '\$id': "bb8ea5c16897e", diff --git a/test/services/functions_test.dart b/test/services/functions_test.dart index aae489d9..75d34f13 100644 --- a/test/services/functions_test.dart +++ b/test/services/functions_test.dart @@ -100,7 +100,7 @@ void main() { 'responseHeaders': [], 'logs': "", 'errors': "", - 'duration': 0.4, + 'duration': 1.23, }; when( @@ -132,7 +132,7 @@ void main() { 'responseHeaders': [], 'logs': "", 'errors': "", - 'duration': 0.4, + 'duration': 1.23, }; when( diff --git a/test/src/models/execution_test.dart b/test/src/models/execution_test.dart index 15955b9a..2ead39c0 100644 --- a/test/src/models/execution_test.dart +++ b/test/src/models/execution_test.dart @@ -23,7 +23,7 @@ void main() { responseHeaders: [], logs: "", errors: "", - duration: 0.4, + duration: 1.23, ); final map = model.toMap(); @@ -46,7 +46,7 @@ void main() { expect(result.responseHeaders, []); expect(result.logs, ""); expect(result.errors, ""); - expect(result.duration, 0.4); + expect(result.duration, 1.23); }); }); } diff --git a/test/src/models/identity_test.dart b/test/src/models/identity_test.dart index a88b2dbe..5d8d275c 100644 --- a/test/src/models/identity_test.dart +++ b/test/src/models/identity_test.dart @@ -15,6 +15,8 @@ void main() { providerAccessToken: "MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3", providerAccessTokenExpiry: "2020-10-15T06:38:00.000+00:00", providerRefreshToken: "MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3", + providerIdToken: + "eyJhbGciOiJSUzI1NiIsImtpZCI6IjBhYzNmMWQwNWExYjhlN2YifQ.eyJzdWIiOiIxMTAxNjk0ODQ0NzQzODYyNzYzMzQifQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c", ); final map = model.toMap(); @@ -30,6 +32,10 @@ void main() { expect(result.providerAccessToken, "MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3"); expect(result.providerAccessTokenExpiry, "2020-10-15T06:38:00.000+00:00"); expect(result.providerRefreshToken, "MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3"); + expect( + result.providerIdToken, + "eyJhbGciOiJSUzI1NiIsImtpZCI6IjBhYzNmMWQwNWExYjhlN2YifQ.eyJzdWIiOiIxMTAxNjk0ODQ0NzQzODYyNzYzMzQifQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c", + ); }); }); } diff --git a/test/src/models/log_list_test.dart b/test/src/models/log_list_test.dart deleted file mode 100644 index b07ca8ee..00000000 --- a/test/src/models/log_list_test.dart +++ /dev/null @@ -1,19 +0,0 @@ -import 'package:appwrite/models.dart'; -import 'package:flutter_test/flutter_test.dart'; - -void main() { - group('LogList', () { - test('model', () { - final model = LogList( - total: 5, - logs: [], - ); - - final map = model.toMap(); - final result = LogList.fromMap(map); - - expect(result.total, 5); - expect(result.logs, []); - }); - }); -} diff --git a/test/src/models/log_test.dart b/test/src/models/log_test.dart deleted file mode 100644 index 3b4d95af..00000000 --- a/test/src/models/log_test.dart +++ /dev/null @@ -1,59 +0,0 @@ -import 'package:appwrite/models.dart'; -import 'package:flutter_test/flutter_test.dart'; - -void main() { - group('Log', () { - test('model', () { - final model = Log( - event: "account.sessions.create", - userId: "610fc2f985ee0", - userEmail: "john@appwrite.io", - userName: "John Doe", - mode: "admin", - userType: "user", - ip: "127.0.0.1", - time: "2020-10-15T06:38:00.000+00:00", - osCode: "Mac", - osName: "Mac", - osVersion: "Mac", - clientType: "browser", - clientCode: "CM", - clientName: "Chrome Mobile iOS", - clientVersion: "84.0", - clientEngine: "WebKit", - clientEngineVersion: "605.1.15", - deviceName: "smartphone", - deviceBrand: "Google", - deviceModel: "Nexus 5", - countryCode: "US", - countryName: "United States", - ); - - final map = model.toMap(); - final result = Log.fromMap(map); - - expect(result.event, "account.sessions.create"); - expect(result.userId, "610fc2f985ee0"); - expect(result.userEmail, "john@appwrite.io"); - expect(result.userName, "John Doe"); - expect(result.mode, "admin"); - expect(result.userType, "user"); - expect(result.ip, "127.0.0.1"); - expect(result.time, "2020-10-15T06:38:00.000+00:00"); - expect(result.osCode, "Mac"); - expect(result.osName, "Mac"); - expect(result.osVersion, "Mac"); - expect(result.clientType, "browser"); - expect(result.clientCode, "CM"); - expect(result.clientName, "Chrome Mobile iOS"); - expect(result.clientVersion, "84.0"); - expect(result.clientEngine, "WebKit"); - expect(result.clientEngineVersion, "605.1.15"); - expect(result.deviceName, "smartphone"); - expect(result.deviceBrand, "Google"); - expect(result.deviceModel, "Nexus 5"); - expect(result.countryCode, "US"); - expect(result.countryName, "United States"); - }); - }); -}