205 lines
		
	
	
	
		
			5.7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			205 lines
		
	
	
	
		
			5.7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*
 | |
| This file is part of Telegram Desktop,
 | |
| the official desktop application for the Telegram messaging service.
 | |
| 
 | |
| For license and copyright information please follow this link:
 | |
| https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 | |
| */
 | |
| #include "api/api_polls.h"
 | |
| 
 | |
| #include "api/api_common.h"
 | |
| #include "api/api_updates.h"
 | |
| #include "apiwrap.h"
 | |
| #include "base/random.h"
 | |
| #include "data/data_changes.h"
 | |
| #include "data/data_histories.h"
 | |
| #include "data/data_poll.h"
 | |
| #include "data/data_session.h"
 | |
| #include "history/history.h"
 | |
| #include "history/history_message.h" // ShouldSendSilent
 | |
| #include "main/main_session.h"
 | |
| 
 | |
| namespace Api {
 | |
| namespace {
 | |
| 
 | |
| [[nodiscard]] TimeId UnixtimeFromMsgId(mtpMsgId msgId) {
 | |
| 	return TimeId(msgId >> 32);
 | |
| }
 | |
| 
 | |
| } // namespace
 | |
| 
 | |
| Polls::Polls(not_null<ApiWrap*> api)
 | |
| : _session(&api->session())
 | |
| , _api(&api->instance()) {
 | |
| }
 | |
| 
 | |
| void Polls::create(
 | |
| 		const PollData &data,
 | |
| 		const SendAction &action,
 | |
| 		Fn<void()> done,
 | |
| 		Fn<void(const MTP::Error &error)> fail) {
 | |
| 	_session->api().sendAction(action);
 | |
| 
 | |
| 	const auto history = action.history;
 | |
| 	const auto peer = history->peer;
 | |
| 	auto sendFlags = MTPmessages_SendMedia::Flags(0);
 | |
| 	if (action.replyTo) {
 | |
| 		sendFlags |= MTPmessages_SendMedia::Flag::f_reply_to_msg_id;
 | |
| 	}
 | |
| 	const auto clearCloudDraft = action.clearDraft;
 | |
| 	if (clearCloudDraft) {
 | |
| 		sendFlags |= MTPmessages_SendMedia::Flag::f_clear_draft;
 | |
| 		history->clearLocalDraft();
 | |
| 		history->clearCloudDraft();
 | |
| 		history->startSavingCloudDraft();
 | |
| 	}
 | |
| 	const auto silentPost = ShouldSendSilent(peer, action.options);
 | |
| 	if (silentPost) {
 | |
| 		sendFlags |= MTPmessages_SendMedia::Flag::f_silent;
 | |
| 	}
 | |
| 	if (action.options.scheduled) {
 | |
| 		sendFlags |= MTPmessages_SendMedia::Flag::f_schedule_date;
 | |
| 	}
 | |
| 	const auto sendAs = action.options.sendAs;
 | |
| 	if (sendAs) {
 | |
| 		sendFlags |= MTPmessages_SendMedia::Flag::f_send_as;
 | |
| 	}
 | |
| 	auto &histories = history->owner().histories();
 | |
| 	const auto requestType = Data::Histories::RequestType::Send;
 | |
| 	histories.sendRequest(history, requestType, [=](Fn<void()> finish) {
 | |
| 		const auto replyTo = action.replyTo;
 | |
| 		history->sendRequestId = _api.request(MTPmessages_SendMedia(
 | |
| 			MTP_flags(sendFlags),
 | |
| 			peer->input,
 | |
| 			MTP_int(replyTo),
 | |
| 			PollDataToInputMedia(&data),
 | |
| 			MTP_string(),
 | |
| 			MTP_long(base::RandomValue<uint64>()),
 | |
| 			MTPReplyMarkup(),
 | |
| 			MTPVector<MTPMessageEntity>(),
 | |
| 			MTP_int(action.options.scheduled),
 | |
| 			(sendAs ? sendAs->input : MTP_inputPeerEmpty())
 | |
| 		)).done([=](
 | |
| 				const MTPUpdates &result,
 | |
| 				const MTP::Response &response) mutable {
 | |
| 			_session->updates().applyUpdates(result);
 | |
| 			if (clearCloudDraft) {
 | |
| 				history->finishSavingCloudDraft(
 | |
| 					UnixtimeFromMsgId(response.outerMsgId));
 | |
| 			}
 | |
| 			_session->changes().historyUpdated(
 | |
| 				history,
 | |
| 				(action.options.scheduled
 | |
| 					? Data::HistoryUpdate::Flag::ScheduledSent
 | |
| 					: Data::HistoryUpdate::Flag::MessageSent));
 | |
| 			done();
 | |
| 			finish();
 | |
| 		}).fail([=](
 | |
| 				const MTP::Error &error,
 | |
| 				const MTP::Response &response) mutable {
 | |
| 			if (clearCloudDraft) {
 | |
| 				history->finishSavingCloudDraft(
 | |
| 					UnixtimeFromMsgId(response.outerMsgId));
 | |
| 			}
 | |
| 			fail(error);
 | |
| 			finish();
 | |
| 		}).afterRequest(history->sendRequestId
 | |
| 		).send();
 | |
| 		return history->sendRequestId;
 | |
| 	});
 | |
| }
 | |
| 
 | |
| void Polls::sendVotes(
 | |
| 		FullMsgId itemId,
 | |
| 		const std::vector<QByteArray> &options) {
 | |
| 	if (_pollVotesRequestIds.contains(itemId)) {
 | |
| 		return;
 | |
| 	}
 | |
| 	const auto item = _session->data().message(itemId);
 | |
| 	const auto media = item ? item->media() : nullptr;
 | |
| 	const auto poll = media ? media->poll() : nullptr;
 | |
| 	if (!item) {
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| 	const auto showSending = poll && !options.empty();
 | |
| 	const auto hideSending = [=] {
 | |
| 		if (showSending) {
 | |
| 			if (const auto item = _session->data().message(itemId)) {
 | |
| 				poll->sendingVotes.clear();
 | |
| 				_session->data().requestItemRepaint(item);
 | |
| 			}
 | |
| 		}
 | |
| 	};
 | |
| 	if (showSending) {
 | |
| 		poll->sendingVotes = options;
 | |
| 		_session->data().requestItemRepaint(item);
 | |
| 	}
 | |
| 
 | |
| 	auto prepared = QVector<MTPbytes>();
 | |
| 	prepared.reserve(options.size());
 | |
| 	ranges::transform(
 | |
| 		options,
 | |
| 		ranges::back_inserter(prepared),
 | |
| 		[](const QByteArray &option) { return MTP_bytes(option); });
 | |
| 	const auto requestId = _api.request(MTPmessages_SendVote(
 | |
| 		item->history()->peer->input,
 | |
| 		MTP_int(item->id),
 | |
| 		MTP_vector<MTPbytes>(prepared)
 | |
| 	)).done([=](const MTPUpdates &result) {
 | |
| 		_pollVotesRequestIds.erase(itemId);
 | |
| 		hideSending();
 | |
| 		_session->updates().applyUpdates(result);
 | |
| 	}).fail([=] {
 | |
| 		_pollVotesRequestIds.erase(itemId);
 | |
| 		hideSending();
 | |
| 	}).send();
 | |
| 	_pollVotesRequestIds.emplace(itemId, requestId);
 | |
| }
 | |
| 
 | |
| void Polls::close(not_null<HistoryItem*> item) {
 | |
| 	const auto itemId = item->fullId();
 | |
| 	if (_pollCloseRequestIds.contains(itemId)) {
 | |
| 		return;
 | |
| 	}
 | |
| 	const auto media = item ? item->media() : nullptr;
 | |
| 	const auto poll = media ? media->poll() : nullptr;
 | |
| 	if (!poll) {
 | |
| 		return;
 | |
| 	}
 | |
| 	const auto requestId = _api.request(MTPmessages_EditMessage(
 | |
| 		MTP_flags(MTPmessages_EditMessage::Flag::f_media),
 | |
| 		item->history()->peer->input,
 | |
| 		MTP_int(item->id),
 | |
| 		MTPstring(),
 | |
| 		PollDataToInputMedia(poll, true),
 | |
| 		MTPReplyMarkup(),
 | |
| 		MTPVector<MTPMessageEntity>(),
 | |
| 		MTP_int(0) // schedule_date
 | |
| 	)).done([=](const MTPUpdates &result) {
 | |
| 		_pollCloseRequestIds.erase(itemId);
 | |
| 		_session->updates().applyUpdates(result);
 | |
| 	}).fail([=] {
 | |
| 		_pollCloseRequestIds.erase(itemId);
 | |
| 	}).send();
 | |
| 	_pollCloseRequestIds.emplace(itemId, requestId);
 | |
| }
 | |
| 
 | |
| void Polls::reloadResults(not_null<HistoryItem*> item) {
 | |
| 	const auto itemId = item->fullId();
 | |
| 	if (!item->isRegular() || _pollReloadRequestIds.contains(itemId)) {
 | |
| 		return;
 | |
| 	}
 | |
| 	const auto requestId = _api.request(MTPmessages_GetPollResults(
 | |
| 		item->history()->peer->input,
 | |
| 		MTP_int(item->id)
 | |
| 	)).done([=](const MTPUpdates &result) {
 | |
| 		_pollReloadRequestIds.erase(itemId);
 | |
| 		_session->updates().applyUpdates(result);
 | |
| 	}).fail([=] {
 | |
| 		_pollReloadRequestIds.erase(itemId);
 | |
| 	}).send();
 | |
| 	_pollReloadRequestIds.emplace(itemId, requestId);
 | |
| }
 | |
| 
 | |
| } // namespace Api
 | 
