diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index 496db060f..08ef09e9a 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -545,6 +545,25 @@ supergroupMembersFilterMention query:string message_thread_id:int53 = Supergroup supergroupMembersFilterBots = SupergroupMembersFilter; +//@description Contains a chat invite link @invite_link Chat invite link @administrator_user_id User identifier of an administrator created the link +//@date Point in time (Unix timestamp) when the link was created @expire_date Point in time (Unix timestamp) when the link will expire; 0 if never +//@usage_limit Maximum number of times the link can be used; 0 if not limited @usage_count Number of times the link has already been used +//@is_permanent True, if the link is permanent. Permanent invite link can't have expire date or usage limit. There is exactly one permanent invite link for each administrator at any time +//@is_expired True, if the link is already expired @is_revoked True, if the link was revoked +chatInviteLink invite_link:string administrator_user_id:int32 date:int32 expire_date:int32 usage_limit:int32 usage_count:int32 is_permanent:Bool is_expired:Bool is_revoked:Bool = ChatInviteLink; + +//@description Contains information about a chat invite link +//@chat_id Chat identifier of the invite link; 0 if the user has no access to the chat before joining +//@accessible_for If non-zero, the amount of time for which read access to the chat will remain available, in seconds +//@type Contains information about the type of the chat +//@title Title of the chat +//@photo Chat photo; may be null +//@member_count Number of members in the chat +//@member_user_ids User identifiers of some chat members that may be known to the current user +//@is_public True, if the chat is a public supergroup or channel, i.e. it has a username or it is a location-based supergroup +chatInviteLinkInfo chat_id:int53 accessible_for:int32 type:ChatType title:string photo:chatPhotoInfo member_count:int32 member_user_ids:vector is_public:Bool = ChatInviteLinkInfo; + + //@description Represents a basic group of 0-200 users (must be upgraded to a supergroup to accommodate more than 200 users) //@id Group identifier //@member_count Number of members in the group @@ -558,8 +577,8 @@ basicGroup id:int32 member_count:int32 status:ChatMemberStatus is_active:Bool up //@param_description Group description //@creator_user_id User identifier of the creator of the group; 0 if unknown //@members Group members -//@invite_link Invite link for this group; available only after it has been generated at least once and only for the group creator -basicGroupFullInfo photo:chatPhoto description:string creator_user_id:int32 members:vector invite_link:string = BasicGroupFullInfo; +//@invite_link Permanent invite link for this group; only for the group creator +basicGroupFullInfo photo:chatPhoto description:string creator_user_id:int32 members:vector invite_link:chatInviteLink = BasicGroupFullInfo; //@description Represents a supergroup or channel with zero or more members (subscribers in the case of channels). From the point of view of the system, a channel is a special kind of a supergroup: only administrators can post and see the list of members, and posts from all administrators use the name and photo of the channel instead of individual names and profile photos. Unlike supergroups, channels can have an unlimited number of subscribers @@ -596,10 +615,10 @@ supergroup id:int32 username:string date:int32 status:ChatMemberStatus member_co //@is_all_history_available True, if new chat members will have access to old messages. In public or discussion groups and both public and private channels, old messages are always available, so this option affects only private supergroups without a linked chat. The value of this field is only available for chat administrators //@sticker_set_id Identifier of the supergroup sticker set; 0 if none //@location Location to which the supergroup is connected; may be null -//@invite_link Invite link for this chat +//@invite_link Permanent invite link for this chat; for chat administrators only //@upgraded_from_basic_group_id Identifier of the basic group from which supergroup was upgraded; 0 if none //@upgraded_from_max_message_id Identifier of the last message in the basic group from which supergroup was upgraded; 0 if none -supergroupFullInfo photo:chatPhoto description:string member_count:int32 administrator_count:int32 restricted_count:int32 banned_count:int32 linked_chat_id:int53 slow_mode_delay:int32 slow_mode_delay_expires_in:double can_get_members:Bool can_set_username:Bool can_set_sticker_set:Bool can_set_location:Bool can_get_statistics:Bool is_all_history_available:Bool sticker_set_id:int64 location:chatLocation invite_link:string upgraded_from_basic_group_id:int32 upgraded_from_max_message_id:int53 = SupergroupFullInfo; +supergroupFullInfo photo:chatPhoto description:string member_count:int32 administrator_count:int32 restricted_count:int32 banned_count:int32 linked_chat_id:int53 slow_mode_delay:int32 slow_mode_delay_expires_in:double can_get_members:Bool can_set_username:Bool can_set_sticker_set:Bool can_set_location:Bool can_get_statistics:Bool is_all_history_available:Bool sticker_set_id:int64 location:chatLocation invite_link:chatInviteLink upgraded_from_basic_group_id:int32 upgraded_from_max_message_id:int53 = SupergroupFullInfo; //@class SecretChatState @description Describes the current secret chat state @@ -884,25 +903,6 @@ chatNearby chat_id:int53 distance:int32 = ChatNearby; chatsNearby users_nearby:vector supergroups_nearby:vector = ChatsNearby; -//@description Contains a chat invite link @invite_link Chat invite link @administrator_user_id User identifier of an administrator created the link -//@date Point in time (Unix timestamp) when the link was created @expire_date Point in time (Unix timestamp) when the link will expire; 0 if never -//@usage_limit Maximum number of times the link can be used; 0 if not limited @usage_count Number of times the link has already been used -//@is_permanent True, if the link is permanent. Permanent invite link can't have expire date or usage limit. There is exactly one permanent invite link for each administrator at any time -//@is_expired True, if the link is already expired @is_revoked True, if the link was revoked -chatInviteLink invite_link:string administrator_user_id:int32 date:int32 expire_date:int32 usage_limit:int32 usage_count:int32 is_permanent:Bool is_expired:Bool is_revoked:Bool = ChatInviteLink; - -//@description Contains information about a chat invite link -//@chat_id Chat identifier of the invite link; 0 if the user has no access to the chat before joining -//@accessible_for If non-zero, the amount of time for which read access to the chat will remain available, in seconds -//@type Contains information about the type of the chat -//@title Title of the chat -//@photo Chat photo; may be null -//@member_count Number of members in the chat -//@member_user_ids User identifiers of some chat members that may be known to the current user -//@is_public True, if the chat is a public supergroup or channel, i.e. it has a username or it is a location-based supergroup -chatInviteLinkInfo chat_id:int53 accessible_for:int32 type:ChatType title:string photo:chatPhotoInfo member_count:int32 member_user_ids:vector is_public:Bool = ChatInviteLinkInfo; - - //@class PublicChatType @description Describes a type of public chats //@description The chat is public, because it has username @@ -4354,7 +4354,7 @@ deleteFile file_id:int32 = Ok; //@chat_id Chat identifier //@expire_date Point in time (Unix timestamp) when the link will expire; pass 0 if never //@usage_limit Maximum number of times the link can be used; pass 0 if not limited -//@is_permanent True, if new permanent chat link needs to be created instead of the previous +//@is_permanent True, if new permanent chat link needs to be created instead of the previous one createChatInviteLink chat_id:int53 expire_date:int32 usage_limit:int32 is_permanent:Bool = ChatInviteLink; //@description Edits an invite link for a chat. Available for basic groups, supergroups, and channels. Requires administrator privileges and can_invite_users right diff --git a/td/generate/scheme/td_api.tlo b/td/generate/scheme/td_api.tlo index 4fcafafa0..68ae908dd 100644 Binary files a/td/generate/scheme/td_api.tlo and b/td/generate/scheme/td_api.tlo differ diff --git a/td/telegram/ContactsManager.cpp b/td/telegram/ContactsManager.cpp index 4eb4993c5..6f892d834 100644 --- a/td/telegram/ContactsManager.cpp +++ b/td/telegram/ContactsManager.cpp @@ -3491,13 +3491,15 @@ template void ContactsManager::ChatFull::store(StorerT &storer) const { using td::store; bool has_description = !description.empty(); - bool has_invite_link = !invite_link.empty(); + bool has_legacy_invite_link = false; bool has_photo = !photo.is_empty(); + bool has_invite_link = invite_link.is_valid(); BEGIN_STORE_FLAGS(); STORE_FLAG(has_description); - STORE_FLAG(has_invite_link); + STORE_FLAG(has_legacy_invite_link); STORE_FLAG(can_set_username); STORE_FLAG(has_photo); + STORE_FLAG(has_invite_link); END_STORE_FLAGS(); store(version, storer); store(creator_user_id, storer); @@ -3505,25 +3507,27 @@ void ContactsManager::ChatFull::store(StorerT &storer) const { if (has_description) { store(description, storer); } - if (has_invite_link) { - store(invite_link, storer); - } if (has_photo) { store(photo, storer); } + if (has_invite_link) { + store(invite_link, storer); + } } template void ContactsManager::ChatFull::parse(ParserT &parser) { using td::parse; bool has_description; - bool has_invite_link; + bool legacy_has_invite_link; bool has_photo; + bool has_invite_link; BEGIN_PARSE_FLAGS(); PARSE_FLAG(has_description); - PARSE_FLAG(has_invite_link); + PARSE_FLAG(legacy_has_invite_link); PARSE_FLAG(can_set_username); PARSE_FLAG(has_photo); + PARSE_FLAG(has_invite_link); END_PARSE_FLAGS(); parse(version, parser); parse(creator_user_id, parser); @@ -3531,12 +3535,16 @@ void ContactsManager::ChatFull::parse(ParserT &parser) { if (has_description) { parse(description, parser); } - if (has_invite_link) { - parse(invite_link, parser); + if (legacy_has_invite_link) { + string legacy_invite_link; + parse(legacy_invite_link, parser); } if (has_photo) { parse(photo, parser); } + if (has_invite_link) { + parse(invite_link, parser); + } } template @@ -3699,7 +3707,7 @@ void ContactsManager::ChannelFull::store(StorerT &storer) const { bool has_administrator_count = administrator_count != 0; bool has_restricted_count = restricted_count != 0; bool has_banned_count = banned_count != 0; - bool has_invite_link = !invite_link.empty(); + bool legacy_has_invite_link = false; bool has_sticker_set = sticker_set_id.is_valid(); bool has_linked_channel_id = linked_channel_id.is_valid(); bool has_migrated_from_max_message_id = migrated_from_max_message_id.is_valid(); @@ -3711,12 +3719,13 @@ void ContactsManager::ChannelFull::store(StorerT &storer) const { bool has_stats_dc_id = stats_dc_id.is_exact(); bool has_photo = !photo.is_empty(); bool legacy_has_active_group_call_id = false; + bool has_invite_link = invite_link.is_valid(); BEGIN_STORE_FLAGS(); STORE_FLAG(has_description); STORE_FLAG(has_administrator_count); STORE_FLAG(has_restricted_count); STORE_FLAG(has_banned_count); - STORE_FLAG(has_invite_link); + STORE_FLAG(legacy_has_invite_link); STORE_FLAG(has_sticker_set); STORE_FLAG(has_linked_channel_id); STORE_FLAG(has_migrated_from_max_message_id); @@ -3736,6 +3745,7 @@ void ContactsManager::ChannelFull::store(StorerT &storer) const { STORE_FLAG(is_can_view_statistics_inited); STORE_FLAG(can_view_statistics); STORE_FLAG(legacy_has_active_group_call_id); + STORE_FLAG(has_invite_link); END_STORE_FLAGS(); if (has_description) { store(description, storer); @@ -3750,9 +3760,6 @@ void ContactsManager::ChannelFull::store(StorerT &storer) const { if (has_banned_count) { store(banned_count, storer); } - if (has_invite_link) { - store(invite_link, storer); - } if (has_sticker_set) { store(sticker_set_id, storer); } @@ -3784,6 +3791,9 @@ void ContactsManager::ChannelFull::store(StorerT &storer) const { if (has_photo) { store(photo, storer); } + if (has_invite_link) { + store(invite_link, storer); + } } template @@ -3793,7 +3803,7 @@ void ContactsManager::ChannelFull::parse(ParserT &parser) { bool has_administrator_count; bool has_restricted_count; bool has_banned_count; - bool has_invite_link; + bool legacy_has_invite_link; bool has_sticker_set; bool has_linked_channel_id; bool has_migrated_from_max_message_id; @@ -3806,12 +3816,13 @@ void ContactsManager::ChannelFull::parse(ParserT &parser) { bool has_stats_dc_id; bool has_photo; bool legacy_has_active_group_call_id; + bool has_invite_link; BEGIN_PARSE_FLAGS(); PARSE_FLAG(has_description); PARSE_FLAG(has_administrator_count); PARSE_FLAG(has_restricted_count); PARSE_FLAG(has_banned_count); - PARSE_FLAG(has_invite_link); + PARSE_FLAG(legacy_has_invite_link); PARSE_FLAG(has_sticker_set); PARSE_FLAG(has_linked_channel_id); PARSE_FLAG(has_migrated_from_max_message_id); @@ -3831,6 +3842,7 @@ void ContactsManager::ChannelFull::parse(ParserT &parser) { PARSE_FLAG(is_can_view_statistics_inited); PARSE_FLAG(can_view_statistics); PARSE_FLAG(legacy_has_active_group_call_id); + PARSE_FLAG(has_invite_link); END_PARSE_FLAGS(); if (has_description) { parse(description, parser); @@ -3845,8 +3857,9 @@ void ContactsManager::ChannelFull::parse(ParserT &parser) { if (has_banned_count) { parse(banned_count, parser); } - if (has_invite_link) { - parse(invite_link, parser); + if (legacy_has_invite_link) { + string legacy_invite_link; + parse(legacy_invite_link, parser); } if (has_sticker_set) { parse(sticker_set_id, parser); @@ -3883,6 +3896,9 @@ void ContactsManager::ChannelFull::parse(ParserT &parser) { InputGroupCallId input_group_call_id; parse(input_group_call_id, parser); } + if (has_invite_link) { + parse(invite_link, parser); + } if (legacy_can_view_statistics) { LOG(DEBUG) << "Ignore legacy can view statistics flag"; @@ -11166,7 +11182,7 @@ void ContactsManager::on_update_channel_full_photo(ChannelFull *channel_full, Ch void ContactsManager::on_update_chat_full_invite_link(ChatFull *chat_full, tl_object_ptr &&invite_link) { CHECK(chat_full != nullptr); - if (update_invite_link(chat_full->invite_link, std::move(invite_link))) { + if (update_persistent_invite_link(chat_full->invite_link, std::move(invite_link))) { chat_full->is_changed = true; } } @@ -11174,7 +11190,7 @@ void ContactsManager::on_update_chat_full_invite_link(ChatFull *chat_full, void ContactsManager::on_update_channel_full_invite_link( ChannelFull *channel_full, tl_object_ptr &&invite_link) { CHECK(channel_full != nullptr); - if (update_invite_link(channel_full->invite_link, std::move(invite_link))) { + if (update_persistent_invite_link(channel_full->invite_link, std::move(invite_link))) { channel_full->is_changed = true; } } @@ -11482,19 +11498,14 @@ void ContactsManager::remove_dialog_access_by_invite_link(DialogId dialog_id) { invite_link_info_expire_timeout_.cancel_timeout(dialog_id.get()); } -bool ContactsManager::update_invite_link(string &invite_link, - tl_object_ptr &&exported_chat_invite) { - string new_invite_link; - if (exported_chat_invite != nullptr) { - new_invite_link = std::move(exported_chat_invite->link_); - } - +bool ContactsManager::update_persistent_invite_link( + DialogInviteLink &invite_link, tl_object_ptr &&exported_chat_invite) { + DialogInviteLink new_invite_link(std::move(exported_chat_invite)); if (new_invite_link != invite_link) { - if (!invite_link.empty()) { - invite_link_infos_.erase(invite_link); + if (invite_link.is_valid() && invite_link.get_invite_link() != new_invite_link.get_invite_link()) { + // old link was invalidated + invite_link_infos_.erase(invite_link.get_invite_link()); } - LOG_IF(ERROR, !new_invite_link.empty() && !DialogInviteLink::is_valid_invite_link(new_invite_link)) - << "Unsupported invite link " << new_invite_link; invite_link = std::move(new_invite_link); return true; @@ -12002,7 +12013,7 @@ void ContactsManager::drop_chat_full(ChatId chat_id) { // chat_full->creator_user_id = UserId(); chat_full->participants.clear(); chat_full->version = -1; - update_invite_link(chat_full->invite_link, nullptr); + on_update_chat_full_invite_link(chat_full, nullptr); update_chat_online_member_count(chat_full, chat_id, true); chat_full->is_changed = true; update_chat_full(chat_full, chat_id); @@ -12850,12 +12861,18 @@ bool ContactsManager::is_chat_full_outdated(const ChatFull *chat_full, const Cha for (const auto &participant : chat_full->participants) { auto u = get_user(participant.user_id); if (u != nullptr && is_bot_info_expired(participant.user_id, u->bot_info_version)) { - LOG(INFO) << "Have outdated botInfo for " << participant.user_id << ", expected version " << u->bot_info_version; + LOG(INFO) << "Have outdated botInfo for " << participant.user_id << " in " << chat_id << "; expected version " + << u->bot_info_version; return true; } } - LOG(INFO) << "Full " << chat_id << " is up-to-date with version " << chat_full->version; + if (c->status.is_creator() && !chat_full->invite_link.is_valid()) { + LOG(INFO) << "Have outdated invite link in " << chat_id; + return true; + } + + LOG(DEBUG) << "Full " << chat_id << " is up-to-date with version " << chat_full->version; return false; } @@ -14345,7 +14362,7 @@ tl_object_ptr ContactsManager::get_basic_group_full_ get_user_id_object(chat_full->creator_user_id, "basicGroupFullInfo"), transform(chat_full->participants, [this](const DialogParticipant &chat_participant) { return get_chat_member_object(chat_participant); }), - chat_full->invite_link); + chat_full->invite_link.get_chat_invite_link_object(this)); } td_api::object_ptr ContactsManager::get_update_unknown_supergroup_object( @@ -14396,7 +14413,7 @@ tl_object_ptr ContactsManager::get_supergroup_full_i slow_mode_delay_expires_in, channel_full->can_get_participants, channel_full->can_set_username, channel_full->can_set_sticker_set, channel_full->can_set_location, channel_full->can_view_statistics, channel_full->is_all_history_available, channel_full->sticker_set_id.get(), - channel_full->location.get_chat_location_object(), channel_full->invite_link, + channel_full->location.get_chat_location_object(), channel_full->invite_link.get_chat_invite_link_object(this), get_basic_group_id_object(channel_full->migrated_from_chat_id, "get_supergroup_full_info_object"), channel_full->migrated_from_max_message_id.get()); } diff --git a/td/telegram/ContactsManager.h b/td/telegram/ContactsManager.h index e350966c4..25a4601a6 100644 --- a/td/telegram/ContactsManager.h +++ b/td/telegram/ContactsManager.h @@ -739,7 +739,7 @@ class ContactsManager : public Actor { string description; - string invite_link; + DialogInviteLink invite_link; bool can_set_username = false; @@ -815,7 +815,8 @@ class ContactsManager : public Actor { int32 administrator_count = 0; int32 restricted_count = 0; int32 banned_count = 0; - string invite_link; + + DialogInviteLink invite_link; uint32 speculative_version = 1; uint32 repair_request_version = 0; @@ -1348,7 +1349,8 @@ class ContactsManager : public Actor { Status can_manage_dialog_invite_links(DialogId dialog_id); - bool update_invite_link(string &invite_link, tl_object_ptr &&exported_chat_invite); + bool update_persistent_invite_link(DialogInviteLink &invite_link, + tl_object_ptr &&exported_chat_invite); const DialogParticipant *get_chat_participant(ChatId chat_id, UserId user_id) const; diff --git a/td/telegram/DialogInviteLink.cpp b/td/telegram/DialogInviteLink.cpp index 51e5a3dec..1512dcc2e 100644 --- a/td/telegram/DialogInviteLink.cpp +++ b/td/telegram/DialogInviteLink.cpp @@ -22,6 +22,7 @@ DialogInviteLink::DialogInviteLink(tl_object_ptrlink_); + LOG_IF(ERROR, !is_valid_invite_link(invite_link_)) << "Unsupported invite link " << invite_link_; administrator_user_id_ = UserId(exported_invite->admin_id_); if (!administrator_user_id_.is_valid()) { LOG(ERROR) << "Receive invalid " << administrator_user_id_ << " as creator of a link " << invite_link_; diff --git a/td/telegram/DialogInviteLink.h b/td/telegram/DialogInviteLink.h index 5440598d6..1cd787eb1 100644 --- a/td/telegram/DialogInviteLink.h +++ b/td/telegram/DialogInviteLink.h @@ -54,6 +54,10 @@ class DialogInviteLink { int32 get_expire_time() const; + const string &get_invite_link() const { + return invite_link_; + } + UserId get_administrator_user_id() const { return administrator_user_id_; }