diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index 7ab4bf23f..2acd9aab1 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -4241,17 +4241,29 @@ checkPhoneNumberConfirmationCode code:string = Ok; setBotUpdatesStatus pending_update_count:int32 error_message:string = Ok; -//@description Uploads a PNG image with a sticker; for bots only; returns the uploaded file @user_id Sticker file owner @png_sticker PNG image with the sticker; must be up to 512 KB in size and fit in 512x512 square +//@description Uploads a PNG image with a sticker; for bots only; returns the uploaded file +//@user_id Sticker file owner @png_sticker PNG image with the sticker; must be up to 512 KB in size and fit in 512x512 square uploadStickerFile user_id:int32 png_sticker:InputFile = File; -//@description Creates a new sticker set; for bots only. Returns the newly created sticker set @user_id Sticker set owner @title Sticker set title; 1-64 characters @name Sticker set name. Can contain only English letters, digits and underscores. Must end with *"_by_"* (** is case insensitive); 1-64 characters -//@is_masks True, if stickers are masks @stickers List of stickers to be added to the set +//@description Creates a new sticker set; for bots only. Returns the newly created sticker set +//@user_id Sticker set owner +//@title Sticker set title; 1-64 characters @name Sticker set name. Can contain only English letters, digits and underscores. Must end with *"_by_"* (** is case insensitive); 1-64 characters +//@is_masks True, if stickers are masks +//@stickers List of stickers to be added to the set createNewStickerSet user_id:int32 title:string name:string is_masks:Bool stickers:vector = StickerSet; -//@description Adds a new sticker to a set; for bots only. Returns the sticker set @user_id Sticker set owner @name Sticker set name @sticker Sticker to add to the set +//@description Adds a new sticker to a set; for bots only. Returns the sticker set +//@user_id Sticker set owner @name Sticker set name +//@sticker Sticker to add to the set addStickerToSet user_id:int32 name:string sticker:inputSticker = StickerSet; -//@description Changes the position of a sticker in the set to which it belongs; for bots only. The sticker set must have been created by the bot @sticker Sticker @position New position of the sticker in the set, zero-based +//@description Sets a sticker set thumbnail; for bots only. Returns the sticker set +//@user_id Sticker set owner @name Sticker set name +//@thumbnail Thumbnail to set in PNG format. You can use a zero InputFileId to delete the thumbnail +setStickerSetThumbnail user_id:int32 name:string thumbnail:InputFile = StickerSet; + +//@description Changes the position of a sticker in the set to which it belongs; for bots only. The sticker set must have been created by the bot +//@sticker Sticker @position New position of the sticker in the set, zero-based setStickerPositionInSet sticker:InputFile position:int32 = Ok; //@description Removes a sticker from the set to which it belongs; for bots only. The sticker set must have been created by the bot @sticker Sticker diff --git a/td/generate/scheme/td_api.tlo b/td/generate/scheme/td_api.tlo index d7039b5a3..9a00e4dfe 100644 Binary files a/td/generate/scheme/td_api.tlo and b/td/generate/scheme/td_api.tlo differ diff --git a/td/telegram/StickersManager.cpp b/td/telegram/StickersManager.cpp index 30e01ef2d..160e50920 100644 --- a/td/telegram/StickersManager.cpp +++ b/td/telegram/StickersManager.cpp @@ -940,6 +940,36 @@ class AddStickerToSetQuery : public Td::ResultHandler { } }; +class SetStickerSetThumbnailQuery : public Td::ResultHandler { + Promise promise_; + + public: + explicit SetStickerSetThumbnailQuery(Promise &&promise) : promise_(std::move(promise)) { + } + + void send(const string &short_name, tl_object_ptr &&input_document) { + send_query(G()->net_query_creator().create(telegram_api::stickers_setStickerSetThumb( + make_tl_object(short_name), std::move(input_document)))); + } + + void on_result(uint64 id, BufferSlice packet) override { + auto result_ptr = fetch_result(packet); + if (result_ptr.is_error()) { + return on_error(id, result_ptr.move_as_error()); + } + + td->stickers_manager_->on_get_messages_sticker_set(StickerSetId(), result_ptr.move_as_ok(), true, + "SetStickerSetThumbnailQuery"); + + promise_.set_value(Unit()); + } + + void on_error(uint64 id, Status status) override { + CHECK(status.is_error()); + promise_.set_error(std::move(status)); + } +}; + class SetStickerPositionQuery : public Td::ResultHandler { Promise promise_; @@ -3555,16 +3585,20 @@ Result> StickersManager::prepare_input_sticker(td return Status::Error(400, "Emojis must be encoded in UTF-8"); } - return prepare_input_file(sticker->png_sticker_); + return prepare_input_file(sticker->png_sticker_, false); } Result> StickersManager::prepare_input_file( - const tl_object_ptr &input_file) { - auto r_file_id = td_->file_manager_->get_input_file_id(FileType::Document, input_file, {}, false, false, false); + const tl_object_ptr &input_file, bool allow_zero) { + auto r_file_id = + td_->file_manager_->get_input_file_id(FileType::Document, input_file, DialogId(), allow_zero, false, false); if (r_file_id.is_error()) { return Status::Error(7, r_file_id.error().message()); } auto file_id = r_file_id.move_as_ok(); + if (file_id.empty()) { + return std::make_tuple(FileId(), false, false); + } td_->documents_manager_->create_document(file_id, string(), PhotoSize(), "sticker.png", "image/png", false); @@ -3607,7 +3641,7 @@ FileId StickersManager::upload_sticker_file(UserId user_id, const tl_object_ptr< return FileId(); } - auto r_file_id = prepare_input_file(sticker); + auto r_file_id = prepare_input_file(sticker, false); if (r_file_id.is_error()) { promise.set_error(r_file_id.move_as_error()); return FileId(); @@ -3939,6 +3973,84 @@ void StickersManager::on_added_sticker_uploaded(int64 random_id, Result re get_input_sticker(pending_add_sticker_to_set->sticker.get(), pending_add_sticker_to_set->file_id)); } +void StickersManager::set_sticker_set_thumbnail(UserId user_id, string &short_name, + tl_object_ptr &&thumbnail, Promise &&promise) { + auto input_user = td_->contacts_manager_->get_input_user(user_id); + if (input_user == nullptr) { + return promise.set_error(Status::Error(3, "User not found")); + } + DialogId dialog_id(user_id); + auto input_peer = td_->messages_manager_->get_input_peer(dialog_id, AccessRights::Write); + if (input_peer == nullptr) { + return promise.set_error(Status::Error(3, "Have no access to the user")); + } + + short_name = strip_empty_characters(short_name, MAX_STICKER_SET_SHORT_NAME_LENGTH); + if (short_name.empty()) { + return promise.set_error(Status::Error(3, "Sticker set name can't be empty")); + } + + auto r_file_id = prepare_input_file(thumbnail, true); + if (r_file_id.is_error()) { + return promise.set_error(r_file_id.move_as_error()); + } + auto file_id = std::get<0>(r_file_id.ok()); + auto is_url = std::get<1>(r_file_id.ok()); + auto is_local = std::get<2>(r_file_id.ok()); + + if (!file_id.is_valid()) { + td_->create_handler(std::move(promise)) + ->send(short_name, telegram_api::make_object()); + return; + } + + auto pending_set_sticker_set_thumbnail = make_unique(); + pending_set_sticker_set_thumbnail->short_name = short_name; + pending_set_sticker_set_thumbnail->file_id = file_id; + pending_set_sticker_set_thumbnail->promise = std::move(promise); + + int64 random_id; + do { + random_id = Random::secure_int64(); + } while (random_id == 0 || + pending_set_sticker_set_thumbnails_.find(random_id) != pending_set_sticker_set_thumbnails_.end()); + pending_set_sticker_set_thumbnails_[random_id] = std::move(pending_set_sticker_set_thumbnail); + + auto on_upload_promise = PromiseCreator::lambda([random_id](Result result) { + send_closure(G()->stickers_manager(), &StickersManager::on_sticker_set_thumbnail_uploaded, random_id, + std::move(result)); + }); + + if (is_url) { + do_upload_sticker_file(user_id, file_id, nullptr, std::move(on_upload_promise)); + } else if (is_local) { + upload_sticker_file(user_id, file_id, std::move(on_upload_promise)); + } else { + on_upload_promise.set_value(Unit()); + } +} + +void StickersManager::on_sticker_set_thumbnail_uploaded(int64 random_id, Result result) { + auto it = pending_set_sticker_set_thumbnails_.find(random_id); + CHECK(it != pending_set_sticker_set_thumbnails_.end()); + + auto pending_set_sticker_set_thumbnail = std::move(it->second); + CHECK(pending_set_sticker_set_thumbnail != nullptr); + + pending_set_sticker_set_thumbnails_.erase(it); + + if (result.is_error()) { + pending_set_sticker_set_thumbnail->promise.set_error(result.move_as_error()); + return; + } + + FileView file_view = td_->file_manager_->get_file_view(pending_set_sticker_set_thumbnail->file_id); + CHECK(file_view.has_remote_location()); + + td_->create_handler(std::move(pending_set_sticker_set_thumbnail->promise)) + ->send(pending_set_sticker_set_thumbnail->short_name, file_view.main_remote_location().as_input_document()); +} + void StickersManager::set_sticker_position_in_set(const tl_object_ptr &sticker, int32 position, Promise &&promise) { if (position < 0) { diff --git a/td/telegram/StickersManager.h b/td/telegram/StickersManager.h index 474683f4c..306db2b71 100644 --- a/td/telegram/StickersManager.h +++ b/td/telegram/StickersManager.h @@ -152,6 +152,9 @@ class StickersManager : public Actor { void add_sticker_to_set(UserId user_id, string &short_name, tl_object_ptr &&sticker, Promise &&promise); + void set_sticker_set_thumbnail(UserId user_id, string &short_name, tl_object_ptr &&thumbnail, + Promise &&promise); + void set_sticker_position_in_set(const tl_object_ptr &sticker, int32 position, Promise &&promise); @@ -343,6 +346,12 @@ class StickersManager : public Actor { Promise<> promise; }; + struct PendingSetStickerSetThumbnail { + string short_name; + FileId file_id; + Promise<> promise; + }; + struct SpecialStickerSet { StickerSetId id_; int64 access_hash_ = 0; @@ -472,7 +481,8 @@ class StickersManager : public Actor { template void parse_sticker_set(StickerSet *sticker_set, ParserT &parser); - Result> prepare_input_file(const tl_object_ptr &input_file); + Result> prepare_input_file(const tl_object_ptr &input_file, + bool allow_zero); Result> prepare_input_sticker(td_api::inputSticker *sticker); @@ -492,6 +502,8 @@ class StickersManager : public Actor { void on_added_sticker_uploaded(int64 random_id, Result result); + void on_sticker_set_thumbnail_uploaded(int64 random_id, Result result); + bool update_sticker_set_cache(const StickerSet *sticker_set, Promise &promise); void start_up() override; @@ -618,6 +630,8 @@ class StickersManager : public Actor { std::unordered_map> pending_add_sticker_to_sets_; + std::unordered_map> pending_set_sticker_set_thumbnails_; + std::shared_ptr upload_sticker_file_callback_; std::unordered_map>, FileIdHash> being_uploaded_files_; diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index e75f7958e..e0b576eb3 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -2549,6 +2549,33 @@ class AddStickerToSetRequest : public RequestOnceActor { } }; +class SetStickerSetThumbnailRequest : public RequestOnceActor { + UserId user_id_; + string name_; + tl_object_ptr thumbnail_; + + void do_run(Promise &&promise) override { + td->stickers_manager_->set_sticker_set_thumbnail(user_id_, name_, std::move(thumbnail_), std::move(promise)); + } + + void do_send_result() override { + auto set_id = td->stickers_manager_->search_sticker_set(name_, Auto()); + if (!set_id.is_valid()) { + return send_error(Status::Error(500, "Sticker set not found")); + } + send_result(td->stickers_manager_->get_sticker_set_object(set_id)); + } + + public: + SetStickerSetThumbnailRequest(ActorShared td, uint64 request_id, int32 user_id, string &&name, + tl_object_ptr &&thumbnail) + : RequestOnceActor(std::move(td), request_id) + , user_id_(user_id) + , name_(std::move(name)) + , thumbnail_(std::move(thumbnail)) { + } +}; + class GetRecentStickersRequest : public RequestActor<> { bool is_attached_; @@ -6331,6 +6358,13 @@ void Td::on_request(uint64 id, td_api::addStickerToSet &request) { CREATE_REQUEST(AddStickerToSetRequest, request.user_id_, std::move(request.name_), std::move(request.sticker_)); } +void Td::on_request(uint64 id, td_api::setStickerSetThumbnail &request) { + CHECK_IS_BOT(); + CLEAN_INPUT_STRING(request.name_); + CREATE_REQUEST(SetStickerSetThumbnailRequest, request.user_id_, std::move(request.name_), + std::move(request.thumbnail_)); +} + void Td::on_request(uint64 id, td_api::setStickerPositionInSet &request) { CHECK_IS_BOT(); CREATE_OK_REQUEST_PROMISE(); diff --git a/td/telegram/Td.h b/td/telegram/Td.h index ce2bcb290..ea5583e08 100644 --- a/td/telegram/Td.h +++ b/td/telegram/Td.h @@ -837,6 +837,8 @@ class Td final : public NetQueryCallback { void on_request(uint64 id, td_api::addStickerToSet &request); + void on_request(uint64 id, td_api::setStickerSetThumbnail &request); + void on_request(uint64 id, td_api::setStickerPositionInSet &request); void on_request(uint64 id, td_api::removeStickerFromSet &request); diff --git a/td/telegram/files/FileManager.cpp b/td/telegram/files/FileManager.cpp index d1f0476ec..40ea427c6 100644 --- a/td/telegram/files/FileManager.cpp +++ b/td/telegram/files/FileManager.cpp @@ -2988,11 +2988,11 @@ Result FileManager::get_input_thumbnail_file_id(const tl_object_ptr FileManager::get_input_file_id(FileType type, const tl_object_ptr &file, DialogId owner_dialog_id, bool allow_zero, bool is_encrypted, bool get_by_hash, bool is_secure) { - if (!file) { + if (file == nullptr) { if (allow_zero) { return FileId(); } - return Status::Error(6, "InputFile not specified"); + return Status::Error(6, "InputFile is not specified"); } if (is_encrypted || is_secure) {