chore: format with csharpier

This commit is contained in:
sam 2024-10-09 17:35:11 +02:00
parent 2f516dcb73
commit 4f54077c68
59 changed files with 2000 additions and 942 deletions

View file

@ -30,18 +30,17 @@ public class DatabaseContext : DbContext
}.ConnectionString;
var dataSourceBuilder = new NpgsqlDataSourceBuilder(connString);
dataSourceBuilder
.EnableDynamicJson()
.UseNodaTime();
dataSourceBuilder.EnableDynamicJson().UseNodaTime();
_dataSource = dataSourceBuilder.Build();
_loggerFactory = loggerFactory;
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) =>
optionsBuilder
.ConfigureWarnings(c =>
c.Ignore(CoreEventId.ManyServiceProvidersCreatedWarning)
.Ignore(CoreEventId.SaveChangesFailed))
.Ignore(CoreEventId.SaveChangesFailed)
)
.UseNpgsql(_dataSource, o => o.UseNodaTime())
.UseSnakeCaseNamingConvention()
.UseLoggerFactory(_loggerFactory)
@ -53,14 +52,17 @@ public class DatabaseContext : DbContext
configurationBuilder.Properties<List<ulong>>().HaveConversion<UlongArrayValueConverter>();
}
private static readonly ValueComparer<List<ulong>> UlongListValueComparer = new(
(c1, c2) => c1 != null && c2 != null && c1.SequenceEqual(c2),
c => c.Aggregate(0, (a, v) => HashCode.Combine(a, v.GetHashCode()))
);
private static readonly ValueComparer<List<ulong>> UlongListValueComparer =
new(
(c1, c2) => c1 != null && c2 != null && c1.SequenceEqual(c2),
c => c.Aggregate(0, (a, v) => HashCode.Combine(a, v.GetHashCode()))
);
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Guild>().Property(g => g.KeyRoles)
modelBuilder
.Entity<Guild>()
.Property(g => g.KeyRoles)
.Metadata.SetValueComparer(UlongListValueComparer);
modelBuilder.Entity<Invite>().HasKey(i => i.Code);
@ -76,22 +78,25 @@ public class DesignTimeDatabaseContextFactory : IDesignTimeDbContextFactory<Data
public DatabaseContext CreateDbContext(string[] args)
{
// Read the configuration file
var config = new ConfigurationBuilder()
.AddConfiguration()
.Build()
// Get the configuration as our config class
.Get<Config>() ?? new();
var config =
new ConfigurationBuilder()
.AddConfiguration()
.Build()
// Get the configuration as our config class
.Get<Config>() ?? new();
return new DatabaseContext(config, null);
}
}
public class UlongValueConverter() : ValueConverter<ulong, long>(
convertToProviderExpression: x => (long)x,
convertFromProviderExpression: x => (ulong)x
);
public class UlongValueConverter()
: ValueConverter<ulong, long>(
convertToProviderExpression: x => (long)x,
convertFromProviderExpression: x => (ulong)x
);
public class UlongArrayValueConverter() : ValueConverter<List<ulong>, List<long>>(
convertToProviderExpression: x => x.Select(i => (long)i).ToList(),
convertFromProviderExpression: x => x.Select(i => (ulong)i).ToList()
);
public class UlongArrayValueConverter()
: ValueConverter<List<ulong>, List<long>>(
convertToProviderExpression: x => x.Select(i => (long)i).ToList(),
convertFromProviderExpression: x => x.Select(i => (ulong)i).ToList()
);

View file

@ -33,4 +33,4 @@ public class EncryptionService(Config config) : IEncryptionService
return Encoding.UTF8.GetString(plaintext);
}
}
}

View file

@ -4,4 +4,4 @@ public interface IEncryptionService
{
public byte[] Encrypt(string data);
public string Decrypt(byte[] input);
}
}

View file

