implemented polls in the discord bot
This commit is contained in:
parent
1d999e89bf
commit
715b14ecc5
13 changed files with 277 additions and 6 deletions
|
@ -64,6 +64,22 @@ namespace DiscordBot.CommandHandlers
|
||||||
await component.RespondAsync("Opting out failed, please try again later or change the setting on the website.");
|
await component.RespondAsync("Opting out failed, please try again later or change the setting on the website.");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case Constants.ComponentIds.POLL_ANSWER_BUTTON:
|
||||||
|
PollMessage.Parameters pollAnswerParameters = PollMessage.ParseId(component.Data.CustomId);
|
||||||
|
ApiPollAnswer answer = new ApiPollAnswer()
|
||||||
|
{
|
||||||
|
Answer = string.Empty,
|
||||||
|
OptionId = pollAnswerParameters.OptionId,
|
||||||
|
PollId = pollAnswerParameters.PollId,
|
||||||
|
UserId = component.User.Id
|
||||||
|
};
|
||||||
|
await _httpService.AnswerPoll(answer);
|
||||||
|
await component.RespondAsync("Answer sent.", ephemeral: true);
|
||||||
|
break;
|
||||||
|
case Constants.ComponentIds.POLL_CUSTOM_ANSWER_BUTTON:
|
||||||
|
PollMessage.Parameters pollCustomParameters = PollMessage.ParseId(component.Data.CustomId);
|
||||||
|
await component.RespondWithModalAsync(PollCustomModal.buildMessage(pollCustomParameters.PollId, component.Message.Content));
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -63,6 +63,19 @@ namespace DiscordBot.CommandHandlers
|
||||||
await modal.RespondAsync($"signing up failed", ephemeral: true);
|
await modal.RespondAsync($"signing up failed", ephemeral: true);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case Constants.ComponentIds.POLL_CUSTOM_ANSWER_MODAL:
|
||||||
|
PollCustomModal.Parameters pollParameters = PollCustomModal.ParseId(modal.Data.CustomId);
|
||||||
|
string modalAnswer = components.First(x => x.CustomId == Constants.ComponentIds.POLL_CUSTOM_ANSWER_TEXT_BOX).Value;
|
||||||
|
ApiPollAnswer answer = new ApiPollAnswer()
|
||||||
|
{
|
||||||
|
Answer = modalAnswer,
|
||||||
|
OptionId = 0,
|
||||||
|
PollId = pollParameters.PollId,
|
||||||
|
UserId = modal.User.Id
|
||||||
|
};
|
||||||
|
await _httpService.AnswerPoll(answer);
|
||||||
|
await modal.RespondAsync("Answer sent.", ephemeral: true);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,6 +54,18 @@ namespace DiscordBot.CommandHandlers
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case Constants.ComponentIds.POLL_DROP_DOWN:
|
||||||
|
PollMessage.Parameters pollParameters = PollMessage.ParseId(component.Data.CustomId);
|
||||||
|
ApiPollAnswer answer = new ApiPollAnswer()
|
||||||
|
{
|
||||||
|
Answer = string.Empty,
|
||||||
|
OptionId = int.Parse(component.Data.Values.First()),
|
||||||
|
PollId = pollParameters.PollId,
|
||||||
|
UserId = component.User.Id
|
||||||
|
};
|
||||||
|
await _httpService.AnswerPoll(answer);
|
||||||
|
await component.RespondAsync("Answer sent.", ephemeral: true);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,13 @@
|
||||||
public const string CREATE_ACCOUNT_MODAL = "createAccountModal";
|
public const string CREATE_ACCOUNT_MODAL = "createAccountModal";
|
||||||
|
|
||||||
public const string SIGN_UP_EXTERNAL_MODAL = "signUpExternalModal";
|
public const string SIGN_UP_EXTERNAL_MODAL = "signUpExternalModal";
|
||||||
|
|
||||||
|
|
||||||
|
public const string POLL_DROP_DOWN = "pollDropDown";
|
||||||
|
public const string POLL_ANSWER_BUTTON = "pollAnswerButton";
|
||||||
|
public const string POLL_CUSTOM_ANSWER_BUTTON = "pollCustomAnswerButton";
|
||||||
|
public const string POLL_CUSTOM_ANSWER_MODAL = "pollCustomAnswerModal";
|
||||||
|
public const string POLL_CUSTOM_ANSWER_TEXT_BOX = "pollCustomAnswerTextBox";
|
||||||
}
|
}
|
||||||
|
|
||||||
public class SlashCommands
|
public class SlashCommands
|
||||||
|
|
|
@ -118,5 +118,38 @@ namespace DiscordBot.Controllers
|
||||||
{
|
{
|
||||||
await ReminderSubscriptionMessage.sendMessage(_client, userId);
|
await ReminderSubscriptionMessage.sendMessage(_client, userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpPost]
|
||||||
|
[Route("[action]")]
|
||||||
|
public async Task<List<ulong>> SendDropdownPoll(ApiPoll poll)
|
||||||
|
{
|
||||||
|
return await SendPoll(poll, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost]
|
||||||
|
[Route("[action]")]
|
||||||
|
public async Task<List<ulong>> SendButtonPoll(ApiPoll poll)
|
||||||
|
{
|
||||||
|
return await SendPoll(poll, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<List<ulong>> SendPoll(ApiPoll poll, bool isDropdown)
|
||||||
|
{
|
||||||
|
List<ulong> sent = new List<ulong>();
|
||||||
|
foreach(ulong userId in poll.UserIds)
|
||||||
|
{
|
||||||
|
var user = await _client.GetUserAsync(userId);
|
||||||
|
if(user != null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await user.SendMessageAsync(poll.Question, components: PollMessage.buildMessage(poll, isDropdown));
|
||||||
|
sent.Add(user.Id);
|
||||||
|
}
|
||||||
|
catch {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sent;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
38
DiscordBot/Messages/PollCustomModal.cs
Normal file
38
DiscordBot/Messages/PollCustomModal.cs
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
using Discord;
|
||||||
|
using Discord.WebSocket;
|
||||||
|
using System;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using SharedClasses.SharedModels;
|
||||||
|
|
||||||
|
namespace DiscordBot.Messages
|
||||||
|
{
|
||||||
|
public class PollCustomModal
|
||||||
|
{
|
||||||
|
public static Modal buildMessage(int pollId, string question)
|
||||||
|
{
|
||||||
|
var mb = new ModalBuilder()
|
||||||
|
.WithTitle(question)
|
||||||
|
.WithCustomId($"{Constants.ComponentIds.POLL_CUSTOM_ANSWER_MODAL}-{pollId}")
|
||||||
|
.AddTextInput("Answer", Constants.ComponentIds.POLL_CUSTOM_ANSWER_TEXT_BOX, placeholder: "Yes", required: true);
|
||||||
|
|
||||||
|
return mb.Build();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Parameters ParseId(string customId)
|
||||||
|
{
|
||||||
|
Parameters parameters = new Parameters();
|
||||||
|
|
||||||
|
string[] ids = customId.Split('-');
|
||||||
|
if(ids.Length > 1)
|
||||||
|
{
|
||||||
|
int.TryParse(ids[1],out parameters.PollId);
|
||||||
|
}
|
||||||
|
return parameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Parameters
|
||||||
|
{
|
||||||
|
public int PollId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
63
DiscordBot/Messages/PollMessage.cs
Normal file
63
DiscordBot/Messages/PollMessage.cs
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
using Discord;
|
||||||
|
using SharedClasses.SharedModels;
|
||||||
|
|
||||||
|
namespace DiscordBot.Messages
|
||||||
|
{
|
||||||
|
public class PollMessage
|
||||||
|
{
|
||||||
|
public static MessageComponent buildMessage(ApiPoll poll, bool isDropdown)
|
||||||
|
{
|
||||||
|
var builder = new ComponentBuilder();
|
||||||
|
if(isDropdown)
|
||||||
|
{
|
||||||
|
var signUpSelect = new SelectMenuBuilder()
|
||||||
|
.WithPlaceholder(poll.Question)
|
||||||
|
.WithCustomId($"{Constants.ComponentIds.POLL_DROP_DOWN}-{poll.PollId}")
|
||||||
|
.WithMinValues(1)
|
||||||
|
.WithMaxValues(1);
|
||||||
|
|
||||||
|
foreach(KeyValuePair<int, string> option in poll.Options)
|
||||||
|
{
|
||||||
|
signUpSelect.AddOption(option.Value, option.Key.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.WithSelectMenu(signUpSelect, 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
foreach(KeyValuePair<int, string> option in poll.Options)
|
||||||
|
{
|
||||||
|
builder.WithButton(option.Value, $"{Constants.ComponentIds.POLL_ANSWER_BUTTON}-{poll.PollId}-{option.Key}", ButtonStyle.Secondary);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(poll.AllowCustomAnswer)
|
||||||
|
{
|
||||||
|
builder.WithButton("Custom", $"{Constants.ComponentIds.POLL_CUSTOM_ANSWER_BUTTON}-{poll.PollId}", ButtonStyle.Secondary);
|
||||||
|
}
|
||||||
|
return builder.Build();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Parameters ParseId(string customId)
|
||||||
|
{
|
||||||
|
Parameters parameters = new Parameters();
|
||||||
|
|
||||||
|
string[] ids = customId.Split('-');
|
||||||
|
if(ids.Length > 1)
|
||||||
|
{
|
||||||
|
int.TryParse(ids[1], out parameters.PollId);
|
||||||
|
}
|
||||||
|
if(ids.Length > 2)
|
||||||
|
{
|
||||||
|
int.TryParse(ids[2], out parameters.OptionId);
|
||||||
|
}
|
||||||
|
return parameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Parameters
|
||||||
|
{
|
||||||
|
public int PollId;
|
||||||
|
public int OptionId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -269,5 +269,19 @@ namespace DiscordBot.Services
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task AnswerPoll(ApiPollAnswer answer)
|
||||||
|
{
|
||||||
|
var httpClient = _httpClientFactory.CreateClient(Constants.HTTP_CLIENT_NAME);
|
||||||
|
|
||||||
|
var raidItemJson = new StringContent(
|
||||||
|
JsonSerializer.Serialize(answer),
|
||||||
|
Encoding.UTF8,
|
||||||
|
Application.Json);
|
||||||
|
|
||||||
|
var httpResponseMessage = await httpClient.PostAsync("DiscordBot/AnswerPoll", raidItemJson);
|
||||||
|
|
||||||
|
httpResponseMessage.EnsureSuccessStatusCode();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -17,15 +17,17 @@ namespace Lieb.Controllers
|
||||||
{
|
{
|
||||||
RaidService _raidService;
|
RaidService _raidService;
|
||||||
UserService _userService;
|
UserService _userService;
|
||||||
|
PollService _pollService;
|
||||||
GuildWars2AccountService _gw2AccountService;
|
GuildWars2AccountService _gw2AccountService;
|
||||||
DiscordService _discordService;
|
DiscordService _discordService;
|
||||||
|
|
||||||
public DiscordBotController(RaidService raidService, UserService userService, GuildWars2AccountService gw2AccountService, DiscordService discordService)
|
public DiscordBotController(RaidService raidService, UserService userService, GuildWars2AccountService gw2AccountService, DiscordService discordService, PollService pollService)
|
||||||
{
|
{
|
||||||
_raidService = raidService;
|
_raidService = raidService;
|
||||||
_userService = userService;
|
_userService = userService;
|
||||||
_gw2AccountService = gw2AccountService;
|
_gw2AccountService = gw2AccountService;
|
||||||
_discordService = discordService;
|
_discordService = discordService;
|
||||||
|
_pollService = pollService;
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
|
@ -306,5 +308,12 @@ namespace Lieb.Controllers
|
||||||
{
|
{
|
||||||
return Ok(await _userService.ReminderOptOut(userId));
|
return Ok(await _userService.ReminderOptOut(userId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpPost]
|
||||||
|
[Route("[action]")]
|
||||||
|
public async Task AnswerPoll(ApiPollAnswer answer)
|
||||||
|
{
|
||||||
|
await _pollService.UpdateAnswer(answer.PollId, answer.OptionId, answer.Answer, answer.UserId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -171,11 +171,11 @@ namespace Lieb.Data
|
||||||
context.RaidSignUps.AddRange(signUps);
|
context.RaidSignUps.AddRange(signUps);
|
||||||
context.SaveChanges();
|
context.SaveChanges();
|
||||||
|
|
||||||
GuildWars2Build healTempest = new GuildWars2Build() { BuildName = "HealTempest", Class = GuildWars2Class.Elementalist, EliteSpecialization = EliteSpecialization.Tempest, Might = true, Alacrity = true, DamageType = DamageType.Heal };
|
GuildWars2Build healTempest = new GuildWars2Build() { BuildName = "HealTempest", Class = GuildWars2Class.Elementalist, EliteSpecialization = EliteSpecialization.Tempest, Might = true, Alacrity = true, DamageType = DamageType.Heal, UseInRandomRaid = true };
|
||||||
GuildWars2Build condiScourge = new GuildWars2Build() { BuildName = "CondiScourge", Class = GuildWars2Class.Necromancer, EliteSpecialization = EliteSpecialization.Scourge, DamageType = DamageType.Condition };
|
GuildWars2Build condiScourge = new GuildWars2Build() { BuildName = "CondiScourge", Class = GuildWars2Class.Necromancer, EliteSpecialization = EliteSpecialization.Scourge, DamageType = DamageType.Condition, UseInRandomRaid = true };
|
||||||
GuildWars2Build quickBrand = new GuildWars2Build() { BuildName = "QuickBrand", Class = GuildWars2Class.Guard, EliteSpecialization = EliteSpecialization.Firebrand, Quickness = true, DamageType = DamageType.Condition };
|
GuildWars2Build quickBrand = new GuildWars2Build() { BuildName = "QuickBrand", Class = GuildWars2Class.Guard, EliteSpecialization = EliteSpecialization.Firebrand, Quickness = true, DamageType = DamageType.Condition, UseInRandomRaid = true };
|
||||||
GuildWars2Build alacregate = new GuildWars2Build() { BuildName = "Alacregate", Class = GuildWars2Class.Revenant, EliteSpecialization = EliteSpecialization.Renegade, Alacrity = true, DamageType = DamageType.Power };
|
GuildWars2Build alacregate = new GuildWars2Build() { BuildName = "Alacregate", Class = GuildWars2Class.Revenant, EliteSpecialization = EliteSpecialization.Renegade, Alacrity = true, DamageType = DamageType.Power, UseInRandomRaid = true };
|
||||||
GuildWars2Build chrono = new GuildWars2Build() { BuildName = "Chrono", Class = GuildWars2Class.Mesmer, EliteSpecialization = EliteSpecialization.Chronomancer, Alacrity = true, Quickness = true, DamageType = DamageType.Power };
|
GuildWars2Build chrono = new GuildWars2Build() { BuildName = "Chrono", Class = GuildWars2Class.Mesmer, EliteSpecialization = EliteSpecialization.Chronomancer, Alacrity = true, Quickness = true, DamageType = DamageType.Power, UseInRandomRaid = true };
|
||||||
GuildWars2Build daredevil = new GuildWars2Build() { BuildName = "Daredevil", Class = GuildWars2Class.Thief, EliteSpecialization = EliteSpecialization.DareDevil };
|
GuildWars2Build daredevil = new GuildWars2Build() { BuildName = "Daredevil", Class = GuildWars2Class.Thief, EliteSpecialization = EliteSpecialization.DareDevil };
|
||||||
context.GuildWars2Builds.AddRange(new List<GuildWars2Build>(){healTempest, condiScourge, quickBrand, alacregate, chrono, daredevil });
|
context.GuildWars2Builds.AddRange(new List<GuildWars2Build>(){healTempest, condiScourge, quickBrand, alacregate, chrono, daredevil });
|
||||||
context.SaveChanges();
|
context.SaveChanges();
|
||||||
|
|
|
@ -5,6 +5,7 @@ using System.Text.Json;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using Lieb.Models.GuildWars2.Raid;
|
using Lieb.Models.GuildWars2.Raid;
|
||||||
using Lieb.Models;
|
using Lieb.Models;
|
||||||
|
using Lieb.Models.Poll;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
namespace Lieb.Data
|
namespace Lieb.Data
|
||||||
|
@ -421,5 +422,42 @@ namespace Lieb.Data
|
||||||
}
|
}
|
||||||
catch {}
|
catch {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task SendPoll(Poll poll, List<ulong>? userIds = null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var httpClient = _httpClientFactory.CreateClient(Constants.HttpClientName);
|
||||||
|
|
||||||
|
if(userIds == null)
|
||||||
|
{
|
||||||
|
userIds = poll.Answers.Select(a => a.UserId).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
ApiPoll apiPoll = new ApiPoll()
|
||||||
|
{
|
||||||
|
AllowCustomAnswer = poll.AllowCustomAnswer,
|
||||||
|
PollId = poll.PollId,
|
||||||
|
Question = poll.Question,
|
||||||
|
UserIds = userIds,
|
||||||
|
Options = poll.Options.ToDictionary(o => o.PollOptionId, o => o.Name)
|
||||||
|
};
|
||||||
|
|
||||||
|
var messageItemJson = new StringContent(
|
||||||
|
JsonSerializer.Serialize(apiPoll),
|
||||||
|
Encoding.UTF8,
|
||||||
|
Application.Json);
|
||||||
|
|
||||||
|
if(poll.AnswerType == AnswerType.Dropdown)
|
||||||
|
{
|
||||||
|
var httpResponseMessage = await httpClient.PostAsync("raid/SendDropdownPoll", messageItemJson);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var httpResponseMessage = await httpClient.PostAsync("raid/SendButtonPoll", messageItemJson);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -74,6 +74,7 @@ namespace Lieb.Data
|
||||||
using var context = _contextFactory.CreateDbContext();
|
using var context = _contextFactory.CreateDbContext();
|
||||||
context.Polls.Add(poll);
|
context.Polls.Add(poll);
|
||||||
await context.SaveChangesAsync();
|
await context.SaveChangesAsync();
|
||||||
|
await _discordService.SendPoll(poll);
|
||||||
return poll.PollId;
|
return poll.PollId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,11 +103,18 @@ namespace Lieb.Data
|
||||||
using var context = _contextFactory.CreateDbContext();
|
using var context = _contextFactory.CreateDbContext();
|
||||||
Poll? poll = context.Polls
|
Poll? poll = context.Polls
|
||||||
.Include(p => p.Answers)
|
.Include(p => p.Answers)
|
||||||
|
.Include(p => p.Options)
|
||||||
.FirstOrDefault(p => p.PollId == pollId && p.Answers.Where(a => a.UserId == userId).Any());
|
.FirstOrDefault(p => p.PollId == pollId && p.Answers.Where(a => a.UserId == userId).Any());
|
||||||
|
|
||||||
if (poll == null) return;
|
if (poll == null) return;
|
||||||
|
|
||||||
PollAnswer pollAnswer = poll.Answers.First(a => a.UserId == userId);
|
PollAnswer pollAnswer = poll.Answers.First(a => a.UserId == userId);
|
||||||
|
if(string.IsNullOrEmpty(answer) && pollOptionId > 0)
|
||||||
|
{
|
||||||
|
PollOption option = poll.Options.FirstOrDefault(o => o.PollOptionId == pollOptionId);
|
||||||
|
answer = option != null ? option.Name : string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
pollAnswer.Answer = answer;
|
pollAnswer.Answer = answer;
|
||||||
pollAnswer.PollOptionId = pollOptionId;
|
pollAnswer.PollOptionId = pollOptionId;
|
||||||
await context.SaveChangesAsync();
|
await context.SaveChangesAsync();
|
||||||
|
@ -126,6 +134,7 @@ namespace Lieb.Data
|
||||||
UserId = userId
|
UserId = userId
|
||||||
});
|
});
|
||||||
await context.SaveChangesAsync();
|
await context.SaveChangesAsync();
|
||||||
|
await _discordService.SendPoll(poll, new List<ulong>(){userId});
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task RemoveUser(int pollId, ulong userId)
|
public async Task RemoveUser(int pollId, ulong userId)
|
||||||
|
|
19
SharedClasses/SharedModels/ApiPoll.cs
Normal file
19
SharedClasses/SharedModels/ApiPoll.cs
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
namespace SharedClasses.SharedModels
|
||||||
|
{
|
||||||
|
public class ApiPoll
|
||||||
|
{
|
||||||
|
public int PollId { get; set; }
|
||||||
|
public string Question { get; set; } = string.Empty;
|
||||||
|
public Dictionary<int, string> Options { get; set; } = new Dictionary<int, string>();
|
||||||
|
public bool AllowCustomAnswer {get; set;} = false;
|
||||||
|
public List<ulong> UserIds {get; set;} = new List<ulong>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ApiPollAnswer
|
||||||
|
{
|
||||||
|
public int PollId { get; set; }
|
||||||
|
public int OptionId {get; set;}
|
||||||
|
public string Answer {get; set;} = string.Empty;
|
||||||
|
public ulong UserId {get; set;}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue