diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c237a8a4..d649e3e48 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,12 @@ +## 1.0.12 +Fixed logout + +## 1.0.11 +ParseFile fixed +Anonymous login +SecurityContext +CloudFunctions with objects + ## 1.0.10 Add ParseConfig. Fixed whereEqualsTo('', PARSEOBJECT) and other queries diff --git a/README.md b/README.md index d9927e47d..54869f96d 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.10 + parse_server_sdk: ^1.0.12 ``` 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. @@ -33,8 +33,11 @@ Parse().initialize( ApplicationConstants.keyApplicationId, ApplicationConstants.keyParseServerUrl, masterKey: ApplicationConstants.keyParseMasterKey, - debug: true, - liveQuery: true); + clientKey: ApplicationConstants.keyParseClientKey, + debug: true, + liveQuery: true, + autoSendSessionId: true, + securityContext: securityContext); ``` ## Queries diff --git a/example/lib/diet_plan.dart b/example/lib/diet_plan.dart index 52995379d..2a064a3b7 100644 --- a/example/lib/diet_plan.dart +++ b/example/lib/diet_plan.dart @@ -1,15 +1,15 @@ import 'dart:core'; -import 'package:parse_server_sdk/parse.dart'; +import 'package:parse_server_sdk/parse_server_sdk.dart'; class DietPlan extends ParseObject implements ParseCloneable { - DietPlan() : super(_keyTableName); - DietPlan.clone(): this(); + DietPlan.clone() : this(); /// Looks strangely hacky but due to Flutter not using reflection, we have to /// mimic a clone - @override clone(Map map) => DietPlan.clone()..fromJson(map); + @override + clone(Map map) => DietPlan.clone()..fromJson(map); static const String _keyTableName = 'Diet_Plans'; static const String keyName = 'Name'; diff --git a/example/lib/main.dart b/example/lib/main.dart index cee1b4c99..99468d277 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_plugin_example/application_constants.dart'; import 'package:flutter_plugin_example/diet_plan.dart'; -import 'package:parse_server_sdk/parse.dart'; +import 'package:parse_server_sdk/parse_server_sdk.dart'; void main() => runApp(new MyApp()); @@ -155,9 +155,14 @@ class _MyAppState extends State { // Best practice for starting the app. This will check for a valid user user = await ParseUser.currentUser(); await user.logout(); - user = await ParseUser.currentUser(); - response = await ParseUser.getCurrentUserFromServer(); + user = + ParseUser("TestFlutter", "TestPassword123", "phill.wiggins@gmail.com"); + response = await user.login(); + if (response.success) user = response.result; + + response = await ParseUser.getCurrentUserFromServer( + token: user.get(keyHeaderSessionToken)); if (response.success) user = response.result; response = await user.save(); @@ -178,20 +183,13 @@ class _MyAppState extends State { } function() async { - var user = - ParseUser("TestFlutter", "TestPassword123", "TestFlutterSDK@gmail.com"); - await user.signUp(); - var loginResponse = await user.login(); - if (loginResponse.success) user = loginResponse.result; - - var customClient = ParseHTTPClient(); - customClient.additionalHeaders = { - keyHeaderSessionToken: ParseCoreData().sessionId - }; - var function = ParseCloudFunction('hello', client: customClient); - function.execute(); - - user.destroy(); + var function = ParseCloudFunction('hello'); + var result = await function.executeObjectFunction(); + if (result.success) { + if (result.result is ParseObject) { + print((result.result as ParseObject).className); + } + } } functionWithParameters() async { diff --git a/lib/parse.dart b/lib/parse_server_sdk.dart similarity index 72% rename from lib/parse.dart rename to lib/parse_server_sdk.dart index 50ced0b16..a6c9ff267 100644 --- a/lib/parse.dart +++ b/lib/parse_server_sdk.dart @@ -22,13 +22,13 @@ 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_live_query.dart'; part 'src/network/parse_query.dart'; part 'src/objects/parse_base.dart'; -part 'src/objects/parse_clonable.dart'; +part 'src/objects/parse_cloneable.dart'; part 'src/objects/parse_config.dart'; @@ -58,11 +58,11 @@ part 'src/utils/parse_utils.dart'; class Parse { ParseCoreData data; - bool _hasBeenInitialised = false; + bool _hasBeenInitialized = false; - /// To initialise Parse Server in your application + /// To initialize Parse Server in your application /// - /// This should be initialised in MyApp() creation + /// This should be initialized in MyApp() creation /// /// ``` /// Parse().initialize( @@ -79,6 +79,7 @@ class Parse { String clientKey, String masterKey, String sessionId, + bool autoSendSessionId, SecurityContext securityContext}) { ParseCoreData.init(appId, serverUrl, debug: debug, @@ -87,30 +88,37 @@ class Parse { masterKey: masterKey, clientKey: clientKey, sessionId: sessionId, + autoSendSessionId: autoSendSessionId, securityContext: securityContext); - ParseCoreData().initStorage(); - - _hasBeenInitialised = true; + _hasBeenInitialized = true; return Parse(); } - bool hasParseBeenInitialised() => _hasBeenInitialised; + bool hasParseBeenInitialized() => _hasBeenInitialized; - Future healthCheck() async { + Future healthCheck( + {bool debug, ParseHTTPClient client, bool autoSendSessionId}) async { ParseResponse parseResponse; + bool _debug = isDebugEnabled(objectLevelDebug: debug); + ParseHTTPClient _client = client ?? + ParseHTTPClient( + autoSendSessionId: + autoSendSessionId ?? ParseCoreData().autoSendSessionId, + securityContext: ParseCoreData().securityContext); + try { - var response = await ParseHTTPClient(ParseCoreData().securityContext) - .get("${ParseCoreData().serverUrl}$keyEndPointHealth"); + var response = + await _client.get("${ParseCoreData().serverUrl}$keyEndPointHealth"); parseResponse = ParseResponse.handleResponse(this, response, returnAsResult: true); } on Exception catch (e) { parseResponse = ParseResponse.handleException(e); } - if (ParseCoreData().debug) { + if (_debug) { logger(ParseCoreData().appName, keyClassMain, ParseApiRQ.healthCheck.toString(), parseResponse); } diff --git a/lib/src/base/parse_constants.dart b/lib/src/base/parse_constants.dart index d501b6029..e596da78c 100644 --- a/lib/src/base/parse_constants.dart +++ b/lib/src/base/parse_constants.dart @@ -1,12 +1,13 @@ part of flutter_parse_sdk; // Library -const String keySdkVersion = '1.0.10'; +const String keySdkVersion = '1.0.12'; const String keyLibraryName = 'Flutter Parse SDK'; // End Points const String keyEndPointUserName = '/users/me'; const String keyEndPointLogin = '/login'; +const String keyEndPointLogout = '/logout'; const String keyEndPointUsers = '/users'; const String keyEndPointVerificationEmail = '/verificationEmailRequest'; const String keyEndPointRequestPasswordReset = '/requestPasswordReset'; @@ -21,6 +22,7 @@ const String keyVarUpdatedAt = 'updatedAt'; const String keyVarUsername = 'username'; const String keyVarEmail = 'email'; const String keyVarPassword = 'password'; +const String keyVarSessionToken = 'sessionToken'; const String keyVarAcl = 'ACL'; // Classes diff --git a/lib/src/data/parse_core_data.dart b/lib/src/data/parse_core_data.dart index c19f82cd7..b5b0bccee 100644 --- a/lib/src/data/parse_core_data.dart +++ b/lib/src/data/parse_core_data.dart @@ -17,6 +17,7 @@ class ParseCoreData { masterKey, clientKey, sessionId, + autoSendSessionId, securityContext}) { _instance = ParseCoreData._init(appId, serverUrl); @@ -26,6 +27,8 @@ class ParseCoreData { if (clientKey != null) _instance.clientKey = clientKey; if (masterKey != null) _instance.masterKey = masterKey; if (sessionId != null) _instance.sessionId = sessionId; + if (autoSendSessionId != null) + _instance.autoSendSessionId = autoSendSessionId; if (securityContext != null) _instance.securityContext = securityContext; } @@ -36,6 +39,7 @@ class ParseCoreData { String masterKey; String clientKey; String sessionId; + bool autoSendSessionId; SecurityContext securityContext; bool debug; SharedPreferences storage; @@ -52,12 +56,8 @@ class ParseCoreData { this.sessionId = sessionId; } - void initStorage() async { - storage = await SharedPreferences.getInstance(); - } - Future getStore() async { - return storage != null ? storage : await SharedPreferences.getInstance(); + return storage ?? (storage = await SharedPreferences.getInstance()); } @override diff --git a/lib/src/enums/parse_enum_api_rq.dart b/lib/src/enums/parse_enum_api_rq.dart index 0d9d93db5..6b6f2b338 100644 --- a/lib/src/enums/parse_enum_api_rq.dart +++ b/lib/src/enums/parse_enum_api_rq.dart @@ -12,6 +12,7 @@ enum ParseApiRQ { currentUser, signUp, login, + logout, loginAnonymous, verificationEmailRequest, requestPasswordReset, diff --git a/lib/src/network/parse_http_client.dart b/lib/src/network/parse_http_client.dart index c84d9842d..a31da62da 100644 --- a/lib/src/network/parse_http_client.dart +++ b/lib/src/network/parse_http_client.dart @@ -3,12 +3,15 @@ part of flutter_parse_sdk; /// Creates a custom version of HTTP Client that has Parse Data Preset class ParseHTTPClient extends BaseClient { final Client _client; + final bool _autoSendSessionId; final String _userAgent = "$keyLibraryName $keySdkVersion"; ParseCoreData data = ParseCoreData(); Map additionalHeaders; - ParseHTTPClient([SecurityContext securityContext]) - : _client = securityContext != null + ParseHTTPClient( + {bool autoSendSessionId = false, SecurityContext securityContext}) + : _autoSendSessionId = autoSendSessionId, + _client = securityContext != null ? IOClient(HttpClient(context: securityContext)) : IOClient(); @@ -17,13 +20,19 @@ class ParseHTTPClient extends BaseClient { Future send(BaseRequest request) { request.headers[keyHeaderUserAgent] = _userAgent; request.headers[keyHeaderApplicationId] = data.applicationId; + if ((_autoSendSessionId == true) && + (data.sessionId != null) && + (request.headers[keyHeaderSessionToken] == null)) + request.headers[keyHeaderSessionToken] = data.sessionId; - if (data.clientKey != null) request.headers[keyHeaderClientKey] = data.clientKey; - if (data.masterKey != null) request.headers[keyHeaderMasterKey] = data.masterKey; + if (data.clientKey != null) + request.headers[keyHeaderClientKey] = data.clientKey; + if (data.masterKey != null) + request.headers[keyHeaderMasterKey] = data.masterKey; /// If developer wants to add custom headers, extend this class and add headers needed. - if (additionalHeaders != null && additionalHeaders.length > 0){ - additionalHeaders.forEach((k,v) => request.headers[k] = v); + if (additionalHeaders != null && additionalHeaders.length > 0) { + additionalHeaders.forEach((k, v) => request.headers[k] = v); } return _client.send(request); diff --git a/lib/src/network/parse_livequery.dart b/lib/src/network/parse_live_query.dart similarity index 100% rename from lib/src/network/parse_livequery.dart rename to lib/src/network/parse_live_query.dart diff --git a/lib/src/network/parse_query.dart b/lib/src/network/parse_query.dart index ce3958560..3d3813e74 100644 --- a/lib/src/network/parse_query.dart +++ b/lib/src/network/parse_query.dart @@ -27,7 +27,7 @@ class QueryBuilder { limiters['where'] = where; } - /// Orders the results ascedingly. + /// Sorts the results in ascending order. /// /// [String] order will be the column of the table that the results are /// ordered by @@ -35,7 +35,7 @@ class QueryBuilder { limiters["order"] = order; } - /// Orders the results descendingly. + /// Sorts the results descending order. /// /// [String] order will be the column of the table that the results are /// ordered by @@ -48,12 +48,12 @@ class QueryBuilder { /// [String] keys will only return the columns of a result you want the data for, /// this is useful for large objects void keysToReturn(List keys) { - limiters["keys"] = concatArray(keys); + limiters["keys"] = concatenateArray(keys); } /// Includes other ParseObjects stored as a Pointer void includeObject(List objectTypes) { - limiters["include"] = concatArray(objectTypes); + limiters["include"] = concatenateArray(objectTypes); } /// Returns an object where the [String] column starts with [value] @@ -131,7 +131,7 @@ class QueryBuilder { MapEntry(column, value), "\$nin")); } - /// Returns an object where the [String] column for the object has data correctley entered/saved + /// 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")); @@ -211,7 +211,7 @@ class QueryBuilder { return queryBuilder; } - String concatArray(List queries) { + String concatenateArray(List queries) { String queryBuilder = ""; for (var item in queries) { @@ -252,17 +252,17 @@ 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 sanitisedQueries = List(); + List sanitizedQueries = List(); List keysAlreadyCompacted = List(); // Run through each query for (var query in queries) { - // Add queries that don't need sanitising + // Add queries that don't need sanitizing if (query.key == _NO_OPERATOR_NEEDED || query.key == _SINGLE_QUERY) { - sanitisedQueries.add(MapEntry(_NO_OPERATOR_NEEDED, query.value)); + sanitizedQueries.add(MapEntry(_NO_OPERATOR_NEEDED, query.value)); } - // Check if query with same column name has been sanitised + // Check if query with same column name has been sanitized if (!keysAlreadyCompacted.contains(query.key) && query.key != _NO_OPERATOR_NEEDED && query.key != _SINGLE_QUERY) { @@ -290,11 +290,11 @@ class QueryBuilder { } } - sanitisedQueries.add(MapEntry(query.key, queryStart += "{$queryEnd}")); + sanitizedQueries.add(MapEntry(query.key, queryStart += "{$queryEnd}")); } } - return sanitisedQueries; + return sanitizedQueries; } /// Adds the limiters to the query, i.e. skip=10, limit=10 diff --git a/lib/src/objects/parse_base.dart b/lib/src/objects/parse_base.dart index 55007efc3..8cc15fba9 100644 --- a/lib/src/objects/parse_base.dart +++ b/lib/src/objects/parse_base.dart @@ -88,7 +88,7 @@ abstract class ParseBase { /// Returns the objects variables @protected - Map getObjectData() => _objectData != null ? _objectData : Map(); + Map getObjectData() => _objectData ?? Map(); /// Saves in storage @protected @@ -147,10 +147,10 @@ abstract class ParseBase { /// Saves item to simple key pair value storage /// /// Replicates Android SDK pin process and saves object to storage - Future unpin() async { + Future unpin({String key}) async { if (objectId != null) { - await SharedPreferences.getInstance() - ..remove(objectId); + await ParseCoreData().getStore() + ..remove(key ?? objectId); return true; } @@ -165,13 +165,7 @@ abstract class ParseBase { var itemFromStore = (await ParseCoreData().getStore()).getString(objectId); - if (itemFromStore != null) { - var map = json.decode(itemFromStore); - - if (map != null) { - return fromJson(map); - } - } + if (itemFromStore != null) return fromJson(json.decode(itemFromStore)); } return null; } diff --git a/lib/src/objects/parse_clonable.dart b/lib/src/objects/parse_cloneable.dart similarity index 100% rename from lib/src/objects/parse_clonable.dart rename to lib/src/objects/parse_cloneable.dart diff --git a/lib/src/objects/parse_config.dart b/lib/src/objects/parse_config.dart index d2fbc4d67..14e7b025e 100644 --- a/lib/src/objects/parse_config.dart +++ b/lib/src/objects/parse_config.dart @@ -1,12 +1,15 @@ part of flutter_parse_sdk; class ParseConfig extends ParseObject { - var _client = ParseHTTPClient(ParseCoreData().securityContext); - /// Creates an instance of ParseConfig so that you can grab all configs from the server - ParseConfig({bool debug, ParseHTTPClient client}) : super('config') { - if (debug != null) setDebug(debug); - if (client != null) setClient(client); + ParseConfig({bool debug, ParseHTTPClient client, bool autoSendSessionId}) + : super('config') { + _debug = isDebugEnabled(objectLevelDebug: debug); + _client = client ?? + ParseHTTPClient( + autoSendSessionId: + autoSendSessionId ?? ParseCoreData().autoSendSessionId, + securityContext: ParseCoreData().securityContext); } /// Gets all configs from the server diff --git a/lib/src/objects/parse_error.dart b/lib/src/objects/parse_error.dart index 3817213ec..e2d059206 100644 --- a/lib/src/objects/parse_error.dart +++ b/lib/src/objects/parse_error.dart @@ -48,7 +48,7 @@ class ParseError { 204: 'EmailMissing', 205: 'EmailNotFound', 206: 'SessionMissing', - 207: 'MustCreateUserThroughSignup', + 207: 'MustCreateUserThroughSignUp', 208: 'AccountAlreadyLinked', 209: 'InvalidSessionToken', 250: 'LinkedIdMissing', @@ -63,7 +63,7 @@ class ParseError { ParseError( {this.code = -1, - this.message = "Unkown error", + this.message = "Unknown error", this.isTypeOfException = false, bool debug: false}) { type = exceptions[code]; diff --git a/lib/src/objects/parse_file.dart b/lib/src/objects/parse_file.dart index 5c31f87c1..531d1422e 100644 --- a/lib/src/objects/parse_file.dart +++ b/lib/src/objects/parse_file.dart @@ -1,28 +1,18 @@ part of flutter_parse_sdk; class ParseFile extends ParseObject { - File _file; - String _fileName; - String _fileUrl; + File file; + String name; + String url; @override String _path; - String get name => _fileName; - - String get url => _fileUrl; - - File get file => _file; - - set url(String url) => _fileUrl = url; - - set name(String name) => _fileName = name; - bool get saved => url != null; @override toJson({bool forApiRQ: false}) => - {'__type': keyFile, 'name': _fileName, 'url': _fileUrl}; + {'__type': keyFile, 'name': name, 'url': url}; @override String toString() => json.encode(toString()); @@ -30,54 +20,60 @@ class ParseFile extends ParseObject { /// Creates a new file /// /// {https://docs.parseplatform.org/rest/guide/#files/} - ParseFile(this._file, - {String name, String url, bool debug, ParseHTTPClient client}) + ParseFile(this.file, + {String name, + String url, + bool debug, + ParseHTTPClient client, + bool autoSendSessionId}) : super(keyFile) { - client == null - ? _client = ParseHTTPClient(ParseCoreData().securityContext) - : _client = client; - _debug = isDebugEnabled(objectLevelDebug: debug); - if (_file != null) { - this._fileName = path.basename(_file.path); - this._path = 'files/$_fileName'; + _client = client ?? + ParseHTTPClient( + autoSendSessionId: + autoSendSessionId ?? ParseCoreData().autoSendSessionId, + securityContext: ParseCoreData().securityContext); + + if (file != null) { + this.name = path.basename(file.path); + this._path = 'files/$name'; } else { - this._fileName = name; - this._fileUrl = url; + this.name = name; + this.url = url; } } Future loadStorage() async { Directory tempPath = await getTemporaryDirectory(); - if (_fileName == null) { - _file = null; + if (name == null) { + file = null; return this; } - File possibleFile = new File("${tempPath.path}/$_fileName"); + File possibleFile = new File("${tempPath.path}/$name"); bool exists = await possibleFile.exists(); if (exists) { - _file = possibleFile; + file = possibleFile; } else { - _file = null; + file = null; } return this; } Future download() async { - if (_fileUrl == null) { + if (url == null) { return this; } Directory tempPath = await getTemporaryDirectory(); - this._file = new File("${tempPath.path}/$_fileName"); - await _file.create(); + this.file = new File("${tempPath.path}/$name"); + await file.create(); - var response = await _client.get(_fileUrl); - _file.writeAsBytes(response.bodyBytes); + var response = await _client.get(url); + file.writeAsBytes(response.bodyBytes); return this; } @@ -88,13 +84,13 @@ class ParseFile extends ParseObject { return this; } - final ext = path.extension(_file.path).replaceAll('.', ''); + final ext = path.extension(file.path).replaceAll('.', ''); final headers = { HttpHeaders.contentTypeHeader: getContentType(ext) }; var uri = _client.data.serverUrl + "$_path"; - final body = await _file.readAsBytes(); + final body = await file.readAsBytes(); final response = await _client.post(uri, headers: headers, body: body); return handleResponse( this, response, ParseApiRQ.upload, _debug, className); diff --git a/lib/src/objects/parse_function.dart b/lib/src/objects/parse_function.dart index 6c0e7e632..7b23368f7 100644 --- a/lib/src/objects/parse_function.dart +++ b/lib/src/objects/parse_function.dart @@ -9,12 +9,17 @@ class ParseCloudFunction extends ParseObject { /// Creates a new cloud function object /// /// {https://docs.parseplatform.org/cloudcode/guide/} - ParseCloudFunction(this.functionName, {bool debug, ParseHTTPClient client}) + ParseCloudFunction(this.functionName, + {bool debug, ParseHTTPClient client, bool autoSendSessionId}) : super(functionName) { _path = "/functions/$functionName"; - if (debug != null) setDebug(debug); - if (client != null) setClient(client); + _debug = isDebugEnabled(objectLevelDebug: debug); + _client = client ?? + ParseHTTPClient( + autoSendSessionId: + autoSendSessionId ?? ParseCoreData().autoSendSessionId, + securityContext: ParseCoreData().securityContext); } /// Executes a cloud function diff --git a/lib/src/objects/parse_geo_point.dart b/lib/src/objects/parse_geo_point.dart index f0ff5512b..e541fcefb 100644 --- a/lib/src/objects/parse_geo_point.dart +++ b/lib/src/objects/parse_geo_point.dart @@ -9,15 +9,18 @@ class ParseGeoPoint extends ParseObject { {double latitude = 0.0, double longitude = 0.0, bool debug, - ParseHTTPClient client}) + ParseHTTPClient client, + bool autoSendSessionId}) : super(keyGeoPoint) { _latitude = latitude; _longitude = longitude; - client == null - ? _client = ParseHTTPClient(ParseCoreData().securityContext) - : _client = client; _debug = isDebugEnabled(objectLevelDebug: debug); + _client = client ?? + ParseHTTPClient( + autoSendSessionId: + autoSendSessionId ?? ParseCoreData().autoSendSessionId, + securityContext: ParseCoreData().securityContext); } double get latitude => _latitude; @@ -33,4 +36,4 @@ class ParseGeoPoint extends ParseObject { assert(value >= -180.0 || value <= 180.0); _longitude = value; } -} \ No newline at end of file +} diff --git a/lib/src/objects/parse_object.dart b/lib/src/objects/parse_object.dart index 3eea1587c..5c28f8e8a 100644 --- a/lib/src/objects/parse_object.dart +++ b/lib/src/objects/parse_object.dart @@ -1,7 +1,6 @@ part of flutter_parse_sdk; class ParseObject extends ParseBase implements ParseCloneable { - ParseObject.clone(String className) : this(className); @override @@ -16,19 +15,18 @@ class ParseObject extends ParseBase implements ParseCloneable { /// [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(String className, {bool debug: false}) : super() { + ParseObject(String className, + {bool debug: false, ParseHTTPClient client, bool autoSendSessionId}) + : super() { setClassName(className); _path = "$keyEndPointClasses$className"; - setClient(ParseHTTPClient(ParseCoreData().securityContext)); - setDebug(isDebugEnabled(objectLevelDebug: debug)); - } - - void setDebug(bool debug) { - _debug = debug; - } - void setClient(ParseHTTPClient client) { - _client = client; + _debug = isDebugEnabled(objectLevelDebug: debug); + _client = client ?? + ParseHTTPClient( + autoSendSessionId: + autoSendSessionId ?? ParseCoreData().autoSendSessionId, + securityContext: ParseCoreData().securityContext); } String toPointer() => parseEncode(this); diff --git a/lib/src/objects/parse_user.dart b/lib/src/objects/parse_user.dart index 86b469440..7c7b05e7f 100644 --- a/lib/src/objects/parse_user.dart +++ b/lib/src/objects/parse_user.dart @@ -30,10 +30,15 @@ class ParseUser extends ParseObject implements ParseCloneable { set emailAddress(String emailAddress) => set(keyVarEmail, emailAddress); + String get sessionToken => super.get(keyVarSessionToken); + + set sessionToken(String sessionToken) => + set(keyVarSessionToken, sessionToken); + /// 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] + /// they can also create their own custom version of [ParseHttpClient] /// /// Creates a new user locally /// @@ -41,16 +46,18 @@ class ParseUser extends ParseObject implements ParseCloneable { /// is required as well to create a full new user object on ParseServer. Only /// username and password is required to login ParseUser(String username, String password, String emailAddress, - {bool debug, ParseHTTPClient client}) + {String sessionToken, bool debug, ParseHTTPClient client}) : super(keyClassUser) { - client == null - ? _client = ParseHTTPClient(ParseCoreData().securityContext) - : _client = client; _debug = isDebugEnabled(objectLevelDebug: debug); + _client = client ?? + ParseHTTPClient( + autoSendSessionId: true, + securityContext: ParseCoreData().securityContext); this.username = username; this.password = password; this.emailAddress = emailAddress; + this.sessionToken = sessionToken; } ParseUser.forQuery() : super(keyClassUser); @@ -65,16 +72,21 @@ class ParseUser extends ParseObject implements ParseCloneable { /// fromServer can be called and an updated version of the [User] object will be /// returned static Future getCurrentUserFromServer( - {String token, bool debug}) async { + {String token, bool debug, ParseHTTPClient client}) async { bool _debug = isDebugEnabled(objectLevelDebug: debug); + ParseHTTPClient _client = client ?? + ParseHTTPClient( + autoSendSessionId: true, + securityContext: ParseCoreData().securityContext); // We can't get the current user and session without a sessionId - if (token == null && ParseCoreData().sessionId == null) { + if ((ParseCoreData().sessionId == null) && (token == null)) { return null; } - if (token == null) { - token = ParseCoreData().sessionId; + final Map headers = {}; + if (token != null) { + headers[keyHeaderSessionToken] = token; } try { @@ -85,8 +97,7 @@ class ParseUser extends ParseObject implements ParseCloneable { host: tempUri.host, path: "${tempUri.path}$keyEndPointUserName"); - final response = await ParseHTTPClient(ParseCoreData().securityContext) - .get(uri, headers: {keyHeaderSessionToken: token}); + final response = await _client.get(uri, headers: headers); return _handleResponse(_getEmptyUser(), response, ParseApiRQ.currentUser, _debug, _getEmptyUser().className); } on Exception catch (e) { @@ -100,7 +111,7 @@ class ParseUser extends ParseObject implements ParseCloneable { /// 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() { + static Future currentUser() { return _getUserFromLocalStore(); } @@ -195,11 +206,36 @@ class ParseUser extends ParseObject implements ParseCloneable { } } - /// Removes the current user from the session data - logout() { + /// Sends a request to delete the sessions token from the + /// server. Will also delete the local user data unless + /// deleteLocalUserData is false. + Future logout({bool deleteLocalUserData = true}) async { + final String sessionId = _client.data.sessionId; + _client.data.sessionId = null; - unpin(); - setObjectData(null); + ParseCoreData().setSessionId(null); + + if (deleteLocalUserData == true) { + unpin(key: keyParseStoreUser); + setObjectData(null); + } + + try { + Uri tempUri = Uri.parse(_client.data.serverUrl); + + Uri url = Uri( + scheme: tempUri.scheme, + host: tempUri.host, + path: "${tempUri.path}$keyEndPointLogout"); + + final response = + await _client.post(url, headers: {keyHeaderSessionToken: sessionId}); + + return _handleResponse( + this, response, ParseApiRQ.logout, _debug, className); + } on Exception catch (e) { + return _handleException(e, ParseApiRQ.logout, _debug, className); + } } /// Sends a verification email to the users email address @@ -242,9 +278,7 @@ class ParseUser extends ParseObject implements ParseCloneable { var uri = _client.data.serverUrl + "$path/$objectId"; var body = json.encode(toJson(forApiRQ: true), toEncodable: dateTimeEncoder); - final response = await _client.put(uri, - headers: {keyHeaderSessionToken: _client.data.sessionId}, - body: body); + final response = await _client.put(uri, body: body); return _handleResponse( this, response, ParseApiRQ.save, _debug, className); } on Exception catch (e) { @@ -257,9 +291,8 @@ class ParseUser extends ParseObject implements ParseCloneable { Future destroy() async { if (objectId != null) { try { - final response = await _client.delete( - _client.data.serverUrl + "$path/$objectId", - headers: {keyHeaderSessionToken: _client.data.sessionId}); + final response = + await _client.delete(_client.data.serverUrl + "$path/$objectId"); return _handleResponse( this, response, ParseApiRQ.destroy, _debug, className); } on Exception catch (e) { @@ -271,17 +304,22 @@ class ParseUser extends ParseObject implements ParseCloneable { } /// Gets a list of all users (limited return) - static Future all() async { + static Future all({bool debug, ParseHTTPClient client}) async { var emptyUser = ParseUser(null, null, null); + bool _debug = isDebugEnabled(objectLevelDebug: debug); + ParseHTTPClient _client = client ?? + ParseHTTPClient( + autoSendSessionId: true, + securityContext: ParseCoreData().securityContext); + try { - final response = await ParseHTTPClient(ParseCoreData().securityContext) - .get("${ParseCoreData().serverUrl}/$path"); + final response = await _client.get("${ParseCoreData().serverUrl}/$path"); ParseResponse parseResponse = ParseResponse.handleResponse(emptyUser, response); - if (ParseCoreData().debug) { + if (_debug) { logger(ParseCoreData().appName, keyClassUser, ParseApiRQ.getAll.toString(), parseResponse); } @@ -335,7 +373,8 @@ class ParseUser extends ParseObject implements ParseCloneable { Map responseData = JsonDecoder().convert(response.body); if (responseData.containsKey(keyVarObjectId)) { parseResponse.result.fromJson(responseData); - ParseCoreData().setSessionId(responseData[keyParamSessionToken]); + user.sessionToken = responseData[keyParamSessionToken]; + ParseCoreData().setSessionId(user.sessionToken); } if (type == ParseApiRQ.getAll || type == ParseApiRQ.destroy) { diff --git a/lib/src/utils/parse_file_extensions.dart b/lib/src/utils/parse_file_extensions.dart index 105d23e62..23fa1f147 100644 --- a/lib/src/utils/parse_file_extensions.dart +++ b/lib/src/utils/parse_file_extensions.dart @@ -25,7 +25,7 @@ String getContentType(String extension) { return contentType; } -/// Add content types based on extesion to a map +/// Add content types based on extension to a map Map _queryExtensions() { Map extensions = Map(); diff --git a/lib/src/utils/parse_utils.dart b/lib/src/utils/parse_utils.dart index 760354ab0..422e011e3 100644 --- a/lib/src/utils/parse_utils.dart +++ b/lib/src/utils/parse_utils.dart @@ -2,17 +2,15 @@ part of flutter_parse_sdk; /// Checks whether debug is enabled /// -/// Debug can be set in 2 places, one global param in the Parse.initialise, and -/// then can be overidden class by class -bool isDebugEnabled({objectLevelDebug: false}) { - bool debug = objectLevelDebug; - if (ParseCoreData().debug != null) debug = ParseCoreData().debug; - return debug; +/// Debug can be set in 2 places, one global param in the Parse.initialize, and +/// then can be overwritten class by class +bool isDebugEnabled({bool objectLevelDebug}) { + return objectLevelDebug ?? ParseCoreData().debug ?? false; } /// Converts the object to the correct value for JSON, /// -/// Strings are wrapped with "" but ints and others are not +/// Strings are wrapped with "" but integers and others are not convertValueToCorrectType(dynamic value) { if (value is String && !value.contains('__type')) { return "\"$value\""; diff --git a/pubspec.yaml b/pubspec.yaml index 7ed5bd270..b8f53edbe 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: parse_server_sdk description: Flutter plugin for Parse Server, (https://parseplatform.org), (https://back4app.com) -version: 1.0.10 +version: 1.0.12 homepage: https://github.com/phillwiggins/flutter_parse_sdk author: PhillWiggins diff --git a/test/parse_client_configuration_test.dart b/test/parse_client_configuration_test.dart index ae47e0f62..e017fb36f 100644 --- a/test/parse_client_configuration_test.dart +++ b/test/parse_client_configuration_test.dart @@ -1,10 +1,9 @@ +import 'package:parse_server_sdk/parse_server_sdk.dart'; import 'package:test/test.dart'; -import 'package:parse_server_sdk/parse.dart'; -void main(){ - test("testBuilder",() { - Parse().initialize("appId", - "serverUrl", +void main() { + test("testBuilder", () { + Parse().initialize("appId", "serverUrl", clientKey: "clientKey", liveQueryUrl: "liveQueryUrl", appName: "appName", @@ -20,6 +19,5 @@ void main(){ expect(ParseCoreData().masterKey, "masterKey"); expect(ParseCoreData().sessionId, "sessionId"); expect(ParseCoreData().debug, true); - }); -} \ No newline at end of file +}