@ -20,23 +20,22 @@ namespace Catalogger.Backend.Database.Migrations
id = table.Column<long>(type: "bigint", nullable: false),
channels = table.Column<Guild.ChannelConfig>(type: "jsonb", nullable: false),
banned_systems = table.Column<List<string>>(type: "text[]", nullable: false),
key_roles = table.Column<List<long>>(type: "bigint[]", nullable: false)
key_roles = table.Column<List<long>>(type: "bigint[]", nullable: false),
},
constraints: table =>
{
table.PrimaryKey("pk_guilds", x => x.id);
});
}
);
migrationBuilder.CreateTable(
name: "ignored_messages",
columns: table => new
{
id = table.Column<long>(type: "bigint", nullable: false)
},
columns: table => new { id = table.Column<long>(type: "bigint", nullable: false) },
constraints: table =>
{
table.PrimaryKey("pk_ignored_messages", x => x.id);
});
}
);
migrationBuilder.CreateTable(
name: "invites",
@ -44,12 +43,13 @@ namespace Catalogger.Backend.Database.Migrations
{
code = table.Column<string>(type: "text", nullable: false),
guild_id = table.Column<long>(type: "bigint", nullable: false),
name = table.Column<string>(type: "text", nullable: false)
name = table.Column<string>(type: "text", nullable: false),
},
constraints: table =>
{
table.PrimaryKey("pk_invites", x => x.code);
});
}
);
migrationBuilder.CreateTable(
name: "messages",
@ -65,12 +65,13 @@ namespace Catalogger.Backend.Database.Migrations
username = table.Column<byte[]>(type: "bytea", nullable: false),
content = table.Column<byte[]>(type: "bytea", nullable: false),
metadata = table.Column<byte[]>(type: "bytea", nullable: true),
attachment_size = table.Column<int>(type: "integer", nullable: false)
attachment_size = table.Column<int>(type: "integer", nullable: false),
},
constraints: table =>
{
table.PrimaryKey("pk_messages", x => x.id);
});
}
);
migrationBuilder.CreateTable(
name: "watchlists",
@ -78,38 +79,39 @@ namespace Catalogger.Backend.Database.Migrations
{
guild_id = table.Column<long>(type: "bigint", nullable: false),
user_id = table.Column<long>(type: "bigint", nullable: false),
added_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false, defaultValueSql: "now()"),
added_at = table.Column<Instant>(
type: "timestamp with time zone",
nullable: false,
defaultValueSql: "now()"
),
moderator_id = table.Column<long>(type: "bigint", nullable: false),
reason = table.Column<string>(type: "text", nullable: false)
reason = table.Column<string>(type: "text", nullable: false),
},
constraints: table =>
{
table.PrimaryKey("pk_watchlists", x => new { x.guild_id, x.user_id });
});
}
);
migrationBuilder.CreateIndex(
name: "ix_invites_guild_id",
table: "invites",
column: "guild_id");
column: "guild_id"
);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "guilds");
migrationBuilder.DropTable(name: "guilds");
migrationBuilder.DropTable(
name: "ignored_messages");
migrationBuilder.DropTable(name: "ignored_messages");
migrationBuilder.DropTable(
name: "invites");
migrationBuilder.DropTable(name: "invites");
migrationBuilder.DropTable(
name: "messages");
migrationBuilder.DropTable(name: "messages");
migrationBuilder.DropTable(
name: "watchlists");
migrationBuilder.DropTable(name: "watchlists");
}
}
}

View file

@ -9,18 +9,26 @@ public class Guild
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public required ulong Id { get; init; }
[Column(TypeName = "jsonb")] public ChannelConfig Channels { get; init; } = new();
[Column(TypeName = "jsonb")]
public ChannelConfig Channels { get; init; } = new();
public List<string> BannedSystems { get; init; } = [];
public List<ulong> KeyRoles { get; init; } = [];
public bool IsMessageIgnored(Snowflake channelId, Snowflake userId)
{
if (Channels is { MessageDelete: 0, MessageUpdate: 0, MessageDeleteBulk: 0 } ||
Channels.IgnoredChannels.Contains(channelId.ToUlong()) ||
Channels.IgnoredUsers.Contains(userId.ToUlong())) return true;
if (
Channels is { MessageDelete: 0, MessageUpdate: 0, MessageDeleteBulk: 0 }
|| Channels.IgnoredChannels.Contains(channelId.ToUlong())
|| Channels.IgnoredUsers.Contains(userId.ToUlong())
)
return true;
if (Channels.IgnoredUsersPerChannel.TryGetValue(channelId.ToUlong(),
out var thisChannelIgnoredUsers))
if (
Channels.IgnoredUsersPerChannel.TryGetValue(
channelId.ToUlong(),
out var thisChannelIgnoredUsers
)
)
return thisChannelIgnoredUsers.Contains(userId.ToUlong());
return false;
@ -56,4 +64,4 @@ public class Guild
public ulong MessageDelete { get; set; }
public ulong MessageDeleteBulk { get; set; }
}
}
}

