defaultCoreDataMergeHandler static method
Future<void>
defaultCoreDataMergeHandler(
- Session session, {
- required UuidValue userToKeepId,
- required UuidValue userToRemoveId,
- required Transaction transaction,
Merges core Serverpod data from userToRemove to userToKeep.
This includes:
- Merging scopes
- Moving access tokens and refresh tokens
- Moving user profile (if userToKeep does not have one)
Implementation
static Future<void> defaultCoreDataMergeHandler(
final Session session, {
required final UuidValue userToKeepId,
required final UuidValue userToRemoveId,
required final Transaction transaction,
}) async {
final users = await Future.wait([
AuthUser.db.findById(
session,
userToKeepId,
transaction: transaction,
),
AuthUser.db.findById(
session,
userToRemoveId,
transaction: transaction,
),
]);
AuthUser? userToKeep = users[0];
final userToRemove = users[1];
if (userToKeep == null || userToRemove == null) {
throw AuthUserNotFoundException();
}
// Merge Scopes
final combinedScopes = {
...userToKeep.scopeNames,
...userToRemove.scopeNames,
};
final mergedBlocked = userToKeep.blocked || userToRemove.blocked;
if (combinedScopes.length > userToKeep.scopeNames.length ||
mergedBlocked != userToKeep.blocked) {
userToKeep = userToKeep.copyWith(
scopeNames: combinedScopes,
blocked: mergedBlocked,
);
userToKeep = await AuthUser.db.updateRow(
session,
userToKeep,
transaction: transaction,
);
}
// Move Refresh Tokens
await RefreshToken.db.updateWhere(
session,
where: (final t) => t.authUserId.equals(userToRemove.id),
columnValues: (final t) => [t.authUserId(userToKeep!.id!)],
transaction: transaction,
);
// Move Server-Side Sessions
await ServerSideSession.db.updateWhere(
session,
where: (final t) => t.authUserId.equals(userToRemove.id),
columnValues: (final t) => [t.authUserId(userToKeep!.id!)],
transaction: transaction,
);
// Load existing profiles
final profiles = await Future.wait([
UserProfile.db.findFirstRow(
session,
where: (final t) => t.authUserId.equals(userToKeep!.id!),
transaction: transaction,
),
UserProfile.db.findFirstRow(
session,
where: (final t) => t.authUserId.equals(userToRemove.id),
transaction: transaction,
),
]);
final keepProfile = profiles[0];
final removeProfile = profiles[1];
// Merge User Profile
if (removeProfile != null) {
if (keepProfile != null) {
// Both profiles exist, merge fields
final mergedProfile = keepProfile.merge(removeProfile);
if (keepProfile.imageId == null && removeProfile.imageId != null) {
await UserProfileImage.db.updateWhere(
session,
where: (final t) => t.id.equals(removeProfile.imageId),
columnValues: (final t) => [
t.userProfileId(keepProfile.id!),
],
transaction: transaction,
);
}
await UserProfile.db.updateRow(
session,
mergedProfile,
transaction: transaction,
);
// Don't need to remove the userToRemove profile since that database
// relationship is set to onDelete=cascade.
} else {
session.log(
'No profile found for user to keep ${userToKeep.id}. As a '
'fallback, the profile from to-be-deleted user ${userToRemove.id} '
'is being migrated to User ${userToKeep.id}. This likely '
'constitutes an error -- please file an issue with the Serverpod '
'team.',
level: LogLevel.warning,
);
// Target has no profile, move the origin profile over
await UserProfile.db.updateRow(
session,
removeProfile.copyWith(authUserId: userToKeep.id),
columns: (final t) => [t.authUserId],
transaction: transaction,
);
}
}
}