Added autodelete for users after one year inactivity

This commit is contained in:
Sarah Faey 2022-12-08 17:37:00 +01:00
parent c886c6475e
commit 929ca9c0a7
7 changed files with 730 additions and 2 deletions

View file

@ -112,6 +112,9 @@ namespace Lieb.Data
return false;
}
using var context = _contextFactory.CreateDbContext();
LiebUser user = context.LiebUsers.FirstOrDefault(l => l.Id == liebUserId);
if(user == null) return false;
List<RaidSignUp> signUps = context.RaidSignUps.Where(r => r.RaidId == raidId && r.LiebUserId == liebUserId).ToList();
if (signUpType != SignUpType.Flex && signUps.Where(r => r.SignUpType != SignUpType.Flex).Any())
@ -122,15 +125,16 @@ namespace Lieb.Data
else if (!signUps.Where(r => r.RaidRoleId == plannedRoleId).Any())
{
RaidSignUp signUp = new RaidSignUp(raidId, liebUserId, guildWars2AccountId, plannedRoleId, signUpType);
string userName = context.LiebUsers.FirstOrDefault(l => l.Id == liebUserId)?.Name;
context.RaidSignUps.Add(signUp);
await context.SaveChangesAsync();
await LogSignUp(signUp, userName, signedUpByUserId);
await LogSignUp(signUp, user.Name, signedUpByUserId);
}
else
{
return false;
}
user.LastSignUpAt = DateTime.UtcNow;
await context.SaveChangesAsync();
await _discordService.PostRaidMessage(raidId);
return true;
}

View file

@ -6,6 +6,7 @@ namespace Lieb.Data
{
private Timer _minuteTimer = null!;
private Timer _fiveMinuteTimer = null!;
private Timer _dailyTimer = null!;
private IServiceProvider _services;
public TimerService(IServiceProvider services)
@ -19,6 +20,8 @@ namespace Lieb.Data
TimeSpan.FromMinutes(1));
_fiveMinuteTimer = new Timer(CleanUpRaids, null, TimeSpan.Zero,
TimeSpan.FromMinutes(5));
_dailyTimer = new Timer(CleanUpDatabase, null, TimeSpan.Zero,
TimeSpan.FromDays(1));
return Task.CompletedTask;
}
@ -59,6 +62,17 @@ namespace Lieb.Data
}
}
private async void CleanUpDatabase(object? state)
{
using (var scope = _services.CreateScope())
{
var userService =
scope.ServiceProvider
.GetRequiredService<UserService>();
await userService.DeleteInactiveUsers();
}
}
public Task StopAsync(CancellationToken stoppingToken)
{
_minuteTimer?.Change(Timeout.Infinite, 0);

View file

@ -318,5 +318,20 @@ namespace Lieb.Data
return usableAccounts.First().GuildWars2AccountId;
}
}
public async Task DeleteInactiveUsers()
{
using var context = _contextFactory.CreateDbContext();
List<LiebUser> users = context.LiebUsers.ToList();
foreach(LiebUser user in users)
{
if((user.LastSignUpAt == null && user.CreatedAt < DateTime.UtcNow.AddYears(-1))
|| (user.LastSignUpAt != null && user.LastSignUpAt < DateTime.UtcNow.AddYears(-1)))
{
await DeleteUser(user.Id);
}
}
}
}
}

View file

@ -0,0 +1,650 @@
// <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("20221207211355_AddUserCreatedAtLastSignUp")]
partial class AddUserCreatedAtLastSignUp
{
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<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.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 System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Lieb.Migrations
{
public partial class AddUserCreatedAtLastSignUp : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<DateTime>(
name: "CreatedAt",
table: "LiebUser",
type: "TEXT",
nullable: false,
defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified));
migrationBuilder.AddColumn<DateTime>(
name: "LastSignUpAt",
table: "LiebUser",
type: "TEXT",
nullable: true);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "CreatedAt",
table: "LiebUser");
migrationBuilder.DropColumn(
name: "LastSignUpAt",
table: "LiebUser");
}
}
}

View file

@ -447,6 +447,12 @@ namespace Lieb.Migrations
b.Property<DateTime?>("Birthday")
.HasColumnType("TEXT");
b.Property<DateTime>("CreatedAt")
.HasColumnType("TEXT");
b.Property<DateTime?>("LastSignUpAt")
.HasColumnType("TEXT");
b.Property<int>("MainGW2Account")
.HasColumnType("INTEGER");

View file

@ -18,6 +18,8 @@ namespace Lieb.Models
public DateTime? Birthday { get; set; }
public DateTime? BannedUntil { get; set; }
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
public DateTime? LastSignUpAt { get; set; }
public int MainGW2Account { get; set; }
public bool AlwaysSignUpWithMainAccount { get; set; } = false;
public ICollection<GuildWars2Account> GuildWars2Accounts { get; set; } = new List<GuildWars2Account>();