View file

@ -5,4 +5,4 @@ public class Invite
public required ulong GuildId { get; init; }
public required string Code { get; init; }
public required string Name { get; set; }
}
}

View file

@ -15,13 +15,16 @@ public class Message
public string? Member { get; set; }
public string? System { get; set; }
[Column("username")] public byte[] EncryptedUsername { get; set; } = [];
[Column("content")] public byte[] EncryptedContent { get; set; } = [];
[Column("metadata")] public byte[]? EncryptedMetadata { get; set; }
[Column("username")]
public byte[] EncryptedUsername { get; set; } = [];
[Column("content")]
public byte[] EncryptedContent { get; set; } = [];
[Column("metadata")]
public byte[]? EncryptedMetadata { get; set; }
public int AttachmentSize { get; set; } = 0;
}
public record IgnoredMessage(
[property: DatabaseGenerated(DatabaseGeneratedOption.None)]
ulong Id);
public record IgnoredMessage([property: DatabaseGenerated(DatabaseGeneratedOption.None)] ulong Id);

View file

@ -10,4 +10,4 @@ public class Watchlist
public required ulong ModeratorId { get; set; }
public required string Reason { get; set; }
}
}

View file

@ -6,7 +6,11 @@ using DbMessage = Catalogger.Backend.Database.Models.Message;
namespace Catalogger.Backend.Database.Queries;
public class MessageRepository(ILogger logger, DatabaseContext db, IEncryptionService encryptionService)
public class MessageRepository(
ILogger logger,
DatabaseContext db,
IEncryptionService encryptionService
)
{
private readonly ILogger _logger = logger.ForContext<MessageRepository>();
@ -14,8 +18,10 @@ public class MessageRepository(ILogger logger, DatabaseContext db, IEncryptionSe
{
_logger.Debug("Saving message {MessageId}", msg.ID);
var metadata = new Metadata(IsWebhook: msg.WebhookID.HasValue,
msg.Attachments.Select(a => new Attachment(a.Filename, a.Size, a.ContentType.Value)));
var metadata = new Metadata(
IsWebhook: msg.WebhookID.HasValue,
msg.Attachments.Select(a => new Attachment(a.Filename, a.Size, a.ContentType.Value))
);
var dbMessage = new DbMessage
{
@ -24,12 +30,22 @@ public class MessageRepository(ILogger logger, DatabaseContext db, IEncryptionSe
ChannelId = msg.ChannelID.ToUlong(),
GuildId = msg.GuildID.ToUlong(),
EncryptedContent =
await Task.Run(
() => encryptionService.Encrypt(string.IsNullOrWhiteSpace(msg.Content) ? "None" : msg.Content), ct),
EncryptedUsername = await Task.Run(() => encryptionService.Encrypt(msg.Author.Tag()), ct),
EncryptedMetadata = await Task.Run(() => encryptionService.Encrypt(JsonSerializer.Serialize(metadata)), ct),
AttachmentSize = msg.Attachments.Select(a => a.Size).Sum()
EncryptedContent = await Task.Run(
() =>
encryptionService.Encrypt(
string.IsNullOrWhiteSpace(msg.Content) ? "None" : msg.Content
),
ct
),
EncryptedUsername = await Task.Run(
() => encryptionService.Encrypt(msg.Author.Tag()),
ct
),
EncryptedMetadata = await Task.Run(
() => encryptionService.Encrypt(JsonSerializer.Serialize(metadata)),
ct
),
AttachmentSize = msg.Attachments.Select(a => a.Size).Sum(),
};
db.Add(dbMessage);
@ -56,17 +72,32 @@ public class MessageRepository(ILogger logger, DatabaseContext db, IEncryptionSe
}
else
{
var metadata = new Metadata(IsWebhook: msg.WebhookID.HasValue,
msg.Attachments.Select(a => new Attachment(a.Filename, a.Size, a.ContentType.Value)));
var metadata = new Metadata(
IsWebhook: msg.WebhookID.HasValue,
msg.Attachments.Select(a => new Attachment(a.Filename, a.Size, a.ContentType.Value))
);
var dbMsg = await db.Messages.FindAsync(msg.ID.Value);
if (dbMsg == null) throw new CataloggerError("Message was null despite HasProxyInfoAsync returning true");
if (dbMsg == null)
throw new CataloggerError(
"Message was null despite HasProxyInfoAsync returning true"
);
dbMsg.EncryptedContent = await Task.Run(
() => encryptionService.Encrypt(string.IsNullOrWhiteSpace(msg.Content) ? "None" : msg.Content), ct);
dbMsg.EncryptedUsername = await Task.Run(() => encryptionService.Encrypt(msg.Author.Tag()), ct);
dbMsg.EncryptedMetadata =
await Task.Run(() => encryptionService.Encrypt(JsonSerializer.Serialize(metadata)), ct);
() =>
encryptionService.Encrypt(
string.IsNullOrWhiteSpace(msg.Content) ? "None" : msg.Content
),
ct
);
dbMsg.EncryptedUsername = await Task.Run(
() => encryptionService.Encrypt(msg.Author.Tag()),
ct
);
dbMsg.EncryptedMetadata = await Task.Run(
() => encryptionService.Encrypt(JsonSerializer.Serialize(metadata)),
ct
);
db.Update(dbMsg);
await db.SaveChangesAsync(ct);
@ -80,17 +111,26 @@ public class MessageRepository(ILogger logger, DatabaseContext db, IEncryptionSe
_logger.Debug("Retrieving message {MessageId}", id);
var dbMsg = await db.Messages.FindAsync(id);
if (dbMsg == null) return null;
if (dbMsg == null)
return null;
return new Message(dbMsg.Id, dbMsg.OriginalId, dbMsg.UserId, dbMsg.ChannelId, dbMsg.GuildId, dbMsg.Member,
return new Message(
dbMsg.Id,
dbMsg.OriginalId,
dbMsg.UserId,
dbMsg.ChannelId,
dbMsg.GuildId,
dbMsg.Member,
dbMsg.System,
Username: await Task.Run(() => encryptionService.Decrypt(dbMsg.EncryptedUsername), ct),
Content: await Task.Run(() => encryptionService.Decrypt(dbMsg.EncryptedContent), ct),
Metadata: dbMsg.EncryptedMetadata != null
? JsonSerializer.Deserialize<Metadata>(
await Task.Run(() => encryptionService.Decrypt(dbMsg.EncryptedMetadata), ct))
await Task.Run(() => encryptionService.Decrypt(dbMsg.EncryptedMetadata), ct)
)
: null,
dbMsg.AttachmentSize);
dbMsg.AttachmentSize
);
}
/// <summary>
@ -101,12 +141,19 @@ public class MessageRepository(ILogger logger, DatabaseContext db, IEncryptionSe
{
_logger.Debug("Checking if message {MessageId} has proxy information", id);
var msg = await db.Messages.Select(m => new { m.Id, m.OriginalId }).FirstOrDefaultAsync(m => m.Id == id);
var msg = await db
.Messages.Select(m => new { m.Id, m.OriginalId })
.FirstOrDefaultAsync(m => m.Id == id);
return (msg != null, msg?.OriginalId != null);
}
public async Task SetProxiedMessageDataAsync(ulong id, ulong originalId, ulong authorId, string? systemId,
string? memberId)
public async Task SetProxiedMessageDataAsync(
ulong id,
ulong originalId,
ulong authorId,
string? systemId,
string? memberId
)
{
_logger.Debug("Setting proxy information for message {MessageId}", id);
@ -151,4 +198,4 @@ public class MessageRepository(ILogger logger, DatabaseContext db, IEncryptionSe
public record Metadata(bool IsWebhook, IEnumerable<Attachment> Attachments);
public record Attachment(string Filename, int Size, string ContentType);
}
}

View file

@ -6,21 +6,34 @@ namespace Catalogger.Backend.Database.Queries;
public static class QueryExtensions
{
public static async ValueTask<Guild> GetGuildAsync(this DatabaseContext db, Snowflake id,
CancellationToken ct = default) => await db.GetGuildAsync(id.ToUlong(), ct);
public static async ValueTask<Guild> GetGuildAsync(
this DatabaseContext db,
Snowflake id,
CancellationToken ct = default
) => await db.GetGuildAsync(id.ToUlong(), ct);
public static async ValueTask<Guild> GetGuildAsync(this DatabaseContext db, Optional<Snowflake> id,
CancellationToken ct = default) => await db.GetGuildAsync(id.ToUlong(), ct);
public static async ValueTask<Guild> GetGuildAsync(
this DatabaseContext db,
Optional<Snowflake> id,
CancellationToken ct = default
) => await db.GetGuildAsync(id.ToUlong(), ct);
public static async ValueTask<Guild> GetGuildAsync(this DatabaseContext db, ulong id,
CancellationToken ct = default)
public static async ValueTask<Guild> GetGuildAsync(
this DatabaseContext db,
ulong id,
CancellationToken ct = default
)
{
var guild = await db.Guilds.FindAsync([id], ct);
if (guild == null) throw new CataloggerError("Guild not found, was not initialized during guild create");
if (guild == null)
throw new CataloggerError("Guild not found, was not initialized during guild create");
return guild;
}
public static async Task<Watchlist?> GetWatchlistEntryAsync(this DatabaseContext db, Snowflake guildId,
Snowflake userId, CancellationToken ct = default) =>
await db.Watchlists.FindAsync([guildId.Value, userId.Value], ct);
}
public static async Task<Watchlist?> GetWatchlistEntryAsync(
this DatabaseContext db,
Snowflake guildId,
Snowflake userId,
CancellationToken ct = default
) => await db.Watchlists.FindAsync([guildId.Value, userId.Value], ct);
}

View file

@ -5,12 +5,12 @@ namespace Catalogger.Backend.Database.Redis;
public class RedisService(Config config)
{
private readonly ConnectionMultiplexer _multiplexer = ConnectionMultiplexer.Connect(config.Database.Redis!);
private readonly ConnectionMultiplexer _multiplexer = ConnectionMultiplexer.Connect(
config.Database.Redis!
);
private readonly JsonSerializerOptions _options = new()
{
PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower
};
private readonly JsonSerializerOptions _options =
new() { PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower };
public IDatabase GetDatabase(int db = -1) => _multiplexer.GetDatabase(db);
@ -32,10 +32,18 @@ public class RedisService(Config config)
await GetDatabase().HashSetAsync(hashKey, fieldKey, json);
}
public async Task SetHashAsync<T>(string hashKey, IEnumerable<T> values, Func<T, string> keySelector)
public async Task SetHashAsync<T>(
string hashKey,
IEnumerable<T> values,
Func<T, string> keySelector
)
{
var hashEntries = values
.Select(v => new { Key = keySelector(v), Value = JsonSerializer.Serialize(v, _options) })
.Select(v => new
{
Key = keySelector(v),
Value = JsonSerializer.Serialize(v, _options),
})
.Select(v => new HashEntry(v.Key, v.Value));
await GetDatabase().HashSetAsync(hashKey, hashEntries.ToArray());
}
@ -45,4 +53,4 @@ public class RedisService(Config config)
var value = await GetDatabase().HashGetAsync(hashKey, fieldKey);
return value.IsNull ? default : JsonSerializer.Deserialize<T>(value!, _options);
}
}
}