Skip to content

Commit

Permalink
Implemented polls (#116)
Browse files Browse the repository at this point in the history
* Initial poll implementation

* Added entity extensions. Added poll prefix to method name

* Added poll dispatch handlers

* Added poll permissions

* Added REST error codes

* Added poll intents

* Added poll gateway events

* Implemented local poll CreateFrom methods.
  • Loading branch information
Quahu authored May 25, 2024
1 parent 95343cc commit 49a8b81
Show file tree
Hide file tree
Showing 57 changed files with 1,178 additions and 6 deletions.
14 changes: 14 additions & 0 deletions src/Disqord.Abstractions/Client/DiscordClientBase.Events.cs
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,20 @@ public event AsynchronousEventHandler<StageDeletedEventArgs> StageDeleted
remove => GatewayClient.StageDeleted -= value;
}

/// <inheritdoc/>
public event AsynchronousEventHandler<PollVoteAddedEventArgs> PollVoteAdded
{
add => GatewayClient.PollVoteAdded += value;
remove => GatewayClient.PollVoteAdded -= value;
}

/// <inheritdoc/>
public event AsynchronousEventHandler<PollVoteRemovedEventArgs> PollVoteRemoved
{
add => GatewayClient.PollVoteRemoved += value;
remove => GatewayClient.PollVoteRemoved -= value;
}

/// <inheritdoc/>
public event AsynchronousEventHandler<TypingStartedEventArgs> TypingStarted
{
Expand Down
5 changes: 5 additions & 0 deletions src/Disqord.Core/Discord/Limits/Rest/Discord.Limits.Rest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,11 @@ public static class Rest
/// Represents the page size for fetching event users.
/// </summary>
public const int FetchGuildEventUsersPageSize = 100;

/// <summary>
/// Represents the page size for fetching poll answer voters.
/// </summary>
public const int FetchPollAnswerVotersPageSize = 100;
}
}
}
5 changes: 5 additions & 0 deletions src/Disqord.Core/Entities/Core/Message/User/IUserMessage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -113,4 +113,9 @@ public interface IUserMessage : IMessage
/// Gets the stickers sent with this message.
/// </summary>
IReadOnlyList<IMessageSticker> Stickers { get; }

/// <summary>
/// Gets the poll of this message.
/// </summary>
IPoll? Poll { get; }
}
40 changes: 40 additions & 0 deletions src/Disqord.Core/Entities/Core/Message/User/Poll/IPoll.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using System;
using System.Collections.Generic;

namespace Disqord;

/// <summary>
/// Represents a poll.
/// </summary>
public interface IPoll : IEntity
{
/// <summary>
/// Gets the question of this poll.
/// </summary>
IPollMedia Question { get; }

/// <summary>
/// Gets the answers of this poll.
/// </summary>
IReadOnlyList<IPollAnswer> Answers { get; }

/// <summary>
/// Gets the expiry of this poll.
/// </summary>
DateTimeOffset? Expiry { get; }

/// <summary>
/// Gets whether this poll allows selection of multiple answers.
/// </summary>
bool AllowMultiselect { get; }

/// <summary>
/// Gets the layout type of this poll.
/// </summary>
PollLayoutType LayoutType { get; }

/// <summary>
/// Gets the results of this poll.
/// </summary>
IPollResults? Results { get; }
}
17 changes: 17 additions & 0 deletions src/Disqord.Core/Entities/Core/Message/User/Poll/IPollAnswer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
namespace Disqord;

