Skip to content

Commit 71c8f60

Browse files
committed
update to v1.0.24
2 parents e6e0f05 + 35fa250 commit 71c8f60

26 files changed

+780
-132
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
.DS_Store
22
.dart_tool/
3-
3+
.history
44
.packages
55
.pub/
66
pubspec.lock

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,12 @@
1+
## 1.0.24
2+
3+
## 1.0.23
4+
Fixed LiveQuery
5+
Bug fixes
6+
17
## 1.0.22
8+
Added dirty children
9+
Added option of sembast or share_preferences
210

311
## 1.0.21
412
LiveQuery fix

README.md

Lines changed: 87 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ Want to get involved? Join our Slack channel and help out! (http://flutter-parse
1313
To install, either add to your pubspec.yaml
1414
```yml
1515
dependencies:
16-
parse_server_sdk: ^1.0.22
16+
parse_server_sdk: ^1.0.24
1717
```
1818
or clone this repository and add to your project. As this is an early development with multiple contributors, it is probably best to download/clone and keep updating as an when a new feature is added.
1919
@@ -44,9 +44,9 @@ It's possible to add other parameters to work with your instance of Parse Server
4444
clientKey: keyParseClientKey, // Required for some setups
4545
debug: true, // When enabled, prints logs to console
4646
liveQueryUrl: keyLiveQueryUrl, // Required if using LiveQuery
47-
autoSendSessionId: true, // Some confurations require this to be true
47+
autoSendSessionId: true, // Required for authentication and ACL
4848
securityContext: securityContext, // Again, required for some setups
49-
coreStore: await CoreStoreSharedPrefsImp.getInstance()); // Will use SharedPreferences instead of Sembast as an internal DB
49+
coreStore: await CoreStoreSharedPrefsImp.getInstance()); // Local data storage method. Will use SharedPreferences instead of Sembast as an internal DB
5050
```
5151

5252
## Objects
@@ -133,6 +133,17 @@ and to retrieve it
133133
var dietPlan = DietPlan().fromPin('OBJECT ID OF OBJECT');
134134
```
135135

136+
## Storage
137+
We now have 2 types of storage, secure and unsecure. We currently rely on 2 third party options:
138+
139+
- SharedPreferences
140+
- Sembast
141+
Sembast offers secured storage, whilst SharePreferences wraps NSUserDefaults (on iOS) and SharedPreferences (on Android).
142+
143+
The storage method is defined in the parameter __coreStore__ in Parse().initialize
144+
145+
Check sample code for options
146+
136147
## Increment Counter values in objects
137148
Retrieve it, call
138149

@@ -441,13 +452,52 @@ Also, once logged in you can manage sessions tokens. This feature can be called
441452
```dart
442453
user = ParseUser.currentUser();
443454
```
455+
456+
To add additional columns to the user:
457+
```dart
458+
var user = ParseUser("TestFlutter", "TestPassword123", "[email protected]")
459+
..set("userLocation", "FlutterLand");
460+
```
461+
444462
Other user features are:-
445463
* Request Password Reset
446464
* Verification Email Request
447465
* Get all users
448466
* Save
449467
* Destroy user
450468
* Queries
469+
470+
## Facebook, OAuth and 3rd Party Login/User
471+
472+
Usually, each provider will provide their own library for logins, but the loginWith method on ParseUser accepts a name of provider, then a Map<String, dynamic> with the authentication details required.
473+
For Facebook and the example below, we used the library provided at https://pub.dev/packages/flutter_facebook_login
474+
475+
```
476+
Future<void> goToFacebookLogin() async {
477+
final FacebookLogin facebookLogin = FacebookLogin();
478+
final FacebookLoginResult result = await facebookLogin.logInWithReadPermissions(['email']);
479+
480+
switch (result.status) {
481+
case FacebookLoginStatus.loggedIn:
482+
final ParseResponse response = await ParseUser.loginWith(
483+
'facebook',
484+
facebook(result.accessToken.token,
485+
result.accessToken.userId,
486+
result.accessToken.expires));
487+
488+
if (response.success) {
489+
// User is logged in, test with ParseUser.currentUser()
490+
}
491+
break;
492+
case FacebookLoginStatus.cancelledByUser:
493+
// User cancelled
494+
break;
495+
case FacebookLoginStatus.error:
496+
// Error
497+
break;
498+
}
499+
}
500+
```
451501

