signing up through the discord bot works now

This commit is contained in:
Sarah Faey 2022-11-07 00:16:49 +01:00
parent e445b2a181
commit 69337e69ae
11 changed files with 327 additions and 42 deletions

View file

@ -2,6 +2,9 @@
using Discord.Commands;
using Discord.WebSocket;
using System.Reflection;
using DiscordBot.Services;
using SharedClasses.SharedModels;
using DiscordBot.Messages;
namespace DiscordBot
{
@ -9,18 +12,21 @@ namespace DiscordBot
{
private readonly DiscordSocketClient _client;
private readonly CommandService _commands;
private readonly HttpService _httpService;
// Retrieve client and CommandService instance via ctor
public CommandHandler(DiscordSocketClient client, CommandService commands)
public CommandHandler(DiscordSocketClient client, CommandService commands, HttpService httpService)
{
_commands = commands;
_client = client;
_httpService = httpService;
}
public async Task InstallCommandsAsync()
{
_client.SlashCommandExecuted += SlashCommandHandler;
_client.ButtonExecuted += MyButtonHandler;
_client.ButtonExecuted += ButtonHandler;
_client.SelectMenuExecuted += SelectMenuHandler;
}
private async Task SlashCommandHandler(SocketSlashCommand command)
@ -54,28 +60,95 @@ namespace DiscordBot
await command.RespondAsync(embed: embedBuiler.Build());
}
public async Task MyButtonHandler(SocketMessageComponent component)
public async Task ButtonHandler(SocketMessageComponent component)
{
string[] ids = component.Data.CustomId.Split('-');
List<ApiRole> roles = new List<ApiRole>();
int parsedRaidId = 0;
if(ids.Length > 1)
{
int.TryParse(ids[1],out parsedRaidId);
}
switch(ids[0])
{
case Constants.ComponentIds.SIGN_UP:
//await component.RespondAsync($"{component.User.Mention} has clicked the SignUp button!");
var mb = new ModalBuilder()
.WithTitle("Fav Food")
.WithCustomId("food_menu")
.AddTextInput("What??", "food_name", placeholder:"Pizza")
.AddTextInput("Why??", "food_reason", TextInputStyle.Paragraph,
"Kus it's so tasty");
//await component.RespondWithModalAsync(mb.Build());
await component.RespondAsync("hi", ephemeral: true);
case Constants.ComponentIds.SIGN_UP_BUTTON:
roles = await _httpService.GetRoles(parsedRaidId, component.User.Id);
await component.RespondAsync("Please choose a role.", components: SignUpMessage.buildMessage(roles, parsedRaidId, ids[0], false) , ephemeral: true);
break;
case Constants.ComponentIds.SIGN_OFF:
//await component.RespondAsync($"{component.User.Mention} has clicked the SignOff button!");
case Constants.ComponentIds.MAYBE_BUTTON:
case Constants.ComponentIds.BACKUP_BUTTON:
case Constants.ComponentIds.FLEX_BUTTON:
roles = await _httpService.GetRoles(parsedRaidId, component.User.Id);
await component.RespondAsync("Please choose a role.", components: SignUpMessage.buildMessage(roles, parsedRaidId, ids[0], true) , ephemeral: true);
break;
case Constants.ComponentIds.SIGN_OFF_BUTTON:
ApiSignUp signOff = new ApiSignUp()
{
raidId = parsedRaidId,
userId = component.User.Id
};
await _httpService.SignOff(signOff);
await Respond(component);
break;
}
}
public async Task SelectMenuHandler(SocketMessageComponent component)
{
string[] ids = component.Data.CustomId.Split('-');
List<ApiRole> roles = new List<ApiRole>();
int parsedRaidId = 0;
if(ids.Length > 1)
{
int.TryParse(ids[1],out parsedRaidId);
}
switch(ids[0])
{
case Constants.ComponentIds.SIGN_UP_DROP_DOWN:
await ManageSignUp(ids[2], parsedRaidId, component);
await Respond(component);
break;
}
}
private async Task ManageSignUp(string buttonType, int raidId, SocketMessageComponent component)
{
if(! int.TryParse(component.Data.Values.First(), out int parsedRoleId)) return;
ApiSignUp signUp = new ApiSignUp()
{
raidId = raidId,
userId = component.User.Id,
roleId = parsedRoleId
};
switch(buttonType)
{
case Constants.ComponentIds.SIGN_UP_BUTTON:
await _httpService.SignUp(signUp);
break;
case Constants.ComponentIds.MAYBE_BUTTON:
await _httpService.SignUpMaybe(signUp);
break;
case Constants.ComponentIds.BACKUP_BUTTON:
await _httpService.SignUpBackup(signUp);
break;
case Constants.ComponentIds.FLEX_BUTTON:
await _httpService.SignUpFlex(signUp);
break;
}
}
//to avoid error messages because of no response...
private async Task Respond(SocketMessageComponent component)
{
try
{
await component.RespondAsync();
}
catch(Discord.Net.HttpException e)
{
}
}
}

