Added Polls and locking raids if not enough users are signed up
needs testing
This commit is contained in:
parent
32af72a262
commit
ccb276a265
14 changed files with 289 additions and 8 deletions
|
@ -8,6 +8,12 @@
|
|||
public static readonly int RaidEditPowerLevel = Roles.Moderator.PowerLevel;
|
||||
public const int REMOVE_MAYBE_MINUTES = 15;
|
||||
|
||||
public static class Polls
|
||||
{
|
||||
public const string YES = "yes";
|
||||
public const string NO = "no";
|
||||
}
|
||||
|
||||
public static class Roles
|
||||
{
|
||||
public static readonly RoleConstant User = new RoleConstant("user", 20);
|
||||
|
|
|
@ -306,8 +306,15 @@ namespace Lieb.Data
|
|||
|
||||
public static ApiRaid ConvertRaid(Raid raid)
|
||||
{
|
||||
string title = raid.Title;
|
||||
if (raid.SignUps.Count < raid.MinUsers
|
||||
&& raid.MinUserDeadLineUTC.UtcDateTime > DateTimeOffset.UtcNow)
|
||||
{
|
||||
title = $"The raid was canceled because of not enough sign ups.\n\n{raid.Title}";
|
||||
}
|
||||
|
||||
ApiRaid apiRaid = new ApiRaid(){
|
||||
Title = raid.Title,
|
||||
Title = title,
|
||||
Description = raid.Description,
|
||||
Guild = raid.Guild,
|
||||
Organizer = raid.Organizer,
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
using Lieb.Models;
|
||||
using Lieb.Models.GuildWars2;
|
||||
using Lieb.Models.GuildWars2.Raid;
|
||||
using Lieb.Models.Poll;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Lieb.Data
|
||||
|
@ -26,6 +27,9 @@ namespace Lieb.Data
|
|||
public DbSet<RaidSignUp> RaidSignUps { get; set; }
|
||||
public DbSet<DiscordRaidMessage> DiscordRaidMessages { get; set; }
|
||||
public DbSet<DiscordSettings> DiscordSettings { get; set; }
|
||||
public DbSet<Poll> Polls { get; set; }
|
||||
public DbSet<PollOption> PollOptions { get; set; }
|
||||
public DbSet<PollAnswer> PollAnswers { get; set; }
|
||||
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||
|
@ -43,6 +47,9 @@ namespace Lieb.Data
|
|||
modelBuilder.Entity<RaidSignUp>().ToTable("RaidSignUp");
|
||||
modelBuilder.Entity<DiscordRaidMessage>().ToTable("DiscordRaidMessage");
|
||||
modelBuilder.Entity<DiscordSettings>().ToTable("DiscordSettings");
|
||||
modelBuilder.Entity<Poll>().ToTable("Poll");
|
||||
modelBuilder.Entity<PollOption>().ToTable("PollOption");
|
||||
modelBuilder.Entity<PollAnswer>().ToTable("PollAnswer");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
113
Lieb/Data/PollService.cs
Normal file
113
Lieb/Data/PollService.cs
Normal file
|
@ -0,0 +1,113 @@
|
|||
using Lieb.Models.GuildWars2.Raid;
|
||||
using Lieb.Models.Poll;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Internal;
|
||||
|
||||
namespace Lieb.Data
|
||||
{
|
||||
public class PollService
|
||||
{
|
||||
private readonly IDbContextFactory<LiebContext> _contextFactory;
|
||||
private readonly DiscordService _discordService;
|
||||
public PollService(IDbContextFactory<LiebContext> contextFactory, DiscordService discordService)
|
||||
{
|
||||
_contextFactory = contextFactory;
|
||||
_discordService = discordService;
|
||||
}
|
||||
|
||||
public Poll GetPoll(int pollId)
|
||||
{
|
||||
using var context = _contextFactory.CreateDbContext();
|
||||
Poll? poll = context.Polls
|
||||
.Include(p => p.Options)
|
||||
.Include(p => p.Answers)
|
||||
.FirstOrDefault(p => p.PollId == pollId);
|
||||
|
||||
if (poll != null) return poll;
|
||||
|
||||
return new Poll();
|
||||
}
|
||||
|
||||
public List<Poll> GetPollsByRaidId(int raidId)
|
||||
{
|
||||
using var context = _contextFactory.CreateDbContext();
|
||||
return context.Polls
|
||||
.Include(p => p.Options)
|
||||
.Include(p => p.Answers)
|
||||
.Where(p => p.RaidId == raidId).ToList();
|
||||
}
|
||||
|
||||
public async Task<int> CreatePoll(string question, List<string> options, int raidId)
|
||||
{
|
||||
using var context = _contextFactory.CreateDbContext();
|
||||
Raid? raid = context.Raids
|
||||
.Include(r => r.SignUps)
|
||||
.FirstOrDefault(r => r.RaidId == raidId);
|
||||
|
||||
if (raid == null) return 0;
|
||||
List<ulong> users = raid.SignUps.Where(s => s.LiebUserId != null).Select(s => (ulong)s.LiebUserId).ToList();
|
||||
return await CreatePoll(question, options, users, raidId);
|
||||
}
|
||||
|
||||
public async Task<int> CreatePoll(string question, List<string> options, List<ulong> users, int? raidId = null)
|
||||
{
|
||||
Poll poll = new Poll()
|
||||
{
|
||||
Question = question,
|
||||
RaidId = raidId
|
||||
};
|
||||
foreach(string option in options)
|
||||
{
|
||||
poll.Options.Add(new PollOption()
|
||||
{
|
||||
Name = option
|
||||
});
|
||||
}
|
||||
foreach(ulong user in users)
|
||||
{
|
||||
poll.Answers.Add(new PollAnswer()
|
||||
{
|
||||
UserId = user
|
||||
});
|
||||
}
|
||||
|
||||
using var context = _contextFactory.CreateDbContext();
|
||||
context.Polls.Add(poll);
|
||||
await context.SaveChangesAsync();
|
||||
return poll.PollId;
|
||||
}
|
||||
|
||||
public async Task DeletePoll(int pollId)
|
||||
{
|
||||
using var context = _contextFactory.CreateDbContext();
|
||||
Poll? poll = context.Polls
|
||||
.Include(p => p.Options)
|
||||
.Include(p => p.Answers)
|
||||
.FirstOrDefault(p => p.PollId == pollId);
|
||||
|
||||
if(poll == null) return;
|
||||
|
||||
context.PollOptions.RemoveRange(poll.Options);
|
||||
context.PollAnswers.RemoveRange(poll.Answers);
|
||||
await context.SaveChangesAsync();
|
||||
|
||||
poll.Options.Clear();
|
||||
poll.Answers.Clear();
|
||||
context.Polls.Remove(poll);
|
||||
await context.SaveChangesAsync();
|
||||
}
|
||||
|
||||
public async Task UpdateAnswer(int pollId, int pollOptionId, ulong userId)
|
||||
{
|
||||
using var context = _contextFactory.CreateDbContext();
|
||||
Poll? poll = context.Polls
|
||||
.Include(p => p.Answers)
|
||||
.FirstOrDefault(p => p.PollId == pollId && p.Answers.Where(a => a.UserId == userId).Any());
|
||||
|
||||
if (poll == null) return;
|
||||
|
||||
PollAnswer answer = poll.Answers.First(a => a.UserId == userId);
|
||||
answer.PollOptionId = pollOptionId;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
using Lieb.Models;
|
||||
using Lieb.Models.GuildWars2;
|
||||
using Lieb.Models.GuildWars2.Raid;
|
||||
using Lieb.Models.Poll;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Lieb.Data
|
||||
|
@ -9,11 +10,13 @@ namespace Lieb.Data
|
|||
{
|
||||
private readonly IDbContextFactory<LiebContext> _contextFactory;
|
||||
private readonly DiscordService _discordService;
|
||||
private readonly PollService _pollService;
|
||||
|
||||
public RaidService(IDbContextFactory<LiebContext> contextFactory, DiscordService discordService)
|
||||
public RaidService(IDbContextFactory<LiebContext> contextFactory, DiscordService discordService, PollService pollService)
|
||||
{
|
||||
_contextFactory = contextFactory;
|
||||
_discordService = discordService;
|
||||
_pollService = pollService;
|
||||
}
|
||||
|
||||
public List<Raid> GetRaids()
|
||||
|
@ -444,6 +447,7 @@ namespace Lieb.Data
|
|||
errorMessage = string.Empty;
|
||||
using var context = _contextFactory.CreateDbContext();
|
||||
Raid? raid = context.Raids
|
||||
.Include(r => r.SignUps)
|
||||
.AsNoTracking()
|
||||
.FirstOrDefault(r => r.RaidId == raidId);
|
||||
if(raid == null)
|
||||
|
@ -451,6 +455,14 @@ namespace Lieb.Data
|
|||
errorMessage = "Raid not found.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (raid.SignUps.Count < raid.MinUsers
|
||||
&& raid.MinUserDeadLineUTC.UtcDateTime > DateTimeOffset.UtcNow)
|
||||
{
|
||||
errorMessage = $"The raid was canceled because of not enough sign ups.";
|
||||
return false;
|
||||
}
|
||||
|
||||
LiebUser? user = context.LiebUsers
|
||||
.Include(u => u.RoleAssignments)
|
||||
.ThenInclude(a => a.LiebRole)
|
||||
|
@ -670,5 +682,49 @@ namespace Lieb.Data
|
|||
await context.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task CheckMinUsers()
|
||||
{
|
||||
using var context = _contextFactory.CreateDbContext();
|
||||
List<Raid> raids = context.Raids
|
||||
.Include(r => r.SignUps)
|
||||
.Where(r => r.SignUps.Count < r.MinUsers && r.MinUserPollId == null).ToList();
|
||||
foreach (Raid raid in raids.Where(r => r.MinUserDeadLineUTC < DateTimeOffset.UtcNow && r.StartTimeUTC > DateTimeOffset.UtcNow))
|
||||
{
|
||||
raid.MinUserPollId = await _pollService.CreatePoll(
|
||||
"The raid has not the required users, do you want to raid anyway?",
|
||||
new List<string>() {Constants.Polls.YES, Constants.Polls.NO }, raid.RaidId);
|
||||
await context.SaveChangesAsync();
|
||||
await _discordService.PostRaidMessage(raid.RaidId);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task CheckMinUserPollResult()
|
||||
{
|
||||
using var context = _contextFactory.CreateDbContext();
|
||||
List<Raid> raids = context.Raids
|
||||
.Include(r => r.SignUps)
|
||||
.Where(r => r.SignUps.Count < r.MinUsers && r.MinUserPollId != null).ToList();
|
||||
foreach (Raid raid in raids.Where(r => r.MinUserDeadLineUTC < DateTimeOffset.UtcNow && r.StartTimeUTC > DateTimeOffset.UtcNow))
|
||||
{
|
||||
Poll poll = _pollService.GetPoll(raid.MinUserPollId.Value);
|
||||
|
||||
if (poll.Answers.Count == 0) continue;
|
||||
if (poll.Answers.Where(a => a.PollOptionId == null).Any()) continue;
|
||||
|
||||
int noOptionId = poll.Options.First(o => o.Name == Constants.Polls.NO).PollOptionId;
|
||||
if(poll.Answers.Where(a => a.PollOptionId == noOptionId).Any())
|
||||
{
|
||||
await _discordService.SendMessageToRaidUsers("The raid is canceled.", raid);
|
||||
}
|
||||
else
|
||||
{
|
||||
raid.MinUsers = 0;
|
||||
await context.SaveChangesAsync();
|
||||
await _discordService.SendMessageToRaidUsers("The raid will take place. Signing up is allowed again.", raid);
|
||||
await _discordService.PostRaidMessage(raid.RaidId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -49,6 +49,8 @@ namespace Lieb.Data
|
|||
.GetRequiredService<RaidService>();
|
||||
await raidService.SendReminders();
|
||||
await raidService.RemoveMaybes();
|
||||
await raidService.CheckMinUsers();
|
||||
await raidService.CheckMinUserPollResult();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -14,6 +14,10 @@ namespace Lieb.Models.GuildWars2.Raid
|
|||
|
||||
public DateTimeOffset FreeForAllTimeUTC { get; set; }
|
||||
|
||||
public DateTimeOffset MinUserDeadLineUTC { get; set; }
|
||||
|
||||
public int? MinUserPollId { get; set; }
|
||||
|
||||
public ICollection<RaidSignUp> SignUps { get; set; } = new HashSet<RaidSignUp>();
|
||||
|
||||
public Raid() { }
|
||||
|
@ -24,6 +28,7 @@ namespace Lieb.Models.GuildWars2.Raid
|
|||
StartTimeUTC = TimeZoneInfo.ConvertTimeToUtc(template.StartTime, timeZone);
|
||||
EndTimeUTC = TimeZoneInfo.ConvertTimeToUtc(template.EndTime, timeZone);
|
||||
FreeForAllTimeUTC = TimeZoneInfo.ConvertTimeToUtc(template.FreeForAllTime, timeZone);
|
||||
MinUserDeadLineUTC = TimeZoneInfo.ConvertTimeToUtc(template.MinUserDeadLine, timeZone);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -52,7 +52,8 @@ namespace Lieb.Models.GuildWars2.Raid
|
|||
|
||||
public ulong? RaidOwnerId { get; set; }
|
||||
|
||||
//role name, number of spots
|
||||
public int MinUsers { get; set; } = 0;
|
||||
|
||||
public ICollection<RaidRole> Roles { get; set; } = new HashSet<RaidRole>();
|
||||
|
||||
public ICollection<RaidReminder> Reminders { get; set; } = new List<RaidReminder>();
|
||||
|
@ -73,6 +74,7 @@ namespace Lieb.Models.GuildWars2.Raid
|
|||
this.MoveFlexUsers = template.MoveFlexUsers;
|
||||
this.RaidOwnerId = template.RaidOwnerId;
|
||||
this.EventType = template.EventType;
|
||||
this.MinUsers = template.MinUsers;
|
||||
|
||||
foreach (RaidRole role in template.Roles)
|
||||
{
|
||||
|
|
|
@ -14,6 +14,8 @@ namespace Lieb.Models.GuildWars2.Raid
|
|||
|
||||
public DateTime FreeForAllTime { get; set; }
|
||||
|
||||
public DateTime MinUserDeadLine { get; set; }
|
||||
|
||||
public string TimeZone { get; set; } = String.Empty;
|
||||
|
||||
public int Interval { get; set; }
|
||||
|
|
12
Lieb/Models/Poll/Poll.cs
Normal file
12
Lieb/Models/Poll/Poll.cs
Normal file
|
@ -0,0 +1,12 @@
|
|||
namespace Lieb.Models.Poll
|
||||
{
|
||||
public class Poll
|
||||
{
|
||||
public int PollId { get; set; }
|
||||
public string Question { get; set; }
|
||||
public ICollection<PollOption> Options { get; set; } = new List<PollOption>();
|
||||
public ICollection<PollAnswer> Answers { get; set; } = new List<PollAnswer>();
|
||||
public int? RaidId { get; set; }
|
||||
|
||||
}
|
||||
}
|
11
Lieb/Models/Poll/PollAnswer.cs
Normal file
11
Lieb/Models/Poll/PollAnswer.cs
Normal file
|
@ -0,0 +1,11 @@
|
|||
namespace Lieb.Models.Poll
|
||||
{
|
||||
public class PollAnswer
|
||||
{
|
||||
public int PollAnswerId { get; set; }
|
||||
|
||||
public int? PollOptionId { get; set; }
|
||||
|
||||
public ulong UserId { get; set; }
|
||||
}
|
||||
}
|
8
Lieb/Models/Poll/PollOption.cs
Normal file
8
Lieb/Models/Poll/PollOption.cs
Normal file
|
@ -0,0 +1,8 @@
|
|||
namespace Lieb.Models.Poll
|
||||
{
|
||||
public class PollOption
|
||||
{
|
||||
public int PollOptionId { get; set; }
|
||||
public string Name { get; set;}
|
||||
}
|
||||
}
|
|
@ -115,6 +115,26 @@
|
|||
</label>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<label>
|
||||
Minimal required users:
|
||||
<InputNumber @bind-Value="_raid.MinUsers" />
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label>
|
||||
Minimal user deadline date:
|
||||
<InputDate @bind-Value="_minUserDeadlineDate" />
|
||||
</label>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<label>
|
||||
Minimal user deadline time:
|
||||
<input type="time" @bind="_minUserDeadlineTime" />
|
||||
</label>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<label>
|
||||
Organizer:
|
||||
|
@ -194,6 +214,8 @@
|
|||
private DateTimeOffset _endTime;
|
||||
private DateTimeOffset _freeForAllDate = DateTime.Now.Date;
|
||||
private DateTimeOffset _freeForAllTime;
|
||||
private DateTimeOffset _minUserDeadlineDate = DateTime.Now.Date;
|
||||
private DateTimeOffset _minUserDeadlineTime;
|
||||
|
||||
private List<RaidRole> _rolesToDelete = new List<RaidRole>();
|
||||
private List<RaidReminder> _remindersToDelete = new List<RaidReminder>();
|
||||
|
@ -240,6 +262,8 @@
|
|||
_raidDate = _startTime.Date;
|
||||
_freeForAllTime = await TimeZoneService.GetLocalDateTime(_raid.FreeForAllTimeUTC);
|
||||
_freeForAllDate = _freeForAllTime.Date;
|
||||
_minUserDeadlineTime = await TimeZoneService.GetLocalDateTime(_raid.MinUserDeadLineUTC);
|
||||
_minUserDeadlineDate = _minUserDeadlineTime.Date;
|
||||
foreach(RaidReminder reminder in _raid.Reminders)
|
||||
{
|
||||
if(reminder.TimeType == RaidReminder.ReminderTimeType.Static)
|
||||
|
@ -337,6 +361,7 @@
|
|||
_raid.EndTimeUTC = await TimeZoneService.GetUTCDateTime(_raidDate.Date.AddDays(1) + _endTime.TimeOfDay);
|
||||
}
|
||||
_raid.FreeForAllTimeUTC = await TimeZoneService.GetUTCDateTime(_freeForAllDate.Date + _freeForAllTime.TimeOfDay);
|
||||
_raid.MinUserDeadLineUTC = await TimeZoneService.GetUTCDateTime(_minUserDeadlineDate.Date + _minUserDeadlineTime.TimeOfDay);
|
||||
|
||||
if (!_raid.RaidOwnerId.HasValue)
|
||||
{
|
||||
|
|
|
@ -130,6 +130,26 @@
|
|||
<input type="time" @bind="_freeForAllTime" />
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label>
|
||||
Minimal required users:
|
||||
<InputNumber @bind-Value="_template.MinUsers" />
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label>
|
||||
Minimal user deadline date:
|
||||
<InputDate @bind-Value="_minUserDeadlineDate" />
|
||||
</label>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<label>
|
||||
Minimal user deadline time:
|
||||
<input type="time" @bind="_minUserDeadlineTime" />
|
||||
</label>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<label>
|
||||
Organizer:
|
||||
|
@ -222,6 +242,8 @@
|
|||
private DateTimeOffset _endTime;
|
||||
private DateTimeOffset _freeForAllDate = DateTime.Now.Date;
|
||||
private DateTimeOffset _freeForAllTime;
|
||||
private DateTimeOffset _minUserDeadlineDate = DateTime.Now.Date;
|
||||
private DateTimeOffset _minUserDeadlineTime;
|
||||
private string _userTimeZone = string.Empty;
|
||||
|
||||
private List<RaidRole> _rolesToDelete = new List<RaidRole>();
|
||||
|
@ -274,6 +296,8 @@
|
|||
_raidDate = _startTime.Date;
|
||||
_freeForAllTime = _template.FreeForAllTime;
|
||||
_freeForAllDate = _freeForAllTime.Date;
|
||||
_minUserDeadlineTime = _template.MinUserDeadLine;
|
||||
_minUserDeadlineDate = _minUserDeadlineTime.Date;
|
||||
foreach(RaidReminder reminder in _template.Reminders)
|
||||
{
|
||||
if(reminder.TimeType == RaidReminder.ReminderTimeType.Static)
|
||||
|
@ -290,8 +314,8 @@
|
|||
}
|
||||
else
|
||||
{
|
||||
_template = new RaidTemplate();
|
||||
_dynamicReminders.Add(DynamicRaidReminder.Create30MinReminder());
|
||||
_template = new RaidTemplate();
|
||||
_dynamicReminders.Add(DynamicRaidReminder.Create30MinReminder());
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -366,6 +390,7 @@
|
|||
_template.EndTime = _raidDate.Date.AddDays(1) + _endTime.TimeOfDay;
|
||||
}
|
||||
_template.FreeForAllTime = _freeForAllDate.Date + _freeForAllTime.TimeOfDay;
|
||||
_template.MinUserDeadLine = _minUserDeadlineDate.Date + _minUserDeadlineTime.TimeOfDay;
|
||||
|
||||
if (!_template.RaidOwnerId.HasValue)
|
||||
{
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue