Added signed up options for role reminder

Added option to opt out of reminders
This commit is contained in:
Sarah Faey 2022-12-09 22:26:16 +01:00
parent 64ce169094
commit c88bf5b133
18 changed files with 911 additions and 99 deletions

View file

@ -54,6 +54,16 @@ namespace DiscordBot.CommandHandlers
await _httpService.SignOff(signOff); await _httpService.SignOff(signOff);
await component.RespondAsync("Signed Off", ephemeral: true); await component.RespondAsync("Signed Off", ephemeral: true);
break; break;
case Constants.ComponentIds.OPT_OUT_BUTTON:
if(await _httpService.ReminderOptOut(component.User.Id))
{
await component.RespondAsync("You opted out of the raid reminders.");
}
else
{
await component.RespondAsync("Opting out failed, please try again later or change the setting on the website.");
}
break;
} }
} }
} }

View file

@ -10,6 +10,7 @@
public const string BACKUP_BUTTON = "backupButton"; public const string BACKUP_BUTTON = "backupButton";
public const string FLEX_BUTTON = "flexButton"; public const string FLEX_BUTTON = "flexButton";
public const string SIGN_OFF_BUTTON = "signOffButton"; public const string SIGN_OFF_BUTTON = "signOffButton";
public const string OPT_OUT_BUTTON = "optOutButton";
public const string ROLE_SELECT_DROP_DOWN = "roleSelectDropDown"; public const string ROLE_SELECT_DROP_DOWN = "roleSelectDropDown";
public const string ROLE_SELECT_EXTERNAL_DROP_DOWN = "roleSelectExternalDropDown"; public const string ROLE_SELECT_EXTERNAL_DROP_DOWN = "roleSelectExternalDropDown";

View file

@ -95,5 +95,12 @@ namespace DiscordBot.Controllers
{ {
await DiscordBot.CommandHandlers.HandlerFunctions.RenameUser(_client, user.userId, user.Name, user.Account, user.ServerIds); await DiscordBot.CommandHandlers.HandlerFunctions.RenameUser(_client, user.userId, user.Name, user.Account, user.ServerIds);
} }
[HttpGet]
[Route("[action]/{userId}")]
public async Task SendReminderOptOutMessage(ulong userId)
{
await ReminderSubscriptionMessage.sendMessage(_client, userId);
}
} }
} }

View file

@ -0,0 +1,32 @@
using Discord;
using Discord.WebSocket;
namespace DiscordBot.Messages
{
public class ReminderSubscriptionMessage
{
public static async Task sendMessage(DiscordSocketClient client, ulong userId)
{
var builder = new ComponentBuilder()
.WithButton("Opt Out", $"{Constants.ComponentIds.OPT_OUT_BUTTON}", ButtonStyle.Danger);
string message = "Hi, I'm Raid-o-Tron. \n"
+ "I will send you reminders for raids you have signed up for.\n"
+ "The reminders will look like\n"
+ "> Testraid: The raid starts in 30 minutes. \n"
+ "You can opt out of the reminders here or change it any time at https://lieb.games \n"
+ " ------------------------------------------- \n"
+ "Hi, ich bin Raid-o-Tron. \n"
+ "Ich werde dir Erinnerungen für Raid an denen du dich angemeldet hast schicken.\n"
+ "Die Erinnerungen werden so aussehen:\n"
+ "> Testraid: The raid starts in 30 minutes. \n"
+ "Du kannst dich von den Erinnerungen hier abmelden oder deine Einstellungen jederzeit auf https://lieb.games ändern.";
var user = await client.GetUserAsync(userId);
if(user != null)
{
await user.SendMessageAsync(message, components: builder.Build());
}
}
}
}

View file

@ -242,5 +242,20 @@ namespace DiscordBot.Services
} }
return new Tuple<bool, string>(true, string.Empty); return new Tuple<bool, string>(true, string.Empty);
} }
public async Task<bool> ReminderOptOut(ulong userId)
{
var httpClient = _httpClientFactory.CreateClient(Constants.HTTP_CLIENT_NAME);
var httpResponseMessage = await httpClient.GetAsync($"DiscordBot/ReminderOptOut/{userId}");
if (httpResponseMessage.IsSuccessStatusCode)
{
using var contentStream =
await httpResponseMessage.Content.ReadAsStreamAsync();
return await JsonSerializer.DeserializeAsync<bool>(contentStream, _serializerOptions);
}
return false;
}
} }
} }

View file

