Public poll added. Fixed normal poll bugs. #264

This commit is contained in:
Kwoth 2016-10-24 20:26:28 +02:00
parent 4fa0f1533a
commit 443c6297d9
3 changed files with 116 additions and 32 deletions

View File

@ -16,8 +16,18 @@ namespace NadekoBot.Modules.Games
public static ConcurrentDictionary<IGuild, Poll> ActivePolls = new ConcurrentDictionary<IGuild, Poll>(); public static ConcurrentDictionary<IGuild, Poll> ActivePolls = new ConcurrentDictionary<IGuild, Poll>();
[NadekoCommand, Usage, Description, Aliases] [NadekoCommand, Usage, Description, Aliases]
[RequirePermission(GuildPermission.ManageMessages)]
[RequireContext(ContextType.Guild)] [RequireContext(ContextType.Guild)]
public async Task Poll(IUserMessage umsg, [Remainder] string arg = null) public Task Poll(IUserMessage umsg, [Remainder] string arg = null)
=> InternalStartPoll(umsg, arg, isPublic: false);
[NadekoCommand, Usage, Description, Aliases]
[RequirePermission(GuildPermission.ManageMessages)]
[RequireContext(ContextType.Guild)]
public Task PublicPoll(IUserMessage umsg, [Remainder] string arg = null)
=> InternalStartPoll(umsg, arg, isPublic: true);
private async Task InternalStartPoll(IUserMessage umsg, string arg, bool isPublic = false)
{ {
var channel = (ITextChannel)umsg.Channel; var channel = (ITextChannel)umsg.Channel;
@ -29,57 +39,63 @@ namespace NadekoBot.Modules.Games
if (data.Length < 3) if (data.Length < 3)
return; return;
var poll = new Poll(umsg, data[0], data.Skip(1)); var poll = new Poll(umsg, data[0], data.Skip(1), isPublic: isPublic);
if (ActivePolls.TryAdd(channel.Guild, poll)) if (ActivePolls.TryAdd(channel.Guild, poll))
{ {
await poll.StartPoll().ConfigureAwait(false); await poll.StartPoll().ConfigureAwait(false);
} }
else
await channel.SendMessageAsync("`Poll is already running on this server.`").ConfigureAwait(false);
} }
[NadekoCommand, Usage, Description, Aliases] [NadekoCommand, Usage, Description, Aliases]
[RequirePermission(GuildPermission.ManageMessages)]
[RequireContext(ContextType.Guild)] [RequireContext(ContextType.Guild)]
public async Task Pollend(IUserMessage umsg) public async Task Pollend(IUserMessage umsg)
{ {
var channel = (ITextChannel)umsg.Channel; var channel = (ITextChannel)umsg.Channel;
if (!(umsg.Author as IGuildUser).GuildPermissions.ManageChannels)
return;
Poll poll; Poll poll;
ActivePolls.TryGetValue(channel.Guild, out poll); ActivePolls.TryRemove(channel.Guild, out poll);
await poll.StopPoll(channel).ConfigureAwait(false); await poll.StopPoll().ConfigureAwait(false);
} }
} }
public class Poll public class Poll
{ {
private readonly IUserMessage umsg; private readonly IUserMessage originalMessage;
private readonly IGuild guild; private readonly IGuild guild;
private readonly string[] answers; private readonly string[] answers;
private ConcurrentDictionary<ulong, int> participants = new ConcurrentDictionary<ulong, int>(); private ConcurrentDictionary<ulong, int> participants = new ConcurrentDictionary<ulong, int>();
private readonly string question; private readonly string question;
private DateTime started; private DateTime started;
private CancellationTokenSource pollCancellationSource = new CancellationTokenSource(); private CancellationTokenSource pollCancellationSource = new CancellationTokenSource();
private readonly bool isPublic;
public Poll(IUserMessage umsg, string question, IEnumerable<string> enumerable) public Poll(IUserMessage umsg, string question, IEnumerable<string> enumerable, bool isPublic = false)
{ {
this.umsg = umsg; this.originalMessage = umsg;
this.guild = ((ITextChannel)umsg.Channel).Guild; this.guild = ((ITextChannel)umsg.Channel).Guild;
this.question = question; this.question = question;
this.answers = enumerable as string[] ?? enumerable.ToArray(); this.answers = enumerable as string[] ?? enumerable.ToArray();
this.isPublic = isPublic;
} }
public async Task StartPoll() public async Task StartPoll()
{ {
started = DateTime.Now; started = DateTime.Now;
NadekoBot.Client.MessageReceived += Vote; NadekoBot.Client.MessageReceived += Vote;
var msgToSend = $"📃**{umsg.Author.Username}** has created a poll which requires your attention:\n\n**{question}**\n"; var msgToSend = $"📃**{originalMessage.Author.Username}** has created a poll which requires your attention:\n\n**{question}**\n";
var num = 1; var num = 1;
msgToSend = answers.Aggregate(msgToSend, (current, answ) => current + $"`{num++}.` **{answ}**\n"); msgToSend = answers.Aggregate(msgToSend, (current, answ) => current + $"`{num++}.` **{answ}**\n");
msgToSend += "\n**Private Message me with the corresponding number of the answer.**"; if (!isPublic)
await umsg.Channel.SendMessageAsync(msgToSend).ConfigureAwait(false); msgToSend += "\n**Private Message me with the corresponding number of the answer.**";
else
msgToSend += "\n**Send a Message here with the corresponding number of the answer.**";
await originalMessage.Channel.SendMessageAsync(msgToSend).ConfigureAwait(false);
} }
public async Task StopPoll(IGuildChannel ch) public async Task StopPoll()
{ {
NadekoBot.Client.MessageReceived -= Vote; NadekoBot.Client.MessageReceived -= Vote;
try try
@ -91,7 +107,7 @@ namespace NadekoBot.Modules.Games
var totalVotesCast = results.Sum(kvp => kvp.Value); var totalVotesCast = results.Sum(kvp => kvp.Value);
if (totalVotesCast == 0) if (totalVotesCast == 0)
{ {
await umsg.Channel.SendMessageAsync("📄 **No votes have been cast.**").ConfigureAwait(false); await originalMessage.Channel.SendMessageAsync("📄 **No votes have been cast.**").ConfigureAwait(false);
return; return;
} }
var closeMessage = $"--------------**POLL CLOSED**--------------\n" + var closeMessage = $"--------------**POLL CLOSED**--------------\n" +
@ -100,7 +116,7 @@ namespace NadekoBot.Modules.Games
$" has {kvp.Value} votes." + $" has {kvp.Value} votes." +
$"({kvp.Value * 1.0f / totalVotesCast * 100}%)\n"); $"({kvp.Value * 1.0f / totalVotesCast * 100}%)\n");
await umsg.Channel.SendMessageAsync($"📄 **Total votes cast**: {totalVotesCast}\n{closeMessage}").ConfigureAwait(false); await originalMessage.Channel.SendMessageAsync($"📄 **Total votes cast**: {totalVotesCast}\n{closeMessage}").ConfigureAwait(false);
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -108,30 +124,62 @@ namespace NadekoBot.Modules.Games
} }
} }
private async Task Vote(IMessage imsg) private Task Vote(IMessage imsg)
{ {
// has to be a user message // has to be a user message
var msg = imsg as IUserMessage; var msg = imsg as IUserMessage;
if (msg == null || msg.Author.IsBot) if (msg == null || msg.Author.IsBot)
return; return Task.CompletedTask;
// channel must be private
IPrivateChannel ch;
if ((ch = msg.Channel as IPrivateChannel) == null)
return;
var guildUsers = await guild.GetUsersAsync().ConfigureAwait(false);
if (!guildUsers.Any(u => u.Id == imsg.Author.Id))
return;
// has to be an integer // has to be an integer
int vote; int vote;
if (!int.TryParse(msg.Content, out vote)) return; if (!int.TryParse(imsg.Content, out vote))
return Task.CompletedTask;
if (vote < 1 || vote > answers.Length) if (vote < 1 || vote > answers.Length)
return; return Task.CompletedTask;
if (participants.TryAdd(msg.Author.Id, vote))
var t = Task.Run(async () =>
{ {
try { await ((IMessageChannel)ch).SendMessageAsync($"Thanks for voting **{msg.Author.Username}**.").ConfigureAwait(false); } catch { } try
} {
return; IMessageChannel ch;
if (isPublic)
{
//if public, channel must be the same the poll started in
if (originalMessage.Channel.Id != imsg.Channel.Id)
return;
ch = imsg.Channel;
}
else
{
//if private, channel must be dm channel
if ((ch = msg.Channel as IDMChannel) == null)
return;
// user must be a member of the guild this poll is in
var guildUsers = await guild.GetUsersAsync().ConfigureAwait(false);
if (!guildUsers.Any(u => u.Id == imsg.Author.Id))
return;
}
//user can vote only once
if (participants.TryAdd(msg.Author.Id, vote))
{
if (!isPublic)
{
await ch.SendMessageAsync($"Thanks for voting **{msg.Author.Username}**.").ConfigureAwait(false);
}
else
{
var toDelete = await ch.SendMessageAsync($"{msg.Author.Mention} cast their vote.").ConfigureAwait(false);
await Task.Delay(5000);
await toDelete.DeleteAsync().ConfigureAwait(false);
}
}
}
catch { }
});
return Task.CompletedTask;
} }
} }
} }

