diff --git a/.idea/flutter_parse_sdk.iml b/.idea/flutter_parse_sdk.iml
new file mode 100644
index 000000000..c9d208a4e
--- /dev/null
+++ b/.idea/flutter_parse_sdk.iml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Dart_Packages.xml b/.idea/libraries/Dart_Packages.xml
index 66de4becd..fdd01077d 100644
--- a/.idea/libraries/Dart_Packages.xml
+++ b/.idea/libraries/Dart_Packages.xml
@@ -1,162 +1,25 @@
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.idea/libraries/Dart_SDK.xml b/.idea/libraries/Dart_SDK.xml
index 128e0bcc2..b257e38dc 100644
--- a/.idea/libraries/Dart_SDK.xml
+++ b/.idea/libraries/Dart_SDK.xml
@@ -1,25 +1,25 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.idea/libraries/Flutter_Plugins.xml b/.idea/libraries/Flutter_Plugins.xml
index b0f697111..b7751cdc9 100644
--- a/.idea/libraries/Flutter_Plugins.xml
+++ b/.idea/libraries/Flutter_Plugins.xml
@@ -1,6 +1,8 @@
-
-
+
+
+
+
diff --git a/.idea/modules.xml b/.idea/modules.xml
index e5ed7a4dd..c749759a5 100644
--- a/.idea/modules.xml
+++ b/.idea/modules.xml
@@ -2,8 +2,7 @@
-
-
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 000000000..35eb1ddfb
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/workspace.xml b/.idea/workspace.xml
index ec2cb194f..ec30ad3fd 100644
--- a/.idea/workspace.xml
+++ b/.idea/workspace.xml
@@ -10,39 +10,154 @@
-
-
-
-
-
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -53,6 +168,10 @@
User()
import
+ BaseClient
+ bad
+ client
+ send
part
@@ -62,7 +181,7 @@
@@ -84,39 +203,43 @@
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
-
+
+
+
+
+
+
+
+
+
-
-
-
+
+
+
+
@@ -138,228 +261,83 @@
-
+
+
-
+
-
+
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- $PROJECT_DIR$/.idea/workspace.xml
- $PROJECT_DIR$/CHANGELOG.md
- $PROJECT_DIR$/README.md
- $PROJECT_DIR$/example/lib/diet_plan.dart
- $PROJECT_DIR$/example/lib/main.dart
- $PROJECT_DIR$/lib/parse.dart
- $PROJECT_DIR$/pubspec.yaml
-
-
-
-
-
-
-
- $PROJECT_DIR$/lib/src/base/parse_constants.dart
- $PROJECT_DIR$/lib/src/data/parse_data_server.dart
- $PROJECT_DIR$/lib/src/data/parse_data_user.dart
- $PROJECT_DIR$/lib/src/enums/parse_enum_function_call.dart
- $PROJECT_DIR$/lib/src/enums/parse_enum_object_call.dart
- $PROJECT_DIR$/lib/src/enums/parse_enum_user_call.dart
- $PROJECT_DIR$/lib/src/network/parse_http_client.dart
- $PROJECT_DIR$/lib/src/network/parse_livequery.dart
- $PROJECT_DIR$/lib/src/network/parse_query.dart
- $PROJECT_DIR$/lib/src/objects/parse_base.dart
- $PROJECT_DIR$/lib/src/objects/parse_exception.dart
- $PROJECT_DIR$/lib/src/objects/parse_function.dart
- $PROJECT_DIR$/lib/src/objects/parse_geo_point.dart
- $PROJECT_DIR$/lib/src/objects/parse_object.dart
- $PROJECT_DIR$/lib/src/objects/parse_response.dart
- $PROJECT_DIR$/lib/src/objects/parse_user.dart
- $PROJECT_DIR$/lib/src/utils/parse_utils.dart
- $PROJECT_DIR$/lib/src/utils/parse_utils_date.dart
- $PROJECT_DIR$/lib/src/utils/parse_utils_objects.dart
-
-
-
-
-
-
-
- $PROJECT_DIR$/lib/base/parse_constants.dart
- $PROJECT_DIR$/lib/data/parse_data.dart
- $PROJECT_DIR$/lib/data/parse_data_objects.dart
- $PROJECT_DIR$/lib/data/parse_data_server.dart
- $PROJECT_DIR$/lib/data/parse_data_user.dart
- $PROJECT_DIR$/lib/enums/parse_enum_function_call.dart
- $PROJECT_DIR$/lib/enums/parse_enum_object_call.dart
- $PROJECT_DIR$/lib/enums/parse_enum_user_call.dart
- $PROJECT_DIR$/lib/network/parse_http_client.dart
- $PROJECT_DIR$/lib/network/parse_livequery.dart
- $PROJECT_DIR$/lib/network/parse_query.dart
- $PROJECT_DIR$/lib/objects/parse_base.dart
- $PROJECT_DIR$/lib/objects/parse_exception.dart
- $PROJECT_DIR$/lib/objects/parse_function.dart
- $PROJECT_DIR$/lib/objects/parse_object.dart
- $PROJECT_DIR$/lib/objects/parse_response.dart
- $PROJECT_DIR$/lib/objects/parse_user.dart
- $PROJECT_DIR$/lib/utils/parse_utils_date.dart
- $PROJECT_DIR$/lib/utils/parse_utils_network.dart
- $PROJECT_DIR$/lib/utils/parse_utils_objects.dart
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
@@ -374,34 +352,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -435,6 +385,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -489,83 +458,116 @@
1546895042011
-
+
+ 1547051168221
+
+
+
+ 1547051168221
+
+
+ 1547051408891
+
+
+
+ 1547051408891
+
+
+ 1547051451156
+
+
+
+ 1547051451156
+
+
+
+
+
+
+
+
+
+
+
-
+
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
+
+
-
+
+
+
+
-
-
-
-
-
-
-
-
+
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -574,128 +576,41 @@
-
+
+
+
-
-
-
-
- file://$PROJECT_DIR$/lib/objects/parse_object.dart
- 76
-
-
-
-
+
+
+
+ _getUserFromLocalStore()
+ Dart
+ EXPRESSION
+
+
+ await _getUserFromLocalStore()
+ Dart
+ EXPRESSION
+
+
+ super.toJson();
+ Dart
+ EXPRESSION
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -717,229 +632,301 @@
-
+
+
+
-
-
+
+
-
-
-
+
-
+
-
+
-
-
+
+
-
+
+
+
+
+
+
+
+
+
+
-
-
+
+
-
+
-
-
+
+
-
+
-
-
+
+
-
+
-
-
+
+
-
+
+
+
+
-
-
+
+
-
+
-
-
+
+
-
+
-
-
+
+
+
+
+
+
+
-
+
-
-
+
+
-
+
-
-
+
+
-
+
-
-
+
+
-
+
-
-
+
+
-
+
-
-
+
+
-
+
-
-
+
+
-
+
-
-
+
+
-
+
-
-
+
+
-
+
-
-
+
+
-
+
-
-
+
+
-
+
-
-
-
-
-
+
+
-
+
-
-
+
+
-
+
-
-
-
-
-
+
+
-
+
-
-
-
-
-
+
+
-
+
-
-
+
+
-
+
-
-
+
+
+
+
+
+
+
+
+
-
-
+
+
-
+
-
-
-
-
-
+
+
-
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ No facets are configured
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1.8
+
+
+
+
+
+
+
+
+
+
+
+ flutter_parse_sdk
+
+
+
+
+
+
+
+
+
+
1.8
@@ -952,6 +939,18 @@
+
+
+ Dart Packages
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
index f8a7f12ce..cabacd842 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,9 @@
+## 1.0.3
+
+Added persistent storage. When a logged in user closes the app, then reopens, the data
+will now be persistent. Best practice would be to Parse.init, then Parse.currentUser. This
+will return the current user session and allow auto login. Can also pin data in storage.
+
## 1.0.2
Fixed login
diff --git a/README.md b/README.md
index 207619a64..ad4b89437 100644
--- a/README.md
+++ b/README.md
@@ -13,7 +13,7 @@ Want to get involved? Join our Slack channel and help out! (http://flutter-parse
To install, either add to your pubspec.yaml
```
dependencies:
- parse_server_sdk: ^1.0.2
+ parse_server_sdk: ^1.0.3
```
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.
@@ -115,6 +115,7 @@ The features available are:-
* Query - By object Id
* Delete
* Complex queries as shown above
+ * Pin
* Plenty more
## Custom Objects
@@ -146,21 +147,21 @@ var user = ParseUser().create("TestFlutter", "TestPassword123", "TestFlutterSDK
Then have the user sign up:
```
-user = await ParseUser().signUp();
+user = await user.signUp();
```
You can also logout and login with the user:
```
-user = await ParseUser().login();
+user = await user.login();
```
-Also, once logged in you can manage sessions tokens:
+Also, once logged in you can manage sessions tokens. This feature can be called after Parse().init() on startup to check for a logged in user.
```
-user = await ParseUser().currentUser(fromServer: true);
+user = ParseUser.currentUser();
```
Other user features are:-
* Request Password Reset
-* Verification Email Request
+ * Verification Email Request
* Get all users
-* Save
+ * Save
* Destroy user
## Other Features of this library
@@ -171,6 +172,7 @@ Main:
* Queries
* LiveQueries
* GeoPoints
+* Persistent storage
* Debug Mode - Logging API calls
* Manage Session ID's tokens
diff --git a/example/android/gradlew b/example/android/gradlew
old mode 100644
new mode 100755
diff --git a/example/ios/Flutter/Debug.xcconfig b/example/ios/Flutter/Debug.xcconfig
index 592ceee85..e8efba114 100644
--- a/example/ios/Flutter/Debug.xcconfig
+++ b/example/ios/Flutter/Debug.xcconfig
@@ -1 +1,2 @@
+#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
#include "Generated.xcconfig"
diff --git a/example/ios/Flutter/Release.xcconfig b/example/ios/Flutter/Release.xcconfig
index 592ceee85..399e9340e 100644
--- a/example/ios/Flutter/Release.xcconfig
+++ b/example/ios/Flutter/Release.xcconfig
@@ -1 +1,2 @@
+#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
#include "Generated.xcconfig"
diff --git a/example/lib/application_constants.dart b/example/lib/application_constants.dart
index 7ddb84685..e2b7f38b0 100644
--- a/example/lib/application_constants.dart
+++ b/example/lib/application_constants.dart
@@ -1,6 +1,6 @@
-abstract class ApplicationConstants {
+abstract class ApplicationConstants { // Start
static const String APP_NAME = "";
static const String PARSE_APPLICATION_ID = "";
static const String PARSE_MASTER_KEY = "";
static const String PARSE_SERVER_URL = "";
-}
\ No newline at end of file
+} // End
\ No newline at end of file
diff --git a/example/lib/main.dart b/example/lib/main.dart
index a104d292d..492f7aa08 100644
--- a/example/lib/main.dart
+++ b/example/lib/main.dart
@@ -70,7 +70,7 @@ class _MyAppState extends State {
print(ApplicationConstants.APP_NAME + ": " + (plan as DietPlan).name);
}
} else {
- print(ApplicationConstants.APP_NAME + ": " + response.exception.message);
+ print(ApplicationConstants.APP_NAME + ": " + response.error.message);
}
}
@@ -80,7 +80,7 @@ class _MyAppState extends State {
if (response.success) {
print(ApplicationConstants.APP_NAME + ": " + (response.result as DietPlan).toString());
} else {
- print(ApplicationConstants.APP_NAME + ": " + response.exception.message);
+ print(ApplicationConstants.APP_NAME + ": " + response.error.message);
}
}
@@ -94,20 +94,29 @@ class _MyAppState extends State {
if (response.success) {
print("Result: ${((response.result as List).first as DietPlan).toString()}");
} else {
- print("Result: ${response.exception.message}");
+ print("Result: ${response.error.message}");
}
}
initUser() async {
- var user = ParseUser().create("TestFlutter", "TestPassword123", "TestFlutterSDK@gmail.com");
- user = await ParseUser().signUp();
- user = await ParseUser().login();
- user = await ParseUser().currentUser(fromServer: true);
- user = await ParseUser().requestPasswordReset();
- user = await ParseUser().verificationEmailRequest();
- user = await ParseUser().all();
- user = await ParseUser().save();
- user = await ParseUser().destroy();
+
+ // All return type ParseUser except all
+ var user = ParseUser("TestFlutter", "TestPassword123", "TestFlutterSDK@gmail.com");
+ user = await user.signUp();
+ user = await user.login();
+ user = null;
+
+ // Best practice for starting the app. This will check for a
+ user = ParseUser.currentUser();
+ user = await user.getCurrentUserFromServer();
+ user = await user.requestPasswordReset();
+ user = await user.verificationEmailRequest();
+
+ user = await user.save();
+ await user.destroy();
+
+ // Returns type ParseResponse as its a query, not a single result
+ var response = await ParseUser.all();
}
function() {
diff --git a/lib/parse.dart b/lib/parse.dart
index 67b87dca6..19062d354 100644
--- a/lib/parse.dart
+++ b/lib/parse.dart
@@ -4,22 +4,19 @@ import 'dart:async';
import 'dart:convert';
import 'dart:io';
+import 'package:shared_preferences/shared_preferences.dart';
import 'package:http/http.dart';
-import 'package:intl/intl.dart';
import 'package:meta/meta.dart';
import 'package:web_socket_channel/io.dart';
part 'src/base/parse_constants.dart';
-part 'src/data/parse_data_server.dart';
-part 'src/data/parse_data_user.dart';
-part 'src/enums/parse_enum_function_call.dart';
-part 'src/enums/parse_enum_object_call.dart';
-part 'src/enums/parse_enum_user_call.dart';
+part 'src/data/parse_core_data.dart';
+part 'src/enums/parse_enum_api_rq.dart';
part 'src/network/parse_http_client.dart';
part 'src/network/parse_livequery.dart';
part 'src/network/parse_query.dart';
part 'src/objects/parse_base.dart';
-part 'src/objects/parse_exception.dart';
+part 'src/objects/parse_error.dart';
part 'src/objects/parse_function.dart';
part 'src/objects/parse_geo_point.dart';
part 'src/objects/parse_object.dart';
@@ -28,9 +25,12 @@ part 'src/objects/parse_user.dart';
part 'src/utils/parse_utils_date.dart';
part 'src/utils/parse_utils_objects.dart';
part 'src/utils/parse_utils.dart';
+part 'src/utils/parse_encoder.dart';
+part 'src/utils/parse_decoder.dart';
+part 'src/utils/parse_logger.dart';
class Parse {
- ParseDataServer data;
+ ParseCoreData data;
final ParseHTTPClient client = new ParseHTTPClient();
/// To initialise Parse Server in your application
@@ -47,21 +47,22 @@ class Parse {
// ```
Parse initialize(appId, serverUrl,
{debug, appName, liveQueryUrl, masterKey, sessionId}) {
- ParseDataServer.init(appId, serverUrl,
+ ParseCoreData.init(appId, serverUrl,
debug: debug,
appName: appName,
liveQueryUrl: liveQueryUrl,
masterKey: masterKey,
sessionId: sessionId);
- return _newInstance(ParseDataServer());
+ return _newInstance(ParseCoreData());
}
- /// Creates a singleton instance of [ParseDataServer] that contains all the server information
- Parse _newInstance(ParseDataServer data) {
+ /// Creates a singleton instance of [ParseCoreData] that contains all the server information
+ Parse _newInstance(ParseCoreData data) {
var parse = Parse();
parse.data = data;
parse.client.data = data;
+ data.initStorage();
return parse;
}
}
diff --git a/lib/src/base/parse_constants.dart b/lib/src/base/parse_constants.dart
index b1404df56..c6ea7893d 100644
--- a/lib/src/base/parse_constants.dart
+++ b/lib/src/base/parse_constants.dart
@@ -1,13 +1,17 @@
part of flutter_parse_sdk;
-/// Class containing all constants for this library
-class ParseConstants {
+// Utils
+const String PARSE_DATE_FORMAT = "yyyy-MM-dd'T'HH:mm";
- static const String PARSE_DATE_FORMAT = "yyyy-MM-dd'T'HH:mm";
- static const String OBJECT_ID = 'objectId';
- static const String CREATED_AT = 'createdAt';
- static const String UPDATED_AT = 'updatedAT';
+// ParseObject variables
+const String OBJECT_ID = 'objectId';
+const String CREATED_AT = 'createdAt';
+const String UPDATED_AT = 'updatedAT';
- static const String HEADER_SESSION_TOKEN = 'X-Parse-Session-Token';
- static const String HEADER_REVOCABLE_SESSION = 'X-Parse-Revocable-Session';
-}
\ No newline at end of file
+// Headers
+const String HEADER_SESSION_TOKEN = 'X-Parse-Session-Token';
+const String HEADER_REVOCABLE_SESSION = 'X-Parse-Revocable-Session';
+
+// Storage
+const String PARSE_STORE_BASE = 'flutter_parse_sdk_';
+const String PARSE_STORE_USER = "${PARSE_STORE_BASE}user";
\ No newline at end of file
diff --git a/lib/src/data/parse_data_server.dart b/lib/src/data/parse_core_data.dart
similarity index 74%
rename from lib/src/data/parse_data_server.dart
rename to lib/src/data/parse_core_data.dart
index b796314db..516169610 100644
--- a/lib/src/data/parse_data_server.dart
+++ b/lib/src/data/parse_core_data.dart
@@ -1,16 +1,16 @@
part of flutter_parse_sdk;
/// Singleton class that defines all user keys and data
-class ParseDataServer {
- static ParseDataServer _instance;
- static ParseDataServer get instance => _instance;
+class ParseCoreData {
+ static ParseCoreData _instance;
+ static ParseCoreData get instance => _instance;
/// Creates an instance of Parse Server
///
/// This class should not be user unless switching servers during the app,
/// which is odd. Should only be user by Parse.init
static void init(appId, serverUrl, {debug, appName, liveQueryUrl, masterKey, sessionId}){
- _instance = ParseDataServer._init(appId, serverUrl);
+ _instance = ParseCoreData._init(appId, serverUrl);
if (debug != null) _instance.debug = debug;
if (appName != null) _instance.appName = appName;
@@ -26,12 +26,13 @@ class ParseDataServer {
String masterKey;
String sessionId;
bool debug;
+ SharedPreferences storage;
- ParseDataServer._init(
+ ParseCoreData._init(
this.applicationId,
this.serverUrl);
- factory ParseDataServer() => _instance;
+ factory ParseCoreData() => _instance;
/// Sets the current sessionId.
///
@@ -41,6 +42,12 @@ class ParseDataServer {
this.sessionId = sessionId;
}
+ void initStorage() async {
+ storage = await SharedPreferences.getInstance();
+ }
+
+ SharedPreferences getStore() => storage;
+
@override
String toString() => "$applicationId $masterKey";
}
diff --git a/lib/src/data/parse_data_user.dart b/lib/src/data/parse_data_user.dart
deleted file mode 100644
index b4238cbe9..000000000
--- a/lib/src/data/parse_data_user.dart
+++ /dev/null
@@ -1,61 +0,0 @@
-part of flutter_parse_sdk;
-
-/// User class that contains the current user data
-class User extends ParseBase {
- static User _instance;
-
- static User get instance => _instance;
-
- /// Creates an instance of a ParseUser
- static void init(username, password, emailAddress) =>
- _instance ??= User._init(username, password, emailAddress);
-
- /// Clears user data to mimic logout
- static void logout() => _instance = null;
-
- String acl;
- String username;
- String password;
- String emailAddress;
-
- /// Creates a singleton instance of a user.
- ///
- /// There can only be one user
- User._init(this.username, this.password, this.emailAddress): super();
-
- factory User() => _instance;
-
- /// Returns a [User] from a [Map] object
- fromJson(objectData) {
- if (getObjectData() == null) setObjectData(objectData);
- getObjectData().addAll(objectData);
- if (getObjectData().containsKey(ParseConstants.OBJECT_ID)) objectId = getObjectData()[ParseConstants.OBJECT_ID];
- if (getObjectData().containsKey(ParseConstants.CREATED_AT)) createdAt = convertStringToDateTime(getObjectData()[ParseConstants.CREATED_AT]);
- if (getObjectData().containsKey(ParseConstants.UPDATED_AT)) updatedAt = convertStringToDateTime(getObjectData()[ParseConstants.UPDATED_AT]);
- if (getObjectData().containsKey(ACL)) acl = getObjectData()[ACL].toString();
- if (getObjectData().containsKey(USERNAME)) username = getObjectData()[USERNAME];
- if (getObjectData().containsKey(PASSWORD)) password = getObjectData()[PASSWORD];
- if (getObjectData().containsKey(EMAIL)) emailAddress = getObjectData()[EMAIL];
-
- if (updatedAt == null) updatedAt = createdAt;
-
- return this;
- }
-
- /// Returns a JSON string of the current user
- Map toJson() => {
- ACL: acl,
- USERNAME: username,
- PASSWORD: password,
- EMAIL: emailAddress,
- };
-
- @override
- String toString() => "Username: $username \n"
- "Email Address:$emailAddress";
-
- static const String USERNAME = 'Username';
- static const String EMAIL = 'Email';
- static const String PASSWORD = 'Password';
- static const String ACL = 'ACL';
-}
diff --git a/lib/src/enums/parse_enum_api_rq.dart b/lib/src/enums/parse_enum_api_rq.dart
new file mode 100644
index 000000000..51f04bfdf
--- /dev/null
+++ b/lib/src/enums/parse_enum_api_rq.dart
@@ -0,0 +1,19 @@
+part of flutter_parse_sdk;
+
+/// Used to define the API calls made in ParseObject logs
+enum ParseApiRQ {
+ get,
+ getAll,
+ create,
+ save,
+ query,
+ delete,
+ currentUser,
+ signUp,
+ login,
+ verificationEmailRequest,
+ requestPasswordReset,
+ destroy,
+ all,
+ execute
+}
diff --git a/lib/src/enums/parse_enum_function_call.dart b/lib/src/enums/parse_enum_function_call.dart
deleted file mode 100644
index 9cd5ad2ea..000000000
--- a/lib/src/enums/parse_enum_function_call.dart
+++ /dev/null
@@ -1,4 +0,0 @@
-part of flutter_parse_sdk;
-
-/// Used to define the API calls made in ParseFunction logs
-enum ParseApiFunction { execute }
diff --git a/lib/src/enums/parse_enum_object_call.dart b/lib/src/enums/parse_enum_object_call.dart
deleted file mode 100644
index 43e748549..000000000
--- a/lib/src/enums/parse_enum_object_call.dart
+++ /dev/null
@@ -1,4 +0,0 @@
-part of flutter_parse_sdk;
-
-/// Used to define the API calls made in ParseObject logs
-enum ParseApiObject { get, getAll, create, save, query, delete }
diff --git a/lib/src/enums/parse_enum_user_call.dart b/lib/src/enums/parse_enum_user_call.dart
deleted file mode 100644
index a6e4530fa..000000000
--- a/lib/src/enums/parse_enum_user_call.dart
+++ /dev/null
@@ -1,13 +0,0 @@
-part of flutter_parse_sdk;
-
-/// Used to define the API calls made in ParseUser logs
-enum ParseApiUser {
- currentUser,
- signUp,
- login,
- verificationEmailRequest,
- requestPasswordReset,
- save,
- destroy,
- all
-}
diff --git a/lib/src/network/parse_http_client.dart b/lib/src/network/parse_http_client.dart
index 7b070df50..f47ed62b7 100644
--- a/lib/src/network/parse_http_client.dart
+++ b/lib/src/network/parse_http_client.dart
@@ -2,9 +2,9 @@ part of flutter_parse_sdk;
/// Creates a custom version of HTTP Client that has Parse Data Preset
class ParseHTTPClient extends BaseClient {
- final Client _client = new Client();
- final String _userAgent = "Dart Parse SDK 0.1";
- ParseDataServer data = ParseDataServer();
+ final Client _client = Client();
+ final String _userAgent = "Flutter Parse SDK 1.0.3";
+ ParseCoreData data = ParseCoreData();
ParseHTTPClient();
@@ -14,8 +14,7 @@ class ParseHTTPClient extends BaseClient {
request.headers['user-agent'] = _userAgent;
request.headers['X-Parse-Application-Id'] = data.applicationId;
request.headers['Content-Type'] = 'application/json';
- if (data.masterKey != null)
- request.headers['X-Parse-Master-Key'] = data.masterKey;
+ if (data.masterKey != null) request.headers['X-Parse-Master-Key'] = data.masterKey;
return _client.send(request);
}
}
diff --git a/lib/src/objects/parse_base.dart b/lib/src/objects/parse_base.dart
index ed042f850..48c363f1c 100644
--- a/lib/src/objects/parse_base.dart
+++ b/lib/src/objects/parse_base.dart
@@ -2,23 +2,27 @@ part of flutter_parse_sdk;
abstract class ParseBase {
/// Stores all the values of a class
- Map _objectData;
+ Map _objectData = Map();
/// Returns [String] objectId
- get getObjectId => _objectData['objectId'] == null ? objectId : _objectData['objectId'];
- String objectId;
+ String get objectId => _objectData['objectId'];
+ set objectId(String objectId) => _objectData[objectId];
/// Returns [DateTime] createdAt
- get getCreatedAt => _objectData['createdAt'] == null ? createdAt : _objectData['createdAt'];
- DateTime createdAt;
+ DateTime get createdAt => stringToDateTime(_objectData['createdAt']);
+ set createdAt(DateTime createdAt) =>
+ _objectData['createdAt'] = dateTimeToString(createdAt);
/// Returns [DateTime] updatedAt
- get getUpdatedAt => _objectData['updatedAt'] == null ? updatedAt : _objectData['updatedAt'];
- DateTime updatedAt;
+ DateTime get updatedAt => stringToDateTime(_objectData['updatedAt']);
+ set updatedAt(DateTime updatedAt) =>
+ _objectData['updatedAt'] = dateTimeToString(updatedAt);
+ /// Converts object to [String] in JSON format
@protected
toJson() => JsonEncoder().convert(getObjectData());
+ /// Creates a copy of this class
@protected
copy() => JsonDecoder().convert(fromJson(getObjectData()));
@@ -30,6 +34,12 @@ abstract class ParseBase {
@protected
getObjectData() => _objectData;
+ /// Saves in storage
+ @protected
+ saveInStorage(String key) async {
+ await ParseCoreData().getStore().setString(key, toJson());
+ }
+
@protected
fromJson(Map objectData) {
if (_objectData == null) _objectData = Map();
@@ -37,7 +47,7 @@ abstract class ParseBase {
}
/// Create a new variable for this object, [bool] forceUpdate is always true,
- /// if unsure as to wether an item is needed or not, set to false
+ /// if unsure as to whether an item is needed or not, set to false
set(String key, dynamic value, {bool forceUpdate: true}) {
if (value != null) {
if (getObjectData().containsKey(key)) {
@@ -56,4 +66,45 @@ abstract class ParseBase {
return defaultValue;
}
}
+
+ /// Saves item to simple key pair value storage
+ ///
+ /// Replicates Android SDK pin process and saves object to storage
+ pin() async {
+ if (objectId != null) {
+ await ParseCoreData().getStore().setString(objectId, toJson());
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /// Saves item to simple key pair value storage
+ ///
+ /// Replicates Android SDK pin process and saves object to storage
+ unpin() async {
+ if (objectId != null) {
+ var itemToSave = await ParseCoreData().getStore().setString(objectId, null);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /// Saves item to simple key pair value storage
+ ///
+ /// Replicates Android SDK pin process and saves object to storage
+ fromPin() async {
+ if (objectId != null) {
+ var itemFromStore = await ParseCoreData().getStore().getString(objectId);
+
+ if (itemFromStore != null) {
+ Map itemFromStoreMap = JsonDecoder().convert(
+ itemFromStore);
+ fromJson(itemFromStoreMap);
+ return this;
+ }
+ }
+ return null;
+ }
}
diff --git a/lib/src/objects/parse_error.dart b/lib/src/objects/parse_error.dart
new file mode 100644
index 000000000..7cce784f8
--- /dev/null
+++ b/lib/src/objects/parse_error.dart
@@ -0,0 +1,78 @@
+part of flutter_parse_sdk;
+
+/// ParseException is used in [ParseResult] to inform the user of the exception
+class ParseError {
+
+ Map exceptions = {
+ -1 :'UnknownError',
+
+ // SDK errors / Errors
+ 1: 'No Results',
+ 400: 'Bad Request',
+
+ // Parse specific / Exceptions
+ 100: 'ConnectionFailed',
+ 101: 'ObjectNotFound',
+ 102: 'InvalidQuery',
+ 103: 'InvalidClassName',
+ 104: 'MissingObjectId',
+ 105: 'InvalidKeyName',
+ 106: 'InvalidPointer',
+ 107: 'InvalidJson',
+ 108: 'CommandUnavailable',
+ 109: 'NotInitialized',
+ 111: 'IncorrectType',
+ 112: 'InvalidChannelName',
+ 115: 'PushMisconfigured',
+ 116: 'ObjectTooLarge',
+ 119: 'OperationForbidden',
+ 120: 'CacheMiss',
+ 121: 'InvalidNestedKey',
+ 122: 'InvalidFileName',
+ 123: 'InvalidAcl',
+ 124: 'Timeout',
+ 125: 'InvalidEmailAddress',
+ 135: 'MissingRequiredFieldError',
+ 137: 'DuplicateValue',
+ 139: 'InvalidRoleName',
+ 140: 'ExceededQuota',
+ 141: 'ScriptError',
+ 142: 'ValidationError',
+ 153: 'FileDeleteError',
+ 155: 'RequestLimitExceeded',
+ 160: 'InvalidEventName',
+ 200: 'UsernameMissing',
+ 201: 'PasswordMissing',
+ 202: 'UsernameTaken',
+ 203: 'EmailTaken',
+ 204: 'EmailMissing',
+ 205: 'EmailNotFound',
+ 206: 'SessionMissing',
+ 207: 'MustCreateUserThroughSignup',
+ 208: 'AccountAlreadyLinked',
+ 209: 'InvalidSessionToken',
+ 250: 'LinkedIdMissing',
+ 251: 'InvalidLinkedSession',
+ 252: 'UnsupportedService'};
+
+ final int code;
+ final String message;
+ final bool isTypeOfException;
+ String type;
+
+ ParseError({this.code = -1, this.message = "Unkown error", this.isTypeOfException = false, bool debug: false}){
+ type = exceptions[code];
+ if (debug) print(toString());
+ }
+
+ @override
+ String toString() {
+ var exceptionString = ' \n';
+ exceptionString += "----";
+ exceptionString +="\nParseException (Type: $type) :";
+ exceptionString +="\nCode: $code";
+ exceptionString +="\nMessage: $message";
+ exceptionString += "----";
+ return exceptionString;
+ }
+}
\ No newline at end of file
diff --git a/lib/src/objects/parse_exception.dart b/lib/src/objects/parse_exception.dart
deleted file mode 100644
index e349d83cd..000000000
--- a/lib/src/objects/parse_exception.dart
+++ /dev/null
@@ -1,9 +0,0 @@
-part of flutter_parse_sdk;
-
-/// ParseException is used in [ParseResult] to inform the user of the exception
-class ParseException {
-
- String message;
-
- ParseException();
-}
\ No newline at end of file
diff --git a/lib/src/objects/parse_function.dart b/lib/src/objects/parse_function.dart
index 4da8ddee7..578930446 100644
--- a/lib/src/objects/parse_function.dart
+++ b/lib/src/objects/parse_function.dart
@@ -1,19 +1,21 @@
part of flutter_parse_sdk;
-class ParseCloudFunction extends ParseBase {
+class ParseCloudFunction extends ParseObject {
final String functionName;
- String _path;
bool _debug;
ParseHTTPClient _client;
+ @override
+ String _path;
+
/// Creates a new cloud function object
///
/// {https://docs.parseplatform.org/cloudcode/guide/}
- ParseCloudFunction(this.functionName, {bool debug, ParseHTTPClient client}) {
- client == null ? _client = ParseHTTPClient() : _client = client;
- _debug = isDebugEnabled(debug, _client);
+ ParseCloudFunction(this.functionName, {bool debug, ParseHTTPClient client}) : super (functionName) {
_path = "/functions/$functionName";
- setObjectData(Map());
+
+ if (debug != null) setDebug(debug);
+ if (client != null) setClient(client);
}
/// Executes a cloud function
@@ -22,32 +24,6 @@ class ParseCloudFunction extends ParseBase {
execute() async {
var uri = _client.data.serverUrl + "$_path";
var result = await _client.post(uri, body: JsonEncoder().convert(getObjectData()));
- return _handleResult(result, ParseApiFunction.execute);
- }
-
- /// Handles an API response
- ParseResponse _handleResult(Response response, ParseApiFunction type) {
- ParseResponse parseResponse = ParseResponse.handleResponse(this, response);
- Map responseData = JsonDecoder().convert(response.body);
-
- if (_client.data.debug || _debug) {
- var responseString = ' \n';
-
- responseString += "----"
- "\n${_client.data.appName} API Response ($functionName : ${type.toString()}) :";
-
- if (parseResponse.success && parseResponse.result != null) {
- responseString += "\nStatus Code: ${parseResponse.statusCode}";
- responseString += "\nPayload: ${responseData.toString()}";
- } else if (!parseResponse.success) {
- responseString += "\nStatus Code: ${responseData['code'] == null ? parseResponse.statusCode : responseData['code']}";
- responseString += "\nException: ${responseData['error'] == null ? responseData.toString() : responseData['error']}";
- }
-
- responseString += "\n----\n";
- print(responseString);
- }
-
- return parseResponse;
+ return super.handleResponse(result, ParseApiRQ.execute);
}
}
diff --git a/lib/src/objects/parse_geo_point.dart b/lib/src/objects/parse_geo_point.dart
index c2769c68e..77f979b92 100644
--- a/lib/src/objects/parse_geo_point.dart
+++ b/lib/src/objects/parse_geo_point.dart
@@ -1,17 +1,17 @@
part of flutter_parse_sdk;
-class ParseGeoPoint extends ParseBase {
- final String className = 'GeoPoint';
+class ParseGeoPoint extends ParseObject {
double _latitude;
double _longitude;
/// Creates a Parse Object of type GeoPoint
- ParseGeoPoint({double latitude = 0.0, double longitude = 0.0}):
- assert(latitude >= -90.0 || latitude <= 90.0),
- assert(longitude >= -180.0 || longitude <= 180.0) {
+ ParseGeoPoint({double latitude = 0.0, double longitude = 0.0, bool debug, ParseHTTPClient client}): super ('GeoPoint') {
_latitude = latitude;
_longitude = longitude;
+
+ if (debug != null) setDebug(debug);
+ if (client != null) setClient(client);
}
double get latitude => _latitude;
diff --git a/lib/src/objects/parse_object.dart b/lib/src/objects/parse_object.dart
index bbc4a3ed5..97ec7cbcf 100644
--- a/lib/src/objects/parse_object.dart
+++ b/lib/src/objects/parse_object.dart
@@ -11,35 +11,51 @@ class ParseObject extends ParseBase {
/// [String] className refers to the Table Name in your Parse Server,
/// [bool] debug will overwrite the current default debug settings and
/// [ParseHttpClient] can be overwritten to create your own HTTP Client
- ParseObject(this.className, {bool debug: false, ParseHTTPClient client}) {
+ ParseObject(this.className, {bool debug: false}): super() {
+ _path = "/classes/$className";
+ setClient(ParseHTTPClient());
+ setDebug(isDebugEnabled(_client, objectLevelDebug: debug));
+ }
- client == null ? _client = ParseHTTPClient() : _client = client;
- _debug = isDebugEnabled(debug, _client);
+ setDebug(bool debug){
+ _debug = debug;
+ }
- _path = "/classes/$className";
- setObjectData(Map());
+ setClient(ParseHTTPClient client){
+ _client = client;
}
/// Gets an object from the server using it's [String] objectId
getObject(String objectId) async {
- var uri = _getBasePath(_path);
- if (objectId != null) uri += "/$objectId";
- var result = await _client.get(uri);
- return _handleResult(result, ParseApiObject.get);
+ try {
+ var uri = "${ParseCoreData().serverUrl}$_path";
+ if (objectId != null) uri += "/$objectId";
+ var result = await _client.get(uri);
+ return handleResponse(result, ParseApiRQ.get);
+ } on Exception catch (e) {
+ return handleException(e, ParseApiRQ.get);
+ }
}
/// Gets all objects from this table - Limited response at the moment
getAll() async {
- var result = await _client.get(_getBasePath(_path));
- return _handleResult(result, ParseApiObject.getAll);
+ try {
+ var result = await _client.get("${ParseCoreData().serverUrl}$_path");
+ return handleResponse(result, ParseApiRQ.getAll);
+ } on Exception catch (e) {
+ return handleException(e, ParseApiRQ.getAll);
+ }
}
/// Creates a new object and saves it online
create() async {
- var uri = _client.data.serverUrl + "$_path";
- var result =
- await _client.post(uri, body: JsonEncoder().convert(getObjectData()));
- return _handleResult(result, ParseApiObject.create);
+ try {
+ var uri = _client.data.serverUrl + "$_path";
+ var result = await _client.post(uri, body: JsonEncoder().convert(getObjectData()));
+ return handleResponse(result, ParseApiRQ.create);
+ } on Exception catch (e) {
+ return handleException(e, ParseApiRQ.create);
+ }
}
/// Saves the current object online
@@ -47,51 +63,57 @@ class ParseObject extends ParseBase {
if (getObjectData() == null) {
return create();
} else {
- var uri = "${_getBasePath(_path)}/$objectId";
- var result =
- await _client.put(uri, body: JsonEncoder().convert(getObjectData()));
- return _handleResult(result, ParseApiObject.save);
+ try {
+ var uri = "${ParseCoreData().serverUrl}$_path/$objectId";
+ var result = await _client.put(uri, body: JsonEncoder().convert(getObjectData()));
+ return handleResponse(result, ParseApiRQ.save);
+ } on Exception catch (e) {
+ return handleException(e, ParseApiRQ.save);
+ }
}
}
/// Can be used to create custom queries
query(String query) async {
- var uri = "${_getBasePath(_path)}?$query";
- var result = await _client.get(uri);
- return _handleResult(result, ParseApiObject.query);
+ try {
+ var uri = "${ParseCoreData().serverUrl}$_path?$query";
+ var result = await _client.get(uri);
+ return handleResponse(result, ParseApiRQ.query);
+ } on Exception catch (e) {
+ return handleException(e, ParseApiRQ.query);
+ }
}
/// Deletes the current object locally and online
delete(String path, String objectId) async {
- var uri = "${_getBasePath(path)}/$objectId";
- var result = await _client.delete(uri);
- return _handleResult(result, ParseApiObject.delete);
+ try {
+ var uri = "${ParseCoreData().serverUrl}$_path/$objectId";
+ var result = await _client.delete(uri);
+ return handleResponse(result, ParseApiRQ.delete);
+ } on Exception catch (e) {
+ return handleException(e, ParseApiRQ.delete);
+ }
}
- /// Generates the path for the object
- _getBasePath(String path) => "${_client.data.serverUrl}$path";
-
/// Handles an API response and logs data if [bool] debug is enabled
- ParseResponse _handleResult(Response response, ParseApiObject type) {
+ @protected
+ ParseResponse handleResponse(Response response, ParseApiRQ type) {
ParseResponse parseResponse = ParseResponse.handleResponse(this, response);
- Map responseData = JsonDecoder().convert(response.body);
- if (_client.data.debug || _debug) {
- var responseString = ' \n';
+ if (_debug) {
+ logger(ParseCoreData().appName, className, type.toString(), parseResponse);
+ }
- responseString += "----"
- "\n${_client.data.appName} API Response ($className : ${type.toString()}) :";
+ return parseResponse;
+ }
- if (parseResponse.success && parseResponse.result != null) {
- responseString += "\nStatus Code: ${parseResponse.statusCode}";
- responseString += "\nPayload: ${responseData.toString()}";
- } else if (!parseResponse.success) {
- responseString += "\nStatus Code: ${responseData['code'] == null ? parseResponse.statusCode : responseData['code']}";
- responseString += "\nException: ${responseData['error'] == null ? responseData.toString() : responseData['error']}";
- }
+ /// Handles an API response and logs data if [bool] debug is enabled
+ @protected
+ ParseResponse handleException(Exception exception, ParseApiRQ type) {
+ ParseResponse parseResponse = ParseResponse.handleException(this, exception);
- responseString += "\n----\n";
- print(responseString);
+ if (_debug) {
+ logger(ParseCoreData().appName, className, type.toString(), parseResponse);
}
return parseResponse;
diff --git a/lib/src/objects/parse_response.dart b/lib/src/objects/parse_response.dart
index d1bfa81bc..daf450c34 100644
--- a/lib/src/objects/parse_response.dart
+++ b/lib/src/objects/parse_response.dart
@@ -4,7 +4,7 @@ class ParseResponse {
bool success = false;
int statusCode = -1;
dynamic result;
- ParseException exception;
+ ParseError error;
/// Handles all the ParseObject responses
///
@@ -12,43 +12,48 @@ class ParseResponse {
/// 1. Fail - [ParseResponse] will be returned with further details
/// 2. Success but no results. [ParseResponse] is returned.
/// 3. Success with results. Again [ParseResponse] is returned
- static handleResponse(ParseBase object, Response value) {
- var response = ParseResponse();
+ static handleResponse(ParseBase object, Response apiResponse) {
+ var parseResponse = ParseResponse();
- if (value != null) {
- response.statusCode = value.statusCode;
+ if (apiResponse != null) {
+ parseResponse.statusCode = apiResponse.statusCode;
- if (value.statusCode != 200) {
- return _handleError(response, value);
- } else if (value.body == "{\"results\":[]}"){
- return _handleSuccessWithNoResults(response, "Successful request, but no results found");
+ if (apiResponse.statusCode != 200) {
+ return _handleError(parseResponse, apiResponse);
+ } else if (apiResponse.body == "{\"results\":[]}"){
+ return _handleSuccessWithNoResults(parseResponse, "Successful request, but no results found");
} else {
- return _handleSuccess(response, object, value.body);
+ return _handleSuccess(parseResponse, object, apiResponse.body);
}
} else {
- response.exception = ParseException();
- response.exception.message = "Error reaching server, or server response was null";
- return response;
+ parseResponse.error = ParseError(message: "Error reaching server, or server response was null");
+ return apiResponse;
}
}
+ /// Handles exception instead of throwing an exception
+ static handleException(ParseBase object, Exception exception) {
+ var response = ParseResponse();
+ response.error = ParseError(message: exception.toString(), isTypeOfException: true);
+ return response;
+ }
+
/// Handles any errors returned in response
- static ParseResponse _handleError(ParseResponse response, Response value) {
- response.exception = ParseException();
- response.exception.message = value.reasonPhrase;
+ static ParseResponse _handleError(ParseResponse response, Response apiResponse) {
+ Map responseData = JsonDecoder().convert(apiResponse.body);
+ response.error = ParseError(code: responseData['code'], message: responseData['error']);
return response;
}
/// Handles successful responses with no results
static ParseResponse _handleSuccessWithNoResults(ParseResponse response, String value) {
response.statusCode = 200;
- response.exception = ParseException();
- response.exception.message = value;
+ response.error = ParseError(code: 1, message: value);
return response;
}
- /// Handles succsful response with results
- static ParseResponse _handleSuccess(ParseResponse response, ParseObject object, String responseBody) {
+ /// Handles successful response with results
+ static ParseResponse _handleSuccess(ParseResponse response, ParseBase object, String responseBody) {
response.success = true;
var map = JsonDecoder().convert(responseBody) as Map;
@@ -63,7 +68,7 @@ class ParseResponse {
}
/// Handles a response with a multiple result object
- static _handleMultipleResults(ParseObject object, dynamic map) {
+ static _handleMultipleResults(ParseBase object, dynamic map) {
var resultsList = List();
for (var value in map) {
@@ -74,7 +79,7 @@ class ParseResponse {
}
/// Handles a response with a single result object
- static _handleSingleResult(ParseObject object, map) {
+ static _handleSingleResult(ParseBase object, map) {
populateObjectBaseData(object, map);
return object.fromJson(map);
}
diff --git a/lib/src/objects/parse_user.dart b/lib/src/objects/parse_user.dart
index ce188d30c..384f08b0f 100644
--- a/lib/src/objects/parse_user.dart
+++ b/lib/src/objects/parse_user.dart
@@ -1,41 +1,77 @@
part of flutter_parse_sdk;
-class ParseUser {
- ParseHTTPClient _client;
+class ParseUser extends ParseBase {
static final String className = '_User';
- String path = "/classes/$className";
+ static final String path = "/classes/$className";
bool _debug;
+ ParseHTTPClient _client;
+
+ String acl;
+ String username;
+ String password;
+ String emailAddress;
/// Creates an instance of ParseUser
///
/// Users can set whether debug should be set on this class with a [bool],
/// they can also create thier own custom version of [ParseHttpClient]
- ParseUser({debug, ParseHTTPClient client}) {
- client != null ? _client = client : _client = ParseHTTPClient();
- _debug = isDebugEnabled(debug, _client);
- }
-
+ ///
/// Creates a new user locally
///
/// Requires [String] username, [String] password. [String] email address
/// is required as well to create a full new user object on ParseServer. Only
/// username and password is required to login
+ ParseUser(this.username, this.password, this.emailAddress, {bool debug, ParseHTTPClient client}) : super() {
+ client == null ? _client = ParseHTTPClient() : _client = client;
+ _debug = isDebugEnabled(client, objectLevelDebug: debug);
+ }
+
+ /// Returns a [User] from a [Map] object
+ fromJson(objectData) {
+ if (getObjectData() == null) {
+ setObjectData(objectData);
+ } else {
+ getObjectData().addAll(objectData);
+ }
+
+ objectId = getObjectData()[OBJECT_ID];
+ createdAt = stringToDateTime(getObjectData()[CREATED_AT]);
+ updatedAt = stringToDateTime(getObjectData()[UPDATED_AT]);
+ acl = getObjectData()[ACL].toString();
+ username = getObjectData()[USERNAME];
+ password = getObjectData()[PASSWORD];
+ emailAddress = getObjectData()[EMAIL];
+
+ if (updatedAt == null) updatedAt = createdAt;
+
+ saveInStorage(PARSE_STORE_USER);
+
+ return getObjectData();
+ }
+
+ /// Returns a [String] that's human readable. Ideal for printing logs
+ @override
+ String toString() => "Username: $username \nEmail Address:$emailAddress";
+
+ static const String USERNAME = 'Username';
+ static const String EMAIL = 'Email';
+ static const String PASSWORD = 'Password';
+ static const String ACL = 'ACL';
+
create(String username, String password, [String emailAddress]) {
- User.init(username, password, emailAddress);
- return User.instance;
+ return ParseUser(username, password, emailAddress);
}
- /// Gets the current user
+ /// Gets the current user from the server
///
/// Current user is stored locally, but in case of a server update [bool]
/// fromServer can be called and an updated version of the [User] object will be
/// returned
- currentUser({bool fromServer: false}) async {
- if (_client.data.sessionId == null) {
- return null;
- } else if (fromServer == false) {
- return User.instance;
- } else {
+ getCurrentUserFromServer() async {
+ // We can't get the current user and session without a sessionId
+ if (_client.data.sessionId == null) return null;
+
+ try {
Uri tempUri = Uri.parse(_client.data.serverUrl);
Uri uri = Uri(
@@ -43,41 +79,53 @@ class ParseUser {
host: tempUri.host,
path: "${tempUri.path}/users/me");
- final response = await _client.get(uri, headers: {
- ParseConstants.HEADER_SESSION_TOKEN: _client.data.sessionId
- });
- return _handleResponse(response, ParseApiUser.currentUser);
+ final response = await _client
+ .get(uri, headers: {HEADER_SESSION_TOKEN: _client.data.sessionId});
+ return _handleResponse(response, ParseApiRQ.currentUser);
+ } on Exception catch (e) {
+ return _handleException(e, ParseApiRQ.currentUser);
}
}
+ /// Gets the current user from storage
+ ///
+ /// Current user is stored locally, but in case of a server update [bool]
+ /// fromServer can be called and an updated version of the [User] object will be
+ /// returned
+ static currentUser() {
+ return _getUserFromLocalStore();
+ }
/// Registers a user on Parse Server
///
/// After creating a new user via [Parse.create] call this method to register
/// that user on Parse
signUp() async {
+ try {
+ if (emailAddress == null) return null;
- if (User().emailAddress == null) return null;
-
- Map bodyData = {};
- bodyData["email"] = User().emailAddress;
- bodyData["password"] = User().password;
- bodyData["username"] = User().username;
+ Map bodyData = {};
+ bodyData["email"] = emailAddress;
+ bodyData["password"] = password;
+ bodyData["username"] = username;
- Uri tempUri = Uri.parse(_client.data.serverUrl);
-
- Uri url = Uri(
- scheme: tempUri.scheme,
- host: tempUri.host,
- path: "${tempUri.path}$path");
-
- final response = await _client.post(url,
- headers: {
- ParseConstants.HEADER_REVOCABLE_SESSION: "1",
- },
- body: JsonEncoder().convert(bodyData));
+ Uri tempUri = Uri.parse(_client.data.serverUrl);
- _handleResponse(response, ParseApiUser.signUp);
- return User.instance;
+ Uri url = Uri(
+ scheme: tempUri.scheme,
+ host: tempUri.host,
+ path: "${tempUri.path}$path");
+
+ final response = await _client.post(url,
+ headers: {
+ HEADER_REVOCABLE_SESSION: "1",
+ },
+ body: JsonEncoder().convert(bodyData));
+
+ _handleResponse(response, ParseApiRQ.signUp);
+ return this;
+ } on Exception catch (e) {
+ return _handleException(e, ParseApiRQ.signUp);
+ }
}
/// Logs a user in via Parse
@@ -85,48 +133,56 @@ class ParseUser {
/// Once a user is created using [Parse.create] and a username and password is
/// provided, call this method to login.
login() async {
- Uri tempUri = Uri.parse(_client.data.serverUrl);
+ try {
+ Uri tempUri = Uri.parse(_client.data.serverUrl);
- Uri url = Uri(
- scheme: tempUri.scheme,
- host: tempUri.host,
- path: "${tempUri.path}/login",
- queryParameters: {
- "username": User.instance.username,
- "password": User.instance.password
- });
+ Uri url = Uri(
+ scheme: tempUri.scheme,
+ host: tempUri.host,
+ path: "${tempUri.path}/login",
+ queryParameters: {"username": username, "password": password});
- final response = await _client.post(url, headers: {
- ParseConstants.HEADER_REVOCABLE_SESSION: "1",
- });
+ final response = await _client.post(url, headers: {
+ HEADER_REVOCABLE_SESSION: "1",
+ });
- _handleResponse(response, ParseApiUser.login);
- return User.instance;
+ _handleResponse(response, ParseApiRQ.login);
+ return this;
+ } on Exception catch (e) {
+ return _handleException(e, ParseApiRQ.login);
+ }
}
/// Removes the current user from the session data
- logout(){
+ logout() {
_client.data.sessionId = null;
- User.logout();
+ setObjectData(null);
}
/// Sends a verification email to the users email address
verificationEmailRequest() async {
- final response = await _client.post(
- "${_client.data.serverUrl}/verificationEmailRequest",
- body: JsonEncoder().convert({"email": User().emailAddress}));
-
- return _handleResponse(
- response, ParseApiUser.verificationEmailRequest);
+ try {
+ final response = await _client.post(
+ "${_client.data.serverUrl}/verificationEmailRequest",
+ body: JsonEncoder().convert({"email": emailAddress}));
+
+ return _handleResponse(response, ParseApiRQ.verificationEmailRequest);
+ } on Exception catch (e) {
+ return _handleException(e, ParseApiRQ.verificationEmailRequest);
+ }
}
/// Sends a password reset email to the users email address
requestPasswordReset() async {
- final response = await _client.post(
- "${_client.data.serverUrl}/requestPasswordReset",
- body: JsonEncoder().convert({"email": User().emailAddress}));
-
- return _handleResponse(response, ParseApiUser.requestPasswordReset);
+ try {
+ final response = await _client.post(
+ "${_client.data.serverUrl}/requestPasswordReset",
+ body: JsonEncoder().convert({"email": emailAddress}));
+
+ return _handleResponse(response, ParseApiRQ.requestPasswordReset);
+ } on Exception catch (e) {
+ return _handleException(e, ParseApiRQ.requestPasswordReset);
+ }
}
/// Saves the current user
@@ -134,59 +190,108 @@ class ParseUser {
/// If changes are made to the current user, call save to sync them with
/// Parse Server
save() async {
- if (User.instance.objectId == null) {
+ if (objectId == null) {
return signUp();
} else {
- final response = await _client.put(
- _client.data.serverUrl + "$path/${User().objectId}",
- body: JsonEncoder().convert(User().getObjectData()));
- return _handleResponse(response, ParseApiUser.save);
+ try {
+ final response = await _client.put(
+ _client.data.serverUrl + "$path/$objectId",
+ body: JsonEncoder().convert(getObjectData()));
+ return _handleResponse(response, ParseApiRQ.save);
+ } on Exception catch (e) {
+ return _handleException(e, ParseApiRQ.save);
+ }
}
}
/// Removes a user from Parse Server locally and online
destroy() async {
- final response = await _client.delete(
- _client.data.serverUrl + "$path/${User().objectId}",
- headers: {"X-Parse-Session-Token": _client.data.sessionId});
-
- _handleResponse(response, ParseApiUser.destroy);
-
- return User.instance.objectId;
+ if (objectId != null) {
+ try {
+ final response = await _client.delete(
+ _client.data.serverUrl + "$path/$objectId",
+ headers: {"X-Parse-Session-Token": _client.data.sessionId});
+ _handleResponse(response, ParseApiRQ.destroy);
+ return objectId;
+ } on Exception catch (e) {
+ return _handleException(e, ParseApiRQ.destroy);
+ }
+ }
}
/// Gets a list of all users (limited return)
- all() async {
- final response = await _client.get(_client.data.serverUrl + "$path");
- return _handleResponse(response, ParseApiUser.all);
+ static all() async {
+
+ var emptyUser = ParseUser(null, null, null);
+
+ try {
+ final response = await ParseHTTPClient().get(
+ "${ParseCoreData().serverUrl}/$path");
+
+ ParseResponse parseResponse = ParseResponse.handleResponse(emptyUser, response);
+
+ if (ParseCoreData().debug) {
+ logger(ParseCoreData().appName, className, ParseApiRQ.getAll.toString(), parseResponse);
+ }
+
+ return parseResponse;
+ } on Exception catch (e) {
+ return ParseResponse.handleException(emptyUser, e);
+ }
}
- /// Handles all the reponse data for this class
- _handleResponse(Response response, ParseApiUser type) {
- Map responseData = JsonDecoder().convert(response.body);
+ static _getUserFromLocalStore() {
+ var userJson = ParseCoreData().getStore().getString(PARSE_STORE_USER);
- var responseString = ' \n';
+ if (userJson != null) {
+ var userMap = JsonDecoder().convert(userJson);
- responseString += "----""\n${_client.data.appName} API Response ($className : ${type.toString()}) :";
+ if (userMap != null) {
+ ParseCoreData().sessionId = userMap['sessionToken'];
- if (response.statusCode == 200 || response.statusCode == 201) {
- responseString += "\nStatus Code: ${response.statusCode}";
- responseString += "\nPayload: ${responseData.toString()}";
+ var user = ParseUser(
+ userMap['username'],
+ userMap['password'],
+ userMap['emailAddress']);
- if (responseData.containsKey('objectId')) {
- User.instance.fromJson(responseData);
- _client.data.sessionId = responseData['sessionToken'];
+ user.fromJson(userMap);
+ return user;
}
- } else {
- responseString += "\nStatus Code: ${responseData['code']}";
- responseString += "\nException: ${responseData['error']}";
}
- if (_client.data.debug || _debug) {
- responseString += "\n----\n";
- print(responseString);
+ return null;
+ }
+
+ /// Handles an API response and logs data if [bool] debug is enabled
+ @protected
+ ParseResponse _handleException(Exception exception, ParseApiRQ type) {
+ ParseResponse parseResponse = ParseResponse.handleException(this, exception);
+
+ if (_debug) {
+ logger(ParseCoreData().appName, className, type.toString(), parseResponse);
}
- return User.instance;
+ return parseResponse;
+ }
+
+ /// Handles all the response data for this class
+ _handleResponse(Response response, ParseApiRQ type) {
+
+ ParseResponse parseResponse = ParseResponse.handleResponse(this, response);
+ if (_debug) {
+ logger(ParseCoreData().appName, className, type.toString(), parseResponse);
+ }
+
+ Map responseData = JsonDecoder().convert(response.body);
+ if (responseData.containsKey('objectId')) {
+ fromJson(responseData);
+ _client.data.sessionId = responseData['sessionToken'];
+ }
+
+ if (type == ParseApiRQ.getAll) {
+ return parseResponse;
+ } else {
+ return this;
+ }
}
}
diff --git a/lib/src/utils/parse_decoder.dart b/lib/src/utils/parse_decoder.dart
new file mode 100644
index 000000000..353b7b4c6
--- /dev/null
+++ b/lib/src/utils/parse_decoder.dart
@@ -0,0 +1,76 @@
+part of flutter_parse_sdk;
+
+class ParseDecoder {
+
+ List _convertJSONArrayToList(List array) {
+ List list = new List();
+ array.forEach((value) {
+ list.add(decode(value));
+ });
+ return list;
+ }
+
+ Map _convertJSONObjectToMap(Map object) {
+ Map map = new Map();
+ object.forEach((key, value) {
+ map.putIfAbsent(key, () => decode(value));
+ });
+ return map;
+ }
+
+ /// Decode any type value
+ dynamic decode(dynamic value) {
+ if (value is List) {
+ return _convertJSONArrayToList(value);
+ }
+
+ if (value is bool) {
+ return value;
+ }
+
+ if (value is int) {
+ return value.toInt();
+ }
+
+ if (value is double) {
+ return value.toDouble();
+ }
+
+ if (value is num) {
+ return value;
+ }
+
+ if (!(value is Map)) {
+ return value;
+ }
+
+ Map map = value;
+ if (!map.containsKey("__type")) {
+ return _convertJSONObjectToMap(map);
+ }
+
+ switch (map["__type"]) {
+ case "Date":
+ String iso = map["iso"];
+ return stringToDateTime(iso);
+ case "Bytes":
+ String val = map["base64"];
+ return base64.decode(val);
+ case "Pointer":
+ String className = map["className"];
+ return new ParseObject(className)..fromJson(map);
+ case "Object":
+ String className = map["className"];
+ if (className == '_User') {
+ return new ParseUser(map['username'], map['password'], map['emailaddress'])..fromJson(map);
+ }
+ return new ParseObject(className)..fromJson(map);
+ case "GeoPoint":
+ num latitude = map["latitude"] ?? 0.0;
+ num longitude = map["longitude"] ?? 0.0;
+ return new ParseGeoPoint(latitude: latitude.toDouble(), longitude: longitude.toDouble());
+ }
+
+ return null;
+ }
+}
\ No newline at end of file
diff --git a/lib/src/utils/parse_encoder.dart b/lib/src/utils/parse_encoder.dart
new file mode 100644
index 000000000..e1c41727f
--- /dev/null
+++ b/lib/src/utils/parse_encoder.dart
@@ -0,0 +1,49 @@
+part of flutter_parse_sdk;
+
+class ParseEncoder {
+
+ bool isValidType(dynamic value) {
+ return value == null ||
+ value is String ||
+ value is num ||
+ value is bool ||
+ value is DateTime ||
+ value is List ||
+ value is Map ||
+ value is ParseObject ||
+ value is ParseGeoPoint ||
+ value is ParseUser;
+ }
+
+ /// Custom json encoder for types related to parse
+ dynamic encode(dynamic value) {
+ if (value is DateTime) return _encodeDate(value);
+
+ if (value is List) {
+ return value.map((v){
+ return encode(v);
+ }).toList();
+ }
+
+ if (value is ParseObject) {
+ return value.toJson;
+ }
+
+ if (value is ParseUser) {
+ return value.toJson;
+ }
+
+ if (value is ParseGeoPoint) {
+ return value.toJson;
+ }
+
+ return value;
+ }
+
+ Map _encodeDate(DateTime date) {
+ return {
+ "__type": "Date",
+ "iso": dateTimeToString(date)
+ };
+ }
+}
\ No newline at end of file
diff --git a/lib/src/utils/parse_logger.dart b/lib/src/utils/parse_logger.dart
new file mode 100644
index 000000000..b35df4129
--- /dev/null
+++ b/lib/src/utils/parse_logger.dart
@@ -0,0 +1,26 @@
+part of flutter_parse_sdk;
+
+void logger(
+ String appName,
+ String className,
+ String type,
+ ParseResponse parseResponse) {
+ var responseString = ' \n';
+
+ responseString += "----\n$appName API Response ($className : $type) :";
+
+ if (parseResponse.success && parseResponse.result != null) {
+ responseString += "\nStatus Code: ${parseResponse.statusCode}";
+ responseString += "\nPayload: ${parseResponse.result.toString()}";
+ } else if (!parseResponse.success) {
+ responseString += "\nStatus Code: ${parseResponse.error.code}";
+ responseString += "\nType: ${parseResponse.error.type}";
+
+ String errorOrException = parseResponse.error.isTypeOfException ? "Exception" : "Error";
+
+ responseString += "\n$errorOrException: ${parseResponse.error.message}";
+ }
+
+ responseString += "\n----\n";
+ print(responseString);
+}
\ No newline at end of file
diff --git a/lib/src/utils/parse_utils.dart b/lib/src/utils/parse_utils.dart
index 3ab8c88b8..7a448b6db 100644
--- a/lib/src/utils/parse_utils.dart
+++ b/lib/src/utils/parse_utils.dart
@@ -1,15 +1,11 @@
part of flutter_parse_sdk;
-/// Checks wether debug is enabled
+/// Checks whether debug is enabled
///
/// Debug can be set in 2 places, one global param in the Parse.initialise, and
-/// then can be overriden class by class
-bool isDebugEnabled(bool debug, ParseHTTPClient _client) {
- if (debug == null) {
- _client.data.debug != null ? debug = _client.data.debug : debug = false;
- } else {
- return debug;
- }
-
+/// then can be overidden class by class
+bool isDebugEnabled(ParseHTTPClient _client, {objectLevelDebug: false}) {
+ bool debug = objectLevelDebug;
+ if (ParseCoreData().debug != null) debug = ParseCoreData().debug;
return debug;
}
\ No newline at end of file
diff --git a/lib/src/utils/parse_utils_date.dart b/lib/src/utils/parse_utils_date.dart
index 3f8561188..c0073abbd 100644
--- a/lib/src/utils/parse_utils_date.dart
+++ b/lib/src/utils/parse_utils_date.dart
@@ -1,23 +1,51 @@
part of flutter_parse_sdk;
/// Converts a [String] into a [DateTime] from a Parse Server format
-DateTime convertStringToDateTime(String date) {
+DateTime stringToDateTime(String date) {
if (date == null) return null;
try {
- var formatter = DateFormat(ParseConstants.PARSE_DATE_FORMAT);
- return formatter.parse(_removeTimeZones(date));
+ return DateTime.parse(date);
} on FormatException {
return null;
}
}
-/// Removes timezones as our current implementation does work
-String _removeTimeZones(String date) {
- // TODO - library doesn't support timezones. Monitor this
- if (date.contains('zzzZ')) {
- return date.replaceRange(date.length - 4, date.length, '');
- } else {
- return date;
+/// Serialize [DateTime] into an ISO-8601 full-precision extended format representation.
+String dateTimeToString(DateTime datetime) {
+ if (datetime == null) return null;
+
+ if (!datetime.isUtc) {
+ datetime = datetime.toUtc();
}
+
+ String y = _fourDigits(datetime.year);
+ String m = _twoDigits(datetime.month);
+ String d = _twoDigits(datetime.day);
+ String h = _twoDigits(datetime.hour);
+ String min = _twoDigits(datetime.minute);
+ String sec = _twoDigits(datetime.second);
+ String ms = _threeDigits(datetime.millisecond);
+
+ return "$y-$m-${d}T$h:$min:$sec.${ms}Z";
+}
+
+String _fourDigits(int n) {
+ int absN = n.abs();
+ String sign = n < 0 ? "-" : "";
+ if (absN >= 1000) return "$n";
+ if (absN >= 100) return "${sign}0$absN";
+ if (absN >= 10) return "${sign}00$absN";
+ return "${sign}000$absN";
+}
+
+String _threeDigits(int n) {
+ if (n >= 100) return "$n";
+ if (n >= 10) return "0$n";
+ return "00$n";
}
+
+String _twoDigits(int n) {
+ if (n >= 10) return "$n";
+return "0$n";
+}
\ No newline at end of file
diff --git a/lib/src/utils/parse_utils_objects.dart b/lib/src/utils/parse_utils_objects.dart
index 8d218e62b..2c59d29e0 100644
--- a/lib/src/utils/parse_utils_objects.dart
+++ b/lib/src/utils/parse_utils_objects.dart
@@ -1,9 +1,9 @@
part of flutter_parse_sdk;
/// Populates the base object data from a server response
-populateObjectBaseData(ParseObject object, Map objectData) {
- object.set(ParseConstants.OBJECT_ID, objectData[ParseConstants.OBJECT_ID]);
- object.set(ParseConstants.CREATED_AT, convertStringToDateTime(objectData[ParseConstants.CREATED_AT]));
- object.set(ParseConstants.OBJECT_ID, convertStringToDateTime(objectData[ParseConstants.UPDATED_AT]));
+populateObjectBaseData(ParseBase object, Map objectData) {
+ object.set(OBJECT_ID, objectData[OBJECT_ID]);
+ object.set(CREATED_AT, stringToDateTime(objectData[CREATED_AT]));
+ object.set(OBJECT_ID, stringToDateTime(objectData[UPDATED_AT]));
return object;
}
diff --git a/pubspec.yaml b/pubspec.yaml
index add1ec577..9c7ef5f04 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,6 +1,6 @@
name: parse_server_sdk
-description: This is a Flutter plugin that allows communication with a Parse Server, (https://parseplatform.org)
-version: 1.0.2
+description: Flutter plugin for Parse Server, (https://parseplatform.org), (https://back4app.com)
+version: 1.0.3
homepage: https://github.com/phillwiggins/flutter_parse_sdk
author: PhillWiggins
@@ -16,4 +16,4 @@ dependencies:
http: ^0.12.0
# Utils
- intl: ^0.15.7
\ No newline at end of file
+ shared_preferences: ^0.4.3
\ No newline at end of file