diff options
| -rw-r--r-- | Controllers/MediaController.cs | 2 | ||||
| -rw-r--r-- | HBContext.cs | 10 | ||||
| -rw-r--r-- | Media.cs | 2 | ||||
| -rw-r--r-- | Pages/TagDefinitions.razor | 8 | ||||
| -rw-r--r-- | Server.csproj | 2 | ||||
| -rw-r--r-- | Services/ConfigService.cs | 10 | ||||
| -rw-r--r-- | Services/TagService.cs | 35 | ||||
| -rw-r--r-- | Tag.cs | 10 | ||||
| -rw-r--r-- | appsettings.json | 3 |
9 files changed, 44 insertions, 38 deletions
diff --git a/Controllers/MediaController.cs b/Controllers/MediaController.cs index 3f36064..3fd716e 100644 --- a/Controllers/MediaController.cs +++ b/Controllers/MediaController.cs @@ -119,7 +119,7 @@ public class MediaController : Controller { var fileRecord = new UploadedFile() { Filename = formFile.FileName, OriginalChecksum = hash, - UploadTime = DateTime.Now, + UploadTime = DateTime.UtcNow, LastAccessTime = lastAccessTime, LastWriteTime = lastWriteTime, CreateTime = createTime diff --git a/HBContext.cs b/HBContext.cs index 162a2c7..04f2d1a 100644 --- a/HBContext.cs +++ b/HBContext.cs @@ -1,6 +1,5 @@ using Microsoft.EntityFrameworkCore; using HyperBooru.Services; -using Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage; namespace HyperBooru; @@ -18,9 +17,7 @@ public class HBContext : DbContext { protected override void OnConfiguring(DbContextOptionsBuilder options) { options.UseLazyLoadingProxies(); - - var path = Path.Join(config.DataPath, "HyperBooru.db"); - options.UseSqlite($"Data Source = {config.DbPath}"); + options.UseNpgsql(config.DbConnectionString); #if DEBUG options.EnableSensitiveDataLogging(); @@ -28,17 +25,22 @@ public class HBContext : DbContext { } protected override void OnModelCreating(ModelBuilder modelBuilder) { + // Don't use shared tables for inherited types modelBuilder.Entity<HBObject>().ToTable("Objects"); modelBuilder.Entity<TagDefinition>().ToTable("TagDefinitions"); modelBuilder.Entity<Tag>().ToTable("Tags"); modelBuilder.Entity<Media>().ToTable("Media"); modelBuilder.Entity<UploadedFile>().ToTable("UploadedFiles"); + // Seed internal tag definitions + // These should NEVER change modelBuilder.Entity<TagDefinition>().HasData(new TagDefinition[] { new() { ObjectId = -1, Source = TagSource.Internal, Name = "nsfw" }, new() { ObjectId = -2, Source = TagSource.Internal, Name = "ingest" } }); + // Implicit tags need some special attention to make many<->many + // navigations work for the same object type. modelBuilder.Entity<TagDefinition>() .HasMany(e => e.ImplicitTags) .WithMany(); @@ -35,7 +35,7 @@ public record UploadedFile { public int UploadedFileId { get; set; } public string OriginalChecksum { get; set; } public string? Filename { get; set; } - public DateTime UploadTime { get; set; } = DateTime.Now; + public DateTime UploadTime { get; set; } = DateTime.UtcNow; public DateTime? LastAccessTime { get; set; } public DateTime? LastWriteTime { get; set; } public DateTime? CreateTime { get; set; } diff --git a/Pages/TagDefinitions.razor b/Pages/TagDefinitions.razor index 75e93f9..cb0a17c 100644 --- a/Pages/TagDefinitions.razor +++ b/Pages/TagDefinitions.razor @@ -73,11 +73,12 @@ private TagDefinition? toDelete; private TagDefinition? toEditImplicit; - private IEnumerable<TagDefinition> tagDefinitions => + private TagDefinition[] tagDefinitions => dbFactory.CreateDbContext().TagDefinitions .Where(td => td.Source == TagSource.UserTag) .OrderBy(td => td.Namespace) - .ThenBy(td => td.Name); + .ThenBy(td => td.Name) + .ToArray(); private void CreateTagDefinition() { if(string.IsNullOrEmpty(tagNamespace)) @@ -112,8 +113,7 @@ if(toEditImplicit is null) return; - foreach(var tagDef in tagDefs) - tagService.AddImplicitTag(toEditImplicit, tagDef); + tagService.SetImplicitTags(toEditImplicit, tagDefs); StateHasChanged(); } } diff --git a/Server.csproj b/Server.csproj index 10953e6..9c65f5c 100644 --- a/Server.csproj +++ b/Server.csproj @@ -27,8 +27,8 @@ <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> </PackageReference> <PackageReference Include="Microsoft.EntityFrameworkCore.Proxies" Version="7.0.10" /> - <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="7.0.10" /> <PackageReference Include="Mime-Detective" Version="23.6.1" /> + <PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="7.0.4" /> <PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" /> </ItemGroup> diff --git a/Services/ConfigService.cs b/Services/ConfigService.cs index 6ba3936..814a47b 100644 --- a/Services/ConfigService.cs +++ b/Services/ConfigService.cs @@ -1,9 +1,9 @@ namespace HyperBooru.Services; public interface IConfigService { - public string DataPath { get; } - public string DbPath { get; } - public string MediaBasePath { get; } + public string DataPath { get; } + public string DbConnectionString { get; } + public string MediaBasePath { get; } public string GetPath(Media media); public string GetPath(Media media, int width, int height); @@ -38,8 +38,8 @@ public class ConfigService : IConfigService { } } - public string DbPath => - Path.Join(DataPath, $"{AppName}.db"); + public string DbConnectionString => + config.GetConnectionString("DefaultConnection"); public string MediaBasePath => Path.Join(DataPath, "media"); diff --git a/Services/TagService.cs b/Services/TagService.cs index da2bb2d..c3b8e14 100644 --- a/Services/TagService.cs +++ b/Services/TagService.cs @@ -1,6 +1,8 @@ using Microsoft.AspNetCore.Components.Web; using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Razor.TagHelpers; using Microsoft.EntityFrameworkCore; +using System.Reflection.Metadata; namespace HyperBooru.Services; @@ -9,8 +11,8 @@ public interface ITagService { public void AddTag(HBObject obj, TagDefinition tagDef); public void RemoveTag(Guid obj, Guid tagDef); public void RemoveTag(HBObject obj, TagDefinition tagDef); - public void AddImplicitTag(TagDefinition tagDef, TagDefinition implicitTagDef); - public void RemoveImplicitTag(TagDefinition tagDef, TagDefinition implicitTagDef); + public void SetImplicitTags(TagDefinition tagDef, TagDefinition[] implicitTagDefs); + public void SetImplicitTags(Guid tagDef, Guid[] implicitTagDefs); public void CreateTagDefinition(string name, string? @namespace); public void DeleteTagDefinition(TagDefinition tagDef); public (TagDefinition tagDefinition, bool isImplicit)[] GetAllTags(Guid obj); @@ -52,28 +54,27 @@ public class TagService : ITagService { public void RemoveTag(HBObject obj, TagDefinition tagDef) => RemoveTag(obj.Guid, tagDef.Guid); - public void AddImplicitTag(TagDefinition tagDef, TagDefinition implicitTagDef) { + public void SetImplicitTags(Guid tagDef, Guid[] implicitTagDefs) { using var db = dbFactory.CreateDbContext(); - db.Entry(tagDef).State = EntityState.Unchanged; - - if(tagDef.ImplicitTags.Select(td => td.Guid).Contains(implicitTagDef.Guid)) - throw new ArgumentException("Tag definition already contains implicit tag"); - - tagDef.ImplicitTags.Add(implicitTagDef); - db.SaveChanges(); - } + using var transaction = db.Database.BeginTransaction(); - public void RemoveImplicitTag(TagDefinition tagDef, TagDefinition implicitTagDef) { - using var db = dbFactory.CreateDbContext(); - db.Entry(tagDef).State = EntityState.Unchanged; + var tag = db.TagDefinitions.First(td => td.Guid == tagDef); - if(!tagDef.ImplicitTags.Select(td => td.Guid).Contains(implicitTagDef.Guid)) - throw new ArgumentException("Tag definition doesn't contain implicit tag"); + tag.ImplicitTags.RemoveAll(td => !implicitTagDefs.Contains(td.Guid)); + tag.ImplicitTags.AddRange( + db.TagDefinitions + .Where(td => implicitTagDefs.Contains(td.Guid)) + .Where(td => !tag.ImplicitTags + .Select(td => td.Guid) + .Contains(td.Guid))); - tagDef.ImplicitTags.Remove(implicitTagDef); db.SaveChanges(); + transaction.Commit(); } + public void SetImplicitTags(TagDefinition tagDef, TagDefinition[] implicitTagDefs) => + SetImplicitTags(tagDef.Guid, implicitTagDefs.Select(td => td.Guid).ToArray()); + public void CreateTagDefinition(string name, string? @namespace) { using var db = dbFactory.CreateDbContext(); @@ -10,15 +10,15 @@ public enum TagSource { } public class TagDefinition : HBObject { - public TagSource Source { get; set; } = TagSource.Internal; - public string? Namespace { get; set; } - public string Name { get; set; } - public virtual List<TagDefinition> ImplicitTags { get; set; } = new(); + public TagSource Source { get; set; } = TagSource.Internal; + public string? Namespace { get; set; } + public string Name { get; set; } + public virtual List<TagDefinition> ImplicitTags { get; set; } = new(); } public class Tag : HBObject { public virtual TagDefinition TagDefinition { get; set; } - public DateTime CreateTime { get; set; } = DateTime.Now; + public DateTime CreateTime { get; set; } = DateTime.UtcNow; public virtual HBObject Target { get; set; } public Tag() {} diff --git a/appsettings.json b/appsettings.json index 10f68b8..90977fc 100644 --- a/appsettings.json +++ b/appsettings.json @@ -5,5 +5,8 @@ "Microsoft.AspNetCore": "Warning" } }, + "ConnectionStrings": { + "DefaultConnection": "Host=127.0.0.1;Database=HyperBooru;Username=hyperbooru;Password=password" + }, "AllowedHosts": "*" } |