@ -250,5 +250,12 @@ namespace Lieb.Controllers
} }
return Ok(); return Ok();
} }
[HttpGet]
[Route("[action]/{userId}")]
public async Task<ActionResult> ReminderOptOut(ulong userId)
{
return Ok(await _userService.ReminderOptOut(userId));
}
} }
} }

View file

@ -160,16 +160,62 @@ namespace Lieb.Data
} }
} }
public async Task<bool> SendMessageToRaidUsers(string message, Raid raid) public async Task<bool> SendMessageToRaidUsers(string message, Raid raid)
{
if(raid == null) return false;
HashSet<ulong> userIds = new HashSet<ulong>();
foreach(RaidSignUp signUp in raid.SignUps)
{
if(signUp.LiebUserId.HasValue)
{
userIds.Add(signUp.LiebUserId.Value);
}
}
return await SendMessageToUsers(message, raid.Title, userIds);
}
public async Task SendGroupReminder(RaidReminder reminder, Raid raid)
{
using var context = _contextFactory.CreateDbContext();
HashSet<ulong> groupMembers = context.LiebUsers.Where(u => u.RoleAssignments.Where(r => r.LiebRole.LiebRoleId == reminder.RoleId).Any()).Select(u => u.Id).ToHashSet();
HashSet<ulong> userIds;
switch(reminder.RoleType)
{
case RaidReminder.RoleReminderType.All:
userIds = groupMembers;
break;
case RaidReminder.RoleReminderType.SignedUp:
userIds = groupMembers.Where(m => raid.SignUps.Where(s => s.LiebUserId == m).Any()).ToHashSet();
break;
case RaidReminder.RoleReminderType.NotSignedUp:
userIds = groupMembers.Where(m => !raid.SignUps.Where(s => s.LiebUserId == m).Any()).ToHashSet();
break;
default:
userIds = new HashSet<ulong>();
break;
}
if (await SendMessageToUsers(reminder.Message, raid.Title, userIds))
{
reminder.Sent = true;
context.Update(reminder);
await context.SaveChangesAsync();
}
}
public async Task<bool> SendMessageToUsers(string message, string raidTitle, HashSet<ulong> userIds)
{ {
try try
{ {
using var context = _contextFactory.CreateDbContext();
HashSet<ulong> userIdsToSendTo = context.LiebUsers
.Where(u => u.ReminderSubscription == userIds.Contains(u.Id))
.Select(u => u.Id)
.ToHashSet();
var httpClient = _httpClientFactory.CreateClient(Constants.HttpClientName); var httpClient = _httpClientFactory.CreateClient(Constants.HttpClientName);
if(raid == null) return false; ApiUserReminder apiReminder = CreateUserReminder(message, raidTitle, userIds);
ApiUserReminder apiReminder = ConvertUserReminder(message, raid);
var raidItemJson = new StringContent( var raidItemJson = new StringContent(
JsonSerializer.Serialize(apiReminder), JsonSerializer.Serialize(apiReminder),
@ -184,21 +230,12 @@ namespace Lieb.Data
return false; return false;
} }
public static ApiUserReminder ConvertUserReminder(string message, Raid raid) public static ApiUserReminder CreateUserReminder(string message, string raidTitle, HashSet<ulong> userIds)
{ {
ApiUserReminder apiReminder = new ApiUserReminder() ApiUserReminder apiReminder = new ApiUserReminder()
{ {
Message = $"{raid.Title}: {message}" Message = $"{raidTitle}: {message}"
}; };
apiReminder.UserIds = new List<ulong>();
HashSet<ulong> userIds = new HashSet<ulong>();
foreach(RaidSignUp signUp in raid.SignUps)
{
if(signUp.LiebUserId.HasValue)
{
userIds.Add(signUp.LiebUserId.Value);
}
}
apiReminder.UserIds = userIds.ToList(); apiReminder.UserIds = userIds.ToList();
return apiReminder; return apiReminder;
} }
@ -249,51 +286,6 @@ namespace Lieb.Data
#endregion ChannelReminder #endregion ChannelReminder
#region GroupReminder
public async Task SendGroupReminder(RaidReminder reminder, string raidTitle)
{
using var context = _contextFactory.CreateDbContext();
HashSet<ulong> groupMembers = context.LiebUsers.Where(u => u.RoleAssignments.Where(r => r.LiebRole.LiebRoleId == reminder.RoleId).Any()).Select(u => u.Id).ToHashSet();
if (await SendMessageToGroup(reminder.Message, raidTitle, groupMembers))
{
reminder.Sent = true;
context.Update(reminder);
await context.SaveChangesAsync();
}
}
public async Task<bool> SendMessageToGroup(string message, string raidTitle, HashSet<ulong> userIds)
{
try
{
var httpClient = _httpClientFactory.CreateClient(Constants.HttpClientName);
ApiUserReminder apiReminder = ConvertGroupReminder(message, raidTitle, userIds);
var raidItemJson = new StringContent(
JsonSerializer.Serialize(apiReminder),
Encoding.UTF8,
Application.Json);
var httpResponseMessage = await httpClient.PostAsync("raid/SendUserReminder", raidItemJson);
return httpResponseMessage.IsSuccessStatusCode;
}
catch {}
return false;
}
public static ApiUserReminder ConvertGroupReminder(string message, string raidTitle, HashSet<ulong> groupIds)
{
ApiUserReminder apiReminder = new ApiUserReminder()
{
Message = $"{raidTitle}: {message}"
};
apiReminder.UserIds = groupIds.ToList();
return apiReminder;
}
#endregion GroupReminder
private async Task UpdateDiscordMessages(IEnumerable<ApiRaid.DiscordMessage> messages, Raid raid) private async Task UpdateDiscordMessages(IEnumerable<ApiRaid.DiscordMessage> messages, Raid raid)
{ {
foreach(ApiRaid.DiscordMessage message in messages) foreach(ApiRaid.DiscordMessage message in messages)
@ -406,5 +398,17 @@ namespace Lieb.Data
} }
catch {} catch {}
} }
public async Task SendReminderOptOutMessage(ulong userId)
{
try
{
var httpClient = _httpClientFactory.CreateClient(Constants.HttpClientName);
var httpResponseMessage = await httpClient.GetAsync($"raid/SendReminderOptOutMessage/{userId}");
httpResponseMessage.EnsureSuccessStatusCode();
}
catch {}
}
} }
} }

