Skip to content
Closed
70 changes: 68 additions & 2 deletions packages/dart/lib/src/objects/parse_user.dart
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ class ParseUser extends ParseObject implements ParseCloneable {
static const String keyUsername = 'username';
static const String keyEmailAddress = 'email';
static const String path = '$keyEndPointClasses$keyClassUser';
static const String _keyAuthAnonymous = 'anonymous';

String? _password;

Expand Down Expand Up @@ -70,7 +71,10 @@ class ParseUser extends ParseObject implements ParseCloneable {

String? get username => super.get<String>(keyVarUsername);

set username(String? username) => set<String?>(keyVarUsername, username);
set username(String? username) {
_stripAnonymity();
set<String?>(keyVarUsername, username);
}

String? get emailAddress => super.get<String>(keyVarEmail);

Expand Down Expand Up @@ -282,7 +286,13 @@ class ParseUser extends ParseObject implements ParseCloneable {
}
}

/// Logs in a user anonymously
/// Logs in a user anonymously.
///
/// To convert the resulting anonymous user into a permanent account,
/// set `username` and `password` on the [ParseUser] and call [save].
/// The anonymous provider is unlinked server-side and the local
/// `authData` is reconciled automatically.
///
/// Set [doNotSendInstallationID] to 'true' in order to prevent the SDK from sending the installationID to the Server.
/// This option is especially useful if you are running you application on web and you don't have permission to add 'X-Parse-Installation-Id' as an allowed header on your parse-server.
Future<ParseResponse> loginAnonymous({
Expand Down Expand Up @@ -493,8 +503,11 @@ class ParseUser extends ParseObject implements ParseCloneable {
if (objectId == null) {
return await signUp();
} else {
final String? tokenBefore = sessionToken;
final ParseResponse response = await super.save();
if (response.success) {
_adoptResponseSessionTokenIfChanged(tokenBefore);
_cleanUpAuthData();
await _onResponseSuccess();
}
return response;
Expand All @@ -506,18 +519,71 @@ class ParseUser extends ParseObject implements ParseCloneable {
if (objectId == null) {
return await signUp();
} else {
final String? tokenBefore = sessionToken;
final ParseResponse response = await super.update();
if (response.success) {
_adoptResponseSessionTokenIfChanged(tokenBefore);
_cleanUpAuthData();
await _onResponseSuccess();
}
return response;
}
}

/// Adopt a new sessionToken from a save/update response. Parse Server
/// mints a fresh session when `password` is set on an existing _User
/// (revokeSessionOnPasswordReset, default true since 9.x); the prior
/// session is destroyed server-side, so the global session must be
/// updated or subsequent requests will fail with invalidSessionToken.
/// Mirrors iOS PFUser's _mergeFromServerWithResult.
void _adoptResponseSessionTokenIfChanged(String? tokenBefore) {
final String? tokenAfter = sessionToken;
if (tokenAfter == null || tokenAfter.isEmpty) return;
if (tokenAfter == tokenBefore) return;
ParseCoreData().setSessionId(tokenAfter);
}

Future<void> _onResponseSuccess() async {
await saveInStorage(keyParseStoreUser);
}

void _stripAnonymity() {
final Map<String, dynamic>? authData =
_objectData[keyVarAuthData] as Map<String, dynamic>?;
if (authData == null || !authData.containsKey(_keyAuthAnonymous)) {
return;
}
if (objectId == null) {
authData.remove(_keyAuthAnonymous);
} else {
authData[_keyAuthAnonymous] = null;
}
if (authData.isEmpty) {
_unsavedChanges.remove(keyVarAuthData);
} else {
_unsavedChanges[keyVarAuthData] = authData;
}
}

void _cleanUpAuthData() {
final Map<String, dynamic>? authData =
_objectData[keyVarAuthData] as Map<String, dynamic>?;
if (authData != null) {
authData.removeWhere((_, dynamic value) => value == null);
if (authData.isEmpty) {
_objectData.remove(keyVarAuthData);
}
}
final Map<String, dynamic>? dirty =
_unsavedChanges[keyVarAuthData] as Map<String, dynamic>?;
if (dirty != null) {
dirty.removeWhere((_, dynamic value) => value == null);
if (dirty.isEmpty) {
_unsavedChanges.remove(keyVarAuthData);
}
}
}

/// Removes a user from Parse Server locally and online
Future<ParseResponse?> destroy() async {
if (objectId != null) {
Expand Down
Loading
Loading