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 {
|
||||
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);
|
||||
}
|
||||
|
||||
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,
|
||||
Promise<Unit> &&promise) {
|
||||
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);
|
||||
}
|
||||
|
||||
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) {
|
||||
auto c = get_chat(chat_id);
|
||||
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); })};
|
||||
}
|
||||
|
||||
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,
|
||||
const string &query, int32 limit,
|
||||
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_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,
|
||||
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 leave_dialog(DialogId dialog_id, Promise<Unit> &&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,
|
||||
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_user(ChannelId channel_id, UserId user_id, const DialogParticipantStatus &new_status,
|
||||
const DialogParticipantStatus &old_status);
|
||||
|
||||
void drop_chat_full(ChatId chat_id);
|
||||
|
||||
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,
|
||||
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,
|
||||
tl_object_ptr<telegram_api::InputCheckPasswordSRP> input_check_password,
|
||||
Promise<Unit> &&promise);
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "td/telegram/DialogFilter.hpp"
|
||||
#include "td/telegram/DialogFilterInviteLink.h"
|
||||
#include "td/telegram/DialogManager.h"
|
||||
#include "td/telegram/DialogParticipantManager.h"
|
||||
#include "td/telegram/Global.h"
|
||||
#include "td/telegram/LinkManager.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();
|
||||
|
||||
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());
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "td/db/SqliteKeyValueAsync.h"
|
||||
|
||||
#include "td/actor/MultiPromise.h"
|
||||
#include "td/actor/SleepActor.h"
|
||||
|
||||
#include "td/utils/algorithm.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)) {
|
||||
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));
|
||||
@ -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,
|
||||
std::move(promise));
|
||||
case DialogType::Channel:
|
||||
return td_->contacts_manager_->add_channel_participant(dialog_id.get_channel_id(), user_id,
|
||||
DialogParticipantStatus::Left(), std::move(promise));
|
||||
return add_channel_participant(dialog_id.get_channel_id(), user_id, DialogParticipantStatus::Left(),
|
||||
std::move(promise));
|
||||
case DialogType::SecretChat:
|
||||
return promise.set_error(Status::Error(400, "Can't add members to a secret chat"));
|
||||
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"));
|
||||
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:
|
||||
return promise.set_error(Status::Error(400, "Can't add members to a secret chat"));
|
||||
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));
|
||||
}
|
||||
case DialogType::Channel:
|
||||
return td_->contacts_manager_->set_channel_participant_status(dialog_id.get_channel_id(), participant_dialog_id,
|
||||
std::move(chat_member_status), std::move(promise));
|
||||
return set_channel_participant_status(dialog_id.get_channel_id(), participant_dialog_id,
|
||||
std::move(chat_member_status), std::move(promise));
|
||||
case DialogType::SecretChat:
|
||||
return promise.set_error(Status::Error(400, "Chat member status can't be changed in secret chats"));
|
||||
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));
|
||||
case DialogType::Channel:
|
||||
// must use td_api::chatMemberStatusBanned to properly fix banned_until_date
|
||||
return td_->contacts_manager_->set_channel_participant_status(
|
||||
dialog_id.get_channel_id(), participant_dialog_id,
|
||||
td_api::make_object<td_api::chatMemberStatusBanned>(banned_until_date), std::move(promise));
|
||||
return set_channel_participant_status(dialog_id.get_channel_id(), participant_dialog_id,
|
||||
td_api::make_object<td_api::chatMemberStatusBanned>(banned_until_date),
|
||||
std::move(promise));
|
||||
case DialogType::SecretChat:
|
||||
return promise.set_error(Status::Error(400, "Can't ban members in secret chats"));
|
||||
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,
|
||||
DialogParticipantStatus status) {
|
||||
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,
|
||||
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,
|
||||
DialogParticipantStatus status);
|
||||
|
||||
@ -156,6 +158,26 @@ class DialogParticipantManager final : public Actor {
|
||||
void finish_get_channel_participant(ChannelId channel_id, DialogParticipant &&dialog_participant,
|
||||
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,
|
||||
DialogParticipantStatus &&dialog_participant_status);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user