summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJake Mannens <jake@asger.xyz>2023-08-17 13:54:01 +1000
committerJake Mannens <jake@asger.xyz>2025-08-18 17:03:21 +1000
commit7dcc15cb52c29cc1c0112e3af2cf985b26cd7653 (patch)
treeb12e2c30c8a1717079f5704151af743347c40d1e
parentf150338f7a275bd7664f59a4365f163a17049bd0 (diff)
Fixed implicit tagging completely and switched DB to PostgreSQL
-rw-r--r--Controllers/MediaController.cs2
-rw-r--r--HBContext.cs10
-rw-r--r--Media.cs2
-rw-r--r--Pages/TagDefinitions.razor8
-rw-r--r--Server.csproj2
-rw-r--r--Services/ConfigService.cs10
-rw-r--r--Services/TagService.cs35
-rw-r--r--Tag.cs10
-rw-r--r--appsettings.json3
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();
diff --git a/Media.cs b/Media.cs
index 68ae4c4..2ff10bf 100644
--- a/Media.cs
+++ b/Media.cs
@@ -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();
diff --git a/Tag.cs b/Tag.cs
index 810c49c..70d70c9 100644
--- a/Tag.cs
+++ b/Tag.cs
@@ -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": "*"
}