Allow editing ManageTopics rights/restrictions.

This commit is contained in:
John Preston 2022-10-24 11:23:21 +04:00
parent ed895ace66
commit 53beb6f562
9 changed files with 261 additions and 201 deletions

View file

@ -2890,6 +2890,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_rights_group_invite_link" = "Invite users via link";
"lng_rights_group_invite" = "Add users";
"lng_rights_group_pin" = "Pin messages";
"lng_rights_group_pin_with_topics" = "Pin messages and topics";
"lng_rights_group_topics" = "Manage topics";
"lng_rights_group_add_topics" = "Create topics";
"lng_rights_group_manage_calls" = "Manage voice chats";
"lng_rights_group_delete" = "Delete messages";
"lng_rights_group_anonymous" = "Remain Anonymous";

View file

@ -1127,9 +1127,9 @@ chatOnlines#f041e250 onlines:int = ChatOnlines;
statsURL#47a971e0 url:string = StatsURL;
chatAdminRights#5fb224d5 flags:# change_info:flags.0?true post_messages:flags.1?true edit_messages:flags.2?true delete_messages:flags.3?true ban_users:flags.4?true invite_users:flags.5?true pin_messages:flags.7?true add_admins:flags.9?true anonymous:flags.10?true manage_call:flags.11?true other:flags.12?true = ChatAdminRights;
chatAdminRights#5fb224d5 flags:# change_info:flags.0?true post_messages:flags.1?true edit_messages:flags.2?true delete_messages:flags.3?true ban_users:flags.4?true invite_users:flags.5?true pin_messages:flags.7?true add_admins:flags.9?true anonymous:flags.10?true manage_call:flags.11?true other:flags.12?true manage_topics:flags.13?true = ChatAdminRights;
chatBannedRights#9f120418 flags:# view_messages:flags.0?true send_messages:flags.1?true send_media:flags.2?true send_stickers:flags.3?true send_gifs:flags.4?true send_games:flags.5?true send_inline:flags.6?true embed_links:flags.7?true send_polls:flags.8?true change_info:flags.10?true invite_users:flags.15?true pin_messages:flags.17?true until_date:int = ChatBannedRights;
chatBannedRights#9f120418 flags:# view_messages:flags.0?true send_messages:flags.1?true send_media:flags.2?true send_stickers:flags.3?true send_gifs:flags.4?true send_games:flags.5?true send_inline:flags.6?true embed_links:flags.7?true send_polls:flags.8?true change_info:flags.10?true invite_users:flags.15?true pin_messages:flags.17?true manage_topics:flags.18?true until_date:int = ChatBannedRights;
inputWallPaper#e630b979 id:long access_hash:long = InputWallPaper;
inputWallPaperSlug#72091c80 slug:string = InputWallPaper;

View file

@ -224,6 +224,7 @@ ChatAdminRightsInfo EditAdminBox::defaultRights() const {
| Flag::BanUsers
| Flag::InviteUsers
| Flag::PinMessages
| Flag::ManageTopics
| Flag::ManageCall) }
: ChatAdminRightsInfo{ (Flag::ChangeInfo
| Flag::PostMessages
@ -328,13 +329,17 @@ void EditAdminBox::prepare() {
const auto anyoneCanAddMembers = chat
? chat->anyoneCanAddMembers()
: channel->anyoneCanAddMembers();
const auto options = Data::AdminRightsSetOptions{
.isGroup = isGroup,
.isForum = peer()->isForum(),
.anyoneCanAddMembers = anyoneCanAddMembers,
};
auto [checkboxes, getChecked, changes] = CreateEditAdminRights(
inner,
tr::lng_rights_edit_admin_header(),
prepareFlags,
disabledMessages,
isGroup,
anyoneCanAddMembers);
options);
inner->add(std::move(checkboxes), QMargins());
auto selectedFlags = rpl::single(
@ -355,7 +360,7 @@ void EditAdminBox::prepare() {
}, lifetime());
if (canTransferOwnership()) {
const auto allFlags = AdminRightsForOwnershipTransfer(isGroup);
const auto allFlags = AdminRightsForOwnershipTransfer(options);
setupTransferButton(
inner,
isGroup
@ -746,7 +751,8 @@ void EditRestrictedBox::prepare() {
this,
tr::lng_rights_user_restrictions_header(),
prepareFlags,
disabledMessages);
disabledMessages,
{ .isForum = peer()->isForum() });
addControl(std::move(checkboxes), QMargins());
_until = prepareRights.until;

View file

@ -67,14 +67,6 @@ namespace {
});
}
[[nodiscard]] auto ToPositiveNumberStringRestrictions() {
return rpl::map([](int count) {
return QString::number(count)
+ QString("/")
+ QString::number(int(Data::ListOfRestrictions().size()));
});
}
void AddSkip(
not_null<Ui::VerticalLayout*> container,
int top = st::editPeerTopButtonsLayoutSkip,
@ -1086,10 +1078,16 @@ void Controller::fillManageSection() {
tr::lng_manage_peer_permissions(),
Info::Profile::MigratedOrMeValue(
_peer
) | rpl::map(
Info::Profile::RestrictionsCountValue
) | rpl::flatten_latest(
) | ToPositiveNumberStringRestrictions(),
) | rpl::map([=](not_null<PeerData*> peer) {
return Info::Profile::RestrictionsCountValue(
peer
) | rpl::map([=](int count) {
return QString::number(count)
+ QString("/")
+ QString::number(int(Data::ListOfRestrictions(
{ .isForum = peer->isForum() }).size()));
});
}) | rpl::flatten_latest(),
[=] { ShowEditPermissions(_navigation, _peer); },
{ &st::settingsIconKey, Settings::kIconGreen });
}

