mirror of
https://github.com/telegramdesktop/tdesktop
synced 2025-02-24 01:06:59 +00:00
Allow restricting forwards in groups / channels.
This commit is contained in:
parent
431e3035af
commit
9be47f0870
@ -148,6 +148,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_error_admin_limit" = "Sorry, you've reached the maximum number of admins for this group.";
|
||||
"lng_error_admin_limit_channel" = "Sorry, you've reached the maximum number of admins for this channel.";
|
||||
"lng_error_post_link_invalid" = "Unfortunately, you can't access this message. You are not a member of the chat where it was posted.";
|
||||
"lng_error_noforwards_group" = "Sorry, forwarding is disabled from this group.";
|
||||
"lng_error_noforwards_channel" = "Sorry, forwarding is disabled from this channel.";
|
||||
"lng_sure_add_admin_invite" = "This user is not a member of this group. Add them to the group and promote them to admin?";
|
||||
"lng_sure_add_admin_invite_channel" = "This user is not a subscriber of this channel. Add them to the channel and promote them to admin?";
|
||||
"lng_sure_add_admin_unremove" = "This user is currently restricted or removed. Are you sure you want to promote them?";
|
||||
@ -1808,6 +1810,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_edit_contact_title" = "Edit contact name";
|
||||
"lng_edit_channel_title" = "Edit channel";
|
||||
"lng_edit_sign_messages" = "Sign messages";
|
||||
"lng_edit_allow_forwards" = "Allow saving content";
|
||||
"lng_edit_group" = "Edit group";
|
||||
"lng_edit_self_title" = "Edit your name";
|
||||
"lng_confirm_contact_data" = "New Contact";
|
||||
|
@ -504,6 +504,11 @@ void ApiWrap::sendMessageFail(
|
||||
scheduled.removeSending(item);
|
||||
Ui::show(Box<Ui::InformBox>(tr::lng_cant_do_this(tr::now)));
|
||||
}
|
||||
} else if (error.type() == qstr("CHAT_FORWARDS_RESTRICTED")) {
|
||||
Ui::ShowMultilineToast({ .text = { peer->isBroadcast()
|
||||
? tr::lng_error_noforwards_channel(tr::now)
|
||||
: tr::lng_error_noforwards_group(tr::now)
|
||||
}, .duration = kJoinErrorDuration });
|
||||
}
|
||||
if (const auto item = _session->data().message(itemId)) {
|
||||
Assert(randomId != 0);
|
||||
|
@ -277,6 +277,7 @@ private:
|
||||
std::optional<QString> description;
|
||||
std::optional<bool> hiddenPreHistory;
|
||||
std::optional<bool> signatures;
|
||||
std::optional<bool> forwards;
|
||||
std::optional<ChannelData*> linkedChat;
|
||||
};
|
||||
|
||||
@ -296,6 +297,7 @@ private:
|
||||
void fillLinkedChatButton();
|
||||
//void fillInviteLinkButton();
|
||||
void fillSignaturesButton();
|
||||
void fillForwardsButton();
|
||||
void fillHistoryVisibilityButton();
|
||||
void fillManageSection();
|
||||
void fillPendingRequestsButton();
|
||||
@ -312,6 +314,7 @@ private:
|
||||
bool validateDescription(Saving &to) const;
|
||||
bool validateHistoryVisibility(Saving &to) const;
|
||||
bool validateSignatures(Saving &to) const;
|
||||
bool validateForwards(Saving &to) const;
|
||||
|
||||
void save();
|
||||
void saveUsername();
|
||||
@ -320,6 +323,7 @@ private:
|
||||
void saveDescription();
|
||||
void saveHistoryVisibility();
|
||||
void saveSignatures();
|
||||
void saveForwards();
|
||||
void savePhoto();
|
||||
void pushSaveStage(FnMut<void()> &&lambda);
|
||||
void continueSave();
|
||||
@ -341,6 +345,7 @@ private:
|
||||
std::optional<HistoryVisibility> _historyVisibilitySavedValue;
|
||||
std::optional<QString> _usernameSavedValue;
|
||||
std::optional<bool> _signaturesSavedValue;
|
||||
std::optional<bool> _forwardsSavedValue;
|
||||
|
||||
const not_null<Window::SessionNavigation*> _navigation;
|
||||
const not_null<Ui::BoxContent*> _box;
|
||||
@ -795,6 +800,21 @@ void Controller::fillSignaturesButton() {
|
||||
}, _controls.buttonsLayout->lifetime());
|
||||
}
|
||||
|
||||
void Controller::fillForwardsButton() {
|
||||
Expects(_controls.buttonsLayout != nullptr);
|
||||
|
||||
AddButtonWithText(
|
||||
_controls.buttonsLayout,
|
||||
tr::lng_edit_allow_forwards(),
|
||||
rpl::single(QString()),
|
||||
[=] {}
|
||||
)->toggleOn(rpl::single(_peer->allowsForwarding())
|
||||
)->toggledValue(
|
||||
) | rpl::start_with_next([=](bool toggled) {
|
||||
_forwardsSavedValue = toggled;
|
||||
}, _controls.buttonsLayout->lifetime());
|
||||
}
|
||||
|
||||
void Controller::fillHistoryVisibilityButton() {
|
||||
Expects(_controls.buttonsLayout != nullptr);
|
||||
|
||||
@ -864,6 +884,9 @@ void Controller::fillManageSection() {
|
||||
? (channel->canEditSignatures() && !channel->isMegagroup())
|
||||
: false;
|
||||
}();
|
||||
const auto canEditForwards = [&] {
|
||||
return isChannel ? channel->amCreator() : chat->amCreator();
|
||||
}();
|
||||
const auto canEditPreHistoryHidden = [&] {
|
||||
return isChannel
|
||||
? channel->canEditPreHistoryHidden()
|
||||
@ -937,8 +960,12 @@ void Controller::fillManageSection() {
|
||||
if (canEditSignatures) {
|
||||
fillSignaturesButton();
|
||||
}
|
||||
if (canEditForwards) {
|
||||
fillForwardsButton();
|
||||
}
|
||||
if (canEditPreHistoryHidden
|
||||
|| canEditSignatures
|
||||
|| canEditForwards
|
||||
//|| canEditInviteLinks
|
||||
|| canViewOrEditLinkedChat
|
||||
|| canEditUsername) {
|
||||
@ -1154,7 +1181,8 @@ std::optional<Controller::Saving> Controller::validate() const {
|
||||
&& validateTitle(result)
|
||||
&& validateDescription(result)
|
||||
&& validateHistoryVisibility(result)
|
||||
&& validateSignatures(result)) {
|
||||
&& validateSignatures(result)
|
||||
&& validateForwards(result)) {
|
||||
return result;
|
||||
}
|
||||
return {};
|
||||
@ -1229,6 +1257,14 @@ bool Controller::validateSignatures(Saving &to) const {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Controller::validateForwards(Saving &to) const {
|
||||
if (!_forwardsSavedValue.has_value()) {
|
||||
return true;
|
||||
}
|
||||
to.forwards = _forwardsSavedValue;
|
||||
return true;
|
||||
}
|
||||
|
||||
void Controller::save() {
|
||||
Expects(_wrap != nullptr);
|
||||
|
||||
@ -1243,6 +1279,7 @@ void Controller::save() {
|
||||
pushSaveStage([=] { saveDescription(); });
|
||||
pushSaveStage([=] { saveHistoryVisibility(); });
|
||||
pushSaveStage([=] { saveSignatures(); });
|
||||
pushSaveStage([=] { saveForwards(); });
|
||||
pushSaveStage([=] { savePhoto(); });
|
||||
continueSave();
|
||||
}
|
||||
@ -1499,6 +1536,26 @@ void Controller::saveSignatures() {
|
||||
}).send();
|
||||
}
|
||||
|
||||
void Controller::saveForwards() {
|
||||
if (!_savingData.forwards
|
||||
|| *_savingData.forwards == _peer->allowsForwarding()) {
|
||||
return continueSave();
|
||||
}
|
||||
_api.request(MTPmessages_ToggleNoForwards(
|
||||
_peer->input,
|
||||
MTP_bool(!*_savingData.forwards)
|
||||
)).done([=](const MTPUpdates &result) {
|
||||
_peer->session().api().applyUpdates(result);
|
||||
continueSave();
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
if (error.type() == qstr("CHAT_NOT_MODIFIED")) {
|
||||
continueSave();
|
||||
} else {
|
||||
cancelSave();
|
||||
}
|
||||
}).send();
|
||||
}
|
||||
|
||||
void Controller::savePhoto() {
|
||||
auto image = _controls.photo
|
||||
? _controls.photo->takeResultImage()
|
||||
|
@ -470,6 +470,10 @@ bool ChannelData::canWrite() const {
|
||||
&& !amRestricted(Restriction::SendMessages)));
|
||||
}
|
||||
|
||||
bool ChannelData::allowsForwarding() const {
|
||||
return !(flags() & Flag::NoForwards);
|
||||
}
|
||||
|
||||
bool ChannelData::canViewMembers() const {
|
||||
return flags() & Flag::CanViewParticipants;
|
||||
}
|
||||
|
@ -50,6 +50,7 @@ enum class ChannelDataFlag {
|
||||
CanViewParticipants = (1 << 17),
|
||||
HasLink = (1 << 18),
|
||||
SlowmodeEnabled = (1 << 19),
|
||||
NoForwards = (1 << 20),
|
||||
};
|
||||
inline constexpr bool is_flag_type(ChannelDataFlag) { return true; };
|
||||
using ChannelDataFlags = base::flags<ChannelDataFlag>;
|
||||
@ -293,6 +294,7 @@ public:
|
||||
|
||||
// Like in ChatData.
|
||||
[[nodiscard]] bool canWrite() const;
|
||||
[[nodiscard]] bool allowsForwarding() const;
|
||||
[[nodiscard]] bool canEditInformation() const;
|
||||
[[nodiscard]] bool canEditPermissions() const;
|
||||
[[nodiscard]] bool canEditUsername() const;
|
||||
|
@ -28,7 +28,7 @@ ChatData::ChatData(not_null<Data::Session*> owner, PeerId id)
|
||||
, inputChat(MTP_long(peerToChat(id).bare)) {
|
||||
_flags.changes(
|
||||
) | rpl::start_with_next([=](const Flags::Change &change) {
|
||||
if (change.diff & ChatDataFlag::CallNotEmpty) {
|
||||
if (change.diff & Flag::CallNotEmpty) {
|
||||
if (const auto history = this->owner().historyLoaded(this)) {
|
||||
history->updateChatListEntry();
|
||||
}
|
||||
@ -63,6 +63,10 @@ bool ChatData::canWrite() const {
|
||||
return amIn() && !amRestricted(Restriction::SendMessages);
|
||||
}
|
||||
|
||||
bool ChatData::allowsForwarding() const {
|
||||
return !(flags() & Flag::NoForwards);
|
||||
}
|
||||
|
||||
bool ChatData::canEditInformation() const {
|
||||
return amIn() && !amRestricted(Restriction::ChangeInfo);
|
||||
}
|
||||
@ -74,7 +78,7 @@ bool ChatData::canEditPermissions() const {
|
||||
|
||||
bool ChatData::canEditUsername() const {
|
||||
return amCreator()
|
||||
&& (flags() & ChatDataFlag::CanSetUsername);
|
||||
&& (flags() & Flag::CanSetUsername);
|
||||
}
|
||||
|
||||
bool ChatData::canEditPreHistoryHidden() const {
|
||||
@ -222,7 +226,7 @@ void ChatData::setGroupCall(
|
||||
scheduleDate);
|
||||
owner().registerGroupCall(_call.get());
|
||||
session().changes().peerUpdated(this, UpdateFlag::GroupCall);
|
||||
addFlags(ChatDataFlag::CallActive);
|
||||
addFlags(Flag::CallActive);
|
||||
});
|
||||
}
|
||||
|
||||
@ -236,7 +240,7 @@ void ChatData::clearGroupCall() {
|
||||
_call = nullptr;
|
||||
}
|
||||
session().changes().peerUpdated(this, UpdateFlag::GroupCall);
|
||||
removeFlags(ChatDataFlag::CallActive | ChatDataFlag::CallNotEmpty);
|
||||
removeFlags(Flag::CallActive | Flag::CallNotEmpty);
|
||||
}
|
||||
|
||||
void ChatData::setGroupCallDefaultJoinAs(PeerId peerId) {
|
||||
|
@ -18,6 +18,7 @@ enum class ChatDataFlag {
|
||||
CallActive = (1 << 5),
|
||||
CallNotEmpty = (1 << 6),
|
||||
CanSetUsername = (1 << 7),
|
||||
NoForwards = (1 << 8),
|
||||
};
|
||||
inline constexpr bool is_flag_type(ChatDataFlag) { return true; };
|
||||
using ChatDataFlags = base::flags<ChatDataFlag>;
|
||||
@ -109,6 +110,7 @@ public:
|
||||
|
||||
// Like in ChannelData.
|
||||
[[nodiscard]] bool canWrite() const;
|
||||
[[nodiscard]] bool allowsForwarding() const;
|
||||
[[nodiscard]] bool canEditInformation() const;
|
||||
[[nodiscard]] bool canEditPermissions() const;
|
||||
[[nodiscard]] bool canEditUsername() const;
|
||||
|
@ -848,6 +848,17 @@ bool PeerData::canWrite() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool PeerData::allowsForwarding() const {
|
||||
if (const auto user = asUser()) {
|
||||
return true;
|
||||
} else if (const auto channel = asChannel()) {
|
||||
return channel->allowsForwarding();
|
||||
} else if (const auto chat = asChat()) {
|
||||
return chat->allowsForwarding();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Data::RestrictionCheckResult PeerData::amRestricted(
|
||||
ChatRestriction right) const {
|
||||
using Result = Data::RestrictionCheckResult;
|
||||
|
@ -274,6 +274,7 @@ public:
|
||||
}
|
||||
|
||||
[[nodiscard]] bool canWrite() const;
|
||||
[[nodiscard]] bool allowsForwarding() const;
|
||||
[[nodiscard]] Data::RestrictionCheckResult amRestricted(
|
||||
ChatRestriction right) const;
|
||||
[[nodiscard]] bool amAnonymous() const;
|
||||
|
@ -641,7 +641,8 @@ not_null<PeerData*> Session::processChat(const MTPChat &data) {
|
||||
| Flag::Deactivated
|
||||
| Flag::Forbidden
|
||||
| Flag::CallActive
|
||||
| Flag::CallNotEmpty;
|
||||
| Flag::CallNotEmpty
|
||||
| Flag::NoForwards;
|
||||
const auto flagsSet = (data.is_left() ? Flag::Left : Flag())
|
||||
| (data.is_kicked() ? Flag::Kicked : Flag())
|
||||
| (data.is_creator() ? Flag::Creator : Flag())
|
||||
@ -651,7 +652,8 @@ not_null<PeerData*> Session::processChat(const MTPChat &data) {
|
||||
|| (chat->groupCall()
|
||||
&& chat->groupCall()->fullCount() > 0))
|
||||
? Flag::CallNotEmpty
|
||||
: Flag());
|
||||
: Flag())
|
||||
| (data.is_noforwards() ? Flag::NoForwards : Flag());
|
||||
chat->setFlags((chat->flags() & ~flagsMask) | flagsSet);
|
||||
chat->count = data.vparticipants_count().v;
|
||||
|
||||
@ -739,10 +741,8 @@ not_null<PeerData*> Session::processChat(const MTPChat &data) {
|
||||
| Flag::CallActive
|
||||
| Flag::CallNotEmpty
|
||||
| Flag::Forbidden
|
||||
| (!minimal
|
||||
? Flag::Left
|
||||
| Flag::Creator
|
||||
: Flag());
|
||||
| (!minimal ? (Flag::Left | Flag::Creator) : Flag())
|
||||
| Flag::NoForwards;
|
||||
const auto flagsSet = (data.is_broadcast() ? Flag::Broadcast : Flag())
|
||||
| (data.is_verified() ? Flag::Verified : Flag())
|
||||
| (data.is_scam() ? Flag::Scam : Flag())
|
||||
@ -762,7 +762,8 @@ not_null<PeerData*> Session::processChat(const MTPChat &data) {
|
||||
| (!minimal
|
||||
? (data.is_left() ? Flag::Left : Flag())
|
||||
| (data.is_creator() ? Flag::Creator : Flag())
|
||||
: Flag());
|
||||
: Flag())
|
||||
| (data.is_noforwards() ? Flag::NoForwards : Flag());
|
||||
channel->setFlags((channel->flags() & ~flagsMask) | flagsSet);
|
||||
|
||||
channel->setName(
|
||||
|
@ -1038,7 +1038,9 @@ void HistoryMessage::applySentMessage(
|
||||
}
|
||||
|
||||
bool HistoryMessage::allowsForward() const {
|
||||
return isRegular() && (!_media || _media->allowsForward());
|
||||
return isRegular()
|
||||
&& history()->peer->allowsForwarding()
|
||||
&& (!_media || _media->allowsForward());
|
||||
}
|
||||
|
||||
bool HistoryMessage::allowsSendNow() const {
|
||||
|
Loading…
Reference in New Issue
Block a user