Compare commits

...

14 commits
6.0.3 ... 6.0.4

Author SHA1 Message Date
b9b53ef3e8
I did a dumb and broke the migration 2025-03-14 23:32:23 +13:00
988d8c0250
.savechat no longer owneronly
started implementation of bigwin announcement, but there are problems
2025-03-14 21:03:23 +13:00
082cf79736
Fixed localization init
xp card name is now a little lower
Updated CHANGELOG.md
2025-03-14 20:10:47 +13:00
612c230b7b
fixed unban/unmute timers wrongly trying to unban users on all servers at once 2025-03-14 18:04:58 +13:00
775d77e94e
hopefully final fix for antialt, fixed leftover logs from xpsettings 2025-03-14 18:01:38 +13:00
f2820c980e
undo the antialt query change now that mapping should be correct 2025-03-14 17:54:28 +13:00
947b3794e9
mark minage in antialtsettings as interval type 2025-03-14 17:51:48 +13:00
ba1f5afa01
fix nullref in chatterbot and mapping issue in protectionservice 2025-03-14 16:02:05 +13:00
8fa6b0c999
fixing protection init and plantpick issues 2025-03-14 15:57:52 +13:00
1cd02222b9
fixed muteuserid cleanup migration 2025-03-14 13:35:54 +13:00
9af44d2220
fixed unrole timer cleanup migration 2025-03-14 13:34:15 +13:00
cce4795f9b
removed references to xpshop website 2025-03-14 13:31:14 +13:00
35d5b068be
cleaned up some grpc api of obsolete features 2025-03-14 13:21:13 +13:00
c0d2fb297e
Update CHANGELOG.md
I messed up the formatting.

Signed-off-by: toastie_t0ast <toastie@dragonschildstudios.com>
2025-03-13 19:46:46 +13:00
28 changed files with 259 additions and 299 deletions

View file

@ -2,7 +2,7 @@
*a,c,f,r,o* *a,c,f,r,o*
## [6.0.3] - [12.03.2025] ## [6.0.4] - 14.03.2025
### Added ### Added

View file

@ -12,7 +12,6 @@ service GrpcOther {
rpc GetRoles(GetRolesRequest) returns (GetRolesReply); rpc GetRoles(GetRolesRequest) returns (GetRolesReply);
rpc GetCurrencyLb(GetLbRequest) returns (CurrencyLbReply); rpc GetCurrencyLb(GetLbRequest) returns (CurrencyLbReply);
rpc GetXpLb(GetLbRequest) returns (XpLbReply);
rpc GetWaifuLb(GetLbRequest) returns (WaifuLbReply); rpc GetWaifuLb(GetLbRequest) returns (WaifuLbReply);
rpc GetShardStats(google.protobuf.Empty) returns (stream ShardStatsReply); rpc GetShardStats(google.protobuf.Empty) returns (stream ShardStatsReply);
@ -78,17 +77,6 @@ message GetLbRequest {
int32 perPage = 2; int32 perPage = 2;
} }
message XpLbReply {
repeated XpLbEntryReply entries = 1;
}
message XpLbEntryReply {
string user = 1;
uint64 userId = 2;
int64 totalXp = 3;
int64 level = 4;
}
message WaifuLbReply { message WaifuLbReply {
repeated WaifuLbEntry entries = 1; repeated WaifuLbEntry entries = 1;
} }

View file