View file

@ -106,58 +106,6 @@ void ApplyDependencies(
};
}
std::vector<std::pair<ChatRestrictions, QString>> RestrictionLabels() {
const auto langKeys = {
tr::lng_rights_chat_send_text,
tr::lng_rights_chat_send_media,
tr::lng_rights_chat_send_stickers,
tr::lng_rights_chat_send_links,
tr::lng_rights_chat_send_polls,
tr::lng_rights_chat_add_members,
tr::lng_rights_group_pin,
tr::lng_rights_group_info,
};
std::vector<std::pair<ChatRestrictions, QString>> vector;
const auto restrictions = Data::ListOfRestrictions();
auto i = 0;
for (const auto &key : langKeys) {
vector.emplace_back(restrictions[i++], key(tr::now));
}
return vector;
}
std::vector<std::pair<ChatAdminRights, QString>> AdminRightLabels(
bool isGroup,
bool anyoneCanAddMembers) {
using Flag = ChatAdminRight;
if (isGroup) {
return {
{ Flag::ChangeInfo, tr::lng_rights_group_info(tr::now) },
{ Flag::DeleteMessages, tr::lng_rights_group_delete(tr::now) },
{ Flag::BanUsers, tr::lng_rights_group_ban(tr::now) },
{ Flag::InviteUsers, anyoneCanAddMembers
? tr::lng_rights_group_invite_link(tr::now)
: tr::lng_rights_group_invite(tr::now) },
{ Flag::PinMessages, tr::lng_rights_group_pin(tr::now) },
{ Flag::ManageCall, tr::lng_rights_group_manage_calls(tr::now) },
{ Flag::Anonymous, tr::lng_rights_group_anonymous(tr::now) },
{ Flag::AddAdmins, tr::lng_rights_add_admins(tr::now) },
};
} else {
return {
{ Flag::ChangeInfo, tr::lng_rights_channel_info(tr::now) },
{ Flag::PostMessages, tr::lng_rights_channel_post(tr::now) },
{ Flag::EditMessages, tr::lng_rights_channel_edit(tr::now) },
{ Flag::DeleteMessages, tr::lng_rights_channel_delete(tr::now) },
{ Flag::InviteUsers, tr::lng_rights_group_invite(tr::now) },
{ Flag::ManageCall, tr::lng_rights_channel_manage_calls(tr::now) },
{ Flag::AddAdmins, tr::lng_rights_add_admins(tr::now) }
};
}
}
auto Dependencies(ChatRestrictions)
-> std::vector<std::pair<ChatRestriction, ChatRestriction>> {
using Flag = ChatRestriction;
@ -248,6 +196,103 @@ ChatRestrictions DisabledByAdminRights(not_null<PeerData*> peer) {
: Flag::ChangeInfo);
}
template <
typename Flags,
typename DisabledMessagePairs,
typename FlagLabelPairs>
[[nodiscard]] EditFlagsControl<Flags> CreateEditFlags(
QWidget *parent,
rpl::producer<QString> header,
Flags checked,
const DisabledMessagePairs &disabledMessagePairs,
const FlagLabelPairs &flagLabelPairs) {
auto widget = object_ptr<Ui::VerticalLayout>(parent);
const auto container = widget.data();
const auto checkboxes = container->lifetime(
).make_state<std::map<Flags, QPointer<Ui::Checkbox>>>();
const auto value = [=] {
auto result = Flags(0);
for (const auto &[flags, checkbox] : *checkboxes) {
if (checkbox->checked()) {
result |= flags;
} else {
result &= ~flags;
}
}
return result;
};
const auto changes = container->lifetime(
).make_state<rpl::event_stream<>>();
const auto applyDependencies = [=](Ui::Checkbox *control) {
static const auto dependencies = Dependencies(Flags());
ApplyDependencies(*checkboxes, dependencies, control);
};
container->add(
object_ptr<Ui::FlatLabel>(
container,
std::move(header),
st::rightsHeaderLabel),
st::rightsHeaderMargin);
auto addCheckbox = [&](Flags flags, const QString &text) {
const auto lockedIt = ranges::find_if(
disabledMessagePairs,
[&](const auto &pair) { return (pair.first & flags) != 0; });
const auto locked = (lockedIt != end(disabledMessagePairs))
? std::make_optional(lockedIt->second)
: std::nullopt;
const auto toggled = ((checked & flags) != 0);
auto toggle = std::make_unique<Ui::ToggleView>(
st::rightsToggle,
toggled);
toggle->setLocked(locked.has_value());
const auto control = container->add(
object_ptr<Ui::Checkbox>(
container,
text,
st::rightsCheckbox,
std::move(toggle)),
st::rightsToggleMargin);
control->checkedChanges(
) | rpl::start_with_next([=](bool checked) {
if (locked.has_value()) {
if (checked != toggled) {
Ui::ShowMultilineToast({
.parentOverride = parent,
.text = { *locked },
});
control->setChecked(toggled);
}
} else {
InvokeQueued(control, [=] {
applyDependencies(control);
changes->fire({});
});
}
}, control->lifetime());
checkboxes->emplace(flags, control);
};
for (const auto &[flags, label] : flagLabelPairs) {
addCheckbox(flags, label);
}
applyDependencies(nullptr);
for (const auto &[flags, checkbox] : *checkboxes) {
checkbox->finishAnimating();
}
return {
std::move(widget),
value,
changes->events() | rpl::map(value)
};
}
} // namespace
ChatAdminRights DisabledByDefaultRestrictions(not_null<PeerData*> peer) {
@ -306,9 +351,10 @@ ChatRestrictions FixDependentRestrictions(ChatRestrictions restrictions) {
return restrictions;
}
ChatAdminRights AdminRightsForOwnershipTransfer(bool isGroup) {
ChatAdminRights AdminRightsForOwnershipTransfer(
Data::AdminRightsSetOptions options) {
auto result = ChatAdminRights();
for (const auto &[flag, label] : AdminRightLabels(isGroup, true)) {
for (const auto &[flag, label] : AdminRightLabels(options)) {
if (!(flag & ChatAdminRight::Anonymous)) {
result |= flag;
}
@ -445,7 +491,8 @@ void EditPeerPermissionsBox::prepare() {
this,
tr::lng_rights_default_restrictions_header(),
restrictions,
disabledMessages);
disabledMessages,
{ .isForum = _peer->isForum() });
inner->add(std::move(checkboxes));
@ -668,114 +715,88 @@ void EditPeerPermissionsBox::addBannedButtons(
}
}
template <
typename Flags,
typename DisabledMessagePairs,
typename FlagLabelPairs>
EditFlagsControl<Flags> CreateEditFlags(
QWidget *parent,
rpl::producer<QString> header,
Flags checked,
const DisabledMessagePairs &disabledMessagePairs,
const FlagLabelPairs &flagLabelPairs) {
auto widget = object_ptr<Ui::VerticalLayout>(parent);
const auto container = widget.data();
std::vector<RestrictionLabel> RestrictionLabels(
Data::RestrictionsSetOptions options) {
using Flag = ChatRestriction;
auto result = std::vector<RestrictionLabel>{
{ Flag::SendMessages, tr::lng_rights_chat_send_text(tr::now) },
{ Flag::SendMedia, tr::lng_rights_chat_send_media(tr::now) },
{ Flag::SendStickers
| Flag::SendGifs
| Flag::SendGames
| Flag::SendInline, tr::lng_rights_chat_send_stickers(tr::now) },
{ Flag::EmbedLinks, tr::lng_rights_chat_send_links(tr::now) },
{ Flag::SendPolls, tr::lng_rights_chat_send_polls(tr::now) },
{ Flag::InviteUsers, tr::lng_rights_chat_add_members(tr::now) },
{ Flag::ManageTopics, tr::lng_rights_group_add_topics(tr::now) },
{ Flag::PinMessages, tr::lng_rights_group_pin(tr::now) },
{ Flag::ChangeInfo, tr::lng_rights_group_info(tr::now) },
};
if (!options.isForum) {
result.erase(
ranges::remove(
result,
Flag::ManageTopics,
&RestrictionLabel::flags),
end(result));
}
return result;
}
const auto checkboxes = container->lifetime(
).make_state<std::map<Flags, QPointer<Ui::Checkbox>>>();
std::vector<AdminRightLabel> AdminRightLabels(
Data::AdminRightsSetOptions options) {
using Flag = ChatAdminRight;
const auto value = [=] {
auto result = Flags(0);
for (const auto &[flags, checkbox] : *checkboxes) {
if (checkbox->checked()) {
result |= flags;
} else {
result &= ~flags;
}
if (options.isGroup) {
auto result = std::vector<AdminRightLabel>{
{ Flag::ChangeInfo, tr::lng_rights_group_info(tr::now) },
{ Flag::DeleteMessages, tr::lng_rights_group_delete(tr::now) },
{ Flag::BanUsers, tr::lng_rights_group_ban(tr::now) },
{ Flag::InviteUsers, options.anyoneCanAddMembers
? tr::lng_rights_group_invite_link(tr::now)
: tr::lng_rights_group_invite(tr::now) },
{ Flag::ManageTopics, tr::lng_rights_group_topics(tr::now) },
{ Flag::PinMessages, options.isForum
? tr::lng_rights_group_pin_with_topics(tr::now)
: tr::lng_rights_group_pin(tr::now) },
{ Flag::ManageCall, tr::lng_rights_group_manage_calls(tr::now) },
{ Flag::Anonymous, tr::lng_rights_group_anonymous(tr::now) },
{ Flag::AddAdmins, tr::lng_rights_add_admins(tr::now) },
};
if (!options.isForum) {
result.erase(
ranges::remove(
result,
Flag::ManageTopics,
&AdminRightLabel::flags),
end(result));
}
return result;
};
const auto changes = container->lifetime(
).make_state<rpl::event_stream<>>();
const auto applyDependencies = [=](Ui::Checkbox *control) {
static const auto dependencies = Dependencies(Flags());
ApplyDependencies(*checkboxes, dependencies, control);
};
container->add(
object_ptr<Ui::FlatLabel>(
container,
std::move(header),
st::rightsHeaderLabel),
st::rightsHeaderMargin);
auto addCheckbox = [&](Flags flags, const QString &text) {
const auto lockedIt = ranges::find_if(
disabledMessagePairs,
[&](const auto &pair) { return (pair.first & flags) != 0; });
const auto locked = (lockedIt != end(disabledMessagePairs))
? std::make_optional(lockedIt->second)
: std::nullopt;
const auto toggled = ((checked & flags) != 0);
auto toggle = std::make_unique<Ui::ToggleView>(
st::rightsToggle,
toggled);
toggle->setLocked(locked.has_value());
const auto control = container->add(
object_ptr<Ui::Checkbox>(
container,
text,
st::rightsCheckbox,
std::move(toggle)),
st::rightsToggleMargin);
control->checkedChanges(
) | rpl::start_with_next([=](bool checked) {
if (locked.has_value()) {
if (checked != toggled) {
Ui::ShowMultilineToast({
.parentOverride = parent,
.text = { *locked },
});
control->setChecked(toggled);
}
} else {
InvokeQueued(control, [=] {
applyDependencies(control);
changes->fire({});
});
}
}, control->lifetime());
checkboxes->emplace(flags, control);
};
for (const auto &[flags, label] : flagLabelPairs) {
addCheckbox(flags, label);
} else {
return {
{ Flag::ChangeInfo, tr::lng_rights_channel_info(tr::now) },
{ Flag::PostMessages, tr::lng_rights_channel_post(tr::now) },
{ Flag::EditMessages, tr::lng_rights_channel_edit(tr::now) },
{ Flag::DeleteMessages, tr::lng_rights_channel_delete(tr::now) },
{ Flag::InviteUsers, tr::lng_rights_group_invite(tr::now) },
{ Flag::ManageCall, tr::lng_rights_channel_manage_calls(tr::now) },
{ Flag::AddAdmins, tr::lng_rights_add_admins(tr::now) }
};
}
applyDependencies(nullptr);
for (const auto &[flags, checkbox] : *checkboxes) {
checkbox->finishAnimating();
}
return {
std::move(widget),
value,
changes->events() | rpl::map(value)
};
}
EditFlagsControl<ChatRestrictions> CreateEditRestrictions(
QWidget *parent,
rpl::producer<QString> header,
ChatRestrictions restrictions,
std::map<ChatRestrictions, QString> disabledMessages) {
std::map<ChatRestrictions, QString> disabledMessages,
Data::RestrictionsSetOptions options) {
auto result = CreateEditFlags(
parent,
header,
NegateRestrictions(restrictions),
disabledMessages,
RestrictionLabels());
RestrictionLabels(options));
result.value = [original = std::move(result.value)]{
return NegateRestrictions(original());
};
@ -791,12 +812,11 @@ EditFlagsControl<ChatAdminRights> CreateEditAdminRights(
rpl::producer<QString> header,
ChatAdminRights rights,
std::map<ChatAdminRights, QString> disabledMessages,
bool isGroup,
bool anyoneCanAddMembers) {
Data::AdminRightsSetOptions options) {
return CreateEditFlags(
parent,
header,
rights,
disabledMessages,
AdminRightLabels(isGroup, anyoneCanAddMembers));
AdminRightLabels(options));
}

View file

@ -54,6 +54,20 @@ private:
not_null<ChannelData*> channel,
not_null<Window::SessionController*> controller);
struct RestrictionLabel {
ChatRestrictions flags;
QString label;
};
[[nodiscard]] std::vector<RestrictionLabel> RestrictionLabels(
Data::RestrictionsSetOptions options);
struct AdminRightLabel {
ChatAdminRights flags;
QString label;
};
[[nodiscard]] std::vector<AdminRightLabel> AdminRightLabels(
Data::AdminRightsSetOptions options);
template <typename Flags>
struct EditFlagsControl {
object_ptr<Ui::RpWidget> widget;
@ -61,20 +75,23 @@ struct EditFlagsControl {
rpl::producer<Flags> changes;
};
EditFlagsControl<ChatRestrictions> CreateEditRestrictions(
[[nodiscard]] EditFlagsControl<ChatRestrictions> CreateEditRestrictions(
QWidget *parent,
rpl::producer<QString> header,
ChatRestrictions restrictions,
std::map<ChatRestrictions, QString> disabledMessages);
std::map<ChatRestrictions, QString> disabledMessages,
Data::RestrictionsSetOptions options);
EditFlagsControl<ChatAdminRights> CreateEditAdminRights(
[[nodiscard]] EditFlagsControl<ChatAdminRights> CreateEditAdminRights(
QWidget *parent,
rpl::producer<QString> header,
ChatAdminRights rights,
std::map<ChatAdminRights, QString> disabledMessages,
bool isGroup,
bool anyoneCanAddMembers);
Data::AdminRightsSetOptions options);
ChatAdminRights DisabledByDefaultRestrictions(not_null<PeerData*> peer);
ChatRestrictions FixDependentRestrictions(ChatRestrictions restrictions);
ChatAdminRights AdminRightsForOwnershipTransfer(bool isGroup);
[[nodiscard]] ChatAdminRights DisabledByDefaultRestrictions(
not_null<PeerData*> peer);
[[nodiscard]] ChatRestrictions FixDependentRestrictions(
ChatRestrictions restrictions);
[[nodiscard]] ChatAdminRights AdminRightsForOwnershipTransfer(
Data::AdminRightsSetOptions options);

View file

@ -7,6 +7,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "data/data_chat_participant_status.h"
#include "boxes/peers/edit_peer_permissions_box.h"
namespace {
[[nodiscard]] ChatAdminRights ChatAdminRightsFlags(
@ -43,22 +45,12 @@ ChatRestrictionsInfo::ChatRestrictionsInfo(const MTPChatBannedRights &rights)
namespace Data {
std::vector<ChatRestrictions> ListOfRestrictions() {
using Flag = ChatRestriction;
return {
Flag::SendMessages,
Flag::SendMedia,
Flag::SendStickers
| Flag::SendGifs
| Flag::SendGames
| Flag::SendInline,
Flag::EmbedLinks,
Flag::SendPolls,
Flag::InviteUsers,
Flag::PinMessages,
Flag::ChangeInfo,
};
std::vector<ChatRestrictions> ListOfRestrictions(
RestrictionsSetOptions options) {
auto labels = RestrictionLabels(options);
return ranges::views::all(labels)
| ranges::views::transform(&RestrictionLabel::flags)
| ranges::to_vector;
}
} // namespace Data

View file

@ -24,6 +24,7 @@ enum class ChatAdminRight {
Anonymous = (1 << 10),
ManageCall = (1 << 11),
Other = (1 << 12),
ManageTopics = (1 << 13),
};
inline constexpr bool is_flag_type(ChatAdminRight) { return true; }
using ChatAdminRights = base::flags<ChatAdminRight>;
@ -41,6 +42,7 @@ enum class ChatRestriction {
ChangeInfo = (1 << 10),
InviteUsers = (1 << 15),
PinMessages = (1 << 17),
ManageTopics = (1 << 18),
};
inline constexpr bool is_flag_type(ChatRestriction) { return true; }
using ChatRestrictions = base::flags<ChatRestriction>;
@ -68,6 +70,17 @@ struct ChatRestrictionsInfo {
namespace Data {
std::vector<ChatRestrictions> ListOfRestrictions();
struct AdminRightsSetOptions {
bool isGroup : 1 = false;
bool isForum : 1 = false;
bool anyoneCanAddMembers : 1 = false;
};
struct RestrictionsSetOptions {
bool isForum = false;
};
[[nodiscard]] std::vector<ChatRestrictions> ListOfRestrictions(
RestrictionsSetOptions options);
} // namespace Data

View file

@ -418,12 +418,15 @@ rpl::producer<int> AdminsCountValue(not_null<PeerData*> peer) {
rpl::producer<int> RestrictionsCountValue(not_null<PeerData*> peer) {
const auto countOfRestrictions = [](ChatRestrictions restrictions) {
const auto countOfRestrictions = [](
Data::RestrictionsSetOptions options,
ChatRestrictions restrictions) {
auto count = 0;
for (const auto &f : Data::ListOfRestrictions()) {
const auto list = Data::ListOfRestrictions(options);
for (const auto &f : list) {
if (restrictions & f) count++;
}
return int(Data::ListOfRestrictions().size()) - count;
return int(list.size()) - count;
};
if (const auto chat = peer->asChat()) {
@ -431,14 +434,22 @@ rpl::producer<int> RestrictionsCountValue(not_null<PeerData*> peer) {
peer,
UpdateFlag::Rights
) | rpl::map([=] {
return countOfRestrictions(chat->defaultRestrictions());
return countOfRestrictions({}, chat->defaultRestrictions());
});
} else if (const auto channel = peer->asChannel()) {
return peer->session().changes().peerFlagsValue(
peer,
UpdateFlag::Rights
auto forumValue = channel->flagsValue(
) | rpl::filter([](const ChannelData::Flags::Change &change) {
return (change.diff & ChannelData::Flag::Forum);
});
return rpl::combine(
std::move(forumValue),
channel->session().changes().peerFlagsValue(
channel,
UpdateFlag::Rights)
) | rpl::map([=] {
return countOfRestrictions(channel->defaultRestrictions());
return countOfRestrictions(
{ .isForum = channel->isForum() },
channel->defaultRestrictions());
});
}
Unexpected("User in RestrictionsCountValue().");