View file

@ -519,7 +519,7 @@ namespace Lieb.Data
await _discordService.SendChannelReminder(reminder, raid.Title); await _discordService.SendChannelReminder(reminder, raid.Title);
break; break;
case RaidReminder.ReminderType.Group: case RaidReminder.ReminderType.Group:
await _discordService.SendGroupReminder(reminder, raid.Title); await _discordService.SendGroupReminder(reminder, raid);
break; break;
} }
} }

View file

@ -95,6 +95,7 @@ namespace Lieb.Data
context.RoleAssignments.Add(roleAssignment); context.RoleAssignments.Add(roleAssignment);
await context.SaveChangesAsync(); await context.SaveChangesAsync();
} }
await _discordService.SendReminderOptOutMessage(newUser.Id);
} }
public async Task EditUser(LiebUser user) public async Task EditUser(LiebUser user)
@ -343,5 +344,17 @@ namespace Lieb.Data
} }
} }
} }
public async Task<bool> ReminderOptOut(ulong userId)
{
using var context = _contextFactory.CreateDbContext();
LiebUser? user = await context.LiebUsers
.FirstOrDefaultAsync(u => u.Id == userId);
if(user == null) return false;
user.ReminderSubscription = false;
await context.SaveChangesAsync();
return true;
}
} }
} }

View file

