Monoforum: Fix admin rights check (#6538)
This commit is contained in:
parent
9b17732097
commit
ade72a0727
@ -197,6 +197,7 @@ export interface ApiChatAdminRights {
|
|||||||
postStories?: true;
|
postStories?: true;
|
||||||
editStories?: true;
|
editStories?: true;
|
||||||
deleteStories?: true;
|
deleteStories?: true;
|
||||||
|
manageDirectMessages?: true;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ApiChatBannedRights {
|
export interface ApiChatBannedRights {
|
||||||
|
|||||||
@ -955,6 +955,14 @@
|
|||||||
"EditAdminBanUsers" = "Ban Users";
|
"EditAdminBanUsers" = "Ban Users";
|
||||||
"EditAdminPinMessages" = "Pin Messages";
|
"EditAdminPinMessages" = "Pin Messages";
|
||||||
"EditAdminAddAdmins" = "Add New Admins";
|
"EditAdminAddAdmins" = "Add New Admins";
|
||||||
|
"EditAdminManageDirect" = "Manage Direct Messages";
|
||||||
|
"EditAdminPostStories" = "Post Stories";
|
||||||
|
"EditAdminEditStories" = "Edit Stories of Others";
|
||||||
|
"EditAdminDeleteStories" = "Delete Stories of Others";
|
||||||
|
"EditAdminManageTopics" = "Manage Topics";
|
||||||
|
"EditAdminUnavailable" = "You can't edit the rights of this admin.";
|
||||||
|
"EditAdminConfirmDismissText" = "Are you sure you want to dismiss this admin?";
|
||||||
|
"EditAdminConfirmDismiss" = "Dismiss Admin";
|
||||||
"StartVoipChatPermission" = "Manage Video Chats";
|
"StartVoipChatPermission" = "Manage Video Chats";
|
||||||
"EditAdminSendAnonymously" = "Remain Anonymous";
|
"EditAdminSendAnonymously" = "Remain Anonymous";
|
||||||
"ChannelEditAdminCannotEdit" = "You can't edit the rights of this admin.";
|
"ChannelEditAdminCannotEdit" = "You can't edit the rights of this admin.";
|
||||||
|
|||||||
@ -24,7 +24,8 @@ import {
|
|||||||
selectBot,
|
selectBot,
|
||||||
selectCanDeleteSelectedMessages,
|
selectCanDeleteSelectedMessages,
|
||||||
selectChat,
|
selectChat,
|
||||||
selectChatFullInfo, selectIsChatWithBot,
|
selectChatFullInfo,
|
||||||
|
selectIsChatWithBot,
|
||||||
selectSenderFromMessage,
|
selectSenderFromMessage,
|
||||||
selectTabState,
|
selectTabState,
|
||||||
selectUser,
|
selectUser,
|
||||||
@ -164,7 +165,7 @@ const DeleteMessageModal: FC<OwnProps & StateProps> = ({
|
|||||||
|
|
||||||
const peerListToBan = useMemo(() => {
|
const peerListToBan = useMemo(() => {
|
||||||
const isCurrentUserInList = peerList.some((peer) => peer.id === currentUserId);
|
const isCurrentUserInList = peerList.some((peer) => peer.id === currentUserId);
|
||||||
const shouldReturnEmpty = !canBanUsers || isCurrentUserInList || chat?.isMonoforum;
|
const shouldReturnEmpty = !canBanUsers || isCurrentUserInList;
|
||||||
|
|
||||||
if (shouldReturnEmpty) {
|
if (shouldReturnEmpty) {
|
||||||
return MEMO_EMPTY_ARRAY;
|
return MEMO_EMPTY_ARRAY;
|
||||||
@ -174,7 +175,7 @@ const DeleteMessageModal: FC<OwnProps & StateProps> = ({
|
|||||||
const isAdmin = adminMembersById?.[peer.id];
|
const isAdmin = adminMembersById?.[peer.id];
|
||||||
return isCreator || !isAdmin;
|
return isCreator || !isAdmin;
|
||||||
});
|
});
|
||||||
}, [peerList, isCreator, currentUserId, canBanUsers, adminMembersById, chat?.isMonoforum]);
|
}, [peerList, isCreator, currentUserId, canBanUsers, adminMembersById]);
|
||||||
|
|
||||||
const shouldShowAdditionalOptions = useMemo(() => {
|
const shouldShowAdditionalOptions = useMemo(() => {
|
||||||
return Boolean(peerListToDeleteAll.length || peerListToReportSpam.length || peerListToBan.length);
|
return Boolean(peerListToDeleteAll.length || peerListToReportSpam.length || peerListToBan.length);
|
||||||
@ -510,7 +511,7 @@ export default memo(withGlobal<OwnProps>(
|
|||||||
: undefined;
|
: undefined;
|
||||||
const chatBot = Boolean(chat && !isSystemBot(chat.id) && selectBot(global, chat.id));
|
const chatBot = Boolean(chat && !isSystemBot(chat.id) && selectBot(global, chat.id));
|
||||||
const adminMembersById = chatFullInfo?.adminMembersById;
|
const adminMembersById = chatFullInfo?.adminMembersById;
|
||||||
const canBanUsers = chat && getHasAdminRight(chat, 'banUsers');
|
const canBanUsers = chat && getHasAdminRight(chat, 'banUsers') && !chat.isMonoforum; // TODO: Ban in channel in case of monoforum
|
||||||
const isCreator = chat?.isCreator;
|
const isCreator = chat?.isCreator;
|
||||||
const isChatWithBot = chat ? selectIsChatWithBot(global, chat) : undefined;
|
const isChatWithBot = chat ? selectIsChatWithBot(global, chat) : undefined;
|
||||||
const willDeleteForCurrentUserOnly = (chat && isChatBasicGroup(chat) && !canDeleteForAll) || isChatWithBot;
|
const willDeleteForCurrentUserOnly = (chat && isChatBasicGroup(chat) && !canDeleteForAll) || isChatWithBot;
|
||||||
|
|||||||
@ -1,5 +1,3 @@
|
|||||||
import type { FC } from '../../lib/teact/teact';
|
|
||||||
import type React from '../../lib/teact/teact';
|
|
||||||
import {
|
import {
|
||||||
memo, useMemo,
|
memo, useMemo,
|
||||||
} from '../../lib/teact/teact';
|
} from '../../lib/teact/teact';
|
||||||
@ -19,15 +17,15 @@ import Checkbox from '../ui/Checkbox';
|
|||||||
|
|
||||||
export type OwnProps = {
|
export type OwnProps = {
|
||||||
chatId?: string;
|
chatId?: string;
|
||||||
handlePermissionChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
|
|
||||||
permissions: ApiChatBannedRights;
|
permissions: ApiChatBannedRights;
|
||||||
isMediaDropdownOpen: boolean;
|
isMediaDropdownOpen: boolean;
|
||||||
setIsMediaDropdownOpen: (open: boolean) => void;
|
|
||||||
className?: string;
|
className?: string;
|
||||||
shiftedClassName?: string;
|
shiftedClassName?: string;
|
||||||
dropdownClassName?: string;
|
dropdownClassName?: string;
|
||||||
withCheckbox?: boolean;
|
withCheckbox?: boolean;
|
||||||
permissionGroup?: boolean;
|
permissionGroup?: boolean;
|
||||||
|
handlePermissionChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
|
||||||
|
setIsMediaDropdownOpen: (open: boolean) => void;
|
||||||
getControlIsDisabled?: (key: Exclude<keyof ApiChatBannedRights, 'untilDate'>) => boolean | undefined;
|
getControlIsDisabled?: (key: Exclude<keyof ApiChatBannedRights, 'untilDate'>) => boolean | undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -41,20 +39,20 @@ const permissionKeyList: (keyof ApiChatBannedRights)[] = [
|
|||||||
'sendAudios', 'sendDocs', 'sendVoices', 'sendRoundvideos', 'embedLinks', 'sendPolls',
|
'sendAudios', 'sendDocs', 'sendVoices', 'sendRoundvideos', 'embedLinks', 'sendPolls',
|
||||||
];
|
];
|
||||||
|
|
||||||
const PermissionCheckboxList: FC<OwnProps & StateProps> = ({
|
const PermissionCheckboxList = ({
|
||||||
chat,
|
chat,
|
||||||
isMediaDropdownOpen,
|
isMediaDropdownOpen,
|
||||||
setIsMediaDropdownOpen,
|
|
||||||
hasLinkedChat,
|
hasLinkedChat,
|
||||||
permissions,
|
permissions,
|
||||||
handlePermissionChange,
|
|
||||||
className,
|
className,
|
||||||
shiftedClassName,
|
shiftedClassName,
|
||||||
dropdownClassName,
|
dropdownClassName,
|
||||||
withCheckbox,
|
withCheckbox,
|
||||||
getControlIsDisabled,
|
|
||||||
permissionGroup,
|
permissionGroup,
|
||||||
}) => {
|
setIsMediaDropdownOpen,
|
||||||
|
handlePermissionChange,
|
||||||
|
getControlIsDisabled,
|
||||||
|
}: OwnProps & StateProps) => {
|
||||||
const {
|
const {
|
||||||
showNotification,
|
showNotification,
|
||||||
} = getActions();
|
} = getActions();
|
||||||
|
|||||||
@ -1,5 +1,3 @@
|
|||||||
import type { FC } from '../../../lib/teact/teact';
|
|
||||||
import type React from '../../../lib/teact/teact';
|
|
||||||
import {
|
import {
|
||||||
memo, useCallback, useEffect, useMemo, useState,
|
memo, useCallback, useEffect, useMemo, useState,
|
||||||
} from '../../../lib/teact/teact';
|
} from '../../../lib/teact/teact';
|
||||||
@ -15,7 +13,7 @@ import { selectChat, selectChatFullInfo } from '../../../global/selectors';
|
|||||||
|
|
||||||
import useFlag from '../../../hooks/useFlag';
|
import useFlag from '../../../hooks/useFlag';
|
||||||
import useHistoryBack from '../../../hooks/useHistoryBack';
|
import useHistoryBack from '../../../hooks/useHistoryBack';
|
||||||
import useOldLang from '../../../hooks/useOldLang';
|
import useLang from '../../../hooks/useLang';
|
||||||
|
|
||||||
import PrivateChatInfo from '../../common/PrivateChatInfo';
|
import PrivateChatInfo from '../../common/PrivateChatInfo';
|
||||||
import Checkbox from '../../ui/Checkbox';
|
import Checkbox from '../../ui/Checkbox';
|
||||||
@ -40,15 +38,13 @@ type StateProps = {
|
|||||||
adminMembersById?: Record<string, ApiChatMember>;
|
adminMembersById?: Record<string, ApiChatMember>;
|
||||||
hasFullInfo: boolean;
|
hasFullInfo: boolean;
|
||||||
currentUserId?: string;
|
currentUserId?: string;
|
||||||
isChannel: boolean;
|
|
||||||
isFormFullyDisabled: boolean;
|
isFormFullyDisabled: boolean;
|
||||||
isForum?: boolean;
|
|
||||||
defaultRights?: ApiChatAdminRights;
|
defaultRights?: ApiChatAdminRights;
|
||||||
};
|
};
|
||||||
|
|
||||||
const CUSTOM_TITLE_MAX_LENGTH = 16;
|
const CUSTOM_TITLE_MAX_LENGTH = 16;
|
||||||
|
|
||||||
const ManageGroupAdminRights: FC<OwnProps & StateProps> = ({
|
const ManageGroupAdminRights = ({
|
||||||
isActive,
|
isActive,
|
||||||
isNewAdmin,
|
isNewAdmin,
|
||||||
selectedUserId,
|
selectedUserId,
|
||||||
@ -58,12 +54,10 @@ const ManageGroupAdminRights: FC<OwnProps & StateProps> = ({
|
|||||||
currentUserId,
|
currentUserId,
|
||||||
adminMembersById,
|
adminMembersById,
|
||||||
hasFullInfo,
|
hasFullInfo,
|
||||||
isChannel,
|
|
||||||
isForum,
|
|
||||||
isFormFullyDisabled,
|
isFormFullyDisabled,
|
||||||
onClose,
|
onClose,
|
||||||
onScreenSelect,
|
onScreenSelect,
|
||||||
}) => {
|
}: OwnProps & StateProps) => {
|
||||||
const { updateChatAdmin } = getActions();
|
const { updateChatAdmin } = getActions();
|
||||||
|
|
||||||
const [permissions, setPermissions] = useState<ApiChatAdminRights>({});
|
const [permissions, setPermissions] = useState<ApiChatAdminRights>({});
|
||||||
@ -71,7 +65,11 @@ const ManageGroupAdminRights: FC<OwnProps & StateProps> = ({
|
|||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
const [isDismissConfirmationDialogOpen, openDismissConfirmationDialog, closeDismissConfirmationDialog] = useFlag();
|
const [isDismissConfirmationDialogOpen, openDismissConfirmationDialog, closeDismissConfirmationDialog] = useFlag();
|
||||||
const [customTitle, setCustomTitle] = useState('');
|
const [customTitle, setCustomTitle] = useState('');
|
||||||
const lang = useOldLang();
|
const lang = useLang();
|
||||||
|
|
||||||
|
const isChannel = isChatChannel(chat);
|
||||||
|
const isForum = chat.isForum;
|
||||||
|
const hasDirectMessages = Boolean(chat.linkedMonoforumId);
|
||||||
|
|
||||||
useHistoryBack({
|
useHistoryBack({
|
||||||
isActive,
|
isActive,
|
||||||
@ -186,7 +184,7 @@ const ManageGroupAdminRights: FC<OwnProps & StateProps> = ({
|
|||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
if (promotedByUser) {
|
if (promotedByUser) {
|
||||||
return lang('EditAdminPromotedBy', getUserFullName(promotedByUser));
|
return lang('EditAdminPromotedBy', { user: getUserFullName(promotedByUser) });
|
||||||
}
|
}
|
||||||
|
|
||||||
return lang('ChannelAdmin');
|
return lang('ChannelAdmin');
|
||||||
@ -290,18 +288,28 @@ const ManageGroupAdminRights: FC<OwnProps & StateProps> = ({
|
|||||||
onChange={handlePermissionChange}
|
onChange={handlePermissionChange}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{!isChannel && (
|
{hasDirectMessages && (
|
||||||
<div className="ListItem">
|
<div className="ListItem">
|
||||||
<Checkbox
|
<Checkbox
|
||||||
name="banUsers"
|
name="manageDirectMessages"
|
||||||
checked={Boolean(permissions.banUsers)}
|
checked={Boolean(permissions.manageDirectMessages)}
|
||||||
label={lang('EditAdminBanUsers')}
|
label={lang('EditAdminManageDirect')}
|
||||||
blocking
|
blocking
|
||||||
disabled={getControlIsDisabled('banUsers')}
|
disabled={getControlIsDisabled('manageDirectMessages')}
|
||||||
onChange={handlePermissionChange}
|
onChange={handlePermissionChange}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
<div className="ListItem">
|
||||||
|
<Checkbox
|
||||||
|
name="banUsers"
|
||||||
|
checked={Boolean(permissions.banUsers)}
|
||||||
|
label={lang('EditAdminBanUsers')}
|
||||||
|
blocking
|
||||||
|
disabled={getControlIsDisabled('banUsers')}
|
||||||
|
onChange={handlePermissionChange}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<div className="ListItem">
|
<div className="ListItem">
|
||||||
<Checkbox
|
<Checkbox
|
||||||
name="inviteUsers"
|
name="inviteUsers"
|
||||||
@ -349,7 +357,7 @@ const ManageGroupAdminRights: FC<OwnProps & StateProps> = ({
|
|||||||
<Checkbox
|
<Checkbox
|
||||||
name="manageTopics"
|
name="manageTopics"
|
||||||
checked={Boolean(permissions.manageTopics)}
|
checked={Boolean(permissions.manageTopics)}
|
||||||
label={lang('ManageTopicsPermission')}
|
label={lang('EditAdminManageTopics')}
|
||||||
blocking
|
blocking
|
||||||
disabled={getControlIsDisabled('manageTopics')}
|
disabled={getControlIsDisabled('manageTopics')}
|
||||||
onChange={handlePermissionChange}
|
onChange={handlePermissionChange}
|
||||||
@ -371,7 +379,7 @@ const ManageGroupAdminRights: FC<OwnProps & StateProps> = ({
|
|||||||
|
|
||||||
{isFormFullyDisabled && (
|
{isFormFullyDisabled && (
|
||||||
<p className="section-info mb-4" dir="auto">
|
<p className="section-info mb-4" dir="auto">
|
||||||
{lang('Channel.EditAdmin.CannotEdit')}
|
{lang('EditAdminUnavailable')}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
@ -407,8 +415,8 @@ const ManageGroupAdminRights: FC<OwnProps & StateProps> = ({
|
|||||||
<ConfirmDialog
|
<ConfirmDialog
|
||||||
isOpen={isDismissConfirmationDialogOpen}
|
isOpen={isDismissConfirmationDialogOpen}
|
||||||
onClose={closeDismissConfirmationDialog}
|
onClose={closeDismissConfirmationDialog}
|
||||||
text="Are you sure you want to dismiss this admin?"
|
text={lang('EditAdminConfirmDismissText')}
|
||||||
confirmLabel={lang('Channel.Admin.Dismiss')}
|
confirmLabel={lang('EditAdminConfirmDismiss')}
|
||||||
confirmHandler={handleDismissAdmin}
|
confirmHandler={handleDismissAdmin}
|
||||||
confirmIsDestructive
|
confirmIsDestructive
|
||||||
/>
|
/>
|
||||||
@ -423,16 +431,12 @@ export default memo(withGlobal<OwnProps>(
|
|||||||
const fullInfo = selectChatFullInfo(global, chatId);
|
const fullInfo = selectChatFullInfo(global, chatId);
|
||||||
const { byId: usersById } = global.users;
|
const { byId: usersById } = global.users;
|
||||||
const { currentUserId } = global;
|
const { currentUserId } = global;
|
||||||
const isChannel = isChatChannel(chat);
|
|
||||||
const isFormFullyDisabled = !(chat.isCreator || isPromotedByCurrentUser);
|
const isFormFullyDisabled = !(chat.isCreator || isPromotedByCurrentUser);
|
||||||
const isForum = chat.isForum;
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
chat,
|
chat,
|
||||||
usersById,
|
usersById,
|
||||||
currentUserId,
|
currentUserId,
|
||||||
isChannel,
|
|
||||||
isForum,
|
|
||||||
isFormFullyDisabled,
|
isFormFullyDisabled,
|
||||||
defaultRights: chat.adminRights,
|
defaultRights: chat.adminRights,
|
||||||
hasFullInfo: Boolean(fullInfo),
|
hasFullInfo: Boolean(fullInfo),
|
||||||
|
|||||||
@ -17,6 +17,7 @@ import {
|
|||||||
deletePeerPhoto,
|
deletePeerPhoto,
|
||||||
leaveChat,
|
leaveChat,
|
||||||
removeUnreadMentions,
|
removeUnreadMentions,
|
||||||
|
replaceChatMessages,
|
||||||
replacePeerPhotos,
|
replacePeerPhotos,
|
||||||
replacePinnedTopicIds,
|
replacePinnedTopicIds,
|
||||||
replaceThreadParam,
|
replaceThreadParam,
|
||||||
@ -69,6 +70,15 @@ addActionHandler('apiUpdate', (global, actions, update): ActionReturnType => {
|
|||||||
global = updatePeerStoriesHidden(global, update.id, update.chat.areStoriesHidden || false);
|
global = updatePeerStoriesHidden(global, update.id, update.chat.areStoriesHidden || false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const localAdminRights = localChat?.adminRights;
|
||||||
|
const newAdminRights = update.chat.adminRights;
|
||||||
|
|
||||||
|
if (localAdminRights && localAdminRights.manageDirectMessages && !update.chat.isMin
|
||||||
|
&& newAdminRights?.manageDirectMessages !== localAdminRights.manageDirectMessages
|
||||||
|
&& localChat.linkedMonoforumId) {
|
||||||
|
global = replaceChatMessages(global, localChat.linkedMonoforumId, {});
|
||||||
|
}
|
||||||
|
|
||||||
setGlobal(global);
|
setGlobal(global);
|
||||||
|
|
||||||
const updatedChat = selectChat(global, update.id);
|
const updatedChat = selectChat(global, update.id);
|
||||||
|
|||||||
@ -96,7 +96,9 @@ export function updateCurrentMessageList<T extends GlobalState>(
|
|||||||
}, tabId);
|
}, tabId);
|
||||||
}
|
}
|
||||||
|
|
||||||
function replaceChatMessages<T extends GlobalState>(global: T, chatId: string, newById: Record<number, ApiMessage>): T {
|
export function replaceChatMessages<T extends GlobalState>(
|
||||||
|
global: T, chatId: string, newById: Record<number, ApiMessage>,
|
||||||
|
): T {
|
||||||
return updateMessageStore(global, chatId, {
|
return updateMessageStore(global, chatId, {
|
||||||
byId: newById,
|
byId: newById,
|
||||||
});
|
});
|
||||||
|
|||||||
@ -360,7 +360,7 @@ export function selectIsMonoforumAdmin<T extends GlobalState>(
|
|||||||
const channel = selectMonoforumChannel(global, chatId);
|
const channel = selectMonoforumChannel(global, chatId);
|
||||||
if (!channel) return;
|
if (!channel) return;
|
||||||
|
|
||||||
return Boolean(chat.isCreator || chat.adminRights || channel.isCreator || channel.adminRights);
|
return Boolean(chat.isCreator || getHasAdminRight(channel, 'manageDirectMessages'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import { SERVICE_NOTIFICATIONS_USER_ID } from '../../config';
|
|||||||
import { isUserId } from '../../util/entities/ids';
|
import { isUserId } from '../../util/entities/ids';
|
||||||
import { getCurrentTabId } from '../../util/establishMultitabRole';
|
import { getCurrentTabId } from '../../util/establishMultitabRole';
|
||||||
import { getHasAdminRight, isChatAdmin, isChatChannel, isDeletedUser } from '../helpers';
|
import { getHasAdminRight, isChatAdmin, isChatChannel, isDeletedUser } from '../helpers';
|
||||||
import { selectChat, selectChatFullInfo } from './chats';
|
import { selectChat, selectChatFullInfo, selectIsMonoforumAdmin } from './chats';
|
||||||
import { type ProfileCollectionKey } from './payments';
|
import { type ProfileCollectionKey } from './payments';
|
||||||
import { selectTabState } from './tabs';
|
import { selectTabState } from './tabs';
|
||||||
import { selectBot, selectUser, selectUserFullInfo } from './users';
|
import { selectBot, selectUser, selectUserFullInfo } from './users';
|
||||||
@ -66,7 +66,7 @@ export function selectPeerPaidMessagesStars<T extends GlobalState>(
|
|||||||
|
|
||||||
const chat = selectChat(global, peerId);
|
const chat = selectChat(global, peerId);
|
||||||
if (!chat) return undefined;
|
if (!chat) return undefined;
|
||||||
if (isChatAdmin(chat)) return undefined;
|
if (isChatAdmin(chat) || selectIsMonoforumAdmin(global, chat.id)) return undefined;
|
||||||
return chat.paidMessagesStars;
|
return chat.paidMessagesStars;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
8
src/types/language.d.ts
vendored
8
src/types/language.d.ts
vendored
@ -831,6 +831,14 @@ export interface LangPair {
|
|||||||
'EditAdminBanUsers': undefined;
|
'EditAdminBanUsers': undefined;
|
||||||
'EditAdminPinMessages': undefined;
|
'EditAdminPinMessages': undefined;
|
||||||
'EditAdminAddAdmins': undefined;
|
'EditAdminAddAdmins': undefined;
|
||||||
|
'EditAdminManageDirect': undefined;
|
||||||
|
'EditAdminPostStories': undefined;
|
||||||
|
'EditAdminEditStories': undefined;
|
||||||
|
'EditAdminDeleteStories': undefined;
|
||||||
|
'EditAdminManageTopics': undefined;
|
||||||
|
'EditAdminUnavailable': undefined;
|
||||||
|
'EditAdminConfirmDismissText': undefined;
|
||||||
|
'EditAdminConfirmDismiss': undefined;
|
||||||
'StartVoipChatPermission': undefined;
|
'StartVoipChatPermission': undefined;
|
||||||
'EditAdminSendAnonymously': undefined;
|
'EditAdminSendAnonymously': undefined;
|
||||||
'ChannelEditAdminCannotEdit': undefined;
|
'ChannelEditAdminCannotEdit': undefined;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user