Skip to content

Commit 35f969b

Browse files
committed
Add nocase collation to SQLite User Name/Email, Player Name, Guild Name, log duplicates
1 parent d65efa4 commit 35f969b

File tree

5 files changed

+1125
-4
lines changed

5 files changed

+1125
-4
lines changed

Intersect.Server.Core/Database/DbInterface.cs

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -423,9 +423,75 @@ internal static bool InitDatabase(IServerContext serverContext)
423423
CacheGuildVariableEventTextLookups();
424424
CacheUserVariableEventTextLookups();
425425

426+
CheckPlayerDatabaseCaseInsensitiveCollisions();
427+
426428
return true;
427429
}
428430

431+
private static void CheckPlayerDatabaseCaseInsensitiveCollisions()
432+
{
433+
using var playerContext = CreatePlayerContext();
434+
var conflictingUsersByName =
435+
(from u1 in playerContext.Users
436+
join u2 in playerContext.Users on u1.Name equals u2.Name
437+
where u1.Id != u2.Id
438+
select u1).Distinct()
439+
.ToArray();
440+
if (conflictingUsersByName.Length > 0)
441+
{
442+
ApplicationContext.CurrentContext.Logger.LogError(
443+
"There are {Count} users with conflicting names (they only differ by case):\nThis needs to be resolved but cannot be handled automatically!\n{Users}",
444+
conflictingUsersByName.Length,
445+
string.Join('\n', conflictingUsersByName.Select(u => $"\t{u.Id}"))
446+
);
447+
}
448+
449+
var conflictingUsersByEmail =
450+
(from u1 in playerContext.Users
451+
join u2 in playerContext.Users on u1.Email equals u2.Email
452+
where u1.Id != u2.Id
453+
select u1).Distinct()
454+
.ToArray();
455+
if (conflictingUsersByEmail.Length > 0)
456+
{
457+
ApplicationContext.CurrentContext.Logger.LogError(
458+
"There are {Count} users with conflicting emails (they only differ by case):\nThis needs to be resolved but cannot be handled automatically!\n{Users}",
459+
conflictingUsersByEmail.Length,
460+
string.Join('\n', conflictingUsersByName.Select(u => $"\t{u.Id}"))
461+
);
462+
}
463+
464+
var conflictingPlayersByName =
465+
(from p1 in playerContext.Players
466+
join p2 in playerContext.Players on p1.Name equals p2.Name
467+
where p1.Id != p2.Id
468+
select p1).Distinct()
469+
.ToArray();
470+
if (conflictingPlayersByName.Length > 0)
471+
{
472+
ApplicationContext.CurrentContext.Logger.LogError(
473+
"There are {Count} players with conflicting names (they only differ by case):\nThis needs to be resolved but cannot be handled automatically!\n{Players}",
474+
conflictingPlayersByName.Length,
475+
string.Join('\n', conflictingPlayersByName.Select(p => $"\t{p.Id}"))
476+
);
477+
}
478+
479+
var conflictingGuildsByName =
480+
(from g1 in playerContext.Guilds
481+
join g2 in playerContext.Guilds on g1.Name equals g2.Name
482+
where g1.Id != g2.Id
483+
select g1).Distinct()
484+
.ToArray();
485+
if (conflictingGuildsByName.Length > 0)
486+
{
487+
ApplicationContext.CurrentContext.Logger.LogError(
488+
"There are {Count} guilds with conflicting names (they only differ by case):\nThis needs to be resolved but cannot be handled automatically!\n{Guilds}",
489+
conflictingGuildsByName.Length,
490+
string.Join('\n', conflictingGuildsByName.Select(g => $"\t{g.Id}"))
491+
);
492+
}
493+
}
494+
429495
public static void SetPlayerPower(string username, UserRights power)
430496
{
431497
var user = User.Find(username);

Intersect.Server.Core/Database/PlayerData/SqlitePlayerContext.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
using Intersect.Config;
2+
using Intersect.Server.Database.PlayerData.Players;
3+
using Intersect.Server.Entities;
4+
using Microsoft.EntityFrameworkCore;
25

36
namespace Intersect.Server.Database.PlayerData;
47

@@ -11,4 +14,14 @@ public sealed class SqlitePlayerContext : PlayerContext, ISqliteDbContext
1114
public SqlitePlayerContext(DatabaseContextOptions databaseContextOptions) : base(databaseContextOptions) { }
1215

1316
public override DatabaseType DatabaseType => DatabaseType.Sqlite;
17+
18+
protected override void OnModelCreating(ModelBuilder modelBuilder)
19+
{
20+
base.OnModelCreating(modelBuilder);
21+
22+
modelBuilder.Entity<User>().Property(u => u.Name).UseCollation("NOCASE");
23+
modelBuilder.Entity<User>().Property(u => u.Email).UseCollation("NOCASE");
24+
modelBuilder.Entity<Player>().Property(u => u.Name).UseCollation("NOCASE");
25+
modelBuilder.Entity<Guild>().Property(u => u.Name).UseCollation("NOCASE");
26+
}
1427
}

0 commit comments

Comments
 (0)