@ -0,0 +1,659 @@
// <auto-generated />
using System;
using Lieb.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
#nullable disable
namespace Lieb.Migrations
{
[DbContext(typeof(LiebContext))]
[Migration("20221209181937_AddRoleReminderTypeAndSubscription")]
partial class AddRoleReminderTypeAndSubscription
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder.HasAnnotation("ProductVersion", "6.0.10");
modelBuilder.Entity("Lieb.Models.DiscordSettings", b =>
{
b.Property<ulong>("DiscordSettingsId")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<bool>("ChangeUserNames")
.HasColumnType("INTEGER");
b.Property<ulong>("DiscordLogChannel")
.HasColumnType("INTEGER");
b.HasKey("DiscordSettingsId");
b.ToTable("DiscordSettings", (string)null);
});
modelBuilder.Entity("Lieb.Models.GuildWars2.Equipped", b =>
{
b.Property<int>("EquippedId")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<bool>("CanTank")
.HasColumnType("INTEGER");
b.Property<int>("GuildWars2AccountId")
.HasColumnType("INTEGER");
b.Property<int>("GuildWars2BuildId")
.HasColumnType("INTEGER");
b.HasKey("EquippedId");
b.HasIndex("GuildWars2AccountId");
b.HasIndex("GuildWars2BuildId");
b.ToTable("Equipped", (string)null);
});
modelBuilder.Entity("Lieb.Models.GuildWars2.GuildWars2Account", b =>
{
b.Property<int>("GuildWars2AccountId")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("AccountName")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("ApiKey")
.IsRequired()
.HasColumnType("TEXT");
b.Property<ulong?>("LiebUserId")
.HasColumnType("INTEGER");
b.HasKey("GuildWars2AccountId");
b.HasIndex("LiebUserId");
b.ToTable("GuildWars2Account", (string)null);
});
modelBuilder.Entity("Lieb.Models.GuildWars2.GuildWars2Build", b =>
{
b.Property<int>("GuildWars2BuildId")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<bool>("Alacrity")
.HasColumnType("INTEGER");
b.Property<string>("BuildName")
.IsRequired()
.HasMaxLength(60)
.HasColumnType("TEXT");
b.Property<int>("Class")
.HasColumnType("INTEGER");
b.Property<int>("DamageType")
.HasColumnType("INTEGER");
b.Property<int>("EliteSpecialization")
.HasColumnType("INTEGER");
b.Property<bool>("Might")
.HasColumnType("INTEGER");
b.Property<bool>("Quickness")
.HasColumnType("INTEGER");
b.Property<string>("Source")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("SourceLink")
.IsRequired()
.HasColumnType("TEXT");
b.Property<bool>("UseInRandomRaid")
.HasColumnType("INTEGER");
b.HasKey("GuildWars2BuildId");
b.ToTable("GuildWars2Build", (string)null);
});
modelBuilder.Entity("Lieb.Models.GuildWars2.Raid.DiscordRaidMessage", b =>
{
b.Property<int>("DiscordRaidMessageId")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<ulong>("DiscordChannelId")
.HasColumnType("INTEGER");
b.Property<ulong>("DiscordGuildId")
.HasColumnType("INTEGER");
b.Property<ulong>("DiscordMessageId")
.HasColumnType("INTEGER");
b.Property<int?>("RaidId")
.HasColumnType("INTEGER");
b.Property<int?>("RaidTemplateId")
.HasColumnType("INTEGER");
b.HasKey("DiscordRaidMessageId");
b.HasIndex("RaidId");
b.HasIndex("RaidTemplateId");
b.ToTable("DiscordRaidMessage", (string)null);
});
modelBuilder.Entity("Lieb.Models.GuildWars2.Raid.Raid", b =>
{
b.Property<int>("RaidId")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("Description")
.IsRequired()
.HasMaxLength(1000)
.HasColumnType("TEXT");
b.Property<DateTimeOffset>("EndTimeUTC")
.HasColumnType("TEXT");
b.Property<int>("EventType")
.HasColumnType("INTEGER");
b.Property<DateTimeOffset>("FreeForAllTimeUTC")
.HasColumnType("TEXT");
b.Property<string>("Guild")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("TEXT");
b.Property<bool>("MoveFlexUsers")
.HasColumnType("INTEGER");
b.Property<string>("Organizer")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("TEXT");
b.Property<ulong?>("RaidOwnerId")
.HasColumnType("INTEGER");
b.Property<int>("RaidType")
.HasColumnType("INTEGER");
b.Property<string>("RequiredRole")
.IsRequired()
.HasColumnType("TEXT");
b.Property<DateTimeOffset>("StartTimeUTC")
.HasColumnType("TEXT");
b.Property<string>("Title")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("TEXT");
b.Property<string>("VoiceChat")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("TEXT");
b.HasKey("RaidId");
b.ToTable("Raid", (string)null);
});
modelBuilder.Entity("Lieb.Models.GuildWars2.Raid.RaidReminder", b =>
{
b.Property<int>("RaidReminderId")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<ulong>("DiscordChannelId")
.HasColumnType("INTEGER");
b.Property<ulong>("DiscordServerId")
.HasColumnType("INTEGER");
b.Property<string>("Message")
.IsRequired()
.HasMaxLength(1000)
.HasColumnType("TEXT");
b.Property<int?>("RaidId")
.HasColumnType("INTEGER");
b.Property<int?>("RaidTemplateId")
.HasColumnType("INTEGER");
b.Property<DateTimeOffset>("ReminderTimeUTC")
.HasColumnType("TEXT");
b.Property<int>("RoleId")
.HasColumnType("INTEGER");
b.Property<int>("RoleType")
.HasColumnType("INTEGER");
b.Property<bool>("Sent")
.HasColumnType("INTEGER");
b.Property<int>("TimeType")
.HasColumnType("INTEGER");
b.Property<int>("Type")
.HasColumnType("INTEGER");
b.HasKey("RaidReminderId");
b.HasIndex("RaidId");
b.HasIndex("RaidTemplateId");
b.ToTable("RaidReminder", (string)null);
});
modelBuilder.Entity("Lieb.Models.GuildWars2.Raid.RaidRole", b =>
{
b.Property<int>("RaidRoleId")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("Description")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("TEXT");
b.Property<bool>("IsRandomSignUpRole")
.HasColumnType("INTEGER");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(40)
.HasColumnType("TEXT");
b.Property<int?>("RaidId")
.HasColumnType("INTEGER");
b.Property<int?>("RaidTemplateId")
.HasColumnType("INTEGER");
b.Property<int>("Spots")
.HasColumnType("INTEGER");
b.HasKey("RaidRoleId");
b.HasIndex("RaidId");
b.HasIndex("RaidTemplateId");
b.ToTable("RaidRole", (string)null);
});
modelBuilder.Entity("Lieb.Models.GuildWars2.Raid.RaidSignUp", b =>
{
b.Property<int>("RaidSignUpId")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("ExternalUserName")
.IsRequired()
.HasColumnType("TEXT");
b.Property<int?>("GuildWars2AccountId")
.HasColumnType("INTEGER");
b.Property<ulong?>("LiebUserId")
.HasColumnType("INTEGER");
b.Property<int>("RaidId")
.HasColumnType("INTEGER");
b.Property<int>("RaidRoleId")
.HasColumnType("INTEGER");
b.Property<int>("SignUpType")
.HasColumnType("INTEGER");
b.HasKey("RaidSignUpId");
b.HasIndex("GuildWars2AccountId");
b.HasIndex("LiebUserId");
b.HasIndex("RaidId");
b.HasIndex("RaidRoleId");
b.ToTable("RaidSignUp", (string)null);
});
modelBuilder.Entity("Lieb.Models.GuildWars2.Raid.RaidTemplate", b =>
{
b.Property<int>("RaidTemplateId")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<int>("CreateDaysBefore")
.HasColumnType("INTEGER");
b.Property<string>("Description")
.IsRequired()
.HasMaxLength(1000)
.HasColumnType("TEXT");
b.Property<DateTime>("EndTime")
.HasColumnType("TEXT");
b.Property<int>("EventType")
.HasColumnType("INTEGER");
b.Property<DateTime>("FreeForAllTime")
.HasColumnType("TEXT");
b.Property<string>("Guild")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("TEXT");
b.Property<int>("Interval")
.HasColumnType("INTEGER");
b.Property<bool>("MoveFlexUsers")
.HasColumnType("INTEGER");
b.Property<string>("Organizer")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("TEXT");
b.Property<ulong?>("RaidOwnerId")
.HasColumnType("INTEGER");
b.Property<int>("RaidType")
.HasColumnType("INTEGER");
b.Property<string>("RequiredRole")
.IsRequired()
.HasColumnType("TEXT");
b.Property<DateTime>("StartTime")
.HasColumnType("TEXT");
b.Property<string>("TimeZone")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("Title")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("TEXT");
b.Property<string>("VoiceChat")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("TEXT");
b.HasKey("RaidTemplateId");
b.ToTable("RaidTemplate", (string)null);
});
modelBuilder.Entity("Lieb.Models.LiebRole", b =>
{
b.Property<int>("LiebRoleId")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<int>("Level")
.HasColumnType("INTEGER");
b.Property<int>("LevelToAssign")
.HasColumnType("INTEGER");
b.Property<string>("RoleName")
.IsRequired()
.HasMaxLength(40)
.HasColumnType("TEXT");
b.Property<int>("Type")
.HasColumnType("INTEGER");
b.HasKey("LiebRoleId");
b.ToTable("LiebRole", (string)null);
});
modelBuilder.Entity("Lieb.Models.LiebUser", b =>
{
b.Property<ulong>("Id")
.HasColumnType("INTEGER");
b.Property<bool>("AlwaysSignUpWithMainAccount")
.HasColumnType("INTEGER");
b.Property<DateTime?>("BannedUntil")
.HasColumnType("TEXT");
b.Property<DateTime?>("Birthday")
.HasColumnType("TEXT");
b.Property<DateTime>("CreatedAt")
.HasColumnType("TEXT");
b.Property<DateTime?>("LastSignUpAt")
.HasColumnType("TEXT");
b.Property<int>("MainGW2Account")
.HasColumnType("INTEGER");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(40)
.HasColumnType("TEXT");
b.Property<string>("Pronouns")
.IsRequired()
.HasMaxLength(60)
.HasColumnType("TEXT");
b.Property<bool>("ReminderSubscription")
.HasColumnType("INTEGER");
b.HasKey("Id");
b.ToTable("LiebUser", (string)null);
});
modelBuilder.Entity("Lieb.Models.RoleAssignment", b =>
{
b.Property<int>("RoleAssignmentId")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<int>("LiebRoleId")
.HasColumnType("INTEGER");
b.Property<ulong>("LiebUserId")
.HasColumnType("INTEGER");
b.HasKey("RoleAssignmentId");
b.HasIndex("LiebRoleId");
b.HasIndex("LiebUserId");
b.ToTable("RoleAssignment", (string)null);
});
modelBuilder.Entity("Lieb.Models.GuildWars2.Equipped", b =>
{
b.HasOne("Lieb.Models.GuildWars2.GuildWars2Account", "GuildWars2Account")
.WithMany("EquippedBuilds")
.HasForeignKey("GuildWars2AccountId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Lieb.Models.GuildWars2.GuildWars2Build", "GuildWars2Build")
.WithMany("EquippedRoles")
.HasForeignKey("GuildWars2BuildId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("GuildWars2Account");
b.Navigation("GuildWars2Build");
});
modelBuilder.Entity("Lieb.Models.GuildWars2.GuildWars2Account", b =>
{
b.HasOne("Lieb.Models.LiebUser", null)
.WithMany("GuildWars2Accounts")
.HasForeignKey("LiebUserId");
});
modelBuilder.Entity("Lieb.Models.GuildWars2.Raid.DiscordRaidMessage", b =>
{
b.HasOne("Lieb.Models.GuildWars2.Raid.Raid", null)
.WithMany("DiscordRaidMessages")
.HasForeignKey("RaidId");
b.HasOne("Lieb.Models.GuildWars2.Raid.RaidTemplate", null)
.WithMany("DiscordRaidMessages")
.HasForeignKey("RaidTemplateId");
});
modelBuilder.Entity("Lieb.Models.GuildWars2.Raid.RaidReminder", b =>
{
b.HasOne("Lieb.Models.GuildWars2.Raid.Raid", null)
.WithMany("Reminders")
.HasForeignKey("RaidId");
b.HasOne("Lieb.Models.GuildWars2.Raid.RaidTemplate", null)
.WithMany("Reminders")
.HasForeignKey("RaidTemplateId");
});
modelBuilder.Entity("Lieb.Models.GuildWars2.Raid.RaidRole", b =>
{
b.HasOne("Lieb.Models.GuildWars2.Raid.Raid", null)
.WithMany("Roles")
.HasForeignKey("RaidId");
b.HasOne("Lieb.Models.GuildWars2.Raid.RaidTemplate", null)
.WithMany("Roles")
.HasForeignKey("RaidTemplateId");
});
modelBuilder.Entity("Lieb.Models.GuildWars2.Raid.RaidSignUp", b =>
{
b.HasOne("Lieb.Models.GuildWars2.GuildWars2Account", "GuildWars2Account")
.WithMany()
.HasForeignKey("GuildWars2AccountId");
b.HasOne("Lieb.Models.LiebUser", "LiebUser")
.WithMany()
.HasForeignKey("LiebUserId");
b.HasOne("Lieb.Models.GuildWars2.Raid.Raid", "Raid")
.WithMany("SignUps")
.HasForeignKey("RaidId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Lieb.Models.GuildWars2.Raid.RaidRole", "RaidRole")
.WithMany()
.HasForeignKey("RaidRoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("GuildWars2Account");
b.Navigation("LiebUser");
b.Navigation("Raid");
b.Navigation("RaidRole");
});
modelBuilder.Entity("Lieb.Models.RoleAssignment", b =>
{
b.HasOne("Lieb.Models.LiebRole", "LiebRole")
.WithMany("RoleAssignments")
.HasForeignKey("LiebRoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Lieb.Models.LiebUser", "LiebUser")
.WithMany("RoleAssignments")
.HasForeignKey("LiebUserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("LiebRole");
b.Navigation("LiebUser");
});
modelBuilder.Entity("Lieb.Models.GuildWars2.GuildWars2Account", b =>
{
b.Navigation("EquippedBuilds");
});
modelBuilder.Entity("Lieb.Models.GuildWars2.GuildWars2Build", b =>
{
b.Navigation("EquippedRoles");
});
modelBuilder.Entity("Lieb.Models.GuildWars2.Raid.Raid", b =>
{
b.Navigation("DiscordRaidMessages");
b.Navigation("Reminders");
b.Navigation("Roles");
b.Navigation("SignUps");
});
modelBuilder.Entity("Lieb.Models.GuildWars2.Raid.RaidTemplate", b =>
{
b.Navigation("DiscordRaidMessages");
b.Navigation("Reminders");
b.Navigation("Roles");
});
modelBuilder.Entity("Lieb.Models.LiebRole", b =>
{
b.Navigation("RoleAssignments");
});
modelBuilder.Entity("Lieb.Models.LiebUser", b =>
{
b.Navigation("GuildWars2Accounts");
b.Navigation("RoleAssignments");
});
#pragma warning restore 612, 618
}
}
}

View file

@ -0,0 +1,37 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Lieb.Migrations
{
public partial class AddRoleReminderTypeAndSubscription : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<int>(
name: "RoleType",
table: "RaidReminder",
type: "INTEGER",
nullable: false,
defaultValue: 0);
migrationBuilder.AddColumn<bool>(
name: "ReminderSubscription",
table: "LiebUser",
type: "INTEGER",
nullable: false,
defaultValue: false);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "RoleType",
table: "RaidReminder");
migrationBuilder.DropColumn(
name: "ReminderSubscription",
table: "LiebUser");
}
}
}