@ -10,22 +10,8 @@ service GrpcXp {
rpc GetXpSettings(GetXpSettingsRequest) returns (GetXpSettingsReply); rpc GetXpSettings(GetXpSettingsRequest) returns (GetXpSettingsReply);
rpc AddExclusion(AddExclusionRequest) returns (AddExclusionReply);
rpc DeleteExclusion(DeleteExclusionRequest) returns (DeleteExclusionReply);
rpc AddReward(AddRewardRequest) returns (AddRewardReply); rpc AddReward(AddRewardRequest) returns (AddRewardReply);
rpc DeleteReward(DeleteRewardRequest) returns (DeleteRewardReply); rpc DeleteReward(DeleteRewardRequest) returns (DeleteRewardReply);
rpc SetServerExclusion(SetServerExclusionRequest) returns (SetServerExclusionReply);
}
message SetServerExclusionRequest {
uint64 guildId = 1;
bool serverExcluded = 2;
}
message SetServerExclusionReply {
bool success = 1;
} }
message GetXpLbRequest { message GetXpLbRequest {
@ -57,47 +43,19 @@ message ResetUserXpReply {
} }
message GetXpSettingsReply { message GetXpSettingsReply {
repeated ExclItemReply exclusions = 1;
repeated RewItemReply rewards = 2; repeated RewItemReply rewards = 2;
bool serverExcluded = 3;
} }
message GetXpSettingsRequest { message GetXpSettingsRequest {
uint64 guildId = 1; uint64 guildId = 1;
} }
message ExclItemReply {
string type = 1;
uint64 id = 2;
string name = 3;
}
message RewItemReply { message RewItemReply {
int32 level = 1; int32 level = 1;
string type = 2; string type = 2;
string value = 3; string value = 3;
} }
message AddExclusionRequest {
uint64 guildId = 1;
string type = 2;
uint64 id = 3;
}
message AddExclusionReply {
bool success = 1;
}
message DeleteExclusionRequest {
uint64 guildId = 1;
string type = 2;
uint64 id = 3;
}
message DeleteExclusionReply {
bool success = 1;
}
message AddRewardRequest { message AddRewardRequest {
uint64 guildId = 1; uint64 guildId = 1;
int32 level = 2; int32 level = 2;

View file

@ -272,9 +272,6 @@ public abstract class EllieContext : DbContext
du.Property(x => x.IsClubAdmin) du.Property(x => x.IsClubAdmin)
.HasDefaultValue(false); .HasDefaultValue(false);
du.Property(x => x.NotifyOnLevelUp)
.HasDefaultValue(XpNotificationLocation.None);
du.Property(x => x.TotalXp) du.Property(x => x.TotalXp)
.HasDefaultValue(0); .HasDefaultValue(0);

View file

@ -1,7 +1,5 @@
namespace EllieBot.Db.Models; namespace EllieBot.Db.Models;
// FUTURE remove LastLevelUp from here and UserXpStats
public class DiscordUser : DbEntity public class DiscordUser : DbEntity
{ {
public const string DEFAULT_USERNAME = "??Unknown"; public const string DEFAULT_USERNAME = "??Unknown";
@ -15,7 +13,6 @@ public class DiscordUser : DbEntity
public bool IsClubAdmin { get; set; } public bool IsClubAdmin { get; set; }
public long TotalXp { get; set; } public long TotalXp { get; set; }
public XpNotificationLocation NotifyOnLevelUp { get; set; }
public long CurrencyAmount { get; set; } public long CurrencyAmount { get; set; }

View file

@ -21,4 +21,5 @@ public enum NotifyType
Protection = 1, Prot = 1, Protection = 1, Prot = 1,
AddRoleReward = 2, AddRoleReward = 2,
RemoveRoleReward = 3, RemoveRoleReward = 3,
// BigWin = 4,
} }

View file

@ -2,6 +2,8 @@
using Microsoft.EntityFrameworkCore.Metadata.Builders; using Microsoft.EntityFrameworkCore.Metadata.Builders;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema; using System.ComponentModel.DataAnnotations.Schema;
using LinqToDB.Mapping;
using DataType = LinqToDB.DataType;
namespace EllieBot.Db.Models; namespace EllieBot.Db.Models;

View file

@ -4,7 +4,7 @@
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<ImplicitUsings>true</ImplicitUsings> <ImplicitUsings>true</ImplicitUsings>
<SatelliteResourceLanguages>en</SatelliteResourceLanguages> <SatelliteResourceLanguages>en</SatelliteResourceLanguages>
<Version>6.0.3</Version> <Version>6.0.4</Version>
<!-- Output/build --> <!-- Output/build -->
<RunWorkingDirectory>$(MSBuildProjectDirectory)</RunWorkingDirectory> <RunWorkingDirectory>$(MSBuildProjectDirectory)</RunWorkingDirectory>

View file

@ -1,4 +1,4 @@
BEGIN TRANSACTION; BEGIN TRANSACTION;
DROP INDEX "IX_XpSettings_GuildConfigId"; DROP INDEX "IX_XpSettings_GuildConfigId";
@ -142,7 +142,8 @@ DELETE FROM VcRoleInfo WHERE GuildConfigId IS NULL OR GuildConfigId NOT IN (SELE
UPDATE VcRoleInfo UPDATE VcRoleInfo
SET GuildId = (SELECT GuildId FROM GuildConfigs WHERE GuildConfigs.Id = VcRoleInfo.GuildConfigId); SET GuildId = (SELECT GuildId FROM GuildConfigs WHERE GuildConfigs.Id = VcRoleInfo.GuildConfigId);
DELETE FROM UnroleTimer WHERE GuildConfigId IS NULL OR GuildConfigId NOT IN (SELECT Id FROM GuildConfigs); DELETE FROM UnroleTimer WHERE GuildConfigId IS NULL OR GuildConfigId NOT IN (SELECT Id FROM GuildConfigs)
OR (GuildId, UserId) IN (SELECT GuildId, UserId FROM UnroleTimer GROUP BY GuildId, UserId HAVING COUNT(*) > 1);
UPDATE UnroleTimer UPDATE UnroleTimer
SET GuildId = (SELECT GuildId FROM GuildConfigs WHERE GuildConfigs.Id = UnroleTimer.GuildConfigId); SET GuildId = (SELECT GuildId FROM GuildConfigs WHERE GuildConfigs.Id = UnroleTimer.GuildConfigId);
@ -170,7 +171,8 @@ DELETE FROM Permissions WHERE GuildConfigId IS NULL OR GuildConfigId NOT IN (SEL
UPDATE Permissions UPDATE Permissions
SET GuildId = (SELECT GuildId FROM GuildConfigs WHERE GuildConfigs.Id = Permissions.GuildConfigId); SET GuildId = (SELECT GuildId FROM GuildConfigs WHERE GuildConfigs.Id = Permissions.GuildConfigId);
DELETE FROM MutedUserId WHERE GuildConfigId IS NULL OR GuildConfigId NOT IN (SELECT Id FROM GuildConfigs); DELETE FROM MutedUserId WHERE GuildConfigId IS NULL OR GuildConfigId NOT IN (SELECT Id FROM GuildConfigs)
OR (GuildId, UserId) IN (SELECT GuildId, UserId FROM MutedUserId GROUP BY GuildId, UserId HAVING COUNT(*) > 1);
UPDATE MutedUserId UPDATE MutedUserId
SET GuildId = (SELECT GuildId FROM GuildConfigs WHERE GuildConfigs.Id = MutedUserId.GuildConfigId); SET GuildId = (SELECT GuildId FROM GuildConfigs WHERE GuildConfigs.Id = MutedUserId.GuildConfigId);
@ -761,4 +763,3 @@ INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion")
VALUES ('20250126062816_cleanup', '8.0.8'); VALUES ('20250126062816_cleanup', '8.0.8');
COMMIT; COMMIT;

View file

@ -15,7 +15,12 @@ public enum MuteType
public class MuteService : IEService, IReadyExecutor public class MuteService : IEService, IReadyExecutor
{ {
public enum TimerType { Mute, Ban, AddRole } public enum TimerType
{
Mute,
Ban,
AddRole
}
private static readonly OverwritePermissions _denyOverwrite = new(addReactions: PermValue.Deny, private static readonly OverwritePermissions _denyOverwrite = new(addReactions: PermValue.Deny,
sendMessages: PermValue.Deny, sendMessages: PermValue.Deny,
@ -57,12 +62,12 @@ public class MuteService : IEService, IReadyExecutor
return; return;
_ = Task.Run(() => _sender.Response(user) _ = Task.Run(() => _sender.Response(user)
.Embed(_sender.CreateEmbed(user?.GuildId) .Embed(_sender.CreateEmbed(user?.GuildId)
.WithDescription($"You've been muted in {user.Guild} server") .WithDescription($"You've been muted in {user.Guild} server")
.AddField("Mute Type", type.ToString()) .AddField("Mute Type", type.ToString())
.AddField("Moderator", mod.ToString()) .AddField("Moderator", mod.ToString())
.AddField("Reason", reason)) .AddField("Reason", reason))
.SendAsync()); .SendAsync());
} }
private void OnUserUnmuted( private void OnUserUnmuted(
@ -75,12 +80,12 @@ public class MuteService : IEService, IReadyExecutor
return; return;
_ = Task.Run(() => _sender.Response(user) _ = Task.Run(() => _sender.Response(user)
.Embed(_sender.CreateEmbed(user.GuildId) .Embed(_sender.CreateEmbed(user.GuildId)
.WithDescription($"You've been unmuted in {user.Guild} server") .WithDescription($"You've been unmuted in {user.Guild} server")
.AddField("Unmute Type", type.ToString()) .AddField("Unmute Type", type.ToString())
.AddField("Moderator", mod.ToString()) .AddField("Moderator", mod.ToString())
.AddField("Reason", reason)) .AddField("Reason", reason))
.SendAsync()); .SendAsync());
} }
private Task Client_UserJoined(IGuildUser usr) private Task Client_UserJoined(IGuildUser usr)
@ -105,8 +110,8 @@ public class MuteService : IEService, IReadyExecutor
{ {
await using var uow = _db.GetDbContext(); await using var uow = _db.GetDbContext();
var config = uow.GetTable<GuildConfig>() var config = uow.GetTable<GuildConfig>()
.Where(x => x.GuildId == guildId) .Where(x => x.GuildId == guildId)
.FirstOrDefault(); .FirstOrDefault();
config.MuteRoleName = name; config.MuteRoleName = name;
_guildMuteRoles.AddOrUpdate(guildId, name, (_, _) => name); _guildMuteRoles.AddOrUpdate(guildId, name, (_, _) => name);
await uow.SaveChangesAsync(); await uow.SaveChangesAsync();
@ -121,8 +126,12 @@ public class MuteService : IEService, IReadyExecutor
if (type == MuteType.All) if (type == MuteType.All)
{ {
try try
{ await usr.ModifyAsync(x => x.Mute = true); } {
catch { } await usr.ModifyAsync(x => x.Mute = true);
}
catch
{
}
var muteRole = await GetMuteRole(usr.Guild); var muteRole = await GetMuteRole(usr.Guild);
if (!usr.RoleIds.Contains(muteRole.Id)) if (!usr.RoleIds.Contains(muteRole.Id))
@ -131,19 +140,19 @@ public class MuteService : IEService, IReadyExecutor
await using (var uow = _db.GetDbContext()) await using (var uow = _db.GetDbContext())
{ {
await uow.GetTable<MutedUserId>() await uow.GetTable<MutedUserId>()
.InsertOrUpdateAsync(() => new() .InsertOrUpdateAsync(() => new()
{ {
GuildId = usr.GuildId, GuildId = usr.GuildId,
UserId = usr.Id UserId = usr.Id
}, },
(_) => new() (_) => new()
{ {
}, },
() => new() () => new()
{ {
GuildId = usr.GuildId, GuildId = usr.GuildId,
UserId = usr.Id UserId = usr.Id
}); });
if (_mutedUsers.TryGetValue(usr.Guild.Id, out var muted)) if (_mutedUsers.TryGetValue(usr.Guild.Id, out var muted))
muted.Add(usr.Id); muted.Add(usr.Id);
@ -160,7 +169,9 @@ public class MuteService : IEService, IReadyExecutor
await usr.ModifyAsync(x => x.Mute = true); await usr.ModifyAsync(x => x.Mute = true);
UserMuted(usr, mod, MuteType.Voice, reason); UserMuted(usr, mod, MuteType.Voice, reason);
} }
catch { } catch
{
}
} }
else if (type == MuteType.Chat) else if (type == MuteType.Chat)
{ {
@ -183,12 +194,12 @@ public class MuteService : IEService, IReadyExecutor
await using (var uow = _db.GetDbContext()) await using (var uow = _db.GetDbContext())
{ {
await uow.GetTable<MutedUserId>() await uow.GetTable<MutedUserId>()
.Where(x => x.GuildId == guildId && x.UserId == usrId) .Where(x => x.GuildId == guildId && x.UserId == usrId)
.DeleteAsync(); .DeleteAsync();
await uow.GetTable<UnmuteTimer>() await uow.GetTable<UnmuteTimer>()
.Where(x => x.GuildId == guildId && x.UserId == usrId) .Where(x => x.GuildId == guildId && x.UserId == usrId)
.DeleteAsync(); .DeleteAsync();
if (_mutedUsers.TryGetValue(guildId, out var muted)) if (_mutedUsers.TryGetValue(guildId, out var muted))
muted.TryRemove(usrId); muted.TryRemove(usrId);
@ -197,11 +208,17 @@ public class MuteService : IEService, IReadyExecutor
if (usr is not null) if (usr is not null)
{ {
try try
{ await usr.ModifyAsync(x => x.Mute = false); } {
catch { } await usr.ModifyAsync(x => x.Mute = false);
}
catch
{
}
try try
{ await usr.RemoveRoleAsync(await GetMuteRole(usr.Guild)); } {
await usr.RemoveRoleAsync(await GetMuteRole(usr.Guild));
}
catch catch
{ {
/*ignore*/ /*ignore*/
@ -240,7 +257,9 @@ public class MuteService : IEService, IReadyExecutor
//if it doesn't exist, create it //if it doesn't exist, create it
{ {
try try
{ muteRole = await guild.CreateRoleAsync(muteRoleName, isMentionable: false); } {
muteRole = await guild.CreateRoleAsync(muteRoleName, isMentionable: false);
}
catch catch
{ {
//if creations fails, maybe the name is not correct, find default one, if doesn't work, create default one //if creations fails, maybe the name is not correct, find default one, if doesn't work, create default one
@ -282,12 +301,12 @@ public class MuteService : IEService, IReadyExecutor
{ {
var unmuteAt = DateTime.UtcNow + after; var unmuteAt = DateTime.UtcNow + after;
await uow.GetTable<UnmuteTimer>() await uow.GetTable<UnmuteTimer>()
.InsertAsync(() => new() .InsertAsync(() => new()
{ {
GuildId = user.GuildId, GuildId = user.GuildId,
UserId = user.Id, UserId = user.Id,
UnmuteAt = unmuteAt UnmuteAt = unmuteAt
}); });
} }
StartUn_Timer(user.GuildId, user.Id, after, TimerType.Mute); // start the timer StartUn_Timer(user.GuildId, user.Id, after, TimerType.Mute); // start the timer
@ -305,12 +324,12 @@ public class MuteService : IEService, IReadyExecutor
{ {
var unbanAt = DateTime.UtcNow + after; var unbanAt = DateTime.UtcNow + after;
await uow.GetTable<UnbanTimer>() await uow.GetTable<UnbanTimer>()
.InsertAsync(() => new() .InsertAsync(() => new()
{ {
GuildId = guild.Id, GuildId = guild.Id,
UserId = userId, UserId = userId,
UnbanAt = unbanAt UnbanAt = unbanAt
}); });
} }
StartUn_Timer(guild.Id, userId, after, TimerType.Ban); // start the timer StartUn_Timer(guild.Id, userId, after, TimerType.Ban); // start the timer
@ -415,83 +434,80 @@ public class MuteService : IEService, IReadyExecutor
{ {
await using var uow = _db.GetDbContext(); await using var uow = _db.GetDbContext();
var configs = await uow.Set<GuildConfig>() var configs = await uow.Set<GuildConfig>()
.Where(x => Queries.GuildOnShard(x.GuildId, _shardData.TotalShards, _shardData.ShardId)) .Where(x => Queries.GuildOnShard(x.GuildId, _shardData.TotalShards, _shardData.ShardId))
.ToListAsyncLinqToDB(); .ToListAsyncLinqToDB();
_guildMuteRoles = configs.Where(c => !string.IsNullOrWhiteSpace(c.MuteRoleName)) _guildMuteRoles = configs.Where(c => !string.IsNullOrWhiteSpace(c.MuteRoleName))
.ToDictionary(c => c.GuildId, c => c.MuteRoleName) .ToDictionary(c => c.GuildId, c => c.MuteRoleName)
.ToConcurrent(); .ToConcurrent();
_mutedUsers = await uow.GetTable<MutedUserId>() _mutedUsers = await uow.GetTable<MutedUserId>()
.Where(x => Queries.GuildOnShard(x.GuildId, _shardData.TotalShards, _shardData.ShardId)) .Where(x => Queries.GuildOnShard(x.GuildId, _shardData.TotalShards, _shardData.ShardId))
.ToListAsyncLinqToDB() .ToListAsyncLinqToDB()
.Fmap(x => x.GroupBy(x => x.GuildId) .Fmap(x => x.GroupBy(x => x.GuildId)
.ToDictionary(g => g.Key, g => new ConcurrentHashSet<ulong>(g.Select(x => x.UserId))) .ToDictionary(g => g.Key, g => new ConcurrentHashSet<ulong>(g.Select(x => x.UserId)))
.ToConcurrent()); .ToConcurrent());
var max = TimeSpan.FromDays(49); var max = TimeSpan.FromDays(49);
var unmuteTimers = await uow.GetTable<UnmuteTimer>() var unmuteTimers = await uow.GetTable<UnmuteTimer>()
.Where(x => Queries.GuildOnShard(x.GuildId, _shardData.TotalShards, _shardData.ShardId)) .Where(x => Queries.GuildOnShard(x.GuildId, _shardData.TotalShards, _shardData.ShardId))
.ToListAsyncLinqToDB(); .ToListAsyncLinqToDB();
var unbanTimers = await uow.GetTable<UnbanTimer>() var unbanTimers = await uow.GetTable<UnbanTimer>()
.Where(x => Queries.GuildOnShard(x.GuildId, _shardData.TotalShards, _shardData.ShardId)) .Where(x => Queries.GuildOnShard(x.GuildId, _shardData.TotalShards, _shardData.ShardId))
.ToListAsyncLinqToDB(); .ToListAsyncLinqToDB();
var unroleTimers = await uow.GetTable<UnroleTimer>() var unroleTimers = await uow.GetTable<UnroleTimer>()
.Where(x => Queries.GuildOnShard(x.GuildId, _shardData.TotalShards, _shardData.ShardId)) .Where(x => Queries.GuildOnShard(x.GuildId, _shardData.TotalShards, _shardData.ShardId))
.ToListAsyncLinqToDB(); .ToListAsyncLinqToDB();
foreach (var conf in configs) foreach (var x in unmuteTimers)
{ {
foreach (var x in unmuteTimers) TimeSpan after;
if (x.UnmuteAt - TimeSpan.FromMinutes(2) <= DateTime.UtcNow)
{ {
TimeSpan after; after = TimeSpan.FromMinutes(2);
if (x.UnmuteAt - TimeSpan.FromMinutes(2) <= DateTime.UtcNow) }
{ else
after = TimeSpan.FromMinutes(2); {
} var unmute = x.UnmuteAt - DateTime.UtcNow;
else after = unmute > max ? max : unmute;
{
var unmute = x.UnmuteAt - DateTime.UtcNow;
after = unmute > max ? max : unmute;
}
StartUn_Timer(conf.GuildId, x.UserId, after, TimerType.Mute);
} }
foreach (var x in unbanTimers) StartUn_Timer(x.GuildId, x.UserId, after, TimerType.Mute);
{ }
TimeSpan after;
if (x.UnbanAt - TimeSpan.FromMinutes(2) <= DateTime.UtcNow)
{
after = TimeSpan.FromMinutes(2);
}
else
{
var unban = x.UnbanAt - DateTime.UtcNow;
after = unban > max ? max : unban;
}
StartUn_Timer(conf.GuildId, x.UserId, after, TimerType.Ban); foreach (var x in unbanTimers)
{
TimeSpan after;
if (x.UnbanAt - TimeSpan.FromMinutes(2) <= DateTime.UtcNow)
{
after = TimeSpan.FromMinutes(2);
}
else
{
var unban = x.UnbanAt - DateTime.UtcNow;
after = unban > max ? max : unban;
} }
foreach (var x in unroleTimers) StartUn_Timer(x.GuildId, x.UserId, after, TimerType.Ban);
{ }
TimeSpan after;
if (x.UnbanAt - TimeSpan.FromMinutes(2) <= DateTime.UtcNow)
{
after = TimeSpan.FromMinutes(2);
}
else
{
var unban = x.UnbanAt - DateTime.UtcNow;
after = unban > max ? max : unban;
}
StartUn_Timer(conf.GuildId, x.UserId, after, TimerType.AddRole, x.RoleId); foreach (var x in unroleTimers)
{
TimeSpan after;
if (x.UnbanAt - TimeSpan.FromMinutes(2) <= DateTime.UtcNow)
{
after = TimeSpan.FromMinutes(2);
} }
else
{
var unban = x.UnbanAt - DateTime.UtcNow;
after = unban > max ? max : unban;
}
StartUn_Timer(x.GuildId, x.UserId, after, TimerType.AddRole, x.RoleId);
} }
_client.UserJoined += Client_UserJoined; _client.UserJoined += Client_UserJoined;

View file

@ -0,0 +1,46 @@
// using System.Globalization;
// using EllieBot.Db.Models;
// using EllieBot.Modules.Administration;
//
// namespace EllieBot.Modules.Gambling;
//
// public readonly record struct BigWinNotifyModel(
// string GuildName,
// ulong ChannelId,
// ulong UserId,
// string Amount)
// : INotifyModel<BigWinNotifyModel>
// {
// public const string PH_USER = "user";
// public const string PH_GUILD = "server";
// public const string PH_AMOUNT = "amount";
//
// public static string KeyName
// => "notify.bigwin";
//
// public static NotifyType NotifyType
// => NotifyType.BigWin;
//
// public static bool SupportsOriginTarget
// => true;
//
// public static IReadOnlyList<NotifyModelPlaceholderData<BigWinNotifyModel>> GetReplacements()
// =>
// [
// new(PH_USER, static (data, g) => g.GetUser(data.UserId)?.ToString() ?? data.UserId.ToString()),
// new(PH_AMOUNT, static (data, g) => data.Amount),
// new(PH_GUILD, static (data, g) => data.GuildName)
// ];
//
// public bool TryGetChannelId(out ulong channelId)
// {
// channelId = ChannelId;
// return true;
// }
//
// public bool TryGetUserId(out ulong userId)
// {
// userId = UserId;
// return true;
// }
// }

View file

@ -4,6 +4,7 @@ using EllieBot.Common.ModuleBehaviors;
using EllieBot.Db.Models; using EllieBot.Db.Models;
using EllieBot.Generators; using EllieBot.Generators;
using EllieBot.Modules.Administration.Services; using EllieBot.Modules.Administration.Services;
using EllieBot.Modules.Gambling;
using EllieBot.Modules.Xp.Services; using EllieBot.Modules.Xp.Services;
namespace EllieBot.Modules.Administration; namespace EllieBot.Modules.Administration;

View file

@ -502,9 +502,10 @@ public class ProtectionService : IReadyExecutor, IEService
{ {
await using var uow = _db.GetDbContext(); await using var uow = _db.GetDbContext();
var configs = await uow.GetTable<AntiAltSetting>() var gids = _client.GetGuildIds();
.Where(x => Queries.GuildOnShard(x.GuildId, _shardData.TotalShards, _shardData.ShardId)) var configs = await uow.Set<AntiAltSetting>()
.ToListAsyncLinqToDB(); .Where(x => gids.Contains(x.GuildId))
.ToListAsyncEF();
foreach (var config in configs) foreach (var config in configs)
_antiAltGuilds[config.GuildId] = new(config); _antiAltGuilds[config.GuildId] = new(config);
@ -522,6 +523,7 @@ public class ProtectionService : IReadyExecutor, IEService
} }
var spamConfigs = await uow.GetTable<AntiSpamSetting>() var spamConfigs = await uow.GetTable<AntiSpamSetting>()
.AsNoTracking()
.Where(x => Queries.GuildOnShard(x.GuildId, _shardData.TotalShards, _shardData.ShardId)) .Where(x => Queries.GuildOnShard(x.GuildId, _shardData.TotalShards, _shardData.ShardId))
.ToListAsyncLinqToDB(); .ToListAsyncLinqToDB();

View file

@ -716,8 +716,13 @@ public partial class Administration
var banPrune = await _service.GetBanPruneAsync(ctx.Guild.Id) ?? 7; var banPrune = await _service.GetBanPruneAsync(ctx.Guild.Id) ?? 7;
await ctx.Guild.AddBanAsync(user, banPrune, ("Softban | " + ctx.User + " | " + msg).TrimTo(512)); await ctx.Guild.AddBanAsync(user, banPrune, ("Softban | " + ctx.User + " | " + msg).TrimTo(512));
try try
{ await ctx.Guild.RemoveBanAsync(user); } {
catch { await ctx.Guild.RemoveBanAsync(user); } await ctx.Guild.RemoveBanAsync(user);
}
catch
{
}
var toSend = CreateEmbed() var toSend = CreateEmbed()
.WithOkColor() .WithOkColor()

View file

@ -15,13 +15,6 @@ using EllieBot.Modules.Gambling.Rps;
using EllieBot.Common.TypeReaders; using EllieBot.Common.TypeReaders;
using EllieBot.Modules.Games; using EllieBot.Modules.Games;
using EllieBot.Modules.Patronage; using EllieBot.Modules.Patronage;
using SixLabors.Fonts;
using SixLabors.Fonts.Unicode;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Drawing.Processing;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing;
using Color = SixLabors.ImageSharp.Color;
namespace EllieBot.Modules.Gambling; namespace EllieBot.Modules.Gambling;

View file

@ -25,13 +25,11 @@ public class PlantPickService : IEService, IExecNoCommand, IReadyExecutor
private readonly FontProvider _fonts; private readonly FontProvider _fonts;
private readonly ICurrencyService _cs; private readonly ICurrencyService _cs;
private readonly CommandHandler _cmdHandler; private readonly CommandHandler _cmdHandler;
private readonly EllieRandom _rng;
private readonly DiscordSocketClient _client; private readonly DiscordSocketClient _client;
private readonly GamblingConfigService _gss; private readonly GamblingConfigService _gss;
private readonly GamblingService _gs; private readonly GamblingService _gs;
private ConcurrentHashSet<ulong> _generationChannels; private ConcurrentHashSet<ulong> _generationChannels = [];
private readonly SemaphoreSlim _pickLock = new(1, 1);
public PlantPickService( public PlantPickService(
DbService db, DbService db,
@ -50,13 +48,9 @@ public class PlantPickService : IEService, IExecNoCommand, IReadyExecutor
_fonts = fonts; _fonts = fonts;
_cs = cs; _cs = cs;
_cmdHandler = cmdHandler; _cmdHandler = cmdHandler;
_rng = new();
_client = client; _client = client;
_gss = gss; _gss = gss;
_gs = gs; _gs = gs;
using var uow = db.GetDbContext();
var guildIds = client.Guilds.Select(x => x.Id).ToList();
} }
public Task ExecOnNoCommandAsync(IGuild guild, IUserMessage msg) public Task ExecOnNoCommandAsync(IGuild guild, IUserMessage msg)
@ -416,7 +410,6 @@ public class PlantPickService : IEService, IExecNoCommand, IReadyExecutor
public async Task OnReadyAsync() public async Task OnReadyAsync()
{ {
await using var uow = _db.GetDbContext(); await using var uow = _db.GetDbContext();
_generationChannels = (await uow.GetTable<GCChannelId>() _generationChannels = (await uow.GetTable<GCChannelId>()
.Select(x => x.ChannelId) .Select(x => x.ChannelId)

View file

@ -13,7 +13,7 @@ namespace EllieBot.Modules.Games.Services;
public class ChatterBotService : IExecOnMessage, IReadyExecutor public class ChatterBotService : IExecOnMessage, IReadyExecutor
{ {
private ConcurrentDictionary<ulong, Lazy<IChatterBotSession>> _chatterBotGuilds; private ConcurrentDictionary<ulong, Lazy<IChatterBotSession>> _chatterBotGuilds = [];
public int Priority public int Priority
=> 1; => 1;
@ -165,8 +165,8 @@ public class ChatterBotService : IExecOnMessage, IReadyExecutor
(inTokens) + (result.TokensOut / 2 * 3)); (inTokens) + (result.TokensOut / 2 * 3));
await _sender.Response(channel) await _sender.Response(channel)
.Confirm(result.Text) .Confirm(result.Text)
.SendAsync(); .SendAsync();
} }
else else
{ {
@ -204,12 +204,12 @@ public class ChatterBotService : IExecOnMessage, IReadyExecutor
{ {
await using var uow = _db.GetDbContext(); await using var uow = _db.GetDbContext();
await uow.Set<GuildConfig>() await uow.Set<GuildConfig>()
.ToLinqToDBTable() .ToLinqToDBTable()
.Where(x => x.GuildId == guildId) .Where(x => x.GuildId == guildId)
.UpdateAsync((gc) => new GuildConfig() .UpdateAsync((gc) => new GuildConfig()
{ {
CleverbotEnabled = false CleverbotEnabled = false
}); });
await uow.SaveChangesAsync(); await uow.SaveChangesAsync();
return false; return false;
} }
@ -219,12 +219,12 @@ public class ChatterBotService : IExecOnMessage, IReadyExecutor
await using (var uow = _db.GetDbContext()) await using (var uow = _db.GetDbContext())
{ {
await uow.Set<GuildConfig>() await uow.Set<GuildConfig>()
.ToLinqToDBTable() .ToLinqToDBTable()
.Where(x => x.GuildId == guildId) .Where(x => x.GuildId == guildId)
.UpdateAsync((gc) => new GuildConfig() .UpdateAsync((gc) => new GuildConfig()
{ {
CleverbotEnabled = true CleverbotEnabled = true
}); });
await uow.SaveChangesAsync(); await uow.SaveChangesAsync();
} }
@ -235,12 +235,13 @@ public class ChatterBotService : IExecOnMessage, IReadyExecutor
public async Task OnReadyAsync() public async Task OnReadyAsync()
{ {
await using var uow = _db.GetDbContext(); await using var uow = _db.GetDbContext();
_chatterBotGuilds = uow.GuildConfigs _chatterBotGuilds = await uow.GuildConfigs
.AsNoTracking() .AsNoTracking()
.Where(gc => gc.CleverbotEnabled) .Where(gc => gc.CleverbotEnabled)
.AsEnumerable() .ToListAsyncLinqToDB()
.ToDictionary(gc => gc.GuildId, .Fmap(x => x
_ => new Lazy<IChatterBotSession>(() => CreateSession(), true)) .ToDictionary(gc => gc.GuildId,
.ToConcurrent(); _ => new Lazy<IChatterBotSession>(() => CreateSession(), true))
.ToConcurrent());
} }
} }

View file

@ -642,9 +642,13 @@ public partial class Utility : EllieModule
[Cmd] [Cmd]
[RequireContext(ContextType.Guild)] [RequireContext(ContextType.Guild)]
[OwnerOnly] [UserPerm(GuildPerm.Administrator)]
[Ratelimit(3600)]
public async Task SaveChat(int cnt) public async Task SaveChat(int cnt)
{ {
if (cnt > 1000)
return;
var msgs = new List<IMessage>(cnt); var msgs = new List<IMessage>(cnt);
await ctx.Channel.GetMessagesAsync(cnt).ForEachAsync(dled => msgs.AddRange(dled)); await ctx.Channel.GetMessagesAsync(cnt).ForEachAsync(dled => msgs.AddRange(dled));

View file

@ -314,8 +314,6 @@ public partial class Xp : EllieModule<XpService>
$""" $"""
`{prefix}xpshop bgs` `{prefix}xpshop bgs`
`{prefix}xpshop frames` `{prefix}xpshop frames`
*{GetText(strs.xpshop_website)}*
""") """)
.SendAsync(); .SendAsync();
} }
@ -372,11 +370,6 @@ public partial class Xp : EllieModule<XpService>
if (!string.IsNullOrWhiteSpace(item.Desc)) if (!string.IsNullOrWhiteSpace(item.Desc))
eb.AddField(GetText(strs.desc), item.Desc); eb.AddField(GetText(strs.desc), item.Desc);
#if GLOBAL_NADEKO
if (key == "default")
eb.WithDescription(GetText(strs.xpshop_website));
#endif
var tier = _service.GetXpShopTierRequirement(type); var tier = _service.GetXpShopTierRequirement(type);
if (tier != PatronTier.None) if (tier != PatronTier.None)
{ {

View file

@ -227,11 +227,6 @@ public class XpService : IEService, IReadyExecutor, IExecNoCommand
var oldStats = new LevelStats(u.Xp - data.Xp); var oldStats = new LevelStats(u.Xp - data.Xp);
var newStats = new LevelStats(u.Xp); var newStats = new LevelStats(u.Xp);
Log.Information("User {User} xp updated from {OldLevel} to {NewLevel}",
u.UserId,
oldStats.TotalXp,
newStats.TotalXp);
if (oldStats.Level < newStats.Level) if (oldStats.Level < newStats.Level)
{ {
await _levelUpQueue.EnqueueAsync(NotifyUser(u.GuildId, await _levelUpQueue.EnqueueAsync(NotifyUser(u.GuildId,

View file

@ -119,7 +119,7 @@ public class XpTemplate
Pos = new() Pos = new()
{ {
X = 394, X = 394,
Y = 35 Y = 40
}, },
Show = true Show = true
} }

View file

@ -111,31 +111,6 @@ public sealed class OtherSvc : GrpcOther.GrpcOtherBase, IGrpcSvc, IEService
return reply; return reply;
} }
[GrpcNoAuthRequired]
public override async Task<XpLbReply> GetXpLb(GetLbRequest request, ServerCallContext context)
{
var users = await _xp.GetGlobalUserXps(request.Page);
var reply = new XpLbReply();
var entries = users.Select(x =>
{
var lvl = new LevelStats(x.TotalXp);
return new XpLbEntryReply()
{
Level = lvl.Level,
TotalXp = x.TotalXp,
User = x.Username,
UserId = x.UserId
};
});
reply.Entries.AddRange(entries);
return reply;
}
[GrpcNoAuthRequired] [GrpcNoAuthRequired]
public override async Task<WaifuLbReply> GetWaifuLb(GetLbRequest request, ServerCallContext context) public override async Task<WaifuLbReply> GetWaifuLb(GetLbRequest request, ServerCallContext context)
{ {

View file

@ -35,27 +35,10 @@ public class XpSvc : GrpcXp.GrpcXpBase, IGrpcSvc, IEService
if (guild is null) if (guild is null)
throw new RpcException(new Status(StatusCode.NotFound, "Guild not found")); throw new RpcException(new Status(StatusCode.NotFound, "Guild not found"));
var excludedChannels = new List<ulong>();
var excludedRoles = new List<ulong>();
var isServerExcluded = false; var isServerExcluded = false;
var reply = new GetXpSettingsReply(); var reply = new GetXpSettingsReply();
reply.Exclusions.AddRange(excludedChannels
.Select(x => new ExclItemReply()
{
Id = x,
Type = "Channel",
Name = guild.GetChannel(x)?.Name ?? "????"
})
.Concat(excludedRoles
.Select(x => new ExclItemReply()
{
Id = x,
Type = "Role",
Name = guild.GetRole(x)?.Name ?? "????"
})));
var settings = await _xp.GetFullXpSettingsFor(request.GuildId); var settings = await _xp.GetFullXpSettingsFor(request.GuildId);
var curRews = settings.CurrencyRewards; var curRews = settings.CurrencyRewards;
var roleRews = settings.RoleRewards; var roleRews = settings.RoleRewards;
@ -77,8 +60,6 @@ public class XpSvc : GrpcXp.GrpcXpBase, IGrpcSvc, IEService
reply.Rewards.AddRange(rews); reply.Rewards.AddRange(rews);
reply.ServerExcluded = isServerExcluded;
return reply; return reply;
} }

View file

@ -12,7 +12,7 @@ public class Localization : ILocalization, IReadyExecutor, IEService
JsonConvert.DeserializeObject<Dictionary<string, CommandData>>( JsonConvert.DeserializeObject<Dictionary<string, CommandData>>(
File.ReadAllText("./strings/commands/commands.en-US.json")); File.ReadAllText("./strings/commands/commands.en-US.json"));
private ConcurrentDictionary<ulong, CultureInfo> _guildCultureInfos; private ConcurrentDictionary<ulong, CultureInfo> _guildCultureInfos = [];
public IDictionary<ulong, CultureInfo> GuildCultureInfos public IDictionary<ulong, CultureInfo> GuildCultureInfos
=> _guildCultureInfos; => _guildCultureInfos;

View file

@ -6,6 +6,8 @@ using EllieBot.Services.Currency;
using EllieBot.Db.Models; using EllieBot.Db.Models;
using EllieBot.Modules.Gambling; using EllieBot.Modules.Gambling;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using EllieBot.Modules.Administration;
using EllieBot.Modules.Gambling.Services;
namespace EllieBot.Services; namespace EllieBot.Services;
@ -20,10 +22,14 @@ public sealed class GamblingTxTracker : ITxTracker, IEService, IReadyExecutor
private ConcurrentBag<UserBetStats> userStats = new(); private ConcurrentBag<UserBetStats> userStats = new();
private readonly DbService _db; private readonly DbService _db;
private readonly GamblingConfigService _gcs;
private readonly INotifySubscriber _notify;
public GamblingTxTracker(DbService db) public GamblingTxTracker(DbService db, GamblingConfigService gcs, INotifySubscriber notify)
{ {
_db = db; _db = db;
_gcs = gcs;
_notify = notify;
} }
public async Task OnReadyAsync() public async Task OnReadyAsync()
@ -184,6 +190,12 @@ public sealed class GamblingTxTracker : ITxTracker, IEService, IReadyExecutor
if (mType is not { } type) if (mType is not { } type)
return Task.CompletedTask; return Task.CompletedTask;
// var bigWin = _gcs.Data.BigWin;
// if (bigWin > 0 && amount >= bigWin)
// {
// _notify.NotifyAsync<BigWinNotifyModel>(new())
// }
if (txData.Type == "lula") if (txData.Type == "lula")
{ {
if (txData.Extra == "lose") if (txData.Extra == "lose")

View file

@ -21,7 +21,7 @@ dice:
- https://cdn.nadeko.bot/other/dice/8.png - https://cdn.nadeko.bot/other/dice/8.png
- https://cdn.nadeko.bot/other/dice/9.png - https://cdn.nadeko.bot/other/dice/9.png
xp: xp:
bg: https://cdn.nadeko.bot/xp/bgs/v6.png bg: https://cdn.nadeko.bot/other/xp/bg6_mini.png
slots: slots:
emojis: emojis:
- https://cdn.nadeko.bot/slots/10.png - https://cdn.nadeko.bot/slots/10.png

View file

@ -8,21 +8,21 @@
"Name": { "Name": {
"Color": "ffffffff", "Color": "ffffffff",
"Show": true, "Show": true,
"FontSize": 50, "FontSize": 25,
"Pos": { "Pos": {
"X": 105, "X": 65,
"Y": 25 "Y": 8
} }
}, },
"Icon": { "Icon": {
"Show": true, "Show": true,
"Pos": { "Pos": {
"X": 14, "X": 11,
"Y": 14 "Y": 11
}, },
"Size": { "Size": {
"X": 72, "X": 38,
"Y": 71 "Y": 38
} }
}, },
"Level": { "Level": {
@ -47,26 +47,26 @@
"Bar": { "Bar": {
"Show": true, "Show": true,
"Guild": { "Guild": {
"Color": "00000095", "Color": "00000066",
"PointA": { "PointA": {
"X": 282, "X": 202,
"Y": 248 "Y": 66
}, },
"PointB": { "PointB": {
"X": 247, "X": 180,
"Y": 379 "Y": 145
}, },
"Length": 450, "Length": 225,
"Direction": 3 "Direction": 3
} }
}, },
"Guild": { "Guild": {
"Color": "ffffffff", "Color": "ffffffff",
"Show": true, "Show": true,
"FontSize": 50, "FontSize": 25,
"Pos": { "Pos": {
"X": 490, "X": 330,
"Y": 313 "Y": 104
} }
} }
} }
@ -75,21 +75,21 @@
"Icon": { "Icon": {
"Show": true, "Show": true,
"Pos": { "Pos": {
"X": 722, "X": 451,
"Y": 25 "Y": 15
}, },
"Size": { "Size": {
"X": 45, "X": 29,
"Y": 45 "Y": 29
} }
}, },
"Name": { "Name": {
"Color": "ffffffff", "Color": "ffffffff",
"Show": true, "Show": true,
"FontSize": 35, "FontSize": 20,
"Pos": { "Pos": {
"X": 650, "X": 394,
"Y": 55 "Y": 40
} }
} }
} }

View file

@ -1064,7 +1064,6 @@
"patron_insuff_tier": "Your Patron Tier insufficient to perform this action.", "patron_insuff_tier": "Your Patron Tier insufficient to perform this action.",
"xpshop_already_owned": "You already own this item.", "xpshop_already_owned": "You already own this item.",
"xpshop_item_not_found": "An item with that key doesn't exist.", "xpshop_item_not_found": "An item with that key doesn't exist.",
"xpshop_website": "You can see the list of all Xp Shop items here: <https://beta.elliebot.net>",
"sticker_error": "You must either send a sticker along with this command, or upload a 300x300 .png or .apng image. Up to 512KB in size.", "sticker_error": "You must either send a sticker along with this command, or upload a 300x300 .png or .apng image. Up to 512KB in size.",
"sticker_missing_name": "Please specify a name for the sticker.", "sticker_missing_name": "Please specify a name for the sticker.",
"thread_deleted": "Thread Deleted", "thread_deleted": "Thread Deleted",