Skip to content

Commit

Permalink
Merge pull request #1028 from TelegramBots/develop
Browse files Browse the repository at this point in the history
Implement Bot API v5.4
  • Loading branch information
tuscen authored Nov 6, 2021
2 parents e3e812b + 049c704 commit 33ebb8d
Show file tree
Hide file tree
Showing 56 changed files with 3,363 additions and 1,308 deletions.
2 changes: 1 addition & 1 deletion .azure-pipelines/variables.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ variables:
- name: versionPrefix
value: 17.0.0
- name: versionSuffix
value: "alpha.3"
value: "alpha.4"
- name: ciVersionSuffix
value: ci.$(Build.BuildId)+git.commit.$(Build.SourceVersion)
- name: buildConfiguration
Expand Down
37 changes: 37 additions & 0 deletions .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
ARG DOTNET_VERSION=5.0
FROM mcr.microsoft.com/dotnet/sdk:${DOTNET_VERSION}-buster-slim
ARG USERNAME=vscode
ARG USER_UID=1000
ARG USER_GID=${USER_UID}
ENV DEBIAN_FRONTEND=noninteractive

# Install required and misc tools
RUN apt-get update && apt-get -y install --no-install-recommends apt-utils dialog 2>&1 \
&& apt-get -y install openssh-client less iproute2 apt-transport-https gnupg2 curl lsb-release \
git procps ca-certificates vim nano groff zip file jq wget zsh \
# Create a non-root user to use if preferred - see https://aka.ms/vscode-remote/containers/non-root-user.
&& groupadd --gid $USER_GID $USERNAME \
&& useradd -s /bin/bash --uid $USER_UID --gid $USER_GID -m $USERNAME \
# [Optional] Add sudo support for the non-root user
&& apt-get install -y sudo \
&& echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME\
&& chmod 0440 /etc/sudoers.d/$USERNAME

