From 1abc876e5327fccf1553c901b29cd6a13e3e4a8a Mon Sep 17 00:00:00 2001 From: LineOfC0d3 Date: Mon, 6 Apr 2026 15:46:26 +0200 Subject: [PATCH 1/7] Add Request models for Polls --- src/Signal.Bot/Requests/AddPollRequest.cs | 34 +++++++++++++++++++++ src/Signal.Bot/Requests/ClosePollRequest.cs | 22 +++++++++++++ src/Signal.Bot/Requests/VotePollRequest.cs | 34 +++++++++++++++++++++ 3 files changed, 90 insertions(+) create mode 100644 src/Signal.Bot/Requests/AddPollRequest.cs create mode 100644 src/Signal.Bot/Requests/ClosePollRequest.cs create mode 100644 src/Signal.Bot/Requests/VotePollRequest.cs diff --git a/src/Signal.Bot/Requests/AddPollRequest.cs b/src/Signal.Bot/Requests/AddPollRequest.cs new file mode 100644 index 0000000..f74c0cd --- /dev/null +++ b/src/Signal.Bot/Requests/AddPollRequest.cs @@ -0,0 +1,34 @@ +using System.Text.Json.Serialization; + +namespace Signal.Bot.Requests; + +/// +/// Represents a request to create a new poll +/// +/// The phone number of the Signal account from which the poll will be created. +public record AddPollRequest(string Number) : RequestBase($"v1/polls/{Number}", HttpMethod.Post) +{ + /// + /// Gets or sets the indicator if multiple selections are allowed + /// + [JsonPropertyName("allow_multiple_selections")] + public bool? AllowMultipleSelections { get; set; } + + /// + /// Gets or sets the answers for this poll request + /// + [JsonPropertyName("answers")] + public string[]? Answers { get; set; } + + /// + /// Gets or sets the question of this poll + /// + [JsonPropertyName("question")] + public string? Question { get; set; } + + /// + /// Gets or sets the recipient for this poll + /// + [JsonPropertyName("recipient")] + public string? Recipient { get; set; } +} \ No newline at end of file diff --git a/src/Signal.Bot/Requests/ClosePollRequest.cs b/src/Signal.Bot/Requests/ClosePollRequest.cs new file mode 100644 index 0000000..4658a1a --- /dev/null +++ b/src/Signal.Bot/Requests/ClosePollRequest.cs @@ -0,0 +1,22 @@ +using System.Text.Json.Serialization; + +namespace Signal.Bot.Requests; + +/// +/// Represents a request to close a poll +/// +/// The phone number of the Signal account which will close the poll. +public record ClosePollRequest(string Number) : RequestBase($"v1/polls/{Number}", HttpMethod.Delete) +{ + /// + /// Gets or sets the timestamp of the poll to close + /// + [JsonPropertyName("poll_timestamp")] + public DateTime Timestamp { get; set; } + + /// + /// Gets or sets the recipient for this poll + /// + [JsonPropertyName("recipient")] + public string? Recipient { get; set; } +} \ No newline at end of file diff --git a/src/Signal.Bot/Requests/VotePollRequest.cs b/src/Signal.Bot/Requests/VotePollRequest.cs new file mode 100644 index 0000000..13a87db --- /dev/null +++ b/src/Signal.Bot/Requests/VotePollRequest.cs @@ -0,0 +1,34 @@ +using System.Text.Json.Serialization; + +namespace Signal.Bot.Requests; + +/// +/// Represents a request to vote on a poll +/// +/// The phone number of the Signal account to vote in the poll. +public record VotePollRequest(string Number) : RequestBase($"v1/polls/{Number}/vote", HttpMethod.Post) +{ + /// + /// Gets or sets the uuid or phone number of the poll author + /// + [JsonPropertyName("poll_author")] + public string? PollAuthor { get; set; } + + /// + /// Gets or sets the timestamp of the poll to delete + /// + [JsonPropertyName("poll_timestamp")] + public DateTime Timestamp { get; set; } + + /// + /// Gets or sets the recipient for this poll + /// + [JsonPropertyName("recipient")] + public string? Recipient { get; set; } + + /// + /// Gets or sets an array of answers to vote for + /// + [JsonPropertyName("selected_answers")] + public int[]? SelectedAnswers { get; set; } +} \ No newline at end of file From d953acffd48ef222e1b130ecd4ec1fc374459434 Mon Sep 17 00:00:00 2001 From: LineOfC0d3 Date: Mon, 6 Apr 2026 18:43:20 +0200 Subject: [PATCH 2/7] Add PollResponse.cs and implement functions for main client --- src/Signal.Bot/Extensions.cs | 77 +++++++++++++++++++++++ src/Signal.Bot/Requests/AddPollRequest.cs | 3 +- src/Signal.Bot/Types/PollResponse.cs | 16 +++++ 3 files changed, 95 insertions(+), 1 deletion(-) create mode 100644 src/Signal.Bot/Types/PollResponse.cs diff --git a/src/Signal.Bot/Extensions.cs b/src/Signal.Bot/Extensions.cs index 1634056..168dac5 100644 --- a/src/Signal.Bot/Extensions.cs +++ b/src/Signal.Bot/Extensions.cs @@ -943,4 +943,81 @@ public static async Task GetContactAsync(this ISignalBotClient client, } #endregion + + #region Polls + + /// + /// Creates a new poll + /// + /// The instance. + /// A flag indicating if multiple answers are allowed + /// A list of possible answers + /// The question for the poll + /// The recipient for this poll (user or group) + /// A to observe for cancellation requests. + /// + public static async Task CreatePollAsync(this ISignalBotClient client, + bool? allowMultipleSelections, + string[]? answers, + string? question, + string? recipient, + CancellationToken cancellationToken = default) + { + var request = new AddPollRequest(client.Number) + { + AllowMultipleSelections = allowMultipleSelections, + Answers = answers, + Question = question, + Recipient = recipient + }; + return await client.SendRequestAsync(request, cancellationToken: cancellationToken); + } + + /// + /// Closes an open poll + /// + /// The instance. + /// The timestamp of the poll to close + /// The recipient where the poll to close is located (user or group) + /// A to observe for cancellation requests. + public static async Task ClosePollAsync(this ISignalBotClient client, + DateTime timestamp, + string recipient, + CancellationToken cancellationToken = default) + { + var request = new ClosePollRequest(client.Number) + { + Timestamp = timestamp, + Recipient = recipient + }; + await client.SendRequestAsync(request, cancellationToken: cancellationToken); + } + + /// + /// + /// + /// The instance. + /// The phone number OR uuid of the author of the poll to vote for + /// The timestamp of the poll to vor in + /// The recipient where the poll to vote in is located (user or group) + /// The answer(s) to vote for. Voting for multiple answers may not always be possible. + /// A to observe for cancellation requests. + public static async Task VotePollAsync(this ISignalBotClient client, + string pollAuthor, + DateTime timestamp, + string recipient, + int[]? selectedAnswers, + CancellationToken cancellationToken = default) + { + var request = new VotePollRequest(client.Number) + { + PollAuthor = pollAuthor, + Timestamp = timestamp, + Recipient = recipient, + SelectedAnswers = selectedAnswers, + }; + await client.SendRequestAsync(request, cancellationToken: cancellationToken); + } + + #endregion } \ No newline at end of file diff --git a/src/Signal.Bot/Requests/AddPollRequest.cs b/src/Signal.Bot/Requests/AddPollRequest.cs index f74c0cd..f3f8232 100644 --- a/src/Signal.Bot/Requests/AddPollRequest.cs +++ b/src/Signal.Bot/Requests/AddPollRequest.cs @@ -1,4 +1,5 @@ using System.Text.Json.Serialization; +using Signal.Bot.Types; namespace Signal.Bot.Requests; @@ -6,7 +7,7 @@ namespace Signal.Bot.Requests; /// Represents a request to create a new poll /// /// The phone number of the Signal account from which the poll will be created. -public record AddPollRequest(string Number) : RequestBase($"v1/polls/{Number}", HttpMethod.Post) +public record AddPollRequest(string Number) : RequestBase($"v1/polls/{Number}", HttpMethod.Post) { /// /// Gets or sets the indicator if multiple selections are allowed diff --git a/src/Signal.Bot/Types/PollResponse.cs b/src/Signal.Bot/Types/PollResponse.cs new file mode 100644 index 0000000..63618a3 --- /dev/null +++ b/src/Signal.Bot/Types/PollResponse.cs @@ -0,0 +1,16 @@ +using System.Text.Json.Serialization; +using Signal.Bot.Requests; + +namespace Signal.Bot.Types; + +/// +/// Represents a response to a +/// +public record PollResponse() +{ + /// + /// Gets or sets the timestamp + /// + [JsonPropertyName("timestamp")] + public DateTime Timestamp { get; set; } +} \ No newline at end of file From 994004656c09c47d69927d7be59ab14b0db14eb3 Mon Sep 17 00:00:00 2001 From: LineOfC0d3 Date: Mon, 6 Apr 2026 20:50:01 +0200 Subject: [PATCH 3/7] Add UnitTests --- .../Extensions/PollTests.cs | 180 ++++++++++++++++++ .../Serialization/PollSerializationTests.cs | 117 ++++++++++++ src/Signal.Bot/Extensions.cs | 2 +- src/Signal.Bot/Serialization/JsonBotAPI.cs | 6 +- .../Serialization/JsonBotSerializerContext.cs | 4 + 5 files changed, 307 insertions(+), 2 deletions(-) create mode 100644 src/Signal.Bot.UnitTests/Extensions/PollTests.cs create mode 100644 src/Signal.Bot.UnitTests/Serialization/PollSerializationTests.cs diff --git a/src/Signal.Bot.UnitTests/Extensions/PollTests.cs b/src/Signal.Bot.UnitTests/Extensions/PollTests.cs new file mode 100644 index 0000000..abf4091 --- /dev/null +++ b/src/Signal.Bot.UnitTests/Extensions/PollTests.cs @@ -0,0 +1,180 @@ +using NSubstitute; +using Signal.Bot.UnitTests.Utils; + +namespace Signal.Bot.UnitTests.Extensions; + +public class PollTests : BotTestBase +{ + [Fact(Timeout = 5000)] + public async Task AddPollAsync_WithNoArguments_CallsHttpClient() + { + // Arrange + SetupResponse(); + + // Act + await Client.AddPollAsync(null, null, null, null, cancellationToken: TestContext.Current.CancellationToken); + + // Assert + await HttpClientMock + .Received(1) + .SendAsync(Arg.Is(req => + req.Method == HttpMethod.Post), + Arg.Any()); + } + + [Theory(Timeout = 5000)] + [InlineData(true)] + [InlineData(false)] + public async Task AddPollAsync_WithMultipleSelections_CallsHttpClient(bool allowMultiple) + { + // Arrange + SetupResponse(); + + // Act + await Client.AddPollAsync(allowMultiple, null, null, null, + cancellationToken: TestContext.Current.CancellationToken); + + // Assert + await HttpClientMock + .Received(1) + .SendAsync(Arg.Is(req => + req.Method == HttpMethod.Post), + Arg.Any()); + } + + [Fact(Timeout = 5000)] + public async Task AddPollAsync_WithAnswers_CallsHttpClient() + { + // Arrange + SetupResponse(); + + // Act + await Client.AddPollAsync(null, ["abc", "def", "ghi", "jkl"], null, null, cancellationToken: TestContext.Current.CancellationToken); + + // Assert + await HttpClientMock + .Received(1) + .SendAsync(Arg.Is(req => + req.Method == HttpMethod.Post), + Arg.Any()); + } + + [Fact(Timeout = 5000)] + public async Task AddPollAsync_WithQuestion_CallsHttpClient() + { + // Arrange + SetupResponse(); + + // Act + await Client.AddPollAsync(null, null, "What?!", null, cancellationToken: TestContext.Current.CancellationToken); + + // Assert + await HttpClientMock + .Received(1) + .SendAsync(Arg.Is(req => + req.Method == HttpMethod.Post), + Arg.Any()); + } + + [Fact(Timeout = 5000)] + public async Task AddPollAsync_WithRecipient_CallsHttpClient() + { + // Arrange + SetupResponse(); + + // Act + await Client.AddPollAsync(null, null, null, "123456789", cancellationToken: TestContext.Current.CancellationToken); + + // Assert + await HttpClientMock + .Received(1) + .SendAsync(Arg.Is(req => + req.Method == HttpMethod.Post), + Arg.Any()); + } + + [Fact(Timeout = 5000)] + public async Task AddPollAsync_WithFullDataset_CallsHttpClient() + { + // Arrange + SetupResponse(); + + // Act + await Client.AddPollAsync(false, ["abc", "def", "ghi", "jkl"], "What?!", "123456789", cancellationToken: TestContext.Current.CancellationToken); + + // Assert + await HttpClientMock + .Received(1) + .SendAsync(Arg.Is(req => + req.Method == HttpMethod.Post), + Arg.Any()); + } + + [Fact(Timeout = 5000)] + public async Task ClosePollAsync_CallsHttpClient() + { + // Arrange + SetupResponse(); + + // Act + await Client.ClosePollAsync(DateTime.Now, "123456789", cancellationToken: TestContext.Current.CancellationToken); + + // Assert + await HttpClientMock + .Received(1) + .SendAsync(Arg.Is(req => + req.Method == HttpMethod.Delete), + Arg.Any()); + } + + [Fact(Timeout = 5000)] + public async Task VotePollAsync_WithRequiredArguments_CallsHttpClient() + { + // Arrange + SetupResponse(); + + // Act + await Client.VotePollAsync("987654321", DateTime.Now, "123456789", null, cancellationToken: TestContext.Current.CancellationToken); + + // Assert + await HttpClientMock + .Received(1) + .SendAsync(Arg.Is(req => + req.Method == HttpMethod.Post), + Arg.Any()); + } + + [Fact(Timeout = 5000)] + public async Task VotePollAsync_WithSingleSelectedAnswer_CallsHttpClient() + { + // Arrange + SetupResponse(); + + // Act + await Client.VotePollAsync("987654321", DateTime.Now, "123456789", [1], cancellationToken: TestContext.Current.CancellationToken); + + // Assert + await HttpClientMock + .Received(1) + .SendAsync(Arg.Is(req => + req.Method == HttpMethod.Post), + Arg.Any()); + } + + [Fact(Timeout = 5000)] + public async Task VotePollAsync_WithMultipleSelectedAnswers_CallsHttpClient() + { + // Arrange + SetupResponse(); + + // Act + await Client.VotePollAsync("987654321", DateTime.Now, "123456789", [1, 3], cancellationToken: TestContext.Current.CancellationToken); + + // Assert + await HttpClientMock + .Received(1) + .SendAsync(Arg.Is(req => + req.Method == HttpMethod.Post), + Arg.Any()); + } +} \ No newline at end of file diff --git a/src/Signal.Bot.UnitTests/Serialization/PollSerializationTests.cs b/src/Signal.Bot.UnitTests/Serialization/PollSerializationTests.cs new file mode 100644 index 0000000..2308f07 --- /dev/null +++ b/src/Signal.Bot.UnitTests/Serialization/PollSerializationTests.cs @@ -0,0 +1,117 @@ +using System.Text.Json; +using Signal.Bot.Requests; + +namespace Signal.Bot.UnitTests.Serialization; +public class PollSerializationTests +{ + [Fact(Timeout = 5000)] + public void TestAddPollRequestSerializationAndDeserialization() + { + // Arrange + var addPollRequest = new AddPollRequest("") + { + AllowMultipleSelections = true, + Answers = ["yes", "no", "maybe"], + Question = "Does this test succeed?", + Recipient = "123456789" + }; + + // Act + var json = JsonSerializer.Serialize(addPollRequest); + var deserialized = JsonSerializer.Deserialize(json); + + // Assert + Assert.NotNull(deserialized); + Assert.NotNull(deserialized.AllowMultipleSelections); + Assert.Equal(true, deserialized.AllowMultipleSelections); + Assert.NotNull(deserialized.Answers); + Assert.Equal("yes", deserialized.Answers[0]); + Assert.Equal("no", deserialized.Answers[1]); + Assert.Equal("maybe", deserialized.Answers[2]); + Assert.NotNull(deserialized.Question); + Assert.Equal("Does this test succeed?", deserialized.Question); + Assert.NotNull(deserialized.Recipient); + Assert.Equal("123456789", deserialized.Recipient); + } + + [Fact(Timeout = 5000)] + public void TestClosePollRequestSerializationAndDeserialization() + { + // Arrange + var timestamp = DateTime.Now; + var closePollRequest = new ClosePollRequest("") + { + Timestamp = timestamp, + Recipient = "123456789" + }; + + // Act + var json = JsonSerializer.Serialize(closePollRequest); + var deserialized = JsonSerializer.Deserialize(json); + + // Assert + Assert.NotNull(deserialized); + Assert.Equal(timestamp, deserialized.Timestamp); + Assert.NotNull(deserialized.Recipient); + Assert.Equal("123456789", deserialized.Recipient); + } + + [Fact(Timeout = 5000)] + public void TestVotePollRequestSerializationAndDeserialization_SingleAnswer() + { + // Arrange + var timestamp = DateTime.Now; + var votePollRequest = new VotePollRequest("") + { + Recipient = "123456789", + Timestamp = timestamp, + SelectedAnswers = [0], + PollAuthor = "98765421" + }; + + // Act + var json = JsonSerializer.Serialize(votePollRequest); + var deserialized = JsonSerializer.Deserialize(json); + + // Assert + Assert.NotNull(deserialized); + Assert.Equal(timestamp, deserialized.Timestamp); + Assert.NotNull(deserialized.SelectedAnswers); + Assert.Equal(0, deserialized.SelectedAnswers[0]); + Assert.NotNull(deserialized.PollAuthor); + Assert.Equal("98765421", deserialized.PollAuthor); + Assert.NotNull(deserialized.Recipient); + Assert.Equal("123456789", deserialized.Recipient); + } + + + + [Fact(Timeout = 5000)] + public void TestVotePollRequestSerializationAndDeserialization_MultipleAnswers() + { + // Arrange + var timestamp = DateTime.Now; + var votePollRequest = new VotePollRequest("") + { + Recipient = "123456789", + Timestamp = timestamp, + SelectedAnswers = [2, 0], + PollAuthor = "98765421" + }; + + // Act + var json = JsonSerializer.Serialize(votePollRequest); + var deserialized = JsonSerializer.Deserialize(json); + + // Assert + Assert.NotNull(deserialized); + Assert.Equal(timestamp, deserialized.Timestamp); + Assert.NotNull(deserialized.SelectedAnswers); + Assert.Equal(2, deserialized.SelectedAnswers[0]); + Assert.Equal(0, deserialized.SelectedAnswers[1]); + Assert.NotNull(deserialized.PollAuthor); + Assert.Equal("98765421", deserialized.PollAuthor); + Assert.NotNull(deserialized.Recipient); + Assert.Equal("123456789", deserialized.Recipient); + } +} \ No newline at end of file diff --git a/src/Signal.Bot/Extensions.cs b/src/Signal.Bot/Extensions.cs index 168dac5..3f9535a 100644 --- a/src/Signal.Bot/Extensions.cs +++ b/src/Signal.Bot/Extensions.cs @@ -956,7 +956,7 @@ public static async Task GetContactAsync(this ISignalBotClient client, /// The recipient for this poll (user or group) /// A to observe for cancellation requests. /// - public static async Task CreatePollAsync(this ISignalBotClient client, + public static async Task AddPollAsync(this ISignalBotClient client, bool? allowMultipleSelections, string[]? answers, string? question, diff --git a/src/Signal.Bot/Serialization/JsonBotAPI.cs b/src/Signal.Bot/Serialization/JsonBotAPI.cs index b162ac0..3bf49e8 100644 --- a/src/Signal.Bot/Serialization/JsonBotAPI.cs +++ b/src/Signal.Bot/Serialization/JsonBotAPI.cs @@ -90,6 +90,7 @@ public static JsonTypeInfo Get(Type key) { typeof(OfferMessage), JsonBotSerializerContext.Default.OfferMessage }, { typeof(HangupMessage), JsonBotSerializerContext.Default.HangupMessage }, { typeof(IceUpdateMessage), JsonBotSerializerContext.Default.IceUpdateMessage }, + { typeof(PollResponse), JsonBotSerializerContext.Default.PollResponse }, // Request Types { typeof(AddDeviceRequest), JsonBotSerializerContext.Default.AddDeviceRequest }, { typeof(AddGroupAdminRequest), JsonBotSerializerContext.Default.AddGroupAdminRequest }, @@ -141,7 +142,10 @@ public static JsonTypeInfo Get(Type key) { typeof(UpdateGroupRequest), JsonBotSerializerContext.Default.UpdateGroupRequest }, { typeof(UpdateProfileRequest), JsonBotSerializerContext.Default.UpdateProfileRequest }, { typeof(VerifyNumberRequest), JsonBotSerializerContext.Default.VerifyNumberRequest }, - + { typeof(AddPollRequest), JsonBotSerializerContext.Default.AddPollRequest }, + { typeof(ClosePollRequest), JsonBotSerializerContext.Default.ClosePollRequest }, + { typeof(VotePollRequest), JsonBotSerializerContext.Default.VotePollRequest }, + // Collection Types { typeof(List), JsonBotSerializerContext.Default.ListGroup }, { typeof(List), JsonBotSerializerContext.Default.ListAttachment }, diff --git a/src/Signal.Bot/Serialization/JsonBotSerializerContext.cs b/src/Signal.Bot/Serialization/JsonBotSerializerContext.cs index 7c20e14..66354f3 100644 --- a/src/Signal.Bot/Serialization/JsonBotSerializerContext.cs +++ b/src/Signal.Bot/Serialization/JsonBotSerializerContext.cs @@ -57,6 +57,7 @@ namespace Signal.Bot.Serialization; [JsonSerializable(typeof(OfferMessage))] [JsonSerializable(typeof(HangupMessage))] [JsonSerializable(typeof(IceUpdateMessage))] +[JsonSerializable(typeof(PollResponse))] // Requests [JsonSerializable(typeof(AddDeviceRequest))] [JsonSerializable(typeof(AddGroupAdminRequest))] @@ -108,6 +109,9 @@ namespace Signal.Bot.Serialization; [JsonSerializable(typeof(UpdateGroupRequest))] [JsonSerializable(typeof(UpdateProfileRequest))] [JsonSerializable(typeof(VerifyNumberRequest))] +[JsonSerializable(typeof(AddPollRequest))] +[JsonSerializable(typeof(ClosePollRequest))] +[JsonSerializable(typeof(VotePollRequest))] // Arrays/Collections [JsonSerializable(typeof(List))] From d89a2a25fb844a38ae82bbca28e52788304fb545 Mon Sep 17 00:00:00 2001 From: st0o0 <64534642+st0o0@users.noreply.github.com> Date: Mon, 6 Apr 2026 21:36:08 +0200 Subject: [PATCH 4/7] Update packages.lock.json --- src/Signal.Bot/packages.lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Signal.Bot/packages.lock.json b/src/Signal.Bot/packages.lock.json index 2f2a0d8..165e198 100644 --- a/src/Signal.Bot/packages.lock.json +++ b/src/Signal.Bot/packages.lock.json @@ -4,9 +4,9 @@ "net10.0": { "Microsoft.NET.ILLink.Tasks": { "type": "Direct", - "requested": "[10.0.3, )", - "resolved": "10.0.3", - "contentHash": "0B6nZyCHWXnvmlB559oduOspVdNOnpNXPjhpWVMovLPAsDVG7A4jJR9rzECf67JUzxP8/ee/wA8clwIzJcWNFA==" + "requested": "[10.0.4, )", + "resolved": "10.0.4", + "contentHash": "CCx8ojW3mOL150/LnP0DK7qpMrJEt6xxNCmJFKoX89v1h0FwpsEHqennowGPYDxp6zIkIO4f9PxynjOeLF+1zw==" }, "R3": { "type": "Direct", From 89c351071a54816c42e77cc097fc38397659d0ac Mon Sep 17 00:00:00 2001 From: LineOfC0d3 Date: Mon, 6 Apr 2026 21:55:24 +0200 Subject: [PATCH 5/7] Add example for polls --- src/Signal.Bot.Example/Guide/Polls.cs | 35 +++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 src/Signal.Bot.Example/Guide/Polls.cs diff --git a/src/Signal.Bot.Example/Guide/Polls.cs b/src/Signal.Bot.Example/Guide/Polls.cs new file mode 100644 index 0000000..76d79a6 --- /dev/null +++ b/src/Signal.Bot.Example/Guide/Polls.cs @@ -0,0 +1,35 @@ +namespace Signal.Bot.Example.Guide; + +public class Polls +{ + private readonly SignalBotClient client = null!; + + public async Task CreatingPoll() + { + #region CreatingPoll + await client.AddPollAsync(true, + new[] { "Option 1", "Option 2", "Option 3" }, + "Question", + "+1111111111"); + #endregion + } + + public async Task ClosingPoll() + { + #region ClosingPoll + await client.ClosePollAsync( new DateTime(2026,04,06,12,00,00), + "+1111111111"); + #endregion + } + + public async Task VotingInPoll() + { + #region VotingInPoll + + await client.VotePollAsync("+2222222222", + new DateTime(2026, 04, 06, 12, 00, 00), + "+1111111111", + [0, 1]); + #endregion + } +} \ No newline at end of file From 4b6cd04d566757d0ae9f160b4b084270004e8817 Mon Sep 17 00:00:00 2001 From: st0o0 <64534642+st0o0@users.noreply.github.com> Date: Tue, 7 Apr 2026 06:35:33 +0200 Subject: [PATCH 6/7] fix? --- src/Directory.Packages.props | 36 ++++++++++--------- .../Signal.Bot.Example.csproj | 2 ++ src/Signal.Bot/Signal.Bot.csproj | 2 ++ src/Signal.Bot/packages.lock.json | 12 +++++-- 4 files changed, 32 insertions(+), 20 deletions(-) diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props index a053889..8e6afe4 100644 --- a/src/Directory.Packages.props +++ b/src/Directory.Packages.props @@ -1,19 +1,21 @@ - - true - - - - - - - - - - - - - - - + + true + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Signal.Bot.Example/Signal.Bot.Example.csproj b/src/Signal.Bot.Example/Signal.Bot.Example.csproj index 802fff4..2b6b376 100644 --- a/src/Signal.Bot.Example/Signal.Bot.Example.csproj +++ b/src/Signal.Bot.Example/Signal.Bot.Example.csproj @@ -8,6 +8,8 @@ + + diff --git a/src/Signal.Bot/Signal.Bot.csproj b/src/Signal.Bot/Signal.Bot.csproj index 4581e5a..db3924b 100644 --- a/src/Signal.Bot/Signal.Bot.csproj +++ b/src/Signal.Bot/Signal.Bot.csproj @@ -36,6 +36,8 @@ + + diff --git a/src/Signal.Bot/packages.lock.json b/src/Signal.Bot/packages.lock.json index 165e198..2973462 100644 --- a/src/Signal.Bot/packages.lock.json +++ b/src/Signal.Bot/packages.lock.json @@ -2,11 +2,17 @@ "version": 2, "dependencies": { "net10.0": { + "Microsoft.DotNet.ILCompiler": { + "type": "Direct", + "requested": "[10.0.5, )", + "resolved": "10.0.5", + "contentHash": "yadTZIkStCVsG8nGwvfroSfBApPsgjQbodQyaIfp53dgayE0qhZpywixiCB6lx57JYQ+KVg1m1AFLrj54pxpZg==" + }, "Microsoft.NET.ILLink.Tasks": { "type": "Direct", - "requested": "[10.0.4, )", - "resolved": "10.0.4", - "contentHash": "CCx8ojW3mOL150/LnP0DK7qpMrJEt6xxNCmJFKoX89v1h0FwpsEHqennowGPYDxp6zIkIO4f9PxynjOeLF+1zw==" + "requested": "[10.0.5, )", + "resolved": "10.0.5", + "contentHash": "A+5ZuQ0f449tM+MQrhf6R9ZX7lYpjk/ODEwLYKrnF6111rtARx8fVsm4YznUnQiKnnXfaXNBqgxmil6RW3L3SA==" }, "R3": { "type": "Direct", From ede4660b226d16ca8b02e871892d33169167a66c Mon Sep 17 00:00:00 2001 From: LineOfC0d3 Date: Thu, 9 Apr 2026 22:55:26 +0200 Subject: [PATCH 7/7] Update docs --- docs/guide/groups.md | 3 ++- docs/guide/polls.md | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 docs/guide/polls.md diff --git a/docs/guide/groups.md b/docs/guide/groups.md index 069b315..a75e858 100644 --- a/docs/guide/groups.md +++ b/docs/guide/groups.md @@ -64,5 +64,6 @@ Send a message to a group: ## Next Steps - Learn about [attachments](/guide/attachments) +- Learn about [polls](/guide/polls) - Explore [profile management](/guide/profiles) -- Check out [advanced examples](/examples/) \ No newline at end of file +- Check out [advanced examples](/examples/) diff --git a/docs/guide/polls.md b/docs/guide/polls.md new file mode 100644 index 0000000..bc7ea5a --- /dev/null +++ b/docs/guide/polls.md @@ -0,0 +1,19 @@ +# Polls Management + +Manage polls created by your bot or any other user. + +## Creating a poll + +<<< ./../../src/Signal.Bot.Example/Guide/Polls.cs#CreatingPoll{csharp} + +## Closing a poll + +<<< ./../../src/Signal.Bot.Example/Guide/Polls.cs#ClosingPoll{csharp} + +## Voting in a poll + +<<< ./../../src/Signal.Bot.Example/Guide/Polls.cs#VotingInPoll{csharp} + +## Next Steps + +- Check out [examples](/examples/)