View file

@ -2,10 +2,16 @@
{
public class Constants
{
public const string HTTP_CLIENT_NAME = "LiebWebsite";
public class ComponentIds
{
public const string SIGN_UP = "su";
public const string SIGN_OFF = "so";
{
public const string SIGN_UP_BUTTON = "signUpButton";
public const string MAYBE_BUTTON = "maybeButton";
public const string BACKUP_BUTTON = "backupButton";
public const string FLEX_BUTTON = "flexButton";
public const string SIGN_OFF_BUTTON = "signOffButton";
public const string SIGN_UP_DROP_DOWN = "signUpDropDown";
}
public class SlashCommands

View file

@ -33,18 +33,12 @@ namespace DiscordBot.Messages
public async Task<ApiRaid> PostRaidMessage(ApiRaid raid)
{
var menuBuilder = new SelectMenuBuilder()
.WithPlaceholder("Select an option")
.WithCustomId("menu-1")
.WithMinValues(1)
.WithMaxValues(1)
.AddOption("Option A", "opt-a", "Option B is lying!")
.AddOption("Option B", "opt-b", "Option A is telling the truth!");
var builder = new ComponentBuilder()
.WithButton("SignUp", $"{Constants.ComponentIds.SIGN_UP}-{raid.RaidId.ToString()}", ButtonStyle.Secondary)
.WithButton("SignOff", $"{Constants.ComponentIds.SIGN_OFF}-{raid.RaidId.ToString()}", ButtonStyle.Secondary);
//.WithSelectMenu(menuBuilder);
.WithButton("SignUp", $"{Constants.ComponentIds.SIGN_UP_BUTTON}-{raid.RaidId.ToString()}", ButtonStyle.Success)
.WithButton("Maybe", $"{Constants.ComponentIds.MAYBE_BUTTON}-{raid.RaidId.ToString()}", ButtonStyle.Secondary)
.WithButton("Backup", $"{Constants.ComponentIds.BACKUP_BUTTON}-{raid.RaidId.ToString()}", ButtonStyle.Secondary)
.WithButton("Flex", $"{Constants.ComponentIds.FLEX_BUTTON}-{raid.RaidId.ToString()}", ButtonStyle.Secondary)
.WithButton("SignOff", $"{Constants.ComponentIds.SIGN_OFF_BUTTON}-{raid.RaidId.ToString()}", ButtonStyle.Danger);
MessageComponent components = builder.Build();
Embed raidMessage = CreateRaidMessage(raid);
@ -62,7 +56,8 @@ namespace DiscordBot.Messages
Embed = raidMessage,
Components = components
};
await messageChannel.ModifyMessageAsync(message.MessageId, new Action<MessageProperties>(x => x = properties));
IUserMessage discordMessage = (IUserMessage)await messageChannel.GetMessageAsync(message.MessageId);
await discordMessage.ModifyAsync(msg => msg.Embed = raidMessage);
}
else
{
@ -105,7 +100,7 @@ namespace DiscordBot.Messages
Dictionary<string, string> fieldList = new Dictionary<string, string>();
embed.AddField("Signed up", $"({raid.Roles.Sum(r => r.Users.Count)}/{raid.Roles.Sum(r => r.Spots)}):");
foreach (ApiRaid.Role role in raid.Roles)
foreach (ApiRaid.Role role in raid.Roles.OrderBy(x => x.RoleId))
{
//print signed up users
string signedUpUsers = PrintUsers(role);

View file

@ -0,0 +1,68 @@
using Discord;
using Discord.WebSocket;
using System;
using System.ComponentModel.DataAnnotations;
using SharedClasses.SharedModels;
namespace DiscordBot.Messages
{
public class SignUpMessage
{
public static MessageComponent buildMessage(List<ApiRole> roles, int raidId, string buttonType, bool allRoles)
{
var signUpSelect = new SelectMenuBuilder()
.WithPlaceholder("Select an option")
.WithCustomId($"{Constants.ComponentIds.SIGN_UP_DROP_DOWN}-{raidId}-{buttonType}")
.WithMinValues(1)
.WithMaxValues(1);
foreach(ApiRole role in roles)
{
if(allRoles || role.IsSignUpAllowed)
signUpSelect.AddOption(role.Name, role.roleId.ToString(), role.Description);
}
var builder = new ComponentBuilder()
.WithSelectMenu(signUpSelect, 0);
return builder.Build();
}
/*
public static MessageComponent buildMessage(List<ApiRole> roles, int raidId)
{
var signUpSelect = new SelectMenuBuilder()
.WithPlaceholder("Select an option")
.WithCustomId(Constants.ComponentIds.SIGN_UP_DROP_DOWN)
.WithMinValues(1)
.WithMaxValues(1);
foreach(ApiRole role in roles)
{
if(role.IsSignUpAllowed)
signUpSelect.AddOption(role.Name, role.roleId.ToString(), role.Description);
}
var flexSelect = new SelectMenuBuilder()
.WithPlaceholder("Select an option")
.WithCustomId(Constants.ComponentIds.FLEX_DROP_DOWN)
.WithMinValues(1)
.WithMaxValues(1);
foreach(ApiRole role in roles)
{
flexSelect.AddOption(role.Name, role.roleId.ToString(), role.Description);
}
var builder = new ComponentBuilder()
.WithSelectMenu(signUpSelect, 0)
.WithButton("SignUp", $"{Constants.ComponentIds.SIGN_UP_BUTTON}-{raidId.ToString()}", ButtonStyle.Success, row: 1)
.WithSelectMenu(flexSelect, 2)
.WithButton("Maybe", $"{Constants.ComponentIds.MAYBE_BUTTON}-{raidId.ToString()}", ButtonStyle.Success, row: 3)
.WithButton("Backup", $"{Constants.ComponentIds.BACKUP_BUTTON}-{raidId.ToString()}", ButtonStyle.Success, row: 3)
.WithButton("Flex", $"{Constants.ComponentIds.FLEX_BUTTON}-{raidId.ToString()}", ButtonStyle.Success, row: 3);
return builder.Build();
}*/
}
}

View file

@ -2,9 +2,11 @@ using Discord;
using Discord.Commands;
using Discord.Net;
using Discord.WebSocket;
using Microsoft.Net.Http.Headers;
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json;
using System.Reflection;
using DiscordBot.Services;
namespace DiscordBot
{
@ -28,6 +30,7 @@ namespace DiscordBot
builder.Services.AddSingleton<DiscordSocketClient>();
builder.Services.AddSingleton<CommandService>();
builder.Services.AddSingleton<CommandHandler>();
builder.Services.AddSingleton<HttpService>();
builder.Services.AddControllers();
@ -35,6 +38,24 @@ namespace DiscordBot
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddHttpClient(Constants.HTTP_CLIENT_NAME , httpClient =>
{
httpClient.BaseAddress = new Uri("https://localhost:7216/");
httpClient.DefaultRequestHeaders.Add(
HeaderNames.Accept, "application/vnd.github.v3+json");
httpClient.DefaultRequestHeaders.Add(
HeaderNames.UserAgent, "HttpRequestsSample");
}).ConfigurePrimaryHttpMessageHandler(() => {
var handler = new HttpClientHandler();
if (builder.Environment.IsDevelopment())
{
handler.ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => { return true; };
}
return handler;
});
var app = builder.Build();
// Configure the HTTP request pipeline.

View file

@ -0,0 +1,77 @@
using SharedClasses.SharedModels;
using System.Net.Http;
using static System.Net.Mime.MediaTypeNames;
using System.Text.Json;
using System.Text;
namespace DiscordBot.Services
{
public class HttpService
{
private readonly IHttpClientFactory _httpClientFactory;
private readonly JsonSerializerOptions _serializerOptions;
public HttpService(IHttpClientFactory httpClientFactory)
{
_httpClientFactory = httpClientFactory;
_serializerOptions = new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true
};
}
public async Task<List<ApiRole>> GetRoles(int raidId, ulong userId)
{
var httpClient = _httpClientFactory.CreateClient(Constants.HTTP_CLIENT_NAME);
var httpResponseMessage = await httpClient.GetAsync($"DiscordBot/GetRoles/{raidId}/{userId}");
if (httpResponseMessage.IsSuccessStatusCode)
{
using var contentStream =
await httpResponseMessage.Content.ReadAsStreamAsync();
return await JsonSerializer.DeserializeAsync<List<ApiRole>>(contentStream, _serializerOptions);
}
return new List<ApiRole>();
}
public async Task SignUp(ApiSignUp signUp)
{
await SendSignUp(signUp, "DiscordBot/SignUp");
}
public async Task SignUpMaybe(ApiSignUp signUp)
{
await SendSignUp(signUp, "DiscordBot/SignUpMaybe");
}
public async Task SignUpBackup(ApiSignUp signUp)
{
await SendSignUp(signUp, "DiscordBot/SignUpBackup");
}
public async Task SignUpFlex(ApiSignUp signUp)
{
await SendSignUp(signUp, "DiscordBot/SignUpFlex");
}
public async Task SignOff(ApiSignUp signUp)
{
await SendSignUp(signUp, "DiscordBot/SignOff");
}
private async Task SendSignUp(ApiSignUp signUp, string requestUri)
{
var httpClient = _httpClientFactory.CreateClient(Constants.HTTP_CLIENT_NAME);
var raidItemJson = new StringContent(
JsonSerializer.Serialize(signUp),
Encoding.UTF8,
Application.Json);
var httpResponseMessage = await httpClient.PostAsync(requestUri, raidItemJson);
}
}
}

View file

@ -4,6 +4,7 @@ using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Mvc;
using Lieb.Data;
using Lieb.Models.GuildWars2.Raid;
using Lieb.Models.GuildWars2;
using SharedClasses.SharedModels;
namespace Lieb.Controllers
@ -13,20 +14,22 @@ namespace Lieb.Controllers
public class DiscordBotController : ControllerBase
{
RaidService _raidService;
UserService _userService;
public DiscordBotController(RaidService raidService)
public DiscordBotController(RaidService raidService, UserService userService)
{
_raidService = raidService;
_userService = userService;
}
[HttpGet]
[Route("[action]/{raidId}/{userId}")]
public List<ApiRole> GetRoles(int raidId, ulong userId)
public ActionResult<List<ApiRole>> GetRoles(int raidId, ulong userId)
{
Raid raid = _raidService.GetRaid(raidId);
if(!_raidService.IsRaidSignUpAllowed(userId, raidId, out string errorMessage))
{
//TODO: send error message
return Problem(errorMessage);
}
List<ApiRole> apiRoles = new List<ApiRole>();
@ -35,7 +38,8 @@ namespace Lieb.Controllers
apiRoles.Add(new ApiRole(){
Name = role.Name,
Description = role.Description,
IsSignUpAllowed = _raidService.IsRoleSignUpAllowed(userId, role.RaidRoleId, SignUpType.SignedUp)
IsSignUpAllowed = _raidService.IsRoleSignUpAllowed(userId, role.RaidRoleId, SignUpType.SignedUp),
roleId = role.RaidRoleId
});
}
return apiRoles;
@ -45,7 +49,40 @@ namespace Lieb.Controllers
[Route("[action]")]
public async Task SignUp(ApiSignUp signUp)
{
_raidService.SignUp(signUp.raidId, signUp.userId, signUp.gw2AccountId, signUp.roleId, )
int accountId = _userService.GetLiebUserGW2AccountOnly(signUp.userId).GuildWars2Accounts.FirstOrDefault(new GuildWars2Account()).GuildWars2AccountId;
await _raidService.SignUp(signUp.raidId, signUp.userId, accountId, signUp.roleId, SignUpType.SignedUp);
}
[HttpPost]
[Route("[action]")]
public async Task SignUpMaybe(ApiSignUp signUp)
{
int accountId = _userService.GetLiebUserGW2AccountOnly(signUp.userId).GuildWars2Accounts.FirstOrDefault(new GuildWars2Account()).GuildWars2AccountId;
await _raidService.SignUp(signUp.raidId, signUp.userId, signUp.gw2AccountId, signUp.roleId, SignUpType.Maybe);
}
[HttpPost]
[Route("[action]")]
public async Task SignUpBackup(ApiSignUp signUp)
{
int accountId = _userService.GetLiebUserGW2AccountOnly(signUp.userId).GuildWars2Accounts.FirstOrDefault(new GuildWars2Account()).GuildWars2AccountId;
await _raidService.SignUp(signUp.raidId, signUp.userId, signUp.gw2AccountId, signUp.roleId, SignUpType.Backup);
}
[HttpPost]
[Route("[action]")]
public async Task SignUpFlex(ApiSignUp signUp)
{
int accountId = _userService.GetLiebUserGW2AccountOnly(signUp.userId).GuildWars2Accounts.FirstOrDefault(new GuildWars2Account()).GuildWars2AccountId;
await _raidService.SignUp(signUp.raidId, signUp.userId, signUp.gw2AccountId, signUp.roleId, SignUpType.Flex);
}
[HttpPost]
[Route("[action]")]
public async Task SignOff(ApiSignUp signUp)
{
int accountId = _userService.GetLiebUserGW2AccountOnly(signUp.userId).GuildWars2Accounts.FirstOrDefault(new GuildWars2Account()).GuildWars2AccountId;
await _raidService.SignOff(signUp.raidId, signUp.userId);
}
}
}

View file

@ -43,7 +43,7 @@ namespace Lieb.Data
//new LiebUser{Id=0, Name="Sarah", Birthday=DateTime.Parse("1992-01-15"), GuildWars2Accounts = new List<GuildWars2Account>(){ linaith, sarah} },
new LiebUser{Id=194863625477816321, Name="Sarah", Birthday=DateTime.Parse("1992-01-15"), GuildWars2Accounts = new List<GuildWars2Account>(){ linaith, sarah} },
#if DEBUG
new LiebUser{Id=1, Name="Lisa", GuildWars2Accounts = new List<GuildWars2Account>(){ hierpiepts}},
new LiebUser{Id=194455125769715713, Name="Lisa", GuildWars2Accounts = new List<GuildWars2Account>(){ hierpiepts}},
new LiebUser{Id=2, Name="Simon", GuildWars2Accounts = new List<GuildWars2Account>(){ bloodseeker}}
#endif
};

View file

@ -171,7 +171,10 @@ namespace Lieb.Data
}
using var context = _contextFactory.CreateDbContext();
context.Update(raid.DiscordRaidMessages);
foreach(DiscordRaidMessage message in raid.DiscordRaidMessages)
{
context.Update(message);
}
await context.SaveChangesAsync();
}
@ -192,6 +195,7 @@ namespace Lieb.Data
foreach(RaidRole role in raid.Roles)
{
ApiRaid.Role apiRole = new ApiRaid.Role(){
RoleId = role.RaidRoleId,
Description = role.Description,
Name = role.Name,
Spots = role.Spots

View file

@ -36,6 +36,8 @@ namespace SharedClasses.SharedModels
public class Role
{
public int RoleId { get; set; }
public string Name { get; set; } = string.Empty;
public string Description { get; set; } = string.Empty;

View file

@ -7,6 +7,8 @@ namespace SharedClasses.SharedModels
public string Description { get; set; } = String.Empty;
public bool IsSignUpAllowed{ get; set; } = false;
public bool IsSignUpAllowed { get; set; } = false;
public int roleId {get; set;}
}
}