Move set_channel_participant_status and similar methods to DialogParticipantManager.
This commit is contained in:
parent
9660a7f2b1
commit
b1d72276a7
@ -2280,219 +2280,6 @@ class DeleteChatUserQuery final : public Td::ResultHandler {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class JoinChannelQuery final : public Td::ResultHandler {
|
|
||||||
Promise<Unit> promise_;
|
|
||||||
ChannelId channel_id_;
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit JoinChannelQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
|
|
||||||
}
|
|
||||||
|
|
||||||
void send(ChannelId channel_id) {
|
|
||||||
channel_id_ = channel_id;
|
|
||||||
auto input_channel = td_->contacts_manager_->get_input_channel(channel_id);
|
|
||||||
CHECK(input_channel != nullptr);
|
|
||||||
send_query(
|
|
||||||
G()->net_query_creator().create(telegram_api::channels_joinChannel(std::move(input_channel)), {{channel_id}}));
|
|
||||||
}
|
|
||||||
|
|
||||||
void on_result(BufferSlice packet) final {
|
|
||||||
auto result_ptr = fetch_result<telegram_api::channels_joinChannel>(packet);
|
|
||||||
if (result_ptr.is_error()) {
|
|
||||||
return on_error(result_ptr.move_as_error());
|
|
||||||
}
|
|
||||||
|
|
||||||
auto ptr = result_ptr.move_as_ok();
|
|
||||||
LOG(INFO) << "Receive result for JoinChannelQuery: " << to_string(ptr);
|
|
||||||
td_->updates_manager_->on_get_updates(std::move(ptr), std::move(promise_));
|
|
||||||
}
|
|
||||||
|
|
||||||
void on_error(Status status) final {
|
|
||||||
td_->contacts_manager_->on_get_channel_error(channel_id_, status, "JoinChannelQuery");
|
|
||||||
promise_.set_error(std::move(status));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class InviteToChannelQuery final : public Td::ResultHandler {
|
|
||||||
Promise<Unit> promise_;
|
|
||||||
ChannelId channel_id_;
|
|
||||||
vector<UserId> user_ids_;
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit InviteToChannelQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
|
|
||||||
}
|
|
||||||
|
|
||||||
void send(ChannelId channel_id, vector<UserId> user_ids,
|
|
||||||
vector<tl_object_ptr<telegram_api::InputUser>> &&input_users) {
|
|
||||||
channel_id_ = channel_id;
|
|
||||||
user_ids_ = std::move(user_ids);
|
|
||||||
auto input_channel = td_->contacts_manager_->get_input_channel(channel_id);
|
|
||||||
CHECK(input_channel != nullptr);
|
|
||||||
send_query(G()->net_query_creator().create(
|
|
||||||
telegram_api::channels_inviteToChannel(std::move(input_channel), std::move(input_users))));
|
|
||||||
}
|
|
||||||
|
|
||||||
void on_result(BufferSlice packet) final {
|
|
||||||
auto result_ptr = fetch_result<telegram_api::channels_inviteToChannel>(packet);
|
|
||||||
if (result_ptr.is_error()) {
|
|
||||||
return on_error(result_ptr.move_as_error());
|
|
||||||
}
|
|
||||||
|
|
||||||
auto ptr = result_ptr.move_as_ok();
|
|
||||||
LOG(INFO) << "Receive result for InviteToChannelQuery: " << to_string(ptr);
|
|
||||||
td_->contacts_manager_->invalidate_channel_full(channel_id_, false, "InviteToChannelQuery");
|
|
||||||
auto user_ids = td_->updates_manager_->extract_group_invite_privacy_forbidden_updates(ptr);
|
|
||||||
auto promise = PromiseCreator::lambda([dialog_id = DialogId(channel_id_), user_ids = std::move(user_ids),
|
|
||||||
promise = std::move(promise_)](Result<Unit> &&result) mutable {
|
|
||||||
if (result.is_error()) {
|
|
||||||
return promise.set_error(result.move_as_error());
|
|
||||||
}
|
|
||||||
promise.set_value(Unit());
|
|
||||||
if (!user_ids.empty()) {
|
|
||||||
send_closure(G()->contacts_manager(), &ContactsManager::send_update_add_chat_members_privacy_forbidden,
|
|
||||||
dialog_id, std::move(user_ids), "InviteToChannelQuery");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
td_->updates_manager_->on_get_updates(std::move(ptr), std::move(promise));
|
|
||||||
}
|
|
||||||
|
|
||||||
void on_error(Status status) final {
|
|
||||||
if (!td_->auth_manager_->is_bot() && status.message() == "USER_PRIVACY_RESTRICTED") {
|
|
||||||
td_->contacts_manager_->send_update_add_chat_members_privacy_forbidden(
|
|
||||||
DialogId(channel_id_), std::move(user_ids_), "InviteToChannelQuery");
|
|
||||||
return promise_.set_error(Status::Error(406, "USER_PRIVACY_RESTRICTED"));
|
|
||||||
}
|
|
||||||
td_->contacts_manager_->on_get_channel_error(channel_id_, status, "InviteToChannelQuery");
|
|
||||||
td_->contacts_manager_->invalidate_channel_full(channel_id_, false, "InviteToChannelQuery");
|
|
||||||
promise_.set_error(std::move(status));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class EditChannelAdminQuery final : public Td::ResultHandler {
|
|
||||||
Promise<Unit> promise_;
|
|
||||||
ChannelId channel_id_;
|
|
||||||
UserId user_id_;
|
|
||||||
DialogParticipantStatus status_ = DialogParticipantStatus::Left();
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit EditChannelAdminQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
|
|
||||||
}
|
|
||||||
|
|
||||||
void send(ChannelId channel_id, UserId user_id, tl_object_ptr<telegram_api::InputUser> &&input_user,
|
|
||||||
const DialogParticipantStatus &status) {
|
|
||||||
channel_id_ = channel_id;
|
|
||||||
user_id_ = user_id;
|
|
||||||
status_ = status;
|
|
||||||
auto input_channel = td_->contacts_manager_->get_input_channel(channel_id);
|
|
||||||
CHECK(input_channel != nullptr);
|
|
||||||
send_query(G()->net_query_creator().create(telegram_api::channels_editAdmin(
|
|
||||||
std::move(input_channel), std::move(input_user), status.get_chat_admin_rights(), status.get_rank())));
|
|
||||||
}
|
|
||||||
|
|
||||||
void on_result(BufferSlice packet) final {
|
|
||||||
auto result_ptr = fetch_result<telegram_api::channels_editAdmin>(packet);
|
|
||||||
if (result_ptr.is_error()) {
|
|
||||||
return on_error(result_ptr.move_as_error());
|
|
||||||
}
|
|
||||||
|
|
||||||
auto ptr = result_ptr.move_as_ok();
|
|
||||||
LOG(INFO) << "Receive result for EditChannelAdminQuery: " << to_string(ptr);
|
|
||||||
td_->contacts_manager_->invalidate_channel_full(channel_id_, false, "EditChannelAdminQuery");
|
|
||||||
td_->updates_manager_->on_get_updates(std::move(ptr), std::move(promise_));
|
|
||||||
td_->dialog_participant_manager_->on_set_channel_participant_status(channel_id_, DialogId(user_id_), status_);
|
|
||||||
}
|
|
||||||
|
|
||||||
void on_error(Status status) final {
|
|
||||||
if (!td_->auth_manager_->is_bot() && status.message() == "USER_PRIVACY_RESTRICTED") {
|
|
||||||
td_->contacts_manager_->send_update_add_chat_members_privacy_forbidden(DialogId(channel_id_), {user_id_},
|
|
||||||
"EditChannelAdminQuery");
|
|
||||||
return promise_.set_error(Status::Error(406, "USER_PRIVACY_RESTRICTED"));
|
|
||||||
}
|
|
||||||
td_->contacts_manager_->on_get_channel_error(channel_id_, status, "EditChannelAdminQuery");
|
|
||||||
td_->contacts_manager_->invalidate_channel_full(channel_id_, false, "EditChannelAdminQuery");
|
|
||||||
promise_.set_error(std::move(status));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class EditChannelBannedQuery final : public Td::ResultHandler {
|
|
||||||
Promise<Unit> promise_;
|
|
||||||
ChannelId channel_id_;
|
|
||||||
DialogId participant_dialog_id_;
|
|
||||||
DialogParticipantStatus status_ = DialogParticipantStatus::Left();
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit EditChannelBannedQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
|
|
||||||
}
|
|
||||||
|
|
||||||
void send(ChannelId channel_id, DialogId participant_dialog_id, tl_object_ptr<telegram_api::InputPeer> &&input_peer,
|
|
||||||
const DialogParticipantStatus &status) {
|
|
||||||
channel_id_ = channel_id;
|
|
||||||
participant_dialog_id_ = participant_dialog_id;
|
|
||||||
status_ = status;
|
|
||||||
auto input_channel = td_->contacts_manager_->get_input_channel(channel_id);
|
|
||||||
CHECK(input_channel != nullptr);
|
|
||||||
send_query(G()->net_query_creator().create(telegram_api::channels_editBanned(
|
|
||||||
std::move(input_channel), std::move(input_peer), status.get_chat_banned_rights())));
|
|
||||||
}
|
|
||||||
|
|
||||||
void on_result(BufferSlice packet) final {
|
|
||||||
auto result_ptr = fetch_result<telegram_api::channels_editBanned>(packet);
|
|
||||||
if (result_ptr.is_error()) {
|
|
||||||
return on_error(result_ptr.move_as_error());
|
|
||||||
}
|
|
||||||
|
|
||||||
auto ptr = result_ptr.move_as_ok();
|
|
||||||
LOG(INFO) << "Receive result for EditChannelBannedQuery: " << to_string(ptr);
|
|
||||||
td_->contacts_manager_->invalidate_channel_full(channel_id_, false, "EditChannelBannedQuery");
|
|
||||||
td_->updates_manager_->on_get_updates(std::move(ptr), std::move(promise_));
|
|
||||||
td_->dialog_participant_manager_->on_set_channel_participant_status(channel_id_, participant_dialog_id_, status_);
|
|
||||||
}
|
|
||||||
|
|
||||||
void on_error(Status status) final {
|
|
||||||
if (participant_dialog_id_.get_type() != DialogType::Channel) {
|
|
||||||
td_->contacts_manager_->on_get_channel_error(channel_id_, status, "EditChannelBannedQuery");
|
|
||||||
}
|
|
||||||
td_->contacts_manager_->invalidate_channel_full(channel_id_, false, "EditChannelBannedQuery");
|
|
||||||
promise_.set_error(std::move(status));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class LeaveChannelQuery final : public Td::ResultHandler {
|
|
||||||
Promise<Unit> promise_;
|
|
||||||
ChannelId channel_id_;
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit LeaveChannelQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
|
|
||||||
}
|
|
||||||
|
|
||||||
void send(ChannelId channel_id) {
|
|
||||||
channel_id_ = channel_id;
|
|
||||||
auto input_channel = td_->contacts_manager_->get_input_channel(channel_id);
|
|
||||||
CHECK(input_channel != nullptr);
|
|
||||||
send_query(
|
|
||||||
G()->net_query_creator().create(telegram_api::channels_leaveChannel(std::move(input_channel)), {{channel_id}}));
|
|
||||||
}
|
|
||||||
|
|
||||||
void on_result(BufferSlice packet) final {
|
|
||||||
auto result_ptr = fetch_result<telegram_api::channels_leaveChannel>(packet);
|
|
||||||
if (result_ptr.is_error()) {
|
|
||||||
return on_error(result_ptr.move_as_error());
|
|
||||||
}
|
|
||||||
|
|
||||||
auto ptr = result_ptr.move_as_ok();
|
|
||||||
LOG(INFO) << "Receive result for LeaveChannelQuery: " << to_string(ptr);
|
|
||||||
td_->updates_manager_->on_get_updates(std::move(ptr), std::move(promise_));
|
|
||||||
}
|
|
||||||
|
|
||||||
void on_error(Status status) final {
|
|
||||||
if (status.message() == "USER_NOT_PARTICIPANT") {
|
|
||||||
return td_->contacts_manager_->reload_channel(channel_id_, std::move(promise_), "LeaveChannelQuery");
|
|
||||||
}
|
|
||||||
td_->contacts_manager_->on_get_channel_error(channel_id_, status, "LeaveChannelQuery");
|
|
||||||
promise_.set_error(std::move(status));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class CanEditChannelCreatorQuery final : public Td::ResultHandler {
|
class CanEditChannelCreatorQuery final : public Td::ResultHandler {
|
||||||
Promise<Unit> promise_;
|
Promise<Unit> promise_;
|
||||||
|
|
||||||
@ -8036,232 +7823,6 @@ void ContactsManager::add_chat_participant(ChatId chat_id, UserId user_id, int32
|
|||||||
->send(chat_id, user_id, std::move(input_user), forward_limit);
|
->send(chat_id, user_id, std::move(input_user), forward_limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContactsManager::add_channel_participant(ChannelId channel_id, UserId user_id,
|
|
||||||
const DialogParticipantStatus &old_status, Promise<Unit> &&promise) {
|
|
||||||
if (td_->auth_manager_->is_bot()) {
|
|
||||||
return promise.set_error(Status::Error(400, "Bots can't add new chat members"));
|
|
||||||
}
|
|
||||||
|
|
||||||
const Channel *c = get_channel(channel_id);
|
|
||||||
if (c == nullptr) {
|
|
||||||
return promise.set_error(Status::Error(400, "Chat info not found"));
|
|
||||||
}
|
|
||||||
TRY_RESULT_PROMISE(promise, input_user, get_input_user(user_id));
|
|
||||||
|
|
||||||
if (user_id == get_my_id()) {
|
|
||||||
// join the channel
|
|
||||||
if (get_channel_status(c).is_banned()) {
|
|
||||||
return promise.set_error(Status::Error(400, "Can't return to kicked from chat"));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!get_channel_join_request(c)) {
|
|
||||||
speculative_add_channel_user(channel_id, user_id, DialogParticipantStatus::Member(), c->status);
|
|
||||||
}
|
|
||||||
td_->create_handler<JoinChannelQuery>(std::move(promise))->send(channel_id);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!get_channel_permissions(c).can_invite_users()) {
|
|
||||||
return promise.set_error(Status::Error(400, "Not enough rights to invite members to the supergroup chat"));
|
|
||||||
}
|
|
||||||
|
|
||||||
speculative_add_channel_user(channel_id, user_id, DialogParticipantStatus::Member(), old_status);
|
|
||||||
vector<tl_object_ptr<telegram_api::InputUser>> input_users;
|
|
||||||
input_users.push_back(std::move(input_user));
|
|
||||||
td_->create_handler<InviteToChannelQuery>(std::move(promise))->send(channel_id, {user_id}, std::move(input_users));
|
|
||||||
}
|
|
||||||
|
|
||||||
void ContactsManager::add_channel_participants(ChannelId channel_id, const vector<UserId> &user_ids,
|
|
||||||
Promise<Unit> &&promise) {
|
|
||||||
if (td_->auth_manager_->is_bot()) {
|
|
||||||
return promise.set_error(Status::Error(400, "Bots can't add new chat members"));
|
|
||||||
}
|
|
||||||
|
|
||||||
const Channel *c = get_channel(channel_id);
|
|
||||||
if (c == nullptr) {
|
|
||||||
return promise.set_error(Status::Error(400, "Chat info not found"));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!get_channel_permissions(c).can_invite_users()) {
|
|
||||||
return promise.set_error(Status::Error(400, "Not enough rights to invite members to the supergroup chat"));
|
|
||||||
}
|
|
||||||
|
|
||||||
vector<tl_object_ptr<telegram_api::InputUser>> input_users;
|
|
||||||
for (auto user_id : user_ids) {
|
|
||||||
TRY_RESULT_PROMISE(promise, input_user, get_input_user(user_id));
|
|
||||||
|
|
||||||
if (user_id == get_my_id()) {
|
|
||||||
// can't invite self
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
input_users.push_back(std::move(input_user));
|
|
||||||
|
|
||||||
speculative_add_channel_user(channel_id, user_id, DialogParticipantStatus::Member(),
|
|
||||||
DialogParticipantStatus::Left());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (input_users.empty()) {
|
|
||||||
return promise.set_value(Unit());
|
|
||||||
}
|
|
||||||
|
|
||||||
td_->create_handler<InviteToChannelQuery>(std::move(promise))->send(channel_id, user_ids, std::move(input_users));
|
|
||||||
}
|
|
||||||
|
|
||||||
void ContactsManager::set_channel_participant_status(ChannelId channel_id, DialogId participant_dialog_id,
|
|
||||||
td_api::object_ptr<td_api::ChatMemberStatus> &&chat_member_status,
|
|
||||||
Promise<Unit> &&promise) {
|
|
||||||
auto c = get_channel(channel_id);
|
|
||||||
if (c == nullptr) {
|
|
||||||
return promise.set_error(Status::Error(400, "Chat info not found"));
|
|
||||||
}
|
|
||||||
auto status = get_dialog_participant_status(chat_member_status, get_channel_type(c));
|
|
||||||
|
|
||||||
if (participant_dialog_id == DialogId(get_my_id())) {
|
|
||||||
// fast path is needed, because get_channel_status may return Creator, while GetChannelParticipantQuery returning Left
|
|
||||||
return set_channel_participant_status_impl(channel_id, participant_dialog_id, std::move(status),
|
|
||||||
get_channel_status(c), std::move(promise));
|
|
||||||
}
|
|
||||||
if (participant_dialog_id.get_type() != DialogType::User) {
|
|
||||||
if (status.is_administrator() || status.is_member() || status.is_restricted()) {
|
|
||||||
return promise.set_error(Status::Error(400, "Other chats can be only banned or unbanned"));
|
|
||||||
}
|
|
||||||
// always pretend that old_status is different
|
|
||||||
return restrict_channel_participant(
|
|
||||||
channel_id, participant_dialog_id, std::move(status),
|
|
||||||
status.is_banned() ? DialogParticipantStatus::Left() : DialogParticipantStatus::Banned(0), std::move(promise));
|
|
||||||
}
|
|
||||||
|
|
||||||
auto on_result_promise =
|
|
||||||
PromiseCreator::lambda([actor_id = actor_id(this), channel_id, participant_dialog_id, status,
|
|
||||||
promise = std::move(promise)](Result<DialogParticipant> r_dialog_participant) mutable {
|
|
||||||
// ResultHandlers are cleared before managers, so it is safe to capture this
|
|
||||||
if (r_dialog_participant.is_error()) {
|
|
||||||
return promise.set_error(r_dialog_participant.move_as_error());
|
|
||||||
}
|
|
||||||
|
|
||||||
send_closure(actor_id, &ContactsManager::set_channel_participant_status_impl, channel_id, participant_dialog_id,
|
|
||||||
std::move(status), r_dialog_participant.ok().status_, std::move(promise));
|
|
||||||
});
|
|
||||||
|
|
||||||
td_->dialog_participant_manager_->get_channel_participant(channel_id, participant_dialog_id,
|
|
||||||
std::move(on_result_promise));
|
|
||||||
}
|
|
||||||
|
|
||||||
void ContactsManager::set_channel_participant_status_impl(ChannelId channel_id, DialogId participant_dialog_id,
|
|
||||||
DialogParticipantStatus new_status,
|
|
||||||
DialogParticipantStatus old_status, Promise<Unit> &&promise) {
|
|
||||||
if (old_status == new_status && !old_status.is_creator()) {
|
|
||||||
return promise.set_value(Unit());
|
|
||||||
}
|
|
||||||
CHECK(participant_dialog_id.get_type() == DialogType::User);
|
|
||||||
|
|
||||||
LOG(INFO) << "Change status of " << participant_dialog_id << " in " << channel_id << " from " << old_status << " to "
|
|
||||||
<< new_status;
|
|
||||||
bool need_add = false;
|
|
||||||
bool need_promote = false;
|
|
||||||
bool need_restrict = false;
|
|
||||||
if (new_status.is_creator() || old_status.is_creator()) {
|
|
||||||
if (!old_status.is_creator()) {
|
|
||||||
return promise.set_error(Status::Error(400, "Can't add another owner to the chat"));
|
|
||||||
}
|
|
||||||
if (!new_status.is_creator()) {
|
|
||||||
return promise.set_error(Status::Error(400, "Can't remove chat owner"));
|
|
||||||
}
|
|
||||||
auto user_id = get_my_id();
|
|
||||||
if (participant_dialog_id != DialogId(user_id)) {
|
|
||||||
return promise.set_error(Status::Error(400, "Not enough rights to edit chat owner rights"));
|
|
||||||
}
|
|
||||||
if (new_status.is_member() == old_status.is_member()) {
|
|
||||||
// change rank and is_anonymous
|
|
||||||
auto r_input_user = get_input_user(user_id);
|
|
||||||
CHECK(r_input_user.is_ok());
|
|
||||||
td_->create_handler<EditChannelAdminQuery>(std::move(promise))
|
|
||||||
->send(channel_id, user_id, r_input_user.move_as_ok(), new_status);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (new_status.is_member()) {
|
|
||||||
// creator not member -> creator member
|
|
||||||
need_add = true;
|
|
||||||
} else {
|
|
||||||
// creator member -> creator not member
|
|
||||||
need_restrict = true;
|
|
||||||
}
|
|
||||||
} else if (new_status.is_administrator()) {
|
|
||||||
need_promote = true;
|
|
||||||
} else if (!new_status.is_member() || new_status.is_restricted()) {
|
|
||||||
if (new_status.is_member() && !old_status.is_member()) {
|
|
||||||
// TODO there is no way in server API to invite someone and change restrictions
|
|
||||||
// we need to first add user and change restrictions again after that
|
|
||||||
// but if restrictions aren't changed, then adding is enough
|
|
||||||
auto copy_old_status = old_status;
|
|
||||||
copy_old_status.set_is_member(true);
|
|
||||||
if (copy_old_status == new_status) {
|
|
||||||
need_add = true;
|
|
||||||
} else {
|
|
||||||
need_restrict = true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
need_restrict = true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// regular member
|
|
||||||
if (old_status.is_administrator()) {
|
|
||||||
need_promote = true;
|
|
||||||
} else if (old_status.is_restricted() || old_status.is_banned()) {
|
|
||||||
need_restrict = true;
|
|
||||||
} else {
|
|
||||||
CHECK(!old_status.is_member());
|
|
||||||
need_add = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (need_promote) {
|
|
||||||
if (participant_dialog_id.get_type() != DialogType::User) {
|
|
||||||
return promise.set_error(Status::Error(400, "Can't promote chats to chat administrators"));
|
|
||||||
}
|
|
||||||
return promote_channel_participant(channel_id, participant_dialog_id.get_user_id(), new_status, old_status,
|
|
||||||
std::move(promise));
|
|
||||||
} else if (need_restrict) {
|
|
||||||
return restrict_channel_participant(channel_id, participant_dialog_id, std::move(new_status), std::move(old_status),
|
|
||||||
std::move(promise));
|
|
||||||
} else {
|
|
||||||
CHECK(need_add);
|
|
||||||
if (participant_dialog_id.get_type() != DialogType::User) {
|
|
||||||
return promise.set_error(Status::Error(400, "Can't add chats as chat members"));
|
|
||||||
}
|
|
||||||
return add_channel_participant(channel_id, participant_dialog_id.get_user_id(), old_status, std::move(promise));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ContactsManager::promote_channel_participant(ChannelId channel_id, UserId user_id,
|
|
||||||
const DialogParticipantStatus &new_status,
|
|
||||||
const DialogParticipantStatus &old_status, Promise<Unit> &&promise) {
|
|
||||||
LOG(INFO) << "Promote " << user_id << " in " << channel_id << " from " << old_status << " to " << new_status;
|
|
||||||
const Channel *c = get_channel(channel_id);
|
|
||||||
CHECK(c != nullptr);
|
|
||||||
|
|
||||||
if (user_id == get_my_id()) {
|
|
||||||
if (new_status.is_administrator()) {
|
|
||||||
return promise.set_error(Status::Error(400, "Can't promote self"));
|
|
||||||
}
|
|
||||||
CHECK(new_status.is_member());
|
|
||||||
// allow to demote self. TODO is it allowed server-side?
|
|
||||||
} else {
|
|
||||||
if (!get_channel_permissions(c).can_promote_members()) {
|
|
||||||
return promise.set_error(Status::Error(400, "Not enough rights"));
|
|
||||||
}
|
|
||||||
|
|
||||||
CHECK(!old_status.is_creator());
|
|
||||||
CHECK(!new_status.is_creator());
|
|
||||||
}
|
|
||||||
|
|
||||||
TRY_RESULT_PROMISE(promise, input_user, get_input_user(user_id));
|
|
||||||
|
|
||||||
speculative_add_channel_user(channel_id, user_id, new_status, old_status);
|
|
||||||
td_->create_handler<EditChannelAdminQuery>(std::move(promise))
|
|
||||||
->send(channel_id, user_id, std::move(input_user), new_status);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ContactsManager::set_chat_participant_status(ChatId chat_id, UserId user_id, DialogParticipantStatus status,
|
void ContactsManager::set_chat_participant_status(ChatId chat_id, UserId user_id, DialogParticipantStatus status,
|
||||||
Promise<Unit> &&promise) {
|
Promise<Unit> &&promise) {
|
||||||
if (!status.is_member()) {
|
if (!status.is_member()) {
|
||||||
@ -8493,129 +8054,6 @@ void ContactsManager::delete_chat_participant(ChatId chat_id, UserId user_id, bo
|
|||||||
td_->create_handler<DeleteChatUserQuery>(std::move(promise))->send(chat_id, std::move(input_user), revoke_messages);
|
td_->create_handler<DeleteChatUserQuery>(std::move(promise))->send(chat_id, std::move(input_user), revoke_messages);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContactsManager::restrict_channel_participant(ChannelId channel_id, DialogId participant_dialog_id,
|
|
||||||
DialogParticipantStatus &&new_status,
|
|
||||||
DialogParticipantStatus &&old_status, Promise<Unit> &&promise) {
|
|
||||||
TRY_STATUS_PROMISE(promise, G()->close_status());
|
|
||||||
|
|
||||||
LOG(INFO) << "Restrict " << participant_dialog_id << " in " << channel_id << " from " << old_status << " to "
|
|
||||||
<< new_status;
|
|
||||||
const Channel *c = get_channel(channel_id);
|
|
||||||
if (c == nullptr) {
|
|
||||||
return promise.set_error(Status::Error(400, "Chat info not found"));
|
|
||||||
}
|
|
||||||
if (!c->status.is_member() && !c->status.is_creator()) {
|
|
||||||
if (participant_dialog_id == DialogId(get_my_id())) {
|
|
||||||
if (new_status.is_member()) {
|
|
||||||
return promise.set_error(Status::Error(400, "Can't unrestrict self"));
|
|
||||||
}
|
|
||||||
return promise.set_value(Unit());
|
|
||||||
} else {
|
|
||||||
return promise.set_error(Status::Error(400, "Not in the chat"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
auto input_peer = td_->dialog_manager_->get_input_peer(participant_dialog_id, AccessRights::Know);
|
|
||||||
if (input_peer == nullptr) {
|
|
||||||
return promise.set_error(Status::Error(400, "Member not found"));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (participant_dialog_id == DialogId(get_my_id())) {
|
|
||||||
if (new_status.is_restricted() || new_status.is_banned()) {
|
|
||||||
return promise.set_error(Status::Error(400, "Can't restrict self"));
|
|
||||||
}
|
|
||||||
if (new_status.is_member()) {
|
|
||||||
return promise.set_error(Status::Error(400, "Can't unrestrict self"));
|
|
||||||
}
|
|
||||||
|
|
||||||
// leave the channel
|
|
||||||
speculative_add_channel_user(channel_id, participant_dialog_id.get_user_id(), new_status, c->status);
|
|
||||||
td_->create_handler<LeaveChannelQuery>(std::move(promise))->send(channel_id);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (participant_dialog_id.get_type()) {
|
|
||||||
case DialogType::User:
|
|
||||||
// ok;
|
|
||||||
break;
|
|
||||||
case DialogType::Channel:
|
|
||||||
if (new_status.is_administrator() || new_status.is_member() || new_status.is_restricted()) {
|
|
||||||
return promise.set_error(Status::Error(400, "Other chats can be only banned or unbanned"));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return promise.set_error(Status::Error(400, "Can't restrict the chat"));
|
|
||||||
}
|
|
||||||
|
|
||||||
CHECK(!old_status.is_creator());
|
|
||||||
CHECK(!new_status.is_creator());
|
|
||||||
|
|
||||||
if (!get_channel_permissions(c).can_restrict_members()) {
|
|
||||||
return promise.set_error(Status::Error(400, "Not enough rights to restrict/unrestrict chat member"));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (old_status.is_member() && !new_status.is_member() && !new_status.is_banned()) {
|
|
||||||
// we can't make participant Left without kicking it first
|
|
||||||
auto on_result_promise = PromiseCreator::lambda([actor_id = actor_id(this), channel_id, participant_dialog_id,
|
|
||||||
new_status = std::move(new_status),
|
|
||||||
promise = std::move(promise)](Result<> result) mutable {
|
|
||||||
if (result.is_error()) {
|
|
||||||
return promise.set_error(result.move_as_error());
|
|
||||||
}
|
|
||||||
|
|
||||||
create_actor<SleepActor>(
|
|
||||||
"RestrictChannelParticipantSleepActor", 1.0,
|
|
||||||
PromiseCreator::lambda([actor_id, channel_id, participant_dialog_id, new_status = std::move(new_status),
|
|
||||||
promise = std::move(promise)](Result<> result) mutable {
|
|
||||||
if (result.is_error()) {
|
|
||||||
return promise.set_error(result.move_as_error());
|
|
||||||
}
|
|
||||||
|
|
||||||
send_closure(actor_id, &ContactsManager::restrict_channel_participant, channel_id, participant_dialog_id,
|
|
||||||
std::move(new_status), DialogParticipantStatus::Banned(0), std::move(promise));
|
|
||||||
}))
|
|
||||||
.release();
|
|
||||||
});
|
|
||||||
|
|
||||||
promise = std::move(on_result_promise);
|
|
||||||
new_status = DialogParticipantStatus::Banned(G()->unix_time() + 60);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (new_status.is_member() && !old_status.is_member()) {
|
|
||||||
// there is no way in server API to invite someone and change restrictions
|
|
||||||
// we need to first change restrictions and then try to add the user
|
|
||||||
CHECK(participant_dialog_id.get_type() == DialogType::User);
|
|
||||||
new_status.set_is_member(false);
|
|
||||||
auto on_result_promise =
|
|
||||||
PromiseCreator::lambda([actor_id = actor_id(this), channel_id, participant_dialog_id, old_status = new_status,
|
|
||||||
promise = std::move(promise)](Result<> result) mutable {
|
|
||||||
if (result.is_error()) {
|
|
||||||
return promise.set_error(result.move_as_error());
|
|
||||||
}
|
|
||||||
|
|
||||||
create_actor<SleepActor>(
|
|
||||||
"AddChannelParticipantSleepActor", 1.0,
|
|
||||||
PromiseCreator::lambda([actor_id, channel_id, participant_dialog_id, old_status = std::move(old_status),
|
|
||||||
promise = std::move(promise)](Result<> result) mutable {
|
|
||||||
if (result.is_error()) {
|
|
||||||
return promise.set_error(result.move_as_error());
|
|
||||||
}
|
|
||||||
|
|
||||||
send_closure(actor_id, &ContactsManager::add_channel_participant, channel_id,
|
|
||||||
participant_dialog_id.get_user_id(), old_status, std::move(promise));
|
|
||||||
}))
|
|
||||||
.release();
|
|
||||||
});
|
|
||||||
|
|
||||||
promise = std::move(on_result_promise);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (participant_dialog_id.get_type() == DialogType::User) {
|
|
||||||
speculative_add_channel_user(channel_id, participant_dialog_id.get_user_id(), new_status, old_status);
|
|
||||||
}
|
|
||||||
td_->create_handler<EditChannelBannedQuery>(std::move(promise))
|
|
||||||
->send(channel_id, participant_dialog_id, std::move(input_peer), new_status);
|
|
||||||
}
|
|
||||||
|
|
||||||
ChannelId ContactsManager::migrate_chat_to_megagroup(ChatId chat_id, Promise<Unit> &promise) {
|
ChannelId ContactsManager::migrate_chat_to_megagroup(ChatId chat_id, Promise<Unit> &promise) {
|
||||||
auto c = get_chat(chat_id);
|
auto c = get_chat(chat_id);
|
||||||
if (c == nullptr) {
|
if (c == nullptr) {
|
||||||
@ -17388,32 +16826,6 @@ std::pair<int32, vector<DialogId>> ContactsManager::search_among_dialogs(const v
|
|||||||
return {narrow_cast<int32>(result.first), transform(result.second, [](int64 key) { return DialogId(key); })};
|
return {narrow_cast<int32>(result.first), transform(result.second, [](int64 key) { return DialogId(key); })};
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContactsManager::leave_dialog(DialogId dialog_id, Promise<Unit> &&promise) {
|
|
||||||
if (!td_->dialog_manager_->have_dialog_force(dialog_id, "leave_dialog")) {
|
|
||||||
return promise.set_error(Status::Error(400, "Chat not found"));
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (dialog_id.get_type()) {
|
|
||||||
case DialogType::User:
|
|
||||||
return promise.set_error(Status::Error(400, "Can't leave private chats"));
|
|
||||||
case DialogType::Chat:
|
|
||||||
return delete_chat_participant(dialog_id.get_chat_id(), get_my_id(), false, std::move(promise));
|
|
||||||
case DialogType::Channel: {
|
|
||||||
auto channel_id = dialog_id.get_channel_id();
|
|
||||||
auto old_status = get_channel_status(channel_id);
|
|
||||||
auto new_status = old_status;
|
|
||||||
new_status.set_is_member(false);
|
|
||||||
return restrict_channel_participant(channel_id, DialogId(get_my_id()), std::move(new_status),
|
|
||||||
std::move(old_status), std::move(promise));
|
|
||||||
}
|
|
||||||
case DialogType::SecretChat:
|
|
||||||
return promise.set_error(Status::Error(400, "Can't leave secret chats"));
|
|
||||||
case DialogType::None:
|
|
||||||
default:
|
|
||||||
UNREACHABLE();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DialogParticipants ContactsManager::search_private_chat_participants(UserId my_user_id, UserId peer_user_id,
|
DialogParticipants ContactsManager::search_private_chat_participants(UserId my_user_id, UserId peer_user_id,
|
||||||
const string &query, int32 limit,
|
const string &query, int32 limit,
|
||||||
DialogParticipantFilter filter) const {
|
DialogParticipantFilter filter) const {
|
||||||
|
@ -649,24 +649,16 @@ class ContactsManager final : public Actor {
|
|||||||
|
|
||||||
void add_chat_participant(ChatId chat_id, UserId user_id, int32 forward_limit, Promise<Unit> &&promise);
|
void add_chat_participant(ChatId chat_id, UserId user_id, int32 forward_limit, Promise<Unit> &&promise);
|
||||||
|
|
||||||
void add_channel_participant(ChannelId channel_id, UserId user_id, const DialogParticipantStatus &old_status,
|
|
||||||
Promise<Unit> &&promise);
|
|
||||||
|
|
||||||
void add_channel_participants(ChannelId channel_id, const vector<UserId> &user_ids, Promise<Unit> &&promise);
|
|
||||||
|
|
||||||
void set_chat_participant_status(ChatId chat_id, UserId user_id, DialogParticipantStatus status,
|
void set_chat_participant_status(ChatId chat_id, UserId user_id, DialogParticipantStatus status,
|
||||||
Promise<Unit> &&promise);
|
Promise<Unit> &&promise);
|
||||||
|
|
||||||
void set_channel_participant_status(ChannelId channel_id, DialogId participant_dialog_id,
|
|
||||||
td_api::object_ptr<td_api::ChatMemberStatus> &&chat_member_status,
|
|
||||||
Promise<Unit> &&promise);
|
|
||||||
|
|
||||||
void delete_chat_participant(ChatId chat_id, UserId user_id, bool revoke_messages, Promise<Unit> &&promise);
|
void delete_chat_participant(ChatId chat_id, UserId user_id, bool revoke_messages, Promise<Unit> &&promise);
|
||||||
|
|
||||||
void leave_dialog(DialogId dialog_id, Promise<Unit> &&promise);
|
|
||||||
|
|
||||||
void get_chat_participant(ChatId chat_id, UserId user_id, Promise<DialogParticipant> &&promise);
|
void get_chat_participant(ChatId chat_id, UserId user_id, Promise<DialogParticipant> &&promise);
|
||||||
|
|
||||||
|
void speculative_add_channel_user(ChannelId channel_id, UserId user_id, const DialogParticipantStatus &new_status,
|
||||||
|
const DialogParticipantStatus &old_status);
|
||||||
|
|
||||||
void search_dialog_participants(DialogId dialog_id, const string &query, int32 limit, DialogParticipantFilter filter,
|
void search_dialog_participants(DialogId dialog_id, const string &query, int32 limit, DialogParticipantFilter filter,
|
||||||
Promise<DialogParticipants> &&promise);
|
Promise<DialogParticipants> &&promise);
|
||||||
|
|
||||||
@ -1532,9 +1524,6 @@ class ContactsManager final : public Actor {
|
|||||||
|
|
||||||
void speculative_add_channel_participant_count(ChannelId channel_id, int32 delta_participant_count, bool by_me);
|
void speculative_add_channel_participant_count(ChannelId channel_id, int32 delta_participant_count, bool by_me);
|
||||||
|
|
||||||
void speculative_add_channel_user(ChannelId channel_id, UserId user_id, const DialogParticipantStatus &new_status,
|
|
||||||
const DialogParticipantStatus &old_status);
|
|
||||||
|
|
||||||
void drop_chat_full(ChatId chat_id);
|
void drop_chat_full(ChatId chat_id);
|
||||||
|
|
||||||
void do_invalidate_channel_full(ChannelFull *channel_full, ChannelId channel_id, bool need_drop_slow_mode_delay);
|
void do_invalidate_channel_full(ChannelFull *channel_full, ChannelId channel_id, bool need_drop_slow_mode_delay);
|
||||||
@ -1816,17 +1805,6 @@ class ContactsManager final : public Actor {
|
|||||||
tl_object_ptr<telegram_api::channels_channelParticipants> &&channel_participants,
|
tl_object_ptr<telegram_api::channels_channelParticipants> &&channel_participants,
|
||||||
Promise<DialogParticipants> &&promise);
|
Promise<DialogParticipants> &&promise);
|
||||||
|
|
||||||
void set_channel_participant_status_impl(ChannelId channel_id, DialogId participant_dialog_id,
|
|
||||||
DialogParticipantStatus new_status, DialogParticipantStatus old_status,
|
|
||||||
Promise<Unit> &&promise);
|
|
||||||
|
|
||||||
void promote_channel_participant(ChannelId channel_id, UserId user_id, const DialogParticipantStatus &new_status,
|
|
||||||
const DialogParticipantStatus &old_status, Promise<Unit> &&promise);
|
|
||||||
|
|
||||||
void restrict_channel_participant(ChannelId channel_id, DialogId participant_dialog_id,
|
|
||||||
DialogParticipantStatus &&new_status, DialogParticipantStatus &&old_status,
|
|
||||||
Promise<Unit> &&promise);
|
|
||||||
|
|
||||||
void transfer_channel_ownership(ChannelId channel_id, UserId user_id,
|
void transfer_channel_ownership(ChannelId channel_id, UserId user_id,
|
||||||
tl_object_ptr<telegram_api::InputCheckPasswordSRP> input_check_password,
|
tl_object_ptr<telegram_api::InputCheckPasswordSRP> input_check_password,
|
||||||
Promise<Unit> &&promise);
|
Promise<Unit> &&promise);
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
#include "td/telegram/DialogFilter.hpp"
|
#include "td/telegram/DialogFilter.hpp"
|
||||||
#include "td/telegram/DialogFilterInviteLink.h"
|
#include "td/telegram/DialogFilterInviteLink.h"
|
||||||
#include "td/telegram/DialogManager.h"
|
#include "td/telegram/DialogManager.h"
|
||||||
|
#include "td/telegram/DialogParticipantManager.h"
|
||||||
#include "td/telegram/Global.h"
|
#include "td/telegram/Global.h"
|
||||||
#include "td/telegram/LinkManager.h"
|
#include "td/telegram/LinkManager.h"
|
||||||
#include "td/telegram/logevent/LogEvent.h"
|
#include "td/telegram/logevent/LogEvent.h"
|
||||||
@ -1625,7 +1626,7 @@ void DialogFilterManager::delete_dialog_filter(DialogFilterId dialog_filter_id,
|
|||||||
auto lock = mpas.get_promise();
|
auto lock = mpas.get_promise();
|
||||||
|
|
||||||
for (auto &leave_dialog_id : leave_dialog_ids) {
|
for (auto &leave_dialog_id : leave_dialog_ids) {
|
||||||
td_->contacts_manager_->leave_dialog(leave_dialog_id, mpas.get_promise());
|
td_->dialog_participant_manager_->leave_dialog(leave_dialog_id, mpas.get_promise());
|
||||||
}
|
}
|
||||||
|
|
||||||
lock.set_value(Unit());
|
lock.set_value(Unit());
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
#include "td/db/SqliteKeyValueAsync.h"
|
#include "td/db/SqliteKeyValueAsync.h"
|
||||||
|
|
||||||
#include "td/actor/MultiPromise.h"
|
#include "td/actor/MultiPromise.h"
|
||||||
|
#include "td/actor/SleepActor.h"
|
||||||
|
|
||||||
#include "td/utils/algorithm.h"
|
#include "td/utils/algorithm.h"
|
||||||
#include "td/utils/buffer.h"
|
#include "td/utils/buffer.h"
|
||||||
@ -365,6 +366,219 @@ class GetChannelParticipantQuery final : public Td::ResultHandler {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class JoinChannelQuery final : public Td::ResultHandler {
|
||||||
|
Promise<Unit> promise_;
|
||||||
|
ChannelId channel_id_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit JoinChannelQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void send(ChannelId channel_id) {
|
||||||
|
channel_id_ = channel_id;
|
||||||
|
auto input_channel = td_->contacts_manager_->get_input_channel(channel_id);
|
||||||
|
CHECK(input_channel != nullptr);
|
||||||
|
send_query(
|
||||||
|
G()->net_query_creator().create(telegram_api::channels_joinChannel(std::move(input_channel)), {{channel_id}}));
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_result(BufferSlice packet) final {
|
||||||
|
auto result_ptr = fetch_result<telegram_api::channels_joinChannel>(packet);
|
||||||
|
if (result_ptr.is_error()) {
|
||||||
|
return on_error(result_ptr.move_as_error());
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ptr = result_ptr.move_as_ok();
|
||||||
|
LOG(INFO) << "Receive result for JoinChannelQuery: " << to_string(ptr);
|
||||||
|
td_->updates_manager_->on_get_updates(std::move(ptr), std::move(promise_));
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_error(Status status) final {
|
||||||
|
td_->contacts_manager_->on_get_channel_error(channel_id_, status, "JoinChannelQuery");
|
||||||
|
promise_.set_error(std::move(status));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class InviteToChannelQuery final : public Td::ResultHandler {
|
||||||
|
Promise<Unit> promise_;
|
||||||
|
ChannelId channel_id_;
|
||||||
|
vector<UserId> user_ids_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit InviteToChannelQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void send(ChannelId channel_id, vector<UserId> user_ids,
|
||||||
|
vector<tl_object_ptr<telegram_api::InputUser>> &&input_users) {
|
||||||
|
channel_id_ = channel_id;
|
||||||
|
user_ids_ = std::move(user_ids);
|
||||||
|
auto input_channel = td_->contacts_manager_->get_input_channel(channel_id);
|
||||||
|
CHECK(input_channel != nullptr);
|
||||||
|
send_query(G()->net_query_creator().create(
|
||||||
|
telegram_api::channels_inviteToChannel(std::move(input_channel), std::move(input_users))));
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_result(BufferSlice packet) final {
|
||||||
|
auto result_ptr = fetch_result<telegram_api::channels_inviteToChannel>(packet);
|
||||||
|
if (result_ptr.is_error()) {
|
||||||
|
return on_error(result_ptr.move_as_error());
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ptr = result_ptr.move_as_ok();
|
||||||
|
LOG(INFO) << "Receive result for InviteToChannelQuery: " << to_string(ptr);
|
||||||
|
td_->contacts_manager_->invalidate_channel_full(channel_id_, false, "InviteToChannelQuery");
|
||||||
|
auto user_ids = td_->updates_manager_->extract_group_invite_privacy_forbidden_updates(ptr);
|
||||||
|
auto promise = PromiseCreator::lambda([dialog_id = DialogId(channel_id_), user_ids = std::move(user_ids),
|
||||||
|
promise = std::move(promise_)](Result<Unit> &&result) mutable {
|
||||||
|
if (result.is_error()) {
|
||||||
|
return promise.set_error(result.move_as_error());
|
||||||
|
}
|
||||||
|
promise.set_value(Unit());
|
||||||
|
if (!user_ids.empty()) {
|
||||||
|
send_closure(G()->contacts_manager(), &ContactsManager::send_update_add_chat_members_privacy_forbidden,
|
||||||
|
dialog_id, std::move(user_ids), "InviteToChannelQuery");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
td_->updates_manager_->on_get_updates(std::move(ptr), std::move(promise));
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_error(Status status) final {
|
||||||
|
if (!td_->auth_manager_->is_bot() && status.message() == "USER_PRIVACY_RESTRICTED") {
|
||||||
|
td_->contacts_manager_->send_update_add_chat_members_privacy_forbidden(
|
||||||
|
DialogId(channel_id_), std::move(user_ids_), "InviteToChannelQuery");
|
||||||
|
return promise_.set_error(Status::Error(406, "USER_PRIVACY_RESTRICTED"));
|
||||||
|
}
|
||||||
|
td_->contacts_manager_->on_get_channel_error(channel_id_, status, "InviteToChannelQuery");
|
||||||
|
td_->contacts_manager_->invalidate_channel_full(channel_id_, false, "InviteToChannelQuery");
|
||||||
|
promise_.set_error(std::move(status));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class EditChannelAdminQuery final : public Td::ResultHandler {
|
||||||
|
Promise<Unit> promise_;
|
||||||
|
ChannelId channel_id_;
|
||||||
|
UserId user_id_;
|
||||||
|
DialogParticipantStatus status_ = DialogParticipantStatus::Left();
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit EditChannelAdminQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void send(ChannelId channel_id, UserId user_id, tl_object_ptr<telegram_api::InputUser> &&input_user,
|
||||||
|
const DialogParticipantStatus &status) {
|
||||||
|
channel_id_ = channel_id;
|
||||||
|
user_id_ = user_id;
|
||||||
|
status_ = status;
|
||||||
|
auto input_channel = td_->contacts_manager_->get_input_channel(channel_id);
|
||||||
|
CHECK(input_channel != nullptr);
|
||||||
|
send_query(G()->net_query_creator().create(telegram_api::channels_editAdmin(
|
||||||
|
std::move(input_channel), std::move(input_user), status.get_chat_admin_rights(), status.get_rank())));
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_result(BufferSlice packet) final {
|
||||||
|
auto result_ptr = fetch_result<telegram_api::channels_editAdmin>(packet);
|
||||||
|
if (result_ptr.is_error()) {
|
||||||
|
return on_error(result_ptr.move_as_error());
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ptr = result_ptr.move_as_ok();
|
||||||
|
LOG(INFO) << "Receive result for EditChannelAdminQuery: " << to_string(ptr);
|
||||||
|
td_->contacts_manager_->invalidate_channel_full(channel_id_, false, "EditChannelAdminQuery");
|
||||||
|
td_->updates_manager_->on_get_updates(std::move(ptr), std::move(promise_));
|
||||||
|
td_->dialog_participant_manager_->on_set_channel_participant_status(channel_id_, DialogId(user_id_), status_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_error(Status status) final {
|
||||||
|
if (!td_->auth_manager_->is_bot() && status.message() == "USER_PRIVACY_RESTRICTED") {
|
||||||
|
td_->contacts_manager_->send_update_add_chat_members_privacy_forbidden(DialogId(channel_id_), {user_id_},
|
||||||
|
"EditChannelAdminQuery");
|
||||||
|
return promise_.set_error(Status::Error(406, "USER_PRIVACY_RESTRICTED"));
|
||||||
|
}
|
||||||
|
td_->contacts_manager_->on_get_channel_error(channel_id_, status, "EditChannelAdminQuery");
|
||||||
|
td_->contacts_manager_->invalidate_channel_full(channel_id_, false, "EditChannelAdminQuery");
|
||||||
|
promise_.set_error(std::move(status));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class EditChannelBannedQuery final : public Td::ResultHandler {
|
||||||
|
Promise<Unit> promise_;
|
||||||
|
ChannelId channel_id_;
|
||||||
|
DialogId participant_dialog_id_;
|
||||||
|
DialogParticipantStatus status_ = DialogParticipantStatus::Left();
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit EditChannelBannedQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void send(ChannelId channel_id, DialogId participant_dialog_id, tl_object_ptr<telegram_api::InputPeer> &&input_peer,
|
||||||
|
const DialogParticipantStatus &status) {
|
||||||
|
channel_id_ = channel_id;
|
||||||
|
participant_dialog_id_ = participant_dialog_id;
|
||||||
|
status_ = status;
|
||||||
|
auto input_channel = td_->contacts_manager_->get_input_channel(channel_id);
|
||||||
|
CHECK(input_channel != nullptr);
|
||||||
|
send_query(G()->net_query_creator().create(telegram_api::channels_editBanned(
|
||||||
|
std::move(input_channel), std::move(input_peer), status.get_chat_banned_rights())));
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_result(BufferSlice packet) final {
|
||||||
|
auto result_ptr = fetch_result<telegram_api::channels_editBanned>(packet);
|
||||||
|
if (result_ptr.is_error()) {
|
||||||
|
return on_error(result_ptr.move_as_error());
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ptr = result_ptr.move_as_ok();
|
||||||
|
LOG(INFO) << "Receive result for EditChannelBannedQuery: " << to_string(ptr);
|
||||||
|
td_->contacts_manager_->invalidate_channel_full(channel_id_, false, "EditChannelBannedQuery");
|
||||||
|
td_->updates_manager_->on_get_updates(std::move(ptr), std::move(promise_));
|
||||||
|
td_->dialog_participant_manager_->on_set_channel_participant_status(channel_id_, participant_dialog_id_, status_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_error(Status status) final {
|
||||||
|
if (participant_dialog_id_.get_type() != DialogType::Channel) {
|
||||||
|
td_->contacts_manager_->on_get_channel_error(channel_id_, status, "EditChannelBannedQuery");
|
||||||
|
}
|
||||||
|
td_->contacts_manager_->invalidate_channel_full(channel_id_, false, "EditChannelBannedQuery");
|
||||||
|
promise_.set_error(std::move(status));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class LeaveChannelQuery final : public Td::ResultHandler {
|
||||||
|
Promise<Unit> promise_;
|
||||||
|
ChannelId channel_id_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit LeaveChannelQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void send(ChannelId channel_id) {
|
||||||
|
channel_id_ = channel_id;
|
||||||
|
auto input_channel = td_->contacts_manager_->get_input_channel(channel_id);
|
||||||
|
CHECK(input_channel != nullptr);
|
||||||
|
send_query(
|
||||||
|
G()->net_query_creator().create(telegram_api::channels_leaveChannel(std::move(input_channel)), {{channel_id}}));
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_result(BufferSlice packet) final {
|
||||||
|
auto result_ptr = fetch_result<telegram_api::channels_leaveChannel>(packet);
|
||||||
|
if (result_ptr.is_error()) {
|
||||||
|
return on_error(result_ptr.move_as_error());
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ptr = result_ptr.move_as_ok();
|
||||||
|
LOG(INFO) << "Receive result for LeaveChannelQuery: " << to_string(ptr);
|
||||||
|
td_->updates_manager_->on_get_updates(std::move(ptr), std::move(promise_));
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_error(Status status) final {
|
||||||
|
if (status.message() == "USER_NOT_PARTICIPANT") {
|
||||||
|
return td_->contacts_manager_->reload_channel(channel_id_, std::move(promise_), "LeaveChannelQuery");
|
||||||
|
}
|
||||||
|
td_->contacts_manager_->on_get_channel_error(channel_id_, status, "LeaveChannelQuery");
|
||||||
|
promise_.set_error(std::move(status));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
DialogParticipantManager::DialogParticipantManager(Td *td, ActorShared<> parent) : td_(td), parent_(std::move(parent)) {
|
DialogParticipantManager::DialogParticipantManager(Td *td, ActorShared<> parent) : td_(td), parent_(std::move(parent)) {
|
||||||
update_dialog_online_member_count_timeout_.set_callback(on_update_dialog_online_member_count_timeout_callback);
|
update_dialog_online_member_count_timeout_.set_callback(on_update_dialog_online_member_count_timeout_callback);
|
||||||
update_dialog_online_member_count_timeout_.set_callback_data(static_cast<void *>(this));
|
update_dialog_online_member_count_timeout_.set_callback_data(static_cast<void *>(this));
|
||||||
@ -1144,8 +1358,8 @@ void DialogParticipantManager::add_dialog_participant(DialogId dialog_id, UserId
|
|||||||
return td_->contacts_manager_->add_chat_participant(dialog_id.get_chat_id(), user_id, forward_limit,
|
return td_->contacts_manager_->add_chat_participant(dialog_id.get_chat_id(), user_id, forward_limit,
|
||||||
std::move(promise));
|
std::move(promise));
|
||||||
case DialogType::Channel:
|
case DialogType::Channel:
|
||||||
return td_->contacts_manager_->add_channel_participant(dialog_id.get_channel_id(), user_id,
|
return add_channel_participant(dialog_id.get_channel_id(), user_id, DialogParticipantStatus::Left(),
|
||||||
DialogParticipantStatus::Left(), std::move(promise));
|
std::move(promise));
|
||||||
case DialogType::SecretChat:
|
case DialogType::SecretChat:
|
||||||
return promise.set_error(Status::Error(400, "Can't add members to a secret chat"));
|
return promise.set_error(Status::Error(400, "Can't add members to a secret chat"));
|
||||||
case DialogType::None:
|
case DialogType::None:
|
||||||
@ -1170,7 +1384,7 @@ void DialogParticipantManager::add_dialog_participants(DialogId dialog_id, const
|
|||||||
}
|
}
|
||||||
return promise.set_error(Status::Error(400, "Can't add many members at once to a basic group chat"));
|
return promise.set_error(Status::Error(400, "Can't add many members at once to a basic group chat"));
|
||||||
case DialogType::Channel:
|
case DialogType::Channel:
|
||||||
return td_->contacts_manager_->add_channel_participants(dialog_id.get_channel_id(), user_ids, std::move(promise));
|
return add_channel_participants(dialog_id.get_channel_id(), user_ids, std::move(promise));
|
||||||
case DialogType::SecretChat:
|
case DialogType::SecretChat:
|
||||||
return promise.set_error(Status::Error(400, "Can't add members to a secret chat"));
|
return promise.set_error(Status::Error(400, "Can't add members to a secret chat"));
|
||||||
case DialogType::None:
|
case DialogType::None:
|
||||||
@ -1202,8 +1416,8 @@ void DialogParticipantManager::set_dialog_participant_status(
|
|||||||
dialog_id.get_chat_id(), participant_dialog_id.get_user_id(), status, std::move(promise));
|
dialog_id.get_chat_id(), participant_dialog_id.get_user_id(), status, std::move(promise));
|
||||||
}
|
}
|
||||||
case DialogType::Channel:
|
case DialogType::Channel:
|
||||||
return td_->contacts_manager_->set_channel_participant_status(dialog_id.get_channel_id(), participant_dialog_id,
|
return set_channel_participant_status(dialog_id.get_channel_id(), participant_dialog_id,
|
||||||
std::move(chat_member_status), std::move(promise));
|
std::move(chat_member_status), std::move(promise));
|
||||||
case DialogType::SecretChat:
|
case DialogType::SecretChat:
|
||||||
return promise.set_error(Status::Error(400, "Chat member status can't be changed in secret chats"));
|
return promise.set_error(Status::Error(400, "Chat member status can't be changed in secret chats"));
|
||||||
case DialogType::None:
|
case DialogType::None:
|
||||||
@ -1230,9 +1444,9 @@ void DialogParticipantManager::ban_dialog_participant(DialogId dialog_id, Dialog
|
|||||||
dialog_id.get_chat_id(), participant_dialog_id.get_user_id(), revoke_messages, std::move(promise));
|
dialog_id.get_chat_id(), participant_dialog_id.get_user_id(), revoke_messages, std::move(promise));
|
||||||
case DialogType::Channel:
|
case DialogType::Channel:
|
||||||
// must use td_api::chatMemberStatusBanned to properly fix banned_until_date
|
// must use td_api::chatMemberStatusBanned to properly fix banned_until_date
|
||||||
return td_->contacts_manager_->set_channel_participant_status(
|
return set_channel_participant_status(dialog_id.get_channel_id(), participant_dialog_id,
|
||||||
dialog_id.get_channel_id(), participant_dialog_id,
|
td_api::make_object<td_api::chatMemberStatusBanned>(banned_until_date),
|
||||||
td_api::make_object<td_api::chatMemberStatusBanned>(banned_until_date), std::move(promise));
|
std::move(promise));
|
||||||
case DialogType::SecretChat:
|
case DialogType::SecretChat:
|
||||||
return promise.set_error(Status::Error(400, "Can't ban members in secret chats"));
|
return promise.set_error(Status::Error(400, "Can't ban members in secret chats"));
|
||||||
case DialogType::None:
|
case DialogType::None:
|
||||||
@ -1241,6 +1455,390 @@ void DialogParticipantManager::ban_dialog_participant(DialogId dialog_id, Dialog
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DialogParticipantManager::leave_dialog(DialogId dialog_id, Promise<Unit> &&promise) {
|
||||||
|
if (!td_->dialog_manager_->have_dialog_force(dialog_id, "leave_dialog")) {
|
||||||
|
return promise.set_error(Status::Error(400, "Chat not found"));
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (dialog_id.get_type()) {
|
||||||
|
case DialogType::User:
|
||||||
|
return promise.set_error(Status::Error(400, "Can't leave private chats"));
|
||||||
|
case DialogType::Chat:
|
||||||
|
return td_->contacts_manager_->delete_chat_participant(
|
||||||
|
dialog_id.get_chat_id(), td_->contacts_manager_->get_my_id(), false, std::move(promise));
|
||||||
|
case DialogType::Channel: {
|
||||||
|
auto channel_id = dialog_id.get_channel_id();
|
||||||
|
auto old_status = td_->contacts_manager_->get_channel_status(channel_id);
|
||||||
|
auto new_status = old_status;
|
||||||
|
new_status.set_is_member(false);
|
||||||
|
return restrict_channel_participant(channel_id, td_->dialog_manager_->get_my_dialog_id(), std::move(new_status),
|
||||||
|
std::move(old_status), std::move(promise));
|
||||||
|
}
|
||||||
|
case DialogType::SecretChat:
|
||||||
|
return promise.set_error(Status::Error(400, "Can't leave secret chats"));
|
||||||
|
case DialogType::None:
|
||||||
|
default:
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DialogParticipantManager::add_channel_participant(ChannelId channel_id, UserId user_id,
|
||||||
|
const DialogParticipantStatus &old_status,
|
||||||
|
Promise<Unit> &&promise) {
|
||||||
|
if (td_->auth_manager_->is_bot()) {
|
||||||
|
return promise.set_error(Status::Error(400, "Bots can't add new chat members"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!td_->contacts_manager_->have_channel(channel_id)) {
|
||||||
|
return promise.set_error(Status::Error(400, "Chat info not found"));
|
||||||
|
}
|
||||||
|
TRY_RESULT_PROMISE(promise, input_user, td_->contacts_manager_->get_input_user(user_id));
|
||||||
|
|
||||||
|
if (user_id == td_->contacts_manager_->get_my_id()) {
|
||||||
|
// join the channel
|
||||||
|
auto my_status = td_->contacts_manager_->get_channel_status(channel_id);
|
||||||
|
if (my_status.is_banned()) {
|
||||||
|
return promise.set_error(Status::Error(400, "Can't return to kicked from chat"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!td_->contacts_manager_->get_channel_join_request(channel_id)) {
|
||||||
|
td_->contacts_manager_->speculative_add_channel_user(channel_id, user_id, DialogParticipantStatus::Member(),
|
||||||
|
my_status);
|
||||||
|
}
|
||||||
|
td_->create_handler<JoinChannelQuery>(std::move(promise))->send(channel_id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!td_->contacts_manager_->get_channel_permissions(channel_id).can_invite_users()) {
|
||||||
|
return promise.set_error(Status::Error(400, "Not enough rights to invite members to the supergroup chat"));
|
||||||
|
}
|
||||||
|
|
||||||
|
td_->contacts_manager_->speculative_add_channel_user(channel_id, user_id, DialogParticipantStatus::Member(),
|
||||||
|
old_status);
|
||||||
|
vector<tl_object_ptr<telegram_api::InputUser>> input_users;
|
||||||
|
input_users.push_back(std::move(input_user));
|
||||||
|
td_->create_handler<InviteToChannelQuery>(std::move(promise))->send(channel_id, {user_id}, std::move(input_users));
|
||||||
|
}
|
||||||
|
|
||||||
|
void DialogParticipantManager::add_channel_participants(ChannelId channel_id, const vector<UserId> &user_ids,
|
||||||
|
Promise<Unit> &&promise) {
|
||||||
|
if (td_->auth_manager_->is_bot()) {
|
||||||
|
return promise.set_error(Status::Error(400, "Bots can't add new chat members"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!td_->contacts_manager_->have_channel(channel_id)) {
|
||||||
|
return promise.set_error(Status::Error(400, "Chat info not found"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!td_->contacts_manager_->get_channel_permissions(channel_id).can_invite_users()) {
|
||||||
|
return promise.set_error(Status::Error(400, "Not enough rights to invite members to the supergroup chat"));
|
||||||
|
}
|
||||||
|
|
||||||
|
vector<tl_object_ptr<telegram_api::InputUser>> input_users;
|
||||||
|
for (auto user_id : user_ids) {
|
||||||
|
TRY_RESULT_PROMISE(promise, input_user, td_->contacts_manager_->get_input_user(user_id));
|
||||||
|
|
||||||
|
if (user_id == td_->contacts_manager_->get_my_id()) {
|
||||||
|
// can't invite self
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
input_users.push_back(std::move(input_user));
|
||||||
|
|
||||||
|
td_->contacts_manager_->speculative_add_channel_user(channel_id, user_id, DialogParticipantStatus::Member(),
|
||||||
|
DialogParticipantStatus::Left());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (input_users.empty()) {
|
||||||
|
return promise.set_value(Unit());
|
||||||
|
}
|
||||||
|
|
||||||
|
td_->create_handler<InviteToChannelQuery>(std::move(promise))->send(channel_id, user_ids, std::move(input_users));
|
||||||
|
}
|
||||||
|
|
||||||
|
void DialogParticipantManager::set_channel_participant_status(
|
||||||
|
ChannelId channel_id, DialogId participant_dialog_id,
|
||||||
|
td_api::object_ptr<td_api::ChatMemberStatus> &&chat_member_status, Promise<Unit> &&promise) {
|
||||||
|
if (!td_->contacts_manager_->have_channel(channel_id)) {
|
||||||
|
return promise.set_error(Status::Error(400, "Chat info not found"));
|
||||||
|
}
|
||||||
|
auto new_status =
|
||||||
|
get_dialog_participant_status(chat_member_status, td_->contacts_manager_->get_channel_type(channel_id));
|
||||||
|
|
||||||
|
if (participant_dialog_id == td_->dialog_manager_->get_my_dialog_id()) {
|
||||||
|
// fast path is needed, because get_channel_status may return Creator, while GetChannelParticipantQuery returning Left
|
||||||
|
return set_channel_participant_status_impl(channel_id, participant_dialog_id, std::move(new_status),
|
||||||
|
td_->contacts_manager_->get_channel_status(channel_id),
|
||||||
|
std::move(promise));
|
||||||
|
}
|
||||||
|
if (participant_dialog_id.get_type() != DialogType::User) {
|
||||||
|
if (new_status.is_administrator() || new_status.is_member() || new_status.is_restricted()) {
|
||||||
|
return promise.set_error(Status::Error(400, "Other chats can be only banned or unbanned"));
|
||||||
|
}
|
||||||
|
// always pretend that old_status is different
|
||||||
|
return restrict_channel_participant(
|
||||||
|
channel_id, participant_dialog_id, std::move(new_status),
|
||||||
|
new_status.is_banned() ? DialogParticipantStatus::Left() : DialogParticipantStatus::Banned(0),
|
||||||
|
std::move(promise));
|
||||||
|
}
|
||||||
|
|
||||||
|
auto on_result_promise =
|
||||||
|
PromiseCreator::lambda([actor_id = actor_id(this), channel_id, participant_dialog_id, new_status,
|
||||||
|
promise = std::move(promise)](Result<DialogParticipant> r_dialog_participant) mutable {
|
||||||
|
// ResultHandlers are cleared before managers, so it is safe to capture this
|
||||||
|
if (r_dialog_participant.is_error()) {
|
||||||
|
return promise.set_error(r_dialog_participant.move_as_error());
|
||||||
|
}
|
||||||
|
|
||||||
|
send_closure(actor_id, &DialogParticipantManager::set_channel_participant_status_impl, channel_id,
|
||||||
|
participant_dialog_id, std::move(new_status), r_dialog_participant.ok().status_,
|
||||||
|
std::move(promise));
|
||||||
|
});
|
||||||
|
|
||||||
|
td_->dialog_participant_manager_->get_channel_participant(channel_id, participant_dialog_id,
|
||||||
|
std::move(on_result_promise));
|
||||||
|
}
|
||||||
|
|
||||||
|
void DialogParticipantManager::set_channel_participant_status_impl(ChannelId channel_id, DialogId participant_dialog_id,
|
||||||
|
DialogParticipantStatus new_status,
|
||||||
|
DialogParticipantStatus old_status,
|
||||||
|
Promise<Unit> &&promise) {
|
||||||
|
if (old_status == new_status && !old_status.is_creator()) {
|
||||||
|
return promise.set_value(Unit());
|
||||||
|
}
|
||||||
|
CHECK(participant_dialog_id.get_type() == DialogType::User);
|
||||||
|
|
||||||
|
LOG(INFO) << "Change status of " << participant_dialog_id << " in " << channel_id << " from " << old_status << " to "
|
||||||
|
<< new_status;
|
||||||
|
bool need_add = false;
|
||||||
|
bool need_promote = false;
|
||||||
|
bool need_restrict = false;
|
||||||
|
if (new_status.is_creator() || old_status.is_creator()) {
|
||||||
|
if (!old_status.is_creator()) {
|
||||||
|
return promise.set_error(Status::Error(400, "Can't add another owner to the chat"));
|
||||||
|
}
|
||||||
|
if (!new_status.is_creator()) {
|
||||||
|
return promise.set_error(Status::Error(400, "Can't remove chat owner"));
|
||||||
|
}
|
||||||
|
auto user_id = td_->contacts_manager_->get_my_id();
|
||||||
|
if (participant_dialog_id != DialogId(user_id)) {
|
||||||
|
return promise.set_error(Status::Error(400, "Not enough rights to edit chat owner rights"));
|
||||||
|
}
|
||||||
|
if (new_status.is_member() == old_status.is_member()) {
|
||||||
|
// change rank and is_anonymous
|
||||||
|
auto r_input_user = td_->contacts_manager_->get_input_user(user_id);
|
||||||
|
CHECK(r_input_user.is_ok());
|
||||||
|
td_->create_handler<EditChannelAdminQuery>(std::move(promise))
|
||||||
|
->send(channel_id, user_id, r_input_user.move_as_ok(), new_status);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (new_status.is_member()) {
|
||||||
|
// creator not member -> creator member
|
||||||
|
need_add = true;
|
||||||
|
} else {
|
||||||
|
// creator member -> creator not member
|
||||||
|
need_restrict = true;
|
||||||
|
}
|
||||||
|
} else if (new_status.is_administrator()) {
|
||||||
|
need_promote = true;
|
||||||
|
} else if (!new_status.is_member() || new_status.is_restricted()) {
|
||||||
|
if (new_status.is_member() && !old_status.is_member()) {
|
||||||
|
// TODO there is no way in server API to invite someone and change restrictions
|
||||||
|
// we need to first add user and change restrictions again after that
|
||||||
|
// but if restrictions aren't changed, then adding is enough
|
||||||
|
auto copy_old_status = old_status;
|
||||||
|
copy_old_status.set_is_member(true);
|
||||||
|
if (copy_old_status == new_status) {
|
||||||
|
need_add = true;
|
||||||
|
} else {
|
||||||
|
need_restrict = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
need_restrict = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// regular member
|
||||||
|
if (old_status.is_administrator()) {
|
||||||
|
need_promote = true;
|
||||||
|
} else if (old_status.is_restricted() || old_status.is_banned()) {
|
||||||
|
need_restrict = true;
|
||||||
|
} else {
|
||||||
|
CHECK(!old_status.is_member());
|
||||||
|
need_add = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (need_promote) {
|
||||||
|
if (participant_dialog_id.get_type() != DialogType::User) {
|
||||||
|
return promise.set_error(Status::Error(400, "Can't promote chats to chat administrators"));
|
||||||
|
}
|
||||||
|
return promote_channel_participant(channel_id, participant_dialog_id.get_user_id(), new_status, old_status,
|
||||||
|
std::move(promise));
|
||||||
|
} else if (need_restrict) {
|
||||||
|
return restrict_channel_participant(channel_id, participant_dialog_id, std::move(new_status), std::move(old_status),
|
||||||
|
std::move(promise));
|
||||||
|
} else {
|
||||||
|
CHECK(need_add);
|
||||||
|
if (participant_dialog_id.get_type() != DialogType::User) {
|
||||||
|
return promise.set_error(Status::Error(400, "Can't add chats as chat members"));
|
||||||
|
}
|
||||||
|
return add_channel_participant(channel_id, participant_dialog_id.get_user_id(), old_status, std::move(promise));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DialogParticipantManager::promote_channel_participant(ChannelId channel_id, UserId user_id,
|
||||||
|
const DialogParticipantStatus &new_status,
|
||||||
|
const DialogParticipantStatus &old_status,
|
||||||
|
Promise<Unit> &&promise) {
|
||||||
|
LOG(INFO) << "Promote " << user_id << " in " << channel_id << " from " << old_status << " to " << new_status;
|
||||||
|
if (user_id == td_->contacts_manager_->get_my_id()) {
|
||||||
|
if (new_status.is_administrator()) {
|
||||||
|
return promise.set_error(Status::Error(400, "Can't promote self"));
|
||||||
|
}
|
||||||
|
CHECK(new_status.is_member());
|
||||||
|
// allow to demote self. TODO is it allowed server-side?
|
||||||
|
} else {
|
||||||
|
if (!td_->contacts_manager_->get_channel_permissions(channel_id).can_promote_members()) {
|
||||||
|
return promise.set_error(Status::Error(400, "Not enough rights"));
|
||||||
|
}
|
||||||
|
|
||||||
|
CHECK(!old_status.is_creator());
|
||||||
|
CHECK(!new_status.is_creator());
|
||||||
|
}
|
||||||
|
|
||||||
|
TRY_RESULT_PROMISE(promise, input_user, td_->contacts_manager_->get_input_user(user_id));
|
||||||
|
|
||||||
|
td_->contacts_manager_->speculative_add_channel_user(channel_id, user_id, new_status, old_status);
|
||||||
|
td_->create_handler<EditChannelAdminQuery>(std::move(promise))
|
||||||
|
->send(channel_id, user_id, std::move(input_user), new_status);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DialogParticipantManager::restrict_channel_participant(ChannelId channel_id, DialogId participant_dialog_id,
|
||||||
|
DialogParticipantStatus &&new_status,
|
||||||
|
DialogParticipantStatus &&old_status,
|
||||||
|
Promise<Unit> &&promise) {
|
||||||
|
TRY_STATUS_PROMISE(promise, G()->close_status());
|
||||||
|
|
||||||
|
LOG(INFO) << "Restrict " << participant_dialog_id << " in " << channel_id << " from " << old_status << " to "
|
||||||
|
<< new_status;
|
||||||
|
if (!td_->contacts_manager_->have_channel(channel_id)) {
|
||||||
|
return promise.set_error(Status::Error(400, "Chat info not found"));
|
||||||
|
}
|
||||||
|
auto my_status = td_->contacts_manager_->get_channel_status(channel_id);
|
||||||
|
if (!my_status.is_member() && !my_status.is_creator()) {
|
||||||
|
if (participant_dialog_id == td_->dialog_manager_->get_my_dialog_id()) {
|
||||||
|
if (new_status.is_member()) {
|
||||||
|
return promise.set_error(Status::Error(400, "Can't unrestrict self"));
|
||||||
|
}
|
||||||
|
return promise.set_value(Unit());
|
||||||
|
} else {
|
||||||
|
return promise.set_error(Status::Error(400, "Not in the chat"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
auto input_peer = td_->dialog_manager_->get_input_peer(participant_dialog_id, AccessRights::Know);
|
||||||
|
if (input_peer == nullptr) {
|
||||||
|
return promise.set_error(Status::Error(400, "Member not found"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (participant_dialog_id == td_->dialog_manager_->get_my_dialog_id()) {
|
||||||
|
if (new_status.is_restricted() || new_status.is_banned()) {
|
||||||
|
return promise.set_error(Status::Error(400, "Can't restrict self"));
|
||||||
|
}
|
||||||
|
if (new_status.is_member()) {
|
||||||
|
return promise.set_error(Status::Error(400, "Can't unrestrict self"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// leave the channel
|
||||||
|
td_->contacts_manager_->speculative_add_channel_user(channel_id, participant_dialog_id.get_user_id(), new_status,
|
||||||
|
my_status);
|
||||||
|
td_->create_handler<LeaveChannelQuery>(std::move(promise))->send(channel_id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (participant_dialog_id.get_type()) {
|
||||||
|
case DialogType::User:
|
||||||
|
// ok;
|
||||||
|
break;
|
||||||
|
case DialogType::Channel:
|
||||||
|
if (new_status.is_administrator() || new_status.is_member() || new_status.is_restricted()) {
|
||||||
|
return promise.set_error(Status::Error(400, "Other chats can be only banned or unbanned"));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return promise.set_error(Status::Error(400, "Can't restrict the chat"));
|
||||||
|
}
|
||||||
|
|
||||||
|
CHECK(!old_status.is_creator());
|
||||||
|
CHECK(!new_status.is_creator());
|
||||||
|
|
||||||
|
if (!td_->contacts_manager_->get_channel_permissions(channel_id).can_restrict_members()) {
|
||||||
|
return promise.set_error(Status::Error(400, "Not enough rights to restrict/unrestrict chat member"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (old_status.is_member() && !new_status.is_member() && !new_status.is_banned()) {
|
||||||
|
// we can't make participant Left without kicking it first
|
||||||
|
auto on_result_promise = PromiseCreator::lambda([actor_id = actor_id(this), channel_id, participant_dialog_id,
|
||||||
|
new_status = std::move(new_status),
|
||||||
|
promise = std::move(promise)](Result<> result) mutable {
|
||||||
|
if (result.is_error()) {
|
||||||
|
return promise.set_error(result.move_as_error());
|
||||||
|
}
|
||||||
|
|
||||||
|
create_actor<SleepActor>(
|
||||||
|
"RestrictChannelParticipantSleepActor", 1.0,
|
||||||
|
PromiseCreator::lambda([actor_id, channel_id, participant_dialog_id, new_status = std::move(new_status),
|
||||||
|
promise = std::move(promise)](Result<> result) mutable {
|
||||||
|
if (result.is_error()) {
|
||||||
|
return promise.set_error(result.move_as_error());
|
||||||
|
}
|
||||||
|
|
||||||
|
send_closure(actor_id, &DialogParticipantManager::restrict_channel_participant, channel_id,
|
||||||
|
participant_dialog_id, std::move(new_status), DialogParticipantStatus::Banned(0),
|
||||||
|
std::move(promise));
|
||||||
|
}))
|
||||||
|
.release();
|
||||||
|
});
|
||||||
|
|
||||||
|
promise = std::move(on_result_promise);
|
||||||
|
new_status = DialogParticipantStatus::Banned(G()->unix_time() + 60);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (new_status.is_member() && !old_status.is_member()) {
|
||||||
|
// there is no way in server API to invite someone and change restrictions
|
||||||
|
// we need to first change restrictions and then try to add the user
|
||||||
|
CHECK(participant_dialog_id.get_type() == DialogType::User);
|
||||||
|
new_status.set_is_member(false);
|
||||||
|
auto on_result_promise =
|
||||||
|
PromiseCreator::lambda([actor_id = actor_id(this), channel_id, participant_dialog_id, old_status = new_status,
|
||||||
|
promise = std::move(promise)](Result<> result) mutable {
|
||||||
|
if (result.is_error()) {
|
||||||
|
return promise.set_error(result.move_as_error());
|
||||||
|
}
|
||||||
|
|
||||||
|
create_actor<SleepActor>(
|
||||||
|
"AddChannelParticipantSleepActor", 1.0,
|
||||||
|
PromiseCreator::lambda([actor_id, channel_id, participant_dialog_id, old_status = std::move(old_status),
|
||||||
|
promise = std::move(promise)](Result<> result) mutable {
|
||||||
|
if (result.is_error()) {
|
||||||
|
return promise.set_error(result.move_as_error());
|
||||||
|
}
|
||||||
|
|
||||||
|
send_closure(actor_id, &DialogParticipantManager::add_channel_participant, channel_id,
|
||||||
|
participant_dialog_id.get_user_id(), old_status, std::move(promise));
|
||||||
|
}))
|
||||||
|
.release();
|
||||||
|
});
|
||||||
|
|
||||||
|
promise = std::move(on_result_promise);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (participant_dialog_id.get_type() == DialogType::User) {
|
||||||
|
td_->contacts_manager_->speculative_add_channel_user(channel_id, participant_dialog_id.get_user_id(), new_status,
|
||||||
|
old_status);
|
||||||
|
}
|
||||||
|
td_->create_handler<EditChannelBannedQuery>(std::move(promise))
|
||||||
|
->send(channel_id, participant_dialog_id, std::move(input_peer), new_status);
|
||||||
|
}
|
||||||
|
|
||||||
void DialogParticipantManager::on_set_channel_participant_status(ChannelId channel_id, DialogId participant_dialog_id,
|
void DialogParticipantManager::on_set_channel_participant_status(ChannelId channel_id, DialogId participant_dialog_id,
|
||||||
DialogParticipantStatus status) {
|
DialogParticipantStatus status) {
|
||||||
if (G()->close_flag() || participant_dialog_id == td_->dialog_manager_->get_my_dialog_id()) {
|
if (G()->close_flag() || participant_dialog_id == td_->dialog_manager_->get_my_dialog_id()) {
|
||||||
|
@ -96,6 +96,8 @@ class DialogParticipantManager final : public Actor {
|
|||||||
void ban_dialog_participant(DialogId dialog_id, DialogId participant_dialog_id, int32 banned_until_date,
|
void ban_dialog_participant(DialogId dialog_id, DialogId participant_dialog_id, int32 banned_until_date,
|
||||||
bool revoke_messages, Promise<Unit> &&promise);
|
bool revoke_messages, Promise<Unit> &&promise);
|
||||||
|
|
||||||
|
void leave_dialog(DialogId dialog_id, Promise<Unit> &&promise);
|
||||||
|
|
||||||
void on_set_channel_participant_status(ChannelId channel_id, DialogId participant_dialog_id,
|
void on_set_channel_participant_status(ChannelId channel_id, DialogId participant_dialog_id,
|
||||||
DialogParticipantStatus status);
|
DialogParticipantStatus status);
|
||||||
|
|
||||||
@ -156,6 +158,26 @@ class DialogParticipantManager final : public Actor {
|
|||||||
void finish_get_channel_participant(ChannelId channel_id, DialogParticipant &&dialog_participant,
|
void finish_get_channel_participant(ChannelId channel_id, DialogParticipant &&dialog_participant,
|
||||||
Promise<DialogParticipant> &&promise);
|
Promise<DialogParticipant> &&promise);
|
||||||
|
|
||||||
|
void add_channel_participant(ChannelId channel_id, UserId user_id, const DialogParticipantStatus &old_status,
|
||||||
|
Promise<Unit> &&promise);
|
||||||
|
|
||||||
|
void add_channel_participants(ChannelId channel_id, const vector<UserId> &user_ids, Promise<Unit> &&promise);
|
||||||
|
|
||||||
|
void set_channel_participant_status(ChannelId channel_id, DialogId participant_dialog_id,
|
||||||
|
td_api::object_ptr<td_api::ChatMemberStatus> &&chat_member_status,
|
||||||
|
Promise<Unit> &&promise);
|
||||||
|
|
||||||
|
void set_channel_participant_status_impl(ChannelId channel_id, DialogId participant_dialog_id,
|
||||||
|
DialogParticipantStatus new_status, DialogParticipantStatus old_status,
|
||||||
|
Promise<Unit> &&promise);
|
||||||
|
|
||||||
|
void promote_channel_participant(ChannelId channel_id, UserId user_id, const DialogParticipantStatus &new_status,
|
||||||
|
const DialogParticipantStatus &old_status, Promise<Unit> &&promise);
|
||||||
|
|
||||||
|
void restrict_channel_participant(ChannelId channel_id, DialogId participant_dialog_id,
|
||||||
|
DialogParticipantStatus &&new_status, DialogParticipantStatus &&old_status,
|
||||||
|
Promise<Unit> &&promise);
|
||||||
|
|
||||||
void update_channel_participant_status_cache(ChannelId channel_id, DialogId participant_dialog_id,
|
void update_channel_participant_status_cache(ChannelId channel_id, DialogId participant_dialog_id,
|
||||||
DialogParticipantStatus &&dialog_participant_status);
|
DialogParticipantStatus &&dialog_participant_status);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user