Skip to content

Commit 89395f7

Browse files
authored
Merge pull request #24 from ZenonEl/refactor/json-settings
feat(settings): add typed UserSettings JSON model and repository
2 parents dbc7bd6 + 19aa920 commit 89395f7

6 files changed

Lines changed: 173 additions & 1 deletion

File tree

Database/BaseDBMigration.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ private void CreateCommonTables()
3434
.WithColumn("TelegramID").AsInt64().NotNullable()
3535
.WithColumn("Name").AsString(255).NotNullable()
3636
.WithColumn("Link").AsString(255).NotNullable()
37-
.WithColumn("Status").AsString(255).Nullable();
37+
.WithColumn("Status").AsString(255).Nullable()
38+
.WithColumn("SettingsJson").AsString(int.MaxValue).NotNullable().WithDefaultValue("{}");
3839
}
3940

4041
// Contacts

Database/DBInit.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ public static WebApplicationBuilder CreateBuilderByDBType(string[] args)
6363
new SqliteUserRepository(Config.sqlConnectionString!));
6464
builder.Services.AddSingleton<IUserGetter>(_ =>
6565
new SqliteUserGetter(Config.sqlConnectionString!));
66+
builder.Services.AddSingleton<IUserSettingsRepository>(_ =>
67+
new SqliteUserSettingsRepository(Config.sqlConnectionString!));
6668

