Initial commit.

This commit is contained in:
2025-12-11 10:20:10 +09:00
commit 057481803f
21 changed files with 1327 additions and 0 deletions

10
Data/Entities/Config.cs Normal file
View File

@@ -0,0 +1,10 @@
using System.ComponentModel.DataAnnotations;
namespace TriliumMind.Data.Entities;
public class Config
{
[Key]
public string Key { get; set; } = null!;
public string Value { get; set; } = null!;
}

View File

@@ -0,0 +1,20 @@
using System.ComponentModel.DataAnnotations;
namespace TriliumMind.Data.Entities;
public class JiraIssue
{
[Key]
public string Key { get; set; } = null!;
public string Summary { get; set; } = null!;
public string? Parent { get; set; }
public string Type { get; set; } = null!;
public string Status { get; set; } = null!;
public string Assignee { get; set; } = null!;
public string Manager { get; set; } = null!;
public DateTimeOffset Due { get; set; }
public DateTimeOffset Updated { get; set; }
public DateTimeOffset Published { get; set; }
public string? ObjectId { get; set; }
public int NeedNotify { get; set; }
}

13
Data/IAppDbContext.cs Normal file
View File

@@ -0,0 +1,13 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using TriliumMind.Data.Entities;
namespace TriliumMind.Data;
public interface IAppDbContext : IDisposable
{
DbSet<Config> Configs { get; set; }
DbSet<JiraIssue> JiraIssues { get; set; }
DatabaseFacade Database { get; }
Task<int> SaveChangesAsync(CancellationToken cancellationToken = default);
}

87
Data/PostgresDbContext.cs Normal file
View File

@@ -0,0 +1,87 @@
using Microsoft.EntityFrameworkCore;
using Serilog;
using TriliumMind.Data.Entities;
using TriliumMind.Models;
namespace TriliumMind.Data;
public class PostgresDbContext : DbContext, IAppDbContext
{
private readonly Serilog.ILogger _log;
private readonly string _connectionString;
public DbSet<Config> Configs { get; set; }
public DbSet<JiraIssue> JiraIssues { get; set; }
public PostgresDbContext(AppConfigs configs)
{
_log = Log.ForContext<PostgresDbContext>();
var pgConfig = configs.AppSettings.Database.Postgres;
var connectionStringBuilder = new Npgsql.NpgsqlConnectionStringBuilder
{
Host = pgConfig.Host,
Port = pgConfig.Port,
Database = pgConfig.Database,
Username = pgConfig.Username,
Password = pgConfig.Password
};
// Set SSL/TLS
if (!string.IsNullOrEmpty(pgConfig.SslCertificatePath))
{
var certPath = Path.IsPathRooted(pgConfig.SslCertificatePath)
? pgConfig.SslCertificatePath
: Path.Combine(AppContext.BaseDirectory, pgConfig.SslCertificatePath);
if (File.Exists(certPath))
{
_log.Information("Configuring PostgreSQL with SSL certificate: {CertPath}", certPath);
connectionStringBuilder.SslMode = Npgsql.SslMode.VerifyFull;
connectionStringBuilder.RootCertificate = certPath;
}
else
{
_log.Warning("SSL certificate not found at {CertPath}, connecting without SSL", certPath);
connectionStringBuilder.SslMode = Npgsql.SslMode.Prefer;
}
}
else
{
_log.Information("No SSL certificate configured, connecting without SSL");
connectionStringBuilder.SslMode = Npgsql.SslMode.Prefer;
}
_connectionString = connectionStringBuilder.ConnectionString;
_log.Debug("PostgreSQL connection string configured (password hidden)");
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder.UseNpgsql(_connectionString);
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Config>(entity =>
{
entity.HasKey(e => e.Key);
entity.Property(e => e.Key).IsRequired();
entity.Property(e => e.Value).IsRequired();
});
modelBuilder.Entity<JiraIssue>(entity =>
{
entity.HasKey(e => e.Key);
entity.Property(e => e.Key).IsRequired();
entity.Property(e => e.Summary).IsRequired();
entity.Property(e => e.Type).IsRequired();
entity.Property(e => e.Status).IsRequired();
entity.Property(e => e.Assignee).IsRequired();
entity.Property(e => e.Manager).IsRequired();
entity.Property(e => e.Due).IsRequired();
entity.Property(e => e.Updated).IsRequired();
entity.Property(e => e.Published).IsRequired();
entity.Property(e => e.NeedNotify).IsRequired();
});
}
}

62
Data/SqliteDbContext.cs Normal file
View File

@@ -0,0 +1,62 @@
using Microsoft.EntityFrameworkCore;
using TriliumMind.Data.Entities;
using TriliumMind.Models;
namespace TriliumMind.Data;
public class SqliteDbContext : DbContext, IAppDbContext
{
private readonly string _dbFilePath;
public DbSet<Config> Configs { get; set; }
public DbSet<JiraIssue> JiraIssues { get; set; }
public SqliteDbContext(AppConfigs configs)
{
var dbPath = configs.AppSettings.Database.Sqlite.DatabaseFilePath;
if (Path.IsPathRooted(dbPath) && File.Exists(dbPath))
{
_dbFilePath = dbPath;
}
else if (Path.IsPathRooted(dbPath))
{
_dbFilePath = dbPath;
}
else
{
var basePath = AppContext.BaseDirectory;
_dbFilePath = Path.Combine(basePath, dbPath);
}
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder.UseSqlite($"Data Source={_dbFilePath}");
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Config>(entity =>
{
entity.HasKey(e => e.Key);
entity.Property(e => e.Key).IsRequired();
entity.Property(e => e.Value).IsRequired();
});
modelBuilder.Entity<JiraIssue>(entity =>
{
entity.HasKey(e => e.Key);
entity.Property(e => e.Key).IsRequired();
entity.Property(e => e.Summary).IsRequired();
entity.Property(e => e.Type).IsRequired();
entity.Property(e => e.Status).IsRequired();
entity.Property(e => e.Assignee).IsRequired();
entity.Property(e => e.Manager).IsRequired();
entity.Property(e => e.Due).IsRequired();
entity.Property(e => e.Updated).IsRequired();
entity.Property(e => e.Published).IsRequired();
entity.Property(e => e.NeedNotify).IsRequired();
});
}
}