diff --git a/CHANGELOG.md b/CHANGELOG.md index 4d8f850..377ac69 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Change Log +## 16.0.1 + +* Add `setDevKey` method to Client service +* Add `upsertDocument` method to Databases service + ## 16.0.0 * Remove `Gif` from ImageFormat enum diff --git a/README.md b/README.md index 717cdab..b8d7069 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ Add this to your package's `pubspec.yaml` file: ```yml dependencies: - appwrite: ^16.0.0 + appwrite: ^16.1.0 ``` You can install packages from the command line: diff --git a/docs/examples/databases/upsert-document.md b/docs/examples/databases/upsert-document.md new file mode 100644 index 0000000..398a99c --- /dev/null +++ b/docs/examples/databases/upsert-document.md @@ -0,0 +1,15 @@ +import 'package:appwrite/appwrite.dart'; + +Client client = Client() + .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + .setProject(''); // Your project ID + +Databases databases = Databases(client); + +Document result = await databases.upsertDocument( + databaseId: '', + collectionId: '', + documentId: '', + data: {}, + permissions: ["read("any")"], // optional +); diff --git a/lib/query.dart b/lib/query.dart index 4962c9e..7d7d06f 100644 --- a/lib/query.dart +++ b/lib/query.dart @@ -82,19 +82,17 @@ class Query { static String contains(String attribute, dynamic value) => Query._('contains', attribute, value).toString(); - static String or(List queries) => - Query._( - 'or', - null, - queries.map((query) => jsonDecode(query)).toList(), - ).toString(); - - static String and(List queries) => - Query._( - 'and', - null, - queries.map((query) => jsonDecode(query)).toList(), - ).toString(); + static String or(List queries) => Query._( + 'or', + null, + queries.map((query) => jsonDecode(query)).toList(), + ).toString(); + + static String and(List queries) => Query._( + 'and', + null, + queries.map((query) => jsonDecode(query)).toList(), + ).toString(); /// Specify which attributes should be returned by the API call. static String select(List attributes) => diff --git a/lib/services/databases.dart b/lib/services/databases.dart index f276f50..c2ee2c5 100644 --- a/lib/services/databases.dart +++ b/lib/services/databases.dart @@ -94,6 +94,40 @@ class Databases extends Service { return models.Document.fromMap(res.data); } + /// Create or update a Document. Before using this route, you should create a + /// new collection resource using either a [server + /// integration](https://appwrite.io/docs/server/databases#databasesCreateCollection) + /// API or directly from your database console. + Future upsertDocument({ + required String databaseId, + required String collectionId, + required String documentId, + required Map data, + List? permissions, + }) async { + final String apiPath = + '/databases/{databaseId}/collections/{collectionId}/documents/{documentId}' + .replaceAll('{databaseId}', databaseId) + .replaceAll('{collectionId}', collectionId) + .replaceAll('{documentId}', documentId); + + final Map apiParams = { + 'data': data, + 'permissions': permissions, + }; + + final Map apiHeaders = {'content-type': 'application/json'}; + + final res = await client.call( + HttpMethod.put, + path: apiPath, + params: apiParams, + headers: apiHeaders, + ); + + return models.Document.fromMap(res.data); + } + /// Update a document by its unique ID. Using the patch method you can pass /// only specific fields that will get updated. Future updateDocument({ diff --git a/lib/src/client.dart b/lib/src/client.dart index 3af9d66..05fff19 100644 --- a/lib/src/client.dart +++ b/lib/src/client.dart @@ -73,6 +73,11 @@ abstract class Client { /// The user session to authenticate with. Client setSession(value); + /// Set DevKey. + /// + /// Your secret dev API key. + Client setDevKey(value); + /// Add headers that should be sent with all API calls. Client addHeader(String key, String value); diff --git a/lib/src/client_base.dart b/lib/src/client_base.dart index 731258d..a9434e2 100644 --- a/lib/src/client_base.dart +++ b/lib/src/client_base.dart @@ -17,6 +17,10 @@ abstract class ClientBase implements Client { @override ClientBase setSession(value); + /// Your secret dev API key + @override + ClientBase setDevKey(value); + @override ClientBase setSelfSigned({bool status = true}); diff --git a/lib/src/client_browser.dart b/lib/src/client_browser.dart index f1d51f9..2f4a1fc 100644 --- a/lib/src/client_browser.dart +++ b/lib/src/client_browser.dart @@ -40,7 +40,7 @@ class ClientBrowser extends ClientBase with ClientMixin { 'x-sdk-name': 'Flutter', 'x-sdk-platform': 'client', 'x-sdk-language': 'flutter', - 'x-sdk-version': '16.0.0', + 'x-sdk-version': '16.1.0', 'X-Appwrite-Response-Format': '1.7.0', }; @@ -87,6 +87,14 @@ 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; + } + @override ClientBrowser setSelfSigned({bool status = true}) { return this; diff --git a/lib/src/client_io.dart b/lib/src/client_io.dart index 440dbd5..cd18163 100644 --- a/lib/src/client_io.dart +++ b/lib/src/client_io.dart @@ -46,10 +46,9 @@ class ClientIO extends ClientBase with ClientMixin { String endPoint = 'https://cloud.appwrite.io/v1', this.selfSigned = false, }) : _endPoint = endPoint { - _nativeClient = - HttpClient() - ..badCertificateCallback = - ((X509Certificate cert, String host, int port) => selfSigned); + _nativeClient = HttpClient() + ..badCertificateCallback = + ((X509Certificate cert, String host, int port) => selfSigned); _httpClient = IOClient(_nativeClient); _endPointRealtime = endPoint .replaceFirst('https://', 'wss://') @@ -59,7 +58,7 @@ class ClientIO extends ClientBase with ClientMixin { 'x-sdk-name': 'Flutter', 'x-sdk-platform': 'client', 'x-sdk-language': 'flutter', - 'x-sdk-version': '16.0.0', + 'x-sdk-version': '16.1.0', 'X-Appwrite-Response-Format': '1.7.0', }; @@ -114,6 +113,14 @@ 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; + } + @override ClientIO setSelfSigned({bool status = true}) { selfSigned = status; @@ -349,10 +356,9 @@ class ClientIO extends ClientBase with ClientMixin { Future webAuth(Uri url, {String? callbackUrlScheme}) { return FlutterWebAuth2.authenticate( url: url.toString(), - callbackUrlScheme: - callbackUrlScheme != null && _customSchemeAllowed - ? callbackUrlScheme - : "appwrite-callback-" + config['project']!, + callbackUrlScheme: callbackUrlScheme != null && _customSchemeAllowed + ? callbackUrlScheme + : "appwrite-callback-" + config['project']!, options: const FlutterWebAuth2Options(intentFlags: ephemeralIntentFlags), ).then((value) async { Uri url = Uri.parse(value); diff --git a/lib/src/client_mixin.dart b/lib/src/client_mixin.dart index 310bc3c..06c9ebe 100644 --- a/lib/src/client_mixin.dart +++ b/lib/src/client_mixin.dart @@ -124,10 +124,9 @@ mixin ClientMixin { '', streamedResponse.statusCode, headers: streamedResponse.headers.map( - (k, v) => - k.toLowerCase() == 'content-type' - ? MapEntry(k, 'text/plain') - : MapEntry(k, v), + (k, v) => k.toLowerCase() == 'content-type' + ? MapEntry(k, 'text/plain') + : MapEntry(k, v), ), request: streamedResponse.request, isRedirect: streamedResponse.isRedirect, diff --git a/lib/src/realtime_io.dart b/lib/src/realtime_io.dart index bafa4f1..e54546b 100644 --- a/lib/src/realtime_io.dart +++ b/lib/src/realtime_io.dart @@ -59,14 +59,11 @@ class RealtimeIO extends RealtimeBase with RealtimeMixin { var r = Random(); var key = base64.encode(List.generate(16, (_) => r.nextInt(255))); var client = HttpClient(context: SecurityContext()); - client.badCertificateCallback = ( - X509Certificate cert, - String host, - int port, - ) { - debugPrint('AppwriteRealtime: Allow self-signed certificate'); - return true; - }; + client.badCertificateCallback = + (X509Certificate cert, String host, int port) { + debugPrint('AppwriteRealtime: Allow self-signed certificate'); + return true; + }; uri = Uri( scheme: uri.scheme == 'wss' ? 'https' : 'http', diff --git a/lib/src/realtime_stub.dart b/lib/src/realtime_stub.dart index 631afe3..ce0b7e9 100644 --- a/lib/src/realtime_stub.dart +++ b/lib/src/realtime_stub.dart @@ -2,7 +2,6 @@ import 'realtime_base.dart'; import 'client.dart'; /// Implemented in `realtime_browser.dart` and `realtime_io.dart`. -RealtimeBase createRealtime(Client client) => - throw UnsupportedError( - 'Cannot create a client without dart:html or dart:io.', - ); +RealtimeBase createRealtime(Client client) => throw UnsupportedError( + 'Cannot create a client without dart:html or dart:io.', +); diff --git a/pubspec.yaml b/pubspec.yaml index a48a262..5ccf2f9 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: appwrite -version: 16.0.0 +version: 16.1.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 diff --git a/test/services/databases_test.dart b/test/services/databases_test.dart index 1164948..794ac1b 100644 --- a/test/services/databases_test.dart +++ b/test/services/databases_test.dart @@ -122,6 +122,31 @@ void main() { }); + test('test method upsertDocument()', () async { + final Map data = { + '\$id': '5e5ea5c16897e', + '\$collectionId': '5e5ea5c15117e', + '\$databaseId': '5e5ea5c15117e', + '\$createdAt': '2020-10-15T06:38:00.000+00:00', + '\$updatedAt': '2020-10-15T06:38:00.000+00:00', + '\$permissions': [],}; + + + when(client.call( + HttpMethod.put, + )).thenAnswer((_) async => Response(data: data)); + + + final response = await databases.upsertDocument( + databaseId: '', + collectionId: '', + documentId: '', + data: {}, + ); + expect(response, isA()); + + }); + test('test method updateDocument()', () async { final Map data = { '\$id': '5e5ea5c16897e',