color typereader fix

delmsgoncmd
guildconfig init
This commit is contained in:
Toastie 2025-03-30 15:06:56 +13:00
parent aa06f62258
commit 57a5993064
Signed by: toastie_t0ast
GPG key ID: 0861BE54AD481DC7
8 changed files with 244 additions and 213 deletions
src
EllieBot.VotesApi/Controllers
EllieBot

View file

@ -14,7 +14,7 @@ namespace EllieBot.VotesApi.Controllers
[Authorize(Policy = Policies.DiscordsAuth)] [Authorize(Policy = Policies.DiscordsAuth)]
public async Task<IActionResult> DiscordsWebhook([FromBody] DiscordsVoteWebhookModel data) public async Task<IActionResult> DiscordsWebhook([FromBody] DiscordsVoteWebhookModel data)
{ {
if (data.Type != "vote") if ((data.Type?.Contains("vote") ?? false) == false)
return Ok(); return Ok();
logger.LogInformation("User {UserId} has voted for Bot {BotId} on {Platform}", logger.LogInformation("User {UserId} has voted for Bot {BotId} on {Platform}",

View file

@ -113,8 +113,8 @@ public abstract class EllieContext : DbContext
#region GuildColors #region GuildColors
modelBuilder.Entity<GuildColors>() modelBuilder.Entity<GuildColors>()
.HasIndex(x => x.GuildId) .HasIndex(x => x.GuildId)
.IsUnique(true); .IsUnique(true);
#endregion #endregion
@ -123,7 +123,7 @@ public abstract class EllieContext : DbContext
modelBuilder.Entity<ButtonRole>(br => modelBuilder.Entity<ButtonRole>(br =>
{ {
br.HasIndex(x => x.GuildId) br.HasIndex(x => x.GuildId)
.IsUnique(false); .IsUnique(false);
br.HasAlternateKey(x => new br.HasAlternateKey(x => new
{ {
@ -145,27 +145,27 @@ public abstract class EllieContext : DbContext
}); });
sg.HasMany(x => x.Roles) sg.HasMany(x => x.Roles)
.WithOne() .WithOne()
.OnDelete(DeleteBehavior.Cascade); .OnDelete(DeleteBehavior.Cascade);
}); });
modelBuilder.Entity<Sar>() modelBuilder.Entity<Sar>()
.HasAlternateKey(x => new .HasAlternateKey(x => new
{ {
x.GuildId, x.GuildId,
x.RoleId x.RoleId
}); });
modelBuilder.Entity<SarAutoDelete>() modelBuilder.Entity<SarAutoDelete>()
.HasIndex(x => x.GuildId) .HasIndex(x => x.GuildId)
.IsUnique(); .IsUnique();
#endregion #endregion
#region Rakeback #region Rakeback
modelBuilder.Entity<Rakeback>() modelBuilder.Entity<Rakeback>()
.HasKey(x => x.UserId); .HasKey(x => x.UserId);
#endregion #endregion
@ -174,14 +174,14 @@ public abstract class EllieContext : DbContext
modelBuilder.Entity<UserBetStats>(ubs => modelBuilder.Entity<UserBetStats>(ubs =>
{ {
ubs.HasIndex(x => new ubs.HasIndex(x => new
{ {
x.UserId, x.UserId,
x.Game x.Game
}) })
.IsUnique(); .IsUnique();
ubs.HasIndex(x => x.MaxWin) ubs.HasIndex(x => x.MaxWin)
.IsUnique(false); .IsUnique(false);
}); });
#endregion #endregion
@ -189,22 +189,22 @@ public abstract class EllieContext : DbContext
#region Flag Translate #region Flag Translate
modelBuilder.Entity<FlagTranslateChannel>() modelBuilder.Entity<FlagTranslateChannel>()
.HasIndex(x => new .HasIndex(x => new
{ {
x.GuildId, x.GuildId,
x.ChannelId x.ChannelId
}) })
.IsUnique(); .IsUnique();
#endregion #endregion
#region NCanvas #region NCanvas
modelBuilder.Entity<NCPixel>() modelBuilder.Entity<NCPixel>()
.HasAlternateKey(x => x.Position); .HasAlternateKey(x => x.Position);
modelBuilder.Entity<NCPixel>() modelBuilder.Entity<NCPixel>()
.HasIndex(x => x.OwnerId); .HasIndex(x => x.OwnerId);
#endregion #endregion
@ -221,10 +221,11 @@ public abstract class EllieContext : DbContext
var configEntity = modelBuilder.Entity<GuildConfig>(); var configEntity = modelBuilder.Entity<GuildConfig>();
configEntity.HasIndex(c => c.GuildId) configEntity.HasIndex(c => c.GuildId)
.IsUnique(); .IsUnique();
configEntity.Property(x => x.VerboseErrors) configEntity.Property(x => x.VerboseErrors)
.HasDefaultValue(true); .HasDefaultValue(true);
// end shop // end shop
modelBuilder.Entity<PlantedCurrency>().HasIndex(x => x.MessageId).IsUnique(); modelBuilder.Entity<PlantedCurrency>().HasIndex(x => x.MessageId).IsUnique();
@ -270,19 +271,19 @@ public abstract class EllieContext : DbContext
modelBuilder.Entity<DiscordUser>(du => modelBuilder.Entity<DiscordUser>(du =>
{ {
du.Property(x => x.IsClubAdmin) du.Property(x => x.IsClubAdmin)
.HasDefaultValue(false); .HasDefaultValue(false);
du.Property(x => x.TotalXp) du.Property(x => x.TotalXp)
.HasDefaultValue(0); .HasDefaultValue(0);
du.Property(x => x.CurrencyAmount) du.Property(x => x.CurrencyAmount)
.HasDefaultValue(0); .HasDefaultValue(0);
du.HasAlternateKey(w => w.UserId); du.HasAlternateKey(w => w.UserId);
du.HasOne(x => x.Club) du.HasOne(x => x.Club)
.WithMany(x => x.Members) .WithMany(x => x.Members)
.IsRequired(false) .IsRequired(false)
.OnDelete(DeleteBehavior.NoAction); .OnDelete(DeleteBehavior.NoAction);
du.HasIndex(x => x.TotalXp); du.HasIndex(x => x.TotalXp);
du.HasIndex(x => x.CurrencyAmount); du.HasIndex(x => x.CurrencyAmount);
@ -308,11 +309,11 @@ public abstract class EllieContext : DbContext
var xps = modelBuilder.Entity<UserXpStats>(); var xps = modelBuilder.Entity<UserXpStats>();
xps.HasIndex(x => new xps.HasIndex(x => new
{ {
x.UserId, x.UserId,
x.GuildId x.GuildId
}) })
.IsUnique(); .IsUnique();
xps.HasIndex(x => x.UserId); xps.HasIndex(x => x.UserId);
xps.HasIndex(x => x.GuildId); xps.HasIndex(x => x.GuildId);
@ -324,49 +325,49 @@ public abstract class EllieContext : DbContext
var ci = modelBuilder.Entity<ClubInfo>(); var ci = modelBuilder.Entity<ClubInfo>();
ci.HasOne(x => x.Owner) ci.HasOne(x => x.Owner)
.WithOne() .WithOne()
.HasForeignKey<ClubInfo>(x => x.OwnerId) .HasForeignKey<ClubInfo>(x => x.OwnerId)
.OnDelete(DeleteBehavior.SetNull); .OnDelete(DeleteBehavior.SetNull);
ci.HasIndex(x => new ci.HasIndex(x => new
{ {
x.Name x.Name
}) })
.IsUnique(); .IsUnique();
#endregion #endregion
#region ClubManytoMany #region ClubManytoMany
modelBuilder.Entity<ClubApplicants>() modelBuilder.Entity<ClubApplicants>()
.HasKey(t => new .HasKey(t => new
{ {
t.ClubId, t.ClubId,
t.UserId t.UserId
}); });
modelBuilder.Entity<ClubApplicants>() modelBuilder.Entity<ClubApplicants>()
.HasOne(pt => pt.User) .HasOne(pt => pt.User)
.WithMany(); .WithMany();
modelBuilder.Entity<ClubApplicants>() modelBuilder.Entity<ClubApplicants>()
.HasOne(pt => pt.Club) .HasOne(pt => pt.Club)
.WithMany(x => x.Applicants); .WithMany(x => x.Applicants);
modelBuilder.Entity<ClubBans>() modelBuilder.Entity<ClubBans>()
.HasKey(t => new .HasKey(t => new
{ {
t.ClubId, t.ClubId,
t.UserId t.UserId
}); });
modelBuilder.Entity<ClubBans>() modelBuilder.Entity<ClubBans>()
.HasOne(pt => pt.User) .HasOne(pt => pt.User)
.WithMany(); .WithMany();
modelBuilder.Entity<ClubBans>() modelBuilder.Entity<ClubBans>()
.HasOne(pt => pt.Club) .HasOne(pt => pt.Club)
.WithMany(x => x.Bans); .WithMany(x => x.Bans);
#endregion #endregion
@ -375,16 +376,16 @@ public abstract class EllieContext : DbContext
modelBuilder.Entity<CurrencyTransaction>(e => modelBuilder.Entity<CurrencyTransaction>(e =>
{ {
e.HasIndex(x => x.UserId) e.HasIndex(x => x.UserId)
.IsUnique(false); .IsUnique(false);
e.Property(x => x.OtherId) e.Property(x => x.OtherId)
.HasDefaultValueSql(CurrencyTransactionOtherIdDefaultValue); .HasDefaultValueSql(CurrencyTransactionOtherIdDefaultValue);
e.Property(x => x.Type) e.Property(x => x.Type)
.IsRequired(); .IsRequired();
e.Property(x => x.Extra) e.Property(x => x.Extra)
.IsRequired(); .IsRequired();
}); });
#endregion #endregion
@ -399,21 +400,21 @@ public abstract class EllieContext : DbContext
modelBuilder.Entity<BanTemplate>().HasIndex(x => x.GuildId).IsUnique(); modelBuilder.Entity<BanTemplate>().HasIndex(x => x.GuildId).IsUnique();
modelBuilder.Entity<BanTemplate>() modelBuilder.Entity<BanTemplate>()
.Property(x => x.PruneDays) .Property(x => x.PruneDays)
.HasDefaultValue(null) .HasDefaultValue(null)
.IsRequired(false); .IsRequired(false);
#endregion #endregion
#region Perm Override #region Perm Override
modelBuilder.Entity<DiscordPermOverride>() modelBuilder.Entity<DiscordPermOverride>()
.HasIndex(x => new .HasIndex(x => new
{ {
x.GuildId, x.GuildId,
x.Command x.Command
}) })
.IsUnique(); .IsUnique();
#endregion #endregion
@ -430,14 +431,14 @@ public abstract class EllieContext : DbContext
modelBuilder.Entity<ReactionRoleV2>(rr2 => modelBuilder.Entity<ReactionRoleV2>(rr2 =>
{ {
rr2.HasIndex(x => x.GuildId) rr2.HasIndex(x => x.GuildId)
.IsUnique(false); .IsUnique(false);
rr2.HasIndex(x => new rr2.HasIndex(x => new
{ {
x.MessageId, x.MessageId,
x.Emote x.Emote
}) })
.IsUnique(); .IsUnique();
}); });
#endregion #endregion
@ -447,18 +448,18 @@ public abstract class EllieContext : DbContext
modelBuilder.Entity<LogSetting>(ls => ls.HasIndex(x => x.GuildId).IsUnique()); modelBuilder.Entity<LogSetting>(ls => ls.HasIndex(x => x.GuildId).IsUnique());
modelBuilder.Entity<LogSetting>(ls => ls modelBuilder.Entity<LogSetting>(ls => ls
.HasMany(x => x.LogIgnores) .HasMany(x => x.LogIgnores)
.WithOne(x => x.LogSetting) .WithOne(x => x.LogSetting)
.OnDelete(DeleteBehavior.Cascade)); .OnDelete(DeleteBehavior.Cascade));
modelBuilder.Entity<IgnoredLogItem>(ili => ili modelBuilder.Entity<IgnoredLogItem>(ili => ili
.HasIndex(x => new .HasIndex(x => new
{ {
x.LogSettingId, x.LogSettingId,
x.LogItemId, x.LogItemId,
x.ItemType x.ItemType
}) })
.IsUnique()); .IsUnique());
#endregion #endregion
@ -511,12 +512,12 @@ public abstract class EllieContext : DbContext
{ {
// user can own only one of each item // user can own only one of each item
x.HasIndex(model => new x.HasIndex(model => new
{ {
model.UserId, model.UserId,
model.ItemType, model.ItemType,
model.ItemKey model.ItemKey
}) })
.IsUnique(); .IsUnique();
}); });
#endregion #endregion
@ -524,27 +525,27 @@ public abstract class EllieContext : DbContext
#region AutoPublish #region AutoPublish
modelBuilder.Entity<AutoPublishChannel>(apc => apc modelBuilder.Entity<AutoPublishChannel>(apc => apc
.HasIndex(x => x.GuildId) .HasIndex(x => x.GuildId)
.IsUnique()); .IsUnique());
#endregion #endregion
#region GamblingStats #region GamblingStats
modelBuilder.Entity<GamblingStats>(gs => gs modelBuilder.Entity<GamblingStats>(gs => gs
.HasIndex(x => x.Feature) .HasIndex(x => x.Feature)
.IsUnique()); .IsUnique());
#endregion #endregion
#region Sticky Roles #region Sticky Roles
modelBuilder.Entity<StickyRole>(sr => sr.HasIndex(x => new modelBuilder.Entity<StickyRole>(sr => sr.HasIndex(x => new
{ {
x.GuildId, x.GuildId,
x.UserId x.UserId
}) })
.IsUnique()); .IsUnique());
#endregion #endregion
@ -552,35 +553,35 @@ public abstract class EllieContext : DbContext
#region Giveaway #region Giveaway
modelBuilder.Entity<GiveawayModel>() modelBuilder.Entity<GiveawayModel>()
.HasMany(x => x.Participants) .HasMany(x => x.Participants)
.WithOne() .WithOne()
.HasForeignKey(x => x.GiveawayId) .HasForeignKey(x => x.GiveawayId)
.OnDelete(DeleteBehavior.Cascade); .OnDelete(DeleteBehavior.Cascade);
modelBuilder.Entity<GiveawayUser>(gu => gu modelBuilder.Entity<GiveawayUser>(gu => gu
.HasIndex(x => new .HasIndex(x => new
{ {
x.GiveawayId, x.GiveawayId,
x.UserId x.UserId
}) })
.IsUnique()); .IsUnique());
#endregion #endregion
#region Todo #region Todo
modelBuilder.Entity<TodoModel>() modelBuilder.Entity<TodoModel>()
.HasKey(x => x.Id); .HasKey(x => x.Id);
modelBuilder.Entity<TodoModel>() modelBuilder.Entity<TodoModel>()
.HasIndex(x => x.UserId) .HasIndex(x => x.UserId)
.IsUnique(false); .IsUnique(false);
modelBuilder.Entity<ArchivedTodoListModel>() modelBuilder.Entity<ArchivedTodoListModel>()
.HasMany(x => x.Items) .HasMany(x => x.Items)
.WithOne() .WithOne()
.HasForeignKey(x => x.ArchiveId) .HasForeignKey(x => x.ArchiveId)
.OnDelete(DeleteBehavior.Cascade); .OnDelete(DeleteBehavior.Cascade);
#endregion #endregion
@ -588,11 +589,11 @@ public abstract class EllieContext : DbContext
modelBuilder modelBuilder
.Entity<GreetSettings>(gs => gs.HasIndex(x => new .Entity<GreetSettings>(gs => gs.HasIndex(x => new
{ {
x.GuildId, x.GuildId,
x.GreetType x.GreetType
}) })
.IsUnique()); .IsUnique());
modelBuilder.Entity<GreetSettings>(gs => modelBuilder.Entity<GreetSettings>(gs =>
{ {
@ -619,6 +620,6 @@ public abstract class EllieContext : DbContext
#endif #endif
optionsBuilder.ConfigureWarnings(x => x.Log(RelationalEventId.PendingModelChangesWarning) optionsBuilder.ConfigureWarnings(x => x.Log(RelationalEventId.PendingModelChangesWarning)
.Ignore()); .Ignore());
} }
} }

View file

@ -1,4 +1,3 @@
#nullable disable
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders; using Microsoft.EntityFrameworkCore.Metadata.Builders;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
@ -31,39 +30,38 @@ public sealed class GuildFilterConfigEntityConfiguration : IEntityTypeConfigurat
public class GuildConfig : DbEntity public class GuildConfig : DbEntity
{ {
public ulong GuildId { get; set; } public ulong GuildId { get; set; }
public string Prefix { get; set; } public string? Prefix { get; set; } = null;
public bool DeleteMessageOnCommand { get; set; } public bool DeleteMessageOnCommand { get; set; } = false;
public string AutoAssignRoleIds { get; set; }
public string? AutoAssignRoleIds { get; set; } = null;
public bool VerbosePermissions { get; set; } = true; public bool VerbosePermissions { get; set; } = true;
public string PermissionRole { get; set; } public string? PermissionRole { get; set; } = null;
//filtering //filtering
public string MuteRoleName { get; set; } public string? MuteRoleName { get; set; } = null;
// chatterbot // chatterbot
public bool CleverbotEnabled { get; set; } public bool CleverbotEnabled { get; set; } = false;
// aliases // aliases
public bool WarningsInitialized { get; set; } public bool WarningsInitialized { get; set; } = false;
public ulong? GameVoiceChannel { get; set; } public ulong? GameVoiceChannel { get; set; } = null;
public bool VerboseErrors { get; set; } = true; public bool VerboseErrors { get; set; } = true;
public bool NotifyStreamOffline { get; set; } public bool NotifyStreamOffline { get; set; } = true;
public bool DeleteStreamOnlineMessage { get; set; } public bool DeleteStreamOnlineMessage { get; set; } = false;
public int WarnExpireHours { get; set; } public int WarnExpireHours { get; set; } = 0;
public WarnExpireAction WarnExpireAction { get; set; } = WarnExpireAction.Clear; public WarnExpireAction WarnExpireAction { get; set; } = WarnExpireAction.Clear;
public bool DisableGlobalExpressions { get; set; } = false; public bool DisableGlobalExpressions { get; set; } = false;
public bool StickyRoles { get; set; } public bool StickyRoles { get; set; } = false;
public string TimeZoneId { get; set; } public string? TimeZoneId { get; set; } = null;
public string Locale { get; set; } public string? Locale { get; set; } = null;
public List<Permissionv2> Permissions { get; set; } = []; public List<Permissionv2> Permissions { get; set; } = [];
} }

View file

@ -124,7 +124,7 @@ public partial class Administration : EllieModule<AdministrationService>
[Priority(1)] [Priority(1)]
public async Task Delmsgoncmd(Server _ = Server.Server) public async Task Delmsgoncmd(Server _ = Server.Server)
{ {
var enabled = await _service.ToggleDeleteMessageOnCommand(ctx.Guild.Id); var enabled = await _service.ToggleDelMsgOnCmd(ctx.Guild.Id);
if (enabled) if (enabled)
{ {
await Response().Confirm(strs.delmsg_on).SendAsync(); await Response().Confirm(strs.delmsg_on).SendAsync();

View file

@ -1,7 +1,5 @@
#nullable disable #nullable disable
using LinqToDB;
using LinqToDB.EntityFrameworkCore; using LinqToDB.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using EllieBot.Common.ModuleBehaviors; using EllieBot.Common.ModuleBehaviors;
using EllieBot.Db.Models; using EllieBot.Db.Models;
using EllieBot.Modules.Administration._common.results; using EllieBot.Modules.Administration._common.results;
@ -10,8 +8,8 @@ namespace EllieBot.Modules.Administration;
public class AdministrationService : IEService, IReadyExecutor public class AdministrationService : IEService, IReadyExecutor
{ {
private ConcurrentHashSet<ulong> deleteMessagesOnCommand; private ConcurrentHashSet<ulong> _deleteMessagesOnCommand;
private ConcurrentDictionary<ulong, bool> delMsgOnCmdChannels; private ConcurrentDictionary<ulong, bool> _delMsgOnCmdChannels;
private readonly DbService _db; private readonly DbService _db;
private readonly IReplacementService _repSvc; private readonly IReplacementService _repSvc;
@ -39,31 +37,32 @@ public class AdministrationService : IEService, IReadyExecutor
public async Task OnReadyAsync() public async Task OnReadyAsync()
{ {
await using var uow = _db.GetDbContext(); await using var uow = _db.GetDbContext();
deleteMessagesOnCommand = new(await uow.GetTable<GuildConfig>() _deleteMessagesOnCommand = new(await uow.GetTable<GuildConfig>()
.Where(x => Queries.GuildOnShard(x.GuildId, _shardData.TotalShards, _shardData.ShardId) && x.DeleteMessageOnCommand) .Where(x => Queries.GuildOnShard(x.GuildId, _shardData.TotalShards, _shardData.ShardId) &&
.Select(x => x.GuildId) x.DeleteMessageOnCommand)
.ToListAsyncLinqToDB()); .Select(x => x.GuildId)
.ToListAsyncLinqToDB());
delMsgOnCmdChannels = (await uow.GetTable<DelMsgOnCmdChannel>() _delMsgOnCmdChannels = (await uow.GetTable<DelMsgOnCmdChannel>()
.Where(x => deleteMessagesOnCommand.Contains(x.GuildId)) .Where(x => _deleteMessagesOnCommand.Contains(x.GuildId))
.ToDictionaryAsyncLinqToDB(x => x.ChannelId, x => x.State)) .ToDictionaryAsyncLinqToDB(x => x.ChannelId, x => x.State))
.ToConcurrent(); .ToConcurrent();
_cmdHandler.CommandExecuted += DelMsgOnCmd_Handler; _cmdHandler.CommandExecuted += DelMsgOnCmd_Handler;
} }
public async Task<(bool DelMsgOnCmd, IEnumerable<DelMsgOnCmdChannel> channels)> GetDelMsgOnCmdData(ulong guildId) public async Task<(bool DelMsgOnCmd, IEnumerable<DelMsgOnCmdChannel> channels)> GetDelMsgOnCmdData(ulong guildId)
{ {
using var uow = _db.GetDbContext(); await using var uow = _db.GetDbContext();
var conf = await uow.GetTable<GuildConfig>() var conf = await uow.GetTable<GuildConfig>()
.Where(x => x.GuildId == guildId) .Where(x => x.GuildId == guildId)
.Select(x => x.DeleteMessageOnCommand) .Select(x => x.DeleteMessageOnCommand)
.FirstOrDefaultAsyncLinqToDB(); .FirstOrDefaultAsyncLinqToDB();
var channels = await uow.GetTable<DelMsgOnCmdChannel>() var channels = await uow.GetTable<DelMsgOnCmdChannel>()
.Where(x => x.GuildId == guildId) .Where(x => x.GuildId == guildId)
.ToListAsyncLinqToDB(); .ToListAsyncLinqToDB();
return (conf, channels); return (conf, channels);
} }
@ -76,50 +75,50 @@ public class AdministrationService : IEService, IReadyExecutor
_ = Task.Run(async () => _ = Task.Run(async () =>
{ {
//wat ?! //wat ?!
if (delMsgOnCmdChannels.TryGetValue(channel.Id, out var state)) if (_delMsgOnCmdChannels.TryGetValue(channel.Id, out var state))
{ {
if (state && cmd.Name != "prune" && cmd.Name != "pick") if (state && cmd.Name != "prune" && cmd.Name != "pick")
{ {
_logService.AddDeleteIgnore(msg.Id); _logService.AddDeleteIgnore(msg.Id);
try try
{ await msg.DeleteAsync(); } {
catch { } await msg.DeleteAsync();
}
catch
{
}
} }
//if state is false, that means do not do it //if state is false, that means do not do it
} }
else if (deleteMessagesOnCommand.Contains(channel.Guild.Id) && cmd.Name != "prune" && cmd.Name != "pick") else if (_deleteMessagesOnCommand.Contains(channel.Guild.Id) && cmd.Name != "prune" && cmd.Name != "pick")
{ {
_logService.AddDeleteIgnore(msg.Id); _logService.AddDeleteIgnore(msg.Id);
try try
{ await msg.DeleteAsync(); } {
catch { } await msg.DeleteAsync();
}
catch
{
}
} }
}); });
return Task.CompletedTask; return Task.CompletedTask;
} }
public async Task<bool> ToggleDeleteMessageOnCommand(ulong guildId) public async Task<bool> ToggleDelMsgOnCmd(ulong guildId)
{ {
using var uow = _db.GetDbContext(); await using var uow = _db.GetDbContext();
var conf = await uow.GetTable<GuildConfig>() var gc = uow.GuildConfigsForId(guildId);
.Where(x => x.GuildId == guildId) gc.DeleteMessageOnCommand = !gc.DeleteMessageOnCommand;
.UpdateWithOutputAsync(x => new()
{
DeleteMessageOnCommand = !x.DeleteMessageOnCommand
}, (old, newVal) => newVal);
if (conf.Length == 0) if (gc.DeleteMessageOnCommand)
return false; _deleteMessagesOnCommand.Add(guildId);
var val = conf[0].DeleteMessageOnCommand;
if (val)
deleteMessagesOnCommand.Add(guildId);
else else
deleteMessagesOnCommand.TryRemove(guildId); _deleteMessagesOnCommand.TryRemove(guildId);
return val; await uow.SaveChangesAsync();
return gc.DeleteMessageOnCommand;
} }
public async Task SetDelMsgOnCmdState(ulong guildId, ulong chId, Administration.State newState) public async Task SetDelMsgOnCmdState(ulong guildId, ulong chId, Administration.State newState)
@ -151,7 +150,7 @@ public class AdministrationService : IEService, IReadyExecutor
} }
old.State = newState == Administration.State.Enable; old.State = newState == Administration.State.Enable;
delMsgOnCmdChannels[chId] = newState == Administration.State.Enable; _delMsgOnCmdChannels[chId] = newState == Administration.State.Enable;
} }
await uow.SaveChangesAsync(); await uow.SaveChangesAsync();
@ -162,11 +161,11 @@ public class AdministrationService : IEService, IReadyExecutor
} }
else if (newState == Administration.State.Enable) else if (newState == Administration.State.Enable)
{ {
delMsgOnCmdChannels[chId] = true; _delMsgOnCmdChannels[chId] = true;
} }
else else
{ {
delMsgOnCmdChannels.TryRemove(chId, out _); _delMsgOnCmdChannels.TryRemove(chId, out _);
} }
} }
@ -249,5 +248,6 @@ public class AdministrationService : IEService, IReadyExecutor
return SetServerIconResult.Success; return SetServerIconResult.Success;
} }
private bool IsValidUri(string img) => !string.IsNullOrWhiteSpace(img) && Uri.IsWellFormedUriString(img, UriKind.Absolute); private bool IsValidUri(string img)
=> !string.IsNullOrWhiteSpace(img) && Uri.IsWellFormedUriString(img, UriKind.Absolute);
} }

