Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BREAKING CHANGE: Reworked image upload, using IFormFile instead of byte arrays #68

Merged
merged 2 commits into from
Jun 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ public class KnowledgeEntryRecord : EntityBase
public int Order { get; set; }

[DataMember]
public List<LinkFragment> Links { get; set; } = new();
public virtual List<LinkFragment> Links { get; set; } = new();

[DataMember]
public List<ImageRecord> Images { get; set; }
public virtual List<ImageRecord> Images { get; set; } = new();
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
namespace Eurofurence.App.Server.Services.Abstractions.ArtistsAlley
using System;

namespace Eurofurence.App.Server.Services.Abstractions.ArtistsAlley
{
public class TableRegistrationRequest
{
Expand All @@ -8,7 +10,7 @@ public class TableRegistrationRequest

public string ShortDescription { get; set; }

public string ImageContent { get; set; }
public Guid ImageId { get; set; }

public string Location { get; set; }

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
namespace Eurofurence.App.Server.Services.Abstractions.Fursuits
using System;

namespace Eurofurence.App.Server.Services.Abstractions.Fursuits
{
public class FursuitBadgeRegistration
{
Expand All @@ -8,7 +10,7 @@ public class FursuitBadgeRegistration
public string WornBy { get; set; }
public string Species { get; set; }
public string Gender { get; set; }
public string ImageContent { get; set; }
public Guid ImageId { get; set; }
public int DontPublish { get; set; }
public string CollectionCode { get; set; }
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Eurofurence.App.Domain.Model.Fursuits;
Expand All @@ -9,7 +10,7 @@ public interface IFursuitBadgeService
{
Task<Guid> UpsertFursuitBadgeAsync(FursuitBadgeRegistration registration);

Task<byte[]> GetFursuitBadgeImageAsync(Guid id);
Task<Stream> GetFursuitBadgeImageAsync(Guid id);

IQueryable<FursuitBadgeRecord> GetFursuitBadges(FursuitBadgeFilter filter = null);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
using System;
using System.IO;
using System.Threading.Tasks;
using Eurofurence.App.Domain.Model.Fragments;
using Eurofurence.App.Domain.Model.Images;

namespace Eurofurence.App.Server.Services.Abstractions.Images
{
public interface IImageService : IEntityServiceOperations<ImageRecord>
{
Task InsertImageAsync(ImageRecord image, byte[] imageBytes);
Task<ImageRecord> InsertOrUpdateImageAsync(string internalReference, byte[] imageBytes);
Task<byte[]> GetImageContentByImageIdAsync(Guid id);
byte[] GeneratePlaceholderImage();
Task<ImageRecord> InsertImageAsync(string internalReference, Stream stream);
Task<ImageRecord> ReplaceImageAsync(Guid id, string internalReference, Stream stream);
Task<Stream> GetImageContentByImageIdAsync(Guid id);
Stream GeneratePlaceholderImage();
Task<ImageRecord> EnforceMaximumDimensionsAsync(ImageRecord image, int width, int height);
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
using Eurofurence.App.Domain.Model.Knowledge;
using System;
using System.Threading.Tasks;

namespace Eurofurence.App.Server.Services.Abstractions.Knowledge
{
public interface IKnowledgeEntryService :
IEntityServiceOperations<KnowledgeEntryRecord>,
IPatchOperationProcessor<KnowledgeEntryRecord>
{
public Task<KnowledgeEntryRecord> InsertKnowledgeEntryAsync(KnowledgeEntryRequest request);

public Task<KnowledgeEntryRecord> ReplaceKnowledgeEntryAsync(Guid id, KnowledgeEntryRequest request);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using Eurofurence.App.Domain.Model.Fragments;
using System.Collections.Generic;
using System;

namespace Eurofurence.App.Server.Services.Abstractions.Knowledge
{
public class KnowledgeEntryRequest
{
public Guid KnowledgeGroupId { get; set; }

public string Title { get; set; }

public string Text { get; set; }

public int Order { get; set; }

public List<LinkFragment> Links { get; set; } = new();

public List<Guid> ImageIds { get; set; } = new();
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
Expand Down Expand Up @@ -45,8 +46,7 @@ public async Task RegisterTableAsync(string uid, TableRegistrationRequest reques
{
var identity = await _appDbContext.RegSysIdentities.AsNoTracking().FirstOrDefaultAsync(a => a.Uid == uid);

var imageBytes = Convert.FromBase64String(request.ImageContent);
var image = await _imageService.InsertOrUpdateImageAsync(Guid.NewGuid().ToString(), imageBytes);
var image = await _imageService.FindOneAsync(request.ImageId);

image = await _imageService.EnforceMaximumDimensionsAsync(image, 1500, 1500);

Expand Down Expand Up @@ -126,11 +126,16 @@ private async Task BroadcastAsync(TableRegistrationRecord record)

if (record.Image != null)
{
var imageBytes = await _imageService.GetImageContentByImageIdAsync(record.Image.Id);
await _telegramMessageSender.SendImageToChatAsync(
_configuration.TelegramAnnouncementChannelId,
imageBytes,
telegramMessage);
using (MemoryStream ms = new())
{
var stream = await _imageService.GetImageContentByImageIdAsync(record.Image.Id);
await stream.CopyToAsync(ms);
await stream.DisposeAsync();
await _telegramMessageSender.SendImageToChatAsync(
_configuration.TelegramAnnouncementChannelId,
ms.ToArray(),
telegramMessage);
}
}
else
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,14 @@
using System;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using Eurofurence.App.Common.Utility;
using Eurofurence.App.Domain.Model.Fursuits;
using Eurofurence.App.Server.Services.Abstractions;
using Eurofurence.App.Server.Services.Abstractions.Fursuits;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Processing;
using System.Threading;
using Eurofurence.App.Domain.Model.Images;
using Eurofurence.App.Infrastructure.EntityFramework;
using Eurofurence.App.Server.Services.Abstractions.Images;
using Microsoft.EntityFrameworkCore;
using SixLabors.ImageSharp.Processing.Processors.Transforms;
using SixLabors.ImageSharp.Formats.Jpeg;

namespace Eurofurence.App.Server.Services.Fursuits
{
Expand All @@ -39,9 +32,6 @@ IImageService imageService

public async Task<Guid> UpsertFursuitBadgeAsync(FursuitBadgeRegistration registration)
{
byte[] imageBytes = Convert.FromBase64String(registration.ImageContent);
var hash = Hashing.ComputeHashSha1(imageBytes);

await _sync.WaitAsync();

FursuitBadgeRecord? fursuitBadge = null;
Expand All @@ -68,45 +58,12 @@ public async Task<Guid> UpsertFursuitBadgeAsync(FursuitBadgeRegistration registr
record.IsPublic = (registration.DontPublish == 0);
record.WornBy = registration.WornBy;
record.CollectionCode = registration.CollectionCode;
record.ImageId = registration.ImageId;
record.Touch();

var imageRecord = await _appDbContext.Images.FirstOrDefaultAsync(entity => entity.Id == record.ImageId);
var imageRecord = await _appDbContext.Images.AsNoTracking().FirstOrDefaultAsync(entity => entity.Id == record.ImageId);

if (imageRecord == null)
{
imageRecord = new ImageRecord
{
InternalReference = record.Id.ToString(),
Width = 240,
Height = 320,
MimeType = "image/jpeg"
};
imageRecord.Touch();
}

if (imageRecord.ContentHashSha1 != hash)
{
imageRecord.ContentHashSha1 = hash;

var image = Image.Load(imageBytes);

image.Mutate(ctx =>
ctx.Resize(new ResizeOptions()
{
Mode = ResizeMode.Max,
Size = new Size(240, 320),
Sampler = new BicubicResampler()
})
);

var ms = new MemoryStream();
await image.SaveAsJpegAsync(ms, new JpegEncoder() { Quality = 85 });
imageRecord.SizeInBytes = ms.Length;
imageRecord.Touch();
var createdImage = await _imageService.InsertOrUpdateImageAsync(record.Id.ToString(), ms.ToArray());
record.ImageId = createdImage.Id;
await ms.DisposeAsync();
}
await _imageService.EnforceMaximumDimensionsAsync(imageRecord, 240, 320);

_appDbContext.FursuitBadges.Update(record);

Expand All @@ -116,26 +73,6 @@ public async Task<Guid> UpsertFursuitBadgeAsync(FursuitBadgeRegistration registr
}
catch (Exception ex)
{
if (fursuitBadge == null)
{
return Guid.Empty;
}

var fursuitBadgeToDelete = await _appDbContext.FursuitBadges.SingleOrDefaultAsync(entity => entity.Id == fursuitBadge.Id);
var fursuitBadgeImageToDelete = await _appDbContext.Images.SingleOrDefaultAsync(entity => entity.Id == fursuitBadge.ImageId);

if (fursuitBadgeToDelete != null)
{
_appDbContext.Remove(fursuitBadgeToDelete);
}

if (fursuitBadgeImageToDelete != null)
{
await _imageService.DeleteOneAsync(fursuitBadgeImageToDelete.Id);
}

await _appDbContext.SaveChangesAsync();

return Guid.Empty;
}
finally
Expand All @@ -144,11 +81,11 @@ public async Task<Guid> UpsertFursuitBadgeAsync(FursuitBadgeRegistration registr
}
}

public async Task<byte[]> GetFursuitBadgeImageAsync(Guid id)
public async Task<Stream> GetFursuitBadgeImageAsync(Guid id)
{
var content = await _appDbContext.FursuitBadges
.FirstOrDefaultAsync(entity => entity.Id == id);
byte[] result = null;
Stream result = null;

if (content.ImageId != null)
{
Expand Down
Loading