Skip to content

Commit

Permalink
Merge pull request #46 from quizer-app/develop
Browse files Browse the repository at this point in the history
Add Cloudflare Image support
  • Loading branch information
EloToJaa authored Feb 27, 2024
2 parents 4f6a731 + 8201b4c commit d895d68
Show file tree
Hide file tree
Showing 34 changed files with 337 additions and 175 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@
**/obj
**/logs
# **/wwwroot
**/.containers
**/.containers
**/secrets.json
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,6 @@ This project implements CLEAN architecture and DDD in a simple quiz application.
To run a database migration, run the following command:

```pwsh
dotnet ef migrations add -p .\src\Quizer.Infrastructure\Quizer.Infrastructure.csproj -s .\src\Quizer.Api\Quizer.Api.csproj MIGRATION_NAME
dotnet ef migrations add -p .\src\Quizer.Infrastructure\Quizer.Infrastructure.csproj -s .\src\Quizer.Api\Quizer.Api.csproj InitialSchema
dotnet ef database update -p .\src\Quizer.Infrastructure\Quizer.Infrastructure.csproj -s .\src\Quizer.Api\Quizer.Api.csproj
```
2 changes: 1 addition & 1 deletion src/Quizer.Api/ApplicationConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public static WebApplication UsePresentation(this WebApplication app, Configurat

app.UseSerilogRequestLogging();

app.UseExceptionHandler("/error");
app.UseExceptionHandler("/api/v1/errors");

app.UseHttpsRedirection();

Expand Down
12 changes: 5 additions & 7 deletions src/Quizer.Api/Controllers/V1/ImageController.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Quizer.Application.Services.Image;
using Quizer.Contracts.Image;

namespace Quizer.Api.Controllers.V1;

Expand All @@ -16,16 +17,13 @@ public ImageController(IImageService imageService)
}

[AllowAnonymous]
[HttpPost("{imageType}/{id:guid}")]
public async Task<IActionResult> UploadImage(
[FromRoute] string imageType,
[FromRoute] Guid id,
[FromForm(Name = "Data")] IFormFile file)
[HttpGet("upload")]
public async Task<IActionResult> UploadImage()
{
var result = await _imageService.UploadImage(file, imageType);
var result = await _imageService.DirectUpload();

return result.Match(
Ok,
data => Ok(new ImageUploadResponse(data.Result.Id, data.Result.UploadUrl)),
Problem);
}
}
10 changes: 9 additions & 1 deletion src/Quizer.Api/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,18 @@

var builder = WebApplication.CreateBuilder(args);
{
builder.Configuration.Sources.Clear();
builder.Configuration
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddJsonFile($"appsettings.{builder.Environment.EnvironmentName}.json", optional: true, reloadOnChange: true)
.AddJsonFile("secrets.json", optional: true, reloadOnChange: true)
.AddEnvironmentVariables();

builder.Host.UseSerilog((context, configuration) =>
configuration.ReadFrom.Configuration(context.Configuration));

builder.Services
.AddApplication()
.AddApplication(builder.Configuration)
.AddInfractructure(builder.Configuration)
.AddPresentation(builder.Configuration);
}
Expand Down
5 changes: 0 additions & 5 deletions src/Quizer.Api/Quizer.Api.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
<ImplicitUsings>enable</ImplicitUsings>
<InvariantGlobalization>true</InvariantGlobalization>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<UserSecretsId>d18eeebe-791d-4590-b139-d3860dcac549</UserSecretsId>
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
<DockerfileContext>..\..</DockerfileContext>
<DockerComposeProjectPath>..\..\docker-compose.dcproj</DockerComposeProjectPath>
Expand Down Expand Up @@ -40,8 +39,4 @@
<Compile Include="..\..\AssemblyInfo.cs" />
</ItemGroup>

<ItemGroup>
<Folder Include="wwwroot\" />
</ItemGroup>

</Project>
8 changes: 8 additions & 0 deletions src/Quizer.Application/Common/Settings/ImagesSettings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace Quizer.Application.Common.Settings;

public class ImagesSettings
{
public const string SectionName = "Images";
public string AccountId { get; init; } = null!;
public string ApiToken { get; init; } = null!;
}
11 changes: 6 additions & 5 deletions src/Quizer.Application/DependencyInjection.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using FluentValidation;
using MediatR;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Quizer.Application.Common.Behaviors;
using Quizer.Application.Services;
Expand All @@ -9,7 +10,7 @@ namespace Quizer.Application;