View file

@ -247,6 +247,9 @@ namespace Lieb.Migrations
b.Property<int>("RoleId") b.Property<int>("RoleId")
.HasColumnType("INTEGER"); .HasColumnType("INTEGER");
b.Property<int>("RoleType")
.HasColumnType("INTEGER");
b.Property<bool>("Sent") b.Property<bool>("Sent")
.HasColumnType("INTEGER"); .HasColumnType("INTEGER");
@ -469,6 +472,9 @@ namespace Lieb.Migrations
.HasMaxLength(60) .HasMaxLength(60)
.HasColumnType("TEXT"); .HasColumnType("TEXT");
b.Property<bool>("ReminderSubscription")
.HasColumnType("INTEGER");
b.HasKey("Id"); b.HasKey("Id");
b.ToTable("LiebUser", (string)null); b.ToTable("LiebUser", (string)null);

View file

@ -18,6 +18,13 @@ namespace Lieb.Models.GuildWars2.Raid
Dynamic = 2 Dynamic = 2
} }
public enum RoleReminderType
{
All = 0,
SignedUp = 1,
NotSignedUp = 2
}
public int RaidReminderId { get; set; } public int RaidReminderId { get; set; }
[Required] [Required]
@ -40,6 +47,8 @@ namespace Lieb.Models.GuildWars2.Raid
public ulong DiscordChannelId { get; set; } public ulong DiscordChannelId { get; set; }
public int RoleId {get; set; } public int RoleId {get; set; }
public RoleReminderType RoleType {get; set;}
public bool Sent { get; set; } = false; public bool Sent { get; set; } = false;
} }

