Skip to content

Commit

Permalink
IHS-52 Hide/unhide handlers (#81)
Browse files Browse the repository at this point in the history
* add current working directory for codecov action

* rename base uri to public url for images

* add hide/unhide image handler

* add required constraint for object name
  • Loading branch information
adedw authored Sep 23, 2024
1 parent e68bbfb commit a1c06a5
Show file tree
Hide file tree
Showing 10 changed files with 62 additions and 21 deletions.
7 changes: 6 additions & 1 deletion .github/workflows/codecov.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,21 +19,26 @@ jobs:
uses: actions/setup-dotnet@v4
with:
dotnet-version: 8.0.x
cache: true
cache-dependency-path: '**/packages.lock.json'

- name: Restore dependencies
working-directory: ./tests/ImageHosting.Storage.UnitTests
run: dotnet restore

- name: Build
working-directory: ./tests/ImageHosting.Storage.UnitTests
run: dotnet build --no-restore /p:ContinuousIntegrationBuild=true

- name: Test
working-directory: ./tests/ImageHosting.Storage.UnitTests
run: dotnet test --no-build --verbosity normal /p:CollectCoverage=true /p:CoverletOutputFormat=opencover

- name: Upload coverage reports to Codecov
uses: codecov/codecov-action@v4
with:
fail_ci_if_error: true
directory: ImageHosting.Storage.UnitTests
directory: ./tests/ImageHosting.Storage.UnitTests
file: coverage.opencover.xml
flags: unittests
token: ${{ secrets.CODECOV_TOKEN }}
Expand Down
2 changes: 1 addition & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ services:
Kafka__BootstrapServers__0: kafka:9092
Kafka__NewImagesProducer__TopicName: new-images.v1
Minio__Endpoint: minio:9000
Images__BaseUri: "http://localhost:8080"
Images__PublicUrl: "http://localhost:8080"
depends_on:
- minio
- postgres
Expand Down
2 changes: 1 addition & 1 deletion src/ImageHosting.Storage.Domain/Entities/Image.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ public class Image
public ImageId Id { get; set; }

public UserId UserId { get; set; }

public required string ObjectName { get; set; }
public bool Hidden { get; set; }
public DateTime UploadedAt { get; set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,24 @@ public static RouteGroupBuilder MapImagesEndpoints(this IEndpointRouteBuilder ro
.ProducesValidationProblem(StatusCodes.Status422UnprocessableEntity)
.MapToApiVersion(1);

images.MapPut(pattern: "{id}/hide", async ([FromRoute] ImageId id, [FromServices] ISetHidenessHandler setHidenessHandler, CancellationToken ct) =>
{
var readImage = await setHidenessHandler.SetHidenessAsync(id, true, ct);
return TypedResults.Ok(readImage);
})
.WithName("HideImage")
.WithTags("Images")
.MapToApiVersion(1);

images.MapPut(pattern: "{id}/unhide", async ([FromRoute] ImageId id, [FromServices] ISetHidenessHandler setHidenessHandler, CancellationToken ct) =>
{
var readImage = await setHidenessHandler.SetHidenessAsync(id, false, ct);
return TypedResults.Ok(readImage);
})
.WithName("UnhideImage")
.WithTags("Images")
.MapToApiVersion(1);

var tags = images.MapGroup(prefix: "{id}/tags");

tags.MapPost(pattern: "", handler: async ([FromRoute] ImageId id, [FromBody] AddTagsCommand addTagsCommand,
Expand All @@ -102,7 +120,7 @@ public static RouteGroupBuilder MapImagesEndpoints(this IEndpointRouteBuilder ro
.WithTags("Tags")
.MapToApiVersion(1);

tags.MapGet("", async ([FromRoute] ImageId id, [FromServices] IGetAllImageTagsHandler getAllImageTagsHandler, CancellationToken ct) =>
tags.MapGet(pattern: "", async ([FromRoute] ImageId id, [FromServices] IGetAllImageTagsHandler getAllImageTagsHandler, CancellationToken ct) =>
{
var tags = await getAllImageTagsHandler.GetTagsAsync(id, ct);
return TypedResults.Ok(tags);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ namespace ImageHosting.Storage.WebApi.Features.Images.Extensions;

public static class QueryableExtensions
{
public static IQueryable<ReadImage> ToReadImages(this IQueryable<Image> queryable, Uri baseUri)
public static IQueryable<ReadImage> ToReadImages(this IQueryable<Image> queryable, Uri publicUrl)
{
return queryable.Select(i => new ReadImage
{
Expand All @@ -15,7 +15,7 @@ public static IQueryable<ReadImage> ToReadImages(this IQueryable<Image> queryabl
UploadedAt = i.UploadedAt,
Hidden = i.Hidden,
Categories = i.Tags.Select(it => it.TagName).ToList(),
Asset = new Uri(baseUri, $"api/v1/images/{i.Id}/asset")
Asset = new Uri(publicUrl, $"api/v1/images/{i.Id}/asset")
}).AsSplitQuery();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public static IServiceCollection AddImageServices(this IServiceCollection servic
.AddScoped<IUpdateNameHandler, UpdateNameHandler>()
.AddScoped<IAddTagsHandler, AddTagsHandler>()
.AddScoped<IDeleteTagsHandler, DeleteTagsHandler>()
.AddScoped<IGetAllImageTagsHandler, GetAllImageTagsHandler>();
.AddScoped<IGetAllImageTagsHandler, GetAllImageTagsHandler>()
.AddScoped<ISetHidenessHandler, SetHidenessHandler>();
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
using ImageHosting.Storage.Domain.ValueTypes;
using ImageHosting.Storage.Infrastructure.DbContexts;
using ImageHosting.Storage.WebApi.Features.Images.Exceptions;
using ImageHosting.Storage.WebApi.Features.Images.Extensions;
using ImageHosting.Storage.WebApi.Features.Images.Models;
using ImageHosting.Storage.WebApi.Options;
Expand All @@ -11,25 +10,19 @@ namespace ImageHosting.Storage.WebApi.Features.Images.Handlers;

public interface IGetImageHandler
{
Task<ReadImage> GetAsync(ImageId id, CancellationToken cancellationToken = default);
Task<ReadImage?> GetAsync(ImageId id, CancellationToken cancellationToken = default);
}

public class GetImageHandler(IImageHostingDbContext dbContext, IOptions<ImagesOptions> options) : IGetImageHandler
{
private readonly ImagesOptions _options = options.Value;
private readonly Uri _publicUrl = options.Value.PublicUrl;

public async Task<ReadImage> GetAsync(ImageId id, CancellationToken cancellationToken = default)
public Task<ReadImage?> GetAsync(ImageId id, CancellationToken cancellationToken = default)
{
var image = await dbContext.Images
return dbContext.Images
.AsNoTracking()
.Where(i => i.Id == id)
.ToReadImages(_options.BaseUri)
.ToReadImages(_publicUrl)
.FirstOrDefaultAsync(cancellationToken);
if (image is null)
{
throw new ImageMetadataNotFoundException(id);
}

return image;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using ImageHosting.Storage.Domain.ValueTypes;
using ImageHosting.Storage.Infrastructure.DbContexts;
using ImageHosting.Storage.WebApi.Features.Images.Models;
using Microsoft.EntityFrameworkCore;

namespace ImageHosting.Storage.WebApi.Features.Images.Handlers;

public interface ISetHidenessHandler
{
Task<ReadImage?> SetHidenessAsync(ImageId imageId, bool hidden, CancellationToken ct = default);
}

public class SetHidenessHandler(IImageHostingDbContext dbContext, IGetImageHandler getImageHandler) : ISetHidenessHandler
{
public async Task<ReadImage?> SetHidenessAsync(ImageId imageId, bool hidden, CancellationToken ct = default)
{
await dbContext.Images
.Where(i => i.Id == imageId)
.ExecuteUpdateAsync(calls => calls.SetProperty(i => i.Hidden, hidden), ct);

var readImage = await getImageHandler.GetAsync(imageId, ct);
return readImage;
}
}
2 changes: 1 addition & 1 deletion src/ImageHosting.Storage.WebApi/Options/ImagesOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@ public class ImagesOptions
{
public const string SectionName = "Images";

[Required] public required Uri BaseUri { get; init; }
[Required] public required Uri PublicUrl { get; init; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,6 @@
}
},
"Images": {
"BaseUri": "http://localhost:8080"
"PublicUrl": "http://localhost:8080"
}
}

0 comments on commit a1c06a5

Please sign in to comment.