View File

@ -4443,7 +4443,7 @@ namespace NadekoBot.Resources {
} }
/// <summary> /// <summary>
/// Looks up a localized string similar to Creates a poll, only person who has manage server permission can do it.. /// Looks up a localized string similar to Creates a poll which requires users to send the number of the voting option to the bot..
/// </summary> /// </summary>
public static string poll_desc { public static string poll_desc {
get { get {
@ -4514,6 +4514,33 @@ namespace NadekoBot.Resources {
} }
} }
/// <summary>
/// Looks up a localized string similar to publicpoll ppoll.
/// </summary>
public static string publicpoll_cmd {
get {
return ResourceManager.GetString("publicpoll_cmd", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Creates a public poll which requires users to type a number of the voting option in the channel command is ran in..
/// </summary>
public static string publicpoll_desc {
get {
return ResourceManager.GetString("publicpoll_desc", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to `{0}ppoll Question?;Answer1;Answ 2;A_3`.
/// </summary>
public static string publicpoll_usage {
get {
return ResourceManager.GetString("publicpoll_usage", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to queue q yq. /// Looks up a localized string similar to queue q yq.
/// </summary> /// </summary>

View File

@ -1336,7 +1336,7 @@
<value>poll</value> <value>poll</value>
</data> </data>
<data name="poll_desc" xml:space="preserve"> <data name="poll_desc" xml:space="preserve">
<value>Creates a poll, only person who has manage server permission can do it.</value> <value>Creates a poll which requires users to send the number of the voting option to the bot.</value>
</data> </data>
<data name="poll_usage" xml:space="preserve"> <data name="poll_usage" xml:space="preserve">
<value>`{0}poll Question?;Answer1;Answ 2;A_3`</value> <value>`{0}poll Question?;Answer1;Answ 2;A_3`</value>
@ -2538,4 +2538,13 @@
<data name="togethertube_usage" xml:space="preserve"> <data name="togethertube_usage" xml:space="preserve">
<value>`{0}totube`</value> <value>`{0}totube`</value>
</data> </data>
<data name="publicpoll_cmd" xml:space="preserve">
<value>publicpoll ppoll</value>
</data>
<data name="publicpoll_desc" xml:space="preserve">
<value>Creates a public poll which requires users to type a number of the voting option in the channel command is ran in.</value>
</data>
<data name="publicpoll_usage" xml:space="preserve">
<value>`{0}ppoll Question?;Answer1;Answ 2;A_3`</value>
</data>
</root> </root>