View file

@ -22,6 +22,7 @@ namespace Lieb.Models
public DateTime? LastSignUpAt { get; set; } public DateTime? LastSignUpAt { get; set; }
public int MainGW2Account { get; set; } public int MainGW2Account { get; set; }
public bool AlwaysSignUpWithMainAccount { get; set; } = false; public bool AlwaysSignUpWithMainAccount { get; set; } = false;
public bool ReminderSubscription { get; set; } = true;
public ICollection<GuildWars2Account> GuildWars2Accounts { get; set; } = new List<GuildWars2Account>(); public ICollection<GuildWars2Account> GuildWars2Accounts { get; set; } = new List<GuildWars2Account>();
public ICollection<RoleAssignment> RoleAssignments { get; set; } = new List<RoleAssignment>(); public ICollection<RoleAssignment> RoleAssignments { get; set; } = new List<RoleAssignment>();
} }

View file

@ -14,30 +14,24 @@
<th>Hours</th> <th>Hours</th>
<th>Minutes</th> <th>Minutes</th>
<th>Type</th> <th>Type</th>
@{bool channelReminderExists = _raidReminders.Where(r => r.Type == RaidReminder.ReminderType.Channel).Any(); @if(_raidReminders.Where(r => r.Type == RaidReminder.ReminderType.Group).Any())
bool groupReminderExists = _raidReminders.Where(r => r.Type == RaidReminder.ReminderType.Group).Any();}
@if(channelReminderExists && groupReminderExists)
{ {
<th>Group</th> <th>Group</th>
<th>Server</th> <th>Signed Up</th>
<th>Channel</th>
}
else if(channelReminderExists)
{
<th></th>
<th>Server</th>
<th>Channel</th>
}
else if(groupReminderExists)
{
<th>Group</th>
<th></th>
<th></th>
} }
else else
{ {
<th></th> <th></th>
<th></th> <th></th>
}
@if(_raidReminders.Where(r => r.Type == RaidReminder.ReminderType.Channel).Any())
{
<th>Server</th>
<th>Channel</th>
}
else
{
<th></th>
<th></th> <th></th>
} }
<th>Message</th> <th>Message</th>
@ -66,6 +60,14 @@
} }
</InputSelect> </InputSelect>
</td> </td>
<td>
<InputSelect @bind-Value="reminder.RoleType" hidden="@groupHidden">
@foreach(RaidReminder.RoleReminderType type in Enum.GetValues(typeof(RaidReminder.RoleReminderType)))
{
<option value="@type">@type.ToString()</option>
}
</InputSelect>
</td>
<td> <td>
<InputSelect @bind-Value="reminder.DiscordServerId" hidden="@discordHidden"> <InputSelect @bind-Value="reminder.DiscordServerId" hidden="@discordHidden">
@foreach(DiscordServer item in _discordServers) @foreach(DiscordServer item in _discordServers)

