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

Enable forwarding static locations #8553

Merged
merged 3 commits into from
May 10, 2022
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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())
);
}
96 changes: 96 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,91 @@ 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(() => {
jest.spyOn(Date, 'now').mockReturnValue(now);
});

afterAll(() => {
jest.spyOn(Date, 'now').mockRestore();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I might be missing why is this necessary?

});

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