6769
builder.Services.AddSingleton<IContactGroupRepository>(_ =>
6870
new SqliteContactGroupRepository(Config.sqlConnectionString!));
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright (C) 2024-2025 ZenonEl
2+
// This program is free software: you can redistribute it and/or modify
3+
// it under the terms of the GNU Affero General Public License as published
4+
// by the Free Software Foundation, either version 3 of the License, or
5+
// (at your option) any later version.
6+
7+
// Эта программа является свободным программным обеспечением: вы можете распространять и/или изменять
8+
// её на условиях Стандартной общественной лицензии GNU Affero, опубликованной
9+
// Фондом свободного программного обеспечения, либо версии 3 лицензии, либо
10+
// (по вашему выбору) любой более поздней версии.
11+
12+
using TelegramMediaRelayBot.Domain.Models;
13+
14+
namespace TelegramMediaRelayBot.Database.Interfaces;
15+
16+
public interface IUserSettingsRepository
17+
{
18+
Task<UserSettings> GetSettingsAsync(int userId);
19+
Task<bool> SaveSettingsAsync(int userId, UserSettings settings);
20+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Copyright (C) 2024-2025 ZenonEl
2+
// This program is free software: you can redistribute it and/or modify
3+
// it under the terms of the GNU Affero General Public License as published
4+
// by the Free Software Foundation, either version 3 of the License, or
5+
// (at your option) any later version.
6+
7+
// Эта программа является свободным программным обеспечением: вы можете распространять и/или изменять
8+
// её на условиях Стандартной общественной лицензии GNU Affero, опубликованной
9+
// Фондом свободного программного обеспечения, либо версии 3 лицензии, либо
10+
// (по вашему выбору) любой более поздней версии.
11+
12+
using FluentMigrator;
13+
14+
namespace TelegramMediaRelayBot.Database.Migrations;
15+
16+
[Migration(20260328)]
17+
public class AddSettingsJsonColumn : Migration
18+
{
19+
public override void Up()
20+
{
21+
if (!Schema.Table("Users").Column("SettingsJson").Exists())
22+
{
23+
Alter.Table("Users")
24+
.AddColumn("SettingsJson").AsString(int.MaxValue).NotNullable().WithDefaultValue("{}");
25+
}
26+
}
27+
28+
public override void Down()
29+
{
30+
Delete.Column("SettingsJson").FromTable("Users");
31+
}
32+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// Copyright (C) 2024-2025 ZenonEl
2+
// This program is free software: you can redistribute it and/or modify
3+
// it under the terms of the GNU Affero General Public License as published
4+
// by the Free Software Foundation, either version 3 of the License, or
5+
// (at your option) any later version.
6+
7+
// Эта программа является свободным программным обеспечением: вы можете распространять и/или изменять
8+
// её на условиях Стандартной общественной лицензии GNU Affero, опубликованной
9+
// Фондом свободного программного обеспечения, либо версии 3 лицензии, либо
10+
// (по вашему выбору) любой более поздней версии.
11+
12+
using Dapper;
13+
using Microsoft.Data.Sqlite;
14+
using TelegramMediaRelayBot.Database.Interfaces;
15+
using TelegramMediaRelayBot.Domain.Models;
16+
17+
namespace TelegramMediaRelayBot.Database.Repositories.Sqlite;
18+
19+
public class SqliteUserSettingsRepository(string connectionString) : IUserSettingsRepository
20+
{
21+
private readonly string _connectionString = connectionString;
22+
23+
public async Task<UserSettings> GetSettingsAsync(int userId)
24+
{
25+
const string query = "SELECT SettingsJson FROM Users WHERE ID = @userId";
26+
27+
try
28+
{
29+
using var connection = new SqliteConnection(_connectionString);
30+
var json = await connection.ExecuteScalarAsync<string>(query, new { userId });
31+
return UserSettings.FromJson(json ?? "{}");
32+
}
33+
catch (Exception ex)
34+
{
35+
Log.Error(ex, "Failed to get settings for user {UserId}", userId);
36+
return new UserSettings();
37+
}
38+
}
39+
40+
public async Task<bool> SaveSettingsAsync(int userId, UserSettings settings)
41+
{
42+
const string query = "UPDATE Users SET SettingsJson = @json WHERE ID = @userId";
43+
44+
try
45+
{
46+
var json = settings.ToJson();
47+
using var connection = new SqliteConnection(_connectionString);
48+
var affected = await connection.ExecuteAsync(query, new { json, userId });
49+
return affected > 0;
50+
}
51+
catch (Exception ex)
52+
{
53+
Log.Error(ex, "Failed to save settings for user {UserId}", userId);
54+
return false;
55+
}
56+
}
57+
}

Domain/Models/UserSettings.cs

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
// Copyright (C) 2024-2025 ZenonEl
2+
// This program is free software: you can redistribute it and/or modify
3+
// it under the terms of the GNU Affero General Public License as published
4+
// by the Free Software Foundation, either version 3 of the License, or
5+
// (at your option) any later version.
6+
7+
// Эта программа является свободным программным обеспечением: вы можете распространять и/или изменять
8+
// её на условиях Стандартной общественной лицензии GNU Affero, опубликованной
9+
// Фондом свободного программного обеспечения, либо версии 3 лицензии, либо
10+
// (по вашему выбору) любой более поздней версии.
11+
12+
using System.Text.Json;
13+
using System.Text.Json.Serialization;
14+
15+
namespace TelegramMediaRelayBot.Domain.Models;
16+
17+
public sealed class UserSettings
18+
{
19+
public DistributionSettings Distribution { get; set; } = new();
20+
public PrivacyUserSettings Privacy { get; set; } = new();
21+
22+
private static readonly JsonSerializerOptions JsonOptions = new()
23+
{
24+
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
25+
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault
26+
};
27+
28+
public string ToJson() => JsonSerializer.Serialize(this, JsonOptions);
29+
30+
public static UserSettings FromJson(string json)
31+
{
32+
if (string.IsNullOrWhiteSpace(json)) return new();
33+
try { return JsonSerializer.Deserialize<UserSettings>(json, JsonOptions) ?? new(); }
34+
catch { return new(); }
35+
}
36+
}
37+
38+
public sealed class DistributionSettings
39+
{
40+
public string DefaultAction { get; set; } = "send_only_to_me";
41+
public string DefaultActionCondition { get; set; } = "";
42+
public int AutoSendDelaySeconds { get; set; } = 30;
43+
public List<int> TargetGroupIds { get; set; } = [];
44+
public List<int> TargetContactIds { get; set; } = [];
45+
}
46+
47+
public sealed class PrivacyUserSettings
48+
{
49+
public bool InboxEnabled { get; set; } = false;
50+
public bool AllowContentForwarding { get; set; } = true;
51+
public string WhoCanFindMe { get; set; } = "everyone";
52+
public SiteFilterSettings SiteFilter { get; set; } = new();
53+
}
54+
55+
public sealed class SiteFilterSettings
56+
{
57+
public bool Enabled { get; set; } = false;
58+
public string FilterType { get; set; } = "none";
59+
public List<string> BlockedDomains { get; set; } = [];
60+
}

0 commit comments

Comments
 (0)