/// <summary>
/// Represents a poll answer.
/// </summary>
public interface IPollAnswer : IEntity
{
/// <summary>
/// Gets the ID of the poll answer. This is used to match <see cref="IPollAnswerCount"/> based on the ID.
/// </summary>
int Id { get; }

/// <summary>
/// Gets the media of this poll answer.
/// </summary>
IPollMedia Media { get; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
namespace Disqord;

/// <summary>
/// Represents the vote count of a poll answer.
/// </summary>
public interface IPollAnswerCount : IEntity
{
/// <summary>
/// Gets the ID of the poll answer.
/// </summary>
int AnswerId { get; }

/// <summary>
/// Gets the amount of users that selected the poll answer.
/// </summary>
int Count { get; }

/// <summary>
/// Gets whether the bot has selected the poll answer.
/// </summary>
bool HasOwnVote { get; }
}
17 changes: 17 additions & 0 deletions src/Disqord.Core/Entities/Core/Message/User/Poll/IPollMedia.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
namespace Disqord;

/// <summary>
/// Represents poll media.
/// </summary>
public interface IPollMedia : IEntity
{
/// <summary>
/// Gets the text of this poll media.
/// </summary>
string? Text { get; }

/// <summary>
/// Gets the emoji of this poll media.
/// </summary>
IEmoji? Emoji { get; }
}
19 changes: 19 additions & 0 deletions src/Disqord.Core/Entities/Core/Message/User/Poll/IPollResults.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using System.Collections.Generic;

namespace Disqord;

/// <summary>
/// Represents the results of a poll.
/// </summary>
public interface IPollResults : IEntity
{
/// <summary>
/// Gets whether the votes have been precisely counted.
/// </summary>
bool IsFinalized { get; }

/// <summary>
/// Gets the vote counts of each answer.
/// </summary>
IReadOnlyList<IPollAnswerCount> AnswerCounts { get; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -147,4 +147,11 @@ public static TMessage WithStickerIds<TMessage>(this TMessage message, params Sn
{
return message.WithStickerIds(stickerIds as IEnumerable<Snowflake>);
}

public static TMessage WithPoll<TMessage>(this TMessage message, LocalPoll poll)
where TMessage : LocalMessageBase
{
message.Poll = poll;
return message;
}
}
6 changes: 6 additions & 0 deletions src/Disqord.Core/Entities/Local/Message/LocalMessageBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,11 @@ public abstract class LocalMessageBase : ILocalConstruct<LocalMessageBase>
/// </summary>
public Optional<IList<Snowflake>> StickerIds { get; set; }

/// <summary>
/// Gets or sets the poll of this message.
/// </summary>
public Optional<LocalPoll> Poll { get; set; }

/// <summary>
/// Instantiates a new <see cref="LocalMessageBase"/>.
/// </summary>
Expand All @@ -71,6 +76,7 @@ protected LocalMessageBase(LocalMessageBase other)
Attachments = other.Attachments.DeepClone();
Components = other.Components.DeepClone();
StickerIds = other.StickerIds.Clone();
Poll = other.Poll.Clone();
}

public abstract LocalMessageBase Clone();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using System.ComponentModel;

namespace Disqord;

[EditorBrowsable(EditorBrowsableState.Never)]
public static class LocalPollAnswerExtensions
{
public static TPollAnswer WithMedia<TPollAnswer>(this TPollAnswer answer, LocalPollMedia media)
where TPollAnswer : LocalPollAnswer
{
answer.Media = media;
return answer;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
using System.Collections.Generic;
using System.ComponentModel;
using Qommon;

namespace Disqord;

[EditorBrowsable(EditorBrowsableState.Never)]
public static class LocalPollExtensions
{
public static TPoll WithQuestion<TPoll>(this TPoll poll, string text)
where TPoll : LocalPoll
{
var media = new LocalPollMedia()
{
Text = text
};

return poll.WithQuestion(media);
}

public static TPoll WithQuestion<TPoll>(this TPoll poll, LocalPollMedia question)
where TPoll : LocalPoll
{
poll.Question = question;
return poll;
}

public static TPoll AddAnswer<TPoll>(this TPoll poll, string text, LocalEmoji? emoji = null)
where TPoll : LocalPoll
{
var media = new LocalPollMedia
{
Text = text,
Emoji = Optional.FromNullable(emoji)
};

var answer = new LocalPollAnswer()
{
Media = media
};

return poll.AddAnswer(answer);
}

public static TPoll AddAnswer<TPoll>(this TPoll poll, LocalPollAnswer answer)
where TPoll : LocalPoll
{
if (poll.Answers.Add(answer, out var list))
poll.Answers = new(list);

return poll;
}

public static TPoll WithAnswers<TPoll>(this TPoll poll, IEnumerable<LocalPollAnswer> answers)
where TPoll : LocalPoll
{
Guard.IsNotNull(answers);

if (poll.Answers.With(answers, out var list))
poll.Answers = new(list);

return poll;
}

public static TPoll WithAnswers<TPoll>(this TPoll poll, params LocalPollAnswer[] answers)
where TPoll : LocalPoll
{
return poll.WithAnswers(answers as IEnumerable<LocalPollAnswer>);
}

public static TPoll WithDuration<TPoll>(this TPoll poll, int duration)
where TPoll : LocalPoll
{
poll.Duration = duration;
return poll;
}

public static TPoll WithAllowMultiselect<TPoll>(this TPoll poll, bool allowMultiselect = true)
where TPoll : LocalPoll
{
poll.AllowMultiselect = allowMultiselect;
return poll;
}

public static TPoll WithLayoutType<TPoll>(this TPoll poll, PollLayoutType layoutType)
where TPoll : LocalPoll
{
poll.LayoutType = layoutType;
return poll;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using System.ComponentModel;

namespace Disqord;

[EditorBrowsable(EditorBrowsableState.Never)]
public static class LocalPollMediaExtensions
{
public static TPollMedia WithText<TPollMedia>(this TPollMedia media, string text)
where TPollMedia : LocalPollMedia
{
media.Text = text;
return media;
}

public static TPollMedia WithEmoji<TPollMedia>(this TPollMedia media, LocalEmoji emoji)
where TPollMedia : LocalPollMedia
{
media.Emoji = emoji;
return media;
}
}
Loading

0 comments on commit 49a8b81

Please sign in to comment.