452502
## Security for Objects - ParseACL
453503
For any object, you can specify which users are allowed to read the object, and which users are allowed to modify an object.
@@ -539,6 +589,40 @@ final Map<String, String> params = <String, String>{'plan': 'paid'};
539589
function.execute(parameters: params);
540590
```
541591

592+
## Relation
593+
594+
The SDK supports Relation.
595+
596+
To add relation to object:
597+
598+
```dart
599+
dietPlan.addRelation('fruits', [ParseObject("Fruits")..set("objectId", "XGadzYxnac")]);
600+
```
601+
602+
To remove relation to object:
603+
604+
```dart
605+
dietPlan.removeRelation('fruits', [ParseObject("Fruits")..set("objectId", "XGadzYxnac")]);
606+
```
607+
608+
To Retrive a relation instance for user, call:
609+
```dart
610+
final relation = dietPlan.getRelation('fruits');
611+
```
612+
613+
and then you can add a relation to the passed in object:
614+
```
615+
relation.add(dietPlan);
616+
final result = await user.save();
617+
```
618+
619+
To retrieve objects that are members of Relation field of a parent object:
620+
```dart
621+
QueryBuilder<ParseObject> query =
622+
QueryBuilder<ParseObject>(ParseObject('Fruits'))
623+
..whereRelatedTo('fruits', 'DietPlan', DietPlan.objectId);
624+
```
625+
542626
## Other Features of this library
543627
Main:
544628
* Installation (View the example application)

example/lib/main.dart

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -248,22 +248,22 @@ class _MyAppState extends State<MyApp> with AutomaticKeepAliveClientMixin {
248248

249249
Future<void> runTestQueries() async {
250250
// Basic repository example
251-
await repositoryAddUser();
251+
/* await repositoryAddUser();
252252
await repositoryAddItems();
253253
await repositoryGetAllItems();
254-
254+
*/
255255
//Basic usage
256-
await createItem();
256+
/* await createItem();
257257
await getAllItems();
258258
await getAllItemsByName();
259259
await getSingleItem();
260260
await getConfigs();
261-
await query();
261+
await query();*/
262262
await initUser();
263-
await initInstallation();
263+
/* await initInstallation();
264264
await function();
265265
await functionWithParameters();
266-
await test();
266+
await test();*/
267267
}
268268

269269
Future<void> initInstallation() async {
@@ -375,16 +375,19 @@ class _MyAppState extends State<MyApp> with AutomaticKeepAliveClientMixin {
375375
Future<void> initUser() async {
376376
// All return type ParseUser except all
377377
ParseUser user =
378-
ParseUser('TestFlutter', 'TestPassword123', 'test.flutter@gmail.com');
378+
ParseUser('RE9fU360lishjFKC5dLZS4Zwm', 'password', 'test@facebook.com');
379379

380380
/// Sign-up
381-
ParseResponse response = await user.signUp();
381+
/*ParseResponse response = await user.signUp();
382382
if (response.success) {
383383
user = response.result;
384-
}
384+
}*/
385+
386+
ParseUser user1 = await ParseUser.currentUser();
387+
user1.authData;
385388

386389
/// Login
387-
response = await user.login();
390+
ParseResponse response = await user.login();
388391
if (response.success) {
389392
user = response.result;
390393
}

lib/parse_server_sdk.dart

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,11 @@ import 'package:sembast/sembast.dart';
1717
import 'package:sembast/sembast_io.dart';
1818
import 'package:shared_preferences/shared_preferences.dart';
1919
import 'package:uuid/uuid.dart';
20-
import 'package:web_socket_channel/io.dart';
2120
import 'package:xxtea/xxtea.dart';
2221

22+
export 'src/network/parse_live_query.dart'
23+
if (dart.library.js) 'src/network/parse_live_query_web.dart';
24+
2325
part 'package:parse_server_sdk/src/objects/response/parse_error_response.dart';
2426

2527
part 'package:parse_server_sdk/src/objects/response/parse_exception_response.dart';
@@ -46,8 +48,6 @@ part 'src/enums/parse_enum_api_rq.dart';
4648

4749
part 'src/network/parse_http_client.dart';
4850

49-
part 'src/network/parse_live_query.dart';
50-
5151
part 'src/network/parse_query.dart';
5252

5353
part 'src/objects/parse_acl.dart';
@@ -90,6 +90,10 @@ part 'src/utils/parse_logger.dart';
9090

9191
part 'src/utils/parse_utils.dart';
9292

93+
part 'src/utils/parse_login_helpers.dart';
94+
95+
part 'src/objects/parse_merge.dart';
96+
9397
class Parse {
9498
ParseCoreData data;
9599
bool _hasBeenInitialized = false;

lib/src/base/parse_constants.dart

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
part of flutter_parse_sdk;
22

33
// Library
4-
const String keySdkVersion = '1.0.22';
4+
const String keySdkVersion = '1.0.24';
55
const String keyLibraryName = 'Flutter Parse SDK';
66

77
// End Points
@@ -15,6 +15,7 @@ const String keyEndPointVerificationEmail = '/verificationEmailRequest';
1515
const String keyEndPointRequestPasswordReset = '/requestPasswordReset';
1616
const String keyEndPointClasses = '/classes/';
1717
const String keyEndPointHealth = '/health';
18+
const String keyEndPointAggregate = '/aggregate/';
1819

1920
// ParseObject variables
2021
const String keyVarClassName = 'className';
@@ -25,6 +26,7 @@ const String keyVarUsername = 'username';
2526
const String keyVarEmail = 'email';
2627
const String keyVarPassword = 'password';
2728
const String keyVarSessionToken = 'sessionToken';
29+
const String keyVarAuthData = 'authData';
2830
const String keyVarAcl = 'ACL';
2931
const String keyVarName = 'name';
3032
const String keyVarURL = 'url';

lib/src/enums/parse_enum_api_rq.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ enum ParseApiRQ {
55
healthCheck,
66
get,
77
getAll,
8+
unset,
89
create,
910
save,
1011
query,

lib/src/network/parse_http_client.dart

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ class ParseHTTPClient extends BaseClient {
66
: _sendSessionId = sendSessionId,
77
_client = securityContext != null
88
? IOClient(HttpClient(context: securityContext))
9-
: IOClient();
9+
: Client();
1010

1111
final Client _client;
1212
final bool _sendSessionId;
@@ -17,7 +17,9 @@ class ParseHTTPClient extends BaseClient {
1717
/// Overrides the call method for HTTP Client and adds custom headers
1818
@override
1919
Future<StreamedResponse> send(BaseRequest request) {
20-
request.headers[keyHeaderUserAgent] = _userAgent;
20+
if (!identical(0, 0.0)) {
21+
request.headers[keyHeaderUserAgent] = _userAgent;
22+
}
2123
request.headers[keyHeaderApplicationId] = data.applicationId;
2224
if ((_sendSessionId == true) &&
2325
(data.sessionId != null) &&

lib/src/network/parse_live_query.dart

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
1-
part of flutter_parse_sdk;
1+
import 'dart:convert';
2+
import 'dart:io';
3+
4+
import 'package:web_socket_channel/io.dart';
5+
6+
import '../../parse_server_sdk.dart';
27

38
enum LiveQueryEvent { create, enter, update, leave, delete, error }
49

@@ -49,8 +54,9 @@ class LiveQuery {
4954
}
5055

5156
final String _className = query.object.parseClassName;
57+
final List<String> keysToReturn = query.limiters['keys']?.split(',');
5258
query.limiters.clear(); //Remove limits in LiveQuery
53-
final String _where = query._buildQuery().replaceAll('where=', '');
59+
final String _where = query.buildQuery().replaceAll('where=', '');
5460

5561
//Convert where condition to Map
5662
Map<String, dynamic> _whereMap = Map<String, dynamic>();
@@ -90,7 +96,7 @@ class LiveQuery {
9096
final String className = map['className'];
9197
if (className == '_User') {
9298
eventCallbacks[actionData['op']](
93-
ParseUser._getEmptyUser().fromJson(map));
99+
ParseUser(null, null, null).fromJson(map));
94100
} else {
95101
eventCallbacks[actionData['op']](
96102
ParseObject(className).fromJson(map));
@@ -103,7 +109,7 @@ class LiveQuery {
103109
if (_debug) {
104110
print('$_printConstLiveQuery: Done');
105111
}
106-
}, onError: (dynamic error) {
112+
}, onError: (Object error) {
107113
if (_debug) {
108114
print(
109115
'$_printConstLiveQuery: Error: ${error.runtimeType.toString()}');
@@ -116,13 +122,17 @@ class LiveQuery {
116122
//It should be the first message sent from a client after the WebSocket connection is established.
117123
_connectMessage = <String, String>{
118124
'op': 'connect',
119-
'applicationId': _client.data.applicationId,
120-
'clientKey': _client.data.clientKey ?? ''
125+
'applicationId': _client.data.applicationId
121126
};
122-
if (_sendSessionId) {
127+
if (_sendSessionId && _client.data.sessionId != null) {
123128
_connectMessage['sessionToken'] = _client.data.sessionId;
124129
}
125130

131+
if (_client.data.clientKey != null)
132+
_connectMessage['clientKey'] = _client.data.clientKey;
133+
if (_client.data.masterKey != null)
134+
_connectMessage['masterKey'] = _client.data.masterKey;
135+
126136
if (_debug) {
127137
print('$_printConstLiveQuery: ConnectMessage: $_connectMessage');
128138
}
@@ -136,9 +146,11 @@ class LiveQuery {
136146
'query': <String, dynamic>{
137147
'className': _className,
138148
'where': _whereMap,
149+
if (keysToReturn != null && keysToReturn.isNotEmpty)
150+
'fields': keysToReturn
139151
}
140152
};
141-
if (_sendSessionId) {
153+
if (_sendSessionId && _client.data.sessionId != null) {
142154
_subscribeMessage['sessionToken'] = _client.data.sessionId;
143155
}
144156

0 commit comments

Comments
 (0)