diff options
Diffstat (limited to 'Services')
| -rw-r--r-- | Services/FeedService.cs | 117 | ||||
| -rw-r--r-- | Services/MediaService.cs | 27 | ||||
| -rw-r--r-- | Services/SecurityService.cs | 6 |
3 files changed, 98 insertions, 52 deletions
diff --git a/Services/FeedService.cs b/Services/FeedService.cs index c66b9ee..b664d62 100644 --- a/Services/FeedService.cs +++ b/Services/FeedService.cs @@ -1,78 +1,109 @@ using Microsoft.EntityFrameworkCore; -using System.Data.Common; +using Microsoft.EntityFrameworkCore.Query; namespace HyperBooru.Services; -public enum FeedOrder { +public enum FeedSortOrder { + Ascending, + Descending +} + +public enum FeedSortType { Chronological, Rating } +public record FeedOptions { + public FeedSortType SortType { get; set; } + public FeedSortOrder SortOrder { get; set; } + public bool RandomPosition { get; set; } + + public Func<IQueryable<Media>, IQueryable<Media>>? IncludeProperties { get; set; } +} + public interface IFeedService { public IEnumerable<Media> Feed { get; } - - public void InitializeFeed( - FeedOrder order = FeedOrder.Chronological, - bool descending = true, - bool randomPosition = false); + public void InitializeFeed(FeedOptions feedOptions); + public Media[] Next(int count); } public class FeedService : IFeedService { - private FeedConfiguration? feedConfig; + private const int FeedChunkSize = 50; + + private FeedOptions? feedOptions; + private Media? last; private IDbContextFactory<HBContext> dbFactory; public FeedService(IDbContextFactory<HBContext> dbFactory) => this.dbFactory = dbFactory; - public void InitializeFeed( - FeedOrder order, - bool descending, - bool randomPosition) { - - feedConfig = new() { - Order = order, - Descending = descending, - RandomPosition = randomPosition - }; + public void InitializeFeed(FeedOptions feedOptions) { + this.feedOptions = feedOptions; + last = null; } public IEnumerable<Media> Feed { get { - if(feedConfig is null) - throw new InvalidOperationException("Feed must be initialized first"); - + last = null; while(true) { - var db = dbFactory.CreateDbContext(); + var media = Next(FeedChunkSize); + if(media.Count() == 0) + break; + foreach(var m in media) + yield return m; + } + } + } - IOrderedQueryable<Media> media; + public Media[] Next(int count) => + NextDbChunk(Math.Abs(count), count < 0); - switch(feedConfig.Order) { - default: - case FeedOrder.Chronological: - if(feedConfig.Descending) - media = db.Media.OrderByDescending(m => m.ObjectId); + private Media[] NextDbChunk(int chunkSize, bool reverse = false) { + if(feedOptions is null) + throw new InvalidOperationException("Feed must be initialized first"); + + while(true) { + var db = dbFactory.CreateDbContext(); + + IQueryable<Media> media = db.Media; + + if(feedOptions.IncludeProperties is not null) + media = feedOptions.IncludeProperties(media); + + var sortOrder = feedOptions.SortOrder; + if(reverse) + sortOrder = sortOrder == FeedSortOrder.Ascending + ? FeedSortOrder.Descending + : FeedSortOrder.Ascending; + + if(last is not null) { + switch(feedOptions.SortType) { + case FeedSortType.Chronological: + if(sortOrder == FeedSortOrder.Descending) + media = media.Where(m => m.ObjectId < last.ObjectId); else - media = db.Media.OrderBy(m => m.ObjectId); + media = media.Where(m => m.ObjectId > last.ObjectId); break; } + media = media.Where(m => m.ObjectId != last.ObjectId); + } - Media[] mediaArray = media.Take(50).ToArray(); - - db.Dispose(); - - if(mediaArray.Count() == 0) + switch(feedOptions.SortType) { + case FeedSortType.Chronological: + if(sortOrder == FeedSortOrder.Descending) + media = media.OrderByDescending(m => m.ObjectId); + else + media = media.OrderBy(m => m.ObjectId); break; - - foreach(var m in mediaArray) - yield return m; } - } - } - private record FeedConfiguration { - public FeedOrder Order { get; set; } - public bool Descending { get; set; } - public bool RandomPosition { get; set; } + Media[] mediaArray = media + .Take(chunkSize) + .ToArray(); + + if(mediaArray.Count() != 0) + last = mediaArray.Last(); + } } } diff --git a/Services/MediaService.cs b/Services/MediaService.cs index abc026f..a9e744e 100644 --- a/Services/MediaService.cs +++ b/Services/MediaService.cs @@ -132,6 +132,7 @@ public class MediaService : IMediaService { using var magickImage = new MagickImage(fileData); var media = db.UploadedFiles + .Include(uf => uf.Media) .FirstOrDefault(uf => uf.Checksum == hash)? .Media; @@ -154,28 +155,35 @@ public class MediaService : IMediaService { .First(td => td.Guid == HBObjectGuid.IngestTag); media = new() { - CurrentUploadedFile = fileRecord, - UploadedFiles = new() { - fileRecord + UploadedFiles = new() { + fileRecord, }, Tags = new() { new() { TagDefinition = ingestTagDef } } }; - using var newFile = System.IO.File.Create(GetPath(media)); + using var newFile = File.Create(GetPath(media)); fileData.Seek(0, SeekOrigin.Begin); fileData.CopyTo(newFile); newFile.Flush(); db.Media.Add(media); + db.SaveChanges(); + media.CurrentUploadedFile = fileRecord; + db.SaveChanges(); } else { - media.UploadedFiles.Add(fileRecord); + db.Entry(media).Collection(m => m.UploadedFiles).Load(); + var fileHashes = media.UploadedFiles + .Select(uf => GetUploadedFileHash(uf)); + // Only add the uploaded file record if it contains new information + if(!fileHashes.Contains(GetUploadedFileHash(fileRecord))) + media.UploadedFiles.Add(fileRecord); db.Update(media); + db.SaveChanges(); } - db.SaveChanges(); transaction.Commit(); return media; @@ -305,4 +313,11 @@ public class MediaService : IMediaService { Directory.CreateDirectory(fileInfo.Directory.FullName); return fileInfo.FullName; } + + private int GetUploadedFileHash(UploadedFile uf) => ( + uf.CreateTime, + uf.LastWriteTime, + uf.Filename, + uf.Length, + uf.Checksum).GetHashCode(); } diff --git a/Services/SecurityService.cs b/Services/SecurityService.cs index 85513ec..1a0c445 100644 --- a/Services/SecurityService.cs +++ b/Services/SecurityService.cs @@ -64,13 +64,13 @@ public class SecurityService : ISecurityService { principalProvider.SearchPrincipals(name); public IPrincipal? GetPrincipal(string name) => - principalProvider.GetPrincipal(name); + principalProvider.GetPrincipal(name.Trim()); public IUser? GetUser(string name) => - principalProvider.GetUser(name); + principalProvider.GetUser(name.Trim()); public IGroup? GetGroup(string name) => - principalProvider.GetGroup(name); + principalProvider.GetGroup(name.Trim()); public bool ValidatePassword(IUser user, string password) => principalProvider.ValidatePassword(user, password); |
