Skip to content
This repository has been archived by the owner on Sep 11, 2024. It is now read-only.

Commit

Permalink
Enable forwarding static locations (#8553)
Browse files Browse the repository at this point in the history
* enable forwarding for location events

Signed-off-by: Kerry Archibald <kerrya@element.io>

* allow forwarding of static locations

Signed-off-by: Kerry Archibald <kerrya@element.io>

* add comment

Signed-off-by: Kerry Archibald <kerrya@element.io>
  • Loading branch information
Kerry committed May 10, 2022
1 parent 3c5942a commit c67b41f
Show file tree
Hide file tree
Showing 5 changed files with 135 additions and 11 deletions.
39 changes: 33 additions & 6 deletions src/components/views/dialogs/ForwardDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import { Room } from "matrix-js-sdk/src/models/room";
import { MatrixClient } from "matrix-js-sdk/src/client";
import { RoomMember } from "matrix-js-sdk/src/models/room-member";
import { EventType } from "matrix-js-sdk/src/@types/event";
import { ILocationContent, LocationAssetType, M_TIMESTAMP } from "matrix-js-sdk/src/@types/location";
import { makeLocationContent } from "matrix-js-sdk/src/content-helpers";

import { _t } from "../../../languageHandler";
import dis from "../../../dispatcher/dispatcher";
Expand All @@ -47,6 +49,8 @@ import { Action } from "../../../dispatcher/actions";
import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload";
import { ButtonEvent } from "../elements/AccessibleButton";
import { roomContextDetailsText } from "../../../utils/i18n-helpers";
import { isLocationEvent } from "../../../utils/EventUtils";
import { isSelfLocation, locationEventGeoUri } from "../../../utils/location";

const AVATAR_SIZE = 30;

Expand Down Expand Up @@ -156,19 +160,42 @@ const Entry: React.FC<IEntryProps> = ({ room, type, content, matrixClient: cli,
</div>;
};

const getStrippedEventContent = (event: MatrixEvent): IContent => {
const {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
"m.relates_to": _, // strip relations - in future we will attach a relation pointing at the original event
// We're taking a shallow copy here to avoid https://github.com/vector-im/element-web/issues/10924
...content
} = event.getContent();

// self location shares should have their description removed
// and become 'pin' share type
if (isLocationEvent(event) && isSelfLocation(content as ILocationContent)) {
const timestamp = M_TIMESTAMP.findIn<number>(content);
const geoUri = locationEventGeoUri(event);
return {
...content,
...makeLocationContent(
undefined, // text
geoUri,
timestamp || Date.now(),
undefined, // description
LocationAssetType.Pin,
),
};
}

return content;
};

const ForwardDialog: React.FC<IProps> = ({ matrixClient: cli, event, permalinkCreator, onFinished }) => {
const userId = cli.getUserId();
const [profileInfo, setProfileInfo] = useState<any>({});
useEffect(() => {
cli.getProfileInfo(userId).then(info => setProfileInfo(info));
}, [cli, userId]);

const {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
"m.relates_to": _, // strip relations - in future we will attach a relation pointing at the original event
// We're taking a shallow copy here to avoid https://github.com/vector-im/element-web/issues/10924
...content
} = event.getContent();
const content = getStrippedEventContent(event);

// For the message preview we fake the sender as ourselves
const mockEvent = new MatrixEvent({
Expand Down
1 change: 0 additions & 1 deletion src/utils/EventUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,6 @@ export const isLocationEvent = (event: MatrixEvent): boolean => {

export function canForward(event: MatrixEvent): boolean {
return !(
isLocationEvent(event) ||
M_POLL_START.matches(event.getType())
);
}
98 changes: 98 additions & 0 deletions test/components/views/dialogs/ForwardDialog-test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,23 @@ import React from "react";
import { mount } from "enzyme";
import { act } from "react-dom/test-utils";
import { MatrixEvent, EventType } from "matrix-js-sdk/src/matrix";
import { ReactWrapper } from "enzyme";
import { LocationAssetType, M_ASSET, M_LOCATION, M_TIMESTAMP } from "matrix-js-sdk/src/@types/location";
import { TEXT_NODE_TYPE } from "matrix-js-sdk/src/@types/extensible_events";

import { MatrixClientPeg } from "../../../../src/MatrixClientPeg";
import ForwardDialog from "../../../../src/components/views/dialogs/ForwardDialog";
import DMRoomMap from "../../../../src/utils/DMRoomMap";
import { RoomPermalinkCreator } from "../../../../src/utils/permalinks/Permalinks";
import {
getMockClientWithEventEmitter,
makeLegacyLocationEvent,
makeLocationEvent,
mkEvent,
mkMessage,
mkStubRoom,
} from "../../../test-utils";
import { TILE_SERVER_WK_KEY } from "../../../../src/utils/WellKnownUtils";

describe("ForwardDialog", () => {
const sourceRoom = "!111111111111111111:example.org";
Expand Down Expand Up @@ -58,6 +64,9 @@ describe("ForwardDialog", () => {
}),
decryptEventIfNeeded: jest.fn(),
sendEvent: jest.fn(),
getClientWellKnown: jest.fn().mockReturnValue({
[TILE_SERVER_WK_KEY.name]: { map_style_url: 'maps.com' },
}),
});
const defaultRooms = ["a", "A", "b"].map(name => mkStubRoom(name, name, mockClient));

Expand Down Expand Up @@ -199,4 +208,93 @@ describe("ForwardDialog", () => {
const secondButton = wrapper.find("AccessibleButton.mx_ForwardList_sendButton").last();
expect(secondButton.prop("disabled")).toBe(false);
});

describe('Location events', () => {
// 14.03.2022 16:15
const now = 1647270879403;
const roomId = "a";
const geoUri = "geo:51.5076,-0.1276";
const legacyLocationEvent = makeLegacyLocationEvent(geoUri);
const modernLocationEvent = makeLocationEvent(geoUri);
const pinDropLocationEvent = makeLocationEvent(geoUri, LocationAssetType.Pin);

beforeEach(() => {
// legacy events will default timestamp to Date.now()
// mock a stable now for easy assertion
jest.spyOn(Date, 'now').mockReturnValue(now);
});

afterAll(() => {
jest.spyOn(Date, 'now').mockRestore();
});

const sendToFirstRoom = (wrapper: ReactWrapper): void =>
act(() => {
const sendToFirstRoomButton = wrapper.find("AccessibleButton.mx_ForwardList_sendButton").first();
sendToFirstRoomButton.simulate("click");
});

it('converts legacy location events to pin drop shares', async () => {
const wrapper = await mountForwardDialog(legacyLocationEvent);

expect(wrapper.find('MLocationBody').length).toBeTruthy();
sendToFirstRoom(wrapper);

// text and description from original event are removed
// text gets new default message from event values
// timestamp is defaulted to now
const text = `Location ${geoUri} at ${new Date(now).toISOString()}`;
const expectedStrippedContent = {
...modernLocationEvent.getContent(),
body: text,
[TEXT_NODE_TYPE.name]: text,
[M_TIMESTAMP.name]: now,
[M_ASSET.name]: { type: LocationAssetType.Pin },
[M_LOCATION.name]: {
uri: geoUri,
description: undefined,
},
};
expect(mockClient.sendEvent).toHaveBeenCalledWith(
roomId, legacyLocationEvent.getType(), expectedStrippedContent,
);
});

it('removes personal information from static self location shares', async () => {
const wrapper = await mountForwardDialog(modernLocationEvent);

expect(wrapper.find('MLocationBody').length).toBeTruthy();
sendToFirstRoom(wrapper);

const timestamp = M_TIMESTAMP.findIn<number>(modernLocationEvent.getContent());
// text and description from original event are removed
// text gets new default message from event values
const text = `Location ${geoUri} at ${new Date(timestamp).toISOString()}`;
const expectedStrippedContent = {
...modernLocationEvent.getContent(),
body: text,
[TEXT_NODE_TYPE.name]: text,
[M_ASSET.name]: { type: LocationAssetType.Pin },
[M_LOCATION.name]: {
uri: geoUri,
description: undefined,
},
};
expect(mockClient.sendEvent).toHaveBeenCalledWith(
roomId, modernLocationEvent.getType(), expectedStrippedContent,
);
});

it('forwards pin drop event', async () => {
const wrapper = await mountForwardDialog(pinDropLocationEvent);

expect(wrapper.find('MLocationBody').length).toBeTruthy();

sendToFirstRoom(wrapper);

expect(mockClient.sendEvent).toHaveBeenCalledWith(
roomId, pinDropLocationEvent.getType(), pinDropLocationEvent.getContent(),
);
});
});
});
4 changes: 2 additions & 2 deletions test/test-utils/location.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@ limitations under the License.

import { LocationAssetType, M_LOCATION } from "matrix-js-sdk/src/@types/location";
import { makeLocationContent } from "matrix-js-sdk/src/content-helpers";
import { MatrixEvent } from "matrix-js-sdk/src/matrix";
import { MatrixEvent, EventType } from "matrix-js-sdk/src/matrix";

let id = 1;
export const makeLegacyLocationEvent = (geoUri: string): MatrixEvent => {
return new MatrixEvent(
{
"event_id": `$${++id}`,
"type": M_LOCATION.name,
"type": EventType.RoomMessage,
"content": {
"body": "Something about where I am",
"msgtype": "m.location",
Expand Down
4 changes: 2 additions & 2 deletions test/utils/EventUtils-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -315,11 +315,11 @@ describe('EventUtils', () => {
});

describe('canForward()', () => {
it('returns false for a location event', () => {
it('returns true for a location event', () => {
const event = new MatrixEvent({
type: M_LOCATION.name,
});
expect(canForward(event)).toBe(false);
expect(canForward(event)).toBe(true);
});
it('returns false for a poll event', () => {
const event = makePollStartEvent('Who?', userId);
Expand Down

0 comments on commit c67b41f

Please sign in to comment.