diff --git a/src/EventHub.Admin.Application.Contracts/Events/EventDetailDto.cs b/src/EventHub.Admin.Application.Contracts/Events/EventDetailDto.cs index a0bded1..04b0c53 100644 --- a/src/EventHub.Admin.Application.Contracts/Events/EventDetailDto.cs +++ b/src/EventHub.Admin.Application.Contracts/Events/EventDetailDto.cs @@ -13,8 +13,6 @@ namespace EventHub.Admin.Events public DateTime EndTime { get; set; } - public byte[] CoverImageContent { get; set; } - public bool IsOnline { get; set; } public string OnlineLink { get; set; } diff --git a/src/EventHub.Admin.Application.Contracts/Events/IEventAppService.cs b/src/EventHub.Admin.Application.Contracts/Events/IEventAppService.cs index 12c2a22..da46c3b 100644 --- a/src/EventHub.Admin.Application.Contracts/Events/IEventAppService.cs +++ b/src/EventHub.Admin.Application.Contracts/Events/IEventAppService.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Threading.Tasks; using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Services; +using Volo.Abp.Content; namespace EventHub.Admin.Events { @@ -16,6 +17,6 @@ namespace EventHub.Admin.Events Task> GetCountriesLookupAsync(); - Task GetCoverImageAsync(Guid id); + Task GetCoverImageAsync(Guid id); } } diff --git a/src/EventHub.Admin.Application.Contracts/Events/UpdateEventDto.cs b/src/EventHub.Admin.Application.Contracts/Events/UpdateEventDto.cs index 1b041bd..e6c9d54 100644 --- a/src/EventHub.Admin.Application.Contracts/Events/UpdateEventDto.cs +++ b/src/EventHub.Admin.Application.Contracts/Events/UpdateEventDto.cs @@ -2,6 +2,7 @@ using System.ComponentModel.DataAnnotations; using EventHub.Events; using JetBrains.Annotations; +using Volo.Abp.Content; namespace EventHub.Admin.Events { @@ -24,7 +25,7 @@ namespace EventHub.Admin.Events public DateTime EndTime { get; set; } [CanBeNull] - public byte[] CoverImageContent { get; set; } + public RemoteStreamContent CoverImageStreamContent { get; set; } public bool IsOnline { get; set; } diff --git a/src/EventHub.Admin.Application/EventHubApplicationAutoMapperProfile.cs b/src/EventHub.Admin.Application/EventHubApplicationAutoMapperProfile.cs index e3bc1de..f4a9ca2 100644 --- a/src/EventHub.Admin.Application/EventHubApplicationAutoMapperProfile.cs +++ b/src/EventHub.Admin.Application/EventHubApplicationAutoMapperProfile.cs @@ -26,8 +26,7 @@ namespace EventHub.Admin CreateMap(); - CreateMap() - .Ignore(x => x.CoverImageContent); + CreateMap(); CreateMap(); diff --git a/src/EventHub.Admin.Application/Events/EventAppService.cs b/src/EventHub.Admin.Application/Events/EventAppService.cs index daf2b16..7544238 100644 --- a/src/EventHub.Admin.Application/Events/EventAppService.cs +++ b/src/EventHub.Admin.Application/Events/EventAppService.cs @@ -9,6 +9,7 @@ using EventHub.Events; using Microsoft.AspNetCore.Authorization; using Volo.Abp.Application.Dtos; using Volo.Abp.BlobStoring; +using Volo.Abp.Content; using Volo.Abp.Domain.Repositories; namespace EventHub.Admin.Events @@ -36,9 +37,7 @@ namespace EventHub.Admin.Events public async Task GetAsync(Guid id) { var @event = await _eventRepository.GetAsync(id); - var eventDetailDto = ObjectMapper.Map(@event); - eventDetailDto.CoverImageContent = await GetCoverImageAsync(id); return eventDetailDto; } @@ -69,16 +68,26 @@ namespace EventHub.Admin.Events @event.SetTime(input.StartTime, @event.EndTime); await _eventManager.SetCapacityAsync(@event, input.Capacity); - await SetCoverImageAsync(blobName: id.ToString(), input.CoverImageContent); + if (input.CoverImageStreamContent != null && input.CoverImageStreamContent.ContentLength > 0) + { + await SetCoverImageAsync(blobName: id.ToString(), input.CoverImageStreamContent); + } await _eventRepository.UpdateAsync(@event); } - public async Task GetCoverImageAsync(Guid id) + [AllowAnonymous] + public async Task GetCoverImageAsync(Guid id) { var blobName = id.ToString(); + var coverImageStream = await _eventBlobContainer.GetOrNullAsync(blobName); + + if (coverImageStream == null) + { + return null; + } - return await _eventBlobContainer.GetAllBytesOrNullAsync(blobName); + return new RemoteStreamContent(coverImageStream); } public async Task> GetCountriesLookupAsync() @@ -94,9 +103,9 @@ namespace EventHub.Admin.Events return ObjectMapper.Map, List>(countries); } - private async Task SetCoverImageAsync(string blobName, byte[] coverImageContent, bool overrideExisting = true) + private async Task SetCoverImageAsync(string blobName, IRemoteStreamContent streamContent, bool overrideExisting = true) { - await _eventBlobContainer.SaveAsync(blobName, coverImageContent, overrideExisting); + await _eventBlobContainer.SaveAsync(blobName, streamContent.GetStream(), overrideExisting); } } } diff --git a/src/EventHub.Admin.HttpApi.Host/Controllers/Events/EventController.cs b/src/EventHub.Admin.HttpApi.Host/Controllers/Events/EventController.cs index 5cc02a3..0850679 100644 --- a/src/EventHub.Admin.HttpApi.Host/Controllers/Events/EventController.cs +++ b/src/EventHub.Admin.HttpApi.Host/Controllers/Events/EventController.cs @@ -2,10 +2,13 @@ using System.Collections.Generic; using System.Threading.Tasks; using EventHub.Admin.Events; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Volo.Abp; using Volo.Abp.Application.Dtos; using Volo.Abp.AspNetCore.Mvc; +using Volo.Abp.Content; +using Volo.Abp.VirtualFileSystem; namespace EventHub.Admin.Controllers.Events { @@ -17,10 +20,12 @@ namespace EventHub.Admin.Controllers.Events public class EventController : AbpController, IEventAppService { private readonly IEventAppService _eventAppService; - - public EventController(IEventAppService eventAppService) + private readonly IVirtualFileProvider _virtualFileProvider; + + public EventController(IEventAppService eventAppService, IVirtualFileProvider virtualFileProvider) { _eventAppService = eventAppService; + _virtualFileProvider = virtualFileProvider; } [HttpGet("{id}")] @@ -36,9 +41,28 @@ namespace EventHub.Admin.Controllers.Events } [HttpGet("cover-image/{id}")] - public Task GetCoverImageAsync(Guid id) + [AllowAnonymous] + public async Task GetCoverImageAsync(Guid id) { - return _eventAppService.GetCoverImageAsync(id); + var remoteStreamContent = await _eventAppService.GetCoverImageAsync(id); + if (remoteStreamContent is null) + { + var stream = _virtualFileProvider + .GetFileInfo("/Images/eh-event.png") + .CreateReadStream(); + + remoteStreamContent = new RemoteStreamContent(stream) + { + ContentType = "image/png" + }; + + await stream.FlushAsync(); + } + + Response.Headers.Add("Accept-Ranges", "bytes"); + Response.ContentType = remoteStreamContent.ContentType; + + return remoteStreamContent; } [HttpGet] diff --git a/src/EventHub.Admin.HttpApi.Host/EventHubAdminHttpApiHostModule.cs b/src/EventHub.Admin.HttpApi.Host/EventHubAdminHttpApiHostModule.cs index b059e42..32df968 100644 --- a/src/EventHub.Admin.HttpApi.Host/EventHubAdminHttpApiHostModule.cs +++ b/src/EventHub.Admin.HttpApi.Host/EventHubAdminHttpApiHostModule.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; +using EventHub.Admin.Events; using EventHub.Admin.Organizations; using EventHub.Admin.Utils; using EventHub.EntityFrameworkCore; @@ -69,6 +70,7 @@ namespace EventHub.Admin Configure(options => { options.ConventionalControllers.FormBodyBindingIgnoredTypes.Add(typeof(UpdateOrganizationDto)); + options.ConventionalControllers.FormBodyBindingIgnoredTypes.Add(typeof(UpdateEventDto)); }); } diff --git a/src/EventHub.Admin.HttpApi.Host/Images/eh-event.png b/src/EventHub.Admin.HttpApi.Host/Images/eh-event.png new file mode 100644 index 0000000..b49547e Binary files /dev/null and b/src/EventHub.Admin.HttpApi.Host/Images/eh-event.png differ diff --git a/src/EventHub.Admin.Web/Pages/EventManagement.razor b/src/EventHub.Admin.Web/Pages/EventManagement.razor index 64435b2..0576599 100644 --- a/src/EventHub.Admin.Web/Pages/EventManagement.razor +++ b/src/EventHub.Admin.Web/Pages/EventManagement.razor @@ -3,11 +3,14 @@ @using EventHub.Admin.Permissions @using EventHub.Admin.Events @using EventHub.Events +@using EventHub.Web +@using Microsoft.Extensions.Options @using Volo.Abp.AspNetCore.Components.Notifications @inherits EventHubComponentBase @attribute [Authorize(EventHubPermissions.Events.Default)] @inject IEventAppService EventAppService @inject NavigationManager NavigationManager +@inject IOptions UrlOptions diff --git a/src/EventHub.Admin.Web/Pages/EventManagement.razor.cs b/src/EventHub.Admin.Web/Pages/EventManagement.razor.cs index a0ed087..e026c6b 100644 --- a/src/EventHub.Admin.Web/Pages/EventManagement.razor.cs +++ b/src/EventHub.Admin.Web/Pages/EventManagement.razor.cs @@ -12,6 +12,7 @@ using System.IO; using System.Globalization; using NUglify.Helpers; using Volo.Abp; +using Volo.Abp.Content; namespace EventHub.Admin.Web.Pages { @@ -92,9 +93,10 @@ namespace EventHub.Admin.Web.Pages { EditingEventId = input.Id; Event = await EventAppService.GetAsync(EditingEventId); - EditingEvent = ObjectMapper.Map(Event); - FillCoverImageUrl(EditingEvent.CoverImageContent); + + FileEntry = new FileEntry(); + CoverImageUrl = UrlOptions.Value.AdminApi.EnsureEndsWith('/') + "api/eventhub/admin/event/cover-image/" + EditingEventId; EditEventModal.Show(); } @@ -143,16 +145,15 @@ namespace EventHub.Admin.Web.Pages await GetEventsAsync(); } - private void FillCoverImageUrl(byte[] content) + private void SetCoverImageUrl(string contentType, byte[] content) { if (content.IsNullOrEmpty()) { return; } - var imageBase64Data = Convert.ToBase64String(content); - var imageDataUrl = $"data:image/png;base64,{imageBase64Data}"; - CoverImageUrl = imageDataUrl; + contentType = string.IsNullOrWhiteSpace(contentType) ? "image/png" : contentType; + CoverImageUrl = $"data:{contentType};base64,{Convert.ToBase64String(content)}"; } private async Task OnCoverImageFileChanged(FileChangedEventArgs e) @@ -163,20 +164,23 @@ namespace EventHub.Admin.Web.Pages return; } - using (var stream = new MemoryStream()) + var stream = new MemoryStream(); + await FileEntry.WriteToStreamAsync(stream); + stream.Seek(0, SeekOrigin.Begin); + + EditingEvent.CoverImageStreamContent = new RemoteStreamContent(stream) { - await FileEntry.WriteToStreamAsync(stream); + ContentType = FileEntry.Type, + FileName = FileEntry.Name + }; - stream.Seek(0, SeekOrigin.Begin); - EditingEvent.CoverImageContent = stream.ToArray(); - FillCoverImageUrl(EditingEvent.CoverImageContent); - await InvokeAsync(StateHasChanged); - } + SetCoverImageUrl(FileEntry.Type, stream.ToArray()); + await InvokeAsync(StateHasChanged); } private void OnDeleteCoverImageButtonClicked() { - EditingEvent.CoverImageContent = null; + EditingEvent.CoverImageStreamContent = null; FileEntry = new FileEntry(); CoverImageUrl = null; }