Update layer to 109. Add new poll types.
GitOrigin-RevId: cc82f1bfdf1d4cd906212009f2dc8d84e0cb543a
This commit is contained in:
parent
0f35cb04fd
commit
a7501e1582
@ -211,6 +211,15 @@ maskPosition point:MaskPoint x_shift:double y_shift:double scale:double = MaskPo
|
||||
pollOption text:string voter_count:int32 vote_percentage:int32 is_chosen:Bool is_being_chosen:Bool = PollOption;
|
||||
|
||||
|
||||
//@class PollType @description Describes the type of a poll
|
||||
|
||||
//@description A regular poll @allow_multiple_answers True, if multiple answer options can be chosen simultaneously
|
||||
pollTypeRegular allow_multiple_answers:Bool = PollType;
|
||||
|
||||
//@description A quiz, which has exactly one correct answer option and can be answered only once @correct_option_id 0-based identifier of the correct answer option
|
||||
pollTypeQuiz correct_option_id:int32 = PollType;
|
||||
|
||||
|
||||
//@description Describes an animation file. The animation must be encoded in GIF or MPEG4 format @duration Duration of the animation, in seconds; as defined by the sender @width Width of the animation @height Height of the animation
|
||||
//@file_name Original name of the file; as defined by the sender @mime_type MIME type of the file, usually "image/gif" or "video/mp4"
|
||||
//@minithumbnail Animation minithumbnail; may be null @thumbnail Animation thumbnail; may be null @animation File containing the animation
|
||||
@ -257,8 +266,10 @@ venue location:location title:string address:string provider:string id:string ty
|
||||
//@param_description Game description @photo Game photo @animation Game animation; may be null
|
||||
game id:int64 short_name:string title:string text:formattedText description:string photo:photo animation:animation = Game;
|
||||
|
||||
//@description Describes a poll @id Unique poll identifier @question Poll question, 1-255 characters @options List of poll answer options @total_voter_count Total number of voters, participating in the poll @is_closed True, if the poll is closed
|
||||
poll id:int64 question:string options:vector<pollOption> total_voter_count:int32 is_closed:Bool = Poll;
|
||||
//@description Describes a poll @id Unique poll identifier @question Poll question, 1-255 characters @options List of poll answer options
|
||||
//@total_voter_count Total number of voters, participating in the poll @is_closed True, if the poll is closed
|
||||
//@is_anonymous True, if the poll is anonymous @type Type of the poll
|
||||
poll id:int64 question:string options:vector<pollOption> total_voter_count:int32 is_closed:Bool is_anonymous:Bool type:PollType = Poll;
|
||||
|
||||
|
||||
//@description Describes a user profile photo @id Photo identifier; 0 for an empty photo. Can be used to find a photo in a list of userProfilePhotos
|
||||
@ -269,7 +280,7 @@ profilePhoto id:int64 small:file big:file = ProfilePhoto;
|
||||
chatPhoto small:file big:file = ChatPhoto;
|
||||
|
||||
|
||||
//@class UserType @description Represents the type of the user. The following types are possible: regular users, deleted users and bots
|
||||
//@class UserType @description Represents the type of a user. The following types are possible: regular users, deleted users and bots
|
||||
|
||||
//@description A regular user
|
||||
userTypeRegular = UserType;
|
||||
@ -972,9 +983,13 @@ pageBlockMap location:location zoom:int32 width:int32 height:int32 caption:pageB
|
||||
webPageInstantView page_blocks:vector<PageBlock> version:int32 url:string is_rtl:Bool is_full:Bool = WebPageInstantView;
|
||||
|
||||
|
||||
//@description Describes a web page preview @url Original URL of the link @display_url URL to display
|
||||
//@description Describes a web page preview
|
||||
//@url Original URL of the link
|
||||
//@display_url URL to display
|
||||
//@type Type of the web page. Can be: article, photo, audio, video, document, profile, app, or something else
|
||||
//@site_name Short name of the site (e.g., Google Docs, App Store) @title Title of the content @param_description Description of the content
|
||||
//@site_name Short name of the site (e.g., Google Docs, App Store)
|
||||
//@title Title of the content
|
||||
//@param_description Description of the content
|
||||
//@photo Image representing the content; may be null
|
||||
//@embed_url URL to show in the embedded preview
|
||||
//@embed_type MIME type of the embedded preview, (e.g., text/html or video/mp4)
|
||||
@ -1302,50 +1317,50 @@ inputPassportElementError type:PassportElementType message:string source:InputPa
|
||||
//@description A text message @text Text of the message @web_page A preview of the web page that's mentioned in the text; may be null
|
||||
messageText text:formattedText web_page:webPage = MessageContent;
|
||||
|
||||
//@description An animation message (GIF-style). @animation Message content @caption Animation caption @is_secret True, if the animation thumbnail must be blurred and the animation must be shown only while tapped
|
||||
//@description An animation message (GIF-style). @animation The animation description @caption Animation caption @is_secret True, if the animation thumbnail must be blurred and the animation must be shown only while tapped
|
||||
messageAnimation animation:animation caption:formattedText is_secret:Bool = MessageContent;
|
||||
|
||||
//@description An audio message @audio Message content @caption Audio caption
|
||||
//@description An audio message @audio The audio description @caption Audio caption
|
||||
messageAudio audio:audio caption:formattedText = MessageContent;
|
||||
|
||||
//@description A document message (general file) @document Message content @caption Document caption
|
||||
//@description A document message (general file) @document The document description @caption Document caption
|
||||
messageDocument document:document caption:formattedText = MessageContent;
|
||||
|
||||
//@description A photo message @photo Message content @caption Photo caption @is_secret True, if the photo must be blurred and must be shown only while tapped
|
||||
//@description A photo message @photo The photo description @caption Photo caption @is_secret True, if the photo must be blurred and must be shown only while tapped
|
||||
messagePhoto photo:photo caption:formattedText is_secret:Bool = MessageContent;
|
||||
|
||||
//@description An expired photo message (self-destructed after TTL has elapsed)
|
||||
messageExpiredPhoto = MessageContent;
|
||||
|
||||
//@description A sticker message @sticker Message content
|
||||
//@description A sticker message @sticker The sticker description
|
||||
messageSticker sticker:sticker = MessageContent;
|
||||
|
||||
//@description A video message @video Message content @caption Video caption @is_secret True, if the video thumbnail must be blurred and the video must be shown only while tapped
|
||||
//@description A video message @video The video description @caption Video caption @is_secret True, if the video thumbnail must be blurred and the video must be shown only while tapped
|
||||
messageVideo video:video caption:formattedText is_secret:Bool = MessageContent;
|
||||
|
||||
//@description An expired video message (self-destructed after TTL has elapsed)
|
||||
messageExpiredVideo = MessageContent;
|
||||
|
||||
//@description A video note message @video_note Message content @is_viewed True, if at least one of the recipients has viewed the video note @is_secret True, if the video note thumbnail must be blurred and the video note must be shown only while tapped
|
||||
//@description A video note message @video_note The video note description @is_viewed True, if at least one of the recipients has viewed the video note @is_secret True, if the video note thumbnail must be blurred and the video note must be shown only while tapped
|
||||
messageVideoNote video_note:videoNote is_viewed:Bool is_secret:Bool = MessageContent;
|
||||
|
||||
//@description A voice note message @voice_note Message content @caption Voice note caption @is_listened True, if at least one of the recipients has listened to the voice note
|
||||
//@description A voice note message @voice_note The voice note description @caption Voice note caption @is_listened True, if at least one of the recipients has listened to the voice note
|
||||
messageVoiceNote voice_note:voiceNote caption:formattedText is_listened:Bool = MessageContent;
|
||||
|
||||
//@description A message with a location @location Message content @live_period Time relative to the message sent date until which the location can be updated, in seconds
|
||||
//@description A message with a location @location The location description @live_period Time relative to the message sent date until which the location can be updated, in seconds
|
||||
//@expires_in Left time for which the location can be updated, in seconds. updateMessageContent is not sent when this field changes
|
||||
messageLocation location:location live_period:int32 expires_in:int32 = MessageContent;
|
||||
|
||||
//@description A message with information about a venue @venue Message content
|
||||
//@description A message with information about a venue @venue The venue description
|
||||
messageVenue venue:venue = MessageContent;
|
||||
|
||||
//@description A message with a user contact @contact Message content
|
||||
//@description A message with a user contact @contact The contact description
|
||||
messageContact contact:contact = MessageContent;
|
||||
|
||||
//@description A message with a game @game Game
|
||||
//@description A message with a game @game The game description
|
||||
messageGame game:game = MessageContent;
|
||||
|
||||
//@description A message with a poll @poll Poll
|
||||
//@description A message with a poll @poll The poll description
|
||||
messagePoll poll:poll = MessageContent;
|
||||
|
||||
//@description A message with an invoice from a bot @title Product title @param_description Product description @photo Product photo; may be null @currency Currency for the product price @total_amount Product total price in the minimal quantity of the currency
|
||||
@ -1548,7 +1563,8 @@ inputMessageGame bot_user_id:int32 game_short_name:string = InputMessageContent;
|
||||
inputMessageInvoice invoice:invoice title:string description:string photo_url:string photo_size:int32 photo_width:int32 photo_height:int32 payload:bytes provider_token:string provider_data:string start_parameter:string = InputMessageContent;
|
||||
|
||||
//@description A message with a poll. Polls can't be sent to private or secret chats @question Poll question, 1-255 characters @options List of poll answer options, 2-10 strings 1-100 characters each
|
||||
inputMessagePoll question:string options:vector<string> = InputMessageContent;
|
||||
//@is_anonymous True, if the poll voters are anonymous. Non-anonymous polls can't be sent or forwarded to channels @type Type of the poll
|
||||
inputMessagePoll question:string options:vector<string> is_anonymous:Bool type:PollType = InputMessageContent;
|
||||
|
||||
//@description A forwarded message @from_chat_id Identifier for the chat this forwarded message came from @message_id Identifier of the message to forward
|
||||
//@in_game_share True, if a game message should be shared within a launched game; applies only to game messages
|
||||
@ -2106,7 +2122,7 @@ backgroundFillSolid color:int32 = BackgroundFill;
|
||||
backgroundFillGradient top_color:int32 bottom_color:int32 rotation_angle:int32 = BackgroundFill;
|
||||
|
||||
|
||||
//@class BackgroundType @description Describes a type of a background
|
||||
//@class BackgroundType @description Describes the type of a background
|
||||
|
||||
//@description A wallpaper in JPEG format
|
||||
//@is_blurred True, if the wallpaper must be downscaled to fit in 450x450 square and then box-blurred with radius 12
|
||||
@ -2283,7 +2299,7 @@ notificationTypeNewCall call_id:int32 = NotificationType;
|
||||
notificationTypeNewPushMessage message_id:int53 sender_user_id:int32 content:PushMessageContent = NotificationType;
|
||||
|
||||
|
||||
//@class NotificationGroupType @description Describes type of notifications in the group
|
||||
//@class NotificationGroupType @description Describes the type of notifications in a notification group
|
||||
|
||||
//@description A group containing notifications of type notificationTypeNewMessage and notificationTypeNewPushMessage with ordinary unread messages
|
||||
notificationGroupTypeMessages = NotificationGroupType;
|
||||
@ -2683,7 +2699,7 @@ textParseModeMarkdown version:int32 = TextParseMode;
|
||||
textParseModeHTML = TextParseMode;
|
||||
|
||||
|
||||
//@class ProxyType @description Describes the type of the proxy server
|
||||
//@class ProxyType @description Describes the type of a proxy server
|
||||
|
||||
//@description A SOCKS5 proxy server @username Username for logging in; may be empty @password Password for logging in; may be empty
|
||||
proxyTypeSocks5 username:string password:string = ProxyType;
|
||||
@ -3411,8 +3427,8 @@ getJsonValue json:string = JsonValue;
|
||||
getJsonString json_value:JsonValue = Text;
|
||||
|
||||
|
||||
//@description Changes user answer to a poll @chat_id Identifier of the chat to which the poll belongs @message_id Identifier of the message containing the poll
|
||||
//@option_ids 0-based identifiers of options, chosen by the user. Currently user can't choose more than 1 option
|
||||
//@description Changes the user answer to a poll. A quiz poll can be answered only once @chat_id Identifier of the chat to which the poll belongs @message_id Identifier of the message containing the poll
|
||||
//@option_ids 0-based identifiers of options, chosen by the user. User can choose more than 1 option only is the poll allows multiple answers
|
||||
setPollAnswer chat_id:int53 message_id:int53 option_ids:vector<int32> = Ok;
|
||||
|
||||
//@description Stops a poll. A poll in a message can be stopped when the message has can_be_edited flag set
|
||||
|
Binary file not shown.
@ -58,7 +58,7 @@ inputMediaDocumentExternal#fb52dc99 flags:# url:string ttl_seconds:flags.0?int =
|
||||
inputMediaGame#d33f43f3 id:InputGame = InputMedia;
|
||||
inputMediaInvoice#f4e096c3 flags:# title:string description:string photo:flags.0?InputWebDocument invoice:Invoice payload:bytes provider:string provider_data:DataJSON start_param:string = InputMedia;
|
||||
inputMediaGeoLive#ce4e82fd flags:# stopped:flags.0?true geo_point:InputGeoPoint period:flags.1?int = InputMedia;
|
||||
inputMediaPoll#6b3765b poll:Poll = InputMedia;
|
||||
inputMediaPoll#abe9ca25 flags:# poll:Poll correct_answers:flags.0?Vector<bytes> = InputMedia;
|
||||
|
||||
inputChatPhotoEmpty#1ca48f57 = InputChatPhoto;
|
||||
inputChatUploadedPhoto#927c55b4 file:InputFile = InputChatPhoto;
|
||||
@ -1002,11 +1002,11 @@ help.userInfo#1eb3758 message:string entities:Vector<MessageEntity> author:strin
|
||||
|
||||
pollAnswer#6ca9c2e9 text:string option:bytes = PollAnswer;
|
||||
|
||||
poll#d5529d06 id:long flags:# closed:flags.0?true question:string answers:Vector<PollAnswer> = Poll;
|
||||
poll#d5529d06 id:long flags:# closed:flags.0?true public_voters:flags.1?true multiple_choice:flags.2?true quiz:flags.3?true question:string answers:Vector<PollAnswer> = Poll;
|
||||
|
||||
pollAnswerVoters#3b6ddad2 flags:# chosen:flags.0?true option:bytes voters:int = PollAnswerVoters;
|
||||
pollAnswerVoters#3b6ddad2 flags:# chosen:flags.0?true correct:flags.1?true option:bytes voters:int = PollAnswerVoters;
|
||||
|
||||
pollResults#5755785a flags:# min:flags.0?true results:flags.1?Vector<PollAnswerVoters> total_voters:flags.2?int = PollResults;
|
||||
pollResults#c87024a2 flags:# min:flags.0?true results:flags.1?Vector<PollAnswerVoters> total_voters:flags.2?int recent_voters:flags.3?Vector<int> = PollResults;
|
||||
|
||||
chatOnlines#f041e250 onlines:int = ChatOnlines;
|
||||
|
||||
@ -1093,6 +1093,10 @@ themeSettings#9c14984a flags:# base_theme:BaseTheme accent_color:int message_top
|
||||
|
||||
webPageAttributeTheme#54b56617 flags:# documents:flags.0?Vector<Document> settings:flags.1?ThemeSettings = WebPageAttribute;
|
||||
|
||||
messageUserVote#f212f56d user_id:int option:bytes = MessageUserVote;
|
||||
|
||||
messages.votesList#823f649 flags:# count:int votes:Vector<MessageUserVote> users:Vector<User> next_offset:flags.0?string = messages.VotesList;
|
||||
|
||||
---functions---
|
||||
|
||||
invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X;
|
||||
@ -1329,6 +1333,7 @@ messages.getScheduledHistory#e2c2685b peer:InputPeer hash:int = messages.Message
|
||||
messages.getScheduledMessages#bdbb0464 peer:InputPeer id:Vector<int> = messages.Messages;
|
||||
messages.sendScheduledMessages#bd38850a peer:InputPeer id:Vector<int> = Updates;
|
||||
messages.deleteScheduledMessages#59ae2b16 peer:InputPeer id:Vector<int> = Updates;
|
||||
messages.getPollVotes#b86e380e flags:# peer:InputPeer id:int option:flags.0?bytes offset:flags.1?string limit:int = messages.VotesList;
|
||||
|
||||
updates.getState#edd4882a = updates.State;
|
||||
updates.getDifference#25939651 flags:# pts:int pts_total_limit:flags.0?int date:int qts:int = updates.Difference;
|
||||
|
Binary file not shown.
@ -1806,8 +1806,34 @@ static Result<InputMessageContent> create_input_message_content(
|
||||
}
|
||||
}
|
||||
|
||||
content = make_unique<MessagePoll>(
|
||||
td->poll_manager_->create_poll(std::move(input_poll->question_), std::move(input_poll->options_)));
|
||||
bool allow_multiple_answers = false;
|
||||
bool is_quiz = false;
|
||||
int32 correct_option_id = -1;
|
||||
if (input_poll->type_ == nullptr) {
|
||||
return Status::Error(400, "Poll type must not be empty");
|
||||
}
|
||||
switch (input_poll->type_->get_id()) {
|
||||
case td_api::pollTypeRegular::ID: {
|
||||
auto type = td_api::move_object_as<td_api::pollTypeRegular>(input_poll->type_);
|
||||
allow_multiple_answers = type->allow_multiple_answers_;
|
||||
break;
|
||||
}
|
||||
case td_api::pollTypeQuiz::ID: {
|
||||
auto type = td_api::move_object_as<td_api::pollTypeQuiz>(input_poll->type_);
|
||||
is_quiz = true;
|
||||
correct_option_id = type->correct_option_id_;
|
||||
if (correct_option_id < 0 || correct_option_id >= static_cast<int32>(input_poll->options_.size())) {
|
||||
return Status::Error(400, "Wrong correct option ID specified");
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
content = make_unique<MessagePoll>(td->poll_manager_->create_poll(
|
||||
std::move(input_poll->question_), std::move(input_poll->options_), input_poll->is_anonymous_,
|
||||
allow_multiple_answers, is_quiz, correct_option_id, false));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@ -2727,6 +2753,15 @@ bool get_message_content_poll_is_closed(const Td *td, const MessageContent *cont
|
||||
}
|
||||
}
|
||||
|
||||
bool get_message_content_poll_is_anonymous(const Td *td, const MessageContent *content) {
|
||||
switch (content->get_type()) {
|
||||
case MessageContentType::Poll:
|
||||
return td->poll_manager_->get_poll_is_anonymous(static_cast<const MessagePoll *>(content)->poll_id);
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
WebPageId get_message_content_web_page_id(const MessageContent *content) {
|
||||
if (content->get_type() == MessageContentType::Text) {
|
||||
return static_cast<const MessageText *>(content)->web_page_id;
|
||||
|
@ -184,6 +184,8 @@ int32 get_message_content_live_location_period(const MessageContent *content);
|
||||
|
||||
bool get_message_content_poll_is_closed(const Td *td, const MessageContent *content);
|
||||
|
||||
bool get_message_content_poll_is_anonymous(const Td *td, const MessageContent *content);
|
||||
|
||||
WebPageId get_message_content_web_page_id(const MessageContent *content);
|
||||
|
||||
void set_message_content_web_page_id(MessageContent *content, WebPageId web_page_id);
|
||||
|
@ -17837,23 +17837,8 @@ Status MessagesManager::can_send_message_content(DialogId dialog_id, const Messa
|
||||
}
|
||||
break;
|
||||
case MessageContentType::Game:
|
||||
switch (dialog_id.get_type()) {
|
||||
case DialogType::User:
|
||||
case DialogType::Chat:
|
||||
// ok
|
||||
break;
|
||||
case DialogType::Channel: {
|
||||
auto channel_type = td_->contacts_manager_->get_channel_type(dialog_id.get_channel_id());
|
||||
if (channel_type == ChannelType::Broadcast) {
|
||||
// return Status::Error(400, "Games can't be sent to channel chats");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DialogType::SecretChat:
|
||||
return Status::Error(400, "Games can't be sent to secret chats");
|
||||
case DialogType::None:
|
||||
default:
|
||||
UNREACHABLE();
|
||||
if (is_broadcast_channel(dialog_id)) {
|
||||
// return Status::Error(400, "Games can't be sent to channel chats");
|
||||
}
|
||||
|
||||
if (!can_send_games) {
|
||||
@ -17898,6 +17883,9 @@ Status MessagesManager::can_send_message_content(DialogId dialog_id, const Messa
|
||||
if (!can_send_polls) {
|
||||
return Status::Error(400, "Not enough rights to send polls to the chat");
|
||||
}
|
||||
if (!get_message_content_poll_is_anonymous(td_, content) && is_broadcast_channel(dialog_id)) {
|
||||
return Status::Error(400, "Non-anonymous polls can't be sent to channel chats");
|
||||
}
|
||||
break;
|
||||
case MessageContentType::Sticker:
|
||||
if (!can_send_stickers) {
|
||||
|
@ -57,8 +57,7 @@ class GetPollResultsQuery : public Td::ResultHandler {
|
||||
auto input_peer = td->messages_manager_->get_input_peer(dialog_id_, AccessRights::Read);
|
||||
if (input_peer == nullptr) {
|
||||
LOG(INFO) << "Can't reget poll, because have no read access to " << dialog_id_;
|
||||
// do not signal error to PollManager
|
||||
return;
|
||||
return promise_.set_value(nullptr);
|
||||
}
|
||||
|
||||
auto message_id = full_message_id.get_message_id().get_server_message_id().get();
|
||||
@ -151,7 +150,8 @@ class StopPollActor : public NetActorOnce {
|
||||
auto message_id = full_message_id.get_message_id().get_server_message_id().get();
|
||||
auto poll = telegram_api::make_object<telegram_api::poll>();
|
||||
poll->flags_ |= telegram_api::poll::CLOSED_MASK;
|
||||
auto input_media = telegram_api::make_object<telegram_api::inputMediaPoll>(std::move(poll));
|
||||
auto input_media =
|
||||
telegram_api::make_object<telegram_api::inputMediaPoll>(0, std::move(poll), vector<BufferSlice>());
|
||||
auto query = G()->net_query_creator().create(create_storer(telegram_api::messages_editMessage(
|
||||
flags, false /*ignored*/, std::move(input_peer), message_id, string(), std::move(input_media),
|
||||
std::move(input_reply_markup), vector<tl_object_ptr<telegram_api::MessageEntity>>(), 0)));
|
||||
@ -473,15 +473,23 @@ td_api::object_ptr<td_api::poll> PollManager::get_poll_object(PollId poll_id, co
|
||||
poll_options[i]->vote_percentage_ = vote_percentage[i];
|
||||
}
|
||||
}
|
||||
td_api::object_ptr<td_api::PollType> poll_type;
|
||||
if (poll->is_quiz) {
|
||||
poll_type = td_api::make_object<td_api::pollTypeQuiz>(poll->correct_option_id);
|
||||
} else {
|
||||
poll_type = td_api::make_object<td_api::pollTypeRegular>(poll->allow_multiple_answers);
|
||||
}
|
||||
|
||||
return td_api::make_object<td_api::poll>(poll_id.get(), poll->question, std::move(poll_options), total_voter_count,
|
||||
poll->is_closed);
|
||||
poll->is_closed, poll->is_anonymous, std::move(poll_type));
|
||||
}
|
||||
|
||||
telegram_api::object_ptr<telegram_api::pollAnswer> PollManager::get_input_poll_option(const PollOption &poll_option) {
|
||||
return telegram_api::make_object<telegram_api::pollAnswer>(poll_option.text, BufferSlice(poll_option.data));
|
||||
}
|
||||
|
||||
PollId PollManager::create_poll(string &&question, vector<string> &&options) {
|
||||
PollId PollManager::create_poll(string &&question, vector<string> &&options, bool is_anonymous,
|
||||
bool allow_multiple_answers, bool is_quiz, int32 correct_option_id, bool is_closed) {
|
||||
auto poll = make_unique<Poll>();
|
||||
poll->question = std::move(question);
|
||||
int pos = '0';
|
||||
@ -491,6 +499,11 @@ PollId PollManager::create_poll(string &&question, vector<string> &&options) {
|
||||
option.data = string(1, narrow_cast<char>(pos++));
|
||||
poll->options.push_back(std::move(option));
|
||||
}
|
||||
poll->is_anonymous = is_anonymous;
|
||||
poll->allow_multiple_answers = allow_multiple_answers;
|
||||
poll->is_quiz = is_quiz;
|
||||
poll->correct_option_id = correct_option_id;
|
||||
poll->is_closed = is_closed;
|
||||
|
||||
PollId poll_id(--current_local_poll_id_);
|
||||
CHECK(is_local_poll_id(poll_id));
|
||||
@ -536,6 +549,12 @@ bool PollManager::get_poll_is_closed(PollId poll_id) const {
|
||||
return poll->is_closed;
|
||||
}
|
||||
|
||||
bool PollManager::get_poll_is_anonymous(PollId poll_id) const {
|
||||
auto poll = get_poll(poll_id);
|
||||
CHECK(poll != nullptr);
|
||||
return poll->is_anonymous;
|
||||
}
|
||||
|
||||
string PollManager::get_poll_search_text(PollId poll_id) const {
|
||||
auto poll = get_poll(poll_id);
|
||||
CHECK(poll != nullptr);
|
||||
@ -550,11 +569,11 @@ string PollManager::get_poll_search_text(PollId poll_id) const {
|
||||
|
||||
void PollManager::set_poll_answer(PollId poll_id, FullMessageId full_message_id, vector<int32> &&option_ids,
|
||||
Promise<Unit> &&promise) {
|
||||
if (option_ids.size() > 1) {
|
||||
return promise.set_error(Status::Error(400, "Can't choose more than 1 option"));
|
||||
}
|
||||
std::sort(option_ids.begin(), option_ids.end());
|
||||
option_ids.erase(std::unique(option_ids.begin(), option_ids.end()), option_ids.end());
|
||||
|
||||
if (is_local_poll_id(poll_id)) {
|
||||
return promise.set_error(Status::Error(5, "Poll can't be answered"));
|
||||
return promise.set_error(Status::Error(400, "Poll can't be answered"));
|
||||
}
|
||||
|
||||
auto poll = get_poll(poll_id);
|
||||
@ -562,11 +581,18 @@ void PollManager::set_poll_answer(PollId poll_id, FullMessageId full_message_id,
|
||||
if (poll->is_closed) {
|
||||
return promise.set_error(Status::Error(400, "Can't answer closed poll"));
|
||||
}
|
||||
if (!poll->allow_multiple_answers && option_ids.size() > 1) {
|
||||
return promise.set_error(Status::Error(400, "Can't choose more than 1 option in the poll"));
|
||||
}
|
||||
if (poll->is_quiz && option_ids.empty()) {
|
||||
return promise.set_error(Status::Error(400, "Can't retract vote in a quiz"));
|
||||
}
|
||||
|
||||
vector<string> options;
|
||||
for (auto &option_id : option_ids) {
|
||||
auto index = static_cast<size_t>(option_id);
|
||||
if (index >= poll->options.size()) {
|
||||
return promise.set_error(Status::Error(400, "Invalid option id specified"));
|
||||
return promise.set_error(Status::Error(400, "Invalid option ID specified"));
|
||||
}
|
||||
options.push_back(poll->options[index].data);
|
||||
}
|
||||
@ -809,16 +835,19 @@ void PollManager::on_update_poll_timeout(PollId poll_id) {
|
||||
void PollManager::on_get_poll_results(PollId poll_id, uint64 generation,
|
||||
Result<tl_object_ptr<telegram_api::Updates>> result) {
|
||||
if (result.is_error()) {
|
||||
if (!get_poll_is_closed(poll_id) && !td_->auth_manager_->is_bot()) {
|
||||
if (!get_poll_is_closed(poll_id) && !G()->close_flag() && !td_->auth_manager_->is_bot()) {
|
||||
auto timeout = get_polling_timeout();
|
||||
LOG(INFO) << "Schedule updating of " << poll_id << " in " << timeout;
|
||||
update_poll_timeout_.add_timeout_in(poll_id.get(), timeout);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (result.ok() == nullptr) {
|
||||
return;
|
||||
}
|
||||
if (generation != current_generation_) {
|
||||
LOG(INFO) << "Receive possibly outdated result of " << poll_id << ", reget it";
|
||||
if (!get_poll_is_closed(poll_id) && !td_->auth_manager_->is_bot()) {
|
||||
if (!get_poll_is_closed(poll_id) && !G()->close_flag() && !td_->auth_manager_->is_bot()) {
|
||||
update_poll_timeout_.set_timeout_in(poll_id.get(), 0.0);
|
||||
}
|
||||
return;
|
||||
@ -845,8 +874,30 @@ void PollManager::on_online() {
|
||||
tl_object_ptr<telegram_api::InputMedia> PollManager::get_input_media(PollId poll_id) const {
|
||||
auto poll = get_poll(poll_id);
|
||||
CHECK(poll != nullptr);
|
||||
return telegram_api::make_object<telegram_api::inputMediaPoll>(telegram_api::make_object<telegram_api::poll>(
|
||||
0, 0, false /* ignored */, poll->question, transform(poll->options, get_input_poll_option)));
|
||||
|
||||
int32 poll_flags = 0;
|
||||
if (!poll->is_anonymous) {
|
||||
poll_flags |= telegram_api::poll::PUBLIC_VOTERS_MASK;
|
||||
}
|
||||
if (poll->allow_multiple_answers) {
|
||||
poll_flags |= telegram_api::poll::MULTIPLE_CHOICE_MASK;
|
||||
}
|
||||
if (poll->is_quiz) {
|
||||
poll_flags |= telegram_api::poll::QUIZ_MASK;
|
||||
}
|
||||
|
||||
int32 flags = 0;
|
||||
vector<BufferSlice> correct_answers;
|
||||
if (poll->is_quiz) {
|
||||
flags |= telegram_api::inputMediaPoll::CORRECT_ANSWERS_MASK;
|
||||
correct_answers.push_back(BufferSlice(poll->options[poll->correct_option_id].data));
|
||||
}
|
||||
return telegram_api::make_object<telegram_api::inputMediaPoll>(
|
||||
flags,
|
||||
telegram_api::make_object<telegram_api::poll>(0, flags, false /*ignored*/, false /*ignored*/, false /*ignored*/,
|
||||
false /*ignored*/, poll->question,
|
||||
transform(poll->options, get_input_poll_option)),
|
||||
std::move(correct_answers));
|
||||
}
|
||||
|
||||
vector<PollManager::PollOption> PollManager::get_poll_options(
|
||||
@ -917,6 +968,25 @@ PollId PollManager::on_get_poll(PollId poll_id, tl_object_ptr<telegram_api::poll
|
||||
poll->is_closed = is_closed;
|
||||
is_changed = true;
|
||||
}
|
||||
bool is_anonymous = (poll_server->flags_ & telegram_api::poll::PUBLIC_VOTERS_MASK) == 0;
|
||||
if (is_anonymous != poll->is_anonymous) {
|
||||
poll->is_anonymous = is_anonymous;
|
||||
is_changed = true;
|
||||
}
|
||||
bool allow_multiple_answers = (poll_server->flags_ & telegram_api::poll::MULTIPLE_CHOICE_MASK) != 0;
|
||||
bool is_quiz = (poll_server->flags_ & telegram_api::poll::QUIZ_MASK) != 0;
|
||||
if (is_quiz && allow_multiple_answers) {
|
||||
LOG(ERROR) << "Receive quiz " << poll_id << " allowing multiple answers";
|
||||
allow_multiple_answers = false;
|
||||
}
|
||||
if (allow_multiple_answers != poll->allow_multiple_answers) {
|
||||
poll->allow_multiple_answers = allow_multiple_answers;
|
||||
is_changed = true;
|
||||
}
|
||||
if (is_quiz != poll->is_quiz) {
|
||||
poll->is_quiz = is_quiz;
|
||||
is_changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
CHECK(poll_results != nullptr);
|
||||
@ -930,7 +1000,9 @@ PollId PollManager::on_get_poll(PollId poll_id, tl_object_ptr<telegram_api::poll
|
||||
}
|
||||
is_changed = true;
|
||||
}
|
||||
for (auto &poll_result : poll_results->results_) {
|
||||
int32 correct_option_id = -1;
|
||||
for (size_t i = 0; i < poll_results->results_.size(); i++) {
|
||||
auto &poll_result = poll_results->results_[i];
|
||||
Slice data = poll_result->option_.as_slice();
|
||||
for (auto &option : poll->options) {
|
||||
if (option.data != data) {
|
||||
@ -943,6 +1015,13 @@ PollId PollManager::on_get_poll(PollId poll_id, tl_object_ptr<telegram_api::poll
|
||||
is_changed = true;
|
||||
}
|
||||
}
|
||||
bool is_correct = (poll_result->flags_ & telegram_api::pollAnswerVoters::CORRECT_MASK) != 0;
|
||||
if (is_correct) {
|
||||
if (correct_option_id != -1) {
|
||||
LOG(ERROR) << "Receive more than 1 correct answers " << correct_option_id << " and " << i;
|
||||
}
|
||||
correct_option_id = static_cast<int32>(i);
|
||||
}
|
||||
if (poll_result->voters_ != option.voter_count) {
|
||||
option.voter_count = poll_result->voters_;
|
||||
if (option.voter_count < 0) {
|
||||
@ -978,6 +1057,18 @@ PollId PollManager::on_get_poll(PollId poll_id, tl_object_ptr<telegram_api::poll
|
||||
poll->total_voter_count = max_total_voter_count;
|
||||
}
|
||||
}
|
||||
if (poll->is_quiz) {
|
||||
if (correct_option_id == -1) {
|
||||
LOG(ERROR) << "Have no correct option in quiz " << poll_id;
|
||||
correct_option_id = 0;
|
||||
}
|
||||
if (poll->correct_option_id != correct_option_id) {
|
||||
poll->correct_option_id = correct_option_id;
|
||||
is_changed = true;
|
||||
}
|
||||
} else if (correct_option_id != -1) {
|
||||
LOG(ERROR) << "Receive correct option " << correct_option_id << " in quiz " << poll_id;
|
||||
}
|
||||
|
||||
if (!td_->auth_manager_->is_bot() && !poll->is_closed) {
|
||||
auto timeout = get_polling_timeout();
|
||||
|
@ -41,7 +41,8 @@ class PollManager : public Actor {
|
||||
|
||||
static bool is_local_poll_id(PollId poll_id);
|
||||
|
||||
PollId create_poll(string &&question, vector<string> &&options);
|
||||
PollId create_poll(string &&question, vector<string> &&options, bool is_anonymous, bool allow_multiple_answers,
|
||||
bool is_quiz, int32 correct_option_id, bool is_closed);
|
||||
|
||||
void register_poll(PollId poll_id, FullMessageId full_message_id);
|
||||
|
||||
@ -49,6 +50,8 @@ class PollManager : public Actor {
|
||||
|
||||
bool get_poll_is_closed(PollId poll_id) const;
|
||||
|
||||
bool get_poll_is_anonymous(PollId poll_id) const;
|
||||
|
||||
string get_poll_search_text(PollId poll_id) const;
|
||||
|
||||
void set_poll_answer(PollId poll_id, FullMessageId full_message_id, vector<int32> &&option_ids,
|
||||
@ -93,6 +96,10 @@ class PollManager : public Actor {
|
||||
string question;
|
||||
vector<PollOption> options;
|
||||
int32 total_voter_count = 0;
|
||||
int32 correct_option_id = -1;
|
||||
bool is_anonymous = true;
|
||||
bool allow_multiple_answers = false;
|
||||
bool is_quiz = false;
|
||||
bool is_closed = false;
|
||||
|
||||
template <class StorerT>
|
||||
|
@ -7,6 +7,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "td/telegram/PollManager.h"
|
||||
#include "td/telegram/Version.h"
|
||||
|
||||
#include "td/utils/common.h"
|
||||
#include "td/utils/misc.h"
|
||||
@ -41,25 +42,43 @@ void PollManager::PollOption::parse(ParserT &parser) {
|
||||
template <class StorerT>
|
||||
void PollManager::Poll::store(StorerT &storer) const {
|
||||
using ::td::store;
|
||||
bool is_public = !is_anonymous;
|
||||
BEGIN_STORE_FLAGS();
|
||||
STORE_FLAG(is_closed);
|
||||
STORE_FLAG(is_public);
|
||||
STORE_FLAG(allow_multiple_answers);
|
||||
STORE_FLAG(is_quiz);
|
||||
END_STORE_FLAGS();
|
||||
|
||||
store(question, storer);
|
||||
store(options, storer);
|
||||
store(total_voter_count, storer);
|
||||
if (is_quiz) {
|
||||
store(correct_option_id, storer);
|
||||
}
|
||||
}
|
||||
|
||||
template <class ParserT>
|
||||
void PollManager::Poll::parse(ParserT &parser) {
|
||||
using ::td::parse;
|
||||
bool is_public;
|
||||
BEGIN_PARSE_FLAGS();
|
||||
PARSE_FLAG(is_closed);
|
||||
PARSE_FLAG(is_public);
|
||||
PARSE_FLAG(allow_multiple_answers);
|
||||
PARSE_FLAG(is_quiz);
|
||||
END_PARSE_FLAGS();
|
||||
is_anonymous = !is_public;
|
||||
|
||||
parse(question, parser);
|
||||
parse(options, parser);
|
||||
parse(total_voter_count, parser);
|
||||
if (is_quiz) {
|
||||
parse(correct_option_id, parser);
|
||||
if (correct_option_id < 0 || correct_option_id >= static_cast<int32>(options.size())) {
|
||||
parser.set_error("Wrong correct_option_id");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class StorerT>
|
||||
@ -68,9 +87,18 @@ void PollManager::store_poll(PollId poll_id, StorerT &storer) const {
|
||||
if (is_local_poll_id(poll_id)) {
|
||||
auto poll = get_poll(poll_id);
|
||||
CHECK(poll != nullptr);
|
||||
BEGIN_STORE_FLAGS();
|
||||
STORE_FLAG(poll->is_closed);
|
||||
STORE_FLAG(poll->is_anonymous);
|
||||
STORE_FLAG(poll->allow_multiple_answers);
|
||||
STORE_FLAG(poll->is_quiz);
|
||||
END_STORE_FLAGS();
|
||||
store(poll->question, storer);
|
||||
vector<string> options = transform(poll->options, [](const PollOption &option) { return option.text; });
|
||||
store(options, storer);
|
||||
if (poll->is_quiz) {
|
||||
store(poll->correct_option_id, storer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -82,12 +110,33 @@ PollId PollManager::parse_poll(ParserT &parser) {
|
||||
if (is_local_poll_id(poll_id)) {
|
||||
string question;
|
||||
vector<string> options;
|
||||
bool is_closed = false;
|
||||
bool is_anonymous = true;
|
||||
bool allow_multiple_answers = false;
|
||||
bool is_quiz = false;
|
||||
int32 correct_option_id = -1;
|
||||
|
||||
if (parser.version() >= static_cast<int32>(Version::SupportPolls2_0)) {
|
||||
BEGIN_PARSE_FLAGS();
|
||||
PARSE_FLAG(is_closed);
|
||||
PARSE_FLAG(is_anonymous);
|
||||
PARSE_FLAG(allow_multiple_answers);
|
||||
PARSE_FLAG(is_quiz);
|
||||
END_PARSE_FLAGS();
|
||||
}
|
||||
parse(question, parser);
|
||||
parse(options, parser);
|
||||
if (is_quiz) {
|
||||
parse(correct_option_id, parser);
|
||||
if (correct_option_id < 0 || correct_option_id >= static_cast<int32>(options.size())) {
|
||||
parser.set_error("Wrong correct_option_id");
|
||||
}
|
||||
}
|
||||
if (parser.get_error() != nullptr) {
|
||||
return PollId();
|
||||
}
|
||||
return create_poll(std::move(question), std::move(options));
|
||||
return create_poll(std::move(question), std::move(options), is_anonymous, allow_multiple_answers, is_quiz,
|
||||
correct_option_id, is_closed);
|
||||
}
|
||||
|
||||
auto poll = get_poll_force(poll_id);
|
||||
|
@ -454,6 +454,19 @@ bool UpdatesManager::is_acceptable_message(const telegram_api::Message *message_
|
||||
}
|
||||
}
|
||||
/*
|
||||
// the users are always min, so no need to check
|
||||
if (media_id == telegram_api::messageMediaPoll::ID) {
|
||||
auto message_media_poll = static_cast<const telegram_api::messageMediaPoll *>(message->media_.get());
|
||||
for (auto recent_voter_user_id : message_media_poll->results_->recent_voters_) {
|
||||
UserId user_id(recent_voter_user_id);
|
||||
if (!is_acceptable_user(user_id)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
/*
|
||||
// the channel is always min, so no need to check
|
||||
if (media_id == telegram_api::messageMediaWebPage::ID) {
|
||||
auto message_media_web_page = static_cast<const telegram_api::messageMediaWebPage *>(message->media_.get());
|
||||
if (message_media_web_page->webpage_->get_id() == telegram_api::webPage::ID) {
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
namespace td {
|
||||
|
||||
constexpr int32 MTPROTO_LAYER = 108;
|
||||
constexpr int32 MTPROTO_LAYER = 109;
|
||||
|
||||
enum class Version : int32 {
|
||||
Initial,
|
||||
@ -35,6 +35,7 @@ enum class Version : int32 {
|
||||
AddVideoCallsSupport,
|
||||
AddPhotoSizeSource,
|
||||
AddFolders,
|
||||
SupportPolls2_0,
|
||||
Next
|
||||
};
|
||||
|
||||
|
@ -3194,14 +3194,21 @@ class CliClient final : public Actor {
|
||||
|
||||
send_message(chat_id, td_api::make_object<td_api::inputMessageLocation>(as_location(latitude, longitude),
|
||||
to_integer<int32>(period)));
|
||||
} else if (op == "spoll") {
|
||||
} else if (op == "spoll" || op == "spollm" || op == "squiz") {
|
||||
string chat_id;
|
||||
string question;
|
||||
std::tie(chat_id, args) = split(args);
|
||||
std::tie(question, args) = split(args);
|
||||
auto options = full_split(args);
|
||||
|
||||
send_message(chat_id, td_api::make_object<td_api::inputMessagePoll>(question, std::move(options)));
|
||||
td_api::object_ptr<td_api::PollType> poll_type;
|
||||
if (op == "squiz") {
|
||||
poll_type = td_api::make_object<td_api::pollTypeQuiz>(narrow_cast<int32>(options.size() - 1));
|
||||
} else {
|
||||
poll_type = td_api::make_object<td_api::pollTypeRegular>(op == "spollm");
|
||||
}
|
||||
send_message(chat_id, td_api::make_object<td_api::inputMessagePoll>(question, std::move(options), true,
|
||||
std::move(poll_type)));
|
||||
} else if (op == "sp" || op == "spcaption" || op == "spttl") {
|
||||
string chat_id;
|
||||
string photo_path;
|
||||
|
Loading…
Reference in New Issue
Block a user