support setting kickDetails in room summary
This commit is contained in:
parent
85385295a6
commit
b13bfee3d8
1 changed files with 73 additions and 4 deletions
|
@ -28,13 +28,15 @@ function applyTimelineEntries(data, timelineEntries, isInitialSync, canMarkUnrea
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function applySyncResponse(data, roomResponse, membership) {
|
function applySyncResponse(data, roomResponse, membership, ownUserId) {
|
||||||
if (roomResponse.summary) {
|
if (roomResponse.summary) {
|
||||||
data = updateSummary(data, roomResponse.summary);
|
data = updateSummary(data, roomResponse.summary);
|
||||||
}
|
}
|
||||||
|
let needKickDetails = false;
|
||||||
if (membership !== data.membership) {
|
if (membership !== data.membership) {
|
||||||
data = data.cloneIfNeeded();
|
data = data.cloneIfNeeded();
|
||||||
data.membership = membership;
|
data.membership = membership;
|
||||||
|
needKickDetails = membership === "leave" || membership === "ban";
|
||||||
}
|
}
|
||||||
if (roomResponse.account_data) {
|
if (roomResponse.account_data) {
|
||||||
data = roomResponse.account_data.events.reduce(processRoomAccountData, data);
|
data = roomResponse.account_data.events.reduce(processRoomAccountData, data);
|
||||||
|
@ -42,7 +44,12 @@ function applySyncResponse(data, roomResponse, membership) {
|
||||||
const stateEvents = roomResponse?.state?.events;
|
const stateEvents = roomResponse?.state?.events;
|
||||||
// state comes before timeline
|
// state comes before timeline
|
||||||
if (Array.isArray(stateEvents)) {
|
if (Array.isArray(stateEvents)) {
|
||||||
data = stateEvents.reduce(processStateEvent, data);
|
data = stateEvents.reduce((data, event) => {
|
||||||
|
if (needKickDetails) {
|
||||||
|
data = findKickDetails(data, event, ownUserId);
|
||||||
|
}
|
||||||
|
return processStateEvent(data, event, ownUserId, needKickDetails);
|
||||||
|
}, data);
|
||||||
}
|
}
|
||||||
const timelineEvents = roomResponse?.timeline?.events;
|
const timelineEvents = roomResponse?.timeline?.events;
|
||||||
// process state events in timeline
|
// process state events in timeline
|
||||||
|
@ -51,6 +58,9 @@ function applySyncResponse(data, roomResponse, membership) {
|
||||||
if (Array.isArray(timelineEvents)) {
|
if (Array.isArray(timelineEvents)) {
|
||||||
data = timelineEvents.reduce((data, event) => {
|
data = timelineEvents.reduce((data, event) => {
|
||||||
if (typeof event.state_key === "string") {
|
if (typeof event.state_key === "string") {
|
||||||
|
if (needKickDetails) {
|
||||||
|
data = findKickDetails(data, event, ownUserId);
|
||||||
|
}
|
||||||
return processStateEvent(data, event);
|
return processStateEvent(data, event);
|
||||||
}
|
}
|
||||||
return data;
|
return data;
|
||||||
|
@ -112,6 +122,22 @@ export function processStateEvent(data, event) {
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function findKickDetails(data, event, ownUserId) {
|
||||||
|
if (event.type === "m.room.member") {
|
||||||
|
// did we get kicked?
|
||||||
|
if (event.state_key === ownUserId && event.sender !== event.state_key) {
|
||||||
|
data = data.cloneIfNeeded();
|
||||||
|
data.kickDetails = {
|
||||||
|
// this is different from the room membership in the sync section, which can only be leave
|
||||||
|
membership: event.content?.membership, // could be leave or ban
|
||||||
|
reason: event.content?.reason,
|
||||||
|
sender: event.sender,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
function processTimelineEvent(data, eventEntry, isInitialSync, canMarkUnread, ownUserId) {
|
function processTimelineEvent(data, eventEntry, isInitialSync, canMarkUnread, ownUserId) {
|
||||||
if (eventEntry.eventType === "m.room.message") {
|
if (eventEntry.eventType === "m.room.message") {
|
||||||
if (!data.lastMessageTimestamp || eventEntry.timestamp > data.lastMessageTimestamp) {
|
if (!data.lastMessageTimestamp || eventEntry.timestamp > data.lastMessageTimestamp) {
|
||||||
|
@ -180,6 +206,7 @@ export class SummaryData {
|
||||||
this.tags = copy ? copy.tags : null;
|
this.tags = copy ? copy.tags : null;
|
||||||
this.isDirectMessage = copy ? copy.isDirectMessage : false;
|
this.isDirectMessage = copy ? copy.isDirectMessage : false;
|
||||||
this.dmUserId = copy ? copy.dmUserId : null;
|
this.dmUserId = copy ? copy.dmUserId : null;
|
||||||
|
this.kickDetails = copy ? copy.kickDetails : null;
|
||||||
this.cloned = copy ? true : false;
|
this.cloned = copy ? true : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -217,8 +244,8 @@ export class SummaryData {
|
||||||
return applyTimelineEntries(this, timelineEntries, isInitialSync, canMarkUnread, ownUserId);
|
return applyTimelineEntries(this, timelineEntries, isInitialSync, canMarkUnread, ownUserId);
|
||||||
}
|
}
|
||||||
|
|
||||||
applySyncResponse(roomResponse, membership) {
|
applySyncResponse(roomResponse, membership, ownUserId) {
|
||||||
return applySyncResponse(this, roomResponse, membership);
|
return applySyncResponse(this, roomResponse, membership, ownUserId);
|
||||||
}
|
}
|
||||||
|
|
||||||
applyInvite(invite) {
|
applyInvite(invite) {
|
||||||
|
@ -301,6 +328,17 @@ export class RoomSummary {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function tests() {
|
export function tests() {
|
||||||
|
function createMemberEvent(sender, target, membership, reason) {
|
||||||
|
return {
|
||||||
|
sender,
|
||||||
|
state_key: target,
|
||||||
|
type: "m.room.member",
|
||||||
|
content: { reason, membership }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const bob = "@bob:hs.tld";
|
||||||
|
const alice = "@alice:hs.tld";
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"serialize doesn't include null fields or cloned": assert => {
|
"serialize doesn't include null fields or cloned": assert => {
|
||||||
const roomId = "!123:hs.tld";
|
const roomId = "!123:hs.tld";
|
||||||
|
@ -312,6 +350,37 @@ export function tests() {
|
||||||
const nullCount = Object.values(serialized).reduce((count, value) => count + value === null ? 1 : 0, 0);
|
const nullCount = Object.values(serialized).reduce((count, value) => count + value === null ? 1 : 0, 0);
|
||||||
assert.strictEqual(nullCount, 0);
|
assert.strictEqual(nullCount, 0);
|
||||||
},
|
},
|
||||||
|
"ban/kick sets kickDetails from state event": assert => {
|
||||||
|
const reason = "Bye!";
|
||||||
|
const leaveEvent = createMemberEvent(alice, bob, "ban", reason);
|
||||||
|
const data = new SummaryData(null, "!123:hs.tld");
|
||||||
|
const newData = data.applySyncResponse({state: {events: [leaveEvent]}}, "leave", bob);
|
||||||
|
assert.equal(newData.membership, "leave");
|
||||||
|
assert.equal(newData.kickDetails.membership, "ban");
|
||||||
|
assert.equal(newData.kickDetails.reason, reason);
|
||||||
|
assert.equal(newData.kickDetails.sender, alice);
|
||||||
|
},
|
||||||
|
"ban/kick sets kickDetails from timeline state event, taking precedence over state": assert => {
|
||||||
|
const reason = "Bye!";
|
||||||
|
const inviteEvent = createMemberEvent(alice, bob, "invite");
|
||||||
|
const leaveEvent = createMemberEvent(alice, bob, "ban", reason);
|
||||||
|
const data = new SummaryData(null, "!123:hs.tld");
|
||||||
|
const newData = data.applySyncResponse({
|
||||||
|
state: { events: [inviteEvent] },
|
||||||
|
timeline: {events: [leaveEvent] }
|
||||||
|
}, "leave", bob);
|
||||||
|
assert.equal(newData.membership, "leave");
|
||||||
|
assert.equal(newData.kickDetails.membership, "ban");
|
||||||
|
assert.equal(newData.kickDetails.reason, reason);
|
||||||
|
assert.equal(newData.kickDetails.sender, alice);
|
||||||
|
},
|
||||||
|
"leaving without being kicked doesn't produce kickDetails": assert => {
|
||||||
|
const leaveEvent = createMemberEvent(bob, bob, "leave");
|
||||||
|
const data = new SummaryData(null, "!123:hs.tld");
|
||||||
|
const newData = data.applySyncResponse({state: {events: [leaveEvent]}}, "leave", bob);
|
||||||
|
assert.equal(newData.membership, "leave");
|
||||||
|
assert.equal(newData.kickDetails, null);
|
||||||
|
},
|
||||||
"membership trigger change": function(assert) {
|
"membership trigger change": function(assert) {
|
||||||
const summary = new RoomSummary("id");
|
const summary = new RoomSummary("id");
|
||||||
let written = false;
|
let written = false;
|
||||||
|
|
Reference in a new issue