diff --git a/src/i18n/en-US.json b/src/i18n/en-US.json
index 896c571388f..41edaf9d632 100644
--- a/src/i18n/en-US.json
+++ b/src/i18n/en-US.json
@@ -650,6 +650,7 @@
"dataSharingModalDecline": "Decline",
"dataSharingModalDescription": "Help to improve Wire by sharing your usage data via a pseudonymous ID. The data is neither linked to your personal information nor shared with third parties besides Wire Group. It includes, for example, when you use a feature, your app version, device type, or your operating system. This data will be deleted at the latest after 365 days.
Find further details in ourĀ [link]Privacy Policy[/link]. You can revoke your consent at any time.",
"dataSharingModalTitle": "Consent to share user data",
+ "deletedUser": "Deleted User",
"downloadLatestMLS": "Download the latest MLS Wire version",
"enumerationAnd": ", and ",
"ephemeralRemaining": "remaining",
diff --git a/src/script/user/UserRepository.ts b/src/script/user/UserRepository.ts
index 0053823d01d..51d19deeb81 100644
--- a/src/script/user/UserRepository.ts
+++ b/src/script/user/UserRepository.ts
@@ -216,26 +216,36 @@ export class UserRepository extends TypedEventEmitter {
// the entries we get back will be used to feed the availabilities of those users
const nonQualifiedUsers = await this.userService.clearNonQualifiedUsers();
- const dbUsers = await this.userService.loadUserFromDb();
+ const dbUsers = await this.userService.loadUsersFromDb();
// The self user doesn't need to be re-fetched
const usersToFetch = users.filter(user => !matchQualifiedIds(selfUser.qualifiedId, user));
const {found, failed} = await this.fetchRawUsers(usersToFetch, selfUser.domain);
- const userWithAvailability = found.map(user => {
- const availability = [...dbUsers, ...nonQualifiedUsers].find(userRecord => userRecord.id === user.id);
+ const usersWithAvailability = found.map(user => {
+ const localUser = dbUsers.find(
+ dbUser => dbUser.id === user.id || matchQualifiedIds(dbUser.qualified_id, user.qualified_id),
+ );
+
+ const userWithAvailability = [...dbUsers, ...nonQualifiedUsers].find(userRecord => userRecord.id === user.id);
+
+ const userWithEscapedDefaultName = this.replaceDeletedUserNameWithNameInDb(user, localUser);
- if (availability) {
- return {availability: availability.availability, ...user};
+ if (userWithAvailability) {
+ return {
+ availability: userWithAvailability.availability,
+ ...userWithEscapedDefaultName,
+ };
}
- return user;
+
+ return userWithEscapedDefaultName;
});
// Save all new users to the database
- await Promise.all(userWithAvailability.map(user => this.saveUserInDb(user)));
+ await Promise.all(usersWithAvailability.map(user => this.saveUserInDb(user)));
- const mappedUsers = this.mapUserResponse(userWithAvailability, failed, dbUsers);
+ const mappedUsers = this.mapUserResponse(usersWithAvailability, failed, dbUsers);
// Assign connections to users
mappedUsers.forEach(user => {
@@ -323,6 +333,14 @@ export class UserRepository extends TypedEventEmitter {
* Will update the user both in database and in memory.
*/
private async updateUser(userId: QualifiedId, user: Partial, isWebSocket = false): Promise {
+ if (user.deleted && user.name) {
+ const dbUser = await this.userService.loadUserFromDb(userId);
+
+ if (dbUser && dbUser.name) {
+ user.name = dbUser?.name;
+ }
+ }
+
const selfUser = this.userState.self();
const isSelfUser = matchQualifiedIds(userId, selfUser.qualifiedId);
const userEntity = isSelfUser ? selfUser : await this.getUserById(userId);
@@ -575,23 +593,19 @@ export class UserRepository extends TypedEventEmitter {
}
// Replaces a deleted user name ("default") with the name from the local database.
- private restoreDeletedUserNames(apiUsers: APIClientUser[], dbUsers: UserRecord[]): UserRecord[] {
- return apiUsers.map(user => {
- if (!user.deleted) {
- return user;
- }
-
- const localUser = dbUsers.find(dbUser => dbUser.id === user.id);
+ private replaceDeletedUserNameWithNameInDb(user: APIClientUser, localUser?: UserRecord): UserRecord {
+ if (!user.deleted) {
+ return user;
+ }
- if (localUser && localUser.name) {
- return {
- ...user,
- name: localUser.name,
- };
- }
+ if (localUser && localUser.name) {
+ return {
+ ...user,
+ name: localUser.name,
+ };
+ }
- return user;
- });
+ return {...user, name: t('deletedUser')};
}
private mapUserResponse(found: APIClientUser[], failed: QualifiedId[], dbUsers: UserRecord[]): User[] {
@@ -615,9 +629,7 @@ export class UserRepository extends TypedEventEmitter {
return new User(userId.id, userId.domain);
});
- const users = this.restoreDeletedUserNames(found, dbUsers);
-
- const mappedUsers = this.userMapper.mapUsersFromJson(users, selfDomain).concat(failedToLoad);
+ const mappedUsers = this.userMapper.mapUsersFromJson(found, selfDomain).concat(failedToLoad);
if (this.teamState.isTeam()) {
this.mapGuestStatus(mappedUsers);
@@ -633,7 +645,7 @@ export class UserRepository extends TypedEventEmitter {
*/
private async fetchUsers(userIds: QualifiedId[]): Promise {
const {found, failed} = await this.fetchRawUsers(userIds, this.userState.self().domain);
- const dbUsers = await this.userService.loadUserFromDb();
+ const dbUsers = await this.userService.loadUsersFromDb();
const users = this.mapUserResponse(found, failed, dbUsers);
let fetchedUserEntities = this.saveUsers(users);
@@ -713,6 +725,7 @@ export class UserRepository extends TypedEventEmitter {
if (localOnly) {
const deletedUser = new User(userId.id, userId.domain);
deletedUser.isDeleted = true;
+ deletedUser.name(t('deletedUser'));
return deletedUser;
}
try {
diff --git a/src/script/user/UserService.ts b/src/script/user/UserService.ts
index 9d16b1350b0..812edb30aba 100644
--- a/src/script/user/UserService.ts
+++ b/src/script/user/UserService.ts
@@ -58,10 +58,20 @@ export class UserService {
* @todo There might be more keys which are returned by this function
* @returns Resolves with all the stored user states
*/
- loadUserFromDb(): Promise {
+ loadUsersFromDb(): Promise {
return this.storageService.getAll(this.USER_STORE_NAME);
}
+ /**
+ * Loads user from the local database
+ * @returns Resolves to the stored user, if it does not exists resolves to undefined
+ */
+ loadUserFromDb(qualifiedId: QualifiedId): Promise {
+ const primaryKey = constructUserPrimaryKey(qualifiedId);
+
+ return this.storageService.load(this.USER_STORE_NAME, primaryKey);
+ }
+
/**
* Will remove all the non-qualified entries in the DB
*/
diff --git a/src/types/i18n.d.ts b/src/types/i18n.d.ts
index 333c2c42d1c..e9a1f5280f7 100644
--- a/src/types/i18n.d.ts
+++ b/src/types/i18n.d.ts
@@ -443,11 +443,11 @@ declare module 'I18n/en-US.json' {
'conversationDetailsActionConversationParticipants': `Show all ({number})`;
'conversationDetailsActionCreateGroup': `Create group`;
'conversationDetailsActionDelete': `Delete group`;
+ 'conversationDetailsActionDeleteForMe': `Delete for Me`;
'conversationDetailsActionDevices': `Devices`;
'conversationDetailsActionGuestOptions': `Guests`;
'conversationDetailsActionLeave': `Leave group`;
'conversationDetailsActionNotifications': `Notifications`;
- 'conversationDetailsActionDeleteForMe': `Delete for Me`;
'conversationDetailsActionServicesOptions': `Services`;
'conversationDetailsActionTimedMessages': `Self-deleting messages`;
'conversationDetailsActionUnblock': `Unblock`;
@@ -654,6 +654,7 @@ declare module 'I18n/en-US.json' {
'dataSharingModalDecline': `Decline`;
'dataSharingModalDescription': `Help to improve Wire by sharing your usage data via a pseudonymous ID. The data is neither linked to your personal information nor shared with third parties besides Wire Group. It includes, for example, when you use a feature, your app version, device type, or your operating system. This data will be deleted at the latest after 365 days.
Find further details in ourĀ [link]Privacy Policy[/link]. You can revoke your consent at any time.`;
'dataSharingModalTitle': `Consent to share user data`;
+ 'deletedUser': `Deleted User`;
'downloadLatestMLS': `Download the latest MLS Wire version`;
'enumerationAnd': `, and `;
'ephemeralRemaining': `remaining`;