# Cleanup APT
RUN apt-get autoremove -y \
&& apt-get clean -y \
&& rm -rf /var/lib/apt/lists/*

RUN chsh -s $(which zsh) ${USERNAME}
USER ${USERNAME}

RUN sh -c "$(curl -fsSL https://raw.github.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"
# This is needed for Global Tools to work
ENV PATH="${PATH}:/home/${USERNAME}/.dotnet/tools"
# Install .NET Global Tools
RUN dotnet tool install -g dotnet-format \
&& dotnet tool install -g microsoft.dotnet-httprepl

ENV DEBIAN_FRONTEND=dialog

WORKDIR /workspace
17 changes: 17 additions & 0 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"name": "Telegram.Bot",
"dockerComposeFile": "docker-compose.yml",
"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"
],
"remoteUser": "vscode"
}
12 changes: 12 additions & 0 deletions .devcontainer/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
version: '3'
services:
devhost:
user: vscode
build: .
environment:
- DOTNET_ENVIRONMENT=Development
- DOTNET_NOLOGO=1
volumes:
- ..:/workspace
- ./persistence/nuget:/vscode/.nuget
command: sleep infinity
3 changes: 0 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,3 @@ src/Telegram.Bot.Documentation/

# Rider IDE
.idea

# VS Code
.vscode/
26 changes: 26 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,32 @@ and this project adheres to [Semantic Versioning](https://semver.org/).

## [Unreleased]

### Added
- Request `ApproveChatJoinRequest`
- Request `DeclineChatJoinRequest`
- Property `bool? CreateChatInviteLinkRequest.CreatesJoinRequest`
- Property `string? CreateChatInviteLinkRequest.Name`
- Property `bool? EditChatInviteLinkRequest.CreatesJoinRequest`
- Property `string? EditChatInviteLinkRequest.Name`
- Property `bool ChatInviteLink.CreatesJoinRequest`
- Property `int? ChatInviteLink.PendingJoinRequestCount`
- Type `ChatJoinRequest`
- Property `ChatJoinRequest Update.ChatJoinRequest`
- Enum member `ChatAction.ChooseSticker`
- Extension method `TelegramBotClientExtensions.ApproveChatJoinRequestAsync`
- Extension method `TelegramBotClientExtensions.DeclineChatJoinRequestAsync`

### Changed
- Extension method `TelegramBotClientExtensions.EditChatInviteLinkAsync`:
- Added parameters `string? name` and `bool? createsJoinRequest`
- Extension method `TelegramBotClientExtensions.CreateChatInviteLinkAsync`:
- Added parameters `string? name` and `bool? createsJoinRequest`

### Changed
- Fields `ChatId.Identifier` and `ChatId.Username` changed into get-only properties

## [v17.0.0-alpha.3] - 2021-09-01

### Changed
- Method `GetInfoAndDownloadFileAsync` moved into static class `TelegramBotClientExtensions` as an extension method
- Symbols are always include in the package
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -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-5.2%20(June%2025,%202021)-f36caf.svg?style=flat-square)](https://core.telegram.org/bots/api)
[![Bot API Version](https://img.shields.io/badge/Bot%20API-5.4%20(November%205,%202021)-f36caf.svg?style=flat-square)](https://core.telegram.org/bots/api)
[![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)

Expand Down
27 changes: 27 additions & 0 deletions Telegram.Bot.sln
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,30 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
README.md = README.md
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".azure-pipelines", ".azure-pipelines", "{71662597-40F2-4192-AC4D-5FB9A1F12642}"
ProjectSection(SolutionItems) = preProject
.azure-pipelines\ci.yml = .azure-pipelines\ci.yml
.azure-pipelines\default-pipeline.yml = .azure-pipelines\default-pipeline.yml
.azure-pipelines\develop-pipeline.yml = .azure-pipelines\develop-pipeline.yml
.azure-pipelines\manual-pipeline.yml = .azure-pipelines\manual-pipeline.yml
.azure-pipelines\release-pipeline.yml = .azure-pipelines\release-pipeline.yml
.azure-pipelines\setVersionVariables.js = .azure-pipelines\setVersionVariables.js
.azure-pipelines\variables.yml = .azure-pipelines\variables.yml
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "jobs", "jobs", "{C20A563E-603B-49E8-A954-DB90D4F351DE}"
ProjectSection(SolutionItems) = preProject
.azure-pipelines\jobs\run-integration-tests.yml = .azure-pipelines\jobs\run-integration-tests.yml
.azure-pipelines\jobs\run-unit-tests.yml = .azure-pipelines\jobs\run-unit-tests.yml
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".devcontainer", ".devcontainer", "{4897F36C-2F57-48A7-B425-D8F695E0AC0D}"
ProjectSection(SolutionItems) = preProject
.devcontainer\devcontainer.json = .devcontainer\devcontainer.json
.devcontainer\docker-compose.yml = .devcontainer\docker-compose.yml
.devcontainer\Dockerfile = .devcontainer\Dockerfile
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -47,6 +71,9 @@ Global
{12FD39CD-A6FD-4040-8C8B-8FABEDD5FE0F} = {838231A4-B081-44B0-AC16-DC4C2FABAE86}
{B662E909-CF8B-47C6-BAA8-FCA595BA53EA} = {15F0DD71-1D15-4085-AF6F-E3E5D8ACB489}
{AAB9E3BA-D749-4D38-9021-EBD8D0BC8975} = {15F0DD71-1D15-4085-AF6F-E3E5D8ACB489}
{71662597-40F2-4192-AC4D-5FB9A1F12642} = {C45387C6-C93F-4FD2-84A8-A69CCE93B7EE}
{C20A563E-603B-49E8-A954-DB90D4F351DE} = {71662597-40F2-4192-AC4D-5FB9A1F12642}
{4897F36C-2F57-48A7-B425-D8F695E0AC0D} = {C45387C6-C93F-4FD2-84A8-A69CCE93B7EE}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {F6A9C4CA-DF26-4772-9119-627935D70E7C}
Expand Down
2 changes: 2 additions & 0 deletions src/Telegram.Bot/AsyncEventHandler`T.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@

namespace Telegram.Bot
{
#pragma warning disable CA1711
public delegate ValueTask AsyncEventHandler<in TArgs>(
#pragma warning restore CA1711
ITelegramBotClient botClient,
TArgs args,
CancellationToken cancellationToken = default
Expand Down
13 changes: 4 additions & 9 deletions src/Telegram.Bot/Converters/BanTimeUnixDateTimeConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,18 @@ namespace Telegram.Bot.Converters
{
internal class BanTimeUnixDateTimeConverter : UnixDateTimeConverter
{
static readonly DateTime DefaultUtc = DateTime.SpecifyKind(default, DateTimeKind.Utc);

public override object? ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var nonNullable = Nullable.GetUnderlyingType(objectType) is null;

if (reader.TokenType == JsonToken.Integer && reader.Value is 0L)
{
return nonNullable ? DefaultUtc : null;
}

return base.ReadJson(reader, objectType, existingValue, serializer);
return reader.TokenType == JsonToken.Integer && reader.Value is 0L
? nonNullable ? default : null
: base.ReadJson(reader, objectType, existingValue, serializer);
}

public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
{
if (value is null || value.Equals(DefaultUtc))
if (value is null || value.Equals(default(DateTime)))
{
writer.WriteValue(0);
}
Expand Down
4 changes: 2 additions & 2 deletions src/Telegram.Bot/Converters/InputMediaConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ public override object ReadJson(

if (value is null) { return null!; }

return value.StartsWith("attach://")
? new InputMedia(Stream.Null, value.Substring(9))
return value.StartsWith("attach://", StringComparison.InvariantCulture)
? new(Stream.Null, value.Substring(9))
: new InputMedia(value);
}
}
Expand Down
2 changes: 2 additions & 0 deletions src/Telegram.Bot/Exceptions/ApiRequestException.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ namespace Telegram.Bot.Exceptions
/// Represents an API error
/// </summary>
// ReSharper disable once ClassWithVirtualMembersNeverInherited.Global
#pragma warning disable CA1032
public class ApiRequestException : RequestException
#pragma warning restore CA1032
{
/// <summary>
/// Gets the error code.
Expand Down
2 changes: 2 additions & 0 deletions src/Telegram.Bot/Exceptions/RequestException.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ namespace Telegram.Bot.Exceptions
/// <summary>
/// Represents a request error
/// </summary>
#pragma warning disable CA1032
public class RequestException : Exception
#pragma warning restore CA1032
{
/// <summary>
/// <see cref="HttpStatusCode"/> of the received response
Expand Down
37 changes: 24 additions & 13 deletions src/Telegram.Bot/Helpers/Extensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ internal static void AddStreamContent(
fileName ??= name;
var contentDisposition = $@"form-data; name=""{name}""; filename=""{fileName}""".EncodeUtf8();

// It will be dispose of after the request is made
#pragma warning disable CA2000
var mediaPartContent = new StreamContent(content)
{
Headers =
Expand All @@ -40,6 +42,7 @@ internal static void AddStreamContent(
{"Content-Disposition", contentDisposition}
}
};
#pragma warning restore CA2000

multipartContent.Add(mediaPartContent, name, fileName);
}
Expand All @@ -53,13 +56,19 @@ internal static void AddContentIfInputFileStream(
{
if (input.Media.FileType == FileType.Stream)
{
multipartContent.AddStreamContent(input.Media.Content!, input.Media.FileName!);
multipartContent.AddStreamContent(
content: input.Media.Content!,
name: input.Media.FileName!
);
}

if (input is IInputMediaThumb mediaThumb &&
mediaThumb.Thumb?.FileType == FileType.Stream)
{
multipartContent.AddStreamContent(mediaThumb.Thumb.Content!, mediaThumb.Thumb.FileName!);
multipartContent.AddStreamContent(
content: mediaThumb.Thumb.Content!,
name: mediaThumb.Thumb.FileName!
);
}
}
}
Expand All @@ -74,7 +83,7 @@ internal static void AddContentIfInputFileStream(
/// <exception cref="RequestException">
/// Thrown when body in the response can not be deserialized into <typeparamref name="T"/>
/// </exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(methodImplOptions: MethodImplOptions.AggressiveInlining)]
internal static async Task<T> DeserializeContentAsync<T>(
this HttpResponseMessage httpResponse,
Func<T, bool> guard)
Expand All @@ -83,10 +92,12 @@ internal static async Task<T> DeserializeContentAsync<T>(
Stream? contentStream = null;

if (httpResponse.Content is null)
{
throw new RequestException(
"Response doesn't contain any content",
httpResponse.StatusCode
message: "Response doesn't contain any content",
httpStatusCode: httpResponse.StatusCode
);
}

try
{
Expand All @@ -96,7 +107,7 @@ internal static async Task<T> DeserializeContentAsync<T>(
{
contentStream = await httpResponse.Content
.ReadAsStreamAsync()
.ConfigureAwait(false);
.ConfigureAwait(continueOnCapturedContext: false);

deserializedObject = contentStream
.DeserializeJsonFromStream<T>();
Expand Down Expand Up @@ -133,7 +144,7 @@ internal static async Task<T> DeserializeContentAsync<T>(
if (contentStream is not null)
{
#if NETCOREAPP3_1_OR_GREATER
await contentStream.DisposeAsync();
await contentStream.DisposeAsync().ConfigureAwait(false);
#else
contentStream.Dispose();
#endif
Expand All @@ -151,7 +162,7 @@ internal static async Task<T> DeserializeContentAsync<T>(
static T? DeserializeJsonFromStream<T>(this Stream? stream)
where T : class
{
if (stream is null || !stream.CanRead) return default;
if (stream is null || !stream.CanRead) { return default; }

using var streamReader = new StreamReader(stream);
using var jsonTextReader = new JsonTextReader(streamReader);
Expand All @@ -174,13 +185,13 @@ static RequestException CreateRequestException(
) =>
exception is null
? new RequestException(
message,
httpResponse.StatusCode
message: message,
httpStatusCode: httpResponse.StatusCode
)
: new RequestException(
message,
httpResponse.StatusCode,
exception
message: message,
httpStatusCode: httpResponse.StatusCode,
innerException: exception
);
}
}
8 changes: 5 additions & 3 deletions src/Telegram.Bot/ITelegramBotClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
using Telegram.Bot.Args;
using Telegram.Bot.Exceptions;
using Telegram.Bot.Requests.Abstractions;
using File = Telegram.Bot.Types.File;

namespace Telegram.Bot
{
Expand Down Expand Up @@ -64,11 +63,14 @@ Task<TResponse> MakeRequestAsync<TResponse>(
Task<bool> TestApiAsync(CancellationToken cancellationToken = default);

/// <summary>
/// Use this method to download a file. Get <paramref name="filePath"/> by calling <see cref="TelegramBotClientExtensions.GetFileAsync(ITelegramBotClient, string, CancellationToken)"/>.
/// Use this method to download a file. Get <paramref name="filePath"/> by calling
/// <see cref="TelegramBotClientExtensions.GetFileAsync(ITelegramBotClient, string, CancellationToken)"/>
/// </summary>
/// <param name="filePath">Path to file on server</param>
/// <param name="destination">Destination stream to write file to</param>
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
/// <param name="cancellationToken">
/// A cancellation token that can be used by other objects or threads to receive notice of cancellation.
/// </param>
/// <exception cref="ArgumentException">filePath is <c>null</c>, empty or too short</exception>
/// <exception cref="ArgumentNullException"><paramref name="destination"/> is <c>null</c></exception>
Task DownloadFileAsync(
Expand Down
2 changes: 2 additions & 0 deletions src/Telegram.Bot/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using System;
using System.Runtime.CompilerServices;

[assembly: InternalsVisibleTo("Telegram.Bot.Tests.Unit")]
[assembly: InternalsVisibleTo("Telegram.Bot.Tests.Integ")]
[assembly: CLSCompliant(false)]
7 changes: 4 additions & 3 deletions src/Telegram.Bot/Requests/Abstractions/Documentation.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
using Telegram.Bot.Types.ReplyMarkups;

#nullable disable
#pragma warning disable 169
// ReSharper disable InconsistentNaming
#pragma warning disable CA1823

using Telegram.Bot.Types.ReplyMarkups;

// ReSharper disable InconsistentNaming
namespace Telegram.Bot.Requests.Abstractions
{
// ReSharper disable once UnusedType.Global
Expand Down
Loading

0 comments on commit 33ebb8d

Please sign in to comment.