Dice: Add permission check (#6697)

This commit is contained in:
zubiden 2026-02-22 23:43:19 +01:00 committed by Alexander Zinchuk
parent 1f0ac5b276
commit cdc4f0396c
16 changed files with 60 additions and 68 deletions

View File

@ -6,7 +6,6 @@ import type { ApiChat } from '../../api/types';
import {
getChatTitle,
getPrivateChatUserId,
getUserFirstOrLastName,
isChatBasicGroup,
isChatChannel,
@ -244,12 +243,10 @@ export default memo(withGlobal<OwnProps>(
(global, { chat, isSavedDialog }): Complete<StateProps> => {
const isPrivateChat = isUserId(chat.id);
const isChatWithSelf = selectIsChatWithSelf(global, chat.id);
const user = isPrivateChat && selectUser(global, getPrivateChatUserId(chat)!);
const user = selectUser(global, chat.id);
const isBot = user && isUserBot(user) && !chat.isSupport;
const canDeleteForAll = (isPrivateChat && !isChatWithSelf && !isBot && !isSavedDialog);
const contactName = isPrivateChat
? getUserFirstOrLastName(selectUser(global, getPrivateChatUserId(chat)!))
: undefined;
const contactName = isPrivateChat ? getUserFirstOrLastName(user) : undefined;
return {
isPrivateChat,

View File

@ -12,7 +12,6 @@ import type { IRadioOption } from '../ui/CheckboxGroup';
import {
getHasAdminRight,
getPrivateChatUserId,
getUserFirstOrLastName, isChatBasicGroup,
isChatChannel,
isChatSuperGroup,
@ -506,14 +505,14 @@ export default memo(withGlobal<OwnProps>(
const isSuperGroup = Boolean(chat) && isChatSuperGroup(chat);
const isSchedule = deleteMessageModal?.isSchedule;
const onConfirm = deleteMessageModal?.onConfirm;
const contactName = chat && isUserId(chat.id)
? getUserFirstOrLastName(selectUser(global, getPrivateChatUserId(chat)!))
const contactName = chatId && isUserId(chatId)
? getUserFirstOrLastName(selectUser(global, chatId))
: undefined;
const chatBot = Boolean(chat && !isSystemBot(chat.id) && selectBot(global, chat.id));
const adminMembersById = chatFullInfo?.adminMembersById;
const canBanUsers = chat && getHasAdminRight(chat, 'banUsers') && !chat.isMonoforum; // TODO: Ban in channel in case of monoforum
const isCreator = chat?.isCreator;
const isChatWithBot = chat ? selectIsChatWithBot(global, chat) : undefined;
const isChatWithBot = chatId ? selectIsChatWithBot(global, chatId) : undefined;
const willDeleteForCurrentUserOnly = (chat && isChatBasicGroup(chat) && !canDeleteForAll) || isChatWithBot;
const willDeleteForAll = chat && (isChatSuperGroup(chat) || isChannel);

View File

@ -2,7 +2,6 @@ import { memo, useState } from '../../lib/teact/teact';
import { getActions, withGlobal } from '../../global';
import {
getPrivateChatUserId,
getUserFirstOrLastName,
isChatBasicGroup,
isChatChannel,
@ -112,8 +111,8 @@ export default memo(withGlobal<OwnProps>(
const isGroup = Boolean(chat) && isChatBasicGroup(chat);
const isSuperGroup = Boolean(chat) && isChatSuperGroup(chat);
const canPinForAll = (isPrivateChat && !isChatWithSelf) || isSuperGroup || isGroup;
const contactName = chat && isUserId(chat.id)
? getUserFirstOrLastName(selectUser(global, getPrivateChatUserId(chat)!))
const contactName = chatId && isUserId(chatId)
? getUserFirstOrLastName(selectUser(global, chatId))
: undefined;
return {

View File

@ -1,10 +1,9 @@
import type { FC } from '../../../lib/teact/teact';
import { memo } from '../../../lib/teact/teact';
import { getActions, withGlobal } from '../../../global';
import type {
ApiChat, ApiMessage,
ApiUser,
ApiMessage,
ApiPeer,
} from '../../../api/types';
import {
@ -12,9 +11,9 @@ import {
getMessageRoundVideo,
getMessageSticker,
getMessageVideo,
getPrivateChatUserId,
} from '../../../global/helpers';
import { selectChat, selectUser } from '../../../global/selectors';
import { isApiPeerUser } from '../../../global/helpers/peers';
import { selectPeer } from '../../../global/selectors';
import buildClassName from '../../../util/buildClassName';
import { formatPastTimeShort } from '../../../util/dates/dateFormat';
import { type LangFn } from '../../../util/localization';
@ -44,17 +43,15 @@ type OwnProps = {
};
type StateProps = {
chat?: ApiChat;
privateChatUser?: ApiUser;
peer?: ApiPeer;
};
const ChatMessage: FC<OwnProps & StateProps> = ({
const ChatMessage = ({
message,
searchQuery,
chatId,
chat,
privateChatUser,
}) => {
peer,
}: OwnProps & StateProps) => {
const { focusMessage } = getActions();
const { isMobile } = useAppLayout();
@ -73,11 +70,11 @@ const ChatMessage: FC<OwnProps & StateProps> = ({
const buttonRef = useSelectWithEnter(handleClick);
if (!chat) {
if (!peer) {
return undefined;
}
const peer = privateChatUser || chat;
const user = isApiPeerUser(peer) ? peer : undefined;
return (
<ListItem
@ -88,14 +85,14 @@ const ChatMessage: FC<OwnProps & StateProps> = ({
>
<Avatar
peer={peer}
isSavedMessages={privateChatUser?.isSelf}
isSavedMessages={user?.isSelf}
/>
<div className="info">
<div className="info-row">
<FullNameTitle
peer={peer}
withEmojiStatus
isSavedMessages={chatId === privateChatUser?.id && privateChatUser?.isSelf}
isSavedMessages={user?.isSelf}
/>
<div className="message-date">
<Link className="date">
@ -141,17 +138,10 @@ function renderSummary(
export default memo(withGlobal<OwnProps>(
(global, { chatId }): Complete<StateProps> => {
const chat = selectChat(global, chatId);
if (!chat) {
return {} as Complete<StateProps>;
}
const privateChatUserId = getPrivateChatUserId(chat);
const privateChatUser = privateChatUserId ? selectUser(global, privateChatUserId) : undefined;
const peer = selectPeer(global, chatId);
return {
chat,
privateChatUser,
peer,
};
},
)(ChatMessage));

View File

@ -48,6 +48,7 @@ import { AudioOrigin } from '../../../types';
import { EMOJI_STATUS_LOOP_LIMIT, MESSAGE_APPEARANCE_DELAY } from '../../../config';
import {
areReactionsEmpty,
getAllowedAttachmentOptions,
getIsDownloading,
getMainUsername,
getMessageContent,
@ -88,6 +89,7 @@ import {
selectFullWebPageFromMessage,
selectIsChatProtected,
selectIsChatRestricted,
selectIsChatWithBot,
selectIsChatWithSelf,
selectIsCurrentUserFrozen,
selectIsCurrentUserPremium,
@ -331,6 +333,7 @@ type StateProps = {
isMediaNsfw?: boolean;
isReplyMediaNsfw?: boolean;
summary?: TextSummary;
canSendStickers?: boolean;
};
type MetaPosition =
@ -458,6 +461,7 @@ const Message = ({
minFutureTime,
webPage,
summary,
canSendStickers,
observeIntersectionForBottom,
observeIntersectionForLoading,
observeIntersectionForPlaying,
@ -1369,6 +1373,7 @@ const Message = ({
)}
{dice && (
<DiceWrapper
canSendDice={canSendStickers}
isLocal={isLocal}
dice={dice}
isOutgoing={isOwn}
@ -2015,6 +2020,7 @@ export default memo(withGlobal<OwnProps>(
const chat = selectChat(global, chatId);
const isChatWithSelf = selectIsChatWithSelf(global, chatId);
const isChatWithBot = selectIsChatWithBot(global, chatId);
const isSystemBotChat = isSystemBot(chatId);
const isAnonymousForwards = isAnonymousForwardsChat(chatId);
const isChannel = chat && isChatChannel(chat);
@ -2144,6 +2150,8 @@ export default memo(withGlobal<OwnProps>(
const summary = selectMessageSummary(global, chatId, message.id, requestedTranslationLanguage);
const allowedAttachmentOptions = getAllowedAttachmentOptions(chat, chatFullInfo, isChatWithBot);
return {
theme: selectTheme(global),
forceSenderName,
@ -2244,6 +2252,7 @@ export default memo(withGlobal<OwnProps>(
isReplyMediaNsfw,
webPage,
summary,
canSendStickers: allowedAttachmentOptions.canSendStickers,
};
},
)(Message));

View File

@ -1,14 +1,14 @@
.root {
cursor: var(--custom-cursor, pointer);
position: relative;
display: block !important;
width: var(--_size);
height: var(--_size);
}
.interactive {
cursor: pointer;
}
.sticker {
position: absolute;
inset: 0;

View File

@ -29,6 +29,7 @@ const FALLBACK_SIZE = 13 * REM;
const Dice = ({
dice,
canSendDice,
idleSticker,
valueSticker,
winEffect,
@ -62,6 +63,7 @@ const Dice = ({
});
const handleClick = useLastCallback(() => {
if (!canSendDice) return;
showNotification({
message: {
key: 'DiceToast',
@ -85,7 +87,11 @@ const Dice = ({
});
return (
<div className={styles.root} style={`--_size: ${width}px`} onClick={handleClick}>
<div
className={buildClassName(styles.root, canSendDice && styles.interactive)}
style={`--_size: ${width}px`}
onClick={handleClick}
>
{idleSticker && (
<div
ref={idleContainerRef}

View File

@ -13,6 +13,7 @@ export type OwnProps = {
canPlayWinEffect?: boolean;
isLocal?: boolean;
isOutgoing?: boolean;
canSendDice?: boolean;
onEffectPlayed?: NoneToVoidFunction;
observeIntersectionForLoading?: ObserveFn;
observeIntersectionForPlaying?: ObserveFn;

View File

@ -36,6 +36,7 @@ const WIN_BACKGROUND_DELAY = 700;
const SlotMachine = ({
dice,
canSendDice,
canPlayWinEffect,
isLocal,
isOutgoing,
@ -122,6 +123,7 @@ const SlotMachine = ({
});
const handleClick = useLastCallback(() => {
if (!canSendDice) return;
showNotification({
message: {
key: 'DiceToast',
@ -171,7 +173,12 @@ const SlotMachine = ({
}
return (
<div ref={ref} className={styles.root} style={`--_size: ${width}px`} onClick={handleClick}>
<div
ref={ref}
className={buildClassName(styles.root, canSendDice && styles.interactive)}
style={`--_size: ${width}px`}
onClick={handleClick}
>
{renderSticker(backgroundData, backgroundState !== 'base', false, true)}
{renderSticker(frameWinData, backgroundState !== 'win', false, false, undefined, onWinBackgroundFrame)}

View File

@ -173,7 +173,7 @@ export default memo(withGlobal(
const { chatId, threadId } = selectCurrentMessageList(global) || {};
const chat = chatId ? selectChat(global, chatId) : undefined;
const chatFullInfo = chatId ? selectChatFullInfo(global, chatId) : undefined;
const isChatWithBot = chat ? selectIsChatWithBot(global, chat) : undefined;
const isChatWithBot = chatId ? selectIsChatWithBot(global, chatId) : undefined;
const isSavedMessages = Boolean(chatId) && selectIsChatWithSelf(global, chatId);
const threadInfo = chatId && threadId ? selectThreadInfo(global, chatId, threadId) : undefined;
const isMessageThread = Boolean(!threadInfo?.isCommentsInfo && threadInfo?.fromChannelId);

View File

@ -70,6 +70,7 @@ import {
isMessageLocal,
isServiceNotificationMessage,
isUserBot,
isUserRightBanned,
splitMessagesForForwarding,
} from '../../helpers';
import { isApiPeerChat, isApiPeerUser } from '../../helpers/peers';
@ -452,9 +453,11 @@ addActionHandler('sendMessage', async (global, actions, payload): Promise<void>
});
}
const areStickersDisabled = isUserRightBanned(chat, 'sendStickers');
const diceEmojies = global.appConfig.diceEmojies;
let dice = payload.dice;
if (payload.text && !payload.entities?.length && diceEmojies.includes(payload.text)) {
if (!areStickersDisabled && payload.text && !payload.entities?.length && diceEmojies.includes(payload.text)) {
dice = payload.text;
}

View File

@ -350,7 +350,7 @@ addActionHandler('showAllowedMessageTypesNotification', (global, actions, payloa
if (!chat) return;
const chatFullInfo = selectChatFullInfo(global, chatId);
const isSavedMessages = chatId ? selectIsChatWithSelf(global, chatId) : undefined;
const isChatWithBot = chatId ? selectIsChatWithBot(global, chat) : undefined;
const isChatWithBot = chatId ? selectIsChatWithBot(global, chatId) : undefined;
const {
canSendPlainText, canSendPhotos, canSendVideos, canSendDocuments, canSendAudios,

View File

@ -85,13 +85,6 @@ export function getChatTypeLangKey(chat: ApiChat): RegularLangKey {
}
}
export function getPrivateChatUserId(chat: ApiChat) {
if (chat.type !== 'chatTypePrivate' && chat.type !== 'chatTypeSecret') {
return undefined;
}
return chat.id;
}
export function getChatTitle(lang: OldLangFn | LangFn, chat: ApiChat, isSelf = false) {
if (isSelf) {
return lang('SavedMessages');

View File

@ -12,7 +12,6 @@ import { isUserId } from '../../util/entities/ids';
import { getCurrentTabId } from '../../util/establishMultitabRole';
import {
getHasAdminRight,
getPrivateChatUserId,
isChatChannel,
isChatPublic,
isChatSuperGroup,
@ -45,21 +44,12 @@ export function selectChatListLoadingParameters<T extends GlobalState>(
return global.chats.loadingParameters[listType];
}
export function selectChatUser<T extends GlobalState>(global: T, chat: ApiChat) {
const userId = getPrivateChatUserId(chat);
if (!userId) {
return false;
}
return selectUser(global, userId);
}
export function selectIsChatWithSelf<T extends GlobalState>(global: T, chatId: string) {
return chatId === global.currentUserId;
}
export function selectIsChatWithBot<T extends GlobalState>(global: T, chat: ApiChat) {
const user = selectChatUser(global, chat);
export function selectIsChatWithBot<T extends GlobalState>(global: T, chatId: string) {
const user = selectUser(global, chatId);
return user && isUserBot(user);
}

View File

@ -1374,7 +1374,7 @@ export function selectForwardsCanBeSentToChat<T extends GlobalState>(
const chatMessages = selectChatMessages(global, fromChatId!);
const isSavedMessages = toChatId ? selectIsChatWithSelf(global, toChatId) : undefined;
const isChatWithBot = toChatId ? selectIsChatWithBot(global, chat) : undefined;
const isChatWithBot = toChatId ? selectIsChatWithBot(global, toChatId) : undefined;
const options = getAllowedAttachmentOptions(chat, chatFullInfo, isChatWithBot, isSavedMessages);
return !messageIds!.some((messageId) => сheckMessageSendingDenied(chatMessages[messageId], options));
}

View File

@ -11,7 +11,6 @@ import {
getChatAvatarHash,
getChatTitle,
getMessageRecentReaction,
getPrivateChatUserId,
getUserFullName,
} from '../global/helpers';
import { getIsChatMuted, getIsChatSilent, getShouldShowMessagePreview } from '../global/helpers/notifications';
@ -320,8 +319,7 @@ function getNotificationContent(chat: ApiChat, message: ApiMessage, reaction?: A
}
const { isScreenLocked } = global.passcode;
const privateChatUserId = getPrivateChatUserId(chat);
const isSelf = privateChatUserId === global.currentUserId;
const isSelf = chat.id === global.currentUserId;
let body: string;
if (