diff --git a/.azure-pipelines/variables.yml b/.azure-pipelines/variables.yml index f62e9d522..f26fdfe0c 100644 --- a/.azure-pipelines/variables.yml +++ b/.azure-pipelines/variables.yml @@ -3,7 +3,7 @@ variables: - name: versionPrefix value: 20.0.0 - name: versionSuffix - value: 'alpha.2' + value: 'alpha.3' - name: ciVersionSuffix value: ci.$(Build.BuildId)+git.commit.$(Build.SourceVersion) - name: isPreRelease diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 94397f0ca..676357a4d 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,5 +1,5 @@ -ARG DOTNET_VERSION=6.0 -FROM mcr.microsoft.com/dotnet/sdk:${DOTNET_VERSION}-bullseye-slim +ARG DOTNET_VERSION=8.0 +FROM mcr.microsoft.com/dotnet/sdk:${DOTNET_VERSION}-bookworm-slim ARG USERNAME=vscode ARG USER_UID=1000 ARG USER_GID=${USER_UID} diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index a79f624d2..e88852588 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -4,14 +4,18 @@ "service": "devhost", "shutdownAction": "stopCompose", "workspaceFolder": "/workspace", - "extensions": [ - "ms-dotnettools.csharp", - "ms-azuretools.vscode-docker", - "editorconfig.editorconfig", - "eamodio.gitlens", - "tintoy.msbuild-project-tools", - "logerfo.sln-support", - "formulahendry.dotnet-test-explorer" - ], + "customizations": { + "vscode": { + "extensions": [ + "ms-dotnettools.csdevkit", + "ms-azuretools.vscode-docker", + "editorconfig.editorconfig", + "eamodio.gitlens", + "tintoy.msbuild-project-tools", + "logerfo.sln-support", + "formulahendry.dotnet-test-explorer" + ] + } + }, "remoteUser": "vscode" } diff --git a/CHANGELOG.md b/CHANGELOG.md index 3414d4887..feea649b1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,120 @@ and this project adheres to [Semantic Versioning](https://semver.org/). +## [Unreleased] + +> [Bot API 7.0](https://core.telegram.org/bots/api#december-29-2023) (December 29, 2023) +> [Bot API 7.1](https://core.telegram.org/bots/api#february-16-2024) (February 16, 2024) + +### Added + +- API methods on `ITelegramBotClient` that accept request classes with parameters +- Class `UnpinAllGeneralForumTopicMessagesRequest` +- The classes `ReactionType`, `ReactionTypeEmoji` and `ReactionTypeCustomEmoji` representing different types of reaction. +- Enum `ReactionTypeKind` +- Enum `ChatBoostSourceType` +- The class `KnownReactionTypeEmoji` containing Emojis available for `ReactionTypeEmoji`. +- Updates about a reaction change on a message with non-anonymous reactions, represented by the class `MessageReactionUpdated` +and the property `MessageReaction` in the class `Update`. The bot must explicitly allow the update to receive it. +- Updates about reaction changes on a message with anonymous reactions, represented by the class `MessageReactionCountUpdated` +and the property `MessageReactionCount` in the class `Update`. The bot must explicitly allow the update to receive it. +- New enum values `MessageReaction`, `MessageReactionCount` for `UpdateType`. +- Type `ReactionCount`. +- Request classes `SetMessageReactionRequest` that allows bots to react to messages. +- New method `ITelegramBotClient.SetMessageReactionAsync` that allows bots to react to messages. +- The property `AvailableReactions` to the class `Chat`. +- The class `ExternalReplyInfo` and the property `ExternalReply` of type `ExternalReplyInfo` to the class `Message`, +containing information about a message that is replied to by the current message, but can be from another chat or forum topic. +- The class `TextQuote` and the property `Quote` of type `TextQuote` to the class `Message`, +which contains the part of the replied message text or caption that is quoted in the current message. +- The class `ReplyParameters`. +- The class `LinkPreviewOptions`. +- The property `LinkPreviewOptions` to the class `Message` with information about the link preview options used to send the message. +- New enum value `Blockquote` for `MessageEntityType`. +- Request classes `DeleteMessagesRequest`, `ForwardMessagesRequest` and `CopyMessagesRequest`. +- New methods `ITelegramBotClient.DeleteMessagesAsync`, `ITelegramBotClient.ForwardMessagesAsync` and `ITelegramBotClient.CopyMessagesAsync`. +- Updates about chat boost changes, represented by the classes `ChatBoostUpdated` and `ChatBoostRemoved` and the properties `ChatBoost` and `RemovedChatBoost` +in the class `Update`. The bot must be an administrator in the chat to receive these updates. +- The classes `ChatBoostSourcePremium`, `ChatBoostSourceGiftCode` and `ChatBoostSourceGiveaway`, representing different sources of a chat boost. +- The method `ITelegramBotClient.GetUserChatBoostsAsync` for obtaining the list of all active boosts a user has contributed to a chat. +- Request class `GetUserChatBoostsRequest` for obtaining the list of all active boosts a user has contributed to a chat. +- The class `Giveaway` and the property `Giveaway` to the class `Message` for messages about scheduled giveaways. +- The class `GiveawayCreated` and the property `GiveawayCreated` to the class `Message` for service messages about the creation of a scheduled giveaway. +- The class `GiveawayWinners` and the property `GiveawayWinners` to the class `Message` for messages about the completion of a giveaway with public winners. +- The class `GiveawayCompleted` and the property `GiveawayCompleted` to the class `Message` for service messages about the completion of a giveaway without public winners. +- New `MessageType` enum members: `Giveaway`, `GiveawayCreated`, `GiveawayWinners` and `GiveawayCompleted` +- The properties `AccentColorId`, `BackgroundCustomEmojiId`, `ProfileAccentColorId`, and `ProfileBackgroundCustomEmojiId` to the class `Chat`. +- The property `HasVisibleHistory` to the class `Chat`. +- Classes `MaybeInaccessibleMessage` and `InaccessibleMessage`. +- The class `ChatBoostAdded` +- Classes `MessageOrigin`, `MessageOriginUser`, `MessageOriginHiddenUser` and `MessageOriginChannel` +- Enum `MessageOriginType` +- Fields `UnrestrictBoostCount` and `CustomEmojiStickerSetName` to type `Chat` +- Enum member `MessageType.BoostAdded` +- Fields `SenderBoostCount`, `ReplyToStory` and `BoostAdded` to type `Message` +- Fields `Chat` and `Id` to type `Story` + +### Changed +- All required properties without setters marked as required using `required` keyword +- All non-default ctors are marked as obsolete in favor of the default ctors with object initialization syntax and required properties +- All API methods with positional parameters on `ITelegramBotClient` are marked obsolete +- Class `UnpinAllGeneralForumTopicMessages` marked as obsolete +- Replaced parameters `ReplyToMessageId` and `AllowSendingWithoutReply` with the property `ReplyParameters` of type `ReplyParameters` in the methods + - `ITelegramBotClient.CopyMessageAsync`, + - `ITelegramBotClient.SendMessageAsync`, + - `ITelegramBotClient.SendPhotoAsync`, + - `ITelegramBotClient.SendVideoAsync`, + - `ITelegramBotClient.SendAnimationAsync`, + - `ITelegramBotClient.SendAudioAsync`, + - `ITelegramBotClient.SendDocumentAsync`, + - `ITelegramBotClient.SendStickerAsync`, + - `ITelegramBotClient.SendVideoNoteAsync`, + - `ITelegramBotClient.SendVoiceAsync`, + - `ITelegramBotClient.SendLocationAsync`, + - `ITelegramBotClient.SendVenueAsync`, + - `ITelegramBotClient.SendContactAsync`, + - `ITelegramBotClient.SendPollAsync`, + - `ITelegramBotClient.SendDiceAsync`, + - `ITelegramBotClient.SendInvoiceAsync`, + - `ITelegramBotClient.SendGameAsync`, + - `ITelegramBotClient.SendMediaGroupAsync` +- Replaced properties `ReplyToMessageId` and `AllowSendingWithoutReply` with the property `ReplyParameters` of type `ReplyParameters` in the request classes + - `CopyMessageRequest`, + - `SendMessageRequest`, + - `SendPhotoRequest`, + - `SendVideoRequest`, + - `SendAnimationRequest`, + - `SendAudioRequest`, + - `SendDocumentRequest`, + - `SendStickerRequest`, + - `SendVideoNoteRequest`, + - `SendVoiceRequest`, + - `SendLocationRequest`, + - `SendVenueRequest`, + - `SendContactRequest`, + - `SendPollRequest`, + - `SendDiceRequest`, + - `SendInvoiceRequest`, + - `SendGameRequest`, + - `SendMediaGroupRequest` +- Replaced the parameter `DisableWebPagePreview` with `LinkPreviewOptions` in the methods `SendTextMessageAsync` and `EditMessageTextAsync`. +- Replaced the property `DisableWebPagePreview` with `LinkPreviewOptions` in the request classes `SendMessageRequest`, `EditMessageTextRequest` + and `EditInlineMessageTextRequest`. +- Replaced the property disable_web_page_preview with `DisableWebPagePreview` in the class `InputTextMessageContent`. +- Renamed the class `KeyboardButtonRequestUser` to `KeyboardButtonRequestUsers` and added the property `MaxQuantity` to it. +- Renamed the property `RequestUser` in the class `KeyboardButton` to `RequestUsers`. The old name will still work for backward compatibility. +- Renamed the class `UserShared` to `UsersShared` and changed the property `UserId` to `UserIds`. +- Replaced the property `UserShared` in the class Message with the property `UsersShared`. +- Replaced enum member `MessageType.UserShared` with `MessageType.UsersShared` +- Fields `ForwardFrom`, `ForwardFromChat`, `ForwardFromMessageId`, `ForwardSignature`, `ForwardSenderName` +and `ForwardDate` replaced with the field `ForwardOrigin` of type `MessageOrigin` in the class `Message`. +- Type of the property `Message` of the class `CallbackQuery` to `MaybeInaccessibleMessage` +- Type of the property `PinnedMessage` of the class `Message` to `MaybeInaccessibleMessage`. + +### Removed +- Fields `ForwardFrom`, `ForwardFromChat`, `ForwardFromMessageId`, `ForwardSignature`, `ForwardSenderName` + and `ForwardDate` from type `Message` + ## [v20.0.0] - Unreleased > [Bot API 6.9](https://core.telegram.org/bots/api#september-22-2023) (September 22, 2023) diff --git a/Directory.Build.props b/Directory.Build.props new file mode 100644 index 000000000..9f6a21db5 --- /dev/null +++ b/Directory.Build.props @@ -0,0 +1,5 @@ + + + en + + diff --git a/README.md b/README.md index daf9c3f35..8ebc3ade9 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # .NET Client for Telegram Bot API [![package](https://img.shields.io/nuget/vpre/Telegram.Bot.svg?label=Telegram.Bot&style=flat-square)](https://www.nuget.org/packages/Telegram.Bot) -[![Bot API Version](https://img.shields.io/badge/Bot%20API-6.9%20(September%2022,%202023)-f36caf.svg?style=flat-square)](https://core.telegram.org/bots/api#september-22-2023) +[![Bot API Version](https://img.shields.io/badge/Bot%20API-7.1%20(February%2016,%202024)-f36caf.svg?style=flat-square)](https://core.telegram.org/bots/api#february-16-2024) [![documentations](https://img.shields.io/badge/Documentations-Book-orange.svg?style=flat-square)](https://telegrambots.github.io/book/) [![telegram chat](https://img.shields.io/badge/Support_Chat-Telegram-blue.svg?style=flat-square)](https://t.me/joinchat/B35YY0QbLfd034CFnvCtCA) diff --git a/Telegram.Bot.sln b/Telegram.Bot.sln index db2d533c5..8c5817cac 100644 --- a/Telegram.Bot.sln +++ b/Telegram.Bot.sln @@ -25,6 +25,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution .gitignore = .gitignore .gitpod.yml = .gitpod.yml LICENSE = LICENSE + Directory.Build.props = Directory.Build.props EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".azure-pipelines", ".azure-pipelines", "{71662597-40F2-4192-AC4D-5FB9A1F12642}" diff --git a/src/EnumSerializer.Generator/EnumSerializer.Generator.csproj b/src/EnumSerializer.Generator/EnumSerializer.Generator.csproj index d95a01efa..d4d409290 100644 --- a/src/EnumSerializer.Generator/EnumSerializer.Generator.csproj +++ b/src/EnumSerializer.Generator/EnumSerializer.Generator.csproj @@ -14,10 +14,10 @@ - + - - + + diff --git a/src/Telegram.Bot/Converters/ChatBoostSourceConverter.cs b/src/Telegram.Bot/Converters/ChatBoostSourceConverter.cs new file mode 100644 index 000000000..fc1e79983 --- /dev/null +++ b/src/Telegram.Bot/Converters/ChatBoostSourceConverter.cs @@ -0,0 +1,58 @@ +using System.Reflection; +using Newtonsoft.Json.Linq; +using Telegram.Bot.Types.Enums; + +namespace Telegram.Bot.Converters; + +internal class ChatBoostSourceConverter : JsonConverter +{ + static readonly TypeInfo BaseType = typeof(ChatBoostSource).GetTypeInfo(); + + public override bool CanWrite => false; + public override bool CanRead => true; + public override bool CanConvert(Type objectType) => + BaseType.IsAssignableFrom(objectType.GetTypeInfo()); + + public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) + { + if (value is null) + { + writer.WriteNull(); + } + else + { + var jo = JObject.FromObject(value); + jo.WriteTo(writer); + } + } + + public override object? ReadJson( + JsonReader reader, + Type objectType, + object? existingValue, + JsonSerializer serializer) + { + var jo = JObject.Load(reader); + var type = jo["source"]?.ToObject(); + + if (type is null) + { + return null; + } + + var actualType = type switch + { + ChatBoostSourceType.Premium => typeof(ChatBoostSourcePremium), + ChatBoostSourceType.GiftCode => typeof(ChatBoostSourceGiftCode), + ChatBoostSourceType.Giveaway => typeof(ChatBoostSourceGiveaway), + _ => throw new JsonSerializationException($"Unknown chat boost source value of '{jo["source"]}'") + }; + + // Remove status because status property only has getter + jo.Remove("source"); + var value = Activator.CreateInstance(actualType)!; + serializer.Populate(jo.CreateReader(), value); + + return value; + } +} diff --git a/src/Telegram.Bot/Converters/InputFileConverter.cs b/src/Telegram.Bot/Converters/InputFileConverter.cs index 1ca84c50e..0a30ef462 100644 --- a/src/Telegram.Bot/Converters/InputFileConverter.cs +++ b/src/Telegram.Bot/Converters/InputFileConverter.cs @@ -32,7 +32,7 @@ public override void WriteJson(JsonWriter writer, InputFile? value, JsonSerializ } return Uri.TryCreate(value, UriKind.Absolute, out var url) - ? new InputFileUrl(url) - : new InputFileId(value); + ? InputFile.FromUri(url) + : InputFile.FromFileId(value); } } diff --git a/src/Telegram.Bot/Converters/MaybeInaccessibleMessageConverter.cs b/src/Telegram.Bot/Converters/MaybeInaccessibleMessageConverter.cs new file mode 100644 index 000000000..26508e1be --- /dev/null +++ b/src/Telegram.Bot/Converters/MaybeInaccessibleMessageConverter.cs @@ -0,0 +1,54 @@ +using System.Reflection; +using Newtonsoft.Json.Linq; + +namespace Telegram.Bot.Converters; + +internal class MaybeInaccessibleMessageConverter : JsonConverter +{ + static readonly TypeInfo BaseType = typeof(MaybeInaccessibleMessage).GetTypeInfo(); + + public override bool CanWrite => false; + public override bool CanRead => true; + public override bool CanConvert(Type objectType) => + BaseType.IsAssignableFrom(objectType.GetTypeInfo()); + + public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) + { + if (value is null) + { + writer.WriteNull(); + } + else + { + var jo = JObject.FromObject(value); + jo.WriteTo(writer); + } + } + + public override object? ReadJson( + JsonReader reader, + Type objectType, + object? existingValue, + JsonSerializer serializer) + { + var jo = JObject.Load(reader); + var date = jo["date"]?.Value(); + + if (date is null) + { + return null; + } + + var actualType = date switch + { + 0 => typeof(InaccessibleMessage), + _ => typeof(Message), + }; + + // Remove status because status property only has getter + var value = Activator.CreateInstance(actualType)!; + serializer.Populate(jo.CreateReader(), value); + + return value; + } +} diff --git a/src/Telegram.Bot/Converters/MessageOriginConverter.cs b/src/Telegram.Bot/Converters/MessageOriginConverter.cs new file mode 100644 index 000000000..11b7e8439 --- /dev/null +++ b/src/Telegram.Bot/Converters/MessageOriginConverter.cs @@ -0,0 +1,59 @@ +using System.Reflection; +using Newtonsoft.Json.Linq; +using Telegram.Bot.Types.Enums; + +namespace Telegram.Bot.Converters; + +internal class MessageOriginConverter : JsonConverter +{ + static readonly TypeInfo BaseType = typeof(MessageOrigin).GetTypeInfo(); + + public override bool CanWrite => false; + public override bool CanRead => true; + public override bool CanConvert(Type objectType) => + BaseType.IsAssignableFrom(objectType.GetTypeInfo()); + + public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) + { + if (value is null) + { + writer.WriteNull(); + } + else + { + var jo = JObject.FromObject(value); + jo.WriteTo(writer); + } + } + + public override object? ReadJson( + JsonReader reader, + Type objectType, + object? existingValue, + JsonSerializer serializer) + { + var jo = JObject.Load(reader); + var type = jo["type"]?.ToObject(); + + if (type is null) + { + return null; + } + + var actualType = type switch + { + MessageOriginType.User => typeof(MessageOriginUser), + MessageOriginType.HiddenUser => typeof(MessageOriginHiddenUser), + MessageOriginType.Chat => typeof(MessageOriginChat), + MessageOriginType.Channel => typeof(MessageOriginChannel), + _ => throw new JsonSerializationException($"Unknown message origin type value of '{jo["type"]}'") + }; + + // Remove status because status property only has getter + jo.Remove("type"); + var value = Activator.CreateInstance(actualType)!; + serializer.Populate(jo.CreateReader(), value); + + return value; + } +} diff --git a/src/Telegram.Bot/Converters/ReactionTypeConverter.cs b/src/Telegram.Bot/Converters/ReactionTypeConverter.cs new file mode 100644 index 000000000..382f7281b --- /dev/null +++ b/src/Telegram.Bot/Converters/ReactionTypeConverter.cs @@ -0,0 +1,56 @@ +using System.Reflection; +using Newtonsoft.Json.Linq; + +namespace Telegram.Bot.Converters; + +internal class ReactionTypeConverter : JsonConverter +{ + static readonly TypeInfo BaseType = typeof(ReactionType).GetTypeInfo(); + + public override bool CanWrite => false; + public override bool CanRead => true; + public override bool CanConvert(Type objectType) => + BaseType.IsAssignableFrom(objectType.GetTypeInfo()); + + public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) + { + if (value is null) + { + writer.WriteNull(); + } + else + { + var jo = JObject.FromObject(value); + jo.WriteTo(writer); + } + } + + public override object? ReadJson( + JsonReader reader, + Type objectType, + object? existingValue, + JsonSerializer serializer) + { + var jo = JObject.Load(reader); + var type = jo["type"]?.Value(); + + if (type is null) + { + return null; + } + + var actualType = type switch + { + "emoji" => typeof(ReactionTypeEmoji), + "custom_emoji" => typeof(ReactionTypeCustomEmoji), + _ => throw new JsonSerializationException($"Unknown reaction type value of '{jo["type"]}'") + }; + + // Remove status because status property only has getter + jo.Remove("type"); + var value = Activator.CreateInstance(actualType)!; + serializer.Populate(jo.CreateReader(), value); + + return value; + } +} diff --git a/src/Telegram.Bot/Requests/Abstractions/Documentation.cs b/src/Telegram.Bot/Requests/Abstractions/Documentation.cs index 3202bd265..f353e976f 100644 --- a/src/Telegram.Bot/Requests/Abstractions/Documentation.cs +++ b/src/Telegram.Bot/Requests/Abstractions/Documentation.cs @@ -1,6 +1,6 @@ #nullable disable #pragma warning disable 169 -#pragma warning disable CA1823 +#pragma warning disable IDE0051 using Telegram.Bot.Types.ReplyMarkups; @@ -57,14 +57,9 @@ internal static class Documentation static readonly object DisableNotification; /// - /// If the message is a reply, ID of the original message + /// Description of the message to reply to /// - static readonly object ReplyToMessageId; - - /// - /// Pass , if the message should be sent even if the specified replied-to message is not found - /// - static readonly object AllowSendingWithoutReply; + static readonly object ReplyParameters; /// /// Thumbnail of the file sent; can be ignored if thumbnail generation for the file is supported diff --git a/src/Telegram.Bot/Requests/Available methods/AnswerCallbackQueryRequest.cs b/src/Telegram.Bot/Requests/Available methods/AnswerCallbackQueryRequest.cs index ea52aee09..ed41d35f0 100644 --- a/src/Telegram.Bot/Requests/Available methods/AnswerCallbackQueryRequest.cs +++ b/src/Telegram.Bot/Requests/Available methods/AnswerCallbackQueryRequest.cs @@ -1,3 +1,5 @@ +using System.Diagnostics.CodeAnalysis; + // ReSharper disable once CheckNamespace namespace Telegram.Bot.Requests; @@ -19,7 +21,7 @@ public class AnswerCallbackQueryRequest : RequestBase /// Unique identifier for the query to be answered /// [JsonProperty(Required = Required.Always)] - public string CallbackQueryId { get; } + public required string CallbackQueryId { get; init; } /// /// Text of the notification. If not specified, nothing will be shown to the user, 0-200 characters @@ -54,12 +56,19 @@ public class AnswerCallbackQueryRequest : RequestBase [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] public int? CacheTime { get; set; } + /// + /// Initializes a new request with callbackQueryId + /// + public AnswerCallbackQueryRequest() : base("answerCallbackQuery") { } + /// /// Initializes a new request with callbackQueryId /// /// Unique identifier for the query to be answered + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public AnswerCallbackQueryRequest(string callbackQueryId) - : base("answerCallbackQuery") + : this() { CallbackQueryId = callbackQueryId; } diff --git a/src/Telegram.Bot/Requests/Available methods/Commands/SetMyCommandsRequest.cs b/src/Telegram.Bot/Requests/Available methods/Commands/SetMyCommandsRequest.cs index 49afa7909..ac5051f9b 100644 --- a/src/Telegram.Bot/Requests/Available methods/Commands/SetMyCommandsRequest.cs +++ b/src/Telegram.Bot/Requests/Available methods/Commands/SetMyCommandsRequest.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; // ReSharper disable once CheckNamespace namespace Telegram.Bot.Requests; @@ -16,7 +17,7 @@ public class SetMyCommandsRequest : RequestBase /// At most 100 commands can be specified. /// [JsonProperty(Required = Required.Always)] - public IEnumerable Commands { get; } + public required IEnumerable Commands { get; init; } /// /// An object, describing scope of users for which the commands are relevant. @@ -36,9 +37,18 @@ public class SetMyCommandsRequest : RequestBase /// Initializes a new request with commands /// /// A list of bot commands to be set + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public SetMyCommandsRequest(IEnumerable commands) - : base("setMyCommands") + : this() { Commands = commands; } + + /// + /// Initializes a new request with commands + /// + public SetMyCommandsRequest() + : base("setMyCommands") + { } } diff --git a/src/Telegram.Bot/Requests/Available methods/Get Files/GetFileRequest.cs b/src/Telegram.Bot/Requests/Available methods/Get Files/GetFileRequest.cs index 6c189f65e..c062fd337 100644 --- a/src/Telegram.Bot/Requests/Available methods/Get Files/GetFileRequest.cs +++ b/src/Telegram.Bot/Requests/Available methods/Get Files/GetFileRequest.cs @@ -1,4 +1,7 @@ // ReSharper disable once CheckNamespace + +using System.Diagnostics.CodeAnalysis; + namespace Telegram.Bot.Requests; /// @@ -21,15 +24,24 @@ public class GetFileRequest : RequestBase /// File identifier to get info about /// [JsonProperty(Required = Required.Always)] - public string FileId { get; } + public required string FileId { get; init; } /// /// Initializes a new request with /// /// File identifier to get info about + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public GetFileRequest(string fileId) - : base("getFile") + : this() { FileId = fileId; } + + /// + /// Initializes a new request + /// + public GetFileRequest() + : base("getFile") + { } } diff --git a/src/Telegram.Bot/Requests/Available methods/Get Files/GetUserProfilePhotosRequest.cs b/src/Telegram.Bot/Requests/Available methods/Get Files/GetUserProfilePhotosRequest.cs index 1c5efc2e6..b4591778b 100644 --- a/src/Telegram.Bot/Requests/Available methods/Get Files/GetUserProfilePhotosRequest.cs +++ b/src/Telegram.Bot/Requests/Available methods/Get Files/GetUserProfilePhotosRequest.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Requests.Abstractions; // ReSharper disable once CheckNamespace @@ -12,7 +13,7 @@ public class GetUserProfilePhotosRequest : RequestBase, IUser { /// [JsonProperty(Required = Required.Always)] - public long UserId { get; } + public required long UserId { get; init; } /// /// Sequential number of the first photo to be returned. By default, all photos are returned @@ -30,9 +31,18 @@ public class GetUserProfilePhotosRequest : RequestBase, IUser /// Initializes a new request with userId /// /// Unique identifier of the target user + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public GetUserProfilePhotosRequest(long userId) - : base("getUserProfilePhotos") + : this() { UserId = userId; } + + /// + /// Initializes a new request with userId + /// + public GetUserProfilePhotosRequest() + : base("getUserProfilePhotos") + { } } diff --git a/src/Telegram.Bot/Requests/Available methods/GetMyDefaultAdministratorRightsRequest.cs b/src/Telegram.Bot/Requests/Available methods/GetMyDefaultAdministratorRightsRequest.cs index fde9f8d90..85d99e7c3 100644 --- a/src/Telegram.Bot/Requests/Available methods/GetMyDefaultAdministratorRightsRequest.cs +++ b/src/Telegram.Bot/Requests/Available methods/GetMyDefaultAdministratorRightsRequest.cs @@ -1,4 +1,7 @@ // ReSharper disable once CheckNamespace + +using System.Diagnostics.CodeAnalysis; + namespace Telegram.Bot.Requests; /// diff --git a/src/Telegram.Bot/Requests/Available methods/GetUserChatBoostsRequest.cs b/src/Telegram.Bot/Requests/Available methods/GetUserChatBoostsRequest.cs new file mode 100644 index 000000000..62dce8505 --- /dev/null +++ b/src/Telegram.Bot/Requests/Available methods/GetUserChatBoostsRequest.cs @@ -0,0 +1,48 @@ +using System.Diagnostics.CodeAnalysis; + +// ReSharper disable once CheckNamespace +namespace Telegram.Bot.Requests; + +/// +/// Use this method to get the list of boosts added to a chat by a user. +/// Requires administrator rights in the chat. +/// Returns a object. +/// +[JsonObject(MemberSerialization.OptIn, NamingStrategyType = typeof(SnakeCaseNamingStrategy))] +public class GetUserChatBoostsRequest : RequestBase +{ + /// + /// Unique identifier for the chat or username of the channel (in the format @channelusername) + /// + [JsonProperty(Required = Required.Always)] + public required ChatId ChatId { get; init; } + + /// + /// Unique identifier of the target user + /// + [JsonProperty(Required = Required.Always)] + public required long UserId { get; init; } + + /// + /// Initializes a new request + /// + public GetUserChatBoostsRequest() + : base("getUserChatBoosts") + { } + + /// + /// Initializes a new request with chatId and userId + /// + /// + /// Unique identifier for the chat or username of the channel (in the format @channelusername) + /// + /// Unique identifier of the target user + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] + public GetUserChatBoostsRequest(ChatId chatId, long userId) + : this() + { + ChatId = chatId; + UserId = userId; + } +} diff --git a/src/Telegram.Bot/Requests/Available methods/Manage Chat/BanChatMemberRequest.cs b/src/Telegram.Bot/Requests/Available methods/Manage Chat/BanChatMemberRequest.cs index e8d3a84f8..88ee3ec09 100644 --- a/src/Telegram.Bot/Requests/Available methods/Manage Chat/BanChatMemberRequest.cs +++ b/src/Telegram.Bot/Requests/Available methods/Manage Chat/BanChatMemberRequest.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using Newtonsoft.Json.Converters; using Telegram.Bot.Requests.Abstractions; @@ -16,11 +17,11 @@ public class BanChatMemberRequest : RequestBase, IChatTargetable, IUserTar { /// [JsonProperty(Required = Required.Always)] - public ChatId ChatId { get; } + public required ChatId ChatId { get; init; } /// [JsonProperty(Required = Required.Always)] - public long UserId { get; } + public required long UserId { get; init; } /// /// Date when the user will be unbanned. If user is banned for more than 366 days or less @@ -46,10 +47,19 @@ public class BanChatMemberRequest : RequestBase, IChatTargetable, IUserTar /// (in the format @channelusername) /// /// Unique identifier of the target user + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public BanChatMemberRequest(ChatId chatId, long userId) - : base("banChatMember") + : this() { ChatId = chatId; UserId = userId; } + + /// + /// Initializes a new request + /// + public BanChatMemberRequest() + : base("banChatMember") + { } } diff --git a/src/Telegram.Bot/Requests/Available methods/Manage Chat/BanChatSenderChatRequest.cs b/src/Telegram.Bot/Requests/Available methods/Manage Chat/BanChatSenderChatRequest.cs index 2f11e85fa..67cc0c9da 100644 --- a/src/Telegram.Bot/Requests/Available methods/Manage Chat/BanChatSenderChatRequest.cs +++ b/src/Telegram.Bot/Requests/Available methods/Manage Chat/BanChatSenderChatRequest.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using Newtonsoft.Json.Converters; using Telegram.Bot.Requests.Abstractions; @@ -15,13 +16,13 @@ public class BanChatSenderChatRequest : RequestBase, IChatTargetable { /// [JsonProperty(Required = Required.Always)] - public ChatId ChatId { get; } + public required ChatId ChatId { get; init; } /// /// Unique identifier of the target sender chat /// [JsonProperty(Required = Required.Always)] - public long SenderChatId { get; } + public required long SenderChatId { get; init; } /// /// Date when the sender chat will be unbanned, unix time. If the chat is banned for more than 366 days or @@ -40,10 +41,19 @@ public class BanChatSenderChatRequest : RequestBase, IChatTargetable /// /// Unique identifier of the target sender chat /// + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public BanChatSenderChatRequest(ChatId chatId, long senderChatId) - : base("banChatSenderChat") + : this() { ChatId = chatId; SenderChatId = senderChatId; } + + /// + /// Initializes a new request + /// + public BanChatSenderChatRequest() + : base("banChatSenderChat") + { } } diff --git a/src/Telegram.Bot/Requests/Available methods/Manage Chat/Chat Invite Link/ApproveChatJoinRequest.cs b/src/Telegram.Bot/Requests/Available methods/Manage Chat/Chat Invite Link/ApproveChatJoinRequest.cs index f27f1ae6f..a061a24a8 100644 --- a/src/Telegram.Bot/Requests/Available methods/Manage Chat/Chat Invite Link/ApproveChatJoinRequest.cs +++ b/src/Telegram.Bot/Requests/Available methods/Manage Chat/Chat Invite Link/ApproveChatJoinRequest.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Requests.Abstractions; // ReSharper disable once CheckNamespace @@ -13,13 +14,13 @@ public class ApproveChatJoinRequest : RequestBase, IChatTargetable, IUserT { /// [JsonProperty(Required = Required.Always)] - public ChatId ChatId { get; } + public required ChatId ChatId { get; init; } /// /// Unique identifier of the target user /// [JsonProperty(Required = Required.Always)] - public long UserId { get; } + public required long UserId { get; init; } /// /// Initializes a new request with chatId and userId @@ -28,10 +29,19 @@ public class ApproveChatJoinRequest : RequestBase, IChatTargetable, IUserT /// (in the format @channelusername) /// /// Unique identifier of the target user + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public ApproveChatJoinRequest(ChatId chatId, long userId) - : base("approveChatJoinRequest") + : this() { ChatId = chatId; UserId = userId; } + + /// + /// Initializes a new request with chatId and userId + /// + public ApproveChatJoinRequest() + : base("approveChatJoinRequest") + { } } diff --git a/src/Telegram.Bot/Requests/Available methods/Manage Chat/Chat Invite Link/CreateChatInviteLinkRequest.cs b/src/Telegram.Bot/Requests/Available methods/Manage Chat/Chat Invite Link/CreateChatInviteLinkRequest.cs index 39364bb9f..9babf9bb3 100644 --- a/src/Telegram.Bot/Requests/Available methods/Manage Chat/Chat Invite Link/CreateChatInviteLinkRequest.cs +++ b/src/Telegram.Bot/Requests/Available methods/Manage Chat/Chat Invite Link/CreateChatInviteLinkRequest.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using Newtonsoft.Json.Converters; using Telegram.Bot.Requests.Abstractions; @@ -15,7 +16,7 @@ public class CreateChatInviteLinkRequest : RequestBase, IChatTar { /// [JsonProperty(Required = Required.Always)] - public ChatId ChatId { get; } + public required ChatId ChatId { get; init; } /// /// Invite link name; 0-32 characters @@ -50,9 +51,18 @@ public class CreateChatInviteLinkRequest : RequestBase, IChatTar /// Unique identifier for the target chat or username of the target channel /// (in the format @channelusername) /// + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public CreateChatInviteLinkRequest(ChatId chatId) - : base("createChatInviteLink") + : this() { ChatId = chatId; } + + /// + /// Initializes a new request + /// + public CreateChatInviteLinkRequest() + : base("createChatInviteLink") + { } } diff --git a/src/Telegram.Bot/Requests/Available methods/Manage Chat/Chat Invite Link/DeclineChatJoinRequest.cs b/src/Telegram.Bot/Requests/Available methods/Manage Chat/Chat Invite Link/DeclineChatJoinRequest.cs index fd62dabf5..05d848040 100644 --- a/src/Telegram.Bot/Requests/Available methods/Manage Chat/Chat Invite Link/DeclineChatJoinRequest.cs +++ b/src/Telegram.Bot/Requests/Available methods/Manage Chat/Chat Invite Link/DeclineChatJoinRequest.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Requests.Abstractions; // ReSharper disable once CheckNamespace @@ -13,13 +14,13 @@ public class DeclineChatJoinRequest : RequestBase, IChatTargetable, IUserT { /// [JsonProperty(Required = Required.Always)] - public ChatId ChatId { get; } + public required ChatId ChatId { get; init; } /// /// Unique identifier of the target user /// [JsonProperty(Required = Required.Always)] - public long UserId { get; } + public required long UserId { get; init; } /// /// Initializes a new request with chatId and userId @@ -28,10 +29,19 @@ public class DeclineChatJoinRequest : RequestBase, IChatTargetable, IUserT /// (in the format @channelusername) /// /// Unique identifier of the target user + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public DeclineChatJoinRequest(ChatId chatId, long userId) - : base("declineChatJoinRequest") + : this() { ChatId = chatId; UserId = userId; } + + /// + /// Initializes a new request with chatId and userId + /// + public DeclineChatJoinRequest() + : base("declineChatJoinRequest") + { } } diff --git a/src/Telegram.Bot/Requests/Available methods/Manage Chat/Chat Invite Link/EditChatInviteLinkRequest.cs b/src/Telegram.Bot/Requests/Available methods/Manage Chat/Chat Invite Link/EditChatInviteLinkRequest.cs index 3099e3e01..54cba67fc 100644 --- a/src/Telegram.Bot/Requests/Available methods/Manage Chat/Chat Invite Link/EditChatInviteLinkRequest.cs +++ b/src/Telegram.Bot/Requests/Available methods/Manage Chat/Chat Invite Link/EditChatInviteLinkRequest.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using Newtonsoft.Json.Converters; using Telegram.Bot.Requests.Abstractions; @@ -14,13 +15,13 @@ public class EditChatInviteLinkRequest : RequestBase, IChatTarge { /// [JsonProperty(Required = Required.Always)] - public ChatId ChatId { get; } + public required ChatId ChatId { get; init; } /// /// The invite link to edit /// [JsonProperty(Required = Required.Always)] - public string InviteLink { get; } + public required string InviteLink { get; init; } /// /// Invite link name; 0-32 characters @@ -56,10 +57,19 @@ public class EditChatInviteLinkRequest : RequestBase, IChatTarge /// (in the format @channelusername) /// /// The invite link to edit + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public EditChatInviteLinkRequest(ChatId chatId, string inviteLink) - : base("editChatInviteLink") + : this() { ChatId = chatId; InviteLink = inviteLink; } + + /// + /// Initializes a new request + /// + public EditChatInviteLinkRequest() + : base("editChatInviteLink") + { } } diff --git a/src/Telegram.Bot/Requests/Available methods/Manage Chat/Chat Invite Link/ExportChatInviteLinkRequest.cs b/src/Telegram.Bot/Requests/Available methods/Manage Chat/Chat Invite Link/ExportChatInviteLinkRequest.cs index 4254342b6..ff7881197 100644 --- a/src/Telegram.Bot/Requests/Available methods/Manage Chat/Chat Invite Link/ExportChatInviteLinkRequest.cs +++ b/src/Telegram.Bot/Requests/Available methods/Manage Chat/Chat Invite Link/ExportChatInviteLinkRequest.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Requests.Abstractions; // ReSharper disable once CheckNamespace @@ -13,7 +14,7 @@ public class ExportChatInviteLinkRequest : RequestBase, IChatTargetable { /// [JsonProperty(Required = Required.Always)] - public ChatId ChatId { get; } + public required ChatId ChatId { get; init; } /// /// Initializes a new request with chatId @@ -21,9 +22,18 @@ public class ExportChatInviteLinkRequest : RequestBase, IChatTargetable /// Unique identifier for the target chat or username of the target channel /// (in the format @channelusername) /// + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public ExportChatInviteLinkRequest(ChatId chatId) - : base("exportChatInviteLink") + : this() { ChatId = chatId; } + + /// + /// Initializes a new request with chatId + /// + public ExportChatInviteLinkRequest() + : base("exportChatInviteLink") + { } } diff --git a/src/Telegram.Bot/Requests/Available methods/Manage Chat/Chat Invite Link/RevokeChatInviteLinkRequest.cs b/src/Telegram.Bot/Requests/Available methods/Manage Chat/Chat Invite Link/RevokeChatInviteLinkRequest.cs index 945db9dec..5d1fe0222 100644 --- a/src/Telegram.Bot/Requests/Available methods/Manage Chat/Chat Invite Link/RevokeChatInviteLinkRequest.cs +++ b/src/Telegram.Bot/Requests/Available methods/Manage Chat/Chat Invite Link/RevokeChatInviteLinkRequest.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Requests.Abstractions; // ReSharper disable once CheckNamespace @@ -14,13 +15,13 @@ public class RevokeChatInviteLinkRequest : RequestBase, IChatTar { /// [JsonProperty(Required = Required.Always)] - public ChatId ChatId { get; } + public required ChatId ChatId { get; init; } /// /// The invite link to revoke /// [JsonProperty(Required = Required.Always)] - public string InviteLink { get; } + public required string InviteLink { get; init; } /// /// Initializes a new request with chatId and inviteLink @@ -29,10 +30,19 @@ public class RevokeChatInviteLinkRequest : RequestBase, IChatTar /// (in the format @channelusername) /// /// The invite link to revoke + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public RevokeChatInviteLinkRequest(ChatId chatId, string inviteLink) - : base("revokeChatInviteLink") + : this() { ChatId = chatId; InviteLink = inviteLink; } + + /// + /// Initializes a new request with chatId and inviteLink + /// + public RevokeChatInviteLinkRequest() + : base("revokeChatInviteLink") + { } } diff --git a/src/Telegram.Bot/Requests/Available methods/Manage Chat/CloseForumTopicRequest.cs b/src/Telegram.Bot/Requests/Available methods/Manage Chat/CloseForumTopicRequest.cs index cca6ffebe..0a147a893 100644 --- a/src/Telegram.Bot/Requests/Available methods/Manage Chat/CloseForumTopicRequest.cs +++ b/src/Telegram.Bot/Requests/Available methods/Manage Chat/CloseForumTopicRequest.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Requests.Abstractions; // ReSharper disable once CheckNamespace @@ -13,23 +14,32 @@ public class CloseForumTopicRequest : RequestBase, IChatTargetable { /// [JsonProperty(Required = Required.Always)] - public ChatId ChatId { get; } + public required ChatId ChatId { get; init; } /// /// Unique identifier for the target message thread of the forum topic /// [JsonProperty(Required = Required.Always)] - public int MessageThreadId { get; } + public required int MessageThreadId { get; init; } /// /// Initializes a new request /// /// Unique identifier for the target chat or username of the target supergroup /// Unique identifier for the target message thread of the forum topic + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public CloseForumTopicRequest(ChatId chatId, int messageThreadId) - : base("closeForumTopic") + : this() { ChatId = chatId; MessageThreadId = messageThreadId; } + + /// + /// Initializes a new request + /// + public CloseForumTopicRequest() + : base("closeForumTopic") + { } } diff --git a/src/Telegram.Bot/Requests/Available methods/Manage Chat/CloseGeneralForumTopicRequest.cs b/src/Telegram.Bot/Requests/Available methods/Manage Chat/CloseGeneralForumTopicRequest.cs index 2f7998df9..87c6825ef 100644 --- a/src/Telegram.Bot/Requests/Available methods/Manage Chat/CloseGeneralForumTopicRequest.cs +++ b/src/Telegram.Bot/Requests/Available methods/Manage Chat/CloseGeneralForumTopicRequest.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Requests.Abstractions; // ReSharper disable once CheckNamespace @@ -13,12 +14,21 @@ public class CloseGeneralForumTopicRequest : RequestBase, IChatTargetable { /// [JsonProperty(Required = Required.Always)] - public ChatId ChatId { get; } + public required ChatId ChatId { get; init; } /// /// Initializes a new request /// /// Unique identifier for the target chat or username of the target supergroup - public CloseGeneralForumTopicRequest(ChatId chatId) - : base("closeGeneralForumTopic") => ChatId = chatId; + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] + public CloseGeneralForumTopicRequest(ChatId chatId) : this() + => ChatId = chatId; + + /// + /// Initializes a new request + /// + public CloseGeneralForumTopicRequest() + : base("closeGeneralForumTopic") + { } } diff --git a/src/Telegram.Bot/Requests/Available methods/Manage Chat/CreateForumTopicRequest.cs b/src/Telegram.Bot/Requests/Available methods/Manage Chat/CreateForumTopicRequest.cs index c73ddd196..5fd3dd2fd 100644 --- a/src/Telegram.Bot/Requests/Available methods/Manage Chat/CreateForumTopicRequest.cs +++ b/src/Telegram.Bot/Requests/Available methods/Manage Chat/CreateForumTopicRequest.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Converters; using Telegram.Bot.Requests.Abstractions; @@ -14,13 +15,13 @@ public class CreateForumTopicRequest : RequestBase, IChatTargetable { /// [JsonProperty(Required = Required.Always)] - public ChatId ChatId { get; } + public required ChatId ChatId { get; init; } /// /// Topic name, 1-128 characters /// [JsonProperty(Required = Required.Always)] - public string Name { get; } + public required string Name { get; init; } /// /// Optional. Color of the topic icon in RGB format. Currently, must be one of 0x6FB9F0, 0xFFD67E, 0xCB86DB, @@ -41,10 +42,19 @@ public class CreateForumTopicRequest : RequestBase, IChatTargetable /// /// Unique identifier for the target chat or username of the target supergroup /// Topic name + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public CreateForumTopicRequest(ChatId chatId, string name) - : base("createForumTopic") + : this() { ChatId = chatId; Name = name; } + + /// + /// Initializes a new request + /// + public CreateForumTopicRequest() + : base("createForumTopic") + { } } diff --git a/src/Telegram.Bot/Requests/Available methods/Manage Chat/DeleteChatPhotoRequest.cs b/src/Telegram.Bot/Requests/Available methods/Manage Chat/DeleteChatPhotoRequest.cs index 4881e90de..2a8325685 100644 --- a/src/Telegram.Bot/Requests/Available methods/Manage Chat/DeleteChatPhotoRequest.cs +++ b/src/Telegram.Bot/Requests/Available methods/Manage Chat/DeleteChatPhotoRequest.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Requests.Abstractions; // ReSharper disable once CheckNamespace @@ -13,7 +14,7 @@ public class DeleteChatPhotoRequest : RequestBase, IChatTargetable { /// [JsonProperty(Required = Required.Always)] - public ChatId ChatId { get; } + public required ChatId ChatId { get; init; } /// /// Initializes a new request with chatId @@ -21,9 +22,18 @@ public class DeleteChatPhotoRequest : RequestBase, IChatTargetable /// Unique identifier for the target chat or username of the target channel /// (in the format @channelusername) /// + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public DeleteChatPhotoRequest(ChatId chatId) - : base("deleteChatPhoto") + : this() { ChatId = chatId; } + + /// + /// Initializes a new request + /// + public DeleteChatPhotoRequest() + : base("deleteChatPhoto") + { } } diff --git a/src/Telegram.Bot/Requests/Available methods/Manage Chat/DeleteChatStickerSetRequest.cs b/src/Telegram.Bot/Requests/Available methods/Manage Chat/DeleteChatStickerSetRequest.cs index de3cca835..ab028e5d5 100644 --- a/src/Telegram.Bot/Requests/Available methods/Manage Chat/DeleteChatStickerSetRequest.cs +++ b/src/Telegram.Bot/Requests/Available methods/Manage Chat/DeleteChatStickerSetRequest.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Requests.Abstractions; // ReSharper disable once CheckNamespace @@ -14,7 +15,7 @@ public class DeleteChatStickerSetRequest : RequestBase, IChatTargetable { /// [JsonProperty(Required = Required.Always)] - public ChatId ChatId { get; } + public required ChatId ChatId { get; init; } /// /// Initializes a new request with chatId @@ -22,9 +23,18 @@ public class DeleteChatStickerSetRequest : RequestBase, IChatTargetable /// Unique identifier for the target chat or username of the target channel /// (in the format @channelusername) /// + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public DeleteChatStickerSetRequest(ChatId chatId) - : base("deleteChatStickerSet") + : this() { ChatId = chatId; } + + /// + /// Initializes a new request + /// + public DeleteChatStickerSetRequest() + : base("deleteChatStickerSet") + { } } diff --git a/src/Telegram.Bot/Requests/Available methods/Manage Chat/DeleteForumTopicRequest.cs b/src/Telegram.Bot/Requests/Available methods/Manage Chat/DeleteForumTopicRequest.cs index 644b7cec6..4cb60a1b7 100644 --- a/src/Telegram.Bot/Requests/Available methods/Manage Chat/DeleteForumTopicRequest.cs +++ b/src/Telegram.Bot/Requests/Available methods/Manage Chat/DeleteForumTopicRequest.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Requests.Abstractions; // ReSharper disable once CheckNamespace @@ -13,23 +14,32 @@ public class DeleteForumTopicRequest : RequestBase, IChatTargetable { /// [JsonProperty(Required = Required.Always)] - public ChatId ChatId { get; } + public required ChatId ChatId { get; init; } /// /// Unique identifier for the target message thread of the forum topic /// [JsonProperty(Required = Required.Always)] - public int MessageThreadId { get; } + public required int MessageThreadId { get; init; } /// /// Initializes a new request /// /// Unique identifier for the target chat or username of the target supergroup /// Unique identifier for the target message thread of the forum topic + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public DeleteForumTopicRequest(ChatId chatId, int messageThreadId) - : base("deleteForumTopic") + : this() { ChatId = chatId; MessageThreadId = messageThreadId; } + + /// + /// Initializes a new request + /// + public DeleteForumTopicRequest() + : base("deleteForumTopic") + { } } diff --git a/src/Telegram.Bot/Requests/Available methods/Manage Chat/EditForumTopicRequest.cs b/src/Telegram.Bot/Requests/Available methods/Manage Chat/EditForumTopicRequest.cs index a267bc979..b02c2f0a0 100644 --- a/src/Telegram.Bot/Requests/Available methods/Manage Chat/EditForumTopicRequest.cs +++ b/src/Telegram.Bot/Requests/Available methods/Manage Chat/EditForumTopicRequest.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Requests.Abstractions; // ReSharper disable once CheckNamespace @@ -13,13 +14,13 @@ public class EditForumTopicRequest : RequestBase, IChatTargetable { /// [JsonProperty(Required = Required.Always)] - public ChatId ChatId { get; } + public required ChatId ChatId { get; init; } /// /// Unique identifier for the target message thread of the forum topic /// [JsonProperty(Required = Required.Always)] - public int MessageThreadId { get; } + public required int MessageThreadId { get; init; } /// /// New topic name, 0-128 characters. If not specififed or empty, the current name of the topic will be kept @@ -40,7 +41,16 @@ public class EditForumTopicRequest : RequestBase, IChatTargetable /// /// Unique identifier for the target chat or username of the target supergroup /// Unique identifier for the target message thread of the forum topic + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public EditForumTopicRequest(ChatId chatId, int messageThreadId) - : base("editForumTopic") => - (ChatId, MessageThreadId) = (chatId, messageThreadId); + : this() + => (ChatId, MessageThreadId) = (chatId, messageThreadId); + + /// + /// Initializes a new request + /// + public EditForumTopicRequest() + : base("editForumTopic") + { } } diff --git a/src/Telegram.Bot/Requests/Available methods/Manage Chat/EditGeneralForumTopicRequest.cs b/src/Telegram.Bot/Requests/Available methods/Manage Chat/EditGeneralForumTopicRequest.cs index eb5a76bfd..8844d0a9e 100644 --- a/src/Telegram.Bot/Requests/Available methods/Manage Chat/EditGeneralForumTopicRequest.cs +++ b/src/Telegram.Bot/Requests/Available methods/Manage Chat/EditGeneralForumTopicRequest.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Requests.Abstractions; // ReSharper disable once CheckNamespace @@ -13,19 +14,28 @@ public class EditGeneralForumTopicRequest : RequestBase, IChatTargetable { /// [JsonProperty(Required = Required.Always)] - public ChatId ChatId { get; } + public required ChatId ChatId { get; init; } /// /// New topic name, 1-128 characters /// [JsonProperty(Required = Required.Always)] - public string Name { get; } + public required string Name { get; init; } /// /// Initializes a new request /// /// Unique identifier for the target chat or username of the target supergroup /// New topic name, 1-128 characters - public EditGeneralForumTopicRequest(ChatId chatId, string name) - : base("editGeneralForumTopic") => (ChatId, Name) = (chatId, name); + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] + public EditGeneralForumTopicRequest(ChatId chatId, string name) : this() + => (ChatId, Name) = (chatId, name); + + /// + /// Initializes a new request + /// + public EditGeneralForumTopicRequest() + : base("editGeneralForumTopic") + { } } diff --git a/src/Telegram.Bot/Requests/Available methods/Manage Chat/Get Chat/GetChatAdministratorsRequest.cs b/src/Telegram.Bot/Requests/Available methods/Manage Chat/Get Chat/GetChatAdministratorsRequest.cs index 221803d8e..16d2bb42d 100644 --- a/src/Telegram.Bot/Requests/Available methods/Manage Chat/Get Chat/GetChatAdministratorsRequest.cs +++ b/src/Telegram.Bot/Requests/Available methods/Manage Chat/Get Chat/GetChatAdministratorsRequest.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Requests.Abstractions; // ReSharper disable once CheckNamespace @@ -14,7 +15,7 @@ public class GetChatAdministratorsRequest : RequestBase, IChatTarg { /// [JsonProperty(Required = Required.Always)] - public ChatId ChatId { get; } + public required ChatId ChatId { get; init; } /// /// Initializes a new request with chatId @@ -23,9 +24,18 @@ public class GetChatAdministratorsRequest : RequestBase, IChatTarg /// Unique identifier for the target chat or username of the target supergroup or channel /// (in the format @channelusername) /// + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public GetChatAdministratorsRequest(ChatId chatId) - : base("getChatAdministrators") + : this() { ChatId = chatId; } + + /// + /// Initializes a new request + /// + public GetChatAdministratorsRequest() + : base("getChatAdministrators") + { } } diff --git a/src/Telegram.Bot/Requests/Available methods/Manage Chat/Get Chat/GetChatMemberCountRequest.cs b/src/Telegram.Bot/Requests/Available methods/Manage Chat/Get Chat/GetChatMemberCountRequest.cs index 61fded3b8..de4320675 100644 --- a/src/Telegram.Bot/Requests/Available methods/Manage Chat/Get Chat/GetChatMemberCountRequest.cs +++ b/src/Telegram.Bot/Requests/Available methods/Manage Chat/Get Chat/GetChatMemberCountRequest.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Requests.Abstractions; // ReSharper disable once CheckNamespace @@ -11,7 +12,7 @@ public class GetChatMemberCountRequest : RequestBase, IChatTargetable { /// [JsonProperty(Required = Required.Always)] - public ChatId ChatId { get; } + public required ChatId ChatId { get; init; } /// /// Initializes a new request with chatId @@ -20,9 +21,18 @@ public class GetChatMemberCountRequest : RequestBase, IChatTargetable /// Unique identifier for the target chat or username of the target supergroup or channel /// (in the format @channelusername) /// + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public GetChatMemberCountRequest(ChatId chatId) - : base("getChatMemberCount") + : this() { ChatId = chatId; } + + /// + /// Initializes a new request with chatId + /// + public GetChatMemberCountRequest() + : base("getChatMemberCount") + { } } diff --git a/src/Telegram.Bot/Requests/Available methods/Manage Chat/Get Chat/GetChatMemberRequest.cs b/src/Telegram.Bot/Requests/Available methods/Manage Chat/Get Chat/GetChatMemberRequest.cs index 0a6197f94..f4bdd3672 100644 --- a/src/Telegram.Bot/Requests/Available methods/Manage Chat/Get Chat/GetChatMemberRequest.cs +++ b/src/Telegram.Bot/Requests/Available methods/Manage Chat/Get Chat/GetChatMemberRequest.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Requests.Abstractions; // ReSharper disable once CheckNamespace @@ -12,11 +13,11 @@ public class GetChatMemberRequest : RequestBase, IChatTargetable, IU { /// [JsonProperty(Required = Required.Always)] - public ChatId ChatId { get; } + public required ChatId ChatId { get; init; } /// [JsonProperty(Required = Required.Always)] - public long UserId { get; } + public required long UserId { get; init; } /// /// Initializes a new request with chatId and userId @@ -26,10 +27,19 @@ public class GetChatMemberRequest : RequestBase, IChatTargetable, IU /// (in the format @channelusername) /// /// Unique identifier of the target user + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public GetChatMemberRequest(ChatId chatId, long userId) - : base("getChatMember") + : this() { ChatId = chatId; UserId = userId; } + + /// + /// Initializes a new request with chatId and userId + /// + public GetChatMemberRequest() + : base("getChatMember") + { } } diff --git a/src/Telegram.Bot/Requests/Available methods/Manage Chat/Get Chat/GetChatRequest.cs b/src/Telegram.Bot/Requests/Available methods/Manage Chat/Get Chat/GetChatRequest.cs index fb610defd..3b625d32d 100644 --- a/src/Telegram.Bot/Requests/Available methods/Manage Chat/Get Chat/GetChatRequest.cs +++ b/src/Telegram.Bot/Requests/Available methods/Manage Chat/Get Chat/GetChatRequest.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Converters; using Telegram.Bot.Requests.Abstractions; @@ -15,7 +16,7 @@ public class GetChatRequest : RequestBase, IChatTargetable /// [JsonProperty(Required = Required.Always)] [JsonConverter(typeof(ChatIdConverter))] - public ChatId ChatId { get; } + public required ChatId ChatId { get; init; } /// /// Initializes a new request with chatId @@ -24,9 +25,18 @@ public class GetChatRequest : RequestBase, IChatTargetable /// Unique identifier for the target chat or username of the target supergroup or channel /// (in the format @channelusername) /// + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public GetChatRequest(ChatId chatId) - : base("getChat") + : this() { ChatId = chatId; } + + /// + /// Initializes a new request with chatId + /// + public GetChatRequest() + : base("getChat") + { } } diff --git a/src/Telegram.Bot/Requests/Available methods/Manage Chat/HideGeneralForumTopicRequest.cs b/src/Telegram.Bot/Requests/Available methods/Manage Chat/HideGeneralForumTopicRequest.cs index 4149de12b..bc951440e 100644 --- a/src/Telegram.Bot/Requests/Available methods/Manage Chat/HideGeneralForumTopicRequest.cs +++ b/src/Telegram.Bot/Requests/Available methods/Manage Chat/HideGeneralForumTopicRequest.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Requests.Abstractions; // ReSharper disable once CheckNamespace @@ -13,12 +14,21 @@ public class HideGeneralForumTopicRequest : RequestBase, IChatTargetable { /// [JsonProperty(Required = Required.Always)] - public ChatId ChatId { get; } + public required ChatId ChatId { get; init; } /// /// Initializes a new request /// /// Unique identifier for the target chat or username of the target supergroup - public HideGeneralForumTopicRequest(ChatId chatId) - : base("hideGeneralForumTopic") => ChatId = chatId; + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] + public HideGeneralForumTopicRequest(ChatId chatId) : this() + => ChatId = chatId; + + /// + /// Initializes a new request + /// + public HideGeneralForumTopicRequest() + : base("hideGeneralForumTopic") + { } } diff --git a/src/Telegram.Bot/Requests/Available methods/Manage Chat/LeaveChatRequest.cs b/src/Telegram.Bot/Requests/Available methods/Manage Chat/LeaveChatRequest.cs index 5b947c684..f2c520df4 100644 --- a/src/Telegram.Bot/Requests/Available methods/Manage Chat/LeaveChatRequest.cs +++ b/src/Telegram.Bot/Requests/Available methods/Manage Chat/LeaveChatRequest.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Requests.Abstractions; // ReSharper disable once CheckNamespace @@ -11,7 +12,7 @@ public class LeaveChatRequest : RequestBase, IChatTargetable { /// [JsonProperty(Required = Required.Always)] - public ChatId ChatId { get; } + public required ChatId ChatId { get; init; } /// /// Initializes a new request with chatId @@ -20,9 +21,18 @@ public class LeaveChatRequest : RequestBase, IChatTargetable /// Unique identifier for the target chat or username of the target supergroup or channel /// (in the format @channelusername) /// + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public LeaveChatRequest(ChatId chatId) - : base("leaveChat") + : this() { ChatId = chatId; } + + /// + /// Initializes a new request with chatId + /// + public LeaveChatRequest() + : base("leaveChat") + { } } diff --git a/src/Telegram.Bot/Requests/Available methods/Manage Chat/PinChatMessageRequest.cs b/src/Telegram.Bot/Requests/Available methods/Manage Chat/PinChatMessageRequest.cs index 73dc8ba13..671039a7a 100644 --- a/src/Telegram.Bot/Requests/Available methods/Manage Chat/PinChatMessageRequest.cs +++ b/src/Telegram.Bot/Requests/Available methods/Manage Chat/PinChatMessageRequest.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Requests.Abstractions; // ReSharper disable once CheckNamespace @@ -15,13 +16,13 @@ public class PinChatMessageRequest : RequestBase, IChatTargetable { /// [JsonProperty(Required = Required.Always)] - public ChatId ChatId { get; } + public required ChatId ChatId { get; init; } /// /// Identifier of a message to pin /// [JsonProperty(Required = Required.Always)] - public int MessageId { get; } + public required int MessageId { get; init; } /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] @@ -34,10 +35,19 @@ public class PinChatMessageRequest : RequestBase, IChatTargetable /// (in the format @channelusername) /// /// Identifier of a message to pin + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public PinChatMessageRequest(ChatId chatId, int messageId) - : base("pinChatMessage") + : this() { ChatId = chatId; MessageId = messageId; } + + /// + /// Initializes a new request with chatId and messageId + /// + public PinChatMessageRequest() + : base("pinChatMessage") + { } } diff --git a/src/Telegram.Bot/Requests/Available methods/Manage Chat/PromoteChatMemberRequest.cs b/src/Telegram.Bot/Requests/Available methods/Manage Chat/PromoteChatMemberRequest.cs index d13245ac1..74b26a91a 100644 --- a/src/Telegram.Bot/Requests/Available methods/Manage Chat/PromoteChatMemberRequest.cs +++ b/src/Telegram.Bot/Requests/Available methods/Manage Chat/PromoteChatMemberRequest.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Requests.Abstractions; // ReSharper disable once CheckNamespace @@ -13,11 +14,11 @@ public class PromoteChatMemberRequest : RequestBase, IChatTargetable, IUse { /// [JsonProperty(Required = Required.Always)] - public ChatId ChatId { get; } + public required ChatId ChatId { get; init; } /// [JsonProperty(Required = Required.Always)] - public long UserId { get; } + public required long UserId { get; init; } /// /// Pass , if the administrator's presence in the chat is hidden @@ -121,10 +122,19 @@ public class PromoteChatMemberRequest : RequestBase, IChatTargetable, IUse /// (in the format @channelusername) /// /// Unique identifier of the target user + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public PromoteChatMemberRequest(ChatId chatId, long userId) - : base("promoteChatMember") + : this() { ChatId = chatId; UserId = userId; } + + /// + /// Initializes a new request + /// + public PromoteChatMemberRequest() + : base("promoteChatMember") + { } } diff --git a/src/Telegram.Bot/Requests/Available methods/Manage Chat/ReopenForumTopicRequest.cs b/src/Telegram.Bot/Requests/Available methods/Manage Chat/ReopenForumTopicRequest.cs index 52d6fe8eb..5443af88d 100644 --- a/src/Telegram.Bot/Requests/Available methods/Manage Chat/ReopenForumTopicRequest.cs +++ b/src/Telegram.Bot/Requests/Available methods/Manage Chat/ReopenForumTopicRequest.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Requests.Abstractions; // ReSharper disable once CheckNamespace @@ -13,23 +14,32 @@ public class ReopenForumTopicRequest : RequestBase, IChatTargetable { /// [JsonProperty(Required = Required.Always)] - public ChatId ChatId { get; } + public required ChatId ChatId { get; init; } /// /// Unique identifier for the target message thread of the forum topic /// [JsonProperty(Required = Required.Always)] - public int MessageThreadId { get; } + public required int MessageThreadId { get; init; } /// /// Initializes a new request /// /// Unique identifier for the target chat or username of the target supergroup /// Unique identifier for the target message thread of the forum topic + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public ReopenForumTopicRequest(ChatId chatId, int messageThreadId) - : base("reopenForumTopic") + : this() { ChatId = chatId; MessageThreadId = messageThreadId; } + + /// + /// Initializes a new request + /// + public ReopenForumTopicRequest() + : base("reopenForumTopic") + { } } diff --git a/src/Telegram.Bot/Requests/Available methods/Manage Chat/ReopenGeneralForumTopicRequest.cs b/src/Telegram.Bot/Requests/Available methods/Manage Chat/ReopenGeneralForumTopicRequest.cs index 6094c28cb..f9280fe66 100644 --- a/src/Telegram.Bot/Requests/Available methods/Manage Chat/ReopenGeneralForumTopicRequest.cs +++ b/src/Telegram.Bot/Requests/Available methods/Manage Chat/ReopenGeneralForumTopicRequest.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Requests.Abstractions; // ReSharper disable once CheckNamespace @@ -13,12 +14,21 @@ public class ReopenGeneralForumTopicRequest : RequestBase, IChatTargetable { /// [JsonProperty(Required = Required.Always)] - public ChatId ChatId { get; } + public required ChatId ChatId { get; init; } /// /// Initializes a new request /// /// Unique identifier for the target chat or username of the target supergroup - public ReopenGeneralForumTopicRequest(ChatId chatId) - : base("reopenGeneralForumTopic") => ChatId = chatId; + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] + public ReopenGeneralForumTopicRequest(ChatId chatId) : this() + => ChatId = chatId; + + /// + /// Initializes a new request + /// + public ReopenGeneralForumTopicRequest() + : base("reopenGeneralForumTopic") + { } } diff --git a/src/Telegram.Bot/Requests/Available methods/Manage Chat/RestrictChatMemberRequest.cs b/src/Telegram.Bot/Requests/Available methods/Manage Chat/RestrictChatMemberRequest.cs index 5fa83aa97..43e99c6e5 100644 --- a/src/Telegram.Bot/Requests/Available methods/Manage Chat/RestrictChatMemberRequest.cs +++ b/src/Telegram.Bot/Requests/Available methods/Manage Chat/RestrictChatMemberRequest.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using Newtonsoft.Json.Converters; using Telegram.Bot.Requests.Abstractions; @@ -14,17 +15,17 @@ public class RestrictChatMemberRequest : RequestBase, IChatTargetable, IUs { /// [JsonProperty(Required = Required.Always)] - public ChatId ChatId { get; } + public required ChatId ChatId { get; init; } /// [JsonProperty(Required = Required.Always)] - public long UserId { get; } + public required long UserId { get; init; } /// /// New user permissions /// [JsonProperty(Required = Required.Always)] - public ChatPermissions Permissions { get; } + public required ChatPermissions Permissions { get; init; } /// /// Pass if chat permissions are set independently. Otherwise, the @@ -56,11 +57,20 @@ public class RestrictChatMemberRequest : RequestBase, IChatTargetable, IUs /// /// Unique identifier of the target user /// New user permissions + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public RestrictChatMemberRequest(ChatId chatId, long userId, ChatPermissions permissions) - : base("restrictChatMember") + : this() { ChatId = chatId; UserId = userId; Permissions = permissions; } + + /// + /// Initializes a new request + /// + public RestrictChatMemberRequest() + : base("restrictChatMember") + { } } diff --git a/src/Telegram.Bot/Requests/Available methods/Manage Chat/SetChatAdministratorCustomTitleRequest.cs b/src/Telegram.Bot/Requests/Available methods/Manage Chat/SetChatAdministratorCustomTitleRequest.cs index 8688da527..9ed2f9284 100644 --- a/src/Telegram.Bot/Requests/Available methods/Manage Chat/SetChatAdministratorCustomTitleRequest.cs +++ b/src/Telegram.Bot/Requests/Available methods/Manage Chat/SetChatAdministratorCustomTitleRequest.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Requests.Abstractions; // ReSharper disable once CheckNamespace @@ -12,17 +13,17 @@ public class SetChatAdministratorCustomTitleRequest : RequestBase, IChatTa { /// [JsonProperty(Required = Required.Always)] - public ChatId ChatId { get; } + public required ChatId ChatId { get; init; } /// [JsonProperty(Required = Required.Always)] - public long UserId { get; } + public required long UserId { get; init; } /// /// New custom title for the administrator; 0-16 characters, emoji are not allowed /// [JsonProperty(Required = Required.Always)] - public string CustomTitle { get; } + public required string CustomTitle { get; init; } /// /// Initializes a new request with chatId, userId and customTitle @@ -34,11 +35,20 @@ public class SetChatAdministratorCustomTitleRequest : RequestBase, IChatTa /// /// New custom title for the administrator; 0-16 characters, emoji are not allowed /// + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public SetChatAdministratorCustomTitleRequest(ChatId chatId, long userId, string customTitle) - : base("setChatAdministratorCustomTitle") + : this() { ChatId = chatId; UserId = userId; CustomTitle = customTitle; } + + /// + /// Initializes a new request + /// + public SetChatAdministratorCustomTitleRequest() + : base("setChatAdministratorCustomTitle") + { } } diff --git a/src/Telegram.Bot/Requests/Available methods/Manage Chat/SetChatDescriptionRequest.cs b/src/Telegram.Bot/Requests/Available methods/Manage Chat/SetChatDescriptionRequest.cs index aa49b0d2c..234018482 100644 --- a/src/Telegram.Bot/Requests/Available methods/Manage Chat/SetChatDescriptionRequest.cs +++ b/src/Telegram.Bot/Requests/Available methods/Manage Chat/SetChatDescriptionRequest.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Requests.Abstractions; // ReSharper disable once CheckNamespace @@ -13,7 +14,7 @@ public class SetChatDescriptionRequest : RequestBase, IChatTargetable { /// [JsonProperty(Required = Required.Always)] - public ChatId ChatId { get; } + public required ChatId ChatId { get; init; } /// /// New chat Description, 0-255 characters @@ -28,9 +29,18 @@ public class SetChatDescriptionRequest : RequestBase, IChatTargetable /// Unique identifier for the target chat or username of the target channel /// (in the format @channelusername) /// + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public SetChatDescriptionRequest(ChatId chatId) - : base("setChatDescription") + : this() { ChatId = chatId; } + + /// + /// Initializes a new request + /// + public SetChatDescriptionRequest() + : base("setChatDescription") + { } } diff --git a/src/Telegram.Bot/Requests/Available methods/Manage Chat/SetChatPermissionsRequest.cs b/src/Telegram.Bot/Requests/Available methods/Manage Chat/SetChatPermissionsRequest.cs index 1644dba4f..556fb4307 100644 --- a/src/Telegram.Bot/Requests/Available methods/Manage Chat/SetChatPermissionsRequest.cs +++ b/src/Telegram.Bot/Requests/Available methods/Manage Chat/SetChatPermissionsRequest.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Requests.Abstractions; // ReSharper disable once CheckNamespace @@ -13,13 +14,13 @@ public class SetChatPermissionsRequest : RequestBase, IChatTargetable { /// [JsonProperty(Required = Required.Always)] - public ChatId ChatId { get; } + public required ChatId ChatId { get; init; } /// /// New default chat permissions /// [JsonProperty(Required = Required.Always)] - public ChatPermissions Permissions { get; } + public required ChatPermissions Permissions { get; init; } /// /// Pass if chat permissions are set independently. Otherwise, the @@ -41,10 +42,19 @@ public class SetChatPermissionsRequest : RequestBase, IChatTargetable /// (in the format @channelusername) /// /// New default chat permissions + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public SetChatPermissionsRequest(ChatId chatId, ChatPermissions permissions) - : base("setChatPermissions") + : this() { ChatId = chatId; Permissions = permissions; } + + /// + /// Initializes a new request with chatId and new default permissions + /// + public SetChatPermissionsRequest() + : base("setChatPermissions") + { } } diff --git a/src/Telegram.Bot/Requests/Available methods/Manage Chat/SetChatPhotoRequest.cs b/src/Telegram.Bot/Requests/Available methods/Manage Chat/SetChatPhotoRequest.cs index 2f2c08632..44170308e 100644 --- a/src/Telegram.Bot/Requests/Available methods/Manage Chat/SetChatPhotoRequest.cs +++ b/src/Telegram.Bot/Requests/Available methods/Manage Chat/SetChatPhotoRequest.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using System.Net.Http; using Telegram.Bot.Requests.Abstractions; @@ -14,13 +15,13 @@ public class SetChatPhotoRequest : FileRequestBase, IChatTargetable { /// [JsonProperty(Required = Required.Always)] - public ChatId ChatId { get; } + public required ChatId ChatId { get; init; } /// /// New chat photo, uploaded using multipart/form-data /// [JsonProperty(Required = Required.Always)] - public InputFileStream Photo { get; } + public required InputFileStream Photo { get; init; } /// /// Initializes a new request with chatId and photo @@ -29,13 +30,22 @@ public class SetChatPhotoRequest : FileRequestBase, IChatTargetable /// (in the format @channelusername) /// /// New chat photo, uploaded using multipart/form-data + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public SetChatPhotoRequest(ChatId chatId, InputFileStream photo) - : base("setChatPhoto") + : this() { ChatId = chatId; Photo = photo; } + /// + /// Initializes a new request + /// + public SetChatPhotoRequest() + : base("setChatPhoto") + { } + /// public override HttpContent ToHttpContent() => ToMultipartFormDataContent("photo", Photo); diff --git a/src/Telegram.Bot/Requests/Available methods/Manage Chat/SetChatStickerSetRequest.cs b/src/Telegram.Bot/Requests/Available methods/Manage Chat/SetChatStickerSetRequest.cs index 4bb49a721..2c3b9b0cc 100644 --- a/src/Telegram.Bot/Requests/Available methods/Manage Chat/SetChatStickerSetRequest.cs +++ b/src/Telegram.Bot/Requests/Available methods/Manage Chat/SetChatStickerSetRequest.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Requests.Abstractions; // ReSharper disable once CheckNamespace @@ -14,13 +15,13 @@ public class SetChatStickerSetRequest : RequestBase, IChatTargetable { /// [JsonProperty(Required = Required.Always)] - public ChatId ChatId { get; } + public required ChatId ChatId { get; init; } /// /// Name of the sticker set to be set as the group sticker set /// [JsonProperty(Required = Required.Always)] - public string StickerSetName { get; } + public required string StickerSetName { get; init; } /// /// Initializes a new request with chatId and new stickerSetName @@ -29,10 +30,19 @@ public class SetChatStickerSetRequest : RequestBase, IChatTargetable /// (in the format @channelusername) /// /// Name of the sticker set to be set as the group sticker set + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public SetChatStickerSetRequest(ChatId chatId, string stickerSetName) - : base("setChatStickerSet") + : this() { ChatId = chatId; StickerSetName = stickerSetName; } + + /// + /// Initializes a new request + /// + public SetChatStickerSetRequest() + : base("setChatStickerSet") + { } } diff --git a/src/Telegram.Bot/Requests/Available methods/Manage Chat/SetChatTitleRequest.cs b/src/Telegram.Bot/Requests/Available methods/Manage Chat/SetChatTitleRequest.cs index 70ba0f165..7eeca20d0 100644 --- a/src/Telegram.Bot/Requests/Available methods/Manage Chat/SetChatTitleRequest.cs +++ b/src/Telegram.Bot/Requests/Available methods/Manage Chat/SetChatTitleRequest.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Requests.Abstractions; // ReSharper disable once CheckNamespace @@ -13,13 +14,13 @@ public class SetChatTitleRequest : RequestBase, IChatTargetable { /// [JsonProperty(Required = Required.Always)] - public ChatId ChatId { get; } + public required ChatId ChatId { get; init; } /// /// New chat title, 1-255 characters /// [JsonProperty(Required = Required.Always)] - public string Title { get; } + public required string Title { get; init; } /// /// Initializes a new request with chatId and title @@ -28,10 +29,19 @@ public class SetChatTitleRequest : RequestBase, IChatTargetable /// (in the format @channelusername) /// /// New chat title, 1-255 characters + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public SetChatTitleRequest(ChatId chatId, string title) - : base("setChatTitle") + : this() { ChatId = chatId; Title = title; } + + /// + /// Initializes a new request with chatId and title + /// + public SetChatTitleRequest() + : base("setChatTitle") + { } } diff --git a/src/Telegram.Bot/Requests/Available methods/Manage Chat/UnbanChatMemberRequest.cs b/src/Telegram.Bot/Requests/Available methods/Manage Chat/UnbanChatMemberRequest.cs index 90e57e117..6bae92753 100644 --- a/src/Telegram.Bot/Requests/Available methods/Manage Chat/UnbanChatMemberRequest.cs +++ b/src/Telegram.Bot/Requests/Available methods/Manage Chat/UnbanChatMemberRequest.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Requests.Abstractions; // ReSharper disable once CheckNamespace @@ -16,11 +17,11 @@ public class UnbanChatMemberRequest : RequestBase, IChatTargetable, IUserT { /// [JsonProperty(Required = Required.Always)] - public ChatId ChatId { get; } + public required ChatId ChatId { get; init; } /// [JsonProperty(Required = Required.Always)] - public long UserId { get; } + public required long UserId { get; init; } /// /// Do nothing if the user is not banned @@ -35,10 +36,19 @@ public class UnbanChatMemberRequest : RequestBase, IChatTargetable, IUserT /// (in the format @channelusername) /// /// Unique identifier of the target user + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public UnbanChatMemberRequest(ChatId chatId, long userId) - : base("unbanChatMember") + : this() { ChatId = chatId; UserId = userId; } + + /// + /// Initializes a new request + /// + public UnbanChatMemberRequest() + : base("unbanChatMember") + { } } diff --git a/src/Telegram.Bot/Requests/Available methods/Manage Chat/UnbanChatSenderChatRequest.cs b/src/Telegram.Bot/Requests/Available methods/Manage Chat/UnbanChatSenderChatRequest.cs index b24dada2b..5406a2cba 100644 --- a/src/Telegram.Bot/Requests/Available methods/Manage Chat/UnbanChatSenderChatRequest.cs +++ b/src/Telegram.Bot/Requests/Available methods/Manage Chat/UnbanChatSenderChatRequest.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Requests.Abstractions; // ReSharper disable once CheckNamespace @@ -13,13 +14,13 @@ public class UnbanChatSenderChatRequest : RequestBase, IChatTargetable { /// [JsonProperty(Required = Required.Always)] - public ChatId ChatId { get; } + public required ChatId ChatId { get; init; } /// /// Unique identifier of the target sender chat /// [JsonProperty(Required = Required.Always)] - public long SenderChatId { get; } + public required long SenderChatId { get; init; } /// /// Initializes a new request with chatId and senderChatId @@ -30,10 +31,19 @@ public class UnbanChatSenderChatRequest : RequestBase, IChatTargetable /// /// Unique identifier of the target sender chat /// + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public UnbanChatSenderChatRequest(ChatId chatId, long senderChatId) - : base("unbanChatSenderChat") + : this() { ChatId = chatId; SenderChatId = senderChatId; } + + /// + /// Initializes a new request + /// + public UnbanChatSenderChatRequest() + : base("unbanChatSenderChat") + { } } diff --git a/src/Telegram.Bot/Requests/Available methods/Manage Chat/UnhideGeneralForumTopicRequest.cs b/src/Telegram.Bot/Requests/Available methods/Manage Chat/UnhideGeneralForumTopicRequest.cs index 6a60c4cba..52cfbb097 100644 --- a/src/Telegram.Bot/Requests/Available methods/Manage Chat/UnhideGeneralForumTopicRequest.cs +++ b/src/Telegram.Bot/Requests/Available methods/Manage Chat/UnhideGeneralForumTopicRequest.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Requests.Abstractions; // ReSharper disable once CheckNamespace @@ -13,12 +14,22 @@ public class UnhideGeneralForumTopicRequest : RequestBase, IChatTargetable { /// [JsonProperty(Required = Required.Always)] - public ChatId ChatId { get; } + public required ChatId ChatId { get; init; } /// /// Initializes a new request /// /// Unique identifier for the target chat or username of the target supergroup + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public UnhideGeneralForumTopicRequest(ChatId chatId) - : base("unhideGeneralForumTopic") => ChatId = chatId; + : this() + => ChatId = chatId; + + /// + /// Initializes a new request + /// + public UnhideGeneralForumTopicRequest() + : base("unhideGeneralForumTopic") + { } } diff --git a/src/Telegram.Bot/Requests/Available methods/Manage Chat/UnpinAllChatMessagesRequest.cs b/src/Telegram.Bot/Requests/Available methods/Manage Chat/UnpinAllChatMessagesRequest.cs index 52874d1f6..80374dfdb 100644 --- a/src/Telegram.Bot/Requests/Available methods/Manage Chat/UnpinAllChatMessagesRequest.cs +++ b/src/Telegram.Bot/Requests/Available methods/Manage Chat/UnpinAllChatMessagesRequest.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Requests.Abstractions; // ReSharper disable once CheckNamespace @@ -15,7 +16,7 @@ public class UnpinAllChatMessagesRequest : RequestBase, IChatTargetable { /// [JsonProperty(Required = Required.Always)] - public ChatId ChatId { get; } + public required ChatId ChatId { get; init; } /// /// Initializes a new request with chatId @@ -23,9 +24,18 @@ public class UnpinAllChatMessagesRequest : RequestBase, IChatTargetable /// Unique identifier for the target chat or username of the target channel /// (in the format @channelusername) /// + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public UnpinAllChatMessagesRequest(ChatId chatId) - : base("unpinAllChatMessages") + : this() { ChatId = chatId; } + + /// + /// Initializes a new request with chatId + /// + public UnpinAllChatMessagesRequest() + : base("unpinAllChatMessages") + { } } diff --git a/src/Telegram.Bot/Requests/Available methods/Manage Chat/UnpinAllForumTopicMessagesRequest.cs b/src/Telegram.Bot/Requests/Available methods/Manage Chat/UnpinAllForumTopicMessagesRequest.cs index 86e38cf8c..e4de3973a 100644 --- a/src/Telegram.Bot/Requests/Available methods/Manage Chat/UnpinAllForumTopicMessagesRequest.cs +++ b/src/Telegram.Bot/Requests/Available methods/Manage Chat/UnpinAllForumTopicMessagesRequest.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Requests.Abstractions; // ReSharper disable once CheckNamespace @@ -13,23 +14,32 @@ public class UnpinAllForumTopicMessagesRequest : RequestBase, IChatTargeta { /// [JsonProperty(Required = Required.Always)] - public ChatId ChatId { get; } + public required ChatId ChatId { get; init; } /// /// Unique identifier for the target message thread of the forum topic /// [JsonProperty(Required = Required.Always)] - public int MessageThreadId { get; } + public required int MessageThreadId { get; init; } /// /// Initializes a new request /// /// Unique identifier for the target chat or username of the target supergroup /// Unique identifier for the target message thread of the forum topic + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public UnpinAllForumTopicMessagesRequest(ChatId chatId, int messageThreadId) - : base("unpinAllForumTopicMessages") + : this() { ChatId = chatId; MessageThreadId = messageThreadId; } + + /// + /// Initializes a new request + /// + public UnpinAllForumTopicMessagesRequest() + : base("unpinAllForumTopicMessages") + { } } diff --git a/src/Telegram.Bot/Requests/Available methods/Manage Chat/UnpinAllGeneralForumTopicMessages.cs b/src/Telegram.Bot/Requests/Available methods/Manage Chat/UnpinAllGeneralForumTopicMessages.cs index bffb715c5..e95f50681 100644 --- a/src/Telegram.Bot/Requests/Available methods/Manage Chat/UnpinAllGeneralForumTopicMessages.cs +++ b/src/Telegram.Bot/Requests/Available methods/Manage Chat/UnpinAllGeneralForumTopicMessages.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Requests.Abstractions; // ReSharper disable once CheckNamespace @@ -5,23 +6,33 @@ namespace Telegram.Bot.Requests; /// /// Use this method to clear the list of pinned messages in a General forum topic. The bot must be an administrator in -/// the chat for this to work and must have the administrator right in the supergroup. -/// Returns on success. +/// the chat for this to work and must have the administrator +/// right in the supergroup. Returns on success. /// [JsonObject(MemberSerialization.OptIn, NamingStrategyType = typeof(SnakeCaseNamingStrategy))] +[Obsolete("Use class UnpinAllGeneralForumTopicMessagesRequest")] public class UnpinAllGeneralForumTopicMessages : RequestBase, IChatTargetable { /// [JsonProperty(Required = Required.Always)] - public ChatId ChatId { get; } + public required ChatId ChatId { get; init; } /// /// Initializes a new request /// /// Unique identifier for the target chat or username of the target supergroup + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public UnpinAllGeneralForumTopicMessages(ChatId chatId) - : base("unpinAllGeneralForumTopicMessages") + : this() { ChatId = chatId; } + + /// + /// Initializes a new request + /// + public UnpinAllGeneralForumTopicMessages() + : base("unpinAllGeneralForumTopicMessages") + { } } diff --git a/src/Telegram.Bot/Requests/Available methods/Manage Chat/UnpinAllGeneralForumTopicMessagesRequest.cs b/src/Telegram.Bot/Requests/Available methods/Manage Chat/UnpinAllGeneralForumTopicMessagesRequest.cs new file mode 100644 index 000000000..4bd82407a --- /dev/null +++ b/src/Telegram.Bot/Requests/Available methods/Manage Chat/UnpinAllGeneralForumTopicMessagesRequest.cs @@ -0,0 +1,37 @@ +using System.Diagnostics.CodeAnalysis; +using Telegram.Bot.Requests.Abstractions; + +// ReSharper disable once CheckNamespace +namespace Telegram.Bot.Requests; + +/// +/// Use this method to clear the list of pinned messages in a General forum topic. The bot must be an administrator in +/// the chat for this to work and must have the administrator +/// right in the supergroup. Returns on success. +/// +[JsonObject(MemberSerialization.OptIn, NamingStrategyType = typeof(SnakeCaseNamingStrategy))] +public class UnpinAllGeneralForumTopicMessagesRequest : RequestBase, IChatTargetable +{ + /// + [JsonProperty(Required = Required.Always)] + public required ChatId ChatId { get; init; } + + /// + /// Initializes a new request + /// + /// Unique identifier for the target chat or username of the target supergroup + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] + public UnpinAllGeneralForumTopicMessagesRequest(ChatId chatId) + : this() + { + ChatId = chatId; + } + + /// + /// Initializes a new request + /// + public UnpinAllGeneralForumTopicMessagesRequest() + : base("unpinAllGeneralForumTopicMessages") + { } +} diff --git a/src/Telegram.Bot/Requests/Available methods/Manage Chat/UnpinChatMessageRequest.cs b/src/Telegram.Bot/Requests/Available methods/Manage Chat/UnpinChatMessageRequest.cs index 53ad93406..663dbbb09 100644 --- a/src/Telegram.Bot/Requests/Available methods/Manage Chat/UnpinChatMessageRequest.cs +++ b/src/Telegram.Bot/Requests/Available methods/Manage Chat/UnpinChatMessageRequest.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Requests.Abstractions; // ReSharper disable once CheckNamespace @@ -15,7 +16,7 @@ public class UnpinChatMessageRequest : RequestBase, IChatTargetable { /// [JsonProperty(Required = Required.Always)] - public ChatId ChatId { get; } + public required ChatId ChatId { get; init; } /// /// Identifier of a message to unpin. If not specified, the most recent pinned message @@ -30,9 +31,18 @@ public class UnpinChatMessageRequest : RequestBase, IChatTargetable /// Unique identifier for the target chat or username of the target channel /// (in the format @channelusername) /// + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public UnpinChatMessageRequest(ChatId chatId) - : base("unpinChatMessage") + : this() { ChatId = chatId; } + + /// + /// Initializes a new request + /// + public UnpinChatMessageRequest() + : base("unpinChatMessage") + { } } diff --git a/src/Telegram.Bot/Requests/Available methods/Messages/CopyMessageRequest.cs b/src/Telegram.Bot/Requests/Available methods/Messages/CopyMessageRequest.cs index 2712b17f3..85264a70e 100644 --- a/src/Telegram.Bot/Requests/Available methods/Messages/CopyMessageRequest.cs +++ b/src/Telegram.Bot/Requests/Available methods/Messages/CopyMessageRequest.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Requests.Abstractions; using Telegram.Bot.Types.Enums; using Telegram.Bot.Types.ReplyMarkups; @@ -21,7 +22,7 @@ public class CopyMessageRequest : RequestBase, IChatTargetable /// (in the format @channelusername) /// [JsonProperty(Required = Required.Always)] - public ChatId ChatId { get; } + public required ChatId ChatId { get; init; } /// /// Unique identifier for the target message thread (topic) of the forum; for forum supergroups only @@ -34,13 +35,13 @@ public class CopyMessageRequest : RequestBase, IChatTargetable /// (or channel username in the format @channelusername) /// [JsonProperty(Required = Required.Always)] - public ChatId FromChatId { get; } + public required ChatId FromChatId { get; init; } /// /// Message identifier in the chat specified in /// [JsonProperty(Required = Required.Always)] - public int MessageId { get; } + public required int MessageId { get; init; } /// /// New caption for media, 0-1024 characters after entities parsing. @@ -65,13 +66,9 @@ public class CopyMessageRequest : RequestBase, IChatTargetable [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] public bool? ProtectContent { get; set; } - /// + /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public int? ReplyToMessageId { get; set; } - - /// - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public bool? AllowSendingWithoutReply { get; set; } + public ReplyParameters? ReplyParameters { get; set; } /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] @@ -90,11 +87,20 @@ public class CopyMessageRequest : RequestBase, IChatTargetable /// /// Message identifier in the chat specified in /// + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public CopyMessageRequest(ChatId chatId, ChatId fromChatId, int messageId) - : base("copyMessage") + : this() { ChatId = chatId; FromChatId = fromChatId; MessageId = messageId; } + + /// + /// Initializes a new request + /// + public CopyMessageRequest() + : base("copyMessage") + { } } diff --git a/src/Telegram.Bot/Requests/Available methods/Messages/CopyMessagesRequest.cs b/src/Telegram.Bot/Requests/Available methods/Messages/CopyMessagesRequest.cs new file mode 100644 index 000000000..38e2180ee --- /dev/null +++ b/src/Telegram.Bot/Requests/Available methods/Messages/CopyMessagesRequest.cs @@ -0,0 +1,91 @@ +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using Telegram.Bot.Requests.Abstractions; + +// ReSharper disable once CheckNamespace +namespace Telegram.Bot.Requests; + +/// +/// Use this method to copy messages of any kind. If some of the specified messages can't be found or copied, +/// they are skipped. Service messages, giveaway messages, giveaway winners messages, and invoice messages +/// can't be copied. A quiz can be copied only if the value of the field +/// CorrectOptionId is known to the bot. The method is analogous +/// to the method , but the copied messages don't have a link +/// to the original message. Album grouping is kept for copied messages. +/// On success, an array of of the sent messages is returned. +/// +[JsonObject(MemberSerialization.OptIn, NamingStrategyType = typeof(SnakeCaseNamingStrategy))] +public class CopyMessagesRequest : RequestBase, IChatTargetable +{ + /// + /// Unique identifier for the target chat or username of the target channel + /// (in the format @channelusername) + /// + [JsonProperty(Required = Required.Always)] + public required ChatId ChatId { get; init; } + + /// + /// Unique identifier for the chat where the original messages were sent + /// (or channel username in the format @channelusername) + /// + [JsonProperty(Required = Required.Always)] + public required ChatId FromChatId { get; init; } + + /// + /// Identifiers of 1-100 messages in the chat to copy. + /// The identifiers must be specified in a strictly increasing order. + /// + [JsonProperty(Required = Required.Always)] + public required IEnumerable MessageIds { get; init; } + + /// + /// Unique identifier for the target message thread (topic) of the forum; for forum supergroups only + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public int? MessageThreadId { get; set; } + + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public bool? DisableNotification { get; set; } + + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public bool? ProtectContent { get; set; } + + /// + /// Pass to copy the messages without their captions + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public bool? RemoveCaption { get; set; } + + /// + /// Initializes a new request with chatId, fromChatId and messageIds + /// + /// Unique identifier for the target chat or username of the target channel + /// (in the format @channelusername) + /// + /// + /// Unique identifier for the chat where the original messages were sent + /// (or channel username in the format @channelusername) + /// + /// + /// Identifiers of 1-100 messages in the chat to copy. + /// The identifiers must be specified in a strictly increasing order. + /// + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] + public CopyMessagesRequest(ChatId chatId, ChatId fromChatId, int[] messageIds) + : this() + { + ChatId = chatId; + FromChatId = fromChatId; + MessageIds = messageIds; + } + + /// + /// Initializes a new request + /// + public CopyMessagesRequest() + : base("copyMessages") + { } +} diff --git a/src/Telegram.Bot/Requests/Available methods/Messages/ForwardMessageRequest.cs b/src/Telegram.Bot/Requests/Available methods/Messages/ForwardMessageRequest.cs index 994b22b41..b3fe4ee2d 100644 --- a/src/Telegram.Bot/Requests/Available methods/Messages/ForwardMessageRequest.cs +++ b/src/Telegram.Bot/Requests/Available methods/Messages/ForwardMessageRequest.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Requests.Abstractions; // ReSharper disable once CheckNamespace @@ -14,26 +15,26 @@ public class ForwardMessageRequest : RequestBase, IChatTargetable /// (in the format @channelusername) /// [JsonProperty(Required = Required.Always)] - public ChatId ChatId { get; } - - /// - /// Unique identifier for the target message thread (topic) of the forum; for forum supergroups only - /// - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public int? MessageThreadId { get; set; } + public required ChatId ChatId { get; init; } /// /// Unique identifier for the chat where the original message was sent /// (or channel username in the format @channelusername) /// [JsonProperty(Required = Required.Always)] - public ChatId FromChatId { get; } + public required ChatId FromChatId { get; init; } /// /// Message identifier in the chat specified in /// [JsonProperty(Required = Required.Always)] - public int MessageId { get; } + public required int MessageId { get; init; } + + /// + /// Unique identifier for the target message thread (topic) of the forum; for forum supergroups only + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public int? MessageThreadId { get; set; } /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] @@ -56,11 +57,20 @@ public class ForwardMessageRequest : RequestBase, IChatTargetable /// /// Message identifier in the chat specified in /// + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public ForwardMessageRequest(ChatId chatId, ChatId fromChatId, int messageId) - : base("forwardMessage") + : this() { ChatId = chatId; FromChatId = fromChatId; MessageId = messageId; } + + /// + /// Initializes a new request + /// + public ForwardMessageRequest() + : base("forwardMessage") + { } } diff --git a/src/Telegram.Bot/Requests/Available methods/Messages/ForwardMessagesRequest.cs b/src/Telegram.Bot/Requests/Available methods/Messages/ForwardMessagesRequest.cs new file mode 100644 index 000000000..74fb120f2 --- /dev/null +++ b/src/Telegram.Bot/Requests/Available methods/Messages/ForwardMessagesRequest.cs @@ -0,0 +1,83 @@ +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using Telegram.Bot.Requests.Abstractions; + +// ReSharper disable once CheckNamespace +namespace Telegram.Bot.Requests; + +/// +/// Use this method to forward multiple messages of any kind. If some of the specified messages can't be found +/// or forwarded, they are skipped. Service messages and messages with protected content can't be forwarded. +/// Album grouping is kept for forwarded messages. +/// On success, an array of of the sent messages is returned. +/// +[JsonObject(MemberSerialization.OptIn, NamingStrategyType = typeof(SnakeCaseNamingStrategy))] +public class ForwardMessagesRequest : RequestBase, IChatTargetable +{ + /// + /// Unique identifier for the target chat or username of the target channel + /// (in the format @channelusername) + /// + [JsonProperty(Required = Required.Always)] + public required ChatId ChatId { get; init; } + + /// + /// Unique identifier for the chat where the original messages were sent + /// (or channel username in the format @channelusername) + /// + [JsonProperty(Required = Required.Always)] + public required ChatId FromChatId { get; init; } + + /// + /// Identifiers of 1-100 messages in the chat from_chat_id to forward. + /// The identifiers must be specified in a strictly increasing order. + /// + [JsonProperty(Required = Required.Always)] + public required IEnumerable MessageIds { get; init; } + + /// + /// Unique identifier for the target message thread (topic) of the forum; for forum supergroups only + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public int? MessageThreadId { get; set; } + + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public bool? DisableNotification { get; set; } + + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public bool? ProtectContent { get; set; } + + /// + /// Initializes a new request with chatId, fromChatId and messageIds + /// + /// + /// Unique identifier for the target chat or username of the target channel + /// (in the format @channelusername) + /// + /// + /// Unique identifier for the chat where the original messages were sent + /// (or channel username in the format @channelusername) + /// + /// + /// Identifiers of 1-100 messages in the chat from_chat_id to forward. + /// The identifiers must be specified in a strictly increasing order. + /// + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] + public ForwardMessagesRequest(ChatId chatId, ChatId fromChatId, IEnumerable messageIds) + : this() + { + ChatId = chatId; + FromChatId = fromChatId; + MessageIds = messageIds; + } + + /// + /// Initializes a new request + /// + public ForwardMessagesRequest() + :base("forwardMessages") + { } +} diff --git a/src/Telegram.Bot/Requests/Available methods/Messages/Location/EditInlineMessageLiveLocationRequest.cs b/src/Telegram.Bot/Requests/Available methods/Messages/Location/EditInlineMessageLiveLocationRequest.cs index fa8d1247c..147af9a5f 100644 --- a/src/Telegram.Bot/Requests/Available methods/Messages/Location/EditInlineMessageLiveLocationRequest.cs +++ b/src/Telegram.Bot/Requests/Available methods/Messages/Location/EditInlineMessageLiveLocationRequest.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Types.ReplyMarkups; // ReSharper disable once CheckNamespace @@ -13,19 +14,19 @@ public class EditInlineMessageLiveLocationRequest : RequestBase { /// [JsonProperty(Required = Required.Always)] - public string InlineMessageId { get; } + public required string InlineMessageId { get; init; } /// /// Latitude of new location /// [JsonProperty(Required = Required.Always)] - public double Latitude { get; } + public required double Latitude { get; init; } /// /// Longitude of new location /// [JsonProperty(Required = Required.Always)] - public double Longitude { get; } + public required double Longitude { get; init; } /// /// The radius of uncertainty for the location, measured in meters; 0-1500 @@ -56,11 +57,20 @@ public class EditInlineMessageLiveLocationRequest : RequestBase /// Identifier of the inline message /// Latitude of new location /// Longitude of new location + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public EditInlineMessageLiveLocationRequest(string inlineMessageId, double latitude, double longitude) - : base("editMessageLiveLocation") + : this() { InlineMessageId = inlineMessageId; Latitude = latitude; Longitude = longitude; } + + /// + /// Initializes a new request + /// + public EditInlineMessageLiveLocationRequest() + : base("editMessageLiveLocation") + { } } diff --git a/src/Telegram.Bot/Requests/Available methods/Messages/Location/EditMessageLiveLocationRequest.cs b/src/Telegram.Bot/Requests/Available methods/Messages/Location/EditMessageLiveLocationRequest.cs index 239653d94..9ad752e96 100644 --- a/src/Telegram.Bot/Requests/Available methods/Messages/Location/EditMessageLiveLocationRequest.cs +++ b/src/Telegram.Bot/Requests/Available methods/Messages/Location/EditMessageLiveLocationRequest.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Requests.Abstractions; using Telegram.Bot.Types.ReplyMarkups; @@ -14,25 +15,25 @@ public class EditMessageLiveLocationRequest : RequestBase, IChatTargeta { /// [JsonProperty(Required = Required.Always)] - public ChatId ChatId { get; } + public required ChatId ChatId { get; init; } /// /// Identifier of the message to edit /// [JsonProperty(Required = Required.Always)] - public int MessageId { get; } + public required int MessageId { get; init; } /// /// Latitude of new location /// [JsonProperty(Required = Required.Always)] - public double Latitude { get; } + public required double Latitude { get; init; } /// /// Longitude of new location /// [JsonProperty(Required = Required.Always)] - public double Longitude { get; } + public required double Longitude { get; init; } /// /// The radius of uncertainty for the location, measured in meters; 0-1500 @@ -67,12 +68,21 @@ public class EditMessageLiveLocationRequest : RequestBase, IChatTargeta /// Identifier of the message to edit /// Latitude of new location /// Longitude of new location + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public EditMessageLiveLocationRequest(ChatId chatId, int messageId, double latitude, double longitude) - : base("editMessageLiveLocation") + : this() { ChatId = chatId; MessageId = messageId; Latitude = latitude; Longitude = longitude; } + + /// + /// Initializes a new request + /// + public EditMessageLiveLocationRequest() + : base("editMessageLiveLocation") + { } } diff --git a/src/Telegram.Bot/Requests/Available methods/Messages/Location/SendLocationRequest.cs b/src/Telegram.Bot/Requests/Available methods/Messages/Location/SendLocationRequest.cs index 60089f584..c0733db4d 100644 --- a/src/Telegram.Bot/Requests/Available methods/Messages/Location/SendLocationRequest.cs +++ b/src/Telegram.Bot/Requests/Available methods/Messages/Location/SendLocationRequest.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Requests.Abstractions; using Telegram.Bot.Types.ReplyMarkups; @@ -12,7 +13,7 @@ public class SendLocationRequest : RequestBase, IChatTargetable { /// [JsonProperty(Required = Required.Always)] - public ChatId ChatId { get; } + public required ChatId ChatId { get; init; } /// /// Unique identifier for the target message thread (topic) of the forum; for forum supergroups only @@ -24,13 +25,19 @@ public class SendLocationRequest : RequestBase, IChatTargetable /// Latitude of the location /// [JsonProperty(Required = Required.Always)] - public double Latitude { get; } + public required double Latitude { get; init; } /// /// Longitude of the location /// [JsonProperty(Required = Required.Always)] - public double Longitude { get; } + public required double Longitude { get; init; } + + /// + /// The radius of uncertainty for the location, measured in meters; 0-1500 + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public double? HorizontalAccuracy { get; set; } /// /// Period in seconds for which the location will be updated, should be between 60 and 86400 @@ -62,17 +69,9 @@ public class SendLocationRequest : RequestBase, IChatTargetable [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] public bool? ProtectContent { get; set; } - /// - /// If the message is a reply, ID of the original message - /// + /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public int? ReplyToMessageId { get; set; } - - /// - /// Pass , if the message should be sent even if the specified replied-to message is not found - /// - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public bool? AllowSendingWithoutReply { get; set; } + public ReplyParameters? ReplyParameters { get; set; } /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] @@ -86,11 +85,20 @@ public class SendLocationRequest : RequestBase, IChatTargetable /// /// Latitude of the location /// Longitude of the location + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public SendLocationRequest(ChatId chatId, double latitude, double longitude) - : base("sendLocation") + : this() { ChatId = chatId; Latitude = latitude; Longitude = longitude; } + + /// + /// Initializes a new request + /// + public SendLocationRequest() + : base("sendLocation") + { } } diff --git a/src/Telegram.Bot/Requests/Available methods/Messages/Location/SendVenueRequest.cs b/src/Telegram.Bot/Requests/Available methods/Messages/Location/SendVenueRequest.cs index 9b1613cf8..0558c9898 100644 --- a/src/Telegram.Bot/Requests/Available methods/Messages/Location/SendVenueRequest.cs +++ b/src/Telegram.Bot/Requests/Available methods/Messages/Location/SendVenueRequest.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Requests.Abstractions; using Telegram.Bot.Types.ReplyMarkups; @@ -12,7 +13,7 @@ public class SendVenueRequest : RequestBase, IChatTargetable { /// [JsonProperty(Required = Required.Always)] - public ChatId ChatId { get; } + public required ChatId ChatId { get; init; } /// /// Unique identifier for the target message thread (topic) of the forum; for forum supergroups only @@ -24,25 +25,25 @@ public class SendVenueRequest : RequestBase, IChatTargetable /// Latitude of the venue /// [JsonProperty(Required = Required.Always)] - public double Latitude { get; } + public required double Latitude { get; init; } /// /// Longitude of the venue /// [JsonProperty(Required = Required.Always)] - public double Longitude { get; } + public required double Longitude { get; init; } /// /// Name of the venue /// [JsonProperty(Required = Required.Always)] - public string Title { get; } + public required string Title { get; init; } /// /// Address of the venue /// [JsonProperty(Required = Required.Always)] - public string Address { get; } + public required string Address { get; init; } /// /// Foursquare identifier of the venue @@ -78,13 +79,9 @@ public class SendVenueRequest : RequestBase, IChatTargetable [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] public bool? ProtectContent { get; set; } - /// + /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public int? ReplyToMessageId { get; set; } - - /// - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public bool? AllowSendingWithoutReply { get; set; } + public ReplyParameters? ReplyParameters { get; set; } /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] @@ -100,12 +97,14 @@ public class SendVenueRequest : RequestBase, IChatTargetable /// Longitude of the venue /// Name of the venue /// Address of the venue + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public SendVenueRequest( ChatId chatId, double latitude, double longitude, string title, - string address) : base("sendVenue") + string address) : this() { ChatId = chatId; Latitude = latitude; @@ -113,4 +112,10 @@ public class SendVenueRequest : RequestBase, IChatTargetable Title = title; Address = address; } + + /// + /// Initializes a new request + /// + public SendVenueRequest() : base("sendVenue") + { } } diff --git a/src/Telegram.Bot/Requests/Available methods/Messages/Location/StopInlineMessageLiveLocationRequest.cs b/src/Telegram.Bot/Requests/Available methods/Messages/Location/StopInlineMessageLiveLocationRequest.cs index cd15c54b9..8e0a1e6ad 100644 --- a/src/Telegram.Bot/Requests/Available methods/Messages/Location/StopInlineMessageLiveLocationRequest.cs +++ b/src/Telegram.Bot/Requests/Available methods/Messages/Location/StopInlineMessageLiveLocationRequest.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Types.ReplyMarkups; // ReSharper disable once CheckNamespace @@ -12,7 +13,7 @@ public class StopInlineMessageLiveLocationRequest : RequestBase { /// [JsonProperty(Required = Required.Always)] - public string InlineMessageId { get; } + public required string InlineMessageId { get; init; } /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] @@ -22,9 +23,18 @@ public class StopInlineMessageLiveLocationRequest : RequestBase /// Initializes a new request with inlineMessageId /// /// Identifier of the inline message + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public StopInlineMessageLiveLocationRequest(string inlineMessageId) - : base("stopMessageLiveLocation") + : this() { InlineMessageId = inlineMessageId; } + + /// + /// Initializes a new request + /// + public StopInlineMessageLiveLocationRequest() + : base("stopMessageLiveLocation") + { } } diff --git a/src/Telegram.Bot/Requests/Available methods/Messages/Location/StopMessageLiveLocationRequest.cs b/src/Telegram.Bot/Requests/Available methods/Messages/Location/StopMessageLiveLocationRequest.cs index 2e7420b36..ed60f59f5 100644 --- a/src/Telegram.Bot/Requests/Available methods/Messages/Location/StopMessageLiveLocationRequest.cs +++ b/src/Telegram.Bot/Requests/Available methods/Messages/Location/StopMessageLiveLocationRequest.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Requests.Abstractions; using Telegram.Bot.Types.ReplyMarkups; @@ -14,13 +15,13 @@ public class StopMessageLiveLocationRequest : RequestBase, IChatTargeta { /// [JsonProperty(Required = Required.Always)] - public ChatId ChatId { get; } + public required ChatId ChatId { get; init; } /// /// Identifier of the sent message /// [JsonProperty(Required = Required.Always)] - public int MessageId { get; } + public required int MessageId { get; init; } /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] @@ -33,10 +34,19 @@ public class StopMessageLiveLocationRequest : RequestBase, IChatTargeta /// (in the format @channelusername) /// /// Identifier of the sent message + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public StopMessageLiveLocationRequest(ChatId chatId, int messageId) - : base("stopMessageLiveLocation") + : this() { ChatId = chatId; MessageId = messageId; } + + /// + /// Initializes a new request + /// + public StopMessageLiveLocationRequest() + : base("stopMessageLiveLocation") + { } } diff --git a/src/Telegram.Bot/Requests/Available methods/Messages/SendAnimationRequest.cs b/src/Telegram.Bot/Requests/Available methods/Messages/SendAnimationRequest.cs index 8a926e368..f3c7f81c3 100644 --- a/src/Telegram.Bot/Requests/Available methods/Messages/SendAnimationRequest.cs +++ b/src/Telegram.Bot/Requests/Available methods/Messages/SendAnimationRequest.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Net.Http; using Telegram.Bot.Extensions; using Telegram.Bot.Requests.Abstractions; @@ -18,13 +19,7 @@ public class SendAnimationRequest : FileRequestBase, IChatTargetable { /// [JsonProperty(Required = Required.Always)] - public ChatId ChatId { get; } - - /// - /// Unique identifier for the target message thread (topic) of the forum; for forum supergroups only - /// - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public int? MessageThreadId { get; set; } + public required ChatId ChatId { get; init; } /// /// Animation to send. Pass a as String to send an animation @@ -32,7 +27,13 @@ public class SendAnimationRequest : FileRequestBase, IChatTargetable /// to get an animation from the Internet, or upload a new animation using multipart/form-data /// [JsonProperty(Required = Required.Always)] - public InputFile Animation { get; } + public required InputFile Animation { get; init; } + + /// + /// Unique identifier for the target message thread (topic) of the forum; for forum supergroups only + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public int? MessageThreadId { get; set; } /// /// Duration of sent animation in seconds @@ -85,13 +86,9 @@ public class SendAnimationRequest : FileRequestBase, IChatTargetable [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] public bool? ProtectContent { get; set; } - /// + /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public int? ReplyToMessageId { get; set; } - - /// - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public bool? AllowSendingWithoutReply { get; set; } + public ReplyParameters? ReplyParameters { get; set; } /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] @@ -108,13 +105,22 @@ public class SendAnimationRequest : FileRequestBase, IChatTargetable /// that exists on the Telegram servers (recommended), pass an HTTP URL as a String for Telegram to /// get an animation from the Internet, or upload a new animation using multipart/form-data /// + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public SendAnimationRequest(ChatId chatId, InputFile animation) - : base("sendAnimation") + : this() { ChatId = chatId; Animation = animation; } + /// + /// Initializes a new request + /// + public SendAnimationRequest() + : base("sendAnimation") + { } + /// public override HttpContent? ToHttpContent() => Animation is InputFileStream || Thumbnail is InputFileStream diff --git a/src/Telegram.Bot/Requests/Available methods/Messages/SendAudioRequest.cs b/src/Telegram.Bot/Requests/Available methods/Messages/SendAudioRequest.cs index 61f7e4857..5b4b09536 100644 --- a/src/Telegram.Bot/Requests/Available methods/Messages/SendAudioRequest.cs +++ b/src/Telegram.Bot/Requests/Available methods/Messages/SendAudioRequest.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Net.Http; using Telegram.Bot.Extensions; using Telegram.Bot.Requests.Abstractions; @@ -19,13 +20,7 @@ public class SendAudioRequest : FileRequestBase, IChatTargetable { /// [JsonProperty(Required = Required.Always)] - public ChatId ChatId { get; } - - /// - /// Unique identifier for the target message thread (topic) of the forum; for forum supergroups only - /// - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public int? MessageThreadId { get; set; } + public required ChatId ChatId { get; init; } /// /// Audio file to send. Pass a as String to send an audio @@ -33,7 +28,13 @@ public class SendAudioRequest : FileRequestBase, IChatTargetable /// Telegram to get an audio file from the Internet, or upload a new one using multipart/form-data /// [JsonProperty(Required = Required.Always)] - public InputFile Audio { get; } + public required InputFile Audio { get; init; } + + /// + /// Unique identifier for the target message thread (topic) of the forum; for forum supergroups only + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public int? MessageThreadId { get; set; } /// /// Audio caption, 0-1024 characters after entities parsing @@ -79,13 +80,9 @@ public class SendAudioRequest : FileRequestBase, IChatTargetable [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] public bool? ProtectContent { get; set; } - /// + /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public int? ReplyToMessageId { get; set; } - - /// - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public bool? AllowSendingWithoutReply { get; set; } + public ReplyParameters? ReplyParameters { get; set; } /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] @@ -102,13 +99,22 @@ public class SendAudioRequest : FileRequestBase, IChatTargetable /// file that exists on the Telegram servers (recommended), pass an HTTP URL as a String for /// Telegram to get an audio file from the Internet, or upload a new one using multipart/form-data /// + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public SendAudioRequest(ChatId chatId, InputFile audio) - : base("sendAudio") + : this() { ChatId = chatId; Audio = audio; } + /// + /// Initializes a new request + /// + public SendAudioRequest() + : base("sendAudio") + { } + /// public override HttpContent? ToHttpContent() => Audio is InputFileStream || Thumbnail is InputFileStream diff --git a/src/Telegram.Bot/Requests/Available methods/Messages/SendChatActionRequest.cs b/src/Telegram.Bot/Requests/Available methods/Messages/SendChatActionRequest.cs index 9f10e73c2..ba251bd36 100644 --- a/src/Telegram.Bot/Requests/Available methods/Messages/SendChatActionRequest.cs +++ b/src/Telegram.Bot/Requests/Available methods/Messages/SendChatActionRequest.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Requests.Abstractions; using Telegram.Bot.Types.Enums; @@ -25,13 +26,7 @@ public class SendChatActionRequest : RequestBase, IChatTargetable { /// [JsonProperty(Required = Required.Always)] - public ChatId ChatId { get; } - - /// - /// Unique identifier for the target message thread; supergroups only - /// - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public int? MessageThreadId { get; set; } + public required ChatId ChatId { get; init; } /// /// Type of action to broadcast. Choose one, depending on what the user is about to receive: @@ -46,7 +41,13 @@ public class SendChatActionRequest : RequestBase, IChatTargetable /// video notes /// [JsonProperty(Required = Required.Always)] - public ChatAction Action { get; } + public required ChatAction Action { get; init; } + + /// + /// Unique identifier for the target message thread; supergroups only + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public int? MessageThreadId { get; set; } /// /// Initializes a new request chatId and action @@ -57,10 +58,19 @@ public class SendChatActionRequest : RequestBase, IChatTargetable /// /// Type of action to broadcast. Choose one, depending on what the user is about to receive /// + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public SendChatActionRequest(ChatId chatId, ChatAction action) - : base("sendChatAction") + : this() { ChatId = chatId; Action = action; } + + /// + /// Initializes a new request + /// + public SendChatActionRequest() + : base("sendChatAction") + { } } diff --git a/src/Telegram.Bot/Requests/Available methods/Messages/SendContactRequest.cs b/src/Telegram.Bot/Requests/Available methods/Messages/SendContactRequest.cs index a3f219054..e4835d9b6 100644 --- a/src/Telegram.Bot/Requests/Available methods/Messages/SendContactRequest.cs +++ b/src/Telegram.Bot/Requests/Available methods/Messages/SendContactRequest.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Requests.Abstractions; using Telegram.Bot.Types.ReplyMarkups; @@ -12,25 +13,25 @@ public class SendContactRequest : RequestBase, IChatTargetable { /// [JsonProperty(Required = Required.Always)] - public ChatId ChatId { get; } - - /// - /// Unique identifier for the target message thread (topic) of the forum; for forum supergroups only - /// - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public int? MessageThreadId { get; set; } + public required ChatId ChatId { get; init; } /// /// Contact's phone number /// [JsonProperty(Required = Required.Always)] - public string PhoneNumber { get; } + public required string PhoneNumber { get; init; } /// /// Contact's first name /// [JsonProperty(Required = Required.Always)] - public string FirstName { get; } + public required string FirstName { get; init; } + + /// + /// Unique identifier for the target message thread (topic) of the forum; for forum supergroups only + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public int? MessageThreadId { get; set; } /// /// Contact's last name @@ -52,13 +53,9 @@ public class SendContactRequest : RequestBase, IChatTargetable [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] public bool? ProtectContent { get; set; } - /// + /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public int? ReplyToMessageId { get; set; } - - /// - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public bool? AllowSendingWithoutReply { get; set; } + public ReplyParameters? ReplyParameters { get; set; } /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] @@ -72,11 +69,20 @@ public class SendContactRequest : RequestBase, IChatTargetable /// /// Contact's phone number /// Contact's first name + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public SendContactRequest(ChatId chatId, string phoneNumber, string firstName) - : base("sendContact") + : this() { ChatId = chatId; PhoneNumber = phoneNumber; FirstName = firstName; } + + /// + /// Initializes a new request + /// + public SendContactRequest() + : base("sendContact") + { } } diff --git a/src/Telegram.Bot/Requests/Available methods/Messages/SendDiceRequest.cs b/src/Telegram.Bot/Requests/Available methods/Messages/SendDiceRequest.cs index 0f62b3489..7203cd83d 100644 --- a/src/Telegram.Bot/Requests/Available methods/Messages/SendDiceRequest.cs +++ b/src/Telegram.Bot/Requests/Available methods/Messages/SendDiceRequest.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Requests.Abstractions; using Telegram.Bot.Types.Enums; using Telegram.Bot.Types.ReplyMarkups; @@ -16,7 +17,7 @@ public class SendDiceRequest : RequestBase, IChatTargetable { /// [JsonProperty(Required = Required.Always)] - public ChatId ChatId { get; } + public required ChatId ChatId { get; init; } /// /// Unique identifier for the target message thread (topic) of the forum; for forum supergroups only @@ -38,13 +39,9 @@ public class SendDiceRequest : RequestBase, IChatTargetable [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] public bool? ProtectContent { get; set; } - /// + /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public int? ReplyToMessageId { get; set; } - - /// - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public bool? AllowSendingWithoutReply { get; set; } + public ReplyParameters? ReplyParameters { get; set; } /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] @@ -55,9 +52,18 @@ public class SendDiceRequest : RequestBase, IChatTargetable /// /// Unique identifier for the target chat or username of the target channel /// (in the format @channelusername) + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public SendDiceRequest(ChatId chatId) - : base("sendDice") + : this() { ChatId = chatId; } + + /// + /// Initializes a new request + /// + public SendDiceRequest() + : base("sendDice") + { } } diff --git a/src/Telegram.Bot/Requests/Available methods/Messages/SendDocumentRequest.cs b/src/Telegram.Bot/Requests/Available methods/Messages/SendDocumentRequest.cs index e0996bbd2..b9ac628a4 100644 --- a/src/Telegram.Bot/Requests/Available methods/Messages/SendDocumentRequest.cs +++ b/src/Telegram.Bot/Requests/Available methods/Messages/SendDocumentRequest.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Net.Http; using Telegram.Bot.Extensions; using Telegram.Bot.Requests.Abstractions; @@ -18,13 +19,7 @@ public class SendDocumentRequest : FileRequestBase, IChatTargetable { /// [JsonProperty(Required = Required.Always)] - public ChatId ChatId { get; } - - /// - /// Unique identifier for the target message thread (topic) of the forum; for forum supergroups only - /// - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public int? MessageThreadId { get; set; } + public required ChatId ChatId { get; init; } /// /// File to send. Pass a as String to send a file that @@ -32,7 +27,13 @@ public class SendDocumentRequest : FileRequestBase, IChatTargetable /// to get a file from the Internet, or upload a new one using multipart/form-data /// [JsonProperty(Required = Required.Always)] - public InputFile Document { get; } + public required InputFile Document { get; init; } + + /// + /// Unique identifier for the target message thread (topic) of the forum; for forum supergroups only + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public int? MessageThreadId { get; set; } /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] @@ -67,13 +68,9 @@ public class SendDocumentRequest : FileRequestBase, IChatTargetable [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] public bool? ProtectContent { get; set; } - /// + /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public int? ReplyToMessageId { get; set; } - - /// - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public bool? AllowSendingWithoutReply { get; set; } + public ReplyParameters? ReplyParameters { get; set; } /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] @@ -90,13 +87,22 @@ public class SendDocumentRequest : FileRequestBase, IChatTargetable /// exists on the Telegram servers (recommended), pass an HTTP URL as a String for Telegram /// to get a file from the Internet, or upload a new one using multipart/form-data /// + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public SendDocumentRequest(ChatId chatId, InputFile document) - : base("sendDocument") + : this() { ChatId = chatId; Document = document; } + /// + /// Initializes a new request + /// + public SendDocumentRequest() + : base("sendDocument") + { } + /// public override HttpContent? ToHttpContent() => Document is InputFileStream || Thumbnail is InputFileStream diff --git a/src/Telegram.Bot/Requests/Available methods/Messages/SendMediaGroupRequest.cs b/src/Telegram.Bot/Requests/Available methods/Messages/SendMediaGroupRequest.cs index 9283d291f..f51872725 100644 --- a/src/Telegram.Bot/Requests/Available methods/Messages/SendMediaGroupRequest.cs +++ b/src/Telegram.Bot/Requests/Available methods/Messages/SendMediaGroupRequest.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Net.Http; using Telegram.Bot.Extensions; using Telegram.Bot.Requests.Abstractions; @@ -16,7 +17,7 @@ public class SendMediaGroupRequest : FileRequestBase, IChatTargetable { /// [JsonProperty(Required = Required.Always)] - public ChatId ChatId { get; } + public required ChatId ChatId { get; init; } /// /// Unique identifier for the target message thread (topic) of the forum; for forum supergroups only @@ -28,7 +29,7 @@ public class SendMediaGroupRequest : FileRequestBase, IChatTargetable /// An array describing messages to be sent, must include 2-10 items /// [JsonProperty(Required = Required.Always)] - public IEnumerable Media { get; } + public required IEnumerable Media { get; init; } /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] @@ -38,13 +39,9 @@ public class SendMediaGroupRequest : FileRequestBase, IChatTargetable [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] public bool? ProtectContent { get; set; } - /// + /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public int? ReplyToMessageId { get; set; } - - /// - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public bool? AllowSendingWithoutReply { get; set; } + public ReplyParameters? ReplyParameters { get; set; } /// /// Initializes a request with chatId and media @@ -54,13 +51,22 @@ public class SendMediaGroupRequest : FileRequestBase, IChatTargetable /// (in the format @channelusername) /// /// An array describing messages to be sent, must include 2-10 items + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public SendMediaGroupRequest(ChatId chatId, IEnumerable media) - : base("sendMediaGroup") + : this() { ChatId = chatId; Media = media; } + /// + /// Initializes a request + /// + public SendMediaGroupRequest() + : base("sendMediaGroup") + { } + /// public override HttpContent ToHttpContent() { diff --git a/src/Telegram.Bot/Requests/Available methods/Messages/SendMessageRequest.cs b/src/Telegram.Bot/Requests/Available methods/Messages/SendMessageRequest.cs index 68ea39c0c..fdc09fbcf 100644 --- a/src/Telegram.Bot/Requests/Available methods/Messages/SendMessageRequest.cs +++ b/src/Telegram.Bot/Requests/Available methods/Messages/SendMessageRequest.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Requests.Abstractions; using Telegram.Bot.Types.Enums; using Telegram.Bot.Types.ReplyMarkups; @@ -14,19 +15,19 @@ public class SendMessageRequest : RequestBase, IChatTargetable { /// [JsonProperty(Required = Required.Always)] - public ChatId ChatId { get; } + public required ChatId ChatId { get; init; } /// - /// Unique identifier for the target message thread (topic) of the forum; for forum supergroups only + /// Text of the message to be sent, 1-4096 characters after entities parsing /// - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public int? MessageThreadId { get; set; } + [JsonProperty(Required = Required.Always)] + public required string Text { get; init; } /// - /// Text of the message to be sent, 1-4096 characters after entities parsing + /// Unique identifier for the target message thread (topic) of the forum; for forum supergroups only /// - [JsonProperty(Required = Required.Always)] - public string Text { get; } + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public int? MessageThreadId { get; set; } /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] @@ -37,10 +38,10 @@ public class SendMessageRequest : RequestBase, IChatTargetable public IEnumerable? Entities { get; set; } /// - /// Disables link previews for links in this message + /// Link preview generation options for the message /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public bool? DisableWebPagePreview { get; set; } + public LinkPreviewOptions? LinkPreviewOptions { get; set; } /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] @@ -50,13 +51,9 @@ public class SendMessageRequest : RequestBase, IChatTargetable [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] public bool? ProtectContent { get; set; } - /// - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public int? ReplyToMessageId { get; set; } - - /// + /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public bool? AllowSendingWithoutReply { get; set; } + public ReplyParameters? ReplyParameters { get; set; } /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] @@ -69,10 +66,19 @@ public class SendMessageRequest : RequestBase, IChatTargetable /// (in the format @channelusername) /// /// Text of the message to be sent, 1-4096 characters after entities parsing + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public SendMessageRequest(ChatId chatId, string text) - : base("sendMessage") + : this() { ChatId = chatId; Text = text; } + + /// + /// Initializes a new request + /// + public SendMessageRequest() + : base("sendMessage") + { } } diff --git a/src/Telegram.Bot/Requests/Available methods/Messages/SendPhotoRequest.cs b/src/Telegram.Bot/Requests/Available methods/Messages/SendPhotoRequest.cs index a119f9cb0..a83ba5014 100644 --- a/src/Telegram.Bot/Requests/Available methods/Messages/SendPhotoRequest.cs +++ b/src/Telegram.Bot/Requests/Available methods/Messages/SendPhotoRequest.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Net.Http; using Telegram.Bot.Requests.Abstractions; using Telegram.Bot.Types.Enums; @@ -15,7 +16,7 @@ public class SendPhotoRequest : FileRequestBase, IChatTargetable { /// [JsonProperty(Required = Required.Always)] - public ChatId ChatId { get; } + public required ChatId ChatId { get; init; } /// /// Unique identifier for the target message thread (topic) of the forum; for forum supergroups only @@ -31,7 +32,7 @@ public class SendPhotoRequest : FileRequestBase, IChatTargetable /// Width and height ratio must be at most 20 /// [JsonProperty(Required = Required.Always)] - public InputFile Photo { get; } + public required InputFile Photo { get; init; } /// /// Photo caption (may also be used when resending photos by ), @@ -62,13 +63,9 @@ public class SendPhotoRequest : FileRequestBase, IChatTargetable [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] public bool? ProtectContent { get; set; } - /// + /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public int? ReplyToMessageId { get; set; } - - /// - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public bool? AllowSendingWithoutReply { get; set; } + public ReplyParameters? ReplyParameters { get; set; } /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] @@ -86,18 +83,27 @@ public class SendPhotoRequest : FileRequestBase, IChatTargetable /// get a photo from the Internet, or upload a new photo using multipart/form-data. The photo /// must be at most 10 MB in size. The photo's width and height must not exceed 10000 in total. /// Width and height ratio must be at most 20 + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public SendPhotoRequest(ChatId chatId, InputFile photo) - : base("sendPhoto") + : this() { ChatId = chatId; Photo = photo; } + /// + /// Initializes a new request + /// + public SendPhotoRequest() + : base("sendPhoto") + { } + /// public override HttpContent? ToHttpContent() => Photo switch { InputFileStream photo => ToMultipartFormDataContent(fileParameterName: "photo", inputFile: photo), - _ => base.ToHttpContent() + _ => base.ToHttpContent() }; } diff --git a/src/Telegram.Bot/Requests/Available methods/Messages/SendPollRequest.cs b/src/Telegram.Bot/Requests/Available methods/Messages/SendPollRequest.cs index acaeed7dd..4035913e8 100644 --- a/src/Telegram.Bot/Requests/Available methods/Messages/SendPollRequest.cs +++ b/src/Telegram.Bot/Requests/Available methods/Messages/SendPollRequest.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using Newtonsoft.Json.Converters; using Telegram.Bot.Requests.Abstractions; using Telegram.Bot.Types.Enums; @@ -15,7 +16,7 @@ public class SendPollRequest : RequestBase, IChatTargetable { /// [JsonProperty(Required = Required.Always)] - public ChatId ChatId { get; } + public required ChatId ChatId { get; init; } /// /// Unique identifier for the target message thread (topic) of the forum; for forum supergroups only @@ -27,13 +28,13 @@ public class SendPollRequest : RequestBase, IChatTargetable /// Poll question, 1-300 characters /// [JsonProperty(Required = Required.Always)] - public string Question { get; } + public required string Question { get; init; } /// /// A list of answer options, 2-10 strings 1-100 characters each /// [JsonProperty(Required = Required.Always)] - public IEnumerable Options { get; } + public required IEnumerable Options { get; init; } /// /// , if the poll needs to be anonymous, defaults to @@ -111,13 +112,9 @@ public class SendPollRequest : RequestBase, IChatTargetable [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] public bool? ProtectContent { get; set; } - /// + /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public int? ReplyToMessageId { get; set; } - - /// - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public bool? AllowSendingWithoutReply { get; set; } + public ReplyParameters? ReplyParameters { get; set; } /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] @@ -131,11 +128,20 @@ public class SendPollRequest : RequestBase, IChatTargetable /// /// Poll question, 1-300 characters /// A list of answer options, 2-10 strings 1-100 characters each + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public SendPollRequest(ChatId chatId, string question, IEnumerable options) - : base("sendPoll") + : this() { ChatId = chatId; Question = question; Options = options; } + + /// + /// Initializes a new request + /// + public SendPollRequest() + : base("sendPoll") + { } } diff --git a/src/Telegram.Bot/Requests/Available methods/Messages/SendVideoNoteRequest.cs b/src/Telegram.Bot/Requests/Available methods/Messages/SendVideoNoteRequest.cs index df0c2f52e..a13af1c65 100644 --- a/src/Telegram.Bot/Requests/Available methods/Messages/SendVideoNoteRequest.cs +++ b/src/Telegram.Bot/Requests/Available methods/Messages/SendVideoNoteRequest.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using System.Net.Http; using Telegram.Bot.Extensions; using Telegram.Bot.Requests.Abstractions; @@ -16,7 +17,7 @@ public class SendVideoNoteRequest : FileRequestBase, IChatTargetable { /// [JsonProperty(Required = Required.Always)] - public ChatId ChatId { get; } + public required ChatId ChatId { get; init; } /// /// Unique identifier for the target message thread (topic) of the forum; for forum supergroups only @@ -30,7 +31,7 @@ public class SendVideoNoteRequest : FileRequestBase, IChatTargetable /// multipart/form-data. Sending video notes by a URL is currently unsupported /// [JsonProperty(Required = Required.Always)] - public InputFile VideoNote { get; } + public required InputFile VideoNote { get; init; } /// /// Duration of sent video in seconds @@ -56,13 +57,9 @@ public class SendVideoNoteRequest : FileRequestBase, IChatTargetable [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] public bool? ProtectContent { get; set; } - /// + /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public int? ReplyToMessageId { get; set; } - - /// - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public bool? AllowSendingWithoutReply { get; set; } + public ReplyParameters? ReplyParameters { get; set; } /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] @@ -79,13 +76,22 @@ public class SendVideoNoteRequest : FileRequestBase, IChatTargetable /// note that exists on the Telegram servers (recommended) or upload a new video using /// multipart/form-data. Sending video notes by a URL is currently unsupported /// + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public SendVideoNoteRequest(ChatId chatId, InputFile videoNote) - : base("sendVideoNote") + : this() { ChatId = chatId; VideoNote = videoNote; } + /// + /// Initializes a new request + /// + public SendVideoNoteRequest() + : base("sendVideoNote") + { } + /// public override HttpContent? ToHttpContent() => VideoNote is InputFileStream || Thumbnail is InputFileStream diff --git a/src/Telegram.Bot/Requests/Available methods/Messages/SendVideoRequest.cs b/src/Telegram.Bot/Requests/Available methods/Messages/SendVideoRequest.cs index 64747f53e..3d4a65786 100644 --- a/src/Telegram.Bot/Requests/Available methods/Messages/SendVideoRequest.cs +++ b/src/Telegram.Bot/Requests/Available methods/Messages/SendVideoRequest.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Net.Http; using Telegram.Bot.Extensions; using Telegram.Bot.Requests.Abstractions; @@ -18,7 +19,7 @@ public class SendVideoRequest : FileRequestBase, IChatTargetable { /// [JsonProperty(Required = Required.Always)] - public ChatId ChatId { get; } + public required ChatId ChatId { get; init; } /// /// Unique identifier for the target message thread (topic) of the forum; for forum supergroups only @@ -32,7 +33,7 @@ public class SendVideoRequest : FileRequestBase, IChatTargetable /// get a video from the Internet, or upload a new video using multipart/form-data /// [JsonProperty(Required = Required.Always)] - public InputFile Video { get; } + public required InputFile Video { get; init; } /// /// Duration of sent video in seconds @@ -91,13 +92,9 @@ public class SendVideoRequest : FileRequestBase, IChatTargetable [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] public bool? ProtectContent { get; set; } - /// + /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public int? ReplyToMessageId { get; set; } - - /// - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public bool? AllowSendingWithoutReply { get; set; } + public ReplyParameters? ReplyParameters { get; set; } /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] @@ -114,13 +111,22 @@ public class SendVideoRequest : FileRequestBase, IChatTargetable /// exists on the Telegram servers (recommended), pass an HTTP URL as a String for Telegram to /// get a video from the Internet, or upload a new video using multipart/form-data /// + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public SendVideoRequest(ChatId chatId, InputFile video) - : base("sendVideo") + : this() { ChatId = chatId; Video = video; } + /// + /// Initializes a new request + /// + public SendVideoRequest() + : base("sendVideo") + { } + /// public override HttpContent? ToHttpContent() => Video is InputFileStream || Thumbnail is InputFileStream diff --git a/src/Telegram.Bot/Requests/Available methods/Messages/SendVoiceRequest.cs b/src/Telegram.Bot/Requests/Available methods/Messages/SendVoiceRequest.cs index 8cbed9619..8c8ce6f85 100644 --- a/src/Telegram.Bot/Requests/Available methods/Messages/SendVoiceRequest.cs +++ b/src/Telegram.Bot/Requests/Available methods/Messages/SendVoiceRequest.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Net.Http; using Telegram.Bot.Requests.Abstractions; using Telegram.Bot.Types.Enums; @@ -19,7 +20,7 @@ public class SendVoiceRequest : FileRequestBase, IChatTargetable { /// [JsonProperty(Required = Required.Always)] - public ChatId ChatId { get; } + public required ChatId ChatId { get; init; } /// /// Unique identifier for the target message thread (topic) of the forum; for forum supergroups only @@ -33,7 +34,7 @@ public class SendVoiceRequest : FileRequestBase, IChatTargetable /// a file from the Internet, or upload a new one using multipart/form-data /// [JsonProperty(Required = Required.Always)] - public InputFile Voice { get; } + public required InputFile Voice { get; init; } /// /// Voice message caption, 0-1024 characters after entities parsing @@ -63,13 +64,9 @@ public class SendVoiceRequest : FileRequestBase, IChatTargetable [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] public bool? ProtectContent { get; set; } - /// + /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public int? ReplyToMessageId { get; set; } - - /// - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public bool? AllowSendingWithoutReply { get; set; } + public ReplyParameters? ReplyParameters { get; set; } /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] @@ -86,13 +83,22 @@ public class SendVoiceRequest : FileRequestBase, IChatTargetable /// that exists on the Telegram servers (recommended), pass an HTTP URL as a String for Telegram /// to get a file from the Internet, or upload a new one using multipart/form-data /// + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public SendVoiceRequest(ChatId chatId, InputFile voice) - : base("sendVoice") + : this() { ChatId = chatId; Voice = voice; } + /// + /// Initializes a new request + /// + public SendVoiceRequest() + : base("sendVoice") + { } + /// public override HttpContent? ToHttpContent() => Voice switch diff --git a/src/Telegram.Bot/Requests/Available methods/Messages/SetMessageReactionRequest.cs b/src/Telegram.Bot/Requests/Available methods/Messages/SetMessageReactionRequest.cs new file mode 100644 index 000000000..7ee9704bc --- /dev/null +++ b/src/Telegram.Bot/Requests/Available methods/Messages/SetMessageReactionRequest.cs @@ -0,0 +1,68 @@ +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using Telegram.Bot.Requests.Abstractions; + +// ReSharper disable once CheckNamespace +namespace Telegram.Bot.Requests; + +/// +/// Use this method to change the chosen reactions on a message. Service messages can't be reacted to. +/// Automatically forwarded messages from a channel to its discussion group have the same +/// available reactions as messages in the channel. +/// Returns on success. +/// +[JsonObject(MemberSerialization.OptIn, NamingStrategyType = typeof(SnakeCaseNamingStrategy))] +public class SetMessageReactionRequest : RequestBase, + IChatTargetable +{ + /// + [JsonProperty(Required = Required.Always)] + public required ChatId ChatId { get; init; } + + /// + /// Identifier of the target message. If the message belongs to a media group, the reaction + /// is set to the first non-deleted message in the group instead. + /// + [JsonProperty(Required = Required.Always)] + public required int MessageId { get; init; } + + /// + /// New list of reaction types to set on the message. Currently, as non-premium users, bots can + /// set up to one reaction per message. A custom emoji reaction can be used if it is either + /// already present on the message or explicitly allowed by chat administrators. + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public IEnumerable? Reaction { get; set; } + + /// + /// Pass to set the reaction with a big animation + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public bool? IsBig { get; set; } + + /// + /// Initializes a new request with chatId and messageId + /// + /// Unique identifier for the target chat or username of the target channel + /// (in the format @channelusername) + /// + /// + /// Identifier of the target message. If the message belongs to a media group, the reaction + /// is set to the first non-deleted message in the group instead. + /// + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] + public SetMessageReactionRequest(ChatId chatId, int messageId) + : this() + { + ChatId = chatId; + MessageId = messageId; + } + + /// + /// Initializes a new request + /// + public SetMessageReactionRequest() + : base("setMessageReaction") + { } +} diff --git a/src/Telegram.Bot/Requests/Games/GetGameHighScoresRequest.cs b/src/Telegram.Bot/Requests/Games/GetGameHighScoresRequest.cs index d197a7907..f4c65e5ad 100644 --- a/src/Telegram.Bot/Requests/Games/GetGameHighScoresRequest.cs +++ b/src/Telegram.Bot/Requests/Games/GetGameHighScoresRequest.cs @@ -1,4 +1,5 @@ -using Telegram.Bot.Requests.Abstractions; +using System.Diagnostics.CodeAnalysis; +using Telegram.Bot.Requests.Abstractions; // ReSharper disable once CheckNamespace namespace Telegram.Bot.Requests; @@ -18,13 +19,13 @@ public class GetGameHighScoresRequest : RequestBase, IUserTarge { /// [JsonProperty(Required = Required.Always)] - public long UserId { get; } + public required long UserId { get; init; } /// /// Unique identifier for the target chat /// [JsonProperty(Required = Required.Always)] - public long ChatId { get; } + public required long ChatId { get; init; } /// ChatId IChatTargetable.ChatId => ChatId; @@ -33,7 +34,7 @@ public class GetGameHighScoresRequest : RequestBase, IUserTarge /// Identifier of the sent message /// [JsonProperty(Required = Required.Always)] - public int MessageId { get; } + public required int MessageId { get; init; } /// /// Initializes a new request with userId, chatId and messageId @@ -41,11 +42,20 @@ public class GetGameHighScoresRequest : RequestBase, IUserTarge /// Target user id /// Unique identifier for the target chat /// Identifier of the sent message + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public GetGameHighScoresRequest(long userId, long chatId, int messageId) - : base("getGameHighScores") + : this() { UserId = userId; ChatId = chatId; MessageId = messageId; } + + /// + /// Initializes a new request + /// + public GetGameHighScoresRequest() + : base("getGameHighScores") + { } } diff --git a/src/Telegram.Bot/Requests/Games/GetInlineGameHighScoresRequest.cs b/src/Telegram.Bot/Requests/Games/GetInlineGameHighScoresRequest.cs index 495b6f48e..1e7536aa9 100644 --- a/src/Telegram.Bot/Requests/Games/GetInlineGameHighScoresRequest.cs +++ b/src/Telegram.Bot/Requests/Games/GetInlineGameHighScoresRequest.cs @@ -1,4 +1,5 @@ -using Telegram.Bot.Requests.Abstractions; +using System.Diagnostics.CodeAnalysis; +using Telegram.Bot.Requests.Abstractions; // ReSharper disable once CheckNamespace namespace Telegram.Bot.Requests; @@ -18,21 +19,30 @@ public class GetInlineGameHighScoresRequest : RequestBase, IUse { /// [JsonProperty(Required = Required.Always)] - public long UserId { get; } + public required long UserId { get; init; } /// [JsonProperty(Required = Required.Always)] - public string InlineMessageId { get; } + public required string InlineMessageId { get; init; } /// /// Initializes a new request with userId and inlineMessageId /// /// User identifier /// Identifier of the inline message + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public GetInlineGameHighScoresRequest(long userId, string inlineMessageId) - : base("getGameHighScores") + : this() { UserId = userId; InlineMessageId = inlineMessageId; } + + /// + /// Initializes a new request + /// + public GetInlineGameHighScoresRequest() + : base("getGameHighScores") + { } } diff --git a/src/Telegram.Bot/Requests/Games/SendGameRequest.cs b/src/Telegram.Bot/Requests/Games/SendGameRequest.cs index dc5a6d125..abb390577 100644 --- a/src/Telegram.Bot/Requests/Games/SendGameRequest.cs +++ b/src/Telegram.Bot/Requests/Games/SendGameRequest.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Requests.Abstractions; using Telegram.Bot.Types.ReplyMarkups; @@ -14,7 +15,7 @@ public class SendGameRequest : RequestBase, IChatTargetable /// Unique identifier for the target chat /// [JsonProperty(Required = Required.Always)] - public long ChatId { get; } + public required long ChatId { get; init; } /// ChatId IChatTargetable.ChatId => ChatId; @@ -30,7 +31,7 @@ public class SendGameRequest : RequestBase, IChatTargetable /// via @BotFather /// [JsonProperty(Required = Required.Always)] - public string GameShortName { get; } + public required string GameShortName { get; init; } /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] @@ -40,13 +41,9 @@ public class SendGameRequest : RequestBase, IChatTargetable [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] public bool? ProtectContent { get; set; } - /// + /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public int? ReplyToMessageId { get; set; } - - /// - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public bool? AllowSendingWithoutReply { get; set; } + public ReplyParameters? ReplyParameters { get; set; } /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] @@ -60,10 +57,19 @@ public class SendGameRequest : RequestBase, IChatTargetable /// Short name of the game, serves as the unique identifier for the game. Set up your games via /// @BotFather /// + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public SendGameRequest(long chatId, string gameShortName) - : base("sendGame") + : this() { ChatId = chatId; GameShortName = gameShortName; } + + /// + /// Initializes a new request + /// + public SendGameRequest() + : base("sendGame") + { } } diff --git a/src/Telegram.Bot/Requests/Games/SetGameScoreRequest.cs b/src/Telegram.Bot/Requests/Games/SetGameScoreRequest.cs index 7cfd9d297..0e0c9f20a 100644 --- a/src/Telegram.Bot/Requests/Games/SetGameScoreRequest.cs +++ b/src/Telegram.Bot/Requests/Games/SetGameScoreRequest.cs @@ -1,4 +1,5 @@ -using Telegram.Bot.Requests.Abstractions; +using System.Diagnostics.CodeAnalysis; +using Telegram.Bot.Requests.Abstractions; // ReSharper disable once CheckNamespace namespace Telegram.Bot.Requests; @@ -13,13 +14,13 @@ public class SetGameScoreRequest : RequestBase, IUserTargetable, IChatT { /// [JsonProperty(Required = Required.Always)] - public long UserId { get; } + public required long UserId { get; init; } /// /// New score, must be non-negative /// [JsonProperty(Required = Required.Always)] - public int Score { get; } + public required int Score { get; init; } /// /// Pass , if the high score is allowed to decrease. This can be useful when fixing mistakes @@ -39,7 +40,7 @@ public class SetGameScoreRequest : RequestBase, IUserTargetable, IChatT /// Unique identifier for the target chat /// [JsonProperty(Required = Required.Always)] - public long ChatId { get; } + public required long ChatId { get; init; } /// ChatId IChatTargetable.ChatId => ChatId; @@ -48,7 +49,7 @@ public class SetGameScoreRequest : RequestBase, IUserTargetable, IChatT /// Identifier of the sent message /// [JsonProperty(Required = Required.Always)] - public int MessageId { get; } + public required int MessageId { get; init; } /// /// Initializes a new request @@ -57,12 +58,21 @@ public class SetGameScoreRequest : RequestBase, IUserTargetable, IChatT /// New score, must be non-negative /// Unique identifier for the target chat /// Identifier of the sent message + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public SetGameScoreRequest(long userId, int score, long chatId, int messageId) - : base("setGameScore") + : this() { UserId = userId; Score = score; ChatId = chatId; MessageId = messageId; } + + /// + /// Initializes a new request + /// + public SetGameScoreRequest() + : base("setGameScore") + { } } diff --git a/src/Telegram.Bot/Requests/Games/SetInlineGameScoreRequest.cs b/src/Telegram.Bot/Requests/Games/SetInlineGameScoreRequest.cs index 82dd80fab..1796949db 100644 --- a/src/Telegram.Bot/Requests/Games/SetInlineGameScoreRequest.cs +++ b/src/Telegram.Bot/Requests/Games/SetInlineGameScoreRequest.cs @@ -1,4 +1,5 @@ -using Telegram.Bot.Requests.Abstractions; +using System.Diagnostics.CodeAnalysis; +using Telegram.Bot.Requests.Abstractions; // ReSharper disable once CheckNamespace namespace Telegram.Bot.Requests; @@ -13,13 +14,13 @@ public class SetInlineGameScoreRequest : RequestBase, IUserTargetable { /// [JsonProperty(Required = Required.Always)] - public long UserId { get; } + public required long UserId { get; init; } /// /// New score, must be non-negative /// [JsonProperty(Required = Required.Always)] - public int Score { get; } + public required int Score { get; init; } /// /// Pass , if the high score is allowed to decrease. This can be useful when fixing mistakes @@ -37,7 +38,7 @@ public class SetInlineGameScoreRequest : RequestBase, IUserTargetable /// [JsonProperty(Required = Required.Always)] - public string InlineMessageId { get; } + public required string InlineMessageId { get; init; } /// /// Initializes a new request with userId, inlineMessageId and new score @@ -45,11 +46,20 @@ public class SetInlineGameScoreRequest : RequestBase, IUserTargetable /// User identifier /// New score, must be non-negative /// Identifier of the inline message + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public SetInlineGameScoreRequest(long userId, int score, string inlineMessageId) - : base("setGameScore") + : this() { UserId = userId; Score = score; InlineMessageId = inlineMessageId; } + + /// + /// Initializes a new request + /// + public SetInlineGameScoreRequest() + : base("setGameScore") + { } } diff --git a/src/Telegram.Bot/Requests/Getting Updates/SetWebhookRequest.cs b/src/Telegram.Bot/Requests/Getting Updates/SetWebhookRequest.cs index 9cab0c1b7..aa52c998f 100644 --- a/src/Telegram.Bot/Requests/Getting Updates/SetWebhookRequest.cs +++ b/src/Telegram.Bot/Requests/Getting Updates/SetWebhookRequest.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Net.Http; using Telegram.Bot.Types.Enums; @@ -40,7 +41,7 @@ public class SetWebhookRequest : FileRequestBase /// HTTPS URL to send updates to. Use an empty string to remove webhook integration /// [JsonProperty(Required = Required.Always)] - public string Url { get; } + public required string Url { get; init; } /// /// Upload your public key certificate so that the root certificate in use can be checked. See @@ -100,9 +101,16 @@ public class SetWebhookRequest : FileRequestBase /// /// HTTPS url to send updates to. Use an empty string to remove webhook integration /// - public SetWebhookRequest(string url) - : base("setWebhook") => - Url = url; + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] + public SetWebhookRequest(string url) : base("setWebhook") + => Url = url; + + /// + /// Initializes a new request + /// + public SetWebhookRequest() : base("setWebhook") + { } /// public override HttpContent? ToHttpContent() => diff --git a/src/Telegram.Bot/Requests/Inline Mode/AnswerInlineQueryRequest.cs b/src/Telegram.Bot/Requests/Inline Mode/AnswerInlineQueryRequest.cs index 5bc0bcbe4..4b2265397 100644 --- a/src/Telegram.Bot/Requests/Inline Mode/AnswerInlineQueryRequest.cs +++ b/src/Telegram.Bot/Requests/Inline Mode/AnswerInlineQueryRequest.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Types.InlineQueryResults; // ReSharper disable once CheckNamespace @@ -17,13 +18,13 @@ public class AnswerInlineQueryRequest : RequestBase /// Unique identifier for the answered query /// [JsonProperty(Required = Required.Always)] - public string InlineQueryId { get; } + public required string InlineQueryId { get; init; } /// /// An array of results for the inline query /// [JsonProperty(Required = Required.Always)] - public IEnumerable Results { get; } + public required IEnumerable Results { get; init; } /// /// The maximum amount of time in seconds that the result of the @@ -58,10 +59,19 @@ public class AnswerInlineQueryRequest : RequestBase /// /// Unique identifier for the answered query /// An array of results for the inline query + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public AnswerInlineQueryRequest(string inlineQueryId, IEnumerable results) - : base("answerInlineQuery") + : this() { InlineQueryId = inlineQueryId; Results = results; } + + /// + /// Initializes a new request + /// + public AnswerInlineQueryRequest() + : base("answerInlineQuery") + { } } diff --git a/src/Telegram.Bot/Requests/Inline Mode/AnswerWebAppQueryRequest.cs b/src/Telegram.Bot/Requests/Inline Mode/AnswerWebAppQueryRequest.cs index a4b14f194..320cb4457 100644 --- a/src/Telegram.Bot/Requests/Inline Mode/AnswerWebAppQueryRequest.cs +++ b/src/Telegram.Bot/Requests/Inline Mode/AnswerWebAppQueryRequest.cs @@ -1,4 +1,5 @@ -using Telegram.Bot.Types.InlineQueryResults; +using System.Diagnostics.CodeAnalysis; +using Telegram.Bot.Types.InlineQueryResults; // ReSharper disable once CheckNamespace namespace Telegram.Bot.Requests; @@ -15,23 +16,32 @@ public class AnswerWebAppQueryRequest : RequestBase /// Unique identifier for the query to be answered /// [JsonProperty(Required = Required.Always)] - public string WebAppQueryId { get; } + public required string WebAppQueryId { get; init; } /// /// An object describing the message to be sent /// [JsonProperty(Required = Required.Always)] - public InlineQueryResult Result { get; } + public required InlineQueryResult Result { get; init; } /// /// Initializes a new request with and a /// /// Unique identifier for the query to be answered /// An object describing the message to be sent + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public AnswerWebAppQueryRequest(string webAppQueryId, InlineQueryResult result) - : base("answerWebAppQuery") + : this() { WebAppQueryId = webAppQueryId; Result = result; } + + /// + /// Initializes a new request + /// + public AnswerWebAppQueryRequest() + : base("answerWebAppQuery") + { } } diff --git a/src/Telegram.Bot/Requests/ParameterlessRequest.cs b/src/Telegram.Bot/Requests/ParameterlessRequest.cs index 1c9cd5fd7..e0a2bff02 100644 --- a/src/Telegram.Bot/Requests/ParameterlessRequest.cs +++ b/src/Telegram.Bot/Requests/ParameterlessRequest.cs @@ -7,13 +7,13 @@ namespace Telegram.Bot.Requests; /// /// [JsonObject(MemberSerialization.OptIn, NamingStrategyType = typeof(SnakeCaseNamingStrategy))] -public class ParameterlessRequest : RequestBase +public abstract class ParameterlessRequest : RequestBase { /// /// Initializes an instance of /// /// Name of request method - public ParameterlessRequest(string methodName) + protected ParameterlessRequest(string methodName) : base(methodName) { } @@ -22,7 +22,7 @@ public ParameterlessRequest(string methodName) /// /// Name of request method /// HTTP request method - public ParameterlessRequest(string methodName, HttpMethod method) + protected ParameterlessRequest(string methodName, HttpMethod method) : base(methodName, method) { } diff --git a/src/Telegram.Bot/Requests/Payments/AnswerPreCheckoutQueryRequest.cs b/src/Telegram.Bot/Requests/Payments/AnswerPreCheckoutQueryRequest.cs index 7f62bbc09..3e20680ca 100644 --- a/src/Telegram.Bot/Requests/Payments/AnswerPreCheckoutQueryRequest.cs +++ b/src/Telegram.Bot/Requests/Payments/AnswerPreCheckoutQueryRequest.cs @@ -1,4 +1,6 @@ -// ReSharper disable once CheckNamespace +using System.Diagnostics.CodeAnalysis; + +// ReSharper disable once CheckNamespace namespace Telegram.Bot.Requests; /// @@ -17,14 +19,14 @@ public class AnswerPreCheckoutQueryRequest : RequestBase /// Unique identifier for the query to be answered /// [JsonProperty(Required = Required.Always)] - public string PreCheckoutQueryId { get; } + public required string PreCheckoutQueryId { get; init; } /// /// Specify if everything is alright (goods are available, etc.) and the /// bot is ready to proceed with the order. Use if there are any problems. /// [JsonProperty(Required = Required.Always)] - public bool Ok { get; } + public required bool Ok { get; init; } /// /// Required if is . Error message in human readable form that explains @@ -33,14 +35,15 @@ public class AnswerPreCheckoutQueryRequest : RequestBase /// Please choose a different color or garment!"). Telegram will display this message to the user. /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public string? ErrorMessage { get; } + public string? ErrorMessage { get; set; } /// /// Initializes a new successful answerPreCheckoutQuery request /// /// Unique identifier for the query to be answered + [SetsRequiredMembers] public AnswerPreCheckoutQueryRequest(string preCheckoutQueryId) - : base("answerPreCheckoutQuery") + : this() { PreCheckoutQueryId = preCheckoutQueryId; Ok = true; @@ -56,11 +59,19 @@ public AnswerPreCheckoutQueryRequest(string preCheckoutQueryId) /// our amazing black T-shirts while you were busy filling out your payment details. Please /// choose a different color or garment!"). Telegram will display this message to the user. /// + [SetsRequiredMembers] public AnswerPreCheckoutQueryRequest(string preCheckoutQueryId, string errorMessage) - : base("answerPreCheckoutQuery") + : this() { PreCheckoutQueryId = preCheckoutQueryId; Ok = false; ErrorMessage = errorMessage; } + + /// + /// Initializes a new failing answerPreCheckoutQuery request with error message + /// + public AnswerPreCheckoutQueryRequest() + : base("answerPreCheckoutQuery") + { } } diff --git a/src/Telegram.Bot/Requests/Payments/AnswerShippingQueryRequest.cs b/src/Telegram.Bot/Requests/Payments/AnswerShippingQueryRequest.cs index 64d07c70e..7f973b710 100644 --- a/src/Telegram.Bot/Requests/Payments/AnswerShippingQueryRequest.cs +++ b/src/Telegram.Bot/Requests/Payments/AnswerShippingQueryRequest.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Types.Payments; // ReSharper disable once CheckNamespace @@ -17,20 +18,20 @@ public class AnswerShippingQueryRequest : RequestBase /// Unique identifier for the query to be answered /// [JsonProperty(Required = Required.Always)] - public string ShippingQueryId { get; } + public required string ShippingQueryId { get; init; } /// /// Specify if delivery to the specified address is possible and /// if there are any problems (for example, if delivery to the specified address is not possible) /// [JsonProperty(Required = Required.Always)] - public bool Ok { get; } + public required bool Ok { get; init; } /// /// Required if is . An array of available shipping options. /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public IEnumerable? ShippingOptions { get; } + public IEnumerable? ShippingOptions { get; init; } /// /// Required if is . Error message in human readable form that explains @@ -38,15 +39,16 @@ public class AnswerShippingQueryRequest : RequestBase /// is unavailable'). Telegram will display this message to the user. /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public string? ErrorMessage { get; } + public string? ErrorMessage { get; set; } /// /// Initializes a new failing answerShippingQuery request with error message /// /// Unique identifier for the query to be answered /// Error message in human readable form + [SetsRequiredMembers] public AnswerShippingQueryRequest(string shippingQueryId, string errorMessage) - : base("answerShippingQuery") + : this() { ShippingQueryId = shippingQueryId; Ok = false; @@ -58,12 +60,20 @@ public AnswerShippingQueryRequest(string shippingQueryId, string errorMessage) /// /// Unique identifier for the query to be answered /// A JSON-serialized array of available shipping options + [SetsRequiredMembers] public AnswerShippingQueryRequest( string shippingQueryId, - IEnumerable shippingOptions) : base("answerShippingQuery") + IEnumerable shippingOptions) : this() { ShippingQueryId = shippingQueryId; Ok = true; ShippingOptions = shippingOptions; } + + /// + /// Initializes a new request + /// + public AnswerShippingQueryRequest() + : base("answerShippingQuery") + { } } diff --git a/src/Telegram.Bot/Requests/Payments/CreateInvoiceLinkRequest.cs b/src/Telegram.Bot/Requests/Payments/CreateInvoiceLinkRequest.cs index 7d4c3b715..5252145a1 100644 --- a/src/Telegram.Bot/Requests/Payments/CreateInvoiceLinkRequest.cs +++ b/src/Telegram.Bot/Requests/Payments/CreateInvoiceLinkRequest.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Types.Payments; // ReSharper disable once CheckNamespace @@ -14,40 +15,40 @@ public class CreateInvoiceLinkRequest : RequestBase /// Product name, 1-32 characters /// [JsonProperty(Required = Required.Always)] - public string Title { get; } + public required string Title { get; init; } /// /// Product description, 1-255 characters /// [JsonProperty(Required = Required.Always)] - public string Description { get; } + public required string Description { get; init; } /// /// Bot-defined invoice payload, 1-128 bytes.This will not be displayed to the user, /// use for your internal processes. /// [JsonProperty(Required = Required.Always)] - public string Payload { get; } + public required string Payload { get; init; } /// /// Payments provider token, obtained via @BotFather /// [JsonProperty(Required = Required.Always)] - public string ProviderToken { get; } + public required string ProviderToken { get; init; } /// /// Three-letter ISO 4217 currency code, see /// more on currencies /// [JsonProperty(Required = Required.Always)] - public string Currency { get; } + public required string Currency { get; init; } /// /// Price breakdown, a list of components (e.g. product price, tax, discount, delivery cost, /// delivery tax, bonus, etc.) /// [JsonProperty(Required = Required.Always)] - public IEnumerable Prices { get; } + public required IEnumerable Prices { get; init; } /// /// The maximum accepted amount for tips in the smallest units of the currency. @@ -160,13 +161,16 @@ public class CreateInvoiceLinkRequest : RequestBase /// Price breakdown, a list of components (e.g. product price, tax, discount, delivery cost, /// delivery tax, bonus, etc.) /// + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public CreateInvoiceLinkRequest( string title, string description, string payload, string providerToken, string currency, - IEnumerable prices) : base("createInvoiceLink") + IEnumerable prices) + : this() { Title = title; Description = description; @@ -175,4 +179,11 @@ public class CreateInvoiceLinkRequest : RequestBase Currency = currency; Prices = prices; } + + /// + /// Initializes a new request + /// + public CreateInvoiceLinkRequest() + : base("createInvoiceLink") + { } } diff --git a/src/Telegram.Bot/Requests/Payments/SendInvoiceRequest.cs b/src/Telegram.Bot/Requests/Payments/SendInvoiceRequest.cs index 89d81738d..d681cf4b0 100644 --- a/src/Telegram.Bot/Requests/Payments/SendInvoiceRequest.cs +++ b/src/Telegram.Bot/Requests/Payments/SendInvoiceRequest.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Requests.Abstractions; using Telegram.Bot.Types.Payments; using Telegram.Bot.Types.ReplyMarkups; @@ -17,7 +18,7 @@ public class SendInvoiceRequest : RequestBase, IChatTargetable /// (in the format @channelusername) /// [JsonProperty(Required = Required.Always)] - public long ChatId { get; } + public required long ChatId { get; init; } /// ChatId IChatTargetable.ChatId => ChatId; @@ -32,40 +33,40 @@ public class SendInvoiceRequest : RequestBase, IChatTargetable /// Product name, 1-32 characters /// [JsonProperty(Required = Required.Always)] - public string Title { get; } + public required string Title { get; init; } /// /// Product description, 1-255 characters /// [JsonProperty(Required = Required.Always)] - public string Description { get; } + public required string Description { get; init; } /// /// Bot-defined invoice payload, 1-128 bytes. This will not be displayed to the user, /// use for your internal processes /// [JsonProperty(Required = Required.Always)] - public string Payload { get; } + public required string Payload { get; init; } /// /// Payments provider token, obtained via @BotFather /// [JsonProperty(Required = Required.Always)] - public string ProviderToken { get; } + public required string ProviderToken { get; init; } /// /// Three-letter ISO 4217 currency code, see /// more on currencies /// [JsonProperty(Required = Required.Always)] - public string Currency { get; } + public required string Currency { get; init; } /// /// Price breakdown, a list of components (e.g. product price, tax, discount, delivery cost, /// delivery tax, bonus, etc.) /// [JsonProperty(Required = Required.Always)] - public IEnumerable Prices { get; } + public required IEnumerable Prices { get; init; } /// /// The maximum accepted amount for tips in the smallest units of the currency. @@ -178,13 +179,9 @@ public class SendInvoiceRequest : RequestBase, IChatTargetable [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] public bool? ProtectContent { get; set; } - /// + /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public int? ReplyToMessageId { get; set; } - - /// - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public bool? AllowSendingWithoutReply { get; set; } + public ReplyParameters? ReplyParameters { get; set; } /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] @@ -212,6 +209,8 @@ public class SendInvoiceRequest : RequestBase, IChatTargetable /// Price breakdown, a list of components (e.g. product price, tax, discount, delivery cost, /// delivery tax, bonus, etc.) /// + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public SendInvoiceRequest( long chatId, string title, @@ -219,7 +218,7 @@ public class SendInvoiceRequest : RequestBase, IChatTargetable string payload, string providerToken, string currency, - IEnumerable prices) : base("sendInvoice") + IEnumerable prices) : this() { ChatId = chatId; Title = title; @@ -229,4 +228,11 @@ public class SendInvoiceRequest : RequestBase, IChatTargetable Currency = currency; Prices = prices; } + + /// + /// Initializes a new request + /// + public SendInvoiceRequest() + : base("sendInvoice") + { } } diff --git a/src/Telegram.Bot/Requests/Stickers/AddStickerToSetRequest.cs b/src/Telegram.Bot/Requests/Stickers/AddStickerToSetRequest.cs index fe4267fa5..e7e8e12cc 100644 --- a/src/Telegram.Bot/Requests/Stickers/AddStickerToSetRequest.cs +++ b/src/Telegram.Bot/Requests/Stickers/AddStickerToSetRequest.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using System.Net.Http; using Telegram.Bot.Requests.Abstractions; @@ -25,20 +26,20 @@ public class AddStickerToSetRequest : FileRequestBase, IUserTargetable { /// [JsonProperty(Required = Required.Always)] - public long UserId { get; } + public required long UserId { get; init; } /// /// Sticker set name /// [JsonProperty(Required = Required.Always)] - public string Name { get; } + public required string Name { get; init; } /// /// A JSON-serialized object with information about the added sticker. /// If exactly the same sticker had already been added to the set, then the set isn't changed. /// [JsonProperty(Required = Required.Always)] - public InputSticker Sticker { get; } + public required InputSticker Sticker { get; init; } /// /// Initializes a new request with userId, name and sticker @@ -53,17 +54,26 @@ public class AddStickerToSetRequest : FileRequestBase, IUserTargetable /// A JSON-serialized object with information about the added sticker. /// If exactly the same sticker had already been added to the set, then the set isn't changed. /// + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public AddStickerToSetRequest( long userId, string name, InputSticker sticker) - : base("addStickerToSet") + : this() { UserId = userId; Name = name; Sticker = sticker; } + /// + /// Initializes a new request + /// + public AddStickerToSetRequest() + : base("addStickerToSet") + { } + /// public override HttpContent? ToHttpContent() => diff --git a/src/Telegram.Bot/Requests/Stickers/CreateNewStickerSetRequest.cs b/src/Telegram.Bot/Requests/Stickers/CreateNewStickerSetRequest.cs index a4294d61c..629312d5f 100644 --- a/src/Telegram.Bot/Requests/Stickers/CreateNewStickerSetRequest.cs +++ b/src/Telegram.Bot/Requests/Stickers/CreateNewStickerSetRequest.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Net.Http; using Telegram.Bot.Extensions; using Telegram.Bot.Requests.Abstractions; @@ -17,7 +18,7 @@ public class CreateNewStickerSetRequest : FileRequestBase, IUserTargetable { /// [JsonProperty(Required = Required.Always)] - public long UserId { get; } + public required long UserId { get; init; } /// /// Short name of sticker set, to be used in t.me/addstickers/ URLs (e.g., animals). @@ -26,25 +27,25 @@ public class CreateNewStickerSetRequest : FileRequestBase, IUserTargetable /// <bot_username> is case insensitive. 1-64 characters /// [JsonProperty(Required = Required.Always)] - public string Name { get; } + public required string Name { get; init; } /// /// Sticker set title, 1-64 characters /// [JsonProperty(Required = Required.Always)] - public string Title { get; } + public required string Title { get; init; } /// /// A JSON-serialized list of 1-50 initial stickers to be added to the sticker set /// [JsonProperty(Required = Required.Always)] - public IEnumerable Stickers { get; } + public required IEnumerable Stickers { get; init; } /// /// Format of stickers in the set. /// [JsonProperty(Required = Required.Always)] - public StickerFormat StickerFormat { get; } + public required StickerFormat StickerFormat { get; init; } /// /// Type of stickers in the set. @@ -83,13 +84,15 @@ public class CreateNewStickerSetRequest : FileRequestBase, IUserTargetable /// /// Format of stickers in the set. /// + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public CreateNewStickerSetRequest( long userId, string name, string title, IEnumerable stickers, StickerFormat stickerFormat) - : base("createNewStickerSet") + : this() { UserId = userId; Name = name; @@ -98,6 +101,13 @@ public class CreateNewStickerSetRequest : FileRequestBase, IUserTargetable StickerFormat = stickerFormat; } + /// + /// Initializes a new request + /// + public CreateNewStickerSetRequest() + : base("createNewStickerSet") + { } + /// public override HttpContent ToHttpContent() { diff --git a/src/Telegram.Bot/Requests/Stickers/DeleteStickerFromSetRequest.cs b/src/Telegram.Bot/Requests/Stickers/DeleteStickerFromSetRequest.cs index 5c0956669..7082e5f42 100644 --- a/src/Telegram.Bot/Requests/Stickers/DeleteStickerFromSetRequest.cs +++ b/src/Telegram.Bot/Requests/Stickers/DeleteStickerFromSetRequest.cs @@ -1,3 +1,5 @@ +using System.Diagnostics.CodeAnalysis; + // ReSharper disable once CheckNamespace namespace Telegram.Bot.Requests; @@ -11,7 +13,7 @@ public class DeleteStickerFromSetRequest : RequestBase /// File identifier of the sticker /// [JsonProperty(Required = Required.Always)] - public InputFileId Sticker { get; } + public required InputFileId Sticker { get; init; } /// /// Initializes a new request with sticker @@ -19,9 +21,18 @@ public class DeleteStickerFromSetRequest : RequestBase /// /// File identifier of the sticker /// + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public DeleteStickerFromSetRequest(InputFileId sticker) - : base("deleteStickerFromSet") + : this() { Sticker = sticker; } + + /// + /// Initializes a new request with sticker + /// + public DeleteStickerFromSetRequest() + : base("deleteStickerFromSet") + { } } diff --git a/src/Telegram.Bot/Requests/Stickers/DeleteStickerSetRequest.cs b/src/Telegram.Bot/Requests/Stickers/DeleteStickerSetRequest.cs index 2efd192e7..d7d467e26 100644 --- a/src/Telegram.Bot/Requests/Stickers/DeleteStickerSetRequest.cs +++ b/src/Telegram.Bot/Requests/Stickers/DeleteStickerSetRequest.cs @@ -1,3 +1,6 @@ +using System.Diagnostics.CodeAnalysis; + +// ReSharper disable once CheckNamespace namespace Telegram.Bot.Requests; /// @@ -11,7 +14,7 @@ namespace Telegram.Bot.Requests; /// Sticker set name /// [JsonProperty(Required = Required.Always)] - public string Name { get; } + public required string Name { get; init; } /// /// Initializes a new request with name @@ -19,9 +22,18 @@ namespace Telegram.Bot.Requests; /// /// Sticker set name /// + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public DeleteStickerSetRequest(string name) - : base("deleteStickerSet") + : this() { Name = name; } + + /// + /// Initializes a new request + /// + public DeleteStickerSetRequest() + : base("deleteStickerSet") + { } } diff --git a/src/Telegram.Bot/Requests/Stickers/GetCustomEmojiStickersRequest.cs b/src/Telegram.Bot/Requests/Stickers/GetCustomEmojiStickersRequest.cs index c9a641e25..9a339ba6e 100644 --- a/src/Telegram.Bot/Requests/Stickers/GetCustomEmojiStickersRequest.cs +++ b/src/Telegram.Bot/Requests/Stickers/GetCustomEmojiStickersRequest.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; // ReSharper disable once CheckNamespace namespace Telegram.Bot.Requests; @@ -14,16 +15,26 @@ public class GetCustomEmojiStickersRequest : RequestBase /// List of custom emoji identifiers. At most 200 custom emoji identifiers can be specified. /// [JsonProperty(Required = Required.Always)] - public IEnumerable CustomEmojiIds { get; } + public required IEnumerable CustomEmojiIds { get; init; } /// /// Initializes a new request with name /// - /// List of custom emoji identifiers. At most 200 custom emoji - /// identifiers can be specified. + /// + /// List of custom emoji identifiers. At most 200 custom emoji identifiers can be specified. + /// + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public GetCustomEmojiStickersRequest(IEnumerable customEmojiIds) - : base("getCustomEmojiStickers") + : this() { CustomEmojiIds = customEmojiIds; } + + /// + /// Initializes a new request with name + /// + public GetCustomEmojiStickersRequest() + : base("getCustomEmojiStickers") + { } } diff --git a/src/Telegram.Bot/Requests/Stickers/GetStickerSetRequest.cs b/src/Telegram.Bot/Requests/Stickers/GetStickerSetRequest.cs index 261a3bca6..0715a00d9 100644 --- a/src/Telegram.Bot/Requests/Stickers/GetStickerSetRequest.cs +++ b/src/Telegram.Bot/Requests/Stickers/GetStickerSetRequest.cs @@ -1,3 +1,5 @@ +using System.Diagnostics.CodeAnalysis; + // ReSharper disable once CheckNamespace namespace Telegram.Bot.Requests; @@ -11,15 +13,24 @@ public class GetStickerSetRequest : RequestBase /// Name of the sticker set /// [JsonProperty(Required = Required.Always)] - public string Name { get; } + public required string Name { get; init; } /// /// Initializes a new request with name /// /// Name of the sticker set + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public GetStickerSetRequest(string name) - : base("getStickerSet") + : this() { Name = name; } + + /// + /// Initializes a new request with name + /// + public GetStickerSetRequest() + : base("getStickerSet") + { } } diff --git a/src/Telegram.Bot/Requests/Stickers/SendStickerRequest.cs b/src/Telegram.Bot/Requests/Stickers/SendStickerRequest.cs index 02790c5da..12f581792 100644 --- a/src/Telegram.Bot/Requests/Stickers/SendStickerRequest.cs +++ b/src/Telegram.Bot/Requests/Stickers/SendStickerRequest.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using System.Net.Http; using Telegram.Bot.Requests.Abstractions; using Telegram.Bot.Types.ReplyMarkups; @@ -14,7 +15,7 @@ public class SendStickerRequest : FileRequestBase, IChatTargetable { /// [JsonProperty(Required = Required.Always)] - public ChatId ChatId { get; } + public required ChatId ChatId { get; init; } /// /// Optional. Unique identifier for the target message thread (topic) of the forum; for forum supergroups only @@ -31,7 +32,7 @@ public class SendStickerRequest : FileRequestBase, IChatTargetable /// Animated stickers can't be sent via an HTTP URL. /// [JsonProperty(Required = Required.Always)] - public InputFile Sticker { get; } + public required InputFile Sticker { get; init; } /// /// Optional. Emoji associated with the sticker; only for just uploaded stickers @@ -47,13 +48,9 @@ public class SendStickerRequest : FileRequestBase, IChatTargetable [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] public bool? ProtectContent { get; set; } - /// + /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public int? ReplyToMessageId { get; set; } - - /// - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public bool? AllowSendingWithoutReply { get; set; } + public ReplyParameters? ReplyParameters { get; set; } /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] @@ -74,13 +71,22 @@ public class SendStickerRequest : FileRequestBase, IChatTargetable /// Video stickers can only be sent by a . /// Animated stickers can't be sent via an HTTP URL. /// + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public SendStickerRequest(ChatId chatId, InputFile sticker) - : base("sendSticker") + : this() { ChatId = chatId; Sticker = sticker; } + /// + /// Initializes a new request chatId and sticker + /// + public SendStickerRequest() + : base("sendSticker") + { } + /// public override HttpContent? ToHttpContent() => Sticker switch diff --git a/src/Telegram.Bot/Requests/Stickers/SetCustomEmojiStickerSetThumbnailRequest.cs b/src/Telegram.Bot/Requests/Stickers/SetCustomEmojiStickerSetThumbnailRequest.cs index a4f33948c..c4b0f983d 100644 --- a/src/Telegram.Bot/Requests/Stickers/SetCustomEmojiStickerSetThumbnailRequest.cs +++ b/src/Telegram.Bot/Requests/Stickers/SetCustomEmojiStickerSetThumbnailRequest.cs @@ -1,3 +1,6 @@ +using System.Diagnostics.CodeAnalysis; + +// ReSharper disable once CheckNamespace namespace Telegram.Bot.Requests; /// @@ -11,7 +14,7 @@ public class SetCustomEmojiStickerSetThumbnailRequest : RequestBase /// Sticker set name /// [JsonProperty(Required = Required.Always)] - public string Name { get; } + public required string Name { get; init; } /// /// Optional. Custom emoji identifier of a from the ; @@ -26,9 +29,18 @@ public class SetCustomEmojiStickerSetThumbnailRequest : RequestBase /// /// Sticker set name /// + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public SetCustomEmojiStickerSetThumbnailRequest(string name) - : base("setCustomEmojiStickerSetThumbnail") + : this() { Name = name; } + + /// + /// Initializes a new request + /// + public SetCustomEmojiStickerSetThumbnailRequest() + : base("setCustomEmojiStickerSetThumbnail") + { } } diff --git a/src/Telegram.Bot/Requests/Stickers/SetStickerEmojiListRequest.cs b/src/Telegram.Bot/Requests/Stickers/SetStickerEmojiListRequest.cs index 3b88db490..a063aabcd 100644 --- a/src/Telegram.Bot/Requests/Stickers/SetStickerEmojiListRequest.cs +++ b/src/Telegram.Bot/Requests/Stickers/SetStickerEmojiListRequest.cs @@ -1,5 +1,7 @@ using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +// ReSharper disable once CheckNamespace namespace Telegram.Bot.Requests; /// @@ -14,13 +16,13 @@ public class SetStickerEmojiListRequest : RequestBase /// File identifier of the sticker /// [JsonProperty(Required = Required.Always)] - public InputFileId Sticker { get; } + public required InputFileId Sticker { get; init; } /// /// A JSON-serialized list of 1-20 emoji associated with the sticker /// [JsonProperty(Required = Required.Always)] - public IEnumerable EmojiList { get; } + public required IEnumerable EmojiList { get; init; } /// /// Initializes a new request with sticker and emojiList @@ -31,10 +33,19 @@ public class SetStickerEmojiListRequest : RequestBase /// /// A JSON-serialized list of 1-20 emoji associated with the sticker /// + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public SetStickerEmojiListRequest(InputFileId sticker, IEnumerable emojiList) - : base("setStickerEmojiList") + : this() { Sticker = sticker; EmojiList = emojiList; } + + /// + /// Initializes a new request + /// + public SetStickerEmojiListRequest() + : base("setStickerEmojiList") + { } } diff --git a/src/Telegram.Bot/Requests/Stickers/SetStickerKeywordsRequest.cs b/src/Telegram.Bot/Requests/Stickers/SetStickerKeywordsRequest.cs index 28b66a993..222c680b2 100644 --- a/src/Telegram.Bot/Requests/Stickers/SetStickerKeywordsRequest.cs +++ b/src/Telegram.Bot/Requests/Stickers/SetStickerKeywordsRequest.cs @@ -1,5 +1,7 @@ using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +// ReSharper disable once CheckNamespace namespace Telegram.Bot.Requests; /// @@ -14,7 +16,7 @@ public class SetStickerKeywordsRequest : RequestBase /// File identifier of the sticker /// [JsonProperty(Required = Required.Always)] - public InputFileId Sticker { get; } + public required InputFileId Sticker { get; init; } /// /// Optional. A JSON-serialized list of 0-20 search keywords for the sticker @@ -29,9 +31,18 @@ public class SetStickerKeywordsRequest : RequestBase /// /// File identifier of the sticker /// + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public SetStickerKeywordsRequest(InputFileId sticker) - : base("setStickerKeywords") + : this() { Sticker = sticker; } + + /// + /// Initializes a new request + /// + public SetStickerKeywordsRequest() + : base("setStickerKeywords") + { } } diff --git a/src/Telegram.Bot/Requests/Stickers/SetStickerMaskPositionRequest.cs b/src/Telegram.Bot/Requests/Stickers/SetStickerMaskPositionRequest.cs index 277f35d14..651c12fd9 100644 --- a/src/Telegram.Bot/Requests/Stickers/SetStickerMaskPositionRequest.cs +++ b/src/Telegram.Bot/Requests/Stickers/SetStickerMaskPositionRequest.cs @@ -1,3 +1,6 @@ +using System.Diagnostics.CodeAnalysis; + +// ReSharper disable once CheckNamespace namespace Telegram.Bot.Requests; /// @@ -13,7 +16,7 @@ public class SetStickerMaskPositionRequest : RequestBase /// File identifier of the sticker /// [JsonProperty(Required = Required.Always)] - public InputFileId Sticker { get; } + public required InputFileId Sticker { get; init; } /// /// A JSON-serialized object with the position where the mask should be placed on faces. @@ -28,9 +31,18 @@ public class SetStickerMaskPositionRequest : RequestBase /// /// File identifier of the sticker /// + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public SetStickerMaskPositionRequest(InputFileId sticker) - : base("setStickerMaskPosition") + : this() { Sticker = sticker; } + + /// + /// Initializes a new request + /// + public SetStickerMaskPositionRequest() + : base("setStickerMaskPosition") + { } } diff --git a/src/Telegram.Bot/Requests/Stickers/SetStickerPositionInSetRequest.cs b/src/Telegram.Bot/Requests/Stickers/SetStickerPositionInSetRequest.cs index 83676b6ec..d6ea2baaa 100644 --- a/src/Telegram.Bot/Requests/Stickers/SetStickerPositionInSetRequest.cs +++ b/src/Telegram.Bot/Requests/Stickers/SetStickerPositionInSetRequest.cs @@ -1,3 +1,5 @@ +using System.Diagnostics.CodeAnalysis; + // ReSharper disable once CheckNamespace namespace Telegram.Bot.Requests; @@ -12,13 +14,13 @@ public class SetStickerPositionInSetRequest : RequestBase /// File identifier of the sticker /// [JsonProperty(Required = Required.Always)] - public InputFileId Sticker { get; } + public required InputFileId Sticker { get; init; } /// /// New sticker position in the set, zero-based /// [JsonProperty(Required = Required.Always)] - public int Position { get; } + public required int Position { get; init; } /// /// Initializes a new request with sticker and position @@ -27,10 +29,19 @@ public class SetStickerPositionInSetRequest : RequestBase /// File identifier of the sticker /// /// New sticker position in the set, zero-based + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public SetStickerPositionInSetRequest(InputFileId sticker, int position) - : base("setStickerPositionInSet") + : this() { Sticker = sticker; Position = position; } + + /// + /// Initializes a new request + /// + public SetStickerPositionInSetRequest() + : base("setStickerPositionInSet") + { } } diff --git a/src/Telegram.Bot/Requests/Stickers/SetStickerSetThumbnailRequest.cs b/src/Telegram.Bot/Requests/Stickers/SetStickerSetThumbnailRequest.cs index 34e7d8ad0..6945d85bc 100644 --- a/src/Telegram.Bot/Requests/Stickers/SetStickerSetThumbnailRequest.cs +++ b/src/Telegram.Bot/Requests/Stickers/SetStickerSetThumbnailRequest.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using System.Net.Http; using Telegram.Bot.Requests.Abstractions; @@ -16,11 +17,11 @@ public class SetStickerSetThumbnailRequest : FileRequestBase, IUserTargeta /// Sticker set name /// [JsonProperty(Required = Required.Always)] - public string Name { get; } + public required string Name { get; init; } /// [JsonProperty(Required = Required.Always)] - public long UserId { get; } + public required long UserId { get; init; } /// /// A .WEBP or .PNG image with the thumbnail, must be up to 128 kilobytes in size and have @@ -41,13 +42,22 @@ public class SetStickerSetThumbnailRequest : FileRequestBase, IUserTargeta /// /// Sticker set name /// User identifier of the sticker set owner + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public SetStickerSetThumbnailRequest(string name, long userId) - : base("setStickerSetThumbnail") + : this() { Name = name; UserId = userId; } + /// + /// Initializes a new request + /// + public SetStickerSetThumbnailRequest() + : base("setStickerSetThumbnail") + { } + /// public override HttpContent? ToHttpContent() => Thumbnail switch diff --git a/src/Telegram.Bot/Requests/Stickers/SetStickerSetTitleRequest.cs b/src/Telegram.Bot/Requests/Stickers/SetStickerSetTitleRequest.cs index 130546cc1..3f970c79f 100644 --- a/src/Telegram.Bot/Requests/Stickers/SetStickerSetTitleRequest.cs +++ b/src/Telegram.Bot/Requests/Stickers/SetStickerSetTitleRequest.cs @@ -1,3 +1,6 @@ +using System.Diagnostics.CodeAnalysis; + +// ReSharper disable once CheckNamespace namespace Telegram.Bot.Requests; /// @@ -11,13 +14,13 @@ public class SetStickerSetTitleRequest : RequestBase /// Sticker set name /// [JsonProperty(Required = Required.Always)] - public string Name { get; } + public required string Name { get; init; } /// /// Sticker set title, 1-64 characters /// [JsonProperty(Required = Required.Always)] - public string Title { get; } + public required string Title { get; init; } /// /// Initializes a new request with name and title @@ -28,10 +31,19 @@ public class SetStickerSetTitleRequest : RequestBase /// /// Sticker set title, 1-64 characters /// + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public SetStickerSetTitleRequest(string name, string title) - : base("setStickerSetTitle") + : this() { Name = name; Title = title; } + + /// + /// Initializes a new request + /// + public SetStickerSetTitleRequest() + : base("setStickerSetTitle") + { } } diff --git a/src/Telegram.Bot/Requests/Stickers/UploadStickerFileRequest.cs b/src/Telegram.Bot/Requests/Stickers/UploadStickerFileRequest.cs index 8d7250a4c..1e31a0eb4 100644 --- a/src/Telegram.Bot/Requests/Stickers/UploadStickerFileRequest.cs +++ b/src/Telegram.Bot/Requests/Stickers/UploadStickerFileRequest.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using System.Net.Http; using Telegram.Bot.Requests.Abstractions; using Telegram.Bot.Types.Enums; @@ -17,19 +18,19 @@ public class UploadStickerFileRequest : FileRequestBase, IUserTargetable { /// [JsonProperty(Required = Required.Always)] - public long UserId { get; } + public required long UserId { get; init; } /// /// A file with the sticker in .WEBP, .PNG, .TGS, or .WEBM format. /// [JsonProperty(Required = Required.Always)] - public InputFileStream Sticker { get; } + public required InputFileStream Sticker { get; init; } /// /// Format of the sticker /// [JsonProperty(Required = Required.Always)] - public StickerFormat StickerFormat { get; } + public required StickerFormat StickerFormat { get; init; } /// /// Initializes a new request with userId, sticker and stickerFormat @@ -43,14 +44,23 @@ public class UploadStickerFileRequest : FileRequestBase, IUserTargetable /// /// Format of the sticker /// + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public UploadStickerFileRequest(long userId, InputFileStream sticker, StickerFormat stickerFormat) - : base("uploadStickerFile") + : this() { UserId = userId; Sticker = sticker; StickerFormat = stickerFormat; } + /// + /// Initializes a new request + /// + public UploadStickerFileRequest() + : base("uploadStickerFile") + { } + /// public override HttpContent? ToHttpContent() => ToMultipartFormDataContent(fileParameterName: "sticker", inputFile: Sticker); diff --git a/src/Telegram.Bot/Requests/Updating messages/DeleteMessageRequest.cs b/src/Telegram.Bot/Requests/Updating messages/DeleteMessageRequest.cs index a4d3b2c88..fe7780bee 100644 --- a/src/Telegram.Bot/Requests/Updating messages/DeleteMessageRequest.cs +++ b/src/Telegram.Bot/Requests/Updating messages/DeleteMessageRequest.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Requests.Abstractions; // ReSharper disable once CheckNamespace @@ -24,13 +25,13 @@ public class DeleteMessageRequest : RequestBase, IChatTargetable { /// [JsonProperty(Required = Required.Always)] - public ChatId ChatId { get; } + public required ChatId ChatId { get; init; } /// /// Identifier of the message to delete /// [JsonProperty(Required = Required.Always)] - public int MessageId { get; } + public required int MessageId { get; init; } /// /// Initializes a new request with chatId and messageId @@ -40,10 +41,19 @@ public class DeleteMessageRequest : RequestBase, IChatTargetable /// (in the format @channelusername) /// /// Identifier of the message to delete + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public DeleteMessageRequest(ChatId chatId, int messageId) - : base("deleteMessage") + : this() { ChatId = chatId; MessageId = messageId; } + + /// + /// Initializes a new request + /// + public DeleteMessageRequest() + : base("deleteMessage") + { } } diff --git a/src/Telegram.Bot/Requests/Updating messages/DeleteMessagesRequest.cs b/src/Telegram.Bot/Requests/Updating messages/DeleteMessagesRequest.cs new file mode 100644 index 000000000..5f4e67797 --- /dev/null +++ b/src/Telegram.Bot/Requests/Updating messages/DeleteMessagesRequest.cs @@ -0,0 +1,53 @@ +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using Telegram.Bot.Requests.Abstractions; + +// ReSharper disable once CheckNamespace +namespace Telegram.Bot.Requests; + +/// +/// Use this method to delete multiple messages simultaneously. +/// If some of the specified messages can't be found, they are skipped. +/// Returns on success. +/// +[JsonObject(MemberSerialization.OptIn, NamingStrategyType = typeof(SnakeCaseNamingStrategy))] +public class DeleteMessagesRequest : RequestBase, IChatTargetable +{ + /// + [JsonProperty(Required = Required.Always)] + public required ChatId ChatId { get; init; } + + /// + /// Identifiers of 1-100 messages to delete. See + /// for limitations on which messages can be deleted + /// + [JsonProperty(Required = Required.Always)] + public required IEnumerable MessageIds { get; init; } + + /// + /// Initializes a new request with chatId and messageIds + /// + /// + /// Unique identifier for the target chat or username of the target channel + /// (in the format @channelusername) + /// + /// + /// Identifiers of 1-100 messages to delete. See + /// for limitations on which messages can be deleted + /// + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] + public DeleteMessagesRequest(ChatId chatId, IEnumerable messageIds) + : this() + { + ChatId = chatId; + MessageIds = messageIds; + } + + /// + /// Initializes a new request with chatId and messageIds + /// + public DeleteMessagesRequest() + : base("deleteMessages") + { } +} diff --git a/src/Telegram.Bot/Requests/Updating messages/EditInlineMessageCaptionRequest.cs b/src/Telegram.Bot/Requests/Updating messages/EditInlineMessageCaptionRequest.cs index a2e2899a2..660291d1a 100644 --- a/src/Telegram.Bot/Requests/Updating messages/EditInlineMessageCaptionRequest.cs +++ b/src/Telegram.Bot/Requests/Updating messages/EditInlineMessageCaptionRequest.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Requests.Abstractions; using Telegram.Bot.Types.Enums; using Telegram.Bot.Types.ReplyMarkups; @@ -14,7 +15,7 @@ public class EditInlineMessageCaptionRequest : RequestBase { /// [JsonProperty(Required = Required.Always)] - public string InlineMessageId { get; } + public required string InlineMessageId { get; init; } /// /// New caption of the message, 0-1024 characters after entities parsing @@ -38,9 +39,18 @@ public class EditInlineMessageCaptionRequest : RequestBase /// Initializes a new request with inlineMessageId and new caption /// /// Identifier of the inline message + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public EditInlineMessageCaptionRequest(string inlineMessageId) - : base("editMessageCaption") + : this() { InlineMessageId = inlineMessageId; } + + /// + /// Initializes a new request with inlineMessageId and new caption + /// + public EditInlineMessageCaptionRequest() + : base("editMessageCaption") + { } } diff --git a/src/Telegram.Bot/Requests/Updating messages/EditInlineMessageMediaRequest.cs b/src/Telegram.Bot/Requests/Updating messages/EditInlineMessageMediaRequest.cs index b54ce9e58..e918dd761 100644 --- a/src/Telegram.Bot/Requests/Updating messages/EditInlineMessageMediaRequest.cs +++ b/src/Telegram.Bot/Requests/Updating messages/EditInlineMessageMediaRequest.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Requests.Abstractions; using Telegram.Bot.Types.ReplyMarkups; @@ -16,13 +17,13 @@ public class EditInlineMessageMediaRequest : RequestBase { /// [JsonProperty(Required = Required.Always)] - public string InlineMessageId { get; } + public required string InlineMessageId { get; init; } /// /// A new media content of the message /// [JsonProperty(Required = Required.Always)] - public InputMedia Media { get; } + public required InputMedia Media { get; init; } /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] @@ -33,10 +34,19 @@ public class EditInlineMessageMediaRequest : RequestBase /// /// Identifier of the inline message /// A new media content of the message + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public EditInlineMessageMediaRequest(string inlineMessageId, InputMedia media) - : base("editMessageMedia") + : this() { InlineMessageId = inlineMessageId; Media = media; } + + /// + /// Initializes a new request with inlineMessageId and new media + /// + public EditInlineMessageMediaRequest() + : base("editMessageMedia") + { } } diff --git a/src/Telegram.Bot/Requests/Updating messages/EditInlineMessageReplyMarkupRequest.cs b/src/Telegram.Bot/Requests/Updating messages/EditInlineMessageReplyMarkupRequest.cs index cd8bdd2a2..3d6d10f96 100644 --- a/src/Telegram.Bot/Requests/Updating messages/EditInlineMessageReplyMarkupRequest.cs +++ b/src/Telegram.Bot/Requests/Updating messages/EditInlineMessageReplyMarkupRequest.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Requests.Abstractions; using Telegram.Bot.Types.ReplyMarkups; @@ -12,7 +13,7 @@ public class EditInlineMessageReplyMarkupRequest : RequestBase { /// [JsonProperty(Required = Required.Always)] - public string InlineMessageId { get; } + public required string InlineMessageId { get; init; } /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] @@ -22,9 +23,18 @@ public class EditInlineMessageReplyMarkupRequest : RequestBase /// Initializes a new request with inlineMessageId and new inline keyboard /// /// Identifier of the inline message + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public EditInlineMessageReplyMarkupRequest(string inlineMessageId) - : base("editMessageReplyMarkup") + : this() { InlineMessageId = inlineMessageId; } + + /// + /// Initializes a new request + /// + public EditInlineMessageReplyMarkupRequest() + : base("editMessageReplyMarkup") + { } } diff --git a/src/Telegram.Bot/Requests/Updating messages/EditInlineMessageTextRequest.cs b/src/Telegram.Bot/Requests/Updating messages/EditInlineMessageTextRequest.cs index a44308bb4..727dd7bcc 100644 --- a/src/Telegram.Bot/Requests/Updating messages/EditInlineMessageTextRequest.cs +++ b/src/Telegram.Bot/Requests/Updating messages/EditInlineMessageTextRequest.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Requests.Abstractions; using Telegram.Bot.Types.Enums; using Telegram.Bot.Types.ReplyMarkups; @@ -14,13 +15,13 @@ public class EditInlineMessageTextRequest : RequestBase { /// [JsonProperty(Required = Required.Always)] - public string InlineMessageId { get; } + public required string InlineMessageId { get; init; } /// /// New text of the message, 1-4096 characters after entities parsing /// [JsonProperty(Required = Required.Always)] - public string Text { get; } + public required string Text { get; init; } /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] @@ -31,10 +32,10 @@ public class EditInlineMessageTextRequest : RequestBase public IEnumerable? Entities { get; set; } /// - /// Disables link previews for links in this message + /// Link preview generation options for the message /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public bool? DisableWebPagePreview { get; set; } + public LinkPreviewOptions? LinkPreviewOptions { get; set; } /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] @@ -45,10 +46,19 @@ public class EditInlineMessageTextRequest : RequestBase /// /// Identifier of the inline message /// New text of the message, 1-4096 characters after entities parsing + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public EditInlineMessageTextRequest(string inlineMessageId, string text) - : base("editMessageText") + : this() { InlineMessageId = inlineMessageId; Text = text; } + + /// + /// Initializes a new request with inlineMessageId and new text + /// + public EditInlineMessageTextRequest() + : base("editMessageText") + { } } diff --git a/src/Telegram.Bot/Requests/Updating messages/EditMessageCaptionRequest.cs b/src/Telegram.Bot/Requests/Updating messages/EditMessageCaptionRequest.cs index ba67b17cf..a0ad5b8f3 100644 --- a/src/Telegram.Bot/Requests/Updating messages/EditMessageCaptionRequest.cs +++ b/src/Telegram.Bot/Requests/Updating messages/EditMessageCaptionRequest.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Requests.Abstractions; using Telegram.Bot.Types.Enums; using Telegram.Bot.Types.ReplyMarkups; @@ -14,13 +15,13 @@ public class EditMessageCaptionRequest : RequestBase, IChatTargetable { /// [JsonProperty(Required = Required.Always)] - public ChatId ChatId { get; } + public required ChatId ChatId { get; init; } /// /// Identifier of the message to edit /// [JsonProperty(Required = Required.Always)] - public int MessageId { get; } + public required int MessageId { get; init; } /// /// New caption of the message, 0-1024 characters after entities parsing @@ -47,10 +48,19 @@ public class EditMessageCaptionRequest : RequestBase, IChatTargetable /// (in the format @channelusername) /// /// Identifier of the message to edit + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public EditMessageCaptionRequest(ChatId chatId, int messageId) - : base("editMessageCaption") + : this() { ChatId = chatId; MessageId = messageId; } + + /// + /// Initializes a new request with chatId and messageIdn + /// + public EditMessageCaptionRequest() + : base("editMessageCaption") + { } } diff --git a/src/Telegram.Bot/Requests/Updating messages/EditMessageMediaRequest.cs b/src/Telegram.Bot/Requests/Updating messages/EditMessageMediaRequest.cs index c7396d401..ae3bc83cd 100644 --- a/src/Telegram.Bot/Requests/Updating messages/EditMessageMediaRequest.cs +++ b/src/Telegram.Bot/Requests/Updating messages/EditMessageMediaRequest.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using System.Net.Http; using Telegram.Bot.Extensions; using Telegram.Bot.Requests.Abstractions; @@ -19,19 +20,19 @@ public class EditMessageMediaRequest : FileRequestBase, IChatTargetable { /// [JsonProperty(Required = Required.Always)] - public ChatId ChatId { get; } + public required ChatId ChatId { get; init; } /// /// Identifier of the message to edit /// [JsonProperty(Required = Required.Always)] - public int MessageId { get; } + public required int MessageId { get; init; } /// /// A new media content of the message /// [JsonProperty(Required = Required.Always)] - public InputMedia Media { get; } + public required InputMedia Media { get; init; } /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] @@ -46,14 +47,23 @@ public class EditMessageMediaRequest : FileRequestBase, IChatTargetable /// /// Identifier of the message to edit /// A new media content of the message + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public EditMessageMediaRequest(ChatId chatId, int messageId, InputMedia media) - : base("editMessageMedia") + : this() { ChatId = chatId; MessageId = messageId; Media = media; } + /// + /// Initializes a new + /// + public EditMessageMediaRequest() + : base("editMessageMedia") + { } + /// public override HttpContent? ToHttpContent() { diff --git a/src/Telegram.Bot/Requests/Updating messages/EditMessageReplyMarkupRequest.cs b/src/Telegram.Bot/Requests/Updating messages/EditMessageReplyMarkupRequest.cs index 7335fbf35..a8c7a7158 100644 --- a/src/Telegram.Bot/Requests/Updating messages/EditMessageReplyMarkupRequest.cs +++ b/src/Telegram.Bot/Requests/Updating messages/EditMessageReplyMarkupRequest.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Requests.Abstractions; using Telegram.Bot.Types.ReplyMarkups; @@ -13,13 +14,13 @@ public class EditMessageReplyMarkupRequest : RequestBase, IChatTargetab { /// [JsonProperty(Required = Required.Always)] - public ChatId ChatId { get; } + public required ChatId ChatId { get; init; } /// /// Identifier of the message to edit /// [JsonProperty(Required = Required.Always)] - public int MessageId { get; } + public required int MessageId { get; init; } /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] @@ -33,10 +34,19 @@ public class EditMessageReplyMarkupRequest : RequestBase, IChatTargetab /// (in the format @channelusername) /// /// Identifier of the message to edit + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public EditMessageReplyMarkupRequest(ChatId chatId, int messageId) - : base("editMessageReplyMarkup") + : this() { ChatId = chatId; MessageId = messageId; } + + /// + /// Initializes a new request with chatId and messageId + /// + public EditMessageReplyMarkupRequest() + : base("editMessageReplyMarkup") + { } } diff --git a/src/Telegram.Bot/Requests/Updating messages/EditMessageTextRequest.cs b/src/Telegram.Bot/Requests/Updating messages/EditMessageTextRequest.cs index b3bbba159..cab8edc66 100644 --- a/src/Telegram.Bot/Requests/Updating messages/EditMessageTextRequest.cs +++ b/src/Telegram.Bot/Requests/Updating messages/EditMessageTextRequest.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Requests.Abstractions; using Telegram.Bot.Types.Enums; using Telegram.Bot.Types.ReplyMarkups; @@ -14,19 +15,19 @@ public class EditMessageTextRequest : RequestBase, IChatTargetable { /// [JsonProperty(Required = Required.Always)] - public ChatId ChatId { get; } + public required ChatId ChatId { get; init; } /// /// Identifier of the message to edit /// [JsonProperty(Required = Required.Always)] - public int MessageId { get; } + public required int MessageId { get; init; } /// /// New text of the message, 1-4096 characters after entities parsing /// [JsonProperty(Required = Required.Always)] - public string Text { get; } + public required string Text { get; init; } /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] @@ -37,10 +38,10 @@ public class EditMessageTextRequest : RequestBase, IChatTargetable public IEnumerable? Entities { get; set; } /// - /// Disables link previews for links in this message + /// Link preview generation options for the message /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public bool? DisableWebPagePreview { get; set; } + public LinkPreviewOptions? LinkPreviewOptions { get; set; } /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] @@ -55,11 +56,20 @@ public class EditMessageTextRequest : RequestBase, IChatTargetable /// /// Identifier of the message to edit /// New text of the message, 1-4096 characters after entities parsing + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public EditMessageTextRequest(ChatId chatId, int messageId, string text) - : base("editMessageText") + : this() { ChatId = chatId; MessageId = messageId; Text = text; } + + /// + /// Initializes a new request + /// + public EditMessageTextRequest() + : base("editMessageText") + { } } diff --git a/src/Telegram.Bot/Requests/Updating messages/StopPollRequest.cs b/src/Telegram.Bot/Requests/Updating messages/StopPollRequest.cs index 0eadcf287..0c9dbe1f0 100644 --- a/src/Telegram.Bot/Requests/Updating messages/StopPollRequest.cs +++ b/src/Telegram.Bot/Requests/Updating messages/StopPollRequest.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Requests.Abstractions; using Telegram.Bot.Types.ReplyMarkups; @@ -14,13 +15,13 @@ public class StopPollRequest : RequestBase, IChatTargetable { /// [JsonProperty(Required = Required.Always)] - public ChatId ChatId { get; } + public required ChatId ChatId { get; init; } /// /// Identifier of the original message with the poll /// [JsonProperty(Required = Required.Always)] - public int MessageId { get; } + public required int MessageId { get; init; } /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] @@ -34,10 +35,19 @@ public class StopPollRequest : RequestBase, IChatTargetable /// @channelusername) /// /// Identifier of the original message with the poll + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public StopPollRequest(ChatId chatId, int messageId) - : base("stopPoll") + : this() { ChatId = chatId; MessageId = messageId; } + + /// + /// Initializes a new request + /// + public StopPollRequest() + : base("stopPoll") + { } } diff --git a/src/Telegram.Bot/Telegram.Bot.csproj b/src/Telegram.Bot/Telegram.Bot.csproj index 883305b5a..23caa6dc8 100644 --- a/src/Telegram.Bot/Telegram.Bot.csproj +++ b/src/Telegram.Bot/Telegram.Bot.csproj @@ -2,9 +2,8 @@ netstandard2.0;net6.0 - 11 + 12 enable - 7 True AllEnabledByDefault latest-recommended @@ -24,6 +23,7 @@ RoundRobin,Poulad,tuscen Copyright © Robin Müller 2016 package-icon.png + README.md https://github.com/TelegramBots/telegram.bot MIT https://github.com/TelegramBots/telegram.bot.git @@ -52,7 +52,12 @@ 'HttpClient.GetAsync(Uri, HttpCompletionOption, CancellationToken)' instead of 'HttpClient.GetAsync(string, HttpCompletionOption, CancellationToken)' --> $(NoWarn);CA1031 - $(NoWarn);MA0046;MA0048;MA0051 + $(NoWarn);CA1716 + $(NoWarn);CA1510 + $(NoWarn);MA0046 + $(NoWarn);MA0048;MA0051 @@ -60,6 +65,7 @@ true / + @@ -70,7 +76,7 @@ - + @@ -79,9 +85,11 @@ - - - + + + + + diff --git a/src/Telegram.Bot/TelegramBotClient.cs b/src/Telegram.Bot/TelegramBotClient.cs index d3b0adfd7..bdf77b08c 100644 --- a/src/Telegram.Bot/TelegramBotClient.cs +++ b/src/Telegram.Bot/TelegramBotClient.cs @@ -149,7 +149,7 @@ public TimeSpan Timeout var apiResponse = await httpResponse .DeserializeContentAsync>( - guard: response => response.Ok == false || + guard: response => !response.Ok || response.Result is null ) .ConfigureAwait(false); @@ -253,8 +253,13 @@ await MakeRequestAsync(request: new GetMeRequest(), cancellationToken: cancellat try { +#if NET6_0_OR_GREATER + await httpResponse.Content.CopyToAsync(destination, cancellationToken) + .ConfigureAwait(false); +#else await httpResponse.Content.CopyToAsync(destination) .ConfigureAwait(false); +#endif } catch (Exception exception) { diff --git a/src/Telegram.Bot/TelegramBotClientExtensions.ApiMethods.Requests.cs b/src/Telegram.Bot/TelegramBotClientExtensions.ApiMethods.Requests.cs new file mode 100644 index 000000000..0ecc34fae --- /dev/null +++ b/src/Telegram.Bot/TelegramBotClientExtensions.ApiMethods.Requests.cs @@ -0,0 +1,2529 @@ +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using Telegram.Bot.Extensions; +using Telegram.Bot.Requests; +using Telegram.Bot.Types.Enums; +using Telegram.Bot.Types.Payments; +using Telegram.Bot.Types.ReplyMarkups; +using File = Telegram.Bot.Types.File; + +namespace Telegram.Bot; + +/// +/// Extension methods that map to requests from Bot API documentation +/// +public static partial class TelegramBotClientExtensions +{ + /// + /// Use this method to send answers to callback queries sent from + /// inline keyboards. The answer will be displayed + /// to the user as a notification at the top of the chat screen or as an alert + /// + /// + /// Alternatively, the user can be redirected to the specified Game URL.For this option to work, you must + /// first create a game for your bot via @BotFather and accept the terms. Otherwise, you may use + /// links like t.me/your_bot?start=XXXX that open your bot with a parameter + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + public static async Task AnswerCallbackQueryAsync( + this ITelegramBotClient botClient, + AnswerCallbackQueryRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to delete the list of the bot’s commands for the given + /// and user language. After deletion, + /// higher level commands + /// will be shown to affected users + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + public static async Task DeleteMyCommandsAsync( + this ITelegramBotClient botClient, + DeleteMyCommandsRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to get the current list of the bot’s commands for the given + /// and user language + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + /// + /// Returns Array of on success. If commands aren't set, an empty list is returned + /// + public static async Task GetMyCommandsAsync( + this ITelegramBotClient botClient, + GetMyCommandsRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to change the list of the bot’s commands. + /// See for more details about bot commands + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + public static async Task SetMyCommandsAsync( + this ITelegramBotClient botClient, + SetMyCommandsRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to get the current bot description + /// for the given user language. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + /// + /// Returns on success. + /// + public static async Task GetMyDescriptionAsync( + this ITelegramBotClient botClient, + GetMyDescriptionRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to change the bot's description, which is shown in the chat + /// with the bot if the chat is empty. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + public static async Task SetMyDescriptionAsync( + this ITelegramBotClient botClient, + SetMyDescriptionRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to get basic info about a file and prepare it for downloading. For the moment, bots can + /// download files of up to 20MB in size. The file can then be downloaded via the link + /// https://api.telegram.org/file/bot<token>/<file_path>, where <file_path> + /// is taken from the response. It is guaranteed that the link will be valid for at least 1 hour. + /// When the link expires, a new one can be requested by calling + /// GetFileAsync again. + /// + /// + /// You can use or + /// methods to download the file + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + /// On success, a object is returned. + public static async Task GetFileAsync( + this ITelegramBotClient botClient, + GetFileRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to get basic info about a file download it. For the moment, bots can download files + /// of up to 20MB in size. + /// + /// An instance of + /// File identifier to get info about + /// Destination stream to write file to + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + /// On success, a object is returned. + public static async Task GetInfoAndDownloadFileAsync( + this ITelegramBotClient botClient, + string fileId, + Stream destination, + CancellationToken cancellationToken = default) + { + var file = await botClient.ThrowIfNull() + .MakeRequestAsync(new GetFileRequest { FileId = fileId }, cancellationToken) + .ConfigureAwait(false); + + await botClient.DownloadFileAsync(filePath: file.FilePath!, destination, cancellationToken) + .ConfigureAwait(false); + + return file; + } + + /// + /// Use this method to get a list of profile pictures for a user. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + /// Returns a object + public static async Task GetUserProfilePhotosAsync( + this ITelegramBotClient botClient, + GetUserProfilePhotosRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to get the current value of the bot’s menu button in a private chat, + /// or the default menu button. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + /// set for the given chat id or a default one + public static async Task GetChatMenuButtonAsync( + this ITelegramBotClient botClient, + GetChatMenuButtonRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// A simple method for testing your bot’s auth token. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + /// Returns basic information about the bot in form of a object. + public static async Task GetMeAsync( + this ITelegramBotClient botClient, + GetMeRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to get the current default administrator rights of the bot. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + /// Default or channel + public static async Task GetMyDefaultAdministratorRightsAsync( + this ITelegramBotClient botClient, + GetMyDefaultAdministratorRightsRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to get the current bot name for the given user language. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + /// + /// Returns on success. + /// + public static async Task GetMyNameAsync( + this ITelegramBotClient botClient, + GetMyNameRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to get the list of boosts added to a chat by a user. + /// Requires administrator rights in the chat. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + /// Returns a object. + public static async Task GetUserChatBoostsAsync( + this ITelegramBotClient botClient, + GetUserChatBoostsRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to close the bot instance before moving it from one local server to another. You need to + /// delete the webhook before calling this method to ensure that the bot isn't launched again after server + /// restart. The method will return error 429 in the first 10 minutes after the bot is launched. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + public static async Task CloseAsync( + this ITelegramBotClient botClient, + CloseRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to log out from the cloud Bot API server before launching the bot locally. You must + /// log out the bot before running it locally, otherwise there is no guarantee that the bot will receive + /// updates. After a successful call, you can immediately log in on a local server, but will not be able to + /// log in back to the cloud Bot API server for 10 minutes. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + public static async Task LogOutAsync( + this ITelegramBotClient botClient, + LogOutRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to ban a user in a group, a supergroup or a channel. In the case of supergroups and + /// channels, the user will not be able to return to the chat on their own using invite links, etc., unless + /// unbanned + /// first. The bot must be an administrator in the chat for this to work and must have the appropriate + /// admin rights. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + public static async Task BanChatMemberAsync( + this ITelegramBotClient botClient, + BanChatMemberRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + /// + public static async Task BanChatSenderChatAsync( + this ITelegramBotClient botClient, + BanChatSenderChatRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to approve a chat join request. The bot must be an administrator in the chat for this to + /// work and must have the administrator right. + /// Returns on success. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + public static async Task ApproveChatJoinRequestAsync( + this ITelegramBotClient botClient, + ApproveChatJoinRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to create an additional invite link for a chat. The bot must be an administrator + /// in the chat for this to work and must have the appropriate admin rights. The link can be revoked + /// using the method + /// RevokeChatInviteLinkAsync + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + /// Returns the new invite link as object. + public static async Task CreateChatInviteLinkAsync( + this ITelegramBotClient botClient, + CreateChatInviteLinkRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to decline a chat join request. The bot must be an administrator in the chat for this to + /// work and must have the administrator right. + /// Returns on success. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + public static async Task DeclineChatJoinRequestAsync( + this ITelegramBotClient botClient, + DeclineChatJoinRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to edit a non-primary invite link created by the bot. The bot must be an + /// administrator in the chat for this to work and must have the appropriate admin rights + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + /// Returns the edited invite link as a object. + public static async Task EditChatInviteLinkAsync( + this ITelegramBotClient botClient, + EditChatInviteLinkRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to generate a new primary invite link for a chat; any previously generated primary + /// link is revoked. The bot must be an administrator in the chat for this to work and must have the + /// appropriate admin rights + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + public static async Task ExportChatInviteLinkAsync( + this ITelegramBotClient botClient, + ExportChatInviteLinkRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to revoke an invite link created by the bot. If the primary link is revoked, a new + /// link is automatically generated. The bot must be an administrator in the chat for this to work and + /// must have the appropriate admin rights + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + /// Returns the revoked invite link as object. + public static async Task RevokeChatInviteLinkAsync( + this ITelegramBotClient botClient, + RevokeChatInviteLinkRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to close an open topic in a forum supergroup chat. The bot must be an administrator in the chat + /// for this to work and must have the administrator rights, + /// unless it is the creator of the topic. Returns on success. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + public static async Task CloseForumTopicAsync( + this ITelegramBotClient botClient, + CloseForumTopicRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to close an open 'General' topic in a forum supergroup chat. The bot must be an administrator + /// in the chat for this to work and must have the + /// administrator rights. Returns on success. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + public static async Task CloseGeneralForumTopicAsync( + this ITelegramBotClient botClient, + CloseGeneralForumTopicRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to create a topic in a forum supergroup chat. The bot must be an administrator in the chat for + /// this to work and must have the administrator rights. + /// Returns information about the created topic as a object. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + /// + /// Returns information about the created topic as a object. + /// + public static async Task CreateForumTopicAsync( + this ITelegramBotClient botClient, + CreateForumTopicRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to delete a chat photo. Photos can't be changed for private chats. The bot must be an + /// administrator in the chat for this to work and must have the appropriate admin rights + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + public static async Task DeleteChatPhotoAsync( + this ITelegramBotClient botClient, + DeleteChatPhotoRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to delete a group sticker set from a supergroup. The bot must be an administrator in the + /// chat for this to work and must have the appropriate admin rights. Use the field + /// optionally returned in + /// GetChatAsync + /// requests to check if the bot can use this method + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + public static async Task DeleteChatStickerSetAsync( + this ITelegramBotClient botClient, + DeleteChatStickerSetRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to delete a forum topic along with all its messages in a forum supergroup chat. The bot must be + /// an administrator in the chat for this to work and must have the + /// administrator rights. Returns + /// on success. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + public static async Task DeleteForumTopicAsync( + this ITelegramBotClient botClient, + DeleteForumTopicRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to edit name and icon of a topic in a forum supergroup chat. The bot must be an administrator + /// in the chat for this to work and must have administrator + /// rights, unless it is the creator of the topic. Returns on success. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + public static async Task EditForumTopicAsync( + this ITelegramBotClient botClient, + EditForumTopicRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to edit the name of the 'General' topic in a forum supergroup chat. The bot must be an + /// administrator in the chat for this to work and must have + /// administrator rights. Returns on success. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + public static async Task EditGeneralForumTopicAsync( + this ITelegramBotClient botClient, + EditGeneralForumTopicRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to get a list of administrators in a chat. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + /// + /// On success, returns an Array of objects that contains information about all chat + /// administrators except other bots. If the chat is a group or a supergroup and no administrators were + /// appointed, only the creator will be returned + /// + public static async Task GetChatAdministratorsAsync( + this ITelegramBotClient botClient, + GetChatAdministratorsRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to get the number of members in a chat. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + /// Returns on success. + public static async Task GetChatMemberCountAsync( + this ITelegramBotClient botClient, + GetChatMemberCountRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to get information about a member of a chat. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + /// Returns a object on success. + public static async Task GetChatMemberAsync( + this ITelegramBotClient botClient, + GetChatMemberRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to get up to date information about the chat (current name of the user for one-on-one + /// conversations, current username of a user, group or channel, etc.) + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + /// Returns a object on success. + public static async Task GetChatAsync( + this ITelegramBotClient botClient, + GetChatRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to hide the 'General' topic in a forum supergroup chat. The bot must be an administrator in the + /// chat for this to work and must have the administrator + /// rights. The topic will be automatically closed if it was open. Returns on success. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + public static async Task HideGeneralForumTopicAsync( + this ITelegramBotClient botClient, + HideGeneralForumTopicRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method for your bot to leave a group, supergroup or channel. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + public static async Task LeaveChatAsync( + this ITelegramBotClient botClient, + LeaveChatRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + /// + public static async Task PinChatMessageAsync( + this ITelegramBotClient botClient, + PinChatMessageRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to promote or demote a user in a supergroup or a channel. The bot must be an administrator in + /// the chat for this to work and must have the appropriate admin rights. Pass for + /// all boolean parameters to demote a user. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + public static async Task PromoteChatMemberAsync( + this ITelegramBotClient botClient, + PromoteChatMemberRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to reopen a closed topic in a forum supergroup chat. The bot must be an administrator in the + /// chat for this to work and must have the administrator + /// rights, unless it is the creator of the topic. Returns on success. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + public static async Task ReopenForumTopicAsync( + this ITelegramBotClient botClient, + ReopenForumTopicRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to reopen a closed 'General' topic in a forum supergroup chat. The bot must be an + /// administrator in the chat for this to work and must have the + /// administrator rights. The topic will be automatically + /// unhidden if it was hidden. Returns on success. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + public static async Task ReopenGeneralForumTopicAsync( + this ITelegramBotClient botClient, + ReopenGeneralForumTopicRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to restrict a user in a supergroup. The bot must be an administrator in the supergroup + /// for this to work and must have the appropriate admin rights. Pass for all permissions to + /// lift restrictions from a user. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + public static async Task RestrictChatMemberAsync( + this ITelegramBotClient botClient, + RestrictChatMemberRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to set a custom title for an administrator in a supergroup promoted by the bot. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + public static async Task SetChatAdministratorCustomTitleAsync( + this ITelegramBotClient botClient, + SetChatAdministratorCustomTitleRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to change the description of a group, a supergroup or a channel. The bot must + /// be an administrator in the chat for this to work and must have the appropriate admin rights + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + public static async Task SetChatDescriptionAsync( + this ITelegramBotClient botClient, + SetChatDescriptionRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to set default chat permissions for all members. The bot must be an administrator + /// in the group or a supergroup for this to work and must have the + /// admin rights + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + public static async Task SetChatPermissionsAsync( + this ITelegramBotClient botClient, + SetChatPermissionsRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to set a new profile photo for the chat. Photos can't be changed for private chats. + /// The bot must be an administrator in the chat for this to work and must have the appropriate admin rights + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + public static async Task SetChatPhotoAsync( + this ITelegramBotClient botClient, + SetChatPhotoRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to set a new group sticker set for a supergroup. The bot must be an administrator in the + /// chat for this to work and must have the appropriate admin rights. Use the field + /// optionally returned in + /// GetChatAsync + /// request to check if the bot can use this method. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + public static async Task SetChatStickerSetAsync( + this ITelegramBotClient botClient, + SetChatStickerSetRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to change the title of a chat. Titles can't be changed for private chats. The bot + /// must be an administrator in the chat for this to work and must have the appropriate admin rights + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + public static async Task SetChatTitleAsync( + this ITelegramBotClient botClient, + SetChatTitleRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to unban a previously banned user in a supergroup or channel. The user will not + /// return to the group or channel automatically, but will be able to join via link, etc. The bot must be an + /// administrator for this to work. By default, this method guarantees that after the call the user is not a + /// member of the chat, but will be able to join it. So if the user is a member of the chat they will also be + /// removed from the chat. + /// If you don't want this, use the property + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + public static async Task UnbanChatMemberAsync( + this ITelegramBotClient botClient, + UnbanChatMemberRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to unban a previously banned channel chat in a supergroup or channel. The bot must be + /// an administrator for this to work and must have the appropriate administrator rights. + /// Returns on success. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + public static async Task UnbanChatSenderChatAsync( + this ITelegramBotClient botClient, + UnbanChatSenderChatRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to uhhide the 'General' topic in a forum supergroup chat. The bot must be an administrator + /// in the chat for this to work and must have the + /// administrator rights. Returns on success. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + public static async Task UnhideGeneralForumTopicAsync( + this ITelegramBotClient botClient, + UnhideGeneralForumTopicRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to clear the list of pinned messages in a chat. If the chat is not a private chat, + /// the bot must be an administrator in the chat for this to work and must have the + /// '' admin right in a supergroup or + /// '' admin right in a channel + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + public static async Task UnpinAllChatMessagesAsync( + this ITelegramBotClient botClient, + UnpinAllChatMessagesRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to clear the list of pinned messages in a forum topic. The bot must be an administrator in the + /// chat for this to work and must have the administrator + /// right in the supergroup. Returns on success. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + public static async Task UnpinAllForumTopicMessagesAsync( + this ITelegramBotClient botClient, + UnpinAllForumTopicMessagesRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to clear the list of pinned messages in a General forum topic. The bot must be an administrator + /// in the chat for this to work and must have the + /// administrator right in the supergroup. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + public static async Task UnpinAllGeneralForumTopicMessagesAsync( + this ITelegramBotClient botClient, + UnpinAllGeneralForumTopicMessagesRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to remove a message from the list of pinned messages in a chat. If the chat is not + /// a private chat, the bot must be an administrator in the chat for this to work and must have the + /// '' admin right in a supergroup or + /// '' admin right in a channel + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + public static async Task UnpinChatMessageAsync( + this ITelegramBotClient botClient, + UnpinChatMessageRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to copy messages of any kind. Service messages and invoice messages can't be copied. + /// The method is analogous to the method + /// , but the + /// copied message doesn't have a link to the original message. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + /// Returns the of the sent message on success. + public static async Task CopyMessageAsync( + this ITelegramBotClient botClient, + CopyMessageRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to copy messages of any kind. If some of the specified messages can't be found or copied, + /// they are skipped. Service messages, giveaway messages, giveaway winners messages, and invoice messages + /// can't be copied. A quiz can be copied only if the value of the field + /// CorrectOptionId is known to the bot. The method is analogous + /// to the method + /// , but the + /// copied messages don't have a link to the original message. Album grouping is kept for copied messages. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + /// On success, an array of of the sent messages is returned. + public static async Task CopyMessagesAsync( + this ITelegramBotClient botClient, + CopyMessagesRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to forward messages of any kind. Service messages can't be forwarded. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + /// On success, the sent is returned. + public static async Task ForwardMessageAsync( + this ITelegramBotClient botClient, + ForwardMessageRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to forward multiple messages of any kind. If some of the specified messages can't be found + /// or forwarded, they are skipped. Service messages and messages with protected content can't be forwarded. + /// Album grouping is kept for forwarded messages. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + /// On success, an array of of the sent messages is returned. + public static async Task ForwardMessagesAsync( + this ITelegramBotClient botClient, + ForwardMessagesRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to edit live location messages. A location can be edited until its + /// expires or editing is explicitly disabled by a call to + /// . + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + public static async Task EditInlineMessageLiveLocationAsync( + this ITelegramBotClient botClient, + EditInlineMessageLiveLocationRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to edit live location messages. A location can be edited until its + /// expires or editing is explicitly disabled by a call to + /// . + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + /// On success the edited is returned. + public static async Task EditMessageLiveLocationAsync( + this ITelegramBotClient botClient, + EditMessageLiveLocationRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to send point on the map. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + /// On success, the sent is returned. + public static async Task SendLocationAsync( + this ITelegramBotClient botClient, + SendLocationRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to send information about a venue. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + /// On success, the sent is returned. + /// + public static async Task SendVenueAsync( + this ITelegramBotClient botClient, + SendVenueRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to stop updating a live location message before + /// expires. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + public static async Task StopInlineMessageLiveLocationAsync( + this ITelegramBotClient botClient, + StopInlineMessageLiveLocationRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to stop updating a live location message before + /// expires. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + /// On success the sent is returned. + public static async Task StopMessageLiveLocationAsync( + this ITelegramBotClient botClient, + StopMessageLiveLocationRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to send animation files (GIF or H.264/MPEG-4 AVC video without sound). Bots can currently + /// send animation files of up to 50 MB in size, this limit may be changed in the future. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + /// On success, the sent is returned. + public static async Task SendAnimationAsync( + this ITelegramBotClient botClient, + SendAnimationRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to send audio files, if you want Telegram clients to display them in the music player. + /// Your audio must be in the .MP3 or .M4A format. Bots can currently send audio files of up to 50 MB in size, + /// this limit may be changed in the future. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + /// On success, the sent is returned. + public static async Task SendAudioAsync( + this ITelegramBotClient botClient, + SendAudioRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method when you need to tell the user that something is happening on the bot’s side. The status is + /// set for 5 seconds or less (when a message arrives from your bot, Telegram clients clear its typing status). + /// + /// + /// + /// The ImageBot needs some time to process a request and upload the + /// image. Instead of sending a text message along the lines of “Retrieving image, please wait…”, the bot may use + /// SendChatActionAsync + /// with = . The user will see a + /// “sending photo” status for the bot. + /// + /// + /// We only recommend using this method when a response from the bot will take a noticeable amount of + /// time to arrive. + /// + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + public static async Task SendChatActionAsync( + this ITelegramBotClient botClient, + SendChatActionRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to send phone contacts. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + /// On success, the sent is returned. + public static async Task SendContactAsync( + this ITelegramBotClient botClient, + SendContactRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to send an animated emoji that will display a random value. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + /// On success, the sent is returned. + public static async Task SendDiceAsync( + this ITelegramBotClient botClient, + SendDiceRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to send general files. Bots can currently send files of any type of up to 50 MB in size, + /// this limit may be changed in the future. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + /// On success, the sent is returned. + public static async Task SendDocumentAsync( + this ITelegramBotClient botClient, + SendDocumentRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to send a group of photos, videos, documents or audios as an album. Documents and audio + /// files can be only grouped in an album with messages of the same type. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + /// On success, an array of s that were sent is returned. + public static async Task SendMediaGroupAsync( + this ITelegramBotClient botClient, + SendMediaGroupRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to send text messages. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + /// On success, the sent is returned. + public static async Task SendMessageAsync( + this ITelegramBotClient botClient, + SendMessageRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to send photos. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + /// On success, the sent is returned. + public static async Task SendPhotoAsync( + this ITelegramBotClient botClient, + SendPhotoRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to send a native poll. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + /// On success, the sent is returned. + public static async Task SendPollAsync( + this ITelegramBotClient botClient, + SendPollRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// As of v.4.0, Telegram clients + /// support rounded square mp4 videos of up to 1 minute long. Use this method to send video messages. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + /// On success, the sent is returned. + public static async Task SendVideoNoteAsync( + this ITelegramBotClient botClient, + SendVideoNoteRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to send video files, Telegram clients support mp4 videos (other formats may be sent as + /// ). Bots can currently send video files of up to 50 MB in size, this limit may be + /// changed in the future. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + /// On success, the sent is returned. + public static async Task SendVideoAsync( + this ITelegramBotClient botClient, + SendVideoRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to send audio files, if you want Telegram clients to display the file as a playable voice + /// message. For this to work, your audio must be in an .OGG file encoded with OPUS (other formats may be sent + /// as or ). Bots can currently send voice messages of up to 50 MB + /// in size, this limit may be changed in the future. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + /// On success, the sent is returned. + public static async Task SendVoiceAsync( + this ITelegramBotClient botClient, + SendVoiceRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to change the chosen reactions on a message. Service messages can't be reacted to. + /// Automatically forwarded messages from a channel to its discussion group have the same + /// available reactions as messages in the channel. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + public static async Task SetMessageReactionAsync( + this ITelegramBotClient botClient, + SetMessageReactionRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to change the bot’s menu button in a private chat, or the default menu button. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + public static async Task SetChatMenuButtonAsync( + this ITelegramBotClient botClient, + SetChatMenuButtonRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to change the default administrator rights requested by the bot when it's added as an + /// administrator to groups or channels. These rights will be suggested to users, but they are free to modify + /// the list before adding the bot. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + public static async Task SetMyDefaultAdministratorRightsAsync( + this ITelegramBotClient botClient, + SetMyDefaultAdministratorRightsRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to change the bot's name. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + public static async Task SetMyNameAsync( + this ITelegramBotClient botClient, + SetMyNameRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to get the current bot short description + /// for the given user language. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + /// + /// Returns on success. + /// + public static async Task GetMyShortDescriptionAsync( + this ITelegramBotClient botClient, + GetMyShortDescriptionRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to change the bot's short description,which is shown on + /// the bot's profile page and is sent together with the link when users share the bot. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + /// + public static async Task SetMyShortDescriptionAsync( + this ITelegramBotClient botClient, + SetMyShortDescriptionRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to get data for high score tables. Will return the score of the specified user and + /// several of their neighbors in a game. + /// + /// + /// This method will currently return scores for the target user, plus two of their closest neighbors on + /// each side. Will also return the top three users if the user and his neighbors are not among them. + /// Please note that this behavior is subject to change. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + /// On success, returns an Array of objects. + public static async Task GetGameHighScoresAsync( + this ITelegramBotClient botClient, + GetGameHighScoresRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to get data for high score tables. Will return the score of the specified user and + /// several of their neighbors in a game. + /// + /// + /// This method will currently return scores for the target user, plus two of their closest neighbors + /// on each side. Will also return the top three users if the user and his neighbors are not among them. + /// Please note that this behavior is subject to change. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + /// On success, returns an Array of objects. + public static async Task GetInlineGameHighScoresAsync( + this ITelegramBotClient botClient, + GetInlineGameHighScoresRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to send a game. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + /// On success, the sent is returned. + public static async Task SendGameAsync( + this ITelegramBotClient botClient, + SendGameRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to set the score of the specified user in a game. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + /// + /// On success returns the edited . Returns an error, if the new score is not greater + /// than the user's current score in the chat and is + /// + public static async Task SetGameScoreAsync( + this ITelegramBotClient botClient, + SetGameScoreRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to set the score of the specified user in a game. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + /// + /// Returns an error, if the new score is not greater than the user's current score in the chat and + /// is + /// + public static async Task SetInlineGameScoreAsync( + this ITelegramBotClient botClient, + SetInlineGameScoreRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to remove webhook integration if you decide to switch back to + /// GetUpdatesAsync + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + /// Returns on success + public static async Task DeleteWebhookAsync( + this ITelegramBotClient botClient, + DeleteWebhookRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to receive incoming updates using long polling + /// (wiki) + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + /// + /// + /// This method will not work if an outgoing webhook is set up + /// + /// In order to avoid getting duplicate updates, recalculate after each server + /// response + /// + /// + /// + /// An Array of objects is returned. + public static async Task GetUpdatesAsync( + this ITelegramBotClient botClient, + GetUpdatesRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to get current webhook status. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + /// + /// On success, returns a object. If the bot is using + /// , will return an object + /// with the field empty. + /// + public static async Task GetWebhookInfoAsync( + this ITelegramBotClient botClient, + GetWebhookInfoRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to specify a URL and receive incoming updates via an outgoing webhook. + /// Whenever there is an update for the bot, we will send an HTTPS POST request to the + /// specified URL, containing a JSON-serialized . In case of + /// an unsuccessful request, we will give up after a reasonable amount of attempts. + /// Returns on success. + /// + /// If you'd like to make sure that the webhook was set by you, you can specify secret data + /// in the parameter . If specified, the request + /// will contain a header X-Telegram-Bot-Api-Secret-Token with the secret token as content. + /// + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + /// + /// + /// + /// You will not be able to receive updates using + /// for as long as an + /// outgoing webhook is set up + /// + /// + /// To use a self-signed certificate, you need to upload your + /// public key certificate using + /// parameter. Please upload as , + /// sending a string will not work + /// + /// Ports currently supported for webhooks: 443, 80, 88, 8443 + /// + /// If you're having any trouble setting up webhooks, please check out this + /// amazing guide to Webhooks. + /// + + public static async Task SetWebhookAsync( + this ITelegramBotClient botClient, + SetWebhookRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to send answers to an inline query. + /// + /// + /// No more than 50 results per query are allowed. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + public static async Task AnswerInlineQueryAsync( + this ITelegramBotClient botClient, + AnswerInlineQueryRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to set the result of an interaction with a Web App and send a corresponding message on + /// behalf of the user to the chat from which the query originated. On success, a + /// object is returned. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + public static async Task AnswerWebAppQueryAsync( + this ITelegramBotClient botClient, + AnswerWebAppQueryRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Once the user has confirmed their payment and shipping details, the Bot API sends the final confirmation + /// in the form of an with the field . + /// Use this method to respond to such pre-checkout queries. + /// + /// + /// Note: The Bot API must receive an answer within 10 seconds after the pre-checkout query was sent. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + public static async Task AnswerPreCheckoutQueryAsync( + this ITelegramBotClient botClient, + AnswerPreCheckoutQueryRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// If you sent an invoice requesting a shipping address and the parameter isFlexible" was specified, + /// the Bot API will send an with a field + /// to the bot. Use this method to reply to shipping queries + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + public static async Task AnswerShippingQueryAsync( + this ITelegramBotClient botClient, + AnswerShippingQueryRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to create a link for an invoice. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + /// On success, the sent is returned. + public static async Task CreateInvoiceLinkAsync( + this ITelegramBotClient botClient, + CreateInvoiceLinkRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to send invoices. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + /// On success, the sent is returned. + public static async Task SendInvoiceAsync( + this ITelegramBotClient botClient, + SendInvoiceRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to add a new sticker to a set created by the bot. + /// The format of the added sticker must match the format of the other stickers in the set. + /// + /// + /// Emoji sticker sets can have up to 200 stickers. + /// + /// + /// Animated and video sticker sets can have up to 50 stickers. + /// + /// + /// Static sticker sets can have up to 120 stickers. + /// + /// + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + public static async Task AddStickerToSetAsync( + this ITelegramBotClient botClient, + AddStickerToSetRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to create a new sticker set owned by a user. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + public static async Task CreateNewStickerSetAsync( + this ITelegramBotClient botClient, + CreateNewStickerSetRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to delete a sticker from a set created by the bot. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + public static async Task DeleteStickerFromSetAsync( + this ITelegramBotClient botClient, + DeleteStickerFromSetRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to delete a sticker set that was created by the bot. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + public static async Task DeleteStickerSetAsync( + this ITelegramBotClient botClient, + DeleteStickerSetRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to get information about custom emoji stickers by their identifiers. + /// Returns an Array of objects. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + /// On success, a object is returned. + public static async Task GetCustomEmojiStickersAsync( + this ITelegramBotClient botClient, + GetCustomEmojiStickersRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to get custom emoji stickers, which can be used as a forum topic icon by any user. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + /// Returns an Array of objects. + public static async Task GetForumTopicIconStickersAsync( + this ITelegramBotClient botClient, + GetForumTopicIconStickersRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to get a sticker set. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + /// + /// On success, a object is returned. + /// + public static async Task GetStickerSetAsync( + this ITelegramBotClient botClient, + GetStickerSetRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to send static .WEBP, animated .TGS, or video .WEBM stickers. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + /// + /// On success, the sent is returned. + /// + public static async Task SendStickerAsync( + this ITelegramBotClient botClient, + SendStickerRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to set the thumbnail of a custom emoji sticker set. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + public static async Task SetCustomEmojiStickerSetThumbnailAsync( + this ITelegramBotClient botClient, + SetCustomEmojiStickerSetThumbnailRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to change the list of emoji assigned to a regular or custom emoji sticker. + /// The sticker must belong to a sticker set created by the bot. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + public static async Task SetStickerEmojiListAsync( + this ITelegramBotClient botClient, + SetStickerEmojiListRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to change search keywords assigned to a regular or custom emoji sticker. + /// The sticker must belong to a sticker set created by the bot. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + public static async Task SetStickerKeywordsAsync( + this ITelegramBotClient botClient, + SetStickerKeywordsRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to change the mask position of a mask sticker. + /// The sticker must belong to a sticker set that was created by the bot. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + public static async Task SetStickerMaskPositionAsync( + this ITelegramBotClient botClient, + SetStickerMaskPositionRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to move a sticker in a set created by the bot to a specific position. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + public static async Task SetStickerPositionInSetAsync( + this ITelegramBotClient botClient, + SetStickerPositionInSetRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to set the thumbnail of a regular or mask sticker set. + /// The format of the thumbnail file must match the format of the stickers in the set. + /// Returns on success. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + public static async Task SetStickerSetThumbnailAsync( + this ITelegramBotClient botClient, + SetStickerSetThumbnailRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to set the title of a created sticker set. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + public static async Task SetStickerSetTitleAsync( + this ITelegramBotClient botClient, + SetStickerSetTitleRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to upload a file with a sticker for later use in the + /// and + /// methods (the file can be used multiple times). + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + /// + /// Returns the uploaded on success. + /// + public static async Task UploadStickerFileAsync( + this ITelegramBotClient botClient, + UploadStickerFileRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to delete a message, including service messages, with the following limitations: + /// + /// A message can only be deleted if it was sent less than 48 hours ago + /// A dice message in a private chat can only be deleted if it was sent more than 24 hours ago + /// Bots can delete outgoing messages in private chats, groups, and supergroups + /// Bots can delete incoming messages in private chats + /// Bots granted can_post_messages permissions can delete outgoing messages in channels + /// If the bot is an administrator of a group, it can delete any message there + /// + /// If the bot has can_delete_messages permission in a supergroup or a channel, it can delete any message there + /// + /// + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + public static async Task DeleteMessageAsync( + this ITelegramBotClient botClient, + DeleteMessageRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to delete multiple messages simultaneously. + /// If some of the specified messages can't be found, they are skipped. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + public static async Task DeleteMessagesAsync( + this ITelegramBotClient botClient, + DeleteMessagesRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to edit captions of messages. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + public static async Task EditInlineMessageCaptionAsync( + this ITelegramBotClient botClient, + EditInlineMessageCaptionRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to edit animation, audio, document, photo, or video messages. If a message is part of + /// a message album, then it can be edited only to an audio for audio albums, only to a document for document + /// albums and to a photo or a video otherwise. Use a previously uploaded file via its + /// or specify a URL + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + public static async Task EditInlineMessageMediaAsync( + this ITelegramBotClient botClient, + EditInlineMessageMediaRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to edit only the reply markup of messages. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + public static async Task EditInlineMessageReplyMarkupAsync( + this ITelegramBotClient botClient, + EditInlineMessageReplyMarkupRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to edit text and game messages. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + public static async Task EditInlineMessageTextAsync( + this ITelegramBotClient botClient, + EditInlineMessageTextRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to edit captions of messages. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + /// On success the edited is returned. + public static async Task EditMessageCaptionAsync( + this ITelegramBotClient botClient, + EditMessageCaptionRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to edit animation, audio, document, photo, or video messages. If a message is part of + /// a message album, then it can be edited only to an audio for audio albums, only to a document for document + /// albums and to a photo or a video otherwise. Use a previously uploaded file via its + /// or specify a URL + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + /// On success the edited is returned. + public static async Task EditMessageMediaAsync( + this ITelegramBotClient botClient, + EditMessageMediaRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to edit only the reply markup of messages. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + /// On success the edited is returned. + public static async Task EditMessageReplyMarkupAsync( + this ITelegramBotClient botClient, + EditMessageReplyMarkupRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to edit text and game messages. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + /// On success the edited is returned. + public static async Task EditMessageTextAsync( + this ITelegramBotClient botClient, + EditMessageTextRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to stop a poll which was sent by the bot. + /// + /// An instance of + /// Request parameters + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + /// On success, the stopped with the final results is returned. + public static async Task StopPollAsync( + this ITelegramBotClient botClient, + StopPollRequest request, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync(request, cancellationToken) + .ConfigureAwait(false); +} diff --git a/src/Telegram.Bot/TelegramBotClientExtensions.ApiMethods.cs b/src/Telegram.Bot/TelegramBotClientExtensions.ApiMethods.cs index 6484efb61..84a09f1c2 100644 --- a/src/Telegram.Bot/TelegramBotClientExtensions.ApiMethods.cs +++ b/src/Telegram.Bot/TelegramBotClientExtensions.ApiMethods.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.IO; using System.Threading; using System.Threading.Tasks; using Telegram.Bot.Extensions; @@ -27,8 +26,9 @@ public static partial class TelegramBotClientExtensions /// /// Identifier of the first update to be returned. Must be greater by one than the highest among the /// identifiers of previously received updates. By default, updates starting with the earliest unconfirmed - /// update are returned. An update is considered confirmed as soon as is called - /// with an higher than its . The negative offset can be + /// update are returned. An update is considered confirmed as soon as + /// is called with an + /// higher than its . The negative offset can be /// specified to retrieve updates starting from -offset update from the end /// of the updates queue. All previous updates will forgotten. /// @@ -60,6 +60,7 @@ public static partial class TelegramBotClientExtensions /// /// /// An Array of objects is returned. + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task GetUpdatesAsync( this ITelegramBotClient botClient, int? offset = default, @@ -70,12 +71,12 @@ public static partial class TelegramBotClientExtensions ) => await botClient.ThrowIfNull() .MakeRequestAsync( - request: new GetUpdatesRequest + new GetUpdatesRequest { Offset = offset, Limit = limit, Timeout = timeout, - AllowedUpdates = allowedUpdates + AllowedUpdates = allowedUpdates, }, cancellationToken ) @@ -118,7 +119,8 @@ await botClient.ThrowIfNull() /// /// /// Please note that this parameter doesn't affect updates created before the call to the - /// , so unwanted updates may be received for a short period of time. + /// , + /// so unwanted updates may be received for a short period of time. /// /// /// Pass to drop all pending updates @@ -133,8 +135,9 @@ await botClient.ThrowIfNull() /// /// /// - /// You will not be able to receive updates using for as long as an outgoing - /// webhook is set up + /// You will not be able to receive updates using + /// for as long as + /// an outgoing webhook is set up /// /// /// To use a self-signed certificate, you need to upload your @@ -147,6 +150,7 @@ await botClient.ThrowIfNull() /// If you're having any trouble setting up webhooks, please check out this /// amazing guide to Webhooks. /// + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task SetWebhookAsync( this ITelegramBotClient botClient, string url, @@ -160,8 +164,9 @@ await botClient.ThrowIfNull() ) => await botClient.ThrowIfNull() .MakeRequestAsync( - request: new SetWebhookRequest(url) + new SetWebhookRequest { + Url = url, Certificate = certificate, IpAddress = ipAddress, MaxConnections = maxConnections, @@ -175,7 +180,8 @@ await botClient.ThrowIfNull() /// - /// Use this method to remove webhook integration if you decide to switch back to + /// Use this method to remove webhook integration if you decide to switch back to + /// /// /// An instance of /// Pass to drop all pending updates @@ -183,6 +189,7 @@ await botClient.ThrowIfNull() /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// /// Returns true on success + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task DeleteWebhookAsync( this ITelegramBotClient botClient, bool? dropPendingUpdates = default, @@ -190,10 +197,7 @@ await botClient.ThrowIfNull() ) => await botClient.ThrowIfNull() .MakeRequestAsync( - request: new DeleteWebhookRequest - { - DropPendingUpdates = dropPendingUpdates - }, + new DeleteWebhookRequest { DropPendingUpdates = dropPendingUpdates }, cancellationToken ) .ConfigureAwait(false); @@ -206,15 +210,17 @@ await botClient.ThrowIfNull() /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// /// - /// On success, returns a object. If the bot is using , + /// On success, returns a object. If the bot is using + /// , /// will return an object with the field empty. /// + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task GetWebhookInfoAsync( this ITelegramBotClient botClient, CancellationToken cancellationToken = default ) => await botClient.ThrowIfNull() - .MakeRequestAsync(request: new GetWebhookInfoRequest(), cancellationToken) + .MakeRequestAsync(new GetWebhookInfoRequest(), cancellationToken) .ConfigureAwait(false); #endregion Getting updates @@ -229,12 +235,13 @@ await botClient.ThrowIfNull() /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// /// Returns basic information about the bot in form of a object. + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task GetMeAsync( this ITelegramBotClient botClient, CancellationToken cancellationToken = default ) => await botClient.ThrowIfNull() - .MakeRequestAsync(request: new GetMeRequest(), cancellationToken) + .MakeRequestAsync(new GetMeRequest(), cancellationToken) .ConfigureAwait(false); /// @@ -247,12 +254,13 @@ await botClient.ThrowIfNull() /// /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task LogOutAsync( this ITelegramBotClient botClient, CancellationToken cancellationToken = default ) => await botClient.ThrowIfNull() - .MakeRequestAsync(request: new LogOutRequest(), cancellationToken) + .MakeRequestAsync(new LogOutRequest(), cancellationToken) .ConfigureAwait(false); /// @@ -264,12 +272,13 @@ await botClient.ThrowIfNull() /// /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task CloseAsync( this ITelegramBotClient botClient, CancellationToken cancellationToken = default ) => await botClient.ThrowIfNull() - .MakeRequestAsync(request: new CloseRequest(), cancellationToken) + .MakeRequestAsync(new CloseRequest(), cancellationToken) .ConfigureAwait(false); /// @@ -293,15 +302,12 @@ await botClient.ThrowIfNull() /// List of special entities that appear in message text, which can be specified instead /// of /// - /// Disables link previews for links in this message + /// Link preview generation options for the message /// /// Sends the message silently. Users will receive a notification with no sound /// /// Protects the contents of sent messages from forwarding and saving - /// If the message is a reply, ID of the original message - /// - /// Pass , if the message should be sent even if the specified replied-to message is not found - /// + /// Description of the message to reply to /// /// Additional interface options. An inline keyboard, /// custom reply keyboard, instructions to @@ -312,6 +318,7 @@ await botClient.ThrowIfNull() /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// /// On success, the sent is returned. + [Obsolete("Use the method SendMessageAsync instead")] public static async Task SendTextMessageAsync( this ITelegramBotClient botClient, ChatId chatId, @@ -319,27 +326,27 @@ await botClient.ThrowIfNull() int? messageThreadId = default, ParseMode? parseMode = default, IEnumerable? entities = default, - bool? disableWebPagePreview = default, + LinkPreviewOptions? linkPreviewOptions = default, bool? disableNotification = default, bool? protectContent = default, - int? replyToMessageId = default, - bool? allowSendingWithoutReply = default, + ReplyParameters? replyParameters = default, IReplyMarkup? replyMarkup = default, CancellationToken cancellationToken = default ) => await botClient.ThrowIfNull() .MakeRequestAsync( - request: new SendMessageRequest(chatId, text) + new SendMessageRequest { + ChatId = chatId, + Text = text, + MessageThreadId = messageThreadId, ParseMode = parseMode, Entities = entities, - DisableWebPagePreview = disableWebPagePreview, + LinkPreviewOptions = linkPreviewOptions, DisableNotification = disableNotification, ProtectContent = protectContent, - ReplyToMessageId = replyToMessageId, - AllowSendingWithoutReply = allowSendingWithoutReply, + ReplyParameters = replyParameters, ReplyMarkup = replyMarkup, - MessageThreadId = messageThreadId, }, cancellationToken ) @@ -369,6 +376,7 @@ await botClient.ThrowIfNull() /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// /// On success, the sent is returned. + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task ForwardMessageAsync( this ITelegramBotClient botClient, ChatId chatId, @@ -381,11 +389,71 @@ await botClient.ThrowIfNull() ) => await botClient.ThrowIfNull() .MakeRequestAsync( - request: new ForwardMessageRequest(chatId, fromChatId, messageId) + new ForwardMessageRequest { + ChatId = chatId, + FromChatId = fromChatId, + MessageId = messageId, + MessageThreadId = messageThreadId, DisableNotification = disableNotification, ProtectContent = protectContent, + }, + cancellationToken + ) + .ConfigureAwait(false); + + /// + /// Use this method to forward multiple messages of any kind. If some of the specified messages can't be found + /// or forwarded, they are skipped. Service messages and messages with protected content can't be forwarded. + /// Album grouping is kept for forwarded messages. + /// + /// An instance of + /// + /// Unique identifier for the target chat or username of the target channel + /// (in the format @channelusername) + /// + /// + /// Unique identifier for the chat where the original messages were sent + /// (or channel username in the format @channelusername) + /// + /// + /// Identifiers of 1-100 messages in the chat from_chat_id to forward. + /// The identifiers must be specified in a strictly increasing order. + /// + /// + /// Unique identifier for the target message thread (topic) of the forum; for forum supergroups only + /// + /// + /// Sends the message silently. Users will receive a notification with no sound. + /// + /// + /// Protects the contents of sent messages from forwarding and saving + /// + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + /// On success, an array of of the sent messages is returned. + [Obsolete("Use the overload that accepts the corresponding request class")] + public static async Task ForwardMessagesAsync( + this ITelegramBotClient botClient, + ChatId chatId, + ChatId fromChatId, + IEnumerable messageIds, + int? messageThreadId = default, + bool? disableNotification = default, + bool? protectContent = default, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync( + new ForwardMessagesRequest + { + ChatId = chatId, + FromChatId = fromChatId, + MessageIds = messageIds, MessageThreadId = messageThreadId, + DisableNotification = disableNotification, + ProtectContent = protectContent, }, cancellationToken ) @@ -393,8 +461,9 @@ await botClient.ThrowIfNull() /// /// Use this method to copy messages of any kind. Service messages and invoice messages can't be copied. - /// The method is analogous to the method , but the copied message doesn't - /// have a link to the original message. + /// The method is analogous to the method + /// , + /// but the copied message doesn't have a link to the original message. /// /// An instance of /// @@ -426,10 +495,7 @@ await botClient.ThrowIfNull() /// Sends the message silently. Users will receive a notification with no sound /// /// Protects the contents of sent messages from forwarding and saving - /// If the message is a reply, ID of the original message - /// - /// Pass , if the message should be sent even if the specified replied-to message is not found - /// + /// Description of the message to reply to /// /// Additional interface options. An inline keyboard, /// custom reply keyboard, instructions to @@ -440,6 +506,7 @@ await botClient.ThrowIfNull() /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// /// Returns the of the sent message on success. + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task CopyMessageAsync( this ITelegramBotClient botClient, ChatId chatId, @@ -451,24 +518,91 @@ await botClient.ThrowIfNull() IEnumerable? captionEntities = default, bool? disableNotification = default, bool? protectContent = default, - int? replyToMessageId = default, - bool? allowSendingWithoutReply = default, + ReplyParameters? replyParameters = default, IReplyMarkup? replyMarkup = default, CancellationToken cancellationToken = default ) => await botClient.ThrowIfNull() .MakeRequestAsync( - request: new CopyMessageRequest(chatId, fromChatId, messageId) + new CopyMessageRequest { + ChatId = chatId, + FromChatId = fromChatId, + MessageId = messageId, + MessageThreadId = messageThreadId, Caption = caption, ParseMode = parseMode, CaptionEntities = captionEntities, - ReplyToMessageId = replyToMessageId, DisableNotification = disableNotification, ProtectContent = protectContent, - AllowSendingWithoutReply = allowSendingWithoutReply, + ReplyParameters = replyParameters, ReplyMarkup = replyMarkup, + }, + cancellationToken + ) + .ConfigureAwait(false); + + /// + /// Use this method to copy messages of any kind. If some of the specified messages can't be found or copied, + /// they are skipped. Service messages, giveaway messages, giveaway winners messages, and invoice messages + /// can't be copied. A quiz can be copied only if the value of the field + /// CorrectOptionId is known to the bot. The method is analogous + /// to the method + /// , but the + /// copied messages don't have a link to the original message. Album grouping is kept for copied messages. + /// + /// An instance of + /// + /// Unique identifier for the target chat or username of the target channel + /// (in the format @channelusername) + /// + /// + /// Unique identifier for the chat where the original messages were sent + /// (or channel username in the format @channelusername) + /// + /// + /// Identifiers of 1-100 messages in the chat to copy. + /// The identifiers must be specified in a strictly increasing order. + /// + /// + /// Unique identifier for the target message thread (topic) of the forum; for forum supergroups only + /// + /// + /// Sends the message silently. Users will receive a notification with no sound. + /// + /// + /// Protects the contents of sent messages from forwarding and saving + /// + /// + /// Pass to copy the messages without their captions + /// + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + /// On success, an array of of the sent messages is returned. + [Obsolete("Use the overload that accepts the corresponding request class")] + public static async Task CopyMessagesAsync( + this ITelegramBotClient botClient, + ChatId chatId, + ChatId fromChatId, + int[] messageIds, + int? messageThreadId = default, + bool? disableNotification = default, + bool? protectContent = default, + bool? removeCaption = default, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync( + new CopyMessagesRequest + { + ChatId = chatId, + FromChatId = fromChatId, + MessageIds = messageIds, MessageThreadId = messageThreadId, + DisableNotification = disableNotification, + ProtectContent = protectContent, + RemoveCaption = removeCaption, }, cancellationToken ) @@ -511,10 +645,7 @@ await botClient.ThrowIfNull() /// Sends the message silently. Users will receive a notification with no sound /// /// Protects the contents of sent messages from forwarding and saving - /// If the message is a reply, ID of the original message - /// - /// Pass , if the message should be sent even if the specified replied-to message is not found - /// + /// Description of the message to reply to /// /// Additional interface options. An inline keyboard, /// custom reply keyboard, instructions to @@ -525,6 +656,7 @@ await botClient.ThrowIfNull() /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// /// On success, the sent is returned. + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task SendPhotoAsync( this ITelegramBotClient botClient, ChatId chatId, @@ -536,25 +668,25 @@ await botClient.ThrowIfNull() bool? hasSpoiler = default, bool? disableNotification = default, bool? protectContent = default, - int? replyToMessageId = default, - bool? allowSendingWithoutReply = default, + ReplyParameters? replyParameters = default, IReplyMarkup? replyMarkup = default, CancellationToken cancellationToken = default ) => await botClient.ThrowIfNull(). MakeRequestAsync( - request: new SendPhotoRequest(chatId, photo) + new SendPhotoRequest { + ChatId = chatId, + Photo = photo, + MessageThreadId = messageThreadId, Caption = caption, ParseMode = parseMode, CaptionEntities = captionEntities, HasSpoiler = hasSpoiler, DisableNotification = disableNotification, ProtectContent = protectContent, - ReplyToMessageId = replyToMessageId, - AllowSendingWithoutReply = allowSendingWithoutReply, + ReplyParameters = replyParameters, ReplyMarkup = replyMarkup, - MessageThreadId = messageThreadId, }, cancellationToken ) @@ -602,10 +734,7 @@ await botClient.ThrowIfNull() /// Sends the message silently. Users will receive a notification with no sound /// /// Protects the contents of sent messages from forwarding and saving - /// If the message is a reply, ID of the original message - /// - /// Pass , if the message should be sent even if the specified replied-to message is not found - /// + /// Description of the message to reply to /// /// Additional interface options. An inline keyboard, /// custom reply keyboard, instructions to @@ -616,6 +745,7 @@ await botClient.ThrowIfNull() /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// /// On success, the sent is returned. + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task SendAudioAsync( this ITelegramBotClient botClient, ChatId chatId, @@ -630,15 +760,17 @@ await botClient.ThrowIfNull() InputFile? thumbnail = default, bool? disableNotification = default, bool? protectContent = default, - int? replyToMessageId = default, - bool? allowSendingWithoutReply = default, + ReplyParameters? replyParameters = default, IReplyMarkup? replyMarkup = default, CancellationToken cancellationToken = default ) => await botClient.ThrowIfNull() .MakeRequestAsync( - request: new SendAudioRequest(chatId, audio) + new SendAudioRequest { + ChatId = chatId, + Audio = audio, + MessageThreadId = messageThreadId, Caption = caption, ParseMode = parseMode, CaptionEntities = captionEntities, @@ -648,10 +780,8 @@ await botClient.ThrowIfNull() Thumbnail = thumbnail, DisableNotification = disableNotification, ProtectContent = protectContent, - ReplyToMessageId = replyToMessageId, - AllowSendingWithoutReply = allowSendingWithoutReply, + ReplyParameters = replyParameters, ReplyMarkup = replyMarkup, - MessageThreadId = messageThreadId, }, cancellationToken ) @@ -701,10 +831,7 @@ await botClient.ThrowIfNull() /// Sends the message silently. Users will receive a notification with no sound /// /// Protects the contents of sent messages from forwarding and saving - /// If the message is a reply, ID of the original message - /// - /// Pass , if the message should be sent even if the specified replied-to message is not found - /// + /// Description of the message to reply to /// /// Additional interface options. An inline keyboard, /// custom reply keyboard, instructions to @@ -715,6 +842,7 @@ await botClient.ThrowIfNull() /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// /// On success, the sent is returned. + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task SendDocumentAsync( this ITelegramBotClient botClient, ChatId chatId, @@ -727,15 +855,17 @@ await botClient.ThrowIfNull() bool? disableContentTypeDetection = default, bool? disableNotification = default, bool? protectContent = default, - int? replyToMessageId = default, - bool? allowSendingWithoutReply = default, + ReplyParameters? replyParameters = default, IReplyMarkup? replyMarkup = default, CancellationToken cancellationToken = default ) => await botClient.ThrowIfNull() .MakeRequestAsync( - request: new SendDocumentRequest(chatId, document) + new SendDocumentRequest { + ChatId = chatId, + Document = document, + MessageThreadId = messageThreadId, Thumbnail = thumbnail, Caption = caption, ParseMode = parseMode, @@ -743,10 +873,8 @@ await botClient.ThrowIfNull() DisableContentTypeDetection = disableContentTypeDetection, DisableNotification = disableNotification, ProtectContent = protectContent, - ReplyToMessageId = replyToMessageId, - AllowSendingWithoutReply = allowSendingWithoutReply, + ReplyParameters = replyParameters, ReplyMarkup = replyMarkup, - MessageThreadId = messageThreadId, }, cancellationToken ) @@ -800,10 +928,7 @@ await botClient.ThrowIfNull() /// Sends the message silently. Users will receive a notification with no sound /// /// Protects the contents of sent messages from forwarding and saving - /// If the message is a reply, ID of the original message - /// - /// Pass , if the message should be sent even if the specified replied-to message is not found - /// + /// Description of the message to reply to /// /// Additional interface options. An inline keyboard, /// custom reply keyboard, instructions to @@ -814,6 +939,7 @@ await botClient.ThrowIfNull() /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// /// On success, the sent is returned. + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task SendVideoAsync( this ITelegramBotClient botClient, ChatId chatId, @@ -830,15 +956,17 @@ await botClient.ThrowIfNull() bool? supportsStreaming = default, bool? disableNotification = default, bool? protectContent = default, - int? replyToMessageId = default, - bool? allowSendingWithoutReply = default, + ReplyParameters? replyParameters = default, IReplyMarkup? replyMarkup = default, CancellationToken cancellationToken = default ) => await botClient.ThrowIfNull() .MakeRequestAsync( - request: new SendVideoRequest(chatId, video) + new SendVideoRequest { + ChatId = chatId, + Video = video, + MessageThreadId = messageThreadId, Duration = duration, Width = width, Height = height, @@ -850,10 +978,8 @@ await botClient.ThrowIfNull() SupportsStreaming = supportsStreaming, DisableNotification = disableNotification, ProtectContent = protectContent, - ReplyToMessageId = replyToMessageId, - AllowSendingWithoutReply = allowSendingWithoutReply, + ReplyParameters = replyParameters, ReplyMarkup = replyMarkup, - MessageThreadId = messageThreadId, }, cancellationToken ) @@ -900,16 +1026,13 @@ await botClient.ThrowIfNull() /// of /// /// - /// Pass if the animatopn needs to be covered with a spoiler animation + /// Pass if the animation needs to be covered with a spoiler animation /// /// /// Sends the message silently. Users will receive a notification with no sound /// /// Protects the contents of sent messages from forwarding and saving - /// If the message is a reply, ID of the original message - /// - /// Pass , if the message should be sent even if the specified replied-to message is not found - /// + /// Description of the message to reply to /// /// Additional interface options. An inline keyboard, /// custom reply keyboard, instructions to @@ -920,6 +1043,7 @@ await botClient.ThrowIfNull() /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// /// On success, the sent is returned. + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task SendAnimationAsync( this ITelegramBotClient botClient, ChatId chatId, @@ -935,15 +1059,17 @@ await botClient.ThrowIfNull() bool? hasSpoiler = default, bool? disableNotification = default, bool? protectContent = default, - int? replyToMessageId = default, - bool? allowSendingWithoutReply = default, + ReplyParameters? replyParameters = default, IReplyMarkup? replyMarkup = default, CancellationToken cancellationToken = default ) => await botClient.ThrowIfNull() .MakeRequestAsync( - request: new SendAnimationRequest(chatId, animation) + new SendAnimationRequest { + ChatId = chatId, + Animation = animation, + MessageThreadId = messageThreadId, Duration = duration, Width = width, Height = height, @@ -954,10 +1080,8 @@ await botClient.ThrowIfNull() HasSpoiler = hasSpoiler, DisableNotification = disableNotification, ProtectContent = protectContent, - ReplyToMessageId = replyToMessageId, - AllowSendingWithoutReply = allowSendingWithoutReply, + ReplyParameters = replyParameters, ReplyMarkup = replyMarkup, - MessageThreadId = messageThreadId, }, cancellationToken ) @@ -974,10 +1098,10 @@ await botClient.ThrowIfNull() /// Unique identifier for the target chat or username of the target channel /// (in the format @channelusername) /// - /// /// /// Unique identifier for the target message thread (topic) of the forum; for forum supergroups only /// + /// /// Audio file to send. Pass a as String to send a file that exists /// on the Telegram servers (recommended), pass an HTTP URL as a String for Telegram to get a file from /// the Internet, or upload a new one using multipart/form-data @@ -997,10 +1121,7 @@ await botClient.ThrowIfNull() /// Sends the message silently. Users will receive a notification with no sound /// /// Protects the contents of sent messages from forwarding and saving - /// If the message is a reply, ID of the original message - /// - /// Pass , if the message should be sent even if the specified replied-to message is not found - /// + /// Description of the message to reply to /// /// Additional interface options. An inline keyboard, /// custom reply keyboard, instructions to @@ -1011,6 +1132,7 @@ await botClient.ThrowIfNull() /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// /// On success, the sent is returned. + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task SendVoiceAsync( this ITelegramBotClient botClient, ChatId chatId, @@ -1022,25 +1144,25 @@ await botClient.ThrowIfNull() int? duration = default, bool? disableNotification = default, bool? protectContent = default, - int? replyToMessageId = default, - bool? allowSendingWithoutReply = default, + ReplyParameters? replyParameters = default, IReplyMarkup? replyMarkup = default, CancellationToken cancellationToken = default ) => await botClient.ThrowIfNull() .MakeRequestAsync( - request: new SendVoiceRequest(chatId, voice) + new SendVoiceRequest { + ChatId = chatId, + Voice = voice, + MessageThreadId = messageThreadId, Caption = caption, ParseMode = parseMode, CaptionEntities = captionEntities, Duration = duration, DisableNotification = disableNotification, ProtectContent = protectContent, - ReplyToMessageId = replyToMessageId, - AllowSendingWithoutReply = allowSendingWithoutReply, + ReplyParameters = replyParameters, ReplyMarkup = replyMarkup, - MessageThreadId = messageThreadId, }, cancellationToken ) @@ -1076,10 +1198,7 @@ await botClient.ThrowIfNull() /// Sends the message silently. Users will receive a notification with no sound /// /// Protects the contents of sent messages from forwarding and saving - /// If the message is a reply, ID of the original message - /// - /// Pass , if the message should be sent even if the specified replied-to message is not found - /// + /// Description of the message to reply to /// /// Additional interface options. An inline keyboard, /// custom reply keyboard, instructions to @@ -1090,6 +1209,7 @@ await botClient.ThrowIfNull() /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// /// On success, the sent is returned. + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task SendVideoNoteAsync( this ITelegramBotClient botClient, ChatId chatId, @@ -1100,24 +1220,24 @@ await botClient.ThrowIfNull() InputFile? thumbnail = default, bool? disableNotification = default, bool? protectContent = default, - int? replyToMessageId = default, - bool? allowSendingWithoutReply = default, + ReplyParameters? replyParameters = default, IReplyMarkup? replyMarkup = default, CancellationToken cancellationToken = default ) => await botClient.ThrowIfNull() .MakeRequestAsync( - request: new SendVideoNoteRequest(chatId, videoNote) + new SendVideoNoteRequest { + ChatId = chatId, + VideoNote = videoNote, + MessageThreadId = messageThreadId, Duration = duration, Length = length, Thumbnail = thumbnail, DisableNotification = disableNotification, ProtectContent = protectContent, - ReplyToMessageId = replyToMessageId, - AllowSendingWithoutReply = allowSendingWithoutReply, + ReplyParameters = replyParameters, ReplyMarkup = replyMarkup, - MessageThreadId = messageThreadId, }, cancellationToken ) @@ -1140,14 +1260,12 @@ await botClient.ThrowIfNull() /// Sends the message silently. Users will receive a notification with no sound /// /// Protects the contents of sent messages from forwarding and saving - /// If the message is a reply, ID of the original message - /// - /// Pass , if the message should be sent even if the specified replied-to message is not found - /// + /// Description of the message to reply to /// /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// /// On success, an array of s that were sent is returned. + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task SendMediaGroupAsync( this ITelegramBotClient botClient, ChatId chatId, @@ -1155,19 +1273,19 @@ await botClient.ThrowIfNull() int? messageThreadId = default, bool? disableNotification = default, bool? protectContent = default, - int? replyToMessageId = default, - bool? allowSendingWithoutReply = default, + ReplyParameters? replyParameters = default, CancellationToken cancellationToken = default ) => await botClient.ThrowIfNull() .MakeRequestAsync( - request: new SendMediaGroupRequest(chatId, media) + new SendMediaGroupRequest { + ChatId = chatId, + Media = media, + MessageThreadId = messageThreadId, DisableNotification = disableNotification, ProtectContent = protectContent, - ReplyToMessageId = replyToMessageId, - AllowSendingWithoutReply = allowSendingWithoutReply, - MessageThreadId = messageThreadId, + ReplyParameters = replyParameters, }, cancellationToken ) @@ -1186,6 +1304,7 @@ await botClient.ThrowIfNull() /// /// Unique identifier for the target message thread (topic) of the forum; for forum supergroups only /// + /// The radius of uncertainty for the location, measured in meters; 0-1500 /// /// Period in seconds for which the location will be updated, should be between 60 and 86400 /// @@ -1201,10 +1320,7 @@ await botClient.ThrowIfNull() /// Sends the message silently. Users will receive a notification with no sound /// /// Protects the contents of sent messages from forwarding and saving - /// If the message is a reply, ID of the original message - /// - /// Pass , if the message should be sent even if the specified replied-to message is not found - /// + /// Description of the message to reply to /// /// Additional interface options. An inline keyboard, /// custom reply keyboard, instructions to @@ -1215,35 +1331,39 @@ await botClient.ThrowIfNull() /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// /// On success, the sent is returned. + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task SendLocationAsync( this ITelegramBotClient botClient, ChatId chatId, double latitude, double longitude, int? messageThreadId = default, + double? horizontalAccuracy = default, int? livePeriod = default, int? heading = default, int? proximityAlertRadius = default, bool? disableNotification = default, bool? protectContent = default, - int? replyToMessageId = default, - bool? allowSendingWithoutReply = default, + ReplyParameters? replyParameters = default, IReplyMarkup? replyMarkup = default, CancellationToken cancellationToken = default ) => await botClient.ThrowIfNull() .MakeRequestAsync( - request: new SendLocationRequest(chatId, latitude, longitude) + new SendLocationRequest { + ChatId = chatId, + Latitude = latitude, + Longitude = longitude, + MessageThreadId = messageThreadId, + HorizontalAccuracy = horizontalAccuracy, LivePeriod = livePeriod, Heading = heading, ProximityAlertRadius = proximityAlertRadius, DisableNotification = disableNotification, ProtectContent = protectContent, - ReplyToMessageId = replyToMessageId, - AllowSendingWithoutReply = allowSendingWithoutReply, + ReplyParameters = replyParameters, ReplyMarkup = replyMarkup, - MessageThreadId = messageThreadId, }, cancellationToken ) @@ -1282,6 +1402,7 @@ await botClient.ThrowIfNull() /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// /// On success the edited is returned. + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task EditMessageLiveLocationAsync( this ITelegramBotClient botClient, ChatId chatId, @@ -1296,12 +1417,16 @@ await botClient.ThrowIfNull() ) => await botClient.ThrowIfNull() .MakeRequestAsync( - request: new EditMessageLiveLocationRequest(chatId, messageId, latitude, longitude) + new EditMessageLiveLocationRequest { + ChatId = chatId, + MessageId = messageId, + Latitude = latitude, + Longitude = longitude, HorizontalAccuracy = horizontalAccuracy, Heading = heading, ProximityAlertRadius = proximityAlertRadius, - ReplyMarkup = replyMarkup + ReplyMarkup = replyMarkup, }, cancellationToken ) @@ -1335,6 +1460,7 @@ await botClient.ThrowIfNull() /// /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task EditMessageLiveLocationAsync( this ITelegramBotClient botClient, string inlineMessageId, @@ -1348,8 +1474,11 @@ await botClient.ThrowIfNull() ) => await botClient.ThrowIfNull() .MakeRequestAsync( - request: new EditInlineMessageLiveLocationRequest(inlineMessageId, latitude, longitude) + new EditInlineMessageLiveLocationRequest { + InlineMessageId = inlineMessageId, + Latitude = latitude, + Longitude = longitude, HorizontalAccuracy = horizontalAccuracy, Heading = heading, ProximityAlertRadius = proximityAlertRadius, @@ -1379,6 +1508,7 @@ await botClient.ThrowIfNull() /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// /// On success the sent is returned. + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task StopMessageLiveLocationAsync( this ITelegramBotClient botClient, ChatId chatId, @@ -1388,9 +1518,11 @@ await botClient.ThrowIfNull() ) => await botClient.ThrowIfNull() .MakeRequestAsync( - request: new StopMessageLiveLocationRequest(chatId, messageId) + new StopMessageLiveLocationRequest { - ReplyMarkup = replyMarkup + ChatId = chatId, + MessageId = messageId, + ReplyMarkup = replyMarkup, }, cancellationToken ) @@ -1411,6 +1543,7 @@ await botClient.ThrowIfNull() /// /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task StopMessageLiveLocationAsync( this ITelegramBotClient botClient, string inlineMessageId, @@ -1419,9 +1552,10 @@ await botClient.ThrowIfNull() ) => await botClient.ThrowIfNull() .MakeRequestAsync( - request: new StopInlineMessageLiveLocationRequest(inlineMessageId) + new StopInlineMessageLiveLocationRequest { - ReplyMarkup = replyMarkup + InlineMessageId = inlineMessageId, + ReplyMarkup = replyMarkup, }, cancellationToken ) @@ -1456,10 +1590,7 @@ await botClient.ThrowIfNull() /// Sends the message silently. Users will receive a notification with no sound /// /// Protects the contents of sent messages from forwarding and saving - /// If the message is a reply, ID of the original message - /// - /// Pass , if the message should be sent even if the specified replied-to message is not found - /// + /// Description of the message to reply to /// /// Additional interface options. An inline keyboard, /// custom reply keyboard, instructions to @@ -1471,6 +1602,7 @@ await botClient.ThrowIfNull() /// /// On success, the sent is returned. /// + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task SendVenueAsync( this ITelegramBotClient botClient, ChatId chatId, @@ -1485,23 +1617,26 @@ await botClient.ThrowIfNull() string? googlePlaceType = default, bool? disableNotification = default, bool? protectContent = default, - int? replyToMessageId = default, - bool? allowSendingWithoutReply = default, + ReplyParameters? replyParameters = default, IReplyMarkup? replyMarkup = default, CancellationToken cancellationToken = default ) => await botClient.ThrowIfNull() .MakeRequestAsync( - request: new SendVenueRequest(chatId, latitude, longitude, title, address) + new SendVenueRequest { + ChatId = chatId, + Latitude = latitude, + Longitude = longitude, + Title = title, + Address = address, FoursquareId = foursquareId, FoursquareType = foursquareType, GooglePlaceId = googlePlaceId, GooglePlaceType = googlePlaceType, DisableNotification = disableNotification, ProtectContent = protectContent, - ReplyToMessageId = replyToMessageId, - AllowSendingWithoutReply = allowSendingWithoutReply, + ReplyParameters = replyParameters, ReplyMarkup = replyMarkup, MessageThreadId = messageThreadId, }, @@ -1528,10 +1663,7 @@ await botClient.ThrowIfNull() /// Sends the message silently. Users will receive a notification with no sound /// /// Protects the contents of sent messages from forwarding and saving - /// If the message is a reply, ID of the original message - /// - /// Pass , if the message should be sent even if the specified replied-to message is not found - /// + /// Description of the message to reply to /// /// Additional interface options. An inline keyboard, /// custom reply keyboard, instructions to @@ -1542,6 +1674,7 @@ await botClient.ThrowIfNull() /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// /// On success, the sent is returned. + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task SendContactAsync( this ITelegramBotClient botClient, ChatId chatId, @@ -1552,21 +1685,22 @@ await botClient.ThrowIfNull() string? vCard = default, bool? disableNotification = default, bool? protectContent = default, - int? replyToMessageId = default, - bool? allowSendingWithoutReply = default, + ReplyParameters? replyParameters = default, IReplyMarkup? replyMarkup = default, CancellationToken cancellationToken = default ) => await botClient.ThrowIfNull() .MakeRequestAsync( - request: new SendContactRequest(chatId, phoneNumber, firstName) + new SendContactRequest { + ChatId = chatId, + PhoneNumber = phoneNumber, + FirstName = firstName, LastName = lastName, Vcard = vCard, DisableNotification = disableNotification, ProtectContent = protectContent, - ReplyToMessageId = replyToMessageId, - AllowSendingWithoutReply = allowSendingWithoutReply, + ReplyParameters = replyParameters, ReplyMarkup = replyMarkup, MessageThreadId = messageThreadId, }, @@ -1627,10 +1761,7 @@ await botClient.ThrowIfNull() /// Sends the message silently. Users will receive a notification with no sound /// /// Protects the contents of sent messages from forwarding and saving - /// If the message is a reply, ID of the original message - /// - /// Pass , if the message should be sent even if the specified replied-to message is not found - /// + /// Description of the message to reply to /// /// Additional interface options. An inline keyboard, /// custom reply keyboard, instructions to @@ -1641,6 +1772,7 @@ await botClient.ThrowIfNull() /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// /// On success, the sent is returned. + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task SendPollAsync( this ITelegramBotClient botClient, ChatId chatId, @@ -1659,15 +1791,18 @@ await botClient.ThrowIfNull() bool? isClosed = default, bool? disableNotification = default, bool? protectContent = default, - int? replyToMessageId = default, - bool? allowSendingWithoutReply = default, + ReplyParameters? replyParameters = default, IReplyMarkup? replyMarkup = default, CancellationToken cancellationToken = default ) => await botClient.ThrowIfNull() .MakeRequestAsync( - request: new SendPollRequest(chatId, question, options) + new SendPollRequest { + ChatId = chatId, + Question = question, + Options = options, + MessageThreadId = messageThreadId, IsAnonymous = isAnonymous, Type = type, AllowsMultipleAnswers = allowsMultipleAnswers, @@ -1680,10 +1815,8 @@ await botClient.ThrowIfNull() IsClosed = isClosed, DisableNotification = disableNotification, ProtectContent = protectContent, - ReplyToMessageId = replyToMessageId, - AllowSendingWithoutReply = allowSendingWithoutReply, + ReplyParameters = replyParameters, ReplyMarkup = replyMarkup, - MessageThreadId = messageThreadId, }, cancellationToken ) @@ -1706,16 +1839,13 @@ await botClient.ThrowIfNull() /// or . Dice can have values 1-6 for /// , and , values 1-5 for /// and , and values 1-64 for - /// . Defauts to + /// . Defaults to /// /// /// Sends the message silently. Users will receive a notification with no sound /// /// Protects the contents of sent messages from forwarding and saving - /// If the message is a reply, ID of the original message - /// - /// Pass , if the message should be sent even if the specified replied-to message is not found - /// + /// Description of the message to reply to /// /// Additional interface options. An inline keyboard, /// custom reply keyboard, instructions to @@ -1726,6 +1856,7 @@ await botClient.ThrowIfNull() /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// /// On success, the sent is returned. + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task SendDiceAsync( this ITelegramBotClient botClient, ChatId chatId, @@ -1733,22 +1864,21 @@ await botClient.ThrowIfNull() Emoji? emoji = default, bool? disableNotification = default, bool? protectContent = default, - int? replyToMessageId = default, - bool? allowSendingWithoutReply = default, + ReplyParameters? replyParameters = default, IReplyMarkup? replyMarkup = default, CancellationToken cancellationToken = default ) => await botClient.ThrowIfNull() .MakeRequestAsync( - request: new SendDiceRequest(chatId) + new SendDiceRequest { + ChatId = chatId, + MessageThreadId = messageThreadId, Emoji = emoji, DisableNotification = disableNotification, ProtectContent = protectContent, - ReplyToMessageId = replyToMessageId, - AllowSendingWithoutReply = allowSendingWithoutReply, + ReplyParameters = replyParameters, ReplyMarkup = replyMarkup, - MessageThreadId = messageThreadId, }, cancellationToken ) @@ -1762,7 +1892,8 @@ await botClient.ThrowIfNull() /// /// The ImageBot needs some time to process a request and upload the /// image. Instead of sending a text message along the lines of “Retrieving image, please wait…”, the bot may - /// use with = . + /// use with + /// = . /// The user will see a “sending photo” status for the bot. /// /// @@ -1778,19 +1909,24 @@ await botClient.ThrowIfNull() /// /// Type of action to broadcast. Choose one, depending on what the user is about to receive: /// for text messages, - /// for photos, + /// for + /// photos, /// or for - /// videos, or - /// for voice notes, - /// for general files, - /// for location data, + /// videos, + /// or for + /// voice notes, + /// for + /// general files, + /// for + /// location data, /// or for - /// video notes + /// video notes /// /// Unique identifier for the target message thread; supergroups only /// /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task SendChatActionAsync( this ITelegramBotClient botClient, ChatId chatId, @@ -1800,7 +1936,58 @@ await botClient.ThrowIfNull() ) => await botClient.ThrowIfNull() .MakeRequestAsync( - new SendChatActionRequest(chatId, chatAction) { MessageThreadId = messageThreadId }, + new SendChatActionRequest + { + ChatId = chatId, + Action = chatAction, + MessageThreadId = messageThreadId, + }, + cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to change the chosen reactions on a message. Service messages can't be reacted to. + /// Automatically forwarded messages from a channel to its discussion group have the same + /// available reactions as messages in the channel. + /// + /// An instance of + /// + /// Unique identifier for the target chat or username of the target channel + /// (in the format @channelusername) + /// + /// + /// Identifier of the target message. If the message belongs to a media group, the reaction + /// is set to the first non-deleted message in the group instead. + /// + /// + /// New list of reaction types to set on the message. Currently, as non-premium users, bots can + /// set up to one reaction per message. A custom emoji reaction can be used if it is either + /// already present on the message or explicitly allowed by chat administrators. + /// + /// + /// Pass to set the reaction with a big animation + /// + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + [Obsolete("Use the overload that accepts the corresponding request class")] + public static async Task SetMessageReactionAsync( + this ITelegramBotClient botClient, + ChatId chatId, + int messageId, + IEnumerable? reaction, + bool? isBig, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync( + new SetMessageReactionRequest + { + ChatId = chatId, + MessageId = messageId, + Reaction = reaction, + IsBig = isBig, + }, cancellationToken) .ConfigureAwait(false); @@ -1819,6 +2006,7 @@ await botClient.ThrowIfNull() /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// /// Returns a object + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task GetUserProfilePhotosAsync( this ITelegramBotClient botClient, long userId, @@ -1828,10 +2016,11 @@ await botClient.ThrowIfNull() ) => await botClient.ThrowIfNull() .MakeRequestAsync( - request: new GetUserProfilePhotosRequest(userId) + new GetUserProfilePhotosRequest { + UserId = userId, Offset = offset, - Limit = limit + Limit = limit, }, cancellationToken ) @@ -1842,7 +2031,8 @@ await botClient.ThrowIfNull() /// download files of up to 20MB in size. The file can then be downloaded via the link /// https://api.telegram.org/file/bot<token>/<file_path>, where <file_path> /// is taken from the response. It is guaranteed that the link will be valid for at least 1 hour. - /// When the link expires, a new one can be requested by calling again. + /// When the link expires, a new one can be requested by calling + /// again. /// /// /// You can use or @@ -1854,6 +2044,7 @@ await botClient.ThrowIfNull() /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// /// On success, a object is returned. + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task GetFileAsync( this ITelegramBotClient botClient, string fileId, @@ -1861,38 +2052,11 @@ await botClient.ThrowIfNull() ) => await botClient.ThrowIfNull() .MakeRequestAsync( - request: new GetFileRequest(fileId), - cancellationToken: cancellationToken + new GetFileRequest { FileId = fileId }, + cancellationToken ) .ConfigureAwait(false); - /// - /// Use this method to get basic info about a file download it. For the moment, bots can download files - /// of up to 20MB in size. - /// - /// An instance of - /// File identifier to get info about - /// Destination stream to write file to - /// - /// A cancellation token that can be used by other objects or threads to receive notice of cancellation - /// - /// On success, a object is returned. - public static async Task GetInfoAndDownloadFileAsync( - this ITelegramBotClient botClient, - string fileId, - Stream destination, - CancellationToken cancellationToken = default) - { - var file = await botClient.ThrowIfNull() - .MakeRequestAsync(request: new GetFileRequest(fileId), cancellationToken) - .ConfigureAwait(false); - - await botClient.DownloadFileAsync(filePath: file.FilePath!, destination, cancellationToken) - .ConfigureAwait(false); - - return file; - } - /// /// Use this method to ban a user in a group, a supergroup or a channel. In the case of supergroups and /// channels, the user will not be able to return to the chat on their own using invite links, etc., unless @@ -1918,6 +2082,7 @@ await botClient.DownloadFileAsync(filePath: file.FilePath!, destination, cancell /// /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task BanChatMemberAsync( this ITelegramBotClient botClient, ChatId chatId, @@ -1928,10 +2093,12 @@ await botClient.DownloadFileAsync(filePath: file.FilePath!, destination, cancell ) => await botClient.ThrowIfNull() .MakeRequestAsync( - request: new BanChatMemberRequest(chatId, userId) + new BanChatMemberRequest { + ChatId = chatId, + UserId = userId, UntilDate = untilDate, - RevokeMessages = revokeMessages + RevokeMessages = revokeMessages, }, cancellationToken ) @@ -1954,6 +2121,7 @@ await botClient.ThrowIfNull() /// /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task UnbanChatMemberAsync( this ITelegramBotClient botClient, ChatId chatId, @@ -1963,9 +2131,11 @@ await botClient.ThrowIfNull() ) => await botClient.ThrowIfNull() .MakeRequestAsync( - request: new UnbanChatMemberRequest(chatId, userId) + new UnbanChatMemberRequest { - OnlyIfBanned = onlyIfBanned + ChatId = chatId, + UserId = userId, + OnlyIfBanned = onlyIfBanned, }, cancellationToken ) @@ -1993,10 +2163,11 @@ await botClient.ThrowIfNull() /// permissions; the permission will imply the /// permission. /// - /// Date when restrictions will be lifted for the user, unix time. If user is restricted for more than 366 days or less than 30 seconds from the current time, they are considered to be restricted forever. + /// Date when restrictions will be lifted for this user; Unix time. If 0, then the user is restricted forever /// /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task RestrictChatMemberAsync( this ITelegramBotClient botClient, ChatId chatId, @@ -2008,8 +2179,11 @@ await botClient.ThrowIfNull() ) => await botClient.ThrowIfNull() .MakeRequestAsync( - request: new RestrictChatMemberRequest(chatId, userId, permissions) + new RestrictChatMemberRequest { + ChatId = chatId, + UserId = userId, + Permissions = permissions, UntilDate = untilDate, UseIndependentChatPermissions = useIndependentChatPermissions, }, @@ -2018,7 +2192,9 @@ await botClient.ThrowIfNull() .ConfigureAwait(false); /// - /// Use this method to promote or demote a user in a supergroup or a channel. The bot must be an administrator in the chat for this to work and must have the appropriate admin rights. Pass for all boolean parameters to demote a user. + /// Use this method to promote or demote a user in a supergroup or a channel. The bot must be an administrator in + /// the chat for this to work and must have the appropriate admin rights. Pass for + /// all boolean parameters to demote a user. /// /// An instance of /// @@ -2026,24 +2202,60 @@ await botClient.ThrowIfNull() /// (in the format @channelusername) /// /// Unique identifier of the target user - /// Pass , if the administrator's presence in the chat is hidden - /// Pass , if the administrator can access the chat event log, chat statistics, message statistics in channels, see channel members, see anonymous administrators in supergroups and ignore slow mode. Implied by any other administrator privilege - /// Pass , if the administrator can create channel posts, channels only - /// Pass , if the administrator can edit messages of other users, channels only - /// Pass , if the administrator can delete messages of other users - /// Pass if the administrator can post stories in the channel; channels only - /// Pass if the administrator can edit stories posted by other users; channels only - /// Pass if the administrator can delete stories posted by other users; channels only - /// Pass , if the administrator can manage voice chats, supergroups only - /// Pass , if the administrator can restrict, ban or unban chat members - /// Pass , if the administrator can add new administrators with a subset of his own privileges or demote administrators that he has promoted, directly or indirectly (promoted by administrators that were appointed by him) - /// Pass , if the administrator can change chat title, photo and other settings - /// Pass , if the administrator can invite new users to the chat - /// Pass , if the administrator can pin messages, supergroups only - /// Pass if the user is allowed to create, rename, close, and reopen forum topics, supergroups only + /// + /// Pass , if the administrator's presence in the chat is hidden + /// + /// + /// Pass , if the administrator can access the chat event log, chat statistics, message + /// statistics in channels, see channel members, see anonymous administrators in supergroups and ignore slow mode. + /// Implied by any other administrator privilege + /// + /// + /// Pass , if the administrator can create channel posts, channels only + /// + /// + /// Pass , if the administrator can edit messages of other users, channels only + /// + /// + /// Pass , if the administrator can delete messages of other users + /// + /// + /// Pass if the administrator can post stories in the channel; channels only + /// + /// + /// Pass if the administrator can edit stories posted by other users; channels only + /// + /// + /// Pass if the administrator can delete stories posted by other users; channels only + /// + /// + /// Pass , if the administrator can manage voice chats, supergroups only + /// + /// + /// Pass , if the administrator can restrict, ban or unban chat members + /// + /// + /// Pass , if the administrator can add new administrators with a subset of his own + /// privileges or demote administrators that he has promoted, directly or indirectly (promoted by administrators + /// that were appointed by him) + /// + /// + /// Pass , if the administrator can change chat title, photo and other settings + /// + /// + /// Pass , if the administrator can invite new users to the chat + /// + /// + /// Pass , if the administrator can pin messages, supergroups only + /// + /// + /// Pass if the user is allowed to create, rename, close, and reopen forum topics, + /// supergroups only + /// /// /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task PromoteChatMemberAsync( this ITelegramBotClient botClient, ChatId chatId, @@ -2067,8 +2279,10 @@ await botClient.ThrowIfNull() ) => await botClient.ThrowIfNull() .MakeRequestAsync( - request: new PromoteChatMemberRequest(chatId, userId) + new PromoteChatMemberRequest { + ChatId = chatId, + UserId = userId, IsAnonymous = isAnonymous, CanManageChat = canManageChat, CanPostMessages = canPostMessages, @@ -2104,6 +2318,7 @@ await botClient.ThrowIfNull() /// /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task SetChatAdministratorCustomTitleAsync( this ITelegramBotClient botClient, ChatId chatId, @@ -2113,7 +2328,12 @@ await botClient.ThrowIfNull() ) => await botClient.ThrowIfNull() .MakeRequestAsync( - request: new SetChatAdministratorCustomTitleRequest(chatId, userId, customTitle), + new SetChatAdministratorCustomTitleRequest + { + ChatId = chatId, + UserId = userId, + CustomTitle = customTitle, + }, cancellationToken ) .ConfigureAwait(false); @@ -2133,6 +2353,7 @@ await botClient.ThrowIfNull() /// /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task BanChatSenderChatAsync(this ITelegramBotClient botClient, ChatId chatId, long senderChatId, @@ -2140,7 +2361,11 @@ await botClient.ThrowIfNull() ) => await botClient.ThrowIfNull() .MakeRequestAsync( - new BanChatSenderChatRequest(chatId, senderChatId), + new BanChatSenderChatRequest + { + ChatId = chatId, + SenderChatId = senderChatId, + }, cancellationToken ) .ConfigureAwait(false); @@ -2159,6 +2384,7 @@ await botClient.ThrowIfNull() /// /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task UnbanChatSenderChatAsync(this ITelegramBotClient botClient, ChatId chatId, long senderChatId, @@ -2166,7 +2392,11 @@ await botClient.ThrowIfNull() ) => await botClient.ThrowIfNull() .MakeRequestAsync( - new UnbanChatSenderChatRequest(chatId, senderChatId), + new UnbanChatSenderChatRequest + { + ChatId = chatId, + SenderChatId = senderChatId, + }, cancellationToken ) .ConfigureAwait(false); @@ -2194,6 +2424,7 @@ await botClient.ThrowIfNull() /// /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task SetChatPermissionsAsync( this ITelegramBotClient botClient, ChatId chatId, @@ -2203,8 +2434,10 @@ await botClient.ThrowIfNull() ) => await botClient.ThrowIfNull() .MakeRequestAsync( - request: new SetChatPermissionsRequest(chatId, permissions) + new SetChatPermissionsRequest { + ChatId = chatId, + Permissions = permissions, UseIndependentChatPermissions = useIndependentChatPermissions, }, cancellationToken @@ -2224,6 +2457,7 @@ await botClient.ThrowIfNull() /// /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task ExportChatInviteLinkAsync( this ITelegramBotClient botClient, ChatId chatId, @@ -2231,7 +2465,10 @@ await botClient.ThrowIfNull() ) => await botClient.ThrowIfNull() .MakeRequestAsync( - request: new ExportChatInviteLinkRequest(chatId), + new ExportChatInviteLinkRequest + { + ChatId = chatId, + }, cancellationToken ) .ConfigureAwait(false); @@ -2239,7 +2476,8 @@ await botClient.ThrowIfNull() /// /// Use this method to create an additional invite link for a chat. The bot must be an administrator /// in the chat for this to work and must have the appropriate admin rights. The link can be revoked - /// using the method + /// using the method + /// /// /// An instance of /// @@ -2260,6 +2498,7 @@ await botClient.ThrowIfNull() /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// /// Returns the new invite link as object. + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task CreateChatInviteLinkAsync( this ITelegramBotClient botClient, ChatId chatId, @@ -2271,8 +2510,9 @@ await botClient.ThrowIfNull() ) => await botClient.ThrowIfNull() .MakeRequestAsync( - request: new CreateChatInviteLinkRequest(chatId) + new CreateChatInviteLinkRequest { + ChatId = chatId, Name = name, ExpireDate = expireDate, MemberLimit = memberLimit, @@ -2306,6 +2546,7 @@ await botClient.ThrowIfNull() /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// /// Returns the edited invite link as a object. + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task EditChatInviteLinkAsync( this ITelegramBotClient botClient, ChatId chatId, @@ -2318,8 +2559,10 @@ await botClient.ThrowIfNull() ) => await botClient.ThrowIfNull() .MakeRequestAsync( - request: new EditChatInviteLinkRequest(chatId, inviteLink) + new EditChatInviteLinkRequest { + ChatId = chatId, + InviteLink = inviteLink, Name = name, ExpireDate = expireDate, MemberLimit = memberLimit, @@ -2344,6 +2587,7 @@ await botClient.ThrowIfNull() /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// /// Returns the revoked invite link as object. + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task RevokeChatInviteLinkAsync( this ITelegramBotClient botClient, ChatId chatId, @@ -2352,7 +2596,11 @@ await botClient.ThrowIfNull() ) => await botClient.ThrowIfNull() .MakeRequestAsync( - request: new RevokeChatInviteLinkRequest(chatId, inviteLink), + new RevokeChatInviteLinkRequest + { + ChatId = chatId, + InviteLink = inviteLink, + }, cancellationToken ) .ConfigureAwait(false); @@ -2371,6 +2619,7 @@ await botClient.ThrowIfNull() /// /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task ApproveChatJoinRequest( this ITelegramBotClient botClient, ChatId chatId, @@ -2379,7 +2628,11 @@ await botClient.ThrowIfNull() ) => await botClient.ThrowIfNull() .MakeRequestAsync( - request: new ApproveChatJoinRequest(chatId, userId), + new ApproveChatJoinRequest + { + ChatId = chatId, + UserId = userId, + }, cancellationToken ) .ConfigureAwait(false); @@ -2398,6 +2651,7 @@ await botClient.ThrowIfNull() /// /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task DeclineChatJoinRequest( this ITelegramBotClient botClient, ChatId chatId, @@ -2406,7 +2660,11 @@ await botClient.ThrowIfNull() ) => await botClient.ThrowIfNull() .MakeRequestAsync( - request: new DeclineChatJoinRequest(chatId, userId), + new DeclineChatJoinRequest + { + ChatId = chatId, + UserId = userId, + }, cancellationToken ) .ConfigureAwait(false); @@ -2424,6 +2682,7 @@ await botClient.ThrowIfNull() /// /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task SetChatPhotoAsync( this ITelegramBotClient botClient, ChatId chatId, @@ -2432,7 +2691,11 @@ await botClient.ThrowIfNull() ) => await botClient.ThrowIfNull() .MakeRequestAsync( - request: new SetChatPhotoRequest(chatId, photo), + new SetChatPhotoRequest + { + ChatId = chatId, + Photo = photo, + }, cancellationToken) .ConfigureAwait(false); @@ -2447,6 +2710,7 @@ await botClient.ThrowIfNull() /// /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task DeleteChatPhotoAsync( this ITelegramBotClient botClient, ChatId chatId, @@ -2454,7 +2718,7 @@ await botClient.ThrowIfNull() ) => await botClient.ThrowIfNull() .MakeRequestAsync( - request: new DeleteChatPhotoRequest(chatId), + new DeleteChatPhotoRequest { ChatId = chatId }, cancellationToken ) .ConfigureAwait(false); @@ -2472,6 +2736,7 @@ await botClient.ThrowIfNull() /// /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task SetChatTitleAsync( this ITelegramBotClient botClient, ChatId chatId, @@ -2479,7 +2744,14 @@ await botClient.ThrowIfNull() CancellationToken cancellationToken = default ) => await botClient.ThrowIfNull() - .MakeRequestAsync(request: new SetChatTitleRequest(chatId, title), cancellationToken) + .MakeRequestAsync( + new SetChatTitleRequest + { + ChatId = chatId, + Title = title, + }, + cancellationToken + ) .ConfigureAwait(false); /// @@ -2495,6 +2767,7 @@ await botClient.ThrowIfNull() /// /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task SetChatDescriptionAsync( this ITelegramBotClient botClient, ChatId chatId, @@ -2503,7 +2776,7 @@ await botClient.ThrowIfNull() ) => await botClient.ThrowIfNull() .MakeRequestAsync( - request: new SetChatDescriptionRequest(chatId) { Description = description }, + new SetChatDescriptionRequest { ChatId = chatId, Description = description }, cancellationToken ) .ConfigureAwait(false); @@ -2511,7 +2784,7 @@ await botClient.ThrowIfNull() /// /// Use this method to add a message to the list of pinned messages in a chat. If the chat is not a private /// chat, the bot must be an administrator in the chat for this to work and must have the - /// '' admin right in a supergroup or + /// '' admin right in a supergroup or /// '' admin right in a channel /// /// An instance of @@ -2527,6 +2800,7 @@ await botClient.ThrowIfNull() /// /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task PinChatMessageAsync( this ITelegramBotClient botClient, ChatId chatId, @@ -2536,9 +2810,11 @@ await botClient.ThrowIfNull() ) => await botClient.ThrowIfNull(). MakeRequestAsync( - request: new PinChatMessageRequest(chatId, messageId) + new PinChatMessageRequest { - DisableNotification = disableNotification + ChatId = chatId, + MessageId = messageId, + DisableNotification = disableNotification, }, cancellationToken ) @@ -2562,6 +2838,7 @@ await botClient.ThrowIfNull() /// /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task UnpinChatMessageAsync( this ITelegramBotClient botClient, ChatId chatId, @@ -2570,7 +2847,7 @@ await botClient.ThrowIfNull() ) => await botClient.ThrowIfNull(). MakeRequestAsync( - request: new UnpinChatMessageRequest(chatId) { MessageId = messageId }, + new UnpinChatMessageRequest { ChatId = chatId, MessageId = messageId }, cancellationToken ) .ConfigureAwait(false); @@ -2589,13 +2866,14 @@ await botClient.ThrowIfNull() /// /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task UnpinAllChatMessages( this ITelegramBotClient botClient, ChatId chatId, CancellationToken cancellationToken = default ) => await botClient.ThrowIfNull(). - MakeRequestAsync(request: new UnpinAllChatMessagesRequest(chatId), cancellationToken) + MakeRequestAsync(new UnpinAllChatMessagesRequest { ChatId = chatId }, cancellationToken) .ConfigureAwait(false); /// @@ -2609,13 +2887,14 @@ await botClient.ThrowIfNull() /// /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task LeaveChatAsync( this ITelegramBotClient botClient, ChatId chatId, CancellationToken cancellationToken = default ) => await botClient.ThrowIfNull(). - MakeRequestAsync(request: new LeaveChatRequest(chatId), cancellationToken) + MakeRequestAsync(new LeaveChatRequest { ChatId = chatId }, cancellationToken) .ConfigureAwait(false); /// @@ -2631,13 +2910,14 @@ await botClient.ThrowIfNull() /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// /// Returns a object on success. + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task GetChatAsync( this ITelegramBotClient botClient, ChatId chatId, CancellationToken cancellationToken = default ) => await botClient.ThrowIfNull() - .MakeRequestAsync(request: new GetChatRequest(chatId), cancellationToken) + .MakeRequestAsync(new GetChatRequest { ChatId = chatId }, cancellationToken) .ConfigureAwait(false); /// @@ -2656,13 +2936,14 @@ await botClient.ThrowIfNull() /// administrators except other bots. If the chat is a group or a supergroup and no administrators were /// appointed, only the creator will be returned /// + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task GetChatAdministratorsAsync( this ITelegramBotClient botClient, ChatId chatId, CancellationToken cancellationToken = default ) => await botClient.ThrowIfNull() - .MakeRequestAsync(request: new GetChatAdministratorsRequest(chatId), cancellationToken) + .MakeRequestAsync(new GetChatAdministratorsRequest { ChatId = chatId }, cancellationToken) .ConfigureAwait(false); /// @@ -2676,14 +2957,15 @@ await botClient.ThrowIfNull() /// /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// - /// Returns on success.. + /// Returns on success. + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task GetChatMemberCountAsync( this ITelegramBotClient botClient, ChatId chatId, CancellationToken cancellationToken = default ) => await botClient.ThrowIfNull() - .MakeRequestAsync(request: new GetChatMemberCountRequest(chatId), cancellationToken) + .MakeRequestAsync(new GetChatMemberCountRequest { ChatId = chatId }, cancellationToken) .ConfigureAwait(false); /// @@ -2699,6 +2981,7 @@ await botClient.ThrowIfNull() /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// /// Returns a object on success. + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task GetChatMemberAsync( this ITelegramBotClient botClient, ChatId chatId, @@ -2706,14 +2989,18 @@ await botClient.ThrowIfNull() CancellationToken cancellationToken = default ) => await botClient.ThrowIfNull() - .MakeRequestAsync(request: new GetChatMemberRequest(chatId, userId), cancellationToken) + .MakeRequestAsync( + new GetChatMemberRequest { ChatId = chatId, UserId = userId }, + cancellationToken + ) .ConfigureAwait(false); /// /// Use this method to set a new group sticker set for a supergroup. The bot must be an administrator in the /// chat for this to work and must have the appropriate admin rights. Use the field - /// optionally returned in requests to check - /// if the bot can use this method. + /// optionally returned in + /// requests to check if the bot + /// can use this method. /// /// An instance of /// @@ -2724,6 +3011,7 @@ await botClient.ThrowIfNull() /// /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task SetChatStickerSetAsync( this ITelegramBotClient botClient, ChatId chatId, @@ -2731,14 +3019,18 @@ await botClient.ThrowIfNull() CancellationToken cancellationToken = default ) => await botClient.ThrowIfNull() - .MakeRequestAsync(request: new SetChatStickerSetRequest(chatId, stickerSetName), cancellationToken) + .MakeRequestAsync( + new SetChatStickerSetRequest { ChatId = chatId, StickerSetName = stickerSetName }, + cancellationToken + ) .ConfigureAwait(false); /// /// Use this method to delete a group sticker set from a supergroup. The bot must be an administrator in the /// chat for this to work and must have the appropriate admin rights. Use the field - /// optionally returned in requests to - /// check if the bot can use this method + /// optionally returned in + /// requests to check if the bot + /// can use this method /// /// An instance of /// @@ -2748,13 +3040,14 @@ await botClient.ThrowIfNull() /// /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task DeleteChatStickerSetAsync( this ITelegramBotClient botClient, ChatId chatId, CancellationToken cancellationToken = default ) => await botClient.ThrowIfNull() - .MakeRequestAsync(request: new DeleteChatStickerSetRequest(chatId), cancellationToken) + .MakeRequestAsync(new DeleteChatStickerSetRequest { ChatId = chatId }, cancellationToken) .ConfigureAwait(false); /// @@ -2765,6 +3058,7 @@ await botClient.ThrowIfNull() /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// /// Returns an Array of objects. + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task GetForumTopicIconStickersAsync( this ITelegramBotClient botClient, CancellationToken cancellationToken = default @@ -2789,7 +3083,8 @@ await botClient.ThrowIfNull() /// 13338331 (0xCB86DB), 9367192 (0x8EEE98), 16749490 (0xFF93B2), or 16478047 (0xFB6F5F) /// /// - /// Unique identifier of the custom emoji shown as the topic icon. Use + /// Unique identifier of the custom emoji shown as the topic icon. Use + /// /// to get all allowed custom emoji identifiers /// /// @@ -2798,6 +3093,7 @@ await botClient.ThrowIfNull() /// /// Returns information about the created topic as a object. /// + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task CreateForumTopicAsync( this ITelegramBotClient botClient, ChatId chatId, @@ -2808,8 +3104,10 @@ await botClient.ThrowIfNull() ) => await botClient.ThrowIfNull() .MakeRequestAsync( - new CreateForumTopicRequest(chatId, name) + new CreateForumTopicRequest { + ChatId = chatId, + Name = name, IconColor = iconColor, IconCustomEmojiId = iconCustomEmojiId, }, @@ -2839,6 +3137,7 @@ await botClient.ThrowIfNull() /// /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task EditForumTopicAsync( this ITelegramBotClient botClient, ChatId chatId, @@ -2849,8 +3148,10 @@ await botClient.ThrowIfNull() ) => await botClient.ThrowIfNull() .MakeRequestAsync( - new EditForumTopicRequest(chatId, messageThreadId) + new EditForumTopicRequest { + ChatId = chatId, + MessageThreadId = messageThreadId, Name = name, IconCustomEmojiId = iconCustomEmojiId, }, @@ -2872,6 +3173,7 @@ await botClient.ThrowIfNull() /// /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task CloseForumTopicAsync( this ITelegramBotClient botClient, ChatId chatId, @@ -2879,7 +3181,10 @@ await botClient.ThrowIfNull() CancellationToken cancellationToken = default ) => await botClient.ThrowIfNull() - .MakeRequestAsync(new CloseForumTopicRequest(chatId, messageThreadId), cancellationToken) + .MakeRequestAsync( + new CloseForumTopicRequest { ChatId = chatId, MessageThreadId = messageThreadId }, + cancellationToken + ) .ConfigureAwait(false); /// @@ -2896,6 +3201,7 @@ await botClient.ThrowIfNull() /// /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task ReopenForumTopicAsync( this ITelegramBotClient botClient, ChatId chatId, @@ -2903,7 +3209,10 @@ await botClient.ThrowIfNull() CancellationToken cancellationToken = default ) => await botClient.ThrowIfNull() - .MakeRequestAsync(new ReopenForumTopicRequest(chatId, messageThreadId), cancellationToken) + .MakeRequestAsync( + new ReopenForumTopicRequest { ChatId = chatId, MessageThreadId = messageThreadId }, + cancellationToken + ) .ConfigureAwait(false); /// @@ -2921,6 +3230,7 @@ await botClient.ThrowIfNull() /// /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task DeleteForumTopicAsync( this ITelegramBotClient botClient, ChatId chatId, @@ -2928,7 +3238,10 @@ await botClient.ThrowIfNull() CancellationToken cancellationToken = default ) => await botClient.ThrowIfNull() - .MakeRequestAsync(new DeleteForumTopicRequest(chatId, messageThreadId), cancellationToken) + .MakeRequestAsync( + new DeleteForumTopicRequest { ChatId = chatId, MessageThreadId = messageThreadId }, + cancellationToken + ) .ConfigureAwait(false); /// @@ -2945,6 +3258,7 @@ await botClient.ThrowIfNull() /// /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task UnpinAllForumTopicMessagesAsync( this ITelegramBotClient botClient, ChatId chatId, @@ -2952,7 +3266,10 @@ await botClient.ThrowIfNull() CancellationToken cancellationToken = default ) => await botClient.ThrowIfNull() - .MakeRequestAsync(new UnpinAllForumTopicMessagesRequest(chatId, messageThreadId), cancellationToken) + .MakeRequestAsync( + new UnpinAllForumTopicMessagesRequest { ChatId = chatId, MessageThreadId = messageThreadId }, + cancellationToken + ) .ConfigureAwait(false); /// @@ -2969,6 +3286,7 @@ await botClient.ThrowIfNull() /// /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task EditGeneralForumTopicAsync( this ITelegramBotClient botClient, ChatId chatId, @@ -2976,7 +3294,10 @@ await botClient.ThrowIfNull() CancellationToken cancellationToken = default ) => await botClient.ThrowIfNull() - .MakeRequestAsync(new EditGeneralForumTopicRequest(chatId, name), cancellationToken) + .MakeRequestAsync( + new EditGeneralForumTopicRequest { ChatId = chatId, Name = name }, + cancellationToken + ) .ConfigureAwait(false); /// @@ -2992,13 +3313,14 @@ await botClient.ThrowIfNull() /// /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task CloseGeneralForumTopicAsync( this ITelegramBotClient botClient, ChatId chatId, CancellationToken cancellationToken = default ) => await botClient.ThrowIfNull() - .MakeRequestAsync(new CloseGeneralForumTopicRequest(chatId), cancellationToken) + .MakeRequestAsync(new CloseGeneralForumTopicRequest { ChatId = chatId }, cancellationToken) .ConfigureAwait(false); /// @@ -3015,13 +3337,14 @@ await botClient.ThrowIfNull() /// /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task ReopenGeneralForumTopicAsync( this ITelegramBotClient botClient, ChatId chatId, CancellationToken cancellationToken = default ) => await botClient.ThrowIfNull() - .MakeRequestAsync(new ReopenGeneralForumTopicRequest(chatId), cancellationToken) + .MakeRequestAsync(new ReopenGeneralForumTopicRequest { ChatId = chatId }, cancellationToken) .ConfigureAwait(false); /// @@ -3037,13 +3360,14 @@ await botClient.ThrowIfNull() /// /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task HideGeneralForumTopicAsync( this ITelegramBotClient botClient, ChatId chatId, CancellationToken cancellationToken = default ) => await botClient.ThrowIfNull() - .MakeRequestAsync(new HideGeneralForumTopicRequest(chatId), cancellationToken) + .MakeRequestAsync(new HideGeneralForumTopicRequest { ChatId = chatId }, cancellationToken) .ConfigureAwait(false); /// @@ -3059,18 +3383,20 @@ await botClient.ThrowIfNull() /// /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task UnhideGeneralForumTopicAsync( this ITelegramBotClient botClient, ChatId chatId, CancellationToken cancellationToken = default ) => await botClient.ThrowIfNull() - .MakeRequestAsync(new UnhideGeneralForumTopicRequest(chatId), cancellationToken) + .MakeRequestAsync(new UnhideGeneralForumTopicRequest { ChatId = chatId }, cancellationToken) .ConfigureAwait(false); /// - /// Use this method to clear the list of pinned messages in a General forum topic. The bot must be an administrator in - /// the chat for this to work and must have the administrator right in the supergroup. + /// Use this method to clear the list of pinned messages in a General forum topic. The bot must be an administrator + /// in the chat for this to work and must have the + /// administrator right in the supergroup. /// /// An instance of /// @@ -3080,13 +3406,14 @@ await botClient.ThrowIfNull() /// /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task UnpinAllGeneralForumTopicMessagesAsync( this ITelegramBotClient botClient, ChatId chatId, CancellationToken cancellationToken = default ) => await botClient.ThrowIfNull() - .MakeRequestAsync(new UnpinAllGeneralForumTopicMessages(chatId), cancellationToken) + .MakeRequestAsync(new UnpinAllGeneralForumTopicMessagesRequest { ChatId = chatId }, cancellationToken) .ConfigureAwait(false); /// @@ -3124,6 +3451,7 @@ await botClient.ThrowIfNull() /// /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task AnswerCallbackQueryAsync( this ITelegramBotClient botClient, string callbackQueryId, @@ -3135,41 +3463,42 @@ await botClient.ThrowIfNull() ) => await botClient.ThrowIfNull() .MakeRequestAsync( - request: new AnswerCallbackQueryRequest(callbackQueryId) + new AnswerCallbackQueryRequest { + CallbackQueryId = callbackQueryId, Text = text, ShowAlert = showAlert, Url = url, - CacheTime = cacheTime + CacheTime = cacheTime, }, cancellationToken ) .ConfigureAwait(false); /// - /// Use this method to set the result of an interaction with a Web App and send a corresponding message on - /// behalf of the user to the chat from which the query originated. On success, a - /// object is returned. + /// Use this method to get the list of boosts added to a chat by a user. + /// Requires administrator rights in the chat. /// /// An instance of - /// Unique identifier for the query to be answered - /// - /// An object describing the message to be sent + /// + /// Unique identifier for the chat or username of the channel (in the format @channelusername) + /// + /// + /// Unique identifier of the target user /// /// /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// - public static async Task AnswerWebAppQueryAsync( + /// Returns a object. + [Obsolete("Use the overload that accepts the corresponding request class")] + public static async Task GetUserChatBoostsAsync( this ITelegramBotClient botClient, - string webAppQueryId, - InlineQueryResult result, + ChatId chatId, + long userId, CancellationToken cancellationToken = default ) => await botClient.ThrowIfNull() - .MakeRequestAsync( - request: new AnswerWebAppQueryRequest(webAppQueryId, result), - cancellationToken - ) + .MakeRequestAsync(new GetUserChatBoostsRequest { ChatId = chatId, UserId = userId }, cancellationToken) .ConfigureAwait(false); /// @@ -3191,6 +3520,7 @@ await botClient.ThrowIfNull() /// /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task SetMyCommandsAsync( this ITelegramBotClient botClient, IEnumerable commands, @@ -3200,10 +3530,11 @@ await botClient.ThrowIfNull() ) => await botClient.ThrowIfNull() .MakeRequestAsync( - request: new SetMyCommandsRequest(commands) + new SetMyCommandsRequest { + Commands = commands, Scope = scope, - LanguageCode = languageCode + LanguageCode = languageCode, }, cancellationToken ) @@ -3227,6 +3558,7 @@ await botClient.ThrowIfNull() /// /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task DeleteMyCommandsAsync( this ITelegramBotClient botClient, BotCommandScope? scope = default, @@ -3235,10 +3567,10 @@ await botClient.ThrowIfNull() ) => await botClient.ThrowIfNull() .MakeRequestAsync( - request: new DeleteMyCommandsRequest + new DeleteMyCommandsRequest { Scope = scope, - LanguageCode = languageCode + LanguageCode = languageCode, }, cancellationToken ) @@ -3261,6 +3593,7 @@ await botClient.ThrowIfNull() /// /// Returns Array of on success. If commands aren't set, an empty list is returned /// + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task GetMyCommandsAsync( this ITelegramBotClient botClient, BotCommandScope? scope = default, @@ -3269,10 +3602,10 @@ await botClient.ThrowIfNull() ) => await botClient.ThrowIfNull() .MakeRequestAsync( - request: new GetMyCommandsRequest + new GetMyCommandsRequest { Scope = scope, - LanguageCode = languageCode + LanguageCode = languageCode, }, cancellationToken ) @@ -3292,6 +3625,7 @@ await botClient.ThrowIfNull() /// /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task SetMyNameAsync( this ITelegramBotClient botClient, string? name = default, @@ -3300,7 +3634,7 @@ await botClient.ThrowIfNull() ) => await botClient.ThrowIfNull() .MakeRequestAsync( - request: new SetMyNameRequest { Name = name, LanguageCode = languageCode }, + new SetMyNameRequest { Name = name, LanguageCode = languageCode }, cancellationToken ) .ConfigureAwait(false); @@ -3318,6 +3652,7 @@ await botClient.ThrowIfNull() /// /// Returns on success. /// + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task GetMyNameAsync( this ITelegramBotClient botClient, string? languageCode = default, @@ -3325,7 +3660,7 @@ await botClient.ThrowIfNull() ) => await botClient.ThrowIfNull() .MakeRequestAsync( - request: new GetMyNameRequest { LanguageCode = languageCode }, + new GetMyNameRequest { LanguageCode = languageCode }, cancellationToken ) .ConfigureAwait(false); @@ -3346,6 +3681,7 @@ await botClient.ThrowIfNull() /// /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task SetMyDescriptionAsync( this ITelegramBotClient botClient, string? description = default, @@ -3354,7 +3690,7 @@ await botClient.ThrowIfNull() ) => await botClient.ThrowIfNull() .MakeRequestAsync( - request: new SetMyDescriptionRequest { Description = description, LanguageCode = languageCode }, + new SetMyDescriptionRequest { Description = description, LanguageCode = languageCode }, cancellationToken ) .ConfigureAwait(false); @@ -3373,6 +3709,7 @@ await botClient.ThrowIfNull() /// /// Returns on success. /// + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task GetMyDescriptionAsync( this ITelegramBotClient botClient, string? languageCode = default, @@ -3380,7 +3717,7 @@ await botClient.ThrowIfNull() ) => await botClient.ThrowIfNull() .MakeRequestAsync( - request: new GetMyDescriptionRequest { LanguageCode = languageCode }, + new GetMyDescriptionRequest { LanguageCode = languageCode }, cancellationToken ) .ConfigureAwait(false); @@ -3402,6 +3739,7 @@ await botClient.ThrowIfNull() /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// /// + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task SetMyShortDescriptionAsync( this ITelegramBotClient botClient, string? shortDescription = default, @@ -3410,7 +3748,7 @@ await botClient.ThrowIfNull() ) => await botClient.ThrowIfNull() .MakeRequestAsync( - request: new SetMyShortDescriptionRequest + new SetMyShortDescriptionRequest { ShortDescription = shortDescription, LanguageCode = languageCode, @@ -3433,6 +3771,7 @@ await botClient.ThrowIfNull() /// /// Returns on success. /// + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task GetMyShortDescriptionAsync( this ITelegramBotClient botClient, string? languageCode = default, @@ -3440,7 +3779,7 @@ await botClient.ThrowIfNull() ) => await botClient.ThrowIfNull() .MakeRequestAsync( - request: new GetMyShortDescriptionRequest { LanguageCode = languageCode }, + new GetMyShortDescriptionRequest { LanguageCode = languageCode }, cancellationToken ) .ConfigureAwait(false); @@ -3458,6 +3797,7 @@ await botClient.ThrowIfNull() /// /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task SetChatMenuButtonAsync( this ITelegramBotClient botClient, long? chatId = default, @@ -3466,7 +3806,7 @@ await botClient.ThrowIfNull() ) => await botClient.ThrowIfNull() .MakeRequestAsync( - request: new SetChatMenuButtonRequest { ChatId = chatId, MenuButton = menuButton }, + new SetChatMenuButtonRequest { ChatId = chatId, MenuButton = menuButton }, cancellationToken ) .ConfigureAwait(false); @@ -3483,6 +3823,7 @@ await botClient.ThrowIfNull() /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// /// set for the given chat id or a default one + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task GetChatMenuButtonAsync( this ITelegramBotClient botClient, long? chatId = default, @@ -3490,7 +3831,7 @@ await botClient.ThrowIfNull() ) => await botClient.ThrowIfNull() .MakeRequestAsync( - request: new GetChatMenuButtonRequest() { ChatId = chatId }, + new GetChatMenuButtonRequest { ChatId = chatId }, cancellationToken ) .ConfigureAwait(false); @@ -3512,6 +3853,7 @@ await botClient.ThrowIfNull() /// /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task SetMyDefaultAdministratorRightsAsync( this ITelegramBotClient botClient, ChatAdministratorRights? rights = default, @@ -3520,7 +3862,7 @@ await botClient.ThrowIfNull() ) => await botClient.ThrowIfNull() .MakeRequestAsync( - request: new SetMyDefaultAdministratorRightsRequest() + new SetMyDefaultAdministratorRightsRequest { Rights = rights, ForChannels = forChannels, @@ -3541,6 +3883,7 @@ await botClient.ThrowIfNull() /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// /// Default or channel + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task GetMyDefaultAdministratorRightsAsync( this ITelegramBotClient botClient, bool? forChannels = default, @@ -3548,7 +3891,7 @@ await botClient.ThrowIfNull() ) => await botClient.ThrowIfNull() .MakeRequestAsync( - request: new GetMyDefaultAdministratorRightsRequest { ForChannels = forChannels }, + new GetMyDefaultAdministratorRightsRequest { ForChannels = forChannels }, cancellationToken ) .ConfigureAwait(false); @@ -3576,7 +3919,7 @@ await botClient.ThrowIfNull() /// List of special entities that appear in message text, which can be specified instead /// of /// - /// Disables link previews for links in this message + /// Link preview generation options for the message /// /// Additional interface options. An inline keyboard, /// custom reply keyboard, instructions to @@ -3587,6 +3930,7 @@ await botClient.ThrowIfNull() /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// /// On success the edited is returned. + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task EditMessageTextAsync( this ITelegramBotClient botClient, ChatId chatId, @@ -3594,18 +3938,21 @@ await botClient.ThrowIfNull() string text, ParseMode? parseMode = default, IEnumerable? entities = default, - bool? disableWebPagePreview = default, + LinkPreviewOptions? linkPreviewOptions = default, InlineKeyboardMarkup? replyMarkup = default, CancellationToken cancellationToken = default ) => await botClient.ThrowIfNull() .MakeRequestAsync( - request: new EditMessageTextRequest(chatId, messageId, text) + new EditMessageTextRequest { + ChatId = chatId, + MessageId = messageId, + Text = text, ParseMode = parseMode, Entities = entities, - DisableWebPagePreview = disableWebPagePreview, - ReplyMarkup = replyMarkup + LinkPreviewOptions = linkPreviewOptions, + ReplyMarkup = replyMarkup, }, cancellationToken ) @@ -3626,7 +3973,7 @@ await botClient.ThrowIfNull() /// List of special entities that appear in message text, which can be specified instead /// of /// - /// Disables link previews for links in this message + /// Link preview generation options for the message /// /// Additional interface options. An inline keyboard, /// custom reply keyboard, instructions to @@ -3636,24 +3983,27 @@ await botClient.ThrowIfNull() /// /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task EditMessageTextAsync( this ITelegramBotClient botClient, string inlineMessageId, string text, ParseMode? parseMode = default, IEnumerable? entities = default, - bool? disableWebPagePreview = default, + LinkPreviewOptions? linkPreviewOptions = default, InlineKeyboardMarkup? replyMarkup = default, CancellationToken cancellationToken = default ) => await botClient.ThrowIfNull() .MakeRequestAsync( - request: new EditInlineMessageTextRequest(inlineMessageId, text) + new EditInlineMessageTextRequest { + InlineMessageId = inlineMessageId, + Text = text, ParseMode = parseMode, Entities = entities, - DisableWebPagePreview = disableWebPagePreview, - ReplyMarkup = replyMarkup + LinkPreviewOptions = linkPreviewOptions, + ReplyMarkup = replyMarkup, }, cancellationToken ) @@ -3667,7 +4017,7 @@ await botClient.ThrowIfNull() /// Unique identifier for the target chat or username of the target channel /// (in the format @channelusername) /// - /// dentifier of the message to edit + /// Identifier of the message to edit /// New caption of the message, 0-1024 characters after entities parsing /// /// Mode for parsing entities in the new caption. See @@ -3688,6 +4038,7 @@ await botClient.ThrowIfNull() /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// /// On success the edited is returned. + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task EditMessageCaptionAsync( this ITelegramBotClient botClient, ChatId chatId, @@ -3700,12 +4051,14 @@ await botClient.ThrowIfNull() ) => await botClient.ThrowIfNull() .MakeRequestAsync( - request: new EditMessageCaptionRequest(chatId, messageId) + new EditMessageCaptionRequest { + ChatId = chatId, + MessageId = messageId, Caption = caption, ParseMode = parseMode, CaptionEntities = captionEntities, - ReplyMarkup = replyMarkup + ReplyMarkup = replyMarkup, }, cancellationToken ) @@ -3735,6 +4088,7 @@ await botClient.ThrowIfNull() /// /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task EditMessageCaptionAsync( this ITelegramBotClient botClient, string inlineMessageId, @@ -3746,12 +4100,13 @@ await botClient.ThrowIfNull() ) => await botClient.ThrowIfNull() .MakeRequestAsync( - request: new EditInlineMessageCaptionRequest(inlineMessageId) + new EditInlineMessageCaptionRequest { + InlineMessageId = inlineMessageId, Caption = caption, ParseMode = parseMode, CaptionEntities = captionEntities, - ReplyMarkup = replyMarkup + ReplyMarkup = replyMarkup, }, cancellationToken ) @@ -3780,6 +4135,7 @@ await botClient.ThrowIfNull() /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// /// On success the edited is returned. + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task EditMessageMediaAsync( this ITelegramBotClient botClient, ChatId chatId, @@ -3790,9 +4146,12 @@ await botClient.ThrowIfNull() ) => await botClient.ThrowIfNull() .MakeRequestAsync( - request: new EditMessageMediaRequest(chatId, messageId, media) + new EditMessageMediaRequest { - ReplyMarkup = replyMarkup + ChatId = chatId, + MessageId = messageId, + Media = media, + ReplyMarkup = replyMarkup, }, cancellationToken ) @@ -3816,6 +4175,7 @@ await botClient.ThrowIfNull() /// /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task EditMessageMediaAsync( this ITelegramBotClient botClient, string inlineMessageId, @@ -3825,9 +4185,11 @@ await botClient.ThrowIfNull() ) => await botClient.ThrowIfNull() .MakeRequestAsync( - request: new EditInlineMessageMediaRequest(inlineMessageId, media) + new EditInlineMessageMediaRequest { - ReplyMarkup = replyMarkup + InlineMessageId = inlineMessageId, + Media = media, + ReplyMarkup = replyMarkup, }, cancellationToken ) @@ -3852,6 +4214,7 @@ await botClient.ThrowIfNull() /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// /// On success the edited is returned. + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task EditMessageReplyMarkupAsync( this ITelegramBotClient botClient, ChatId chatId, @@ -3861,9 +4224,11 @@ await botClient.ThrowIfNull() ) => await botClient.ThrowIfNull() .MakeRequestAsync( - request: new EditMessageReplyMarkupRequest(chatId, messageId) + new EditMessageReplyMarkupRequest { - ReplyMarkup = replyMarkup + ChatId = chatId, + MessageId = messageId, + ReplyMarkup = replyMarkup, }, cancellationToken ) @@ -3883,6 +4248,7 @@ await botClient.ThrowIfNull() /// /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task EditMessageReplyMarkupAsync( this ITelegramBotClient botClient, string inlineMessageId, @@ -3891,9 +4257,10 @@ await botClient.ThrowIfNull() ) => await botClient.ThrowIfNull() .MakeRequestAsync( - request: new EditInlineMessageReplyMarkupRequest(inlineMessageId) + new EditInlineMessageReplyMarkupRequest { - ReplyMarkup = replyMarkup + InlineMessageId = inlineMessageId, + ReplyMarkup = replyMarkup, }, cancellationToken ) @@ -3918,6 +4285,7 @@ await botClient.ThrowIfNull() /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// /// On success, the stopped with the final results is returned. + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task StopPollAsync( this ITelegramBotClient botClient, ChatId chatId, @@ -3927,9 +4295,11 @@ await botClient.ThrowIfNull() ) => await botClient.ThrowIfNull() .MakeRequestAsync( - request: new StopPollRequest(chatId, messageId) + new StopPollRequest { - ReplyMarkup = replyMarkup + ChatId = chatId, + MessageId = messageId, + ReplyMarkup = replyMarkup, }, cancellationToken ) @@ -3958,6 +4328,7 @@ await botClient.ThrowIfNull() /// /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task DeleteMessageAsync( this ITelegramBotClient botClient, ChatId chatId, @@ -3965,7 +4336,38 @@ await botClient.ThrowIfNull() CancellationToken cancellationToken = default ) => await botClient.ThrowIfNull() - .MakeRequestAsync(request: new DeleteMessageRequest(chatId, messageId), cancellationToken) + .MakeRequestAsync(new DeleteMessageRequest { ChatId = chatId, MessageId = messageId }, cancellationToken) + .ConfigureAwait(false); + + /// + /// Use this method to delete multiple messages simultaneously. + /// If some of the specified messages can't be found, they are skipped. + /// + /// An instance of + /// + /// Unique identifier for the target chat or username of the target channel + /// (in the format @channelusername) + /// + /// + /// Identifiers of 1-100 messages to delete. See + /// for limitations + /// on which messages can be deleted + /// + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + [Obsolete("Use the overload that accepts the corresponding request class")] + public static async Task DeleteMessagesAsync( + this ITelegramBotClient botClient, + ChatId chatId, + IEnumerable messageIds, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync( + new DeleteMessagesRequest { ChatId = chatId, MessageIds = messageIds }, + cancellationToken + ) .ConfigureAwait(false); #endregion Updating messages @@ -4002,13 +4404,7 @@ await botClient.ThrowIfNull() /// /// Protects the contents of sent messages from forwarding and saving /// - /// - /// If the message is a reply, ID of the original message - /// - /// - /// Pass , if the message should be sent even if the specified - /// replied-to message is not found - /// + /// Description of the message to reply to /// /// Additional interface options. An inline keyboard, /// custom reply keyboard, instructions to @@ -4021,6 +4417,7 @@ await botClient.ThrowIfNull() /// /// On success, the sent is returned. /// + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task SendStickerAsync( this ITelegramBotClient botClient, ChatId chatId, @@ -4029,24 +4426,24 @@ await botClient.ThrowIfNull() string? emoji = default, bool? disableNotification = default, bool? protectContent = default, - int? replyToMessageId = default, - bool? allowSendingWithoutReply = default, + ReplyParameters? replyParameters = default, IReplyMarkup? replyMarkup = default, CancellationToken cancellationToken = default ) => await botClient.ThrowIfNull() .MakeRequestAsync( - request: new SendStickerRequest(chatId, sticker) + new SendStickerRequest { + ChatId = chatId, + Sticker = sticker, + MessageThreadId = messageThreadId, + Emoji = emoji, DisableNotification = disableNotification, ProtectContent = protectContent, - ReplyToMessageId = replyToMessageId, - AllowSendingWithoutReply = allowSendingWithoutReply, + ReplyParameters = replyParameters, ReplyMarkup = replyMarkup, - MessageThreadId = messageThreadId, - Emoji = emoji, }, - cancellationToken: cancellationToken + cancellationToken ) .ConfigureAwait(false); @@ -4065,16 +4462,14 @@ await botClient.ThrowIfNull() /// /// On success, a object is returned. /// + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task GetStickerSetAsync( this ITelegramBotClient botClient, string name, CancellationToken cancellationToken = default ) => await botClient.ThrowIfNull() - .MakeRequestAsync( - request: new GetStickerSetRequest(name), - cancellationToken: cancellationToken - ) + .MakeRequestAsync(new GetStickerSetRequest { Name = name }, cancellationToken) .ConfigureAwait(false); /// @@ -4088,6 +4483,7 @@ await botClient.ThrowIfNull() /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// /// On success, a object is returned. + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task GetCustomEmojiStickersAsync( this ITelegramBotClient botClient, IEnumerable customEmojiIds, @@ -4095,8 +4491,8 @@ await botClient.ThrowIfNull() ) => await botClient.ThrowIfNull() .MakeRequestAsync( - request: new GetCustomEmojiStickersRequest(customEmojiIds), - cancellationToken: cancellationToken + new GetCustomEmojiStickersRequest { CustomEmojiIds = customEmojiIds }, + cancellationToken ) .ConfigureAwait(false); @@ -4123,6 +4519,7 @@ await botClient.ThrowIfNull() /// /// Returns the uploaded on success. /// + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task UploadStickerFileAsync( this ITelegramBotClient botClient, long userId, @@ -4132,8 +4529,13 @@ await botClient.ThrowIfNull() ) => await botClient.ThrowIfNull() .MakeRequestAsync( - request: new UploadStickerFileRequest(userId, sticker, stickerFormat), - cancellationToken: cancellationToken + new UploadStickerFileRequest + { + UserId = userId, + Sticker = sticker, + StickerFormat = stickerFormat, + }, + cancellationToken ) .ConfigureAwait(false); @@ -4148,7 +4550,7 @@ await botClient.ThrowIfNull() /// /// /// Short name of sticker set, to be used in t.me/addstickers/ URLs (e.g., animals). Can contain - /// only english letters, digits and underscores. Must begin with a letter, can't contain consecutive + /// only English letters, digits and underscores. Must begin with a letter, can't contain consecutive /// underscores and must end in "_by_<bot username>". <bot_username> is case /// insensitive. 1-64 characters /// @@ -4174,6 +4576,7 @@ await botClient.ThrowIfNull() /// /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task CreateNewStickerSetAsync( this ITelegramBotClient botClient, long userId, @@ -4187,12 +4590,17 @@ await botClient.ThrowIfNull() ) => await botClient.ThrowIfNull() .MakeRequestAsync( - request: new CreateNewStickerSetRequest(userId, name, title, stickers, stickerFormat) + new CreateNewStickerSetRequest { + UserId = userId, + Name = name, + Title = title, + Stickers = stickers, + StickerFormat = stickerFormat, NeedsRepainting = needsRepainting, StickerType = stickerType, }, - cancellationToken: cancellationToken + cancellationToken ) .ConfigureAwait(false); @@ -4227,6 +4635,7 @@ await botClient.ThrowIfNull() /// /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task AddStickerToSetAsync( this ITelegramBotClient botClient, long userId, @@ -4236,8 +4645,8 @@ await botClient.ThrowIfNull() ) => await botClient.ThrowIfNull() .MakeRequestAsync( - request: new AddStickerToSetRequest(userId, name, sticker), - cancellationToken: cancellationToken + new AddStickerToSetRequest { UserId = userId, Name = name, Sticker = sticker, }, + cancellationToken ) .ConfigureAwait(false); @@ -4252,6 +4661,7 @@ await botClient.ThrowIfNull() /// /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task SetStickerPositionInSetAsync( this ITelegramBotClient botClient, InputFileId sticker, @@ -4260,8 +4670,8 @@ await botClient.ThrowIfNull() ) => await botClient.ThrowIfNull() .MakeRequestAsync( - request: new SetStickerPositionInSetRequest(sticker, position), - cancellationToken: cancellationToken + new SetStickerPositionInSetRequest { Sticker = sticker, Position = position, }, + cancellationToken ) .ConfigureAwait(false); @@ -4275,6 +4685,7 @@ await botClient.ThrowIfNull() /// /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task DeleteStickerFromSetAsync( this ITelegramBotClient botClient, InputFileId sticker, @@ -4282,8 +4693,8 @@ await botClient.ThrowIfNull() ) => await botClient.ThrowIfNull() .MakeRequestAsync( - request: new DeleteStickerFromSetRequest(sticker), - cancellationToken: cancellationToken + new DeleteStickerFromSetRequest { Sticker = sticker }, + cancellationToken ) .ConfigureAwait(false); @@ -4303,6 +4714,7 @@ await botClient.ThrowIfNull() /// /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task SetStickerEmojiListAsync( this ITelegramBotClient botClient, InputFileId sticker, @@ -4311,8 +4723,8 @@ await botClient.ThrowIfNull() ) => await botClient.ThrowIfNull() .MakeRequestAsync( - request: new SetStickerEmojiListRequest(sticker, emojiList), - cancellationToken: cancellationToken + new SetStickerEmojiListRequest { Sticker = sticker, EmojiList = emojiList }, + cancellationToken ) .ConfigureAwait(false); @@ -4333,6 +4745,7 @@ await botClient.ThrowIfNull() /// /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task SetStickerKeywordsAsync( this ITelegramBotClient botClient, InputFileId sticker, @@ -4341,11 +4754,8 @@ await botClient.ThrowIfNull() ) => await botClient.ThrowIfNull() .MakeRequestAsync( - request: new SetStickerKeywordsRequest(sticker) - { - Keywords = keywords, - }, - cancellationToken: cancellationToken + new SetStickerKeywordsRequest { Sticker = sticker, Keywords = keywords, }, + cancellationToken ) .ConfigureAwait(false); @@ -4366,6 +4776,7 @@ await botClient.ThrowIfNull() /// /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task SetStickerMaskPositionAsync( this ITelegramBotClient botClient, InputFileId sticker, @@ -4374,8 +4785,8 @@ await botClient.ThrowIfNull() ) => await botClient.ThrowIfNull() .MakeRequestAsync( - request: new SetStickerMaskPositionRequest(sticker) { MaskPosition = maskPosition }, - cancellationToken: cancellationToken + new SetStickerMaskPositionRequest { Sticker = sticker, MaskPosition = maskPosition }, + cancellationToken ) .ConfigureAwait(false); @@ -4394,6 +4805,7 @@ await botClient.ThrowIfNull() /// /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task SetStickerSetTitleAsync( this ITelegramBotClient botClient, string name, @@ -4402,8 +4814,8 @@ await botClient.ThrowIfNull() ) => await botClient.ThrowIfNull() .MakeRequestAsync( - request: new SetStickerSetTitleRequest(name, title), - cancellationToken: cancellationToken + new SetStickerSetTitleRequest { Name = name, Title = title }, + cancellationToken ) .ConfigureAwait(false); @@ -4435,6 +4847,7 @@ await botClient.ThrowIfNull() /// /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task SetStickerSetThumbnailAsync( this ITelegramBotClient botClient, string name, @@ -4444,11 +4857,8 @@ await botClient.ThrowIfNull() ) => await botClient.ThrowIfNull() .MakeRequestAsync( - request: new SetStickerSetThumbnailRequest(name, userId) - { - Thumbnail = thumbnail, - }, - cancellationToken: cancellationToken + new SetStickerSetThumbnailRequest { Name = name, UserId = userId, Thumbnail = thumbnail }, + cancellationToken ) .ConfigureAwait(false); @@ -4468,6 +4878,7 @@ await botClient.ThrowIfNull() /// /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task SetCustomEmojiStickerSetThumbnailAsync( this ITelegramBotClient botClient, string name, @@ -4476,11 +4887,8 @@ await botClient.ThrowIfNull() ) => await botClient.ThrowIfNull() .MakeRequestAsync( - request: new SetCustomEmojiStickerSetThumbnailRequest(name) - { - CustomEmojiId = customEmojiId, - }, - cancellationToken: cancellationToken + new SetCustomEmojiStickerSetThumbnailRequest { Name = name, CustomEmojiId = customEmojiId }, + cancellationToken ) .ConfigureAwait(false); @@ -4496,16 +4904,14 @@ await botClient.ThrowIfNull() /// /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task DeleteStickerSetAsync( this ITelegramBotClient botClient, string name, CancellationToken cancellationToken = default ) => await botClient.ThrowIfNull() - .MakeRequestAsync( - request: new DeleteStickerSetRequest(name), - cancellationToken: cancellationToken - ) + .MakeRequestAsync(new DeleteStickerSetRequest { Name = name }, cancellationToken) .ConfigureAwait(false); #endregion @@ -4539,6 +4945,7 @@ await botClient.ThrowIfNull() /// /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task AnswerInlineQueryAsync( this ITelegramBotClient botClient, string inlineQueryId, @@ -4551,8 +4958,10 @@ await botClient.ThrowIfNull() ) => await botClient.ThrowIfNull() .MakeRequestAsync( - request: new AnswerInlineQueryRequest(inlineQueryId, results) + new AnswerInlineQueryRequest { + InlineQueryId = inlineQueryId, + Results = results, CacheTime = cacheTime, IsPersonal = isPersonal, NextOffset = nextOffset, @@ -4562,6 +4971,33 @@ await botClient.ThrowIfNull() ) .ConfigureAwait(false); + /// + /// Use this method to set the result of an interaction with a Web App and send a corresponding message on + /// behalf of the user to the chat from which the query originated. On success, a + /// object is returned. + /// + /// An instance of + /// Unique identifier for the query to be answered + /// + /// An object describing the message to be sent + /// + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation + /// + [Obsolete("Use the overload that accepts the corresponding request class")] + public static async Task AnswerWebAppQueryAsync( + this ITelegramBotClient botClient, + string webAppQueryId, + InlineQueryResult result, + CancellationToken cancellationToken = default + ) => + await botClient.ThrowIfNull() + .MakeRequestAsync( + new AnswerWebAppQueryRequest { WebAppQueryId = webAppQueryId, Result = result }, + cancellationToken + ) + .ConfigureAwait(false); + #endregion Inline mode #region Payments @@ -4643,10 +5079,7 @@ await botClient.ThrowIfNull() /// Sends the message silently. Users will receive a notification with no sound /// /// Protects the contents of sent messages from forwarding and saving - /// If the message is a reply, ID of the original message - /// - /// Pass , if the message should be sent even if the specified replied-to message is not found - /// + /// Description of the message to reply to /// /// Additional interface options. An inline keyboard, /// custom reply keyboard, instructions to @@ -4657,6 +5090,7 @@ await botClient.ThrowIfNull() /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// /// On success, the sent is returned. + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task SendInvoiceAsync( this ITelegramBotClient botClient, long chatId, @@ -4684,23 +5118,22 @@ await botClient.ThrowIfNull() bool? isFlexible = default, bool? disableNotification = default, bool? protectContent = default, - int? replyToMessageId = default, - bool? allowSendingWithoutReply = default, + ReplyParameters? replyParameters = default, InlineKeyboardMarkup? replyMarkup = default, CancellationToken cancellationToken = default ) => await botClient.ThrowIfNull() .MakeRequestAsync( - request: new SendInvoiceRequest( - chatId, - title, - description, - payload, - providerToken, - currency, - // ReSharper disable once PossibleMultipleEnumeration - prices) + new SendInvoiceRequest { + ChatId = chatId, + Title = title, + Description = description, + Payload = payload, + ProviderToken = providerToken, + Currency = currency, + Prices = prices, + MessageThreadId = messageThreadId, MaxTipAmount = maxTipAmount, SuggestedTipAmounts = suggestedTipAmounts, StartParameter = startParameter, @@ -4718,10 +5151,8 @@ await botClient.ThrowIfNull() IsFlexible = isFlexible, DisableNotification = disableNotification, ProtectContent = protectContent, - ReplyToMessageId = replyToMessageId, - AllowSendingWithoutReply = allowSendingWithoutReply, + ReplyParameters = replyParameters, ReplyMarkup = replyMarkup, - MessageThreadId = messageThreadId, }, cancellationToken ) @@ -4790,6 +5221,7 @@ await botClient.ThrowIfNull() /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// /// On success, the sent is returned. + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task CreateInvoiceLinkAsync( this ITelegramBotClient botClient, string title, @@ -4816,15 +5248,14 @@ await botClient.ThrowIfNull() ) => await botClient.ThrowIfNull() .MakeRequestAsync( - request: new CreateInvoiceLinkRequest( - title, - description, - payload, - providerToken, - currency, - // ReSharper disable once PossibleMultipleEnumeration - prices) + new CreateInvoiceLinkRequest { + Title = title, + Description = description, + Payload = payload, + ProviderToken = providerToken, + Currency = currency, + Prices = prices, MaxTipAmount = maxTipAmount, SuggestedTipAmounts = suggestedTipAmounts, ProviderData = providerData, @@ -4838,7 +5269,7 @@ await botClient.ThrowIfNull() NeedShippingAddress = needShippingAddress, SendPhoneNumberToProvider = sendPhoneNumberToProvider, SendEmailToProvider = sendEmailToProvider, - IsFlexible = isFlexible + IsFlexible = isFlexible, }, cancellationToken ) @@ -4857,6 +5288,7 @@ await botClient.ThrowIfNull() /// /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task AnswerShippingQueryAsync( this ITelegramBotClient botClient, string shippingQueryId, @@ -4865,7 +5297,7 @@ await botClient.ThrowIfNull() ) => await botClient.ThrowIfNull() .MakeRequestAsync( - request: new AnswerShippingQueryRequest(shippingQueryId, shippingOptions), + new AnswerShippingQueryRequest(shippingQueryId, shippingOptions), cancellationToken ) .ConfigureAwait(false); @@ -4885,6 +5317,7 @@ await botClient.ThrowIfNull() /// /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task AnswerShippingQueryAsync( this ITelegramBotClient botClient, string shippingQueryId, @@ -4893,7 +5326,7 @@ await botClient.ThrowIfNull() ) => await botClient.ThrowIfNull() .MakeRequestAsync( - request: new AnswerShippingQueryRequest(shippingQueryId, errorMessage), + new AnswerShippingQueryRequest(shippingQueryId, errorMessage), cancellationToken ) .ConfigureAwait(false); @@ -4911,13 +5344,14 @@ await botClient.ThrowIfNull() /// /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task AnswerPreCheckoutQueryAsync( this ITelegramBotClient botClient, string preCheckoutQueryId, CancellationToken cancellationToken = default ) => await botClient.ThrowIfNull() - .MakeRequestAsync(request: new AnswerPreCheckoutQueryRequest(preCheckoutQueryId), cancellationToken) + .MakeRequestAsync(new AnswerPreCheckoutQueryRequest(preCheckoutQueryId), cancellationToken) .ConfigureAwait(false); /// @@ -4936,6 +5370,7 @@ await botClient.ThrowIfNull() /// /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task AnswerPreCheckoutQueryAsync( this ITelegramBotClient botClient, string preCheckoutQueryId, @@ -4944,7 +5379,7 @@ await botClient.ThrowIfNull() ) => await botClient.ThrowIfNull() .MakeRequestAsync( - request: new AnswerPreCheckoutQueryRequest(preCheckoutQueryId, errorMessage), + new AnswerPreCheckoutQueryRequest(preCheckoutQueryId, errorMessage), cancellationToken ) .ConfigureAwait(false); @@ -4958,10 +5393,10 @@ await botClient.ThrowIfNull() /// /// An instance of /// Unique identifier for the target chat - /// /// /// Unique identifier for the target message thread (topic) of the forum; for forum supergroups only /// + /// /// Short name of the game, serves as the unique identifier for the game. Set up your games via /// @BotFather /// @@ -4969,10 +5404,7 @@ await botClient.ThrowIfNull() /// Sends the message silently. Users will receive a notification with no sound /// /// Protects the contents of sent messages from forwarding and saving - /// If the message is a reply, ID of the original message - /// - /// Pass , if the message should be sent even if the specified replied-to message is not found - /// + /// Description of the message to reply to /// /// Additional interface options. An inline keyboard, /// custom reply keyboard, instructions to @@ -4983,6 +5415,7 @@ await botClient.ThrowIfNull() /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// /// On success, the sent is returned. + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task SendGameAsync( this ITelegramBotClient botClient, long chatId, @@ -4990,21 +5423,21 @@ await botClient.ThrowIfNull() int? messageThreadId = default, bool? disableNotification = default, bool? protectContent = default, - int? replyToMessageId = default, - bool? allowSendingWithoutReply = default, + ReplyParameters? replyParameters = default, InlineKeyboardMarkup? replyMarkup = default, CancellationToken cancellationToken = default ) => await botClient.ThrowIfNull() .MakeRequestAsync( - request: new SendGameRequest(chatId, gameShortName) + new SendGameRequest { + ChatId = chatId, + GameShortName = gameShortName, + MessageThreadId = messageThreadId, DisableNotification = disableNotification, ProtectContent = protectContent, - ReplyToMessageId = replyToMessageId, - AllowSendingWithoutReply = allowSendingWithoutReply, + ReplyParameters = replyParameters, ReplyMarkup = replyMarkup, - MessageThreadId = messageThreadId, }, cancellationToken ) @@ -5032,6 +5465,7 @@ await botClient.ThrowIfNull() /// On success returns the edited . Returns an error, if the new score is not greater /// than the user's current score in the chat and is /// + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task SetGameScoreAsync( this ITelegramBotClient botClient, long userId, @@ -5044,10 +5478,14 @@ await botClient.ThrowIfNull() ) => await botClient.ThrowIfNull() .MakeRequestAsync( - request: new SetGameScoreRequest(userId, score, chatId, messageId) + new SetGameScoreRequest { + UserId = userId, + Score = score, + ChatId = chatId, + MessageId = messageId, Force = force, - DisableEditMessage = disableEditMessage + DisableEditMessage = disableEditMessage, }, cancellationToken ) @@ -5074,6 +5512,7 @@ await botClient.ThrowIfNull() /// Returns an error, if the new score is not greater than the user's current score in the chat and /// is /// + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task SetGameScoreAsync( this ITelegramBotClient botClient, long userId, @@ -5085,10 +5524,13 @@ await botClient.ThrowIfNull() ) => await botClient.ThrowIfNull() .MakeRequestAsync( - request: new SetInlineGameScoreRequest(userId, score, inlineMessageId) + new SetInlineGameScoreRequest { + UserId = userId, + Score = score, + InlineMessageId = inlineMessageId, Force = force, - DisableEditMessage = disableEditMessage + DisableEditMessage = disableEditMessage, }, cancellationToken ) @@ -5111,6 +5553,7 @@ await botClient.ThrowIfNull() /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// /// On success, returns an Array of objects. + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task GetGameHighScoresAsync( this ITelegramBotClient botClient, long userId, @@ -5119,7 +5562,15 @@ await botClient.ThrowIfNull() CancellationToken cancellationToken = default ) => await botClient.ThrowIfNull() - .MakeRequestAsync(request: new GetGameHighScoresRequest(userId, chatId, messageId), cancellationToken) + .MakeRequestAsync( + new GetGameHighScoresRequest + { + ChatId = chatId, + UserId = userId, + MessageId = messageId, + }, + cancellationToken + ) .ConfigureAwait(false); /// @@ -5138,6 +5589,7 @@ await botClient.ThrowIfNull() /// A cancellation token that can be used by other objects or threads to receive notice of cancellation /// /// On success, returns an Array of objects. + [Obsolete("Use the overload that accepts the corresponding request class")] public static async Task GetGameHighScoresAsync( this ITelegramBotClient botClient, long userId, @@ -5146,7 +5598,7 @@ await botClient.ThrowIfNull() ) => await botClient.ThrowIfNull() .MakeRequestAsync( - request: new GetInlineGameHighScoresRequest(userId, inlineMessageId), + new GetInlineGameHighScoresRequest { UserId = userId, InlineMessageId = inlineMessageId }, cancellationToken ) .ConfigureAwait(false); diff --git a/src/Telegram.Bot/Types/ApiResponse.cs b/src/Telegram.Bot/Types/ApiResponse.cs index 0e2429987..c7d5e89c9 100644 --- a/src/Telegram.Bot/Types/ApiResponse.cs +++ b/src/Telegram.Bot/Types/ApiResponse.cs @@ -1,6 +1,4 @@ -using System.Diagnostics.CodeAnalysis; - -namespace Telegram.Bot.Types; +namespace Telegram.Bot.Types; /// /// Represents bot API response @@ -37,9 +35,7 @@ public class ApiResponse /// Gets the result object. /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - [MaybeNull] - [AllowNull] - public TResult Result { get; private set; } + public TResult? Result { get; private set; } /// /// Initializes an instance of diff --git a/src/Telegram.Bot/Types/CallbackGame.cs b/src/Telegram.Bot/Types/CallbackGame.cs index 193ecc905..6b01d1cba 100644 --- a/src/Telegram.Bot/Types/CallbackGame.cs +++ b/src/Telegram.Bot/Types/CallbackGame.cs @@ -5,6 +5,4 @@ namespace Telegram.Bot.Types; /// to set up your game. /// [JsonObject(MemberSerialization.OptIn, NamingStrategyType = typeof(SnakeCaseNamingStrategy))] -public class CallbackGame -{ -} +public class CallbackGame; diff --git a/src/Telegram.Bot/Types/CallbackQuery.cs b/src/Telegram.Bot/Types/CallbackQuery.cs index 502f6cd56..e3eae6e60 100644 --- a/src/Telegram.Bot/Types/CallbackQuery.cs +++ b/src/Telegram.Bot/Types/CallbackQuery.cs @@ -31,11 +31,10 @@ public class CallbackQuery public User From { get; set; } = default!; /// - /// Optional. Description with the callback button that originated the query. Note that message content and - /// message date will not be available if the message is too old + /// Optional. Message sent by the bot with the callback button that originated the query /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public Message? Message { get; set; } + public MaybeInaccessibleMessage? Message { get; set; } /// /// Optional. Identifier of the message sent via the bot in inline mode, that originated the query diff --git a/src/Telegram.Bot/Types/Chat.cs b/src/Telegram.Bot/Types/Chat.cs index cf9415f58..f1b09a25c 100644 --- a/src/Telegram.Bot/Types/Chat.cs +++ b/src/Telegram.Bot/Types/Chat.cs @@ -68,6 +68,44 @@ public class Chat [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] public string[]? ActiveUsernames { get; set; } + /// + /// Optional. List of available reactions allowed in the chat. If omitted, then all emoji reactions are allowed. + /// Returned only in . + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public ReactionType[]? AvailableReactions { get; set; } + + /// + /// Optional. Identifier of the accent color + /// for the chat name and backgrounds of the chat photo, reply header, and link preview. + /// See accent colors for more details. Returned only in . + /// Always returned in . + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public int? AccentColorId { get; set; } + + /// + /// Optional. Custom emoji identifier of emoji chosen by the chat for the reply header and link preview background. + /// Returned only in . + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public string? BackgroundCustomEmojiId { get; set; } + + /// + /// Optional. Identifier of the accent color for the chat's profile background. + /// See profile accent colors for more details. + /// Returned only in . + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public int? ProfileAccentColorId { get; set; } + + /// + /// Optional. Custom emoji identifier of the emoji chosen by the chat for its profile background. + /// Returned only in . + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public string? ProfileBackgroundCustomEmojiId { get; set; } + /// /// Optional. Custom emoji identifier of emoji status of the other party in a private chat. /// Returned only in . @@ -154,6 +192,13 @@ public class Chat [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] public int? SlowModeDelay { get; set; } + /// + /// Optional. For supergroups, the minimum number of boosts that a non-administrator user needs to add in order + /// to ignore slow mode and chat permissions. Returned only in getChat. + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public int? UnrestrictBoostCount { get; set; } + /// /// Optional. The time after which all messages sent to the chat will be automatically deleted; in seconds. /// Returned only in . @@ -175,6 +220,13 @@ public class Chat [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] public bool? HasHiddenMembers { get; set; } + /// + /// Optional. , if new chat members will have access to old messages; available only to chat administrators. + /// Returned only in . + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public bool? HasVisibleHistory { get; set; } + /// /// Optional. , if messages from the chat can't be forwarded to other chats. /// Returned only in . @@ -196,6 +248,14 @@ public class Chat [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] public bool? CanSetStickerSet { get; set; } + /// + /// Optional. For supergroups, the name of the group's custom emoji sticker set. Custom emoji from this set can be + /// used by all users and bots in the group. + /// Returned only in . + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public string? CustomEmojiStickerSetName { get; set; } + /// /// Optional. Unique identifier for the linked chat, i.e. the discussion group identifier for a channel /// and vice versa; for supergroups and channel chats. This identifier may be greater than 32 bits and some diff --git a/src/Telegram.Bot/Types/ChatBoost.cs b/src/Telegram.Bot/Types/ChatBoost.cs new file mode 100644 index 000000000..468238820 --- /dev/null +++ b/src/Telegram.Bot/Types/ChatBoost.cs @@ -0,0 +1,36 @@ +using Newtonsoft.Json.Converters; + +namespace Telegram.Bot.Types; + +/// +/// This object contains information about a chat boost. +/// +[JsonObject(MemberSerialization.OptIn, NamingStrategyType = typeof(SnakeCaseNamingStrategy))] +public class ChatBoost +{ + /// + /// Unique identifier of the boost + /// + [JsonProperty(Required = Required.Always)] + public string BoostId { get; set; } = default!; + + /// + /// Point in time when the chat was boosted + /// + [JsonProperty(Required = Required.Always)] + [JsonConverter(typeof(UnixDateTimeConverter))] + public DateTime AddDate { get; set; } = default!; + + /// + /// Point in time when the boost will automatically expire, unless the booster's Telegram Premium subscription is prolonged + /// + [JsonProperty(Required = Required.Always)] + [JsonConverter(typeof(UnixDateTimeConverter))] + public DateTime ExpirationDate { get; set; } = default!; + + /// + /// Source of the added boost + /// + [JsonProperty(Required = Required.Always)] + public ChatBoostSource Source { get; set; } = default!; +} diff --git a/src/Telegram.Bot/Types/ChatBoostAdded.cs b/src/Telegram.Bot/Types/ChatBoostAdded.cs new file mode 100644 index 000000000..9a0b7f9b3 --- /dev/null +++ b/src/Telegram.Bot/Types/ChatBoostAdded.cs @@ -0,0 +1,14 @@ +namespace Telegram.Bot.Types; + +/// +/// This object represents a service message about a user boosting a chat. +/// +[JsonObject(MemberSerialization.OptIn, NamingStrategyType = typeof(SnakeCaseNamingStrategy))] +public class ChatBoostAdded +{ + /// + /// Number of boosts added by the user + /// + [JsonProperty(Required = Required.Always)] + public int BoostCount { get; set; } +} diff --git a/src/Telegram.Bot/Types/ChatBoostRemoved.cs b/src/Telegram.Bot/Types/ChatBoostRemoved.cs new file mode 100644 index 000000000..1465cdaca --- /dev/null +++ b/src/Telegram.Bot/Types/ChatBoostRemoved.cs @@ -0,0 +1,35 @@ +using Newtonsoft.Json.Converters; + +namespace Telegram.Bot.Types; + +/// +/// This object represents a boost removed from a chat. +/// +[JsonObject(MemberSerialization.OptIn, NamingStrategyType = typeof(SnakeCaseNamingStrategy))] +public class ChatBoostRemoved +{ + /// + /// Chat which was boosted + /// + [JsonProperty(Required = Required.Always)] + public Chat Chat { get; set; } = default!; + + /// + /// Unique identifier of the boost + /// + [JsonProperty(Required = Required.Always)] + public string BoostId { get; set; } = default!; + + /// + /// Point in time when the boost was removed + /// + [JsonProperty(Required = Required.Always)] + [JsonConverter(typeof(UnixDateTimeConverter))] + public DateTime RemoveDate { get; set; } = default!; + + /// + /// Source of the removed boost + /// + [JsonProperty(Required = Required.Always)] + public ChatBoostSource Source { get; set; } = default!; +} diff --git a/src/Telegram.Bot/Types/ChatBoostSource.cs b/src/Telegram.Bot/Types/ChatBoostSource.cs new file mode 100644 index 000000000..89790bad4 --- /dev/null +++ b/src/Telegram.Bot/Types/ChatBoostSource.cs @@ -0,0 +1,92 @@ +using Telegram.Bot.Converters; +using Telegram.Bot.Types.Enums; + +namespace Telegram.Bot.Types; + +/// +/// This object describes the source of a chat boost. It can be one of +/// +/// +/// +/// +/// +/// +[JsonObject(MemberSerialization.OptIn, NamingStrategyType = typeof(SnakeCaseNamingStrategy))] +[JsonConverter(typeof(ChatBoostSourceConverter))] +public abstract class ChatBoostSource +{ + /// + /// Source of the boost + /// + [JsonProperty] + public abstract ChatBoostSourceType Source { get; } +} + +/// +/// The boost was obtained by subscribing to Telegram Premium or by gifting a Telegram Premium subscription to another user. +/// +[JsonObject(MemberSerialization.OptIn, NamingStrategyType = typeof(SnakeCaseNamingStrategy))] +public class ChatBoostSourcePremium : ChatBoostSource +{ + /// + /// Source of the boost, always "premium" + /// + public override ChatBoostSourceType Source => ChatBoostSourceType.Premium; + + /// + /// User that boosted the chat + /// + [JsonProperty(Required = Required.Always)] + public User User { get; set; } = default!; +} + +/// +/// The boost was obtained by the creation of Telegram Premium gift codes to boost a chat. +/// Each such code boosts the chat 4 times for the duration of the corresponding Telegram Premium subscription. +/// +[JsonObject(MemberSerialization.OptIn, NamingStrategyType = typeof(SnakeCaseNamingStrategy))] +public class ChatBoostSourceGiftCode : ChatBoostSource +{ + /// + /// Source of the boost, always "gift_code" + /// + public override ChatBoostSourceType Source => ChatBoostSourceType.GiftCode; + + /// + /// User for which the gift code was created + /// + [JsonProperty(Required = Required.Always)] + public User User { get; set; } = default!; +} + +/// +/// The boost was obtained by the creation of a Telegram Premium giveaway. +/// This boosts the chat 4 times for the duration of the corresponding Telegram Premium subscription. +/// +[JsonObject(MemberSerialization.OptIn, NamingStrategyType = typeof(SnakeCaseNamingStrategy))] +public class ChatBoostSourceGiveaway : ChatBoostSource +{ + /// + /// Source of the boost, always "giveaway" + /// + public override ChatBoostSourceType Source => ChatBoostSourceType.Giveaway; + + /// + /// Identifier of a message in the chat with the giveaway; the message could have been deleted already. + /// May be 0 if the message isn't sent yet. + /// + [JsonProperty(Required = Required.Always)] + public int GiveawayMessageId { get; set; } + + /// + /// Optional. User that won the prize in the giveaway if any + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public User? User { get; set; } + + /// + /// Optional. , if the giveaway was completed, but there was no user to win the prize + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public bool? IsUnclaimed { get; set; } +} diff --git a/src/Telegram.Bot/Types/ChatBoostUpdated.cs b/src/Telegram.Bot/Types/ChatBoostUpdated.cs new file mode 100644 index 000000000..b91889c3f --- /dev/null +++ b/src/Telegram.Bot/Types/ChatBoostUpdated.cs @@ -0,0 +1,20 @@ +namespace Telegram.Bot.Types; + +/// +/// This object represents a boost added to a chat or changed. +/// +[JsonObject(MemberSerialization.OptIn, NamingStrategyType = typeof(SnakeCaseNamingStrategy))] +public class ChatBoostUpdated +{ + /// + /// Chat which was boosted + /// + [JsonProperty(Required = Required.Always)] + public Chat Chat { get; set; } = default!; + + /// + /// Information about the chat boost + /// + [JsonProperty(Required = Required.Always)] + public ChatBoost Boost { get; set; } = default!; +} diff --git a/src/Telegram.Bot/Types/Color.cs b/src/Telegram.Bot/Types/Color.cs index ecb637ea7..8caf2e862 100644 --- a/src/Telegram.Bot/Types/Color.cs +++ b/src/Telegram.Bot/Types/Color.cs @@ -85,7 +85,7 @@ public Color(int color) /// public Color(uint color) { - if (color is > MaxRgbValue or < 0) + if (color is > MaxRgbValue) { throw new ArgumentOutOfRangeException(nameof(color), color, "Color is out of range"); } diff --git a/src/Telegram.Bot/Types/Enums/ChatBoostSourceType.cs b/src/Telegram.Bot/Types/Enums/ChatBoostSourceType.cs new file mode 100644 index 000000000..b25bab360 --- /dev/null +++ b/src/Telegram.Bot/Types/Enums/ChatBoostSourceType.cs @@ -0,0 +1,24 @@ +namespace Telegram.Bot.Types.Enums; + +/// +/// Type of chat boost source +/// +[JsonConverter(typeof(ChatBoostSourceTypeConverter))] +public enum ChatBoostSourceType +{ + /// + /// The boost was obtained by subscribing to Telegram Premium + /// or by gifting a Telegram Premium subscription to another user + /// + Premium = 1, + + /// + /// The boost was obtained by the creation of Telegram Premium gift codes to boost a chat + /// + GiftCode, + + /// + /// The boost was obtained by the creation of a Telegram Premium giveaway + /// + Giveaway, +} diff --git a/src/Telegram.Bot/Types/Enums/KnownReactionTypeEmoji.cs b/src/Telegram.Bot/Types/Enums/KnownReactionTypeEmoji.cs new file mode 100644 index 000000000..3725afaf1 --- /dev/null +++ b/src/Telegram.Bot/Types/Enums/KnownReactionTypeEmoji.cs @@ -0,0 +1,300 @@ +namespace Telegram.Bot.Types.Enums; + +/// +/// Reaction emoji. +/// +public static class KnownReactionTypeEmoji +{ + /// + /// Thumbs Up Emoji + /// + public const string ThumbsUp = "👍"; + /// + /// Thumbs Down Emoji + /// + public const string ThumbsDown = "👎"; + /// + /// Red Heart Emoji + /// + public const string RedHeart = "❤"; + /// + /// Fire Emoji + /// + public const string Fire = "🔥"; + /// + /// Smiling Face with Hearts Emoji + /// + public const string SmilingFaceWithHearts = "🥰"; + /// + /// Clapping Hands Emoji + /// + public const string ClappingHands = "👏"; + /// + /// Beaming Face with Smiling Eyes Emoji + /// + public const string BeamingFaceWithSmilingEyes = "😁"; + /// + /// Thinking Face Emoji + /// + public const string ThinkingFace = "🤔"; + /// + /// Exploding Head Emoji + /// + public const string ExplodingHead = "🤯"; + /// + /// Face Screaming in Fear Emoji + /// + public const string FaceScreamingInFear = "😱"; + /// + /// Face with Symbols on Mouth Emoji + /// + public const string FaceWithSymbolsOnMouth = "🤬"; + /// + /// Crying Face Emoji + /// + public const string CryingFace = "😢"; + /// + /// Party Popper Emoji + /// + public const string PartyPopper = "🎉"; + /// + /// Star-Struck Emoji + /// + public const string StarStruck = "🤩"; + /// + /// Face Vomiting Emoji + /// + public const string FaceVomiting = "🤮"; + /// + /// Pile of Poo Emoji + /// + public const string PileOfPoo = "💩"; + /// + /// Folded Hands Emoji + /// + public const string FoldedHands = "🙏"; + /// + /// OK Hand Emoji + /// + public const string OKHand = "👌"; + /// + /// Dove Emoji + /// + public const string Dove = "🕊"; + /// + /// Clown Face Emoji + /// + public const string ClownFace = "🤡"; + /// + /// Yawning Face Emoji + /// + public const string YawningFace = "🥱"; + /// + /// Woozy Face Emoji + /// + public const string WoozyFace = "🥴"; + /// + /// Smiling Face with Heart-Eyes Emoji + /// + public const string SmilingFaceWithHeartEyes = "😍"; + /// + /// Spouting Whale Emoji + /// + public const string SpoutingWhale = "🐳"; + /// + /// Heart on Fire Emoji + /// + public const string HeartOnFire = "❤‍🔥"; + /// + /// New Moon Face Emoji + /// + public const string NewMoonFace = "🌚"; + /// + /// Hot Dog Emoji + /// + public const string HotDog = "🌭"; + /// + /// Hundred Points Emoji + /// + public const string HundredPoints = "💯"; + /// + /// Rolling on the Floor Laughing Emoji + /// + public const string RollingOnTheFloorLaughing = "🤣"; + /// + /// High Voltage Emoji + /// + public const string HighVoltage = "⚡"; + /// + /// Banana Emoji + /// + public const string Banana = "🍌"; + /// + /// Trophy Emoji + /// + public const string Trophy = "🏆"; + /// + /// Broken Heart Emoji + /// + public const string BrokenHeart = "💔"; + /// + /// Face with Raised Eyebrow Emoji + /// + public const string FaceWithRaisedEyebrow = "🤨"; + /// + /// Neutral Face Emoji + /// + public const string NeutralFace = "😐"; + /// + /// Strawberry Emoji + /// + public const string Strawberry = "🍓"; + /// + /// Bottle with Popping Cork Emoji + /// + public const string BottleWithPoppingCork = "🍾"; + /// + /// Kiss Mark Emoji + /// + public const string KissMark = "💋"; + /// + /// Middle Finger Emoji + /// + public const string MiddleFinger = "🖕"; + /// + /// Smiling Face with Horns Emoji + /// + public const string SmilingFaceWithHorns = "😈"; + /// + /// Sleeping Face Emoji + /// + public const string SleepingFace = "😴"; + /// + /// Loudly Crying Face Emoji + /// + public const string LoudlyCryingFace = "😭"; + /// + /// Nerd Face Emoji + /// + public const string NerdFace = "🤓"; + /// + /// Ghost Emoji + /// + public const string Ghost = "👻"; + /// + /// Man Technologist Emoji + /// + public const string ManTechnologist = "👨‍💻"; + /// + /// Eyes Emoji + /// + public const string Eyes = "👀"; + /// + /// Jack-O-Lantern Emoji + /// + public const string JackOLantern = "🎃"; + /// + /// See-No-Evil Monkey Emoji + /// + public const string SeeNoEvilMonkey = "🙈"; + /// + /// Smiling Face with Halo Emoji + /// + public const string SmilingFaceWithHalo = "😇"; + /// + /// Fearful Face Emoji + /// + public const string FearfulFace = "😨"; + /// + /// Handshake Emoji + /// + public const string Handshake = "🤝"; + /// + /// Writing Hand Emoji + /// + public const string WritingHand = "✍"; + /// + /// Smiling Face with Open Hands Emoji + /// + public const string SmilingFaceWithOpenHands = "🤗"; + /// + /// Saluting Face Emoji + /// + public const string SalutingFace = "🫡"; + /// + /// Santa Claus Emoji + /// + public const string SantaClaus = "🎅"; + /// + /// Christmas Tree Emoji + /// + public const string ChristmasTree = "🎄"; + /// + /// Snowman Emoji + /// + public const string Snowman = "☃"; + /// + /// Nail Polish Emoji + /// + public const string NailPolish = "💅"; + /// + /// Zany Face Emoji + /// + public const string ZanyFace = "🤪"; + /// + /// Moai Emoji + /// + public const string Moai = "🗿"; + /// + /// Cool Button Emoji + /// + public const string CoolButton = "🆒"; + /// + /// Heart with Arrow Emoji + /// + public const string HeartWithArrow = "💘"; + /// + /// Hear-No-Evil Monkey Emoji + /// + public const string HearNoEvilMonkey = "🙉"; + /// + /// Unicorn Emoji + /// + public const string Unicorn = "🦄"; + /// + /// Face Blowing a Kiss Emoji + /// + public const string FaceBlowingAKiss = "😘"; + /// + /// Pill Emoji + /// + public const string Pill = "💊"; + /// + /// Speak-No-Evil Monkey Emoji + /// + public const string SpeakNoEvilMonkey = "🙊"; + /// + /// Smiling Face with Sunglasses Emoji + /// + public const string SmilingFaceWithSunglasses = "😎"; + /// + /// Alien Monster Emoji + /// + public const string AlienMonster = "👾"; + /// + /// Man Shrugging Emoji + /// + public const string ManShrugging = "🤷‍♂"; + /// + /// Shrugging Person Emoji + /// + public const string ShruggingPerson = "🤷"; + /// + /// Woman Shrugging Emoji + /// + public const string WomanShrugging = "🤷‍♀"; + /// + /// Enraged Face Emoji + /// + public const string EnragedFace = "😡"; +} diff --git a/src/Telegram.Bot/Types/Enums/MenuButtonType.cs b/src/Telegram.Bot/Types/Enums/MenuButtonType.cs index a3d26e94c..0e0d309d4 100644 --- a/src/Telegram.Bot/Types/Enums/MenuButtonType.cs +++ b/src/Telegram.Bot/Types/Enums/MenuButtonType.cs @@ -19,5 +19,5 @@ public enum MenuButtonType /// /// Represents a menu button, which launches a Web App. /// - WebApp + WebApp, } diff --git a/src/Telegram.Bot/Types/Enums/MessageEntityType.cs b/src/Telegram.Bot/Types/Enums/MessageEntityType.cs index b372293ba..891e44695 100644 --- a/src/Telegram.Bot/Types/Enums/MessageEntityType.cs +++ b/src/Telegram.Bot/Types/Enums/MessageEntityType.cs @@ -90,4 +90,9 @@ public enum MessageEntityType /// Inline custom emoji stickers /// CustomEmoji, + + /// + /// Block quotation + /// + Blockquote, } diff --git a/src/Telegram.Bot/Types/Enums/MessageOriginType.cs b/src/Telegram.Bot/Types/Enums/MessageOriginType.cs new file mode 100644 index 000000000..ee7b834e6 --- /dev/null +++ b/src/Telegram.Bot/Types/Enums/MessageOriginType.cs @@ -0,0 +1,28 @@ +namespace Telegram.Bot.Types.Enums; + +/// +/// Message origin type +/// +[JsonConverter(typeof(MessageOriginTypeConverter))] +public enum MessageOriginType +{ + /// + /// Message origin is from a user + /// + User = 1, + + /// + /// Message origin is from a hidden user + /// + HiddenUser, + + /// + /// Message origin is a chat + /// + Chat, + + /// + /// Message origin is a channel + /// + Channel, +} diff --git a/src/Telegram.Bot/Types/Enums/MessageType.cs b/src/Telegram.Bot/Types/Enums/MessageType.cs index 97ddbc946..252cb1b39 100644 --- a/src/Telegram.Bot/Types/Enums/MessageType.cs +++ b/src/Telegram.Bot/Types/Enums/MessageType.cs @@ -12,232 +12,262 @@ public enum MessageType Unknown = 0, /// - /// The contains text + /// The contains /// Text, /// - /// The contains a + /// The contains a /// Photo, /// - /// The contains an + /// The contains an /// Audio, /// - /// The contains a + /// The contains a /// Video, /// - /// The contains a + /// The contains a /// Voice, /// - /// The contains a + /// The contains a /// Document, /// - /// The contains a + /// The contains a /// Sticker, /// - /// The contains a + /// The contains a /// Location, /// - /// The contains a + /// The contains a /// Contact, /// - /// The contains a + /// The contains a /// Venue, /// - /// The contains a + /// The contains a /// Game, /// - /// The contains a + /// The contains a /// VideoNote, /// - /// The contains a + /// The contains an /// Invoice, /// - /// The contains a + /// The contains a /// SuccessfulPayment, /// /// The contains a /// - WebsiteConnected, + ConnectedWebsite, /// /// The contains a /// - ChatMembersAdded, + NewChatMembers, /// /// The contains a /// - ChatMemberLeft, + LeftChatMember, /// /// The contains a /// - ChatTitleChanged, + NewChatTitle, /// /// The contains a /// - ChatPhotoChanged, + NewChatPhoto, /// /// The contains a /// - MessagePinned, + PinnedMessage, /// /// The contains a /// - ChatPhotoDeleted, + DeleteChatPhoto, /// /// The contains a /// - GroupCreated, + GroupChatCreated, /// /// The contains a /// - SupergroupCreated, + SupergroupChatCreated, /// /// The contains a /// - ChannelCreated, + ChannelChatCreated, /// - /// The contains non-default + /// The contains a /// - MigratedToSupergroup, + MigrateFromChatId, /// - /// The contains non-default + /// The contains a /// - MigratedFromGroup, + MigrateToChatId, /// - /// The contains + /// The contains a /// Poll, /// - /// The contains + /// The contains a /// Dice, /// - /// The contains + /// The contains a /// MessageAutoDeleteTimerChanged, /// - /// The contains + /// The contains a /// ProximityAlertTriggered, /// - /// The contains + /// The contains a /// WebAppData, /// - /// The contains + /// The contains a /// VideoChatScheduled, /// - /// The contains + /// The contains a /// VideoChatStarted, /// - /// The contains + /// The contains a /// VideoChatEnded, /// - /// The contains + /// The contains a /// VideoChatParticipantsInvited, /// - /// The contains + /// The contains a /// Animation, /// - /// The contains + /// The contains a /// ForumTopicCreated, /// - /// The contains + /// The contains a /// ForumTopicClosed, /// - /// The contains + /// The contains a /// ForumTopicReopened, /// - /// The contains + /// The contains a /// ForumTopicEdited, /// - /// The contains + /// The contains a /// GeneralForumTopicHidden, /// - /// The contains + /// The contains a /// GeneralForumTopicUnhidden, /// - /// The contains + /// The contains a /// WriteAccessAllowed, /// - /// The contains + /// The contains a /// - UserShared, + UsersShared, /// - /// The contains + /// The contains a /// ChatShared, /// - /// The contains + /// The contains a /// Story, + + /// + /// The contains a + /// + PassportData, + + /// + /// The contains a + /// + GiveawayCreated, + + /// + /// The contains a + /// + Giveaway, + + /// + /// The contains a + /// + GiveawayWinners, + + /// + /// The contains a + /// + GiveawayCompleted, + + /// + /// The contains a + /// + BoostAdded, } diff --git a/src/Telegram.Bot/Types/Enums/ReactionTypeKind.cs b/src/Telegram.Bot/Types/Enums/ReactionTypeKind.cs new file mode 100644 index 000000000..9ba85a676 --- /dev/null +++ b/src/Telegram.Bot/Types/Enums/ReactionTypeKind.cs @@ -0,0 +1,18 @@ +namespace Telegram.Bot.Types.Enums; + +/// +/// Type of the reaction +/// +[JsonConverter(typeof(ReactionTypeKindConverter))] +public enum ReactionTypeKind +{ + /// + /// The reaction is based on an emoji. + /// + Emoji = 1, + + /// + /// The reaction is based on a custom emoji. + /// + CustomEmoji, +} diff --git a/src/Telegram.Bot/Types/Enums/UpdateType.cs b/src/Telegram.Bot/Types/Enums/UpdateType.cs index 15524bbdf..f689721f3 100644 --- a/src/Telegram.Bot/Types/Enums/UpdateType.cs +++ b/src/Telegram.Bot/Types/Enums/UpdateType.cs @@ -1,4 +1,4 @@ -namespace Telegram.Bot.Types.Enums; +namespace Telegram.Bot.Types.Enums; /// /// The type of an @@ -12,72 +12,92 @@ public enum UpdateType Unknown = 0, /// - /// The contains a . + /// The contains a . /// Message, /// - /// The contains an . + /// The contains an . /// InlineQuery, /// - /// The contains a . + /// The contains a . /// ChosenInlineResult, /// - /// The contains a + /// The contains a /// CallbackQuery, /// - /// The contains an edited + /// The contains /// EditedMessage, /// - /// The contains a channel post + /// The contains a /// ChannelPost, /// - /// The contains an edited channel post + /// The contains /// EditedChannelPost, /// - /// The contains an + /// The contains a /// ShippingQuery, /// - /// The contains an + /// The contains a /// PreCheckoutQuery, /// - /// The contains an + /// The contains a /// Poll, /// - /// The contains an + /// The contains a /// PollAnswer, /// - /// The contains an + /// The contains a /// MyChatMember, /// - /// The contains an + /// The contains a /// ChatMember, /// - /// The contains an + /// The contains a /// ChatJoinRequest, + + /// + /// The contains a + /// + MessageReaction, + + /// + /// The contains a + /// + MessageReactionCount, + + /// + /// The contains a + /// + ChatBoost, + + /// + /// The contains a + /// + RemovedChatBoost, } diff --git a/src/Telegram.Bot/Types/ExternalReplyInfo.cs b/src/Telegram.Bot/Types/ExternalReplyInfo.cs new file mode 100644 index 000000000..52c915a0d --- /dev/null +++ b/src/Telegram.Bot/Types/ExternalReplyInfo.cs @@ -0,0 +1,149 @@ +using Telegram.Bot.Types.Payments; + +namespace Telegram.Bot.Types; + +/// +/// This object contains information about a message that is being replied to, which may come from another chat or forum topic. +/// +[JsonObject(MemberSerialization.OptIn, NamingStrategyType = typeof(SnakeCaseNamingStrategy))] +public class ExternalReplyInfo +{ + /// + /// Origin of the message replied to by the given message + /// + [JsonProperty(Required = Required.Always)] + public MessageOrigin Origin { get; set; } = default!; + + /// + /// Optional.Chat the original message belongs to.Available only if the chat is a supergroup or a channel. + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public Chat? Chat { get; set; } + + /// + /// Optional.Unique message identifier inside the original chat.Available only if the original chat + /// is a supergroup or a channel. + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public int? MessageId { get; set; } + + /// + /// Optional.Options used for link preview generation for the original message, if it is a text message + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public LinkPreviewOptions? LinkPreviewOptions { get; set; } + + /// + /// Optional. Message is an animation, information about the animation + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public Animation? Animation { get; set; } + + /// + /// Optional. Message is an audio file, information about the file + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public Audio? Audio { get; set; } + + /// + /// Optional. Message is a general file, information about the file + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public Document? Document { get; set; } + + /// + /// Optional. Message is a photo, available sizes of the photo + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public PhotoSize[]? Photo { get; set; } + + /// + /// Optional. Message is a sticker, information about the sticker + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public Sticker? Sticker { get; set; } + + /// + /// Optional. Message is a forwarded story + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public Story? Story { get; set; } + + /// + /// Optional. Message is a video, information about the video + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public Video? Video { get; set; } + + /// + /// Optional. Message is a video note, information about the video message + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public VideoNote? VideoNote { get; set; } + + /// + /// Optional. Message is a voice message, information about the file + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public Voice? Voice { get; set; } + + /// + /// Optional. , if the message media is covered by a spoiler animation + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public bool? HasMediaSpoiler { get; set; } + + /// + /// Optional. Message is a shared contact, information about the contact + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public Contact? Contact { get; set; } + + /// + /// Optional. Message is a dice with random value + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public Dice? Dice { get; set; } + + /// + /// Optional. Message is a game, information about the game. + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public Game? Game { get; set; } + + /// + /// Optional. Message is a scheduled giveaway, information about the giveaway + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public Giveaway? Giveaway { get; set; } + + /// + /// Optional.A giveaway with public winners was completed + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public GiveawayWinners? GiveawayWinners { get; set; } + + /// + /// Optional. Message is an invoice for a payment, information about the invoice. + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public Invoice? Invoice { get; set; } + + /// + /// Optional. Message is a shared location, information about the location + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public Location? Location { get; set; } + + /// + /// Optional. Message is a native poll, information about the poll + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public Poll? Poll { get; set; } + + /// + /// Optional. Message is a venue, information about the venue + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public Venue? Venue { get; set; } +} diff --git a/src/Telegram.Bot/Types/File.cs b/src/Telegram.Bot/Types/File.cs index e072c2a1c..b80119c1c 100644 --- a/src/Telegram.Bot/Types/File.cs +++ b/src/Telegram.Bot/Types/File.cs @@ -1,14 +1,21 @@ +using System.Threading; +using Telegram.Bot.Requests; + namespace Telegram.Bot.Types; /// -/// This object represents a file ready to be downloaded. The file can be downloaded via . -/// It is guaranteed that the link will be valid for at least 1 hour. When the link expires, a new one can be requested by calling . +/// This object represents a file ready to be downloaded. The file can be downloaded via +/// . +/// It is guaranteed that the link will be valid for at least 1 hour. When the link expires, a new one can be requested +/// by calling . /// [JsonObject(MemberSerialization.OptIn, NamingStrategyType = typeof(SnakeCaseNamingStrategy))] public class File : FileBase { /// - /// Optional. File path. Use to get the file. + /// Optional. File path. Use + /// + /// to get the file. /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] public string? FilePath { get; set; } diff --git a/src/Telegram.Bot/Types/FileBase.cs b/src/Telegram.Bot/Types/FileBase.cs index 7132acfba..5b4a91ae9 100644 --- a/src/Telegram.Bot/Types/FileBase.cs +++ b/src/Telegram.Bot/Types/FileBase.cs @@ -1,10 +1,14 @@ +using System.Threading; +using Telegram.Bot.Requests; + namespace Telegram.Bot.Types; /// /// This object represents a file ready to be downloaded. The file can be downloaded via -/// . It is guaranteed that the link will be valid for +/// . +/// It is guaranteed that the link will be valid for /// at least 1 hour. When the link expires, a new one can be requested by calling -/// . +/// . /// [JsonObject(MemberSerialization.OptIn, NamingStrategyType = typeof(SnakeCaseNamingStrategy))] public abstract class FileBase diff --git a/src/Telegram.Bot/Types/ForumTopicClosed.cs b/src/Telegram.Bot/Types/ForumTopicClosed.cs index 71d3548e2..410afffc8 100644 --- a/src/Telegram.Bot/Types/ForumTopicClosed.cs +++ b/src/Telegram.Bot/Types/ForumTopicClosed.cs @@ -4,4 +4,4 @@ namespace Telegram.Bot.Types; /// This object represents a service message about a forum topic closed in the chat. Currently holds no information. /// [JsonObject(MemberSerialization.OptIn, NamingStrategyType = typeof(SnakeCaseNamingStrategy))] -public class ForumTopicClosed { } +public class ForumTopicClosed; diff --git a/src/Telegram.Bot/Types/ForumTopicReopened.cs b/src/Telegram.Bot/Types/ForumTopicReopened.cs index 8b9f0b120..f6beac7c4 100644 --- a/src/Telegram.Bot/Types/ForumTopicReopened.cs +++ b/src/Telegram.Bot/Types/ForumTopicReopened.cs @@ -4,4 +4,4 @@ namespace Telegram.Bot.Types; /// This object represents a service message about a forum topic reopened in the chat. Currently holds no information. /// [JsonObject(MemberSerialization.OptIn, NamingStrategyType = typeof(SnakeCaseNamingStrategy))] -public class ForumTopicReopened { } +public class ForumTopicReopened; diff --git a/src/Telegram.Bot/Types/GeneralForumTopicHidden.cs b/src/Telegram.Bot/Types/GeneralForumTopicHidden.cs index 2aea8eaf1..cd2e1023f 100644 --- a/src/Telegram.Bot/Types/GeneralForumTopicHidden.cs +++ b/src/Telegram.Bot/Types/GeneralForumTopicHidden.cs @@ -5,4 +5,4 @@ namespace Telegram.Bot.Types; /// Currently holds no information. /// [JsonObject(MemberSerialization.OptIn, NamingStrategyType = typeof(SnakeCaseNamingStrategy))] -public class GeneralForumTopicHidden { } +public class GeneralForumTopicHidden; diff --git a/src/Telegram.Bot/Types/GeneralForumTopicUnhidden.cs b/src/Telegram.Bot/Types/GeneralForumTopicUnhidden.cs index 6c765f321..e8c63cf6b 100644 --- a/src/Telegram.Bot/Types/GeneralForumTopicUnhidden.cs +++ b/src/Telegram.Bot/Types/GeneralForumTopicUnhidden.cs @@ -5,4 +5,4 @@ namespace Telegram.Bot.Types; /// Currently holds no information. /// [JsonObject(MemberSerialization.OptIn, NamingStrategyType = typeof(SnakeCaseNamingStrategy))] -public class GeneralForumTopicUnhidden { } +public class GeneralForumTopicUnhidden; diff --git a/src/Telegram.Bot/Types/Giveaway.cs b/src/Telegram.Bot/Types/Giveaway.cs new file mode 100644 index 000000000..fc32f12be --- /dev/null +++ b/src/Telegram.Bot/Types/Giveaway.cs @@ -0,0 +1,62 @@ +using Newtonsoft.Json.Converters; + +namespace Telegram.Bot.Types; + +/// +/// This object represents a message about a scheduled giveaway. +/// +[JsonObject(MemberSerialization.OptIn, NamingStrategyType = typeof(SnakeCaseNamingStrategy))] +public class Giveaway +{ + /// + /// The list of chats which the user must join to participate in the giveaway + /// + [JsonProperty(Required = Required.Always)] + public Chat[] Chats { get; set; } = default!; + + /// + /// Point in time when winners of the giveaway will be selected + /// + [JsonProperty(Required = Required.Always)] + [JsonConverter(typeof(UnixDateTimeConverter))] + public DateTime WinnersSelectionDate { get; set; } = default!; + + /// + /// The number of users which are supposed to be selected as winners of the giveaway + /// + [JsonProperty(Required = Required.Always)] + public int WinnerCount { get; set; } = default!; + + /// + /// Optional. , if only users who join the chats after the giveaway started should be eligible to win + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public bool? OnlyNewMembers { get; set; } + + /// + /// Optional., if the list of giveaway winners will be visible to everyone + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public bool? HasPublicWinners { get; set; } + + /// + /// Optional. Description of additional giveaway prize + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public string? PrizeDescription { get; set; } + + /// + /// Optional.A list of two-letter ISO 3166-1 alpha-2 + /// country codes indicating the countries from which eligible users for the giveaway must come. + /// If empty, then all users can participate in the giveaway. + /// Users with a phone number that was bought on Fragment can always participate in giveaways. + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public string[]? CountryCodes { get; set; } + + /// + /// Optional. The number of months the Telegram Premium subscription won from the giveaway will be active for + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public int? PremiumSubscriptionMonthCount { get; set; } +} diff --git a/src/Telegram.Bot/Types/GiveawayCompleted.cs b/src/Telegram.Bot/Types/GiveawayCompleted.cs new file mode 100644 index 000000000..1f7fdd4e4 --- /dev/null +++ b/src/Telegram.Bot/Types/GiveawayCompleted.cs @@ -0,0 +1,26 @@ +namespace Telegram.Bot.Types; + +/// +/// This object represents a service message about the completion of a giveaway without public winners. +/// +[JsonObject(MemberSerialization.OptIn, NamingStrategyType = typeof(SnakeCaseNamingStrategy))] +public class GiveawayCompleted +{ + /// + /// Number of winners in the giveaway + /// + [JsonProperty(Required = Required.Always)] + public int WinnerCount { get; set; } = default!; + + /// + /// Optional. Number of undistributed prizes + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public int? UnclaimedPrizeCount { get; set; } + + /// + /// Optional. Message with the giveaway that was completed, if it wasn't deleted + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public Message? GiveawayMessage { get; set; } +} diff --git a/src/Telegram.Bot/Types/GiveawayCreated.cs b/src/Telegram.Bot/Types/GiveawayCreated.cs new file mode 100644 index 000000000..dcf66f328 --- /dev/null +++ b/src/Telegram.Bot/Types/GiveawayCreated.cs @@ -0,0 +1,8 @@ +namespace Telegram.Bot.Types; + +/// +/// This object represents a service message about the creation of a scheduled giveaway. +/// Currently holds no information. +/// +[JsonObject(MemberSerialization.OptIn, NamingStrategyType = typeof(SnakeCaseNamingStrategy))] +public class GiveawayCreated; diff --git a/src/Telegram.Bot/Types/GiveawayWinners.cs b/src/Telegram.Bot/Types/GiveawayWinners.cs new file mode 100644 index 000000000..b59cdc83d --- /dev/null +++ b/src/Telegram.Bot/Types/GiveawayWinners.cs @@ -0,0 +1,77 @@ +using Newtonsoft.Json.Converters; + +namespace Telegram.Bot.Types; + +/// +/// This object represents a message about the completion of a giveaway with public winners. +/// +[JsonObject(MemberSerialization.OptIn, NamingStrategyType = typeof(SnakeCaseNamingStrategy))] +public class GiveawayWinners +{ + /// + /// The chat that created the giveaway + /// + [JsonProperty(Required = Required.Always)] + public Chat Chat { get; set; } = default!; + + /// + /// Identifier of the message with the giveaway in the chat + /// + [JsonProperty(Required = Required.Always)] + public int GiveawayMessageId { get; set; } = default!; + + /// + /// Point in time when winners of the giveaway were selected + /// + [JsonProperty(Required = Required.Always)] + [JsonConverter(typeof(UnixDateTimeConverter))] + public DateTime WinnersSelectionDate { get; set; } = default!; + + /// + /// Total number of winners in the giveaway + /// + [JsonProperty(Required = Required.Always)] + public int WinnerCount { get; set; } = default!; + + /// + /// List of up to 100 winners of the giveaway + /// + [JsonProperty(Required = Required.Always)] + public User[] Winners { get; set; } = default!; + + /// + /// Optional. The number of other chats the user had to join in order to be eligible for the giveaway + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public int? AdditionalChatCount { get; set; } + + /// + /// Optional. The number of months the Telegram Premium subscription won from the giveaway will be active for + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public int? PremiumSubscriptionMonthCount { get; set; } + + /// + /// Optional. Number of undistributed prizes + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public int? UnclaimedPrizeCount { get; set; } + + /// + /// Optional. , if only users who had joined the chats after the giveaway started were eligible to win + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public bool? OnlyNewMembers { get; set; } + + /// + /// Optional. , if the giveaway was canceled because the payment for it was refunded + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public bool? WasRefunded { get; set; } + + /// + /// Optional. Description of additional giveaway prize + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public string? PrizeDescription { get; set; } +} diff --git a/src/Telegram.Bot/Types/InaccessibleMessage.cs b/src/Telegram.Bot/Types/InaccessibleMessage.cs new file mode 100644 index 000000000..763a90f4e --- /dev/null +++ b/src/Telegram.Bot/Types/InaccessibleMessage.cs @@ -0,0 +1,26 @@ +namespace Telegram.Bot.Types; + +/// +/// This object describes a message that was deleted or is otherwise inaccessible to the bot. +/// +[JsonObject(MemberSerialization.OptIn, NamingStrategyType = typeof(SnakeCaseNamingStrategy))] +public class InaccessibleMessage : MaybeInaccessibleMessage +{ + /// + /// Chat the message belonged to + /// + [JsonProperty(Required = Required.Always)] + public Chat Chat { get; set; } = default!; + + /// + /// Unique message identifier inside the chat + /// + [JsonProperty(Required = Required.Always)] + public int MessageId { get; set; } = default!; + + /// + /// Always 0. The field can be used to differentiate regular and inaccessible messages. + /// + [JsonProperty(Required = Required.Always)] + public int Date { get; set; } = default!; +} diff --git a/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResult.cs b/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResult.cs index df9fc6979..2e9a26ef2 100644 --- a/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResult.cs +++ b/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResult.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Types.ReplyMarkups; // ReSharper disable once CheckNamespace @@ -19,7 +20,7 @@ public abstract class InlineQueryResult /// Unique identifier for this result, 1-64 Bytes /// [JsonProperty(Required = Required.Always)] - public string Id { get; } + public required string Id { get; init; } /// /// Optional. Inline keyboard attached to the message @@ -31,5 +32,13 @@ public abstract class InlineQueryResult /// Initializes a new inline query result /// /// Unique identifier for this result, 1-64 Bytes + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] protected InlineQueryResult(string id) => Id = id; + + /// + /// Initializes a new inline query result + /// + protected InlineQueryResult() + { } } diff --git a/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResultArticle.cs b/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResultArticle.cs index 3df212960..abfaa2aa0 100644 --- a/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResultArticle.cs +++ b/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResultArticle.cs @@ -1,4 +1,4 @@ - +using System.Diagnostics.CodeAnalysis; // ReSharper disable once CheckNamespace namespace Telegram.Bot.Types.InlineQueryResults; @@ -19,13 +19,13 @@ public class InlineQueryResultArticle : InlineQueryResult /// Title of the result /// [JsonProperty(Required = Required.Always)] - public string Title { get; } + public required string Title { get; init; } /// /// Content of the message to be sent /// [JsonProperty(Required = Required.Always)] - public InputMessageContent InputMessageContent { get; } + public required InputMessageContent InputMessageContent { get; init; } /// /// Optional. URL of the result. @@ -63,10 +63,18 @@ public class InlineQueryResultArticle : InlineQueryResult /// Unique identifier of this result /// Title of the result /// Content of the message to be sent + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public InlineQueryResultArticle(string id, string title, InputMessageContent inputMessageContent) : base(id) { Title = title; InputMessageContent = inputMessageContent; } + + /// + /// Initializes a new object + /// + public InlineQueryResultArticle() + { } } diff --git a/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResultAudio.cs b/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResultAudio.cs index 3f7e8b639..bbfde1677 100644 --- a/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResultAudio.cs +++ b/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResultAudio.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Types.Enums; // ReSharper disable once CheckNamespace @@ -21,13 +22,13 @@ public class InlineQueryResultAudio : InlineQueryResult /// A valid URL for the audio file /// [JsonProperty(Required = Required.Always)] - public string AudioUrl { get; } + public required string AudioUrl { get; init; } /// /// Title /// [JsonProperty(Required = Required.Always)] - public string Title { get; } + public required string Title { get; init; } /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] @@ -63,10 +64,18 @@ public class InlineQueryResultAudio : InlineQueryResult /// Unique identifier of this result /// A valid URL for the audio file /// Title of the result + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public InlineQueryResultAudio(string id, string audioUrl, string title) : base(id) { AudioUrl = audioUrl; Title = title; } + + /// + /// Initializes a new inline query result + /// + public InlineQueryResultAudio() + { } } diff --git a/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResultCached/InlineQueryResultCachedAudio.cs b/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResultCached/InlineQueryResultCachedAudio.cs index 501fbc610..d7e31cfb9 100644 --- a/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResultCached/InlineQueryResultCachedAudio.cs +++ b/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResultCached/InlineQueryResultCachedAudio.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Types.Enums; // ReSharper disable once CheckNamespace @@ -22,7 +23,7 @@ public class InlineQueryResultCachedAudio : InlineQueryResult /// A valid file identifier for the audio file /// [JsonProperty(Required = Required.Always)] - public string AudioFileId { get; } + public required string AudioFileId { get; init; } /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] @@ -45,9 +46,17 @@ public class InlineQueryResultCachedAudio : InlineQueryResult /// /// Unique identifier of this result /// A valid file identifier for the audio file + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public InlineQueryResultCachedAudio(string id, string audioFileId) : base(id) { AudioFileId = audioFileId; } + + /// + /// Initializes a new inline query result + /// + public InlineQueryResultCachedAudio() + { } } diff --git a/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResultCached/InlineQueryResultCachedDocument.cs b/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResultCached/InlineQueryResultCachedDocument.cs index 5294f0046..ebdfe0f33 100644 --- a/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResultCached/InlineQueryResultCachedDocument.cs +++ b/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResultCached/InlineQueryResultCachedDocument.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Types.Enums; // ReSharper disable once CheckNamespace @@ -22,13 +23,13 @@ public class InlineQueryResultCachedDocument : InlineQueryResult /// Title for the result /// [JsonProperty(Required = Required.Always)] - public string Title { get; } + public required string Title { get; init; } /// /// A valid file identifier for the file /// [JsonProperty(Required = Required.Always)] - public string DocumentFileId { get; } + public required string DocumentFileId { get; init; } /// /// Optional. Short description of the result @@ -58,10 +59,18 @@ public class InlineQueryResultCachedDocument : InlineQueryResult /// Unique identifier of this result /// A valid file identifier for the file /// Title of the result + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public InlineQueryResultCachedDocument(string id, string documentFileId, string title) : base(id) { DocumentFileId = documentFileId; Title = title; } + + /// + /// Initializes a new inline query result + /// + public InlineQueryResultCachedDocument() + { } } diff --git a/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResultCached/InlineQueryResultCachedGif.cs b/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResultCached/InlineQueryResultCachedGif.cs index 0bac4d871..8b602833f 100644 --- a/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResultCached/InlineQueryResultCachedGif.cs +++ b/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResultCached/InlineQueryResultCachedGif.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Types.Enums; // ReSharper disable once CheckNamespace @@ -22,7 +23,7 @@ public class InlineQueryResultCachedGif : InlineQueryResult /// A valid file identifier for the GIF file /// [JsonProperty(Required = Required.Always)] - public string GifFileId { get; } + public required string GifFileId { get; init; } /// /// Optional. Title for the result @@ -51,9 +52,17 @@ public class InlineQueryResultCachedGif : InlineQueryResult /// /// Unique identifier of this result /// A valid file identifier for the GIF file + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public InlineQueryResultCachedGif(string id, string gifFileId) : base(id) { GifFileId = gifFileId; } + + /// + /// Initializes a new inline query result + /// + public InlineQueryResultCachedGif() + { } } diff --git a/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResultCached/InlineQueryResultCachedMpeg4Gif.cs b/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResultCached/InlineQueryResultCachedMpeg4Gif.cs index 725134fcd..c7ab246da 100644 --- a/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResultCached/InlineQueryResultCachedMpeg4Gif.cs +++ b/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResultCached/InlineQueryResultCachedMpeg4Gif.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Types.Enums; // ReSharper disable once CheckNamespace @@ -23,7 +24,7 @@ public class InlineQueryResultCachedMpeg4Gif : InlineQueryResult /// A valid file identifier for the MP4 file /// [JsonProperty(Required = Required.Always)] - public string Mpeg4FileId { get; } + public required string Mpeg4FileId { get; init; } /// /// Optional. Title for the result @@ -52,9 +53,17 @@ public class InlineQueryResultCachedMpeg4Gif : InlineQueryResult /// /// Unique identifier of this result /// A valid file identifier for the MP4 file + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public InlineQueryResultCachedMpeg4Gif(string id, string mpeg4FileId) : base(id) { Mpeg4FileId = mpeg4FileId; } + + /// + /// Initializes a new inline query result + /// + public InlineQueryResultCachedMpeg4Gif() + { } } diff --git a/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResultCached/InlineQueryResultCachedPhoto.cs b/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResultCached/InlineQueryResultCachedPhoto.cs index 542eeeb75..6ef88c4ae 100644 --- a/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResultCached/InlineQueryResultCachedPhoto.cs +++ b/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResultCached/InlineQueryResultCachedPhoto.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Types.Enums; // ReSharper disable once CheckNamespace @@ -22,7 +23,7 @@ public class InlineQueryResultCachedPhoto : InlineQueryResult /// A valid file identifier of the photo /// [JsonProperty(Required = Required.Always)] - public string PhotoFileId { get; } + public required string PhotoFileId { get; init; } /// /// Optional. Title for the result @@ -57,9 +58,17 @@ public class InlineQueryResultCachedPhoto : InlineQueryResult /// /// Unique identifier of this result /// A valid file identifier of the photo + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public InlineQueryResultCachedPhoto(string id, string photoFileId) : base(id) { PhotoFileId = photoFileId; } + + /// + /// Initializes a new inline query result + /// + public InlineQueryResultCachedPhoto() + { } } diff --git a/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResultCached/InlineQueryResultCachedSticker.cs b/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResultCached/InlineQueryResultCachedSticker.cs index ed4f1cb8e..597f46d24 100644 --- a/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResultCached/InlineQueryResultCachedSticker.cs +++ b/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResultCached/InlineQueryResultCachedSticker.cs @@ -1,4 +1,4 @@ - +using System.Diagnostics.CodeAnalysis; // ReSharper disable once CheckNamespace namespace Telegram.Bot.Types.InlineQueryResults; @@ -22,7 +22,7 @@ public class InlineQueryResultCachedSticker : InlineQueryResult /// A valid file identifier of the sticker /// [JsonProperty(Required = Required.Always)] - public string StickerFileId { get; } + public required string StickerFileId { get; init; } /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] @@ -33,9 +33,17 @@ public class InlineQueryResultCachedSticker : InlineQueryResult /// /// Unique identifier of this result /// A valid file identifier of the sticker + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public InlineQueryResultCachedSticker(string id, string stickerFileId) : base(id) { StickerFileId = stickerFileId; } + + /// + /// Initializes a new inline query result + /// + public InlineQueryResultCachedSticker() + { } } diff --git a/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResultCached/InlineQueryResultCachedVideo.cs b/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResultCached/InlineQueryResultCachedVideo.cs index 9bef333d5..aa960d185 100644 --- a/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResultCached/InlineQueryResultCachedVideo.cs +++ b/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResultCached/InlineQueryResultCachedVideo.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Types.Enums; // ReSharper disable once CheckNamespace @@ -22,13 +23,13 @@ public class InlineQueryResultCachedVideo : InlineQueryResult /// A valid file identifier for the video file /// [JsonProperty(Required = Required.Always)] - public string VideoFileId { get; } + public required string VideoFileId { get; init; } /// /// Title for the result /// [JsonProperty(Required = Required.Always)] - public string Title { get; } + public required string Title { get; init; } /// /// Optional. Short description of the result @@ -58,10 +59,18 @@ public class InlineQueryResultCachedVideo : InlineQueryResult /// Unique identifier of this result /// A valid file identifier for the video file /// Title of the result + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public InlineQueryResultCachedVideo(string id, string videoFileId, string title) : base(id) { VideoFileId = videoFileId; Title = title; } + + /// + /// Initializes a new inline query result + /// + public InlineQueryResultCachedVideo() + { } } diff --git a/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResultCached/InlineQueryResultCachedVoice.cs b/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResultCached/InlineQueryResultCachedVoice.cs index 700208f0d..feaeb03a7 100644 --- a/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResultCached/InlineQueryResultCachedVoice.cs +++ b/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResultCached/InlineQueryResultCachedVoice.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Types.Enums; // ReSharper disable once CheckNamespace @@ -22,13 +23,13 @@ public class InlineQueryResultCachedVoice : InlineQueryResult /// A valid file identifier for the voice message /// [JsonProperty(Required = Required.Always)] - public string VoiceFileId { get; } + public required string VoiceFileId { get; init; } /// /// Voice message title /// [JsonProperty(Required = Required.Always)] - public string Title { get; } + public required string Title { get; init; } /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] @@ -52,10 +53,18 @@ public class InlineQueryResultCachedVoice : InlineQueryResult /// Unique identifier of this result /// A valid file identifier for the voice message /// Title of the result + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public InlineQueryResultCachedVoice(string id, string fileId, string title) : base(id) { VoiceFileId = fileId; Title = title; } + + /// + /// Initializes a new inline query result + /// + public InlineQueryResultCachedVoice() + { } } diff --git a/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResultContact.cs b/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResultContact.cs index a953c1c1f..fa4ec2e70 100644 --- a/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResultContact.cs +++ b/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResultContact.cs @@ -1,4 +1,4 @@ - +using System.Diagnostics.CodeAnalysis; // ReSharper disable once CheckNamespace namespace Telegram.Bot.Types.InlineQueryResults; @@ -21,13 +21,13 @@ public class InlineQueryResultContact : InlineQueryResult /// Contact's phone number /// [JsonProperty(Required = Required.Always)] - public string PhoneNumber { get; } + public required string PhoneNumber { get; init; } /// /// Contact's first name /// [JsonProperty(Required = Required.Always)] - public string FirstName { get; } + public required string FirstName { get; init; } /// /// Optional. Contact's last name @@ -63,10 +63,18 @@ public class InlineQueryResultContact : InlineQueryResult /// Unique identifier of this result /// Contact's phone number /// Contact's first name + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public InlineQueryResultContact(string id, string phoneNumber, string firstName) : base(id) { PhoneNumber = phoneNumber; FirstName = firstName; } + + /// + /// Initializes a new inline query result + /// + public InlineQueryResultContact() + { } } diff --git a/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResultDocument.cs b/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResultDocument.cs index 2dd53a93d..cc09a34d1 100644 --- a/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResultDocument.cs +++ b/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResultDocument.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Types.Enums; // ReSharper disable once CheckNamespace @@ -22,7 +23,7 @@ public class InlineQueryResultDocument : InlineQueryResult /// Title for the result /// [JsonProperty(Required = Required.Always)] - public string Title { get; } + public required string Title { get; init; } /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] @@ -40,13 +41,13 @@ public class InlineQueryResultDocument : InlineQueryResult /// A valid URL for the file /// [JsonProperty(Required = Required.Always)] - public string DocumentUrl { get; } + public required string DocumentUrl { get; init; } /// /// Mime type of the content of the file, either “application/pdf” or “application/zip” /// [JsonProperty(Required = Required.Always)] - public string MimeType { get; } + public required string MimeType { get; init; } /// /// Optional. Short description of the result @@ -79,6 +80,8 @@ public class InlineQueryResultDocument : InlineQueryResult /// /// Mime type of the content of the file, either “application/pdf” or “application/zip” /// + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public InlineQueryResultDocument(string id, string documentUrl, string title, string mimeType) : base(id) { @@ -86,4 +89,10 @@ public InlineQueryResultDocument(string id, string documentUrl, string title, st Title = title; MimeType = mimeType; } + + /// + /// Initializes a new inline query result + /// + public InlineQueryResultDocument() + { } } diff --git a/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResultGame.cs b/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResultGame.cs index 747be7605..e55cf110a 100644 --- a/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResultGame.cs +++ b/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResultGame.cs @@ -1,4 +1,4 @@ - +using System.Diagnostics.CodeAnalysis; // ReSharper disable once CheckNamespace namespace Telegram.Bot.Types.InlineQueryResults; @@ -19,16 +19,24 @@ public class InlineQueryResultGame : InlineQueryResult /// Short name of the game /// [JsonProperty(Required = Required.Always)] - public string GameShortName { get; } + public required string GameShortName { get; init; } /// /// Initializes a new inline query result /// /// Unique identifier of this result /// Short name of the game + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public InlineQueryResultGame(string id, string gameShortName) : base(id) { GameShortName = gameShortName; } + + /// + /// Initializes a new inline query result + /// + public InlineQueryResultGame() + { } } diff --git a/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResultGif.cs b/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResultGif.cs index c7cba9940..43116bf8d 100644 --- a/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResultGif.cs +++ b/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResultGif.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Types.Enums; // ReSharper disable once CheckNamespace @@ -22,7 +23,7 @@ public class InlineQueryResultGif : InlineQueryResult /// A valid URL for the GIF file. File size must not exceed 1MB /// [JsonProperty(Required = Required.Always)] - public string GifUrl { get; } + public required string GifUrl { get; init; } /// /// Optional. Width of the GIF. @@ -46,7 +47,7 @@ public class InlineQueryResultGif : InlineQueryResult /// URL of the static (JPEG or GIF) or animated (MPEG4) thumbnail for the result /// [JsonProperty(Required = Required.Always)] - public string ThumbnailUrl { get; } + public required string ThumbnailUrl { get; init; } /// /// Optional. MIME type of the thumbnail, must be one of “image/jpeg”, “image/gif”, @@ -83,10 +84,18 @@ public class InlineQueryResultGif : InlineQueryResult /// Unique identifier of this result /// Width of the GIF /// Url of the thumbnail for the result. + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public InlineQueryResultGif(string id, string gifUrl, string thumbnailUrl) : base(id) { GifUrl = gifUrl; ThumbnailUrl = thumbnailUrl; } + + /// + /// Initializes a new inline query result + /// + public InlineQueryResultGif() + { } } diff --git a/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResultLocation.cs b/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResultLocation.cs index 7226b1307..7da6fd44d 100644 --- a/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResultLocation.cs +++ b/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResultLocation.cs @@ -1,4 +1,4 @@ - +using System.Diagnostics.CodeAnalysis; // ReSharper disable once CheckNamespace namespace Telegram.Bot.Types.InlineQueryResults; @@ -19,17 +19,17 @@ public class InlineQueryResultLocation : InlineQueryResult /// [JsonProperty(Required = Required.Always)] - public double Latitude { get; } + public required double Latitude { get; init; } /// [JsonProperty(Required = Required.Always)] - public double Longitude { get; } + public required double Longitude { get; init; } /// /// Location title /// [JsonProperty(Required = Required.Always)] - public string Title { get; } + public required string Title { get; init; } /// /// Optional. The radius of uncertainty for the location, measured in meters; 0-1500 @@ -80,6 +80,8 @@ public class InlineQueryResultLocation : InlineQueryResult /// Latitude of the location in degrees /// Longitude of the location in degrees /// Title of the result + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public InlineQueryResultLocation(string id, double latitude, double longitude, string title) : base(id) { @@ -87,4 +89,10 @@ public InlineQueryResultLocation(string id, double latitude, double longitude, s Longitude = longitude; Title = title; } + + /// + /// Initializes a new inline query result + /// + public InlineQueryResultLocation() + { } } diff --git a/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResultMpeg4Gif.cs b/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResultMpeg4Gif.cs index 2fb39947f..044db7a24 100644 --- a/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResultMpeg4Gif.cs +++ b/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResultMpeg4Gif.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Types.Enums; // ReSharper disable once CheckNamespace @@ -22,7 +23,7 @@ public class InlineQueryResultMpeg4Gif : InlineQueryResult /// A valid URL for the MP4 file. File size must not exceed 1MB /// [JsonProperty(Required = Required.Always)] - public string Mpeg4Url { get; } + public required string Mpeg4Url { get; init; } /// /// Optional. Video width @@ -46,7 +47,7 @@ public class InlineQueryResultMpeg4Gif : InlineQueryResult /// URL of the static (JPEG or GIF) or animated (MPEG4) thumbnail for the result /// [JsonProperty(Required = Required.Always)] - public string ThumbnailUrl { get; } + public required string ThumbnailUrl { get; init; } /// /// Optional. MIME type of the thumbnail, must be one of “image/jpeg”, “image/gif”, @@ -83,10 +84,18 @@ public class InlineQueryResultMpeg4Gif : InlineQueryResult /// Unique identifier of this result /// A valid URL for the MP4 file. File size must not exceed 1MB. /// Url of the thumbnail for the result. + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public InlineQueryResultMpeg4Gif(string id, string mpeg4Url, string thumbnailUrl) : base(id) { Mpeg4Url = mpeg4Url; ThumbnailUrl = thumbnailUrl; } + + /// + /// Initializes a new inline query result + /// + public InlineQueryResultMpeg4Gif() + { } } diff --git a/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResultPhoto.cs b/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResultPhoto.cs index 8af55ed21..49b72db4a 100644 --- a/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResultPhoto.cs +++ b/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResultPhoto.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Types.Enums; // ReSharper disable once CheckNamespace @@ -21,11 +22,11 @@ public class InlineQueryResultPhoto : InlineQueryResult /// A valid URL of the photo. Photo must be in jpeg format. Photo size must not exceed 5MB /// [JsonProperty(Required = Required.Always)] - public string PhotoUrl { get; } + public required string PhotoUrl { get; init; } /// [JsonProperty(Required = Required.Always)] - public string ThumbnailUrl { get; } + public required string ThumbnailUrl { get; init; } /// /// Optional. Width of the photo @@ -73,10 +74,18 @@ public class InlineQueryResultPhoto : InlineQueryResult /// Unique identifier of this result /// A valid URL of the photo. Photo size must not exceed 5MB. /// Optional. Url of the thumbnail for the result. + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public InlineQueryResultPhoto(string id, string photoUrl, string thumbnailUrl) : base(id) { PhotoUrl = photoUrl; ThumbnailUrl = thumbnailUrl; } + + /// + /// Initializes a new inline query representing a link to a photo + /// + public InlineQueryResultPhoto() + { } } diff --git a/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResultVenue.cs b/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResultVenue.cs index 654dd27fc..1e127702b 100644 --- a/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResultVenue.cs +++ b/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResultVenue.cs @@ -1,4 +1,4 @@ - +using System.Diagnostics.CodeAnalysis; // ReSharper disable once CheckNamespace namespace Telegram.Bot.Types.InlineQueryResults; @@ -19,23 +19,23 @@ public class InlineQueryResultVenue : InlineQueryResult /// [JsonProperty(Required = Required.Always)] - public double Latitude { get; } + public required double Latitude { get; init; } /// [JsonProperty(Required = Required.Always)] - public double Longitude { get; } + public required double Longitude { get; init; } /// /// Title of the venue /// [JsonProperty(Required = Required.Always)] - public string Title { get; } + public required string Title { get; init; } /// /// Address of the venue /// [JsonProperty(Required = Required.Always)] - public string Address { get; } + public required string Address { get; init; } /// /// Optional. Foursquare identifier of the venue if known @@ -87,6 +87,8 @@ public class InlineQueryResultVenue : InlineQueryResult /// Longitude of the location in degrees /// Title of the result /// Address of the venue + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public InlineQueryResultVenue( string id, double latitude, @@ -99,4 +101,10 @@ public class InlineQueryResultVenue : InlineQueryResult Title = title; Address = address; } + + /// + /// Initializes a new inline query result + /// + public InlineQueryResultVenue() + { } } diff --git a/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResultVideo.cs b/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResultVideo.cs index c0596a7ed..482bea227 100644 --- a/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResultVideo.cs +++ b/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResultVideo.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Types.Enums; // ReSharper disable once CheckNamespace @@ -26,25 +27,25 @@ public class InlineQueryResultVideo : InlineQueryResult /// A valid URL for the embedded video player or video file /// [JsonProperty(Required = Required.Always)] - public string VideoUrl { get; } + public required string VideoUrl { get; init; } /// /// Mime type of the content of video url, “text/html” or “video/mp4” /// [JsonProperty(Required = Required.Always)] - public string MimeType { get; } + public required string MimeType { get; init; } /// /// URL of the thumbnail (jpeg only) for the video /// [JsonProperty(Required = Required.Always)] - public string ThumbnailUrl { get; } + public required string ThumbnailUrl { get; init; } /// /// Title for the result /// [JsonProperty(Required = Required.Always)] - public string Title { get; } + public required string Title { get; init; } /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] @@ -102,6 +103,8 @@ public class InlineQueryResultVideo : InlineQueryResult /// is used to send an HTML-page as a result /// (e.g., a YouTube video). /// + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public InlineQueryResultVideo( string id, string videoUrl, @@ -115,4 +118,10 @@ public class InlineQueryResultVideo : InlineQueryResult Title = title; InputMessageContent = inputMessageContent; } + + /// + /// Initializes a new inline query result + /// + public InlineQueryResultVideo() + { } } diff --git a/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResultVoice.cs b/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResultVoice.cs index ba8dec565..4e8655449 100644 --- a/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResultVoice.cs +++ b/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResultVoice.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Types.Enums; // ReSharper disable once CheckNamespace @@ -22,13 +23,13 @@ public class InlineQueryResultVoice : InlineQueryResult /// A valid URL for the voice recording /// [JsonProperty(Required = Required.Always)] - public string VoiceUrl { get; } + public required string VoiceUrl { get; init; } /// /// Recording title /// [JsonProperty(Required = Required.Always)] - public string Title { get; } + public required string Title { get; init; } /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] @@ -58,10 +59,18 @@ public class InlineQueryResultVoice : InlineQueryResult /// Unique identifier of this result /// A valid URL for the voice recording /// Title of the result + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public InlineQueryResultVoice(string id, string voiceUrl, string title) : base(id) { VoiceUrl = voiceUrl; Title = title; } + + /// + /// Initializes a new inline query result + /// + public InlineQueryResultVoice() + { } } diff --git a/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResultsButton.cs b/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResultsButton.cs index bf6d554da..214bc4b33 100644 --- a/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResultsButton.cs +++ b/src/Telegram.Bot/Types/InlineQueryResults/InlineQueryResult/InlineQueryResultsButton.cs @@ -12,7 +12,7 @@ public class InlineQueryResultsButton /// Label text on the button /// [JsonProperty(Required = Required.Always)] - public string Text { get; } + public required string Text { get; init; } /// /// Optional. Description of the Web App that will be launched when the user presses @@ -49,4 +49,10 @@ public InlineQueryResultsButton(string text) { Text = text; } + + /// + /// Initializes a new object + /// + public InlineQueryResultsButton() + { } } diff --git a/src/Telegram.Bot/Types/InlineQueryResults/InputMessageContent/InputContactMessageContent.cs b/src/Telegram.Bot/Types/InlineQueryResults/InputMessageContent/InputContactMessageContent.cs index ac6833554..354d971ab 100644 --- a/src/Telegram.Bot/Types/InlineQueryResults/InputMessageContent/InputContactMessageContent.cs +++ b/src/Telegram.Bot/Types/InlineQueryResults/InputMessageContent/InputContactMessageContent.cs @@ -1,4 +1,4 @@ - +using System.Diagnostics.CodeAnalysis; // ReSharper disable once CheckNamespace namespace Telegram.Bot.Types.InlineQueryResults; @@ -13,13 +13,13 @@ public class InputContactMessageContent : InputMessageContent /// Contact's phone number /// [JsonProperty(Required = Required.Always)] - public string PhoneNumber { get; } + public required string PhoneNumber { get; init; } /// /// Contact's first name /// [JsonProperty(Required = Required.Always)] - public string FirstName { get; } + public required string FirstName { get; init; } /// /// Optional. Contact's last name @@ -38,9 +38,17 @@ public class InputContactMessageContent : InputMessageContent /// /// The phone number of the contact /// The first name of the contact + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public InputContactMessageContent(string phoneNumber, string firstName) { PhoneNumber = phoneNumber; FirstName = firstName; } + + /// + /// Initializes a new input contact message content + /// + public InputContactMessageContent() + { } } diff --git a/src/Telegram.Bot/Types/InlineQueryResults/InputMessageContent/InputInvoiceMessageContent.cs b/src/Telegram.Bot/Types/InlineQueryResults/InputMessageContent/InputInvoiceMessageContent.cs index 6520b811a..ee0915a85 100644 --- a/src/Telegram.Bot/Types/InlineQueryResults/InputMessageContent/InputInvoiceMessageContent.cs +++ b/src/Telegram.Bot/Types/InlineQueryResults/InputMessageContent/InputInvoiceMessageContent.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Types.Payments; // ReSharper disable once CheckNamespace @@ -15,40 +16,40 @@ public class InputInvoiceMessageContent : InputMessageContent /// Product name, 1-32 characters /// [JsonProperty(Required = Required.Always)] - public string Title { get; } + public required string Title { get; init; } /// /// Product description, 1-255 characters /// [JsonProperty(Required = Required.Always)] - public string Description { get; } + public required string Description { get; init; } /// /// Bot-defined invoice payload, 1-128 bytes. This will not be displayed to the user, /// use for your internal processes. /// [JsonProperty(Required = Required.Always)] - public string Payload { get; } + public required string Payload { get; init; } /// /// Payment provider token, obtained via @BotFather /// [JsonProperty(Required = Required.Always)] - public string ProviderToken { get; } + public required string ProviderToken { get; init; } /// /// Three-letter ISO 4217 currency code, see /// more on currencies /// [JsonProperty(Required = Required.Always)] - public string Currency { get; } + public required string Currency { get; init; } /// /// Price breakdown, a list of components (e.g. product price, tax, discount, delivery cost, /// delivery tax, bonus, etc.) /// [JsonProperty(Required = Required.Always)] - public IEnumerable Prices { get; } + public required IEnumerable Prices { get; init; } /// /// Optional. The maximum accepted amount for tips in the smallest units of the currency @@ -158,6 +159,8 @@ public class InputInvoiceMessageContent : InputMessageContent /// Price breakdown, a list of components (e.g. product price, tax, discount, delivery cost, /// delivery tax, bonus, etc.) /// + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public InputInvoiceMessageContent( string title, string description, @@ -173,4 +176,10 @@ public class InputInvoiceMessageContent : InputMessageContent Currency = currency; Prices = prices; } + + /// + /// Initializes a new input message content + /// + public InputInvoiceMessageContent() + { } } diff --git a/src/Telegram.Bot/Types/InlineQueryResults/InputMessageContent/InputLocationMessageContent.cs b/src/Telegram.Bot/Types/InlineQueryResults/InputMessageContent/InputLocationMessageContent.cs index 0174dbfbe..f3aa2f83a 100644 --- a/src/Telegram.Bot/Types/InlineQueryResults/InputMessageContent/InputLocationMessageContent.cs +++ b/src/Telegram.Bot/Types/InlineQueryResults/InputMessageContent/InputLocationMessageContent.cs @@ -1,4 +1,4 @@ - +using System.Diagnostics.CodeAnalysis; // ReSharper disable once CheckNamespace namespace Telegram.Bot.Types.InlineQueryResults; @@ -14,13 +14,13 @@ public class InputLocationMessageContent : InputMessageContent /// Latitude of the location in degrees /// [JsonProperty(Required = Required.Always)] - public double Latitude { get; } + public required double Latitude { get; init; } /// /// Longitude of the location in degrees /// [JsonProperty(Required = Required.Always)] - public double Longitude { get; } + public required double Longitude { get; init; } /// /// Optional. The radius of uncertainty for the location, measured in meters; 0-1500 @@ -52,9 +52,17 @@ public class InputLocationMessageContent : InputMessageContent /// /// The latitude of the location /// The longitude of the location + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public InputLocationMessageContent(double latitude, double longitude) { Latitude = latitude; Longitude = longitude; } + + /// + /// Initializes a new input location message content + /// + public InputLocationMessageContent() + { } } diff --git a/src/Telegram.Bot/Types/InlineQueryResults/InputMessageContent/InputMessageContent.cs b/src/Telegram.Bot/Types/InlineQueryResults/InputMessageContent/InputMessageContent.cs index ddf99ad34..c82e75490 100644 --- a/src/Telegram.Bot/Types/InlineQueryResults/InputMessageContent/InputMessageContent.cs +++ b/src/Telegram.Bot/Types/InlineQueryResults/InputMessageContent/InputMessageContent.cs @@ -1,5 +1,3 @@ - - // ReSharper disable once CheckNamespace namespace Telegram.Bot.Types.InlineQueryResults; @@ -8,4 +6,4 @@ namespace Telegram.Bot.Types.InlineQueryResults; /// inline query. /// [JsonObject(NamingStrategyType = typeof(SnakeCaseNamingStrategy))] -public abstract class InputMessageContent { } +public abstract class InputMessageContent; diff --git a/src/Telegram.Bot/Types/InlineQueryResults/InputMessageContent/InputTextMessageContent.cs b/src/Telegram.Bot/Types/InlineQueryResults/InputMessageContent/InputTextMessageContent.cs index 0cba239fd..919d2fb5b 100644 --- a/src/Telegram.Bot/Types/InlineQueryResults/InputMessageContent/InputTextMessageContent.cs +++ b/src/Telegram.Bot/Types/InlineQueryResults/InputMessageContent/InputTextMessageContent.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Types.Enums; // ReSharper disable once CheckNamespace @@ -14,7 +15,7 @@ public class InputTextMessageContent : InputMessageContent /// Text of the message to be sent, 1-4096 characters /// [JsonProperty(Required = Required.Always)] - public string MessageText { get; } + public required string MessageText { get; init; } /// /// Optional. Mode for @@ -32,17 +33,25 @@ public class InputTextMessageContent : InputMessageContent public MessageEntity[]? Entities { get; set; } // ToDo: add test /// - /// Optional. Disables link previews for links in the sent message + /// Optional. Link preview generation options for the message /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public bool? DisableWebPagePreview { get; set; } + public LinkPreviewOptions? LinkPreviewOptions { get; set; } /// /// Initializes a new input text message content /// /// The text of the message + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public InputTextMessageContent(string messageText) { MessageText = messageText; } + + /// + /// Initializes a new input text message content + /// + public InputTextMessageContent() + { } } diff --git a/src/Telegram.Bot/Types/InlineQueryResults/InputMessageContent/InputVenueMessageContent.cs b/src/Telegram.Bot/Types/InlineQueryResults/InputMessageContent/InputVenueMessageContent.cs index e36f4860f..3f3f86954 100644 --- a/src/Telegram.Bot/Types/InlineQueryResults/InputMessageContent/InputVenueMessageContent.cs +++ b/src/Telegram.Bot/Types/InlineQueryResults/InputMessageContent/InputVenueMessageContent.cs @@ -1,4 +1,4 @@ - +using System.Diagnostics.CodeAnalysis; // ReSharper disable once CheckNamespace namespace Telegram.Bot.Types.InlineQueryResults; @@ -14,25 +14,25 @@ public class InputVenueMessageContent : InputMessageContent /// Latitude of the venue in degrees /// [JsonProperty(Required = Required.Always)] - public double Latitude { get; } + public required double Latitude { get; init; } /// /// Longitude of the venue in degrees /// [JsonProperty(Required = Required.Always)] - public double Longitude { get; } + public required double Longitude { get; init; } /// /// Name of the venue /// [JsonProperty(Required = Required.Always)] - public string Title { get; } + public required string Title { get; init; } /// /// Address of the venue /// [JsonProperty(Required = Required.Always)] - public string Address { get; } + public required string Address { get; init; } /// /// Optional. Foursquare identifier of the venue, if known @@ -67,6 +67,8 @@ public class InputVenueMessageContent : InputMessageContent /// The address of the venue /// The latitude of the venue /// The longitude of the venue + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public InputVenueMessageContent(string title, string address, double latitude, double longitude) { Title = title; @@ -74,4 +76,10 @@ public InputVenueMessageContent(string title, string address, double latitude, d Latitude = latitude; Longitude = longitude; } + + /// + /// Initializes a new inline query result + /// + public InputVenueMessageContent() + { } } diff --git a/src/Telegram.Bot/Types/InputFiles/InputFile.cs b/src/Telegram.Bot/Types/InputFiles/InputFile.cs index 51e612a9b..b8080b472 100644 --- a/src/Telegram.Bot/Types/InputFiles/InputFile.cs +++ b/src/Telegram.Bot/Types/InputFiles/InputFile.cs @@ -26,8 +26,8 @@ public abstract class InputFile /// An instance of a class that implements public static InputFile FromString(string urlOrFileId) => Uri.TryCreate(urlOrFileId, UriKind.Absolute, out var url) - ? new InputFileUrl(url) - : new InputFileId(urlOrFileId); + ? FromUri(url) + : FromFileId(urlOrFileId); /// /// Creates an from an instance diff --git a/src/Telegram.Bot/Types/InputFiles/InputFileId.cs b/src/Telegram.Bot/Types/InputFiles/InputFileId.cs index 658986544..67c9aacce 100644 --- a/src/Telegram.Bot/Types/InputFiles/InputFileId.cs +++ b/src/Telegram.Bot/Types/InputFiles/InputFileId.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Types.Enums; // ReSharper disable once CheckNamespace @@ -14,11 +15,19 @@ public class InputFileId : InputFile /// /// A file identifier /// - public string Id { get; } + public required string Id { get; init; } + + /// + /// This object represents a file that is already stored somewhere on the Telegram servers + /// + public InputFileId() + {} /// /// This object represents a file that is already stored somewhere on the Telegram servers /// /// A file identifier - public InputFileId(string id) => Id = id; + [SetsRequiredMembers] + public InputFileId(string id) + => Id = id; } diff --git a/src/Telegram.Bot/Types/InputFiles/InputFileStream.cs b/src/Telegram.Bot/Types/InputFiles/InputFileStream.cs index 4c065af4d..fc3f1cbfb 100644 --- a/src/Telegram.Bot/Types/InputFiles/InputFileStream.cs +++ b/src/Telegram.Bot/Types/InputFiles/InputFileStream.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using System.IO; using Telegram.Bot.Types.Enums; @@ -16,7 +17,7 @@ public class InputFileStream : InputFile /// /// File content to upload /// - public Stream Content { get; } + public required Stream Content { get; init; } /// /// Name of a file to upload using multipart/form-data @@ -29,6 +30,14 @@ public class InputFileStream : InputFile /// /// File content to upload /// Name of a file to upload using multipart/form-data + [SetsRequiredMembers] public InputFileStream(Stream content, string? fileName = default) => (Content, FileName) = (content, fileName); + + /// + /// This object represents the contents of a file to be uploaded. Must be posted using multipart/form-data + /// in the usual way that files are uploaded via the browser. + /// + public InputFileStream() + { } } diff --git a/src/Telegram.Bot/Types/InputFiles/InputFileUrl.cs b/src/Telegram.Bot/Types/InputFiles/InputFileUrl.cs index b2f078fdd..22d6b0a0d 100644 --- a/src/Telegram.Bot/Types/InputFiles/InputFileUrl.cs +++ b/src/Telegram.Bot/Types/InputFiles/InputFileUrl.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Types.Enums; // ReSharper disable once CheckNamespace @@ -14,17 +15,27 @@ public class InputFileUrl : InputFile /// /// HTTP URL for the file to be sent /// - public Uri Url { get; } + public required Uri Url { get; init; } /// /// This object represents an HTTP URL for the file to be sent /// /// HTTP URL for the file to be sent - public InputFileUrl(string url) => Url = new(url); + [SetsRequiredMembers] + public InputFileUrl(string url) + => Url = new(url); /// /// This object represents an HTTP URL for the file to be sent /// /// HTTP URL for the file to be sent - public InputFileUrl(Uri uri) => Url = uri; + [SetsRequiredMembers] + public InputFileUrl(Uri uri) + => Url = uri; + + /// + /// This object represents an HTTP URL for the file to be sent + /// + public InputFileUrl() + { } } diff --git a/src/Telegram.Bot/Types/InputFiles/InputMedia/IAlbumInputMedia.cs b/src/Telegram.Bot/Types/InputFiles/InputMedia/IAlbumInputMedia.cs index 4dc00df7d..232bccaf6 100644 --- a/src/Telegram.Bot/Types/InputFiles/InputMedia/IAlbumInputMedia.cs +++ b/src/Telegram.Bot/Types/InputFiles/InputMedia/IAlbumInputMedia.cs @@ -4,5 +4,4 @@ namespace Telegram.Bot.Types; /// /// A marker for input media types that can be used in sendMediaGroup method. /// -public interface IAlbumInputMedia -{ } +public interface IAlbumInputMedia; diff --git a/src/Telegram.Bot/Types/InputFiles/InputMedia/InputMedia.cs b/src/Telegram.Bot/Types/InputFiles/InputMedia/InputMedia.cs index 7e032b79a..bae459a8b 100644 --- a/src/Telegram.Bot/Types/InputFiles/InputMedia/InputMedia.cs +++ b/src/Telegram.Bot/Types/InputFiles/InputMedia/InputMedia.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Types.Enums; // ReSharper disable once CheckNamespace @@ -21,7 +22,7 @@ public abstract class InputMedia /// to upload a new one using multipart/form-data under <file_attach_name%gt; name. /// [JsonProperty(Required = Required.Always)] - public InputFile Media { get; } + public required InputFile Media { get; init; } /// /// Optional. Caption of the photo to be sent, 0-1024 characters @@ -46,5 +47,13 @@ public abstract class InputMedia /// Initialize an object /// /// File to send + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] protected InputMedia(InputFile media) => Media = media; + + /// + /// Initialize an object + /// + protected InputMedia() + { } } diff --git a/src/Telegram.Bot/Types/InputFiles/InputMedia/InputMediaAnimation.cs b/src/Telegram.Bot/Types/InputFiles/InputMedia/InputMediaAnimation.cs index a4965630e..94cae62a5 100644 --- a/src/Telegram.Bot/Types/InputFiles/InputMedia/InputMediaAnimation.cs +++ b/src/Telegram.Bot/Types/InputFiles/InputMedia/InputMediaAnimation.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Types.Enums; // ReSharper disable once CheckNamespace @@ -47,7 +48,15 @@ public class InputMediaAnimation : /// Initializes a new animation media to send with an /// /// File to send + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public InputMediaAnimation(InputFile media) : base(media) { } + + /// + /// Initializes a new animation media to send with an + /// + public InputMediaAnimation() + { } } diff --git a/src/Telegram.Bot/Types/InputFiles/InputMedia/InputMediaAudio.cs b/src/Telegram.Bot/Types/InputFiles/InputMedia/InputMediaAudio.cs index 00bade1b2..13c6ca3f7 100644 --- a/src/Telegram.Bot/Types/InputFiles/InputMedia/InputMediaAudio.cs +++ b/src/Telegram.Bot/Types/InputFiles/InputMedia/InputMediaAudio.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Types.Enums; // ReSharper disable once CheckNamespace @@ -42,7 +43,15 @@ public class InputMediaAudio : /// Initializes a new audio media to send with an /// /// File to send + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public InputMediaAudio(InputFile media) : base(media) { } + + /// + /// Initializes a new audio media to send with an + /// + public InputMediaAudio() + { } } diff --git a/src/Telegram.Bot/Types/InputFiles/InputMedia/InputMediaDocument.cs b/src/Telegram.Bot/Types/InputFiles/InputMedia/InputMediaDocument.cs index c94ac9761..60ca90685 100644 --- a/src/Telegram.Bot/Types/InputFiles/InputMedia/InputMediaDocument.cs +++ b/src/Telegram.Bot/Types/InputFiles/InputMedia/InputMediaDocument.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Types.Enums; // ReSharper disable once CheckNamespace @@ -31,7 +32,15 @@ public class InputMediaDocument : /// Initializes a new document media to send with an /// /// File to send + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public InputMediaDocument(InputFile media) : base(media) { } + + /// + /// Initializes a new document media to send with an + /// + public InputMediaDocument() + { } } diff --git a/src/Telegram.Bot/Types/InputFiles/InputMedia/InputMediaPhoto.cs b/src/Telegram.Bot/Types/InputFiles/InputMedia/InputMediaPhoto.cs index c31ec9a59..b96b707dc 100644 --- a/src/Telegram.Bot/Types/InputFiles/InputMedia/InputMediaPhoto.cs +++ b/src/Telegram.Bot/Types/InputFiles/InputMedia/InputMediaPhoto.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Types.Enums; // ReSharper disable once CheckNamespace @@ -24,7 +25,15 @@ public class InputMediaPhoto : /// Initializes a new photo media to send with an /// /// File to send + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public InputMediaPhoto(InputFile media) : base(media) { } + + /// + /// Initializes a new photo media to send with an + /// + public InputMediaPhoto() + { } } diff --git a/src/Telegram.Bot/Types/InputFiles/InputMedia/InputMediaVideo.cs b/src/Telegram.Bot/Types/InputFiles/InputMedia/InputMediaVideo.cs index 670304451..d77f2b2e2 100644 --- a/src/Telegram.Bot/Types/InputFiles/InputMedia/InputMediaVideo.cs +++ b/src/Telegram.Bot/Types/InputFiles/InputMedia/InputMediaVideo.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Types.Enums; // ReSharper disable once CheckNamespace @@ -54,7 +55,15 @@ public class InputMediaVideo : /// Initializes a new video media to send with an /// /// File to send + [SetsRequiredMembers] + [Obsolete("Use parameterless constructor with required properties")] public InputMediaVideo(InputFile media) : base(media) { } + + /// + /// Initializes a new video media to send with an + /// + public InputMediaVideo() + { } } diff --git a/src/Telegram.Bot/Types/InputSticker.cs b/src/Telegram.Bot/Types/InputSticker.cs index aa893e57b..4da5f8cf3 100644 --- a/src/Telegram.Bot/Types/InputSticker.cs +++ b/src/Telegram.Bot/Types/InputSticker.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using Telegram.Bot.Types.Enums; namespace Telegram.Bot.Types; @@ -19,13 +20,13 @@ public class InputSticker /// If you are using a , then the property is required. /// [JsonProperty(Required = Required.Always)] - public InputFile Sticker { get; } + public required InputFile Sticker { get; init; } /// /// List of 1-20 emoji associated with the sticker /// [JsonProperty(Required = Required.Always)] - public IEnumerable EmojiList { get; } + public required IEnumerable EmojiList { get; init; } /// /// Optional. Position where the mask should be placed on faces. @@ -55,9 +56,16 @@ public class InputSticker /// /// List of 1-20 emoji associated with the sticker /// + [SetsRequiredMembers] public InputSticker(InputFile sticker, IEnumerable emojiList) { Sticker = sticker; EmojiList = emojiList; } + + /// + /// Initializes a new input sticker to create or add sticker sets + /// + public InputSticker() + { } } diff --git a/src/Telegram.Bot/Types/LinkPreviewOptions.cs b/src/Telegram.Bot/Types/LinkPreviewOptions.cs new file mode 100644 index 000000000..565ff812a --- /dev/null +++ b/src/Telegram.Bot/Types/LinkPreviewOptions.cs @@ -0,0 +1,42 @@ +namespace Telegram.Bot.Types; + +/// +/// Describes the options used for link preview generation. +/// +[JsonObject(MemberSerialization.OptIn, NamingStrategyType = typeof(SnakeCaseNamingStrategy))] +public class LinkPreviewOptions +{ + /// + /// Optional. , if the link preview is disabled + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public bool? IsDisabled { get; set; } + + /// + /// Optional. URL to use for the link preview. If empty, then the first URL found in the message text + /// will be used + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public string? Url { get; set; } + + /// + /// Optional. , if the media in the link preview is supposed to be shrunk; + /// ignored if the URL isn't explicitly specified or media size change isn't supported for the preview + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public bool? PreferSmallMedia { get; set; } + + /// + /// Optional. , if the media in the link preview is supposed to be enlarged; + /// ignored if the URL isn't explicitly specified or media size change isn't supported for the preview + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public bool? PreferLargeMedia { get; set; } + + /// + /// Optional. , if the link preview must be shown above the message text; + /// otherwise, the link preview will be shown below the message text + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public bool? ShowAboveText { get; set; } +} diff --git a/src/Telegram.Bot/Types/MaybeInaccessibleMessage.cs b/src/Telegram.Bot/Types/MaybeInaccessibleMessage.cs new file mode 100644 index 000000000..2eaeb4c58 --- /dev/null +++ b/src/Telegram.Bot/Types/MaybeInaccessibleMessage.cs @@ -0,0 +1,14 @@ +using Telegram.Bot.Converters; + +namespace Telegram.Bot.Types; + +/// +/// This object describes a message that can be inaccessible to the bot. It can be one of +/// +/// +/// +/// +/// +[JsonObject(MemberSerialization.OptIn, NamingStrategyType = typeof(SnakeCaseNamingStrategy))] +[JsonConverter(typeof(MaybeInaccessibleMessageConverter))] +public abstract class MaybeInaccessibleMessage; diff --git a/src/Telegram.Bot/Types/Message.cs b/src/Telegram.Bot/Types/Message.cs index 4602fd24c..17b5659db 100644 --- a/src/Telegram.Bot/Types/Message.cs +++ b/src/Telegram.Bot/Types/Message.cs @@ -12,7 +12,7 @@ namespace Telegram.Bot.Types; /// This object represents a message. /// [JsonObject(MemberSerialization.OptIn, NamingStrategyType = typeof(SnakeCaseNamingStrategy))] -public class Message +public class Message : MaybeInaccessibleMessage { /// /// Unique message identifier inside this chat @@ -40,6 +40,12 @@ public class Message [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] public Chat? SenderChat { get; set; } + /// + /// Optional. If the sender of the message boosted the chat, the number of boosts added by the user + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public int? SenderBoostCount { get; set; } + /// /// Date the message was sent /// @@ -54,10 +60,10 @@ public class Message public Chat Chat { get; set; } = default!; /// - /// Optional. For forwarded messages, sender of the original message + ///Optional. Information about the original message for forwarded messages /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public User? ForwardFrom { get; set; } + public MessageOrigin? ForwardOrigin { get; set; } /// /// Optional. , if the message is sent to a forum topic @@ -66,51 +72,37 @@ public class Message public bool? IsTopicMessage { get; set; } /// - /// Optional. For messages forwarded from channels or from anonymous administrators, information about the - /// original sender chat - /// - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public Chat? ForwardFromChat { get; set; } - - /// - /// Optional. For messages forwarded from channels, identifier of the original message in the channel - /// - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public int? ForwardFromMessageId { get; set; } - - /// - /// Optional. For messages forwarded from channels, signature of the post author if present + /// Optional. , if the message is a channel post that was automatically forwarded to the connected + /// discussion group /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public string? ForwardSignature { get; set; } + public bool? IsAutomaticForward { get; set; } /// - /// Optional. Sender's name for messages forwarded from users who disallow adding a link to their account in - /// forwarded messages + /// Optional. For replies, the original message. Note that the object in this field + /// will not contain further fields even if it itself is a reply. /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public string? ForwardSenderName { get; set; } + public Message? ReplyToMessage { get; set; } /// - /// Optional. For forwarded messages, date the original message was sent + /// Optional. Information about the message that is being replied to, which may come from + /// another chat or forum topic /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - [JsonConverter(typeof(UnixDateTimeConverter))] - public DateTime? ForwardDate { get; set; } + public ExternalReplyInfo? ExternalReply { get; set; } /// - /// Optional. , if the message is a channel post that was automatically forwarded to the connected - /// discussion group + /// Optional. For replies that quote part of the original message, the quoted part of the message /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public bool? IsAutomaticForward { get; set; } + public TextQuote? Quote { get; set; } /// - /// Optional. For replies, the original message. Note that the object in this field - /// will not contain further fields even if it itself is a reply. + /// Optional. For replies to a story, the original story /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public Message? ReplyToMessage { get; set; } + public Story? ReplyToStory { get; set; } /// /// Optional. Bot through which the message was sent @@ -169,6 +161,13 @@ public class Message ? default : Entities?.Select(entity => Text.Substring(entity.Offset, entity.Length)); + /// + /// Optional. Options used for link preview generation for the message, if it is a text message + /// and link preview options were changed + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public LinkPreviewOptions? LinkPreviewOptions { get; set; } + /// /// Optional. Message is an animation, information about the animation. For backward compatibility, when this /// field is set, the field will also be set @@ -364,11 +363,11 @@ public class Message public long? MigrateFromChatId { get; set; } /// - /// Optional. Specified message was pinned. Note that the Message object in this field will not contain - /// further fields even if it is itself a reply. + /// Optional. Specified message was pinned. Note that the object in this field + /// will not contain further fields even if it itself is a reply. /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public Message? PinnedMessage { get; set; } + public MaybeInaccessibleMessage? PinnedMessage { get; set; } /// /// Optional. Message is an invoice for a @@ -387,7 +386,7 @@ public class Message /// Optional. Service message: a user was shared with the bot /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public UserShared? UserShared { get; set; } + public UsersShared? UsersShared { get; set; } /// /// Optional. Service message: a chat was shared with the bot @@ -420,6 +419,12 @@ public class Message [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] public ProximityAlertTriggered? ProximityAlertTriggered { get; set; } + /// + /// Optional. Service message: user boosted the chat + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public ChatBoostAdded? BoostAdded { get; set; } + /// /// Optional. Service message: forum topic created /// @@ -456,6 +461,30 @@ public class Message [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] public GeneralForumTopicUnhidden? GeneralForumTopicUnhidden { get; set; } + /// + /// Optional. Service message: a scheduled giveaway was created + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public GiveawayCreated? GiveawayCreated { get; set; } + + /// + /// Optional. The message is a scheduled giveaway message + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public Giveaway? Giveaway { get; set; } + + /// + /// Optional. A giveaway with public winners was completed + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public GiveawayWinners? GiveawayWinners { get; set; } + + /// + /// Optional. Service message: a giveaway without public winners was completed + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public GiveawayCompleted? GiveawayCompleted { get; set; } + /// /// Optional. Service message: video chat scheduled /// @@ -502,53 +531,58 @@ public class Message public MessageType Type => this switch { - { Text: { } } => MessageType.Text, - { Photo: { } } => MessageType.Photo, - { Audio: { } } => MessageType.Audio, - { Video: { } } => MessageType.Video, - { Voice: { } } => MessageType.Voice, - { Animation: { } } => MessageType.Animation, - { Document: { } } => MessageType.Document, - { Sticker: { } } => MessageType.Sticker, - { Story: { } } => MessageType.Story, - // Venue also contains Location - { Location: { } } and { Venue: null } => MessageType.Location, - { Venue: { } } => MessageType.Venue, - { Contact: { } } => MessageType.Contact, - { Game: { } } => MessageType.Game, - { VideoNote: { } } => MessageType.VideoNote, - { Invoice: { } } => MessageType.Invoice, - { SuccessfulPayment: { } } => MessageType.SuccessfulPayment, - { ConnectedWebsite: { } } => MessageType.WebsiteConnected, - { NewChatMembers: { Length: > 0 } } => MessageType.ChatMembersAdded, - { LeftChatMember: { } } => MessageType.ChatMemberLeft, - { NewChatTitle: { } } => MessageType.ChatTitleChanged, - { NewChatPhoto: { } } => MessageType.ChatPhotoChanged, - { PinnedMessage: { } } => MessageType.MessagePinned, - { DeleteChatPhoto: { } } => MessageType.ChatPhotoDeleted, - { GroupChatCreated: { } } => MessageType.GroupCreated, - { SupergroupChatCreated: { } } => MessageType.SupergroupCreated, - { ChannelChatCreated: { } } => MessageType.ChannelCreated, - { MigrateToChatId: { } } => MessageType.MigratedToSupergroup, - { MigrateFromChatId: { } } => MessageType.MigratedFromGroup, - { Poll: { } } => MessageType.Poll, - { Dice: { } } => MessageType.Dice, - { MessageAutoDeleteTimerChanged: { } } => MessageType.MessageAutoDeleteTimerChanged, - { ProximityAlertTriggered: { } } => MessageType.ProximityAlertTriggered, - { VideoChatScheduled: { } } => MessageType.VideoChatScheduled, - { VideoChatStarted: { } } => MessageType.VideoChatStarted, - { VideoChatEnded: { } } => MessageType.VideoChatEnded, - { VideoChatParticipantsInvited: { } } => MessageType.VideoChatParticipantsInvited, - { WebAppData: { } } => MessageType.WebAppData, - { ForumTopicCreated: { } } => MessageType.ForumTopicCreated, - { ForumTopicEdited: { } } => MessageType.ForumTopicEdited, - { ForumTopicClosed: { } } => MessageType.ForumTopicClosed, - { ForumTopicReopened: { } } => MessageType.ForumTopicReopened, - { GeneralForumTopicHidden: { } } => MessageType.GeneralForumTopicHidden, - { GeneralForumTopicUnhidden: { } } => MessageType.GeneralForumTopicUnhidden, - { WriteAccessAllowed: { } } => MessageType.WriteAccessAllowed, - { UserShared: { } } => MessageType.UserShared, - { ChatShared: { } } => MessageType.ChatShared, - _ => MessageType.Unknown + { Text: not null } => MessageType.Text, + { Animation: not null } => MessageType.Animation, + { Audio: not null } => MessageType.Audio, + { Document: not null } => MessageType.Document, + { Photo: not null } => MessageType.Photo, + { Sticker: not null } => MessageType.Sticker, + { Story: not null } => MessageType.Story, + { Video: not null } => MessageType.Video, + { VideoNote: not null } => MessageType.VideoNote, + { Voice: not null } => MessageType.Voice, + { Contact: not null } => MessageType.Contact, + { Dice: not null } => MessageType.Dice, + { Game: not null } => MessageType.Game, + { Poll: not null } => MessageType.Poll, + { Venue: not null } => MessageType.Venue, + { Location: not null } and { Venue: null } => MessageType.Location, + { NewChatMembers.Length: > 0 } => MessageType.NewChatMembers, + { LeftChatMember: not null } => MessageType.LeftChatMember, + { NewChatTitle: not null } => MessageType.NewChatTitle, + { NewChatPhoto: not null } => MessageType.NewChatPhoto, + { DeleteChatPhoto: not null } => MessageType.DeleteChatPhoto, + { GroupChatCreated: not null } => MessageType.GroupChatCreated, + { SupergroupChatCreated: not null } => MessageType.SupergroupChatCreated, + { ChannelChatCreated: not null } => MessageType.ChannelChatCreated, + { MessageAutoDeleteTimerChanged: not null } => MessageType.MessageAutoDeleteTimerChanged, + { MigrateToChatId: not null } => MessageType.MigrateToChatId, + { MigrateFromChatId: not null } => MessageType.MigrateFromChatId, + { PinnedMessage: not null } => MessageType.PinnedMessage, + { Invoice: not null } => MessageType.Invoice, + { SuccessfulPayment: not null } => MessageType.SuccessfulPayment, + { UsersShared: not null } => MessageType.UsersShared, + { ChatShared: not null } => MessageType.ChatShared, + { ConnectedWebsite: not null } => MessageType.ConnectedWebsite, + { WriteAccessAllowed: not null } => MessageType.WriteAccessAllowed, + { PassportData: not null } => MessageType.PassportData, + { ProximityAlertTriggered: not null } => MessageType.ProximityAlertTriggered, + { BoostAdded: not null } => MessageType.BoostAdded, + { ForumTopicCreated: not null } => MessageType.ForumTopicCreated, + { ForumTopicEdited: not null } => MessageType.ForumTopicEdited, + { ForumTopicClosed: not null } => MessageType.ForumTopicClosed, + { ForumTopicReopened: not null } => MessageType.ForumTopicReopened, + { GeneralForumTopicHidden: not null } => MessageType.GeneralForumTopicHidden, + { GeneralForumTopicUnhidden: not null } => MessageType.GeneralForumTopicUnhidden, + { GiveawayCreated: not null } => MessageType.GiveawayCreated, + { Giveaway: not null } => MessageType.Giveaway, + { GiveawayWinners: not null } => MessageType.GiveawayWinners, + { GiveawayCompleted: not null } => MessageType.GiveawayCompleted, + { VideoChatScheduled: not null } => MessageType.VideoChatScheduled, + { VideoChatStarted: not null } => MessageType.VideoChatStarted, + { VideoChatEnded: not null } => MessageType.VideoChatEnded, + { VideoChatParticipantsInvited: not null } => MessageType.VideoChatParticipantsInvited, + { WebAppData: not null } => MessageType.WebAppData, + _ => MessageType.Unknown }; } diff --git a/src/Telegram.Bot/Types/MessageOrigin.cs b/src/Telegram.Bot/Types/MessageOrigin.cs new file mode 100644 index 000000000..dd401c22c --- /dev/null +++ b/src/Telegram.Bot/Types/MessageOrigin.cs @@ -0,0 +1,143 @@ +using Newtonsoft.Json.Converters; +using Telegram.Bot.Converters; +using Telegram.Bot.Types.Enums; + +namespace Telegram.Bot.Types; + +/// +/// This object describes the origin of a message. It can be one of +/// +/// +/// +/// +/// +/// +/// +[JsonObject(MemberSerialization.OptIn, NamingStrategyType = typeof(SnakeCaseNamingStrategy))] +[JsonConverter(typeof(MessageOriginConverter))] +public abstract class MessageOrigin +{ + /// + /// Type of the message origin + /// + [JsonProperty] + public abstract MessageOriginType Type { get; } + + /// + /// Date the message was sent originally + /// + [JsonProperty(Required = Required.Always)] + [JsonConverter(typeof(UnixDateTimeConverter))] + public abstract DateTime Date { get; set; } +} + +/// +/// The message was originally sent by a known user. +/// +[JsonObject(MemberSerialization.OptIn, NamingStrategyType = typeof(SnakeCaseNamingStrategy))] +public class MessageOriginUser : MessageOrigin +{ + /// + /// Type of the message origin, always + /// + public override MessageOriginType Type => MessageOriginType.User; + + /// + [JsonProperty(Required = Required.Always)] + [JsonConverter(typeof(UnixDateTimeConverter))] + public override DateTime Date { get; set; } + + /// + /// User that sent the message originally + /// + [JsonProperty(Required = Required.Always)] + public User SenderUser { get; set; } = default!; +} + +/// +/// The message was originally sent by an unknown user. +/// +[JsonObject(MemberSerialization.OptIn, NamingStrategyType = typeof(SnakeCaseNamingStrategy))] +public class MessageOriginHiddenUser : MessageOrigin +{ + /// + /// Type of the message origin, always + /// + public override MessageOriginType Type => MessageOriginType.HiddenUser; + + /// + [JsonProperty(Required = Required.Always)] + [JsonConverter(typeof(UnixDateTimeConverter))] + public override DateTime Date { get; set; } + + /// + /// Name of the user that sent the message originally + /// + [JsonProperty(Required = Required.Always)] + public string SenderUserName { get; set; } = default!; +} + +/// +/// The message was originally sent on behalf of a chat to a group chat. +/// +[JsonObject(MemberSerialization.OptIn, NamingStrategyType = typeof(SnakeCaseNamingStrategy))] +public class MessageOriginChat : MessageOrigin +{ + /// + /// Type of the message origin, always + /// + public override MessageOriginType Type => MessageOriginType.Chat; + + /// + [JsonProperty(Required = Required.Always)] + [JsonConverter(typeof(UnixDateTimeConverter))] + public override DateTime Date { get; set; } + + /// + /// Chat that sent the message originally + /// + [JsonProperty(Required = Required.Always)] + public Chat SenderChat { get; set; } = default!; + + /// + /// Optional. For messages originally sent by an anonymous chat administrator, + /// original message author signature + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public string? AuthorSignature { get; set; } +} + +/// +/// The message was originally sent to a channel chat. +/// +[JsonObject(MemberSerialization.OptIn, NamingStrategyType = typeof(SnakeCaseNamingStrategy))] +public class MessageOriginChannel : MessageOrigin +{ + /// + /// Type of the message origin, always + /// + public override MessageOriginType Type => MessageOriginType.Channel; + + /// + [JsonProperty(Required = Required.Always)] + [JsonConverter(typeof(UnixDateTimeConverter))] + public override DateTime Date { get; set; } + + /// + /// Channel chat to which the message was originally sent + /// + [JsonProperty(Required = Required.Always)] + public Chat Chat { get; set; } = default!; + + /// + /// Unique message identifier inside the chat + /// + [JsonProperty(Required = Required.Always)] + public int MessageId { get; set; } = default!; + + /// + /// Optional. Signature of the original post author + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public string? AuthorSignature { get; set; } +} diff --git a/src/Telegram.Bot/Types/MessageReactionCountUpdated.cs b/src/Telegram.Bot/Types/MessageReactionCountUpdated.cs new file mode 100644 index 000000000..cc516ee1c --- /dev/null +++ b/src/Telegram.Bot/Types/MessageReactionCountUpdated.cs @@ -0,0 +1,35 @@ +using Newtonsoft.Json.Converters; + +namespace Telegram.Bot.Types; + +/// +/// This object represents reaction changes on a message with anonymous reactions. +/// +[JsonObject(MemberSerialization.OptIn, NamingStrategyType = typeof(SnakeCaseNamingStrategy))] +public class MessageReactionCountUpdated +{ + /// + /// The chat containing the message + /// + [JsonProperty(Required = Required.Always)] + public Chat Chat { get; set; } = default!; + + /// + /// Unique message identifier inside the chat + /// + [JsonProperty(Required = Required.Always)] + public int MessageId { get; set; } = default!; + + /// + /// Date of the change + /// + [JsonProperty(Required = Required.Always)] + [JsonConverter(typeof(UnixDateTimeConverter))] + public DateTime Date { get; set; } = default!; + + /// + /// List of reactions that are present on the message + /// + [JsonProperty(Required = Required.Always)] + public ReactionCount[] Reactions { get; set; } = default!; +} diff --git a/src/Telegram.Bot/Types/MessageReactionUpdated.cs b/src/Telegram.Bot/Types/MessageReactionUpdated.cs new file mode 100644 index 000000000..7c74d3420 --- /dev/null +++ b/src/Telegram.Bot/Types/MessageReactionUpdated.cs @@ -0,0 +1,53 @@ +using Newtonsoft.Json.Converters; + +namespace Telegram.Bot.Types; + +/// +/// This object represents a change of a reaction on a message performed by a user. +/// +[JsonObject(MemberSerialization.OptIn, NamingStrategyType = typeof(SnakeCaseNamingStrategy))] +public class MessageReactionUpdated +{ + /// + /// The chat containing the message the user reacted to + /// + [JsonProperty(Required = Required.Always)] + public Chat Chat { get; set; } = default!; + + /// + /// Unique identifier of the message inside the chat + /// + [JsonProperty(Required = Required.Always)] + public int MessageId { get; set; } = default!; + + /// + /// Optional.The user that changed the reaction, if the user isn't anonymous + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public User? User { get; set; } + + /// + /// Optional.The chat on behalf of which the reaction was changed, if the user is anonymous + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public Chat? ActorChat { get; set; } + + /// + /// Date of the change + /// + [JsonProperty(Required = Required.Always)] + [JsonConverter(typeof(UnixDateTimeConverter))] + public DateTime Date { get; set; } = default!; + + /// + /// Previous list of reaction types that were set by the user + /// + [JsonProperty(Required = Required.Always)] + public ReactionType[] OldReaction { get; set; } = default!; + + /// + /// New list of reaction types that have been set by the user + /// + [JsonProperty(Required = Required.Always)] + public ReactionType[] NewReaction { get; set; } = default!; +} diff --git a/src/Telegram.Bot/Types/Payments/LabeledPrice.cs b/src/Telegram.Bot/Types/Payments/LabeledPrice.cs index 3d69e143c..f575c7fb4 100644 --- a/src/Telegram.Bot/Types/Payments/LabeledPrice.cs +++ b/src/Telegram.Bot/Types/Payments/LabeledPrice.cs @@ -1,3 +1,5 @@ +using System.Diagnostics.CodeAnalysis; + namespace Telegram.Bot.Types.Payments; /// @@ -11,7 +13,7 @@ public class LabeledPrice /// Portion label /// [JsonProperty(Required = Required.Always)] - public string Label { get; set; } + public required string Label { get; init; } /// /// Price of the product in the smallest units of the @@ -24,7 +26,7 @@ public class LabeledPrice /// /// [JsonProperty(Required = Required.Always)] - public int Amount { get; set; } + public required int Amount { get; init; } /// /// Initializes an instance of @@ -32,9 +34,16 @@ public class LabeledPrice /// Portion label /// Price of the product [JsonConstructor] + [SetsRequiredMembers] public LabeledPrice(string label, int amount) { Label = label; Amount = amount; } + + /// + /// Initializes an instance of + /// + public LabeledPrice() + { } } diff --git a/src/Telegram.Bot/Types/ReactionCount.cs b/src/Telegram.Bot/Types/ReactionCount.cs new file mode 100644 index 000000000..e0503a418 --- /dev/null +++ b/src/Telegram.Bot/Types/ReactionCount.cs @@ -0,0 +1,20 @@ +namespace Telegram.Bot.Types; + +/// +/// Represents a reaction added to a message along with the number of times it was added. +/// +[JsonObject(MemberSerialization.OptIn, NamingStrategyType = typeof(SnakeCaseNamingStrategy))] +public class ReactionCount +{ + /// + /// Type of the reaction + /// + [JsonProperty(Required = Required.Always)] + public ReactionType Type { get; set; } = default!; + + /// + /// Number of times the reaction was added + /// + [JsonProperty(Required = Required.Always)] + public int TotalCount { get; set; } = default!; +} diff --git a/src/Telegram.Bot/Types/ReactionType.cs b/src/Telegram.Bot/Types/ReactionType.cs new file mode 100644 index 000000000..1f3fa8023 --- /dev/null +++ b/src/Telegram.Bot/Types/ReactionType.cs @@ -0,0 +1,66 @@ +using Telegram.Bot.Converters; +using Telegram.Bot.Types.Enums; + +namespace Telegram.Bot.Types; + +/// +/// This object describes the type of a reaction. Currently, it can be one of +/// +/// +/// +/// +/// +[JsonObject(MemberSerialization.OptIn, NamingStrategyType = typeof(SnakeCaseNamingStrategy))] +[JsonConverter(typeof(ReactionTypeConverter))] +public abstract class ReactionType +{ + /// + /// Type of the reaction + /// + [JsonProperty] + public abstract ReactionTypeKind Type { get; } +} + +/// +/// The reaction is based on an emoji. +/// +[JsonObject(MemberSerialization.OptIn, NamingStrategyType = typeof(SnakeCaseNamingStrategy))] +public class ReactionTypeEmoji : ReactionType +{ + /// + /// Type of the reaction, always "emoji" + /// + public override ReactionTypeKind Type => ReactionTypeKind.Emoji; + + /// + /// Reaction emoji. Currently, it can be one of "👍", "👎", "❤", "🔥", "🥰", "👏", "😁", + /// "🤔", "🤯", "😱", "🤬", "😢", "🎉", "🤩", "🤮", "💩", "🙏", "👌", "🕊", "🤡", "🥱", + /// "🥴", "😍", "🐳", "❤‍🔥", "🌚", "🌭", "💯", "🤣", "⚡", "🍌", "🏆", "💔", "🤨", + /// "😐", "🍓", "🍾", "💋", "🖕", "😈", "😴", "😭", "🤓", "👻", "👨‍💻", "👀", "🎃", + /// "🙈", "😇", "😨", "🤝", "✍", "🤗", "🫡", "🎅", "🎄", "☃", "💅", "🤪", "🗿", "🆒", + /// "💘", "🙉", "🦄", "😘", "💊", "🙊", "😎", "👾", "🤷‍♂", "🤷", "🤷‍♀", "😡" + /// + /// + /// Available shortcuts: + /// + [JsonProperty(Required = Required.Always)] + public string Emoji { get; set; } = default!; +} + +/// +/// The reaction is based on an emoji. +/// +[JsonObject(MemberSerialization.OptIn, NamingStrategyType = typeof(SnakeCaseNamingStrategy))] +public class ReactionTypeCustomEmoji : ReactionType +{ + /// + /// Type of the reaction, always "custom_emoji" + /// + public override ReactionTypeKind Type => ReactionTypeKind.CustomEmoji; + + /// + /// Custom emoji identifier + /// + [JsonProperty(Required = Required.Always)] + public string CustomEmojiId { get; set; } = default!; +} diff --git a/src/Telegram.Bot/Types/ReplyMarkups/IKeyboardButton.cs b/src/Telegram.Bot/Types/ReplyMarkups/IKeyboardButton.cs index 8bbeb1fb9..9cf582698 100644 --- a/src/Telegram.Bot/Types/ReplyMarkups/IKeyboardButton.cs +++ b/src/Telegram.Bot/Types/ReplyMarkups/IKeyboardButton.cs @@ -6,7 +6,8 @@ namespace Telegram.Bot.Types.ReplyMarkups; public interface IKeyboardButton { /// - /// Text of the button. If none of the optional fields are used, it will be sent as a message when the button is pressed + /// Text of the button. If none of the optional fields are used, + /// it will be sent as a message when the button is pressed /// - string Text { get; set; } -} \ No newline at end of file + string Text { get; } +} diff --git a/src/Telegram.Bot/Types/ReplyMarkups/IReplyMarkup.cs b/src/Telegram.Bot/Types/ReplyMarkups/IReplyMarkup.cs index 360d16d55..164df00d1 100644 --- a/src/Telegram.Bot/Types/ReplyMarkups/IReplyMarkup.cs +++ b/src/Telegram.Bot/Types/ReplyMarkups/IReplyMarkup.cs @@ -3,6 +3,4 @@ /// /// A marker interface for reply markups that define how a can reply to the sent /// -public interface IReplyMarkup -{ -} \ No newline at end of file +public interface IReplyMarkup; \ No newline at end of file diff --git a/src/Telegram.Bot/Types/ReplyMarkups/InlineKeyboardButton.cs b/src/Telegram.Bot/Types/ReplyMarkups/InlineKeyboardButton.cs index ca7bfe755..1ec7a231e 100644 --- a/src/Telegram.Bot/Types/ReplyMarkups/InlineKeyboardButton.cs +++ b/src/Telegram.Bot/Types/ReplyMarkups/InlineKeyboardButton.cs @@ -1,3 +1,5 @@ +using System.Diagnostics.CodeAnalysis; + namespace Telegram.Bot.Types.ReplyMarkups; /// @@ -8,11 +10,12 @@ public class InlineKeyboardButton : IKeyboardButton { /// [JsonProperty(Required = Required.Always)] - public string Text { get; set; } + public required string Text { get; init; } /// - /// Optional. HTTP or tg:// URL to be opened when the button is pressed. Links tg://user?id=<user_id> - /// can be used to mention a user by their ID without using a username, if this is allowed by their privacy settings. + /// Optional. HTTP or tg:// URL to be opened when the button is pressed. + /// Links tg://user?id=<user_id> can be used to mention a user by their ID without using a username, + /// if this is allowed by their privacy settings. /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] public string? Url { get; set; } @@ -82,7 +85,8 @@ public class InlineKeyboardButton : IKeyboardButton public CallbackGame? CallbackGame { get; set; } /// - /// Optional. Specify , to send a Pay button. + /// Optional. Specify , to send a + /// Pay button. /// /// /// NOTE: This type of button must always be the first button in the first row. @@ -90,11 +94,18 @@ public class InlineKeyboardButton : IKeyboardButton [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] public bool? Pay { get; set; } + /// + /// Instantiates new Inline Keyboard object + /// + public InlineKeyboardButton() + { } + /// /// Instantiates new Inline Keyboard object /// /// Label text on the button [JsonConstructor] + [SetsRequiredMembers] public InlineKeyboardButton(string text) { Text = text; @@ -178,7 +189,10 @@ public InlineKeyboardButton(string text) /// with an optional default inline query. /// /// - public static InlineKeyboardButton WithSwitchInlineQueryChosenChat(string text, SwitchInlineQueryChosenChat switchInlineQueryChosenChat) => + public static InlineKeyboardButton WithSwitchInlineQueryChosenChat( + string text, + SwitchInlineQueryChosenChat switchInlineQueryChosenChat + ) => new(text) { SwitchInlineQueryChosenChat = switchInlineQueryChosenChat }; /// diff --git a/src/Telegram.Bot/Types/ReplyMarkups/InlineKeyboardMarkup.cs b/src/Telegram.Bot/Types/ReplyMarkups/InlineKeyboardMarkup.cs index 660d81caa..82edd77ac 100644 --- a/src/Telegram.Bot/Types/ReplyMarkups/InlineKeyboardMarkup.cs +++ b/src/Telegram.Bot/Types/ReplyMarkups/InlineKeyboardMarkup.cs @@ -18,12 +18,13 @@ public class InlineKeyboardMarkup : IReplyMarkup /// . /// [JsonProperty(Required = Required.Always)] - public IEnumerable> InlineKeyboard { get; } + public required IEnumerable> InlineKeyboard { get; init; } /// /// Initializes a new instance of the class with only one keyboard button /// /// Keyboard button + [SetsRequiredMembers] public InlineKeyboardMarkup(InlineKeyboardButton inlineKeyboardButton) : this(new[] { inlineKeyboardButton }) { } @@ -32,6 +33,7 @@ public InlineKeyboardMarkup(InlineKeyboardButton inlineKeyboardButton) /// Initializes a new instance of the class with a one-row keyboard /// /// The inline keyboard row + [SetsRequiredMembers] public InlineKeyboardMarkup(IEnumerable inlineKeyboardRow) : this(new[] { inlineKeyboardRow }) { } @@ -41,6 +43,7 @@ public InlineKeyboardMarkup(IEnumerable inlineKeyboardRow) /// /// The inline keyboard. [JsonConstructor] + [SetsRequiredMembers] public InlineKeyboardMarkup(IEnumerable> inlineKeyboard) => InlineKeyboard = inlineKeyboard; diff --git a/src/Telegram.Bot/Types/ReplyMarkups/KeyboardButton.cs b/src/Telegram.Bot/Types/ReplyMarkups/KeyboardButton.cs index 3266255ae..4b43751ba 100644 --- a/src/Telegram.Bot/Types/ReplyMarkups/KeyboardButton.cs +++ b/src/Telegram.Bot/Types/ReplyMarkups/KeyboardButton.cs @@ -1,36 +1,26 @@ +using System.Diagnostics.CodeAnalysis; + namespace Telegram.Bot.Types.ReplyMarkups; /// -/// This object represents one button of the reply keyboard. For simple text buttons can be -/// used instead of this object to specify text of the button. +/// This object represents one button of the reply keyboard. +/// For simple text buttons, can be used instead of this object to specify the button text. +/// The optional fields , , , +/// , , and are mutually exclusive. /// -/// -/// -/// Note: and options will only work in Telegram -/// versions released after 9 April, 2016. Older clients will display unsupported message. -/// -/// -/// Note: option will only work in Telegram versions released after 23 January, 2020. -/// Older clients will display unsupported message. -/// -/// -/// Note: option will only work in Telegram versions released after 16 April, 2022. Older -/// clients will display unsupported message. -/// -/// [JsonObject(MemberSerialization.OptIn, NamingStrategyType = typeof(SnakeCaseNamingStrategy))] public class KeyboardButton : IKeyboardButton { /// [JsonProperty(Required = Required.Always)] - public string Text { get; set; } + public required string Text { get; init; } /// - /// Optional. If specified, pressing the button will open a list of suitable users. Tapping on any user will send - /// their identifier to the bot in a “user_shared” service message. Available in private chats only. + /// Optional. If specified, pressing the button will open a list of suitable users. Identifiers of selected users + /// will be sent to the bot in a "" service message. Available in private chats only. /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public KeyboardButtonRequestUser? RequestUser { get; set; } + public KeyboardButtonRequestUsers? RequestUsers { get; set; } /// /// Optional. If specified, pressing the button will open a list of suitable chats. Tapping on a chat will send @@ -72,6 +62,7 @@ public class KeyboardButton : IKeyboardButton /// /// Label text on the button [JsonConstructor] + [SetsRequiredMembers] public KeyboardButton(string text) => Text = text; /// @@ -103,29 +94,64 @@ public class KeyboardButton : IKeyboardButton /// Generate a keyboard button to request a web app /// /// Button's text - /// Web app information + /// + /// An HTTPS URL of a Web App to be opened with additional data as specified in + /// Initializing Web Apps + /// /// + public static KeyboardButton WithWebApp(string text, string url) => + new(text) { WebApp = new(url) }; + + /// + /// Generate a keyboard button to request a web app + /// + /// Button's text + /// Web app information public static KeyboardButton WithWebApp(string text, WebAppInfo webAppInfo) => new(text) { WebApp = webAppInfo }; /// - /// Generate a keyboard button to request user info + /// Generate a keyboard button to request users /// /// Button's text - /// Criteria used to request a suitable user + /// Criteria used to request a suitable users /// - public static KeyboardButton WithRequestUser(string text, KeyboardButtonRequestUser requestUser) => - new(text) { RequestUser = requestUser }; + public static KeyboardButton WithRequestUsers(string text, KeyboardButtonRequestUsers requestUsers) => + new(text) { RequestUsers = requestUsers }; /// - /// Generate a keyboard button to request chat info + /// Generate a keyboard button to request users + /// + /// Button's text + /// + /// Signed 32-bit identifier of the request that will be received back in the object. + /// Must be unique within the message + /// + public static KeyboardButton WithRequestUsers(string text, int requestId) => + new(text) { RequestUsers = new(requestId) }; + + /// + /// Generate a keyboard button to request a chat /// /// Button's text /// Criteria used to request a suitable chat - /// public static KeyboardButton WithRequestChat(string text, KeyboardButtonRequestChat requestChat) => new(text) { RequestChat = requestChat }; + /// + /// Generate a keyboard button to request a chat + /// + /// Button's text + /// + /// Signed 32-bit identifier of the request, which will be received back in the object. + /// Must be unique within the message + /// + /// + /// Pass to request a channel chat, pass to request a group or a supergroup chat. + /// + public static KeyboardButton WithRequestChat(string text, int requestId, bool chatIsChannel) => + new(text) { RequestChat = new(requestId, chatIsChannel) }; + /// /// Generate a keyboard button from text /// diff --git a/src/Telegram.Bot/Types/ReplyMarkups/KeyboardButtonPollType.cs b/src/Telegram.Bot/Types/ReplyMarkups/KeyboardButtonPollType.cs index b66a1cb0b..7ea6579ed 100644 --- a/src/Telegram.Bot/Types/ReplyMarkups/KeyboardButtonPollType.cs +++ b/src/Telegram.Bot/Types/ReplyMarkups/KeyboardButtonPollType.cs @@ -1,13 +1,15 @@ namespace Telegram.Bot.Types.ReplyMarkups; /// -/// This object represents type of a poll, which is allowed to be created and sent when the corresponding button is pressed. +/// This object represents type of a poll, which is allowed to be created +/// and sent when the corresponding button is pressed. /// [JsonObject(MemberSerialization.OptIn, NamingStrategyType = typeof(SnakeCaseNamingStrategy))] public class KeyboardButtonPollType { /// - /// Optional. If quiz is passed, the user will be allowed to create only polls in the quiz mode. If regular is passed, only regular polls will be allowed. Otherwise, the user will be allowed to create a poll of any type. + /// Optional. If quiz is passed, the user will be allowed to create only polls in the quiz mode. If regular is + /// passed, only regular polls will be allowed. Otherwise, the user will be allowed to create a poll of any type. /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] public string? Type { get; set; } diff --git a/src/Telegram.Bot/Types/ReplyMarkups/KeyboardButtonRequestChat.cs b/src/Telegram.Bot/Types/ReplyMarkups/KeyboardButtonRequestChat.cs index b551c0a6b..eaec4b34c 100644 --- a/src/Telegram.Bot/Types/ReplyMarkups/KeyboardButtonRequestChat.cs +++ b/src/Telegram.Bot/Types/ReplyMarkups/KeyboardButtonRequestChat.cs @@ -1,3 +1,5 @@ +using System.Diagnostics.CodeAnalysis; + namespace Telegram.Bot.Types.ReplyMarkups; /// @@ -8,17 +10,18 @@ namespace Telegram.Bot.Types.ReplyMarkups; public class KeyboardButtonRequestChat { /// - /// Signed 32-bit identifier of the request + /// Signed 32-bit identifier of the request, which will be received back in the object. + /// Must be unique within the message /// [JsonProperty(Required = Required.Always)] - public int RequestId { get; set; } + public required int RequestId { get; init; } /// - /// Pass to request a channel chat, pass to request a group - /// or a supergroup chat. + /// Pass to request a channel chat, pass + /// to request a group or a supergroup chat. /// [JsonProperty(Required = Required.Always)] - public bool ChatIsChannel { get; set; } + public required bool ChatIsChannel { get; init; } /// /// Optional. Pass to request a forum supergroup, pass to @@ -63,4 +66,28 @@ public class KeyboardButtonRequestChat /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] public bool BotIsMember { get; set; } + + /// + /// Initializes a new instance of the class with requestId and chatIsChannel + /// + /// + /// Signed 32-bit identifier of the request, which will be received back in the object. + /// Must be unique within the message + /// + /// + /// Pass to request a channel chat, pass + /// to request a group or a supergroup chat. + /// + [SetsRequiredMembers] + public KeyboardButtonRequestChat(int requestId, bool chatIsChannel) + { + RequestId = requestId; + ChatIsChannel = chatIsChannel; + } + + /// + /// Initializes a new instance of the class + /// + public KeyboardButtonRequestChat() + { } } diff --git a/src/Telegram.Bot/Types/ReplyMarkups/KeyboardButtonRequestUser.cs b/src/Telegram.Bot/Types/ReplyMarkups/KeyboardButtonRequestUser.cs deleted file mode 100644 index 00d4552aa..000000000 --- a/src/Telegram.Bot/Types/ReplyMarkups/KeyboardButtonRequestUser.cs +++ /dev/null @@ -1,29 +0,0 @@ -namespace Telegram.Bot.Types.ReplyMarkups; - -/// -/// This object defines the criteria used to request a suitable user. The identifier of the selected user will be -/// shared with the bot when the corresponding button is pressed. -/// -[JsonObject(MemberSerialization.OptIn, NamingStrategyType = typeof(SnakeCaseNamingStrategy))] -public class KeyboardButtonRequestUser -{ - /// - /// Signed 32-bit identifier of the request - /// - [JsonProperty(Required = Required.Always)] - public int RequestId { get; set; } - - /// - /// Optional. Pass to request a bot, pass to request a regular user. If not specified, no additional - /// restrictions are applied. - /// - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public bool? UserIsBot { get; set; } - - /// - /// Optional. Pass to request a premium user, pass to request a non-premium user. If not specified, - /// no additional restrictions are applied. - /// - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public bool? UserIsPremium { get; set; } -} diff --git a/src/Telegram.Bot/Types/ReplyMarkups/KeyboardButtonRequestUsers.cs b/src/Telegram.Bot/Types/ReplyMarkups/KeyboardButtonRequestUsers.cs new file mode 100644 index 000000000..aae6ed7bd --- /dev/null +++ b/src/Telegram.Bot/Types/ReplyMarkups/KeyboardButtonRequestUsers.cs @@ -0,0 +1,54 @@ +using System.Diagnostics.CodeAnalysis; + +namespace Telegram.Bot.Types.ReplyMarkups; + +/// +/// This object defines the criteria used to request a suitable user. The identifier of the selected user will be +/// shared with the bot when the corresponding button is pressed. +/// +[JsonObject(MemberSerialization.OptIn, NamingStrategyType = typeof(SnakeCaseNamingStrategy))] +public class KeyboardButtonRequestUsers +{ + /// + /// Signed 32-bit identifier of the request that will be received back in the object. + /// Must be unique within the message + /// + [JsonProperty(Required = Required.Always)] + public required int RequestId { get; init; } + + /// + /// Optional. Pass to request bots, pass to request regular users. + /// If not specified, no additional restrictions are applied. + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public bool? UserIsBot { get; set; } + + /// + /// Optional. Pass to request premium users, pass to request non-premium users. + /// If not specified, no additional restrictions are applied. + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public bool? UserIsPremium { get; set; } + + /// + /// Optional. The maximum number of users to be selected; 1-10. Defaults to 1. + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public int? MaxQuantity { get; set; } + + /// + /// Initializes a new instance of the class with requestId + /// + /// + /// Signed 32-bit identifier of the request that will be received back in the object. + /// Must be unique within the message + /// + [SetsRequiredMembers] + public KeyboardButtonRequestUsers(int requestId) + => RequestId = requestId; + + /// + /// Initializes a new instance of the class + /// + public KeyboardButtonRequestUsers() {} +} diff --git a/src/Telegram.Bot/Types/ReplyMarkups/ReplyKeyboardMarkup.cs b/src/Telegram.Bot/Types/ReplyMarkups/ReplyKeyboardMarkup.cs index 554f54b04..cfa85f53b 100644 --- a/src/Telegram.Bot/Types/ReplyMarkups/ReplyKeyboardMarkup.cs +++ b/src/Telegram.Bot/Types/ReplyMarkups/ReplyKeyboardMarkup.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq; namespace Telegram.Bot.Types.ReplyMarkups; @@ -13,7 +14,7 @@ public class ReplyKeyboardMarkup : ReplyMarkupBase /// Array of button rows, each represented by an Array of KeyboardButton objects /// [JsonProperty(Required = Required.Always)] - public IEnumerable> Keyboard { get; set; } + public required IEnumerable> Keyboard { get; init; } /// /// Optional. Requests clients to always show the keyboard when the regular keyboard is hidden. Defaults to @@ -23,13 +24,17 @@ public class ReplyKeyboardMarkup : ReplyMarkupBase public bool? IsPersistent { get; set; } /// - /// Optional. Requests clients to resize the keyboard vertically for optimal fit (e.g., make the keyboard smaller if there are just two rows of buttons). Defaults to false, in which case the custom keyboard is always of the same height as the app's standard keyboard. + /// Optional. Requests clients to resize the keyboard vertically for optimal fit (e.g., make the keyboard smaller + /// if there are just two rows of buttons). Defaults to false, in which case the custom keyboard is always + /// of the same height as the app's standard keyboard. /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] public bool? ResizeKeyboard { get; set; } /// - /// Optional. Requests clients to hide the keyboard as soon as it's been used. The keyboard will still be available, but clients will automatically display the usual letter-keyboard in the chat – the user can press a special button in the input field to see the custom keyboard again. Defaults to false. + /// Optional. Requests clients to hide the keyboard as soon as it's been used. The keyboard will still + /// be available, but clients will automatically display the usual letter-keyboard in the chat – the user can + /// press a special button in the input field to see the custom keyboard again. Defaults to false. /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] public bool? OneTimeKeyboard { get; set; } @@ -40,32 +45,38 @@ public class ReplyKeyboardMarkup : ReplyMarkupBase [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] public string? InputFieldPlaceholder { get; set; } + /// + /// Initializes a new instance of + /// + public ReplyKeyboardMarkup() + { } + /// /// Initializes a new instance of with one button /// /// Button on keyboard + [SetsRequiredMembers] public ReplyKeyboardMarkup(KeyboardButton button) - : this(new[] { button }) - { - } + : this([button]) + { } /// /// Initializes a new instance of /// /// The keyboard row. + [SetsRequiredMembers] public ReplyKeyboardMarkup(IEnumerable keyboardRow) - : this(new[] { keyboardRow }) + : this([keyboardRow]) { } /// /// Initializes a new instance of the class. /// /// The keyboard. + [SetsRequiredMembers] [JsonConstructor] public ReplyKeyboardMarkup(IEnumerable> keyboard) - { - Keyboard = keyboard; - } + => Keyboard = keyboard; /// /// Generates a reply keyboard markup with one button diff --git a/src/Telegram.Bot/Types/ReplyMarkups/ReplyKeyboardRemove.cs b/src/Telegram.Bot/Types/ReplyMarkups/ReplyKeyboardRemove.cs index 5d65082f1..736a2b8c1 100644 --- a/src/Telegram.Bot/Types/ReplyMarkups/ReplyKeyboardRemove.cs +++ b/src/Telegram.Bot/Types/ReplyMarkups/ReplyKeyboardRemove.cs @@ -1,13 +1,18 @@ namespace Telegram.Bot.Types.ReplyMarkups; /// -/// Upon receiving a message with this object, Telegram clients will remove the current custom keyboard and display the default letter-keyboard. By default, custom keyboards are displayed until a new keyboard is sent by a bot. An exception is made for one-time keyboards that are hidden immediately after the user presses a button (see ). +/// Upon receiving a message with this object, Telegram clients will remove the current custom keyboard and display +/// the default letter-keyboard. By default, custom keyboards are displayed until a new keyboard is sent by a bot. +/// An exception is made for one-time keyboards that are hidden immediately after the user presses a button +/// (see ). /// [JsonObject(MemberSerialization.OptIn, NamingStrategyType = typeof(SnakeCaseNamingStrategy))] public class ReplyKeyboardRemove : ReplyMarkupBase { /// - /// Requests clients to remove the custom keyboard (user will not be able to summon this keyboard; if you want to hide the keyboard from sight but keep it accessible, use '' in ) + /// Requests clients to remove the custom keyboard (user will not be able to summon this keyboard; if you want to + /// hide the keyboard from sight but keep it accessible, use '' + /// in ) /// [JsonProperty(Required = Required.Always)] public bool RemoveKeyboard => true; diff --git a/src/Telegram.Bot/Types/ReplyParameters.cs b/src/Telegram.Bot/Types/ReplyParameters.cs new file mode 100644 index 000000000..cca410128 --- /dev/null +++ b/src/Telegram.Bot/Types/ReplyParameters.cs @@ -0,0 +1,57 @@ +namespace Telegram.Bot.Types; + +/// +/// Describes reply parameters for the message that is being sent. +/// +[JsonObject(MemberSerialization.OptIn, NamingStrategyType = typeof(SnakeCaseNamingStrategy))] +public class ReplyParameters +{ + /// + /// Identifier of the message that will be replied to in the current chat, + /// or in the chat if it is specified + /// + [JsonProperty(Required = Required.Always)] + public int MessageId { get; set; } + + /// + /// Optional. If the message to be replied to is from a different chat, unique identifier for the + /// chat or username of the channel (in the format @channelusername) + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public ChatId? ChatId { get; set; } + + /// + /// Optional. Pass if the message should be sent even if the specified message + /// to be replied to is not found; can be used only for replies in the same chat and forum topic. + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public bool? AllowSendingWithoutReply { get; set; } + + /// + /// Optional. Quoted part of the message to be replied to; 0-1024 characters after entities parsing. + /// The quote must be an exact substring of the message to be replied to, including bold, italic, + /// underline, strikethrough, spoiler, and custom_emoji entities. + /// The message will fail to send if the quote isn't found in the original message. + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public string? Quote { get; set; } + + /// + /// Optional. Mode for parsing entities in the quote. See formatting options for more details. + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public string? QuoteParseMode { get; set; } + + /// + /// Optional. A JSON-serialized list of special entities that appear in the quote. + /// It can be specified instead of . + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public MessageEntity[]? QuoteEntities { get; set; } + + /// + /// Optional. Position of the quote in the original message in UTF-16 code units + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public int? QuotePosition { get; set; } +} diff --git a/src/Telegram.Bot/Types/Story.cs b/src/Telegram.Bot/Types/Story.cs index 4b70bece2..a160e6a39 100644 --- a/src/Telegram.Bot/Types/Story.cs +++ b/src/Telegram.Bot/Types/Story.cs @@ -6,4 +6,16 @@ namespace Telegram.Bot.Types; [JsonObject(MemberSerialization.OptIn, NamingStrategyType = typeof(SnakeCaseNamingStrategy))] public class Story { + + /// + /// Chat that posted the story + /// + [JsonProperty(Required = Required.Always)] + public Chat Chat { get; set; } = default!; + + /// + /// Unique identifier for the story in the chat + /// + [JsonProperty(Required = Required.Always)] + public int Id { get; set; } } diff --git a/src/Telegram.Bot/Types/TextQuote.cs b/src/Telegram.Bot/Types/TextQuote.cs new file mode 100644 index 000000000..478e1d6ee --- /dev/null +++ b/src/Telegram.Bot/Types/TextQuote.cs @@ -0,0 +1,34 @@ +namespace Telegram.Bot.Types; + +/// +/// This object contains information about the quoted part of a message that is replied to by the given message. +/// +[JsonObject(MemberSerialization.OptIn, NamingStrategyType = typeof(SnakeCaseNamingStrategy))] +public class TextQuote +{ + /// + /// Text of the quoted part of a message that is replied to by the given message + /// + [JsonProperty(Required = Required.Always)] + public string Text { get; set; } = default!; + + /// + /// Optional. Special entities that appear in the quote. Currently, only bold, italic, underline, + /// strikethrough, spoiler, and custom_emoji entities are kept in quotes. + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public MessageEntity[]? Entities { get; set; } + + /// + /// Approximate quote position in the original message in UTF-16 code units as specified by the sender + /// + [JsonProperty(Required = Required.Always)] + public int Position { get; set; } + + /// + /// Optional.True, if the quote was chosen manually by the message sender. + /// Otherwise, the quote was added automatically by the server. + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public bool IsManual { get; set; } +} diff --git a/src/Telegram.Bot/Types/Update.cs b/src/Telegram.Bot/Types/Update.cs index 575ac82a7..d314cd6fe 100644 --- a/src/Telegram.Bot/Types/Update.cs +++ b/src/Telegram.Bot/Types/Update.cs @@ -46,6 +46,23 @@ public class Update [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] public Message? EditedChannelPost { get; set; } + /// + /// Optional. A reaction to a message was changed by a user. The bot must be an administrator + /// in the chat and must explicitly specify "" in the list + /// of AllowedUpdates to receive these updates. + /// The update isn't received for reactions set by bots. + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public MessageReactionUpdated? MessageReaction { get; set; } + + /// + /// Optional. Reactions to a message with anonymous reactions were changed. The bot must + /// be an administrator in the chat and must explicitly specify "" + /// in the list of AllowedUpdates to receive these updates. + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public MessageReactionCountUpdated? MessageReactionCount { get; set; } + /// /// Optional. New incoming inline query /// @@ -98,7 +115,7 @@ public class Update /// /// Optional. A chat member's status was updated in a chat. The bot must be an administrator in the chat - /// and must explicitly specify “” in the list of allowed_updates to + /// and must explicitly specify “” in the list of AllowedUpdates to /// receive these updates. /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] @@ -111,6 +128,20 @@ public class Update [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] public ChatJoinRequest? ChatJoinRequest { get; set; } + /// + /// Optional. A chat boost was added or changed. + /// The bot must be an administrator in the chat to receive these updates. + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public ChatBoostUpdated? ChatBoost { get; set; } + + /// + /// Optional. A boost was removed from a chat. + /// The bot must be an administrator in the chat to receive these updates. + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public ChatBoostRemoved? RemovedChatBoost { get; set; } + /// /// Gets the update type. /// @@ -119,20 +150,24 @@ public class Update /// public UpdateType Type => this switch { - { Message: { } } => UpdateType.Message, - { EditedMessage: { } } => UpdateType.EditedMessage, - { InlineQuery: { } } => UpdateType.InlineQuery, - { ChosenInlineResult: { } } => UpdateType.ChosenInlineResult, - { CallbackQuery: { } } => UpdateType.CallbackQuery, - { ChannelPost: { } } => UpdateType.ChannelPost, - { EditedChannelPost: { } } => UpdateType.EditedChannelPost, - { ShippingQuery: { } } => UpdateType.ShippingQuery, - { PreCheckoutQuery: { } } => UpdateType.PreCheckoutQuery, - { Poll: { } } => UpdateType.Poll, - { PollAnswer: { } } => UpdateType.PollAnswer, - { MyChatMember: { } } => UpdateType.MyChatMember, - { ChatMember: { } } => UpdateType.ChatMember, - { ChatJoinRequest: { } } => UpdateType.ChatJoinRequest, - _ => UpdateType.Unknown + { Message: not null } => UpdateType.Message, + { EditedMessage: not null } => UpdateType.EditedMessage, + { ChannelPost: not null } => UpdateType.ChannelPost, + { EditedChannelPost: not null } => UpdateType.EditedChannelPost, + { MessageReaction: not null } => UpdateType.MessageReaction, + { MessageReactionCount: not null } => UpdateType.MessageReactionCount, + { InlineQuery: not null } => UpdateType.InlineQuery, + { ChosenInlineResult: not null } => UpdateType.ChosenInlineResult, + { CallbackQuery: not null } => UpdateType.CallbackQuery, + { ShippingQuery: not null } => UpdateType.ShippingQuery, + { PreCheckoutQuery: not null } => UpdateType.PreCheckoutQuery, + { Poll: not null } => UpdateType.Poll, + { PollAnswer: not null } => UpdateType.PollAnswer, + { MyChatMember: not null } => UpdateType.MyChatMember, + { ChatMember: not null } => UpdateType.ChatMember, + { ChatJoinRequest: not null } => UpdateType.ChatJoinRequest, + { ChatBoost: not null } => UpdateType.ChatBoost, + { RemovedChatBoost: not null } => UpdateType.RemovedChatBoost, + _ => UpdateType.Unknown }; } diff --git a/src/Telegram.Bot/Types/User.cs b/src/Telegram.Bot/Types/User.cs index 7eb768af0..d1866cbdf 100644 --- a/src/Telegram.Bot/Types/User.cs +++ b/src/Telegram.Bot/Types/User.cs @@ -56,19 +56,22 @@ public class User public bool? AddedToAttachmentMenu { get; set; } /// - /// Optional. , if the bot can be invited to groups. Returned only in + /// Optional. , if the bot can be invited to groups. + /// Returned only in /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] public bool? CanJoinGroups { get; set; } /// - /// Optional. , if privacy mode is disabled for the bot. Returned only in + /// Optional. , if privacy mode is disabled for the bot. + /// Returned only in /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] public bool? CanReadAllGroupMessages { get; set; } /// - /// Optional. , if the bot supports inline queries. Returned only in + /// Optional. , if the bot supports inline queries. + /// Returned only in /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] public bool? SupportsInlineQueries { get; set; } diff --git a/src/Telegram.Bot/Types/UserChatBoosts.cs b/src/Telegram.Bot/Types/UserChatBoosts.cs new file mode 100644 index 000000000..4463eb334 --- /dev/null +++ b/src/Telegram.Bot/Types/UserChatBoosts.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; + +namespace Telegram.Bot.Types; + +/// +/// This object represents a list of boosts added to a chat by a user. +/// +[JsonObject(MemberSerialization.OptIn, NamingStrategyType = typeof(SnakeCaseNamingStrategy))] +public class UserChatBoosts +{ + /// + /// The list of boosts added to the chat by the user + /// + [JsonProperty(Required = Required.Always)] + public IEnumerable Boosts { get; set; } = default!; +} diff --git a/src/Telegram.Bot/Types/UserShared.cs b/src/Telegram.Bot/Types/UserShared.cs deleted file mode 100644 index 885634920..000000000 --- a/src/Telegram.Bot/Types/UserShared.cs +++ /dev/null @@ -1,27 +0,0 @@ -using Telegram.Bot.Types.ReplyMarkups; - -namespace Telegram.Bot.Types; - -/// -/// This object contains information about the user whose identifier was shared with the bot using a -/// button. -/// -[JsonObject(MemberSerialization.OptIn, NamingStrategyType = typeof(SnakeCaseNamingStrategy))] -public class UserShared -{ - /// - /// Identifier of the request - /// - [JsonProperty(Required = Required.Always)] - public int RequestId { get; set; } - - /// - /// Identifier of the shared user. This number may have more than 32 significant bits and some programming - /// languages may have difficulty/silent defects in interpreting it. But it has at most 52 significant bits, - /// so a 64-bit integer or double-precision float type are safe for storing this identifier. The bot may not have - /// access to the user and could be unable to use this identifier, unless the user is already known to the bot by - /// some other means. - /// - [JsonProperty(Required = Required.Always)] - public long UserId { get; set; } -} diff --git a/src/Telegram.Bot/Types/UsersShared.cs b/src/Telegram.Bot/Types/UsersShared.cs new file mode 100644 index 000000000..de9414fcc --- /dev/null +++ b/src/Telegram.Bot/Types/UsersShared.cs @@ -0,0 +1,27 @@ +using Telegram.Bot.Types.ReplyMarkups; + +namespace Telegram.Bot.Types; + +/// +/// This object contains information about the users whose identifiers were shared with the bot +/// using a button. +/// +[JsonObject(MemberSerialization.OptIn, NamingStrategyType = typeof(SnakeCaseNamingStrategy))] +public class UsersShared +{ + /// + /// Identifier of the request + /// + [JsonProperty(Required = Required.Always)] + public int RequestId { get; set; } + + /// + /// Identifiers of the shared users. These numbers may have more than 32 significant bits and some + /// programming languages may have difficulty/silent defects in interpreting them. But they have + /// at most 52 significant bits, so 64-bit integers or double-precision float types are safe for + /// storing these identifiers. The bot may not have access to the users and could be unable to use + /// these identifiers, unless the users are already known to the bot by some other means. + /// + [JsonProperty(Required = Required.Always)] + public long[] UserIds { get; set; } = Array.Empty(); +} diff --git a/src/Telegram.Bot/Types/VideoChatStarted.cs b/src/Telegram.Bot/Types/VideoChatStarted.cs index b05adecf8..e94263d3c 100644 --- a/src/Telegram.Bot/Types/VideoChatStarted.cs +++ b/src/Telegram.Bot/Types/VideoChatStarted.cs @@ -4,5 +4,4 @@ /// This object represents a service message about a video chat started in the chat. Currently holds no information. /// [JsonObject(MemberSerialization.OptIn, NamingStrategyType = typeof(SnakeCaseNamingStrategy))] -public class VideoChatStarted -{ } +public class VideoChatStarted; diff --git a/src/Telegram.Bot/Types/WebAppInfo.cs b/src/Telegram.Bot/Types/WebAppInfo.cs index abefa49f4..d8750f555 100644 --- a/src/Telegram.Bot/Types/WebAppInfo.cs +++ b/src/Telegram.Bot/Types/WebAppInfo.cs @@ -1,4 +1,6 @@ -namespace Telegram.Bot.Types; +using System.Diagnostics.CodeAnalysis; + +namespace Telegram.Bot.Types; /// /// Contains information about a Web App @@ -11,5 +13,22 @@ public class WebAppInfo /// Initializing Web Apps /// [JsonProperty(Required = Required.Always)] - public string Url { get; set; } = default!; + public required string Url { get; init; } + + /// + /// Initializes a new instance of the class with url + /// + /// + /// An HTTPS URL of a Web App to be opened with additional data as specified in + /// Initializing Web Apps + /// + [SetsRequiredMembers] + public WebAppInfo(string url) + => Url = url; + + /// + /// Initializes a new instance of the class + /// + public WebAppInfo() + {} } diff --git a/src/Telegram.Bot/Types/WriteAccessAllowed.cs b/src/Telegram.Bot/Types/WriteAccessAllowed.cs index 7036bd773..bd021fdb5 100644 --- a/src/Telegram.Bot/Types/WriteAccessAllowed.cs +++ b/src/Telegram.Bot/Types/WriteAccessAllowed.cs @@ -3,14 +3,16 @@ namespace Telegram.Bot.Types; /// /// This object represents a service message about a user allowing a bot to write messages after adding /// it to the attachment menu, launching a Web App from a link, or accepting an explicit request from -/// a Web App sent by the method requestWriteAccess. +/// a Web App sent by the method +/// requestWriteAccess. /// [JsonObject(MemberSerialization.OptIn, NamingStrategyType = typeof(SnakeCaseNamingStrategy))] public class WriteAccessAllowed { /// /// Optional. , if the access was granted after the user accepted an explicit request - /// from a Web App sent by the method requestWriteAccess + /// from a Web App sent by the method + /// requestWriteAccess /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] public bool? FromRequest { get; set; } @@ -22,7 +24,8 @@ public class WriteAccessAllowed public string? WebAppName { get; set; } /// - /// Optional. , if the access was granted when the bot was added to the attachment or side menu + /// Optional. , if the access was granted when the bot was added to the attachment + /// or side menu /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] public bool? FromAttachmentMenu { get; set; } diff --git a/test/Telegram.Bot.Tests.Integ/Admin Bot/ChannelAdminBotTestFixture.cs b/test/Telegram.Bot.Tests.Integ/Admin Bot/ChannelAdminBotTestFixture.cs index eb83ea138..2a351742f 100644 --- a/test/Telegram.Bot.Tests.Integ/Admin Bot/ChannelAdminBotTestFixture.cs +++ b/test/Telegram.Bot.Tests.Integ/Admin Bot/ChannelAdminBotTestFixture.cs @@ -1,4 +1,5 @@ using System.IO; +using Telegram.Bot.Requests; using Telegram.Bot.Tests.Integ.Framework; using Telegram.Bot.Tests.Integ.Framework.Fixtures; using Telegram.Bot.Types; @@ -17,7 +18,7 @@ public class ChannelAdminBotTestFixture : AsyncLifetimeFixture public ChannelAdminBotTestFixture(TestsFixture fixture) { AddLifetime( - initialize: async () => + initializer: async () => { _channelChatFixture = new(fixture, Constants.TestCollections.ChannelAdminBots); await _channelChatFixture.InitializeAsync(); @@ -30,15 +31,18 @@ public ChannelAdminBotTestFixture(TestsFixture fixture) _oldChatPhoto = stream.ToArray(); } }, - dispose: async () => + finalizer: async () => { // If chat had a photo before, reset the photo back. if (_oldChatPhoto is not null) { await using MemoryStream photoStream = new(_oldChatPhoto); await fixture.BotClient.SetChatPhotoAsync( - chatId: Chat.Id, - photo: new InputFileStream(photoStream) + new() + { + ChatId = Chat.Id, + Photo = InputFile.FromStream(photoStream), + } ); } diff --git a/test/Telegram.Bot.Tests.Integ/Admin Bot/ChannelAdminBotTests.cs b/test/Telegram.Bot.Tests.Integ/Admin Bot/ChannelAdminBotTests.cs index c009fe303..cb1d5cc53 100644 --- a/test/Telegram.Bot.Tests.Integ/Admin Bot/ChannelAdminBotTests.cs +++ b/test/Telegram.Bot.Tests.Integ/Admin Bot/ChannelAdminBotTests.cs @@ -2,6 +2,7 @@ using System.IO; using System.Threading.Tasks; using Telegram.Bot.Exceptions; +using Telegram.Bot.Requests; using Telegram.Bot.Tests.Integ.Framework; using Telegram.Bot.Types; using Xunit; @@ -10,20 +11,15 @@ namespace Telegram.Bot.Tests.Integ.Admin_Bot; [Collection(Constants.TestCollections.ChannelAdminBots)] [TestCaseOrderer(Constants.TestCaseOrderer, Constants.AssemblyName)] -public class ChannelAdminBotTests : IClassFixture +public class ChannelAdminBotTests(TestsFixture testsFixture, ChannelAdminBotTestFixture classFixture) + : IClassFixture { - readonly ChannelAdminBotTestFixture _classFixture; + readonly ChannelAdminBotTestFixture _classFixture = classFixture; - readonly TestsFixture _fixture; + readonly TestsFixture _fixture = testsFixture; ITelegramBotClient BotClient => _fixture.BotClient; - public ChannelAdminBotTests(TestsFixture testsFixture, ChannelAdminBotTestFixture classFixture) - { - _fixture = testsFixture; - _classFixture = classFixture; - } - #region 1. Changing Chat Title [OrderedFact("Should set chat title")] @@ -31,8 +27,11 @@ public ChannelAdminBotTests(TestsFixture testsFixture, ChannelAdminBotTestFixtur public async Task Should_Set_Chat_Title() { await BotClient.SetChatTitleAsync( - chatId: _classFixture.Chat.Id, - title: "Test Chat Title" + new() + { + ChatId = _classFixture.Chat.Id, + Title = "Test Chat Title", + } ); } @@ -45,8 +44,11 @@ public async Task Should_Set_Chat_Title() public async Task Should_Set_Chat_Description() { await BotClient.SetChatDescriptionAsync( - chatId: _classFixture.Chat.Id, - description: "Test Chat Description" + new SetChatDescriptionRequest + { + ChatId = _classFixture.Chat.Id, + Description = "Test Chat Description", + } ); } @@ -54,7 +56,7 @@ public async Task Should_Set_Chat_Description() [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.SetChatDescription)] public async Task Should_Delete_Chat_Description() { - await BotClient.SetChatDescriptionAsync(_classFixture.Chat.Id); + await BotClient.SetChatDescriptionAsync(new SetChatDescriptionRequest { ChatId = _classFixture.Chat.Id }); } #endregion @@ -65,12 +67,19 @@ public async Task Should_Delete_Chat_Description() [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.PinChatMessage)] public async Task Should_Pin_Message() { - Message msg = await BotClient.SendTextMessageAsync(_classFixture.Chat.Id, "Description to pin"); + Message msg = await BotClient.SendMessageAsync(new() + { + ChatId = _classFixture.Chat.Id, + Text = "Description to pin", + }); await BotClient.PinChatMessageAsync( - chatId: _classFixture.Chat.Id, - messageId: msg.MessageId, - disableNotification: true + new() + { + ChatId = _classFixture.Chat.Id, + MessageId = msg.MessageId, + DisableNotification = true, + } ); _classFixture.PinnedMessage = msg; @@ -82,8 +91,9 @@ public async Task Should_Get_Chat_Pinned_Message() { Message pinnedMsg = _classFixture.PinnedMessage; - Chat chat = await BotClient.GetChatAsync(_classFixture.Chat.Id); + Chat chat = await BotClient.GetChatAsync(new GetChatRequest { ChatId = _classFixture.Chat.Id}); + Assert.NotNull(chat.PinnedMessage); Assert.True(JToken.DeepEquals( JToken.FromObject(pinnedMsg), JToken.FromObject(chat.PinnedMessage) )); @@ -93,14 +103,14 @@ public async Task Should_Get_Chat_Pinned_Message() [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.UnpinChatMessage)] public async Task Should_Unpin_Message() { - await BotClient.UnpinChatMessageAsync(_classFixture.Chat.Id); + await BotClient.UnpinChatMessageAsync(new UnpinChatMessageRequest { ChatId = _classFixture.Chat.Id}); } [OrderedFact("Should get the chat info without a pinned message")] [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.GetChat)] public async Task Should_Get_Chat_With_No_Pinned_Message() { - Chat chat = await BotClient.GetChatAsync(_classFixture.Chat.Id); + Chat chat = await BotClient.GetChatAsync(new GetChatRequest { ChatId = _classFixture.Chat.Id}); Assert.Null(chat.PinnedMessage); } @@ -115,8 +125,11 @@ public async Task Should_Set_Chat_Photo() { await using Stream stream = System.IO.File.OpenRead(Constants.PathToFile.Photos.Logo); await BotClient.SetChatPhotoAsync( - chatId: _classFixture.Chat.Id, - photo: new InputFileStream(stream) + new() + { + ChatId = _classFixture.Chat.Id, + Photo = InputFile.FromStream(stream), + } ); } @@ -124,7 +137,7 @@ public async Task Should_Set_Chat_Photo() [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.GetChat)] public async Task Should_Get_Chat_Photo() { - Chat chat = await BotClient.GetChatAsync(_classFixture.Chat.Id); + Chat chat = await BotClient.GetChatAsync(new GetChatRequest { ChatId = _classFixture.Chat.Id }); Assert.NotNull(chat.Photo); Assert.NotEmpty(chat.Photo.BigFileId); @@ -137,7 +150,7 @@ public async Task Should_Get_Chat_Photo() [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.DeleteChatPhoto)] public async Task Should_Delete_Chat_Photo() { - await BotClient.DeleteChatPhotoAsync(_classFixture.Chat.Id); + await BotClient.DeleteChatPhotoAsync(new DeleteChatPhotoRequest { ChatId = _classFixture.Chat.Id }); } [OrderedFact("Should throw exception in deleting chat photo with no photo currently set")] @@ -145,7 +158,7 @@ public async Task Should_Delete_Chat_Photo() public async Task Should_Throw_On_Deleting_Chat_Deleted_Photo() { ApiRequestException e = await Assert.ThrowsAsync( - async () => await BotClient.DeleteChatPhotoAsync(_classFixture.Chat.Id) + async () => await BotClient.DeleteChatPhotoAsync(new DeleteChatPhotoRequest() { ChatId = _classFixture.Chat.Id }) ); Assert.IsType(e); @@ -163,7 +176,11 @@ public async Task Should_Throw_On_Setting_Chat_Sticker_Set() const string setName = "EvilMinds"; ApiRequestException exception = await Assert.ThrowsAsync(async () => - await _fixture.BotClient.SetChatStickerSetAsync(_classFixture.Chat.Id, setName) + await _fixture.BotClient.SetChatStickerSetAsync(new() + { + ChatId = _classFixture.Chat.Id, + StickerSetName = setName, + }) ); Assert.Equal(400, exception.ErrorCode); diff --git a/test/Telegram.Bot.Tests.Integ/Admin Bot/ChatMemberAdministrationTestFixture.cs b/test/Telegram.Bot.Tests.Integ/Admin Bot/ChatMemberAdministrationTestFixture.cs index e36aef78f..81380fc14 100644 --- a/test/Telegram.Bot.Tests.Integ/Admin Bot/ChatMemberAdministrationTestFixture.cs +++ b/test/Telegram.Bot.Tests.Integ/Admin Bot/ChatMemberAdministrationTestFixture.cs @@ -1,17 +1,15 @@ using System; using System.Threading.Tasks; +using Telegram.Bot.Requests; using Telegram.Bot.Tests.Integ.Framework; using Telegram.Bot.Types; using Xunit; namespace Telegram.Bot.Tests.Integ.Admin_Bot; -public class ChatMemberAdministrationTestFixture : IAsyncLifetime +public class ChatMemberAdministrationTestFixture(TestsFixture testsFixture) + : IAsyncLifetime { - readonly TestsFixture _testsFixture; - - public ChatMemberAdministrationTestFixture(TestsFixture testsFixture) => _testsFixture = testsFixture; - public Chat RegularMemberChat { get; private set; } public long RegularMemberUserId { get; private set; } public string RegularMemberUserName { get; private set; } @@ -25,7 +23,7 @@ static async Task GetChat(TestsFixture testsFixture, string collectionName if (testsFixture.Configuration.RegularGroupMemberId is {} userId) { - chat = await testsFixture.BotClient.GetChatAsync(userId); + chat = await testsFixture.BotClient.GetChatAsync(new GetChatRequest {ChatId = userId}); } else { @@ -53,9 +51,9 @@ public async Task InitializeAsync() { const string collectionName = Constants.TestCollections.ChatMemberAdministration; - RegularMemberChat = await GetChat(_testsFixture, collectionName); + RegularMemberChat = await GetChat(testsFixture, collectionName); - await _testsFixture.SendTestCollectionNotificationAsync( + await testsFixture.SendTestCollectionNotificationAsync( collectionName, $"Chosen regular member is @{RegularMemberChat.GetSafeUsername()}" ); @@ -63,13 +61,13 @@ public async Task InitializeAsync() RegularMemberUserId = RegularMemberChat.Id; RegularMemberUserName = RegularMemberChat.Username; // Updates from regular user will be received - _testsFixture.UpdateReceiver.AllowedUsernames.Add(RegularMemberUserName); + testsFixture.UpdateReceiver.AllowedUsernames.Add(RegularMemberUserName); } public Task DisposeAsync() { // Remove regular user from AllowedUserNames - _testsFixture.UpdateReceiver.AllowedUsernames.Remove(RegularMemberUserName); + testsFixture.UpdateReceiver.AllowedUsernames.Remove(RegularMemberUserName); return Task.CompletedTask; } -} \ No newline at end of file +} diff --git a/test/Telegram.Bot.Tests.Integ/Admin Bot/ChatMemberAdministrationTests.cs b/test/Telegram.Bot.Tests.Integ/Admin Bot/ChatMemberAdministrationTests.cs index df281d3ce..c18def498 100644 --- a/test/Telegram.Bot.Tests.Integ/Admin Bot/ChatMemberAdministrationTests.cs +++ b/test/Telegram.Bot.Tests.Integ/Admin Bot/ChatMemberAdministrationTests.cs @@ -2,6 +2,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using Telegram.Bot.Requests; using Telegram.Bot.Tests.Integ.Framework; using Telegram.Bot.Types; using Telegram.Bot.Types.Enums; @@ -13,19 +14,14 @@ namespace Telegram.Bot.Tests.Integ.Admin_Bot; [Collection(Constants.TestCollections.ChatMemberAdministration)] [Trait(Constants.CategoryTraitName, Constants.InteractiveCategoryValue)] [TestCaseOrderer(Constants.TestCaseOrderer, Constants.AssemblyName)] -public class ChatMemberAdministrationTests : IClassFixture +public class ChatMemberAdministrationTests(TestsFixture fixture, ChatMemberAdministrationTestFixture classFixture) + : IClassFixture { ITelegramBotClient BotClient => _fixture.BotClient; - readonly TestsFixture _fixture; + readonly TestsFixture _fixture = fixture; - readonly ChatMemberAdministrationTestFixture _classFixture; - - public ChatMemberAdministrationTests(TestsFixture fixture, ChatMemberAdministrationTestFixture classFixture) - { - _fixture = fixture; - _classFixture = classFixture; - } + readonly ChatMemberAdministrationTestFixture _classFixture = classFixture; #region Kick, Unban, and Invite chat member back @@ -33,8 +29,11 @@ public ChatMemberAdministrationTests(TestsFixture fixture, ChatMemberAdministrat public async Task Should_Get_Chat_Member_Member() { ChatMember chatMember = await BotClient.GetChatMemberAsync( - chatId: _fixture.SupergroupChat, - userId: _classFixture.RegularMemberUserId + new() + { + ChatId = _fixture.SupergroupChat, + UserId = _classFixture.RegularMemberUserId, + } ); Assert.Equal(ChatMemberStatus.Member, chatMember.Status); @@ -46,8 +45,11 @@ public async Task Should_Get_Chat_Member_Member() public async Task Should_Kick_Chat_Member_For_Ever() { await BotClient.BanChatMemberAsync( - chatId: _fixture.SupergroupChat.Id, - userId: _classFixture.RegularMemberUserId + new() + { + ChatId = _fixture.SupergroupChat.Id, + UserId = _classFixture.RegularMemberUserId, + } ); } @@ -55,8 +57,11 @@ public async Task Should_Kick_Chat_Member_For_Ever() public async Task Should_Get_Chat_Member_Kicked() { ChatMember chatMember = await BotClient.GetChatMemberAsync( - chatId: _fixture.SupergroupChat, - userId: _classFixture.RegularMemberUserId + new() + { + ChatId = _fixture.SupergroupChat, + UserId = _classFixture.RegularMemberUserId, + } ); Assert.Equal(ChatMemberStatus.Kicked, chatMember.Status); @@ -70,8 +75,11 @@ public async Task Should_Get_Chat_Member_Kicked() public async Task Should_Unban_Chat_Member() { await BotClient.UnbanChatMemberAsync( - chatId: _fixture.SupergroupChat.Id, - userId: _classFixture.RegularMemberUserId + new() + { + ChatId = _fixture.SupergroupChat.Id, + UserId = _classFixture.RegularMemberUserId, + } ); } @@ -79,7 +87,9 @@ public async Task Should_Unban_Chat_Member() [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.ExportChatInviteLink)] public async Task Should_Export_Chat_Invite_Link() { - string chatInviteLink = await BotClient.ExportChatInviteLinkAsync(_fixture.SupergroupChat.Id); + string chatInviteLink = await BotClient.ExportChatInviteLinkAsync( + new ExportChatInviteLinkRequest { ChatId = _fixture.SupergroupChat.Id} + ); Assert.Matches("https://t.me/.+", chatInviteLink); @@ -96,17 +106,28 @@ public async Task Should_Receive_New_Chat_Member_Notification() await _fixture.UpdateReceiver.DiscardNewUpdatesAsync(); - await BotClient.SendTextMessageAsync( - chatId: _classFixture.RegularMemberChat, - text: _classFixture.GroupInviteLink + Message privateMessage = await BotClient.SendMessageAsync( + new() + { + ChatId = _classFixture.RegularMemberChat, + Text = _classFixture.GroupInviteLink, + } ); Update update = await _fixture.UpdateReceiver.GetUpdateAsync( predicate: u => u.Message!.Chat.Type == ChatType.Supergroup && u.Message!.Chat.Id == _fixture.SupergroupChat.Id - && u.Message!.Type == MessageType.ChatMembersAdded, - updateTypes: new[] { UpdateType.Message } + && u.Message!.Type == MessageType.NewChatMembers, + updateTypes: [UpdateType.Message] + ); + + await BotClient.DeleteMessageAsync( + new() + { + ChatId = _classFixture.RegularMemberChat, + MessageId = privateMessage.MessageId, + } ); await _fixture.UpdateReceiver.DiscardNewUpdatesAsync(); @@ -130,17 +151,20 @@ public async Task Should_Create_Chat_Invite_Link() { DateTime createdAt = DateTime.UtcNow; - // Milliseconds are ignored during conversion to unix timestamp since it counts only up to + // Milliseconds are ignored during conversion to Unix timestamp since it counts only up to // seconds, so for equality to work later on assertion we need to zero out milliseconds - DateTime expireDate = createdAt.With(new () {Millisecond = 0}).AddHours(1); + DateTime expireDate = createdAt.With(new () {Millisecond = 0}).AddHours(24); string inviteLinkName = $"Created at {createdAt:yyyy-MM-ddTHH:mm:ss}"; ChatInviteLink chatInviteLink = await BotClient.CreateChatInviteLinkAsync( - chatId: _fixture.SupergroupChat.Id, - createsJoinRequest: true, - name: inviteLinkName, - expireDate: expireDate + new CreateChatInviteLinkRequest + { + ChatId = _fixture.SupergroupChat.Id, + CreatesJoinRequest = true, + Name = inviteLinkName, + ExpireDate = expireDate, + } ); Assert.NotNull(chatInviteLink); @@ -162,36 +186,52 @@ public async Task Should_Create_Chat_Invite_Link() public async Task Should_Receive_Chat_Join_Request() { await _fixture.SendTestInstructionsAsync( - $"@{_classFixture.RegularMemberUserName.Replace("_", @"\_")} should send a request to join the" + + $"@{_classFixture.RegularMemberUserName.Replace("_", @"\_")} should send a request to join the " + "chat by following the invite link sent to them in private chat two time. The administrator should " + "decline the first attempt and then approve the second one." ); - await _fixture.UpdateReceiver.DiscardNewUpdatesAsync(); - await BotClient.BanChatMemberAsync( - chatId: _fixture.SupergroupChat.Id, - userId: _classFixture.RegularMemberUserId + new() + { + ChatId = _fixture.SupergroupChat.Id, + UserId = _classFixture.RegularMemberUserId, + } ); - await Task.Delay(TimeSpan.FromSeconds(3)); + await Task.Delay(TimeSpan.FromSeconds(5)); await BotClient.UnbanChatMemberAsync( - chatId: _fixture.SupergroupChat.Id, - userId: _classFixture.RegularMemberUserId + new() + { + ChatId = _fixture.SupergroupChat.Id, + UserId = _classFixture.RegularMemberUserId, + } ); - await Task.Delay(TimeSpan.FromSeconds(3)); + await Task.Delay(TimeSpan.FromSeconds(5)); - await BotClient.SendTextMessageAsync( - chatId: _classFixture.RegularMemberChat, - text: _classFixture.ChatInviteLink.InviteLink + Message privateMessage = await BotClient.SendMessageAsync( + new() + { + ChatId = _classFixture.RegularMemberChat, + Text = _classFixture.ChatInviteLink.InviteLink, + } ); await _fixture.UpdateReceiver.DiscardNewUpdatesAsync(); Update update = await _fixture.UpdateReceiver.GetUpdateAsync( - predicate: u => u.ChatJoinRequest is not null + predicate: u => u.ChatJoinRequest is not null, + updateTypes: [UpdateType.ChatJoinRequest] + ); + + await BotClient.DeleteMessageAsync( + new() + { + ChatId = _classFixture.RegularMemberChat, + MessageId = privateMessage.MessageId, + } ); ChatJoinRequest chatJoinRequest = update.ChatJoinRequest; @@ -211,11 +251,13 @@ public async Task Should_Receive_Chat_Join_Request() [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.DeclineChatJoinRequest)] public async Task Should_Decline_Chat_Join_Request() { - Exception exception = await Record.ExceptionAsync(async () => - await BotClient.DeclineChatJoinRequest( - chatId: _fixture.SupergroupChat.Id, - userId: _classFixture.RegularMemberUserId + await BotClient.DeclineChatJoinRequestAsync( + new() + { + ChatId = _fixture.SupergroupChat.Id, + UserId = _classFixture.RegularMemberUserId, + } ) ); Assert.Null(exception); @@ -225,9 +267,27 @@ public async Task Should_Decline_Chat_Join_Request() [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.ApproveChatJoinRequest)] public async Task Should_Approve_Chat_Join_Request() { + Message privateMessage = await BotClient.SendMessageAsync( + new() + { + ChatId = _classFixture.RegularMemberChat, + Text = _classFixture.ChatInviteLink.InviteLink, + } + ); + + await _fixture.UpdateReceiver.DiscardNewUpdatesAsync(); + Update update = await _fixture.UpdateReceiver.GetUpdateAsync( predicate: u => u.ChatJoinRequest is not null, - updateTypes: UpdateType.ChatJoinRequest + updateTypes: [UpdateType.ChatJoinRequest] + ); + + await BotClient.DeleteMessageAsync( + new() + { + ChatId = _classFixture.RegularMemberChat, + MessageId = privateMessage.MessageId, + } ); ChatJoinRequest chatJoinRequest = update.ChatJoinRequest; @@ -241,9 +301,12 @@ public async Task Should_Approve_Chat_Join_Request() Assert.Equal(chatJoinRequest.From.Id, _classFixture.RegularMemberUserId); Exception exception = await Record.ExceptionAsync(async () => - await BotClient.ApproveChatJoinRequest( - chatId: _fixture.SupergroupChat.Id, - userId: _classFixture.RegularMemberUserId + await BotClient.ApproveChatJoinRequestAsync( + new() + { + ChatId = _fixture.SupergroupChat.Id, + UserId = _classFixture.RegularMemberUserId, + } ) ); Assert.Null(exception); @@ -260,9 +323,12 @@ public async Task Should_Promote_User_To_Change_Chat_Info() //ToDo exception when user isn't in group. Bad Request: bots can't add new chat members await BotClient.PromoteChatMemberAsync( - chatId: _fixture.SupergroupChat.Id, - userId: _classFixture.RegularMemberUserId, - canChangeInfo: true + new() + { + ChatId = _fixture.SupergroupChat.Id, + UserId = _classFixture.RegularMemberUserId, + CanChangeInfo = true, + } ); } @@ -271,19 +337,28 @@ public async Task Should_Promote_User_To_Change_Chat_Info() public async Task Should_Set_Custom_Title_For_Admin() { ChatMember promotedRegularUser = await BotClient.GetChatMemberAsync( - _fixture.SupergroupChat, - _classFixture.RegularMemberUserId + new() + { + ChatId = _fixture.SupergroupChat, + UserId = _classFixture.RegularMemberUserId, + } ); await BotClient.SetChatAdministratorCustomTitleAsync( - chatId: _fixture.SupergroupChat, - userId: promotedRegularUser.User.Id, - customTitle: "CHANGED TITLE" + new() + { + ChatId = _fixture.SupergroupChat, + UserId = promotedRegularUser.User.Id, + CustomTitle = "CHANGED TITLE", + } ); ChatMember newChatMember = await BotClient.GetChatMemberAsync( - _fixture.SupergroupChat, - promotedRegularUser.User.Id + new() + { + ChatId = _fixture.SupergroupChat, + UserId = promotedRegularUser.User.Id, + } ); Assert.Equal(ChatMemberStatus.Administrator, newChatMember.Status); @@ -293,9 +368,12 @@ public async Task Should_Set_Custom_Title_For_Admin() // Restore default title by sending empty string await BotClient.SetChatAdministratorCustomTitleAsync( - chatId: _fixture.SupergroupChat, - userId: promotedRegularUser.User.Id, - customTitle: string.Empty + new() + { + ChatId = _fixture.SupergroupChat, + UserId = promotedRegularUser.User.Id, + CustomTitle = "", + } ); } @@ -306,9 +384,12 @@ public async Task Should_Demote_User() //ToDo exception when user isn't in group. Bad Request: USER_NOT_MUTUAL_CONTACT await BotClient.PromoteChatMemberAsync( - chatId: _fixture.SupergroupChat.Id, - userId: _classFixture.RegularMemberUserId, - canChangeInfo: false + new() + { + ChatId = _fixture.SupergroupChat.Id, + UserId = _classFixture.RegularMemberUserId, + CanChangeInfo = false, + } ); } @@ -319,13 +400,16 @@ public async Task Should_Restrict_Sending_Stickers_Temporarily() const int banSeconds = 35; await BotClient.RestrictChatMemberAsync( - chatId: _fixture.SupergroupChat.Id, - userId: _classFixture.RegularMemberUserId, - untilDate: DateTime.UtcNow.AddSeconds(banSeconds), - permissions: new ChatPermissions + new() { - CanSendMessages = true, - CanSendOtherMessages = false + ChatId = _fixture.SupergroupChat.Id, + UserId = _classFixture.RegularMemberUserId, + UntilDate = DateTime.UtcNow.AddSeconds(banSeconds), + Permissions = new() + { + CanSendMessages = true, + CanSendOtherMessages = false + }, } ); } @@ -334,8 +418,11 @@ public async Task Should_Restrict_Sending_Stickers_Temporarily() public async Task Should_Get_Chat_Member_Restricted() { ChatMember chatMember = await BotClient.GetChatMemberAsync( - chatId: _fixture.SupergroupChat, - userId: _classFixture.RegularMemberUserId + new() + { + ChatId = _fixture.SupergroupChat, + UserId = _classFixture.RegularMemberUserId, + } ); Assert.Equal(ChatMemberStatus.Restricted, chatMember.Status); @@ -371,8 +458,8 @@ public async Task Should_Receive_Chat_Member_Updated() Assert.NotNull(chatMemberUpdated.OldChatMember); Assert.NotNull(chatMemberUpdated.NewChatMember); - Assert.True(chatMemberUpdated.OldChatMember.Status == ChatMemberStatus.Restricted); - Assert.True(chatMemberUpdated.NewChatMember.Status == ChatMemberStatus.Kicked); + Assert.Equal(ChatMemberStatus.Restricted, chatMemberUpdated.OldChatMember.Status); + Assert.Equal(ChatMemberStatus.Kicked, chatMemberUpdated.NewChatMember.Status); Assert.IsType(chatMemberUpdated.OldChatMember); ChatMemberBanned newChatMember = Assert.IsType(chatMemberUpdated.NewChatMember); @@ -398,7 +485,7 @@ public async Task Should_Wait_For_Regular_Chat_Member_To_Join() Update _ = await _fixture.UpdateReceiver .GetUpdateAsync( u => u.Message?.Chat.Id == _fixture.SupergroupChat.Id && - u.Message.Type == MessageType.ChatMembersAdded, + u.Message.Type == MessageType.NewChatMembers, updateTypes: UpdateType.Message, cancellationToken: cts.Token ); @@ -422,9 +509,11 @@ public async Task Should_Kick_Chat_Member_Temporarily() ); await BotClient.BanChatMemberAsync( - chatId: _fixture.SupergroupChat.Id, - userId: _classFixture.RegularMemberUserId, - untilDate: DateTime.UtcNow.AddSeconds(banSeconds) + new(){ + ChatId = _fixture.SupergroupChat.Id, + UserId = _classFixture.RegularMemberUserId, + UntilDate = DateTime.UtcNow.AddSeconds(banSeconds), + } ); } @@ -432,8 +521,11 @@ public async Task Should_Kick_Chat_Member_Temporarily() public async Task Should_Get_Chat_Member_Restricted_With_Until_Date() { ChatMember chatMember = await BotClient.GetChatMemberAsync( - chatId: _fixture.SupergroupChat, - userId: _classFixture.RegularMemberUserId + new() + { + ChatId = _fixture.SupergroupChat, + UserId = _classFixture.RegularMemberUserId, + } ); Assert.Equal(ChatMemberStatus.Kicked, chatMember.Status); diff --git a/test/Telegram.Bot.Tests.Integ/Admin Bot/SupergroupAdminBotTests.cs b/test/Telegram.Bot.Tests.Integ/Admin Bot/SupergroupAdminBotTests.cs index 36c6ac9d5..0284bba9a 100644 --- a/test/Telegram.Bot.Tests.Integ/Admin Bot/SupergroupAdminBotTests.cs +++ b/test/Telegram.Bot.Tests.Integ/Admin Bot/SupergroupAdminBotTests.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Threading.Tasks; using Telegram.Bot.Exceptions; +using Telegram.Bot.Requests; using Telegram.Bot.Tests.Integ.Framework; using Telegram.Bot.Types; using Xunit; @@ -12,16 +13,10 @@ namespace Telegram.Bot.Tests.Integ.Admin_Bot; [Collection(Constants.TestCollections.SupergroupAdminBots)] [TestCaseOrderer(Constants.TestCaseOrderer, Constants.AssemblyName)] -public class SupergroupAdminBotTests : IClassFixture +public class SupergroupAdminBotTests(SupergroupAdminBotTestsFixture classFixture) + : IClassFixture { - readonly SupergroupAdminBotTestsFixture _classFixture; - - ITelegramBotClient BotClient => _classFixture.TestsFixture.BotClient; - - public SupergroupAdminBotTests(SupergroupAdminBotTestsFixture classFixture) - { - _classFixture = classFixture; - } + ITelegramBotClient BotClient => classFixture.TestsFixture.BotClient; #region 1. Changing Chat Title @@ -30,8 +25,11 @@ public SupergroupAdminBotTests(SupergroupAdminBotTestsFixture classFixture) public async Task Should_Set_Chat_Title() { await BotClient.SetChatTitleAsync( - chatId: _classFixture.Chat.Id, - title: "Test Chat Title" + new() + { + ChatId = classFixture.Chat.Id, + Title = "Test Chat Title", + } ); } @@ -45,21 +43,31 @@ public async Task Should_Set_New_Default_Permissions() { ChatPermissions newDefaultPermissions = new() { - CanInviteUsers = false, - CanSendVoiceNotes = true, - CanChangeInfo = false, CanSendMessages = true, - CanPinMessages = false, + CanSendAudios = false, + CanSendDocuments = true, + CanSendPhotos =false, + CanSendVideos = false, + CanSendVideoNotes = false, + CanSendVoiceNotes = true, CanSendPolls = false, CanSendOtherMessages = false, - CanAddWebPagePreviews = false + CanAddWebPagePreviews = false, + CanChangeInfo = false, + CanInviteUsers = false, + CanPinMessages = false, + CanManageTopics = false, }; - await BotClient.SetChatPermissionsAsync(_classFixture.Chat.Id, newDefaultPermissions); - Chat supergroup = await BotClient.GetChatAsync(_classFixture.Chat.Id); - ChatPermissions setChatPermissions = supergroup.Permissions!; + await BotClient.SetChatPermissionsAsync(new() + { + ChatId = classFixture.Chat.Id, + Permissions = newDefaultPermissions, + }); - Asserts.JsonEquals(newDefaultPermissions, setChatPermissions); + Chat supergroup = await BotClient.GetChatAsync(new GetChatRequest { ChatId = classFixture.Chat.Id }); + Assert.NotNull(supergroup.Permissions); + Asserts.JsonEquals(newDefaultPermissions, supergroup.Permissions); } #endregion @@ -71,8 +79,11 @@ public async Task Should_Set_New_Default_Permissions() public async Task Should_Set_Chat_Description() { await BotClient.SetChatDescriptionAsync( - chatId: _classFixture.Chat.Id, - description: "Test Chat Description" + new SetChatDescriptionRequest + { + ChatId = classFixture.Chat.Id, + Description = "Test Chat Description", + } ); } @@ -83,7 +94,7 @@ public async Task Should_Delete_Chat_Description() // ToDo: exception Bad Request: chat description is not modified await BotClient.SetChatDescriptionAsync( - chatId: _classFixture.Chat.Id + new SetChatDescriptionRequest { ChatId = classFixture.Chat.Id, } ); } @@ -95,47 +106,60 @@ public async Task Should_Delete_Chat_Description() [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.PinChatMessage)] public async Task Should_Pin_Message() { - Message msg1 = await _classFixture.TestsFixture.SendTestInstructionsAsync("🧷 This message will be deleted second"); - Message msg2 = await _classFixture.TestsFixture.SendTestInstructionsAsync("🧷 This will be deleted as group"); - Message msg3 = await _classFixture.TestsFixture.SendTestInstructionsAsync("🧷 This will be deleted with previous one"); - Message msg4 = await _classFixture.TestsFixture.SendTestInstructionsAsync("🧷 This message will be deleted first"); + Message msg1 = await classFixture.TestsFixture.SendTestInstructionsAsync("🧷 This message will be deleted second"); + Message msg2 = await classFixture.TestsFixture.SendTestInstructionsAsync("🧷 This will be deleted as group"); + Message msg3 = await classFixture.TestsFixture.SendTestInstructionsAsync("🧷 This will be deleted with previous one"); + Message msg4 = await classFixture.TestsFixture.SendTestInstructionsAsync("🧷 This message will be deleted first"); await BotClient.PinChatMessageAsync( - chatId: _classFixture.Chat.Id, - messageId: msg1.MessageId, - disableNotification: true + new() + { + ChatId = classFixture.Chat.Id, + MessageId = msg1.MessageId, + DisableNotification = true, + } ); await BotClient.PinChatMessageAsync( - chatId: _classFixture.Chat.Id, - messageId: msg2.MessageId, - disableNotification: true + new() + { + ChatId = classFixture.Chat.Id, + MessageId = msg2.MessageId, + DisableNotification = true, + } ); await BotClient.PinChatMessageAsync( - chatId: _classFixture.Chat.Id, - messageId: msg3.MessageId, - disableNotification: true + new() + { + ChatId = classFixture.Chat.Id, + MessageId = msg3.MessageId, + DisableNotification = true, + } ); await BotClient.PinChatMessageAsync( - chatId: _classFixture.Chat.Id, - messageId: msg4.MessageId, - disableNotification: true + new() + { + ChatId = classFixture.Chat.Id, + MessageId = msg4.MessageId, + DisableNotification = true, + } ); - _classFixture.PinnedMessages.Add(msg1); - _classFixture.PinnedMessages.Add(msg2); - _classFixture.PinnedMessages.Add(msg3); - _classFixture.PinnedMessages.Add(msg4); + + classFixture.PinnedMessages.Add(msg1); + classFixture.PinnedMessages.Add(msg2); + classFixture.PinnedMessages.Add(msg3); + classFixture.PinnedMessages.Add(msg4); } [OrderedFact("Should get chat’s pinned message")] [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.GetChat)] public async Task Should_Get_Last_Chat_Pinned_Message() { - Message pinnedMsg = _classFixture.PinnedMessages.Last(); + Message pinnedMsg = classFixture.PinnedMessages.Last(); - Chat chat = await BotClient.GetChatAsync(_classFixture.Chat.Id); + Chat chat = await BotClient.GetChatAsync(new GetChatRequest { ChatId = classFixture.Chat.Id }); Assert.NotNull(chat.PinnedMessage); Assert.True(JToken.DeepEquals( @@ -147,14 +171,14 @@ public async Task Should_Get_Last_Chat_Pinned_Message() [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.UnpinChatMessage)] public async Task Should_Unpin_Last_Message() { - await BotClient.UnpinChatMessageAsync(_classFixture.Chat.Id); + await BotClient.UnpinChatMessageAsync(new UnpinChatMessageRequest { ChatId = classFixture.Chat.Id }); // Wait for chat object to update on Telegram servers await Task.Delay(TimeSpan.FromSeconds(5)); - Chat chat = await BotClient.GetChatAsync(_classFixture.Chat.Id); + Chat chat = await BotClient.GetChatAsync(new GetChatRequest { ChatId = classFixture.Chat.Id }); - Message secondsFromEndPinnedMessage = _classFixture.PinnedMessages[^2]; + Message secondsFromEndPinnedMessage = classFixture.PinnedMessages[^2]; Assert.NotNull(chat.PinnedMessage); Assert.True(JToken.DeepEquals( @@ -168,8 +192,11 @@ public async Task Should_Unpin_Last_Message() public async Task Should_Unpin_First_Message() { await BotClient.UnpinChatMessageAsync( - chatId: _classFixture.Chat.Id, - messageId: _classFixture.PinnedMessages.First().MessageId + new UnpinChatMessageRequest + { + ChatId = classFixture.Chat.Id, + MessageId = classFixture.PinnedMessages.First().MessageId, + } ); } @@ -177,14 +204,14 @@ public async Task Should_Unpin_First_Message() [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.UnpinAllChatMessages)] public async Task Should_Unpin_All_Messages() { - await BotClient.UnpinAllChatMessages(_classFixture.Chat); + await BotClient.UnpinAllChatMessagesAsync(new() { ChatId = classFixture.Chat }); } [OrderedFact("Should get the chat info without a pinned message")] [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.GetChat)] public async Task Should_Get_Chat_With_No_Pinned_Message() { - Chat chat = await BotClient.GetChatAsync(_classFixture.Chat.Id); + Chat chat = await BotClient.GetChatAsync(new GetChatRequest { ChatId = classFixture.Chat.Id }); Assert.Null(chat.PinnedMessage); } @@ -199,8 +226,11 @@ public async Task Should_Set_Chat_Photo() { await using Stream stream = System.IO.File.OpenRead(Constants.PathToFile.Photos.Logo); await BotClient.SetChatPhotoAsync( - chatId: _classFixture.Chat.Id, - photo: new InputFileStream(stream) + new() + { + ChatId = classFixture.Chat.Id, + Photo = InputFile.FromStream(stream), + } ); } @@ -208,7 +238,7 @@ public async Task Should_Set_Chat_Photo() [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.DeleteChatPhoto)] public async Task Should_Delete_Chat_Photo() { - await BotClient.DeleteChatPhotoAsync(_classFixture.Chat.Id); + await BotClient.DeleteChatPhotoAsync(new DeleteChatPhotoRequest { ChatId = classFixture.Chat.Id }); } [OrderedFact("Should throw exception in deleting chat photo with no photo currently set")] @@ -216,7 +246,7 @@ public async Task Should_Delete_Chat_Photo() public async Task Should_Throw_On_Deleting_Chat_Deleted_Photo() { ApiRequestException e = await Assert.ThrowsAsync( - () => BotClient.DeleteChatPhotoAsync(_classFixture.Chat.Id) + () => BotClient.DeleteChatPhotoAsync(new DeleteChatPhotoRequest { ChatId = classFixture.Chat.Id }) ); Assert.IsType(e); @@ -234,7 +264,11 @@ public async Task Should_Throw_On_Setting_Chat_Sticker_Set() const string setName = "EvilMinds"; ApiRequestException exception = await Assert.ThrowsAsync(() => - BotClient.SetChatStickerSetAsync(_classFixture.Chat.Id, setName) + BotClient.SetChatStickerSetAsync(new() + { + ChatId = classFixture.Chat.Id, + StickerSetName = setName, + }) ); Assert.Equal(400, exception.ErrorCode); @@ -251,23 +285,26 @@ public async Task Should_Create_Chat_Invite_Link() { DateTime createdAt = DateTime.UtcNow; - // Milliseconds are ignored during conversion to unix timestamp since it counts only up to + // Milliseconds are ignored during conversion to Unix timestamp since it counts only up to // seconds, so for equality to work later on assertion we need to zero out milliseconds DateTime expireDate = createdAt.With(new () {Millisecond = 0}).AddHours(1); string inviteLinkName = $"Created at {createdAt:yyyy-MM-ddTHH:mm:ss}Z"; ChatInviteLink chatInviteLink = await BotClient.CreateChatInviteLinkAsync( - chatId: _classFixture.TestsFixture.SupergroupChat.Id, - createsJoinRequest: true, - name: inviteLinkName, - expireDate: expireDate + new CreateChatInviteLinkRequest + { + ChatId = classFixture.TestsFixture.SupergroupChat.Id, + Name = inviteLinkName, + ExpireDate = expireDate, + CreatesJoinRequest = true, + } ); Assert.NotNull(chatInviteLink); Assert.NotNull(chatInviteLink.Creator); - Assert.Equal(_classFixture.TestsFixture.BotUser.Id, chatInviteLink.Creator.Id); - Assert.Equal(_classFixture.TestsFixture.BotUser.Username, chatInviteLink.Creator.Username); + Assert.Equal(classFixture.TestsFixture.BotUser.Id, chatInviteLink.Creator.Id); + Assert.Equal(classFixture.TestsFixture.BotUser.Username, chatInviteLink.Creator.Username); Assert.True(chatInviteLink.Creator.IsBot); Assert.NotNull(chatInviteLink.InviteLink); Assert.Matches("https://t.me/.+", chatInviteLink.InviteLink); @@ -279,7 +316,7 @@ public async Task Should_Create_Chat_Invite_Link() Assert.Equal(inviteLinkName, chatInviteLink.Name); Assert.Equal(expireDate, chatInviteLink.ExpireDate); - _classFixture.ChatInviteLink = chatInviteLink; + classFixture.ChatInviteLink = chatInviteLink; } [OrderedFact("Should edit previously created invite link to the group")] @@ -288,22 +325,25 @@ public async Task Should_Edit_Chat_Invite_Link() { DateTime editedAt = DateTime.UtcNow; - // Milliseconds are ignored during conversion to unix timestamp since it counts only up to + // Milliseconds are ignored during conversion to Unix timestamp since it counts only up to // seconds, so for equality to work later on assertion we need to zero out milliseconds DateTime expireDate = editedAt.With(new () {Millisecond = 0}).AddHours(1); string inviteLinkName = $"Edited at {editedAt:yyyy-MM-ddTHH:mm:ss}Z"; ChatInviteLink editedChatInviteLink = await BotClient.EditChatInviteLinkAsync( - chatId: _classFixture.TestsFixture.SupergroupChat.Id, - inviteLink: _classFixture.ChatInviteLink.InviteLink, - createsJoinRequest: false, - name: inviteLinkName, - expireDate: expireDate, - memberLimit: 100 + new() + { + ChatId = classFixture.TestsFixture.SupergroupChat.Id, + InviteLink = classFixture.ChatInviteLink.InviteLink, + Name = inviteLinkName, + ExpireDate = expireDate, + MemberLimit = 100, + CreatesJoinRequest = false, + } ); - ChatInviteLink chatInviteLink = _classFixture.ChatInviteLink; + ChatInviteLink chatInviteLink = classFixture.ChatInviteLink; Assert.NotNull(editedChatInviteLink); Assert.NotNull(editedChatInviteLink.Creator); @@ -317,7 +357,7 @@ public async Task Should_Edit_Chat_Invite_Link() Assert.Equal(chatInviteLink.PendingJoinRequestCount, editedChatInviteLink.PendingJoinRequestCount); Assert.Equal(chatInviteLink.IsRevoked, editedChatInviteLink.IsRevoked); - _classFixture.ChatInviteLink = editedChatInviteLink; + classFixture.ChatInviteLink = editedChatInviteLink; } #endregion @@ -327,11 +367,14 @@ public async Task Should_Edit_Chat_Invite_Link() public async Task Should_Revoke_Chat_Invite_Link() { ChatInviteLink revokedChatInviteLink = await BotClient.RevokeChatInviteLinkAsync( - chatId: _classFixture.TestsFixture.SupergroupChat.Id, - inviteLink: _classFixture.ChatInviteLink.InviteLink + new() + { + ChatId = classFixture.TestsFixture.SupergroupChat.Id, + InviteLink = classFixture.ChatInviteLink.InviteLink, + } ); - ChatInviteLink editedChatInviteLink = _classFixture.ChatInviteLink; + ChatInviteLink editedChatInviteLink = classFixture.ChatInviteLink; Assert.NotNull(revokedChatInviteLink); Assert.NotNull(revokedChatInviteLink.Creator); diff --git a/test/Telegram.Bot.Tests.Integ/Admin Bot/SupergroupAdminBotTestsFixture.cs b/test/Telegram.Bot.Tests.Integ/Admin Bot/SupergroupAdminBotTestsFixture.cs index 718988bfd..5c12c81cf 100644 --- a/test/Telegram.Bot.Tests.Integ/Admin Bot/SupergroupAdminBotTestsFixture.cs +++ b/test/Telegram.Bot.Tests.Integ/Admin Bot/SupergroupAdminBotTestsFixture.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.IO; +using Telegram.Bot.Requests; using Telegram.Bot.Tests.Integ.Framework; using Telegram.Bot.Tests.Integ.Framework.Fixtures; using Telegram.Bot.Types; @@ -22,9 +23,9 @@ public SupergroupAdminBotTestsFixture(TestsFixture testsFixture) PinnedMessages = new(3); AddLifetime( - initialize: async () => + initializer: async () => { - Chat chat = await TestsFixture.BotClient.GetChatAsync(TestsFixture.SupergroupChat); + Chat chat = await TestsFixture.BotClient.GetChatAsync(new GetChatRequest { ChatId = TestsFixture.SupergroupChat }); // Save existing chat photo as byte[] to restore it later because Bot API 4.4+ invalidates old // file_ids after changing chat photo @@ -39,31 +40,39 @@ public SupergroupAdminBotTestsFixture(TestsFixture testsFixture) // Save default permissions so they can be restored _existingDefaultPermissions = chat.Permissions!; }, - dispose: async () => + finalizer: async () => { // If chat had a photo before, reset the photo back. if (_oldChatPhoto is not null) { await using MemoryStream photoStream = new(_oldChatPhoto); await TestsFixture.BotClient.SetChatPhotoAsync( - chatId: Chat.Id, - photo: new InputFileStream(photoStream) + new() + { + ChatId = Chat.Id, + Photo = InputFile.FromStream(photoStream), + } ); } // Reset original default permissions await TestsFixture.BotClient.SetChatPermissionsAsync( - TestsFixture.SupergroupChat, - _existingDefaultPermissions! - + new() + { + ChatId = TestsFixture.SupergroupChat, + Permissions = _existingDefaultPermissions!, + } ); // Revoke invite link created during the test run if (ChatInviteLink is not null) { await TestsFixture.BotClient.RevokeChatInviteLinkAsync( - chatId: TestsFixture.SupergroupChat, - inviteLink: ChatInviteLink.InviteLink + new() + { + ChatId = TestsFixture.SupergroupChat, + InviteLink = ChatInviteLink.InviteLink, + } ); } } diff --git a/test/Telegram.Bot.Tests.Integ/Exceptions/ApiExceptionsTests.cs b/test/Telegram.Bot.Tests.Integ/Exceptions/ApiExceptionsTests.cs index 5adef95c9..5d4510dd4 100644 --- a/test/Telegram.Bot.Tests.Integ/Exceptions/ApiExceptionsTests.cs +++ b/test/Telegram.Bot.Tests.Integ/Exceptions/ApiExceptionsTests.cs @@ -1,8 +1,6 @@ using System.Threading.Tasks; using Telegram.Bot.Exceptions; using Telegram.Bot.Tests.Integ.Framework; -using Telegram.Bot.Types; -using Telegram.Bot.Types.Enums; using Xunit; namespace Telegram.Bot.Tests.Integ.Exceptions; @@ -10,43 +8,39 @@ namespace Telegram.Bot.Tests.Integ.Exceptions; [Collection(Constants.TestCollections.Exceptions)] [Trait(Constants.CategoryTraitName, Constants.InteractiveCategoryValue)] [TestCaseOrderer(Constants.TestCaseOrderer, Constants.AssemblyName)] -public class ApiExceptionsTests +public class ApiExceptionsTests(TestsFixture fixture) { - ITelegramBotClient BotClient => _fixture.BotClient; + ITelegramBotClient BotClient => fixture.BotClient; - readonly TestsFixture _fixture; - - public ApiExceptionsTests(TestsFixture fixture) - { - _fixture = fixture; - } - - [OrderedFact("Should throw ChatNotInitiatedException while trying to send message to a user who hasn't " + + [OrderedFact("Should throw ChatNotFoundException while trying to send message to a user who hasn't " + "started a chat with bot but bot knows about him/her.")] [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.SendMessage)] - public async Task Should_Throw_Exception_ChatNotInitiatedException() + public async Task Should_Throw_Exception_ChatNotFoundException() { //ToDo add exception. forward message from another bot. Forbidden: bot can't send messages to bots - await _fixture.SendTestInstructionsAsync( + await fixture.SendTestInstructionsAsync( "Forward a message to this chat from a user that never started a chat with this bot" ); - await _fixture.UpdateReceiver.DiscardNewUpdatesAsync(); + //await _fixture.UpdateReceiver.DiscardNewUpdatesAsync(); - Update forwardedMessageUpdate = await _fixture.UpdateReceiver.GetUpdateAsync( - predicate: u => u.Message?.ForwardFrom is not null, - updateTypes: new[] { UpdateType.Message } - ); + //Update forwardedMessageUpdate = await _fixture.UpdateReceiver.GetUpdateAsync( + // predicate: u => u.Message?.ForwardOrigin is not null, + // updateTypes: [UpdateType.Message] + //); - User forwardFromUser = forwardedMessageUpdate.Message!.ForwardFrom!; + //MessageOriginHiddenUser hiddenUser = (MessageOriginHiddenUser)forwardedMessageUpdate.Message!.ForwardOrigin; ApiRequestException e = await Assert.ThrowsAsync(async () => - await BotClient.SendTextMessageAsync( - forwardFromUser.Id, - $"Error! If you see this message, talk to @{forwardFromUser.Username}" + await BotClient.SendMessageAsync( + new() + { + ChatId = int.MaxValue, + Text = "Error!", + } ) ); - Assert.Equal(403, e.ErrorCode); + Assert.Equal(400, e.ErrorCode); } -} \ No newline at end of file +} diff --git a/test/Telegram.Bot.Tests.Integ/Exceptions/ApiExceptionsTests2.cs b/test/Telegram.Bot.Tests.Integ/Exceptions/ApiExceptionsTests2.cs index 542fb0ec7..179449bbe 100644 --- a/test/Telegram.Bot.Tests.Integ/Exceptions/ApiExceptionsTests2.cs +++ b/test/Telegram.Bot.Tests.Integ/Exceptions/ApiExceptionsTests2.cs @@ -1,5 +1,6 @@ using System.Threading.Tasks; using Telegram.Bot.Exceptions; +using Telegram.Bot.Requests; using Telegram.Bot.Tests.Integ.Framework; using Telegram.Bot.Types; using Telegram.Bot.Types.ReplyMarkups; @@ -9,23 +10,22 @@ namespace Telegram.Bot.Tests.Integ.Exceptions; [Collection(Constants.TestCollections.Exceptions2)] [TestCaseOrderer(Constants.TestCaseOrderer, Constants.AssemblyName)] -public class ApiExceptionsTests2 +public class ApiExceptionsTests2(TestsFixture fixture) { - ITelegramBotClient BotClient => _fixture.BotClient; - - readonly TestsFixture _fixture; - - public ApiExceptionsTests2(TestsFixture fixture) - { - _fixture = fixture; - } + ITelegramBotClient BotClient => fixture.BotClient; [OrderedFact("Should throw ChatNotFoundException while trying to send message to an invalid chat")] [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.SendMessage)] public async Task Should_Throw_Exception_ChatNotFoundException() { ApiRequestException e = await Assert.ThrowsAsync(() => - BotClient.SendTextMessageAsync(0, "test") + BotClient.SendMessageAsync( + new() + { + ChatId = 0, + Text = "test", + } + ) ); Assert.Equal(400, e.ErrorCode); @@ -36,7 +36,13 @@ public async Task Should_Throw_Exception_ChatNotFoundException() public async Task Should_Throw_Exception_UserNotFoundException() { ApiRequestException e = await Assert.ThrowsAsync(() => - BotClient.PromoteChatMemberAsync(_fixture.SupergroupChat.Id, 123456) + BotClient.PromoteChatMemberAsync( + new() + { + ChatId = fixture.SupergroupChat.Id, + UserId = 123456, + } + ) ); Assert.Equal(400, e.ErrorCode); @@ -53,10 +59,13 @@ public async Task Should_Throw_Exception_ApiRequestException() }); ApiRequestException exception = await Assert.ThrowsAsync(() => - BotClient.SendTextMessageAsync( - chatId: _fixture.SupergroupChat.Id, - text: "You should never see this message", - replyMarkup: replyMarkup + BotClient.SendMessageAsync( + new() + { + ChatId = fixture.SupergroupChat.Id, + Text = "You should never see this message", + ReplyMarkup = replyMarkup, + } ) ); @@ -69,19 +78,25 @@ public async Task Should_Throw_Exception_ApiRequestException() public async Task Should_Throw_Exception_MessageIsNotModifiedException() { const string messageTextToModify = "Message text to modify"; - Message message = await BotClient.SendTextMessageAsync( - chatId: _fixture.SupergroupChat.Id, - text: messageTextToModify + Message message = await BotClient.SendMessageAsync( + new() + { + ChatId = fixture.SupergroupChat.Id, + Text = messageTextToModify, + } ); ApiRequestException e = await Assert.ThrowsAsync(() => BotClient.EditMessageTextAsync( - chatId: _fixture.SupergroupChat.Id, - messageId: message.MessageId, - text: messageTextToModify + new() + { + ChatId = fixture.SupergroupChat.Id, + MessageId = message.MessageId, + Text = messageTextToModify, + } ) ); Assert.Equal(400, e.ErrorCode); } -} \ No newline at end of file +} diff --git a/test/Telegram.Bot.Tests.Integ/Framework/Constants.cs b/test/Telegram.Bot.Tests.Integ/Framework/Constants.cs index 4227fd681..44e0ebb69 100644 --- a/test/Telegram.Bot.Tests.Integ/Framework/Constants.cs +++ b/test/Telegram.Bot.Tests.Integ/Framework/Constants.cs @@ -328,6 +328,8 @@ public static class TelegramBotApiMethods public const string DeleteMessage = "deleteMessage"; + public const string DeleteMessages = "deleteMessages"; + public const string SendLocation = "sendLocation"; public const string EditMessageLiveLocation = "editMessageLiveLocation"; @@ -402,6 +404,8 @@ public static class TelegramBotApiMethods public const string CopyMessage = "copyMessage"; + public const string CopyMessages = "copyMessages"; + public const string UnpinAllChatMessages = "unpinAllChatMessages"; } } diff --git a/test/Telegram.Bot.Tests.Integ/Framework/Fixtures/AsyncLifetimeFixture.cs b/test/Telegram.Bot.Tests.Integ/Framework/Fixtures/AsyncLifetimeFixture.cs index 6922a52bb..c395b0bc7 100644 --- a/test/Telegram.Bot.Tests.Integ/Framework/Fixtures/AsyncLifetimeFixture.cs +++ b/test/Telegram.Bot.Tests.Integ/Framework/Fixtures/AsyncLifetimeFixture.cs @@ -10,16 +10,32 @@ namespace Telegram.Bot.Tests.Integ.Framework.Fixtures; public abstract class AsyncLifetimeFixture : IAsyncLifetime { - readonly List _lifetimes = new(); + readonly List _lifetimes = []; + + protected virtual IEnumerable Lifetimes() => []; + protected virtual IEnumerable> Initializers() => []; + protected virtual IEnumerable> Finalizers() => []; + + protected AsyncLifetimeFixture() + { + // ReSharper disable VirtualMemberCallInConstructor + _lifetimes.AddRange(Initializers().Select(initializer => new AsyncLifetimeAction(initializer: initializer))); + _lifetimes.AddRange(Lifetimes()); + _lifetimes.AddRange(Finalizers().Select(finalizer => new AsyncLifetimeAction(finalizer: finalizer))); + // ReSharper restore VirtualMemberCallInConstructor + } protected void AddLifetime(IAsyncLifetime lifetime) => _lifetimes.Add(lifetime); - protected void AddLifetime(Func? initialize = default, Func? dispose = default) => - _lifetimes.Add(new AsyncLifetimeAction(initialize, dispose)); + protected void AddLifetime(Func? initializer = default, Func? finalizer = default) => + _lifetimes.Add(new AsyncLifetimeAction(initializer, finalizer)); - protected void AddLifetime(Action? initialize = default, Action? dispose = default) => - _lifetimes.Add(new AsyncLifetimeAction(initialize, dispose)); + protected void AddInitializer(Func initializer) => + _lifetimes.Add(new AsyncLifetimeAction(initializer: initializer)); + + protected void AddFinalizer(Func finalizer) => + _lifetimes.Add(new AsyncLifetimeAction(finalizer: finalizer)); public async Task InitializeAsync() { @@ -31,53 +47,24 @@ public async Task InitializeAsync() public async Task DisposeAsync() { - // dispose in reverse order because later lifetimes might depend on previous lifetimes to be intact + // finalizer in reverse order because later lifetimes might depend on previous lifetimes to be intact foreach (var asyncLifetime in ((IEnumerable)_lifetimes).Reverse()) { await asyncLifetime.DisposeAsync(); } } - sealed class AsyncLifetimeAction : IAsyncLifetime + public sealed class AsyncLifetimeAction(Func? initializer = default, Func? finalizer = default) + : IAsyncLifetime { - readonly Func? _initialize; - readonly Func? _dispose; - - public AsyncLifetimeAction(Func? initialize = default, Func? dispose = default) - { - _initialize = initialize; - _dispose = dispose; - } - - public AsyncLifetimeAction(Action? initialize = default, Action? dispose = default) - { - if (initialize is not null) - { - _initialize = () => - { - initialize.Invoke(); - return Task.CompletedTask; - }; - } - - if (dispose is not null) - { - _dispose = () => - { - dispose.Invoke(); - return Task.CompletedTask; - }; - } - } - public async Task InitializeAsync() { - if (_initialize is not null) { await _initialize(); } + if (initializer is not null) { await initializer(); } } public async Task DisposeAsync() { - if (_dispose is not null) { await _dispose(); } + if (finalizer is not null) { await finalizer(); } } } -} \ No newline at end of file +} diff --git a/test/Telegram.Bot.Tests.Integ/Framework/Fixtures/ChannelChatFixture.cs b/test/Telegram.Bot.Tests.Integ/Framework/Fixtures/ChannelChatFixture.cs index 5f7b5698d..5c83c2fcf 100644 --- a/test/Telegram.Bot.Tests.Integ/Framework/Fixtures/ChannelChatFixture.cs +++ b/test/Telegram.Bot.Tests.Integ/Framework/Fixtures/ChannelChatFixture.cs @@ -1,4 +1,5 @@ using System.Threading.Tasks; +using Telegram.Bot.Requests; using Telegram.Bot.Types; using Telegram.Bot.Types.Enums; @@ -15,8 +16,8 @@ public ChannelChatFixture(TestsFixture testsFixture, string collectionName) { _testsFixture = testsFixture; - AddLifetime( - initialize: async () => + AddInitializer( + async () => { _testsFixture.ChannelChat ??= await GetChat(collectionName); ChannelChat = _testsFixture.ChannelChat; @@ -34,7 +35,8 @@ public ChannelChatFixture(TestsFixture testsFixture, string collectionName) async Task GetChat(string collectionName) { var chatId = _testsFixture.Configuration.ChannelChatId; - if (chatId is not null) return await _testsFixture.BotClient.GetChatAsync(chatId.Value); + if (chatId is not null) + return await _testsFixture.BotClient.GetChatAsync(new GetChatRequest {ChatId = chatId.Value}); await _testsFixture.UpdateReceiver.DiscardNewUpdatesAsync(); @@ -46,4 +48,4 @@ async Task GetChat(string collectionName) return await _testsFixture.GetChatFromTesterAsync(ChatType.Channel); } -} \ No newline at end of file +} diff --git a/test/Telegram.Bot.Tests.Integ/Framework/Fixtures/PrivateChatFixture.cs b/test/Telegram.Bot.Tests.Integ/Framework/Fixtures/PrivateChatFixture.cs index ce1888912..c01cf0ff7 100644 --- a/test/Telegram.Bot.Tests.Integ/Framework/Fixtures/PrivateChatFixture.cs +++ b/test/Telegram.Bot.Tests.Integ/Framework/Fixtures/PrivateChatFixture.cs @@ -1,4 +1,5 @@ using System.Threading.Tasks; +using Telegram.Bot.Requests; using Telegram.Bot.Types; using Telegram.Bot.Types.Enums; @@ -10,8 +11,8 @@ public class PrivateChatFixture : AsyncLifetimeFixture public PrivateChatFixture(TestsFixture testsFixture, string collectionName) { - AddLifetime( - initialize: async () => + AddInitializer( + async () => { testsFixture.PrivateChat ??= await GetChat(testsFixture, collectionName); PrivateChat = testsFixture.PrivateChat; @@ -30,7 +31,7 @@ static async Task GetChat(TestsFixture testsFixture, string collectionName long? chatId = testsFixture.Configuration.TesterPrivateChatId; if (chatId.HasValue) { - chat = await testsFixture.BotClient.GetChatAsync(chatId); + chat = await testsFixture.BotClient.GetChatAsync(new GetChatRequest { ChatId = chatId}); } else { @@ -46,4 +47,4 @@ static async Task GetChat(TestsFixture testsFixture, string collectionName } return chat; } -} \ No newline at end of file +} diff --git a/test/Telegram.Bot.Tests.Integ/Framework/OrderedFactAttribute.cs b/test/Telegram.Bot.Tests.Integ/Framework/OrderedFactAttribute.cs index 61a8a00b2..3d9eb369c 100644 --- a/test/Telegram.Bot.Tests.Integ/Framework/OrderedFactAttribute.cs +++ b/test/Telegram.Bot.Tests.Integ/Framework/OrderedFactAttribute.cs @@ -78,10 +78,10 @@ public Type ExceptionType /// Line number in source file. public OrderedFactAttribute(string description, [CallerLineNumber] int line = default) { - if (line < 1) { throw new ArgumentOutOfRangeException(nameof(line)); } + ArgumentOutOfRangeException.ThrowIfLessThan(line, 1); // ReSharper disable once VirtualMemberCallInConstructor if (!string.IsNullOrWhiteSpace(description)) { DisplayName = description; } LineNumber = line; } -} \ No newline at end of file +} diff --git a/test/Telegram.Bot.Tests.Integ/Framework/RetryTelegramBotClient.cs b/test/Telegram.Bot.Tests.Integ/Framework/RetryTelegramBotClient.cs index e0197e156..5bdae8b08 100644 --- a/test/Telegram.Bot.Tests.Integ/Framework/RetryTelegramBotClient.cs +++ b/test/Telegram.Bot.Tests.Integ/Framework/RetryTelegramBotClient.cs @@ -10,45 +10,30 @@ namespace Telegram.Bot.Tests.Integ.Framework; -internal class TestClientOptions : TelegramBotClientOptions +internal class TestClientOptions( + string token, + string? baseUrl, + bool useTestEnvironment, + int retryCount, + TimeSpan defaultTimeout) + : TelegramBotClientOptions(token, baseUrl, useTestEnvironment) { - public int RetryCount { get; } - public TimeSpan DefaultTimeout { get; } - - public TestClientOptions( - string token, - string? baseUrl, - bool useTestEnvironment, - int retryCount, - TimeSpan defaultTimeout) - : base(token, baseUrl, useTestEnvironment) - { - RetryCount = retryCount; - DefaultTimeout = defaultTimeout; - } + public int RetryCount { get; } = retryCount; + public TimeSpan DefaultTimeout { get; } = defaultTimeout; }; -internal class RetryTelegramBotClient : TelegramBotClient +internal class RetryTelegramBotClient( + IMessageSink diagnosticMessageSink, + TestClientOptions options) + : TelegramBotClient(options) { - readonly IMessageSink _diagnosticMessageSink; - readonly TestClientOptions _options; - - public RetryTelegramBotClient( - IMessageSink diagnosticMessageSink, - TestClientOptions options) - : base(options) - { - _diagnosticMessageSink = diagnosticMessageSink; - _options = options; - } - public override async Task MakeRequestAsync( IRequest request, CancellationToken cancellationToken = default) { ApiRequestException apiRequestException = default!; - for (var i = 0; i < _options.RetryCount; i++) + for (var i = 0; i < options.RetryCount; i++) { try { @@ -59,11 +44,11 @@ internal class RetryTelegramBotClient : TelegramBotClient apiRequestException = e; var timeout = e.Parameters?.RetryAfter is null - ? _options.DefaultTimeout + ? options.DefaultTimeout : TimeSpan.FromSeconds(e.Parameters.RetryAfter.Value); var message = $"Retry attempt {i + 1}. Waiting for {timeout} seconds before retrying."; - _diagnosticMessageSink.OnMessage(new DiagnosticMessage(message)); + diagnosticMessageSink.OnMessage(new DiagnosticMessage(message)); await Task.Delay(timeout, cancellationToken); } } diff --git a/test/Telegram.Bot.Tests.Integ/Framework/TestCollectionOrderer.cs b/test/Telegram.Bot.Tests.Integ/Framework/TestCollectionOrderer.cs index 5e61a377e..ab0e508a2 100644 --- a/test/Telegram.Bot.Tests.Integ/Framework/TestCollectionOrderer.cs +++ b/test/Telegram.Bot.Tests.Integ/Framework/TestCollectionOrderer.cs @@ -10,7 +10,7 @@ namespace Telegram.Bot.Tests.Integ.Framework; public class TestCollectionOrderer : ITestCollectionOrderer { readonly string[] _orderedCollections = - { + [ // Tests that require user interaction: Constants.TestCollections.CallbackQuery, Constants.TestCollections.PrivateChatReplyMarkup, @@ -58,7 +58,7 @@ public class TestCollectionOrderer : ITestCollectionOrderer Constants.TestCollections.ChannelAdminBots, Constants.TestCollections.Exceptions2, Constants.TestCollections.SendCopyMessage - }; + ]; public IEnumerable OrderTestCollections(IEnumerable testCollections) { diff --git a/test/Telegram.Bot.Tests.Integ/Framework/TestsFixture.cs b/test/Telegram.Bot.Tests.Integ/Framework/TestsFixture.cs index 135afd2ee..d01ba853f 100644 --- a/test/Telegram.Bot.Tests.Integ/Framework/TestsFixture.cs +++ b/test/Telegram.Bot.Tests.Integ/Framework/TestsFixture.cs @@ -5,6 +5,7 @@ using System.Threading; using System.Threading.Tasks; using Telegram.Bot.Args; +using Telegram.Bot.Requests; using Telegram.Bot.Types; using Telegram.Bot.Types.Enums; using Telegram.Bot.Types.ReplyMarkups; @@ -52,17 +53,21 @@ public void Dispose() await UpdateReceiver.DiscardNewUpdatesAsync(token); var passed = RunSummary.Total - RunSummary.Skipped - RunSummary.Failed; - await BotClient.SendTextMessageAsync( - chatId: SupergroupChat.Id, - text: string.Format( - Constants.TestExecutionResultMessageFormat, - RunSummary.Total, - passed, - RunSummary.Skipped, - RunSummary.Failed - ), - parseMode: ParseMode.Markdown, - cancellationToken: token + await BotClient.SendMessageAsync( + new() + { + ChatId = SupergroupChat.Id, + Text = string.Format( + Constants.TestExecutionResultMessageFormat, + RunSummary.Total, + passed, + RunSummary.Skipped, + RunSummary.Failed + ), + ParseMode = ParseMode.Markdown, + + }, + token ); }).GetAwaiter().GetResult(); } @@ -80,12 +85,15 @@ public void Dispose() : default; return await Ex.WithCancellation(async token => - await BotClient.SendTextMessageAsync( - chatId: chatId, - text: text, - parseMode: ParseMode.Markdown, - replyMarkup: replyMarkup, - cancellationToken: token + await BotClient.SendMessageAsync( + new() + { + ChatId = chatId, + Text = text, + ParseMode = ParseMode.Markdown, + ReplyMarkup = replyMarkup, + }, + token ) ); } @@ -118,7 +126,7 @@ public void Dispose() u.Message.Text?.StartsWith("/test", StringComparison.OrdinalIgnoreCase) == true ) || ( ChatType.Channel == chatType && - ChatType.Channel == u.Message?.ForwardFromChat?.Type + u.Message?.ForwardOrigin is MessageOriginChannel ); var updates = await UpdateReceiver.GetUpdatesAsync( @@ -132,35 +140,35 @@ public void Dispose() await UpdateReceiver.DiscardNewUpdatesAsync(cancellationToken); return chatType == ChatType.Channel - ? update.Message?.ForwardFromChat + ? ((MessageOriginChannel)update.Message?.ForwardOrigin)!.Chat : update.Message?.Chat; } public async Task GetChatFromAdminAsync() { - static bool IsMatch(Update u) => u is - { - Message: - { - Type: MessageType.Contact, - ForwardFrom: not null, - NewChatMembers.Length: > 0, - } - }; + await UpdateReceiver.DiscardNewUpdatesAsync(); - var update = await UpdateReceiver.GetUpdateAsync(IsMatch, updateTypes: UpdateType.Message); + var update = await UpdateReceiver.GetUpdateAsync( + IsMatch, + updateTypes: [UpdateType.Message, UpdateType.ChatMember] + ); await UpdateReceiver.DiscardNewUpdatesAsync(); var userId = update.Message switch { { Contact.UserId: {} id } => id, - { ForwardFrom.Id: var id } => id, + { ForwardOrigin: MessageOriginUser originUser } => originUser.SenderUser.Id, { NewChatMembers: { Length: 1 } members } => members[0].Id, _ => throw new InvalidOperationException() }; - return await BotClient.GetChatAsync(userId!); + return await BotClient.GetChatAsync(new GetChatRequest { ChatId = userId! }); + + static bool IsMatch(Update u) => u + is { Message.Type: MessageType.Contact } + or { Message.NewChatMembers.Length: > 0 } + or { Message.ForwardOrigin: not null }; } async Task InitAsync() @@ -182,8 +190,8 @@ async Task InitAsync() var allowedUserNames = await Ex.WithCancellation( async token => { - BotUser = await BotClient.GetMeAsync(token); - await BotClient.DeleteWebhookAsync(cancellationToken: token); + BotUser = await BotClient.GetMeAsync(new(), token); + await BotClient.DeleteWebhookAsync(new DeleteWebhookRequest(), token); SupergroupChat = await FindSupergroupTestChatAsync(token); return await FindAllowedTesterUserNames(token); @@ -192,20 +200,23 @@ async Task InitAsync() UpdateReceiver = new(BotClient, allowedUserNames); - await Ex.WithCancellation(async token => await BotClient.SendTextMessageAsync( - chatId: SupergroupChat.Id, - text: $""" - ``` - Test execution is starting... - ``` - #testers - These users are allowed to interact with the bot: - - {UpdateReceiver.GetTesters()} - """, - parseMode: ParseMode.Markdown, - disableNotification: true, - cancellationToken: token + await Ex.WithCancellation(async token => await BotClient.SendMessageAsync( + new() + { + ChatId = SupergroupChat.Id, + Text = $""" + ``` + Test execution is starting... + ``` + #testers + These users are allowed to interact with the bot: + + {UpdateReceiver.GetTesters()} + """, + ParseMode = ParseMode.Markdown, + DisableNotification = true, + }, + token )); #if DEBUG @@ -238,12 +249,15 @@ async Task InitAsync() ? (InlineKeyboardMarkup)InlineKeyboardButton.WithSwitchInlineQueryCurrentChat("Start inline query") : default; - var task = BotClient.SendTextMessageAsync( - chatId: chatId, - text: text, - parseMode: ParseMode.Markdown, - replyMarkup: replyMarkup, - cancellationToken: cancellationToken + var task = BotClient.SendMessageAsync( + new() + { + ChatId = chatId, + Text = text, + ParseMode = ParseMode.Markdown, + ReplyMarkup = replyMarkup, + }, + cancellationToken ); return task; } @@ -251,7 +265,7 @@ async Task InitAsync() async Task FindSupergroupTestChatAsync(CancellationToken cancellationToken = default) { var supergroupChatId = Configuration.SuperGroupChatId; - return await BotClient.GetChatAsync(supergroupChatId, cancellationToken); + return await BotClient.GetChatAsync(new GetChatRequest {ChatId = supergroupChatId}, cancellationToken); } async Task> FindAllowedTesterUserNames(CancellationToken cancellationToken = default) @@ -259,10 +273,12 @@ async Task> FindAllowedTesterUserNames(CancellationToken can // Try to get user names from test configurations first var allowedUserNames = Configuration.AllowedUserNames; - if (allowedUserNames.Any()) return allowedUserNames; + if (allowedUserNames.Length != 0) return allowedUserNames; // Assume all chat admins are allowed testers - var admins = await BotClient.GetChatAdministratorsAsync(SupergroupChat, cancellationToken); + var admins = await BotClient.GetChatAdministratorsAsync( + new GetChatAdministratorsRequest {ChatId = SupergroupChat}, cancellationToken + ); allowedUserNames = admins .Where(member => !member.User.IsBot) .Select(member => member.User.Username) @@ -306,7 +322,7 @@ async Task> FindAllowedTesterUserNames(CancellationToken can } } - multipartContent = stringifiedFormContent.ToArray(); + multipartContent = [..stringifiedFormContent]; } else { diff --git a/test/Telegram.Bot.Tests.Integ/Framework/UpdateReceiver.cs b/test/Telegram.Bot.Tests.Integ/Framework/UpdateReceiver.cs index 5b41156f3..14010064e 100644 --- a/test/Telegram.Bot.Tests.Integ/Framework/UpdateReceiver.cs +++ b/test/Telegram.Bot.Tests.Integ/Framework/UpdateReceiver.cs @@ -17,17 +17,9 @@ public enum UpdatePosition Single } -public class UpdateReceiver +public class UpdateReceiver(ITelegramBotClient botClient, IEnumerable? allowedUsernames) { - readonly ITelegramBotClient _botClient; - - public List AllowedUsernames { get; } - - public UpdateReceiver(ITelegramBotClient botClient, IEnumerable? allowedUsernames) - { - _botClient = botClient; - AllowedUsernames = allowedUsernames?.ToList() ?? new(); - } + public List AllowedUsernames { get; } = allowedUsernames?.ToList() ?? []; public async Task DiscardNewUpdatesAsync(CancellationToken cancellationToken = default) { @@ -45,9 +37,12 @@ public async Task DiscardNewUpdatesAsync(CancellationToken cancellationToken = d while (!cancellationToken.IsCancellationRequested) { - var updates = await _botClient.GetUpdatesAsync( - offset: offset, - allowedUpdates: Array.Empty(), + var updates = await botClient.GetUpdatesAsync( + new() + { + Offset = offset, + AllowedUpdates = Enum.GetValues().Where(u => u != UpdateType.Unknown) + }, cancellationToken: cancellationToken ); @@ -79,7 +74,7 @@ public async Task DiscardNewUpdatesAsync(CancellationToken cancellationToken = d cancellationToken = cts.Token; } - Update[] matchingUpdates = Array.Empty(); + Update[] matchingUpdates = []; while (!cancellationToken.IsCancellationRequested) { @@ -143,9 +138,9 @@ public async Task DiscardNewUpdatesAsync(CancellationToken cancellationToken = d if (discardNewUpdates) { await DiscardNewUpdatesAsync(cancellationToken); } var updates = await GetUpdatesAsync( - predicate: u => (messageId is null || u.CallbackQuery?.Message?.MessageId == messageId) && + predicate: u => (messageId is null || ((Message?)u.CallbackQuery?.Message)?.MessageId == messageId) && (data is null || u.CallbackQuery?.Data == data), - updateTypes: new [] { UpdateType.CallbackQuery }, + updateTypes: [UpdateType.CallbackQuery], cancellationToken: cancellationToken ); @@ -161,7 +156,7 @@ public async Task DiscardNewUpdatesAsync(CancellationToken cancellationToken = d if (discardNewUpdates) { await DiscardNewUpdatesAsync(cancellationToken); } var updates = await GetUpdatesAsync( - updateTypes: new [] { UpdateType.InlineQuery }, + updateTypes: [UpdateType.InlineQuery], cancellationToken: cancellationToken ); @@ -190,11 +185,10 @@ public async Task DiscardNewUpdatesAsync(CancellationToken cancellationToken = d { await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken); var updates = await GetUpdatesAsync( - predicate: u => (u.Message is { Chat.Id: var id, Type: var type } && - id == chatId && type == messageType) || - u.ChosenInlineResult is not null, + predicate: u => (u.Message is { Chat.Id: var id, Type: var type } && id == chatId && type == messageType) + || u.ChosenInlineResult is not null, cancellationToken: cancellationToken, - updateTypes: new[] { UpdateType.Message, UpdateType.ChosenInlineResult } + updateTypes: [UpdateType.Message, UpdateType.ChosenInlineResult] ); messageUpdate = updates.SingleOrDefault(u => u.Message?.Type == messageType); @@ -209,7 +203,7 @@ public async Task DiscardNewUpdatesAsync(CancellationToken cancellationToken = d CancellationToken cancellationToken, (Update? update1, Update? update2) updates ) => - !cancellationToken.IsCancellationRequested && updates is not ({}, {}); + !cancellationToken.IsCancellationRequested && updates is not (not null, not null); } async Task GetOnlyAllowedUpdatesAsync( @@ -217,10 +211,12 @@ public async Task DiscardNewUpdatesAsync(CancellationToken cancellationToken = d CancellationToken cancellationToken, params UpdateType[] types) { - var updates = await _botClient.GetUpdatesAsync( - offset: offset, - timeout: 120, - allowedUpdates: types, + var updates = await botClient.GetUpdatesAsync( + new() { + Offset = offset, + Timeout = 120, + AllowedUpdates = types, + }, cancellationToken: cancellationToken ); @@ -243,10 +239,10 @@ or UpdateType.PollAnswer or UpdateType.ChatMember or UpdateType.MyChatMember or UpdateType.ChatJoinRequest => - AllowedUsernames.Contains( - update.GetUser().Username, - StringComparer.OrdinalIgnoreCase - ), + AllowedUsernames.Contains( + update.GetUser().Username, + StringComparer.OrdinalIgnoreCase + ), UpdateType.Poll => true, UpdateType.EditedMessage or UpdateType.ChannelPost diff --git a/test/Telegram.Bot.Tests.Integ/Framework/XunitExtensions/AssemblyFixtureAttribute.cs b/test/Telegram.Bot.Tests.Integ/Framework/XunitExtensions/AssemblyFixtureAttribute.cs index 14106f60c..78d9ef99d 100644 --- a/test/Telegram.Bot.Tests.Integ/Framework/XunitExtensions/AssemblyFixtureAttribute.cs +++ b/test/Telegram.Bot.Tests.Integ/Framework/XunitExtensions/AssemblyFixtureAttribute.cs @@ -3,12 +3,7 @@ namespace Telegram.Bot.Tests.Integ.Framework.XunitExtensions; [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] -public class AssemblyFixtureAttribute : Attribute +public class AssemblyFixtureAttribute(Type fixtureType) : Attribute { - public Type FixtureType { get; } - - public AssemblyFixtureAttribute(Type fixtureType) - { - FixtureType = fixtureType; - } + public Type FixtureType { get; } = fixtureType; } \ No newline at end of file diff --git a/test/Telegram.Bot.Tests.Integ/Framework/XunitExtensions/DelayedMessageBus.cs b/test/Telegram.Bot.Tests.Integ/Framework/XunitExtensions/DelayedMessageBus.cs index 25e32d1c7..e6d0f3be1 100644 --- a/test/Telegram.Bot.Tests.Integ/Framework/XunitExtensions/DelayedMessageBus.cs +++ b/test/Telegram.Bot.Tests.Integ/Framework/XunitExtensions/DelayedMessageBus.cs @@ -9,13 +9,10 @@ namespace Telegram.Bot.Tests.Integ.Framework.XunitExtensions; /// Used to capture messages to potentially be forwarded later. Messages are forwarded by /// disposing of the message bus. /// -public class DelayedMessageBus : IMessageBus +public class DelayedMessageBus(IMessageBus innerBus) : IMessageBus { - readonly IMessageBus _innerBus; readonly List _messages = new(); - public DelayedMessageBus(IMessageBus innerBus) => _innerBus = innerBus; - /// public bool QueueMessage(IMessageSinkMessage message) { @@ -34,7 +31,7 @@ public void Dispose() { foreach (var message in _messages) { - _innerBus.QueueMessage(message); + innerBus.QueueMessage(message); } } diff --git a/test/Telegram.Bot.Tests.Integ/Framework/XunitExtensions/RetryFactDiscoverer.cs b/test/Telegram.Bot.Tests.Integ/Framework/XunitExtensions/RetryFactDiscoverer.cs index 381062259..842f1d874 100644 --- a/test/Telegram.Bot.Tests.Integ/Framework/XunitExtensions/RetryFactDiscoverer.cs +++ b/test/Telegram.Bot.Tests.Integ/Framework/XunitExtensions/RetryFactDiscoverer.cs @@ -4,15 +4,8 @@ namespace Telegram.Bot.Tests.Integ.Framework.XunitExtensions; -public class RetryFactDiscoverer : IXunitTestCaseDiscoverer +public class RetryFactDiscoverer(IMessageSink diagnosticMessageSink) : IXunitTestCaseDiscoverer { - readonly IMessageSink _diagnosticMessageSink; - - public RetryFactDiscoverer(IMessageSink diagnosticMessageSink) - { - _diagnosticMessageSink = diagnosticMessageSink; - } - /// public IEnumerable Discover( ITestFrameworkDiscoveryOptions discoveryOptions, @@ -29,7 +22,7 @@ public RetryFactDiscoverer(IMessageSink diagnosticMessageSink) .GetNamedArgument(nameof(OrderedFactAttribute.ExceptionTypeFullName)); var retryTestCase = new RetryTestCase( - _diagnosticMessageSink, + diagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(), testMethod, maxRetries, diff --git a/test/Telegram.Bot.Tests.Integ/Framework/XunitExtensions/XunitTestAssemblyRunnerWithAssemblyFixture.cs b/test/Telegram.Bot.Tests.Integ/Framework/XunitExtensions/XunitTestAssemblyRunnerWithAssemblyFixture.cs index c1c73418b..03871e23d 100644 --- a/test/Telegram.Bot.Tests.Integ/Framework/XunitExtensions/XunitTestAssemblyRunnerWithAssemblyFixture.cs +++ b/test/Telegram.Bot.Tests.Integ/Framework/XunitExtensions/XunitTestAssemblyRunnerWithAssemblyFixture.cs @@ -9,24 +9,20 @@ namespace Telegram.Bot.Tests.Integ.Framework.XunitExtensions; -public class XunitTestAssemblyRunnerWithAssemblyFixture : XunitTestAssemblyRunner +public class XunitTestAssemblyRunnerWithAssemblyFixture( + ITestAssembly testAssembly, + IEnumerable testCases, + IMessageSink diagnosticMessageSink, + IMessageSink executionMessageSink, + ITestFrameworkExecutionOptions executionOptions) + : XunitTestAssemblyRunner(testAssembly, + testCases, + diagnosticMessageSink, + executionMessageSink, + executionOptions) { readonly Dictionary _assemblyFixtureMappings = new(); - public XunitTestAssemblyRunnerWithAssemblyFixture( - ITestAssembly testAssembly, - IEnumerable testCases, - IMessageSink diagnosticMessageSink, - IMessageSink executionMessageSink, - ITestFrameworkExecutionOptions executionOptions) - : base( - testAssembly, - testCases, - diagnosticMessageSink, - executionMessageSink, - executionOptions) - { } - protected override async Task AfterTestAssemblyStartingAsync() { // Let everything initialize @@ -73,8 +69,8 @@ protected override async Task AfterTestAssemblyStartingAsync() } var fixture = ctor.Invoke(parameters.Length == 1 - ? new object[] { DiagnosticMessageSink } - : Array.Empty() + ? [DiagnosticMessageSink] + : [] ); _assemblyFixtureMappings[fixtureAttr.FixtureType] = fixture; @@ -118,4 +114,4 @@ protected override Task BeforeTestAssemblyFinishedAsync() return runSummary; } -} \ No newline at end of file +} diff --git a/test/Telegram.Bot.Tests.Integ/Framework/XunitExtensions/XunitTestCollectionRunnerWithAssemblyFixture.cs b/test/Telegram.Bot.Tests.Integ/Framework/XunitExtensions/XunitTestCollectionRunnerWithAssemblyFixture.cs index 77b5c6fbb..b5a53f584 100644 --- a/test/Telegram.Bot.Tests.Integ/Framework/XunitExtensions/XunitTestCollectionRunnerWithAssemblyFixture.cs +++ b/test/Telegram.Bot.Tests.Integ/Framework/XunitExtensions/XunitTestCollectionRunnerWithAssemblyFixture.cs @@ -7,32 +7,24 @@ namespace Telegram.Bot.Tests.Integ.Framework.XunitExtensions; -public class XunitTestCollectionRunnerWithAssemblyFixture : XunitTestCollectionRunner +public class XunitTestCollectionRunnerWithAssemblyFixture( + Dictionary assemblyFixtureMappings, + ITestCollection testCollection, + IEnumerable testCases, + IMessageSink diagnosticMessageSink, + IMessageBus messageBus, + ITestCaseOrderer testCaseOrderer, + ExceptionAggregator aggregator, + CancellationTokenSource cancellationTokenSource) + : XunitTestCollectionRunner(testCollection, + testCases, + diagnosticMessageSink, + messageBus, + testCaseOrderer, + aggregator, + cancellationTokenSource) { - readonly Dictionary _assemblyFixtureMappings; - readonly IMessageSink _diagnosticMessageSink; - - public XunitTestCollectionRunnerWithAssemblyFixture( - Dictionary assemblyFixtureMappings, - ITestCollection testCollection, - IEnumerable testCases, - IMessageSink diagnosticMessageSink, - IMessageBus messageBus, - ITestCaseOrderer testCaseOrderer, - ExceptionAggregator aggregator, - CancellationTokenSource cancellationTokenSource) - : base( - testCollection, - testCases, - diagnosticMessageSink, - messageBus, - testCaseOrderer, - aggregator, - cancellationTokenSource) - { - _assemblyFixtureMappings = assemblyFixtureMappings; - _diagnosticMessageSink = diagnosticMessageSink; - } + readonly IMessageSink _diagnosticMessageSink = diagnosticMessageSink; protected override async Task RunTestClassAsync( ITestClass testClass, @@ -41,7 +33,7 @@ public class XunitTestCollectionRunnerWithAssemblyFixture : XunitTestCollectionR { // Don't want to use .Concat + .ToDictionary because of the possibility of overriding types, // so instead we'll just let collection fixtures override assembly fixtures. - var combinedFixtures = new Dictionary(_assemblyFixtureMappings); + var combinedFixtures = new Dictionary(assemblyFixtureMappings); foreach (var (key, value) in CollectionFixtureMappings) { combinedFixtures[key] = value; diff --git a/test/Telegram.Bot.Tests.Integ/Framework/XunitExtensions/XunitTestFrameworkExecutorWithAssemblyFixture.cs b/test/Telegram.Bot.Tests.Integ/Framework/XunitExtensions/XunitTestFrameworkExecutorWithAssemblyFixture.cs index ec3026196..65180c015 100644 --- a/test/Telegram.Bot.Tests.Integ/Framework/XunitExtensions/XunitTestFrameworkExecutorWithAssemblyFixture.cs +++ b/test/Telegram.Bot.Tests.Integ/Framework/XunitExtensions/XunitTestFrameworkExecutorWithAssemblyFixture.cs @@ -5,15 +5,12 @@ namespace Telegram.Bot.Tests.Integ.Framework.XunitExtensions; -public class XunitTestFrameworkExecutorWithAssemblyFixture : XunitTestFrameworkExecutor +public class XunitTestFrameworkExecutorWithAssemblyFixture( + AssemblyName assemblyName, + ISourceInformationProvider sourceInformationProvider, + IMessageSink diagnosticMessageSink) + : XunitTestFrameworkExecutor(assemblyName, sourceInformationProvider, diagnosticMessageSink) { - public XunitTestFrameworkExecutorWithAssemblyFixture( - AssemblyName assemblyName, - ISourceInformationProvider sourceInformationProvider, - IMessageSink diagnosticMessageSink) - : base(assemblyName, sourceInformationProvider, diagnosticMessageSink) - { } - protected override async void RunTestCases( IEnumerable testCases, IMessageSink executionMessageSink, diff --git a/test/Telegram.Bot.Tests.Integ/Framework/XunitExtensions/XunitTestFrameworkWithAssemblyFixture.cs b/test/Telegram.Bot.Tests.Integ/Framework/XunitExtensions/XunitTestFrameworkWithAssemblyFixture.cs index 1ca3ea33e..6b82bde9f 100644 --- a/test/Telegram.Bot.Tests.Integ/Framework/XunitExtensions/XunitTestFrameworkWithAssemblyFixture.cs +++ b/test/Telegram.Bot.Tests.Integ/Framework/XunitExtensions/XunitTestFrameworkWithAssemblyFixture.cs @@ -4,12 +4,8 @@ namespace Telegram.Bot.Tests.Integ.Framework.XunitExtensions; -public class XunitTestFrameworkWithAssemblyFixture : XunitTestFramework +public class XunitTestFrameworkWithAssemblyFixture(IMessageSink messageSink) : XunitTestFramework(messageSink) { - public XunitTestFrameworkWithAssemblyFixture(IMessageSink messageSink) - : base(messageSink) - { } - protected override ITestFrameworkExecutor CreateExecutor(AssemblyName assemblyName) => new XunitTestFrameworkExecutorWithAssemblyFixture( assemblyName, diff --git a/test/Telegram.Bot.Tests.Integ/Games/GamesExceptionTests.cs b/test/Telegram.Bot.Tests.Integ/Games/GamesExceptionTests.cs index fe127fa0f..51e092de4 100644 --- a/test/Telegram.Bot.Tests.Integ/Games/GamesExceptionTests.cs +++ b/test/Telegram.Bot.Tests.Integ/Games/GamesExceptionTests.cs @@ -7,16 +7,9 @@ namespace Telegram.Bot.Tests.Integ.Games; [Collection(Constants.TestCollections.GameException)] [TestCaseOrderer(Constants.TestCaseOrderer, Constants.AssemblyName)] -public class GamesExceptionTests +public class GamesExceptionTests(TestsFixture fixture) { - ITelegramBotClient BotClient => _fixture.BotClient; - - readonly TestsFixture _fixture; - - public GamesExceptionTests(TestsFixture fixture) - { - _fixture = fixture; - } + ITelegramBotClient BotClient => fixture.BotClient; [OrderedFact("Should throw InvalidGameShortNameException")] [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.SendGame)] @@ -24,8 +17,11 @@ public async Task Should_Throw_InvalidGameShortNameException() { ApiRequestException e = await Assert.ThrowsAsync(() => BotClient.SendGameAsync( - chatId: _fixture.SupergroupChat.Id, - gameShortName: "my game" + new() + { + ChatId = fixture.SupergroupChat.Id, + GameShortName = "my game", + } ) ); @@ -38,8 +34,11 @@ public async Task Should_Throw_InvalidGameShortNameException_2() { ApiRequestException e = await Assert.ThrowsAsync(() => BotClient.SendGameAsync( - chatId: _fixture.SupergroupChat.Id, - gameShortName: string.Empty + new() + { + ChatId = fixture.SupergroupChat.Id, + GameShortName = "", + } ) ); @@ -52,8 +51,11 @@ public async Task Should_Throw_InvalidGameShortNameException_3() { ApiRequestException e = await Assert.ThrowsAsync(() => BotClient.SendGameAsync( - chatId: _fixture.SupergroupChat.Id, - gameShortName: "non_existing_game" + new() + { + ChatId = fixture.SupergroupChat.Id, + GameShortName = "non_existing_game", + } ) ); @@ -62,4 +64,4 @@ public async Task Should_Throw_InvalidGameShortNameException_3() // ToDo: Send game with markup & game button NOT as 1st: BUTTON_POS_INVALID // ToDo: Send game with markup & w/o game button: REPLY_MARKUP_GAME_EMPTY -} \ No newline at end of file +} diff --git a/test/Telegram.Bot.Tests.Integ/Games/GamesFixture.cs b/test/Telegram.Bot.Tests.Integ/Games/GamesFixture.cs index 11fa504b6..f28812974 100644 --- a/test/Telegram.Bot.Tests.Integ/Games/GamesFixture.cs +++ b/test/Telegram.Bot.Tests.Integ/Games/GamesFixture.cs @@ -1,6 +1,7 @@ using System; using System.Threading.Tasks; using Telegram.Bot.Exceptions; +using Telegram.Bot.Requests; using Telegram.Bot.Tests.Integ.Framework; using Telegram.Bot.Tests.Integ.Framework.Fixtures; using Telegram.Bot.Types; @@ -31,12 +32,16 @@ public GamesFixture(TestsFixture fixture) { GameShortName = "game1"; - AddLifetime( - initialize: async () => + AddInitializer( + async () => { try { - await fixture.BotClient.SendGameAsync(fixture.SupergroupChat.Id, GameShortName); + await fixture.BotClient.SendGameAsync(new() + { + ChatId = fixture.SupergroupChat.Id, + GameShortName = GameShortName, + }); } catch (ApiRequestException e) { @@ -53,8 +58,8 @@ public GamesFixture(TestsFixture fixture) static async Task GetPlayerIdFromChatAdmins(TestsFixture testsFixture, long chatId) { - ChatMember[] admins = await testsFixture.BotClient.GetChatAdministratorsAsync(chatId); + ChatMember[] admins = await testsFixture.BotClient.GetChatAdministratorsAsync(new GetChatAdministratorsRequest { ChatId = chatId }); ChatMember player = admins[new Random(DateTime.Now.Millisecond).Next(admins.Length)]; return player.User; } -} \ No newline at end of file +} diff --git a/test/Telegram.Bot.Tests.Integ/Games/GamesTests.cs b/test/Telegram.Bot.Tests.Integ/Games/GamesTests.cs index 9ac362949..b2a5f1159 100644 --- a/test/Telegram.Bot.Tests.Integ/Games/GamesTests.cs +++ b/test/Telegram.Bot.Tests.Integ/Games/GamesTests.cs @@ -1,6 +1,7 @@ using System; using System.Linq; using System.Threading.Tasks; +using Telegram.Bot.Requests; using Telegram.Bot.Tests.Integ.Framework; using Telegram.Bot.Types; using Telegram.Bot.Types.Enums; @@ -12,90 +13,90 @@ namespace Telegram.Bot.Tests.Integ.Games; [Collection(Constants.TestCollections.Games)] [Trait(Constants.CategoryTraitName, Constants.InteractiveCategoryValue)] [TestCaseOrderer(Constants.TestCaseOrderer, Constants.AssemblyName)] -public class GamesTests : IClassFixture +public class GamesTests(TestsFixture fixture, GamesFixture classFixture) : IClassFixture { - ITelegramBotClient BotClient => _fixture.BotClient; - - readonly TestsFixture _fixture; - - readonly GamesFixture _classFixture; - - public GamesTests(TestsFixture fixture, GamesFixture classFixture) - { - _fixture = fixture; - _classFixture = classFixture; - } + ITelegramBotClient BotClient => fixture.BotClient; [OrderedFact("Should answer inline query with a game")] [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.AnswerInlineQuery)] public async Task Should_Answer_InlineQuery_With_Game() { - await _fixture.SendTestInstructionsAsync( + await fixture.SendTestInstructionsAsync( "Staring the inline query with this message...", startInlineQuery: true ); - Update queryUpdate = await _fixture.UpdateReceiver.GetInlineQueryUpdateAsync(); + Update queryUpdate = await fixture.UpdateReceiver.GetInlineQueryUpdateAsync(); const string resultId = "game"; await BotClient.AnswerInlineQueryAsync( - inlineQueryId: queryUpdate.InlineQuery!.Id, - results: new InlineQueryResult[] + new() { - new InlineQueryResultGame( - id: resultId, - gameShortName: _classFixture.GameShortName - ) - }, - cacheTime: 0 + InlineQueryId = queryUpdate.InlineQuery!.Id, + Results = [ + new InlineQueryResultGame + { + Id = resultId, + GameShortName = classFixture.GameShortName, + } + ], + CacheTime = 0 + } ); (Update messageUpdate, Update chosenResultUpdate) = - await _fixture.UpdateReceiver.GetInlineQueryResultUpdates( - chatId: _fixture.SupergroupChat.Id, + await fixture.UpdateReceiver.GetInlineQueryResultUpdates( + chatId: fixture.SupergroupChat.Id, messageType: MessageType.Game ); Assert.Equal(MessageType.Game, messageUpdate?.Message?.Type); Assert.Equal(resultId, chosenResultUpdate?.ChosenInlineResult?.ResultId); Assert.NotNull(chosenResultUpdate?.ChosenInlineResult); + Assert.NotNull(chosenResultUpdate); Assert.Empty(chosenResultUpdate.ChosenInlineResult.Query); - _classFixture.InlineGameMessageId = chosenResultUpdate.ChosenInlineResult.InlineMessageId; + classFixture.InlineGameMessageId = chosenResultUpdate.ChosenInlineResult.InlineMessageId; } [OrderedFact("Should get game high score for inline message")] [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.GetGameHighScores)] public async Task Should_Get_High_Scores_Inline_Message() { - GameHighScore[] highScores = await BotClient.GetGameHighScoresAsync( - userId: _classFixture.Player.Id, - inlineMessageId: _classFixture.InlineGameMessageId + GameHighScore[] highScores = await BotClient.GetInlineGameHighScoresAsync( + new() + { + UserId = classFixture.Player.Id, + InlineMessageId = classFixture.InlineGameMessageId, + } ); Assert.All(highScores, _ => Assert.True(_.Position > 0)); Assert.All(highScores, _ => Assert.True(_.Score > 0)); Assert.All(highScores.Select(_ => _.User), Assert.NotNull); - _classFixture.HighScores = highScores; + classFixture.HighScores = highScores; } [OrderedFact("Should set game score for inline message")] [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.SetGameScore)] public async Task Should_Set_Game_Score_Inline_Message() { - long playerId = _classFixture.Player.Id; - int oldScore = _classFixture.HighScores.Single(highScore => highScore.User.Id == playerId).Score; + long playerId = classFixture.Player.Id; + int oldScore = classFixture.HighScores.Single(highScore => highScore.User.Id == playerId).Score; int newScore = oldScore + 1 + new Random().Next(3); - await _fixture.SendTestInstructionsAsync( - $"Changing score from {oldScore} to {newScore} for {_classFixture.Player.Username!.Replace("_", @"\_")}." + await fixture.SendTestInstructionsAsync( + $"Changing score from {oldScore} to {newScore} for {classFixture.Player.Username!.Replace("_", @"\_")}." ); - await BotClient.SetGameScoreAsync( - userId: playerId, - score: newScore, - inlineMessageId: _classFixture.InlineGameMessageId + await BotClient.SetInlineGameScoreAsync( + new() + { + UserId = playerId, + Score = newScore, + InlineMessageId = classFixture.InlineGameMessageId, + } ); } @@ -103,17 +104,20 @@ public async Task Should_Set_Game_Score_Inline_Message() [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.AnswerCallbackQuery)] public async Task Should_Answer_CallbackQuery_With_Game_Url() { - await _fixture.SendTestInstructionsAsync( + await fixture.SendTestInstructionsAsync( "Click on any Play button on any of the game messages above 👆" ); - Update cqUpdate = await _fixture.UpdateReceiver.GetCallbackQueryUpdateAsync(); + Update cqUpdate = await fixture.UpdateReceiver.GetCallbackQueryUpdateAsync(); Assert.True(cqUpdate.CallbackQuery?.IsGameQuery); await BotClient.AnswerCallbackQueryAsync( - callbackQueryId: cqUpdate.CallbackQuery!.Id, - url: "https://tbot.xyz/lumber/" + new AnswerCallbackQueryRequest + { + CallbackQueryId = cqUpdate.CallbackQuery!.Id, + Url = "https://tbot.xyz/lumber/", + } ); } -} \ No newline at end of file +} diff --git a/test/Telegram.Bot.Tests.Integ/Games/GamesTests2.cs b/test/Telegram.Bot.Tests.Integ/Games/GamesTests2.cs index 185644bff..29308f7fa 100644 --- a/test/Telegram.Bot.Tests.Integ/Games/GamesTests2.cs +++ b/test/Telegram.Bot.Tests.Integ/Games/GamesTests2.cs @@ -1,6 +1,7 @@ using System; using System.Linq; using System.Threading.Tasks; +using Telegram.Bot.Requests; using Telegram.Bot.Tests.Integ.Framework; using Telegram.Bot.Types; using Telegram.Bot.Types.Enums; @@ -11,27 +12,20 @@ namespace Telegram.Bot.Tests.Integ.Games; [Collection(Constants.TestCollections.Games2)] [TestCaseOrderer(Constants.TestCaseOrderer, Constants.AssemblyName)] -public class GamesTests2 : IClassFixture +public class GamesTests2(TestsFixture fixture, GamesFixture classFixture) : IClassFixture { - ITelegramBotClient BotClient => _fixture.BotClient; - - readonly TestsFixture _fixture; - - readonly GamesFixture _classFixture; - - public GamesTests2(TestsFixture fixture, GamesFixture classFixture) - { - _fixture = fixture; - _classFixture = classFixture; - } + ITelegramBotClient BotClient => fixture.BotClient; [OrderedFact("Should send game")] [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.SendGame)] public async Task Should_Send_Game() { Message gameMessage = await BotClient.SendGameAsync( - chatId: _fixture.SupergroupChat.Id, - gameShortName: _classFixture.GameShortName + new() + { + ChatId = fixture.SupergroupChat.Id, + GameShortName = classFixture.GameShortName, + } ); Assert.Equal(MessageType.Game, gameMessage.Type); @@ -45,7 +39,7 @@ public async Task Should_Send_Game() Assert.All(gameMessage.Game.Photo, p => Assert.True(p.Width > 80)); Assert.All(gameMessage.Game.Photo, p => Assert.True(p.Height > 40)); - _classFixture.GameMessage = gameMessage; + classFixture.GameMessage = gameMessage; } [OrderedFact("Should send game with a custom reply markup")] @@ -53,12 +47,14 @@ public async Task Should_Send_Game() public async Task Should_Send_Game_With_ReplyMarkup() { Message gameMessage = await BotClient.SendGameAsync( - chatId: _fixture.SupergroupChat.Id, - gameShortName: _classFixture.GameShortName, - replyMarkup: new[] + new() { - InlineKeyboardButton.WithCallBackGame(text: "Play"), - InlineKeyboardButton.WithCallbackData(textAndCallbackData: "Second button") + ChatId = fixture.SupergroupChat.Id, + GameShortName = classFixture.GameShortName, + ReplyMarkup = new([ + InlineKeyboardButton.WithCallBackGame(text: "Play"), + InlineKeyboardButton.WithCallbackData(textAndCallbackData: "Second button") + ]), } ); @@ -78,16 +74,19 @@ public async Task Should_Send_Game_With_ReplyMarkup() public async Task Should_Get_High_Scores() { GameHighScore[] highScores = await BotClient.GetGameHighScoresAsync( - userId: _classFixture.Player.Id, - chatId: _fixture.SupergroupChat.Id, - messageId: _classFixture.GameMessage.MessageId + new() + { + UserId = classFixture.Player.Id, + ChatId = fixture.SupergroupChat.Id, + MessageId = classFixture.GameMessage.MessageId, + } ); Assert.All(highScores, hs => Assert.True(hs.Position > 0)); Assert.All(highScores, hs => Assert.True(hs.Score > 0)); Assert.All(highScores.Select(hs => hs.User), Assert.NotNull); - _classFixture.HighScores = highScores; + classFixture.HighScores = highScores; } [OrderedFact("Should set game score")] @@ -95,34 +94,42 @@ public async Task Should_Get_High_Scores() [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.GetGameHighScores)] public async Task Should_Set_Game_Score() { - long playerId = _classFixture.Player.Id; + long playerId = classFixture.Player.Id; - bool playerAlreadyHasScore = _classFixture.HighScores + bool playerAlreadyHasScore = classFixture.HighScores .Any(highScore => highScore.User.Id == playerId); int oldScore = playerAlreadyHasScore - ? _classFixture.HighScores.Single(highScore => highScore.User.Id == playerId).Score + ? classFixture.HighScores.Single(highScore => highScore.User.Id == playerId).Score : 0; int newScore = oldScore + 1 + new Random().Next(3); - await _fixture.SendTestInstructionsAsync( - $"Changing score from {oldScore} to {newScore} for {_classFixture.Player.Username!.Replace("_", @"\_")}." + await fixture.SendTestInstructionsAsync( + $"Changing score from {oldScore} to {newScore} for {classFixture.Player.Username!.Replace("_", @"\_")}." ); Message gameMessage = await BotClient.SetGameScoreAsync( - userId: playerId, - score: newScore, - chatId: _fixture.SupergroupChat.Id, - messageId: _classFixture.GameMessage.MessageId + new() + { + UserId = playerId, + Score = newScore, + ChatId = fixture.SupergroupChat.Id, + MessageId = classFixture.GameMessage.MessageId, + } ); - Assert.Equal(_classFixture.GameMessage.MessageId, gameMessage.MessageId); + Assert.Equal(classFixture.GameMessage.MessageId, gameMessage.MessageId); // update the high scores cache await Task.Delay(1_000); - _classFixture.HighScores = await BotClient.GetGameHighScoresAsync( - playerId, _fixture.SupergroupChat.Id, gameMessage.MessageId + classFixture.HighScores = await BotClient.GetGameHighScoresAsync( + new() + { + UserId = playerId, + ChatId = fixture.SupergroupChat.Id, + MessageId = gameMessage.MessageId, + } ); } @@ -130,22 +137,25 @@ public async Task Should_Set_Game_Score() [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.SetGameScore)] public async Task Should_Deduct_Game_Score() { - long playerId = _classFixture.Player.Id; - int oldScore = _classFixture.HighScores.Single(highScore => highScore.User.Id == playerId).Score; + long playerId = classFixture.Player.Id; + int oldScore = classFixture.HighScores.Single(highScore => highScore.User.Id == playerId).Score; int newScore = oldScore - 1; - await _fixture.SendTestInstructionsAsync( - $"Changing score from {oldScore} to {newScore} for {_classFixture.Player.Username!.Replace("_", @"\_")}." + await fixture.SendTestInstructionsAsync( + $"Changing score from {oldScore} to {newScore} for {classFixture.Player.Username!.Replace("_", @"\_")}." ); Message gameMessage = await BotClient.SetGameScoreAsync( - userId: playerId, - score: newScore, - chatId: _fixture.SupergroupChat.Id, - messageId: _classFixture.GameMessage.MessageId, - force: true + new() + { + UserId = playerId, + Score = newScore, + ChatId = fixture.SupergroupChat.Id, + MessageId = classFixture.GameMessage.MessageId, + Force = true, + } ); Assert.Equal(MessageType.Game, gameMessage.Type); } -} \ No newline at end of file +} diff --git a/test/Telegram.Bot.Tests.Integ/Getting Updates/GettingUpdatesTests.cs b/test/Telegram.Bot.Tests.Integ/Getting Updates/GettingUpdatesTests.cs index 70745c0b0..c866ef7c3 100644 --- a/test/Telegram.Bot.Tests.Integ/Getting Updates/GettingUpdatesTests.cs +++ b/test/Telegram.Bot.Tests.Integ/Getting Updates/GettingUpdatesTests.cs @@ -1,6 +1,7 @@ using System; using System.Threading.Tasks; using Telegram.Bot.Exceptions; +using Telegram.Bot.Requests; using Telegram.Bot.Tests.Integ.Framework; using Telegram.Bot.Types; using Xunit; @@ -9,13 +10,9 @@ namespace Telegram.Bot.Tests.Integ.Getting_Updates; [Collection(Constants.TestCollections.GettingUpdates)] [TestCaseOrderer(Constants.TestCaseOrderer, Constants.AssemblyName)] -public class GettingUpdatesTests +public class GettingUpdatesTests(TestsFixture fixture) { - ITelegramBotClient BotClient => _fixture.BotClient; - - readonly TestsFixture _fixture; - - public GettingUpdatesTests(TestsFixture fixture) => _fixture = fixture; + ITelegramBotClient BotClient => fixture.BotClient; [OrderedFact("Should pass API Token test with valid token")] [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.GetMe)] @@ -59,7 +56,7 @@ public async Task Should_Test_Bad_BotToken() [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.GetMe)] public async Task Should_Get_Bot_User() { - User botUser = await BotClient.GetMeAsync(); + User botUser = await BotClient.GetMeAsync(new GetMeRequest()); Assert.NotNull(botUser); Assert.NotNull(botUser.Username); diff --git a/test/Telegram.Bot.Tests.Integ/Getting Updates/WebhookTests.cs b/test/Telegram.Bot.Tests.Integ/Getting Updates/WebhookTests.cs index ef1b86a17..de6317b0a 100644 --- a/test/Telegram.Bot.Tests.Integ/Getting Updates/WebhookTests.cs +++ b/test/Telegram.Bot.Tests.Integ/Getting Updates/WebhookTests.cs @@ -1,7 +1,7 @@ using System; using System.IO; using System.Threading.Tasks; -using Polly; +using Telegram.Bot.Requests; using Telegram.Bot.Tests.Integ.Framework; using Telegram.Bot.Types; using Telegram.Bot.Types.Enums; @@ -10,31 +10,24 @@ namespace Telegram.Bot.Tests.Integ.Getting_Updates; +/// Webhook tests /// /// Webhooks must be immediately disabled because the test framework uses getUpdates method. /// [Collection(Constants.TestCollections.Webhook)] [TestCaseOrderer(Constants.TestCaseOrderer, Constants.AssemblyName)] -public class WebhookTests : IDisposable +public class WebhookTests(TestsFixture fixture) : IDisposable { ITelegramBotClient BotClient => _fixture.BotClient; - readonly TestsFixture _fixture; - - public WebhookTests(TestsFixture fixture) - { - _fixture = fixture; - } + readonly TestsFixture _fixture = fixture; /// /// Ensures that the webhooks are immediately disabled after each test case. /// public void Dispose() { - Policy - .Handle() - .WaitAndRetryAsync(new[] {TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(15)}) - .ExecuteAsync(() => BotClient.DeleteWebhookAsync()) + BotClient.DeleteWebhookAsync(new DeleteWebhookRequest()) .GetAwaiter() .GetResult(); } @@ -43,7 +36,7 @@ public void Dispose() [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.SetWebhook)] public async Task Should_Set_Webhook() { - await BotClient.SetWebhookAsync(url: "https://www.telegram.org/"); + await BotClient.SetWebhookAsync(new SetWebhookRequest { Url = "https://www.telegram.org/"}); } [OrderedFact("Should set webhook with options", Skip = "setWebhook requests are rate limited")] @@ -51,9 +44,12 @@ public async Task Should_Set_Webhook() public async Task Should_Set_Webhook_With_Options() { await BotClient.SetWebhookAsync( - url: "https://www.t.me/", - maxConnections: 5, - allowedUpdates: new[] {UpdateType.CallbackQuery, UpdateType.InlineQuery} + new SetWebhookRequest + { + Url = "https://www.t.me/", + MaxConnections = 5, + AllowedUpdates = [UpdateType.CallbackQuery, UpdateType.InlineQuery], + } ); } @@ -61,7 +57,7 @@ public async Task Should_Set_Webhook_With_Options() [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.SetWebhook)] public async Task Should_Delete_Webhook_Using_setWebhook() { - await BotClient.SetWebhookAsync(url: ""); + await BotClient.SetWebhookAsync(new SetWebhookRequest { Url = string.Empty }); } [OrderedFact("Should set webhook with self-signed certificate")] @@ -72,14 +68,17 @@ public async Task Should_Set_Webhook_With_SelfSigned_Cert() await using (Stream stream = File.OpenRead(Constants.PathToFile.Certificate.PublicKey)) { await BotClient.SetWebhookAsync( - url: "https://www.telegram.org/", - certificate: new InputFileStream(stream), - maxConnections: 3, - allowedUpdates: Array.Empty() // send all types of updates + new SetWebhookRequest + { + Url = "https://www.telegram.org/", + Certificate = InputFile.FromStream(stream), + MaxConnections = 3, + AllowedUpdates = Array.Empty(), // send all types of updates + } ); } - WebhookInfo info = await BotClient.GetWebhookInfoAsync(); + WebhookInfo info = await BotClient.GetWebhookInfoAsync(new GetWebhookInfoRequest()); Assert.Equal("https://www.telegram.org/", info.Url); Assert.True(info.HasCustomCertificate); @@ -91,14 +90,14 @@ await using (Stream stream = File.OpenRead(Constants.PathToFile.Certificate.Publ [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.DeleteWebhook)] public async Task Should_Delete_Webhook() { - await BotClient.DeleteWebhookAsync(); + await BotClient.DeleteWebhookAsync(new DeleteWebhookRequest()); } [OrderedFact("Should get info of the deleted webhook")] [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.GetWebhookInfo)] public async Task Should_Get_Deleted_Webhook_Info() { - WebhookInfo info = await BotClient.GetWebhookInfoAsync(); + WebhookInfo info = await BotClient.GetWebhookInfoAsync(new GetWebhookInfoRequest()); Assert.Empty(info.Url); Assert.False(info.HasCustomCertificate); diff --git a/test/Telegram.Bot.Tests.Integ/Inline Keyboard/CallbackQueryTests.cs b/test/Telegram.Bot.Tests.Integ/Inline Keyboard/CallbackQueryTests.cs index 2eec645db..b20eb53c9 100644 --- a/test/Telegram.Bot.Tests.Integ/Inline Keyboard/CallbackQueryTests.cs +++ b/test/Telegram.Bot.Tests.Integ/Inline Keyboard/CallbackQueryTests.cs @@ -1,6 +1,7 @@ using System; using System.Threading.Tasks; using Newtonsoft.Json.Linq; +using Telegram.Bot.Requests; using Telegram.Bot.Tests.Integ.Framework; using Telegram.Bot.Types; using Telegram.Bot.Types.Enums; @@ -13,16 +14,9 @@ namespace Telegram.Bot.Tests.Integ.Interactive; [Collection(Constants.TestCollections.CallbackQuery)] [Trait(Constants.CategoryTraitName, Constants.InteractiveCategoryValue)] [TestCaseOrderer(Constants.TestCaseOrderer, Constants.AssemblyName)] -public class CallbackQueryTests +public class CallbackQueryTests(TestsFixture fixture) { - ITelegramBotClient BotClient => _fixture.BotClient; - - readonly TestsFixture _fixture; - - public CallbackQueryTests(TestsFixture fixture) - { - _fixture = fixture; - } + ITelegramBotClient BotClient => fixture.BotClient; [OrderedFact("Should receive and answer callback query result with a notification")] [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.SendMessage)] @@ -31,22 +25,25 @@ public async Task Should_Answer_With_Notification() { string callbackQueryData = 'a' + new Random().Next(5_000).ToString(); - Message message = await BotClient.SendTextMessageAsync( - chatId: _fixture.SupergroupChat.Id, - text: "Please click on *OK* button.", - parseMode: ParseMode.Markdown, - replyMarkup: new InlineKeyboardMarkup(new[] + Message message = await BotClient.SendMessageAsync( + new() { - InlineKeyboardButton.WithCallbackData("OK", callbackQueryData) - }) + ChatId = fixture.SupergroupChat.Id, + Text = "Please click on *OK* button.", + ParseMode = ParseMode.Markdown, + ReplyMarkup = new InlineKeyboardMarkup([InlineKeyboardButton.WithCallbackData("OK", callbackQueryData)]), + } ); - Update responseUpdate = await _fixture.UpdateReceiver.GetCallbackQueryUpdateAsync(message.MessageId); + Update responseUpdate = await fixture.UpdateReceiver.GetCallbackQueryUpdateAsync(message.MessageId); CallbackQuery callbackQuery = responseUpdate.CallbackQuery!; await BotClient.AnswerCallbackQueryAsync( - callbackQueryId: callbackQuery!.Id, - text: "You clicked on OK" + new AnswerCallbackQueryRequest + { + CallbackQueryId = callbackQuery!.Id, + Text = "You clicked on OK", + } ); Assert.Equal(UpdateType.CallbackQuery, responseUpdate.Type); @@ -70,22 +67,28 @@ public async Task Should_Answer_With_Alert() { string callbackQueryData = $"b{new Random().Next(5_000)}"; - Message message = await BotClient.SendTextMessageAsync( - chatId: _fixture.SupergroupChat.Id, - text: "Please click on *Notify* button.", - parseMode: ParseMode.Markdown, - replyMarkup: new InlineKeyboardMarkup( - InlineKeyboardButton.WithCallbackData("Notify", callbackQueryData) - ) + Message message = await BotClient.SendMessageAsync( + new() + { + ChatId = fixture.SupergroupChat.Id, + Text = "Please click on *Notify* button.", + ParseMode = ParseMode.Markdown, + ReplyMarkup = new InlineKeyboardMarkup( + InlineKeyboardButton.WithCallbackData("Notify", callbackQueryData) + ), + } ); - Update responseUpdate = await _fixture.UpdateReceiver.GetCallbackQueryUpdateAsync(message.MessageId); + Update responseUpdate = await fixture.UpdateReceiver.GetCallbackQueryUpdateAsync(message.MessageId); CallbackQuery callbackQuery = responseUpdate.CallbackQuery!; await BotClient.AnswerCallbackQueryAsync( - callbackQueryId: responseUpdate.CallbackQuery!.Id, - text: "Got it!", - showAlert: true + new AnswerCallbackQueryRequest + { + CallbackQueryId = responseUpdate.CallbackQuery!.Id, + Text = "Got it!", + ShowAlert = true, + } ); Assert.Equal(UpdateType.CallbackQuery, responseUpdate.Type); @@ -97,8 +100,9 @@ public async Task Should_Answer_With_Alert() Assert.False(callbackQuery.From.IsBot); Assert.NotNull(callbackQuery.From.Username); Assert.NotEmpty(callbackQuery.From.Username); + Assert.NotNull(callbackQuery.Message); Assert.True(JToken.DeepEquals( JToken.FromObject(message), JToken.FromObject(callbackQuery.Message) )); } -} \ No newline at end of file +} diff --git a/test/Telegram.Bot.Tests.Integ/Inline Mode/InlineQueryTests.cs b/test/Telegram.Bot.Tests.Integ/Inline Mode/InlineQueryTests.cs index d766aa5f2..103922f75 100644 --- a/test/Telegram.Bot.Tests.Integ/Inline Mode/InlineQueryTests.cs +++ b/test/Telegram.Bot.Tests.Integ/Inline Mode/InlineQueryTests.cs @@ -2,6 +2,7 @@ using System.Linq; using System.Threading.Tasks; using Telegram.Bot.Exceptions; +using Telegram.Bot.Requests; using Telegram.Bot.Tests.Integ.Framework; using Telegram.Bot.Types; using Telegram.Bot.Types.Enums; @@ -14,57 +15,55 @@ namespace Telegram.Bot.Tests.Integ.Inline_Mode; [Collection(Constants.TestCollections.InlineQuery)] [Trait(Constants.CategoryTraitName, Constants.InteractiveCategoryValue)] [TestCaseOrderer(Constants.TestCaseOrderer, Constants.AssemblyName)] -public class InlineQueryTests +public class InlineQueryTests(TestsFixture fixture) { - ITelegramBotClient BotClient => _fixture.BotClient; - - readonly TestsFixture _fixture; - - public InlineQueryTests(TestsFixture fixture) - { - _fixture = fixture; - } + ITelegramBotClient BotClient => fixture.BotClient; [OrderedFact("Should answer inline query with an article")] [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.AnswerInlineQuery)] public async Task Should_Answer_Inline_Query_With_Article() { - await _fixture.SendTestInstructionsAsync( - "1. Start an inline query\n" + - "2. Wait for bot to answer it\n" + - "3. Choose the answer", + await fixture.SendTestInstructionsAsync( + """ + 1. Start an inline query + 2. Wait for bot to answer it + 3. Choose the answer + """, startInlineQuery: true ); // Wait for tester to start an inline query // This looks for an Update having a value on "inline_query" field - Update iqUpdate = await _fixture.UpdateReceiver.GetInlineQueryUpdateAsync(); + Update iqUpdate = await fixture.UpdateReceiver.GetInlineQueryUpdateAsync(); // Prepare results of the query InlineQueryResult[] results = - { - new InlineQueryResultArticle( - id: "article:bot-api", - title: "Telegram Bot API", - inputMessageContent: new InputTextMessageContent("https://core.telegram.org/bots/api")) + [ + new InlineQueryResultArticle { + Id = "article:bot-api", + Title = "Telegram Bot API", + InputMessageContent = new InputTextMessageContent { MessageText = "https://core.telegram.org/bots/api" }, Description = "The Bot API is an HTTP-based interface created for developers", - }, - }; + } + ]; // Answer the query await BotClient.AnswerInlineQueryAsync( - inlineQueryId: iqUpdate.InlineQuery!.Id, - results: results, - cacheTime: 0 + new() + { + InlineQueryId = iqUpdate.InlineQuery!.Id, + Results = results, + CacheTime = 0, + } ); // Wait for tester to choose a result and send it(as a message) to the chat ( Update messageUpdate, Update chosenResultUpdate - ) = await _fixture.UpdateReceiver.GetInlineQueryResultUpdates( - chatId: _fixture.SupergroupChat.Id, + ) = await fixture.UpdateReceiver.GetInlineQueryResultUpdates( + chatId: fixture.SupergroupChat.Id, messageType: MessageType.Text ); @@ -77,72 +76,83 @@ Update chosenResultUpdate [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.AnswerInlineQuery)] public async Task Should_Get_Message_From_Inline_Query_With_ViaBot() { - await _fixture.SendTestInstructionsAsync( - "1. Start an inline query\n" + - "2. Wait for bot to answer it\n" + - "3. Choose the answer", + await fixture.SendTestInstructionsAsync( + """ + 1. Start an inline query + 2. Wait for bot to answer it + 3. Choose the answer + """, startInlineQuery: true ); - Update iqUpdate = await _fixture.UpdateReceiver.GetInlineQueryUpdateAsync(); + Update iqUpdate = await fixture.UpdateReceiver.GetInlineQueryUpdateAsync(); InlineQueryResult[] results = - { - new InlineQueryResultArticle( - id: "article:bot-api", - title: "Telegram Bot API", - inputMessageContent: new InputTextMessageContent("https://core.telegram.org/bots/api")) + [ + new InlineQueryResultArticle { + Id = "article:bot-api", + Title = "Telegram Bot API", + InputMessageContent = new InputTextMessageContent { MessageText = "https://core.telegram.org/bots/api" }, Description = "The Bot API is an HTTP-based interface created for developers", - }, - }; + } + ]; await BotClient.AnswerInlineQueryAsync( - inlineQueryId: iqUpdate.InlineQuery!.Id, - results: results, - cacheTime: 0 + new() + { + InlineQueryId = iqUpdate.InlineQuery!.Id, + Results = results, + CacheTime = 0, + } ); - Update messageUpdate = await _fixture.UpdateReceiver.GetUpdateAsync( + Update messageUpdate = await fixture.UpdateReceiver.GetUpdateAsync( predicate: update => update.Message!.ViaBot is not null, - updateTypes: new[] { UpdateType.Message } + updateTypes: [UpdateType.Message] ); Assert.NotNull(messageUpdate.Message); Assert.Equal(MessageType.Text, messageUpdate.Message.Type); Assert.NotNull(messageUpdate.Message.ViaBot); - Assert.Equal(_fixture.BotUser.Id, messageUpdate.Message.ViaBot.Id); + Assert.Equal(fixture.BotUser.Id, messageUpdate.Message.ViaBot.Id); } [OrderedFact("Should answer inline query with a contact")] [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.AnswerInlineQuery)] public async Task Should_Answer_Inline_Query_With_Contact() { - await _fixture.SendTestInstructionsAsync( + await fixture.SendTestInstructionsAsync( "Staring the inline query with this message...", startInlineQuery: true ); - Update iqUpdate = await _fixture.UpdateReceiver.GetInlineQueryUpdateAsync(); + Update iqUpdate = await fixture.UpdateReceiver.GetInlineQueryUpdateAsync(); const string resultId = "contact:john-doe"; InlineQueryResult[] results = - { - new InlineQueryResultContact(id: resultId, phoneNumber: "+1234567", firstName: "John") + [ + new InlineQueryResultContact { + Id = resultId, + PhoneNumber = "+1234567", + FirstName = "John", LastName = "Doe" } - }; + ]; await BotClient.AnswerInlineQueryAsync( - inlineQueryId: iqUpdate.InlineQuery!.Id, - results: results, - cacheTime: 0 + new() + { + InlineQueryId = iqUpdate.InlineQuery!.Id, + Results = results, + CacheTime = 0, + } ); (Update messageUpdate, Update chosenResultUpdate) = - await _fixture.UpdateReceiver.GetInlineQueryResultUpdates( - chatId: _fixture.SupergroupChat.Id, + await fixture.UpdateReceiver.GetInlineQueryResultUpdates( + chatId: fixture.SupergroupChat.Id, messageType: MessageType.Contact ); Update resultUpdate = chosenResultUpdate; @@ -156,32 +166,37 @@ public async Task Should_Answer_Inline_Query_With_Contact() [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.AnswerInlineQuery)] public async Task Should_Answer_Inline_Query_With_Location() { - await _fixture.SendTestInstructionsAsync( + await fixture.SendTestInstructionsAsync( "Staring the inline query with this message...", startInlineQuery: true ); - Update iqUpdate = await _fixture.UpdateReceiver.GetInlineQueryUpdateAsync(); + Update iqUpdate = await fixture.UpdateReceiver.GetInlineQueryUpdateAsync(); const string resultId = "location:hobitton"; InlineQueryResult[] results = - { - new InlineQueryResultLocation( - id: resultId, - latitude: -37.8721897f, - longitude: 175.6810213f, - title: "Hobbiton Movie Set") - }; + [ + new InlineQueryResultLocation + { + Id = resultId, + Latitude = -37.8721897f, + Longitude = 175.6810213f, + Title = "Hobbiton Movie Set" + } + ]; await BotClient.AnswerInlineQueryAsync( - inlineQueryId: iqUpdate.InlineQuery!.Id, - results: results, - cacheTime: 0 + new() + { + InlineQueryId = iqUpdate.InlineQuery!.Id, + Results = results, + CacheTime = 0, + } ); (Update messageUpdate, Update chosenResultUpdate) = - await _fixture.UpdateReceiver.GetInlineQueryResultUpdates( - chatId: _fixture.SupergroupChat.Id, + await fixture.UpdateReceiver.GetInlineQueryResultUpdates( + chatId: fixture.SupergroupChat.Id, messageType: MessageType.Location ); Update resultUpdate = chosenResultUpdate; @@ -195,33 +210,38 @@ public async Task Should_Answer_Inline_Query_With_Location() [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.AnswerInlineQuery)] public async Task Should_Answer_Inline_Query_With_Venue() { - await _fixture.SendTestInstructionsAsync( + await fixture.SendTestInstructionsAsync( "Staring the inline query with this message...", startInlineQuery: true ); - Update iqUpdate = await _fixture.UpdateReceiver.GetInlineQueryUpdateAsync(); + Update iqUpdate = await fixture.UpdateReceiver.GetInlineQueryUpdateAsync(); const string resultId = "venue:hobbiton"; InlineQueryResult[] results = - { - new InlineQueryResultVenue( - id: resultId, - latitude: -37.8721897f, - longitude: 175.6810213f, - title: "Hobbiton Movie Set", - address: "501 Buckland Rd, Hinuera, Matamata 3472, New Zealand") - }; + [ + new InlineQueryResultVenue + { + Id = resultId, + Latitude = -37.8721897f, + Longitude = 175.6810213f, + Title = "Hobbiton Movie Set", + Address = "501 Buckland Rd, Hinuera, Matamata 3472, New Zealand", + } + ]; await BotClient.AnswerInlineQueryAsync( - inlineQueryId: iqUpdate.InlineQuery!.Id, - results: results, - cacheTime: 0 + new() + { + InlineQueryId = iqUpdate.InlineQuery!.Id, + Results = results, + CacheTime = 0, + } ); (Update messageUpdate, Update chosenResultUpdate) = - await _fixture.UpdateReceiver.GetInlineQueryResultUpdates( - chatId: _fixture.SupergroupChat.Id, + await fixture.UpdateReceiver.GetInlineQueryResultUpdates( + chatId: fixture.SupergroupChat.Id, messageType: MessageType.Venue ); Update resultUpdate = chosenResultUpdate; @@ -235,33 +255,39 @@ public async Task Should_Answer_Inline_Query_With_Venue() [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.AnswerInlineQuery)] public async Task Should_Answer_Inline_Query_With_Photo() { - await _fixture.SendTestInstructionsAsync( + await fixture.SendTestInstructionsAsync( "Staring the inline query with this message...", startInlineQuery: true ); - Update iqUpdate = await _fixture.UpdateReceiver.GetInlineQueryUpdateAsync(); + Update iqUpdate = await fixture.UpdateReceiver.GetInlineQueryUpdateAsync(); const string resultId = "photo:rainbow-girl"; const string url = "https://cdn.pixabay.com/photo/2017/08/30/12/45/girl-2696947_640.jpg"; const string caption = "Rainbow Girl"; InlineQueryResult[] results = - { - new InlineQueryResultPhoto(id: resultId, photoUrl: url, thumbnailUrl: url) + [ + new InlineQueryResultPhoto { + Id = resultId, + PhotoUrl = url, + ThumbnailUrl = url, Caption = caption } - }; + ]; await BotClient.AnswerInlineQueryAsync( - inlineQueryId: iqUpdate.InlineQuery!.Id, - results: results, - cacheTime: 0 + new() + { + InlineQueryId = iqUpdate.InlineQuery!.Id, + Results = results, + CacheTime = 0, + } ); (Update messageUpdate, Update chosenResultUpdate) = - await _fixture.UpdateReceiver.GetInlineQueryResultUpdates( - chatId: _fixture.SupergroupChat.Id, + await fixture.UpdateReceiver.GetInlineQueryResultUpdates( + chatId: fixture.SupergroupChat.Id, messageType: MessageType.Photo ); Update resultUpdate = chosenResultUpdate; @@ -280,36 +306,42 @@ public async Task Should_Answer_Inline_Query_With_Cached_Photo() await using (FileStream stream = System.IO.File.OpenRead(Constants.PathToFile.Photos.Apes)) { photoMessage = await BotClient.SendPhotoAsync( - chatId: _fixture.SupergroupChat, - photo: new InputFileStream(stream), - replyMarkup: (InlineKeyboardMarkup)InlineKeyboardButton - .WithSwitchInlineQueryCurrentChat("Start inline query") + new() + { + ChatId = fixture.SupergroupChat, + Photo = InputFile.FromStream(stream), + ReplyMarkup = (InlineKeyboardMarkup)InlineKeyboardButton + .WithSwitchInlineQueryCurrentChat("Start inline query"), + } ); } - Update iqUpdate = await _fixture.UpdateReceiver.GetInlineQueryUpdateAsync(); + Update iqUpdate = await fixture.UpdateReceiver.GetInlineQueryUpdateAsync(); const string resultId = "photo:apes"; const string caption = "Apes smoking shisha"; InlineQueryResult[] results = - { - new InlineQueryResultCachedPhoto( - id: resultId, - photoFileId: photoMessage.Photo!.First().FileId) + [ + new InlineQueryResultCachedPhoto { + Id = resultId, + PhotoFileId = photoMessage.Photo!.First().FileId, Caption = caption } - }; + ]; await BotClient.AnswerInlineQueryAsync( - inlineQueryId: iqUpdate.InlineQuery!.Id, - results: results, - cacheTime: 0 + new() + { + InlineQueryId = iqUpdate.InlineQuery!.Id, + Results = results, + CacheTime = 0, + } ); (Update messageUpdate, Update chosenResultUpdate) = - await _fixture.UpdateReceiver.GetInlineQueryResultUpdates( - chatId: _fixture.SupergroupChat.Id, + await fixture.UpdateReceiver.GetInlineQueryResultUpdates( + chatId: fixture.SupergroupChat.Id, messageType: MessageType.Photo ); Update resultUpdate = chosenResultUpdate; @@ -324,35 +356,39 @@ await using (FileStream stream = System.IO.File.OpenRead(Constants.PathToFile.Ph [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.AnswerInlineQuery)] public async Task Should_Answer_Inline_Query_With_Video() { - await _fixture.SendTestInstructionsAsync( + await fixture.SendTestInstructionsAsync( "Staring the inline query with this message...", startInlineQuery: true ); - Update iqUpdate = await _fixture.UpdateReceiver.GetInlineQueryUpdateAsync(); + Update iqUpdate = await fixture.UpdateReceiver.GetInlineQueryUpdateAsync(); const string resultId = "sunset_video"; InlineQueryResult[] results = - { - new InlineQueryResultVideo( - id: resultId, - videoUrl: "https://pixabay.com/en/videos/download/video-10737_medium.mp4", - thumbnailUrl: "https://i.vimeocdn.com/video/646283246_640x360.jpg", - title: "Sunset Landscape") + [ + new InlineQueryResultVideo { + Id = resultId, + VideoUrl = "https://pixabay.com/en/videos/download/video-10737_medium.mp4", + ThumbnailUrl = "https://i.vimeocdn.com/video/646283246_640x360.jpg", + MimeType = "video/mp4", + Title = "Sunset Landscape", Description = "A beautiful scene" } - }; + ]; await BotClient.AnswerInlineQueryAsync( - inlineQueryId: iqUpdate.InlineQuery!.Id, - results: results, - cacheTime: 0 + new() + { + InlineQueryId = iqUpdate.InlineQuery!.Id, + Results = results, + CacheTime = 0, + } ); (Update messageUpdate, Update chosenResultUpdate) = - await _fixture.UpdateReceiver.GetInlineQueryResultUpdates( - chatId: _fixture.SupergroupChat.Id, + await fixture.UpdateReceiver.GetInlineQueryResultUpdates( + chatId: fixture.SupergroupChat.Id, messageType: MessageType.Video ); Update resultUpdate = chosenResultUpdate; @@ -368,38 +404,43 @@ public async Task Should_Answer_Inline_Query_With_HTML_Video() { // ToDo exception when input_message_content not specified. Bad Request: SEND_MESSAGE_MEDIA_INVALID - await _fixture.SendTestInstructionsAsync( + await fixture.SendTestInstructionsAsync( "Staring the inline query with this message...", startInlineQuery: true ); - Update iqUpdate = await _fixture.UpdateReceiver.GetInlineQueryUpdateAsync(); + Update iqUpdate = await fixture.UpdateReceiver.GetInlineQueryUpdateAsync(); const string resultId = "youtube_video"; InlineQueryResult[] results = - { - new InlineQueryResultVideo( - id: resultId, - videoUrl: "https://www.youtube.com/watch?v=1S0CTtY8Qa0", - thumbnailUrl: "https://www.youtube.com/watch?v=1S0CTtY8Qa0", - title: "Rocket Launch", - inputMessageContent: - new InputTextMessageContent("[Rocket Launch](https://www.youtube.com/watch?v=1S0CTtY8Qa0)") + [ + new InlineQueryResultVideo + { + Id = resultId, + VideoUrl = "https://www.youtube.com/watch?v=1S0CTtY8Qa0", + ThumbnailUrl = "https://www.youtube.com/watch?v=1S0CTtY8Qa0", + MimeType = "video/mp4", + Title = "Rocket Launch", + InputMessageContent = new InputTextMessageContent { + MessageText = "[Rocket Launch](https://www.youtube.com/watch?v=1S0CTtY8Qa0)", ParseMode = ParseMode.Markdown } - ) - }; + } + ]; await BotClient.AnswerInlineQueryAsync( - inlineQueryId: iqUpdate.InlineQuery!.Id, - results: results, - cacheTime: 0 + new() + { + InlineQueryId = iqUpdate.InlineQuery!.Id, + Results = results, + CacheTime = 0, + } ); (Update messageUpdate, Update chosenResultUpdate) = - await _fixture.UpdateReceiver.GetInlineQueryResultUpdates( - chatId: _fixture.SupergroupChat.Id, + await fixture.UpdateReceiver.GetInlineQueryResultUpdates( + chatId: fixture.SupergroupChat.Id, messageType: MessageType.Text ); Update resultUpdate = chosenResultUpdate; @@ -415,35 +456,41 @@ public async Task Should_Answer_Inline_Query_With_Cached_Video() { // Video from https://pixabay.com/en/videos/fireworks-rocket-new-year-s-eve-7122/ Message videoMessage = await BotClient.SendVideoAsync( - chatId: _fixture.SupergroupChat, - video: new InputFileUrl("https://pixabay.com/en/videos/download/video-7122_medium.mp4"), - replyMarkup: (InlineKeyboardMarkup)InlineKeyboardButton - .WithSwitchInlineQueryCurrentChat("Start inline query") + new() + { + ChatId = fixture.SupergroupChat, + Video = InputFile.FromUri("https://pixabay.com/en/videos/download/video-7122_medium.mp4"), + ReplyMarkup = (InlineKeyboardMarkup)InlineKeyboardButton + .WithSwitchInlineQueryCurrentChat("Start inline query"), + } ); - Update iqUpdate = await _fixture.UpdateReceiver.GetInlineQueryUpdateAsync(); + Update iqUpdate = await fixture.UpdateReceiver.GetInlineQueryUpdateAsync(); const string resultId = "fireworks_video"; InlineQueryResult[] results = - { - new InlineQueryResultCachedVideo( - id: resultId, - videoFileId: videoMessage.Video!.FileId, - title: "New Year's Eve Fireworks") + [ + new InlineQueryResultCachedVideo { + Id = resultId, + VideoFileId = videoMessage.Video!.FileId, + Title = "New Year's Eve Fireworks", Description = "2017 Fireworks in Germany" } - }; + ]; await BotClient.AnswerInlineQueryAsync( - inlineQueryId: iqUpdate.InlineQuery!.Id, - results: results, - cacheTime: 0 + new() + { + InlineQueryId = iqUpdate.InlineQuery!.Id, + Results = results, + CacheTime = 0, + } ); (Update messageUpdate, Update chosenResultUpdate) = - await _fixture.UpdateReceiver.GetInlineQueryResultUpdates( - chatId: _fixture.SupergroupChat.Id, + await fixture.UpdateReceiver.GetInlineQueryResultUpdates( + chatId: fixture.SupergroupChat.Id, messageType: MessageType.Video ); Update resultUpdate = chosenResultUpdate; @@ -457,36 +504,38 @@ public async Task Should_Answer_Inline_Query_With_Cached_Video() [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.AnswerInlineQuery)] public async Task Should_Answer_Inline_Query_With_Audio() { - await _fixture.SendTestInstructionsAsync( + await fixture.SendTestInstructionsAsync( "Staring the inline query with this message...", startInlineQuery: true ); - Update iqUpdate = await _fixture.UpdateReceiver.GetInlineQueryUpdateAsync(); + Update iqUpdate = await fixture.UpdateReceiver.GetInlineQueryUpdateAsync(); const string resultId = "audio_result"; InlineQueryResult[] results = - { - new InlineQueryResultAudio( - id: resultId, - audioUrl: - "https://upload.wikimedia.org/wikipedia/commons/transcoded/b/bb/Test_ogg_mp3_48kbps.wav/Test_ogg_mp3_48kbps.wav.mp3", - title: "Test ogg mp3") + [ + new InlineQueryResultAudio { + Id = resultId, + AudioUrl = "https://upload.wikimedia.org/wikipedia/commons/transcoded/b/bb/Test_ogg_mp3_48kbps.wav/Test_ogg_mp3_48kbps.wav.mp3", + Title = "Test ogg mp3", Performer = "Shishirdasika", AudioDuration = 25 } - }; + ]; await BotClient.AnswerInlineQueryAsync( - inlineQueryId: iqUpdate.InlineQuery!.Id, - results: results, - cacheTime: 0 + new() + { + InlineQueryId = iqUpdate.InlineQuery!.Id, + Results = results, + CacheTime = 0, + } ); (Update messageUpdate, Update chosenResultUpdate) = - await _fixture.UpdateReceiver.GetInlineQueryResultUpdates( - chatId: _fixture.SupergroupChat.Id, + await fixture.UpdateReceiver.GetInlineQueryResultUpdates( + chatId: fixture.SupergroupChat.Id, messageType: MessageType.Audio ); Update resultUpdate = chosenResultUpdate; @@ -505,37 +554,43 @@ public async Task Should_Answer_Inline_Query_With_Cached_Audio() await using (FileStream stream = System.IO.File.OpenRead(Constants.PathToFile.Audio.CantinaRagMp3)) { audioMessage = await BotClient.SendAudioAsync( - chatId: _fixture.SupergroupChat, - audio: new InputFileStream(stream), - performer: "Jackson F. Smith", - duration: 201, - replyMarkup: (InlineKeyboardMarkup)InlineKeyboardButton - .WithSwitchInlineQueryCurrentChat("Start inline query") + new() + { + ChatId = fixture.SupergroupChat, + Audio = InputFile.FromStream(stream), + Performer = "Jackson F. Smith", + Duration = 201, + ReplyMarkup = (InlineKeyboardMarkup)InlineKeyboardButton + .WithSwitchInlineQueryCurrentChat("Start inline query"), + } ); } - Update iqUpdate = await _fixture.UpdateReceiver.GetInlineQueryUpdateAsync(); + Update iqUpdate = await fixture.UpdateReceiver.GetInlineQueryUpdateAsync(); const string resultId = "audio_result"; InlineQueryResult[] results = - { - new InlineQueryResultCachedAudio( - id: resultId, - audioFileId: audioMessage.Audio!.FileId) + [ + new InlineQueryResultCachedAudio { + Id = resultId, + AudioFileId = audioMessage.Audio!.FileId, Caption = "Jackson F. Smith - Cantina Rag" } - }; + ]; await BotClient.AnswerInlineQueryAsync( - inlineQueryId: iqUpdate.InlineQuery!.Id, - results: results, - cacheTime: 0 + new() + { + InlineQueryId = iqUpdate.InlineQuery!.Id, + Results = results, + CacheTime = 0, + } ); (Update messageUpdate, Update chosenResultUpdate) = - await _fixture.UpdateReceiver.GetInlineQueryResultUpdates( - chatId: _fixture.SupergroupChat.Id, + await fixture.UpdateReceiver.GetInlineQueryResultUpdates( + chatId: fixture.SupergroupChat.Id, messageType: MessageType.Audio ); Update resultUpdate = chosenResultUpdate; @@ -549,35 +604,38 @@ await using (FileStream stream = System.IO.File.OpenRead(Constants.PathToFile.Au [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.AnswerInlineQuery)] public async Task Should_Answer_Inline_Query_With_Voice() { - await _fixture.SendTestInstructionsAsync( + await fixture.SendTestInstructionsAsync( "Staring the inline query with this message...", startInlineQuery: true ); - Update iqUpdate = await _fixture.UpdateReceiver.GetInlineQueryUpdateAsync(); + Update iqUpdate = await fixture.UpdateReceiver.GetInlineQueryUpdateAsync(); const string resultId = "voice_result"; InlineQueryResult[] results = - { - new InlineQueryResultVoice( - id: resultId, - voiceUrl: "http://www.vorbis.com/music/Hydrate-Kenny_Beltrey.ogg", - title: "Hydrate - Kenny Beltrey") + [ + new InlineQueryResultVoice { + Id = resultId, + VoiceUrl = "http://www.vorbis.com/music/Hydrate-Kenny_Beltrey.ogg", + Title = "Hydrate - Kenny Beltrey", Caption = "Hydrate - Kenny Beltrey", VoiceDuration = 265 } - }; + ]; await BotClient.AnswerInlineQueryAsync( - inlineQueryId: iqUpdate.InlineQuery!.Id, - results: results, - cacheTime: 0 + new() + { + InlineQueryId = iqUpdate.InlineQuery!.Id, + Results = results, + CacheTime = 0, + } ); (Update messageUpdate, Update chosenResultUpdate) = - await _fixture.UpdateReceiver.GetInlineQueryResultUpdates( - chatId: _fixture.SupergroupChat.Id, + await fixture.UpdateReceiver.GetInlineQueryResultUpdates( + chatId: fixture.SupergroupChat.Id, messageType: MessageType.Voice ); Update resultUpdate = chosenResultUpdate; @@ -595,35 +653,42 @@ public async Task Should_Answer_Inline_Query_With_Cached_Voice() await using (FileStream stream = System.IO.File.OpenRead(Constants.PathToFile.Audio.TestOgg)) { voiceMessage = await BotClient.SendVoiceAsync( - chatId: _fixture.SupergroupChat, - voice: new InputFileStream(stream), - duration: 24, - replyMarkup: (InlineKeyboardMarkup)InlineKeyboardButton - .WithSwitchInlineQueryCurrentChat("Start inline query") + new() + { + ChatId = fixture.SupergroupChat, + Voice = InputFile.FromStream(stream), + Duration = 24, + ReplyMarkup = (InlineKeyboardMarkup)InlineKeyboardButton + .WithSwitchInlineQueryCurrentChat("Start inline query"), + } ); } - Update iqUpdate = await _fixture.UpdateReceiver.GetInlineQueryUpdateAsync(); + Update iqUpdate = await fixture.UpdateReceiver.GetInlineQueryUpdateAsync(); const string resultId = "voice_result"; InlineQueryResult[] results = - { - new InlineQueryResultCachedVoice( - id: resultId, - fileId: voiceMessage.Voice!.FileId, - title: "Test Voice" - ) - }; + [ + new InlineQueryResultCachedVoice + { + Id = resultId, + VoiceFileId = voiceMessage.Voice!.FileId, + Title = "Test Voice", + } + ]; await BotClient.AnswerInlineQueryAsync( - inlineQueryId: iqUpdate.InlineQuery!.Id, - results: results, - cacheTime: 0 + new() + { + InlineQueryId = iqUpdate.InlineQuery!.Id, + Results = results, + CacheTime = 0, + } ); (Update messageUpdate, Update chosenResultUpdate) = - await _fixture.UpdateReceiver.GetInlineQueryResultUpdates( - chatId: _fixture.SupergroupChat.Id, + await fixture.UpdateReceiver.GetInlineQueryResultUpdates( + chatId: fixture.SupergroupChat.Id, messageType: MessageType.Voice ); Update resultUpdate = chosenResultUpdate; @@ -637,36 +702,39 @@ await using (FileStream stream = System.IO.File.OpenRead(Constants.PathToFile.Au [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.AnswerInlineQuery)] public async Task Should_Answer_Inline_Query_With_Document() { - await _fixture.SendTestInstructionsAsync( + await fixture.SendTestInstructionsAsync( "Staring the inline query with this message...", startInlineQuery: true ); - Update iqUpdate = await _fixture.UpdateReceiver.GetInlineQueryUpdateAsync(); + Update iqUpdate = await fixture.UpdateReceiver.GetInlineQueryUpdateAsync(); const string resultId = "document_result"; InlineQueryResult[] results = - { - new InlineQueryResultDocument( - id: resultId, - documentUrl: "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf", - title: "Dummy PDF File", - mimeType: "application/pdf") + [ + new InlineQueryResultDocument { + Id = resultId, + DocumentUrl = "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf", + Title = "Dummy PDF File", + MimeType = "application/pdf", Caption = "Dummy PDF File", Description = "Dummy PDF File for testing", } - }; + ]; await BotClient.AnswerInlineQueryAsync( - inlineQueryId: iqUpdate.InlineQuery!.Id, - results: results, - cacheTime: 0 + new() + { + InlineQueryId = iqUpdate.InlineQuery!.Id, + Results = results, + CacheTime = 0, + } ); (Update messageUpdate, Update chosenResultUpdate) = - await _fixture.UpdateReceiver.GetInlineQueryResultUpdates( - chatId: _fixture.SupergroupChat.Id, + await fixture.UpdateReceiver.GetInlineQueryResultUpdates( + chatId: fixture.SupergroupChat.Id, messageType: MessageType.Document ); Update resultUpdate = chosenResultUpdate; @@ -684,37 +752,43 @@ public async Task Should_Answer_Inline_Query_With_Cached_Document() await using (FileStream stream = System.IO.File.OpenRead(Constants.PathToFile.Documents.Hamlet)) { documentMessage = await BotClient.SendDocumentAsync( - chatId: _fixture.SupergroupChat, - document: new InputFileStream(stream), - replyMarkup: (InlineKeyboardMarkup)InlineKeyboardButton - .WithSwitchInlineQueryCurrentChat("Start inline query") + new() + { + ChatId = fixture.SupergroupChat, + Document = InputFile.FromStream(stream), + ReplyMarkup = (InlineKeyboardMarkup)InlineKeyboardButton + .WithSwitchInlineQueryCurrentChat("Start inline query"), + } ); } - Update iqUpdate = await _fixture.UpdateReceiver.GetInlineQueryUpdateAsync(); + Update iqUpdate = await fixture.UpdateReceiver.GetInlineQueryUpdateAsync(); const string resultId = "document_result"; InlineQueryResult[] results = - { - new InlineQueryResultCachedDocument( - id: resultId, - documentFileId: documentMessage.Document!.FileId, - title: "Test Document") + [ + new InlineQueryResultCachedDocument { + Id = resultId, + DocumentFileId = documentMessage.Document!.FileId, + Title = "Test Document", Caption = "The Tragedy of Hamlet, Prince of Denmark", Description = "Sample PDF Document", } - }; + ]; await BotClient.AnswerInlineQueryAsync( - inlineQueryId: iqUpdate.InlineQuery!.Id, - results: results, - cacheTime: 0 + new() + { + InlineQueryId = iqUpdate.InlineQuery!.Id, + Results = results, + CacheTime = 0, + } ); (Update messageUpdate, Update chosenResultUpdate) = - await _fixture.UpdateReceiver.GetInlineQueryResultUpdates( - chatId: _fixture.SupergroupChat.Id, + await fixture.UpdateReceiver.GetInlineQueryResultUpdates( + chatId: fixture.SupergroupChat.Id, messageType: MessageType.Document ); Update resultUpdate = chosenResultUpdate; @@ -728,21 +802,21 @@ await using (FileStream stream = System.IO.File.OpenRead(Constants.PathToFile.Do [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.AnswerInlineQuery)] public async Task Should_Answer_Inline_Query_With_Gif() { - await _fixture.SendTestInstructionsAsync( + await fixture.SendTestInstructionsAsync( "Staring the inline query with this message...", startInlineQuery: true ); - Update iqUpdate = await _fixture.UpdateReceiver.GetInlineQueryUpdateAsync(); + Update iqUpdate = await fixture.UpdateReceiver.GetInlineQueryUpdateAsync(); const string resultId = "gif_result"; InlineQueryResult[] results = - { - new InlineQueryResultGif( - id: resultId, - gifUrl: "https://upload.wikimedia.org/wikipedia/commons/2/2c/Rotating_earth_%28large%29.gif", - thumbnailUrl: "https://upload.wikimedia.org/wikipedia/commons/2/2c/Rotating_earth_%28large%29.gif") + [ + new InlineQueryResultGif { + Id = resultId, + GifUrl = "https://upload.wikimedia.org/wikipedia/commons/2/2c/Rotating_earth_%28large%29.gif", + ThumbnailUrl = "https://upload.wikimedia.org/wikipedia/commons/2/2c/Rotating_earth_%28large%29.gif", Caption = "Rotating Earth", GifDuration = 4, GifHeight = 400, @@ -750,17 +824,20 @@ public async Task Should_Answer_Inline_Query_With_Gif() Title = "Rotating Earth", ThumbnailMimeType = "image/gif", } - }; + ]; await BotClient.AnswerInlineQueryAsync( - inlineQueryId: iqUpdate.InlineQuery!.Id, - results: results, - cacheTime: 0 + new() + { + InlineQueryId = iqUpdate.InlineQuery!.Id, + Results = results, + CacheTime = 0, + } ); (Update messageUpdate, Update chosenResultUpdate) = - await _fixture.UpdateReceiver.GetInlineQueryResultUpdates( - chatId: _fixture.SupergroupChat.Id, + await fixture.UpdateReceiver.GetInlineQueryResultUpdates( + chatId: fixture.SupergroupChat.Id, messageType: MessageType.Animation ); Update resultUpdate = chosenResultUpdate; @@ -775,33 +852,40 @@ public async Task Should_Answer_Inline_Query_With_Gif() public async Task Should_Answer_Inline_Query_With_Cached_Gif() { Message gifMessage = await BotClient.SendDocumentAsync( - chatId: _fixture.SupergroupChat, - document: new InputFileUrl("https://upload.wikimedia.org/wikipedia/commons/2/2c/Rotating_earth_%28large%29.gif"), - replyMarkup: (InlineKeyboardMarkup)InlineKeyboardButton - .WithSwitchInlineQueryCurrentChat("Start inline query")); + new() + { + ChatId = fixture.SupergroupChat, + Document = InputFile.FromUri("https://upload.wikimedia.org/wikipedia/commons/2/2c/Rotating_earth_%28large%29.gif"), + ReplyMarkup = (InlineKeyboardMarkup)InlineKeyboardButton + .WithSwitchInlineQueryCurrentChat("Start inline query"), + } + ); - Update iqUpdate = await _fixture.UpdateReceiver.GetInlineQueryUpdateAsync(); + Update iqUpdate = await fixture.UpdateReceiver.GetInlineQueryUpdateAsync(); const string resultId = "gif_result"; InlineQueryResult[] results = - { - new InlineQueryResultCachedGif( - id: resultId, - gifFileId: gifMessage.Document!.FileId) + [ + new InlineQueryResultCachedGif { + Id = resultId, + GifFileId = gifMessage.Document!.FileId, Caption = "Rotating Earth", } - }; + ]; await BotClient.AnswerInlineQueryAsync( - inlineQueryId: iqUpdate.InlineQuery!.Id, - results: results, - cacheTime: 0 + new() + { + InlineQueryId = iqUpdate.InlineQuery!.Id, + Results = results, + CacheTime = 0, + } ); (Update messageUpdate, Update chosenResultUpdate) = - await _fixture.UpdateReceiver.GetInlineQueryResultUpdates( - chatId: _fixture.SupergroupChat.Id, + await fixture.UpdateReceiver.GetInlineQueryResultUpdates( + chatId: fixture.SupergroupChat.Id, messageType: MessageType.Animation ); Update resultUpdate = chosenResultUpdate; @@ -815,34 +899,37 @@ public async Task Should_Answer_Inline_Query_With_Cached_Gif() [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.AnswerInlineQuery)] public async Task Should_Answer_Inline_Query_With_Mpeg4Gif() { - await _fixture.SendTestInstructionsAsync( + await fixture.SendTestInstructionsAsync( "Staring the inline query with this message...", startInlineQuery: true ); - Update iqUpdate = await _fixture.UpdateReceiver.GetInlineQueryUpdateAsync(); + Update iqUpdate = await fixture.UpdateReceiver.GetInlineQueryUpdateAsync(); const string resultId = "mpeg4_gif_result"; InlineQueryResult[] results = - { - new InlineQueryResultMpeg4Gif( - id: resultId, - mpeg4Url: "https://pixabay.com/en/videos/download/video-10737_medium.mp4", - thumbnailUrl: "https://i.vimeocdn.com/video/646283246_640x360.jpg") + [ + new InlineQueryResultMpeg4Gif { + Id = resultId, + Mpeg4Url = "https://pixabay.com/en/videos/download/video-10737_medium.mp4", + ThumbnailUrl = "https://i.vimeocdn.com/video/646283246_640x360.jpg", Caption = "A beautiful scene", - }, - }; + } + ]; await BotClient.AnswerInlineQueryAsync( - inlineQueryId: iqUpdate.InlineQuery!.Id, - results: results, - cacheTime: 0 + new() + { + InlineQueryId = iqUpdate.InlineQuery!.Id, + Results = results, + CacheTime = 0, + } ); (Update messageUpdate, Update chosenResultUpdate) = - await _fixture.UpdateReceiver.GetInlineQueryResultUpdates( - chatId: _fixture.SupergroupChat.Id, + await fixture.UpdateReceiver.GetInlineQueryResultUpdates( + chatId: fixture.SupergroupChat.Id, messageType: MessageType.Video ); Update resultUpdate = chosenResultUpdate; @@ -857,33 +944,40 @@ public async Task Should_Answer_Inline_Query_With_Mpeg4Gif() public async Task Should_Answer_Inline_Query_With_Cached_Mpeg4Gif() { Message gifMessage = await BotClient.SendDocumentAsync( - chatId: _fixture.SupergroupChat, - document: new InputFileUrl("https://upload.wikimedia.org/wikipedia/commons/2/2c/Rotating_earth_%28large%29.gif"), - replyMarkup: (InlineKeyboardMarkup)InlineKeyboardButton - .WithSwitchInlineQueryCurrentChat("Start inline query")); + new() + { + ChatId = fixture.SupergroupChat, + Document = InputFile.FromUri("https://upload.wikimedia.org/wikipedia/commons/2/2c/Rotating_earth_%28large%29.gif"), + ReplyMarkup = (InlineKeyboardMarkup)InlineKeyboardButton + .WithSwitchInlineQueryCurrentChat("Start inline query"), + } + ); - Update iqUpdate = await _fixture.UpdateReceiver.GetInlineQueryUpdateAsync(); + Update iqUpdate = await fixture.UpdateReceiver.GetInlineQueryUpdateAsync(); const string resultId = "mpeg4_gif_result"; InlineQueryResult[] results = - { - new InlineQueryResultCachedMpeg4Gif( - id: resultId, - mpeg4FileId: gifMessage.Document!.FileId) + [ + new InlineQueryResultCachedMpeg4Gif { + Id = resultId, + Mpeg4FileId = gifMessage.Document!.FileId, Caption = "Rotating Earth", } - }; + ]; await BotClient.AnswerInlineQueryAsync( - inlineQueryId: iqUpdate.InlineQuery!.Id, - results: results, - cacheTime: 0 + new() + { + InlineQueryId = iqUpdate.InlineQuery!.Id, + Results = results, + CacheTime = 0, + } ); (Update messageUpdate, Update chosenResultUpdate) = - await _fixture.UpdateReceiver.GetInlineQueryResultUpdates( - chatId: _fixture.SupergroupChat.Id, + await fixture.UpdateReceiver.GetInlineQueryResultUpdates( + chatId: fixture.SupergroupChat.Id, messageType: MessageType.Animation ); Update resultUpdate = chosenResultUpdate; @@ -898,30 +992,37 @@ public async Task Should_Answer_Inline_Query_With_Cached_Mpeg4Gif() [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.AnswerInlineQuery)] public async Task Should_Answer_Inline_Query_With_Cached_Sticker() { - await _fixture.SendTestInstructionsAsync( + await fixture.SendTestInstructionsAsync( "Staring the inline query with this message...", startInlineQuery: true ); - Update iqUpdate = await _fixture.UpdateReceiver.GetInlineQueryUpdateAsync(); + Update iqUpdate = await fixture.UpdateReceiver.GetInlineQueryUpdateAsync(); - StickerSet stickerSet = await BotClient.GetStickerSetAsync("EvilMinds"); + StickerSet stickerSet = await BotClient.GetStickerSetAsync(new GetStickerSetRequest { Name = "EvilMinds"}); const string resultId = "sticker_result"; InlineQueryResult[] results = - { - new InlineQueryResultCachedSticker(id: resultId, stickerFileId: stickerSet.Stickers[0].FileId) - }; + [ + new InlineQueryResultCachedSticker + { + Id = resultId, + StickerFileId = stickerSet.Stickers[0].FileId, + } + ]; await BotClient.AnswerInlineQueryAsync( - inlineQueryId: iqUpdate.InlineQuery!.Id, - results: results, - cacheTime: 0 + new() + { + InlineQueryId = iqUpdate.InlineQuery!.Id, + Results = results, + CacheTime = 0, + } ); (Update messageUpdate, Update chosenResultUpdate) = - await _fixture.UpdateReceiver.GetInlineQueryResultUpdates( - chatId: _fixture.SupergroupChat.Id, + await fixture.UpdateReceiver.GetInlineQueryResultUpdates( + chatId: fixture.SupergroupChat.Id, messageType: MessageType.Sticker ); Update resultUpdate = chosenResultUpdate; @@ -935,34 +1036,40 @@ public async Task Should_Answer_Inline_Query_With_Cached_Sticker() [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.AnswerInlineQuery)] public async Task Should_Answer_Inline_Query_With_Photo_With_Markdown_Encoded_Caption() { - await _fixture.SendTestInstructionsAsync( + await fixture.SendTestInstructionsAsync( "Staring the inline query with this message...", startInlineQuery: true ); - Update iqUpdate = await _fixture.UpdateReceiver.GetInlineQueryUpdateAsync(); + Update iqUpdate = await fixture.UpdateReceiver.GetInlineQueryUpdateAsync(); const string resultId = "photo:rainbow-girl-caption"; const string url = "https://cdn.pixabay.com/photo/2017/08/30/12/45/girl-2696947_640.jpg"; const string photoCaption = "Rainbow Girl"; InlineQueryResult[] results = - { - new InlineQueryResultPhoto(id: resultId, photoUrl: url, thumbnailUrl: url) + [ + new InlineQueryResultPhoto { + Id = resultId, + PhotoUrl = url, + ThumbnailUrl = url, Caption = $"*{photoCaption}*", ParseMode = ParseMode.Markdown } - }; + ]; await BotClient.AnswerInlineQueryAsync( - inlineQueryId: iqUpdate.InlineQuery!.Id, - results: results, - cacheTime: 0 + new() + { + InlineQueryId = iqUpdate.InlineQuery!.Id, + Results = results, + CacheTime = 0, + } ); (Update messageUpdate, Update chosenResultUpdate) = - await _fixture.UpdateReceiver.GetInlineQueryResultUpdates( - chatId: _fixture.SupergroupChat.Id, + await fixture.UpdateReceiver.GetInlineQueryResultUpdates( + chatId: fixture.SupergroupChat.Id, messageType: MessageType.Photo ); @@ -979,31 +1086,34 @@ public async Task Should_Answer_Inline_Query_With_Photo_With_Markdown_Encoded_Ca [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.AnswerInlineQuery)] public async Task Should_Throw_Exception_When_Answering_Late() { - await _fixture.SendTestInstructionsAsync( + await fixture.SendTestInstructionsAsync( "Write an inline query that I'll never answer!", startInlineQuery: true ); - Update queryUpdate = await _fixture.UpdateReceiver.GetInlineQueryUpdateAsync(); + Update queryUpdate = await fixture.UpdateReceiver.GetInlineQueryUpdateAsync(); InlineQueryResult[] results = - { - new InlineQueryResultArticle( - id: "article:bot-api", - title: "Telegram Bot API", - inputMessageContent: new InputTextMessageContent("https://core.telegram.org/bots/api")) + [ + new InlineQueryResultArticle { + Id = "article:bot-api", + Title = "Telegram Bot API", + InputMessageContent = new InputTextMessageContent { MessageText = "https://core.telegram.org/bots/api"}, Description = "The Bot API is an HTTP-based interface created for developers", - }, - }; + } + ]; await Task.Delay(10_000); ApiRequestException exception = await Assert.ThrowsAsync(() => BotClient.AnswerInlineQueryAsync( - inlineQueryId: queryUpdate.InlineQuery!.Id, - results: results, - cacheTime: 0 + new() + { + InlineQueryId = queryUpdate.InlineQuery!.Id, + Results = results, + CacheTime = 0, + } ) ); diff --git a/test/Telegram.Bot.Tests.Integ/Location/InlineMessageLiveLocationTests .cs b/test/Telegram.Bot.Tests.Integ/Location/InlineMessageLiveLocationTests .cs index dc4166aa6..3ef0a11bc 100644 --- a/test/Telegram.Bot.Tests.Integ/Location/InlineMessageLiveLocationTests .cs +++ b/test/Telegram.Bot.Tests.Integ/Location/InlineMessageLiveLocationTests .cs @@ -1,5 +1,6 @@ using System; using System.Threading.Tasks; +using Telegram.Bot.Requests; using Telegram.Bot.Tests.Integ.Framework; using Telegram.Bot.Types; using Telegram.Bot.Types.InlineQueryResults; @@ -12,83 +13,80 @@ namespace Telegram.Bot.Tests.Integ.Locations; [Collection(Constants.TestCollections.InlineMessageLiveLocation)] [Trait(Constants.CategoryTraitName, Constants.InteractiveCategoryValue)] [TestCaseOrderer(Constants.TestCaseOrderer, Constants.AssemblyName)] -public class InlineMessageLiveLocationTests : IClassFixture +public class InlineMessageLiveLocationTests(TestsFixture fixture, InlineMessageLiveLocationTests.Fixture classFixture) + : IClassFixture { - ITelegramBotClient BotClient => _fixture.BotClient; - - readonly Fixture _classFixture; - - readonly TestsFixture _fixture; - - public InlineMessageLiveLocationTests(TestsFixture fixture, Fixture classFixture) - { - _fixture = fixture; - _classFixture = classFixture; - } + ITelegramBotClient BotClient => fixture.BotClient; [OrderedFact("Should answer inline query with a location result")] [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.EditMessageLiveLocation)] public async Task Should_Answer_Inline_Query_With_Location() { - await _fixture.SendTestInstructionsAsync( + await fixture.SendTestInstructionsAsync( "Staring the inline query with this message...", startInlineQuery: true ); - Update iqUpdate = await _fixture.UpdateReceiver.GetInlineQueryUpdateAsync(); + Update iqUpdate = await fixture.UpdateReceiver.GetInlineQueryUpdateAsync(); string callbackQueryData = $"edit-location{new Random().Next(1_000)}"; - Location newYork = new Location {Latitude = 40.7128f, Longitude = -74.0060f}; + Location newYork = new() { Latitude = 40.7128f, Longitude = -74.0060f }; await BotClient.AnswerInlineQueryAsync( - inlineQueryId: iqUpdate.InlineQuery!.Id, - cacheTime: 0, - results: new[] + new() { - new InlineQueryResultLocation( - id: "live-location", - latitude: newYork.Latitude, - longitude: newYork.Longitude, - title: "Live Locations Test") - { - LivePeriod = 60, - ReplyMarkup = InlineKeyboardButton.WithCallbackData( - "Start live locations", callbackQueryData - ) - } + InlineQueryId = iqUpdate.InlineQuery!.Id, + CacheTime = 0, + Results = [ + new InlineQueryResultLocation + { + Id = "live-location", + Latitude = newYork.Latitude, + Longitude = newYork.Longitude, + Title = "Live Locations Test", + LivePeriod = 60, + ReplyMarkup = InlineKeyboardButton.WithCallbackData("Start live locations", callbackQueryData) + } + ], } ); - _classFixture.CallbackQueryData = callbackQueryData; + classFixture.CallbackQueryData = callbackQueryData; } [OrderedFact("Should edit live location of previously sent inline message")] [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.EditMessageLiveLocation)] public async Task Should_Edit_Inline_Message_Live_Location() { - await _fixture.SendTestInstructionsAsync("Click on location message's button to edit the location"); + await fixture.SendTestInstructionsAsync("Click on location message's button to edit the location"); - Update cqUpdate = await _fixture.UpdateReceiver - .GetCallbackQueryUpdateAsync(data: _classFixture.CallbackQueryData); + Update cqUpdate = await fixture.UpdateReceiver + .GetCallbackQueryUpdateAsync(data: classFixture.CallbackQueryData); - Location beijing = new Location {Latitude = 39.9042f, Longitude = 116.4074f}; + Location beijing = new() { Latitude = 39.9042f, Longitude = 116.4074f }; - await BotClient.EditMessageLiveLocationAsync( - inlineMessageId: cqUpdate.CallbackQuery!.InlineMessageId!, - latitude: beijing.Latitude, - longitude: beijing.Longitude, - replyMarkup: InlineKeyboardMarkup.Empty() + await BotClient.EditInlineMessageLiveLocationAsync( + new() + { + InlineMessageId = cqUpdate.CallbackQuery!.InlineMessageId!, + Latitude = beijing.Latitude, + Longitude = beijing.Longitude, + ReplyMarkup = InlineKeyboardMarkup.Empty(), + } ); - _classFixture.InlineMessageId = cqUpdate.CallbackQuery.InlineMessageId; + classFixture.InlineMessageId = cqUpdate.CallbackQuery.InlineMessageId; } [OrderedFact("Should stop live locations of previously sent inline message")] [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.StopMessageLiveLocation)] public async Task Should_Stop_Inline_Message_Live_Location() { - await BotClient.StopMessageLiveLocationAsync( - inlineMessageId: _classFixture.InlineMessageId + await BotClient.StopInlineMessageLiveLocationAsync( + new() + { + InlineMessageId = classFixture.InlineMessageId, + } ); } @@ -98,4 +96,4 @@ public class Fixture public string CallbackQueryData { get; set; } } -} \ No newline at end of file +} diff --git a/test/Telegram.Bot.Tests.Integ/Location/LiveLocationTests.cs b/test/Telegram.Bot.Tests.Integ/Location/LiveLocationTests.cs index af3e32f8e..bf09ad6d4 100644 --- a/test/Telegram.Bot.Tests.Integ/Location/LiveLocationTests.cs +++ b/test/Telegram.Bot.Tests.Integ/Location/LiveLocationTests.cs @@ -1,4 +1,5 @@ using System.Threading.Tasks; +using Telegram.Bot.Requests; using Telegram.Bot.Tests.Integ.Framework; using Telegram.Bot.Tests.Integ.Framework.Fixtures; using Telegram.Bot.Types; @@ -10,24 +11,15 @@ namespace Telegram.Bot.Tests.Integ.Locations; [Collection(Constants.TestCollections.LiveLocation)] [TestCaseOrderer(Constants.TestCaseOrderer, Constants.AssemblyName)] -public class LiveLocationTests : IClassFixture> +public class LiveLocationTests(TestsFixture fixture, EntityFixture classFixture) + : IClassFixture> { - ITelegramBotClient BotClient => _fixture.BotClient; + ITelegramBotClient BotClient => fixture.BotClient; Message LocationMessage { - get => _classFixture.Entity; - set => _classFixture.Entity = value; - } - - readonly TestsFixture _fixture; - - readonly EntityFixture _classFixture; - - public LiveLocationTests(TestsFixture fixture, EntityFixture classFixture) - { - _fixture = fixture; - _classFixture = classFixture; + get => classFixture.Entity; + set => classFixture.Entity = value; } [OrderedFact("Should send a location with live period to update")] @@ -38,10 +30,13 @@ public async Task Should_Send_Live_Location() const float lonBerlin = 13.4050f; Message message = await BotClient.SendLocationAsync( - chatId: _fixture.SupergroupChat.Id, - latitude: latBerlin, - longitude: lonBerlin, - livePeriod: 60 + new() + { + ChatId = fixture.SupergroupChat.Id, + Latitude = latBerlin, + Longitude = lonBerlin, + LivePeriod = 60, + } ); Assert.Equal(MessageType.Location, message.Type); @@ -55,11 +50,11 @@ public async Task Should_Send_Live_Location() [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.EditMessageLiveLocation)] public async Task Should_Update_Live_Location() { - Location[] locations = { - new Location { Latitude = 43.6532f, Longitude = -79.3832f }, // Toronto - new Location { Latitude = 59.9343f, Longitude = 30.3351f }, // Saint Petersburg - new Location { Latitude = 35.6892f, Longitude = 51.3890f }, // Tehran - }; + Location[] locations = [ + new() { Latitude = 43.6532f, Longitude = -79.3832f }, // Toronto + new() { Latitude = 59.9343f, Longitude = 30.3351f }, // Saint Petersburg + new() { Latitude = 35.6892f, Longitude = 51.3890f } // Tehran + ]; Message editedMessage = default; foreach (Location newLocation in locations) @@ -67,10 +62,13 @@ public async Task Should_Update_Live_Location() await Task.Delay(1_500); editedMessage = await BotClient.EditMessageLiveLocationAsync( - chatId: LocationMessage.Chat.Id, - messageId: LocationMessage.MessageId, - latitude: newLocation.Latitude, - longitude: newLocation.Longitude + new() + { + ChatId = LocationMessage.Chat.Id, + MessageId = LocationMessage.MessageId, + Latitude = newLocation.Latitude, + Longitude = newLocation.Longitude, + } ); Assert.Equal(MessageType.Location, editedMessage.Type); @@ -87,8 +85,11 @@ public async Task Should_Update_Live_Location() public async Task Should_Stop_Live_Location() { Message message = await BotClient.StopMessageLiveLocationAsync( - chatId: LocationMessage.Chat, - messageId: LocationMessage.MessageId + new StopMessageLiveLocationRequest + { + ChatId = LocationMessage.Chat, + MessageId = LocationMessage.MessageId, + } ); Assert.Equal(LocationMessage.MessageId, message.MessageId); @@ -98,4 +99,4 @@ public async Task Should_Stop_Live_Location() Assert.Equal(LocationMessage.Location.Latitude, message.Location.Latitude); Assert.Equal(LocationMessage.Location.Longitude, message.Location.Longitude); } -} \ No newline at end of file +} diff --git a/test/Telegram.Bot.Tests.Integ/Other/BotCommandsTests.cs b/test/Telegram.Bot.Tests.Integ/Other/BotCommandsTests.cs index 9a67bfe01..c281a3f8a 100644 --- a/test/Telegram.Bot.Tests.Integ/Other/BotCommandsTests.cs +++ b/test/Telegram.Bot.Tests.Integ/Other/BotCommandsTests.cs @@ -1,4 +1,6 @@ +using System; using System.Threading.Tasks; +using Telegram.Bot.Requests; using Telegram.Bot.Tests.Integ.Framework; using Telegram.Bot.Types; using Xunit; @@ -7,24 +9,18 @@ namespace Telegram.Bot.Tests.Integ.Other; [Collection(Constants.TestCollections.BotCommands)] [TestCaseOrderer(Constants.TestCaseOrderer, Constants.AssemblyName)] -public class BotCommandsTests: IAsyncLifetime +public class BotCommandsTests(TestsFixture fixture) : IAsyncLifetime { - readonly TestsFixture _fixture; BotCommandScope _scope; - ITelegramBotClient BotClient => _fixture.BotClient; - - public BotCommandsTests(TestsFixture fixture) - { - _fixture = fixture; - } + ITelegramBotClient BotClient => fixture.BotClient; [OrderedFact("Should set a new bot command list")] [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.SetMyCommands)] public async Task Should_Set_New_Bot_Command_List() { BotCommand[] commands = - { + [ new() { Command = "start", @@ -34,14 +30,17 @@ public async Task Should_Set_New_Bot_Command_List() { Command = "help", Description = "Help command" - }, - }; + } + ]; _scope = BotCommandScope.Default(); await BotClient.SetMyCommandsAsync( - commands: commands, - scope: _scope + new SetMyCommandsRequest + { + Commands = commands, + Scope = _scope, + } ); } @@ -50,7 +49,7 @@ public async Task Should_Set_New_Bot_Command_List() public async Task Should_Get_Set_Bot_Commands() { BotCommand[] commands = - { + [ new() { Command = "start", @@ -61,16 +60,21 @@ public async Task Should_Get_Set_Bot_Commands() Command = "help", Description = "Help command" }, - }; + ]; _scope = BotCommandScope.Default(); - await _fixture.BotClient.SetMyCommandsAsync( - commands: commands, - scope: _scope + await fixture.BotClient.SetMyCommandsAsync( + new SetMyCommandsRequest + { + Commands = commands, + Scope = _scope, + } ); - BotCommand[] currentCommands = await _fixture.BotClient.GetMyCommandsAsync(); + await Task.Delay(TimeSpan.FromSeconds(10)); + + BotCommand[] currentCommands = await fixture.BotClient.GetMyCommandsAsync(new GetMyCommandsRequest()); Assert.Equal(2, currentCommands.Length); Asserts.JsonEquals(commands, currentCommands); @@ -82,7 +86,7 @@ public async Task Should_Get_Set_Bot_Commands() public async Task Should_Delete_Bot_Commands() { BotCommand[] commands = - { + [ new() { Command = "start", @@ -92,24 +96,29 @@ public async Task Should_Delete_Bot_Commands() { Command = "help", Description = "Help command" - }, - }; + } + ]; _scope = BotCommandScope.Default(); await BotClient.SetMyCommandsAsync( - commands: commands, - scope: _scope + new SetMyCommandsRequest + { + Commands = commands, + Scope = _scope, + } ); - BotCommand[] setCommands = await BotClient.GetMyCommandsAsync(); + await Task.Delay(TimeSpan.FromSeconds(10)); + + BotCommand[] setCommands = await BotClient.GetMyCommandsAsync(new GetMyCommandsRequest()); Assert.NotNull(setCommands); Asserts.JsonEquals(commands, setCommands); - await BotClient.DeleteMyCommandsAsync(scope: _scope); + await BotClient.DeleteMyCommandsAsync(new DeleteMyCommandsRequest { Scope = _scope}); - BotCommand[] currentCommands = await BotClient.GetMyCommandsAsync(scope: _scope); + BotCommand[] currentCommands = await BotClient.GetMyCommandsAsync(new GetMyCommandsRequest { Scope = _scope }); Assert.NotNull(currentCommands); Assert.Empty(currentCommands); @@ -120,7 +129,7 @@ public async Task Should_Delete_Bot_Commands() public async Task Should_Set_Group_Scoped_Commands() { BotCommand[] commands = - { + [ new() { Command = "start", @@ -130,21 +139,27 @@ public async Task Should_Set_Group_Scoped_Commands() { Command = "help", Description = "Help command" - }, - }; + } + ]; _scope = BotCommandScope.AllGroupChats(); await BotClient.SetMyCommandsAsync( - commands: commands, - scope: _scope + new SetMyCommandsRequest + { + Commands = commands, + Scope = _scope, + } ); - BotCommand[] newCommands = await BotClient.GetMyCommandsAsync(scope: _scope); + await Task.Delay(TimeSpan.FromSeconds(10)); + + BotCommand[] newCommands = await BotClient.GetMyCommandsAsync(new GetMyCommandsRequest { Scope = _scope }); Asserts.JsonEquals(commands, newCommands); } public Task InitializeAsync() => Task.CompletedTask; - public async Task DisposeAsync() => await _fixture.BotClient.DeleteMyCommandsAsync(scope: _scope); -} \ No newline at end of file + public async Task DisposeAsync() => + await fixture.BotClient.DeleteMyCommandsAsync(new DeleteMyCommandsRequest { Scope = _scope }); +} diff --git a/test/Telegram.Bot.Tests.Integ/Other/BotDescriptionTests.cs b/test/Telegram.Bot.Tests.Integ/Other/BotDescriptionTests.cs index b8de14c42..570dcaa04 100644 --- a/test/Telegram.Bot.Tests.Integ/Other/BotDescriptionTests.cs +++ b/test/Telegram.Bot.Tests.Integ/Other/BotDescriptionTests.cs @@ -1,4 +1,6 @@ +using System; using System.Threading.Tasks; +using Telegram.Bot.Requests; using Telegram.Bot.Tests.Integ.Framework; using Telegram.Bot.Types; using Xunit; @@ -7,17 +9,11 @@ namespace Telegram.Bot.Tests.Integ.Other; [Collection(Constants.TestCollections.BotDescription)] [TestCaseOrderer(Constants.TestCaseOrderer, Constants.AssemblyName)] -public class BotDescriptionTests: IAsyncLifetime +public class BotDescriptionTests(TestsFixture fixture) : IAsyncLifetime { - readonly TestsFixture _fixture; string _languageCode; - ITelegramBotClient BotClient => _fixture.BotClient; - - public BotDescriptionTests(TestsFixture fixture) - { - _fixture = fixture; - } + ITelegramBotClient BotClient => fixture.BotClient; [OrderedFact("Should set a new bot description")] [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.SetMyDescription)] @@ -26,7 +22,10 @@ public async Task Should_Set_New_Bot_Description() string description = "Test bot description"; await BotClient.SetMyDescriptionAsync( - description: description + new SetMyDescriptionRequest + { + Description = description, + } ); } @@ -34,13 +33,18 @@ public async Task Should_Set_New_Bot_Description() [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.GetMyDescription)] public async Task Should_Get_Set_Bot_Description() { - string description = "Test bot description"; + const string description = "Test bot description"; await BotClient.SetMyDescriptionAsync( - description: description + new SetMyDescriptionRequest + { + Description = description, + } ); - BotDescription currentDescription = await _fixture.BotClient.GetMyDescriptionAsync(); + await Task.Delay(TimeSpan.FromSeconds(10)); + + BotDescription currentDescription = await fixture.BotClient.GetMyDescriptionAsync(new GetMyDescriptionRequest()); Assert.NotNull(currentDescription); Assert.Equal(description, currentDescription.Description); @@ -53,19 +57,27 @@ public async Task Should_Delete_Bot_Description() string description = "Test bot description"; await BotClient.SetMyDescriptionAsync( - description: description + new SetMyDescriptionRequest + { + Description = description, + } ); - BotDescription setDescription = await _fixture.BotClient.GetMyDescriptionAsync(); + BotDescription setDescription = await fixture.BotClient.GetMyDescriptionAsync(new GetMyDescriptionRequest()); Assert.NotNull(setDescription); Assert.Equal(description, setDescription.Description); await BotClient.SetMyDescriptionAsync( - description: string.Empty + new SetMyDescriptionRequest + { + Description = string.Empty, + } ); - BotDescription currentDescription = await _fixture.BotClient.GetMyDescriptionAsync(); + await Task.Delay(TimeSpan.FromSeconds(10)); + + BotDescription currentDescription = await fixture.BotClient.GetMyDescriptionAsync(new GetMyDescriptionRequest()); Assert.NotNull(currentDescription.Description); Assert.Empty(currentDescription.Description); @@ -80,11 +92,21 @@ public async Task Should_Set_Description_With_Language_Code_Area() _languageCode = "ru"; await BotClient.SetMyDescriptionAsync( - description: description, - languageCode: _languageCode + new SetMyDescriptionRequest + { + Description = description, + LanguageCode = _languageCode, + } ); - BotDescription newDescription = await _fixture.BotClient.GetMyDescriptionAsync(languageCode: _languageCode); + await Task.Delay(TimeSpan.FromSeconds(10)); + + BotDescription newDescription = await fixture.BotClient.GetMyDescriptionAsync( + new GetMyDescriptionRequest + { + LanguageCode = _languageCode + } + ); Assert.NotNull(newDescription); Assert.Equal(description, newDescription.Description); @@ -95,12 +117,18 @@ public async Task Should_Set_Description_With_Language_Code_Area() public async Task DisposeAsync() { await BotClient.SetMyDescriptionAsync( - description: string.Empty + new SetMyDescriptionRequest + { + Description = string.Empty, + } ); await BotClient.SetMyDescriptionAsync( - description: string.Empty, - languageCode: _languageCode + new SetMyDescriptionRequest + { + Description = string.Empty, + LanguageCode = _languageCode, + } ); } } diff --git a/test/Telegram.Bot.Tests.Integ/Other/BotShortDescriptionTests.cs b/test/Telegram.Bot.Tests.Integ/Other/BotShortDescriptionTests.cs index daa1eafa8..ecc632b1a 100644 --- a/test/Telegram.Bot.Tests.Integ/Other/BotShortDescriptionTests.cs +++ b/test/Telegram.Bot.Tests.Integ/Other/BotShortDescriptionTests.cs @@ -1,4 +1,6 @@ +using System; using System.Threading.Tasks; +using Telegram.Bot.Requests; using Telegram.Bot.Tests.Integ.Framework; using Telegram.Bot.Types; using Xunit; @@ -7,26 +9,20 @@ namespace Telegram.Bot.Tests.Integ.Other; [Collection(Constants.TestCollections.BotShortDescription)] [TestCaseOrderer(Constants.TestCaseOrderer, Constants.AssemblyName)] -public class BotShortDescriptionTests: IAsyncLifetime +public class BotShortDescriptionTests(TestsFixture fixture) : IAsyncLifetime { - readonly TestsFixture _fixture; string _languageCode; - ITelegramBotClient BotClient => _fixture.BotClient; - - public BotShortDescriptionTests(TestsFixture fixture) - { - _fixture = fixture; - } + ITelegramBotClient BotClient => fixture.BotClient; [OrderedFact("Should set a new bot short description")] [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.SetMyShortDescription)] public async Task Should_Set_New_Bot__Short_Description() { - string shortDescription = "Test bot short description"; + const string shortDescription = "Test bot short description"; await BotClient.SetMyShortDescriptionAsync( - shortDescription: shortDescription + new SetMyShortDescriptionRequest { ShortDescription = shortDescription } ); } @@ -34,13 +30,15 @@ public async Task Should_Set_New_Bot__Short_Description() [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.GetMyShortDescription)] public async Task Should_Get_Set_Bot_Short_Description() { - string shortDescription = "Test bot short description"; + const string shortDescription = "Test bot short description"; await BotClient.SetMyShortDescriptionAsync( - shortDescription: shortDescription + new SetMyShortDescriptionRequest { ShortDescription = shortDescription } ); - BotShortDescription currentShortDescription = await _fixture.BotClient.GetMyShortDescriptionAsync(); + await Task.Delay(TimeSpan.FromSeconds(10)); + + BotShortDescription currentShortDescription = await fixture.BotClient.GetMyShortDescriptionAsync(new GetMyShortDescriptionRequest()); Assert.NotNull(currentShortDescription); Assert.Equal(shortDescription, currentShortDescription.ShortDescription); @@ -50,22 +48,25 @@ public async Task Should_Get_Set_Bot_Short_Description() [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.SetMyShortDescription)] public async Task Should_Delete_Bot_Short_Description() { - string shortDescription = "Test bot short description"; + const string shortDescription = "Test bot short description"; await BotClient.SetMyShortDescriptionAsync( - shortDescription: shortDescription + new SetMyShortDescriptionRequest { ShortDescription = shortDescription } ); - BotShortDescription setShortDescription = await _fixture.BotClient.GetMyShortDescriptionAsync(); + BotShortDescription setShortDescription = await fixture.BotClient.GetMyShortDescriptionAsync(new GetMyShortDescriptionRequest()); Assert.NotNull(setShortDescription); Assert.Equal(shortDescription, setShortDescription.ShortDescription); await BotClient.SetMyShortDescriptionAsync( - shortDescription: string.Empty + new SetMyShortDescriptionRequest { ShortDescription = "" } ); - BotShortDescription currentShortDescription = await _fixture.BotClient.GetMyShortDescriptionAsync(); + // Test fails receiving old description without a delay + await Task.Delay(TimeSpan.FromSeconds(20)); + + BotShortDescription currentShortDescription = await fixture.BotClient.GetMyShortDescriptionAsync(new GetMyShortDescriptionRequest()); Assert.NotNull(currentShortDescription.ShortDescription); Assert.Empty(currentShortDescription.ShortDescription); @@ -75,16 +76,23 @@ public async Task Should_Delete_Bot_Short_Description() [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.SetMyShortDescription)] public async Task Should_Set_Short_Description_With_Language_Code_Area() { - string shortDescription = "Короткое тестовое описание бота"; + const string shortDescription = "Короткое тестовое описание бота"; _languageCode = "ru"; await BotClient.SetMyShortDescriptionAsync( - shortDescription: shortDescription, - languageCode: _languageCode + new SetMyShortDescriptionRequest + { + ShortDescription = shortDescription, + LanguageCode = _languageCode, + } ); - BotShortDescription newDescription = await _fixture.BotClient.GetMyShortDescriptionAsync(languageCode: _languageCode); + await Task.Delay(TimeSpan.FromSeconds(10)); + + BotShortDescription newDescription = await fixture.BotClient.GetMyShortDescriptionAsync( + new GetMyShortDescriptionRequest {LanguageCode = _languageCode} + ); Assert.NotNull(newDescription); Assert.Equal(shortDescription, newDescription.ShortDescription); @@ -95,12 +103,15 @@ public async Task Should_Set_Short_Description_With_Language_Code_Area() public async Task DisposeAsync() { await BotClient.SetMyShortDescriptionAsync( - shortDescription: string.Empty - ); + new SetMyShortDescriptionRequest { ShortDescription = "" + }); await BotClient.SetMyShortDescriptionAsync( - shortDescription: string.Empty, - languageCode: _languageCode + new SetMyShortDescriptionRequest + { + ShortDescription = "", + LanguageCode = _languageCode + } ); } } diff --git a/test/Telegram.Bot.Tests.Integ/Other/ChatInfoTests.cs b/test/Telegram.Bot.Tests.Integ/Other/ChatInfoTests.cs index 114dc88ef..4172db049 100644 --- a/test/Telegram.Bot.Tests.Integ/Other/ChatInfoTests.cs +++ b/test/Telegram.Bot.Tests.Integ/Other/ChatInfoTests.cs @@ -1,6 +1,7 @@ using System.Diagnostics; using System.Linq; using System.Threading.Tasks; +using Telegram.Bot.Requests; using Telegram.Bot.Tests.Integ.Framework; using Telegram.Bot.Types; using Telegram.Bot.Types.Enums; @@ -10,21 +11,21 @@ namespace Telegram.Bot.Tests.Integ.Other; [Collection(Constants.TestCollections.ChatInfo)] [TestCaseOrderer(Constants.TestCaseOrderer, Constants.AssemblyName)] -public class ChatInfoTests +public class ChatInfoTests(TestsFixture fixture) { - ITelegramBotClient BotClient => _fixture.BotClient; - readonly TestsFixture _fixture; - - public ChatInfoTests(TestsFixture fixture) => _fixture = fixture; + ITelegramBotClient BotClient => fixture.BotClient; [OrderedFact("Should get supergroup chat info")] [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.GetChat)] public async Task Should_Get_Supergroup_Chat() { - Chat supergroupChat = _fixture.SupergroupChat; + Chat supergroupChat = fixture.SupergroupChat; Chat chat = await BotClient.GetChatAsync( - chatId: supergroupChat.Id + new GetChatRequest + { + ChatId = supergroupChat.Id, + } ); Assert.Equal(ChatType.Supergroup, chat.Type); @@ -48,8 +49,11 @@ public async Task Should_Get_Supergroup_Chat() public async Task Should_Get_Bot_Chat_Member() { ChatMember memberBot = await BotClient.GetChatMemberAsync( - chatId: _fixture.SupergroupChat.Id, - userId: _fixture.BotUser.Id + new() + { + ChatId = fixture.SupergroupChat.Id, + UserId = fixture.BotUser.Id, + } ); Assert.Equal(ChatMemberStatus.Administrator, memberBot.Status); @@ -66,7 +70,7 @@ public async Task Should_Get_Bot_Chat_Member() Assert.Null(administrator.CanPostMessages); Assert.Null(administrator.CanEditMessages); - Asserts.UsersEqual(_fixture.BotUser, memberBot.User); + Asserts.UsersEqual(fixture.BotUser, memberBot.User); } [OrderedFact("Should get supergroup chat administrators")] @@ -74,17 +78,20 @@ public async Task Should_Get_Bot_Chat_Member() public async Task Should_Get_Chat_Admins() { ChatMember[] chatAdmins = await BotClient.GetChatAdministratorsAsync( - chatId: _fixture.SupergroupChat.Id + new GetChatAdministratorsRequest + { + ChatId = fixture.SupergroupChat.Id, + } ); - ChatMember memberCreator = Assert.Single(chatAdmins, _ => _.Status == ChatMemberStatus.Creator); + ChatMember memberCreator = Assert.Single(chatAdmins, admin => admin.Status == ChatMemberStatus.Creator); Assert.IsType(memberCreator); - ChatMember memberBot = Assert.Single(chatAdmins, _ => _.User.IsBot); + ChatMember memberBot = Assert.Single(chatAdmins, admin => admin.User.IsBot); Debug.Assert(memberBot != null); Assert.True(2 <= chatAdmins.Length); // at least, Bot and the Creator - Asserts.UsersEqual(_fixture.BotUser, memberBot.User); + Asserts.UsersEqual(fixture.BotUser, memberBot.User); } [OrderedFact("Should get private chat info")] @@ -97,14 +104,16 @@ public async Task Should_Get_Private_Chat() /* In order to have a private chat id, take the Creator of supergroup and use his User ID because * for a regular user, "User ID" is the same number as "Private Chat ID". */ - ChatMember[] chatAdmins = await BotClient.GetChatAdministratorsAsync(_fixture.SupergroupChat); + ChatMember[] chatAdmins = await BotClient.GetChatAdministratorsAsync( + new GetChatAdministratorsRequest { ChatId = fixture.SupergroupChat } + ); privateChatId = chatAdmins .Single(member => member.Status == ChatMemberStatus.Creator) .User.Id; } Chat chat = await BotClient.GetChatAsync( - chatId: privateChatId + new GetChatRequest { ChatId = privateChatId, } ); Assert.Equal(ChatType.Private, chat.Type); @@ -130,7 +139,7 @@ public async Task Should_Get_Private_Chat() public async Task Should_Get_Chat_Members_Count() { int membersCount = await BotClient.GetChatMemberCountAsync( - chatId: _fixture.SupergroupChat.Id + new GetChatMemberCountRequest {ChatId = fixture.SupergroupChat.Id} ); Assert.True(2 <= membersCount); // at least, Bot and the Creator @@ -145,10 +154,13 @@ public async Task Should_Get_Chat_Members_Count() public async Task Should_Send_Chat_Action() { await BotClient.SendChatActionAsync( - chatId: _fixture.SupergroupChat.Id, - chatAction: ChatAction.RecordVoice + new() + { + ChatId = fixture.SupergroupChat.Id, + Action = ChatAction.RecordVoice, + } ); await Task.Delay(5_000); } -} \ No newline at end of file +} diff --git a/test/Telegram.Bot.Tests.Integ/Other/DiceTests.cs b/test/Telegram.Bot.Tests.Integ/Other/DiceTests.cs index 9eedc99cf..63022311c 100644 --- a/test/Telegram.Bot.Tests.Integ/Other/DiceTests.cs +++ b/test/Telegram.Bot.Tests.Integ/Other/DiceTests.cs @@ -1,4 +1,5 @@ using System.Threading.Tasks; +using Telegram.Bot.Requests; using Telegram.Bot.Tests.Integ.Framework; using Telegram.Bot.Types; using Telegram.Bot.Types.Enums; @@ -8,20 +9,18 @@ namespace Telegram.Bot.Tests.Integ.Other; [Collection(Constants.TestCollections.Dice)] [TestCaseOrderer(Constants.TestCaseOrderer, Constants.AssemblyName)] -public class DiceTests +public class DiceTests(TestsFixture testsFixture) { - readonly TestsFixture _testsFixture; - - public DiceTests(TestsFixture testsFixture) - { - _testsFixture = testsFixture; - } - [OrderedFact("Should send a die")] [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.SendDice)] public async Task Should_Send_A_Die() { - Message message = await _testsFixture.BotClient.SendDiceAsync(_testsFixture.SupergroupChat); + Message message = await testsFixture.BotClient.SendDiceAsync( + new SendDiceRequest + { + ChatId = testsFixture.SupergroupChat + } + ); Assert.Equal(MessageType.Dice, message.Type); Assert.NotNull(message.Dice); @@ -33,9 +32,12 @@ public async Task Should_Send_A_Die() [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.SendDice)] public async Task Should_Send_A_Dart() { - Message message = await _testsFixture.BotClient.SendDiceAsync( - _testsFixture.SupergroupChat, - emoji: Emoji.Darts + Message message = await testsFixture.BotClient.SendDiceAsync( + new SendDiceRequest + { + ChatId = testsFixture.SupergroupChat, + Emoji = Emoji.Darts, + } ); Assert.Equal(MessageType.Dice, message.Type); @@ -48,9 +50,12 @@ public async Task Should_Send_A_Dart() [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.SendDice)] public async Task Should_Send_A_Basketball() { - Message message = await _testsFixture.BotClient.SendDiceAsync( - _testsFixture.SupergroupChat, - emoji: Emoji.Basketball + Message message = await testsFixture.BotClient.SendDiceAsync( + new SendDiceRequest + { + ChatId = testsFixture.SupergroupChat, + Emoji = Emoji.Basketball, + } ); Assert.Equal(MessageType.Dice, message.Type); @@ -63,9 +68,12 @@ public async Task Should_Send_A_Basketball() [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.SendDice)] public async Task Should_Send_A_Football() { - Message message = await _testsFixture.BotClient.SendDiceAsync( - _testsFixture.SupergroupChat, - emoji: Emoji.Football + Message message = await testsFixture.BotClient.SendDiceAsync( + new SendDiceRequest + { + ChatId = testsFixture.SupergroupChat, + Emoji = Emoji.Football, + } ); Assert.Equal(MessageType.Dice, message.Type); @@ -77,9 +85,12 @@ public async Task Should_Send_A_Football() [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.SendDice)] public async Task Should_Send_A_SlotMachine() { - Message message = await _testsFixture.BotClient.SendDiceAsync( - _testsFixture.SupergroupChat, - emoji: Emoji.SlotMachine + Message message = await testsFixture.BotClient.SendDiceAsync( + new SendDiceRequest + { + ChatId = testsFixture.SupergroupChat, + Emoji = Emoji.SlotMachine, + } ); Assert.Equal(MessageType.Dice, message.Type); @@ -92,9 +103,12 @@ public async Task Should_Send_A_SlotMachine() [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.SendDice)] public async Task Should_Send_A_Bowling() { - Message message = await _testsFixture.BotClient.SendDiceAsync( - _testsFixture.SupergroupChat, - emoji: Emoji.Bowling + Message message = await testsFixture.BotClient.SendDiceAsync( + new SendDiceRequest + { + ChatId = testsFixture.SupergroupChat, + Emoji = Emoji.Bowling + } ); Assert.Equal(MessageType.Dice, message.Type); @@ -102,4 +116,4 @@ public async Task Should_Send_A_Bowling() Assert.Equal("🎳", message.Dice.Emoji); Assert.InRange(message.Dice.Value, 1, 6); } -} \ No newline at end of file +} diff --git a/test/Telegram.Bot.Tests.Integ/Other/FileDownloadTests.cs b/test/Telegram.Bot.Tests.Integ/Other/FileDownloadTests.cs index fbe997250..29e533c60 100644 --- a/test/Telegram.Bot.Tests.Integ/Other/FileDownloadTests.cs +++ b/test/Telegram.Bot.Tests.Integ/Other/FileDownloadTests.cs @@ -3,6 +3,7 @@ using System.Threading.Tasks; using Newtonsoft.Json.Linq; using Telegram.Bot.Exceptions; +using Telegram.Bot.Requests; using Telegram.Bot.Tests.Integ.Framework; using Telegram.Bot.Types; using Xunit; @@ -13,20 +14,10 @@ namespace Telegram.Bot.Tests.Integ.Other; [Collection(Constants.TestCollections.FileDownload)] [TestCaseOrderer(Constants.TestCaseOrderer, Constants.AssemblyName)] -public class FileDownloadTests : IClassFixture +public class FileDownloadTests(TestsFixture fixture, FileDownloadTests.Fixture classFixture, ITestOutputHelper output) + : IClassFixture { - readonly ITestOutputHelper _output; - readonly Fixture _classFixture; - readonly TestsFixture _fixture; - - ITelegramBotClient BotClient => _fixture.BotClient; - - public FileDownloadTests(TestsFixture fixture, Fixture classFixture, ITestOutputHelper output) - { - _fixture = fixture; - _classFixture = classFixture; - _output = output; - } + ITelegramBotClient BotClient => fixture.BotClient; [OrderedFact("Should get file info")] [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.GetFile)] @@ -40,8 +31,11 @@ public async Task Should_Get_File_Info() await using (Stream stream = System.IO.File.OpenRead(Constants.PathToFile.Documents.Hamlet)) { documentMessage = await BotClient.SendDocumentAsync( - chatId: _fixture.SupergroupChat, - document: new InputFileStream(stream) + new() + { + ChatId = fixture.SupergroupChat, + Document = InputFile.FromStream(stream), + } ); } @@ -49,7 +43,7 @@ await using (Stream stream = System.IO.File.OpenRead(Constants.PathToFile.Docume #endregion - File file = await BotClient.GetFileAsync(documentMessage.Document.FileId); + File file = await BotClient.GetFileAsync(new GetFileRequest { FileId = documentMessage.Document.FileId }); Assert.Equal(fileId, file.FileId); Assert.NotNull(file.FileSize); @@ -57,20 +51,20 @@ await using (Stream stream = System.IO.File.OpenRead(Constants.PathToFile.Docume Assert.NotNull(file.FilePath); Assert.NotEmpty(file.FilePath); - _classFixture.File = file; + classFixture.File = file; } [OrderedFact("Should download file using file_path and write it to disk")] public async Task Should_Download_Write_Using_FilePath() { - long? fileSize = _classFixture.File.FileSize; + long? fileSize = classFixture.File.FileSize; string destinationFilePath = $"{Path.GetTempFileName()}.{Fixture.FileType}"; - _output.WriteLine($@"Writing file to ""{destinationFilePath}"""); + output.WriteLine($@"Writing file to ""{destinationFilePath}"""); await using FileStream fileStream = System.IO.File.OpenWrite(destinationFilePath); await BotClient.DownloadFileAsync( - filePath: _classFixture.File.FilePath!, + filePath: classFixture.File.FilePath!, destination: fileStream ); @@ -81,21 +75,21 @@ public async Task Should_Download_Write_Using_FilePath() [OrderedFact("Should download file using file_id and write it to disk")] public async Task Should_Download_Write_Using_FileId() { - long? fileSize = _classFixture.File.FileSize; + long? fileSize = classFixture.File.FileSize; string destinationFilePath = $"{Path.GetTempFileName()}.{Fixture.FileType}"; - _output.WriteLine($@"Writing file to ""{destinationFilePath}"""); + output.WriteLine($@"Writing file to ""{destinationFilePath}"""); await using FileStream fileStream = System.IO.File.OpenWrite(destinationFilePath); File file = await BotClient.GetInfoAndDownloadFileAsync( - fileId: _classFixture.File.FileId, + fileId: classFixture.File.FileId, destination: fileStream ); Assert.NotNull(fileSize); Assert.InRange(fileStream.Length, (int)fileSize - 100, (int)fileSize + 100); Assert.True(JToken.DeepEquals( - JToken.FromObject(_classFixture.File), JToken.FromObject(file) + JToken.FromObject(classFixture.File), JToken.FromObject(file) )); } @@ -104,7 +98,7 @@ public async Task Should_Download_Write_Using_FileId() public async Task Should_Throw_FileId_InvalidParameterException() { ApiRequestException exception = await Assert.ThrowsAsync(async () => - await BotClient.GetFileAsync("Invalid_File_id") + await BotClient.GetFileAsync(new GetFileRequest { FileId = "Invalid_File_id" }) ); Assert.Contains("file_id", exception.Message); diff --git a/test/Telegram.Bot.Tests.Integ/Other/GetUserProfileTests.cs b/test/Telegram.Bot.Tests.Integ/Other/GetUserProfileTests.cs index b8deec958..2a1ae4669 100644 --- a/test/Telegram.Bot.Tests.Integ/Other/GetUserProfileTests.cs +++ b/test/Telegram.Bot.Tests.Integ/Other/GetUserProfileTests.cs @@ -1,5 +1,6 @@ using System.Linq; using System.Threading.Tasks; +using Telegram.Bot.Requests; using Telegram.Bot.Tests.Integ.Framework; using Telegram.Bot.Types; using Xunit; @@ -8,23 +9,19 @@ namespace Telegram.Bot.Tests.Integ.Other; [Collection(Constants.TestCollections.GetUserProfilePhotos)] [TestCaseOrderer(Constants.TestCaseOrderer, Constants.AssemblyName)] -public class GetUserProfileTests +public class GetUserProfileTests(TestsFixture fixture) { - ITelegramBotClient BotClient => _fixture.BotClient; - - readonly TestsFixture _fixture; - - public GetUserProfileTests(TestsFixture fixture) - { - _fixture = fixture; - } + ITelegramBotClient BotClient => fixture.BotClient; [OrderedFact("Should get bot’s profile photos")] [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.GetUserProfilePhotos)] public async Task Should_Get_User_Profile_Photos() { UserProfilePhotos profilePhotos = await BotClient.GetUserProfilePhotosAsync( - userId: _fixture.BotUser.Id + new GetUserProfilePhotosRequest + { + UserId = fixture.BotUser.Id, + } ); Assert.True(1 <= profilePhotos.TotalCount); diff --git a/test/Telegram.Bot.Tests.Integ/Other/LeaveChatTests.cs b/test/Telegram.Bot.Tests.Integ/Other/LeaveChatTests.cs index 47c89ece3..f1577ec19 100644 --- a/test/Telegram.Bot.Tests.Integ/Other/LeaveChatTests.cs +++ b/test/Telegram.Bot.Tests.Integ/Other/LeaveChatTests.cs @@ -1,4 +1,5 @@ using System.Threading.Tasks; +using Telegram.Bot.Requests; using Telegram.Bot.Tests.Integ.Framework; using Xunit; @@ -6,16 +7,9 @@ namespace Telegram.Bot.Tests.Integ.Other; [Collection(Constants.TestCollections.LeaveChat)] [TestCaseOrderer(Constants.TestCaseOrderer, Constants.AssemblyName)] -public class LeaveChatTests +public class LeaveChatTests(TestsFixture fixture) { - ITelegramBotClient BotClient => _fixture.BotClient; - - readonly TestsFixture _fixture; - - public LeaveChatTests(TestsFixture fixture) - { - _fixture = fixture; - } + ITelegramBotClient BotClient => fixture.BotClient; [OrderedFact("Should leave chat", Skip = "Bot should stay in chat for other the test cases")] @@ -24,7 +18,10 @@ public async Task Should_Get_Private_Chat() { // ToDo: Exception when leaving private chat await BotClient.LeaveChatAsync( - chatId: _fixture.SupergroupChat + new LeaveChatRequest + { + ChatId = fixture.SupergroupChat, + } ); } -} \ No newline at end of file +} diff --git a/test/Telegram.Bot.Tests.Integ/Payments/PaymentFixture.cs b/test/Telegram.Bot.Tests.Integ/Payments/PaymentFixture.cs index dc645ca90..184441507 100644 --- a/test/Telegram.Bot.Tests.Integ/Payments/PaymentFixture.cs +++ b/test/Telegram.Bot.Tests.Integ/Payments/PaymentFixture.cs @@ -12,14 +12,7 @@ public PaymentFixture(TestsFixture testsFixture) : base(testsFixture, Constants.TestCollections.Payment) { PaymentProviderToken = testsFixture.Configuration.PaymentProviderToken; - if (PaymentProviderToken is null) - { - throw new ArgumentNullException(nameof(PaymentProviderToken)); - } - - if (PaymentProviderToken.Length < 5) - { - throw new ArgumentException("Payment provider token is invalid", nameof(PaymentProviderToken)); - } + ArgumentNullException.ThrowIfNull(PaymentProviderToken); + ArgumentOutOfRangeException.ThrowIfLessThan(PaymentProviderToken.Length, 5); } -} \ No newline at end of file +} diff --git a/test/Telegram.Bot.Tests.Integ/Payments/PaymentTests.cs b/test/Telegram.Bot.Tests.Integ/Payments/PaymentTests.cs index 7c4d4e26f..dc74b5d75 100644 --- a/test/Telegram.Bot.Tests.Integ/Payments/PaymentTests.cs +++ b/test/Telegram.Bot.Tests.Integ/Payments/PaymentTests.cs @@ -18,25 +18,17 @@ namespace Telegram.Bot.Tests.Integ.Payments; [Collection(Constants.TestCollections.Payment)] [Trait(Constants.CategoryTraitName, Constants.InteractiveCategoryValue)] [TestCaseOrderer(Constants.TestCaseOrderer, Constants.AssemblyName)] -public class PaymentTests : IClassFixture, IAsyncLifetime +public class PaymentTests(TestsFixture fixture, PaymentFixture classFixture) + : IClassFixture, IAsyncLifetime { - readonly TestsFixture _fixture; - readonly PaymentFixture _classFixture; - - ITelegramBotClient BotClient => _fixture.BotClient; - - public PaymentTests(TestsFixture fixture, PaymentFixture classFixture) - { - _fixture = fixture; - _classFixture = classFixture; - } + ITelegramBotClient BotClient => fixture.BotClient; [OrderedFact("Should send an invoice")] [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.SendInvoice)] public async Task Should_Send_Invoice() { PaymentsBuilder paymentsBuilder = new PaymentsBuilder() - .WithProduct(_ => _ + .WithProduct(p => p .WithTitle(title: "Lunar crater \"Copernicus\"") .WithDescription(description: "It was named after the astronomer Nicolaus Copernicus. It may have been created by debris" + @@ -51,8 +43,8 @@ public async Task Should_Send_Invoice() .WithCurrency(currency: "USD") .WithStartParameter(startParameter: "crater-copernicus") .WithPayload(payload: "") - .WithPaymentProviderToken(paymentsProviderToken: _classFixture.PaymentProviderToken) - .ToChat(chatId: _classFixture.PrivateChat.Id); + .WithPaymentProviderToken(paymentsProviderToken: classFixture.PaymentProviderToken) + .ToChat(chatId: classFixture.PrivateChat.Id); PreliminaryInvoice preliminaryInvoice = paymentsBuilder.GetPreliminaryInvoice(); SendInvoiceRequest requestRequest = paymentsBuilder.BuildInvoiceRequest(); @@ -75,7 +67,7 @@ public async Task Should_Send_Invoice() public async Task Should_Answer_Shipping_Query_With_Ok() { PaymentsBuilder paymentsBuilder = new PaymentsBuilder() - .WithProduct(_ => _ + .WithProduct(p => p .WithTitle(title: "Reproduction of \"La nascita di Venere\"") .WithDescription(description: "Sandro Botticelli’s the Birth of Venus depicts the goddess Venus arriving at the shore" + @@ -87,7 +79,7 @@ public async Task Should_Answer_Shipping_Query_With_Ok() width: 1280, height: 820 )) - .WithShipping(_ => _ + .WithShipping(s => s .WithTitle(title: "DHL Express") .WithId(id: "dhl-express") .WithPrice(label: "Packaging", amount: 400_000) @@ -96,15 +88,15 @@ public async Task Should_Answer_Shipping_Query_With_Ok() .WithPayload("") .WithFlexible() .RequireShippingAddress() - .WithPaymentProviderToken(_classFixture.PaymentProviderToken) - .ToChat(_classFixture.PrivateChat.Id); + .WithPaymentProviderToken(classFixture.PaymentProviderToken) + .ToChat(classFixture.PrivateChat.Id); double totalCostWithoutShippingCost = paymentsBuilder .GetTotalAmountWithoutShippingCost() .CurrencyFormat(); string instruction = FormatInstructionWithCurrency($"Click on *Pay {totalCostWithoutShippingCost:C}* and send your shipping address."); - await _fixture.SendTestInstructionsAsync(instruction, chatId: _classFixture.PrivateChat.Id); + await fixture.SendTestInstructionsAsync(instruction, chatId: classFixture.PrivateChat.Id); SendInvoiceRequest requestRequest = paymentsBuilder.BuildInvoiceRequest(); @@ -133,7 +125,7 @@ public async Task Should_Answer_Shipping_Query_With_Ok() public async Task Should_Answer_PreCheckout_Query_With_Ok_And_Shipment_Option() { PaymentsBuilder paymentsBuilder = new PaymentsBuilder() - .WithProduct(_ => _ + .WithProduct(p => p .WithTitle(title: "Reproduction of \"La nascita di Venere\"") .WithDescription(description: "Sandro Botticelli’s the Birth of Venus depicts the goddess Venus arriving at the shore" + @@ -145,7 +137,7 @@ public async Task Should_Answer_PreCheckout_Query_With_Ok_And_Shipment_Option() width: 1280, height: 820 )) - .WithShipping(_ => _ + .WithShipping(s => s .WithTitle(title: "DHL Express") .WithId(id: "dhl-express") .WithPrice(label: "Packaging", amount: 400_000) @@ -154,8 +146,8 @@ public async Task Should_Answer_PreCheckout_Query_With_Ok_And_Shipment_Option() .WithPayload("") .WithFlexible() .RequireShippingAddress() - .WithPaymentProviderToken(_classFixture.PaymentProviderToken) - .ToChat(_classFixture.PrivateChat.Id); + .WithPaymentProviderToken(classFixture.PaymentProviderToken) + .ToChat(classFixture.PrivateChat.Id); double totalCostWithoutShippingCost = paymentsBuilder .GetTotalAmountWithoutShippingCost() @@ -164,7 +156,7 @@ public async Task Should_Answer_PreCheckout_Query_With_Ok_And_Shipment_Option() string instruction = FormatInstructionWithCurrency( $"Click on *Pay {totalCostWithoutShippingCost:C}* and send your shipping address. Then click *Pay {totalCostWithoutShippingCost:C}* inside payment dialog. Transaction should be completed." ); - await _fixture.SendTestInstructionsAsync(instruction, chatId: _classFixture.PrivateChat.Id); + await fixture.SendTestInstructionsAsync(instruction, chatId: classFixture.PrivateChat.Id); SendInvoiceRequest requestRequest = paymentsBuilder.BuildInvoiceRequest(); @@ -181,8 +173,8 @@ public async Task Should_Answer_PreCheckout_Query_With_Ok_And_Shipment_Option() Update preCheckoutUpdate = await GetPreCheckoutQueryUpdate(); PreCheckoutQuery query = preCheckoutUpdate.PreCheckoutQuery; - await _fixture.BotClient.AnswerPreCheckoutQueryAsync( - preCheckoutQueryId: query!.Id + await fixture.BotClient.AnswerPreCheckoutQueryAsync( + new AnswerPreCheckoutQueryRequest(query!.Id) ); PreliminaryInvoice preliminaryInvoice = paymentsBuilder.GetPreliminaryInvoice(); @@ -193,7 +185,7 @@ public async Task Should_Answer_PreCheckout_Query_With_Ok_And_Shipment_Option() Assert.Equal("", query.InvoicePayload); Assert.Equal(totalAmount, query.TotalAmount); Assert.Equal(preliminaryInvoice.Currency, query.Currency); - Assert.Contains(query.From.Username, _fixture.UpdateReceiver.AllowedUsernames); + Assert.Contains(query.From.Username, fixture.UpdateReceiver.AllowedUsernames); Assert.NotNull(query.OrderInfo); Assert.Null(query.OrderInfo.PhoneNumber); Assert.Null(query.OrderInfo.Name); @@ -207,7 +199,7 @@ public async Task Should_Answer_PreCheckout_Query_With_Ok_And_Shipment_Option() public async Task Should_Receive_Successful_Payment_With_Shipment_Option() { PaymentsBuilder paymentsBuilder = new PaymentsBuilder() - .WithProduct(_ => _ + .WithProduct(p => p .WithTitle(title: "Reproduction of \"La nascita di Venere\"") .WithDescription(description: "Sandro Botticelli’s the Birth of Venus depicts the goddess Venus arriving at the shore" + @@ -219,7 +211,7 @@ public async Task Should_Receive_Successful_Payment_With_Shipment_Option() width: 1280, height: 820 )) - .WithShipping(_ => _ + .WithShipping(s => s .WithTitle(title: "DHL Express") .WithId(id: "dhl-express") .WithPrice(label: "Packaging", amount: 400_000) @@ -233,8 +225,8 @@ public async Task Should_Receive_Successful_Payment_With_Shipment_Option() .RequireShippingAddress() .SendEmailToProvider() .SendPhoneNumberToProvider() - .WithPaymentProviderToken(_classFixture.PaymentProviderToken) - .ToChat(_classFixture.PrivateChat.Id); + .WithPaymentProviderToken(classFixture.PaymentProviderToken) + .ToChat(classFixture.PrivateChat.Id); double totalCostWithoutShippingCost = paymentsBuilder .GetTotalAmountWithoutShippingCost() @@ -243,7 +235,7 @@ public async Task Should_Receive_Successful_Payment_With_Shipment_Option() string instruction = FormatInstructionWithCurrency( $"Click on *Pay {totalCostWithoutShippingCost:C}*, send your shipping address and confirm payment. Transaction should be completed." ); - await _fixture.SendTestInstructionsAsync(instruction, chatId: _classFixture.PrivateChat.Id); + await fixture.SendTestInstructionsAsync(instruction, chatId: classFixture.PrivateChat.Id); SendInvoiceRequest requestRequest = paymentsBuilder.BuildInvoiceRequest(); @@ -260,8 +252,8 @@ public async Task Should_Receive_Successful_Payment_With_Shipment_Option() Update preCheckoutUpdate = await GetPreCheckoutQueryUpdate(); PreCheckoutQuery query = preCheckoutUpdate.PreCheckoutQuery; - await _fixture.BotClient.AnswerPreCheckoutQueryAsync( - preCheckoutQueryId: query!.Id + await fixture.BotClient.AnswerPreCheckoutQueryAsync( + new AnswerPreCheckoutQueryRequest(query!.Id) ); Update successfulPaymentUpdate = await GetSuccessfulPaymentUpdate(); @@ -291,7 +283,7 @@ public async Task Should_Receive_Successful_Payment_With_Shipment_Option() public async Task Should_Receive_Successful_Payment_With_A_Tip() { PaymentsBuilder paymentsBuilder = new PaymentsBuilder() - .WithProduct(_ => _ + .WithProduct(p => p .WithTitle(title: "Three tasty donuts") .WithDescription(description: "Donuts with special glaze") .WithProductPrice(label: "Donut with chocolate glaze", amount: 550) @@ -306,8 +298,8 @@ public async Task Should_Receive_Successful_Payment_With_A_Tip() .WithPayload("") .WithSuggestedTips(100, 150, 200) .WithMaxTip(maxTipAmount: 300) - .WithPaymentProviderToken(_classFixture.PaymentProviderToken) - .ToChat(_classFixture.PrivateChat.Id); + .WithPaymentProviderToken(classFixture.PaymentProviderToken) + .ToChat(classFixture.PrivateChat.Id); double totalCostWithoutShippingCost = paymentsBuilder .GetTotalAmountWithoutShippingCost() @@ -316,15 +308,15 @@ public async Task Should_Receive_Successful_Payment_With_A_Tip() string instruction = FormatInstructionWithCurrency( $"Click on *Pay {totalCostWithoutShippingCost:C}*, select a tip from given options and confirm payment. Transaction should be completed." ); - await _fixture.SendTestInstructionsAsync(instruction, chatId: _classFixture.PrivateChat.Id); + await fixture.SendTestInstructionsAsync(instruction, chatId: classFixture.PrivateChat.Id); SendInvoiceRequest requestRequest = paymentsBuilder.BuildInvoiceRequest(); Message invoiceMessage = await BotClient.MakeRequestAsync(requestRequest); Update preCheckoutUpdate = await GetPreCheckoutQueryUpdate(); PreCheckoutQuery query = preCheckoutUpdate.PreCheckoutQuery; - await _fixture.BotClient.AnswerPreCheckoutQueryAsync( - preCheckoutQueryId: query!.Id + await fixture.BotClient.AnswerPreCheckoutQueryAsync( + new AnswerPreCheckoutQueryRequest(query!.Id) ); Update successfulPaymentUpdate = await GetSuccessfulPaymentUpdate(); @@ -346,7 +338,7 @@ public async Task Should_Receive_Successful_Payment_With_A_Tip() public async Task Should_Answer_Shipping_Query_With_Error() { PaymentsBuilder paymentsBuilder = new PaymentsBuilder() - .WithProduct(_ => _ + .WithProduct(p => p .WithTitle(title: "Reproduction of \"La nascita di Venere\"") .WithDescription(description: "Sandro Botticelli’s the Birth of Venus depicts the goddess Venus arriving at the shore" + @@ -358,7 +350,7 @@ public async Task Should_Answer_Shipping_Query_With_Error() width: 1280, height: 820 )) - .WithShipping(_ => _ + .WithShipping(s => s .WithTitle(title: "DHL Express") .WithId(id: "dhl-express") .WithPrice(label: "Packaging", amount: 400_000) @@ -367,8 +359,8 @@ public async Task Should_Answer_Shipping_Query_With_Error() .WithPayload("") .WithFlexible() .RequireShippingAddress() - .WithPaymentProviderToken(_classFixture.PaymentProviderToken) - .ToChat(_classFixture.PrivateChat.Id); + .WithPaymentProviderToken(classFixture.PaymentProviderToken) + .ToChat(classFixture.PrivateChat.Id); double totalCostWithoutShippingCost = paymentsBuilder .GetTotalAmountWithoutShippingCost() @@ -377,7 +369,7 @@ public async Task Should_Answer_Shipping_Query_With_Error() string instruction = FormatInstructionWithCurrency( $"Click on *Pay {totalCostWithoutShippingCost:C}* and send your shipping address. You will receive an error. Close payment window after that." ); - await _fixture.SendTestInstructionsAsync(instruction, chatId: _classFixture.PrivateChat.Id); + await fixture.SendTestInstructionsAsync(instruction, chatId: classFixture.PrivateChat.Id); SendInvoiceRequest requestRequest = paymentsBuilder.BuildInvoiceRequest(); @@ -399,7 +391,7 @@ public async Task Should_Answer_Shipping_Query_With_Error() public async Task Should_Answer_PreCheckout_Query_With_Error_For_No_Shipment_Option() { PaymentsBuilder paymentsBuilder = new PaymentsBuilder() - .WithProduct(_ => _ + .WithProduct(p => p .WithTitle(title: "Reproduction of \"La nascita di Venere\"") .WithDescription(description: "Sandro Botticelli’s the Birth of Venus depicts the goddess Venus arriving at the shore" + @@ -413,8 +405,8 @@ public async Task Should_Answer_PreCheckout_Query_With_Error_For_No_Shipment_Opt )) .WithCurrency("USD") .WithPayload("") - .WithPaymentProviderToken(_classFixture.PaymentProviderToken) - .ToChat(_classFixture.PrivateChat.Id); + .WithPaymentProviderToken(classFixture.PaymentProviderToken) + .ToChat(classFixture.PrivateChat.Id); double totalCostWithoutShippingCost = paymentsBuilder .GetTotalAmountWithoutShippingCost() @@ -423,7 +415,7 @@ public async Task Should_Answer_PreCheckout_Query_With_Error_For_No_Shipment_Opt string instruction = FormatInstructionWithCurrency( $"Click on *Pay {totalCostWithoutShippingCost:C}* and confirm payment. You should receive an error. Close payment window after that." ); - await _fixture.SendTestInstructionsAsync(instruction, chatId: _classFixture.PrivateChat.Id); + await fixture.SendTestInstructionsAsync(instruction, chatId: classFixture.PrivateChat.Id); SendInvoiceRequest requestRequest = paymentsBuilder.BuildInvoiceRequest(); @@ -432,9 +424,13 @@ public async Task Should_Answer_PreCheckout_Query_With_Error_For_No_Shipment_Opt Update preCheckoutUpdate = await GetPreCheckoutQueryUpdate(); PreCheckoutQuery query = preCheckoutUpdate.PreCheckoutQuery; - await _fixture.BotClient.AnswerPreCheckoutQueryAsync( - preCheckoutQueryId: query!.Id, - errorMessage: "Sorry, we couldn't process the transaction. Please, contact our support." + await fixture.BotClient.AnswerPreCheckoutQueryAsync( + new AnswerPreCheckoutQueryRequest() + { + PreCheckoutQueryId = query!.Id, + ErrorMessage = "Sorry, we couldn't process the transaction. Please, contact our support.", + Ok = false, + } ); } @@ -443,7 +439,7 @@ public async Task Should_Answer_PreCheckout_Query_With_Error_For_No_Shipment_Opt public async Task Should_Throw_When_Send_Invoice_Invalid_Provider_Data() { PaymentsBuilder paymentsBuilder = new PaymentsBuilder() - .WithProduct(_ => _ + .WithProduct(p => p .WithTitle(title: "Reproduction of \"La nascita di Venere\"") .WithDescription(description: "Sandro Botticelli’s the Birth of Venus depicts the goddess Venus arriving at the shore" + @@ -458,8 +454,8 @@ public async Task Should_Throw_When_Send_Invoice_Invalid_Provider_Data() .WithCurrency("USD") .WithPayload("") .WithProviderData("INVALID-JSON") - .WithPaymentProviderToken(_classFixture.PaymentProviderToken) - .ToChat(_classFixture.PrivateChat.Id); + .WithPaymentProviderToken(classFixture.PaymentProviderToken) + .ToChat(classFixture.PrivateChat.Id); SendInvoiceRequest requestRequest = paymentsBuilder.BuildInvoiceRequest(); @@ -476,7 +472,7 @@ public async Task Should_Throw_When_Send_Invoice_Invalid_Provider_Data() public async Task Should_Throw_When_Answer_Shipping_Query_With_Duplicate_Shipping_Id() { PaymentsBuilder paymentsBuilder = new PaymentsBuilder() - .WithProduct(_ => _ + .WithProduct(p => p .WithTitle(title: "Reproduction of \"La nascita di Venere\"") .WithDescription(description: "Sandro Botticelli’s the Birth of Venus depicts the goddess Venus arriving at the shore" + @@ -488,12 +484,12 @@ public async Task Should_Throw_When_Answer_Shipping_Query_With_Duplicate_Shippin width: 1280, height: 820 )) - .WithShipping(_ => _ + .WithShipping(s => s .WithTitle(title: "DHL Express") .WithId(id: "dhl-express") .WithPrice(label: "Packaging", amount: 400_000) .WithPrice(label: "Shipping price", amount: 337_600)) - .WithShipping(_ => _ + .WithShipping(s => s .WithTitle(title: "DHL Express (Duplicate)") .WithId(id: "dhl-express") .WithPrice(label: "Packaging", amount: 400_000) @@ -502,8 +498,8 @@ public async Task Should_Throw_When_Answer_Shipping_Query_With_Duplicate_Shippin .WithPayload("") .WithFlexible() .RequireShippingAddress() - .WithPaymentProviderToken(_classFixture.PaymentProviderToken) - .ToChat(_classFixture.PrivateChat.Id); + .WithPaymentProviderToken(classFixture.PaymentProviderToken) + .ToChat(classFixture.PrivateChat.Id); double totalCostWithoutShippingCost = paymentsBuilder .GetTotalAmountWithoutShippingCost() @@ -512,7 +508,7 @@ public async Task Should_Throw_When_Answer_Shipping_Query_With_Duplicate_Shippin string instruction = FormatInstructionWithCurrency( $"Click on *Pay {totalCostWithoutShippingCost:C}*, send your shipping address. You should receive an error." ); - await _fixture.SendTestInstructionsAsync(instruction, chatId: _classFixture.PrivateChat.Id); + await fixture.SendTestInstructionsAsync(instruction, chatId: classFixture.PrivateChat.Id); SendInvoiceRequest requestRequest = paymentsBuilder.BuildInvoiceRequest(); @@ -531,9 +527,13 @@ public async Task Should_Throw_When_Answer_Shipping_Query_With_Duplicate_Shippin Assert.Equal(400, exception.ErrorCode); Assert.Equal("Bad Request: SHIPPING_ID_DUPLICATE", exception.Message); - await _fixture.BotClient.AnswerShippingQueryAsync( - shippingQueryId: shippingUpdate.ShippingQuery.Id, - errorMessage: "✅ Test Passed" + await fixture.BotClient.AnswerShippingQueryAsync( + new() + { + Ok = false, + ShippingQueryId = shippingUpdate.ShippingQuery.Id, + ErrorMessage = "✅ Test Passed", + } ); } @@ -541,21 +541,17 @@ public async Task Should_Throw_When_Answer_Shipping_Query_With_Duplicate_Shippin [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.SendInvoice)] public async Task Should_Send_Invoice_With_Reply_Markup() { - InlineKeyboardMarkup replyMarkup = new(new[] - { - new[] - { + InlineKeyboardMarkup replyMarkup = new( + [ + [ InlineKeyboardButton.WithPayment("Pay this invoice"), InlineKeyboardButton.WithUrl("Repository", "https://github.com/TelegramBots/Telegram.Bot") - }, - new[] - { - InlineKeyboardButton.WithCallbackData("Some other button") - } - }); + ], + [InlineKeyboardButton.WithCallbackData("Some other button")] + ]); PaymentsBuilder paymentsBuilder = new PaymentsBuilder() - .WithProduct(_ => _ + .WithProduct(p => p .WithTitle(title: "Reproduction of \"La nascita di Venere\"") .WithDescription(description: "Sandro Botticelli’s the Birth of Venus depicts the goddess Venus arriving at the shore" + @@ -570,8 +566,8 @@ public async Task Should_Send_Invoice_With_Reply_Markup() .WithCurrency("USD") .WithPayload("") .WithReplyMarkup(replyMarkup) - .WithPaymentProviderToken(_classFixture.PaymentProviderToken) - .ToChat(_classFixture.PrivateChat.Id); + .WithPaymentProviderToken(classFixture.PaymentProviderToken) + .ToChat(classFixture.PrivateChat.Id); SendInvoiceRequest requestRequest = paymentsBuilder.BuildInvoiceRequest(); @@ -580,34 +576,35 @@ public async Task Should_Send_Invoice_With_Reply_Markup() async Task GetShippingQueryUpdate(CancellationToken cancellationToken = default) { - Update[] updates = await _fixture.UpdateReceiver.GetUpdatesAsync( + Update[] updates = await fixture.UpdateReceiver.GetUpdatesAsync( cancellationToken: cancellationToken, updateTypes: UpdateType.ShippingQuery ); Update update = updates.Single(); - await _fixture.UpdateReceiver.DiscardNewUpdatesAsync(cancellationToken); + await fixture.UpdateReceiver.DiscardNewUpdatesAsync(cancellationToken); return update; } async Task GetPreCheckoutQueryUpdate(CancellationToken cancellationToken = default) { - Update[] updates = await _fixture.UpdateReceiver.GetUpdatesAsync( + Update[] updates = await fixture.UpdateReceiver.GetUpdatesAsync( cancellationToken: cancellationToken, - updateTypes: UpdateType.PreCheckoutQuery); + updateTypes: UpdateType.PreCheckoutQuery + ); Update update = updates.Single(); - await _fixture.UpdateReceiver.DiscardNewUpdatesAsync(cancellationToken); + await fixture.UpdateReceiver.DiscardNewUpdatesAsync(cancellationToken); return update; } async Task GetSuccessfulPaymentUpdate(CancellationToken cancellationToken = default) { - Update[] updates = await _fixture.UpdateReceiver.GetUpdatesAsync( + Update[] updates = await fixture.UpdateReceiver.GetUpdatesAsync( predicate: u => u.Message?.Type == MessageType.SuccessfulPayment, cancellationToken: cancellationToken, updateTypes: UpdateType.Message @@ -615,12 +612,12 @@ async Task GetSuccessfulPaymentUpdate(CancellationToken cancellationToke Update update = updates.Single(); - await _fixture.UpdateReceiver.DiscardNewUpdatesAsync(cancellationToken); + await fixture.UpdateReceiver.DiscardNewUpdatesAsync(cancellationToken); return update; } - public async Task InitializeAsync() => await _fixture.UpdateReceiver.DiscardNewUpdatesAsync(); + public async Task InitializeAsync() => await fixture.UpdateReceiver.DiscardNewUpdatesAsync(); public Task DisposeAsync() => Task.CompletedTask; public static string FormatInstructionWithCurrency(FormattableString instruction) => diff --git a/test/Telegram.Bot.Tests.Integ/Payments/PaymentsBuilder.cs b/test/Telegram.Bot.Tests.Integ/Payments/PaymentsBuilder.cs index 2ff54b06d..9dfd5914a 100644 --- a/test/Telegram.Bot.Tests.Integ/Payments/PaymentsBuilder.cs +++ b/test/Telegram.Bot.Tests.Integ/Payments/PaymentsBuilder.cs @@ -32,35 +32,37 @@ public class PaymentsBuilder public PaymentsBuilder WithCurrency(string currency) { - if (string.IsNullOrWhiteSpace(currency)) throw new ArgumentException($"{nameof(currency)} is null or empty"); + ArgumentException.ThrowIfNullOrWhiteSpace(currency); _currency = currency; return this; } public PaymentsBuilder WithStartParameter(string startParameter) { - if (string.IsNullOrWhiteSpace(startParameter)) throw new ArgumentException($"{nameof(startParameter)} is null or empty"); + ArgumentException.ThrowIfNullOrWhiteSpace(startParameter); _startParameter = startParameter; return this; } public PaymentsBuilder WithPayload(string payload) { - if (string.IsNullOrWhiteSpace(payload)) throw new ArgumentException($"{nameof(payload)} is null or empty"); + ArgumentException.ThrowIfNullOrWhiteSpace(payload); _payload = payload; return this; } public PaymentsBuilder WithProviderData(string providerData) { - if (string.IsNullOrWhiteSpace(providerData)) throw new ArgumentException($"{nameof(providerData)} is null or empty"); + ArgumentException.ThrowIfNullOrWhiteSpace(providerData); + _providerData = providerData; return this; } public PaymentsBuilder WithReplyMarkup(InlineKeyboardMarkup replyMarkup) { - _replyMarkup = replyMarkup ?? throw new ArgumentNullException(nameof(replyMarkup)); + ArgumentNullException.ThrowIfNull(replyMarkup); + _replyMarkup = replyMarkup; return this; } @@ -114,21 +116,15 @@ public PaymentsBuilder SendPhoneNumberToProvider(bool send = true) public PaymentsBuilder WithPaymentProviderToken(string paymentsProviderToken) { - if (string.IsNullOrWhiteSpace(paymentsProviderToken)) throw new ArgumentException($"{nameof(paymentsProviderToken)} is null or empty"); + ArgumentException.ThrowIfNullOrWhiteSpace(paymentsProviderToken); _paymentsProviderToken = paymentsProviderToken; return this; } public PaymentsBuilder WithMaxTip(int maxTipAmount) { - if (maxTipAmount < 1) - throw new ArgumentOutOfRangeException( - nameof(maxTipAmount), - maxTipAmount, - "Max tip amount must be greater than 0" - ); - - if (_suggestedTipAmounts is not null && _suggestedTipAmounts.Any(_ => _ > maxTipAmount)) + ArgumentOutOfRangeException.ThrowIfLessThan(maxTipAmount, 1); + if (_suggestedTipAmounts is not null && _suggestedTipAmounts.Any(tip => tip > maxTipAmount)) { throw new ArgumentOutOfRangeException( nameof(maxTipAmount), @@ -144,27 +140,16 @@ public PaymentsBuilder WithMaxTip(int maxTipAmount) public PaymentsBuilder WithSuggestedTips(params int[] suggestedTipAmounts) { - if (suggestedTipAmounts.Length is 0) - { - throw new ArgumentException("Suggested tips must not be empty"); - } - - if (suggestedTipAmounts.Length > 4) - { - throw new ArgumentException("No more than four suggested tips can be set"); - } + ArgumentOutOfRangeException.ThrowIfZero(suggestedTipAmounts.Length); + ArgumentOutOfRangeException.ThrowIfGreaterThan(suggestedTipAmounts.Length, 4); - if (suggestedTipAmounts.Any(_ => _ < 1)) - { + if (suggestedTipAmounts.Any(tip => tip < 1)) throw new ArgumentException("Suggested tips must be greater than 0"); - } - if (_maxTipAmount is not null && suggestedTipAmounts.Any(_ => _ < _maxTipAmount)) - { + if (_maxTipAmount is not null && suggestedTipAmounts.Any(tip => tip < _maxTipAmount)) throw new ArgumentException("Suggested tips must not be greater than max tip amount"); - } - _suggestedTipAmounts = suggestedTipAmounts.OrderBy(_ => _).ToArray(); + _suggestedTipAmounts = suggestedTipAmounts.OrderBy(tip => tip).ToArray(); return this; } @@ -194,21 +179,21 @@ public PreliminaryInvoice GetPreliminaryInvoice() public SendInvoiceRequest BuildInvoiceRequest() { - if (_product is null) throw new InvalidOperationException("Product wasn't added"); - if (string.IsNullOrWhiteSpace(_paymentsProviderToken)) throw new ArgumentException("Payments provider token is null or empty"); - if (_chatId is null) throw new InvalidOperationException("ChatId is null"); - if (string.IsNullOrWhiteSpace(_currency)) throw new InvalidOperationException("Currency isn't set"); - if (string.IsNullOrWhiteSpace(_payload)) throw new InvalidOperationException("Payload isn't set"); - - return new( - chatId: _chatId.Value, - title: _product.Title, - description: _product.Description, - payload: _payload, - providerToken: _paymentsProviderToken, - currency: _currency, - prices: _product.ProductPrices) + ArgumentNullException.ThrowIfNull(_product); + ArgumentException.ThrowIfNullOrWhiteSpace(_paymentsProviderToken); + ArgumentNullException.ThrowIfNull(_chatId); + ArgumentException.ThrowIfNullOrWhiteSpace(_currency); + ArgumentException.ThrowIfNullOrWhiteSpace(_payload); + + return new() { + ChatId = _chatId.Value, + Title = _product.Title, + Description = _product.Description, + Payload = _payload, + ProviderToken = _paymentsProviderToken, + Currency = _currency, + Prices = _product.ProductPrices, PhotoUrl = _product.PhotoUrl, PhotoWidth = _product.PhotoWidth, PhotoHeight = _product.PhotoHeight, @@ -229,7 +214,7 @@ public SendInvoiceRequest BuildInvoiceRequest() public AnswerShippingQueryRequest BuildShippingQueryRequest(string shippingQueryId, string? errorMessage = default) { - if (string.IsNullOrWhiteSpace(shippingQueryId)) throw new ArgumentNullException(nameof(shippingQueryId)); + ArgumentException.ThrowIfNullOrWhiteSpace(shippingQueryId); AnswerShippingQueryRequest shippingQueryRequest = errorMessage is null ? new(shippingQueryId, _shippingOptions) @@ -266,22 +251,22 @@ public class ShippingOptionsBuilder public ShippingOptionsBuilder WithId(string id) { - if (string.IsNullOrWhiteSpace(id)) throw new ArgumentNullException(nameof(id)); + ArgumentException.ThrowIfNullOrWhiteSpace(id); _id = id; return this; } public ShippingOptionsBuilder WithTitle(string title) { - if (string.IsNullOrWhiteSpace(title)) throw new ArgumentNullException(nameof(title)); + ArgumentException.ThrowIfNullOrWhiteSpace(title); _title = title; return this; } public ShippingOptionsBuilder WithPrice(string label, int amount) { - if (string.IsNullOrWhiteSpace(label)) throw new ArgumentNullException(nameof(label)); - if (amount <= 0) throw new ArgumentOutOfRangeException(nameof(amount), "Price must be greater than 0"); + ArgumentException.ThrowIfNullOrWhiteSpace(label); + ArgumentOutOfRangeException.ThrowIfNegativeOrZero(amount); _shippingPrices.Add(new(label, amount)); @@ -310,22 +295,23 @@ public class ProductBuilder public ProductBuilder WithTitle(string title) { - if (string.IsNullOrWhiteSpace(title)) throw new ArgumentException($"{nameof(title)} is null or empty"); + ArgumentException.ThrowIfNullOrWhiteSpace(title); _title = title; return this; } public ProductBuilder WithDescription(string description) { - if (string.IsNullOrWhiteSpace(description)) throw new ArgumentException($"{nameof(description)} is null or empty"); + ArgumentException.ThrowIfNullOrWhiteSpace(description); _description = description; return this; } public ProductBuilder WithPhoto(string url, int width, int height) { - if (string.IsNullOrWhiteSpace(url)) throw new ArgumentException($"{nameof(url)} is null or empty"); - if (width < 1 || height < 1) throw new ArgumentException("Dimensions are invalid"); + ArgumentException.ThrowIfNullOrWhiteSpace(url); + ArgumentOutOfRangeException.ThrowIfLessThan(width, 1); + ArgumentOutOfRangeException.ThrowIfLessThan(height, 1); _photoUrl = url; _photoWidth = width; @@ -336,8 +322,8 @@ public ProductBuilder WithPhoto(string url, int width, int height) public ProductBuilder WithProductPrice(string label, int amount) { - if (string.IsNullOrWhiteSpace(label)) throw new ArgumentNullException(nameof(label)); - if (amount <= 0) throw new ArgumentOutOfRangeException(nameof(amount), "Price must be greater than 0"); + ArgumentException.ThrowIfNullOrWhiteSpace(label); + ArgumentOutOfRangeException.ThrowIfNegativeOrZero(amount); _productPrices.Add(new(label, amount)); return this; } diff --git a/test/Telegram.Bot.Tests.Integ/Polls/AnonymousPollTests.cs b/test/Telegram.Bot.Tests.Integ/Polls/AnonymousPollTests.cs index caceb8974..f001ca770 100644 --- a/test/Telegram.Bot.Tests.Integ/Polls/AnonymousPollTests.cs +++ b/test/Telegram.Bot.Tests.Integ/Polls/AnonymousPollTests.cs @@ -11,17 +11,11 @@ namespace Telegram.Bot.Tests.Integ.Polls; [Collection(Constants.TestCollections.NativePolls)] [Trait(Constants.CategoryTraitName, Constants.InteractiveCategoryValue)] [TestCaseOrderer(Constants.TestCaseOrderer, Constants.AssemblyName)] -public class AnonymousPollTests : IClassFixture +public class AnonymousPollTests(AnonymousPollTestsFixture classFixture) : IClassFixture { - readonly AnonymousPollTestsFixture _classFixture; - TestsFixture Fixture => _classFixture.TestsFixture; + TestsFixture Fixture => classFixture.TestsFixture; ITelegramBotClient BotClient => Fixture.BotClient; - public AnonymousPollTests( AnonymousPollTestsFixture classFixture) - { - _classFixture = classFixture; - } - [OrderedFact( "Should send a poll", Skip = "Fails on CI server for some reason, the resulting poll is public")] @@ -29,9 +23,12 @@ public AnonymousPollTests( AnonymousPollTestsFixture classFixture) public async Task Should_Send_Poll() { Message message = await BotClient.SendPollAsync( - chatId: Fixture.SupergroupChat, - question: "Who shot first?", - options: new[] {"Han Solo", "Greedo", "I don't care"} + new() + { + ChatId = Fixture.SupergroupChat, + Question = "Who shot first?", + Options = ["Han Solo", "Greedo", "I don't care"], + } ); Assert.Equal(MessageType.Poll, message.Type); @@ -52,7 +49,7 @@ public async Task Should_Send_Poll() Assert.Equal("I don't care", message.Poll.Options[2].Text); Assert.All(message.Poll.Options, option => Assert.Equal(0, option.VoterCount)); - _classFixture.PollMessage = message; + classFixture.PollMessage = message; } [OrderedFact( @@ -60,7 +57,7 @@ public async Task Should_Send_Poll() Skip = "Fails on CI server for some reason, the resulting poll is public")] public async Task Should_Receive_Poll_State_Update() { - string pollId = _classFixture.PollMessage.Poll!.Id; + string pollId = classFixture.PollMessage.Poll!.Id; await Fixture.SendTestInstructionsAsync("🗳 Vote for any of the options on the poll above 👆"); Update update = (await Fixture.UpdateReceiver.GetUpdatesAsync(updateTypes: UpdateType.Poll)) @@ -78,11 +75,14 @@ public async Task Should_Receive_Poll_State_Update() public async Task Should_Stop_Poll() { Poll poll = await BotClient.StopPollAsync( - chatId: _classFixture.PollMessage.Chat, - messageId: _classFixture.PollMessage.MessageId + new() + { + ChatId = classFixture.PollMessage.Chat, + MessageId = classFixture.PollMessage.MessageId, + } ); - Assert.Equal(_classFixture.PollMessage.Poll!.Id, poll.Id); + Assert.Equal(classFixture.PollMessage.Poll!.Id, poll.Id); Assert.True(poll.IsClosed); } @@ -92,13 +92,16 @@ public async Task Should_Throw_Exception_Not_Enough_Options() { ApiRequestException exception = await Assert.ThrowsAsync(() => BotClient.SendPollAsync( - chatId: Fixture.SupergroupChat, - question: "You should never see this poll", - options: new[] {"The only poll option"} + new() + { + ChatId = Fixture.SupergroupChat, + Question = "You should never see this poll", + Options = ["The only poll option"], + } ) ); Assert.IsType(exception); Assert.Equal("Bad Request: poll must have at least 2 option", exception.Message); } -} \ No newline at end of file +} diff --git a/test/Telegram.Bot.Tests.Integ/Polls/AnonymousPollTestsFixture.cs b/test/Telegram.Bot.Tests.Integ/Polls/AnonymousPollTestsFixture.cs index c398e289c..82fef8c9a 100644 --- a/test/Telegram.Bot.Tests.Integ/Polls/AnonymousPollTestsFixture.cs +++ b/test/Telegram.Bot.Tests.Integ/Polls/AnonymousPollTestsFixture.cs @@ -3,14 +3,9 @@ namespace Telegram.Bot.Tests.Integ.Polls; -public class AnonymousPollTestsFixture +public class AnonymousPollTestsFixture(TestsFixture testsFixture) { - public TestsFixture TestsFixture { get; } + public TestsFixture TestsFixture { get; } = testsFixture; public Message PollMessage { get; set; } - - public AnonymousPollTestsFixture(TestsFixture testsFixture) - { - TestsFixture = testsFixture; - } } \ No newline at end of file diff --git a/test/Telegram.Bot.Tests.Integ/Polls/PublicPollTests.cs b/test/Telegram.Bot.Tests.Integ/Polls/PublicPollTests.cs index 4116a01d1..43b9b8050 100644 --- a/test/Telegram.Bot.Tests.Integ/Polls/PublicPollTests.cs +++ b/test/Telegram.Bot.Tests.Integ/Polls/PublicPollTests.cs @@ -10,17 +10,11 @@ namespace Telegram.Bot.Tests.Integ.Polls; [Collection(Constants.TestCollections.NativePolls)] [Trait(Constants.CategoryTraitName, Constants.InteractiveCategoryValue)] [TestCaseOrderer(Constants.TestCaseOrderer, Constants.AssemblyName)] -public class PublicPollTests : IClassFixture +public class PublicPollTests(PublicPollTestsFixture classFixture) : IClassFixture { - readonly PublicPollTestsFixture _classFixture; - TestsFixture Fixture => _classFixture.TestsFixture; + TestsFixture Fixture => classFixture.TestsFixture; ITelegramBotClient BotClient => Fixture.BotClient; - public PublicPollTests(PublicPollTestsFixture classFixture) - { - _classFixture = classFixture; - } - [OrderedFact( "Should send public poll with multiple answers", Skip = "Poll tests fail too often for unknown reasons")] @@ -28,12 +22,15 @@ public PublicPollTests(PublicPollTestsFixture classFixture) public async Task Should_Send_Non_Anonymous_Poll_With_Multiple_Answers() { Message message = await Fixture.BotClient.SendPollAsync( - chatId: Fixture.SupergroupChat, - question: "Pick your team", - options: new [] { "Aragorn", "Galadriel", "Frodo" }, - isAnonymous: false, - type: PollType.Regular, - allowsMultipleAnswers: true + new() + { + ChatId = Fixture.SupergroupChat, + Question = "Pick your team", + Options = ["Aragorn", "Galadriel", "Frodo"], + IsAnonymous = false, + Type = PollType.Regular, + AllowsMultipleAnswers = true, + } ); Assert.Equal(MessageType.Poll, message.Type); @@ -54,7 +51,7 @@ public async Task Should_Send_Non_Anonymous_Poll_With_Multiple_Answers() Assert.Equal("Frodo", message.Poll.Options[2].Text); Assert.All(message.Poll.Options, option => Assert.Equal(0, option.VoterCount)); - _classFixture.OriginalPollMessage = message; + classFixture.OriginalPollMessage = message; } [OrderedFact( @@ -71,7 +68,7 @@ public async Task Should_Receive_Poll_Answer_Update() updateTypes: UpdateType.PollAnswer ); - Poll poll = _classFixture.OriginalPollMessage.Poll; + Poll poll = classFixture.OriginalPollMessage.Poll; PollAnswer pollAnswer = pollAnswerUpdate.PollAnswer; Assert.NotNull(pollAnswer); @@ -82,7 +79,7 @@ public async Task Should_Receive_Poll_Answer_Update() optionId => Assert.True(optionId < poll.Options.Length) ); - _classFixture.PollAnswer = pollAnswer; + classFixture.PollAnswer = pollAnswer; } [OrderedFact( @@ -96,18 +93,21 @@ public async Task Should_Stop_Non_Anonymous_Poll() await Task.Delay(TimeSpan.FromSeconds(5)); Poll closedPoll = await BotClient.StopPollAsync( - chatId: _classFixture.OriginalPollMessage.Chat, - messageId: _classFixture.OriginalPollMessage.MessageId + new() + { + ChatId = classFixture.OriginalPollMessage.Chat, + MessageId = classFixture.OriginalPollMessage.MessageId, + } ); - Assert.Equal(_classFixture.OriginalPollMessage.Poll!.Id, closedPoll.Id); + Assert.Equal(classFixture.OriginalPollMessage.Poll!.Id, closedPoll.Id); Assert.True(closedPoll.IsClosed); - PollAnswer pollAnswer = _classFixture.PollAnswer; + PollAnswer pollAnswer = classFixture.PollAnswer; Assert.All( pollAnswer.OptionIds, optionId => Assert.True(closedPoll.Options[optionId].VoterCount > 0) ); } -} \ No newline at end of file +} diff --git a/test/Telegram.Bot.Tests.Integ/Polls/PublicPollTestsFixture.cs b/test/Telegram.Bot.Tests.Integ/Polls/PublicPollTestsFixture.cs index 83380b9c7..becab4bad 100644 --- a/test/Telegram.Bot.Tests.Integ/Polls/PublicPollTestsFixture.cs +++ b/test/Telegram.Bot.Tests.Integ/Polls/PublicPollTestsFixture.cs @@ -3,14 +3,9 @@ namespace Telegram.Bot.Tests.Integ.Polls; -public class PublicPollTestsFixture +public class PublicPollTestsFixture(TestsFixture testsFixture) { - public TestsFixture TestsFixture { get; } + public TestsFixture TestsFixture { get; } = testsFixture; public Message OriginalPollMessage { get; set; } public PollAnswer PollAnswer { get; set; } - - public PublicPollTestsFixture(TestsFixture testsFixture) - { - TestsFixture = testsFixture; - } } \ No newline at end of file diff --git a/test/Telegram.Bot.Tests.Integ/Polls/QuizPollTests.cs b/test/Telegram.Bot.Tests.Integ/Polls/QuizPollTests.cs index e4b004d4f..3099f8aaf 100644 --- a/test/Telegram.Bot.Tests.Integ/Polls/QuizPollTests.cs +++ b/test/Telegram.Bot.Tests.Integ/Polls/QuizPollTests.cs @@ -10,17 +10,11 @@ namespace Telegram.Bot.Tests.Integ.Polls; [Collection(Constants.TestCollections.NativePolls)] [Trait(Constants.CategoryTraitName, Constants.InteractiveCategoryValue)] [TestCaseOrderer(Constants.TestCaseOrderer, Constants.AssemblyName)] -public class QuizPollTests : IClassFixture +public class QuizPollTests(QuizPollTestsFixture classFixture) : IClassFixture { - readonly QuizPollTestsFixture _classFixture; - TestsFixture Fixture => _classFixture.TestsFixture; + TestsFixture Fixture => classFixture.TestsFixture; ITelegramBotClient BotClient => Fixture.BotClient; - public QuizPollTests(QuizPollTestsFixture classFixture) - { - _classFixture = classFixture; - } - [OrderedFact( "Should send public quiz poll", Skip = "Poll tests fail too often for unknown reasons")] @@ -28,14 +22,17 @@ public QuizPollTests(QuizPollTestsFixture classFixture) public async Task Should_Send_Public_Quiz_Poll() { Message message = await Fixture.BotClient.SendPollAsync( - chatId: Fixture.SupergroupChat, - question: "How many silmarils were made in J. R. R. Tolkiens's Silmarillion?", - options: new [] { "One", "Ten", "Three" }, - isAnonymous: false, - type: PollType.Quiz, - correctOptionId: 2, // "Three", - explanation: "Three [silmarils](https://en.wikipedia.org/wiki/Silmarils) were made", - explanationParseMode: ParseMode.MarkdownV2 + new() + { + ChatId = Fixture.SupergroupChat, + Question = "How many silmarils were made in J. R. R. Tolkiens's Silmarillion?", + Options = ["One", "Ten", "Three"], + IsAnonymous = false, + Type = PollType.Quiz, + CorrectOptionId = 2, // "Three", + Explanation = "Three [silmarils](https://en.wikipedia.org/wiki/Silmarils) were made", + ExplanationParseMode = ParseMode.MarkdownV2, + } ); Assert.Equal(MessageType.Poll, message.Type); @@ -64,7 +61,7 @@ public async Task Should_Send_Public_Quiz_Poll() entity.Url == "https://en.wikipedia.org/wiki/Silmarils" ); - _classFixture.OriginalPollMessage = message; + classFixture.OriginalPollMessage = message; } [OrderedFact( @@ -76,7 +73,7 @@ public async Task Should_Receive_Poll_Answer_Update() "🗳 Choose any answer in the quiz above 👆" ); - Poll poll = _classFixture.OriginalPollMessage.Poll; + Poll poll = classFixture.OriginalPollMessage.Poll; Update pollAnswerUpdates = await Fixture.UpdateReceiver.GetUpdateAsync( update => update.PollAnswer?.OptionIds.Length == 1 && @@ -94,7 +91,7 @@ public async Task Should_Receive_Poll_Answer_Update() optionId => Assert.True(optionId < poll.Options.Length) ); - _classFixture.PollAnswer = pollAnswer; + classFixture.PollAnswer = pollAnswer; } [OrderedFact( @@ -108,18 +105,21 @@ public async Task Should_Stop_Quiz_Poll() await Task.Delay(TimeSpan.FromSeconds(5)); Poll closedPoll = await BotClient.StopPollAsync( - chatId: _classFixture.OriginalPollMessage.Chat, - messageId: _classFixture.OriginalPollMessage.MessageId + new() + { + ChatId = classFixture.OriginalPollMessage.Chat, + MessageId = classFixture.OriginalPollMessage.MessageId, + } ); - Assert.Equal(_classFixture.OriginalPollMessage.Poll!.Id, closedPoll.Id); + Assert.Equal(classFixture.OriginalPollMessage.Poll!.Id, closedPoll.Id); Assert.True(closedPoll.IsClosed); - PollAnswer pollAnswer = _classFixture.PollAnswer; + PollAnswer pollAnswer = classFixture.PollAnswer; Assert.All( pollAnswer.OptionIds, optionId => Assert.True(closedPoll.Options[optionId].VoterCount > 0) ); } -} \ No newline at end of file +} diff --git a/test/Telegram.Bot.Tests.Integ/Polls/QuizPollTestsFixture.cs b/test/Telegram.Bot.Tests.Integ/Polls/QuizPollTestsFixture.cs index fb112e1dc..0d1c32871 100644 --- a/test/Telegram.Bot.Tests.Integ/Polls/QuizPollTestsFixture.cs +++ b/test/Telegram.Bot.Tests.Integ/Polls/QuizPollTestsFixture.cs @@ -3,14 +3,9 @@ namespace Telegram.Bot.Tests.Integ.Polls; -public class QuizPollTestsFixture +public class QuizPollTestsFixture(TestsFixture testsFixture) { - public TestsFixture TestsFixture { get; } + public TestsFixture TestsFixture { get; } = testsFixture; public Message OriginalPollMessage { get; set; } public PollAnswer PollAnswer { get; set; } - - public QuizPollTestsFixture(TestsFixture testsFixture) - { - TestsFixture = testsFixture; - } } \ No newline at end of file diff --git a/test/Telegram.Bot.Tests.Integ/Polls/SelfStoppingPollTests.cs b/test/Telegram.Bot.Tests.Integ/Polls/SelfStoppingPollTests.cs index 2bf070c51..d279b7a95 100644 --- a/test/Telegram.Bot.Tests.Integ/Polls/SelfStoppingPollTests.cs +++ b/test/Telegram.Bot.Tests.Integ/Polls/SelfStoppingPollTests.cs @@ -9,17 +9,11 @@ namespace Telegram.Bot.Tests.Integ.Polls; [Collection(Constants.TestCollections.NativePolls)] [TestCaseOrderer(Constants.TestCaseOrderer, Constants.AssemblyName)] -public class SelfStoppingPollTests : IClassFixture +public class SelfStoppingPollTests(SelfStoppingPollTestsFixture fixture) : IClassFixture { - readonly SelfStoppingPollTestsFixture _classFixture; - TestsFixture Fixture => _classFixture.TestsFixture; + TestsFixture Fixture => fixture.TestsFixture; ITelegramBotClient BotClient => Fixture.BotClient; - public SelfStoppingPollTests(SelfStoppingPollTestsFixture fixture) - { - _classFixture = fixture; - } - [OrderedFact( "Should send self closing anonymous poll by period", Skip = "Fails on CI server for some reason, the resulting poll is public")] @@ -27,10 +21,13 @@ public SelfStoppingPollTests(SelfStoppingPollTestsFixture fixture) public async Task Should_Send_Self_Closing_Poll_Anonymous_Poll_By_Period() { Message message = await BotClient.SendPollAsync( - chatId: Fixture.SupergroupChat, - question: "Who shot first?", - options: new[] {"Han Solo", "Greedo", "I don't care"}, - openPeriod: 6 + new() + { + ChatId = Fixture.SupergroupChat, + Question = "Who shot first?", + Options = ["Han Solo", "Greedo", "I don't care"], + OpenPeriod = 6, + } ); Assert.Equal(MessageType.Poll, message.Type); @@ -51,8 +48,8 @@ public async Task Should_Send_Self_Closing_Poll_Anonymous_Poll_By_Period() Assert.Equal("I don't care", message.Poll.Options[2].Text); Assert.All(message.Poll.Options, option => Assert.Equal(0, option.VoterCount)); - _classFixture.PollMessage = message; - _classFixture.OpenPeriod = 6; + fixture.PollMessage = message; + fixture.OpenPeriod = 6; } // For some reason Telegram doesn't send poll update when a poll closes itself @@ -83,10 +80,13 @@ public async Task Should_Send_Self_Closing_Poll_Anonymous_Poll_By_Date() DateTime closeDate = DateTime.UtcNow.AddSeconds(8); Message message = await BotClient.SendPollAsync( - chatId: Fixture.SupergroupChat, - question: "Who shot first?", - options: new[] {"Han Solo", "Greedo", "I don't care"}, - closeDate: closeDate + new() + { + ChatId = Fixture.SupergroupChat, + Question = "Who shot first?", + Options = ["Han Solo", "Greedo", "I don't care"], + CloseDate = closeDate, + } ); Assert.Equal(MessageType.Poll, message.Type); @@ -115,8 +115,8 @@ public async Task Should_Send_Self_Closing_Poll_Anonymous_Poll_By_Date() Assert.Equal("I don't care", message.Poll.Options[2].Text); Assert.All(message.Poll.Options, option => Assert.Equal(0, option.VoterCount)); - _classFixture.PollMessage = message; - _classFixture.CloseDate = closeDate; + fixture.PollMessage = message; + fixture.CloseDate = closeDate; } // For some reason Telegram doesn't send poll update when a poll closes itself @@ -142,4 +142,4 @@ public async Task Should_Send_Self_Closing_Poll_Anonymous_Poll_By_Date() // ); // Assert.True(update.Poll.IsClosed); // } -} \ No newline at end of file +} diff --git a/test/Telegram.Bot.Tests.Integ/Polls/SelfStoppingPollTestsFixture.cs b/test/Telegram.Bot.Tests.Integ/Polls/SelfStoppingPollTestsFixture.cs index 1f5a8c4d5..056461b1e 100644 --- a/test/Telegram.Bot.Tests.Integ/Polls/SelfStoppingPollTestsFixture.cs +++ b/test/Telegram.Bot.Tests.Integ/Polls/SelfStoppingPollTestsFixture.cs @@ -4,15 +4,10 @@ namespace Telegram.Bot.Tests.Integ.Polls; -public class SelfStoppingPollTestsFixture +public class SelfStoppingPollTestsFixture(TestsFixture testsFixture) { - public TestsFixture TestsFixture { get; } + public TestsFixture TestsFixture { get; } = testsFixture; public Message PollMessage { get; set; } public int OpenPeriod { get; set; } public DateTime CloseDate { get; set; } - - public SelfStoppingPollTestsFixture(TestsFixture testsFixture) - { - TestsFixture = testsFixture; - } } \ No newline at end of file diff --git a/test/Telegram.Bot.Tests.Integ/ReplyMarkup/PrivateChatReplyMarkupTests.cs b/test/Telegram.Bot.Tests.Integ/ReplyMarkup/PrivateChatReplyMarkupTests.cs index e86124703..79db71931 100644 --- a/test/Telegram.Bot.Tests.Integ/ReplyMarkup/PrivateChatReplyMarkupTests.cs +++ b/test/Telegram.Bot.Tests.Integ/ReplyMarkup/PrivateChatReplyMarkupTests.cs @@ -11,35 +11,29 @@ namespace Telegram.Bot.Tests.Integ.ReplyMarkup; [Collection(Constants.TestCollections.PrivateChatReplyMarkup)] [Trait(Constants.CategoryTraitName, Constants.InteractiveCategoryValue)] [TestCaseOrderer(Constants.TestCaseOrderer, Constants.AssemblyName)] -public class PrivateChatReplyMarkupTests : IClassFixture +public class PrivateChatReplyMarkupTests(TestsFixture testsFixture, PrivateChatReplyMarkupTests.Fixture fixture) : IClassFixture { - ITelegramBotClient BotClient => _fixture.BotClient; + ITelegramBotClient BotClient => testsFixture.BotClient; - readonly Fixture _classFixture; - - readonly TestsFixture _fixture; - - public PrivateChatReplyMarkupTests(TestsFixture testsFixture, Fixture fixture) - { - _fixture = testsFixture; - _classFixture = fixture; - } - - [OrderedFact("Should get contact info from keyboard reply markup")] + [OrderedFact("Should request contact with keyboard reply markup")] [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.SendMessage)] - public async Task Should_Receive_Contact_Info() + public async Task Should_Request_Contact() { - ReplyKeyboardMarkup replyKeyboardMarkup = new ( - keyboardRow: new[] { KeyboardButton.WithRequestContact("Share Contact"), }) + KeyboardButton[] keyboard = [KeyboardButton.WithRequestContact("Share Contact"),]; + + ReplyKeyboardMarkup replyKeyboardMarkup = new (keyboardRow: keyboard) { ResizeKeyboard = true, OneTimeKeyboard = true, }; - await BotClient.SendTextMessageAsync( - chatId: _classFixture.PrivateChat, - text: "Share your contact info using the keyboard reply markup provided.", - replyMarkup: replyKeyboardMarkup + await BotClient.SendMessageAsync( + new() + { + ChatId = fixture.PrivateChat, + Text = "Share your contact info using the keyboard reply markup provided.", + ReplyMarkup = replyKeyboardMarkup, + } ); Message contactMessage = await GetMessageFromChat(MessageType.Contact); @@ -47,47 +41,123 @@ public async Task Should_Receive_Contact_Info() Assert.NotNull(contactMessage.Contact); Assert.NotEmpty(contactMessage.Contact.FirstName); Assert.NotEmpty(contactMessage.Contact.PhoneNumber); - Assert.Equal(_classFixture.PrivateChat.Id, contactMessage.Contact.UserId); - - await BotClient.SendTextMessageAsync( - chatId: _classFixture.PrivateChat, - text: "Got it. Removing reply keyboard markup...", - replyMarkup: new ReplyKeyboardRemove() + Assert.Equal(fixture.PrivateChat.Id, contactMessage.Contact.UserId); + + await BotClient.SendMessageAsync( + new() + { + ChatId = fixture.PrivateChat, + Text = "Got it. Removing reply keyboard markup...", + ReplyMarkup = new ReplyKeyboardRemove(), + } ); } - [OrderedFact("Should get location from keyboard reply markup")] + [OrderedFact("Should request location with keyboard reply markup")] [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.SendMessage)] - public async Task Should_Receive_Location() + public async Task Should_Request_Location() { - await BotClient.SendTextMessageAsync( - chatId: _classFixture.PrivateChat, - text: "Share your location using the keyboard reply markup", - replyMarkup: new ReplyKeyboardMarkup(KeyboardButton.WithRequestLocation("Share Location")) + KeyboardButton[] keyboard = [KeyboardButton.WithRequestLocation("Share Location")]; + ReplyKeyboardMarkup replyKeyboardMarkup = new(keyboardRow: keyboard); + + await BotClient.SendMessageAsync( + new() + { + ChatId = fixture.PrivateChat, + Text = "Share your location using the keyboard reply markup", + ReplyMarkup = replyKeyboardMarkup, + } ); Message locationMessage = await GetMessageFromChat(MessageType.Location); Assert.NotNull(locationMessage.Location); - await BotClient.SendTextMessageAsync( - chatId: _classFixture.PrivateChat, - text: "Got it. Removing reply keyboard markup...", - replyMarkup: new ReplyKeyboardRemove() + await BotClient.SendMessageAsync( + new() + { + ChatId = fixture.PrivateChat, + Text = "Got it. Removing reply keyboard markup...", + ReplyMarkup = new ReplyKeyboardRemove(), + } + ); + } + + [OrderedFact("Should request users with keyboard reply markup")] + [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.SendMessage)] + public async Task Should_Request_Users() + { + KeyboardButton[] keyboard = + [ + KeyboardButton.WithRequestUsers(text: "Share Users", requestId: 1) + ]; + ReplyKeyboardMarkup replyKeyboardMarkup = new(keyboardRow: keyboard); + + await BotClient.SendMessageAsync( + new() + { + ChatId = fixture.PrivateChat, + Text = "Share users using the keyboard reply markup", + ReplyMarkup = replyKeyboardMarkup, + } + ); + + Message usersMessage = await GetMessageFromChat(MessageType.UsersShared); + + Assert.NotNull(usersMessage.UsersShared); + + await BotClient.SendMessageAsync( + new() + { + ChatId = fixture.PrivateChat, + Text = "Got it. Removing reply keyboard markup...", + ReplyMarkup = new ReplyKeyboardRemove(), + } + ); + } + + [OrderedFact("Should request chat with keyboard reply markup")] + [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.SendMessage)] + public async Task Should_Request_Chat() + { + KeyboardButton[] keyboard = + [ + KeyboardButton.WithRequestChat( + text: "Share Chat", + requestId: 1, + chatIsChannel: false) + ]; + ReplyKeyboardMarkup replyKeyboardMarkup = new(keyboardRow: keyboard); + + await BotClient.SendMessageAsync( + new() + { + ChatId = fixture.PrivateChat, + Text = "Share chat using the keyboard reply markup", + ReplyMarkup = replyKeyboardMarkup, + } + ); + + Message chatMessage = await GetMessageFromChat(MessageType.ChatShared); + + Assert.NotNull(chatMessage.ChatShared); + + await BotClient.SendMessageAsync( + new(){ + ChatId = fixture.PrivateChat, + Text = "Got it. Removing reply keyboard markup...", + ReplyMarkup = new ReplyKeyboardRemove(), + } ); } async Task GetMessageFromChat(MessageType messageType) => - (await _fixture.UpdateReceiver.GetUpdateAsync( + (await testsFixture.UpdateReceiver.GetUpdateAsync( predicate: u => u.Message!.Type == messageType && - u.Message.Chat.Id == _classFixture.PrivateChat.Id, + u.Message.Chat.Id == fixture.PrivateChat.Id, updateTypes: UpdateType.Message )).Message; - public class Fixture : PrivateChatFixture - { - public Fixture(TestsFixture testsFixture) - : base(testsFixture, Constants.TestCollections.ReplyMarkup) - { } - } -} \ No newline at end of file + public class Fixture(TestsFixture testsFixture) + : PrivateChatFixture(testsFixture, Constants.TestCollections.ReplyMarkup); +} diff --git a/test/Telegram.Bot.Tests.Integ/ReplyMarkup/ReplyMarkupTests.cs b/test/Telegram.Bot.Tests.Integ/ReplyMarkup/ReplyMarkupTests.cs index 9a0516738..ec572c6a4 100644 --- a/test/Telegram.Bot.Tests.Integ/ReplyMarkup/ReplyMarkupTests.cs +++ b/test/Telegram.Bot.Tests.Integ/ReplyMarkup/ReplyMarkupTests.cs @@ -9,25 +9,21 @@ namespace Telegram.Bot.Tests.Integ.ReplyMarkup; [Collection(Constants.TestCollections.ReplyMarkup)] [TestCaseOrderer(Constants.TestCaseOrderer, Constants.AssemblyName)] -public class ReplyMarkupTests +public class ReplyMarkupTests(TestsFixture testsFixture) { - ITelegramBotClient BotClient => _fixture.BotClient; - - readonly TestsFixture _fixture; - - public ReplyMarkupTests(TestsFixture testsFixture) - { - _fixture = testsFixture; - } + ITelegramBotClient BotClient => testsFixture.BotClient; [OrderedFact("Should send a message with force reply markup")] [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.SendMessage)] public async Task Should_Force_Reply() { - await BotClient.SendTextMessageAsync( - chatId: _fixture.SupergroupChat, - text: "Message with force_reply", - replyMarkup: new ForceReplyMarkup() + await BotClient.SendMessageAsync( + new() + { + ChatId = testsFixture.SupergroupChat, + Text = "Message with force_reply", + ReplyMarkup = new ForceReplyMarkup(), + } ); } @@ -35,16 +31,25 @@ public async Task Should_Force_Reply() [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.SendMessage)] public async Task Should_Send_MultiRow_Keyboard() { - ReplyKeyboardMarkup replyMarkup = new[] { - new[] { "Top-Left", "Top" , "Top-Right" }, - new[] { "Left", "Center", "Right" }, - new[] { "Bottom-Left", "Bottom", "Bottom-Right" }, + KeyboardButton[][] keyboard = + [ + ["Top-Left", "Top" , "Top-Right"], + ["Left", "Center", "Right"], + ["Bottom-Left", "Bottom", "Bottom-Right"], + ]; + + ReplyKeyboardMarkup replyMarkup = new(keyboard: keyboard) + { + ResizeKeyboard = true, }; - await BotClient.SendTextMessageAsync( - chatId: _fixture.SupergroupChat, - text: "Message with 3x3 keyboard", - replyMarkup: replyMarkup + await BotClient.SendMessageAsync( + new() + { + ChatId = testsFixture.SupergroupChat, + Text = "Message with 3x3 keyboard", + ReplyMarkup = replyMarkup, + } ); } @@ -52,10 +57,13 @@ public async Task Should_Send_MultiRow_Keyboard() [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.SendMessage)] public async Task Should_Remove_Reply_Keyboard() { - await BotClient.SendTextMessageAsync( - chatId: _fixture.SupergroupChat, - text: "Message to remove keyboard", - replyMarkup: new ReplyKeyboardRemove() + await BotClient.SendMessageAsync( + new() + { + ChatId = testsFixture.SupergroupChat, + Text = "Message to remove keyboard", + ReplyMarkup = new ReplyKeyboardRemove(), + } ); } @@ -63,59 +71,32 @@ public async Task Should_Remove_Reply_Keyboard() [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.SendMessage)] public async Task Should_Send_Inline_Keyboard() { - Message sentMessage = await BotClient.SendTextMessageAsync( - chatId: _fixture.SupergroupChat, - text: "Message with inline keyboard markup", - replyMarkup: new InlineKeyboardMarkup(new[] + InlineKeyboardButton[][] keyboard = + [ + [ + InlineKeyboardButton.WithUrl( + text: "Link to Repository", + url: "https://github.com/TelegramBots/Telegram.Bot"), + ], + [ + InlineKeyboardButton.WithCallbackData(textAndCallbackData: "callback_data1"), + InlineKeyboardButton.WithCallbackData(text: "callback_data: a2", callbackData: "data"), + ], + [InlineKeyboardButton.WithSwitchInlineQuery(text: "switch_inline_query"),], + [InlineKeyboardButton.WithSwitchInlineQueryCurrentChat(text: "switch_inline_query_current_chat"),], + ]; + + InlineKeyboardMarkup replyMarkup = new(keyboard); + + Message sentMessage = await BotClient.SendMessageAsync( + new() { - new [] - { - InlineKeyboardButton.WithUrl( - "Link to Repository", - "https://github.com/TelegramBots/Telegram.Bot" - ), - }, - new [] - { - InlineKeyboardButton.WithCallbackData("callback_data1"), - InlineKeyboardButton.WithCallbackData("callback_data2", "data"), - }, - new [] { InlineKeyboardButton.WithSwitchInlineQuery("switch_inline_query"), }, - new [] { InlineKeyboardButton.WithSwitchInlineQueryCurrentChat("switch_inline_query_current_chat"), }, - }) + ChatId = testsFixture.SupergroupChat, + Text = "Message with inline keyboard markup", + ReplyMarkup = replyMarkup, + } ); - Assert.True( - JToken.DeepEquals( - JToken.FromObject(sentMessage.ReplyMarkup), - JToken.FromObject( - new InlineKeyboardMarkup( - new[] - { - new[] - { - InlineKeyboardButton.WithUrl( - "Link to Repository", - "https://github.com/TelegramBots/Telegram.Bot" - ), - }, - new[] - { - InlineKeyboardButton.WithCallbackData("callback_data1"), - InlineKeyboardButton.WithCallbackData("callback_data2", "data"), - }, - new[] - { - InlineKeyboardButton.WithSwitchInlineQuery("switch_inline_query"), - }, - new[] - { - InlineKeyboardButton.WithSwitchInlineQueryCurrentChat("switch_inline_query_current_chat"), - }, - } - ) - ) - ) - ); + Asserts.JsonEquals(replyMarkup, sentMessage.ReplyMarkup); } -} \ No newline at end of file +} diff --git a/test/Telegram.Bot.Tests.Integ/Sending Messages/AlbumMessageTests.cs b/test/Telegram.Bot.Tests.Integ/Sending Messages/AlbumMessageTests.cs index 8bdfce4b7..86a75d2a4 100644 --- a/test/Telegram.Bot.Tests.Integ/Sending Messages/AlbumMessageTests.cs +++ b/test/Telegram.Bot.Tests.Integ/Sending Messages/AlbumMessageTests.cs @@ -1,6 +1,7 @@ using System.IO; using System.Linq; using System.Threading.Tasks; +using Telegram.Bot.Requests; using Telegram.Bot.Tests.Integ.Framework; using Telegram.Bot.Tests.Integ.Framework.Fixtures; using Telegram.Bot.Types; @@ -11,19 +12,10 @@ namespace Telegram.Bot.Tests.Integ.Sending_Messages; [Collection(Constants.TestCollections.AlbumMessage)] [TestCaseOrderer(Constants.TestCaseOrderer, Constants.AssemblyName)] -public class AlbumMessageTests : IClassFixture> +public class AlbumMessageTests(TestsFixture testsFixture, EntitiesFixture classFixture) + : IClassFixture> { - ITelegramBotClient BotClient => _fixture.BotClient; - - readonly EntitiesFixture _classFixture; - - readonly TestsFixture _fixture; - - public AlbumMessageTests(TestsFixture testsFixture, EntitiesFixture classFixture) - { - _fixture = testsFixture; - _classFixture = classFixture; - } + ITelegramBotClient BotClient => testsFixture.BotClient; [OrderedFact("Should upload 2 photos with captions and send them in an album")] [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.SendMediaGroup)] @@ -35,22 +27,24 @@ public async Task Should_Upload_2_Photos_Album() stream2 = System.IO.File.OpenRead(Constants.PathToFile.Photos.Bot) ) { - IAlbumInputMedia[] inputMedia = - { - new InputMediaPhoto(new InputFileStream(stream1, "logo.png")) - { - Caption = "Logo" - }, - new InputMediaPhoto(new InputFileStream(stream2, "bot.gif")) - { - Caption = "Bot" - }, - }; - messages = await BotClient.SendMediaGroupAsync( - chatId: _fixture.SupergroupChat.Id, - media: inputMedia, - disableNotification: true + new() + { + ChatId = testsFixture.SupergroupChat.Id, + Media = [ + new InputMediaPhoto + { + Media = InputFile.FromStream(stream1, "logo.png"), + Caption = "Logo", + }, + new InputMediaPhoto + { + Media = InputFile.FromStream(stream2, "bot.gif"), + Caption = "Bot", + }, + ], + DisableNotification = true, + } ); } @@ -59,12 +53,12 @@ public async Task Should_Upload_2_Photos_Album() // All media messages have the same mediaGroupId Assert.NotEmpty(messages.Select(m => m.MediaGroupId)); - Assert.True(messages.Select(msg => msg.MediaGroupId).Distinct().Count() == 1); + Assert.Single(messages.Select(msg => msg.MediaGroupId).Distinct()); Assert.Equal("Logo", messages[0].Caption); Assert.Equal("Bot", messages[1].Caption); - _classFixture.Entities = messages.ToList(); + classFixture.Entities = messages.ToList(); } [OrderedFact("Should send an album with 3 photos using their file_id")] @@ -72,17 +66,19 @@ public async Task Should_Upload_2_Photos_Album() public async Task Should_Send_3_Photos_Album_Using_FileId() { // Take file_id of photos uploaded in previous test case - string[] fileIds = _classFixture.Entities + string[] fileIds = classFixture.Entities .Select(msg => msg.Photo!.First().FileId) .ToArray(); Message[] messages = await BotClient.SendMediaGroupAsync( - chatId: _fixture.SupergroupChat.Id, - media: new IAlbumInputMedia[] + new() { - new InputMediaPhoto(new InputFileId(fileIds[0])), - new InputMediaPhoto(new InputFileId(fileIds[1])), - new InputMediaPhoto(new InputFileId(fileIds[0])), + ChatId = testsFixture.SupergroupChat.Id, + Media = [ + new InputMediaPhoto { Media = InputFile.FromFileId(fileIds[0])}, + new InputMediaPhoto { Media = InputFile.FromFileId(fileIds[1])}, + new InputMediaPhoto { Media = InputFile.FromFileId(fileIds[0])}, + ] } ); @@ -95,16 +91,18 @@ public async Task Should_Send_3_Photos_Album_Using_FileId() public async Task Should_Send_Photo_Album_Using_Url() { // ToDo add exception: Bad Request: failed to get HTTP URL content - int replyToMessageId = _classFixture.Entities.First().MessageId; + int replyToMessageId = classFixture.Entities.First().MessageId; Message[] messages = await BotClient.SendMediaGroupAsync( - chatId: _fixture.SupergroupChat.Id, - media: new IAlbumInputMedia[] + new() { - new InputMediaPhoto(new InputFileUrl("https://cdn.pixabay.com/photo/2017/06/20/19/22/fuchs-2424369_640.jpg")), - new InputMediaPhoto(new InputFileUrl("https://cdn.pixabay.com/photo/2017/04/11/21/34/giraffe-2222908_640.jpg")), - }, - replyToMessageId: replyToMessageId + ChatId = testsFixture.SupergroupChat.Id, + Media = [ + new InputMediaPhoto { Media = InputFile.FromUri("https://cdn.pixabay.com/photo/2017/06/20/19/22/fuchs-2424369_640.jpg")}, + new InputMediaPhoto { Media = InputFile.FromUri("https://cdn.pixabay.com/photo/2017/04/11/21/34/giraffe-2222908_640.jpg")}, + ], + ReplyParameters = new() { MessageId = replyToMessageId } + } ); Assert.Equal(2, messages.Length); @@ -128,28 +126,31 @@ public async Task Should_Upload_2_Videos_Album() stream2 = System.IO.File.OpenRead(Constants.PathToFile.Photos.Bot) ) { - IAlbumInputMedia[] inputMedia = - { - new InputMediaVideo(new InputFileStream(stream0, "GoldenRatio.mp4")) - { - Caption = "Golden Ratio", - Height = 240, - Width = 240, - Duration = 28, - }, - new InputMediaVideo(new InputFileStream(stream1, "MoonLanding.mp4")) - { - Caption = "Moon Landing" - }, - new InputMediaPhoto(new InputFileStream(stream2, "bot.gif")) - { - Caption = "Bot" - }, - }; - messages = await BotClient.SendMediaGroupAsync( - chatId: _fixture.SupergroupChat.Id, - media: inputMedia + new() + { + ChatId = testsFixture.SupergroupChat.Id, + Media = [ + new InputMediaVideo + { + Media = InputFile.FromStream(stream0, "GoldenRatio.mp4"), + Caption = "Golden Ratio", + Height = 240, + Width = 240, + Duration = 28, + }, + new InputMediaVideo + { + Media = InputFile.FromStream(stream1, "MoonLanding.mp4"), + Caption = "Moon Landing" + }, + new InputMediaPhoto + { + Media = InputFile.FromStream(stream2, "bot.gif"), + Caption = "Bot" + }, + ], + } ); } @@ -184,23 +185,25 @@ public async Task Should_Upload_2_Photos_Album_With_Markdown_Encoded_Captions() stream1 = System.IO.File.OpenRead(Constants.PathToFile.Photos.Logo), stream2 = System.IO.File.OpenRead(Constants.PathToFile.Photos.Bot); - IAlbumInputMedia[] inputMedia = - { - new InputMediaPhoto(new InputFileStream(stream1, "logo.png")) - { - Caption = "*Logo*", - ParseMode = ParseMode.Markdown - }, - new InputMediaPhoto(new InputFileStream(stream2, "bot.gif")) - { - Caption = "_Bot_", - ParseMode = ParseMode.Markdown - }, - }; - Message[] messages = await BotClient.SendMediaGroupAsync( - chatId: _fixture.SupergroupChat.Id, - media: inputMedia + new() + { + ChatId = testsFixture.SupergroupChat.Id, + Media = [ + new InputMediaPhoto + { + Media = InputFile.FromStream(stream1, "logo.png"), + Caption = "*Logo*", + ParseMode = ParseMode.Markdown + }, + new InputMediaPhoto + { + Media = InputFile.FromStream(stream2, "bot.gif"), + Caption = "_Bot_", + ParseMode = ParseMode.Markdown + }, + ], + } ); Message message1 = messages[0]; @@ -227,19 +230,23 @@ public async Task Should_Video_With_Thumbnail_In_Album() stream1 = System.IO.File.OpenRead(Constants.PathToFile.Videos.GoldenRatio), stream2 = System.IO.File.OpenRead(Constants.PathToFile.Thumbnail.Video); - IAlbumInputMedia[] inputMedia = - { - new InputMediaVideo(new InputFileStream(stream1, "GoldenRatio.mp4")) - { - Thumbnail = new InputFileStream(stream2, "thumbnail.jpg"), - SupportsStreaming = true, - }, - new InputMediaPhoto(new InputFileUrl("https://cdn.pixabay.com/photo/2017/04/11/21/34/giraffe-2222908_640.jpg")), - }; - Message[] messages = await BotClient.SendMediaGroupAsync( - chatId: _fixture.SupergroupChat.Id, - media: inputMedia + new() + { + ChatId = testsFixture.SupergroupChat.Id, + Media = [ + new InputMediaVideo + { + Media = InputFile.FromStream(stream1, "GoldenRatio.mp4"), + Thumbnail = InputFile.FromStream(stream2, "thumbnail.jpg"), + SupportsStreaming = true, + }, + new InputMediaPhoto + { + Media = InputFile.FromUri("https://cdn.pixabay.com/photo/2017/04/11/21/34/giraffe-2222908_640.jpg"), + }, + ], + } ); Assert.Equal(MessageType.Video, messages[0].Type); diff --git a/test/Telegram.Bot.Tests.Integ/Sending Messages/AnimationMessageTests.cs b/test/Telegram.Bot.Tests.Integ/Sending Messages/AnimationMessageTests.cs index e7e84cef0..9e7f350f6 100644 --- a/test/Telegram.Bot.Tests.Integ/Sending Messages/AnimationMessageTests.cs +++ b/test/Telegram.Bot.Tests.Integ/Sending Messages/AnimationMessageTests.cs @@ -1,6 +1,7 @@ using System.IO; using System.Linq; using System.Threading.Tasks; +using Telegram.Bot.Requests; using Telegram.Bot.Tests.Integ.Framework; using Telegram.Bot.Types; using Telegram.Bot.Types.Enums; @@ -10,16 +11,9 @@ namespace Telegram.Bot.Tests.Integ.Sending_Messages; [Collection(Constants.TestCollections.SendAnimationMessage)] [TestCaseOrderer(Constants.TestCaseOrderer, Constants.AssemblyName)] -public class AnimationMessageTests +public class AnimationMessageTests(TestsFixture fixture) { - ITelegramBotClient BotClient => _fixture.BotClient; - - readonly TestsFixture _fixture; - - public AnimationMessageTests(TestsFixture fixture) - { - _fixture = fixture; - } + ITelegramBotClient BotClient => fixture.BotClient; [OrderedFact("Should send an animation with caption")] [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.SendAnimation)] @@ -29,14 +23,17 @@ public async Task Should_Send_Animation() await using (Stream stream = System.IO.File.OpenRead(Constants.PathToFile.Animation.Earth)) { message = await BotClient.SendAnimationAsync( - chatId: _fixture.SupergroupChat.Id, - animation: new InputFileStream(stream), - duration: 4, - width: 400, - height: 400, - thumbnail: null, - caption: "Rotating Earth", - parseMode: ParseMode.Html + new() + { + ChatId = fixture.SupergroupChat.Id, + Animation = InputFile.FromStream(stream), + Duration = 4, + Width = 400, + Height = 400, + Thumbnail = null, + Caption = "Rotating Earth", + ParseMode = ParseMode.Html, + } ); } @@ -76,9 +73,12 @@ public async Task Should_Send_Animation_With_Thumb() ) { message = await BotClient.SendAnimationAsync( - chatId: _fixture.SupergroupChat, - animation: new InputFileStream(stream1, "earth.gif"), - thumbnail: new InputFileStream(stream2, "thumb.jpg") + new() + { + ChatId = fixture.SupergroupChat, + Animation = InputFile.FromStream(stream1, "earth.gif"), + Thumbnail = InputFile.FromStream(stream2, "thumb.jpg"), + } ); } diff --git a/test/Telegram.Bot.Tests.Integ/Sending Messages/AudioMessageTests.cs b/test/Telegram.Bot.Tests.Integ/Sending Messages/AudioMessageTests.cs index 59962b5ce..11aaaca4e 100644 --- a/test/Telegram.Bot.Tests.Integ/Sending Messages/AudioMessageTests.cs +++ b/test/Telegram.Bot.Tests.Integ/Sending Messages/AudioMessageTests.cs @@ -1,5 +1,6 @@ using System.IO; using System.Threading.Tasks; +using Telegram.Bot.Requests; using Telegram.Bot.Tests.Integ.Framework; using Telegram.Bot.Types; using Telegram.Bot.Types.Enums; @@ -9,16 +10,9 @@ namespace Telegram.Bot.Tests.Integ.Sending_Messages; [Collection(Constants.TestCollections.SendAudioMessage)] [TestCaseOrderer(Constants.TestCaseOrderer, Constants.AssemblyName)] -public class AudioMessageTests +public class AudioMessageTests(TestsFixture fixture) { - ITelegramBotClient BotClient => _fixture.BotClient; - - readonly TestsFixture _fixture; - - public AudioMessageTests(TestsFixture fixture) - { - _fixture = fixture; - } + ITelegramBotClient BotClient => fixture.BotClient; [OrderedFact("Should send an audio with caption")] [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.SendAudio)] @@ -33,12 +27,15 @@ public async Task Should_Send_Audio() await using (Stream stream = System.IO.File.OpenRead(Constants.PathToFile.Audio.CantinaRagMp3)) { message = await BotClient.SendAudioAsync( - chatId: _fixture.SupergroupChat, - audio: new InputFileStream(stream, "Jackson F Smith - Cantina Rag.mp3"), - title: title, - performer: performer, - caption: caption, - duration: duration + new() + { + ChatId = fixture.SupergroupChat, + Audio = InputFile.FromStream(stream, "Jackson F Smith - Cantina Rag.mp3"), + Title = title, + Performer = performer, + Caption = caption, + Duration = duration, + } ); } @@ -67,9 +64,12 @@ public async Task Should_Send_Audio_With_Thumb() ) { message = await BotClient.SendAudioAsync( - chatId: _fixture.SupergroupChat, - audio: new InputFileStream(stream1, "Ask Again - A State of Despair.mp3"), - thumbnail: new InputFileStream(stream2, "thumb.jpg") + new() + { + ChatId = fixture.SupergroupChat, + Audio = InputFile.FromStream(stream1, "Ask Again - A State of Despair.mp3"), + Thumbnail = InputFile.FromStream(stream2, "thumb.jpg"), + } ); } @@ -93,10 +93,13 @@ public async Task Should_Send_Voice() await using (Stream stream = System.IO.File.OpenRead(Constants.PathToFile.Audio.TestOgg)) { message = await BotClient.SendVoiceAsync( - chatId: _fixture.SupergroupChat, - voice: new InputFileStream(stream), - caption: caption, - duration: duration + new() + { + ChatId = fixture.SupergroupChat, + Voice = InputFile.FromStream(stream), + Caption = caption, + Duration = duration, + } ); } diff --git a/test/Telegram.Bot.Tests.Integ/Sending Messages/CopyMessageTests.cs b/test/Telegram.Bot.Tests.Integ/Sending Messages/CopyMessageTests.cs index 1b10a85ed..7155c1b54 100644 --- a/test/Telegram.Bot.Tests.Integ/Sending Messages/CopyMessageTests.cs +++ b/test/Telegram.Bot.Tests.Integ/Sending Messages/CopyMessageTests.cs @@ -1,4 +1,5 @@ using System.Threading.Tasks; +using Telegram.Bot.Requests; using Telegram.Bot.Tests.Integ.Framework; using Telegram.Bot.Types; using Xunit; @@ -7,32 +8,67 @@ namespace Telegram.Bot.Tests.Integ.Sending_Messages; [Collection(Constants.TestCollections.SendCopyMessage)] [TestCaseOrderer(Constants.TestCaseOrderer, Constants.AssemblyName)] -public class CopyMessageTests +public class CopyMessageTests(TestsFixture testsFixture) { ITelegramBotClient BotClient => _fixture.BotClient; - readonly TestsFixture _fixture; - - public CopyMessageTests(TestsFixture testsFixture) - { - _fixture = testsFixture; - } + readonly TestsFixture _fixture = testsFixture; [OrderedFact("Should copy text message")] [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.CopyMessage)] public async Task Should_Copy_Text_Message() { - Message message = await BotClient.SendTextMessageAsync( - chatId: _fixture.SupergroupChat.Id, - text: "hello" + Message message = await BotClient.SendMessageAsync( + new() + { + ChatId = _fixture.SupergroupChat.Id, + Text = "hello", + } ); MessageId copyMessageId = await BotClient.CopyMessageAsync( - _fixture.SupergroupChat.Id, - _fixture.SupergroupChat.Id, - message.MessageId + new() + { + ChatId = _fixture.SupergroupChat.Id, + FromChatId = _fixture.SupergroupChat.Id, + MessageId = message.MessageId, + } ); Assert.NotEqual(0, copyMessageId.Id); } -} \ No newline at end of file + + [OrderedFact("Should copy text messages")] + [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.CopyMessages)] + public async Task Should_Copy_Text_Messages() + { + Message message1 = await BotClient.SendMessageAsync( + new() + { + ChatId = _fixture.SupergroupChat.Id, + Text = "message one.", + } + ); + + Message message2 = await BotClient.SendMessageAsync( + new() + { + ChatId = _fixture.SupergroupChat.Id, + Text = "message two", + } + ); + + int[] messageIds = [message1.MessageId, message2.MessageId]; + + MessageId[] copyMessageIds = await BotClient.CopyMessagesAsync( + new() + { + ChatId = _fixture.SupergroupChat.Id, + FromChatId = _fixture.SupergroupChat.Id, + MessageIds = messageIds, + } + ); + + Assert.Equal(2, copyMessageIds.Length); + } +} diff --git a/test/Telegram.Bot.Tests.Integ/Sending Messages/DocumentMessageTests.cs b/test/Telegram.Bot.Tests.Integ/Sending Messages/DocumentMessageTests.cs index d5ca15142..78bd83c94 100644 --- a/test/Telegram.Bot.Tests.Integ/Sending Messages/DocumentMessageTests.cs +++ b/test/Telegram.Bot.Tests.Integ/Sending Messages/DocumentMessageTests.cs @@ -9,16 +9,9 @@ namespace Telegram.Bot.Tests.Integ.Sending_Messages; [Collection(Constants.TestCollections.SendDocumentMessage)] [TestCaseOrderer(Constants.TestCaseOrderer, Constants.AssemblyName)] -public class SendingDocumentMessageTests +public class SendingDocumentMessageTests(TestsFixture fixture) { - ITelegramBotClient BotClient => _fixture.BotClient; - - readonly TestsFixture _fixture; - - public SendingDocumentMessageTests(TestsFixture fixture) - { - _fixture = fixture; - } + ITelegramBotClient BotClient => fixture.BotClient; [OrderedFact("Should send a pdf document with caption")] [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.SendDocument)] @@ -26,9 +19,12 @@ public async Task Should_Send_Pdf_Document() { await using Stream stream = System.IO.File.OpenRead(Constants.PathToFile.Documents.Hamlet); Message message = await BotClient.SendDocumentAsync( - chatId: _fixture.SupergroupChat.Id, - document: new InputFileStream(content: stream, fileName: "HAMLET.pdf"), - caption: "The Tragedy of Hamlet,\nPrince of Denmark" + new() + { + ChatId = fixture.SupergroupChat.Id, + Document = new InputFileStream(content: stream, fileName: "HAMLET.pdf"), + Caption = "The Tragedy of Hamlet,\nPrince of Denmark", + } ); Assert.Equal(MessageType.Document, message.Type); @@ -50,9 +46,12 @@ public async Task Should_Send_Document_With_Farsi_Name() { await using Stream stream = System.IO.File.OpenRead(Constants.PathToFile.Documents.Hamlet); Message message = await BotClient.SendDocumentAsync( - chatId: _fixture.SupergroupChat.Id, - document: new InputFileStream(content: stream, fileName: "هملت.pdf"), - caption: "تراژدی هملت\nشاهزاده دانمارک" + new() + { + ChatId = fixture.SupergroupChat.Id, + Document = new InputFileStream(content: stream, fileName: "هملت.pdf"), + Caption = "تراژدی هملت\nشاهزاده دانمارک", + } ); Assert.Equal(MessageType.Document, message.Type); @@ -75,9 +74,12 @@ public async Task Should_Send_Document_With_Thumb() thumbStream = System.IO.File.OpenRead(Constants.PathToFile.Thumbnail.TheAbilityToBreak); Message message = await BotClient.SendDocumentAsync( - chatId: _fixture.SupergroupChat, - document: new InputFileStream(content: documentStream, fileName: "Hamlet.pdf"), - thumbnail: new InputFileStream(content: thumbStream, fileName: "thumb.jpg") + new() + { + ChatId = fixture.SupergroupChat, + Document = InputFile.FromStream(documentStream, "Hamlet.pdf"), + Thumbnail = InputFile.FromStream(thumbStream, "thumb.jpg"), + } ); Assert.NotNull(message.Document); diff --git a/test/Telegram.Bot.Tests.Integ/Sending Messages/SendingContactMessageTests.cs b/test/Telegram.Bot.Tests.Integ/Sending Messages/SendingContactMessageTests.cs index 3affd384b..021425eca 100644 --- a/test/Telegram.Bot.Tests.Integ/Sending Messages/SendingContactMessageTests.cs +++ b/test/Telegram.Bot.Tests.Integ/Sending Messages/SendingContactMessageTests.cs @@ -8,16 +8,9 @@ namespace Telegram.Bot.Tests.Integ.Sending_Messages; [Collection(Constants.TestCollections.SendContactMessage)] [TestCaseOrderer(Constants.TestCaseOrderer, Constants.AssemblyName)] -public class SendingContactMessageTests +public class SendingContactMessageTests(TestsFixture fixture) { - ITelegramBotClient BotClient => _fixture.BotClient; - - readonly TestsFixture _fixture; - - public SendingContactMessageTests(TestsFixture fixture) - { - _fixture = fixture; - } + ITelegramBotClient BotClient => fixture.BotClient; [OrderedFact("Should send a contact")] [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.SendContact)] @@ -28,10 +21,13 @@ public async Task Should_Send_Contact() const string lastName = "Solo"; Message message = await BotClient.SendContactAsync( - chatId: _fixture.SupergroupChat, - phoneNumber: phoneNumber, - firstName: firstName, - lastName: lastName + new() + { + ChatId = fixture.SupergroupChat, + PhoneNumber = phoneNumber, + FirstName = firstName, + LastName = lastName, + } ); Assert.Equal(MessageType.Contact, message.Type); @@ -45,31 +41,36 @@ public async Task Should_Send_Contact() public async Task Should_Send_Contact_With_VCard() { const string vcard = - "BEGIN:VCARD" + "\n" + - "VERSION:2.1" + "\n" + - "N:Gump;Forrest;;Mr." + "\n" + - "FN:Forrest Gump" + "\n" + - "ORG:Bubba Gump Shrimp Co." + "\n" + - "TITLE:Shrimp Man" + "\n" + - "PHOTO;JPEG:https://upload.wikimedia.org/wikipedia/commons/9/95/TomHanksForrestGump94.jpg" + "\n" + - "TEL;WORK;VOICE:(111) 555-1212" + "\n" + - "TEL;HOME;VOICE:(404) 555-1212" + "\n" + - "ADR;HOME:;;42 Plantation St.;Baytown;LA;30314;United States of America" + "\n" + - "LABEL;HOME;ENCODING=QUOTED-PRINTABLE;CHARSET=UTF-8:42 Plantation St.=0D=0A=" + "\n" + - " Baytown, LA 30314=0D=0AUnited States of America" + "\n" + - "EMAIL:forrestgump@example.org" + "\n" + - "REV:20080424T195243Z" + "\n" + - "END:VCARD"; + """ + BEGIN:VCARD + VERSION:2.1 + N:Gump;Forrest;;Mr. + FN:Forrest Gump + ORG:Bubba Gump Shrimp Co. + TITLE:Shrimp Man + PHOTO;JPEG:https://upload.wikimedia.org/wikipedia/commons/9/95/TomHanksForrestGump94.jpg + TEL;WORK;VOICE:(111) 555-1212 + TEL;HOME;VOICE:(404) 555-1212 + ADR;HOME:;;42 Plantation St.;Baytown;LA;30314;United States of America + LABEL;HOME;ENCODING=QUOTED-PRINTABLE;CHARSET=UTF-8:42 Plantation St.=0D=0A= + Baytown, LA 30314=0D=0AUnited States of America + EMAIL:forrestgump@example.org + REV:20080424T195243Z + END:VCARD + """; Message message = await BotClient.SendContactAsync( - chatId: _fixture.SupergroupChat, - phoneNumber: "+11115551212", - firstName: "Forrest", - vCard: vcard + new() + { + ChatId = fixture.SupergroupChat, + PhoneNumber = "+11115551212", + FirstName = "Forrest", + Vcard = vcard, + } ); Assert.Equal(MessageType.Contact, message.Type); Assert.NotNull(message.Contact); Assert.Equal(vcard, message.Contact.Vcard); } -} \ No newline at end of file +} diff --git a/test/Telegram.Bot.Tests.Integ/Sending Messages/SendingPhotoMessageTests.cs b/test/Telegram.Bot.Tests.Integ/Sending Messages/SendingPhotoMessageTests.cs index 515c60eb0..0569af970 100644 --- a/test/Telegram.Bot.Tests.Integ/Sending Messages/SendingPhotoMessageTests.cs +++ b/test/Telegram.Bot.Tests.Integ/Sending Messages/SendingPhotoMessageTests.cs @@ -13,19 +13,10 @@ namespace Telegram.Bot.Tests.Integ.Sending_Messages; [Collection(Constants.TestCollections.SendPhotoMessage)] [TestCaseOrderer(Constants.TestCaseOrderer, Constants.AssemblyName)] -public class SendingPhotoMessageTests : IClassFixture> +public class SendingPhotoMessageTests(TestsFixture fixture, EntityFixture classFixture) + : IClassFixture> { - ITelegramBotClient BotClient => _fixture.BotClient; - - readonly TestsFixture _fixture; - - readonly EntityFixture _classFixture; - - public SendingPhotoMessageTests(TestsFixture fixture, EntityFixture classFixture) - { - _fixture = fixture; - _classFixture = classFixture; - } + ITelegramBotClient BotClient => fixture.BotClient; [OrderedFact("Should Send photo using a file")] [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.SendPhoto)] @@ -33,9 +24,12 @@ public async Task Should_Send_Photo_File() { await using Stream stream = System.IO.File.OpenRead(Constants.PathToFile.Photos.Bot); Message message = await BotClient.SendPhotoAsync( - chatId: _fixture.SupergroupChat.Id, - photo: new InputFileStream(stream), - caption: "👆 This is a\nTelegram Bot" + new() + { + ChatId = fixture.SupergroupChat.Id, + Photo = InputFile.FromStream(stream), + Caption = "👆 This is a\nTelegram Bot", + } ); Assert.Equal(MessageType.Photo, message.Type); @@ -47,18 +41,21 @@ public async Task Should_Send_Photo_File() Assert.All(message.Photo.Select(ps => ps.Height), h => Assert.NotEqual(default, h)); Assert.NotNull(message.From); - _classFixture.Entity = message; + classFixture.Entity = message; } [OrderedFact("Should Send previous photo using its file_id")] [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.SendPhoto)] public async Task Should_Send_Photo_FileId() { - string fileId = _classFixture.Entity.Photo!.First().FileId; + string fileId = classFixture.Entity.Photo!.First().FileId; Message message = await BotClient.SendPhotoAsync( - chatId: _fixture.SupergroupChat.Id, - photo: new InputFileId(fileId) + new() + { + ChatId = fixture.SupergroupChat.Id, + Photo = InputFile.FromFileId(fileId), + } ); // Apparently file ids of photos no longer remain the same when sending them @@ -73,7 +70,7 @@ public async Task Should_Send_Photo_FileId() public async Task Should_Parse_Message_Caption_Entities_Into_Values() { (MessageEntityType Type, string Value)[] entityValueMappings = - { + [ (MessageEntityType.PhoneNumber, "+38612345678"), (MessageEntityType.Cashtag, "$EUR"), (MessageEntityType.Hashtag, "#TelegramBots"), @@ -81,14 +78,17 @@ public async Task Should_Parse_Message_Caption_Entities_Into_Values() (MessageEntityType.Url, "https://github.com/TelegramBots"), (MessageEntityType.Email, "security@telegram.org"), (MessageEntityType.BotCommand, "/test"), - (MessageEntityType.BotCommand, $"/test@{_fixture.BotUser.Username}"), - }; + (MessageEntityType.BotCommand, $"/test@{fixture.BotUser.Username}") + ]; await using Stream stream = System.IO.File.OpenRead(Constants.PathToFile.Photos.Logo); Message message = await BotClient.SendPhotoAsync( - chatId: _fixture.SupergroupChat.Id, - photo: new InputFileStream(stream), - caption: string.Join("\n", entityValueMappings.Select(tuple => tuple.Value)) + new() + { + ChatId = fixture.SupergroupChat.Id, + Photo = InputFile.FromStream(stream), + Caption = string.Join("\n", entityValueMappings.Select(tuple => tuple.Value)), + } ); Assert.NotNull(message.CaptionEntities); @@ -104,18 +104,21 @@ public async Task Should_Parse_Message_Caption_Entities_Into_Values() public async Task Should_Send_Photo_With_Markdown_Encoded_Caption() { (MessageEntityType Type, string EntityBody, string EncodedEntity)[] entityValueMappings = - { + [ (MessageEntityType.Bold, "bold", "*bold*"), (MessageEntityType.Italic, "italic", "_italic_"), - (MessageEntityType.TextLink, "Text Link", "[Text Link](https://github.com/TelegramBots)"), - }; + (MessageEntityType.TextLink, "Text Link", "[Text Link](https://github.com/TelegramBots)") + ]; await using Stream stream = System.IO.File.OpenRead(Constants.PathToFile.Photos.Logo); Message message = await BotClient.SendPhotoAsync( - chatId: _fixture.SupergroupChat.Id, - photo: new InputFileStream(stream), - caption: string.Join("\n", entityValueMappings.Select(tuple => tuple.EncodedEntity)), - parseMode: ParseMode.Markdown + new() + { + ChatId = fixture.SupergroupChat.Id, + Photo = InputFile.FromStream(stream), + Caption = string.Join("\n", entityValueMappings.Select(tuple => tuple.EncodedEntity)), + ParseMode = ParseMode.Markdown, + } ); Assert.NotNull(message.CaptionEntities); @@ -130,11 +133,14 @@ public async Task Should_Send_Photo_With_Markdown_Encoded_Caption() [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.SendPhoto)] public async Task Should_Send_Deserialized_Photo_Request() { - string json = $@"{{ - chat_id: ""{_fixture.SupergroupChat.Id}"", - photo: ""https://cdn.pixabay.com/photo/2017/04/11/21/34/giraffe-2222908_640.jpg"", - caption: ""Photo request deserialized from JSON"", - }}"; + string json = + $$""" + { + chat_id: "{{fixture.SupergroupChat.Id}}", + photo: "https://cdn.pixabay.com/photo/2017/04/11/21/34/giraffe-2222908_640.jpg", + caption: "Photo request deserialized from JSON", + } + """; SendPhotoRequest request = JsonConvert.DeserializeObject(json); diff --git a/test/Telegram.Bot.Tests.Integ/Sending Messages/SendingVenueMessageTests.cs b/test/Telegram.Bot.Tests.Integ/Sending Messages/SendingVenueMessageTests.cs index 268253a4a..2ee87f7bb 100644 --- a/test/Telegram.Bot.Tests.Integ/Sending Messages/SendingVenueMessageTests.cs +++ b/test/Telegram.Bot.Tests.Integ/Sending Messages/SendingVenueMessageTests.cs @@ -10,16 +10,9 @@ namespace Telegram.Bot.Tests.Integ.Sending_Messages; [Collection(Constants.TestCollections.SendVenueMessage)] [TestCaseOrderer(Constants.TestCaseOrderer, Constants.AssemblyName)] -public class SendingVenueMessageTests +public class SendingVenueMessageTests(TestsFixture fixture) { - ITelegramBotClient BotClient => _fixture.BotClient; - - readonly TestsFixture _fixture; - - public SendingVenueMessageTests(TestsFixture fixture) - { - _fixture = fixture; - } + ITelegramBotClient BotClient => fixture.BotClient; [OrderedFact("Should send a venue")] [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.SendVenue)] @@ -32,12 +25,15 @@ public async Task Should_Send_Venue() const string foursquareId = "4cc6222106c25481d7a4a047"; Message message = await BotClient.SendVenueAsync( - chatId: _fixture.SupergroupChat, - latitude: lat, - longitude: lon, - title: title, - address: address, - foursquareId: foursquareId + new() + { + ChatId = fixture.SupergroupChat, + Latitude = lat, + Longitude = lon, + Title = title, + Address = address, + FoursquareId = foursquareId, + } ); Assert.Equal(MessageType.Venue, message.Type); @@ -53,15 +49,18 @@ public async Task Should_Send_Venue() [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.SendVenue)] public async Task Should_Deserialize_Send_Venue() { - string json = $@"{{ - chat_id: ""{_fixture.SupergroupChat.Id}"", + string json = + $$""" + { + chat_id: "{{fixture.SupergroupChat.Id}}", latitude: 48.204296, longitude: 16.365514, - title: ""Burggarten"", - address: ""Opernring"", - foursquare_id: ""4b7ff7c3f964a5208d4730e3"", - foursquare_type: ""parks_outdoors/park"" - }}"; + title: "Burggarten", + address: "Opernring", + foursquare_id: "4b7ff7c3f964a5208d4730e3", + foursquare_type: "parks_outdoors/park" + } + """; SendVenueRequest request = JsonConvert.DeserializeObject(json); @@ -76,4 +75,4 @@ public async Task Should_Deserialize_Send_Venue() Assert.InRange(message.Venue.Location.Latitude, 48.204296 - 0.001f, 48.204296 + 0.001f); Assert.InRange(message.Venue.Location.Longitude, 16.365514 - 0.001f, 16.365514 + 0.001f); } -} \ No newline at end of file +} diff --git a/test/Telegram.Bot.Tests.Integ/Sending Messages/TextMessageTests.cs b/test/Telegram.Bot.Tests.Integ/Sending Messages/TextMessageTests.cs index 0d35230d5..9555d3fa4 100644 --- a/test/Telegram.Bot.Tests.Integ/Sending Messages/TextMessageTests.cs +++ b/test/Telegram.Bot.Tests.Integ/Sending Messages/TextMessageTests.cs @@ -13,80 +13,81 @@ namespace Telegram.Bot.Tests.Integ.Sending_Messages; [Collection(Constants.TestCollections.SendTextMessage)] [TestCaseOrderer(Constants.TestCaseOrderer, Constants.AssemblyName)] -public class TextMessageTests : IClassFixture +public class TextMessageTests(TestsFixture testsFixture, TextMessageTests.Fixture classFixture) + : IClassFixture { - ITelegramBotClient BotClient => _fixture.BotClient; - - readonly TestsFixture _fixture; - - readonly Fixture _classFixture; - - public TextMessageTests(TestsFixture testsFixture, Fixture classFixture) - { - _fixture = testsFixture; - _classFixture = classFixture; - } + ITelegramBotClient BotClient => testsFixture.BotClient; [OrderedFact("Should send text message")] [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.SendMessage)] public async Task Should_Send_Text_Message() { - Message message = await BotClient.SendTextMessageAsync( - chatId: _fixture.SupergroupChat.Id, - text: "Hello world!" + Message message = await BotClient.SendMessageAsync( + new() + { + ChatId = testsFixture.SupergroupChat.Id, + Text = "Hello world!", + } ); Assert.Equal("Hello world!", message.Text); Assert.Equal(MessageType.Text, message.Type); - Assert.Equal(_fixture.SupergroupChat.Id.ToString(), message.Chat.Id.ToString()); + Assert.Equal(testsFixture.SupergroupChat.Id.ToString(), message.Chat.Id.ToString()); Assert.InRange(message.Date, DateTime.UtcNow.AddSeconds(-10), DateTime.UtcNow.AddSeconds(2)); Assert.NotNull(message.From); - Assert.Equal(_fixture.BotUser.Id, message.From.Id); - Assert.Equal(_fixture.BotUser.Username, message.From.Username); + Assert.Equal(testsFixture.BotUser.Id, message.From.Id); + Assert.Equal(testsFixture.BotUser.Username, message.From.Username); // getMe request returns more information than is present in received updates - Asserts.UsersEqual(_fixture.BotUser, message.From); + Asserts.UsersEqual(testsFixture.BotUser, message.From); } [OrderedFact("Should send text message to channel")] [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.SendMessage)] public async Task Should_Send_Text_Message_To_Channel() { - string text = $"Hello members of channel {_classFixture.ChannelChatId}"; + string text = $"Hello members of channel {classFixture.ChannelChatId}"; - Message message = await BotClient.SendTextMessageAsync( - chatId: _classFixture.ChannelChatId, - text: text + Message message = await BotClient.SendMessageAsync( + new() + { + ChatId = classFixture.ChannelChatId, + Text = text, + } ); Assert.Equal(text, message.Text); Assert.Equal(MessageType.Text, message.Type); - Assert.Equal(_classFixture.ChannelChat.Id, message.Chat.Id); - Assert.Equal(_classFixture.ChannelChat.Username, message.Chat.Username); + Assert.Equal(classFixture.ChannelChat.Id, message.Chat.Id); + Assert.Equal(classFixture.ChannelChat.Username, message.Chat.Username); } [OrderedFact("Should forward a message to same chat")] [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.ForwardMessage)] public async Task Should_Forward_Message() { - Message message1 = await BotClient.SendTextMessageAsync( - chatId: _fixture.SupergroupChat, - text: "➡️ Message to be forwared ⬅️" + Message message1 = await BotClient.SendMessageAsync( + new() + { + ChatId = testsFixture.SupergroupChat, + Text = "➡️ Message to be forwared ⬅️", + } ); Message message2 = await BotClient.ForwardMessageAsync( - chatId: _fixture.SupergroupChat, - fromChatId: _fixture.SupergroupChat, - messageId: message1.MessageId + new() + { + ChatId = testsFixture.SupergroupChat, + FromChatId = testsFixture.SupergroupChat, + MessageId = message1.MessageId, + } ); - Asserts.UsersEqual(_fixture.BotUser, message2.ForwardFrom); - Assert.Null(message2.ForwardFromChat); - Assert.Equal(default, message2.ForwardFromMessageId); - Assert.Null(message2.ForwardSignature); - Assert.NotNull(message2.ForwardDate); + MessageOriginUser forwardOrigin = (MessageOriginUser)message2.ForwardOrigin; + Assert.NotNull(forwardOrigin); + Asserts.UsersEqual(testsFixture.BotUser, forwardOrigin.SenderUser); Assert.InRange( - message2.ForwardDate.Value, + forwardOrigin.Date, DateTime.UtcNow.AddSeconds(-20), DateTime.UtcNow ); @@ -105,24 +106,27 @@ public async Task Should_Parse_MarkDown_Entities() {MessageEntityType.TextLink, $"[inline url to Telegram.org]({url})"}, { MessageEntityType.TextMention, - $"[{_fixture.BotUser.GetSafeUsername()}](tg://user?id={_fixture.BotUser.Id})" + $"[{testsFixture.BotUser.GetSafeUsername()}](tg://user?id={testsFixture.BotUser.Id})" }, {MessageEntityType.Code, @"inline ""`fixed-width code`"""}, {MessageEntityType.Pre, "```pre-formatted fixed-width code block```"}, }; - Message message = await BotClient.SendTextMessageAsync( - chatId: _fixture.SupergroupChat.Id, - text: string.Join("\n", entityValueMappings.Values), - parseMode: ParseMode.Markdown, - disableWebPagePreview: true + Message message = await BotClient.SendMessageAsync( + new() + { + ChatId = testsFixture.SupergroupChat.Id, + Text = string.Join("\n", entityValueMappings.Values), + ParseMode = ParseMode.Markdown, + LinkPreviewOptions = new() { IsDisabled = true }, + } ); Assert.NotNull(message.Entities); Assert.Equal(entityValueMappings.Keys, message.Entities.Select(e => e.Type)); Assert.Equal(url, message.Entities.Single(e => e.Type == MessageEntityType.TextLink).Url); Asserts.UsersEqual( - _fixture.BotUser, + testsFixture.BotUser, message.Entities.Single(e => e.Type == MessageEntityType.TextMention).User ); } @@ -133,7 +137,7 @@ public async Task Should_Parse_HTML_Entities() { const string url = "https://telegram.org/"; (MessageEntityType Type, string Value)[] entityValueMappings = - { + [ (MessageEntityType.Bold, "bold"), (MessageEntityType.Bold, "<strong>"), (MessageEntityType.Italic, "italic"), @@ -141,20 +145,23 @@ public async Task Should_Parse_HTML_Entities() (MessageEntityType.TextLink, $@"inline url to Telegram.org"), ( MessageEntityType.TextMention, - $@"{_fixture.BotUser.Username}" + $@"{testsFixture.BotUser.Username}" ), (MessageEntityType.Code, @"inline ""fixed-width code"""), (MessageEntityType.Pre, "
pre-formatted fixed-width code block
"), (MessageEntityType.Strikethrough, "strikethrough"), (MessageEntityType.Underline, "underline"), (MessageEntityType.Spoiler, "spoiler"), - }; + ]; - Message message = await BotClient.SendTextMessageAsync( - chatId: _fixture.SupergroupChat.Id, - text: string.Join("\n", entityValueMappings.Select(tuple => tuple.Value)), - parseMode: ParseMode.Html, - disableWebPagePreview: true + Message message = await BotClient.SendMessageAsync( + new() + { + ChatId = testsFixture.SupergroupChat.Id, + Text = string.Join("\n", entityValueMappings.Select(tuple => tuple.Value)), + ParseMode = ParseMode.Html, + LinkPreviewOptions = new() { IsDisabled = true }, + } ); Assert.NotNull(message.Entities); @@ -164,7 +171,7 @@ public async Task Should_Parse_HTML_Entities() ); Assert.Equal(url, message.Entities.Single(e => e.Type == MessageEntityType.TextLink).Url); Asserts.UsersEqual( - _fixture.BotUser, + testsFixture.BotUser, message.Entities.Single(e => e.Type == MessageEntityType.TextMention).User ); } @@ -174,7 +181,7 @@ public async Task Should_Parse_HTML_Entities() public async Task Should_Parse_Message_Entities_Into_Values() { (MessageEntityType Type, string Value)[] entityValueMappings = - { + [ (MessageEntityType.PhoneNumber, "+38612345678"), (MessageEntityType.Cashtag, "$EUR"), (MessageEntityType.Hashtag, "#TelegramBots"), @@ -182,12 +189,15 @@ public async Task Should_Parse_Message_Entities_Into_Values() (MessageEntityType.Url, "https://github.com/TelegramBots"), (MessageEntityType.Email, "security@telegram.org"), (MessageEntityType.BotCommand, "/test"), - (MessageEntityType.BotCommand, $"/test@{_fixture.BotUser.Username}"), - }; + (MessageEntityType.BotCommand, $"/test@{testsFixture.BotUser.Username}"), + ]; - Message message = await BotClient.SendTextMessageAsync( - chatId: _fixture.SupergroupChat.Id, - text: string.Join("\n", entityValueMappings.Select(tuple => tuple.Value)) + Message message = await BotClient.SendMessageAsync( + new() + { + ChatId = testsFixture.SupergroupChat.Id, + Text = string.Join("\n", entityValueMappings.Select(tuple => tuple.Value)), + } ); Assert.NotNull(message.Entities); @@ -211,7 +221,7 @@ public async Task Should_Parse_MarkdownV2_Entities() {MessageEntityType.TextLink, $"[inline url to Telegram\\.org]({url})"}, { MessageEntityType.TextMention, - $"[{_fixture.BotUser.GetSafeUsername()}](tg://user?id={_fixture.BotUser.Id})" + $"[{testsFixture.BotUser.GetSafeUsername()}](tg://user?id={testsFixture.BotUser.Id})" }, {MessageEntityType.Code, @"inline ""`fixed-width code`"""}, {MessageEntityType.Pre, "```pre-formatted fixed-width code block```"}, @@ -220,18 +230,21 @@ public async Task Should_Parse_MarkdownV2_Entities() {MessageEntityType.Spoiler, "||spoiler||"}, }; - Message message = await BotClient.SendTextMessageAsync( - chatId: _fixture.SupergroupChat.Id, - text: string.Join("\n", entityValueMappings.Values), - parseMode: ParseMode.MarkdownV2, - disableWebPagePreview: true + Message message = await BotClient.SendMessageAsync( + new() + { + ChatId = testsFixture.SupergroupChat.Id, + Text = string.Join("\n", entityValueMappings.Values), + ParseMode = ParseMode.MarkdownV2, + LinkPreviewOptions = new() { IsDisabled = true }, + } ); Assert.NotNull(message.Entities); Assert.Equal(entityValueMappings.Keys, message.Entities.Select(e => e.Type)); Assert.Equal(url, message.Entities.Single(e => e.Type == MessageEntityType.TextLink).Url); Asserts.UsersEqual( - _fixture.BotUser, + testsFixture.BotUser, message.Entities.Single(e => e.Type == MessageEntityType.TextMention).User ); } @@ -240,52 +253,57 @@ public async Task Should_Parse_MarkdownV2_Entities() [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.SendMessage)] public async Task Should_Send_Message_With_Protected_Content() { - Message message = await BotClient.SendTextMessageAsync( - chatId: _fixture.SupergroupChat.Id, - text: "This content is protected!", - protectContent: true + Message message = await BotClient.SendMessageAsync( + new() + { + ChatId = testsFixture.SupergroupChat.Id, + Text = "This content is protected!", + ProtectContent = true, + } ); Assert.Equal("This content is protected!", message.Text); Assert.Equal(MessageType.Text, message.Type); - Assert.Equal(_fixture.SupergroupChat.Id.ToString(), message.Chat.Id.ToString()); + Assert.Equal(testsFixture.SupergroupChat.Id.ToString(), message.Chat.Id.ToString()); Assert.InRange(message.Date, DateTime.UtcNow.AddSeconds(-10), DateTime.UtcNow.AddSeconds(2)); Assert.NotNull(message.From); - Assert.Equal(_fixture.BotUser.Id, message.From.Id); - Assert.Equal(_fixture.BotUser.Username, message.From.Username); + Assert.Equal(testsFixture.BotUser.Id, message.From.Id); + Assert.Equal(testsFixture.BotUser.Username, message.From.Username); Assert.True(message.HasProtectedContent); // getMe request returns more information than is present in received updates - Asserts.UsersEqual(_fixture.BotUser, message.From); + Asserts.UsersEqual(testsFixture.BotUser, message.From); } [OrderedFact("Should send a message with protected content")] [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.SendMessage)] public async Task Should_Receive_Error_Trying_Forward_A_Message__With_Protected_Content() { - Message message = await BotClient.SendTextMessageAsync( - chatId: _fixture.SupergroupChat.Id, - text: "This content is protected!", - protectContent: true + Message message = await BotClient.SendMessageAsync( + new() + { + ChatId = testsFixture.SupergroupChat.Id, + Text = "This content is protected!", + ProtectContent = true, + } ); Assert.True(message.HasProtectedContent); ApiRequestException exception = await Assert.ThrowsAsync( async () => await BotClient.ForwardMessageAsync( - fromChatId: _fixture.SupergroupChat.Id, - chatId: _fixture.SupergroupChat.Id, - messageId: message.MessageId + new() + { + FromChatId = testsFixture.SupergroupChat.Id, + ChatId = testsFixture.SupergroupChat.Id, + MessageId = message.MessageId, + } ) ); Assert.Equal(400, exception.ErrorCode); } - public class Fixture : ChannelChatFixture - { - public Fixture(TestsFixture testsFixture) - : base(testsFixture, Constants.TestCollections.SendTextMessage) - { } - } -} \ No newline at end of file + public class Fixture(TestsFixture testsFixture) + : ChannelChatFixture(testsFixture, Constants.TestCollections.SendTextMessage); +} diff --git a/test/Telegram.Bot.Tests.Integ/Sending Messages/VideoMessageTests.cs b/test/Telegram.Bot.Tests.Integ/Sending Messages/VideoMessageTests.cs index 5a389a1de..d445dd0a9 100644 --- a/test/Telegram.Bot.Tests.Integ/Sending Messages/VideoMessageTests.cs +++ b/test/Telegram.Bot.Tests.Integ/Sending Messages/VideoMessageTests.cs @@ -1,5 +1,7 @@ using System.IO; +using System.Net.Http; using System.Threading.Tasks; +using Telegram.Bot.Requests; using Telegram.Bot.Tests.Integ.Framework; using Telegram.Bot.Types; using Telegram.Bot.Types.Enums; @@ -9,16 +11,9 @@ namespace Telegram.Bot.Tests.Integ.Sending_Messages; [Collection(Constants.TestCollections.SendVideoMessage)] [TestCaseOrderer(Constants.TestCaseOrderer, Constants.AssemblyName)] -public class SendingVideoMessageTests +public class SendingVideoMessageTests(TestsFixture fixture) { - ITelegramBotClient BotClient => _fixture.BotClient; - - readonly TestsFixture _fixture; - - public SendingVideoMessageTests(TestsFixture fixture) - { - _fixture = fixture; - } + ITelegramBotClient BotClient => fixture.BotClient; [OrderedFact("Should send a video with caption")] [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.SendVideo)] @@ -28,12 +23,15 @@ public async Task Should_Send_Video() await using (Stream stream = System.IO.File.OpenRead(Constants.PathToFile.Videos.MoonLanding)) { message = await BotClient.SendVideoAsync( - chatId: _fixture.SupergroupChat.Id, - video: new InputFileStream(stream, "moon-landing.mp4"), - duration: 104, - width: 320, - height: 240, - caption: "Moon Landing" + new() + { + ChatId = fixture.SupergroupChat.Id, + Video = InputFile.FromStream(stream, "moon-landing.mp4"), + Duration = 104, + Width = 320, + Height = 240, + Caption = "Moon Landing", + } ); } @@ -42,7 +40,7 @@ await using (Stream stream = System.IO.File.OpenRead(Constants.PathToFile.Videos Assert.NotNull(message.Video); Assert.NotEmpty(message.Video.FileId); Assert.NotEmpty(message.Video.FileUniqueId); - Assert.Equal(104, message.Video.Duration); + Assert.True(message.Video.Duration >= 104); Assert.Equal(320, message.Video.Width); Assert.Equal(240, message.Video.Height); Assert.Equal("video/mp4", message.Video.MimeType); @@ -65,10 +63,13 @@ public async Task Should_Send_Video_Note() await using (Stream stream = System.IO.File.OpenRead(Constants.PathToFile.Videos.GoldenRatio)) { message = await BotClient.SendVideoNoteAsync( - chatId: _fixture.SupergroupChat.Id, - videoNote: new InputFileStream(stream), - duration: 28, - length: 240 + new() + { + ChatId = fixture.SupergroupChat.Id, + VideoNote = InputFile.FromStream(stream), + Duration = 28, + Length = 240, + } ); } @@ -76,7 +77,7 @@ await using (Stream stream = System.IO.File.OpenRead(Constants.PathToFile.Videos Assert.NotNull(message.VideoNote); Assert.NotEmpty(message.VideoNote.FileId); Assert.NotEmpty(message.VideoNote.FileUniqueId); - Assert.Equal(28, message.VideoNote.Duration); + Assert.True(message.VideoNote.Duration >= 28); Assert.Equal(240, message.VideoNote.Length); Assert.NotNull(message.VideoNote.Thumbnail); Assert.NotEmpty(message.VideoNote.Thumbnail.FileId); @@ -98,9 +99,12 @@ public async Task Should_Send_Video_With_Thumb() ) { message = await BotClient.SendVideoAsync( - chatId: _fixture.SupergroupChat, - video: new InputFileStream(stream1), - thumbnail: new InputFileStream(stream2, "thumb.jpg") + new() + { + ChatId = fixture.SupergroupChat, + Video = InputFile.FromStream(stream1), + Thumbnail = InputFile.FromStream(stream2, "thumb.jpg"), + } ); } @@ -111,7 +115,7 @@ public async Task Should_Send_Video_With_Thumb() Assert.Equal(320, message.Video.Thumbnail.Width); Assert.Equal(240, message.Video.Thumbnail.Height); Assert.NotNull(message.Video.Thumbnail.FileSize); - Assert.InRange((int)message.Video.Thumbnail.FileSize, 600, 900); + Assert.InRange((long)message.Video.Thumbnail.FileSize, 600, 900); } [OrderedFact("Should send a video note with thumbnail")] @@ -125,9 +129,12 @@ public async Task Should_Send_Video_Note_With_Thumb() ) { message = await BotClient.SendVideoNoteAsync( - chatId: _fixture.SupergroupChat.Id, - videoNote: new InputFileStream(stream1), - thumbnail: new InputFileStream(stream2, "thumbnail.jpg") + new() + { + ChatId = fixture.SupergroupChat.Id, + VideoNote = InputFile.FromStream(stream1), + Thumbnail = InputFile.FromStream(stream2, "thumbnail.jpg"), + } ); } diff --git a/test/Telegram.Bot.Tests.Integ/Stickers/StickersTests.cs b/test/Telegram.Bot.Tests.Integ/Stickers/StickersTests.cs index 7ec728bab..34a40f2d1 100644 --- a/test/Telegram.Bot.Tests.Integ/Stickers/StickersTests.cs +++ b/test/Telegram.Bot.Tests.Integ/Stickers/StickersTests.cs @@ -1,7 +1,9 @@ +using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Telegram.Bot.Exceptions; +using Telegram.Bot.Requests; using Telegram.Bot.Tests.Integ.Framework; using Telegram.Bot.Types; using Telegram.Bot.Types.Enums; @@ -12,210 +14,205 @@ namespace Telegram.Bot.Tests.Integ.Stickers; [Collection(Constants.TestCollections.Stickers)] [Trait(Constants.CategoryTraitName, Constants.InteractiveCategoryValue)] [TestCaseOrderer(Constants.TestCaseOrderer, Constants.AssemblyName)] -public class StickersTests : IClassFixture +public class StickersTests(TestsFixture fixture, StickersTestsFixture classFixture) + : IClassFixture { - private ITelegramBotClient BotClient => _fixture.BotClient; - - private readonly StickersTestsFixture _stickersTestsFixture; - - private readonly TestsFixture _fixture; - - public StickersTests(TestsFixture fixture, StickersTestsFixture classFixture) - { - _stickersTestsFixture = classFixture; - _fixture = fixture; - } + private ITelegramBotClient BotClient => fixture.BotClient; #region 1. Upload sticker files - [OrderedFact("Shound upload static sticker file")] + [OrderedFact("Should upload static sticker file")] [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.UploadStickerFile)] - public async Task Shound_Upload_Static_Sticker_File() + public async Task Should_Upload_Static_Sticker_File() { - using System.IO.Stream stream = System.IO.File.OpenRead(Constants.PathToFile.Sticker.Regular.StaticFirst); + await using System.IO.Stream stream = System.IO.File.OpenRead(Constants.PathToFile.Sticker.Regular.StaticFirst); File file = await BotClient.UploadStickerFileAsync( - userId: _stickersTestsFixture.OwnerUserId, - sticker: new InputFileStream(stream), - StickerFormat.Static + new() + { + UserId = classFixture.OwnerUserId, + Sticker = new(stream), + StickerFormat = StickerFormat.Static, + } ); Assert.NotEmpty(file.FileId); Assert.True(file.FileSize > 0); - _stickersTestsFixture.TestUploadedStaticStickerFile = file; + classFixture.TestUploadedStaticStickerFile = file; } - [OrderedFact("Shound upload animated sticker file")] + [OrderedFact("Should upload animated sticker file")] [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.UploadStickerFile)] - public async Task Shound_Upload_Animated_Sticker_File() + public async Task Should_Upload_Animated_Sticker_File() { - using System.IO.Stream stream = System.IO.File.OpenRead(Constants.PathToFile.Sticker.Regular.AnimatedFirst); + await using System.IO.Stream stream = System.IO.File.OpenRead(Constants.PathToFile.Sticker.Regular.AnimatedFirst); File file = await BotClient.UploadStickerFileAsync( - userId: _stickersTestsFixture.OwnerUserId, - sticker: new InputFileStream(stream), - StickerFormat.Animated + new() + { + UserId = classFixture.OwnerUserId, + Sticker = InputFile.FromStream(stream), + StickerFormat = StickerFormat.Animated, + } ); Assert.NotEmpty(file.FileId); Assert.True(file.FileSize > 0); - _stickersTestsFixture.TestUploadedAnimatedStickerFile = file; + classFixture.TestUploadedAnimatedStickerFile = file; } - [OrderedFact("Shound upload video sticker file")] + [OrderedFact("Should upload video sticker file")] [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.UploadStickerFile)] - public async Task Shound_Upload_Video_Sticker_File() + public async Task Should_Upload_Video_Sticker_File() { - using System.IO.Stream stream = System.IO.File.OpenRead(Constants.PathToFile.Sticker.Regular.VideoFirst); + await using System.IO.Stream stream = System.IO.File.OpenRead(Constants.PathToFile.Sticker.Regular.VideoFirst); File file = await BotClient.UploadStickerFileAsync( - userId: _stickersTestsFixture.OwnerUserId, - sticker: new InputFileStream(stream), - StickerFormat.Video + new() + { + UserId = classFixture.OwnerUserId, + Sticker = InputFile.FromStream(stream), + StickerFormat = StickerFormat.Video, + } ); Assert.NotEmpty(file.FileId); Assert.True(file.FileSize > 0); - _stickersTestsFixture.TestUploadedVideoStickerFile = file; + classFixture.TestUploadedVideoStickerFile = file; } #endregion #region 2. Create sticker sets - [OrderedFact("Shound create new static sticker set")] + [OrderedFact("Should create new static sticker set")] [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.CreateNewStickerSet)] [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.GetStickerSet)] public async Task Should_Create_New_Static_Sticker_Set() { - List inputStickers = new List(2); - - using System.IO.Stream stream = System.IO.File.OpenRead( + await using System.IO.Stream stream = System.IO.File.OpenRead( Constants.PathToFile.Sticker.Regular.StaticSecond ); - inputStickers.Add( - new InputSticker( - sticker: new InputFileId(_stickersTestsFixture.TestUploadedStaticStickerFile.FileId), - emojiList: _stickersTestsFixture.FirstEmojis - ) - ); - - inputStickers.Add( - new InputSticker( - sticker: new InputFileStream(stream, "Static2.webp"), - emojiList: _stickersTestsFixture.SecondEmojis - ) - ); + List inputStickers = + [ + new( + sticker: InputFile.FromFileId(classFixture.TestUploadedStaticStickerFile.FileId), + emojiList: classFixture.FirstEmojis + ), + new( + sticker: InputFile.FromStream(stream, "Static2.webp"), + emojiList: classFixture.SecondEmojis + ), + ]; await BotClient.CreateNewStickerSetAsync( - userId: _stickersTestsFixture.OwnerUserId, - name: _stickersTestsFixture.TestStaticRegularStickerSetName, - title: _stickersTestsFixture.TestStickerSetTitle, - stickers: inputStickers, - stickerFormat: StickerFormat.Static, - stickerType: StickerType.Regular + new() + { + UserId = classFixture.OwnerUserId, + Name = classFixture.TestStaticRegularStickerSetName, + Title = classFixture.TestStickerSetTitle, + Stickers = inputStickers, + StickerFormat = StickerFormat.Static, + StickerType = StickerType.Regular, + } ); await Task.Delay(1_000); - _stickersTestsFixture.TestStaticRegularStickerSet = await BotClient.GetStickerSetAsync( - name: _stickersTestsFixture.TestStaticRegularStickerSetName + classFixture.TestStaticRegularStickerSet = await BotClient.GetStickerSetAsync( + new GetStickerSetRequest { Name = classFixture.TestStaticRegularStickerSetName } ); - Assert.False(_stickersTestsFixture.TestStaticRegularStickerSet.IsAnimated); - Assert.False(_stickersTestsFixture.TestStaticRegularStickerSet.IsVideo); - Assert.True(_stickersTestsFixture.TestStaticRegularStickerSet.Stickers.Length == 2); + Assert.False(classFixture.TestStaticRegularStickerSet.IsAnimated); + Assert.False(classFixture.TestStaticRegularStickerSet.IsVideo); + Assert.Equal(2, classFixture.TestStaticRegularStickerSet.Stickers.Length); } - [OrderedFact("Shound create new animated sticker set")] + [OrderedFact("Should create new animated sticker set")] [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.CreateNewStickerSet)] [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.GetStickerSet)] public async Task Should_Create_New_Animated_Sticker_Set() { - List inputStickers = new List(2); - - using System.IO.Stream stream = System.IO.File.OpenRead( + await using System.IO.Stream stream = System.IO.File.OpenRead( Constants.PathToFile.Sticker.Regular.AnimatedSecond ); - inputStickers.Add( - new InputSticker( - sticker: new InputFileId(_stickersTestsFixture.TestUploadedAnimatedStickerFile.FileId), - emojiList: _stickersTestsFixture.FirstEmojis - ) - ); - - inputStickers.Add( - new InputSticker( - sticker: new InputFileStream(stream, "Animated2.webp"), - emojiList: _stickersTestsFixture.SecondEmojis - ) - ); + List inputStickers = [ + new( + sticker: InputFile.FromFileId(classFixture.TestUploadedAnimatedStickerFile.FileId), + emojiList: classFixture.FirstEmojis + ), + new( + sticker: InputFile.FromStream(stream, "Animated2.webp"), + emojiList: classFixture.SecondEmojis + ), + ]; await BotClient.CreateNewStickerSetAsync( - userId: _stickersTestsFixture.OwnerUserId, - name: _stickersTestsFixture.TestAnimatedRegularStickerSetName, - title: _stickersTestsFixture.TestStickerSetTitle, - stickers: inputStickers, - stickerFormat: StickerFormat.Animated, - stickerType: StickerType.Regular + new() + { + UserId = classFixture.OwnerUserId, + Name = classFixture.TestAnimatedRegularStickerSetName, + Title = classFixture.TestStickerSetTitle, + Stickers = inputStickers, + StickerFormat = StickerFormat.Animated, + StickerType = StickerType.Regular, + } ); await Task.Delay(1_000); - _stickersTestsFixture.TestAnimatedRegularStickerSet = await BotClient.GetStickerSetAsync( - name: _stickersTestsFixture.TestAnimatedRegularStickerSetName + classFixture.TestAnimatedRegularStickerSet = await BotClient.GetStickerSetAsync( + new GetStickerSetRequest { Name = classFixture.TestAnimatedRegularStickerSetName } ); - Assert.True(_stickersTestsFixture.TestAnimatedRegularStickerSet.IsAnimated); - Assert.False(_stickersTestsFixture.TestAnimatedRegularStickerSet.IsVideo); - Assert.True(_stickersTestsFixture.TestAnimatedRegularStickerSet.Stickers.Length == 2); + Assert.True(classFixture.TestAnimatedRegularStickerSet.IsAnimated); + Assert.False(classFixture.TestAnimatedRegularStickerSet.IsVideo); + Assert.Equal(2, classFixture.TestAnimatedRegularStickerSet.Stickers.Length); } - [OrderedFact("Shound create new video sticker set")] + [OrderedFact("Should create new video sticker set")] [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.CreateNewStickerSet)] [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.GetStickerSet)] public async Task Should_Create_New_Video_Sticker_Set() { - List inputStickers = new List(2); - - using System.IO.Stream stream = System.IO.File.OpenRead( + await using System.IO.Stream stream = System.IO.File.OpenRead( Constants.PathToFile.Sticker.Regular.VideoSecond ); - inputStickers.Add( - new InputSticker( - sticker: new InputFileId(_stickersTestsFixture.TestUploadedVideoStickerFile.FileId), - emojiList: _stickersTestsFixture.FirstEmojis - ) - ); - - inputStickers.Add( - new InputSticker( - sticker: new InputFileStream(stream, "Video2.webp"), - emojiList: _stickersTestsFixture.SecondEmojis - ) - ); + List inputStickers = [ + new( + sticker: InputFile.FromFileId(classFixture.TestUploadedVideoStickerFile.FileId), + emojiList: classFixture.FirstEmojis + ), + new( + sticker: InputFile.FromStream(stream, "Video2.webp"), + emojiList: classFixture.SecondEmojis + ), + ]; await BotClient.CreateNewStickerSetAsync( - userId: _stickersTestsFixture.OwnerUserId, - name: _stickersTestsFixture.TestVideoRegularStickerSetName, - title: _stickersTestsFixture.TestStickerSetTitle, - stickers: inputStickers, - stickerFormat: StickerFormat.Video, - stickerType: StickerType.Regular + new() + { + UserId = classFixture.OwnerUserId, + Name = classFixture.TestVideoRegularStickerSetName, + Title = classFixture.TestStickerSetTitle, + Stickers = inputStickers, + StickerFormat = StickerFormat.Video, + StickerType = StickerType.Regular, + } ); await Task.Delay(1_000); - _stickersTestsFixture.TestVideoRegularStickerSet = await BotClient.GetStickerSetAsync( - name: _stickersTestsFixture.TestVideoRegularStickerSetName + classFixture.TestVideoRegularStickerSet = await BotClient.GetStickerSetAsync( + new GetStickerSetRequest { Name = classFixture.TestVideoRegularStickerSetName } ); - Assert.False(_stickersTestsFixture.TestVideoRegularStickerSet.IsAnimated); - Assert.True(_stickersTestsFixture.TestVideoRegularStickerSet.IsVideo); - Assert.True(_stickersTestsFixture.TestVideoRegularStickerSet.Stickers.Length == 2); + Assert.False(classFixture.TestVideoRegularStickerSet.IsAnimated); + Assert.True(classFixture.TestVideoRegularStickerSet.IsVideo); + Assert.Equal(2, classFixture.TestVideoRegularStickerSet.Stickers.Length); } #endregion @@ -226,25 +223,29 @@ public async Task Should_Create_New_Video_Sticker_Set() public async Task Should_Send_Static_Sticker() { StickerSet stickerSet = await BotClient.GetStickerSetAsync( - name: _stickersTestsFixture.TestStaticRegularStickerSetName + new GetStickerSetRequest { Name = classFixture.TestStaticRegularStickerSetName } ); Assert.False(stickerSet.IsAnimated); Assert.False(stickerSet.IsVideo); - Assert.True(stickerSet.Stickers.Length == 2); + Assert.Equal(2, stickerSet.Stickers.Length); Sticker firstSticker = stickerSet.Stickers.First(); - string firstEmojisString = string.Join(string.Empty, _stickersTestsFixture.FirstEmojis); + string firstEmojisString = string.Concat(classFixture.FirstEmojis); Assert.Equal(firstEmojisString, firstSticker.Emoji); Message stickerMessage = await BotClient.SendStickerAsync( - chatId: _fixture.SupergroupChat.Id, - sticker: new InputFileId(firstSticker.FileId) + new() + { + ChatId = fixture.SupergroupChat.Id, + Sticker = InputFile.FromFileId(firstSticker.FileId), + } ); Assert.Equal(MessageType.Sticker, stickerMessage.Type); + Assert.NotNull(stickerMessage.Sticker); Assert.Equal(firstSticker.FileUniqueId, stickerMessage.Sticker.FileUniqueId); Assert.Equal(firstSticker.FileSize, stickerMessage.Sticker.FileSize); Assert.Equal(firstSticker.Type, stickerMessage.Sticker.Type); @@ -252,6 +253,8 @@ public async Task Should_Send_Static_Sticker() Assert.Equal(firstSticker.Height, stickerMessage.Sticker.Height); Assert.False(stickerMessage.Sticker.IsAnimated); Assert.False(stickerMessage.Sticker.IsVideo); + Assert.NotNull(firstSticker.Thumbnail); + Assert.NotNull(stickerMessage.Sticker.Thumbnail); Assert.Equal(firstSticker.Thumbnail.FileUniqueId, stickerMessage.Sticker.Thumbnail.FileUniqueId); Assert.Equal(firstSticker.Thumbnail.FileSize, stickerMessage.Sticker.Thumbnail.FileSize); Assert.Equal(firstSticker.Thumbnail.Width, stickerMessage.Sticker.Thumbnail.Width); @@ -267,25 +270,29 @@ public async Task Should_Send_Static_Sticker() public async Task Should_Send_Animated_Sticker() { StickerSet stickerSet = await BotClient.GetStickerSetAsync( - name: _stickersTestsFixture.TestAnimatedRegularStickerSetName + new GetStickerSetRequest { Name = classFixture.TestAnimatedRegularStickerSetName } ); Assert.True(stickerSet.IsAnimated); Assert.False(stickerSet.IsVideo); - Assert.True(stickerSet.Stickers.Length == 2); + Assert.Equal(2, stickerSet.Stickers.Length); Sticker firstSticker = stickerSet.Stickers.First(); - string firstEmojisString = string.Join(string.Empty, _stickersTestsFixture.FirstEmojis); + string firstEmojisString = string.Concat(classFixture.FirstEmojis); Assert.Equal(firstEmojisString, firstSticker.Emoji); Message stickerMessage = await BotClient.SendStickerAsync( - chatId: _fixture.SupergroupChat.Id, - sticker: new InputFileId(firstSticker.FileId) + new() + { + ChatId = fixture.SupergroupChat.Id, + Sticker = InputFile.FromFileId(firstSticker.FileId), + } ); Assert.Equal(MessageType.Sticker, stickerMessage.Type); + Assert.NotNull(stickerMessage.Sticker); Assert.Equal(firstSticker.FileUniqueId, stickerMessage.Sticker.FileUniqueId); Assert.Equal(firstSticker.FileSize, stickerMessage.Sticker.FileSize); Assert.Equal(firstSticker.Type, stickerMessage.Sticker.Type); @@ -293,6 +300,8 @@ public async Task Should_Send_Animated_Sticker() Assert.Equal(firstSticker.Height, stickerMessage.Sticker.Height); Assert.True(stickerMessage.Sticker.IsAnimated); Assert.False(stickerMessage.Sticker.IsVideo); + Assert.NotNull(firstSticker.Thumbnail); + Assert.NotNull(stickerMessage.Sticker.Thumbnail); Assert.Equal(firstSticker.Thumbnail.FileUniqueId, stickerMessage.Sticker.Thumbnail.FileUniqueId); Assert.Equal(firstSticker.Thumbnail.FileSize, stickerMessage.Sticker.Thumbnail.FileSize); Assert.Equal(firstSticker.Thumbnail.Width, stickerMessage.Sticker.Thumbnail.Width); @@ -308,25 +317,29 @@ public async Task Should_Send_Animated_Sticker() public async Task Should_Send_Video_Sticker() { StickerSet stickerSet = await BotClient.GetStickerSetAsync( - name: _stickersTestsFixture.TestVideoRegularStickerSetName + new GetStickerSetRequest { Name = classFixture.TestVideoRegularStickerSetName } ); Assert.False(stickerSet.IsAnimated); Assert.True(stickerSet.IsVideo); - Assert.True(stickerSet.Stickers.Length == 2); + Assert.Equal(2, stickerSet.Stickers.Length); Sticker firstSticker = stickerSet.Stickers.First(); - string firstEmojisString = string.Join(string.Empty, _stickersTestsFixture.FirstEmojis); + string firstEmojisString = string.Concat(classFixture.FirstEmojis); Assert.Equal(firstEmojisString, firstSticker.Emoji); Message stickerMessage = await BotClient.SendStickerAsync( - chatId: _fixture.SupergroupChat.Id, - sticker: new InputFileId(firstSticker.FileId) + new() + { + ChatId = fixture.SupergroupChat.Id, + Sticker = InputFile.FromFileId(firstSticker.FileId), + } ); Assert.Equal(MessageType.Sticker, stickerMessage.Type); + Assert.NotNull(stickerMessage.Sticker); Assert.Equal(firstSticker.FileUniqueId, stickerMessage.Sticker.FileUniqueId); Assert.Equal(firstSticker.FileSize, stickerMessage.Sticker.FileSize); Assert.Equal(firstSticker.Type, stickerMessage.Sticker.Type); @@ -350,34 +363,37 @@ public async Task Should_Send_Video_Sticker() [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.GetStickerSet)] public async Task Should_Add_Sticker_To_Static_Sticker_Set() { - using System.IO.Stream stream = System.IO.File.OpenRead( + await using System.IO.Stream stream = System.IO.File.OpenRead( Constants.PathToFile.Sticker.Regular.StaticThird ); - InputSticker inputSticker = new InputSticker( - sticker: new InputFileStream(stream, "Static3.png"), - emojiList: _stickersTestsFixture.ThirdEmojis + InputSticker inputSticker = new( + sticker: InputFile.FromStream(stream, "Static3.png"), + emojiList: classFixture.ThirdEmojis ); await BotClient.AddStickerToSetAsync( - userId: _stickersTestsFixture.OwnerUserId, - name: _stickersTestsFixture.TestStaticRegularStickerSetName, - sticker: inputSticker + new() + { + UserId = classFixture.OwnerUserId, + Name = classFixture.TestStaticRegularStickerSetName, + Sticker = inputSticker, + } ); await Task.Delay(1_000); StickerSet stickerSet = await BotClient.GetStickerSetAsync( - name: _stickersTestsFixture.TestStaticRegularStickerSetName + new GetStickerSetRequest { Name = classFixture.TestStaticRegularStickerSetName } ); Assert.False(stickerSet.IsAnimated); Assert.False(stickerSet.IsVideo); - Assert.True(stickerSet.Stickers.Length == 3); + Assert.Equal(3, stickerSet.Stickers.Length); Sticker thirdSticker = stickerSet.Stickers[2]; - string thirdEmojisString = string.Join(string.Empty, _stickersTestsFixture.ThirdEmojis); + string thirdEmojisString = string.Concat(classFixture.ThirdEmojis); Assert.Equal(thirdEmojisString, thirdSticker.Emoji); Assert.False(thirdSticker.IsAnimated); @@ -389,34 +405,37 @@ public async Task Should_Add_Sticker_To_Static_Sticker_Set() [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.GetStickerSet)] public async Task Should_Add_Sticker_To_Animated_Sticker_Set() { - using System.IO.Stream stream = System.IO.File.OpenRead( + await using System.IO.Stream stream = System.IO.File.OpenRead( Constants.PathToFile.Sticker.Regular.AnimatedThird ); - InputSticker inputSticker = new InputSticker( - sticker: new InputFileStream(stream, "Animated3.tgs"), - emojiList: _stickersTestsFixture.ThirdEmojis + InputSticker inputSticker = new( + sticker: InputFile.FromStream(stream, "Animated3.tgs"), + emojiList: classFixture.ThirdEmojis ); await BotClient.AddStickerToSetAsync( - userId: _stickersTestsFixture.OwnerUserId, - name: _stickersTestsFixture.TestAnimatedRegularStickerSetName, - sticker: inputSticker + new() + { + UserId = classFixture.OwnerUserId, + Name = classFixture.TestAnimatedRegularStickerSetName, + Sticker = inputSticker, + } ); await Task.Delay(1_000); StickerSet stickerSet = await BotClient.GetStickerSetAsync( - name: _stickersTestsFixture.TestAnimatedRegularStickerSetName + new GetStickerSetRequest { Name = classFixture.TestAnimatedRegularStickerSetName } ); Assert.True(stickerSet.IsAnimated); Assert.False(stickerSet.IsVideo); - Assert.True(stickerSet.Stickers.Length == 3); + Assert.Equal(3, stickerSet.Stickers.Length); Sticker thirdSticker = stickerSet.Stickers[2]; - string thirdEmojisString = string.Join(string.Empty, _stickersTestsFixture.ThirdEmojis); + string thirdEmojisString = string.Concat(classFixture.ThirdEmojis); Assert.Equal(thirdEmojisString, thirdSticker.Emoji); Assert.True(thirdSticker.IsAnimated); @@ -428,34 +447,37 @@ public async Task Should_Add_Sticker_To_Animated_Sticker_Set() [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.GetStickerSet)] public async Task Should_Add_Sticker_To_Video_Sticker_Set() { - using System.IO.Stream stream = System.IO.File.OpenRead( + await using System.IO.Stream stream = System.IO.File.OpenRead( Constants.PathToFile.Sticker.Regular.VideoThird ); - InputSticker inputSticker = new InputSticker( - sticker: new InputFileStream(stream, "Video3.webm"), - emojiList: _stickersTestsFixture.ThirdEmojis + InputSticker inputSticker = new( + sticker: InputFile.FromStream(stream, "Video3.webm"), + emojiList: classFixture.ThirdEmojis ); await BotClient.AddStickerToSetAsync( - userId: _stickersTestsFixture.OwnerUserId, - name: _stickersTestsFixture.TestVideoRegularStickerSetName, - sticker: inputSticker + new() + { + UserId = classFixture.OwnerUserId, + Name = classFixture.TestVideoRegularStickerSetName, + Sticker = inputSticker, + } ); await Task.Delay(1_000); StickerSet stickerSet = await BotClient.GetStickerSetAsync( - name: _stickersTestsFixture.TestVideoRegularStickerSetName + new GetStickerSetRequest { Name = classFixture.TestVideoRegularStickerSetName } ); Assert.False(stickerSet.IsAnimated); Assert.True(stickerSet.IsVideo); - Assert.True(stickerSet.Stickers.Length == 3); + Assert.Equal(3, stickerSet.Stickers.Length); Sticker thirdSticker = stickerSet.Stickers[2]; - string thirdEmojisString = string.Join(string.Empty, _stickersTestsFixture.ThirdEmojis); + string thirdEmojisString = string.Concat(classFixture.ThirdEmojis); Assert.Equal(thirdEmojisString, thirdSticker.Emoji); Assert.False(thirdSticker.IsAnimated); @@ -470,20 +492,23 @@ public async Task Should_Add_Sticker_To_Video_Sticker_Set() public async Task Should_Change_Sticker_Position_In_Set() { StickerSet stickerSet = await BotClient.GetStickerSetAsync( - name: _stickersTestsFixture.TestStaticRegularStickerSetName + new GetStickerSetRequest { Name = classFixture.TestStaticRegularStickerSetName } ); Sticker thirdSticker = stickerSet.Stickers[2]; await BotClient.SetStickerPositionInSetAsync( - sticker: new InputFileId(thirdSticker.FileId), - position: 0 + new() + { + Sticker = InputFile.FromFileId(thirdSticker.FileId), + Position = 0, + } ); await Task.Delay(1_000); StickerSet positionedStickerSet = await BotClient.GetStickerSetAsync( - name: _stickersTestsFixture.TestStaticRegularStickerSetName + new GetStickerSetRequest { Name = classFixture.TestStaticRegularStickerSetName } ); Sticker firstStickerInPositionedStickerSet = positionedStickerSet.Stickers.First(); @@ -499,19 +524,20 @@ public async Task Should_Change_Sticker_Position_In_Set() public async Task Should_Delete_Sticker_From_Set() { StickerSet stickerSet = await BotClient.GetStickerSetAsync( - name: _stickersTestsFixture.TestStaticRegularStickerSetName + new GetStickerSetRequest { Name = classFixture.TestStaticRegularStickerSetName } ); Sticker thirdSticker = stickerSet.Stickers[2]; await BotClient.DeleteStickerFromSetAsync( - sticker: new InputFileId(thirdSticker.FileId) + new DeleteStickerFromSetRequest { Sticker = InputFile.FromFileId(thirdSticker.FileId )} + ); await Task.Delay(1_000); StickerSet updatedStickerSet = await BotClient.GetStickerSetAsync( - name: _stickersTestsFixture.TestStaticRegularStickerSetName + new GetStickerSetRequest { Name = classFixture.TestStaticRegularStickerSetName } ); Assert.DoesNotContain(updatedStickerSet.Stickers, s => s.FileId == thirdSticker.FileId); @@ -525,29 +551,32 @@ public async Task Should_Delete_Sticker_From_Set() public async Task Should_Set_First_Sticker_EmojiList() { StickerSet stickerSet = await BotClient.GetStickerSetAsync( - name: _stickersTestsFixture.TestStaticRegularStickerSetName + new GetStickerSetRequest { Name = classFixture.TestStaticRegularStickerSetName } ); Sticker firstSticker = stickerSet.Stickers.First(); - string thirdEmojisString = string.Join(string.Empty, _stickersTestsFixture.ThirdEmojis); + string thirdEmojisString = string.Concat(classFixture.ThirdEmojis); Assert.Equal(thirdEmojisString, firstSticker.Emoji); await BotClient.SetStickerEmojiListAsync( - sticker: new InputFileId(firstSticker.FileId), - emojiList: _stickersTestsFixture.FirstEmojis + new() + { + Sticker = InputFile.FromFileId(firstSticker.FileId), + EmojiList = classFixture.FirstEmojis, + } ); await Task.Delay(1_000); StickerSet updatedStickerSet = await BotClient.GetStickerSetAsync( - name: _stickersTestsFixture.TestStaticRegularStickerSetName + new GetStickerSetRequest { Name = classFixture.TestStaticRegularStickerSetName } ); Sticker updatedFirstSticker = updatedStickerSet.Stickers.First(); - string firstEmojisString = string.Join(string.Empty, _stickersTestsFixture.FirstEmojis); + string firstEmojisString = string.Concat(classFixture.FirstEmojis); Assert.Equal(firstEmojisString, updatedFirstSticker.Emoji); } @@ -559,24 +588,30 @@ public async Task Should_Set_First_Sticker_EmojiList() [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.GetStickerSet)] public async Task Should_Set_First_Sticker_Keywords() { - string[] keywords = new[] { "test", "supertest" }; + string[] keywords = ["test", "supertest"]; StickerSet stickerSet = await BotClient.GetStickerSetAsync( - name: _stickersTestsFixture.TestStaticRegularStickerSetName + new GetStickerSetRequest { Name = classFixture.TestStaticRegularStickerSetName } ); Sticker firstSticker = stickerSet.Stickers.First(); await BotClient.SetStickerKeywordsAsync( - sticker: new InputFileId(firstSticker.FileId), - keywords: keywords + new SetStickerKeywordsRequest + { + Sticker = InputFile.FromFileId(firstSticker.FileId), + Keywords = keywords, + } ); await Task.Delay(1_000); await BotClient.SetStickerKeywordsAsync( - sticker: new InputFileId(firstSticker.FileId), - keywords: null + new SetStickerKeywordsRequest + { + Sticker = InputFile.FromFileId(firstSticker.FileId), + Keywords = null, + } ); } #endregion @@ -590,14 +625,17 @@ public async Task Should_Set_Sticker_Set_Title() const string newStickerSetTitle = "New title for sticker set"; await BotClient.SetStickerSetTitleAsync( - name: _stickersTestsFixture.TestStaticRegularStickerSetName, - title: newStickerSetTitle + new() + { + Name = classFixture.TestStaticRegularStickerSetName, + Title = newStickerSetTitle, + } ); await Task.Delay(1_000); StickerSet stickerSet = await BotClient.GetStickerSetAsync( - name: _stickersTestsFixture.TestStaticRegularStickerSetName + new GetStickerSetRequest { Name = classFixture.TestStaticRegularStickerSetName } ); Assert.Equal(newStickerSetTitle, stickerSet.Title); @@ -610,20 +648,23 @@ public async Task Should_Set_Sticker_Set_Title() [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.GetStickerSet)] public async Task Should_Set_Sticker_Set_Thumbnail() { - using System.IO.Stream stream = System.IO.File.OpenRead( + await using System.IO.Stream stream = System.IO.File.OpenRead( Constants.PathToFile.Sticker.Regular.StaticThumbnail ); await BotClient.SetStickerSetThumbnailAsync( - name: _stickersTestsFixture.TestStaticRegularStickerSetName, - userId: _stickersTestsFixture.OwnerUserId, - thumbnail: new InputFileStream(stream) + new() + { + Name = classFixture.TestStaticRegularStickerSetName, + UserId = classFixture.OwnerUserId, + Thumbnail = InputFile.FromStream(stream), + } ); await Task.Delay(1_000); StickerSet updatedStickerSet = await BotClient.GetStickerSetAsync( - name: _stickersTestsFixture.TestStaticRegularStickerSetName + new GetStickerSetRequest { Name = classFixture.TestStaticRegularStickerSetName } ); Assert.NotNull(updatedStickerSet.Thumbnail); @@ -632,66 +673,69 @@ public async Task Should_Set_Sticker_Set_Thumbnail() #endregion #region 11. Some exceptions - [OrderedFact("Should throw " + nameof(ApiRequestException) + - " while trying to create sticker set with name not ending in _by_")] + [OrderedFact($"Should throw {nameof(ApiRequestException)} while trying to create sticker set with name not ending in _by_")] [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.CreateNewStickerSet)] public async Task Should_Throw_InvalidStickerSetNameException() { const string expectedExceptionMessage = "Bad Request: invalid sticker set name is specified"; - List inputStickers = new List - { - new InputSticker( - sticker: new InputFileId(_stickersTestsFixture.TestUploadedStaticStickerFile.FileId), - emojiList: _stickersTestsFixture.FirstEmojis + List inputStickers = + [ + new( + sticker: InputFile.FromFileId(classFixture.TestUploadedStaticStickerFile.FileId), + emojiList: classFixture.FirstEmojis ) - }; + ]; ApiRequestException exception = await Assert.ThrowsAsync(() => BotClient.CreateNewStickerSetAsync( - userId: _stickersTestsFixture.OwnerUserId, - name: "Invalid_Sticker_Set_Name", - title: _stickersTestsFixture.TestStickerSetTitle, - stickers: inputStickers, - stickerFormat: StickerFormat.Static + new() + { + UserId = classFixture.OwnerUserId, + Name = "Invalid_Sticker_Set_Name", + Title = classFixture.TestStickerSetTitle, + Stickers = inputStickers, + StickerFormat = StickerFormat.Static, + } ) ); Assert.Equal(expectedExceptionMessage, exception.Message); } - [OrderedFact("Should throw " + nameof(ApiRequestException) + - " while trying to create sticker with invalid emoji")] + [OrderedFact($"Should throw {nameof(ApiRequestException)} while trying to create sticker with invalid emoji")] [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.CreateNewStickerSet)] public async Task Should_Throw_InvalidStickerEmojisException() { const string expectedExceptionMessage = "Bad Request: can't parse InputSticker: expected a Unicode emoji"; - string[] invalidEmojis = new[] { "INVALID" }; + string[] invalidEmojis = ["INVALID"]; - List inputStickers = new List - { - new InputSticker( - sticker: new InputFileId(_stickersTestsFixture.TestUploadedStaticStickerFile.FileId), + List inputStickers = + [ + new( + sticker: InputFile.FromFileId(classFixture.TestUploadedStaticStickerFile.FileId), emojiList: invalidEmojis ) - }; + ]; ApiRequestException exception = await Assert.ThrowsAsync(() => BotClient.CreateNewStickerSetAsync( - userId: _stickersTestsFixture.OwnerUserId, - name: _stickersTestsFixture.TestStaticRegularStickerSetName, - title: _stickersTestsFixture.TestStickerSetTitle, - stickers: inputStickers, - stickerFormat: StickerFormat.Static + new() + { + UserId = classFixture.OwnerUserId, + Name = classFixture.TestStaticRegularStickerSetName, + Title = classFixture.TestStickerSetTitle, + Stickers = inputStickers, + StickerFormat = StickerFormat.Static, + } ) ); Assert.Equal(expectedExceptionMessage, exception.Message); } - [OrderedFact("Should throw " + nameof(ApiRequestException) + - " while trying to create sticker with invalid dimensions")] + [OrderedFact($"Should throw {nameof(ApiRequestException)} while trying to create sticker with invalid dimensions")] [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.CreateNewStickerSet)] public async Task Should_Throw_InvalidStickerDimensionsException() { @@ -699,115 +743,121 @@ public async Task Should_Throw_InvalidStickerDimensionsException() const string expectedExceptionMessage = "Bad Request: STICKER_PNG_DIMENSIONS"; - using System.IO.Stream stream = System.IO.File.OpenRead(Constants.PathToFile.Photos.Logo); + await using System.IO.Stream stream = System.IO.File.OpenRead(Constants.PathToFile.Photos.Logo); - List inputStickers = new List - { - new InputSticker( - sticker: new InputFileStream(stream, "logo.png"), - emojiList: _stickersTestsFixture.FirstEmojis + List inputStickers = + [ + new( + sticker: InputFile.FromStream(stream, "logo.png"), + emojiList: classFixture.FirstEmojis ) - }; + ]; //New name, because an exception might be thrown: Bad Request: sticker set name is already occupied - string newStickerSetName = $"new_{_stickersTestsFixture.TestStaticRegularStickerSetName}"; + string newStickerSetName = $"new_{classFixture.TestStaticRegularStickerSetName}"; ApiRequestException exception = await Assert.ThrowsAsync(() => BotClient.CreateNewStickerSetAsync( - userId: _stickersTestsFixture.OwnerUserId, - name: newStickerSetName, - title: _stickersTestsFixture.TestStickerSetTitle, - stickers: inputStickers, - stickerFormat: StickerFormat.Static + new() + { + UserId = classFixture.OwnerUserId, + Name = newStickerSetName, + Title = classFixture.TestStickerSetTitle, + Stickers = inputStickers, + StickerFormat = StickerFormat.Static, + } ) ); Assert.Equal(expectedExceptionMessage, exception.Message); } - [OrderedFact("Should throw " + nameof(ApiRequestException) + - " while trying to create sticker with invalid file size")] + [OrderedFact($"Should throw {nameof(ApiRequestException)} while trying to create sticker with invalid file size")] [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.CreateNewStickerSet)] public async Task Should_Throw_InvalidFileSizeException() { const string expectedExceptionMessage = "Bad Request: file is too big"; - using System.IO.Stream stream = System.IO.File.OpenRead(Constants.PathToFile.Photos.Apes); + await using System.IO.Stream stream = System.IO.File.OpenRead(Constants.PathToFile.Photos.Apes); - List inputStickers = new List - { - new InputSticker( - sticker: new InputFileStream(stream, "apes.jpg"), - emojiList: _stickersTestsFixture.FirstEmojis + List inputStickers = + [ + new( + sticker: InputFile.FromStream(stream, "apes.jpg"), + emojiList: classFixture.FirstEmojis ) - }; + ]; ApiRequestException exception = await Assert.ThrowsAsync(() => BotClient.CreateNewStickerSetAsync( - userId: _stickersTestsFixture.OwnerUserId, - name: _stickersTestsFixture.TestStaticRegularStickerSetName, - title: _stickersTestsFixture.TestStickerSetTitle, - stickers: inputStickers, - stickerFormat: StickerFormat.Static + new() + { + UserId = classFixture.OwnerUserId, + Name = classFixture.TestStaticRegularStickerSetName, + Title = classFixture.TestStickerSetTitle, + Stickers = inputStickers, + StickerFormat = StickerFormat.Static, + } ) ); Assert.Equal(expectedExceptionMessage, exception.Message); } - [OrderedFact("Should throw " + nameof(ApiRequestException) + - " while trying to create sticker set with the same name with ruby photo", Skip = "Bot API Bug")] + [OrderedFact($"Should throw {nameof(ApiRequestException)} while trying to create sticker set with the same name with ruby photo", + Skip = "Bot API Bug")] [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.CreateNewStickerSet)] public async Task Should_Throw_StickerSetNameExistsException() { - const string expectedExceptionMessage = "Bad Request: sticker set name is already occupied"; - using System.IO.Stream stream = System.IO.File.OpenRead(Constants.PathToFile.Photos.Ruby); + await using System.IO.Stream stream = System.IO.File.OpenRead(Constants.PathToFile.Photos.Ruby); - List inputStickers = new List - { - new InputSticker( - sticker: new InputFileStream(stream, "ruby.png"), - emojiList: _stickersTestsFixture.FirstEmojis + List inputStickers = + [ + new( + sticker: InputFile.FromStream(stream, "ruby.png"), + emojiList: classFixture.FirstEmojis ) - }; + ]; // Telegram for some reason does not return an error, so the test is skipped ApiRequestException exception = await Assert.ThrowsAsync(() => BotClient.CreateNewStickerSetAsync( - userId: _stickersTestsFixture.OwnerUserId, - name: _stickersTestsFixture.TestStaticRegularStickerSetName, - title: _stickersTestsFixture.TestStickerSetTitle, - stickers: inputStickers, - stickerFormat: StickerFormat.Static + new() + { + UserId = classFixture.OwnerUserId, + Name = classFixture.TestStaticRegularStickerSetName, + Title = classFixture.TestStickerSetTitle, + Stickers = inputStickers, + StickerFormat = StickerFormat.Static, + } ) ); Assert.Equal(expectedExceptionMessage, exception.Message); } - [OrderedFact("Should throw " + nameof(ApiRequestException) + - " while trying to remove the last sticker in the set twice")] + [OrderedFact($"Should throw {nameof(ApiRequestException)} while trying to remove the last sticker in the set twice")] [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.GetStickerSet)] [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.DeleteStickerFromSet)] public async Task Should_Throw_StickerSetNotModifiedException() { const string expectedExceptionMessage = "Bad Request: STICKERSET_NOT_MODIFIED"; - StickerSet stickerSet = await BotClient.GetStickerSetAsync( - name: _stickersTestsFixture.TestStaticRegularStickerSetName - ); + StickerSet stickerSet = await BotClient.GetStickerSetAsync(new GetStickerSetRequest { Name = classFixture.TestStaticRegularStickerSetName }); Sticker lastSticker = stickerSet.Stickers.Last(); await BotClient.DeleteStickerFromSetAsync( - sticker: new InputFileId(lastSticker.FileId) + new DeleteStickerFromSetRequest { Sticker = InputFile.FromFileId(lastSticker.FileId) } ); - ApiRequestException exception = await Assert.ThrowsAsync(() => - BotClient.DeleteStickerFromSetAsync( - sticker: new InputFileId(lastSticker.FileId) + await Task.Delay(TimeSpan.FromSeconds(10)); + + ApiRequestException exception = await Assert.ThrowsAsync(async () => + await BotClient.DeleteStickerFromSetAsync( + new DeleteStickerFromSetRequest { Sticker = new(lastSticker.FileId) } ) ); @@ -823,36 +873,22 @@ public async Task Should_Delete_Sticker_Sets() { const string expectedExceptionMessage = "Bad Request: STICKERSET_INVALID"; - await BotClient.DeleteStickerSetAsync( - name: _stickersTestsFixture.TestStaticRegularStickerSetName - ); - - await BotClient.DeleteStickerSetAsync( - name: _stickersTestsFixture.TestAnimatedRegularStickerSetName - ); - - await BotClient.DeleteStickerSetAsync( - name: _stickersTestsFixture.TestVideoRegularStickerSetName - ); + await BotClient.DeleteStickerSetAsync(new DeleteStickerSetRequest { Name = classFixture.TestStaticRegularStickerSetName }); + await BotClient.DeleteStickerSetAsync(new DeleteStickerSetRequest { Name = classFixture.TestAnimatedRegularStickerSetName }); + await BotClient.DeleteStickerSetAsync(new DeleteStickerSetRequest { Name = classFixture.TestVideoRegularStickerSetName }); await Task.Delay(1_000); ApiRequestException staticException = await Assert.ThrowsAsync(() => - BotClient.GetStickerSetAsync( - name: _stickersTestsFixture.TestStaticRegularStickerSetName - ) + BotClient.GetStickerSetAsync(new GetStickerSetRequest { Name = classFixture.TestStaticRegularStickerSetName }) ); ApiRequestException animatedException = await Assert.ThrowsAsync(() => - BotClient.GetStickerSetAsync( - name: _stickersTestsFixture.TestAnimatedRegularStickerSetName - ) + BotClient.GetStickerSetAsync(new GetStickerSetRequest { Name = classFixture.TestAnimatedRegularStickerSetName }) ); ApiRequestException videoException = await Assert.ThrowsAsync(() => - BotClient.GetStickerSetAsync( - name: _stickersTestsFixture.TestVideoRegularStickerSetName - ) + BotClient.GetStickerSetAsync(new GetStickerSetRequest { Name = classFixture.TestVideoRegularStickerSetName }) ); Assert.Equal(expectedExceptionMessage, staticException.Message); @@ -862,43 +898,44 @@ public async Task Should_Delete_Sticker_Sets() #endregion #region 13. Mask tests - [OrderedFact("Shound create new mask static sticker set")] + [OrderedFact("Should create new mask static sticker set")] [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.CreateNewStickerSet)] [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.GetStickerSet)] public async Task Should_Create_New_Mask_Static_Sticker_Set() { - List inputStickers = new List(1); - - using System.IO.Stream stream = System.IO.File.OpenRead( + await using System.IO.Stream stream = System.IO.File.OpenRead( Constants.PathToFile.Photos.Tux ); - inputStickers.Add( - new InputSticker( - sticker: new InputFileStream(stream, "tux.png"), - emojiList: _stickersTestsFixture.SecondEmojis + List inputStickers = [ + new( + sticker: InputFile.FromStream(stream, "tux.png"), + emojiList: classFixture.SecondEmojis ) - ); + ]; await BotClient.CreateNewStickerSetAsync( - userId: _stickersTestsFixture.OwnerUserId, - name: _stickersTestsFixture.TestStaticMaskStickerSetName, - title: _stickersTestsFixture.TestStickerSetTitle, - stickers: inputStickers, - stickerFormat: StickerFormat.Static, - stickerType: StickerType.Mask + new() + { + UserId = classFixture.OwnerUserId, + Name = classFixture.TestStaticMaskStickerSetName, + Title = classFixture.TestStickerSetTitle, + Stickers = inputStickers, + StickerFormat = StickerFormat.Static, + StickerType = StickerType.Mask, + } ); await Task.Delay(1_000); - _stickersTestsFixture.TestStaticMaskStickerSet = await BotClient.GetStickerSetAsync( - name: _stickersTestsFixture.TestStaticMaskStickerSetName + classFixture.TestStaticMaskStickerSet = await BotClient.GetStickerSetAsync( + new GetStickerSetRequest { Name = classFixture.TestStaticMaskStickerSetName } ); - Assert.Equal(StickerType.Mask, _stickersTestsFixture.TestStaticMaskStickerSet.StickerType); - Assert.False(_stickersTestsFixture.TestStaticMaskStickerSet.IsAnimated); - Assert.False(_stickersTestsFixture.TestStaticMaskStickerSet.IsVideo); - Assert.True(_stickersTestsFixture.TestStaticMaskStickerSet.Stickers.Length == 1); + Assert.Equal(StickerType.Mask, classFixture.TestStaticMaskStickerSet.StickerType); + Assert.False(classFixture.TestStaticMaskStickerSet.IsAnimated); + Assert.False(classFixture.TestStaticMaskStickerSet.IsVideo); + Assert.Single(classFixture.TestStaticMaskStickerSet.Stickers); } [OrderedFact("Should add VLC logo sticker with mask position like hat on forehead")] @@ -906,15 +943,14 @@ public async Task Should_Create_New_Mask_Static_Sticker_Set() [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.GetStickerSet)] public async Task Should_Add_Sticker_With_Mask_Position_To_Set() { + await using System.IO.Stream stream = System.IO.File.OpenRead(Constants.PathToFile.Photos.Vlc); - using System.IO.Stream stream = System.IO.File.OpenRead(Constants.PathToFile.Photos.Vlc); - - InputSticker inputSticker = new InputSticker( - sticker: new InputFileStream(stream, "vlc.png"), - emojiList: _stickersTestsFixture.SecondEmojis + InputSticker inputSticker = new( + sticker: InputFile.FromStream(stream, "vlc.png"), + emojiList: classFixture.SecondEmojis ) { - MaskPosition = new MaskPosition + MaskPosition = new() { Point = MaskPositionPoint.Forehead, Scale = .8f @@ -922,21 +958,24 @@ public async Task Should_Add_Sticker_With_Mask_Position_To_Set() }; await BotClient.AddStickerToSetAsync( - userId: _stickersTestsFixture.OwnerUserId, - name: _stickersTestsFixture.TestStaticMaskStickerSetName, - sticker: inputSticker + new() + { + UserId = classFixture.OwnerUserId, + Name = classFixture.TestStaticMaskStickerSetName, + Sticker = inputSticker, + } ); await Task.Delay(1_000); StickerSet stickerSet = await BotClient.GetStickerSetAsync( - name: _stickersTestsFixture.TestStaticMaskStickerSetName + new GetStickerSetRequest { Name = classFixture.TestStaticMaskStickerSetName } ); Assert.Equal(StickerType.Mask, stickerSet.StickerType); Assert.False(stickerSet.IsAnimated); Assert.False(stickerSet.IsVideo); - Assert.True(stickerSet.Stickers.Length == 2); + Assert.Equal(2, stickerSet.Stickers.Length); Sticker sticker = stickerSet.Stickers.Last(); @@ -949,27 +988,30 @@ public async Task Should_Add_Sticker_With_Mask_Position_To_Set() [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.AddStickerToSet)] public async Task Should_Set_Mask_Position_From_Last_Sticker() { - MaskPosition newMaskPosition = new MaskPosition + MaskPosition newMaskPosition = new() { Point = MaskPositionPoint.Chin, Scale = .42f }; StickerSet stickerSet = await BotClient.GetStickerSetAsync( - name: _stickersTestsFixture.TestStaticMaskStickerSetName + new GetStickerSetRequest { Name = classFixture.TestStaticMaskStickerSetName } ); Sticker sticker = stickerSet.Stickers.First(); await BotClient.SetStickerMaskPositionAsync( - sticker: new InputFileId(sticker.FileId), - maskPosition: newMaskPosition + new SetStickerMaskPositionRequest + { + Sticker = InputFile.FromFileId(sticker.FileId), + MaskPosition = newMaskPosition, + } ); await Task.Delay(1_000); StickerSet changedStickerSet = await BotClient.GetStickerSetAsync( - name: _stickersTestsFixture.TestStaticMaskStickerSetName + new GetStickerSetRequest { Name = classFixture.TestStaticMaskStickerSetName } ); Sticker changedSticker = changedStickerSet.Stickers.First(); @@ -987,15 +1029,13 @@ public async Task Should_Delete_Mask_Sticker_Set() const string expectedExceptionMessage = "Bad Request: STICKERSET_INVALID"; await BotClient.DeleteStickerSetAsync( - name: _stickersTestsFixture.TestStaticMaskStickerSetName + new DeleteStickerSetRequest { Name = classFixture.TestStaticMaskStickerSetName } ); - await Task.Delay(1_000); + await Task.Delay(TimeSpan.FromSeconds(10)); ApiRequestException exception = await Assert.ThrowsAsync(() => - BotClient.GetStickerSetAsync( - name: _stickersTestsFixture.TestStaticMaskStickerSetName - ) + BotClient.GetStickerSetAsync(new GetStickerSetRequest { Name = classFixture.TestStaticMaskStickerSetName }) ); Assert.Equal(expectedExceptionMessage, exception.Message); @@ -1003,43 +1043,45 @@ public async Task Should_Delete_Mask_Sticker_Set() #endregion #region 14. Custom emoji tests - [OrderedFact("Shound create new custom emoji static sticker set")] + [OrderedFact("Should create new custom emoji static sticker set")] [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.CreateNewStickerSet)] [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.GetStickerSet)] public async Task Should_Create_New_Custom_Emoji_Static_Sticker_Set() { - List inputStickers = new List(1); - - using System.IO.Stream stream = System.IO.File.OpenRead( + await using System.IO.Stream stream = System.IO.File.OpenRead( Constants.PathToFile.Sticker.CustomEmoji.StaticFirst ); - inputStickers.Add( - new InputSticker( - sticker: new InputFileStream(stream, "Static1.png"), - emojiList: _stickersTestsFixture.FirstEmojis + List inputStickers = + [ + new( + sticker: InputFile.FromStream(stream, "Static1.png"), + emojiList: classFixture.FirstEmojis ) - ); + ]; await BotClient.CreateNewStickerSetAsync( - userId: _stickersTestsFixture.OwnerUserId, - name: _stickersTestsFixture.TestStaticCustomEmojiStickerSetName, - title: _stickersTestsFixture.TestStickerSetTitle, - stickers: inputStickers, - stickerFormat: StickerFormat.Static, - stickerType: StickerType.CustomEmoji + new() + { + UserId = classFixture.OwnerUserId, + Name = classFixture.TestStaticCustomEmojiStickerSetName, + Title = classFixture.TestStickerSetTitle, + Stickers = inputStickers, + StickerFormat = StickerFormat.Static, + StickerType = StickerType.CustomEmoji, + } ); await Task.Delay(1_000); - _stickersTestsFixture.TestStaticCustomEmojiStickerSet = await BotClient.GetStickerSetAsync( - name: _stickersTestsFixture.TestStaticCustomEmojiStickerSetName + classFixture.TestStaticCustomEmojiStickerSet = await BotClient.GetStickerSetAsync( + new GetStickerSetRequest { Name = classFixture.TestStaticCustomEmojiStickerSetName } ); - Assert.Equal(StickerType.CustomEmoji, _stickersTestsFixture.TestStaticCustomEmojiStickerSet.StickerType); - Assert.False(_stickersTestsFixture.TestStaticCustomEmojiStickerSet.IsAnimated); - Assert.False(_stickersTestsFixture.TestStaticCustomEmojiStickerSet.IsVideo); - Assert.True(_stickersTestsFixture.TestStaticCustomEmojiStickerSet.Stickers.Length == 1); + Assert.Equal(StickerType.CustomEmoji, classFixture.TestStaticCustomEmojiStickerSet.StickerType); + Assert.False(classFixture.TestStaticCustomEmojiStickerSet.IsAnimated); + Assert.False(classFixture.TestStaticCustomEmojiStickerSet.IsVideo); + Assert.Single(classFixture.TestStaticCustomEmojiStickerSet.Stickers); } [OrderedFact("Should add sticker to a custom emoji set")] @@ -1047,29 +1089,32 @@ public async Task Should_Create_New_Custom_Emoji_Static_Sticker_Set() [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.GetStickerSet)] public async Task Should_Add_Sticker_To_A_Custom_Emoji_set() { - using System.IO.Stream stream = System.IO.File.OpenRead(Constants.PathToFile.Sticker.CustomEmoji.StaticSecond); + await using System.IO.Stream stream = System.IO.File.OpenRead(Constants.PathToFile.Sticker.CustomEmoji.StaticSecond); - InputSticker inputSticker = new InputSticker( - sticker: new InputFileStream(stream, "Static2.png"), - emojiList: _stickersTestsFixture.SecondEmojis + InputSticker inputSticker = new( + sticker: InputFile.FromStream(stream, "Static2.png"), + emojiList: classFixture.SecondEmojis ); await BotClient.AddStickerToSetAsync( - userId: _stickersTestsFixture.OwnerUserId, - name: _stickersTestsFixture.TestStaticCustomEmojiStickerSetName, - sticker: inputSticker + new() + { + UserId = classFixture.OwnerUserId, + Name = classFixture.TestStaticCustomEmojiStickerSetName, + Sticker = inputSticker, + } ); await Task.Delay(1_000); StickerSet stickerSet = await BotClient.GetStickerSetAsync( - name: _stickersTestsFixture.TestStaticCustomEmojiStickerSetName + new GetStickerSetRequest { Name = classFixture.TestStaticCustomEmojiStickerSetName } ); Assert.Equal(StickerType.CustomEmoji, stickerSet.StickerType); Assert.False(stickerSet.IsAnimated); Assert.False(stickerSet.IsVideo); - Assert.True(stickerSet.Stickers.Length == 2); + Assert.Equal(2, stickerSet.Stickers.Length); Sticker sticker = stickerSet.Stickers.Last(); @@ -1082,7 +1127,7 @@ public async Task Should_Add_Sticker_To_A_Custom_Emoji_set() public async Task Should_Set_Custom_Emoji_Set_Thumbnail() { StickerSet stickerSet = await BotClient.GetStickerSetAsync( - name: _stickersTestsFixture.TestStaticCustomEmojiStickerSetName + new GetStickerSetRequest { Name = classFixture.TestStaticCustomEmojiStickerSetName } ); Sticker lastSticker = stickerSet.Stickers.Last(); @@ -1090,19 +1135,22 @@ public async Task Should_Set_Custom_Emoji_Set_Thumbnail() Assert.NotNull(lastSticker.CustomEmojiId); await BotClient.SetCustomEmojiStickerSetThumbnailAsync( - name: _stickersTestsFixture.TestStaticCustomEmojiStickerSetName, - customEmojiId: lastSticker.CustomEmojiId + new SetCustomEmojiStickerSetThumbnailRequest + { + Name = classFixture.TestStaticCustomEmojiStickerSetName, + CustomEmojiId = lastSticker.CustomEmojiId, + } ); StickerSet changedStickerSet = await BotClient.GetStickerSetAsync( - name: _stickersTestsFixture.TestStaticCustomEmojiStickerSetName + new GetStickerSetRequest { Name = classFixture.TestStaticCustomEmojiStickerSetName } ); Assert.NotNull(changedStickerSet.Thumbnail); Assert.NotNull(changedStickerSet.Thumbnail.FileSize); Assert.True(changedStickerSet.Thumbnail.FileSize > 0); - Assert.True(changedStickerSet.Thumbnail.Width == 100); - Assert.True(changedStickerSet.Thumbnail.Height == 100); + Assert.Equal(100, changedStickerSet.Thumbnail.Width); + Assert.Equal(100, changedStickerSet.Thumbnail.Height); } [OrderedFact("Should delete custom emoji sticker set")] @@ -1113,14 +1161,14 @@ public async Task Should_Delete_Custom_Emoji_Sticker_Set() const string expectedExceptionMessage = "Bad Request: STICKERSET_INVALID"; await BotClient.DeleteStickerSetAsync( - name: _stickersTestsFixture.TestStaticCustomEmojiStickerSetName + new DeleteStickerSetRequest { Name = classFixture.TestStaticCustomEmojiStickerSetName } ); await Task.Delay(1_000); ApiRequestException exception = await Assert.ThrowsAsync(() => BotClient.GetStickerSetAsync( - name: _stickersTestsFixture.TestStaticCustomEmojiStickerSetName + new GetStickerSetRequest { Name = classFixture.TestStaticCustomEmojiStickerSetName } ) ); diff --git a/test/Telegram.Bot.Tests.Integ/Stickers/StickersTestsFixture.cs b/test/Telegram.Bot.Tests.Integ/Stickers/StickersTestsFixture.cs index 0b2053569..b7aa26a00 100644 --- a/test/Telegram.Bot.Tests.Integ/Stickers/StickersTestsFixture.cs +++ b/test/Telegram.Bot.Tests.Integ/Stickers/StickersTestsFixture.cs @@ -1,76 +1,68 @@ +using System; using System.Collections.Generic; using System.Threading.Tasks; using Telegram.Bot.Tests.Integ.Framework; +using Telegram.Bot.Tests.Integ.Framework.Fixtures; using Telegram.Bot.Types; using Telegram.Bot.Types.ReplyMarkups; +using Xunit; namespace Telegram.Bot.Tests.Integ.Stickers; -public class StickersTestsFixture +public class StickersTestsFixture(TestsFixture testsFixture) : AsyncLifetimeFixture { + protected override IEnumerable> Initializers() => + [ + async () => + { + OwnerUserId = await GetStickerOwnerIdAsync( + testsFixture, + Constants.TestCollections.Stickers + ); + } + ]; + //Basic information - public string TestStickerSetTitle { get; } + public string TestStickerSetTitle => "Test sticker set"; - public long OwnerUserId { get; } + public long OwnerUserId { get; private set; } //Emojis - public IEnumerable FirstEmojis { get; } + public IEnumerable FirstEmojis { get; } = ["😊"]; - public IEnumerable SecondEmojis { get; } + public IEnumerable SecondEmojis { get; } = ["🥰", "😘"]; - public IEnumerable ThirdEmojis { get; } + public IEnumerable ThirdEmojis { get; } = ["😎"]; //Regular stickers - public string TestStaticRegularStickerSetName { get; } + public string TestStaticRegularStickerSetName { get; } = $"test_static_regular_set_by_{testsFixture.BotUser.Username}"; public File TestUploadedStaticStickerFile { get; set; } public StickerSet TestStaticRegularStickerSet { get; set; } - public string TestAnimatedRegularStickerSetName { get; } + public string TestAnimatedRegularStickerSetName { get; } = $"test_animated_regular_set_by_{testsFixture.BotUser.Username}"; public File TestUploadedAnimatedStickerFile { get; set; } public StickerSet TestAnimatedRegularStickerSet { get; set; } - public string TestVideoRegularStickerSetName { get; } + public string TestVideoRegularStickerSetName { get; } = $"test_video_regular_set_by_{testsFixture.BotUser.Username}"; public File TestUploadedVideoStickerFile { get; set; } public StickerSet TestVideoRegularStickerSet { get; set; } //Mask stickers - public string TestStaticMaskStickerSetName { get; } + public string TestStaticMaskStickerSetName { get; } = $"test_static_mask_set_by_{testsFixture.BotUser.Username}"; public StickerSet TestStaticMaskStickerSet { get; set; } //Custom emoji stickers - public string TestStaticCustomEmojiStickerSetName { get; } + public string TestStaticCustomEmojiStickerSetName { get; } = $"test_static_c_emoji_set_by_{testsFixture.BotUser.Username}"; public StickerSet TestStaticCustomEmojiStickerSet { get; set; } - public StickersTestsFixture(TestsFixture testsFixture) - { - TestStickerSetTitle = "Test sticker set"; - - OwnerUserId = GetStickerOwnerIdAsync( - testsFixture, - Constants.TestCollections.Stickers - ).GetAwaiter().GetResult(); - - FirstEmojis = new string[] { "😊" }; - SecondEmojis = new string[] { "🥰", "😘" }; - ThirdEmojis = new string[] { "😎" }; - - TestStaticRegularStickerSetName = $"test_static_regular_set_by_{testsFixture.BotUser.Username}"; - TestAnimatedRegularStickerSetName = $"test_animated_regular_set_by_{testsFixture.BotUser.Username}"; - TestVideoRegularStickerSetName = $"test_video_regular_set_by_{testsFixture.BotUser.Username}"; - - TestStaticMaskStickerSetName = $"test_static_mask_set_by_{testsFixture.BotUser.Username}"; - - TestStaticCustomEmojiStickerSetName = $"test_static_c_emoji_set_by_{testsFixture.BotUser.Username}"; - } - static async Task GetStickerOwnerIdAsync(TestsFixture testsFixture, string collectionName) { long ownerId; @@ -85,14 +77,16 @@ static async Task GetStickerOwnerIdAsync(TestsFixture testsFixture, string ); const string cqData = "sticker_tests:owner"; - Message cqMessage = await testsFixture.BotClient.SendTextMessageAsync( - testsFixture.SupergroupChat, - testsFixture.UpdateReceiver.GetTesters() + - "\nUse the following button to become Sticker Set Owner", - replyToMessageId: notificationMessage.MessageId, - replyMarkup: new InlineKeyboardMarkup( - InlineKeyboardButton.WithCallbackData("I am the Owner!", cqData) - ) + Message cqMessage = await testsFixture.BotClient.SendMessageAsync( + new() + { + ChatId = testsFixture.SupergroupChat, + Text = $"{testsFixture.UpdateReceiver.GetTesters()}\nUse the following button to become Sticker Set Owner", + ReplyParameters = new() { MessageId = notificationMessage.MessageId }, + ReplyMarkup = new InlineKeyboardMarkup( + InlineKeyboardButton.WithCallbackData("I am the Owner!", cqData) + ), + } ); Update cqUpdate = await testsFixture.UpdateReceiver diff --git a/test/Telegram.Bot.Tests.Integ/Telegram.Bot.Tests.Integ.csproj b/test/Telegram.Bot.Tests.Integ/Telegram.Bot.Tests.Integ.csproj index 2d4277b76..35477cad4 100644 --- a/test/Telegram.Bot.Tests.Integ/Telegram.Bot.Tests.Integ.csproj +++ b/test/Telegram.Bot.Tests.Integ/Telegram.Bot.Tests.Integ.csproj @@ -1,24 +1,23 @@ - net6.0 - 11 + net8.0 + 12.0 disable false - - - - - - - - - - - - - + + + + + + + + + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/test/Telegram.Bot.Tests.Integ/Update Messages/DeleteMessageTests.cs b/test/Telegram.Bot.Tests.Integ/Update Messages/DeleteMessageTests.cs index 92dabe0c6..c4ddd514e 100644 --- a/test/Telegram.Bot.Tests.Integ/Update Messages/DeleteMessageTests.cs +++ b/test/Telegram.Bot.Tests.Integ/Update Messages/DeleteMessageTests.cs @@ -1,4 +1,5 @@ using System.Threading.Tasks; +using Telegram.Bot.Requests; using Telegram.Bot.Tests.Integ.Framework; using Telegram.Bot.Types; using Telegram.Bot.Types.Enums; @@ -10,52 +11,52 @@ namespace Telegram.Bot.Tests.Integ.Update_Messages; [Collection(Constants.TestCollections.DeleteMessage)] [Trait(Constants.CategoryTraitName, Constants.InteractiveCategoryValue)] [TestCaseOrderer(Constants.TestCaseOrderer, Constants.AssemblyName)] -public class DeleteMessageTests +public class DeleteMessageTests(TestsFixture fixture) { - ITelegramBotClient BotClient => _fixture.BotClient; - - readonly TestsFixture _fixture; - - public DeleteMessageTests(TestsFixture fixture) - { - _fixture = fixture; - } + ITelegramBotClient BotClient => fixture.BotClient; [OrderedFact("Should delete message generated from an inline query result")] [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.AnswerInlineQuery)] public async Task Should_Delete_Message_From_InlineQuery() { - await _fixture.SendTestInstructionsAsync( + await fixture.SendTestInstructionsAsync( "Starting the inline query with this message...", startInlineQuery: true ); - Update queryUpdate = await _fixture.UpdateReceiver.GetInlineQueryUpdateAsync(); + Update queryUpdate = await fixture.UpdateReceiver.GetInlineQueryUpdateAsync(); await BotClient.AnswerInlineQueryAsync( - inlineQueryId: queryUpdate.InlineQuery!.Id, - results: new[] - { - new InlineQueryResultArticle( - id: "article-to-delete", - title: "Telegram Bot API", - inputMessageContent: new InputTextMessageContent("https://www.telegram.org/") - ) - }, - cacheTime: 0 + new() + { + InlineQueryId = queryUpdate.InlineQuery!.Id, + Results = new[] + { + new InlineQueryResultArticle + { + Id = "article-to-delete", + Title = "Telegram Bot API", + InputMessageContent = new InputTextMessageContent { MessageText = "https://www.telegram.org/"}, + } + }, + CacheTime = 0, + } ); (Update messageUpdate, _) = - await _fixture.UpdateReceiver.GetInlineQueryResultUpdates( - chatId: _fixture.SupergroupChat.Id, + await fixture.UpdateReceiver.GetInlineQueryResultUpdates( + chatId: fixture.SupergroupChat.Id, messageType: MessageType.Text ); await Task.Delay(1_000); await BotClient.DeleteMessageAsync( - chatId: messageUpdate.Message!.Chat.Id, - messageId: messageUpdate.Message.MessageId + new() + { + ChatId = messageUpdate.Message!.Chat.Id, + MessageId = messageUpdate.Message.MessageId, + } ); } -} \ No newline at end of file +} diff --git a/test/Telegram.Bot.Tests.Integ/Update Messages/DeleteMessageTests2.cs b/test/Telegram.Bot.Tests.Integ/Update Messages/DeleteMessageTests2.cs index 74296bcd8..79964fe39 100644 --- a/test/Telegram.Bot.Tests.Integ/Update Messages/DeleteMessageTests2.cs +++ b/test/Telegram.Bot.Tests.Integ/Update Messages/DeleteMessageTests2.cs @@ -7,32 +7,67 @@ namespace Telegram.Bot.Tests.Integ.Update_Messages; [Collection(Constants.TestCollections.DeleteMessage2)] [TestCaseOrderer(Constants.TestCaseOrderer, Constants.AssemblyName)] -public class DeleteMessageTests2 +public class DeleteMessageTests2(TestsFixture fixture) { - ITelegramBotClient BotClient => _fixture.BotClient; + ITelegramBotClient BotClient => fixture.BotClient; - readonly TestsFixture _fixture; - - public DeleteMessageTests2(TestsFixture fixture) - { - _fixture = fixture; - } [OrderedFact("Should delete message")] [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.SendMessage)] [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.DeleteMessage)] public async Task Should_Delete_Message() { - Message message = await BotClient.SendTextMessageAsync( - chatId: _fixture.SupergroupChat.Id, - text: "This message will be deleted shortly" + Message message = await BotClient.SendMessageAsync( + new() + { + ChatId = fixture.SupergroupChat.Id, + Text = "This message will be deleted shortly", + } ); await Task.Delay(1_000); await BotClient.DeleteMessageAsync( - chatId: message.Chat.Id, - messageId: message.MessageId + new() + { + ChatId = message.Chat.Id, + MessageId = message.MessageId, + } + ); + } + + [OrderedFact("Should delete messages")] + [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.SendMessage)] + [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.DeleteMessages)] + public async Task Should_Delete_Messages() + { + Message message1 = await BotClient.SendMessageAsync( + new() + { + ChatId = fixture.SupergroupChat.Id, + Text = "Message one.\nThis message will be deleted shortly", + } + ); + + Message message2 = await BotClient.SendMessageAsync( + new() + { + ChatId = fixture.SupergroupChat.Id, + Text = "Message two.\nThis message will be deleted shortly", + } + ); + + int[] messageIds = [message1.MessageId, message2.MessageId]; + + await Task.Delay(1_000); + + await BotClient.DeleteMessagesAsync( + new() + { + ChatId = fixture.SupergroupChat.Id, + MessageIds = messageIds, + } ); } -} \ No newline at end of file + +} diff --git a/test/Telegram.Bot.Tests.Integ/Update Messages/EditMessageContentTests.cs b/test/Telegram.Bot.Tests.Integ/Update Messages/EditMessageContentTests.cs index 6c9eb2cbf..c26711d53 100644 --- a/test/Telegram.Bot.Tests.Integ/Update Messages/EditMessageContentTests.cs +++ b/test/Telegram.Bot.Tests.Integ/Update Messages/EditMessageContentTests.cs @@ -1,6 +1,7 @@ using System; using System.Linq; using System.Threading.Tasks; +using Telegram.Bot.Requests; using Telegram.Bot.Tests.Integ.Framework; using Telegram.Bot.Types; using Telegram.Bot.Types.Enums; @@ -13,62 +14,61 @@ namespace Telegram.Bot.Tests.Integ.Update_Messages; [Collection(Constants.TestCollections.EditMessage)] [Trait(Constants.CategoryTraitName, Constants.InteractiveCategoryValue)] [TestCaseOrderer(Constants.TestCaseOrderer, Constants.AssemblyName)] -public class EditMessageContentTests +public class EditMessageContentTests(TestsFixture fixture) { - ITelegramBotClient BotClient => _fixture.BotClient; - - readonly TestsFixture _fixture; - - public EditMessageContentTests(TestsFixture fixture) - { - _fixture = fixture; - } + ITelegramBotClient BotClient => fixture.BotClient; [OrderedFact("Should edit an inline message's text")] [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.AnswerInlineQuery)] [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.EditMessageText)] public async Task Should_Edit_Inline_Message_Text() { - await _fixture.SendTestInstructionsAsync( + await fixture.SendTestInstructionsAsync( "Starting the inline query with this message...", startInlineQuery: true ); #region Answer Inline Query with an Article - Update inlineQUpdate = await _fixture.UpdateReceiver.GetInlineQueryUpdateAsync(); + Update inlineQUpdate = await fixture.UpdateReceiver.GetInlineQueryUpdateAsync(); Assert.NotNull(inlineQUpdate.InlineQuery); const string originalMessagePrefix = "original\n"; (MessageEntityType Type, string Value)[] entityValueMappings = - { + [ (MessageEntityType.Bold, "bold"), - (MessageEntityType.Italic, "italic"), - }; + (MessageEntityType.Italic, "italic") + ]; string messageText = $"{originalMessagePrefix}{string.Join("\n", entityValueMappings.Select(tuple => tuple.Value))}"; string data = $"change-text{new Random().Next(2_000)}"; InlineQueryResult[] inlineQueryResults = - { - new InlineQueryResultArticle( - id: "bot-api", - title: "Telegram Bot API", - inputMessageContent: - new InputTextMessageContent(messageText) + [ + new InlineQueryResultArticle + { + Id = "bot-api", + Title = "Telegram Bot API", + InputMessageContent = new InputTextMessageContent { + MessageText = messageText, ParseMode = ParseMode.Html - } - ) - { + }, ReplyMarkup = InlineKeyboardButton.WithCallbackData("Click here to modify text", data) } - }; + ]; - await BotClient.AnswerInlineQueryAsync(inlineQUpdate.InlineQuery.Id, inlineQueryResults, 0); + await BotClient.AnswerInlineQueryAsync( + new() + { + InlineQueryId = inlineQUpdate.InlineQuery.Id, + Results = inlineQueryResults, + CacheTime = 0, + } + ); #endregion - Update callbackQUpdate = await _fixture.UpdateReceiver + Update callbackQUpdate = await fixture.UpdateReceiver .GetCallbackQueryUpdateAsync(data: data); Assert.NotNull(callbackQUpdate.CallbackQuery); @@ -77,10 +77,13 @@ public async Task Should_Edit_Inline_Message_Text() const string modifiedMessagePrefix = "✌ modified 👌\n"; messageText = $"{modifiedMessagePrefix}{string.Join("\n", entityValueMappings.Select(tuple => tuple.Value))}"; - await BotClient.EditMessageTextAsync( - inlineMessageId: callbackQUpdate.CallbackQuery.InlineMessageId, - text: messageText, - parseMode: ParseMode.Html + await BotClient.EditInlineMessageTextAsync( + new() + { + InlineMessageId = callbackQUpdate.CallbackQuery.InlineMessageId, + Text = messageText, + ParseMode = ParseMode.Html, + } ); } @@ -89,14 +92,14 @@ public async Task Should_Edit_Inline_Message_Text() [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.EditMessageReplyMarkup)] public async Task Should_Edit_Inline_Message_Markup() { - await _fixture.SendTestInstructionsAsync( + await fixture.SendTestInstructionsAsync( "Starting the inline query with this message...", startInlineQuery: true ); #region Answer Inline Query with an Article - Update inlineQUpdate = await _fixture.UpdateReceiver.GetInlineQueryUpdateAsync(); + Update inlineQUpdate = await fixture.UpdateReceiver.GetInlineQueryUpdateAsync(); Assert.NotNull(inlineQUpdate.InlineQuery); string data = "change-me" + new Random().Next(2_000); @@ -105,34 +108,46 @@ public async Task Should_Edit_Inline_Message_Markup() InlineKeyboardButton.WithCallbackData("Click here to change this button", data) }); - InputMessageContent inputMessageContent = - new InputTextMessageContent("https://core.telegram.org/bots/api"); + InputMessageContent inputMessageContent = new InputTextMessageContent + { + MessageText = "https://core.telegram.org/bots/api" + }; InlineQueryResult[] inlineQueryResults = - { - new InlineQueryResultArticle( - id: "bot-api", - title: "Telegram Bot API", - inputMessageContent: inputMessageContent) + [ + new InlineQueryResultArticle { + Id = "bot-api", + Title = "Telegram Bot API", + InputMessageContent = inputMessageContent, Description = "The Bot API is an HTTP-based interface created for developers", ReplyMarkup = initialMarkup, - }, - }; + } + ]; - await BotClient.AnswerInlineQueryAsync(inlineQUpdate.InlineQuery.Id, inlineQueryResults, 0); + await BotClient.AnswerInlineQueryAsync( + new() + { + InlineQueryId = inlineQUpdate.InlineQuery.Id, + Results = inlineQueryResults, + CacheTime = 0, + } + ); #endregion - Update callbackQUpdate = await _fixture.UpdateReceiver + Update callbackQUpdate = await fixture.UpdateReceiver .GetCallbackQueryUpdateAsync(data: data); Assert.NotNull(callbackQUpdate.CallbackQuery); Assert.NotNull(callbackQUpdate.CallbackQuery.InlineMessageId); - await BotClient.EditMessageReplyMarkupAsync( - inlineMessageId: callbackQUpdate.CallbackQuery.InlineMessageId, - replyMarkup: "✌ Edited 👌" + await BotClient.EditInlineMessageReplyMarkupAsync( + new() + { + InlineMessageId = callbackQUpdate.CallbackQuery.InlineMessageId, + ReplyMarkup = "✌ Edited 👌", + } ); } @@ -141,14 +156,14 @@ public async Task Should_Edit_Inline_Message_Markup() [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.EditMessageCaption)] public async Task Should_Edit_Inline_Message_Caption() { - await _fixture.SendTestInstructionsAsync( + await fixture.SendTestInstructionsAsync( "Starting the inline query with this message...", startInlineQuery: true ); #region Answer Inline Query with an Article - Update inlineQUpdate = await _fixture.UpdateReceiver.GetInlineQueryUpdateAsync(); + Update inlineQUpdate = await fixture.UpdateReceiver.GetInlineQueryUpdateAsync(); Assert.NotNull(inlineQUpdate.InlineQuery); string data = "change-me" + new Random().Next(2_000); @@ -159,31 +174,41 @@ public async Task Should_Edit_Inline_Message_Caption() const string url = "https://cdn.pixabay.com/photo/2017/08/30/12/45/girl-2696947_640.jpg"; InlineQueryResult[] inlineQueryResults = - { - new InlineQueryResultPhoto( - id: "photo1", - photoUrl: url, - thumbnailUrl: url) + [ + new InlineQueryResultPhoto { + Id = "photo1", + PhotoUrl = url, + ThumbnailUrl = url, Caption = "Message caption will be updated shortly", ReplyMarkup = replyMarkup } - }; + ]; - await BotClient.AnswerInlineQueryAsync(inlineQUpdate.InlineQuery.Id, inlineQueryResults, 0); + await BotClient.AnswerInlineQueryAsync( + new() + { + InlineQueryId = inlineQUpdate.InlineQuery.Id, + Results = inlineQueryResults, + CacheTime = 0, + } + ); #endregion - Update callbackQUpdate = await _fixture.UpdateReceiver + Update callbackQUpdate = await fixture.UpdateReceiver .GetCallbackQueryUpdateAsync(data: data); Assert.NotNull(callbackQUpdate.CallbackQuery); Assert.NotNull(callbackQUpdate.CallbackQuery.InlineMessageId); - await BotClient.EditMessageCaptionAsync( - inlineMessageId: callbackQUpdate.CallbackQuery.InlineMessageId, - caption: "_Caption is edited_ 👌", - parseMode: ParseMode.Markdown + await BotClient.EditInlineMessageCaptionAsync( + new() + { + InlineMessageId = callbackQUpdate.CallbackQuery.InlineMessageId, + Caption = "_Caption is edited_ 👌", + ParseMode = ParseMode.Markdown, + } ); } } diff --git a/test/Telegram.Bot.Tests.Integ/Update Messages/EditMessageContentTests2.cs b/test/Telegram.Bot.Tests.Integ/Update Messages/EditMessageContentTests2.cs index 865bbfe73..7af3d2554 100644 --- a/test/Telegram.Bot.Tests.Integ/Update Messages/EditMessageContentTests2.cs +++ b/test/Telegram.Bot.Tests.Integ/Update Messages/EditMessageContentTests2.cs @@ -1,6 +1,7 @@ using System.IO; using System.Linq; using System.Threading.Tasks; +using Telegram.Bot.Requests; using Telegram.Bot.Tests.Integ.Framework; using Telegram.Bot.Types; using Telegram.Bot.Types.Enums; @@ -11,16 +12,9 @@ namespace Telegram.Bot.Tests.Integ.Update_Messages; [Collection(Constants.TestCollections.EditMessage2)] [TestCaseOrderer(Constants.TestCaseOrderer, Constants.AssemblyName)] -public class EditMessageContentTests2 +public class EditMessageContentTests2(TestsFixture fixture) { - ITelegramBotClient BotClient => _fixture.BotClient; - - readonly TestsFixture _fixture; - - public EditMessageContentTests2(TestsFixture fixture) - { - _fixture = fixture; - } + ITelegramBotClient BotClient => fixture.BotClient; [OrderedFact("Should edit a message's text")] [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.SendMessage)] @@ -29,16 +23,19 @@ public async Task Should_Edit_Message_Text() { const string originalMessagePrefix = "original\n"; (MessageEntityType Type, string Value)[] entityValueMappings = - { + [ (MessageEntityType.Bold, "bold"), - (MessageEntityType.Italic, "italic"), - }; + (MessageEntityType.Italic, "italic") + ]; string messageText = $"{originalMessagePrefix}{string.Join("\n", entityValueMappings.Select(tuple => tuple.Value))}"; - Message originalMessage = await BotClient.SendTextMessageAsync( - chatId: _fixture.SupergroupChat.Id, - text: messageText, - parseMode: ParseMode.Html + Message originalMessage = await BotClient.SendMessageAsync( + new() + { + ChatId = fixture.SupergroupChat.Id, + Text = messageText, + ParseMode = ParseMode.Html, + } ); await Task.Delay(1_000); @@ -47,10 +44,13 @@ public async Task Should_Edit_Message_Text() messageText = $"{modifiedMessagePrefix}{string.Join("\n", entityValueMappings.Select(tuple => tuple.Value))}"; Message editedMessage = await BotClient.EditMessageTextAsync( - chatId: originalMessage.Chat.Id, - messageId: originalMessage.MessageId, - text: messageText, - parseMode: ParseMode.Html + new() + { + ChatId = originalMessage.Chat.Id, + MessageId = originalMessage.MessageId, + Text = messageText, + ParseMode = ParseMode.Html, + } ); Assert.NotNull(editedMessage.Text); @@ -71,18 +71,24 @@ public async Task Should_Edit_Message_Text() [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.EditMessageReplyMarkup)] public async Task Should_Edit_Message_Markup() { - Message message = await BotClient.SendTextMessageAsync( - chatId: _fixture.SupergroupChat.Id, - text: "Inline keyboard will be updated shortly", - replyMarkup: (InlineKeyboardMarkup)"Original markup" + Message message = await BotClient.SendMessageAsync( + new() + { + ChatId = fixture.SupergroupChat.Id, + Text = "Inline keyboard will be updated shortly", + ReplyMarkup = (InlineKeyboardMarkup)"Original markup", + } ); await Task.Delay(1_000); Message editedMessage = await BotClient.EditMessageReplyMarkupAsync( - chatId: message.Chat.Id, - messageId: message.MessageId, - replyMarkup: "Edited 👍" + new EditMessageReplyMarkupRequest + { + ChatId = message.Chat.Id, + MessageId = message.MessageId, + ReplyMarkup = "Edited 👍", + } ); Assert.Equal(message.MessageId, editedMessage.MessageId); @@ -100,9 +106,12 @@ public async Task Should_Edit_Message_Caption() await using (Stream stream = System.IO.File.OpenRead(Constants.PathToFile.Photos.Bot)) { originalMessage = await BotClient.SendPhotoAsync( - chatId: _fixture.SupergroupChat.Id, - photo: new InputFileStream(stream), - caption: "Message caption will be updated shortly" + new() + { + ChatId = fixture.SupergroupChat.Id, + Photo = InputFile.FromStream(stream), + Caption = "Message caption will be updated shortly", + } ); } @@ -113,10 +122,13 @@ await using (Stream stream = System.IO.File.OpenRead(Constants.PathToFile.Photos string caption = $"{captionPrefix} {captionEntity.Value}"; Message editedMessage = await BotClient.EditMessageCaptionAsync( - chatId: originalMessage.Chat.Id, - messageId: originalMessage.MessageId, - caption: caption, - parseMode: ParseMode.Markdown + new() + { + ChatId = originalMessage.Chat.Id, + MessageId = originalMessage.MessageId, + Caption = caption, + ParseMode = ParseMode.Markdown, + } ); Assert.Equal(originalMessage.MessageId, editedMessage.MessageId); diff --git a/test/Telegram.Bot.Tests.Integ/Update Messages/EditMessageMediaTests.cs b/test/Telegram.Bot.Tests.Integ/Update Messages/EditMessageMediaTests.cs index 4a6126be4..270bee37b 100644 --- a/test/Telegram.Bot.Tests.Integ/Update Messages/EditMessageMediaTests.cs +++ b/test/Telegram.Bot.Tests.Integ/Update Messages/EditMessageMediaTests.cs @@ -1,5 +1,6 @@ using System.IO; using System.Threading.Tasks; +using Telegram.Bot.Requests; using Telegram.Bot.Tests.Integ.Framework; using Telegram.Bot.Types; using Telegram.Bot.Types.Enums; @@ -12,64 +13,67 @@ namespace Telegram.Bot.Tests.Integ.Update_Messages; [Collection(Constants.TestCollections.EditMessageMedia)] [Trait(Constants.CategoryTraitName, Constants.InteractiveCategoryValue)] [TestCaseOrderer(Constants.TestCaseOrderer, Constants.AssemblyName)] -public class EditMessageMediaTests +public class EditMessageMediaTests(TestsFixture fixture) { - ITelegramBotClient BotClient => _fixture.BotClient; - - readonly TestsFixture _fixture; - - public EditMessageMediaTests(TestsFixture fixture) - { - _fixture = fixture; - } + ITelegramBotClient BotClient => fixture.BotClient; [OrderedFact("Should change an inline message's photo to an audio using URL")] [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.AnswerInlineQuery)] [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.EditMessageMedia)] public async Task Should_Edit_Inline_Message_Photo() { - await _fixture.SendTestInstructionsAsync( + await fixture.SendTestInstructionsAsync( "Starting the inline query with this message...", startInlineQuery: true ); #region Answer Inline Query with a media message - Update iqUpdate = await _fixture.UpdateReceiver.GetInlineQueryUpdateAsync(); + Update iqUpdate = await fixture.UpdateReceiver.GetInlineQueryUpdateAsync(); Assert.NotNull(iqUpdate.InlineQuery); InlineQueryResult[] inlineQueryResults = - { - new InlineQueryResultPhoto( - id: "photo:rainbow-girl", - photoUrl: "https://cdn.pixabay.com/photo/2017/08/30/12/45/girl-2696947_640.jpg", - thumbnailUrl: "https://cdn.pixabay.com/photo/2017/08/30/12/45/girl-2696947_640.jpg") + [ + new InlineQueryResultPhoto { + Id = "photo:rainbow-girl", + PhotoUrl = "https://cdn.pixabay.com/photo/2017/08/30/12/45/girl-2696947_640.jpg", + ThumbnailUrl = "https://cdn.pixabay.com/photo/2017/08/30/12/45/girl-2696947_640.jpg", Caption = "Rainbow Girl", ReplyMarkup = InlineKeyboardButton.WithCallbackData("Click here to edit"), } - }; + ]; - await BotClient.AnswerInlineQueryAsync(iqUpdate.InlineQuery.Id, inlineQueryResults, 0); + await BotClient.AnswerInlineQueryAsync( + new() + { + InlineQueryId = iqUpdate.InlineQuery.Id, + Results = inlineQueryResults, + CacheTime = 0, + } + ); #endregion // Bot waits for user to click on inline button under the media - Update cqUpdate = await _fixture.UpdateReceiver.GetCallbackQueryUpdateAsync(data: "Click here to edit"); + Update cqUpdate = await fixture.UpdateReceiver.GetCallbackQueryUpdateAsync(data: "Click here to edit"); Assert.NotNull(cqUpdate.CallbackQuery); Assert.NotNull(cqUpdate.CallbackQuery.InlineMessageId); // Change the photo for an audio. Note that, in the case of an inline message, the new media should be // either an URL or the file_id of a previously uploaded media. - await BotClient.EditMessageMediaAsync( - inlineMessageId: cqUpdate.CallbackQuery.InlineMessageId, - media: new InputMediaAudio(new InputFileUrl( - "https://upload.wikimedia.org/wikipedia/commons/transcoded/b/bb/" + - "Test_ogg_mp3_48kbps.wav/Test_ogg_mp3_48kbps.wav.mp3")) + InputFileUrl inputFileUrl = InputFile.FromUri("https://upload.wikimedia.org/wikipedia/commons/transcoded/b/bb/Test_ogg_mp3_48kbps.wav/Test_ogg_mp3_48kbps.wav.mp3"); + await BotClient.EditInlineMessageMediaAsync( + new() { - Caption = "**Audio** in `.mp3` format", - ParseMode = ParseMode.Markdown, + InlineMessageId = cqUpdate.CallbackQuery.InlineMessageId, + Media = new InputMediaAudio + { + Media = inputFileUrl, + Caption = "**Audio** in `.mp3` format", + ParseMode = ParseMode.Markdown, + }, } ); } @@ -83,12 +87,15 @@ public async Task Should_Edit_Inline_Message_Document_With_FileId() // Upload a GIF file to Telegram servers and obtain its file_id. This file_id will be used later in test. await using Stream stream = System.IO.File.OpenRead(Constants.PathToFile.Animation.Earth); Message gifMessage = await BotClient.SendDocumentAsync( - chatId: _fixture.SupergroupChat, - document: new InputFileStream(stream, "Earth.gif"), - caption: "`file_id` of this GIF will be used", - parseMode: ParseMode.Markdown, - replyMarkup: (InlineKeyboardMarkup) InlineKeyboardButton - .WithSwitchInlineQueryCurrentChat("Start Inline Query") + new() + { + ChatId = fixture.SupergroupChat, + Document = InputFile.FromStream(stream, "Earth.gif"), + Caption = "`file_id` of this GIF will be used", + ParseMode = ParseMode.Markdown, + ReplyMarkup = (InlineKeyboardMarkup) InlineKeyboardButton + .WithSwitchInlineQueryCurrentChat("Start Inline Query"), + } ); Assert.NotNull(gifMessage.Document); @@ -96,36 +103,46 @@ public async Task Should_Edit_Inline_Message_Document_With_FileId() #region Answer Inline Query with a media message - Update iqUpdate = await _fixture.UpdateReceiver.GetInlineQueryUpdateAsync(); + Update iqUpdate = await fixture.UpdateReceiver.GetInlineQueryUpdateAsync(); Assert.NotNull(iqUpdate.InlineQuery); InlineQueryResult[] inlineQueryResults = - { - new InlineQueryResultDocument( - id: "document:acrobat", - documentUrl: "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf", - title: "Dummy PDF File", - mimeType: "application/pdf") + [ + new InlineQueryResultDocument { + Id = "document:acrobat", + DocumentUrl = "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf", + Title = "Dummy PDF File", + MimeType = "application/pdf", ReplyMarkup = InlineKeyboardButton.WithCallbackData("Click here to edit"), } - }; + ]; - await BotClient.AnswerInlineQueryAsync(iqUpdate.InlineQuery.Id, inlineQueryResults, 0); + await BotClient.AnswerInlineQueryAsync( + new() + { + InlineQueryId = iqUpdate.InlineQuery.Id, + Results = inlineQueryResults, + CacheTime = 0, + } + ); #endregion // Bot waits for user to click on inline button under the media - Update cqUpdate = await _fixture.UpdateReceiver.GetCallbackQueryUpdateAsync(data: "Click here to edit"); + Update cqUpdate = await fixture.UpdateReceiver.GetCallbackQueryUpdateAsync(data: "Click here to edit"); Assert.NotNull(cqUpdate.CallbackQuery); Assert.NotNull(cqUpdate.CallbackQuery.InlineMessageId); // Change the YouTube video for an animation. Note that, in the case of an inline message, the new media // should be either an URL or the file_id of a previously uploaded media. // Also, animation thumbnail cannot be uploaded for an inline message. - await BotClient.EditMessageMediaAsync( - inlineMessageId: cqUpdate.CallbackQuery.InlineMessageId, - media: new InputMediaAnimation(new InputFileId(animationFileId)) + await BotClient.EditInlineMessageMediaAsync( + new() + { + InlineMessageId = cqUpdate.CallbackQuery.InlineMessageId, + Media = new InputMediaAnimation { Media = InputFile.FromFileId(animationFileId) }, + } ); } } diff --git a/test/Telegram.Bot.Tests.Integ/Update Messages/EditMessageMediaTests2.cs b/test/Telegram.Bot.Tests.Integ/Update Messages/EditMessageMediaTests2.cs index 986f4ba9d..26f19f17a 100644 --- a/test/Telegram.Bot.Tests.Integ/Update Messages/EditMessageMediaTests2.cs +++ b/test/Telegram.Bot.Tests.Integ/Update Messages/EditMessageMediaTests2.cs @@ -1,6 +1,7 @@ using System; using System.IO; using System.Threading.Tasks; +using Telegram.Bot.Requests; using Telegram.Bot.Tests.Integ.Framework; using Telegram.Bot.Types; using Telegram.Bot.Types.Enums; @@ -10,16 +11,9 @@ namespace Telegram.Bot.Tests.Integ.Update_Messages; [Collection(Constants.TestCollections.EditMessageMedia2)] [TestCaseOrderer(Constants.TestCaseOrderer, Constants.AssemblyName)] -public class EditMessageMediaTests2 +public class EditMessageMediaTests2(TestsFixture fixture) { - ITelegramBotClient BotClient => _fixture.BotClient; - - readonly TestsFixture _fixture; - - public EditMessageMediaTests2(TestsFixture fixture) - { - _fixture = fixture; - } + ITelegramBotClient BotClient => fixture.BotClient; [OrderedFact("Should change a message's video to a document file")] [Trait(Constants.MethodTraitName, Constants.TelegramBotApiMethods.SendVideo)] @@ -31,9 +25,12 @@ public async Task Should_Edit_Message_Video() await using (Stream stream = System.IO.File.OpenRead(Constants.PathToFile.Animation.Earth)) { originalMessage = await BotClient.SendVideoAsync( - chatId: _fixture.SupergroupChat, - video: new InputFileStream(stream), - caption: "This message will be edited shortly" + new() + { + ChatId = fixture.SupergroupChat, + Video = InputFile.FromStream(stream), + Caption = "This message will be edited shortly", + } ); } @@ -44,12 +41,16 @@ await using (Stream stream = System.IO.File.OpenRead(Constants.PathToFile.Animat await using (Stream stream = System.IO.File.OpenRead(Constants.PathToFile.Certificate.PublicKey)) { editedMessage = await BotClient.EditMessageMediaAsync( - chatId: originalMessage.Chat, - messageId: originalMessage.MessageId, - media: new InputMediaDocument(new InputFileStream(stream, "public-key.pem.txt")) + new() { - Caption = "**Public** key in `.pem` format", - ParseMode = ParseMode.Markdown, + ChatId = originalMessage.Chat, + MessageId = originalMessage.MessageId, + Media = new InputMediaDocument + { + Media = InputFile.FromStream(stream, "public-key.pem.txt"), + Caption = "**Public** key in `.pem` format", + ParseMode = ParseMode.Markdown, + }, } ); } @@ -69,18 +70,24 @@ public async Task Should_Edit_Message_Photo() { // Upload a GIF file to Telegram servers and obtain its file_id. This file_id will be used later in test. Message gifMessage = await BotClient.SendDocumentAsync( - chatId: _fixture.SupergroupChat, - document: new InputFileUrl(new Uri("https://upload.wikimedia.org/wikipedia/commons/2/2c/Rotating_earth_%28large%29.gif")), - caption: "`file_id` of this GIF will be used" + new() + { + ChatId = fixture.SupergroupChat, + Document = InputFile.FromUri(new Uri("https://upload.wikimedia.org/wikipedia/commons/2/2c/Rotating_earth_%28large%29.gif")), + Caption = "`file_id` of this GIF will be used", + } ); Assert.NotNull(gifMessage.Document); // Send a photo to chat. This media will be changed later in test. Message originalMessage = await BotClient.SendPhotoAsync( - chatId: _fixture.SupergroupChat, - photo: new InputFileUrl(new Uri("https://cdn.pixabay.com/photo/2017/08/30/12/45/girl-2696947_640.jpg")), - caption: "This message will be edited shortly" + new() + { + ChatId = fixture.SupergroupChat, + Photo = InputFile.FromUri(new Uri("https://cdn.pixabay.com/photo/2017/08/30/12/45/girl-2696947_640.jpg")), + Caption = "This message will be edited shortly", + } ); await Task.Delay(500); @@ -88,14 +95,18 @@ public async Task Should_Edit_Message_Photo() // Replace audio with another audio by uploading the new file. A thumbnail image is also uploaded. await using Stream thumbStream = System.IO.File.OpenRead(Constants.PathToFile.Thumbnail.Video); Message editedMessage = await BotClient.EditMessageMediaAsync( - chatId: originalMessage.Chat, - messageId: originalMessage.MessageId, - media: new InputMediaAnimation(new InputFileId(gifMessage.Document.FileId)) + new() { - Thumbnail = new InputFileStream(thumbStream, "thumb.jpg"), - Duration = 4, - Height = 320, - Width = 320, + ChatId = originalMessage.Chat, + MessageId = originalMessage.MessageId, + Media = new InputMediaAnimation + { + Media = InputFile.FromFileId(gifMessage.Document.FileId), + Thumbnail = InputFile.FromStream(thumbStream, "thumb.jpg"), + Duration = 4, + Height = 320, + Width = 320, + } } ); diff --git a/test/Telegram.Bot.Tests.Unit/EnumConverter/ChatBoostSourceTypeConverterTests.cs b/test/Telegram.Bot.Tests.Unit/EnumConverter/ChatBoostSourceTypeConverterTests.cs new file mode 100644 index 000000000..4941e5bc5 --- /dev/null +++ b/test/Telegram.Bot.Tests.Unit/EnumConverter/ChatBoostSourceTypeConverterTests.cs @@ -0,0 +1,65 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Serialization; +using System; +using Telegram.Bot.Types.Enums; +using Xunit; + +namespace Telegram.Bot.Tests.Unit.EnumConverter; + +public class ChatBoostSourceTypeConverterTests +{ + [Theory] + [InlineData(ChatBoostSourceType.Giveaway, "giveaway")] + [InlineData(ChatBoostSourceType.Premium, "premium")] + [InlineData(ChatBoostSourceType.GiftCode, "gift_code")] + public void Should_Convert_ChatBoostSourceType_To_String(ChatBoostSourceType kind, string value) + { + Container container = new() { Type = kind }; + string expectedResult = @$"{{""type"":""{value}""}}"; + + string result = JsonConvert.SerializeObject(container); + + Assert.Equal(expectedResult, result); + } + + [Theory] + [InlineData(ChatBoostSourceType.Giveaway, "giveaway")] + [InlineData(ChatBoostSourceType.Premium, "premium")] + [InlineData(ChatBoostSourceType.GiftCode, "gift_code")] + public void Should_Convert_String_ToChatBoostSourceType(ChatBoostSourceType kind, string value) + { + Container expectedResult = new() { Type = kind }; + string jsonData = @$"{{""type"":""{value}""}}"; + + Container? result = JsonConvert.DeserializeObject(jsonData); + + Assert.NotNull(result); + Assert.Equal(expectedResult.Type, result.Type); + } + + [Fact] + public void Should_Return_Zero_For_Incorrect_ChatBoostSourceType() + { + string jsonData = @$"{{""type"":""{int.MaxValue}""}}"; + + Container? result = JsonConvert.DeserializeObject(jsonData); + + Assert.NotNull(result); + Assert.Equal((ChatBoostSourceType)0, result.Type); + } + + [Fact] + public void Should_Throw_NotSupportedException_For_Incorrect_ChatBoostSourceType() + { + Container container = new() { Type = (ChatBoostSourceType)int.MaxValue }; + + Assert.Throws(() => JsonConvert.SerializeObject(container)); + } + + [JsonObject(MemberSerialization.OptIn, NamingStrategyType = typeof(SnakeCaseNamingStrategy))] + class Container + { + [JsonProperty(Required = Required.Always)] + public ChatBoostSourceType Type { get; init; } + } +} diff --git a/test/Telegram.Bot.Tests.Unit/EnumConverter/MessageEntityTypeConverterTests.cs b/test/Telegram.Bot.Tests.Unit/EnumConverter/MessageEntityTypeConverterTests.cs index dbedfca50..664c7dbc6 100644 --- a/test/Telegram.Bot.Tests.Unit/EnumConverter/MessageEntityTypeConverterTests.cs +++ b/test/Telegram.Bot.Tests.Unit/EnumConverter/MessageEntityTypeConverterTests.cs @@ -97,6 +97,7 @@ public IEnumerator GetEnumerator() yield return new object[] { MessageEntityType.Strikethrough, "strikethrough" }; yield return new object[] { MessageEntityType.Spoiler, "spoiler" }; yield return new object[] { MessageEntityType.CustomEmoji, "custom_emoji" }; + yield return new object[] { MessageEntityType.Blockquote, "blockquote" }; } IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); diff --git a/test/Telegram.Bot.Tests.Unit/EnumConverter/MessageOriginTypeConverterTests.cs b/test/Telegram.Bot.Tests.Unit/EnumConverter/MessageOriginTypeConverterTests.cs new file mode 100644 index 000000000..6362f9044 --- /dev/null +++ b/test/Telegram.Bot.Tests.Unit/EnumConverter/MessageOriginTypeConverterTests.cs @@ -0,0 +1,67 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Serialization; +using System; +using Telegram.Bot.Types.Enums; +using Xunit; + +namespace Telegram.Bot.Tests.Unit.EnumConverter; + +public class MessageOriginTypeConverterTests +{ + [Theory] + [InlineData(MessageOriginType.User, "user")] + [InlineData(MessageOriginType.HiddenUser, "hidden_user")] + [InlineData(MessageOriginType.Chat, "chat")] + [InlineData(MessageOriginType.Channel, "channel")] + public void Should_Convert_MessageOriginType_To_String(MessageOriginType messageOriginType, string value) + { + MessageOrigin messageOrigin = new() { Type = messageOriginType }; + string expectedResult = @$"{{""type"":""{value}""}}"; + + string result = JsonConvert.SerializeObject(messageOrigin); + + Assert.Equal(expectedResult, result); + } + + [Theory] + [InlineData(MessageOriginType.User, "user")] + [InlineData(MessageOriginType.HiddenUser, "hidden_user")] + [InlineData(MessageOriginType.Chat, "chat")] + [InlineData(MessageOriginType.Channel, "channel")] + public void Should_Convert_String_To_MessageOriginType(MessageOriginType messageOriginType, string value) + { + MessageOrigin expectedResult = new() { Type = messageOriginType }; + string jsonData = @$"{{""type"":""{value}""}}"; + + MessageOrigin? result = JsonConvert.DeserializeObject(jsonData); + + Assert.NotNull(result); + Assert.Equal(expectedResult.Type, result.Type); + } + + [Fact] + public void Should_Return_Zero_For_Incorrect_ChatMemberStatus() + { + string jsonData = @$"{{""type"":""{int.MaxValue}""}}"; + + MessageOrigin? result = JsonConvert.DeserializeObject(jsonData); + + Assert.NotNull(result); + Assert.Equal((MessageOriginType)0, result.Type); + } + + [Fact] + public void Should_Throw_NotSupportedException_For_Incorrect_ChatMemberStatus() + { + MessageOrigin messageOrigin = new() { Type = (MessageOriginType)int.MaxValue }; + + Assert.Throws(() => JsonConvert.SerializeObject(messageOrigin)); + } + + [JsonObject(MemberSerialization.OptIn, NamingStrategyType = typeof(SnakeCaseNamingStrategy))] + class MessageOrigin + { + [JsonProperty(Required = Required.Always)] + public MessageOriginType Type { get; init; } + } +} diff --git a/test/Telegram.Bot.Tests.Unit/EnumConverter/MessageTypeConverterTests.cs b/test/Telegram.Bot.Tests.Unit/EnumConverter/MessageTypeConverterTests.cs index 65696ca78..bd842557b 100644 --- a/test/Telegram.Bot.Tests.Unit/EnumConverter/MessageTypeConverterTests.cs +++ b/test/Telegram.Bot.Tests.Unit/EnumConverter/MessageTypeConverterTests.cs @@ -1,4 +1,7 @@ using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; using Newtonsoft.Json; using Newtonsoft.Json.Serialization; using Telegram.Bot.Types.Enums; @@ -8,47 +11,31 @@ namespace Telegram.Bot.Tests.Unit.EnumConverter; public class MessageTypeConverterTests { + [Fact] + public void Should_Verify_All_MessageType_Members() + { + List messageTypeMembers = Enum + .GetNames() + .OrderBy(x => x) + .ToList(); + List messageTypeDataMembers = new MessageTypeData() + .Select(x => Enum.GetName(typeof(MessageType), x[0])) + .OrderBy(x => x) + .ToList()!; + + Assert.Equal(messageTypeMembers.Count, messageTypeDataMembers.Count); + Assert.Equal(messageTypeMembers, messageTypeDataMembers); + } + [Theory] - [InlineData(MessageType.Unknown, "unknown")] - [InlineData(MessageType.Text, "text")] - [InlineData(MessageType.Photo, "photo")] - [InlineData(MessageType.Audio, "audio")] - [InlineData(MessageType.Video, "video")] - [InlineData(MessageType.Voice, "voice")] - [InlineData(MessageType.Animation, "animation")] - [InlineData(MessageType.Document, "document")] - [InlineData(MessageType.Sticker, "sticker")] - [InlineData(MessageType.Location, "location")] - [InlineData(MessageType.Contact, "contact")] - [InlineData(MessageType.Venue, "venue")] - [InlineData(MessageType.Game, "game")] - [InlineData(MessageType.VideoNote, "video_note")] - [InlineData(MessageType.Invoice, "invoice")] - [InlineData(MessageType.SuccessfulPayment, "successful_payment")] - [InlineData(MessageType.WebsiteConnected, "website_connected")] - [InlineData(MessageType.ChatMembersAdded, "chat_members_added")] - [InlineData(MessageType.ChatMemberLeft, "chat_member_left")] - [InlineData(MessageType.ChatTitleChanged, "chat_title_changed")] - [InlineData(MessageType.ChatPhotoChanged, "chat_photo_changed")] - [InlineData(MessageType.MessagePinned, "message_pinned")] - [InlineData(MessageType.ChatPhotoDeleted, "chat_photo_deleted")] - [InlineData(MessageType.GroupCreated, "group_created")] - [InlineData(MessageType.SupergroupCreated, "supergroup_created")] - [InlineData(MessageType.ChannelCreated, "channel_created")] - [InlineData(MessageType.MigratedToSupergroup, "migrated_to_supergroup")] - [InlineData(MessageType.MigratedFromGroup, "migrated_from_group")] - [InlineData(MessageType.Poll, "poll")] - [InlineData(MessageType.Dice, "dice")] - [InlineData(MessageType.MessageAutoDeleteTimerChanged, "message_auto_delete_timer_changed")] - [InlineData(MessageType.ProximityAlertTriggered, "proximity_alert_triggered")] - [InlineData(MessageType.VideoChatScheduled, "video_chat_scheduled")] - [InlineData(MessageType.VideoChatStarted, "video_chat_started")] - [InlineData(MessageType.VideoChatEnded, "video_chat_ended")] - [InlineData(MessageType.VideoChatParticipantsInvited, "video_chat_participants_invited")] + [ClassData(typeof(MessageTypeData))] public void Should_Convert_UpdateType_To_String(MessageType messageType, string value) { - Message message = new() { Type = messageType }; - string expectedResult = @$"{{""type"":""{value}""}}"; + Message message = new(messageType); + string expectedResult = + $$""" + {"type":"{{value}}"} + """; string result = JsonConvert.SerializeObject(message); @@ -56,46 +43,14 @@ public void Should_Convert_UpdateType_To_String(MessageType messageType, string } [Theory] - [InlineData(MessageType.Unknown, "unknown")] - [InlineData(MessageType.Text, "text")] - [InlineData(MessageType.Photo, "photo")] - [InlineData(MessageType.Audio, "audio")] - [InlineData(MessageType.Video, "video")] - [InlineData(MessageType.Voice, "voice")] - [InlineData(MessageType.Animation, "animation")] - [InlineData(MessageType.Document, "document")] - [InlineData(MessageType.Sticker, "sticker")] - [InlineData(MessageType.Location, "location")] - [InlineData(MessageType.Contact, "contact")] - [InlineData(MessageType.Venue, "venue")] - [InlineData(MessageType.Game, "game")] - [InlineData(MessageType.VideoNote, "video_note")] - [InlineData(MessageType.Invoice, "invoice")] - [InlineData(MessageType.SuccessfulPayment, "successful_payment")] - [InlineData(MessageType.WebsiteConnected, "website_connected")] - [InlineData(MessageType.ChatMembersAdded, "chat_members_added")] - [InlineData(MessageType.ChatMemberLeft, "chat_member_left")] - [InlineData(MessageType.ChatTitleChanged, "chat_title_changed")] - [InlineData(MessageType.ChatPhotoChanged, "chat_photo_changed")] - [InlineData(MessageType.MessagePinned, "message_pinned")] - [InlineData(MessageType.ChatPhotoDeleted, "chat_photo_deleted")] - [InlineData(MessageType.GroupCreated, "group_created")] - [InlineData(MessageType.SupergroupCreated, "supergroup_created")] - [InlineData(MessageType.ChannelCreated, "channel_created")] - [InlineData(MessageType.MigratedToSupergroup, "migrated_to_supergroup")] - [InlineData(MessageType.MigratedFromGroup, "migrated_from_group")] - [InlineData(MessageType.Poll, "poll")] - [InlineData(MessageType.Dice, "dice")] - [InlineData(MessageType.MessageAutoDeleteTimerChanged, "message_auto_delete_timer_changed")] - [InlineData(MessageType.ProximityAlertTriggered, "proximity_alert_triggered")] - [InlineData(MessageType.VideoChatScheduled, "video_chat_scheduled")] - [InlineData(MessageType.VideoChatStarted, "video_chat_started")] - [InlineData(MessageType.VideoChatEnded, "video_chat_ended")] - [InlineData(MessageType.VideoChatParticipantsInvited, "video_chat_participants_invited")] + [ClassData(typeof(MessageTypeData))] public void Should_Convert_String_To_UpdateType(MessageType messageType, string value) { - Message expectedResult = new() { Type = messageType }; - string jsonData = @$"{{""type"":""{value}""}}"; + Message expectedResult = new(messageType); + string jsonData = + $$""" + {"type":"{{value}}"} + """; Message? result = JsonConvert.DeserializeObject(jsonData); @@ -106,7 +61,10 @@ public void Should_Convert_String_To_UpdateType(MessageType messageType, string [Fact] public void Should_Return_Unknown_For_Incorrect_UpdateType() { - string jsonData = @$"{{""type"":""{int.MaxValue}""}}"; + string jsonData = + $$""" + {"type":"{{int.MaxValue}}"} + """; Message? result = JsonConvert.DeserializeObject(jsonData); @@ -117,15 +75,73 @@ public void Should_Return_Unknown_For_Incorrect_UpdateType() [Fact] public void Should_Throw_NotSupportedException_For_Incorrect_MessageType() { - Message message = new() { Type = (MessageType)int.MaxValue }; + Message message = new((MessageType)int.MaxValue ); Assert.Throws(() => JsonConvert.SerializeObject(message)); } [JsonObject(MemberSerialization.OptIn, NamingStrategyType = typeof(SnakeCaseNamingStrategy))] - class Message + record Message([property: JsonProperty(Required = Required.Always)] MessageType Type); + + private class MessageTypeData : IEnumerable { - [JsonProperty(Required = Required.Always)] - public MessageType Type { get; init; } + public IEnumerator GetEnumerator() + { + yield return [MessageType.Unknown, "unknown"]; + yield return [MessageType.Text, "text"]; + yield return [MessageType.Animation, "animation"]; + yield return [MessageType.Audio, "audio"]; + yield return [MessageType.BoostAdded, "boost_added"]; + yield return [MessageType.Document, "document"]; + yield return [MessageType.Photo, "photo"]; + yield return [MessageType.Sticker, "sticker"]; + yield return [MessageType.Story, "story"]; + yield return [MessageType.Video, "video"]; + yield return [MessageType.VideoNote, "video_note"]; + yield return [MessageType.Voice, "voice"]; + yield return [MessageType.Contact, "contact"]; + yield return [MessageType.Dice, "dice"]; + yield return [MessageType.Game, "game"]; + yield return [MessageType.Poll, "poll"]; + yield return [MessageType.Venue, "venue"]; + yield return [MessageType.Location, "location"]; + yield return [MessageType.NewChatMembers, "new_chat_members"]; + yield return [MessageType.LeftChatMember, "left_chat_member"]; + yield return [MessageType.NewChatTitle, "new_chat_title"]; + yield return [MessageType.NewChatPhoto, "new_chat_photo"]; + yield return [MessageType.DeleteChatPhoto, "delete_chat_photo"]; + yield return [MessageType.GroupChatCreated, "group_chat_created"]; + yield return [MessageType.SupergroupChatCreated, "supergroup_chat_created"]; + yield return [MessageType.ChannelChatCreated, "channel_chat_created"]; + yield return [MessageType.MessageAutoDeleteTimerChanged, "message_auto_delete_timer_changed"]; + yield return [MessageType.MigrateToChatId, "migrate_to_chat_id"]; + yield return [MessageType.MigrateFromChatId, "migrate_from_chat_id"]; + yield return [MessageType.PinnedMessage, "pinned_message"]; + yield return [MessageType.Invoice, "invoice"]; + yield return [MessageType.SuccessfulPayment, "successful_payment"]; + yield return [MessageType.UsersShared, "users_shared"]; + yield return [MessageType.ChatShared, "chat_shared"]; + yield return [MessageType.ConnectedWebsite, "connected_website"]; + yield return [MessageType.WriteAccessAllowed, "write_access_allowed"]; + yield return [MessageType.PassportData, "passport_data"]; + yield return [MessageType.ProximityAlertTriggered, "proximity_alert_triggered"]; + yield return [MessageType.ForumTopicCreated, "forum_topic_created"]; + yield return [MessageType.ForumTopicEdited, "forum_topic_edited"]; + yield return [MessageType.ForumTopicClosed, "forum_topic_closed"]; + yield return [MessageType.ForumTopicReopened, "forum_topic_reopened"]; + yield return [MessageType.GeneralForumTopicHidden, "general_forum_topic_hidden"]; + yield return [MessageType.GeneralForumTopicUnhidden, "general_forum_topic_unhidden"]; + yield return [MessageType.GiveawayCreated, "giveaway_created"]; + yield return [MessageType.Giveaway, "giveaway"]; + yield return [MessageType.GiveawayWinners, "giveaway_winners"]; + yield return [MessageType.GiveawayCompleted, "giveaway_completed"]; + yield return [MessageType.VideoChatScheduled, "video_chat_scheduled"]; + yield return [MessageType.VideoChatStarted, "video_chat_started"]; + yield return [MessageType.VideoChatEnded, "video_chat_ended"]; + yield return [MessageType.VideoChatParticipantsInvited, "video_chat_participants_invited"]; + yield return [MessageType.WebAppData, "web_app_data"]; + } + + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } } diff --git a/test/Telegram.Bot.Tests.Unit/EnumConverter/ReactionTypeKindConverterTests.cs b/test/Telegram.Bot.Tests.Unit/EnumConverter/ReactionTypeKindConverterTests.cs new file mode 100644 index 000000000..7a650e1c2 --- /dev/null +++ b/test/Telegram.Bot.Tests.Unit/EnumConverter/ReactionTypeKindConverterTests.cs @@ -0,0 +1,63 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Serialization; +using System; +using Telegram.Bot.Types.Enums; +using Xunit; + +namespace Telegram.Bot.Tests.Unit.EnumConverter; + +public class ReactionTypeKindConverterTests +{ + [Theory] + [InlineData(ReactionTypeKind.Emoji, "emoji")] + [InlineData(ReactionTypeKind.CustomEmoji, "custom_emoji")] + public void Should_Convert_ChatAction_To_String(ReactionTypeKind kind, string value) + { + Container container = new() { Type = kind }; + string expectedResult = @$"{{""type"":""{value}""}}"; + + string result = JsonConvert.SerializeObject(container); + + Assert.Equal(expectedResult, result); + } + + [Theory] + [InlineData(ReactionTypeKind.Emoji, "emoji")] + [InlineData(ReactionTypeKind.CustomEmoji, "custom_emoji")] + public void Should_Convert_String_ToChatAction(ReactionTypeKind kind, string value) + { + Container expectedResult = new() { Type = kind }; + string jsonData = @$"{{""type"":""{value}""}}"; + + Container? result = JsonConvert.DeserializeObject(jsonData); + + Assert.NotNull(result); + Assert.Equal(expectedResult.Type, result.Type); + } + + [Fact] + public void Should_Return_Zero_For_Incorrect_ChatAction() + { + string jsonData = @$"{{""type"":""{int.MaxValue}""}}"; + + Container? result = JsonConvert.DeserializeObject(jsonData); + + Assert.NotNull(result); + Assert.Equal((ReactionTypeKind)0, result.Type); + } + + [Fact] + public void Should_Throw_NotSupportedException_For_Incorrect_ChatAction() + { + Container container = new() { Type = (ReactionTypeKind)int.MaxValue }; + + Assert.Throws(() => JsonConvert.SerializeObject(container)); + } + + [JsonObject(MemberSerialization.OptIn, NamingStrategyType = typeof(SnakeCaseNamingStrategy))] + class Container + { + [JsonProperty(Required = Required.Always)] + public ReactionTypeKind Type { get; init; } + } +} diff --git a/test/Telegram.Bot.Tests.Unit/EnumConverter/UpdateTypeConverterTests.cs b/test/Telegram.Bot.Tests.Unit/EnumConverter/UpdateTypeConverterTests.cs index ba3ade3b3..545fc07b0 100644 --- a/test/Telegram.Bot.Tests.Unit/EnumConverter/UpdateTypeConverterTests.cs +++ b/test/Telegram.Bot.Tests.Unit/EnumConverter/UpdateTypeConverterTests.cs @@ -1,4 +1,7 @@ using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; using Newtonsoft.Json; using Newtonsoft.Json.Serialization; using Telegram.Bot.Types.Enums; @@ -8,22 +11,25 @@ namespace Telegram.Bot.Tests.Unit.EnumConverter; public class UpdateTypeConverterTests { + [Fact] + public void Should_Verify_All_UpdateType_Members() + { + List updateTypeMembers = Enum + .GetNames() + .OrderBy(x => x) + .ToList(); + List updateTypeDataMembers = new UpdateTypeData() + .Select(x => Enum.GetName(typeof(UpdateType), x[0])) + .OrderBy(x => x) + .ToList()!; + + Assert.Equal(updateTypeMembers.Count, updateTypeDataMembers.Count); + Assert.Equal(updateTypeMembers, updateTypeDataMembers); + } + + [Theory] - [InlineData(UpdateType.Unknown, "unknown")] - [InlineData(UpdateType.Message, "message")] - [InlineData(UpdateType.InlineQuery, "inline_query")] - [InlineData(UpdateType.ChosenInlineResult, "chosen_inline_result")] - [InlineData(UpdateType.CallbackQuery, "callback_query")] - [InlineData(UpdateType.EditedMessage, "edited_message")] - [InlineData(UpdateType.ChannelPost, "channel_post")] - [InlineData(UpdateType.EditedChannelPost, "edited_channel_post")] - [InlineData(UpdateType.ShippingQuery, "shipping_query")] - [InlineData(UpdateType.PreCheckoutQuery, "pre_checkout_query")] - [InlineData(UpdateType.Poll, "poll")] - [InlineData(UpdateType.PollAnswer, "poll_answer")] - [InlineData(UpdateType.MyChatMember, "my_chat_member")] - [InlineData(UpdateType.ChatMember, "chat_member")] - [InlineData(UpdateType.ChatJoinRequest, "chat_join_request")] + [ClassData(typeof(UpdateTypeData))] public void Should_Convert_UpdateType_To_String(UpdateType updateType, string value) { Update update = new(updateType); @@ -38,7 +44,7 @@ public void Should_Convert_UpdateType_To_String(UpdateType updateType, string va } [Theory] - [InlineData(UpdateType.Unknown, "unknown")] + [ClassData(typeof(UpdateTypeData))] public void Should_Convert_String_To_UpdateType(UpdateType updateType, string value) { Update expectedResult = new(updateType); @@ -77,4 +83,32 @@ public void Should_Throw_NotSupportedException_For_Incorrect_UpdateType() [JsonObject(MemberSerialization.OptIn, NamingStrategyType = typeof(SnakeCaseNamingStrategy))] record Update([property: JsonProperty(Required = Required.Always)] UpdateType Type); + + private class UpdateTypeData : IEnumerable + { + public IEnumerator GetEnumerator() + { + yield return new object[] { UpdateType.Unknown, "unknown" }; + yield return new object[] { UpdateType.Message, "message" }; + yield return new object[] { UpdateType.EditedMessage, "edited_message" }; + yield return new object[] { UpdateType.ChannelPost, "channel_post" }; + yield return new object[] { UpdateType.EditedChannelPost, "edited_channel_post" }; + yield return new object[] { UpdateType.MessageReaction, "message_reaction" }; + yield return new object[] { UpdateType.MessageReactionCount, "message_reaction_count" }; + yield return new object[] { UpdateType.InlineQuery, "inline_query" }; + yield return new object[] { UpdateType.ChosenInlineResult, "chosen_inline_result" }; + yield return new object[] { UpdateType.CallbackQuery, "callback_query" }; + yield return new object[] { UpdateType.ShippingQuery, "shipping_query" }; + yield return new object[] { UpdateType.PreCheckoutQuery, "pre_checkout_query" }; + yield return new object[] { UpdateType.Poll, "poll" }; + yield return new object[] { UpdateType.PollAnswer, "poll_answer" }; + yield return new object[] { UpdateType.MyChatMember, "my_chat_member" }; + yield return new object[] { UpdateType.ChatMember, "chat_member" }; + yield return new object[] { UpdateType.ChatJoinRequest, "chat_join_request" }; + yield return new object[] { UpdateType.ChatBoost, "chat_boost" }; + yield return new object[] { UpdateType.RemovedChatBoost, "removed_chat_boost" }; + } + + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + } } diff --git a/test/Telegram.Bot.Tests.Unit/Serialization/ChatBoostAddedSerializationTests.cs b/test/Telegram.Bot.Tests.Unit/Serialization/ChatBoostAddedSerializationTests.cs new file mode 100644 index 000000000..d0620d831 --- /dev/null +++ b/test/Telegram.Bot.Tests.Unit/Serialization/ChatBoostAddedSerializationTests.cs @@ -0,0 +1,40 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using Telegram.Bot.Types; +using Xunit; + +namespace Telegram.Bot.Tests.Unit.Serialization; + +public class ChatBoostAddedSerializationTests +{ + [Fact] + public void Should_Deserialize_ChatBoostAdded() + { + const string chatBoostAdded = + """ + { + "boost_count": 101 + } + """; + + ChatBoostAdded? deserialize = JsonConvert.DeserializeObject(chatBoostAdded); + + Assert.NotNull(deserialize); + Assert.Equal(101, deserialize.BoostCount); + } + + [Fact] + public void Should_Serialize_ChatBoostAdded() + { + ChatBoostAdded chat = new() + { + BoostCount = 101, + }; + + string json = JsonConvert.SerializeObject(chat); + JObject j = JObject.Parse(json); + + Assert.Single(j.Children()); + Assert.Equal(101, j["boost_count"]); + } +} diff --git a/test/Telegram.Bot.Tests.Unit/Serialization/ChatMemberSerializationTests.cs b/test/Telegram.Bot.Tests.Unit/Serialization/ChatMemberSerializationTests.cs index 709e2062b..d4be6d138 100644 --- a/test/Telegram.Bot.Tests.Unit/Serialization/ChatMemberSerializationTests.cs +++ b/test/Telegram.Bot.Tests.Unit/Serialization/ChatMemberSerializationTests.cs @@ -1,5 +1,7 @@ using System; +using System.Linq; using Newtonsoft.Json; +using Newtonsoft.Json.Linq; using Telegram.Bot.Types; using Telegram.Bot.Types.Enums; using Xunit; @@ -11,24 +13,23 @@ public class ChatMemberSerializationTests [Fact] public void Should_Deserialize_Chat_Member_Member() { - var creator = new + const string json = """ { - status = ChatMemberStatus.Creator, - user = new - { - id = 12345, - is_bot = true, - first_name = "First Name", - last_name = "Last Name", - username = "test_bot", - language_code = "en_US", + "status": "creator", + "user": { + "id": 12345, + "is_bot": true, + "first_name": "First Name", + "last_name": "Last Name", + "username": "test_bot", + "language_code": "en_US", }, - is_anonymous = true, - custom_title = "custom test title" - }; + "is_anonymous": true, + "custom_title": "custom test title" + } + """; - string? chatMemberJson = JsonConvert.SerializeObject(creator, Formatting.Indented); - ChatMember? chatMember = JsonConvert.DeserializeObject(chatMemberJson); + ChatMember? chatMember = JsonConvert.DeserializeObject(json); ChatMemberOwner owner = Assert.IsType(chatMember); @@ -62,17 +63,24 @@ public void Should_Serialize_Chat_Member_Member() CustomTitle = "Custom test title" }; - string? chatMemberJson = JsonConvert.SerializeObject(creator); - Assert.Contains(@"""status"":""creator""", chatMemberJson); - Assert.Contains(@"""is_anonymous"":true", chatMemberJson); - Assert.Contains(@"""custom_title"":""Custom test title""", chatMemberJson); - Assert.Contains(@"""user"":{", chatMemberJson); - Assert.Contains(@"""id"":12345", chatMemberJson); - Assert.Contains(@"""is_bot"":true", chatMemberJson); - Assert.Contains(@"""first_name"":""First Name""", chatMemberJson); - Assert.Contains(@"""last_name"":""Last Name""", chatMemberJson); - Assert.Contains(@"""username"":""test_bot""", chatMemberJson); - Assert.Contains(@"""language_code"":""en_US""", chatMemberJson); + string chatMemberJson = JsonConvert.SerializeObject(creator); + JObject j = JObject.Parse(chatMemberJson); + + Assert.Equal(4, j.Children().Count()); + Assert.Equal("creator", j["status"]); + Assert.Equal(true, j["is_anonymous"]); + Assert.Equal("Custom test title", j["custom_title"]); + + JToken? ju = j["user"]; + Assert.NotNull(ju); + + Assert.Equal(6, ju.Children().Count()); + Assert.Equal(12345, ju["id"]); + Assert.Equal(true, ju["is_bot"]); + Assert.Equal("First Name", ju["first_name"]); + Assert.Equal("Last Name", ju["first_name"]); + Assert.Equal("test_bot", ju["username"]); + Assert.Equal("en_US", ju["language_code"]); } [Fact] @@ -92,17 +100,24 @@ public void Should_Serialize_Chat_Member_Banned() UntilDate = new(2021, 4, 2, 0, 0, 0, DateTimeKind.Utc) }; - string? chatMemberJson = JsonConvert.SerializeObject(creator); - - Assert.Contains(@"""until_date"":1617321600", chatMemberJson); - Assert.Contains(@"""status"":""kicked""", chatMemberJson); - Assert.Contains(@"""user"":{", chatMemberJson); - Assert.Contains(@"""id"":12345", chatMemberJson); - Assert.Contains(@"""is_bot"":true", chatMemberJson); - Assert.Contains(@"""first_name"":""First Name""", chatMemberJson); - Assert.Contains(@"""last_name"":""Last Name""", chatMemberJson); - Assert.Contains(@"""username"":""test_bot""", chatMemberJson); - Assert.Contains(@"""language_code"":""en_US""", chatMemberJson); + string chatMemberJson = JsonConvert.SerializeObject(creator); + JObject j = JObject.Parse(chatMemberJson); + + Assert.Equal(3, j.Children().Count()); + Assert.Equal(1617321600, j["until_date"]); + Assert.Equal("kicked", j["status"]); + Assert.True(j.ContainsKey("user")); + + JToken? ju = j["user"]; + Assert.NotNull(ju); + + Assert.Equal(6, ju.Children().Count()); + Assert.Equal(12345, ju["id"]); + Assert.Equal(true, ju["is_bot"]); + Assert.Equal("First Name", ju["first_name"]); + Assert.Equal("Last Name", ju["first_name"]); + Assert.Equal("test_bot", ju["username"]); + Assert.Equal("en_US", ju["language_code"]); } [Fact] @@ -122,16 +137,22 @@ public void Should_Serialize_Chat_Member_Banned_2() }; string chatMemberJson = JsonConvert.SerializeObject(creator); - - Assert.DoesNotContain(@"""until_date""", chatMemberJson); - Assert.Contains(@"""status"":""kicked""", chatMemberJson); - Assert.Contains(@"""user"":{", chatMemberJson); - Assert.Contains(@"""id"":12345", chatMemberJson); - Assert.Contains(@"""is_bot"":true", chatMemberJson); - Assert.Contains(@"""first_name"":""First Name""", chatMemberJson); - Assert.Contains(@"""last_name"":""Last Name""", chatMemberJson); - Assert.Contains(@"""username"":""test_bot""", chatMemberJson); - Assert.Contains(@"""language_code"":""en_US""", chatMemberJson); + JObject j = JObject.Parse(chatMemberJson); + + Assert.Equal(2, j.Children().Count()); + Assert.False(j.ContainsKey("until_date")); + Assert.Equal("kicked", j["status"]); + + JToken? ju = j["user"]; + Assert.NotNull(ju); + + Assert.Equal(6, ju.Children().Count()); + Assert.Equal(12345, ju["id"]); + Assert.Equal(true, ju["is_bot"]); + Assert.Equal("First Name", ju["first_name"]); + Assert.Equal("Last Name", ju["first_name"]); + Assert.Equal("test_bot", ju["username"]); + Assert.Equal("en_US", ju["language_code"]); } [Fact] diff --git a/test/Telegram.Bot.Tests.Unit/Serialization/ChatSerializationTests.cs b/test/Telegram.Bot.Tests.Unit/Serialization/ChatSerializationTests.cs new file mode 100644 index 000000000..7b4d330bf --- /dev/null +++ b/test/Telegram.Bot.Tests.Unit/Serialization/ChatSerializationTests.cs @@ -0,0 +1,55 @@ +using System.Linq; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using Telegram.Bot.Types; +using Telegram.Bot.Types.Enums; +using Xunit; + +namespace Telegram.Bot.Tests.Unit.Serialization; + +public class ChatSerializationTests +{ + [Fact] + public void Should_Deserialize_Chat() + { + const string chat = + """ + { + "id": 12345, + "type": "supergroup", + "unrestrict_boost_count": 10, + "custom_emoji_sticker_set_name": "test_sticker_set" + } + """; + + Chat? deserialize = JsonConvert.DeserializeObject(chat); + + Assert.NotNull(deserialize); + Assert.Equal(10, deserialize.UnrestrictBoostCount); + Assert.Equal(12345, deserialize.Id); + Assert.Equal(ChatType.Supergroup, deserialize.Type); + Assert.Equal("test_sticker_set", deserialize.CustomEmojiStickerSetName); + } + + [Fact] + public void Should_Serialize_Chat() + { + Chat chat = new() + { + Id = 1000, + Type = ChatType.Supergroup, + UnrestrictBoostCount = 10, + CustomEmojiStickerSetName = "test_sticker_set" + }; + + string json = JsonConvert.SerializeObject(chat); + + JObject j = JObject.Parse(json); + + Assert.Equal(4, j.Children().Count()); + Assert.Equal(chat.UnrestrictBoostCount, j["unrestrict_boost_count"]); + Assert.Equal("supergroup", j["type"]); + Assert.Equal(chat.Id, j["id"]); + Assert.Equal(chat.CustomEmojiStickerSetName, j["custom_emoji_sticker_set_name"]); + } +} diff --git a/test/Telegram.Bot.Tests.Unit/Serialization/ChatSourceBoostSerializationTests.cs b/test/Telegram.Bot.Tests.Unit/Serialization/ChatSourceBoostSerializationTests.cs new file mode 100644 index 000000000..61d2274ec --- /dev/null +++ b/test/Telegram.Bot.Tests.Unit/Serialization/ChatSourceBoostSerializationTests.cs @@ -0,0 +1,208 @@ +using System; +using System.Linq; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using Telegram.Bot.Types; +using Telegram.Bot.Types.Enums; +using Xunit; + +namespace Telegram.Bot.Tests.Unit.Serialization; + +public class ChatSourceBoostSerializationTests +{ + [Fact] + public void Should_Serialize_ChatBoostSourcePremium() + { + ChatBoostSourcePremium creator = new() + { + User = new() + { + Id = 12345, + IsBot = true, + FirstName = "First Name", + LastName = "Last Name", + Username = "test_bot", + LanguageCode = "en_US", + }, + }; + + string chatMemberJson = JsonConvert.SerializeObject(creator); + JObject j = JObject.Parse(chatMemberJson); + + Assert.Equal(2, j.Children().Count()); + Assert.Equal("premium", j["source"]); + + JToken? ju = j["user"]; + Assert.NotNull(ju); + + Assert.Equal(6, ju.Children().Count()); + Assert.Equal(12345, ju["id"]); + Assert.Equal(true, ju["is_bot"]); + Assert.Equal("First Name", ju["first_name"]); + Assert.Equal("Last Name", ju["first_name"]); + Assert.Equal("test_bot", ju["username"]); + Assert.Equal("en_US", ju["language_code"]); + } + + [Fact] + public void Should_Serialize_ChatBoostSourceGiveaway() + { + ChatBoostSourceGiveaway creator = new() + { + User = new() + { + Id = 12345, + IsBot = true, + FirstName = "First Name", + LastName = "Last Name", + Username = "test_bot", + LanguageCode = "en_US", + }, + GiveawayMessageId = 654321, + IsUnclaimed = true, + }; + + string chatMemberJson = JsonConvert.SerializeObject(creator); + JObject j = JObject.Parse(chatMemberJson); + + Assert.Equal(4, j.Children().Count()); + Assert.Equal("giveaway", j["source"]); + Assert.Equal(654321, j["giveaway_message_id"]); + Assert.Equal(true, j["is_unclaimed"]); + + JToken? ju = j["user"]; + Assert.NotNull(ju); + + Assert.Equal(6, ju.Children().Count()); + Assert.Equal(12345, ju["id"]); + Assert.Equal(true, ju["is_bot"]); + Assert.Equal("First Name", ju["first_name"]); + Assert.Equal("Last Name", ju["first_name"]); + Assert.Equal("test_bot", ju["username"]); + Assert.Equal("en_US", ju["language_code"]); + } + + [Fact] + public void Should_Serialize_ChatBoostSourceGiftCode() + { + ChatBoostSourceGiftCode creator = new() + { + User = new() + { + Id = 12345, + IsBot = true, + FirstName = "First Name", + LastName = "Last Name", + Username = "test_bot", + LanguageCode = "en_US", + }, + }; + + string chatMemberJson = JsonConvert.SerializeObject(creator); + JObject j = JObject.Parse(chatMemberJson); + + Assert.Equal(2, j.Children().Count()); + + JToken? ju = j["user"]; + Assert.NotNull(ju); + + Assert.Equal(6, ju.Children().Count()); + Assert.Equal(12345, ju["id"]); + Assert.Equal(true, ju["is_bot"]); + Assert.Equal("First Name", ju["first_name"]); + Assert.Equal("Last Name", ju["first_name"]); + Assert.Equal("test_bot", ju["username"]); + Assert.Equal("en_US", ju["language_code"]); + } + + [Fact] + public void Should_Deserialize_ChatBoostPremium() + { + const string json = """ + { + "source": "premium", + "user": { + "id": 123, + "is_premium": true, + "is_bot": false, + "first_name": "Test User" + } + } + """; + + ChatBoostSource? boostSource = JsonConvert.DeserializeObject(json); + + ChatBoostSourcePremium premium = Assert.IsAssignableFrom(boostSource); + + Assert.Equal(ChatBoostSourceType.Premium, premium.Source); + Assert.Equal(123, premium.User.Id); + Assert.True(premium.User.IsPremium); + Assert.NotNull(premium.User); + Assert.Equal("Test User", premium.User.FirstName); + } + + + [Fact] + public void Should_Deserialize_ChatBoostSourceGiftCode() + { + string json = """ + { + "source": "gift_code", + "user": { + "id": 12345, + "is_bot": true, + "first_name": "First Name", + "last_name": "Last Name", + "username": "test_bot", + "language_code": "en_US" + } + } + """; + + ChatBoostSourceGiftCode? giveaway = JsonConvert.DeserializeObject(json); + + Assert.NotNull(giveaway); + Assert.Equal(ChatBoostSourceType.GiftCode, giveaway.Source); + Assert.NotNull(giveaway.User); + Assert.Equal(12345, giveaway.User.Id); + Assert.True(giveaway.User.IsBot); + Assert.Equal("First Name", giveaway.User.FirstName); + Assert.Equal("Last Name", giveaway.User.LastName); + Assert.Equal("test_bot", giveaway.User.Username); + Assert.Equal("en_US", giveaway.User.LanguageCode); + } + + [Fact] + public void Should_Deserialize_ChatBoostSourceGiveaway() + { + string json = """ + { + "source": "giveaway", + "giveaway_message_id": 12345, + "is_unclaimed": true, + "user": { + "id": 12345, + "is_bot": true, + "first_name": "First Name", + "last_name": "Last Name", + "username": "test_bot", + "language_code": "en_US" + } + } + """; + + ChatBoostSourceGiveaway? giveaway = JsonConvert.DeserializeObject(json); + + Assert.NotNull(giveaway); + Assert.Equal(ChatBoostSourceType.Giveaway, giveaway.Source); + Assert.True(giveaway.IsUnclaimed); + Assert.Equal(12345, giveaway.GiveawayMessageId); + Assert.NotNull(giveaway.User); + Assert.Equal(12345, giveaway.User.Id); + Assert.True(giveaway.User.IsBot); + Assert.Equal("First Name", giveaway.User.FirstName); + Assert.Equal("Last Name", giveaway.User.LastName); + Assert.Equal("test_bot", giveaway.User.Username); + Assert.Equal("en_US", giveaway.User.LanguageCode); + } +} diff --git a/test/Telegram.Bot.Tests.Unit/Serialization/DocumentSerializationTests.cs b/test/Telegram.Bot.Tests.Unit/Serialization/DocumentSerializationTests.cs index b787064b1..ec7e2ee15 100644 --- a/test/Telegram.Bot.Tests.Unit/Serialization/DocumentSerializationTests.cs +++ b/test/Telegram.Bot.Tests.Unit/Serialization/DocumentSerializationTests.cs @@ -1,5 +1,7 @@ using System; +using System.Linq; using Newtonsoft.Json; +using Newtonsoft.Json.Linq; using Telegram.Bot.Types; using Telegram.Bot.Types.Enums; using Xunit; @@ -35,16 +37,44 @@ public void Should_Serialize_DocumentMessage() FileSize = 123_456, MimeType = "plain/text" }, - Date = DateTime.UtcNow, + Date = new(2024, 1, 1, 10, 0, 0, DateTimeKind.Utc), Caption = "Test Document Description" }; string json = JsonConvert.SerializeObject(documentMessage); Assert.NotNull(json); - Assert.True(json.Length > 100); - Assert.Contains(@"""file_id"":""KLAHCVUydfS_jHIBildtwpmvxZg""", json); - Assert.Contains(@"""can_set_sticker_set"":true", json); + + JObject j = JObject.Parse(json); + Assert.Equal(6, j.Children().Count()); + Assert.Equal(1234, j["message_id"]); + Assert.Equal("Test Document Description", j["caption"]); + Assert.Equal(1704088800, j["date"]); + + JToken? document = j["document"]; + Assert.NotNull(document); + Assert.Equal(5, document.Children().Count()); + Assert.Equal("KLAHCVUydfS_jHIBildtwpmvxZg", document["file_id"]); + Assert.Equal("AgADcOsAAhUdZAc", document["file_unique_id"]); + Assert.Equal("test_file.txt", document["file_name"]); + Assert.Equal(123_456, document["file_size"]); + Assert.Equal("plain/text", document["mime_type"]); + + JToken? user = j["from"]; + Assert.NotNull(user); + Assert.Equal(4, user.Children().Count()); + Assert.Equal(123_456_789, user["id"]); + Assert.Equal("TelegramBots", user["first_name"]); + Assert.Equal("Telegram_Bots", user["username"]); + Assert.Equal(false, user["is_bot"]); + + JToken? chat = j["chat"]; + Assert.NotNull(chat); + Assert.Equal(4, chat.Children().Count()); + Assert.Equal(-9_877_654_320_000, chat["id"]); + Assert.Equal("Test Chat", chat["title"]); + Assert.Equal("supergroup", chat["type"]); + Assert.Equal(true, chat["can_set_sticker_set"]); } [Fact(DisplayName = "Should deserialize a document message")] diff --git a/test/Telegram.Bot.Tests.Unit/Serialization/InputFileSerializationTests.cs b/test/Telegram.Bot.Tests.Unit/Serialization/InputFileSerializationTests.cs index fe5ff997a..e33a19586 100644 --- a/test/Telegram.Bot.Tests.Unit/Serialization/InputFileSerializationTests.cs +++ b/test/Telegram.Bot.Tests.Unit/Serialization/InputFileSerializationTests.cs @@ -2,7 +2,6 @@ using System.IO; using Newtonsoft.Json; using Telegram.Bot.Types; -using Telegram.Bot.Types.Enums; using Xunit; namespace Telegram.Bot.Tests.Unit.Serialization; @@ -13,15 +12,12 @@ public class InputFileSerializationTests public void Should_Serialize_InputFile() { const string fileName = "myFile"; - InputFileStream inputFile = new(new MemoryStream(), fileName); + using MemoryStream memoryStream = new(); + InputFileStream inputFile = new(memoryStream, fileName); - string json = JsonConvert.SerializeObject(inputFile); - InputFileStream obj = JsonConvert.DeserializeObject(json)!; + string serializedValue = JsonConvert.SerializeObject(inputFile); - Assert.Equal(@$"""attach://{fileName}""", json); - Assert.Equal(Stream.Null, obj.Content); - Assert.Equal(fileName, obj.FileName); - Assert.Equal(FileType.Stream, obj.FileType); + Assert.Equal(@$"""attach://{fileName}""", serializedValue); } [Fact(DisplayName = "Should serialize & deserialize input file with file_id")] @@ -30,27 +26,19 @@ public void Should_Serialize_FileId() const string fileId = "This-is-a-file_id"; InputFileId inputFileId = new(fileId); - string json = JsonConvert.SerializeObject(inputFileId); - InputFileId? obj = JsonConvert.DeserializeObject(json); + string serializedValue = JsonConvert.SerializeObject(inputFileId); - Assert.NotNull(obj); - Assert.Equal(@$"""{fileId}""", json); - Assert.Equal(fileId, obj.Id); - Assert.Equal(FileType.Id, obj.FileType); + Assert.Equal($"\"{fileId}\"", serializedValue); } [Fact(DisplayName = "Should serialize & deserialize input file with URL")] public void Should_Serialize_InputUrlFile() { - Uri url = new("http://github.org/TelegramBots"); + Uri url = new("https://github.com/TelegramBots"); InputFileUrl inputFileUrl = new(url); - string json = JsonConvert.SerializeObject(inputFileUrl); - InputFileUrl? obj = JsonConvert.DeserializeObject(json); + string serializedValue = JsonConvert.SerializeObject(inputFileUrl); - Assert.NotNull(obj); - Assert.Equal(@$"""{url}""", json); - Assert.Equal(url, obj.Url); - Assert.Equal(FileType.Url, obj.FileType); + Assert.Equal($"\"{url}\"", serializedValue); } } diff --git a/test/Telegram.Bot.Tests.Unit/Serialization/InputQueryResultTests.cs b/test/Telegram.Bot.Tests.Unit/Serialization/InputQueryResultTests.cs index 9c011b76c..20abec4f6 100644 --- a/test/Telegram.Bot.Tests.Unit/Serialization/InputQueryResultTests.cs +++ b/test/Telegram.Bot.Tests.Unit/Serialization/InputQueryResultTests.cs @@ -1,4 +1,6 @@ +using System.Linq; using Newtonsoft.Json; +using Newtonsoft.Json.Linq; using Telegram.Bot.Requests; using Telegram.Bot.Types.InlineQueryResults; using Xunit; @@ -11,7 +13,7 @@ public class InputQueryResultTests public void Should_Serialize_InlineQueryResultMpeg4Gif_With_ThumbMimeType() { InlineQueryResult[] results = - { + [ new InlineQueryResultMpeg4Gif( id: "mpeg4_gif_result_with_video_thumb", mpeg4Url: "https://pixabay.com/en/videos/download/video-14205_tiny.mp4", @@ -19,19 +21,32 @@ public void Should_Serialize_InlineQueryResultMpeg4Gif_With_ThumbMimeType() { Caption = "A frozing bubble", ThumbnailMimeType = "video/mp4" - }, - }; + } + ]; AnswerInlineQueryRequest request = new("query_id", results) { CacheTime = 0 }; string json = JsonConvert.SerializeObject(request); - Assert.Contains(@"""thumbnail_mime_type"":""video/mp4""", json); + JObject j = JObject.Parse(json); + Assert.Equal(3, j.Children().Count()); + Assert.Equal("query_id", j["inline_query_id"]); + Assert.Equal(0, j["cache_time"]); + + JArray ja = Assert.IsType(j["results"]); + Assert.Single(ja); + + JToken element = ja[0]; + Assert.Equal("video/mp4", element["thumbnail_mime_type"]); + Assert.Equal("gif_result_with_video_thumb", element["id"]); + Assert.Equal("A frozing bubble", element["caption"]); + Assert.Equal("https://pixabay.com/en/videos/download/video-14205_tiny.mp4", element["mpeg4_url"]); + Assert.Equal("https://pixabay.com/en/videos/download/video-14205_tiny.mp4", element["thumbnail_url"]); } [Fact(DisplayName = "Should serialize InlineQueryResultGif with ThumbMimeType")] public void Should_Serialize_InlineQueryResultGif_With_ThumbMimeType() { InlineQueryResult[] results = - { + [ new InlineQueryResultGif( id: "gif_result_with_video_thumb", gifUrl: "https://upload.wikimedia.org/wikipedia/commons/2/2c/Rotating_earth_%28large%29.gif", @@ -39,12 +54,25 @@ public void Should_Serialize_InlineQueryResultGif_With_ThumbMimeType() { Caption = "A frozing bubble", ThumbnailMimeType = "video/mp4" - }, - }; + } + ]; AnswerInlineQueryRequest request = new("query_id", results) { CacheTime = 0 }; string json = JsonConvert.SerializeObject(request); - Assert.Contains(@"""thumbnail_mime_type"":""video/mp4""", json); + JObject j = JObject.Parse(json); + Assert.Equal(3, j.Children().Count()); + Assert.Equal("query_id", j["inline_query_id"]); + Assert.Equal(0, j["cache_time"]); + + JArray ja = Assert.IsType(j["results"]); + Assert.Single(ja); + + JToken element = ja[0]; + Assert.Equal("video/mp4", element["thumbnail_mime_type"]); + Assert.Equal("gif_result_with_video_thumb", element["id"]); + Assert.Equal("A frozing bubble", element["caption"]); + Assert.Equal("https://upload.wikimedia.org/wikipedia/commons/2/2c/Rotating_earth_%28large%29.gif", element["gif_url"]); + Assert.Equal("https://pixabay.com/en/videos/download/video-14205_tiny.mp4", element["thumbnail_url"]); } } diff --git a/test/Telegram.Bot.Tests.Unit/Serialization/InputStickerSerializationTests.cs b/test/Telegram.Bot.Tests.Unit/Serialization/InputStickerSerializationTests.cs index 41cb35e86..469fff2ad 100644 --- a/test/Telegram.Bot.Tests.Unit/Serialization/InputStickerSerializationTests.cs +++ b/test/Telegram.Bot.Tests.Unit/Serialization/InputStickerSerializationTests.cs @@ -1,6 +1,8 @@ using System; using System.IO; +using System.Linq; using Newtonsoft.Json; +using Newtonsoft.Json.Linq; using Telegram.Bot.Types; using Telegram.Bot.Types.Enums; using Xunit; @@ -14,19 +16,21 @@ public void Should_Serialize_InputFile() { const string fileName = "myFile"; InputFileStream inputFile = new(new MemoryStream(), fileName); - string[] emojiList = { "🙂" }; + string[] emojiList = ["🙂"]; InputSticker inputSticker = new(inputFile, emojiList); string json = JsonConvert.SerializeObject(inputSticker); - InputSticker obj = JsonConvert.DeserializeObject(json)!; + JObject j = JObject.Parse(json); - InputFileStream objInputFile = (InputFileStream)obj.Sticker; + Assert.Equal(2, j.Children().Count()); + Assert.Equal($"attach://{fileName}", j["sticker"]); - Assert.Equal(emojiList, obj.EmojiList); - Assert.Contains(@$"""sticker"":""attach://{fileName}""", json); - Assert.Equal(Stream.Null, objInputFile.Content); - Assert.Equal(fileName, objInputFile.FileName); - Assert.Equal(FileType.Stream, objInputFile.FileType); + JToken? je = j["emoji_list"]; + Assert.NotNull(je); + + JArray jEmojiList = Assert.IsType(je); + Assert.Single(jEmojiList); + Assert.Equal("🙂", jEmojiList[0]); } [Fact(DisplayName = "Should serialize & deserialize input sticker with input file id")] @@ -34,40 +38,41 @@ public void Should_Serialize_FileId() { const string fileId = "This-is-a-file_id"; InputFileId inputFileId = new(fileId); - string[] emojiList = new[] { "🙂" }; - InputSticker inputStickerFileId = new InputSticker(inputFileId, emojiList); + string[] emojiList = ["🙂"]; + InputSticker inputStickerFileId = new(inputFileId, emojiList); string json = JsonConvert.SerializeObject(inputStickerFileId); - InputSticker? obj = JsonConvert.DeserializeObject(json); + JObject j = JObject.Parse(json); + + Assert.Equal(2, j.Children().Count()); + Assert.Equal("This-is-a-file_id", j["sticker"]); - InputFileId? objInputFileId = (InputFileId?)obj?.Sticker; + JToken? je = j["emoji_list"]; + Assert.NotNull(je); - Assert.NotNull(obj); - Assert.Equal(emojiList, obj.EmojiList); - Assert.NotNull(objInputFileId); - Assert.Contains(@$"""sticker"":""{fileId}""", json); - Assert.Equal(fileId, objInputFileId.Id); - Assert.Equal(FileType.Id, objInputFileId.FileType); + JArray jEmojiList = Assert.IsType(je); + Assert.Single(jEmojiList); + Assert.Equal("🙂", jEmojiList[0]); } [Fact(DisplayName = "Should serialize & deserialize input sticker with input file URL")] public void Should_Serialize_InputUrlFile() { - Uri url = new("http://github.org/TelegramBots"); + Uri url = new("https://github.com/TelegramBots"); InputFileUrl inputFileUrl = new(url); - string[] emojiList = new[] { "🙂" }; - InputSticker inputStickerFileUrl = new InputSticker(inputFileUrl, emojiList); + string[] emojiList = ["🙂"]; + InputSticker inputStickerFileUrl = new(inputFileUrl, emojiList); string json = JsonConvert.SerializeObject(inputStickerFileUrl); - InputSticker? obj = JsonConvert.DeserializeObject(json); + JObject j = JObject.Parse(json); - InputFileUrl? objInputFileUrl = (InputFileUrl?)obj?.Sticker; + Assert.Equal(2, j.Children().Count()); + Assert.Equal("https://github.com/TelegramBots", j["sticker"]); - Assert.NotNull(obj); - Assert.Equal(emojiList, obj.EmojiList); - Assert.NotNull(objInputFileUrl); - Assert.Contains(@$"""sticker"":""{url}""", json); - Assert.Equal(url, objInputFileUrl.Url); - Assert.Equal(FileType.Url, objInputFileUrl.FileType); + JToken? je = j["emoji_list"]; + Assert.NotNull(je); + JArray jEmojiList = Assert.IsType(je); + Assert.Single(jEmojiList); + Assert.Equal("🙂", jEmojiList[0]); } } diff --git a/test/Telegram.Bot.Tests.Unit/Serialization/MenuButtonSerializationTests.cs b/test/Telegram.Bot.Tests.Unit/Serialization/MenuButtonSerializationTests.cs index 3d6e058d1..1ad491cc1 100644 --- a/test/Telegram.Bot.Tests.Unit/Serialization/MenuButtonSerializationTests.cs +++ b/test/Telegram.Bot.Tests.Unit/Serialization/MenuButtonSerializationTests.cs @@ -1,4 +1,6 @@ -using Newtonsoft.Json; +using System.Linq; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; using Telegram.Bot.Types; using Telegram.Bot.Types.Enums; using Xunit; @@ -10,15 +12,17 @@ public class MenuButtonSerializationTests [Fact] public void Should_Deserialize_Menu_Button_Web_App() { - var button = new + const string button = """ { - type = MenuButtonType.WebApp, - text = "Test text", - web_app = new { url = "https://example.com/link/to/web/app" } - }; + "type": "web_app", + "text": "Test text", + "web_app": { + "url": "https://example.com/link/to/web/app" + } + } + """; - string menuButtonJson = JsonConvert.SerializeObject(button, Formatting.Indented); - MenuButton? menuButton = JsonConvert.DeserializeObject(menuButtonJson); + MenuButton? menuButton = JsonConvert.DeserializeObject(button); MenuButtonWebApp webAppButton = Assert.IsType(menuButton); @@ -35,15 +39,21 @@ public void Should_Serialize_Menu_Button_Web_App() { MenuButtonWebApp webAppButton = new() { - WebApp = new() { Url = "https://example.com/link/to/web/app" }, + WebApp = new(url: "https://example.com/link/to/web/app"), Text = "Test text" }; string webAppButtonJson = JsonConvert.SerializeObject(webAppButton); - Assert.Contains(@"""type"":""web_app""", webAppButtonJson); - Assert.Contains(@"""text"":""Test text""", webAppButtonJson); - Assert.Contains(@"""web_app"":{", webAppButtonJson); - Assert.Contains(@"""url"":""https://example.com/link/to/web/app""", webAppButtonJson); + JObject j = JObject.Parse(webAppButtonJson); + + Assert.Equal(3, j.Children().Count()); + Assert.Equal("web_app", j["type"]); + Assert.Equal("Test text", j["text"]); + + JToken? jWebApp = j["web_app"]; + Assert.NotNull(jWebApp); + Assert.Single(jWebApp); + Assert.Equal("https://example.com/link/to/web/app", jWebApp["url"]); } [Fact] @@ -65,7 +75,9 @@ public void Should_Serialize_Menu_Button_Default() MenuButtonDefault menuButton = new(); string menuButtonJson = JsonConvert.SerializeObject(menuButton); - Assert.Contains(@"""type"":""default""", menuButtonJson); + JObject j = JObject.Parse(menuButtonJson); + Assert.Single(j); + Assert.Equal("default", j["type"]); } [Fact] @@ -73,12 +85,11 @@ public void Should_Deserialize_Menu_Button_Commands() { var button = new { type = MenuButtonType.Commands, }; - string menuButtonJson = JsonConvert.SerializeObject(button, Formatting.Indented); - MenuButton? menuButton = JsonConvert.DeserializeObject(menuButtonJson); + string menuButtonJson = JsonConvert.SerializeObject(button); + JObject j = JObject.Parse(menuButtonJson); - Assert.NotNull(menuButton); - Assert.Equal(MenuButtonType.Commands, menuButton.Type); - Assert.IsType(menuButton); + Assert.Single(j); + Assert.Equal("commands", j["type"]); } [Fact] @@ -87,6 +98,9 @@ public void Should_Serialize_Menu_Button_Commands() MenuButtonCommands menuButton = new(); string menuButtonJson = JsonConvert.SerializeObject(menuButton); - Assert.Contains(@"""type"":""commands""", menuButtonJson); + JObject j = JObject.Parse(menuButtonJson); + + Assert.Single(j); + Assert.Equal("commands", j["type"]); } } diff --git a/test/Telegram.Bot.Tests.Unit/Serialization/MessageEntityTests.cs b/test/Telegram.Bot.Tests.Unit/Serialization/MessageEntityTests.cs index 7fa242f11..7677c32d3 100644 --- a/test/Telegram.Bot.Tests.Unit/Serialization/MessageEntityTests.cs +++ b/test/Telegram.Bot.Tests.Unit/Serialization/MessageEntityTests.cs @@ -1,4 +1,6 @@ -using Newtonsoft.Json; +using System.Linq; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; using Telegram.Bot.Types; using Telegram.Bot.Types.Enums; using Xunit; @@ -34,11 +36,13 @@ public void Should_Serialize_Message_Entity_With_Phone_Number_Type() Type = MessageEntityType.PhoneNumber }; - string? json = JsonConvert.SerializeObject(messageEntity); + string json = JsonConvert.SerializeObject(messageEntity); + JObject j = JObject.Parse(json); - Assert.NotNull(json); - Assert.True(json.Length > 10); - Assert.Contains(@"""type"":""phone_number""", json); + Assert.Equal(3, j.Children().Count()); + Assert.Equal(10, j["length"]); + Assert.Equal(10, j["offset"]); + Assert.Equal("phone_number", j["type"]); } [Fact(DisplayName = "Should deserialize message entity with unknown type")] @@ -68,10 +72,12 @@ public void Should_Serialize_Message_Entity_With_Unknown_Type() Type = 0 }; - string? json = JsonConvert.SerializeObject(messageEntity); + string json = JsonConvert.SerializeObject(messageEntity); + JObject j = JObject.Parse(json); - Assert.NotNull(json); - Assert.True(json.Length > 10); - Assert.Contains(@"""type"":""unknown""", json); + Assert.Equal(3, j.Children().Count()); + Assert.Equal(10, j["length"]); + Assert.Equal(10, j["offset"]); + Assert.Equal("unknown", j["type"]); } } diff --git a/test/Telegram.Bot.Tests.Unit/Serialization/MessageOriginSerializationTests.cs b/test/Telegram.Bot.Tests.Unit/Serialization/MessageOriginSerializationTests.cs new file mode 100644 index 000000000..96e6cdd44 --- /dev/null +++ b/test/Telegram.Bot.Tests.Unit/Serialization/MessageOriginSerializationTests.cs @@ -0,0 +1,254 @@ +using System; +using System.Linq; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using Telegram.Bot.Types; +using Telegram.Bot.Types.Enums; +using Xunit; + +namespace Telegram.Bot.Tests.Unit.Serialization; + +public class MessageOriginSerializationTests +{ + [Fact] + public void Should_Serialize_MessageOriginUser() + { + MessageOriginUser origin = new() + { + SenderUser = new() + { + Id = 12345, + IsBot = true, + FirstName = "First Name", + LastName = "Last Name", + Username = "test_bot", + LanguageCode = "en_US", + }, + Date = new(2024, 2, 16, 18, 0, 0, 0, DateTimeKind.Utc) + }; + + string json = JsonConvert.SerializeObject(origin); + JObject j = JObject.Parse(json); + + Assert.Equal(3, j.Children().Count()); + Assert.Equal(1708106405, j["date"]); + + JToken? senderUser = j["sender_user"]; + Assert.NotNull(senderUser); + + Assert.Equal(6, senderUser.Children().Count()); + Assert.Equal(12345, senderUser["id"]); + Assert.Equal(true, senderUser["is_bot"]); + Assert.Equal("First Name", senderUser["first_name"]); + Assert.Equal("Last Name", senderUser["first_name"]); + Assert.Equal("test_bot", senderUser["username"]); + Assert.Equal("en_US", senderUser["language_code"]); + } + + [Fact] + public void Should_Serialize_MessageOriginHidden() + { + MessageOriginHiddenUser origin = new() + { + SenderUserName = "test_bot", + Date = new(2024, 2, 16, 18, 0, 0, 0, DateTimeKind.Utc) + }; + + string json = JsonConvert.SerializeObject(origin); + JObject j = JObject.Parse(json); + + Assert.Equal(3, j.Children().Count()); + Assert.Equal(1708106405, j["date"]); + + JToken? senderUser = j["sender_user_name"]; + Assert.NotNull(senderUser); + + Assert.Equal("test_bot", senderUser); + } + + [Fact] + public void Should_Serialize_MessageOriginChat() + { + MessageOriginChat origin = new() + { + SenderChat = new() + { + Id = 12345, + Type = ChatType.Supergroup, + Username = "test_group", + IsForum = true, + }, + Date = new(2024, 2, 16, 18, 0, 0, 0, DateTimeKind.Utc) + }; + + string json = JsonConvert.SerializeObject(origin); + JObject j = JObject.Parse(json); + + Assert.Equal(3, j.Children().Count()); + Assert.Equal(1708106405, j["date"]); + + JToken? senderChat = j["sender_chat"]; + Assert.NotNull(senderChat); + + Assert.Equal(4, senderChat.Children().Count()); + Assert.Equal(12345, senderChat["id"]); + Assert.Equal("supergroup", senderChat["type"]); + Assert.Equal("test_group", senderChat["username"]); + Assert.Equal(true, senderChat["is_forum"]); + } + + [Fact] + public void Should_Serialize_MessageOriginChannel() + { + MessageOriginChannel origin = new() + { + Chat = new() + { + Id = 12345, + Type = ChatType.Channel, + Username = "test_channel", + }, + MessageId = 1236886, + AuthorSignature = "author_name", + Date = new(2024, 2, 16, 18, 0, 0, 0, DateTimeKind.Utc) + }; + + string json = JsonConvert.SerializeObject(origin); + JObject j = JObject.Parse(json); + + Assert.Equal(5, j.Children().Count()); + Assert.Equal(1708106405, j["date"]); + Assert.Equal(1236886, j["message_id"]); + Assert.Equal("author_name", j["author_signature"]); + + JToken? chat = j["chat"]; + Assert.NotNull(chat); + + Assert.Equal(3, chat.Children().Count()); + Assert.Equal(12345, chat["id"]); + Assert.Equal("supergroup", chat["type"]); + Assert.Equal("test_group", chat["username"]); + } + + [Fact] + public void Should_Deserialize_MessageOriginUser() + { + const string origin = + """ + { + "type": "user", + "sender_user": { + "id": 12345, + "is_bot": true, + "first_name": "First Name", + "last_name": "Last Name", + "username": "test_bot", + "language_code": "en_US" + }, + "date": 1708106405 + } + """; + + MessageOrigin? messageOrigin = JsonConvert.DeserializeObject(origin); + Assert.NotNull(messageOrigin); + + MessageOriginUser originUser = Assert.IsType(messageOrigin); + + Assert.Equal(MessageOriginType.User, messageOrigin.Type); + Assert.Equal(new(2024, 2, 16, 18, 0, 5, 0, DateTimeKind.Utc), originUser.Date); + Assert.NotNull(originUser.SenderUser); + Assert.Equal(12345, originUser.SenderUser.Id); + Assert.True(originUser.SenderUser.IsBot); + Assert.Equal("First Name", originUser.SenderUser.FirstName); + Assert.Equal("Last Name", originUser.SenderUser.LastName); + Assert.Equal("test_bot", originUser.SenderUser.Username); + Assert.Equal("en_US", originUser.SenderUser.LanguageCode); + } + + [Fact] + public void Should_Deserialize_MessageOriginHidden() + { + const string origin = + """ + { + "type": "hidden_user", + "sender_user_name": "test_bot", + "date": 1708106405 + } + """; + + MessageOrigin? messageOrigin = JsonConvert.DeserializeObject(origin); + Assert.NotNull(messageOrigin); + + MessageOriginHiddenUser originHiddenUser = Assert.IsType(messageOrigin); + + Assert.Equal(MessageOriginType.HiddenUser, messageOrigin.Type); + Assert.Equal(new(2024, 2, 16, 18, 0, 5, 0, DateTimeKind.Utc), originHiddenUser.Date); + Assert.Equal("test_bot", originHiddenUser.SenderUserName); + } + + [Fact] + public void Should_DeSerialize_MessageOriginChat() + { + const string origin = + """ + { + "type": "chat", + "sender_chat": { + "id": 12345, + "type": "supergroup", + "username": "test_bot", + "is_forum": true + }, + "date": 1708106405 + } + """; + + + MessageOrigin? messageOrigin = JsonConvert.DeserializeObject(origin); + Assert.NotNull(messageOrigin); + + MessageOriginChat originChat = Assert.IsType(messageOrigin); + + Assert.Equal(MessageOriginType.Chat, messageOrigin.Type); + Assert.Equal(new(2024, 2, 16, 18, 0, 5, 0, DateTimeKind.Utc), originChat.Date); + Assert.NotNull(originChat.SenderChat); + Assert.Equal(12345, originChat.SenderChat.Id); + Assert.True(originChat.SenderChat.IsForum); + Assert.Equal("test_bot", originChat.SenderChat.Username); + } + + [Fact] + public void Should_Deserialize_MessageOriginChannel() + { + const string origin = + """ + { + "type": "channel", + "chat": { + "id": 12345, + "type": "channel", + "username": "test_channel", + "is_forum": true + }, + "message_id": 1236886, + "author_signature": "author_name", + "date": 1708106405 + } + """; + + MessageOrigin? messageOrigin = JsonConvert.DeserializeObject(origin); + Assert.NotNull(messageOrigin); + + MessageOriginChannel originChannel = Assert.IsType(messageOrigin); + + Assert.Equal(MessageOriginType.Channel, messageOrigin.Type); + Assert.Equal(new(2024, 2, 16, 18, 0, 5, 0, DateTimeKind.Utc), originChannel.Date); + Assert.NotNull(originChannel.Chat); + Assert.Equal(12345, originChannel.Chat.Id); + Assert.True(originChannel.Chat.IsForum); + Assert.Equal("test_channel", originChannel.Chat.Username); + Assert.NotNull(originChannel.AuthorSignature); + Assert.Equal("author_name", originChannel.AuthorSignature); + } +} diff --git a/test/Telegram.Bot.Tests.Unit/Serialization/MethodNameTests.cs b/test/Telegram.Bot.Tests.Unit/Serialization/MethodNameTests.cs index 38e29c33e..fa99b2474 100644 --- a/test/Telegram.Bot.Tests.Unit/Serialization/MethodNameTests.cs +++ b/test/Telegram.Bot.Tests.Unit/Serialization/MethodNameTests.cs @@ -1,6 +1,8 @@ +using System.Linq; using System.Net.Http; using System.Threading.Tasks; using Newtonsoft.Json; +using Newtonsoft.Json.Linq; using Telegram.Bot.Requests; using Xunit; @@ -11,19 +13,29 @@ public class MethodNameTests [Fact(DisplayName = "Should serialize method name in webhook responses")] public void Should_Serialize_MethodName_In_Webhook_Responses() { - SendMessageRequest sendMessageRequest = new(1, "text") { IsWebhookResponse = true }; + SendMessageRequest sendMessageRequest = new(chatId: 1, text: "text") { IsWebhookResponse = true }; string request = JsonConvert.SerializeObject(sendMessageRequest); - Assert.Contains(@"""method"":""sendMessage""", request); + JObject j = JObject.Parse(request); + + Assert.Equal(3, j.Children().Count()); + Assert.Equal(1, j["chat_id"]); + Assert.Equal("text", j["text"]); + Assert.Equal("sendMessage", j["method"]); } [Fact(DisplayName = "Should not serialize method name when not a webhook responses")] public void Should_Not_Serialize_MethodName_When_Not_In_Webhook_Responses() { - SendMessageRequest sendMessageRequest = new(1, "text") { IsWebhookResponse = false }; + SendMessageRequest sendMessageRequest = new(chatId: 1, text: "text") { IsWebhookResponse = false }; string request = JsonConvert.SerializeObject(sendMessageRequest); - Assert.DoesNotContain(@"""method"":""sendMessage""", request); + JObject j = JObject.Parse(request); + + Assert.Equal(2, j.Children().Count()); + Assert.Equal(1, j["chat_id"]); + Assert.Equal("text", j["text"]); + Assert.False(j.ContainsKey("method")); } [Fact(DisplayName = "Should serialize only the method name in parameterless webhook responses")] @@ -32,7 +44,10 @@ public void Should_Serialize_MethodName_In_Parameterless_Webhook_Responses() DeleteWebhookRequest deleteWebhookRequest = new() { IsWebhookResponse = true }; string request = JsonConvert.SerializeObject(deleteWebhookRequest); - Assert.Equal(@"{""method"":""deleteWebhook""}", request); + JObject j = JObject.Parse(request); + + Assert.Single(j.Children()); + Assert.Equal("deleteWebhook", j["method"]); } [Fact(DisplayName = "Should serialize an empty object when not a parameterless webhook response")] @@ -41,7 +56,9 @@ public void Should_Serialize_Empty_Object_When_Not_Parameterless_Webhook_Respons DeleteWebhookRequest deleteWebhookRequest = new() { IsWebhookResponse = false }; string request = JsonConvert.SerializeObject(deleteWebhookRequest); - Assert.Equal("{}", request); + JObject j = JObject.Parse(request); + + Assert.Empty(j.Children()); } [Fact(DisplayName = "Should build a HttpContent in parameterless webhook responses")] @@ -64,7 +81,10 @@ public async Task Should_Build_StringContent_With_MethodName_In_Parameterless_We Assert.NotNull(content); string body = await stringContent.ReadAsStringAsync(); - Assert.Equal(@"{""method"":""close""}", body); + JObject j = JObject.Parse(body); + + Assert.Single(j.Children()); + Assert.Equal("close", j["method"]); } [Fact(DisplayName = "Should not build an HttpContent when not a parameterless webhook responses")] diff --git a/test/Telegram.Bot.Tests.Unit/Serialization/PhotoMessageSerializationTests.cs b/test/Telegram.Bot.Tests.Unit/Serialization/PhotoMessageSerializationTests.cs index 001a2fade..2e039bc17 100644 --- a/test/Telegram.Bot.Tests.Unit/Serialization/PhotoMessageSerializationTests.cs +++ b/test/Telegram.Bot.Tests.Unit/Serialization/PhotoMessageSerializationTests.cs @@ -4,6 +4,7 @@ using Telegram.Bot.Types.Enums; using Xunit; using Newtonsoft.Json; +using Newtonsoft.Json.Linq; namespace Telegram.Bot.Tests.Unit.Serialization; @@ -69,10 +70,10 @@ public void Should_Deserialize_PhotoMessage() Assert.NotNull(message); Assert.Equal(MessageType.Photo, message.Type); Assert.NotNull(message.Photo); - Assert.NotEmpty(message.Photo!); + Assert.NotEmpty(message.Photo); Assert.All(message.Photo.Select(ps => ps.FileId), Assert.NotEmpty); - Assert.All(message.Photo.Select(ps => ps.Width), w => Assert.NotEqual(default, w)); - Assert.All(message.Photo.Select(ps => ps.Height), h => Assert.NotEqual(default, h)); + Assert.All(message.Photo.Select(ps => ps.Width), w => Assert.NotEqual(0, w)); + Assert.All(message.Photo.Select(ps => ps.Height), h => Assert.NotEqual(0, h)); } [Fact(DisplayName = "Should serialize a photo message")] @@ -95,9 +96,9 @@ public void Should_Serialize_PhotoMessage() Type = ChatType.Private }, Date = new(2018, 1, 1, 0, 0, 0, DateTimeKind.Utc), - Photo = new[] - { - new PhotoSize + Photo = + [ + new() { FileId = "AgADAgADvKgxGxW80EtRgjrTaWNmy7UerQ4ABN7x5HqnrHW_wp4BAAEC", FileUniqueId = "AgADcOsAAhUdZAc", @@ -105,7 +106,7 @@ public void Should_Serialize_PhotoMessage() Width = 90, Height = 90, }, - new PhotoSize + new() { FileId = "AgADAgADvKgxGxW80EtRgjrTaWNmy7UerQ4ABIrxzSBLXOQYw54BAAEC", FileUniqueId = "AgADcOsAAhUdZAc", @@ -113,7 +114,7 @@ public void Should_Serialize_PhotoMessage() Width = 320, Height = 320, }, - new PhotoSize + new() { FileId = "AgADAgADvKgxGxW80EtRgjrTaWNmy7UerQ4ABIJONRZpTJFnxJ4BAAEC", FileUniqueId = "AgADcOsAAhUdZAc", @@ -121,7 +122,7 @@ public void Should_Serialize_PhotoMessage() Width = 800, Height = 800, }, - new PhotoSize + new() { FileId = "AgADAgADvKgxGxW80EtRgjrTaWNmy7UerQ4ABP6uRLtwe8Z8wZ4BAAEC", FileUniqueId = "AgADcOsAAhUdZAc", @@ -129,13 +130,53 @@ public void Should_Serialize_PhotoMessage() Width = 1280, Height = 1280, } - } + ] }; - string? json = JsonConvert.SerializeObject(message); + string json = JsonConvert.SerializeObject(message); + JObject j = JObject.Parse(json); + + Assert.Equal(5, j.Children().Count()); + Assert.Equal(1234, j["message_id"]); + Assert.Equal(123, j["date"]); + + JToken? jChat = j["chat"]; + Assert.NotNull(jChat); + Assert.Equal(4, jChat.Children().Count()); + Assert.Equal(1234567, jChat["id"]); + Assert.Equal("Telegram_Bots", jChat["first_name"]); + Assert.Equal("TelegramBots", jChat["username"]); + Assert.Equal("private", jChat["type"]); + + JToken? jFrom = j["from"]; + Assert.NotNull(jFrom); + Assert.Equal(4, jFrom.Children().Count()); + Assert.Equal(1234567, jFrom["id"]); + Assert.Equal("Telegram_Bots", jFrom["first_name"]); + Assert.Equal("TelegramBots", jFrom["username"]); + Assert.Equal(false, jFrom["is_bot"]); + + JToken? jPhoto = j["photo"]; + Assert.NotNull(jPhoto); + Assert.IsType(jPhoto); + Assert.Equal(4, jPhoto.Children().Count()); + Assert.All(jPhoto.Children(), photo => + { + Assert.Equal(5, photo.Children().Count()); + Assert.NotNull(photo["file_id"]); + Assert.Equal(JTokenType.String, photo["file_id"]!.Type); + + Assert.NotNull(photo["file_unique_id"]); + Assert.Equal(JTokenType.String, photo["file_unique_id"]!.Type); + + Assert.NotNull(photo["file_size"]); + Assert.Equal(JTokenType.Integer, photo["file_size"]!.Type); + + Assert.NotNull(photo["width"]); + Assert.Equal(JTokenType.Integer, photo["width"]!.Type); - Assert.NotNull(json); - Assert.True(json.Length > 100); - Assert.Contains(@"""file_id"":""AgADAgADvKgxGxW80EtRgjrTaWNmy7UerQ4ABP6uRLtwe8Z8wZ4BAAEC""", json); + Assert.NotNull(photo["height"]); + Assert.Equal(JTokenType.Integer, photo["height"]!.Type); + }); } } diff --git a/test/Telegram.Bot.Tests.Unit/Serialization/ReplyMarkupSerializationTests.cs b/test/Telegram.Bot.Tests.Unit/Serialization/ReplyMarkupSerializationTests.cs index 17169002b..8096a9d40 100644 --- a/test/Telegram.Bot.Tests.Unit/Serialization/ReplyMarkupSerializationTests.cs +++ b/test/Telegram.Bot.Tests.Unit/Serialization/ReplyMarkupSerializationTests.cs @@ -1,4 +1,6 @@ +using System.Linq; using Newtonsoft.Json; +using Newtonsoft.Json.Linq; using Telegram.Bot.Types.ReplyMarkups; using Xunit; @@ -10,7 +12,7 @@ public class ReplyMarkupSerializationTests [InlineData(null)] [InlineData("regular")] [InlineData("quiz")] - public void Should_Serialize_Request_Poll_Keyboard_Button(string type) + public void Should_Serialize_Request_Poll_Keyboard_Button(string? type) { IReplyMarkup replyMarkup = new ReplyKeyboardMarkup( KeyboardButton.WithRequestPoll("Create a poll", type) @@ -18,12 +20,34 @@ public void Should_Serialize_Request_Poll_Keyboard_Button(string type) string serializedReplyMarkup = JsonConvert.SerializeObject(replyMarkup); - string formattedType = string.IsNullOrEmpty(type) - ? "{}" - : $@"{{""type"":""{type}""}}"; + JObject j = JObject.Parse(serializedReplyMarkup); + Assert.Single(j); - string expectedString = $@"""request_poll"":{formattedType}"; + JToken? jk = j["keyboard"]; + Assert.NotNull(jk); - Assert.Contains(expectedString, serializedReplyMarkup); + JArray jKeyboard = Assert.IsType(jk); + Assert.Single(jKeyboard); + + JToken jRow = jKeyboard[0]; + Assert.Single(jRow); + + JToken? jButton = jRow[0]; + Assert.NotNull(jButton); + Assert.Equal(2, jButton.Children().Count()); + Assert.Equal("Create a poll", jButton["text"]); + + JToken? jRequestPoll = jButton["request_poll"]; + Assert.NotNull(jRequestPoll); + + if (string.IsNullOrEmpty(type)) + { + Assert.Empty(jRequestPoll); + } + else + { + Assert.Single(jRequestPoll); + Assert.Equal(type, jRequestPoll["type"]); + } } } diff --git a/test/Telegram.Bot.Tests.Unit/Serialization/RequestSerializationTests.cs b/test/Telegram.Bot.Tests.Unit/Serialization/RequestSerializationTests.cs index 763ce2e80..892edc622 100644 --- a/test/Telegram.Bot.Tests.Unit/Serialization/RequestSerializationTests.cs +++ b/test/Telegram.Bot.Tests.Unit/Serialization/RequestSerializationTests.cs @@ -1,8 +1,10 @@ using System; +using System.Linq; using Newtonsoft.Json; using Newtonsoft.Json.Serialization; using System.Net.Http; using System.Threading.Tasks; +using Newtonsoft.Json.Linq; using Telegram.Bot.Requests; using Xunit; @@ -17,9 +19,11 @@ public async Task Should_Serialize_DeleteWebhookRequest_Content() HttpContent deleteWebhookContent = deleteWebhookRequest.ToHttpContent()!; string stringContent = await deleteWebhookContent.ReadAsStringAsync(); + JObject j = JObject.Parse(stringContent); - Assert.NotNull(stringContent); - Assert.Contains(@"""drop_pending_updates"":true", stringContent); + + Assert.Single(j); + Assert.Equal(true, j["drop_pending_updates"]); } [Fact(DisplayName = "Should serialize request")] @@ -28,9 +32,10 @@ public void Should_Serialize_Request() GetUpdatesRequest request = new() { Offset = 12345 }; string serializeRequest = JsonConvert.SerializeObject(request); + JObject j = JObject.Parse(serializeRequest); - Assert.DoesNotContain(@"""MethodName""", serializeRequest); - Assert.DoesNotContain(@"""IsWebhookResponse""", serializeRequest); + Assert.Single(j); + Assert.Equal(12345, j["offset"]); } [Fact(DisplayName = "Should properly serialize request with custom json settings")] @@ -51,13 +56,10 @@ public void Should_Properly_Serialize_Request_With_Custom_Json_Settings() }; string serializeRequest = JsonConvert.SerializeObject(request, settings); + JObject j = JObject.Parse(serializeRequest); - Assert.DoesNotContain(@"""MethodName""", serializeRequest); - Assert.DoesNotContain(@"""method_name""", serializeRequest); - Assert.DoesNotContain(@"""IsWebhookResponse""", serializeRequest); - Assert.DoesNotContain(@"""is_webhook_response""", serializeRequest); - Assert.Contains(@"""offset"":12345", serializeRequest); - Assert.DoesNotContain(@"""allowed_updates""", serializeRequest); + Assert.Single(j); + Assert.Equal(12345, j["offset"]); } [Fact(DisplayName = "Should serialize createChatInviteLink request")] @@ -75,11 +77,13 @@ public async Task Should_Serialize_CreateChatInviteLink_Request() HttpContent createChatInviteLinkContent = createChatInviteLinkRequest.ToHttpContent()!; string stringContent = await createChatInviteLinkContent.ReadAsStringAsync(); + JObject j = JObject.Parse(stringContent); - Assert.Contains(@"""expire_date"":1641638025", stringContent); - Assert.Contains(@"""chat_id"":1000000", stringContent); - Assert.Contains(@"""name"":""Test link name""", stringContent); - Assert.Contains(@"""member_limit"":123", stringContent); - Assert.Contains(@"""creates_join_request"":true", stringContent); + Assert.Equal(5, j.Children().Count()); + Assert.Equal(1641638025, j["expire_date"]); + Assert.Equal(1000000, j["chat_id"]); + Assert.Equal("Test link name", j["name"]); + Assert.Equal(123, j["member_limit"]); + Assert.Equal(true, j["creates_join_request"]); } } diff --git a/test/Telegram.Bot.Tests.Unit/Serialization/StorySerializationTests.cs b/test/Telegram.Bot.Tests.Unit/Serialization/StorySerializationTests.cs new file mode 100644 index 000000000..376749add --- /dev/null +++ b/test/Telegram.Bot.Tests.Unit/Serialization/StorySerializationTests.cs @@ -0,0 +1,65 @@ +using System.Linq; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using Telegram.Bot.Types; +using Telegram.Bot.Types.Enums; +using Xunit; + +namespace Telegram.Bot.Tests.Unit.Serialization; + +public class StorySerializationTests +{ + [Fact] + public void Should_Serialize_Story() + { + Story story = new() + { + Id = 1234, + Chat = new() + { + Id = 876543, + Type = ChatType.Private, + Username = "test_user" + }, + }; + + string serializeStory = JsonConvert.SerializeObject(story); + + JObject j = JObject.Parse(serializeStory); + + Assert.Equal(2, j.Children().Count()); + Assert.Equal(1234, j["id"]); + + JToken? jc = j["chat"]; + Assert.NotNull(jc); + + Assert.Equal(3, jc.Children().Count()); + Assert.Equal(876543, jc["id"]); + Assert.Equal("private", jc["type"]); + Assert.Equal("test_user", jc["username"]); + } + + [Fact] + public void Should_Deserialize_Story() + { + const string story = + """ + { + "id": 1234, + "chat": { + "id": 876543, + "type": "private", + "username": "test_user" + } + } + """; + + Story? deserializedStory = JsonConvert.DeserializeObject(story); + + Assert.NotNull(deserializedStory); + Assert.Equal(1234, deserializedStory.Id); + Assert.Equal(876543, deserializedStory.Chat.Id); + Assert.Equal(ChatType.Private, deserializedStory.Chat.Type); + Assert.Equal("test_user", deserializedStory.Chat.Username); + } +} diff --git a/test/Telegram.Bot.Tests.Unit/Telegram.Bot.Tests.Unit.csproj b/test/Telegram.Bot.Tests.Unit/Telegram.Bot.Tests.Unit.csproj index fab480c82..549c13db8 100644 --- a/test/Telegram.Bot.Tests.Unit/Telegram.Bot.Tests.Unit.csproj +++ b/test/Telegram.Bot.Tests.Unit/Telegram.Bot.Tests.Unit.csproj @@ -1,15 +1,15 @@ - net6.0 - 11 + net8.0 + 12.0 enable false - - - - + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive