From 5b04ae11317d16e99966d8063ea87165e6bbb176 Mon Sep 17 00:00:00 2001 From: Mikhail Filimonov Date: Thu, 12 Mar 2026 19:29:26 +0100 Subject: [PATCH] update api --- .../ReplyMarkupMessageAttribute.swift | 10 +++ .../ApiUtils/StoreMessage_Telegram.swift | 3 + .../ApiUtils/TelegramMediaAction.swift | 2 + ...SyncCore_ReplyMarkupMessageAttribute.swift | 27 ++++++- .../SyncCore_TelegramMediaAction.swift | 10 ++- .../TelegramEngine/Peers/AddPeerMember.swift | 74 ++++++++++++++++++- .../Peers/TelegramEnginePeers.swift | 14 +++- 7 files changed, 134 insertions(+), 6 deletions(-) diff --git a/submodules/TelegramCore/Sources/ApiUtils/ReplyMarkupMessageAttribute.swift b/submodules/TelegramCore/Sources/ApiUtils/ReplyMarkupMessageAttribute.swift index 030b49a995..6619556b58 100644 --- a/submodules/TelegramCore/Sources/ApiUtils/ReplyMarkupMessageAttribute.swift +++ b/submodules/TelegramCore/Sources/ApiUtils/ReplyMarkupMessageAttribute.swift @@ -126,6 +126,11 @@ extension ReplyMarkupButton { userAdminRights: userAdminRights.flatMap(TelegramChatAdminRights.init(apiAdminRights:)), botAdminRights: botAdminRights.flatMap(TelegramChatAdminRights.init(apiAdminRights:)) )) + case let .requestPeerTypeCreateBot(data): + mappedPeerType = .createBot(ReplyMarkupButtonRequestPeerType.CreateBot( + suggestedName: data.suggestedName, + suggestedUsername: data.suggestedUsername + )) } self.init(title: text, titleWhenForwarded: nil, action: .requestPeer(peerType: mappedPeerType, buttonId: buttonId, maxQuantity: maxQuantity), style: keyboardButtonRequestPeerData.style.flatMap(ReplyMarkupButton.Style.init(apiStyle:))) case let .inputKeyboardButtonRequestPeer(inputKeyboardButtonRequestPeerData): @@ -156,6 +161,11 @@ extension ReplyMarkupButton { userAdminRights: userAdminRights.flatMap(TelegramChatAdminRights.init(apiAdminRights:)), botAdminRights: botAdminRights.flatMap(TelegramChatAdminRights.init(apiAdminRights:)) )) + case let .requestPeerTypeCreateBot(data): + mappedPeerType = .createBot(ReplyMarkupButtonRequestPeerType.CreateBot( + suggestedName: data.suggestedName, + suggestedUsername: data.suggestedUsername + )) } self.init(title: text, titleWhenForwarded: nil, action: .requestPeer(peerType: mappedPeerType, buttonId: buttonId, maxQuantity: maxQuantity), style: inputKeyboardButtonRequestPeerData.style.flatMap(ReplyMarkupButton.Style.init(apiStyle:))) case let .keyboardButtonCopy(keyboardButtonCopyData): diff --git a/submodules/TelegramCore/Sources/ApiUtils/StoreMessage_Telegram.swift b/submodules/TelegramCore/Sources/ApiUtils/StoreMessage_Telegram.swift index 8dc6ee9f96..e8342db062 100644 --- a/submodules/TelegramCore/Sources/ApiUtils/StoreMessage_Telegram.swift +++ b/submodules/TelegramCore/Sources/ApiUtils/StoreMessage_Telegram.swift @@ -242,6 +242,9 @@ func apiMessagePeerIds(_ message: Api.Message) -> [PeerId] { switch action { case .messageActionChannelCreate, .messageActionChatDeletePhoto, .messageActionChatEditPhoto, .messageActionChatEditTitle, .messageActionEmpty, .messageActionPinMessage, .messageActionHistoryClear, .messageActionGameScore, .messageActionPaymentSent, .messageActionPaymentSentMe, .messageActionPhoneCall, .messageActionScreenshotTaken, .messageActionCustomAction, .messageActionBotAllowed, .messageActionSecureValuesSent, .messageActionSecureValuesSentMe, .messageActionContactSignUp, .messageActionGroupCall, .messageActionSetMessagesTTL, .messageActionGroupCallScheduled, .messageActionSetChatTheme, .messageActionChatJoinedByRequest, .messageActionWebViewDataSent, .messageActionWebViewDataSentMe, .messageActionGiftPremium, .messageActionGiftStars, .messageActionTopicCreate, .messageActionTopicEdit, .messageActionSuggestProfilePhoto, .messageActionSetChatWallPaper, .messageActionGiveawayLaunch, .messageActionGiveawayResults, .messageActionBoostApply, .messageActionRequestedPeerSentMe, .messageActionStarGift, .messageActionStarGiftUnique, .messageActionPaidMessagesRefunded, .messageActionPaidMessagesPrice, .messageActionTodoCompletions, .messageActionTodoAppendTasks, .messageActionSuggestedPostApproval, .messageActionGiftTon, .messageActionSuggestedPostSuccess, .messageActionSuggestedPostRefund, .messageActionSuggestBirthday, .messageActionStarGiftPurchaseOffer, .messageActionStarGiftPurchaseOfferDeclined, .messageActionNoForwardsToggle, .messageActionNoForwardsRequest: break + case let .messageActionManagedBotCreated(messageActionManagedBotCreated): + let botId = messageActionManagedBotCreated.botId + result.append(PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(botId))) case let .messageActionChannelMigrateFrom(messageActionChannelMigrateFromData): let chatId = messageActionChannelMigrateFromData.chatId result.append(PeerId(namespace: Namespaces.Peer.CloudGroup, id: PeerId.Id._internalFromInt64Value(chatId))) diff --git a/submodules/TelegramCore/Sources/ApiUtils/TelegramMediaAction.swift b/submodules/TelegramCore/Sources/ApiUtils/TelegramMediaAction.swift index 9f2360954f..338718bfad 100644 --- a/submodules/TelegramCore/Sources/ApiUtils/TelegramMediaAction.swift +++ b/submodules/TelegramCore/Sources/ApiUtils/TelegramMediaAction.swift @@ -363,6 +363,8 @@ func telegramMediaActionFromApiAction(_ action: Api.MessageAction) -> TelegramMe return TelegramMediaAction(action: .copyProtectionToggle(previousValue: messageActionNoForwardsToggleData.prevValue == .boolTrue, newValue: messageActionNoForwardsToggleData.newValue == .boolTrue)) case let .messageActionNoForwardsRequest(messageActionNoForwardsRequestData): return TelegramMediaAction(action: .copyProtectionRequest(hasExpired: (messageActionNoForwardsRequestData.flags & (1 << 0)) != 0, previousValue: messageActionNoForwardsRequestData.prevValue == .boolTrue, newValue: messageActionNoForwardsRequestData.newValue == .boolTrue)) + case let .messageActionManagedBotCreated(data): + return TelegramMediaAction(action: .managedBotCreated(botId: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(data.botId)))) } } diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_ReplyMarkupMessageAttribute.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_ReplyMarkupMessageAttribute.swift index 22596fe4f5..1ad0982456 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_ReplyMarkupMessageAttribute.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_ReplyMarkupMessageAttribute.swift @@ -7,12 +7,14 @@ public enum ReplyMarkupButtonRequestPeerType: Codable, Equatable { case user = "u" case group = "g" case channel = "c" + case createBot = "cb" } - + enum Discriminator: Int32 { case user = 0 case group = 1 case channel = 2 + case createBot = 3 } public struct User: Codable, Equatable { @@ -144,10 +146,26 @@ public enum ReplyMarkupButtonRequestPeerType: Codable, Equatable { } } + public struct CreateBot: Codable, Equatable { + enum CodingKeys: String, CodingKey { + case suggestedName = "sn" + case suggestedUsername = "su" + } + + public var suggestedName: String? + public var suggestedUsername: String? + + public init(suggestedName: String?, suggestedUsername: String?) { + self.suggestedName = suggestedName + self.suggestedUsername = suggestedUsername + } + } + case user(User) case group(Group) case channel(Channel) - + case createBot(CreateBot) + public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) @@ -158,6 +176,8 @@ public enum ReplyMarkupButtonRequestPeerType: Codable, Equatable { self = .group(try container.decode(Group.self, forKey: .group)) case Discriminator.channel.rawValue: self = .channel(try container.decode(Channel.self, forKey: .channel)) + case Discriminator.createBot.rawValue: + self = .createBot(try container.decode(CreateBot.self, forKey: .createBot)) default: assertionFailure() self = .user(User(isBot: nil, isPremium: nil)) @@ -177,6 +197,9 @@ public enum ReplyMarkupButtonRequestPeerType: Codable, Equatable { case let .channel(channel): try container.encode(Discriminator.channel.rawValue, forKey: .discriminator) try container.encode(channel, forKey: .channel) + case let .createBot(createBot): + try container.encode(Discriminator.createBot.rawValue, forKey: .discriminator) + try container.encode(createBot, forKey: .createBot) } } } diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramMediaAction.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramMediaAction.swift index 412d1e674c..4496c77074 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramMediaAction.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramMediaAction.swift @@ -304,7 +304,8 @@ public enum TelegramMediaActionType: PostboxCoding, Equatable { case groupCreatorChange(GroupCreatorChange) case copyProtectionToggle(previousValue: Bool, newValue: Bool) case copyProtectionRequest(hasExpired: Bool, previousValue: Bool, newValue: Bool) - + case managedBotCreated(botId: PeerId) + public init(decoder: PostboxDecoder) { let rawValue: Int32 = decoder.decodeInt32ForKey("_rawValue", orElse: 0) switch rawValue { @@ -481,6 +482,8 @@ public enum TelegramMediaActionType: PostboxCoding, Equatable { self = .copyProtectionToggle(previousValue: decoder.decodeBoolForKey("previousValue", orElse: false), newValue: decoder.decodeBoolForKey("newValue", orElse: false)) case 61: self = .copyProtectionRequest(hasExpired: decoder.decodeBoolForKey("hasExpired", orElse: false), previousValue: decoder.decodeBoolForKey("previousValue", orElse: false), newValue: decoder.decodeBoolForKey("newValue", orElse: false)) + case 62: + self = .managedBotCreated(botId: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(decoder.decodeInt64ForKey("botId", orElse: 0)))) default: self = .unknown } @@ -984,6 +987,9 @@ public enum TelegramMediaActionType: PostboxCoding, Equatable { encoder.encodeBool(hasExpired, forKey: "hasExpired") encoder.encodeBool(previousValue, forKey: "previousValue") encoder.encodeBool(newValue, forKey: "newValue") + case let .managedBotCreated(botId): + encoder.encodeInt32(62, forKey: "_rawValue") + encoder.encodeInt64(botId.toInt64(), forKey: "botId") } } @@ -1042,6 +1048,8 @@ public enum TelegramMediaActionType: PostboxCoding, Equatable { return conferenceCall.otherParticipants case let .groupCreatorChange(groupCreatorChange): return [groupCreatorChange.targetPeerId] + case let .managedBotCreated(botId): + return [botId] default: return [] } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Peers/AddPeerMember.swift b/submodules/TelegramCore/Sources/TelegramEngine/Peers/AddPeerMember.swift index 9b11d0b92f..691c6f25cd 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Peers/AddPeerMember.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Peers/AddPeerMember.swift @@ -350,7 +350,7 @@ public enum SendBotRequestedPeerError { case generic } -func _internal_sendBotRequestedPeer(account: Account, peerId: PeerId, messageId: MessageId, buttonId: Int32, requestedPeerIds: [PeerId]) -> Signal { +func _internal_sendBotRequestedPeer(account: Account, peerId: PeerId, messageId: MessageId?, requestId: String?, buttonId: Int32, requestedPeerIds: [PeerId]) -> Signal { return account.postbox.transaction { transaction -> Signal in if let peer = transaction.getPeer(peerId) { var inputRequestedPeers: [Api.InputPeer] = [] @@ -360,7 +360,16 @@ func _internal_sendBotRequestedPeer(account: Account, peerId: PeerId, messageId: } } if let inputPeer = apiInputPeer(peer), !inputRequestedPeers.isEmpty { - let signal = account.network.request(Api.functions.messages.sendBotRequestedPeer(peer: inputPeer, msgId: messageId.id, buttonId: buttonId, requestedPeers: inputRequestedPeers)) + var flags: Int32 = 0 + var msgId: Int32? + if let messageId = messageId { + flags |= (1 << 0) + msgId = messageId.id + } + if let _ = requestId { + flags |= (1 << 1) + } + let signal = account.network.request(Api.functions.messages.sendBotRequestedPeer(flags: flags, peer: inputPeer, msgId: msgId, requestId: requestId, buttonId: buttonId, requestedPeers: inputRequestedPeers)) |> mapError { error -> SendBotRequestedPeerError in return .generic } @@ -375,3 +384,64 @@ func _internal_sendBotRequestedPeer(account: Account, peerId: PeerId, messageId: |> castError(SendBotRequestedPeerError.self) |> switchToLatest } + +public enum CreateBotError { + case generic +} + +func _internal_createBot(account: Account, name: String, username: String, managerPeerId: PeerId, viaDeeplink: Bool) -> Signal { + return account.postbox.transaction { transaction -> Api.InputUser? in + if let peer = transaction.getPeer(managerPeerId) { + return apiInputUser(peer) + } + return nil + } + |> castError(CreateBotError.self) + |> mapToSignal { inputUser -> Signal in + guard let inputUser = inputUser else { + return .fail(.generic) + } + var flags: Int32 = 0 + if viaDeeplink { + flags |= (1 << 0) + } + return account.network.request(Api.functions.bots.createBot(flags: flags, name: name, username: username, managerId: inputUser)) + |> mapError { _ -> CreateBotError in + return .generic + } + |> mapToSignal { apiUser -> Signal in + return account.postbox.transaction { transaction -> EnginePeer in + let user = TelegramUser(user: apiUser) + updatePeers(transaction: transaction, accountPeerId: account.peerId, peers: AccumulatedPeers(transaction: transaction, chats: [], users: [apiUser])) + return EnginePeer(user) + } + |> castError(CreateBotError.self) + } + } +} + +public enum GetRequestedWebViewButtonError { + case generic +} + +func _internal_getRequestedWebViewButton(account: Account, botId: PeerId, requestId: String) -> Signal { + return account.postbox.transaction { transaction -> Api.InputUser? in + if let peer = transaction.getPeer(botId) { + return apiInputUser(peer) + } + return nil + } + |> castError(GetRequestedWebViewButtonError.self) + |> mapToSignal { inputUser -> Signal in + guard let inputUser = inputUser else { + return .fail(.generic) + } + return account.network.request(Api.functions.bots.getRequestedWebViewButton(bot: inputUser, requestId: requestId)) + |> mapError { _ -> GetRequestedWebViewButtonError in + return .generic + } + |> map { apiButton -> ReplyMarkupButton in + return ReplyMarkupButton(apiButton: apiButton) + } + } +} diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Peers/TelegramEnginePeers.swift b/submodules/TelegramCore/Sources/TelegramEngine/Peers/TelegramEnginePeers.swift index 1370ffcfc5..8a1236f933 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Peers/TelegramEnginePeers.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Peers/TelegramEnginePeers.swift @@ -637,7 +637,19 @@ public extension TelegramEngine { } public func sendBotRequestedPeer(messageId: MessageId, buttonId: Int32, requestedPeerIds: [PeerId]) -> Signal { - return _internal_sendBotRequestedPeer(account: self.account, peerId: messageId.peerId, messageId: messageId, buttonId: buttonId, requestedPeerIds: requestedPeerIds) + return _internal_sendBotRequestedPeer(account: self.account, peerId: messageId.peerId, messageId: messageId, requestId: nil, buttonId: buttonId, requestedPeerIds: requestedPeerIds) + } + + public func sendBotRequestedPeer(peerId: PeerId, requestId: String, buttonId: Int32, requestedPeerIds: [PeerId]) -> Signal { + return _internal_sendBotRequestedPeer(account: self.account, peerId: peerId, messageId: nil, requestId: requestId, buttonId: buttonId, requestedPeerIds: requestedPeerIds) + } + + public func createBot(name: String, username: String, managerPeerId: PeerId, viaDeeplink: Bool) -> Signal { + return _internal_createBot(account: self.account, name: name, username: username, managerPeerId: managerPeerId, viaDeeplink: viaDeeplink) + } + + public func getRequestedWebViewButton(botId: PeerId, requestId: String) -> Signal { + return _internal_getRequestedWebViewButton(account: self.account, botId: botId, requestId: requestId) } public func addChannelMembers(peerId: PeerId, memberIds: [PeerId]) -> Signal {