public static class DependencyInjection
{
public static IServiceCollection AddApplication(this IServiceCollection services)
public static IServiceCollection AddApplication(this IServiceCollection services, ConfigurationManager configuration)
{
var assembly = Assembly.GetExecutingAssembly();

Expand All @@ -21,11 +22,11 @@ public static IServiceCollection AddApplication(this IServiceCollection services

services.AddValidatorsFromAssembly(assembly);

services.AddServices();
services.AddServices(configuration);

services
.AddFluentEmail("quizer@elotoja.com")
.AddSendGridSender("API_KEY");
//services
// .AddFluentEmail("quizer@elotoja.com")
// .AddSendGridSender("API_KEY");

return services;
}
Expand Down
1 change: 0 additions & 1 deletion src/Quizer.Application/Quizer.Application.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
<PackageReference Include="FluentEmail.SendGrid" Version="3.0.2" />
<PackageReference Include="FluentValidation" Version="11.9.0" />
<PackageReference Include="FluentValidation.AspNetCore" Version="11.3.0" />
<PackageReference Include="Magick.NET-Q16-AnyCPU" Version="13.6.0" />
<PackageReference Include="MediatR" Version="12.2.0" />
</ItemGroup>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ namespace Quizer.Application.Quizes.Commands.CreateQuiz;
public record CreateQuizCommand(
string Name,
string Description,
Guid UserId
Guid UserId,
Guid ImageId
) : IRequest<ErrorOr<QuizId>>;
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
using MediatR;
using Microsoft.AspNetCore.Identity;
using Quizer.Application.Common.Interfaces.Persistance;
using Quizer.Application.Services.Image;
using Quizer.Application.Services.Slugify;
using Quizer.Domain.Common.Errors;
using Quizer.Domain.Common.ValueObjects;
using Quizer.Domain.QuizAggregate;
using Quizer.Domain.UserAggregate;

Expand All @@ -14,12 +16,14 @@ public class CreateQuizCommandHandler : IRequestHandler<CreateQuizCommand, Error
private readonly IQuizRepository _quizRepository;
private readonly ISlugifyService _slugifyService;
private readonly UserManager<User> _userManager;
private readonly IImageService _imageService;

public CreateQuizCommandHandler(IQuizRepository quizRepository, ISlugifyService slugifyService, UserManager<User> userManager)
public CreateQuizCommandHandler(IQuizRepository quizRepository, ISlugifyService slugifyService, UserManager<User> userManager, IImageService imageService)
{
_quizRepository = quizRepository;
_slugifyService = slugifyService;
_userManager = userManager;
_imageService = imageService;
}

public async Task<ErrorOr<QuizId>> Handle(CreateQuizCommand request, CancellationToken cancellationToken)
Expand All @@ -32,8 +36,13 @@ public async Task<ErrorOr<QuizId>> Handle(CreateQuizCommand request, Cancellatio

string slug = _slugifyService.GenerateSlug(request.Name);

bool uploaded = await _imageService.IsSuccessfulyUploaded(request.ImageId);
if (!uploaded)
return Errors.Image.CannotUpload;

var result = Quiz.Create(
request.UserId,
Image.CreateNew(request.ImageId, _imageService.GenerateImageUrl(request.ImageId, "quiz")),
request.Name,
slug,
request.Description,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using ErrorOr;
using MediatR;
using Quizer.Application.Common.Interfaces.Persistance;
using Quizer.Application.Services.Image;
using Quizer.Domain.Common.Errors;
using Quizer.Domain.QuizAggregate;

Expand All @@ -9,10 +10,12 @@ namespace Quizer.Application.Quizes.Commands.DeleteQuiz;
public class DeleteQuizCommandHandler : IRequestHandler<DeleteQuizCommand, ErrorOr<QuizId>>
{
private readonly IQuizRepository _quizRepository;
private readonly IImageService _imageService;

public DeleteQuizCommandHandler(IQuizRepository quizRepository)
public DeleteQuizCommandHandler(IQuizRepository quizRepository, IImageService imageService)
{
_quizRepository = quizRepository;
_imageService = imageService;
}

public async Task<ErrorOr<QuizId>> Handle(DeleteQuizCommand request, CancellationToken cancellationToken)
Expand All @@ -22,6 +25,10 @@ public async Task<ErrorOr<QuizId>> Handle(DeleteQuizCommand request, Cancellatio
if (quiz is null)
return Errors.Quiz.NotFound;

bool deleted = await _imageService.DeleteImage(quiz.Image.ImageId);
if (!deleted)
return Errors.Image.CannotDelete;

var id = (QuizId)quiz.Id;
quiz.Delete();
_quizRepository.Delete(quiz);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ namespace Quizer.Application.Quizes.Commands.UpdateQuiz;

public record UpdateQuizCommand(
Guid UserId,
Guid ImageId,
Guid QuizId,
string Name,
string Description) : IRequest<ErrorOr<QuizId>>;
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
using ErrorOr;
using MediatR;
using Quizer.Application.Common.Interfaces.Persistance;
using Quizer.Application.Services.Image;
using Quizer.Application.Services.Slugify;
using Quizer.Domain.Common.Errors;
using Quizer.Domain.Common.ValueObjects;
using Quizer.Domain.QuizAggregate;

namespace Quizer.Application.Quizes.Commands.UpdateQuiz;
Expand All @@ -11,11 +13,13 @@ public class UpdateQuizCommandHandler : IRequestHandler<UpdateQuizCommand, Error
{
private readonly IQuizRepository _quizRepository;
private readonly ISlugifyService _slugifyService;
private readonly IImageService _imageService;

public UpdateQuizCommandHandler(IQuizRepository quizRepository, ISlugifyService slugifyService)
public UpdateQuizCommandHandler(IQuizRepository quizRepository, ISlugifyService slugifyService, IImageService imageService)
{
_quizRepository = quizRepository;
_slugifyService = slugifyService;
_imageService = imageService;
}

public async Task<ErrorOr<QuizId>> Handle(UpdateQuizCommand request, CancellationToken cancellationToken)
Expand All @@ -29,8 +33,20 @@ public async Task<ErrorOr<QuizId>> Handle(UpdateQuizCommand request, Cancellatio

string slug = _slugifyService.GenerateSlug(request.Name);

if(quiz.Image.ImageId != request.ImageId)
{
bool deleted = await _imageService.DeleteImage(quiz.Image.ImageId);
if (!deleted)
return Errors.Image.CannotDelete;

bool uploaded = await _imageService.IsSuccessfulyUploaded(request.ImageId);
if (!uploaded)
return Errors.Image.CannotUpload;
}

var result = quiz.Update(
request.UserId,
Image.CreateNew(request.ImageId, _imageService.GenerateImageUrl(request.ImageId, "quiz")),
request.Name,
slug,
request.Description);
Expand Down
13 changes: 9 additions & 4 deletions src/Quizer.Application/Services/DependencyInjection.cs
Original file line number Diff line number Diff line change
@@ -1,19 +1,24 @@
using Diacritics;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Quizer.Application.Services.Email;
using Quizer.Application.Common.Settings;
using Quizer.Application.Services.Image;
using Quizer.Application.Services.Slugify;

namespace Quizer.Application.Services;

public static class DependencyInjection
{
public static IServiceCollection AddServices(this IServiceCollection services)
public static IServiceCollection AddServices(this IServiceCollection services, ConfigurationManager configuration)
{
services.Configure<ImagesSettings>(configuration.GetSection(ImagesSettings.SectionName));

services.AddHttpClient<IImageService, ImageService>();
services.AddTransient<IImageService, ImageService>();

services.AddSingleton<IDiacriticsMapper, DefaultDiacriticsMapper>();
services.AddSingleton<ISlugifyService, SlugifyService>();
services.AddSingleton<IEmailService, EmailService>();
services.AddSingleton<IImageService, ImageService>();
//services.AddSingleton<IEmailService, EmailService>();

return services;
}
Expand Down
22 changes: 9 additions & 13 deletions src/Quizer.Application/Services/Image/IImageService.cs
Original file line number Diff line number Diff line change
@@ -1,16 +1,12 @@

using ErrorOr;
using Microsoft.AspNetCore.Http;
using ErrorOr;
using Quizer.Application.Services.Image.Response;

namespace Quizer.Application.Services.Image
namespace Quizer.Application.Services.Image;

public interface IImageService
{
public interface IImageService
{
Task<ErrorOr<string>> UploadImage(IFormFile file, string imageType);
string? FormatAndMove(string filePathIn, string dirPathOut, Guid id);
bool Optimize(string filePath);
bool Resize(string filePath, int width, int height);
string GetImageDir(string imageType);
string GetImagePath(string imageType, Guid id);
}
Task<ErrorOr<DirectUploadResponse>> DirectUpload(bool requireSignedURLs = false);
Task<bool> IsSuccessfulyUploaded(Guid imageId);
Task<bool> DeleteImage(Guid imageId);
Uri GenerateImageUrl(Guid imageId, string variantName);
}
Loading

0 comments on commit d895d68

Please sign in to comment.