From 35a918f450ff4be17e11438cffb1ce24d36a9a8e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 24 Nov 2025 12:10:04 +0000 Subject: [PATCH 1/9] Initial plan From cbab0e46af90485b983ccc52902e4306f0970305 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 24 Nov 2025 12:13:40 +0000 Subject: [PATCH 2/9] Initial plan for fixing content type issue Co-authored-by: mtrezza <5673677+mtrezza@users.noreply.github.com> --- .../src/network/parse_query_test.mocks.dart | 250 ++++++++++++++++++ .../parse_object/parse_object_test.mocks.dart | 250 ++++++++++++++++++ 2 files changed, 500 insertions(+) create mode 100644 packages/dart/test/src/network/parse_query_test.mocks.dart create mode 100644 packages/dart/test/src/objects/parse_object/parse_object_test.mocks.dart diff --git a/packages/dart/test/src/network/parse_query_test.mocks.dart b/packages/dart/test/src/network/parse_query_test.mocks.dart new file mode 100644 index 00000000..87bb7d7f --- /dev/null +++ b/packages/dart/test/src/network/parse_query_test.mocks.dart @@ -0,0 +1,250 @@ +// Mocks generated by Mockito 5.4.6 from annotations +// in parse_server_sdk/test/src/network/parse_query_test.dart. +// Do not manually edit this file. + +// ignore_for_file: no_leading_underscores_for_library_prefixes +import 'dart:async' as _i3; + +import 'package:mockito/mockito.dart' as _i1; +import 'package:parse_server_sdk/parse_server_sdk.dart' as _i2; + +// ignore_for_file: type=lint +// ignore_for_file: avoid_redundant_argument_values +// ignore_for_file: avoid_setters_without_getters +// ignore_for_file: comment_references +// ignore_for_file: deprecated_member_use +// ignore_for_file: deprecated_member_use_from_same_package +// ignore_for_file: implementation_imports +// ignore_for_file: invalid_use_of_visible_for_testing_member +// ignore_for_file: must_be_immutable +// ignore_for_file: prefer_const_constructors +// ignore_for_file: unnecessary_parenthesis +// ignore_for_file: camel_case_types +// ignore_for_file: subtype_of_sealed_class +// ignore_for_file: invalid_use_of_internal_member + +class _FakeParseCoreData_0 extends _i1.SmartFake implements _i2.ParseCoreData { + _FakeParseCoreData_0( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} + +class _FakeParseNetworkResponse_1 extends _i1.SmartFake + implements _i2.ParseNetworkResponse { + _FakeParseNetworkResponse_1( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} + +class _FakeParseNetworkByteResponse_2 extends _i1.SmartFake + implements _i2.ParseNetworkByteResponse { + _FakeParseNetworkByteResponse_2( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} + +/// A class which mocks [ParseClient]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockParseClient extends _i1.Mock implements _i2.ParseClient { + MockParseClient() { + _i1.throwOnMissingStub(this); + } + + @override + _i2.ParseCoreData get data => (super.noSuchMethod( + Invocation.getter(#data), + returnValue: _FakeParseCoreData_0( + this, + Invocation.getter(#data), + ), + ) as _i2.ParseCoreData); + + @override + _i3.Future<_i2.ParseNetworkResponse> get( + String? path, { + _i2.ParseNetworkOptions? options, + _i2.ProgressCallback? onReceiveProgress, + }) => + (super.noSuchMethod( + Invocation.method( + #get, + [path], + { + #options: options, + #onReceiveProgress: onReceiveProgress, + }, + ), + returnValue: _i3.Future<_i2.ParseNetworkResponse>.value( + _FakeParseNetworkResponse_1( + this, + Invocation.method( + #get, + [path], + { + #options: options, + #onReceiveProgress: onReceiveProgress, + }, + ), + )), + ) as _i3.Future<_i2.ParseNetworkResponse>); + + @override + _i3.Future<_i2.ParseNetworkResponse> put( + String? path, { + String? data, + _i2.ParseNetworkOptions? options, + }) => + (super.noSuchMethod( + Invocation.method( + #put, + [path], + { + #data: data, + #options: options, + }, + ), + returnValue: _i3.Future<_i2.ParseNetworkResponse>.value( + _FakeParseNetworkResponse_1( + this, + Invocation.method( + #put, + [path], + { + #data: data, + #options: options, + }, + ), + )), + ) as _i3.Future<_i2.ParseNetworkResponse>); + + @override + _i3.Future<_i2.ParseNetworkResponse> post( + String? path, { + String? data, + _i2.ParseNetworkOptions? options, + }) => + (super.noSuchMethod( + Invocation.method( + #post, + [path], + { + #data: data, + #options: options, + }, + ), + returnValue: _i3.Future<_i2.ParseNetworkResponse>.value( + _FakeParseNetworkResponse_1( + this, + Invocation.method( + #post, + [path], + { + #data: data, + #options: options, + }, + ), + )), + ) as _i3.Future<_i2.ParseNetworkResponse>); + + @override + _i3.Future<_i2.ParseNetworkResponse> postBytes( + String? path, { + _i3.Stream>? data, + _i2.ParseNetworkOptions? options, + _i2.ProgressCallback? onSendProgress, + dynamic cancelToken, + }) => + (super.noSuchMethod( + Invocation.method( + #postBytes, + [path], + { + #data: data, + #options: options, + #onSendProgress: onSendProgress, + #cancelToken: cancelToken, + }, + ), + returnValue: _i3.Future<_i2.ParseNetworkResponse>.value( + _FakeParseNetworkResponse_1( + this, + Invocation.method( + #postBytes, + [path], + { + #data: data, + #options: options, + #onSendProgress: onSendProgress, + #cancelToken: cancelToken, + }, + ), + )), + ) as _i3.Future<_i2.ParseNetworkResponse>); + + @override + _i3.Future<_i2.ParseNetworkResponse> delete( + String? path, { + _i2.ParseNetworkOptions? options, + }) => + (super.noSuchMethod( + Invocation.method( + #delete, + [path], + {#options: options}, + ), + returnValue: _i3.Future<_i2.ParseNetworkResponse>.value( + _FakeParseNetworkResponse_1( + this, + Invocation.method( + #delete, + [path], + {#options: options}, + ), + )), + ) as _i3.Future<_i2.ParseNetworkResponse>); + + @override + _i3.Future<_i2.ParseNetworkByteResponse> getBytes( + String? path, { + _i2.ParseNetworkOptions? options, + _i2.ProgressCallback? onReceiveProgress, + dynamic cancelToken, + }) => + (super.noSuchMethod( + Invocation.method( + #getBytes, + [path], + { + #options: options, + #onReceiveProgress: onReceiveProgress, + #cancelToken: cancelToken, + }, + ), + returnValue: _i3.Future<_i2.ParseNetworkByteResponse>.value( + _FakeParseNetworkByteResponse_2( + this, + Invocation.method( + #getBytes, + [path], + { + #options: options, + #onReceiveProgress: onReceiveProgress, + #cancelToken: cancelToken, + }, + ), + )), + ) as _i3.Future<_i2.ParseNetworkByteResponse>); +} diff --git a/packages/dart/test/src/objects/parse_object/parse_object_test.mocks.dart b/packages/dart/test/src/objects/parse_object/parse_object_test.mocks.dart new file mode 100644 index 00000000..53fd24c4 --- /dev/null +++ b/packages/dart/test/src/objects/parse_object/parse_object_test.mocks.dart @@ -0,0 +1,250 @@ +// Mocks generated by Mockito 5.4.6 from annotations +// in parse_server_sdk/test/src/objects/parse_object/parse_object_test.dart. +// Do not manually edit this file. + +// ignore_for_file: no_leading_underscores_for_library_prefixes +import 'dart:async' as _i3; + +import 'package:mockito/mockito.dart' as _i1; +import 'package:parse_server_sdk/parse_server_sdk.dart' as _i2; + +// ignore_for_file: type=lint +// ignore_for_file: avoid_redundant_argument_values +// ignore_for_file: avoid_setters_without_getters +// ignore_for_file: comment_references +// ignore_for_file: deprecated_member_use +// ignore_for_file: deprecated_member_use_from_same_package +// ignore_for_file: implementation_imports +// ignore_for_file: invalid_use_of_visible_for_testing_member +// ignore_for_file: must_be_immutable +// ignore_for_file: prefer_const_constructors +// ignore_for_file: unnecessary_parenthesis +// ignore_for_file: camel_case_types +// ignore_for_file: subtype_of_sealed_class +// ignore_for_file: invalid_use_of_internal_member + +class _FakeParseCoreData_0 extends _i1.SmartFake implements _i2.ParseCoreData { + _FakeParseCoreData_0( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} + +class _FakeParseNetworkResponse_1 extends _i1.SmartFake + implements _i2.ParseNetworkResponse { + _FakeParseNetworkResponse_1( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} + +class _FakeParseNetworkByteResponse_2 extends _i1.SmartFake + implements _i2.ParseNetworkByteResponse { + _FakeParseNetworkByteResponse_2( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} + +/// A class which mocks [ParseClient]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockParseClient extends _i1.Mock implements _i2.ParseClient { + MockParseClient() { + _i1.throwOnMissingStub(this); + } + + @override + _i2.ParseCoreData get data => (super.noSuchMethod( + Invocation.getter(#data), + returnValue: _FakeParseCoreData_0( + this, + Invocation.getter(#data), + ), + ) as _i2.ParseCoreData); + + @override + _i3.Future<_i2.ParseNetworkResponse> get( + String? path, { + _i2.ParseNetworkOptions? options, + _i2.ProgressCallback? onReceiveProgress, + }) => + (super.noSuchMethod( + Invocation.method( + #get, + [path], + { + #options: options, + #onReceiveProgress: onReceiveProgress, + }, + ), + returnValue: _i3.Future<_i2.ParseNetworkResponse>.value( + _FakeParseNetworkResponse_1( + this, + Invocation.method( + #get, + [path], + { + #options: options, + #onReceiveProgress: onReceiveProgress, + }, + ), + )), + ) as _i3.Future<_i2.ParseNetworkResponse>); + + @override + _i3.Future<_i2.ParseNetworkResponse> put( + String? path, { + String? data, + _i2.ParseNetworkOptions? options, + }) => + (super.noSuchMethod( + Invocation.method( + #put, + [path], + { + #data: data, + #options: options, + }, + ), + returnValue: _i3.Future<_i2.ParseNetworkResponse>.value( + _FakeParseNetworkResponse_1( + this, + Invocation.method( + #put, + [path], + { + #data: data, + #options: options, + }, + ), + )), + ) as _i3.Future<_i2.ParseNetworkResponse>); + + @override + _i3.Future<_i2.ParseNetworkResponse> post( + String? path, { + String? data, + _i2.ParseNetworkOptions? options, + }) => + (super.noSuchMethod( + Invocation.method( + #post, + [path], + { + #data: data, + #options: options, + }, + ), + returnValue: _i3.Future<_i2.ParseNetworkResponse>.value( + _FakeParseNetworkResponse_1( + this, + Invocation.method( + #post, + [path], + { + #data: data, + #options: options, + }, + ), + )), + ) as _i3.Future<_i2.ParseNetworkResponse>); + + @override + _i3.Future<_i2.ParseNetworkResponse> postBytes( + String? path, { + _i3.Stream>? data, + _i2.ParseNetworkOptions? options, + _i2.ProgressCallback? onSendProgress, + dynamic cancelToken, + }) => + (super.noSuchMethod( + Invocation.method( + #postBytes, + [path], + { + #data: data, + #options: options, + #onSendProgress: onSendProgress, + #cancelToken: cancelToken, + }, + ), + returnValue: _i3.Future<_i2.ParseNetworkResponse>.value( + _FakeParseNetworkResponse_1( + this, + Invocation.method( + #postBytes, + [path], + { + #data: data, + #options: options, + #onSendProgress: onSendProgress, + #cancelToken: cancelToken, + }, + ), + )), + ) as _i3.Future<_i2.ParseNetworkResponse>); + + @override + _i3.Future<_i2.ParseNetworkResponse> delete( + String? path, { + _i2.ParseNetworkOptions? options, + }) => + (super.noSuchMethod( + Invocation.method( + #delete, + [path], + {#options: options}, + ), + returnValue: _i3.Future<_i2.ParseNetworkResponse>.value( + _FakeParseNetworkResponse_1( + this, + Invocation.method( + #delete, + [path], + {#options: options}, + ), + )), + ) as _i3.Future<_i2.ParseNetworkResponse>); + + @override + _i3.Future<_i2.ParseNetworkByteResponse> getBytes( + String? path, { + _i2.ParseNetworkOptions? options, + _i2.ProgressCallback? onReceiveProgress, + dynamic cancelToken, + }) => + (super.noSuchMethod( + Invocation.method( + #getBytes, + [path], + { + #options: options, + #onReceiveProgress: onReceiveProgress, + #cancelToken: cancelToken, + }, + ), + returnValue: _i3.Future<_i2.ParseNetworkByteResponse>.value( + _FakeParseNetworkByteResponse_2( + this, + Invocation.method( + #getBytes, + [path], + { + #options: options, + #onReceiveProgress: onReceiveProgress, + #cancelToken: cancelToken, + }, + ), + )), + ) as _i3.Future<_i2.ParseNetworkByteResponse>); +} From a9f3522a00cb4f3a2ed3fe1f55df012db4e7e9fc Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 24 Nov 2025 12:17:16 +0000 Subject: [PATCH 3/9] Fix: Don't send content-type header when file has extension Modified ParseXFile and ParseFile to only send content-type: application/octet-stream when the filename has no extension. When a file extension exists, the server will infer the correct MIME type from the extension, fixing the issue where images were incorrectly saved as application/octet-stream. Co-authored-by: mtrezza <5673677+mtrezza@users.noreply.github.com> --- packages/dart/lib/src/objects/parse_file.dart | 11 ++++++-- .../dart/lib/src/objects/parse_x_file.dart | 28 +++++++++---------- 2 files changed, 22 insertions(+), 17 deletions(-) diff --git a/packages/dart/lib/src/objects/parse_file.dart b/packages/dart/lib/src/objects/parse_file.dart index 31328110..b6000b75 100644 --- a/packages/dart/lib/src/objects/parse_file.dart +++ b/packages/dart/lib/src/objects/parse_file.dart @@ -77,11 +77,18 @@ class ParseFile extends ParseFileBase { _cancelToken = CancelToken(); final Map headers = { - HttpHeaders.contentTypeHeader: - lookupMimeType(file!.path) ?? 'application/octet-stream', HttpHeaders.contentLengthHeader: '${file!.lengthSync()}', }; + // Only set content-type if the file has no extension + // If extension exists, let the server infer the MIME type from the filename + final bool hasExtension = path.extension(name).isNotEmpty; + + if (!hasExtension) { + // No extension, set content-type to application/octet-stream as fallback + headers[HttpHeaders.contentTypeHeader] = 'application/octet-stream'; + } + try { final String uri = ParseCoreData().serverUrl + _path; final ParseNetworkResponse response = await _client.postBytes( diff --git a/packages/dart/lib/src/objects/parse_x_file.dart b/packages/dart/lib/src/objects/parse_x_file.dart index 8dddc0c5..6ac615f0 100644 --- a/packages/dart/lib/src/objects/parse_x_file.dart +++ b/packages/dart/lib/src/objects/parse_x_file.dart @@ -92,21 +92,19 @@ class ParseXFile extends ParseFileBase { progressCallback ??= _progressCallback; _cancelToken = CancelToken(); - Map headers; - if (parseIsWeb) { - headers = { - HttpHeaders.contentTypeHeader: file?.mimeType ?? - lookupMimeType(url ?? file?.name ?? name, - headerBytes: await file?.readAsBytes()) ?? - 'application/octet-stream', - }; - } else { - headers = { - HttpHeaders.contentTypeHeader: file?.mimeType ?? - lookupMimeType(file!.path) ?? - 'application/octet-stream', - HttpHeaders.contentLengthHeader: '${await file!.length()}', - }; + Map headers = {}; + + // Only set content-type if the file has no extension + // If extension exists, let the server infer the MIME type from the filename + final bool hasExtension = path.extension(name).isNotEmpty; + + if (!hasExtension) { + // No extension, set content-type to application/octet-stream as fallback + headers[HttpHeaders.contentTypeHeader] = 'application/octet-stream'; + } + + if (!parseIsWeb) { + headers[HttpHeaders.contentLengthHeader] = '${await file!.length()}'; } try { From 67b48bda73e0902947a43408442ba1fc66d22a0d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 24 Nov 2025 12:18:59 +0000 Subject: [PATCH 4/9] Add tests for file extension detection Added tests to verify that files with extensions and without extensions are correctly identified, which is crucial for the content-type header logic. Co-authored-by: mtrezza <5673677+mtrezza@users.noreply.github.com> --- .../test/src/objects/parse_file_test.dart | 40 +++++++++++++++++++ .../test/src/objects/parse_x_file_test.dart | 40 +++++++++++++++++++ 2 files changed, 80 insertions(+) diff --git a/packages/dart/test/src/objects/parse_file_test.dart b/packages/dart/test/src/objects/parse_file_test.dart index 8a241922..1fcd6d9f 100644 --- a/packages/dart/test/src/objects/parse_file_test.dart +++ b/packages/dart/test/src/objects/parse_file_test.dart @@ -1,6 +1,7 @@ import 'dart:io'; import 'package:parse_server_sdk/parse_server_sdk.dart'; import 'package:test/test.dart'; +import 'package:path/path.dart' as path; import '../../test_utils.dart'; @@ -15,5 +16,44 @@ void main() { final parseFile = ParseFile(file, name: 'bb.jpg'); expect(parseFile.name, 'bb.jpg'); }); + + test('should detect file extension correctly for files with extensions', + () { + // Test various file extensions + final testCases = [ + 'image.jpg', + 'photo.png', + 'document.pdf', + 'myfile.txt', + 'archive.zip', + ]; + + for (final filename in testCases) { + File file = File('/path/to/$filename'); + final parseFile = ParseFile(file, name: filename); + // Verify that the extension is detected + expect(path.extension(parseFile.name).isNotEmpty, true, + reason: '$filename should have an extension'); + } + }); + + test( + 'should detect missing extension correctly for files without extensions', + () { + // Test files without extensions + final testCases = [ + 'image', + 'file', + 'document', + ]; + + for (final filename in testCases) { + File file = File('/path/to/$filename'); + final parseFile = ParseFile(file, name: filename); + // Verify that no extension is detected + expect(path.extension(parseFile.name).isEmpty, true, + reason: '$filename should not have an extension'); + } + }); }); } diff --git a/packages/dart/test/src/objects/parse_x_file_test.dart b/packages/dart/test/src/objects/parse_x_file_test.dart index de446c2b..c94d225f 100644 --- a/packages/dart/test/src/objects/parse_x_file_test.dart +++ b/packages/dart/test/src/objects/parse_x_file_test.dart @@ -1,6 +1,7 @@ import 'package:cross_file/cross_file.dart'; import 'package:parse_server_sdk/parse_server_sdk.dart'; import 'package:test/test.dart'; +import 'package:path/path.dart' as path; import '../../test_utils.dart'; @@ -15,5 +16,44 @@ void main() { final parseFile = ParseXFile(file, name: 'bb.jpg'); expect(parseFile.name, 'bb.jpg'); }); + + test('should detect file extension correctly for files with extensions', + () { + // Test various file extensions + final testCases = [ + 'image.jpg', + 'photo.png', + 'document.pdf', + 'myfile.txt', + 'archive.zip', + ]; + + for (final filename in testCases) { + XFile file = XFile('/path/to/$filename'); + final parseFile = ParseXFile(file, name: filename); + // Verify that the extension is detected + expect(path.extension(parseFile.name).isNotEmpty, true, + reason: '$filename should have an extension'); + } + }); + + test( + 'should detect missing extension correctly for files without extensions', + () { + // Test files without extensions + final testCases = [ + 'image', + 'file', + 'document', + ]; + + for (final filename in testCases) { + XFile file = XFile('/path/to/$filename'); + final parseFile = ParseXFile(file, name: filename); + // Verify that no extension is detected + expect(path.extension(parseFile.name).isEmpty, true, + reason: '$filename should not have an extension'); + } + }); }); } From ae68a7a382fe401d579feaf4b6edd2d582f60b19 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 24 Nov 2025 12:45:17 +0000 Subject: [PATCH 5/9] Remove default content-type, only set if explicitly provided Changed ParseXFile and ParseFile to not set any default content-type header. Content-type is now only set if explicitly provided (e.g., via file.mimeType in XFile). This allows Parse Server to always infer the MIME type from the file extension, addressing feedback from @mtrezza. Co-authored-by: mtrezza <5673677+mtrezza@users.noreply.github.com> --- packages/dart/lib/src/objects/parse_file.dart | 46 ++++++++-------- .../dart/lib/src/objects/parse_x_file.dart | 53 ++++++++++--------- .../test/src/objects/parse_file_test.dart | 24 +++------ .../test/src/objects/parse_x_file_test.dart | 24 +++------ 4 files changed, 64 insertions(+), 83 deletions(-) diff --git a/packages/dart/lib/src/objects/parse_file.dart b/packages/dart/lib/src/objects/parse_file.dart index b6000b75..fb3c73f0 100644 --- a/packages/dart/lib/src/objects/parse_file.dart +++ b/packages/dart/lib/src/objects/parse_file.dart @@ -4,15 +4,14 @@ class ParseFile extends ParseFileBase { /// Creates a new file /// /// {https://docs.parseplatform.org/rest/guide/#files/} - ParseFile(this.file, - {String? name, - super.url, - super.debug, - super.client, - super.autoSendSessionId}) - : super( - name: name ?? path.basename(file?.path ?? ''), - ); + ParseFile( + this.file, { + String? name, + super.url, + super.debug, + super.client, + super.autoSendSessionId, + }) : super(name: name ?? path.basename(file?.path ?? '')); File? file; CancelToken? _cancelToken; @@ -62,14 +61,15 @@ class ParseFile extends ParseFileBase { //Creates a Fake Response to return the correct result final Map response = { 'url': url!, - 'name': name + 'name': name, }; return handleResponse( - this, - ParseNetworkResponse(data: json.encode(response), statusCode: 201), - ParseApiRQ.upload, - _debug, - parseClassName); + this, + ParseNetworkResponse(data: json.encode(response), statusCode: 201), + ParseApiRQ.upload, + _debug, + parseClassName, + ); } progressCallback ??= _progressCallback; @@ -80,14 +80,7 @@ class ParseFile extends ParseFileBase { HttpHeaders.contentLengthHeader: '${file!.lengthSync()}', }; - // Only set content-type if the file has no extension - // If extension exists, let the server infer the MIME type from the filename - final bool hasExtension = path.extension(name).isNotEmpty; - - if (!hasExtension) { - // No extension, set content-type to application/octet-stream as fallback - headers[HttpHeaders.contentTypeHeader] = 'application/octet-stream'; - } + // Do not set content-type - let the server infer it from the filename try { final String uri = ParseCoreData().serverUrl + _path; @@ -105,7 +98,12 @@ class ParseFile extends ParseFileBase { } return handleResponse( - this, response, ParseApiRQ.upload, _debug, parseClassName); + this, + response, + ParseApiRQ.upload, + _debug, + parseClassName, + ); } on Exception catch (e) { return handleException(e, ParseApiRQ.upload, _debug, parseClassName); } diff --git a/packages/dart/lib/src/objects/parse_x_file.dart b/packages/dart/lib/src/objects/parse_x_file.dart index 6ac615f0..230bb9fa 100644 --- a/packages/dart/lib/src/objects/parse_x_file.dart +++ b/packages/dart/lib/src/objects/parse_x_file.dart @@ -4,15 +4,14 @@ class ParseXFile extends ParseFileBase { /// Creates a new file base XFile /// /// {https://docs.parseplatform.org/rest/guide/#files/} - ParseXFile(this.file, - {String? name, - super.url, - super.debug, - super.client, - super.autoSendSessionId}) - : super( - name: name ?? path.basename(file?.path ?? ''), - ); + ParseXFile( + this.file, { + String? name, + super.url, + super.debug, + super.client, + super.autoSendSessionId, + }) : super(name: name ?? path.basename(file?.path ?? '')); XFile? file; CancelToken? _cancelToken; @@ -79,14 +78,15 @@ class ParseXFile extends ParseFileBase { //Creates a Fake Response to return the correct result final Map response = { 'url': url!, - 'name': name + 'name': name, }; return handleResponse( - this, - ParseNetworkResponse(data: json.encode(response), statusCode: 201), - ParseApiRQ.upload, - _debug, - parseClassName); + this, + ParseNetworkResponse(data: json.encode(response), statusCode: 201), + ParseApiRQ.upload, + _debug, + parseClassName, + ); } progressCallback ??= _progressCallback; @@ -94,13 +94,10 @@ class ParseXFile extends ParseFileBase { _cancelToken = CancelToken(); Map headers = {}; - // Only set content-type if the file has no extension - // If extension exists, let the server infer the MIME type from the filename - final bool hasExtension = path.extension(name).isNotEmpty; - - if (!hasExtension) { - // No extension, set content-type to application/octet-stream as fallback - headers[HttpHeaders.contentTypeHeader] = 'application/octet-stream'; + // Only set content-type if explicitly provided by the XFile + // Otherwise, let the server infer the MIME type from the filename + if (file?.mimeType != null) { + headers[HttpHeaders.contentTypeHeader] = file!.mimeType!; } if (!parseIsWeb) { @@ -112,8 +109,9 @@ class ParseXFile extends ParseFileBase { Stream>? data; if (parseIsWeb) { - data = Stream>.fromIterable( - >[await file!.readAsBytes()]); + data = Stream>.fromIterable(>[ + await file!.readAsBytes(), + ]); } else { data = file!.openRead(); } @@ -131,7 +129,12 @@ class ParseXFile extends ParseFileBase { name = map['name'].toString(); } return handleResponse( - this, response, ParseApiRQ.upload, _debug, parseClassName); + this, + response, + ParseApiRQ.upload, + _debug, + parseClassName, + ); } on Exception catch (e) { return handleException(e, ParseApiRQ.upload, _debug, parseClassName); } diff --git a/packages/dart/test/src/objects/parse_file_test.dart b/packages/dart/test/src/objects/parse_file_test.dart index 1fcd6d9f..b78f9589 100644 --- a/packages/dart/test/src/objects/parse_file_test.dart +++ b/packages/dart/test/src/objects/parse_file_test.dart @@ -1,7 +1,6 @@ import 'dart:io'; import 'package:parse_server_sdk/parse_server_sdk.dart'; import 'package:test/test.dart'; -import 'package:path/path.dart' as path; import '../../test_utils.dart'; @@ -17,8 +16,7 @@ void main() { expect(parseFile.name, 'bb.jpg'); }); - test('should detect file extension correctly for files with extensions', - () { + test('should handle files with various extensions', () { // Test various file extensions final testCases = [ 'image.jpg', @@ -31,28 +29,20 @@ void main() { for (final filename in testCases) { File file = File('/path/to/$filename'); final parseFile = ParseFile(file, name: filename); - // Verify that the extension is detected - expect(path.extension(parseFile.name).isNotEmpty, true, - reason: '$filename should have an extension'); + // Verify that the name is set correctly + expect(parseFile.name, filename); } }); - test( - 'should detect missing extension correctly for files without extensions', - () { + test('should handle files without extensions', () { // Test files without extensions - final testCases = [ - 'image', - 'file', - 'document', - ]; + final testCases = ['image', 'file', 'document']; for (final filename in testCases) { File file = File('/path/to/$filename'); final parseFile = ParseFile(file, name: filename); - // Verify that no extension is detected - expect(path.extension(parseFile.name).isEmpty, true, - reason: '$filename should not have an extension'); + // Verify that the name is set correctly + expect(parseFile.name, filename); } }); }); diff --git a/packages/dart/test/src/objects/parse_x_file_test.dart b/packages/dart/test/src/objects/parse_x_file_test.dart index c94d225f..3838277d 100644 --- a/packages/dart/test/src/objects/parse_x_file_test.dart +++ b/packages/dart/test/src/objects/parse_x_file_test.dart @@ -1,7 +1,6 @@ import 'package:cross_file/cross_file.dart'; import 'package:parse_server_sdk/parse_server_sdk.dart'; import 'package:test/test.dart'; -import 'package:path/path.dart' as path; import '../../test_utils.dart'; @@ -17,8 +16,7 @@ void main() { expect(parseFile.name, 'bb.jpg'); }); - test('should detect file extension correctly for files with extensions', - () { + test('should handle files with various extensions', () { // Test various file extensions final testCases = [ 'image.jpg', @@ -31,28 +29,20 @@ void main() { for (final filename in testCases) { XFile file = XFile('/path/to/$filename'); final parseFile = ParseXFile(file, name: filename); - // Verify that the extension is detected - expect(path.extension(parseFile.name).isNotEmpty, true, - reason: '$filename should have an extension'); + // Verify that the name is set correctly + expect(parseFile.name, filename); } }); - test( - 'should detect missing extension correctly for files without extensions', - () { + test('should handle files without extensions', () { // Test files without extensions - final testCases = [ - 'image', - 'file', - 'document', - ]; + final testCases = ['image', 'file', 'document']; for (final filename in testCases) { XFile file = XFile('/path/to/$filename'); final parseFile = ParseXFile(file, name: filename); - // Verify that no extension is detected - expect(path.extension(parseFile.name).isEmpty, true, - reason: '$filename should not have an extension'); + // Verify that the name is set correctly + expect(parseFile.name, filename); } }); }); From 158edc816cf0c32b9eae790405dea41b9d5ed4c2 Mon Sep 17 00:00:00 2001 From: Manuel <5673677+mtrezza@users.noreply.github.com> Date: Mon, 24 Nov 2025 14:03:58 +0100 Subject: [PATCH 6/9] Apply suggestion from @mtrezza --- packages/dart/lib/src/objects/parse_file.dart | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/dart/lib/src/objects/parse_file.dart b/packages/dart/lib/src/objects/parse_file.dart index fb3c73f0..8fc51a90 100644 --- a/packages/dart/lib/src/objects/parse_file.dart +++ b/packages/dart/lib/src/objects/parse_file.dart @@ -80,8 +80,6 @@ class ParseFile extends ParseFileBase { HttpHeaders.contentLengthHeader: '${file!.lengthSync()}', }; - // Do not set content-type - let the server infer it from the filename - try { final String uri = ParseCoreData().serverUrl + _path; final ParseNetworkResponse response = await _client.postBytes( From 32235497e0e6a5e26cba44a42b262f99cf63ed36 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 24 Nov 2025 13:12:46 +0000 Subject: [PATCH 7/9] Restore lookupMimeType logic without fallback to octet-stream Restored the lookupMimeType logic for MIME type detection (similar to JS SDK's base64 identification), but removed the fallback to application/octet-stream. Now the chain is: 1. file.mimeType (if provided) 2. lookupMimeType from filename/path/data 3. If still null, no content-type header sent (server infers from filename) Addresses feedback from @mtrezza to keep lookupMimeType logic. Co-authored-by: mtrezza <5673677+mtrezza@users.noreply.github.com> --- packages/dart/lib/src/objects/parse_file.dart | 7 +++++++ .../dart/lib/src/objects/parse_x_file.dart | 20 +++++++++++++++---- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/packages/dart/lib/src/objects/parse_file.dart b/packages/dart/lib/src/objects/parse_file.dart index 8fc51a90..a3ce0fe3 100644 --- a/packages/dart/lib/src/objects/parse_file.dart +++ b/packages/dart/lib/src/objects/parse_file.dart @@ -80,6 +80,13 @@ class ParseFile extends ParseFileBase { HttpHeaders.contentLengthHeader: '${file!.lengthSync()}', }; + // Try to detect content-type using lookupMimeType + // If it cannot be determined, let the server infer from the filename + final String? contentType = lookupMimeType(file!.path); + if (contentType != null) { + headers[HttpHeaders.contentTypeHeader] = contentType; + } + try { final String uri = ParseCoreData().serverUrl + _path; final ParseNetworkResponse response = await _client.postBytes( diff --git a/packages/dart/lib/src/objects/parse_x_file.dart b/packages/dart/lib/src/objects/parse_x_file.dart index 230bb9fa..2cc6e205 100644 --- a/packages/dart/lib/src/objects/parse_x_file.dart +++ b/packages/dart/lib/src/objects/parse_x_file.dart @@ -94,10 +94,22 @@ class ParseXFile extends ParseFileBase { _cancelToken = CancelToken(); Map headers = {}; - // Only set content-type if explicitly provided by the XFile - // Otherwise, let the server infer the MIME type from the filename - if (file?.mimeType != null) { - headers[HttpHeaders.contentTypeHeader] = file!.mimeType!; + // Set content-type from XFile.mimeType or detect using lookupMimeType + // If neither provides a type, let the server infer from the filename + String? contentType; + if (parseIsWeb) { + contentType = + file?.mimeType ?? + lookupMimeType( + url ?? file?.name ?? name, + headerBytes: await file?.readAsBytes(), + ); + } else { + contentType = file?.mimeType ?? lookupMimeType(file!.path); + } + + if (contentType != null) { + headers[HttpHeaders.contentTypeHeader] = contentType; } if (!parseIsWeb) { From d552c340b78a94046f95f98caad0b2840ac09cd0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 24 Nov 2025 14:57:17 +0000 Subject: [PATCH 8/9] Fix lint errors by running dart format Applied dart format to fix formatting issues across the codebase. All code now follows Dart formatting standards. No functional changes, only whitespace and formatting adjustments. Co-authored-by: mtrezza <5673677+mtrezza@users.noreply.github.com> --- packages/dart/example/main.dart | 15 +- packages/dart/lib/parse_server_sdk.dart | 19 +- .../dart/lib/src/data/parse_core_data.dart | 28 +- .../lib/src/data/parse_subclass_handler.dart | 57 ++- .../dart/lib/src/enums/parse_enum_api_rq.dart | 2 +- .../dart/lib/src/network/parse_client.dart | 11 +- .../lib/src/network/parse_connectivity.dart | 2 +- .../lib/src/network/parse_dio_client.dart | 57 ++- .../lib/src/network/parse_http_client.dart | 54 ++- .../lib/src/network/parse_live_query.dart | 150 ++++--- .../dart/lib/src/network/parse_query.dart | 387 +++++++++++++----- packages/dart/lib/src/objects/parse_acl.dart | 31 +- .../dart/lib/src/objects/parse_array.dart | 16 +- .../dart/lib/src/objects/parse_config.dart | 21 +- .../dart/lib/src/objects/parse_error.dart | 11 +- .../dart/lib/src/objects/parse_file_base.dart | 22 +- .../dart/lib/src/objects/parse_file_web.dart | 34 +- .../dart/lib/src/objects/parse_function.dart | 50 ++- .../dart/lib/src/objects/parse_geo_point.dart | 18 +- .../lib/src/objects/parse_installation.dart | 100 +++-- .../dart/lib/src/objects/parse_number.dart | 2 +- .../dart/lib/src/objects/parse_object.dart | 241 ++++++++--- .../parse_add_relation_operation.dart | 5 +- .../parse_add_unique_operation.dart | 5 +- .../parse_operation/parse_operation.dart | 33 +- .../parse_remove_relation_operation.dart | 11 +- .../dart/lib/src/objects/parse_relation.dart | 23 +- .../dart/lib/src/objects/parse_response.dart | 4 +- .../dart/lib/src/objects/parse_session.dart | 17 +- packages/dart/lib/src/objects/parse_user.dart | 289 +++++++++---- .../dart/lib/src/objects/parse_x_file.dart | 3 +- .../response/parse_error_response.dart | 4 +- .../response/parse_exception_response.dart | 14 +- .../response/parse_response_builder.dart | 25 +- .../response/parse_response_utils.dart | 27 +- .../response/parse_success_no_results.dart | 5 +- 36 files changed, 1217 insertions(+), 576 deletions(-) diff --git a/packages/dart/example/main.dart b/packages/dart/example/main.dart index ce96602d..0de2f60d 100644 --- a/packages/dart/example/main.dart +++ b/packages/dart/example/main.dart @@ -2,12 +2,15 @@ import 'package:parse_server_sdk/parse_server_sdk.dart'; Future main() async { // Parse initialize - await Parse().initialize("keyApplicationId", "keyParseServerUrl", - clientKey: "keyParseClientKey", - debug: true, - liveQueryUrl: "keyLiveQueryUrl", - autoSendSessionId: true, - coreStore: CoreStoreMemoryImp()); + await Parse().initialize( + "keyApplicationId", + "keyParseServerUrl", + clientKey: "keyParseClientKey", + debug: true, + liveQueryUrl: "keyLiveQueryUrl", + autoSendSessionId: true, + coreStore: CoreStoreMemoryImp(), + ); // Set a ParseObject and save it var dietPlan = ParseObject('DietPlan') diff --git a/packages/dart/lib/parse_server_sdk.dart b/packages/dart/lib/parse_server_sdk.dart index dc44313a..3c622171 100644 --- a/packages/dart/lib/parse_server_sdk.dart +++ b/packages/dart/lib/parse_server_sdk.dart @@ -165,22 +165,27 @@ class Parse { bool hasParseBeenInitialized() => _hasBeenInitialized; - Future healthCheck( - {bool? debug, ParseClient? client, bool? sendSessionIdByDefault}) async { + Future healthCheck({ + bool? debug, + ParseClient? client, + bool? sendSessionIdByDefault, + }) async { final bool debugLocal = isDebugEnabled(objectLevelDebug: debug); final ParseClient clientLocal = client ?? ParseCoreData().clientCreator( - sendSessionId: - sendSessionIdByDefault ?? ParseCoreData().autoSendSessionId, - securityContext: ParseCoreData().securityContext); + sendSessionId: + sendSessionIdByDefault ?? ParseCoreData().autoSendSessionId, + securityContext: ParseCoreData().securityContext, + ); const String className = 'parseBase'; const ParseApiRQ type = ParseApiRQ.healthCheck; try { - final ParseNetworkResponse response = await clientLocal - .get('${ParseCoreData().serverUrl}$keyEndPointHealth'); + final ParseNetworkResponse response = await clientLocal.get( + '${ParseCoreData().serverUrl}$keyEndPointHealth', + ); return handleResponse(null, response, type, debugLocal, className); } on Exception catch (e) { return handleException(e, type, debugLocal, className); diff --git a/packages/dart/lib/src/data/parse_core_data.dart b/packages/dart/lib/src/data/parse_core_data.dart index cc50cc81..e96e632e 100644 --- a/packages/dart/lib/src/data/parse_core_data.dart +++ b/packages/dart/lib/src/data/parse_core_data.dart @@ -67,8 +67,9 @@ class ParseCoreData { _instance.clientCreator = clientCreator ?? (({required bool sendSessionId, SecurityContext? securityContext}) => ParseHTTPClient( - sendSessionId: sendSessionId, - securityContext: securityContext)); + sendSessionId: sendSessionId, + securityContext: securityContext, + )); } String applicationId; @@ -93,7 +94,9 @@ class ParseCoreData { late ParseClientCreator clientCreator; void registerSubClass( - String className, ParseObjectConstructor objectConstructor) { + String className, + ParseObjectConstructor objectConstructor, + ) { _subClassHandler.registerSubClass(className, objectConstructor); } @@ -110,10 +113,21 @@ class ParseCoreData { } ParseUser createParseUser( - String? username, String? password, String? emailAddress, - {String? sessionToken, bool? debug, ParseClient? client}) { - return _subClassHandler.createParseUser(username, password, emailAddress, - sessionToken: sessionToken, debug: debug, client: client); + String? username, + String? password, + String? emailAddress, { + String? sessionToken, + bool? debug, + ParseClient? client, + }) { + return _subClassHandler.createParseUser( + username, + password, + emailAddress, + sessionToken: sessionToken, + debug: debug, + client: client, + ); } ParseFileBase createFile({String? url, String? name}) => diff --git a/packages/dart/lib/src/data/parse_subclass_handler.dart b/packages/dart/lib/src/data/parse_subclass_handler.dart index 73b2de3a..c0eb2532 100644 --- a/packages/dart/lib/src/data/parse_subclass_handler.dart +++ b/packages/dart/lib/src/data/parse_subclass_handler.dart @@ -2,16 +2,22 @@ part of '../../parse_server_sdk.dart'; typedef ParseObjectConstructor = ParseObject Function(); typedef ParseUserConstructor = ParseUser Function( - String? username, String? password, String? emailAddress, - {String? sessionToken, bool? debug, ParseClient? client}); + String? username, + String? password, + String? emailAddress, { + String? sessionToken, + bool? debug, + ParseClient? client, +}); typedef ParseFileConstructor = ParseFileBase Function( {String? name, String? url}); class ParseSubClassHandler { - ParseSubClassHandler( - {Map? registeredSubClassMap, - ParseUserConstructor? parseUserConstructor, - ParseFileConstructor? parseFileConstructor}) { + ParseSubClassHandler({ + Map? registeredSubClassMap, + ParseUserConstructor? parseUserConstructor, + ParseFileConstructor? parseFileConstructor, + }) { _subClassMap = registeredSubClassMap ?? {}; _parseUserConstructor = parseUserConstructor; if (parseFileConstructor != null) { @@ -23,8 +29,10 @@ class ParseSubClassHandler { ParseUserConstructor? _parseUserConstructor; ParseFileConstructor _parseFileConstructor = defaultParseFileConstructor; - static ParseFileBase defaultParseFileConstructor( - {String? name, String? url}) { + static ParseFileBase defaultParseFileConstructor({ + String? name, + String? url, + }) { if (parseIsWeb) { return ParseWebFile(null, name: name!, url: url); } else { @@ -33,7 +41,9 @@ class ParseSubClassHandler { } void registerSubClass( - String className, ParseObjectConstructor objectConstructor) { + String className, + ParseObjectConstructor objectConstructor, + ) { if (className != keyClassUser && className != keyClassInstallation && className != keyClassSession && @@ -61,13 +71,30 @@ class ParseSubClassHandler { } ParseUser createParseUser( - String? username, String? password, String? emailAddress, - {String? sessionToken, bool? debug, ParseClient? client}) { + String? username, + String? password, + String? emailAddress, { + String? sessionToken, + bool? debug, + ParseClient? client, + }) { return _parseUserConstructor != null - ? _parseUserConstructor!(username, password, emailAddress, - sessionToken: sessionToken, debug: debug, client: client) - : ParseUser(username, password, emailAddress, - sessionToken: sessionToken, debug: debug, client: client); + ? _parseUserConstructor!( + username, + password, + emailAddress, + sessionToken: sessionToken, + debug: debug, + client: client, + ) + : ParseUser( + username, + password, + emailAddress, + sessionToken: sessionToken, + debug: debug, + client: client, + ); } ParseFileBase createFile({String? name, String? url}) => diff --git a/packages/dart/lib/src/enums/parse_enum_api_rq.dart b/packages/dart/lib/src/enums/parse_enum_api_rq.dart index fb54de72..264a43e7 100644 --- a/packages/dart/lib/src/enums/parse_enum_api_rq.dart +++ b/packages/dart/lib/src/enums/parse_enum_api_rq.dart @@ -33,5 +33,5 @@ enum ParseApiRQ { getConfigs, addConfig, liveQuery, - batch + batch, } diff --git a/packages/dart/lib/src/network/parse_client.dart b/packages/dart/lib/src/network/parse_client.dart index bf29694e..cd34ac47 100644 --- a/packages/dart/lib/src/network/parse_client.dart +++ b/packages/dart/lib/src/network/parse_client.dart @@ -1,7 +1,9 @@ part of '../../parse_server_sdk.dart'; -typedef ParseClientCreator = ParseClient Function( - {required bool sendSessionId, SecurityContext? securityContext}); +typedef ParseClientCreator = ParseClient Function({ + required bool sendSessionId, + SecurityContext? securityContext, +}); abstract class ParseClient { Future get( @@ -81,10 +83,7 @@ abstract class ParseClient { typedef ProgressCallback = void Function(int count, int total); class ParseNetworkResponse { - ParseNetworkResponse({ - required this.data, - this.statusCode = -1, - }); + ParseNetworkResponse({required this.data, this.statusCode = -1}); final String data; final int statusCode; diff --git a/packages/dart/lib/src/network/parse_connectivity.dart b/packages/dart/lib/src/network/parse_connectivity.dart index a6ea3dd8..0512f68f 100644 --- a/packages/dart/lib/src/network/parse_connectivity.dart +++ b/packages/dart/lib/src/network/parse_connectivity.dart @@ -9,7 +9,7 @@ enum ParseConnectivityResult { mobile, /// None: Device not connected to any network - none + none, } abstract class ParseConnectivityProvider { diff --git a/packages/dart/lib/src/network/parse_dio_client.dart b/packages/dart/lib/src/network/parse_dio_client.dart index 2de73b97..a8d64b26 100644 --- a/packages/dart/lib/src/network/parse_dio_client.dart +++ b/packages/dart/lib/src/network/parse_dio_client.dart @@ -53,7 +53,9 @@ class ParseDioClient extends ParseClient { cancelToken: cancelToken, onReceiveProgress: onReceiveProgress, options: _Options( - headers: options?.headers, responseType: dio.ResponseType.bytes), + headers: options?.headers, + responseType: dio.ResponseType.bytes, + ), ); return ParseNetworkByteResponse( bytes: dioResponse.data, @@ -67,14 +69,18 @@ class ParseDioClient extends ParseClient { ); } else { return _getOtherCaseErrorForParseNetworkResponse( - error.error.toString()); + error.error.toString(), + ); } } } @override - Future put(String path, - {String? data, ParseNetworkOptions? options}) async { + Future put( + String path, { + String? data, + ParseNetworkOptions? options, + }) async { try { final dio.Response dioResponse = await _client.put( path, @@ -95,8 +101,11 @@ class ParseDioClient extends ParseClient { } @override - Future post(String path, - {String? data, ParseNetworkOptions? options}) async { + Future post( + String path, { + String? data, + ParseNetworkOptions? options, + }) async { try { final dio.Response dioResponse = await _client.post( path, @@ -117,11 +126,13 @@ class ParseDioClient extends ParseClient { } @override - Future postBytes(String path, - {Stream>? data, - ParseNetworkOptions? options, - ProgressCallback? onSendProgress, - dynamic cancelToken}) async { + Future postBytes( + String path, { + Stream>? data, + ParseNetworkOptions? options, + ProgressCallback? onSendProgress, + dynamic cancelToken, + }) async { try { final dio.Response dioResponse = await _client.post( path, @@ -143,20 +154,24 @@ class ParseDioClient extends ParseClient { ); } else { return _getOtherCaseErrorForParseNetworkResponse( - error.error.toString()); + error.error.toString(), + ); } } } _getOtherCaseErrorForParseNetworkResponse(String error) { return ParseNetworkResponse( - data: "{\"code\":${ParseError.otherCause},\"error\":\"$error\"}", - statusCode: ParseError.otherCause); + data: "{\"code\":${ParseError.otherCause},\"error\":\"$error\"}", + statusCode: ParseError.otherCause, + ); } @override - Future delete(String path, - {ParseNetworkOptions? options}) async { + Future delete( + String path, { + ParseNetworkOptions? options, + }) async { try { final dio.Response dioResponse = await _client.delete( path, @@ -224,7 +239,8 @@ class _ParseDioClient with dio.DioMixin implements dio.Dio { /// If developer wants to add custom headers, extend this class and add headers needed. if (additionalHeaders != null && additionalHeaders!.isNotEmpty) { additionalHeaders!.forEach( - (String key, String value) => options!.headers![key] = value); + (String key, String value) => options!.headers![key] = value, + ); } if (parseCoreData.debug) { @@ -273,11 +289,8 @@ class _ParseDioClient with dio.DioMixin implements dio.Dio { } class _Options extends dio.Options { - _Options({ - super.headers, - super.responseType, - String? contentType, - }) : super( + _Options({super.headers, super.responseType, String? contentType}) + : super( contentType: contentType ?? (headers ?? {})[dio.Headers.contentTypeHeader], ); diff --git a/packages/dart/lib/src/network/parse_http_client.dart b/packages/dart/lib/src/network/parse_http_client.dart index 5b1b9795..8d8f3bf1 100644 --- a/packages/dart/lib/src/network/parse_http_client.dart +++ b/packages/dart/lib/src/network/parse_http_client.dart @@ -8,8 +8,10 @@ import 'package:parse_server_sdk/parse_server_sdk.dart'; import 'http_client_io.dart' if (dart.library.js) 'http_client_js.dart'; class ParseHTTPClient extends ParseClient { - ParseHTTPClient( - {bool sendSessionId = false, SecurityContext? securityContext}) { + ParseHTTPClient({ + bool sendSessionId = false, + SecurityContext? securityContext, + }) { _client = _ParseHTTPClient( sendSessionId: sendSessionId, securityContext: securityContext, @@ -36,7 +38,9 @@ class ParseHTTPClient extends ParseClient { headers: options?.headers, ); return ParseNetworkResponse( - data: response.body, statusCode: response.statusCode); + data: response.body, + statusCode: response.statusCode, + ); } @override @@ -51,7 +55,9 @@ class ParseHTTPClient extends ParseClient { headers: options?.headers, ); return ParseNetworkByteResponse( - bytes: response.bodyBytes, statusCode: response.statusCode); + bytes: response.bodyBytes, + statusCode: response.statusCode, + ); } @override @@ -66,7 +72,9 @@ class ParseHTTPClient extends ParseClient { headers: options?.headers, ); return ParseNetworkResponse( - data: response.body, statusCode: response.statusCode); + data: response.body, + statusCode: response.statusCode, + ); } @override @@ -81,7 +89,9 @@ class ParseHTTPClient extends ParseClient { headers: options?.headers, ); return ParseNetworkResponse( - data: response.body, statusCode: response.statusCode); + data: response.body, + statusCode: response.statusCode, + ); } @override @@ -95,31 +105,40 @@ class ParseHTTPClient extends ParseClient { final http.Response response = await _client.post( Uri.parse(path), //Convert the stream to a list - body: await data?.fold>([], - (List previous, List element) => previous..addAll(element)), + body: await data?.fold>( + [], + (List previous, List element) => previous..addAll(element), + ), headers: options?.headers, ); return ParseNetworkResponse( - data: response.body, statusCode: response.statusCode); + data: response.body, + statusCode: response.statusCode, + ); } @override - Future delete(String path, - {ParseNetworkOptions? options}) async { + Future delete( + String path, { + ParseNetworkOptions? options, + }) async { final http.Response response = await _client.delete( Uri.parse(path), headers: options?.headers, ); return ParseNetworkResponse( - data: response.body, statusCode: response.statusCode); + data: response.body, + statusCode: response.statusCode, + ); } } /// Creates a custom version of HTTP Client that has Parse Data Preset class _ParseHTTPClient extends http.BaseClient { - _ParseHTTPClient( - {bool sendSessionId = false, SecurityContext? securityContext}) - : _sendSessionId = sendSessionId, + _ParseHTTPClient({ + bool sendSessionId = false, + SecurityContext? securityContext, + }) : _sendSessionId = sendSessionId, _client = securityContext != null ? getClient(securityContext) : http.Client(); @@ -152,8 +171,9 @@ class _ParseHTTPClient extends http.BaseClient { /// If developer wants to add custom headers, extend this class and add headers needed. if (additionalHeaders != null && additionalHeaders!.isNotEmpty) { - additionalHeaders! - .forEach((String key, String value) => request.headers[key] = value); + additionalHeaders!.forEach( + (String key, String value) => request.headers[key] = value, + ); } if (parseCoreData.debug) { diff --git a/packages/dart/lib/src/network/parse_live_query.dart b/packages/dart/lib/src/network/parse_live_query.dart index 8778c0e0..a9cd9331 100644 --- a/packages/dart/lib/src/network/parse_live_query.dart +++ b/packages/dart/lib/src/network/parse_live_query.dart @@ -19,7 +19,7 @@ class Subscription { 'update', 'leave', 'delete', - 'error' + 'error', ]; Map eventCallbacks = {}; @@ -47,7 +47,8 @@ class LiveQueryReconnectingController { connectivityProvider.connectivityStream.listen(_connectivityChanged); } else { print( - 'LiveQuery does not work, if there is no ParseConnectivityProvider provided.'); + 'LiveQuery does not work, if there is no ParseConnectivityProvider provided.', + ); } _eventStream.listen((LiveQueryClientEvent event) { switch (event) { @@ -111,11 +112,13 @@ class LiveQueryReconnectingController { _currentTimer == null && !_userDisconnected && retryInterval[_retryState] >= 0) { - _currentTimer = - Timer(Duration(milliseconds: retryInterval[_retryState]), () { - _currentTimer = null; - _reconnect(); - }); + _currentTimer = Timer( + Duration(milliseconds: retryInterval[_retryState]), + () { + _currentTimer = null; + _reconnect(); + }, + ); if (debug) { print('$debugTag: Retry timer set to ${retryInterval[_retryState]}ms'); } @@ -129,8 +132,11 @@ class LiveQueryReconnectingController { class LiveQueryClient { factory LiveQueryClient() => _getInstance(); - LiveQueryClient._internal(this._liveQueryURL, - {bool? debug, bool? autoSendSessionId}) { + LiveQueryClient._internal( + this._liveQueryURL, { + bool? debug, + bool? autoSendSessionId, + }) { _clientEventStreamController = StreamController(); _clientEventStream = _clientEventStreamController.stream.asBroadcastStream(); @@ -139,7 +145,10 @@ class LiveQueryClient { _sendSessionId = autoSendSessionId ?? ParseCoreData().autoSendSessionId; reconnectingController = LiveQueryReconnectingController( - () => reconnect(userInitialized: false), getClientEventStream, _debug); + () => reconnect(userInitialized: false), + getClientEventStream, + _debug, + ); } static LiveQueryClient get instance => _getInstance(); @@ -148,8 +157,10 @@ class LiveQueryClient { static LiveQueryClient _getInstance({bool? debug, bool? autoSendSessionId}) { String? liveQueryURL = ParseCoreData().liveQueryURL; if (liveQueryURL == null) { - assert(false, - 'liveQueryUrl is not set. For how to setup Live Queries, see https://github.com/parse-community/Parse-SDK-Flutter/tree/master/packages/flutter#live-queries.'); + assert( + false, + 'liveQueryUrl is not set. For how to setup Live Queries, see https://github.com/parse-community/Parse-SDK-Flutter/tree/master/packages/flutter#live-queries.', + ); liveQueryURL = ""; } else { if (liveQueryURL.contains('https')) { @@ -159,8 +170,11 @@ class LiveQueryClient { } } LiveQueryClient instance = _instance ?? - LiveQueryClient._internal(liveQueryURL, - debug: debug, autoSendSessionId: autoSendSessionId); + LiveQueryClient._internal( + liveQueryURL, + debug: debug, + autoSendSessionId: autoSendSessionId, + ); _instance ??= instance; return instance; } @@ -218,21 +232,27 @@ class LiveQueryClient { }); _connecting = false; if (userInitialized) { - _clientEventStreamController.sink - .add(LiveQueryClientEvent.userDisconnected); + _clientEventStreamController.sink.add( + LiveQueryClientEvent.userDisconnected, + ); } } Future> subscribe( - QueryBuilder query, - {T? copyObject}) async { + QueryBuilder query, { + T? copyObject, + }) async { if (_webSocket == null) { - await _clientEventStream.any((LiveQueryClientEvent event) => - event == LiveQueryClientEvent.connected); + await _clientEventStream.any( + (LiveQueryClientEvent event) => event == LiveQueryClientEvent.connected, + ); } final int requestId = _requestIdGenerator(); - final Subscription subscription = - Subscription(query, requestId, copyObject: copyObject); + final Subscription subscription = Subscription( + query, + requestId, + copyObject: copyObject, + ); _requestSubscription[requestId] = subscription; //After a client connects to the LiveQuery server, //it can send a subscribe message to subscribe a ParseQuery. @@ -288,29 +308,39 @@ class LiveQueryClient { } WebSocketChannel channel = webSocket.createWebSocketChannel(); _channel = channel; - channel.stream.listen((dynamic message) { - _handleMessage(message); - - chanelStream?.sink.add(message); - }, onDone: () { - _clientEventStreamController.sink - .add(LiveQueryClientEvent.disconnected); - if (_debug) { - print('$_printConstLiveQuery: Done'); - } - }, onError: (Object error) { - _clientEventStreamController.sink - .add(LiveQueryClientEvent.disconnected); - if (_debug) { - print( - '$_printConstLiveQuery: Error: ${error.runtimeType.toString()}'); - } - return Future.value(handleException( - Exception(error), - ParseApiRQ.liveQuery, - _debug, - !parseIsWeb ? 'IOWebSocketChannel' : 'HtmlWebSocketChannel')); - }); + channel.stream.listen( + (dynamic message) { + _handleMessage(message); + + chanelStream?.sink.add(message); + }, + onDone: () { + _clientEventStreamController.sink.add( + LiveQueryClientEvent.disconnected, + ); + if (_debug) { + print('$_printConstLiveQuery: Done'); + } + }, + onError: (Object error) { + _clientEventStreamController.sink.add( + LiveQueryClientEvent.disconnected, + ); + if (_debug) { + print( + '$_printConstLiveQuery: Error: ${error.runtimeType.toString()}', + ); + } + return Future.value( + handleException( + Exception(error), + ParseApiRQ.liveQuery, + _debug, + !parseIsWeb ? 'IOWebSocketChannel' : 'HtmlWebSocketChannel', + ), + ); + }, + ); } on Exception catch (e) { _connecting = false; _clientEventStreamController.sink.add(LiveQueryClientEvent.disconnected); @@ -330,7 +360,7 @@ class LiveQueryClient { //It should be the first message sent from a client after the WebSocket connection is established. final Map connectMessage = { 'op': 'connect', - 'applicationId': ParseCoreData().applicationId + 'applicationId': ParseCoreData().applicationId, }; if (_sendSessionId) { @@ -385,8 +415,8 @@ class LiveQueryClient { 'className': query.object.parseClassName, 'where': whereMap, if (keysToReturn != null && keysToReturn.isNotEmpty) - 'fields': keysToReturn - } + 'fields': keysToReturn, + }, }; if (_sendSessionId && ParseCoreData().sessionId != null) { subscribeMessage['sessionToken'] = ParseCoreData().sessionId; @@ -430,13 +460,21 @@ class LiveQueryClient { final String? className = map['className']; if (className != null) { if (className == keyClassUser) { - eventCallback((subscription.copyObject ?? - ParseCoreData.instance.createParseUser(null, null, null)) - .fromJson(map)); + eventCallback( + (subscription.copyObject ?? + ParseCoreData.instance.createParseUser( + null, + null, + null, + )) + .fromJson(map), + ); } else { - eventCallback((subscription.copyObject ?? - ParseCoreData.instance.createObject(className)) - .fromJson(map)); + eventCallback( + (subscription.copyObject ?? + ParseCoreData.instance.createObject(className)) + .fromJson(map), + ); } } } else { @@ -452,7 +490,9 @@ class LiveQuery { _debug = isDebugEnabled(objectLevelDebug: debug); _sendSessionId = autoSendSessionId ?? ParseCoreData().autoSendSessionId; client = LiveQueryClient._getInstance( - debug: _debug, autoSendSessionId: _sendSessionId); + debug: _debug, + autoSendSessionId: _sendSessionId, + ); } bool? _debug; diff --git a/packages/dart/lib/src/network/parse_query.dart b/packages/dart/lib/src/network/parse_query.dart index 6c27390f..79898c24 100644 --- a/packages/dart/lib/src/network/parse_query.dart +++ b/packages/dart/lib/src/network/parse_query.dart @@ -21,8 +21,10 @@ class QueryBuilder { _constructorInitializer(query: '"\$nor":[', list: list); } - void _constructorInitializer( - {required String query, required List> list}) { + void _constructorInitializer({ + required String query, + required List> list, + }) { for (int i = 0; i < list.length; ++i) { if (i > 0) { query += ','; @@ -36,11 +38,15 @@ class QueryBuilder { factory QueryBuilder.copy(QueryBuilder query) { QueryBuilder copy = QueryBuilder(query.object); copy.queries = query.queries - .map((MapEntry entry) => - MapEntry(entry.key, entry.value.toString())) + .map( + (MapEntry entry) => + MapEntry(entry.key, entry.value.toString()), + ) .toList(); - query.limiters.forEach((String key, dynamic value) => - copy.limiters.putIfAbsent(key, () => value.toString())); + query.limiters.forEach( + (String key, dynamic value) => + copy.limiters.putIfAbsent(key, () => value.toString()), + ); return copy; } @@ -126,11 +132,19 @@ class QueryBuilder { prefix = Uri.encodeComponent(prefix); if (caseSensitive) { - queries.add(MapEntry( - _singleQuery, '"$column":{"\$regex": "^$prefix"}')); + queries.add( + MapEntry( + _singleQuery, + '"$column":{"\$regex": "^$prefix"}', + ), + ); } else { - queries.add(MapEntry( - _singleQuery, '"$column":{"\$regex": "^$prefix", "\$options": "i"}')); + queries.add( + MapEntry( + _singleQuery, + '"$column":{"\$regex": "^$prefix", "\$options": "i"}', + ), + ); } } @@ -144,11 +158,19 @@ class QueryBuilder { prefix = Uri.encodeComponent(prefix); if (caseSensitive) { - queries.add(MapEntry( - _singleQuery, '"$column":{"\$regex": "$prefix\$"}')); + queries.add( + MapEntry( + _singleQuery, + '"$column":{"\$regex": "$prefix\$"}', + ), + ); } else { - queries.add(MapEntry(_singleQuery, - '"$column":{"\$regex": "$prefix\$", "\$options": "i"}')); + queries.add( + MapEntry( + _singleQuery, + '"$column":{"\$regex": "$prefix\$", "\$options": "i"}', + ), + ); } } @@ -159,36 +181,56 @@ class QueryBuilder { value = Uri.encodeComponent(value); } - queries.add(_buildQueryWithColumnValueAndOperator( - MapEntry(column, value), _noOperatorNeeded)); + queries.add( + _buildQueryWithColumnValueAndOperator( + MapEntry(column, value), + _noOperatorNeeded, + ), + ); } /// Returns an object where the [String] column contains a value less than /// value void whereLessThan(String column, dynamic value) { - queries.add(_buildQueryWithColumnValueAndOperator( - MapEntry(column, value), '\$lt')); + queries.add( + _buildQueryWithColumnValueAndOperator( + MapEntry(column, value), + '\$lt', + ), + ); } /// Returns an object where the [String] column contains a value less or equal /// to than value void whereLessThanOrEqualTo(String column, dynamic value) { - queries.add(_buildQueryWithColumnValueAndOperator( - MapEntry(column, value), '\$lte')); + queries.add( + _buildQueryWithColumnValueAndOperator( + MapEntry(column, value), + '\$lte', + ), + ); } /// Returns an object where the [String] column contains a value greater /// than value void whereGreaterThan(String column, dynamic value) { - queries.add(_buildQueryWithColumnValueAndOperator( - MapEntry(column, value), '\$gt')); + queries.add( + _buildQueryWithColumnValueAndOperator( + MapEntry(column, value), + '\$gt', + ), + ); } /// Returns an object where the [String] column contains a value greater /// than equal to value void whereGreaterThanOrEqualsTo(String column, dynamic value) { - queries.add(_buildQueryWithColumnValueAndOperator( - MapEntry(column, value), '\$gte')); + queries.add( + _buildQueryWithColumnValueAndOperator( + MapEntry(column, value), + '\$gte', + ), + ); } /// Add a constraint to the query that requires a particular [column]'s value @@ -198,57 +240,93 @@ class QueryBuilder { value = Uri.encodeComponent(value); } - queries.add(_buildQueryWithColumnValueAndOperator( - MapEntry(column, value), '\$ne')); + queries.add( + _buildQueryWithColumnValueAndOperator( + MapEntry(column, value), + '\$ne', + ), + ); } /// Returns an object where the [String] column is containedIn void whereContainedIn(String column, List value) { - queries.add(_buildQueryWithColumnValueAndOperator( - MapEntry(column, value), '\$in')); + queries.add( + _buildQueryWithColumnValueAndOperator( + MapEntry(column, value), + '\$in', + ), + ); } /// Returns an object where the [String] column is notContainedIn void whereNotContainedIn(String column, List value) { - queries.add(_buildQueryWithColumnValueAndOperator( - MapEntry(column, value), '\$nin')); + queries.add( + _buildQueryWithColumnValueAndOperator( + MapEntry(column, value), + '\$nin', + ), + ); } /// Returns an object where the [String] column for the object has data correctly entered/saved void whereValueExists(String column, bool value) { - queries.add(_buildQueryWithColumnValueAndOperator( - MapEntry(column, value), '\$exists')); + queries.add( + _buildQueryWithColumnValueAndOperator( + MapEntry(column, value), + '\$exists', + ), + ); } /// Retrieves related objets where [String] column is a relation field to the class [String] className void whereRelatedTo(String column, String className, String objectId) { - queries.add(MapEntry(_singleQuery, - '"\$relatedTo":{"object":{"__type":"Pointer","className":"$className","objectId":"$objectId"},"key":"$column"}')); + queries.add( + MapEntry( + _singleQuery, + '"\$relatedTo":{"object":{"__type":"Pointer","className":"$className","objectId":"$objectId"},"key":"$column"}', + ), + ); } /// Returns an object where the [String] column contains select void selectKeys(String column, dynamic value) { - queries.add(_buildQueryWithColumnValueAndOperator( - MapEntry(column, value), '\$select')); + queries.add( + _buildQueryWithColumnValueAndOperator( + MapEntry(column, value), + '\$select', + ), + ); } /// Returns an object where the [String] column doesn't select void dontSelectKeys(String column, dynamic value) { - queries.add(_buildQueryWithColumnValueAndOperator( - MapEntry(column, value), '\$dontSelect')); + queries.add( + _buildQueryWithColumnValueAndOperator( + MapEntry(column, value), + '\$dontSelect', + ), + ); } /// Returns an object where the [String] column contains all void whereArrayContainsAll(String column, List value) { - queries.add(_buildQueryWithColumnValueAndOperator( - MapEntry(column, value), '\$all')); + queries.add( + _buildQueryWithColumnValueAndOperator( + MapEntry(column, value), + '\$all', + ), + ); } /// Returns an object where the [String] column has a regEx performed on, /// this can include ^StringsWith, or ^EndsWith. This can be manipulated to the users desire void regEx(String column, String value) { - queries.add(_buildQueryWithColumnValueAndOperator( - MapEntry(column, value), '\$regex')); + queries.add( + _buildQueryWithColumnValueAndOperator( + MapEntry(column, value), + '\$regex', + ), + ); } /// Add a constraint for finding String values that contain the provided @@ -261,11 +339,19 @@ class QueryBuilder { substring = Uri.encodeComponent(substring); if (caseSensitive) { - queries.add(MapEntry( - _singleQuery, '"$column":{"\$regex": "$substring"}')); + queries.add( + MapEntry( + _singleQuery, + '"$column":{"\$regex": "$substring"}', + ), + ); } else { - queries.add(MapEntry(_singleQuery, - '"$column":{"\$regex": "$substring", "\$options": "i"}')); + queries.add( + MapEntry( + _singleQuery, + '"$column":{"\$regex": "$substring", "\$options": "i"}', + ), + ); } } @@ -281,8 +367,12 @@ class QueryBuilder { }) { searchTerm = Uri.encodeComponent(searchTerm); - queries.add(MapEntry(_singleQuery, - '"$column":{"\$text":{"\$search":{"\$term": "$searchTerm", "\$caseSensitive": $caseSensitive , "\$diacriticSensitive": $diacriticSensitive }}}')); + queries.add( + MapEntry( + _singleQuery, + '"$column":{"\$text":{"\$search":{"\$term": "$searchTerm", "\$caseSensitive": $caseSensitive , "\$diacriticSensitive": $diacriticSensitive }}}', + ), + ); if (orderByScore) { orderByAscending('\$score'); keysToReturn(['\$score']); @@ -293,51 +383,83 @@ class QueryBuilder { void whereNear(String column, ParseGeoPoint point) { final double latitude = point.latitude; final double longitude = point.longitude; - queries.add(MapEntry(_singleQuery, - '"$column":{"\$nearSphere":{"__type":"GeoPoint","latitude":$latitude,"longitude":$longitude}}')); + queries.add( + MapEntry( + _singleQuery, + '"$column":{"\$nearSphere":{"__type":"GeoPoint","latitude":$latitude,"longitude":$longitude}}', + ), + ); } /// Returns an object with key point values near the point given and within the maximum distance given. void whereWithinMiles( - String column, ParseGeoPoint point, double maxDistance) { + String column, + ParseGeoPoint point, + double maxDistance, + ) { final double latitude = point.latitude; final double longitude = point.longitude; - queries.add(MapEntry(_singleQuery, - '"$column":{"\$nearSphere":{"__type":"GeoPoint","latitude":$latitude,"longitude":$longitude},"\$maxDistanceInMiles":$maxDistance}')); + queries.add( + MapEntry( + _singleQuery, + '"$column":{"\$nearSphere":{"__type":"GeoPoint","latitude":$latitude,"longitude":$longitude},"\$maxDistanceInMiles":$maxDistance}', + ), + ); } /// Returns an object with key point values near the point given and within the maximum distance given. void whereWithinKilometers( - String column, ParseGeoPoint point, double maxDistance) { + String column, + ParseGeoPoint point, + double maxDistance, + ) { final double latitude = point.latitude; final double longitude = point.longitude; - queries.add(MapEntry(_singleQuery, - '"$column":{"\$nearSphere":{"__type":"GeoPoint","latitude":$latitude,"longitude":$longitude},"\$maxDistanceInKilometers":$maxDistance}')); + queries.add( + MapEntry( + _singleQuery, + '"$column":{"\$nearSphere":{"__type":"GeoPoint","latitude":$latitude,"longitude":$longitude},"\$maxDistanceInKilometers":$maxDistance}', + ), + ); } /// Returns an object with key point values near the point given and within the maximum distance given. void whereWithinRadians( - String column, ParseGeoPoint point, double maxDistance) { + String column, + ParseGeoPoint point, + double maxDistance, + ) { final double latitude = point.latitude; final double longitude = point.longitude; - queries.add(MapEntry(_singleQuery, - '"$column":{"\$nearSphere":{"__type":"GeoPoint","latitude":$latitude,"longitude":$longitude},"\$maxDistanceInRadians":$maxDistance}')); + queries.add( + MapEntry( + _singleQuery, + '"$column":{"\$nearSphere":{"__type":"GeoPoint","latitude":$latitude,"longitude":$longitude},"\$maxDistanceInRadians":$maxDistance}', + ), + ); } /// Returns an object with key point values contained within a given rectangular geographic bounding box. void whereWithinGeoBox( - String column, ParseGeoPoint southwest, ParseGeoPoint northeast) { + String column, + ParseGeoPoint southwest, + ParseGeoPoint northeast, + ) { final double latitudeS = southwest.latitude; final double longitudeS = southwest.longitude; final double latitudeN = northeast.latitude; final double longitudeN = northeast.longitude; - queries.add(MapEntry(_singleQuery, - '"$column":{"\$within":{"\$box": [{"__type": "GeoPoint","latitude":$latitudeS,"longitude":$longitudeS},{"__type": "GeoPoint","latitude":$latitudeN,"longitude":$longitudeN}]}}')); + queries.add( + MapEntry( + _singleQuery, + '"$column":{"\$within":{"\$box": [{"__type": "GeoPoint","latitude":$latitudeS,"longitude":$longitudeS},{"__type": "GeoPoint","latitude":$latitudeN,"longitude":$longitudeN}]}}', + ), + ); } /// Return an object with key coordinates be contained within and on the bounds of a given polygon. @@ -350,8 +472,12 @@ class QueryBuilder { Map dictionary = {}; dictionary['\$polygon'] = points.map((e) => e.toJson()).toList(); - queries.add(MapEntry( - _singleQuery, '"$column":{"\$geoWithin":${jsonEncode(dictionary)}}')); + queries.add( + MapEntry( + _singleQuery, + '"$column":{"\$geoWithin":${jsonEncode(dictionary)}}', + ), + ); } /// Add a constraint to the query that requires a particular key's coordinates that contains a point @@ -359,33 +485,54 @@ class QueryBuilder { final double latitude = point.latitude; final double longitude = point.longitude; - queries.add(MapEntry(_singleQuery, - '"$column":{"\$geoIntersects":{"\$point":{"__type":"GeoPoint","latitude":$latitude,"longitude":$longitude}}}')); + queries.add( + MapEntry( + _singleQuery, + '"$column":{"\$geoIntersects":{"\$point":{"__type":"GeoPoint","latitude":$latitude,"longitude":$longitude}}}', + ), + ); } /// Add a constraint to the query that requires a particular key's value match another QueryBuilder void whereMatchesQuery( - String column, QueryBuilder query) { - final String inQuery = - query._buildQueryRelational(query.object.parseClassName); + String column, + QueryBuilder query, + ) { + final String inQuery = query._buildQueryRelational( + query.object.parseClassName, + ); - queries.add(MapEntry( - _singleQuery, '"$column":{"\$inQuery":$inQuery}')); + queries.add( + MapEntry( + _singleQuery, + '"$column":{"\$inQuery":$inQuery}', + ), + ); } ///Add a constraint to the query that requires a particular key's value does not match another QueryBuilder void whereDoesNotMatchQuery( - String column, QueryBuilder query) { - final String inQuery = - query._buildQueryRelational(query.object.parseClassName); + String column, + QueryBuilder query, + ) { + final String inQuery = query._buildQueryRelational( + query.object.parseClassName, + ); - queries.add(MapEntry( - _singleQuery, '"$column":{"\$notInQuery":$inQuery}')); + queries.add( + MapEntry( + _singleQuery, + '"$column":{"\$notInQuery":$inQuery}', + ), + ); } /// Add a constraint to the query that requires a particular key's value matches a value for a key in the results of another ParseQuery. void whereMatchesKeyInQuery( - String column, String keyInQuery, QueryBuilder query) { + String column, + String keyInQuery, + QueryBuilder query, + ) { if (query.queries.isEmpty) { throw ArgumentError('query conditions is required'); } @@ -396,16 +543,25 @@ class QueryBuilder { throw ArgumentError('include is not allowed'); } - final String inQuery = - query._buildQueryRelationalKey(query.object.parseClassName, keyInQuery); + final String inQuery = query._buildQueryRelationalKey( + query.object.parseClassName, + keyInQuery, + ); - queries.add(MapEntry( - _singleQuery, '"$column":{"\$select":$inQuery}')); + queries.add( + MapEntry( + _singleQuery, + '"$column":{"\$select":$inQuery}', + ), + ); } /// Add a constraint to the query that requires a particular key's value does not match any value for a key in the results of another ParseQuery void whereDoesNotMatchKeyInQuery( - String column, String keyInQuery, QueryBuilder query) { + String column, + String keyInQuery, + QueryBuilder query, + ) { if (query.queries.isEmpty) { throw ArgumentError('query conditions is required'); } @@ -416,26 +572,31 @@ class QueryBuilder { throw ArgumentError('include is not allowed'); } - final String inQuery = - query._buildQueryRelationalKey(query.object.parseClassName, keyInQuery); + final String inQuery = query._buildQueryRelationalKey( + query.object.parseClassName, + keyInQuery, + ); - queries.add(MapEntry( - _singleQuery, '"$column":{"\$dontSelect":$inQuery}')); + queries.add( + MapEntry( + _singleQuery, + '"$column":{"\$dontSelect":$inQuery}', + ), + ); } /// Finishes the query and calls the server /// /// Make sure to call this after defining your queries - Future query( - {ProgressCallback? progressCallback}) async { - return object.query( - buildQuery(), - progressCallback: progressCallback, - ); + Future query({ + ProgressCallback? progressCallback, + }) async { + return object.query(buildQuery(), progressCallback: progressCallback); } Future distinct( - String className) async { + String className, + ) async { final String queryString = 'distinct=$className'; return object.distinct(queryString); } @@ -488,20 +649,26 @@ class QueryBuilder { /// Creates a query param using the column, the value and the queryOperator /// that the column and value are being queried against MapEntry _buildQueryWithColumnValueAndOperator( - MapEntry columnAndValue, String queryOperator) { + MapEntry columnAndValue, + String queryOperator, + ) { final String key = columnAndValue.key; - final dynamic value = - convertValueToCorrectType(parseEncode(columnAndValue.value)); + final dynamic value = convertValueToCorrectType( + parseEncode(columnAndValue.value), + ); if (queryOperator == _noOperatorNeeded) { return MapEntry( - _noOperatorNeeded, '"$key": ${jsonEncode(value)}'); + _noOperatorNeeded, + '"$key": ${jsonEncode(value)}', + ); } else { String queryString = '"$key":'; final Map queryOperatorAndValueMap = {}; queryOperatorAndValueMap[queryOperator] = parseEncode(value); - final String formattedQueryOperatorAndValue = - jsonEncode(queryOperatorAndValueMap); + final String formattedQueryOperatorAndValue = jsonEncode( + queryOperatorAndValueMap, + ); queryString += formattedQueryOperatorAndValue; return MapEntry(key, queryString); } @@ -510,7 +677,8 @@ class QueryBuilder { /// This joins queries that should be joined together... e.g. age > 10 && /// age < 20, this would be similar to age > 10 < 20 List> _checkForMultipleColumnInstances( - List> queries) { + List> queries, + ) { final List> sanitizedQueries = >[]; final List keysAlreadyCompacted = []; @@ -519,8 +687,9 @@ class QueryBuilder { for (final MapEntry query in queries) { // Add queries that don't need sanitizing if (query.key == _noOperatorNeeded || query.key == _singleQuery) { - sanitizedQueries - .add(MapEntry(_noOperatorNeeded, query.value)); + sanitizedQueries.add( + MapEntry(_noOperatorNeeded, query.value), + ); } // Check if query with same column name has been sanitized @@ -544,7 +713,10 @@ class QueryBuilder { String queryToCompactValue = queryToCompact.value.toString(); queryToCompactValue = queryToCompactValue.replaceFirst('{', ''); queryToCompactValue = queryToCompactValue.replaceRange( - queryToCompactValue.length - 1, queryToCompactValue.length, ''); + queryToCompactValue.length - 1, + queryToCompactValue.length, + '', + ); if (listOfQueriesCompact.first == queryToCompact) { queryEnd += queryToCompactValue.replaceAll(queryStart, ' '); } else { @@ -553,7 +725,8 @@ class QueryBuilder { } sanitizedQueries.add( - MapEntry(query.key, queryStart += '{$queryEnd}')); + MapEntry(query.key, queryStart += '{$queryEnd}'), + ); } } @@ -594,8 +767,10 @@ class QueryBuilder { /// Find the first object that satisfies the query. /// Returns null, if no object is found. Future first() async { - ParseResponse parseResponse = - await (QueryBuilder.copy(this)..setLimit(1)).query(); + ParseResponse parseResponse = await (QueryBuilder.copy( + this, + )..setLimit(1)) + .query(); if (parseResponse.success) { return parseResponse.results?.first; } diff --git a/packages/dart/lib/src/objects/parse_acl.dart b/packages/dart/lib/src/objects/parse_acl.dart index bf498e17..26d00d14 100644 --- a/packages/dart/lib/src/objects/parse_acl.dart +++ b/packages/dart/lib/src/objects/parse_acl.dart @@ -20,15 +20,18 @@ class ParseACL { {}; /// Helper for setting stuff - void _setPermissionsIfNonEmpty( - {required String userId, - required bool readPermission, - required bool writePermission}) { + void _setPermissionsIfNonEmpty({ + required String userId, + required bool readPermission, + required bool writePermission, + }) { if (!(readPermission || writePermission)) { _permissionsById.remove(userId); } else { - _permissionsById[userId] = - _ACLPermissions(readPermission, writePermission); + _permissionsById[userId] = _ACLPermissions( + readPermission, + writePermission, + ); } } @@ -56,9 +59,10 @@ class ParseACL { void setReadAccess({required String userId, bool allowed = true}) { final bool writePermission = getWriteAccess(userId: userId); _setPermissionsIfNonEmpty( - userId: userId, - readPermission: allowed, - writePermission: writePermission); + userId: userId, + readPermission: allowed, + writePermission: writePermission, + ); } /// Get whether the given user id is *explicitly* allowed to read this object. Even if this returns @@ -72,9 +76,10 @@ class ParseACL { void setWriteAccess({required String userId, bool allowed = true}) { final bool readPermission = getReadAccess(userId: userId); _setPermissionsIfNonEmpty( - userId: userId, - readPermission: readPermission, - writePermission: allowed); + userId: userId, + readPermission: readPermission, + writePermission: allowed, + ); } ///Get whether the given user id is *explicitly* allowed to write this object. Even if this @@ -123,6 +128,6 @@ class _ACLPermissions { Map toJson() => { _keyReadPermission: _readPermission, - _keyWritePermission: _writePermission + _keyWritePermission: _writePermission, }; } diff --git a/packages/dart/lib/src/objects/parse_array.dart b/packages/dart/lib/src/objects/parse_array.dart index f4ebf602..4d76b0a7 100644 --- a/packages/dart/lib/src/objects/parse_array.dart +++ b/packages/dart/lib/src/objects/parse_array.dart @@ -17,9 +17,7 @@ class _ParseArray implements _Valuable, _ParseSaveStateAwareChild { _ParseArrayOperation? lastPreformedOperation; - _ParseArray preformArrayOperation( - _ParseArrayOperation arrayOperation, - ) { + _ParseArray preformArrayOperation(_ParseArrayOperation arrayOperation) { arrayOperation.mergeWithPrevious(lastPreformedOperation ?? this); lastPreformedOperation = arrayOperation; @@ -39,7 +37,7 @@ class _ParseArray implements _Valuable, _ParseSaveStateAwareChild { 'className': 'ParseArray', 'estimatedArray': parseEncode(estimatedArray, full: full), 'savedArray': parseEncode(_savedArray, full: full), - 'lastPreformedOperation': lastPreformedOperation?.toJson(full: full) + 'lastPreformedOperation': lastPreformedOperation?.toJson(full: full), }; } @@ -78,11 +76,13 @@ class _ParseArray implements _Valuable, _ParseSaveStateAwareChild { } else { // remove the saved objects and keep the new added objects while saving if (lastPreformedOperation is _ParseRemoveOperation) { - lastPreformedOperation?.valueForApiRequest - .retainWhere((e) => _savedArray.contains(e)); + lastPreformedOperation?.valueForApiRequest.retainWhere( + (e) => _savedArray.contains(e), + ); } else { - lastPreformedOperation?.valueForApiRequest - .removeWhere((e) => _savedArray.contains(e)); + lastPreformedOperation?.valueForApiRequest.removeWhere( + (e) => _savedArray.contains(e), + ); } } diff --git a/packages/dart/lib/src/objects/parse_config.dart b/packages/dart/lib/src/objects/parse_config.dart index 6031ca14..06869119 100644 --- a/packages/dart/lib/src/objects/parse_config.dart +++ b/packages/dart/lib/src/objects/parse_config.dart @@ -2,11 +2,8 @@ part of '../../parse_server_sdk.dart'; class ParseConfig extends ParseObject { /// Creates an instance of ParseConfig so that you can grab all configs from the server - ParseConfig({ - bool? debug, - ParseClient? client, - bool? autoSendSessionId, - }) : super( + ParseConfig({bool? debug, ParseClient? client, bool? autoSendSessionId}) + : super( 'config', debug: debug, client: client, @@ -19,7 +16,12 @@ class ParseConfig extends ParseObject { final String uri = '${ParseCoreData().serverUrl}/config'; final ParseNetworkResponse result = await _client.get(uri); return handleResponse( - this, result, ParseApiRQ.getConfigs, _debug, parseClassName); + this, + result, + ParseApiRQ.getConfigs, + _debug, + parseClassName, + ); } on Exception catch (e) { return handleException(e, ParseApiRQ.getConfigs, _debug, parseClassName); } @@ -33,7 +35,12 @@ class ParseConfig extends ParseObject { '{"params":{"$key": ${json.encode(parseEncode(value))}}}'; final ParseNetworkResponse result = await _client.put(uri, data: body); return handleResponse( - this, result, ParseApiRQ.addConfig, _debug, parseClassName); + this, + result, + ParseApiRQ.addConfig, + _debug, + parseClassName, + ); } on Exception catch (e) { return handleException(e, ParseApiRQ.addConfig, _debug, parseClassName); } diff --git a/packages/dart/lib/src/objects/parse_error.dart b/packages/dart/lib/src/objects/parse_error.dart index 38e39248..0c1527fb 100644 --- a/packages/dart/lib/src/objects/parse_error.dart +++ b/packages/dart/lib/src/objects/parse_error.dart @@ -2,11 +2,12 @@ part of '../../parse_server_sdk.dart'; /// ParseException is used in [ParseResult] to inform the user of the exception class ParseError { - ParseError( - {this.code = otherCause, - this.message = 'OtherCause', - this.exception, - bool debug = false}) { + ParseError({ + this.code = otherCause, + this.message = 'OtherCause', + this.exception, + bool debug = false, + }) { type = _exceptions[code]; if (debug) { print(toString()); diff --git a/packages/dart/lib/src/objects/parse_file_base.dart b/packages/dart/lib/src/objects/parse_file_base.dart index 3c16ed27..c944863e 100644 --- a/packages/dart/lib/src/objects/parse_file_base.dart +++ b/packages/dart/lib/src/objects/parse_file_base.dart @@ -4,16 +4,18 @@ abstract class ParseFileBase extends ParseObject { /// Creates a new file /// /// {https://docs.parseplatform.org/rest/guide/#files/} - ParseFileBase( - {required String name, - String? url, - bool? debug, - ParseClient? client, - bool? autoSendSessionId}) - : super(keyFileClassname, - debug: debug, - autoSendSessionId: autoSendSessionId, - client: client) { + ParseFileBase({ + required String name, + String? url, + bool? debug, + ParseClient? client, + bool? autoSendSessionId, + }) : super( + keyFileClassname, + debug: debug, + autoSendSessionId: autoSendSessionId, + client: client, + ) { _path = '/files/$name'; this.name = name; if (url != null) this.url = url; diff --git a/packages/dart/lib/src/objects/parse_file_web.dart b/packages/dart/lib/src/objects/parse_file_web.dart index cbaba541..7f1c3b76 100644 --- a/packages/dart/lib/src/objects/parse_file_web.dart +++ b/packages/dart/lib/src/objects/parse_file_web.dart @@ -1,12 +1,14 @@ part of '../../parse_server_sdk.dart'; class ParseWebFile extends ParseFileBase { - ParseWebFile(this.file, - {required super.name, - super.url, - super.debug, - super.client, - super.autoSendSessionId}); + ParseWebFile( + this.file, { + required super.name, + super.url, + super.debug, + super.client, + super.autoSendSessionId, + }); Uint8List? file; CancelToken? _cancelToken; @@ -38,14 +40,15 @@ class ParseWebFile extends ParseFileBase { //Creates a Fake Response to return the correct result final Map response = { 'url': url!, - 'name': name + 'name': name, }; return handleResponse( - this, - ParseNetworkResponse(data: json.encode(response), statusCode: 201), - ParseApiRQ.upload, - _debug, - parseClassName); + this, + ParseNetworkResponse(data: json.encode(response), statusCode: 201), + ParseApiRQ.upload, + _debug, + parseClassName, + ); } progressCallback ??= _progressCallback; @@ -71,7 +74,12 @@ class ParseWebFile extends ParseFileBase { name = map['name'].toString(); } return handleResponse( - this, response, ParseApiRQ.upload, _debug, parseClassName); + this, + response, + ParseApiRQ.upload, + _debug, + parseClassName, + ); } on Exception catch (e) { return handleException(e, ParseApiRQ.upload, _debug, parseClassName); } diff --git a/packages/dart/lib/src/objects/parse_function.dart b/packages/dart/lib/src/objects/parse_function.dart index 5e307303..d512d0b2 100644 --- a/packages/dart/lib/src/objects/parse_function.dart +++ b/packages/dart/lib/src/objects/parse_function.dart @@ -27,18 +27,27 @@ class ParseCloudFunction extends ParseObject { /// Executes a cloud function /// /// To add the parameters, create an object and call [set](value to set) - Future execute( - {Map? parameters, Map? headers}) async { + Future execute({ + Map? parameters, + Map? headers, + }) async { final String uri = '${ParseCoreData().serverUrl}$_path'; if (parameters != null) { _setObjectData(parameters); } try { - final ParseNetworkResponse result = await _client.post(uri, - options: ParseNetworkOptions(headers: headers), - data: json.encode(_getObjectData())); + final ParseNetworkResponse result = await _client.post( + uri, + options: ParseNetworkOptions(headers: headers), + data: json.encode(_getObjectData()), + ); return handleResponse( - this, result, ParseApiRQ.execute, _debug, parseClassName); + this, + result, + ParseApiRQ.execute, + _debug, + parseClassName, + ); } on Exception catch (e) { return handleException(e, ParseApiRQ.execute, _debug, parseClassName); } @@ -47,21 +56,34 @@ class ParseCloudFunction extends ParseObject { /// Executes a cloud function that returns a ParseObject type /// /// To add the parameters, create an object and call [set](value to set) - Future executeObjectFunction( - {Map? parameters, Map? headers}) async { + Future executeObjectFunction({ + Map? parameters, + Map? headers, + }) async { final String uri = '${ParseCoreData().serverUrl}$_path'; if (parameters != null) { _setObjectData(parameters); } try { - final ParseNetworkResponse result = await _client.post(uri, - options: ParseNetworkOptions(headers: headers), - data: json.encode(_getObjectData())); - return handleResponse(this, result, - ParseApiRQ.executeObjectionFunction, _debug, parseClassName); + final ParseNetworkResponse result = await _client.post( + uri, + options: ParseNetworkOptions(headers: headers), + data: json.encode(_getObjectData()), + ); + return handleResponse( + this, + result, + ParseApiRQ.executeObjectionFunction, + _debug, + parseClassName, + ); } on Exception catch (e) { return handleException( - e, ParseApiRQ.executeObjectionFunction, _debug, parseClassName); + e, + ParseApiRQ.executeObjectionFunction, + _debug, + parseClassName, + ); } } } diff --git a/packages/dart/lib/src/objects/parse_geo_point.dart b/packages/dart/lib/src/objects/parse_geo_point.dart index f1a89193..cdc36b97 100644 --- a/packages/dart/lib/src/objects/parse_geo_point.dart +++ b/packages/dart/lib/src/objects/parse_geo_point.dart @@ -9,11 +9,17 @@ class ParseGeoPoint { : assert( latitude < 90, 'Latitude must be within the range (-90.0, 90.0).'), assert( - latitude > -90, 'Latitude must be within the range (-90.0, 90.0).'), - assert(latitude < 180, - 'Longitude must be within the range (-180.0, 180.0).'), - assert(latitude > -180, - 'Longitude must be within the range (-180.0, 180.0).'); + latitude > -90, + 'Latitude must be within the range (-90.0, 90.0).', + ), + assert( + latitude < 180, + 'Longitude must be within the range (-180.0, 180.0).', + ), + assert( + latitude > -180, + 'Longitude must be within the range (-180.0, 180.0).', + ); double latitude, longitude; @@ -21,7 +27,7 @@ class ParseGeoPoint { { '__type': 'GeoPoint', 'latitude': latitude, - 'longitude': longitude + 'longitude': longitude, }; @override diff --git a/packages/dart/lib/src/objects/parse_installation.dart b/packages/dart/lib/src/objects/parse_installation.dart index 5f4c01c3..84e5840a 100644 --- a/packages/dart/lib/src/objects/parse_installation.dart +++ b/packages/dart/lib/src/objects/parse_installation.dart @@ -2,11 +2,8 @@ part of '../../parse_server_sdk.dart'; class ParseInstallation extends ParseObject { /// Creates an instance of ParseInstallation - ParseInstallation({ - bool? debug, - ParseClient? client, - bool? autoSendSessionId, - }) : super( + ParseInstallation({bool? debug, ParseClient? client, bool? autoSendSessionId}) + : super( keyClassInstallation, client: client, autoSendSessionId: autoSendSessionId, @@ -22,13 +19,15 @@ class ParseInstallation extends ParseObject { keyAppName, keyAppVersion, keyAppIdentifier, - keyParseVersion + keyParseVersion, ]; static String? _currentInstallationId; //Getters/setters - Map get acl => super - .get>(keyVarAcl, defaultValue: {})!; + Map get acl => super.get>( + keyVarAcl, + defaultValue: {}, + )!; set acl(Map acl) => set>(keyVarAcl, acl); @@ -113,15 +112,18 @@ class ParseInstallation extends ParseObject { } @override - Future create( - {bool allowCustomObjectId = false, dynamic context}) async { + Future create({ + bool allowCustomObjectId = false, + dynamic context, + }) async { final bool isCurrent = await ParseInstallation.isCurrent(this); if (isCurrent) { await _updateInstallation(); } - final ParseResponse parseResponse = - await _create(allowCustomObjectId: allowCustomObjectId); + final ParseResponse parseResponse = await _create( + allowCustomObjectId: allowCustomObjectId, + ); if (parseResponse.success && isCurrent) { clearUnsavedChanges(); await saveInStorage(keyParseStoreInstallation); @@ -149,12 +151,14 @@ class ParseInstallation extends ParseObject { static Future _getFromLocalStore() async { final CoreStore coreStore = ParseCoreData().getStore(); - final String? installationJson = - await coreStore.getString(keyParseStoreInstallation); + final String? installationJson = await coreStore.getString( + keyParseStoreInstallation, + ); if (installationJson != null) { - final Map? installationMap = - json.decode(installationJson); + final Map? installationMap = json.decode( + installationJson, + ); if (installationMap != null) { return ParseInstallation()..fromJson(installationMap); @@ -173,8 +177,10 @@ class ParseInstallation extends ParseObject { final ParseInstallation installation = ParseInstallation(); installation._installationId = _currentInstallationId; await installation._updateInstallation(); - await ParseCoreData().getStore().setString(keyParseStoreInstallation, - json.encode(installation.toJson(full: true))); + await ParseCoreData().getStore().setString( + keyParseStoreInstallation, + json.encode(installation.toJson(full: true)), + ); return installation; } @@ -183,20 +189,27 @@ class ParseInstallation extends ParseObject { try { final String uri = '${ParseCoreData().serverUrl}$keyEndPointInstallations'; - final String body = json.encode(toJson( - forApiRQ: true, - allowCustomObjectId: allowCustomObjectId, - )); + final String body = json.encode( + toJson(forApiRQ: true, allowCustomObjectId: allowCustomObjectId), + ); final Map headers = { - keyHeaderContentType: keyHeaderContentTypeJson + keyHeaderContentType: keyHeaderContentTypeJson, }; if (_debug) { - logRequest(ParseCoreData().appName, parseClassName, - ParseApiRQ.create.toString(), uri, body); + logRequest( + ParseCoreData().appName, + parseClassName, + ParseApiRQ.create.toString(), + uri, + body, + ); } - final ParseNetworkResponse result = await _client.post(uri, - data: body, options: ParseNetworkOptions(headers: headers)); + final ParseNetworkResponse result = await _client.post( + uri, + data: body, + options: ParseNetworkOptions(headers: headers), + ); //Set the objectId on the object after it is created. //This allows you to perform operations on the object after creation @@ -206,7 +219,12 @@ class ParseInstallation extends ParseObject { } return handleResponse( - this, result, ParseApiRQ.create, _debug, parseClassName); + this, + result, + ParseApiRQ.create, + _debug, + parseClassName, + ); } on Exception catch (e) { return handleException(e, ParseApiRQ.create, _debug, parseClassName); } @@ -222,12 +240,22 @@ class ParseInstallation extends ParseObject { '${ParseCoreData().serverUrl}$keyEndPointInstallations/$objectId'; final String body = json.encode(toJson(forApiRQ: true)); if (_debug) { - logRequest(ParseCoreData().appName, parseClassName, - ParseApiRQ.save.toString(), uri, body); + logRequest( + ParseCoreData().appName, + parseClassName, + ParseApiRQ.save.toString(), + uri, + body, + ); } final ParseNetworkResponse result = await _client.put(uri, data: body); return handleResponse( - this, result, ParseApiRQ.save, _debug, parseClassName); + this, + result, + ParseApiRQ.save, + _debug, + parseClassName, + ); } on Exception catch (e) { return handleException(e, ParseApiRQ.save, _debug, parseClassName); } @@ -251,13 +279,15 @@ class ParseInstallation extends ParseObject { ///Returns an > containing all the channel names this device is subscribed to. Future> getSubscribedChannels() async { print('getSubscribedChannels'); - final ParseResponse apiResponse = - await ParseObject(keyClassInstallation).getObject(objectId!); + final ParseResponse apiResponse = await ParseObject( + keyClassInstallation, + ).getObject(objectId!); if (apiResponse.success) { final ParseObject installation = apiResponse.result; - return Future>.value(installation - .get>('channels', defaultValue: [])); + return Future>.value( + installation.get>('channels', defaultValue: []), + ); } else { return []; } diff --git a/packages/dart/lib/src/objects/parse_number.dart b/packages/dart/lib/src/objects/parse_number.dart index 02b8b66f..f97165e4 100644 --- a/packages/dart/lib/src/objects/parse_number.dart +++ b/packages/dart/lib/src/objects/parse_number.dart @@ -36,7 +36,7 @@ class _ParseNumber implements _Valuable, _ParseSaveStateAwareChild { 'estimateNumber': estimateNumber, 'savedNumber': _savedNumber, 'setMode': setMode, - 'lastPreformedOperation': lastPreformedOperation?.toJson(full: full) + 'lastPreformedOperation': lastPreformedOperation?.toJson(full: full), }; } diff --git a/packages/dart/lib/src/objects/parse_object.dart b/packages/dart/lib/src/objects/parse_object.dart index 3af65c45..7252be52 100644 --- a/packages/dart/lib/src/objects/parse_object.dart +++ b/packages/dart/lib/src/objects/parse_object.dart @@ -30,9 +30,9 @@ class ParseObject extends ParseBase implements ParseCloneable { _debug = isDebugEnabled(objectLevelDebug: debug); _client = client ?? ParseCoreData().clientCreator( - sendSessionId: - autoSendSessionId ?? ParseCoreData().autoSendSessionId, - securityContext: ParseCoreData().securityContext); + sendSessionId: autoSendSessionId ?? ParseCoreData().autoSendSessionId, + securityContext: ParseCoreData().securityContext, + ); } ParseObject.clone(String className) : this(className); @@ -60,12 +60,20 @@ class ParseObject extends ParseBase implements ParseCloneable { query = 'include=${concatenateArray(include)}'; } - final Uri url = - getSanitisedUri(_client, '$_path/$objectId', query: query); + final Uri url = getSanitisedUri( + _client, + '$_path/$objectId', + query: query, + ); final ParseNetworkResponse result = await _client.get(url.toString()); return handleResponse( - this, result, ParseApiRQ.get, _debug, parseClassName); + this, + result, + ParseApiRQ.get, + _debug, + parseClassName, + ); } on Exception catch (e) { return handleException(e, ParseApiRQ.get, _debug, parseClassName); } @@ -77,7 +85,12 @@ class ParseObject extends ParseBase implements ParseCloneable { final Uri url = getSanitisedUri(_client, _path); final ParseNetworkResponse result = await _client.get(url.toString()); return handleResponse( - this, result, ParseApiRQ.getAll, _debug, parseClassName); + this, + result, + ParseApiRQ.getAll, + _debug, + parseClassName, + ); } on Exception catch (e) { return handleException(e, ParseApiRQ.getAll, _debug, parseClassName); } @@ -86,14 +99,15 @@ class ParseObject extends ParseBase implements ParseCloneable { /// Creates a new object and saves it online /// /// Prefer using [save] over [create] - Future create( - {bool allowCustomObjectId = false, dynamic context}) async { + Future create({ + bool allowCustomObjectId = false, + dynamic context, + }) async { try { final Uri url = getSanitisedUri(_client, _path); - final String body = json.encode(toJson( - forApiRQ: true, - allowCustomObjectId: allowCustomObjectId, - )); + final String body = json.encode( + toJson(forApiRQ: true, allowCustomObjectId: allowCustomObjectId), + ); _saveChanges(); @@ -102,15 +116,24 @@ class ParseObject extends ParseBase implements ParseCloneable { }; if (context != null) { - headers - .addAll({keyHeaderCloudContext: json.encode(parseEncode(context))}); + headers.addAll({ + keyHeaderCloudContext: json.encode(parseEncode(context)), + }); } - final ParseNetworkResponse result = await _client.post(url.toString(), - data: body, options: ParseNetworkOptions(headers: headers)); + final ParseNetworkResponse result = await _client.post( + url.toString(), + data: body, + options: ParseNetworkOptions(headers: headers), + ); final response = handleResponse( - this, result, ParseApiRQ.create, _debug, parseClassName); + this, + result, + ParseApiRQ.create, + _debug, + parseClassName, + ); if (!response.success) { _notifyChildrenAboutErrorSaving(); @@ -147,15 +170,24 @@ class ParseObject extends ParseBase implements ParseCloneable { }; if (context != null) { - headers - .addAll({keyHeaderCloudContext: json.encode(parseEncode(context))}); + headers.addAll({ + keyHeaderCloudContext: json.encode(parseEncode(context)), + }); } - final ParseNetworkResponse result = await _client.put(url.toString(), - data: body, options: ParseNetworkOptions(headers: headers)); + final ParseNetworkResponse result = await _client.put( + url.toString(), + data: body, + options: ParseNetworkOptions(headers: headers), + ); final response = handleResponse( - this, result, ParseApiRQ.save, _debug, parseClassName); + this, + result, + ParseApiRQ.save, + _debug, + parseClassName, + ); if (!response.success) { _notifyChildrenAboutErrorSaving(); @@ -245,7 +277,12 @@ class ParseObject extends ParseBase implements ParseCloneable { final Set uniqueObjects = {}; final Set uniqueFiles = {}; if (!_collectionDirtyChildren( - object, uniqueObjects, uniqueFiles, {}, {})) { + object, + uniqueObjects, + uniqueFiles, + {}, + {}, + )) { final ParseResponse response = ParseResponse(); return response; } @@ -362,7 +399,7 @@ class ParseObject extends ParseBase implements ParseCloneable { final dynamic request = { 'method': method, 'path': '$parsePath$_path${objectId != null ? '/$objectId' : ''}', - 'body': toJson(forApiRQ: true) + 'body': toJson(forApiRQ: true), }; return request; } @@ -406,33 +443,54 @@ class ParseObject extends ParseBase implements ParseCloneable { } static bool _collectionDirtyChildren( - dynamic object, - Set uniqueObjects, - Set uniqueFiles, - Set seen, - Set seenNew) { + dynamic object, + Set uniqueObjects, + Set uniqueFiles, + Set seen, + Set seenNew, + ) { if (object is Iterable) { for (dynamic child in object) { if (!_collectionDirtyChildren( - child, uniqueObjects, uniqueFiles, seen, seenNew)) { + child, + uniqueObjects, + uniqueFiles, + seen, + seenNew, + )) { return false; } } } else if (object is Map) { for (dynamic child in object.values) { if (!_collectionDirtyChildren( - child, uniqueObjects, uniqueFiles, seen, seenNew)) { + child, + uniqueObjects, + uniqueFiles, + seen, + seenNew, + )) { return false; } } } else if (object is _Valuable) { if (!_collectionDirtyChildren( - object.getValue(), uniqueObjects, uniqueFiles, seen, seenNew)) { + object.getValue(), + uniqueObjects, + uniqueFiles, + seen, + seenNew, + )) { return false; } } else if (object is _ParseRelation) { - if (!_collectionDirtyChildren(object.valueForApiRequest(), uniqueObjects, - uniqueFiles, seen, seenNew)) { + if (!_collectionDirtyChildren( + object.valueForApiRequest(), + uniqueObjects, + uniqueFiles, + seen, + seenNew, + )) { return false; } } else if (object is ParseACL) { @@ -463,7 +521,12 @@ class ParseObject extends ParseBase implements ParseCloneable { seen.add(object); if (!_collectionDirtyChildren( - object._getObjectData(), uniqueObjects, uniqueFiles, seen, seenNew)) { + object._getObjectData(), + uniqueObjects, + uniqueFiles, + seen, + seenNew, + )) { return false; } @@ -525,8 +588,9 @@ class ParseObject extends ParseBase implements ParseCloneable { } throw ParseRelationException( - 'The key $key is associated with a value ($potentialRelation) ' - 'can not be a relation'); + 'The key $key is associated with a value ($potentialRelation) ' + 'can not be a relation', + ); } /// Remove every instance of an [element] from an array @@ -608,11 +672,18 @@ class ParseObject extends ParseBase implements ParseCloneable { final String body = '{"$key":{"__op":"Delete"}}'; - final ParseNetworkResponse result = - await _client.put(url.toString(), data: body); + final ParseNetworkResponse result = await _client.put( + url.toString(), + data: body, + ); final ParseResponse response = handleResponse( - this, result, ParseApiRQ.unset, _debug, parseClassName); + this, + result, + ParseApiRQ.unset, + _debug, + parseClassName, + ); if (response.success) { return ParseResponse()..success = true; @@ -633,8 +704,10 @@ class ParseObject extends ParseBase implements ParseCloneable { } /// Can be used to create custom queries - Future query(String query, - {ProgressCallback? progressCallback}) async { + Future query( + String query, { + ProgressCallback? progressCallback, + }) async { try { final Uri url = getSanitisedUri(_client, _path, query: query); final ParseNetworkResponse result = await _client.get( @@ -642,7 +715,12 @@ class ParseObject extends ParseBase implements ParseCloneable { onReceiveProgress: progressCallback, ); return handleResponse( - this, result, ParseApiRQ.query, _debug, parseClassName); + this, + result, + ParseApiRQ.query, + _debug, + parseClassName, + ); } on Exception catch (e) { return handleException(e, ParseApiRQ.query, _debug, parseClassName); } @@ -653,7 +731,12 @@ class ParseObject extends ParseBase implements ParseCloneable { final Uri url = getSanitisedUri(_client, _aggregatepath, query: query); final ParseNetworkResponse result = await _client.get(url.toString()); return handleResponse( - this, result, ParseApiRQ.query, _debug, parseClassName); + this, + result, + ParseApiRQ.query, + _debug, + parseClassName, + ); } on Exception catch (e) { return handleException(e, ParseApiRQ.query, _debug, parseClassName); } @@ -711,7 +794,12 @@ class ParseObject extends ParseBase implements ParseCloneable { final Uri url = getSanitisedUri(_client, '$_path/$id'); final ParseNetworkResponse result = await _client.delete(url.toString()); return handleResponse( - this, result, ParseApiRQ.delete, _debug, parseClassName); + this, + result, + ParseApiRQ.delete, + _debug, + parseClassName, + ); } on Exception catch (e) { return handleException(e, ParseApiRQ.delete, _debug, parseClassName); } @@ -738,45 +826,57 @@ class ParseObject extends ParseBase implements ParseCloneable { } } - static Future submitEventually( - {ParseClient? client, bool? autoSendSessionId}) async { + static Future submitEventually({ + ParseClient? client, + bool? autoSendSessionId, + }) async { await submitSaveEventually( - client: client, autoSendSessionId: autoSendSessionId); + client: client, + autoSendSessionId: autoSendSessionId, + ); await submitDeleteEventually( - client: client, autoSendSessionId: autoSendSessionId); + client: client, + autoSendSessionId: autoSendSessionId, + ); Parse.objectsExistForEventually = await checkObjectsExistForEventually(); } - static Future submitSaveEventually( - {ParseClient? client, bool? autoSendSessionId}) async { + static Future submitSaveEventually({ + ParseClient? client, + bool? autoSendSessionId, + }) async { // get client ParseClient localClient = client ?? ParseCoreData().clientCreator( - sendSessionId: - autoSendSessionId ?? ParseCoreData().autoSendSessionId, - securityContext: ParseCoreData().securityContext); + sendSessionId: autoSendSessionId ?? ParseCoreData().autoSendSessionId, + securityContext: ParseCoreData().securityContext, + ); // preparation ParseCoreData final CoreStore coreStore = ParseCoreData().getStore(); // save // get json parse saved objects - List? listSaves = - await coreStore.getStringList(keyParseStoreObjects); + List? listSaves = await coreStore.getStringList( + keyParseStoreObjects, + ); if (listSaves != null) { List parseObjectList = []; for (var element in listSaves) { // decode json dynamic object = json.decode(element); - parseObjectList - .add(ParseObject(object[keyVarClassName]).fromJson(object)); + parseObjectList.add( + ParseObject(object[keyVarClassName]).fromJson(object), + ); } // send parseObjects to server - ParseResponse response = - await ParseObject._saveChildren(parseObjectList, localClient); + ParseResponse response = await ParseObject._saveChildren( + parseObjectList, + localClient, + ); // if success clear all objects if (response.success) { @@ -789,15 +889,18 @@ class ParseObject extends ParseBase implements ParseCloneable { return null; } - static Future submitDeleteEventually( - {ParseClient? client, bool? autoSendSessionId}) async { + static Future submitDeleteEventually({ + ParseClient? client, + bool? autoSendSessionId, + }) async { // preparation ParseCoreData final CoreStore coreStore = ParseCoreData().getStore(); // delete // get json parse saved objects - List? listDeletes = - await coreStore.getStringList(keyParseStoreDeletes); + List? listDeletes = await coreStore.getStringList( + keyParseStoreDeletes, + ); if (listDeletes != null) { int firstLength = listDeletes.length; @@ -807,9 +910,11 @@ class ParseObject extends ParseBase implements ParseCloneable { dynamic object = json.decode(element); // crate parse object - ParseObject parseObject = ParseObject(object[keyVarClassName], - client: client, autoSendSessionId: autoSendSessionId) - .fromJson(object); + ParseObject parseObject = ParseObject( + object[keyVarClassName], + client: client, + autoSendSessionId: autoSendSessionId, + ).fromJson(object); // delete parse object ParseResponse deleteResponse = await parseObject.delete(); diff --git a/packages/dart/lib/src/objects/parse_operation/parse_add_relation_operation.dart b/packages/dart/lib/src/objects/parse_operation/parse_add_relation_operation.dart index 2eaa1b5d..1a63e553 100644 --- a/packages/dart/lib/src/objects/parse_operation/parse_add_relation_operation.dart +++ b/packages/dart/lib/src/objects/parse_operation/parse_add_relation_operation.dart @@ -32,8 +32,9 @@ class _ParseAddRelationOperation extends _ParseRelationOperation { value = Set.from(removeDuplicateParseObjectByObjectId(value)); - valueForApiRequest = - Set.from(removeDuplicateParseObjectByObjectId(valueForApiRequest)); + valueForApiRequest = Set.from( + removeDuplicateParseObjectByObjectId(valueForApiRequest), + ); return this; } diff --git a/packages/dart/lib/src/objects/parse_operation/parse_add_unique_operation.dart b/packages/dart/lib/src/objects/parse_operation/parse_add_unique_operation.dart index ac606686..ee0c9785 100644 --- a/packages/dart/lib/src/objects/parse_operation/parse_add_unique_operation.dart +++ b/packages/dart/lib/src/objects/parse_operation/parse_add_unique_operation.dart @@ -44,8 +44,9 @@ class _ParseAddUniqueOperation extends _ParseArrayOperation { value = removeDuplicateParseObjectByObjectId(value); - valueForApiRequest = - removeDuplicateParseObjectByObjectId(valueForApiRequest); + valueForApiRequest = removeDuplicateParseObjectByObjectId( + valueForApiRequest, + ); return this; } diff --git a/packages/dart/lib/src/objects/parse_operation/parse_operation.dart b/packages/dart/lib/src/objects/parse_operation/parse_operation.dart index f9e39b3c..fc5a512f 100644 --- a/packages/dart/lib/src/objects/parse_operation/parse_operation.dart +++ b/packages/dart/lib/src/objects/parse_operation/parse_operation.dart @@ -112,7 +112,8 @@ abstract class _ParseOperation implements _Valuable { } throw ParseOperationException( - 'operation ${newValue.runtimeType} not implemented'); + 'operation ${newValue.runtimeType} not implemented', + ); } static _ParseNumber _handelNumOperation( @@ -128,8 +129,9 @@ abstract class _ParseOperation implements _Valuable { } throw ParseOperationException( - 'wrong key, unable to preform numeric operation on' - ' the previous value: ${previousValue.runtimeType}'); + 'wrong key, unable to preform numeric operation on' + ' the previous value: ${previousValue.runtimeType}', + ); } static _ParseArray _handelArrayOperation( @@ -145,8 +147,9 @@ abstract class _ParseOperation implements _Valuable { } throw ParseOperationException( - 'wrong key, unable to preform Array operation on' - ' the previous value: ${previousValue.runtimeType}'); + 'wrong key, unable to preform Array operation on' + ' the previous value: ${previousValue.runtimeType}', + ); } static _ParseRelation _handelRelationOperation( @@ -160,13 +163,16 @@ abstract class _ParseOperation implements _Valuable { } if (previousValue == null) { - return _ParseRelation(parent: parent, key: key) - .preformRelationOperation(relationOperation); + return _ParseRelation( + parent: parent, + key: key, + ).preformRelationOperation(relationOperation); } throw ParseOperationException( - 'wrong key, unable to preform Relation operation on' - ' the previous value: ${previousValue.runtimeType}'); + 'wrong key, unable to preform Relation operation on' + ' the previous value: ${previousValue.runtimeType}', + ); } /// Returns the estimated value of this operation. @@ -234,8 +240,9 @@ abstract class _ParseRelationOperation } static _ParseRelationOperation? fromFullJson(Map json) { - final Set objects = - Set.from(parseDecode(json['objects']) ?? {}); + final Set objects = Set.from( + parseDecode(json['objects']) ?? {}, + ); final Set? objectsForAPIRequest = json['valueForAPIRequest'] == null @@ -271,7 +278,7 @@ abstract class _ParseRelationOperation } return { '__op': operationName, - 'objects': parseEncode(valueForApiRequest, full: full) + 'objects': parseEncode(valueForApiRequest, full: full), }; } } @@ -287,7 +294,7 @@ abstract class _ParseNumberOperation extends _ParseOperation { return { '__op': operationName, 'amount': valueForApiRequest, - 'estimatedValue': value + 'estimatedValue': value, }; } diff --git a/packages/dart/lib/src/objects/parse_operation/parse_remove_relation_operation.dart b/packages/dart/lib/src/objects/parse_operation/parse_remove_relation_operation.dart index 5985d350..7ef202b7 100644 --- a/packages/dart/lib/src/objects/parse_operation/parse_remove_relation_operation.dart +++ b/packages/dart/lib/src/objects/parse_operation/parse_remove_relation_operation.dart @@ -32,13 +32,16 @@ class _ParseRemoveRelationOperation extends _ParseRelationOperation { value.where((e) => e.objectId != null).map((e) => e.objectId!); value = previousValue - ..removeWhere((e) => - value.contains(e) || parseObjectToRemoveByIds.contains(e.objectId)); + ..removeWhere( + (e) => + value.contains(e) || parseObjectToRemoveByIds.contains(e.objectId), + ); value = Set.from(removeDuplicateParseObjectByObjectId(value)); - valueForApiRequest = - Set.from(removeDuplicateParseObjectByObjectId(valueForApiRequest)); + valueForApiRequest = Set.from( + removeDuplicateParseObjectByObjectId(valueForApiRequest), + ); return this; } diff --git a/packages/dart/lib/src/objects/parse_relation.dart b/packages/dart/lib/src/objects/parse_relation.dart index 3be59616..12f0c3d6 100644 --- a/packages/dart/lib/src/objects/parse_relation.dart +++ b/packages/dart/lib/src/objects/parse_relation.dart @@ -7,10 +7,7 @@ abstract class ParseRelation { //The key of the relation in the parent object. i.e. the column name String getKey(); - factory ParseRelation({ - required ParseObject parent, - required String key, - }) { + factory ParseRelation({required ParseObject parent, required String key}) { return _ParseRelation(parent: parent, key: key); } @@ -105,7 +102,8 @@ class _ParseRelation if (parentObjectId == null) { throw ParseRelationException( - 'The parent objectId is null. Query based on a Relation require ObjectId'); + 'The parent objectId is null. Query based on a Relation require ObjectId', + ); } final QueryBuilder queryBuilder; @@ -156,7 +154,8 @@ class _ParseRelation if (_targetClass != targetClass) { throw ParseRelationException( - 'The target class can not be modified if it is already set'); + 'The target class can not be modified if it is already set', + ); } } @@ -194,7 +193,7 @@ class _ParseRelation 'targetClass': targetClass, 'key': key, 'objects': parseEncode(knownObjects, full: full), - 'lastPreformedOperation': lastPreformedOperation?.toJson(full: full) + 'lastPreformedOperation': lastPreformedOperation?.toJson(full: full), }; } @@ -213,8 +212,9 @@ class _ParseRelation if (_targetClass != null && potentialTargetClass != _targetClass) { throw ParseRelationException( - 'Can not add more then one class for a relation. the current target ' - 'class $targetClass and the passed class $potentialTargetClass'); + 'Can not add more then one class for a relation. the current target ' + 'class $targetClass and the passed class $potentialTargetClass', + ); } } @@ -231,8 +231,9 @@ class _ParseRelation lastPreformedOperation = null; } else { // remove the saved objects and keep the new added objects while saving - lastPreformedOperation?.valueForApiRequest - .removeAll(_valueForApiRequestBeforeSaving ?? []); + lastPreformedOperation?.valueForApiRequest.removeAll( + _valueForApiRequestBeforeSaving ?? [], + ); } _lastPreformedOperationBeforeSaving = null; diff --git a/packages/dart/lib/src/objects/parse_response.dart b/packages/dart/lib/src/objects/parse_response.dart index ad1c21bd..1f49e605 100644 --- a/packages/dart/lib/src/objects/parse_response.dart +++ b/packages/dart/lib/src/objects/parse_response.dart @@ -1,9 +1,7 @@ part of '../../parse_server_sdk.dart'; class ParseResponse { - ParseResponse({ - this.error, - }); + ParseResponse({this.error}); bool success = false; int statusCode = -1; diff --git a/packages/dart/lib/src/objects/parse_session.dart b/packages/dart/lib/src/objects/parse_session.dart index 9f98ab1b..e07700a7 100644 --- a/packages/dart/lib/src/objects/parse_session.dart +++ b/packages/dart/lib/src/objects/parse_session.dart @@ -1,14 +1,8 @@ part of '../../parse_server_sdk.dart'; class ParseSession extends ParseObject implements ParseCloneable { - ParseSession({ - bool? debug, - ParseClient? client, - }) : super( - keyClassSession, - client: client, - debug: debug, - ); + ParseSession({bool? debug, ParseClient? client}) + : super(keyClassSession, client: client, debug: debug); @override ParseSession clone(Map map) { @@ -39,7 +33,12 @@ class ParseSession extends ParseObject implements ParseCloneable { final ParseNetworkResponse response = await _client.get(url.toString()); return handleResponse( - this, response, ParseApiRQ.logout, _debug, parseClassName); + this, + response, + ParseApiRQ.logout, + _debug, + parseClassName, + ); } on Exception catch (e) { return handleException(e, ParseApiRQ.logout, _debug, parseClassName); } diff --git a/packages/dart/lib/src/objects/parse_user.dart b/packages/dart/lib/src/objects/parse_user.dart index eb91a9cb..f8cb1922 100644 --- a/packages/dart/lib/src/objects/parse_user.dart +++ b/packages/dart/lib/src/objects/parse_user.dart @@ -55,8 +55,10 @@ class ParseUser extends ParseObject implements ParseCloneable { } } - Map get acl => super - .get>(keyVarAcl, defaultValue: {})!; + Map get acl => super.get>( + keyVarAcl, + defaultValue: {}, + )!; set acl(Map acl) => set>(keyVarAcl, acl); @@ -86,10 +88,16 @@ class ParseUser extends ParseObject implements ParseCloneable { set authData(Map? authData) => set?>(keyVarAuthData, authData); - static ParseUser createUser( - [String? username, String? password, String? emailAddress]) { - return ParseCoreData.instance - .createParseUser(username, password, emailAddress); + static ParseUser createUser([ + String? username, + String? password, + String? emailAddress, + ]) { + return ParseCoreData.instance.createParseUser( + username, + password, + emailAddress, + ); } /// Gets the current user from the server @@ -99,8 +107,11 @@ class ParseUser extends ParseObject implements ParseCloneable { /// returned. /// /// NOTE: If using custom ParseUserObject create instance and user [getUpdatedUser] - static Future getCurrentUserFromServer(String token, - {bool? debug, ParseClient? client}) async { + static Future getCurrentUserFromServer( + String token, { + bool? debug, + ParseClient? client, + }) async { final ParseUser user = _getEmptyUser(); user.sessionToken = token; return user.getUpdatedUser(debug: debug, client: client); @@ -110,13 +121,16 @@ class ParseUser extends ParseObject implements ParseCloneable { /// /// Uses token to get the latest version of the user. Prefer this to [getCurrentUserFromServer] /// if using custom ParseUser object - Future getUpdatedUser( - {bool? debug, ParseClient? client}) async { + Future getUpdatedUser({ + bool? debug, + ParseClient? client, + }) async { final bool debugLocal = isDebugEnabled(objectLevelDebug: debug); final ParseClient clientLocal = client ?? ParseCoreData().clientCreator( - sendSessionId: true, - securityContext: ParseCoreData().securityContext); + sendSessionId: true, + securityContext: ParseCoreData().securityContext, + ); // We can't get the current user and session without a sessionId if ((ParseCoreData().sessionId == null) && (sessionToken == null)) { @@ -136,10 +150,19 @@ class ParseUser extends ParseObject implements ParseCloneable { options: ParseNetworkOptions(headers: headers), ); return await _handleResponse( - this, response, ParseApiRQ.currentUser, debugLocal, parseClassName); + this, + response, + ParseApiRQ.currentUser, + debugLocal, + parseClassName, + ); } on Exception catch (e) { return handleException( - e, ParseApiRQ.currentUser, debugLocal, parseClassName); + e, + ParseApiRQ.currentUser, + debugLocal, + parseClassName, + ); } } @@ -163,9 +186,10 @@ class ParseUser extends ParseObject implements ParseCloneable { /// By setting [allowWithoutEmail] to `true`, you can sign up without setting an email /// Set [doNotSendInstallationID] to 'true' in order to prevent the SDK from sending the installationID to the Server. /// This option is especially useful if you are running you application on web and you don't have permission to add 'X-Parse-Installation-Id' as an allowed header on your parse-server. - Future signUp( - {bool allowWithoutEmail = false, - bool doNotSendInstallationID = false}) async { + Future signUp({ + bool allowWithoutEmail = false, + bool doNotSendInstallationID = false, + }) async { forgetLocalSession(); try { @@ -173,14 +197,16 @@ class ParseUser extends ParseObject implements ParseCloneable { if (!allowWithoutEmail) { assert(() { print( - '`ParseUser().signUp()` failed, because the email is not set. If you want to allow signUp without a set email, you should run `ParseUser().signUp(allowWithoutEmail = true)`'); + '`ParseUser().signUp()` failed, because the email is not set. If you want to allow signUp without a set email, you should run `ParseUser().signUp(allowWithoutEmail = true)`', + ); return true; }()); throw '`signUp` failed, because `emailAddress` of ParseUser was not provided and `allowWithoutEmail` was `false`'; } else { assert(() { print( - 'It is recommended to only allow user signUp with an email set.'); + 'It is recommended to only allow user signUp with an email set.', + ); return true; }()); } @@ -190,16 +216,25 @@ class ParseUser extends ParseObject implements ParseCloneable { final String body = json.encode(toJson(forApiRQ: true)); _saveChanges(); final String? installationId = await _getInstallationId(); - final ParseNetworkResponse response = await _client.post(url.toString(), - options: ParseNetworkOptions(headers: { + final ParseNetworkResponse response = await _client.post( + url.toString(), + options: ParseNetworkOptions( + headers: { keyHeaderRevocableSession: '1', if (installationId != null && !doNotSendInstallationID) keyHeaderInstallationId: installationId, - }), - data: body); + }, + ), + data: body, + ); return await _handleResponse( - this, response, ParseApiRQ.signUp, _debug, parseClassName); + this, + response, + ParseApiRQ.signUp, + _debug, + parseClassName, + ); } on Exception catch (e) { return handleException(e, ParseApiRQ.signUp, _debug, parseClassName); } @@ -217,7 +252,7 @@ class ParseUser extends ParseObject implements ParseCloneable { try { final Map queryParams = { keyVarUsername: username!, - keyVarPassword: password! + keyVarPassword: password!, }; final String? installationId = await _getInstallationId(); final Uri url = getSanitisedUri(_client, keyEndPointLogin); @@ -225,15 +260,22 @@ class ParseUser extends ParseObject implements ParseCloneable { final ParseNetworkResponse response = await _client.post( url.toString(), data: jsonEncode(queryParams), - options: ParseNetworkOptions(headers: { - keyHeaderRevocableSession: '1', - if (installationId != null && !doNotSendInstallationID) - keyHeaderInstallationId: installationId, - }), + options: ParseNetworkOptions( + headers: { + keyHeaderRevocableSession: '1', + if (installationId != null && !doNotSendInstallationID) + keyHeaderInstallationId: installationId, + }, + ), ); return await _handleResponse( - this, response, ParseApiRQ.login, _debug, parseClassName); + this, + response, + ParseApiRQ.login, + _debug, + parseClassName, + ); } on Exception catch (e) { return handleException(e, ParseApiRQ.login, _debug, parseClassName); } @@ -242,8 +284,9 @@ class ParseUser extends ParseObject implements ParseCloneable { /// Logs in a user anonymously /// Set [doNotSendInstallationID] to 'true' in order to prevent the SDK from sending the installationID to the Server. /// This option is especially useful if you are running you application on web and you don't have permission to add 'X-Parse-Installation-Id' as an allowed header on your parse-server. - Future loginAnonymous( - {bool doNotSendInstallationID = false}) async { + Future loginAnonymous({ + bool doNotSendInstallationID = false, + }) async { forgetLocalSession(); try { final Uri url = getSanitisedUri(_client, keyEndPointUsers); @@ -252,44 +295,64 @@ class ParseUser extends ParseObject implements ParseCloneable { final ParseNetworkResponse response = await _client.post( url.toString(), - options: ParseNetworkOptions(headers: { - keyHeaderRevocableSession: '1', - if (installationId != null && !doNotSendInstallationID) - keyHeaderInstallationId: installationId, - }), + options: ParseNetworkOptions( + headers: { + keyHeaderRevocableSession: '1', + if (installationId != null && !doNotSendInstallationID) + keyHeaderInstallationId: installationId, + }, + ), data: jsonEncode({ 'authData': { - 'anonymous': {'id': uuid.v4()} - } + 'anonymous': {'id': uuid.v4()}, + }, }), ); return await _handleResponse( - this, response, ParseApiRQ.loginAnonymous, _debug, parseClassName); + this, + response, + ParseApiRQ.loginAnonymous, + _debug, + parseClassName, + ); } on Exception catch (e) { return handleException( - e, ParseApiRQ.loginAnonymous, _debug, parseClassName); + e, + ParseApiRQ.loginAnonymous, + _debug, + parseClassName, + ); } } /// Logs in a user using a service /// Set [doNotSendInstallationID] to 'true' in order to prevent the SDK from sending the installationID to the Server. /// This option is especially useful if you are running you application on web and you don't have permission to add 'X-Parse-Installation-Id' as an allowed header on your parse-server. - static Future loginWith(String provider, Object authData, - {bool doNotSendInstallationID = false, - String? username, - String? password, - String? email}) async { + static Future loginWith( + String provider, + Object authData, { + bool doNotSendInstallationID = false, + String? username, + String? password, + String? email, + }) async { final ParseUser user = ParseUser.createUser(username, password, email); - final ParseResponse response = await user._loginWith(provider, authData, - doNotSendInstallationID: doNotSendInstallationID); + final ParseResponse response = await user._loginWith( + provider, + authData, + doNotSendInstallationID: doNotSendInstallationID, + ); return response; } /// Set [doNotSendInstallationID] to 'true' in order to prevent the SDK from sending the installationID to the Server. /// This option is especially useful if you are running you application on web and you don't have permission to add 'X-Parse-Installation-Id' as an allowed header on your parse-server. - Future _loginWith(String provider, Object authData, - {bool doNotSendInstallationID = false}) async { + Future _loginWith( + String provider, + Object authData, { + bool doNotSendInstallationID = false, + }) async { try { final Uri url = getSanitisedUri(_client, keyEndPointUsers); final String? installationId = await _getInstallationId(); @@ -297,16 +360,23 @@ class ParseUser extends ParseObject implements ParseCloneable { body['authData'] = {provider: authData}; final ParseNetworkResponse response = await _client.post( url.toString(), - options: ParseNetworkOptions(headers: { - keyHeaderRevocableSession: '1', - if (installationId != null && !doNotSendInstallationID) - keyHeaderInstallationId: installationId, - }), + options: ParseNetworkOptions( + headers: { + keyHeaderRevocableSession: '1', + if (installationId != null && !doNotSendInstallationID) + keyHeaderInstallationId: installationId, + }, + ), data: jsonEncode(body), ); return await _handleResponse( - this, response, ParseApiRQ.loginWith, _debug, parseClassName); + this, + response, + ParseApiRQ.loginWith, + _debug, + parseClassName, + ); } on Exception catch (e) { return handleException(e, ParseApiRQ.loginWith, _debug, parseClassName); } @@ -320,11 +390,12 @@ class ParseUser extends ParseObject implements ParseCloneable { if (sessionId == null) { return await _handleResponse( - this, - ParseNetworkResponse(data: "{}", statusCode: 200), - ParseApiRQ.logout, - _debug, - parseClassName); + this, + ParseNetworkResponse(data: "{}", statusCode: 200), + ParseApiRQ.logout, + _debug, + parseClassName, + ); } forgetLocalSession(); @@ -338,11 +409,17 @@ class ParseUser extends ParseObject implements ParseCloneable { final ParseNetworkResponse response = await _client.post( url.toString(), options: ParseNetworkOptions( - headers: {keyHeaderSessionToken: sessionId}), + headers: {keyHeaderSessionToken: sessionId}, + ), ); return await _handleResponse( - this, response, ParseApiRQ.logout, _debug, parseClassName); + this, + response, + ParseApiRQ.logout, + _debug, + parseClassName, + ); } on Exception catch (e) { return handleException(e, ParseApiRQ.logout, _debug, parseClassName); } @@ -365,11 +442,20 @@ class ParseUser extends ParseObject implements ParseCloneable { '${ParseCoreData().serverUrl}$keyEndPointVerificationEmail', data: json.encode({keyVarEmail: emailAddress}), ); - return await _handleResponse(this, response, - ParseApiRQ.verificationEmailRequest, _debug, parseClassName); + return await _handleResponse( + this, + response, + ParseApiRQ.verificationEmailRequest, + _debug, + parseClassName, + ); } on Exception catch (e) { return handleException( - e, ParseApiRQ.verificationEmailRequest, _debug, parseClassName); + e, + ParseApiRQ.verificationEmailRequest, + _debug, + parseClassName, + ); } } @@ -380,11 +466,20 @@ class ParseUser extends ParseObject implements ParseCloneable { '${ParseCoreData().serverUrl}$keyEndPointRequestPasswordReset', data: json.encode({keyVarEmail: emailAddress}), ); - return await _handleResponse(this, response, - ParseApiRQ.requestPasswordReset, _debug, parseClassName); + return await _handleResponse( + this, + response, + ParseApiRQ.requestPasswordReset, + _debug, + parseClassName, + ); } on Exception catch (e) { return handleException( - e, ParseApiRQ.requestPasswordReset, _debug, parseClassName); + e, + ParseApiRQ.requestPasswordReset, + _debug, + parseClassName, + ); } } @@ -427,10 +522,16 @@ class ParseUser extends ParseObject implements ParseCloneable { if (objectId != null) { try { final Uri url = getSanitisedUri(_client, '$_path/$objectId'); - final ParseNetworkResponse response = - await _client.delete(url.toString()); + final ParseNetworkResponse response = await _client.delete( + url.toString(), + ); return await _handleResponse( - this, response, ParseApiRQ.destroy, _debug, parseClassName); + this, + response, + ParseApiRQ.destroy, + _debug, + parseClassName, + ); } on Exception catch (e) { return handleException(e, ParseApiRQ.destroy, _debug, parseClassName); } @@ -446,23 +547,31 @@ class ParseUser extends ParseObject implements ParseCloneable { final bool debugLocal = isDebugEnabled(objectLevelDebug: debug); final ParseClient clientLocal = client ?? ParseCoreData().clientCreator( - sendSessionId: true, - securityContext: ParseCoreData().securityContext); + sendSessionId: true, + securityContext: ParseCoreData().securityContext, + ); try { final Uri url = getSanitisedUri(clientLocal, path); - final ParseNetworkResponse response = - await clientLocal.get(url.toString()); + final ParseNetworkResponse response = await clientLocal.get( + url.toString(), + ); final ParseResponse parseResponse = handleResponse( - emptyUser, response, ParseApiRQ.getAll, debugLocal, keyClassUser); + emptyUser, + response, + ParseApiRQ.getAll, + debugLocal, + keyClassUser, + ); return parseResponse; } on Exception catch (e) { return handleException(e, ParseApiRQ.getAll, debugLocal, keyClassUser); } } - static Future _getUserFromLocalStore( - {ParseCloneable? cloneable}) async { + static Future _getUserFromLocalStore({ + ParseCloneable? cloneable, + }) async { final CoreStore coreStore = ParseCoreData().getStore(); final String? userJson = await coreStore.getString(keyParseStoreUser); @@ -483,13 +592,19 @@ class ParseUser extends ParseObject implements ParseCloneable { /// Handles all the response data for this class static Future _handleResponse( - ParseUser user, - ParseNetworkResponse response, - ParseApiRQ type, - bool debug, - String className) async { - final ParseResponse parseResponse = - handleResponse(user, response, type, debug, className); + ParseUser user, + ParseNetworkResponse response, + ParseApiRQ type, + bool debug, + String className, + ) async { + final ParseResponse parseResponse = handleResponse( + user, + response, + type, + debug, + className, + ); final Map responseData = jsonDecode(response.data); if (responseData.containsKey(keyParamSessionToken)) { diff --git a/packages/dart/lib/src/objects/parse_x_file.dart b/packages/dart/lib/src/objects/parse_x_file.dart index 2cc6e205..f6ac5ab1 100644 --- a/packages/dart/lib/src/objects/parse_x_file.dart +++ b/packages/dart/lib/src/objects/parse_x_file.dart @@ -98,8 +98,7 @@ class ParseXFile extends ParseFileBase { // If neither provides a type, let the server infer from the filename String? contentType; if (parseIsWeb) { - contentType = - file?.mimeType ?? + contentType = file?.mimeType ?? lookupMimeType( url ?? file?.name ?? name, headerBytes: await file?.readAsBytes(), diff --git a/packages/dart/lib/src/objects/response/parse_error_response.dart b/packages/dart/lib/src/objects/response/parse_error_response.dart index ef1ccb50..68f98d81 100644 --- a/packages/dart/lib/src/objects/response/parse_error_response.dart +++ b/packages/dart/lib/src/objects/response/parse_error_response.dart @@ -2,7 +2,9 @@ part of '../../../parse_server_sdk.dart'; /// Handles any errors returned in response ParseResponse buildErrorResponse( - ParseResponse response, ParseNetworkResponse apiResponse) { + ParseResponse response, + ParseNetworkResponse apiResponse, +) { final Map responseData = json.decode(apiResponse.data); response.error = ParseError( diff --git a/packages/dart/lib/src/objects/response/parse_exception_response.dart b/packages/dart/lib/src/objects/response/parse_exception_response.dart index fe66ae1b..c7f49df9 100644 --- a/packages/dart/lib/src/objects/response/parse_exception_response.dart +++ b/packages/dart/lib/src/objects/response/parse_exception_response.dart @@ -16,11 +16,12 @@ ParseResponse buildParseResponseWithException(Exception exception) { int.tryParse(codeString ?? '') ?? exception.response?.statusCode; return ParseResponse( - error: ParseError( - message: errorMessage ?? exception.toString(), - exception: exception, - code: errorCode ?? ParseError.otherCause, - )); + error: ParseError( + message: errorMessage ?? exception.toString(), + exception: exception, + code: errorCode ?? ParseError.otherCause, + ), + ); } if (exception is ClientException) { @@ -30,5 +31,6 @@ ParseResponse buildParseResponseWithException(Exception exception) { } return ParseResponse( - error: ParseError(message: exception.toString(), exception: exception)); + error: ParseError(message: exception.toString(), exception: exception), + ); } diff --git a/packages/dart/lib/src/objects/response/parse_response_builder.dart b/packages/dart/lib/src/objects/response/parse_response_builder.dart index 8390476e..d235ece3 100644 --- a/packages/dart/lib/src/objects/response/parse_response_builder.dart +++ b/packages/dart/lib/src/objects/response/parse_response_builder.dart @@ -9,7 +9,10 @@ part of '../../../parse_server_sdk.dart'; /// 4. Success with results. Again [ParseResponse()] is returned class _ParseResponseBuilder { ParseResponse handleResponse( - dynamic object, ParseNetworkResponse apiResponse, ParseApiRQ type) { + dynamic object, + ParseNetworkResponse apiResponse, + ParseApiRQ type, + ) { final ParseResponse parseResponse = ParseResponse(); final bool returnAsResult = shouldReturnAsABaseResult(type); parseResponse.statusCode = apiResponse.statusCode; @@ -21,10 +24,16 @@ class _ParseResponseBuilder { return parseResponse; } else if (isSuccessButNoResults(apiResponse)) { return buildSuccessResponseWithNoResults( - parseResponse, 1, 'Successful request, but no results found'); + parseResponse, + 1, + 'Successful request, but no results found', + ); } else if (returnAsResult) { return _handleSuccessWithoutParseObject( - parseResponse, object, apiResponse.data); + parseResponse, + object, + apiResponse.data, + ); } else { return _handleSuccess(parseResponse, object, apiResponse.data, type); } @@ -32,7 +41,10 @@ class _ParseResponseBuilder { /// Handles successful response without creating a ParseObject ParseResponse _handleSuccessWithoutParseObject( - ParseResponse response, dynamic object, String responseBody) { + ParseResponse response, + dynamic object, + String responseBody, + ) { response.success = true; if (responseBody == 'OK') { @@ -135,7 +147,10 @@ class _ParseResponseBuilder { /// Handles a response with a single result object T? _handleSingleResult( - T object, Map map, bool createNewObject) { + T object, + Map map, + bool createNewObject, + ) { if (createNewObject && object is ParseCloneable) { return object.clone(map); } else if (object is ParseObject) { diff --git a/packages/dart/lib/src/objects/response/parse_response_utils.dart b/packages/dart/lib/src/objects/response/parse_response_utils.dart index 81284926..618170dc 100644 --- a/packages/dart/lib/src/objects/response/parse_response_utils.dart +++ b/packages/dart/lib/src/objects/response/parse_response_utils.dart @@ -2,10 +2,18 @@ part of '../../../parse_server_sdk.dart'; /// Handles an API response and logs data if [bool] debug is enabled @protected -ParseResponse handleResponse(dynamic object, ParseNetworkResponse response, - ParseApiRQ type, bool debug, String className) { - final ParseResponse parseResponse = - _ParseResponseBuilder().handleResponse(object, response, type); +ParseResponse handleResponse( + dynamic object, + ParseNetworkResponse response, + ParseApiRQ type, + bool debug, + String className, +) { + final ParseResponse parseResponse = _ParseResponseBuilder().handleResponse( + object, + response, + type, + ); if (debug) { logAPIResponse(className, type.toString(), parseResponse); @@ -17,9 +25,14 @@ ParseResponse handleResponse(dynamic object, ParseNetworkResponse response, /// Handles an API response and logs data if [bool] debug is enabled @protected ParseResponse handleException( - Exception exception, ParseApiRQ type, bool debug, String className) { - final ParseResponse parseResponse = - buildParseResponseWithException(exception); + Exception exception, + ParseApiRQ type, + bool debug, + String className, +) { + final ParseResponse parseResponse = buildParseResponseWithException( + exception, + ); if (debug) { logAPIResponse(className, type.toString(), parseResponse); diff --git a/packages/dart/lib/src/objects/response/parse_success_no_results.dart b/packages/dart/lib/src/objects/response/parse_success_no_results.dart index 0383458b..d4a127ca 100644 --- a/packages/dart/lib/src/objects/response/parse_success_no_results.dart +++ b/packages/dart/lib/src/objects/response/parse_success_no_results.dart @@ -2,7 +2,10 @@ part of '../../../parse_server_sdk.dart'; /// Handles successful responses with no results ParseResponse buildSuccessResponseWithNoResults( - ParseResponse response, int code, String value) { + ParseResponse response, + int code, + String value, +) { response.success = true; response.statusCode = 200; response.error = ParseError(code: code, message: value); From 5f155db008d74a5c11a414ef927db286dda15426 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 28 Nov 2025 12:51:40 +0000 Subject: [PATCH 9/9] Add changelog entry and bump version to 8.0.2 Added changelog entry for PR #1048 documenting the fix for ParseXFile uploading files with incorrect content-type. Version bumped from 8.0.1 to 8.0.2. Co-authored-by: mtrezza <5673677+mtrezza@users.noreply.github.com> --- packages/dart/CHANGELOG.md | 6 ++++++ packages/dart/pubspec.yaml | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/dart/CHANGELOG.md b/packages/dart/CHANGELOG.md index 64ab61ec..844406ab 100644 --- a/packages/dart/CHANGELOG.md +++ b/packages/dart/CHANGELOG.md @@ -1,3 +1,9 @@ +## [8.0.2](https://github.com/parse-community/Parse-SDK-Flutter/compare/dart-8.0.1...dart-8.0.2) (2025-11-28) + +### Bug Fixes + +* `ParseXFile` uploads file with content-type `application/octet-stream` if not explicitly set ([#1048](https://github.com/parse-community/Parse-SDK-Flutter/pull/1048)) + ## [8.0.1](https://github.com/parse-community/Parse-SDK-Flutter/compare/dart-8.0.0...dart-8.0.1) (2025-11-22) ### Bug Fixes diff --git a/packages/dart/pubspec.yaml b/packages/dart/pubspec.yaml index e9df578f..016673a4 100644 --- a/packages/dart/pubspec.yaml +++ b/packages/dart/pubspec.yaml @@ -1,6 +1,6 @@ name: parse_server_sdk description: The Dart SDK to connect to Parse Server. Build your apps faster with Parse Platform, the complete application stack. -version: 8.0.1 +version: 8.0.2 homepage: https://parseplatform.org repository: https://github.com/parse-community/Parse-SDK-Flutter issue_tracker: https://github.com/parse-community/Parse-SDK-Flutter/issues