mirror of
https://github.com/hedgedoc/hedgedoc.git
synced 2024-12-22 14:51:34 +00:00
fix(realtime): allow realtime user status updates from users that have read-only access
Signed-off-by: Tilman Vatteroth <git@tilmanvatteroth.de>
This commit is contained in:
parent
46330563fa
commit
d29e840bc6
4 changed files with 276 additions and 56 deletions
|
@ -119,6 +119,13 @@ describe('realtime user status adapter', () => {
|
|||
username: null,
|
||||
displayName: guestDisplayName,
|
||||
},
|
||||
{
|
||||
active: true,
|
||||
cursor: null,
|
||||
displayName: clientDeclineUsername,
|
||||
styleIndex: 4,
|
||||
username: clientDeclineUsername,
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
@ -180,6 +187,13 @@ describe('realtime user status adapter', () => {
|
|||
username: null,
|
||||
displayName: guestDisplayName,
|
||||
},
|
||||
{
|
||||
active: true,
|
||||
cursor: null,
|
||||
displayName: clientDeclineUsername,
|
||||
styleIndex: 4,
|
||||
username: clientDeclineUsername,
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
@ -212,6 +226,55 @@ describe('realtime user status adapter', () => {
|
|||
username: clientLoggedIn2Username,
|
||||
displayName: clientLoggedIn2Username,
|
||||
},
|
||||
{
|
||||
active: true,
|
||||
cursor: null,
|
||||
displayName: clientDeclineUsername,
|
||||
styleIndex: 4,
|
||||
username: clientDeclineUsername,
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
const expectedMessage5: Message<MessageType.REALTIME_USER_STATE_SET> = {
|
||||
type: MessageType.REALTIME_USER_STATE_SET,
|
||||
payload: {
|
||||
ownUser: {
|
||||
displayName: clientDeclineUsername,
|
||||
styleIndex: 4,
|
||||
},
|
||||
users: [
|
||||
{
|
||||
active: true,
|
||||
cursor: {
|
||||
from: newFrom,
|
||||
to: newTo,
|
||||
},
|
||||
styleIndex: 0,
|
||||
username: clientLoggedIn1Username,
|
||||
displayName: clientLoggedIn1Username,
|
||||
},
|
||||
{
|
||||
active: true,
|
||||
cursor: {
|
||||
from: 0,
|
||||
to: 0,
|
||||
},
|
||||
styleIndex: 1,
|
||||
username: clientLoggedIn2Username,
|
||||
displayName: clientLoggedIn2Username,
|
||||
},
|
||||
{
|
||||
active: true,
|
||||
cursor: {
|
||||
from: 0,
|
||||
to: 0,
|
||||
},
|
||||
displayName: guestDisplayName,
|
||||
styleIndex: 2,
|
||||
username: null,
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
@ -226,7 +289,10 @@ describe('realtime user status adapter', () => {
|
|||
expectedMessage3,
|
||||
);
|
||||
expect(clientNotReadySendMessageSpy).toHaveBeenCalledTimes(0);
|
||||
expect(clientDeclineSendMessageSpy).toHaveBeenCalledTimes(1);
|
||||
expect(clientDeclineSendMessageSpy).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
expectedMessage5,
|
||||
);
|
||||
});
|
||||
|
||||
it('will inform other clients about removed client', () => {
|
||||
|
@ -256,6 +322,13 @@ describe('realtime user status adapter', () => {
|
|||
username: null,
|
||||
displayName: guestDisplayName,
|
||||
},
|
||||
{
|
||||
active: true,
|
||||
cursor: null,
|
||||
displayName: clientDeclineUsername,
|
||||
styleIndex: 4,
|
||||
username: clientDeclineUsername,
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
@ -278,6 +351,45 @@ describe('realtime user status adapter', () => {
|
|||
username: clientLoggedIn1Username,
|
||||
displayName: clientLoggedIn1Username,
|
||||
},
|
||||
{
|
||||
active: true,
|
||||
cursor: null,
|
||||
displayName: clientDeclineUsername,
|
||||
styleIndex: 4,
|
||||
username: clientDeclineUsername,
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
const expectedMessage5: Message<MessageType.REALTIME_USER_STATE_SET> = {
|
||||
type: MessageType.REALTIME_USER_STATE_SET,
|
||||
payload: {
|
||||
ownUser: {
|
||||
displayName: clientDeclineUsername,
|
||||
styleIndex: 4,
|
||||
},
|
||||
users: [
|
||||
{
|
||||
active: true,
|
||||
cursor: {
|
||||
from: 0,
|
||||
to: 0,
|
||||
},
|
||||
styleIndex: 0,
|
||||
username: clientLoggedIn1Username,
|
||||
displayName: clientLoggedIn1Username,
|
||||
},
|
||||
{
|
||||
active: true,
|
||||
cursor: {
|
||||
from: 0,
|
||||
to: 0,
|
||||
},
|
||||
displayName: guestDisplayName,
|
||||
styleIndex: 2,
|
||||
username: null,
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
@ -292,7 +404,10 @@ describe('realtime user status adapter', () => {
|
|||
expectedMessage3,
|
||||
);
|
||||
expect(clientNotReadySendMessageSpy).toHaveBeenCalledTimes(0);
|
||||
expect(clientDeclineSendMessageSpy).toHaveBeenCalledTimes(1);
|
||||
expect(clientDeclineSendMessageSpy).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
expectedMessage5,
|
||||
);
|
||||
});
|
||||
|
||||
it('will inform other clients about inactivity and reactivity', () => {
|
||||
|
@ -338,7 +453,14 @@ describe('realtime user status adapter', () => {
|
|||
},
|
||||
styleIndex: 2,
|
||||
username: null,
|
||||
displayName: 'Virtuous Mockingbird',
|
||||
displayName: guestDisplayName,
|
||||
},
|
||||
{
|
||||
active: true,
|
||||
cursor: null,
|
||||
displayName: clientDeclineUsername,
|
||||
styleIndex: 4,
|
||||
username: clientDeclineUsername,
|
||||
},
|
||||
],
|
||||
},
|
||||
|
@ -350,7 +472,7 @@ describe('realtime user status adapter', () => {
|
|||
payload: {
|
||||
ownUser: {
|
||||
styleIndex: 2,
|
||||
displayName: 'Virtuous Mockingbird',
|
||||
displayName: guestDisplayName,
|
||||
},
|
||||
users: [
|
||||
{
|
||||
|
@ -373,6 +495,56 @@ describe('realtime user status adapter', () => {
|
|||
username: clientLoggedIn2Username,
|
||||
displayName: clientLoggedIn2Username,
|
||||
},
|
||||
{
|
||||
active: true,
|
||||
cursor: null,
|
||||
displayName: clientDeclineUsername,
|
||||
styleIndex: 4,
|
||||
username: clientDeclineUsername,
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
const expectedInactivityMessage5: Message<MessageType.REALTIME_USER_STATE_SET> =
|
||||
{
|
||||
type: MessageType.REALTIME_USER_STATE_SET,
|
||||
payload: {
|
||||
ownUser: {
|
||||
styleIndex: 4,
|
||||
displayName: clientDeclineUsername,
|
||||
},
|
||||
users: [
|
||||
{
|
||||
active: false,
|
||||
cursor: {
|
||||
from: 0,
|
||||
to: 0,
|
||||
},
|
||||
styleIndex: 0,
|
||||
username: clientLoggedIn1Username,
|
||||
displayName: clientLoggedIn1Username,
|
||||
},
|
||||
{
|
||||
active: true,
|
||||
cursor: {
|
||||
from: 0,
|
||||
to: 0,
|
||||
},
|
||||
styleIndex: 1,
|
||||
username: clientLoggedIn2Username,
|
||||
displayName: clientLoggedIn2Username,
|
||||
},
|
||||
{
|
||||
active: true,
|
||||
cursor: {
|
||||
from: 0,
|
||||
to: 0,
|
||||
},
|
||||
displayName: guestDisplayName,
|
||||
styleIndex: 2,
|
||||
username: null,
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
@ -387,7 +559,10 @@ describe('realtime user status adapter', () => {
|
|||
expectedInactivityMessage3,
|
||||
);
|
||||
expect(clientNotReadySendMessageSpy).toHaveBeenCalledTimes(0);
|
||||
expect(clientDeclineSendMessageSpy).toHaveBeenCalledTimes(1);
|
||||
expect(clientDeclineSendMessageSpy).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
expectedInactivityMessage5,
|
||||
);
|
||||
|
||||
clientLoggedIn1
|
||||
.getTransporter()
|
||||
|
@ -408,7 +583,10 @@ describe('realtime user status adapter', () => {
|
|||
expectedInactivityMessage3,
|
||||
);
|
||||
expect(clientNotReadySendMessageSpy).toHaveBeenCalledTimes(0);
|
||||
expect(clientDeclineSendMessageSpy).toHaveBeenCalledTimes(1);
|
||||
expect(clientDeclineSendMessageSpy).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
expectedInactivityMessage5,
|
||||
);
|
||||
|
||||
clientLoggedIn1
|
||||
.getTransporter()
|
||||
|
@ -446,7 +624,14 @@ describe('realtime user status adapter', () => {
|
|||
},
|
||||
styleIndex: 2,
|
||||
username: null,
|
||||
displayName: 'Virtuous Mockingbird',
|
||||
displayName: guestDisplayName,
|
||||
},
|
||||
{
|
||||
active: true,
|
||||
cursor: null,
|
||||
displayName: clientDeclineUsername,
|
||||
styleIndex: 4,
|
||||
username: clientDeclineUsername,
|
||||
},
|
||||
],
|
||||
},
|
||||
|
@ -458,7 +643,7 @@ describe('realtime user status adapter', () => {
|
|||
payload: {
|
||||
ownUser: {
|
||||
styleIndex: 2,
|
||||
displayName: 'Virtuous Mockingbird',
|
||||
displayName: guestDisplayName,
|
||||
},
|
||||
users: [
|
||||
{
|
||||
|
@ -481,6 +666,56 @@ describe('realtime user status adapter', () => {
|
|||
username: clientLoggedIn2Username,
|
||||
displayName: clientLoggedIn2Username,
|
||||
},
|
||||
{
|
||||
active: true,
|
||||
cursor: null,
|
||||
displayName: clientDeclineUsername,
|
||||
styleIndex: 4,
|
||||
username: clientDeclineUsername,
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
const expectedReactivityMessage5: Message<MessageType.REALTIME_USER_STATE_SET> =
|
||||
{
|
||||
type: MessageType.REALTIME_USER_STATE_SET,
|
||||
payload: {
|
||||
ownUser: {
|
||||
styleIndex: 4,
|
||||
displayName: clientDeclineUsername,
|
||||
},
|
||||
users: [
|
||||
{
|
||||
active: true,
|
||||
cursor: {
|
||||
from: 0,
|
||||
to: 0,
|
||||
},
|
||||
styleIndex: 0,
|
||||
username: clientLoggedIn1Username,
|
||||
displayName: clientLoggedIn1Username,
|
||||
},
|
||||
{
|
||||
active: true,
|
||||
cursor: {
|
||||
from: 0,
|
||||
to: 0,
|
||||
},
|
||||
styleIndex: 1,
|
||||
username: clientLoggedIn2Username,
|
||||
displayName: clientLoggedIn2Username,
|
||||
},
|
||||
{
|
||||
active: true,
|
||||
cursor: {
|
||||
from: 0,
|
||||
to: 0,
|
||||
},
|
||||
displayName: guestDisplayName,
|
||||
styleIndex: 2,
|
||||
username: null,
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
@ -495,7 +730,10 @@ describe('realtime user status adapter', () => {
|
|||
expectedReactivityMessage3,
|
||||
);
|
||||
expect(clientNotReadySendMessageSpy).toHaveBeenCalledTimes(0);
|
||||
expect(clientDeclineSendMessageSpy).toHaveBeenCalledTimes(2);
|
||||
expect(clientDeclineSendMessageSpy).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
expectedReactivityMessage5,
|
||||
);
|
||||
|
||||
clientLoggedIn1
|
||||
.getTransporter()
|
||||
|
@ -516,30 +754,9 @@ describe('realtime user status adapter', () => {
|
|||
expectedReactivityMessage3,
|
||||
);
|
||||
expect(clientNotReadySendMessageSpy).toHaveBeenCalledTimes(0);
|
||||
expect(clientDeclineSendMessageSpy).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
it('will ignore updates from read only clients', () => {
|
||||
expect(clientLoggedIn1SendMessageSpy).toHaveBeenCalledTimes(0);
|
||||
expect(clientLoggedIn2SendMessageSpy).toHaveBeenCalledTimes(0);
|
||||
expect(clientGuestSendMessageSpy).toHaveBeenCalledTimes(0);
|
||||
expect(clientNotReadySendMessageSpy).toHaveBeenCalledTimes(0);
|
||||
expect(clientDeclineSendMessageSpy).toHaveBeenCalledTimes(0);
|
||||
|
||||
clientDecline
|
||||
.getTransporter()
|
||||
.emit(MessageType.REALTIME_USER_SINGLE_UPDATE, {
|
||||
type: MessageType.REALTIME_USER_SINGLE_UPDATE,
|
||||
payload: {
|
||||
from: 0,
|
||||
to: 1234,
|
||||
},
|
||||
});
|
||||
|
||||
expect(clientLoggedIn1SendMessageSpy).toHaveBeenCalledTimes(0);
|
||||
expect(clientLoggedIn2SendMessageSpy).toHaveBeenCalledTimes(0);
|
||||
expect(clientGuestSendMessageSpy).toHaveBeenCalledTimes(0);
|
||||
expect(clientNotReadySendMessageSpy).toHaveBeenCalledTimes(0);
|
||||
expect(clientDeclineSendMessageSpy).toHaveBeenCalledTimes(0);
|
||||
expect(clientDeclineSendMessageSpy).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
expectedReactivityMessage5,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -41,10 +41,12 @@ export class RealtimeUserStatusAdapter {
|
|||
styleIndex: this.findLeastUsedStyleIndex(
|
||||
this.createStyleIndexToCountMap(realtimeNote),
|
||||
),
|
||||
cursor: {
|
||||
from: 0,
|
||||
to: 0,
|
||||
},
|
||||
cursor: !this.acceptCursorUpdateProvider()
|
||||
? null
|
||||
: {
|
||||
from: 0,
|
||||
to: 0,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -53,10 +55,10 @@ export class RealtimeUserStatusAdapter {
|
|||
const transporterMessagesListener = connection.getTransporter().on(
|
||||
MessageType.REALTIME_USER_SINGLE_UPDATE,
|
||||
(message: Message<MessageType.REALTIME_USER_SINGLE_UPDATE>) => {
|
||||
if (this.acceptCursorUpdateProvider()) {
|
||||
this.realtimeUser.cursor = message.payload;
|
||||
this.sendRealtimeUserStatusUpdateEvent(connection);
|
||||
}
|
||||
this.realtimeUser.cursor = this.acceptCursorUpdateProvider()
|
||||
? message.payload
|
||||
: null;
|
||||
this.sendRealtimeUserStatusUpdateEvent(connection);
|
||||
},
|
||||
{ objectify: true },
|
||||
) as Listener;
|
||||
|
@ -83,10 +85,7 @@ export class RealtimeUserStatusAdapter {
|
|||
const realtimeUserSetActivityListener = connection.getTransporter().on(
|
||||
MessageType.REALTIME_USER_SET_ACTIVITY,
|
||||
(message: Message<MessageType.REALTIME_USER_SET_ACTIVITY>) => {
|
||||
if (
|
||||
!this.acceptCursorUpdateProvider() ||
|
||||
this.realtimeUser.active === message.payload.active
|
||||
) {
|
||||
if (this.realtimeUser.active === message.payload.active) {
|
||||
return;
|
||||
}
|
||||
this.realtimeUser.active = message.payload.active;
|
||||
|
@ -115,9 +114,6 @@ export class RealtimeUserStatusAdapter {
|
|||
const realtimeUser =
|
||||
receivingClient.getRealtimeUserStateAdapter().realtimeUser;
|
||||
const realtimeUsers = this.collectAllConnectionsExcept(receivingClient)
|
||||
.filter((client) =>
|
||||
client.getRealtimeUserStateAdapter().acceptCursorUpdateProvider(),
|
||||
)
|
||||
.map((client) => client.getRealtimeUserStateAdapter().realtimeUser)
|
||||
.filter((realtimeUser) => realtimeUser !== null);
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ export interface RealtimeUser {
|
|||
username: string | null
|
||||
active: boolean
|
||||
styleIndex: number
|
||||
cursor: RemoteCursor
|
||||
cursor: RemoteCursor | null
|
||||
}
|
||||
|
||||
export interface RemoteCursor {
|
||||
|
|
|
@ -20,12 +20,19 @@ export class ReceiveRemoteCursorViewPlugin implements PluginValue {
|
|||
this.listener = messageTransporter.on(
|
||||
MessageType.REALTIME_USER_STATE_SET,
|
||||
({ payload }) => {
|
||||
const cursors: RemoteCursor[] = payload.users.map((user) => ({
|
||||
from: user.cursor.from,
|
||||
to: user.cursor.to,
|
||||
displayName: user.displayName,
|
||||
styleIndex: user.styleIndex
|
||||
}))
|
||||
const cursors = payload.users
|
||||
.map((user) => {
|
||||
if (!user.cursor) {
|
||||
return undefined
|
||||
}
|
||||
return {
|
||||
from: user.cursor.from,
|
||||
to: user.cursor.to,
|
||||
displayName: user.displayName,
|
||||
styleIndex: user.styleIndex
|
||||
}
|
||||
})
|
||||
.filter((value) => value !== undefined) as RemoteCursor[]
|
||||
view.dispatch({
|
||||
effects: [remoteCursorUpdateEffect.of(cursors)]
|
||||
})
|
||||
|
|
Loading…
Reference in a new issue