View file

@ -5,6 +5,7 @@ using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Drawing.Processing; using SixLabors.ImageSharp.Drawing.Processing;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing;
using Color = SixLabors.ImageSharp.Color;
using Image = SixLabors.ImageSharp.Image; using Image = SixLabors.ImageSharp.Image;
namespace EllieBot.Modules.Games; namespace EllieBot.Modules.Games;
@ -81,7 +82,15 @@ public partial class Games
using var img = await GetZoomImage(position); using var img = await GetZoomImage(position);
await using var stream = await img.ToStreamAsync(); await using var stream = await img.ToStreamAsync();
await ctx.Channel.SendFileAsync(stream, $"zoom_{position}.png"); var eb = CreateEmbed()
.WithOkColor()
.WithImageUrl($"attachment://zoom_{position}.png")
.WithFooter($"`.ncs code color` to set. (.ncs abc green)" );
await Response()
.Embed(eb)
.File(stream, $"zoom_{position}.png")
.SendAsync();
} }
private async Task<Image<Rgba32>> GetZoomImage(kwum position) private async Task<Image<Rgba32>> GetZoomImage(kwum position)
@ -135,7 +144,7 @@ public partial class Games
} }
[Cmd] [Cmd]
public async Task NcSetPixel(kwum position, string colorHex, [Leftover] string text = "") public async Task NcSetPixel(kwum position, Rgba32 color, [Leftover] string text = "")
{ {
if (position < 0 || position >= _service.GetWidth() * _service.GetHeight()) if (position < 0 || position >= _service.GetWidth() * _service.GetHeight())
{ {
@ -143,15 +152,6 @@ public partial class Games
return; return;
} }
if (colorHex.StartsWith("0x", StringComparison.OrdinalIgnoreCase))
colorHex = colorHex[2..];
if (!Rgba32.TryParseHex(colorHex, out var clr))
{
await Response().Error(strs.invalid_color).SendAsync();
return;
}
var pixel = await _service.GetPixel(position); var pixel = await _service.GetPixel(position);
if (pixel is null) if (pixel is null)
{ {
@ -171,7 +171,7 @@ public partial class Games
return; return;
} }
var result = await _service.SetPixel(position, clr.PackedValue, text, ctx.User.Id, pixel.Price); var result = await _service.SetPixel(position, color.PackedValue, text, ctx.User.Id, pixel.Price);
if (result == SetPixelResult.NotEnoughMoney) if (result == SetPixelResult.NotEnoughMoney)
{ {

View file

@ -46,35 +46,45 @@ public sealed class QuestService(
_ = Task.Run(async () => _ = Task.Run(async () =>
{ {
// Log.Information("Action reported by {UserId}: {EventType} {Metadata}", Log.Information("Action reported by {UserId}: {EventType} {Metadata}",
// userId, userId,
// eventType, eventType,
// metadata.ToJson()); metadata.ToJson());
metadata ??= new(); metadata ??= new();
var now = DateTime.UtcNow; var now = DateTime.UtcNow;
Log.Information("done?");
var alreadyDone = await botCache.GetAsync(UserCompletedDailiesKey(userId)); var alreadyDone = await botCache.GetAsync(UserCompletedDailiesKey(userId));
if (alreadyDone.IsT0) if (alreadyDone.IsT0)
return; return;
Log.Information("not done");
var userQuests = await GetUserQuestsAsync(userId, now); var userQuests = await GetUserQuestsAsync(userId, now);
Log.Information("got quests");
foreach (var (q, uq) in userQuests) foreach (var (q, uq) in userQuests)
{ {
// deleted quest // deleted quest
if (q is null) if (q is null)
continue; continue;
Log.Information("not deleted {QuestEventType} - {EventType}", q.EventType, eventType);
// user already completed or incorrect event // user already completed or incorrect event
if (uq.IsCompleted || q.EventType != eventType) if (uq.IsCompleted || q.EventType != eventType)
continue; continue;
Log.Information("Gonna update progress");
var newProgress = q.TryUpdateProgress(metadata, uq.Progress); var newProgress = q.TryUpdateProgress(metadata, uq.Progress);
// user already did that part of the quest // user already did that part of the quest
if (newProgress == uq.Progress) if (newProgress == uq.Progress)
continue; continue;
Log.Information("new progress");
var isCompleted = newProgress >= q.RequiredAmount; var isCompleted = newProgress >= q.RequiredAmount;
await using var uow = db.GetDbContext(); await using var uow = db.GetDbContext();

View file

@ -8,11 +8,33 @@ public sealed class Rgba32TypeReader : EllieTypeReader<Rgba32>
{ {
public override ValueTask<TypeReaderResult<Rgba32>> ReadAsync(ICommandContext context, string input) public override ValueTask<TypeReaderResult<Rgba32>> ReadAsync(ICommandContext context, string input)
{ {
if (!Color.TryParse(input, out var color))
{
Log.Information("Fail");
return ValueTask.FromResult(
TypeReaderResult.FromError<Rgba32>(CommandError.ParseFailed, "Parameter is not a valid color hex."));
}
Log.Information(color.ToHex());
return ValueTask.FromResult(TypeReaderResult.FromSuccess((Rgba32)color));
if (Rgba32.TryParseHex(input, out var clr)) if (Rgba32.TryParseHex(input, out var clr))
{ {
return ValueTask.FromResult(TypeReaderResult.FromSuccess(clr)); return ValueTask.FromResult(TypeReaderResult.FromSuccess(clr));
} }
if (!Enum.TryParse<Color>(input, true, out var clrName))
return ValueTask.FromResult(
TypeReaderResult.FromError<Rgba32>(CommandError.ParseFailed,
"Parameter is not a valid color hex."));
Log.Information(clrName.ToString());
if (Rgba32.TryParseHex(clrName.ToHex(), out clr))
{
return ValueTask.FromResult(TypeReaderResult.FromSuccess(clr));
}
return ValueTask.FromResult( return ValueTask.FromResult(
TypeReaderResult.FromError<Rgba32>(CommandError.ParseFailed, "Parameter is not a valid color hex.")); TypeReaderResult.FromError<Rgba32>(CommandError.ParseFailed, "Parameter is not a valid color hex."));
} }