fix: do not attempt to join call on doubleclick if missing permissions (#2798)

* fix: do not attempt to join call on doubleclick if missing permissions

* update comment

* export getPowersLevelFromMatrixEvent for usage elsewhere

* only read vc permissions when actually needed instead of reactively
This commit is contained in:
James
2026-04-16 08:25:53 -04:00
committed by GitHub
parent b107109453
commit 098684973e
2 changed files with 18 additions and 7 deletions

View File

@@ -23,12 +23,12 @@ import { useAtom, useAtomValue } from 'jotai';
import { NavItem, NavItemContent, NavItemOptions, NavLink } from '../../components/nav'; import { NavItem, NavItemContent, NavItemOptions, NavLink } from '../../components/nav';
import { UnreadBadge, UnreadBadgeCenter } from '../../components/unread-badge'; import { UnreadBadge, UnreadBadgeCenter } from '../../components/unread-badge';
import { RoomAvatar, RoomIcon } from '../../components/room-avatar'; import { RoomAvatar, RoomIcon } from '../../components/room-avatar';
import { getDirectRoomAvatarUrl, getRoomAvatarUrl } from '../../utils/room'; import { getDirectRoomAvatarUrl, getRoomAvatarUrl, getStateEvent } from '../../utils/room';
import { nameInitials } from '../../utils/common'; import { nameInitials } from '../../utils/common';
import { useMatrixClient } from '../../hooks/useMatrixClient'; import { useMatrixClient } from '../../hooks/useMatrixClient';
import { useRoomUnread } from '../../state/hooks/unread'; import { useRoomUnread } from '../../state/hooks/unread';
import { roomToUnreadAtom } from '../../state/room/roomToUnread'; import { roomToUnreadAtom } from '../../state/room/roomToUnread';
import { usePowerLevels } from '../../hooks/usePowerLevels'; import { getPowersLevelFromMatrixEvent, usePowerLevels } from '../../hooks/usePowerLevels';
import { copyToClipboard } from '../../utils/dom'; import { copyToClipboard } from '../../utils/dom';
import { markAsRead } from '../../utils/notifications'; import { markAsRead } from '../../utils/notifications';
import { UseStateProvider } from '../../components/UseStateProvider'; import { UseStateProvider } from '../../components/UseStateProvider';
@@ -49,8 +49,8 @@ import {
RoomNotificationMode, RoomNotificationMode,
} from '../../hooks/useRoomsNotificationPreferences'; } from '../../hooks/useRoomsNotificationPreferences';
import { RoomNotificationModeSwitcher } from '../../components/RoomNotificationSwitcher'; import { RoomNotificationModeSwitcher } from '../../components/RoomNotificationSwitcher';
import { useRoomCreators } from '../../hooks/useRoomCreators'; import { getRoomCreatorsForRoomId, useRoomCreators } from '../../hooks/useRoomCreators';
import { useRoomPermissions } from '../../hooks/useRoomPermissions'; import { getRoomPermissionsAPI, useRoomPermissions } from '../../hooks/useRoomPermissions';
import { InviteUserPrompt } from '../../components/invite-user-prompt'; import { InviteUserPrompt } from '../../components/invite-user-prompt';
import { useRoomName } from '../../hooks/useRoomMeta'; import { useRoomName } from '../../hooks/useRoomMeta';
import { useCallMembers, useCallSession } from '../../hooks/useCall'; import { useCallMembers, useCallSession } from '../../hooks/useCall';
@@ -59,6 +59,7 @@ import { callChatAtom } from '../../state/callEmbed';
import { useCallPreferencesAtom } from '../../state/hooks/callPreferences'; import { useCallPreferencesAtom } from '../../state/hooks/callPreferences';
import { useAutoDiscoveryInfo } from '../../hooks/useAutoDiscoveryInfo'; import { useAutoDiscoveryInfo } from '../../hooks/useAutoDiscoveryInfo';
import { livekitSupport } from '../../hooks/useLivekitSupport'; import { livekitSupport } from '../../hooks/useLivekitSupport';
import { StateEvent } from '../../../types/matrix/room';
type RoomNavItemMenuProps = { type RoomNavItemMenuProps = {
room: Room; room: Room;
@@ -287,8 +288,18 @@ export function RoomNavItem({
const autoDiscoveryInfo = useAutoDiscoveryInfo(); const autoDiscoveryInfo = useAutoDiscoveryInfo();
const handleStartCall: MouseEventHandler<HTMLAnchorElement> = (evt) => { const handleStartCall: MouseEventHandler<HTMLAnchorElement> = (evt) => {
// Do not join if no livekit support or call is not started by others const powerLevelsEvent = getStateEvent(room, StateEvent.RoomPowerLevels);
if (!livekitSupport(autoDiscoveryInfo) && callMembers.length === 0) { const powerLevels = getPowersLevelFromMatrixEvent(powerLevelsEvent);
const creators = getRoomCreatorsForRoomId(mx, room.roomId);
const permissions = getRoomPermissionsAPI(creators, powerLevels);
const hasCallPermission = permissions.event(
StateEvent.GroupCallMemberPrefix,
mx.getSafeUserId()
);
// Do not join if missing permissions or no livekit support and call is not started by others
if (!hasCallPermission || (!livekitSupport(autoDiscoveryInfo) && callMembers.length === 0)) {
return; return;
} }

View File

@@ -57,7 +57,7 @@ const fillMissingPowers = (powerLevels: IPowerLevels): IPowerLevels =>
return draftPl; return draftPl;
}); });
const getPowersLevelFromMatrixEvent = (mEvent?: MatrixEvent): IPowerLevels => { export const getPowersLevelFromMatrixEvent = (mEvent?: MatrixEvent): IPowerLevels => {
const plContent = mEvent?.getContent<IPowerLevels>(); const plContent = mEvent?.getContent<IPowerLevels>();
const powerLevels = !plContent ? DEFAULT_POWER_LEVELS : fillMissingPowers(plContent); const powerLevels = !plContent ? DEFAULT_POWER_LEVELS : fillMissingPowers(plContent);