View file

@ -13,30 +13,24 @@
<th>Date</th> <th>Date</th>
<th>Time</th> <th>Time</th>
<th>Type</th> <th>Type</th>
@{bool channelReminderExists = _raidReminders.Where(r => r.Type == RaidReminder.ReminderType.Channel).Any(); @if(_raidReminders.Where(r => r.Type == RaidReminder.ReminderType.Group).Any())
bool groupReminderExists = _raidReminders.Where(r => r.Type == RaidReminder.ReminderType.Group).Any();}
@if(channelReminderExists && groupReminderExists)
{ {
<th>Group</th> <th>Group</th>
<th>Server</th> <th>Signed Up</th>
<th>Channel</th>
}
else if(channelReminderExists)
{
<th></th>
<th>Server</th>
<th>Channel</th>
}
else if(groupReminderExists)
{
<th>Group</th>
<th></th>
<th></th>
} }
else else
{ {
<th></th> <th></th>
<th></th> <th></th>
}
@if(_raidReminders.Where(r => r.Type == RaidReminder.ReminderType.Channel).Any())
{
<th>Server</th>
<th>Channel</th>
}
else
{
<th></th>
<th></th> <th></th>
} }
<th>Message</th> <th>Message</th>
@ -73,6 +67,14 @@
} }
</InputSelect> </InputSelect>
</td> </td>
<td>
<InputSelect @bind-Value="reminder.RoleType" hidden="@groupHidden">
@foreach(RaidReminder.RoleReminderType type in Enum.GetValues(typeof(RaidReminder.RoleReminderType)))
{
<option value="@type">@type.ToString()</option>
}
</InputSelect>
</td>
<td> <td>
<InputSelect @bind-Value="reminder.DiscordServerId" hidden="@discordHidden"> <InputSelect @bind-Value="reminder.DiscordServerId" hidden="@discordHidden">
@foreach(DiscordServer item in _discordServers) @foreach(DiscordServer item in _discordServers)

View file

@ -26,6 +26,9 @@
<p> <p>
<input type="checkbox" @bind="_user.AlwaysSignUpWithMainAccount" /> Always sign up with main account <input type="checkbox" @bind="_user.AlwaysSignUpWithMainAccount" /> Always sign up with main account
</p> </p>
<p>
<input type="checkbox" @bind="_user.ReminderSubscription" /> Get Raid Reminders
</p>
@*<p> @*<p>
<label> <label>
Pronouns: Pronouns:

View file

@ -75,18 +75,22 @@ main {
} }
::deep button:disabled { ::deep button:disabled {
background-color: #777777; /*background-color: #777777;
color: darkgrey; color: darkgrey;*/
background-color: rgb(38,38,38);
color: rgb(38,38,38);
} }
::deep button[type="submit"] { ::deep button[type="submit"] {
color: lightgray; color: lightgray;
background-color: green; background-color: #355835;
border: none;
} }
::deep button[type="delete"] { ::deep button[type="delete"] {
color: lightgray; color: lightgray;
background-color: red; background-color: #6e2424;
border: none;
} }
.top-row { .top-row {