Skip to content

Commit

Permalink
Initial draft
Browse files Browse the repository at this point in the history
Signed-off-by: Milton Moura <[email protected]>
  • Loading branch information
mgcm committed Nov 12, 2024
1 parent b7d3906 commit 68bc427
Show file tree
Hide file tree
Showing 18 changed files with 775 additions and 2 deletions.
11 changes: 11 additions & 0 deletions matrix-neoboard-widget/src/widgetCapabilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ import {
ROOM_EVENT_DOCUMENT_CHUNK,
ROOM_EVENT_DOCUMENT_CREATE,
ROOM_EVENT_DOCUMENT_SNAPSHOT,
STATE_EVENT_ROOM_ENCRYPTION,
STATE_EVENT_ROOM_HISTORY_VISIBILITY,
STATE_EVENT_ROOM_NAME,
STATE_EVENT_WHITEBOARD,
STATE_EVENT_WHITEBOARD_SESSIONS,
Expand Down Expand Up @@ -102,6 +104,15 @@ export const widgetCapabilities = [
STATE_EVENT_ROOM_NAME,
),

WidgetEventCapability.forStateEvent(
EventDirection.Receive,
STATE_EVENT_ROOM_HISTORY_VISIBILITY,
),
WidgetEventCapability.forStateEvent(
EventDirection.Receive,
STATE_EVENT_ROOM_ENCRYPTION,
),

WidgetEventCapability.forToDeviceEvent(
EventDirection.Send,
TO_DEVICE_MESSAGE_CONNECTION_SIGNALING,
Expand Down
18 changes: 18 additions & 0 deletions packages/react-sdk/src/components/Whiteboard/WhiteboardHost.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,25 @@ const WhiteboardHost = ({
useLayoutState();
const { activeElementIds } = useActiveElements();
const overrides = useElementOverrides(activeElementIds);
/*
const { data: roomMembers } = useGetRoomMembersQuery();
const whiteboardInstance = useActiveWhiteboardInstance();
useEffect(() => {
const members = roomMembers?.entities;
if (members) {
const invitesOrJoins = Object.values(members).filter((member) => {
return member.content.membership == 'invite' || member.content.membership == 'join';
});
const lastInviteOrJoin = invitesOrJoins.sort((a, b) => {
return b.origin_server_ts - a.origin_server_ts;
});
console.log("MGCM: lastInviteOrJoin:", lastInviteOrJoin[0]);
whiteboardInstance.persistIfNecessary(lastInviteOrJoin[0].origin_server_ts);
}
}, [roomMembers, whiteboardInstance]);
*/
return (
<Box
flex={1}
Expand Down
1 change: 1 addition & 0 deletions packages/react-sdk/src/lib/testUtils/documentTestUtils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ export function mockWhiteboardManager(
observeIsLoading: () => of(false),
destroy: () => {},
persist: () => Promise.resolve(),
getLatestDocumentSnapshot: () => undefined,
};

const whiteboardInstance = new WhiteboardInstanceImpl(
Expand Down
54 changes: 54 additions & 0 deletions packages/react-sdk/src/lib/testUtils/matrixTestUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ import {
DocumentChunk,
DocumentCreate,
DocumentSnapshot,
RoomEncryptionEvent,
RoomHistoryVisibilityEvent,
RoomNameEvent,
Whiteboard,
WhiteboardSession,
Expand Down Expand Up @@ -96,6 +98,58 @@ export function mockPowerLevelsEvent({
};
}

/**
* Create a matrix room encryption event with known test data.
*
* @remarks Only use for tests
*/
export function mockRoomEncryption({
room_id = '!room-id',
content = {},
}: {
room_id?: string;
content?: Partial<RoomEncryptionEvent>;
} = {}): StateEvent<RoomEncryptionEvent> {
return {
type: 'm.room.encryption',
sender: '',
content: {
algorithm: 'm.megolm.v1.aes-sha2',
...content,
},
state_key: room_id,
origin_server_ts: 0,
event_id: '$event-id-0',
room_id,
};
}

/**
* Create a matrix room history visibility event with known test data.
*
* @remarks Only use for tests
*/
export function mockRoomHistoryVisibility({
room_id = '!room-id',
content = {},
}: {
room_id?: string;
content?: Partial<RoomHistoryVisibilityEvent>;
} = {}): StateEvent<RoomHistoryVisibilityEvent> {
return {
type: 'm.room.history_visibility',
sender: '',
content: {
history_visibility: 'shared',
...content,
},
state_key: room_id,
origin_server_ts: 0,
event_id: '$event-id-0',
room_id,
};
}

/**
* Create a matrix room name event with known test data.
*
Expand Down
10 changes: 10 additions & 0 deletions packages/react-sdk/src/model/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,16 @@ export {
isValidDocumentSnapshotRoomEvent,
} from './documentSnapshot';
export type { DocumentSnapshot } from './documentSnapshot';
export {
STATE_EVENT_ROOM_ENCRYPTION,
isValidRoomEncryptionEvent,
} from './roomEncryptionEvent';
export type { RoomEncryptionEvent } from './roomEncryptionEvent';
export {
STATE_EVENT_ROOM_HISTORY_VISIBILITY,
isValidRoomHistoryVisibilityEvent,
} from './roomHistoryVisibilityEvent';
export type { RoomHistoryVisibilityEvent } from './roomHistoryVisibilityEvent';
export { STATE_EVENT_ROOM_NAME, isValidRoomNameEvent } from './roomNameEvent';
export type { RoomNameEvent } from './roomNameEvent';
export {
Expand Down
74 changes: 74 additions & 0 deletions packages/react-sdk/src/model/roomEncryptionEvent.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
* Copyright 2024 Nordeck IT + Consulting GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { describe, expect, it } from 'vitest';
import { isValidRoomEncryptionEvent } from './roomEncryptionEvent';

describe('is valid event', () => {
it('should accept event', () => {
expect(
isValidRoomEncryptionEvent({
content: {
algorithm: 'm.megolm.v1.aes-sha2',
},
event_id: '$event-id',
origin_server_ts: 0,
room_id: '!room-id',
state_key: '',
sender: '@user-id',
type: 'm.room.encryption',
}),
).toBe(true);
});

it('should accept additional properties', () => {
expect(
isValidRoomEncryptionEvent({
content: {
algorithm: 'm.megolm.v1.aes-sha2',
rotation_period_ms: 604800000,
rotation_period_msgs: 100,
},
event_id: '$event-id',
origin_server_ts: 0,
room_id: '!room-id',
state_key: '',
sender: '@user-id',
type: 'm.room.encryption',
}),
).toBe(true);
});

it.each<object>([{ algorithm: undefined }, { algorithm: null }])(
'should reject event with patch %j',
(patch: object) => {
expect(
isValidRoomEncryptionEvent({
content: {
algorithm: 'm.megolm.v1.aes-sha2',
...patch,
},
event_id: '$event-id',
origin_server_ts: 0,
room_id: '!room-id',
state_key: '',
sender: '@user-id',
type: 'm.room.encryption',
}),
).toBe(false);
},
);
});
40 changes: 40 additions & 0 deletions packages/react-sdk/src/model/roomEncryptionEvent.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* Copyright 2024 Nordeck IT + Consulting GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { StateEvent } from '@matrix-widget-toolkit/api';
import Joi from 'joi';
import { isValidEvent } from './validation';

export const STATE_EVENT_ROOM_ENCRYPTION = 'm.room.encryption';

export type RoomEncryptionEvent = {
algorithm: string;
};

// based on https://github.com/matrix-org/matrix-spec/blob/03cdea4b57320926a6da73ad3b3f6c7f4fd0a7c2/data/event-schemas/schema/m.room.encryption.yaml
const roomEncryptionEventSchema = Joi.object<RoomEncryptionEvent, true>({
algorithm: Joi.string().required(),
}).unknown();

export function isValidRoomEncryptionEvent(
event: StateEvent<unknown>,
): event is StateEvent<RoomEncryptionEvent> {
return isValidEvent(
event,
STATE_EVENT_ROOM_ENCRYPTION,
roomEncryptionEventSchema,
);
}
77 changes: 77 additions & 0 deletions packages/react-sdk/src/model/roomHistoryVisibilityEvent.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*
* Copyright 2024 Nordeck IT + Consulting GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { describe, expect, it } from 'vitest';
import { isValidRoomHistoryVisibilityEvent } from './roomHistoryVisibilityEvent';

describe('is valid event', () => {
it('should accept event', () => {
expect(
isValidRoomHistoryVisibilityEvent({
content: {
history_visibility: 'shared',
},
event_id: '$event-id',
origin_server_ts: 0,
room_id: '!room-id',
state_key: '',
sender: '@user-id',
type: 'm.room.history_visibility',
}),
).toBe(true);
});

it.each<object>([
{ history_visibility: 'invited' },
{ history_visibility: 'joined' },
{ history_visibility: 'world_readable' },
])('should accept event with patch %j', (patch: object) => {
expect(
isValidRoomHistoryVisibilityEvent({
content: {
history_visibility: 'shared',
...patch,
},
event_id: '$event-id',
origin_server_ts: 0,
room_id: '!room-id',
state_key: '',
sender: '@user-id',
type: 'm.room.history_visibility',
}),
).toBe(true);
});

it.each<object>([
{ history_visibility: undefined },
{ history_visibility: null },
])('should reject event with patch %j', (patch: object) => {
expect(
isValidRoomHistoryVisibilityEvent({
content: {
history_visibility: 'shared',
...patch,
},
event_id: '$event-id',
origin_server_ts: 0,
room_id: '!room-id',
state_key: '',
sender: '@user-id',
type: 'm.room.history_visibility',
}),
).toBe(false);
});
});
43 changes: 43 additions & 0 deletions packages/react-sdk/src/model/roomHistoryVisibilityEvent.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Copyright 2024 Nordeck IT + Consulting GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { StateEvent } from '@matrix-widget-toolkit/api';
import Joi from 'joi';
import { isValidEvent } from './validation';

export const STATE_EVENT_ROOM_HISTORY_VISIBILITY = 'm.room.history_visibility';

export type RoomHistoryVisibilityEvent = {
history_visibility: string;
};

// based on https://github.com/matrix-org/matrix-spec/blob/03cdea4b57320926a6da73ad3b3f6c7f4fd0a7c2/data/event-schemas/schema/m.room.history_visibility.yaml
const roomHistoryVisibilityEventSchema = Joi.object<
RoomHistoryVisibilityEvent,
true
>({
history_visibility: Joi.string().required(),
}).unknown();

export function isValidRoomHistoryVisibilityEvent(
event: StateEvent<unknown>,
): event is StateEvent<RoomHistoryVisibilityEvent> {
return isValidEvent(
event,
STATE_EVENT_ROOM_HISTORY_VISIBILITY,
roomHistoryVisibilityEventSchema,
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ describe('presentationManager', () => {
undo: vi.fn(),
destroy: vi.fn(),
persist: vi.fn(),
persistIfNecessary: vi.fn(),
};

enableObserveVisibilityStateSubject = new Subject<boolean>();
Expand Down
Loading

0 comments on commit 68bc427

Please sign in to comment.