Merge pull request #1726 from famedly/nico/fix-state-handling-after-invite

fix state handling after invite
This commit is contained in:
Krille-chan 2024-03-05 09:01:31 +01:00 committed by GitHub
commit 2f95e41ee9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 113 additions and 45 deletions

View File

@ -1071,19 +1071,19 @@ class Client extends MatrixApi {
[])); []));
archivedRoom.prev_batch = update.timeline?.prevBatch; archivedRoom.prev_batch = update.timeline?.prevBatch;
update.state?.forEach((event) {
archivedRoom.setState(Event.fromMatrixEvent(
event,
archivedRoom,
));
});
update.timeline?.events?.forEach((event) { final stateEvents = roomUpdate.state;
archivedRoom.setState(Event.fromMatrixEvent( if (stateEvents != null) {
event, await _handleRoomEvents(archivedRoom, stateEvents, EventUpdateType.state,
archivedRoom, store: false);
)); }
});
final timelineEvents = roomUpdate.timeline?.events;
if (timelineEvents != null) {
await _handleRoomEvents(archivedRoom, timelineEvents.reversed.toList(),
EventUpdateType.timeline,
store: false);
}
for (var i = 0; i < timeline.events.length; i++) { for (var i = 0; i < timeline.events.length; i++) {
// Try to decrypt encrypted events but don't update the database. // Try to decrypt encrypted events but don't update the database.
@ -2463,6 +2463,10 @@ class Client extends MatrixApi {
final importantOrRoomLoaded = final importantOrRoomLoaded =
eventUpdate.type == EventUpdateType.inviteState || eventUpdate.type == EventUpdateType.inviteState ||
!room.partial || !room.partial ||
// make sure we do overwrite events we have already loaded.
room.states[stateEvent.type]
?.containsKey(stateEvent.stateKey ?? '') ==
true ||
importantStateEvents.contains(stateEvent.type); importantStateEvents.contains(stateEvent.type);
if ((noMessageOrNoEdit || editingLastEvent || consecutiveEdit) && if ((noMessageOrNoEdit || editingLastEvent || consecutiveEdit) &&
importantOrRoomLoaded) { importantOrRoomLoaded) {

View File

@ -210,10 +210,8 @@ class Event extends MatrixEvent {
type: jsonPayload['type'], type: jsonPayload['type'],
eventId: jsonPayload['event_id'] ?? '', eventId: jsonPayload['event_id'] ?? '',
senderId: jsonPayload['sender'], senderId: jsonPayload['sender'],
originServerTs: jsonPayload['origin_server_ts'] != null originServerTs: DateTime.fromMillisecondsSinceEpoch(
? DateTime.fromMillisecondsSinceEpoch( jsonPayload['origin_server_ts'] ?? 0),
jsonPayload['origin_server_ts'])
: DateTime.now(),
unsigned: unsigned, unsigned: unsigned,
room: room, room: room,
originalSource: originalSource.isEmpty originalSource: originalSource.isEmpty

View File

@ -196,15 +196,6 @@ class Room {
return; return;
} }
// Do not set old events as state events
final prevEvent = getState(state.type, stateKey);
if (prevEvent != null &&
prevEvent.eventId != state.eventId &&
prevEvent.originServerTs.millisecondsSinceEpoch >
state.originServerTs.millisecondsSinceEpoch) {
return;
}
(states[state.type] ??= {})[stateKey] = state; (states[state.type] ??= {})[stateKey] = state;
client.onRoomState.add(state); client.onRoomState.add(state);
@ -1574,8 +1565,6 @@ class Room {
return <User>[]; return <User>[];
} }
bool _requestedParticipants = false;
/// Request the full list of participants from the server. The local list /// Request the full list of participants from the server. The local list
/// from the store is not complete if the client uses lazy loading. /// from the store is not complete if the client uses lazy loading.
/// List `membershipFilter` defines with what membership do you want the /// List `membershipFilter` defines with what membership do you want the
@ -1591,17 +1580,20 @@ class Room {
], ],
bool suppressWarning = false, bool suppressWarning = false,
bool cache = true]) async { bool cache = true]) async {
if (!participantListComplete && partial) { if (!participantListComplete || partial) {
// we aren't fully loaded, maybe the users are in the database // we aren't fully loaded, maybe the users are in the database
// We always need to check the database in the partial case, since state
// events won't get written to memory in this case and someone new could
// have joined, while someone else left, which might lead to the same
// count in the completeness check.
final users = await client.database?.getUsers(this) ?? []; final users = await client.database?.getUsers(this) ?? [];
for (final user in users) { for (final user in users) {
setState(user); setState(user);
} }
} }
// Do not request users from the server if we have already done it // Do not request users from the server if we have already have a complete list locally.
// in this session or have a complete list locally. if (participantListComplete) {
if (_requestedParticipants || participantListComplete) {
return getParticipants(membershipFilter); return getParticipants(membershipFilter);
} }
@ -1626,7 +1618,6 @@ class Room {
} }
} }
_requestedParticipants = cache;
users.removeWhere((u) => !membershipFilter.contains(u.membership)); users.removeWhere((u) => !membershipFilter.contains(u.membership));
return users; return users;
} }
@ -1634,10 +1625,14 @@ class Room {
/// Checks if the local participant list of joined and invited users is complete. /// Checks if the local participant list of joined and invited users is complete.
bool get participantListComplete { bool get participantListComplete {
final knownParticipants = getParticipants(); final knownParticipants = getParticipants();
knownParticipants.removeWhere( final joinedCount =
(u) => ![Membership.join, Membership.invite].contains(u.membership)); knownParticipants.where((u) => u.membership == Membership.join).length;
return knownParticipants.length == final invitedCount = knownParticipants
(summary.mJoinedMemberCount ?? 0) + (summary.mInvitedMemberCount ?? 0); .where((u) => u.membership == Membership.invite)
.length;
return (summary.mJoinedMemberCount ?? 0) == joinedCount &&
(summary.mInvitedMemberCount ?? 0) == invitedCount;
} }
@Deprecated( @Deprecated(

File diff suppressed because one or more lines are too long

View File

@ -70,6 +70,7 @@ void main() {
), ),
}, },
); );
room.setState(Event( room.setState(Event(
room: room, room: room,
eventId: '143273582443PhrSn:example.org', eventId: '143273582443PhrSn:example.org',
@ -80,6 +81,46 @@ void main() {
content: {'join_rule': 'public'}, content: {'join_rule': 'public'},
stateKey: '', stateKey: '',
)); ));
room.setState(Event(
room: room,
eventId: '143273582443PhrSnY:example.org',
originServerTs: DateTime.fromMillisecondsSinceEpoch(1432735824653),
senderId: matrix.userID!,
type: 'm.room.member',
unsigned: {'age': 1234},
content: {'membership': 'join', 'displayname': 'YOU'},
stateKey: matrix.userID!,
));
room.setState(Event(
room: room,
eventId: '143273582443PhrSnA:example.org',
originServerTs: DateTime.fromMillisecondsSinceEpoch(1432735824653),
senderId: '@alice:matrix.org',
type: 'm.room.member',
unsigned: {'age': 1234},
content: {'membership': 'join', 'displayname': 'Alice Margatroid'},
stateKey: '@alice:matrix.org',
));
room.setState(Event(
room: room,
eventId: '143273582443PhrSnB:example.org',
originServerTs: DateTime.fromMillisecondsSinceEpoch(1432735824653),
senderId: '@bob:example.com',
type: 'm.room.member',
unsigned: {'age': 1234},
content: {'membership': 'invite', 'displayname': 'Bob'},
stateKey: '@bob:example.com',
));
room.setState(Event(
room: room,
eventId: '143273582443PhrSnC:example.org',
originServerTs: DateTime.fromMillisecondsSinceEpoch(1432735824653),
senderId: '@charley:example.org',
type: 'm.room.member',
unsigned: {'age': 1234},
content: {'membership': 'invite', 'displayname': 'Charley'},
stateKey: '@charley:example.org',
));
final heroUsers = await room.loadHeroUsers(); final heroUsers = await room.loadHeroUsers();
expect(heroUsers.length, 3); expect(heroUsers.length, 3);
@ -89,9 +130,10 @@ void main() {
expect(room.notificationCount, notificationCount); expect(room.notificationCount, notificationCount);
expect(room.highlightCount, highlightCount); expect(room.highlightCount, highlightCount);
expect(room.summary.mJoinedMemberCount, notificationCount); expect(room.summary.mJoinedMemberCount, notificationCount);
expect(room.summary.mInvitedMemberCount, notificationCount); expect(room.summary.mInvitedMemberCount, 2);
expect(room.summary.mHeroes, heroes); expect(room.summary.mHeroes, heroes);
expect(room.getLocalizedDisplayname(), 'Group with Alice, Bob, Charley'); expect(room.getLocalizedDisplayname(),
'Group with Alice Margatroid, Bob, Charley');
expect( expect(
room.getState('m.room.join_rules')?.content['join_rule'], 'public'); room.getState('m.room.join_rules')?.content['join_rule'], 'public');
expect(room.roomAccountData['com.test.foo']?.content['foo'], 'bar'); expect(room.roomAccountData['com.test.foo']?.content['foo'], 'bar');
@ -434,12 +476,12 @@ void main() {
test('requestParticipants', () async { test('requestParticipants', () async {
final participants = await room.requestParticipants(); final participants = await room.requestParticipants();
expect(participants.length, 1); expect(participants.length, 4);
final user = participants[0]; final user = participants.singleWhere((u) => u.id == '@alice:matrix.org');
expect(user.id, '@alice:example.org'); expect(user.id, '@alice:matrix.org');
expect(user.displayName, 'Alice Margatroid'); expect(user.displayName, 'Alice Margatroid');
expect(user.membership, Membership.join); expect(user.membership, Membership.join);
expect(user.avatarUrl.toString(), 'mxc://example.org/SEsfnsuifSDFSSEF'); //expect(user.avatarUrl.toString(), 'mxc://example.org/SEsfnsuifSDFSSEF');
expect(user.room.id, '!localpart:server.abc'); expect(user.room.id, '!localpart:server.abc');
}); });
@ -1405,10 +1447,13 @@ void main() {
test('getMention', () async { test('getMention', () async {
expect(room.getMention('@invalid'), null); expect(room.getMention('@invalid'), null);
expect(room.getMention('@[Alice Margatroid]'), '@alice:example.org'); expect(room.getMention('@[Alice Margatroid]'), '@alice:matrix.org');
expect(room.getMention('@[Alice Margatroid]#1754'), '@alice:example.org'); expect(room.getMention('@[Alice Margatroid]#1667'), '@alice:matrix.org');
}); });
test('inviteLink', () async { test('inviteLink', () async {
// ensure we don't rerequest members
room.summary.mJoinedMemberCount = 4;
var matrixToLink = await room.matrixToInviteLink(); var matrixToLink = await room.matrixToInviteLink();
expect(matrixToLink.toString(), expect(matrixToLink.toString(),
'https://matrix.to/#/%23testalias%3Aexample.com'); 'https://matrix.to/#/%23testalias%3Aexample.com');
@ -1424,7 +1469,7 @@ void main() {
); );
matrixToLink = await room.matrixToInviteLink(); matrixToLink = await room.matrixToInviteLink();
expect(matrixToLink.toString(), expect(matrixToLink.toString(),
'https://matrix.to/#/!localpart%3Aserver.abc?via=example.org&via=example.com&via=test.abc'); 'https://matrix.to/#/!localpart%3Aserver.abc?via=example.com&via=test.abc&via=example.org');
}); });
test('callMemberStateIsExpired', () { test('callMemberStateIsExpired', () {