diff --git a/src/EventHub.Application.Contracts/Events/CreateEventDto.cs b/src/EventHub.Application.Contracts/Events/CreateEventDto.cs index 3fdfdfa..801c904 100644 --- a/src/EventHub.Application.Contracts/Events/CreateEventDto.cs +++ b/src/EventHub.Application.Contracts/Events/CreateEventDto.cs @@ -22,6 +22,9 @@ namespace EventHub.Events [Required] [StringLength(EventConsts.MaxDescriptionLength, MinimumLength = EventConsts.MinDescriptionLength)] public string Description { get; set; } + + [CanBeNull] + public byte[] CoverImageContent { get; set; } public bool IsOnline { get; set; } diff --git a/src/EventHub.Application.Contracts/Events/EventDetailDto.cs b/src/EventHub.Application.Contracts/Events/EventDetailDto.cs index fa7c64a..e8f17dd 100644 --- a/src/EventHub.Application.Contracts/Events/EventDetailDto.cs +++ b/src/EventHub.Application.Contracts/Events/EventDetailDto.cs @@ -17,6 +17,8 @@ namespace EventHub.Events public DateTime EndTime { get; set; } + public byte[] CoverImageContent { get; set; } + public bool IsOnline { get; set; } public bool IsLive { get; set; } diff --git a/src/EventHub.Application.Contracts/Events/EventInListDto.cs b/src/EventHub.Application.Contracts/Events/EventInListDto.cs index 1b55197..377ebc8 100644 --- a/src/EventHub.Application.Contracts/Events/EventInListDto.cs +++ b/src/EventHub.Application.Contracts/Events/EventInListDto.cs @@ -16,6 +16,8 @@ namespace EventHub.Events public DateTime StartTime { get; set; } public DateTime EndTime { get; set; } + + public byte[] CoverImageContent { get; set; } public bool IsOnline { get; set; } diff --git a/src/EventHub.Application.Contracts/Events/IEventAppService.cs b/src/EventHub.Application.Contracts/Events/IEventAppService.cs index c8cb24a..ca9132b 100644 --- a/src/EventHub.Application.Contracts/Events/IEventAppService.cs +++ b/src/EventHub.Application.Contracts/Events/IEventAppService.cs @@ -23,5 +23,7 @@ namespace EventHub.Events Task UpdateAsync(Guid id, UpdateEventDto input); Task UpdateEventTimingAsync(Guid id, UpdateEventTimingDto input); + + Task SaveCoverImageAsync(Guid id, byte[] coverImageContent); } } diff --git a/src/EventHub.Application/Events/EventAppService.cs b/src/EventHub.Application/Events/EventAppService.cs index 8d5f0dc..fe9ba5a 100644 --- a/src/EventHub.Application/Events/EventAppService.cs +++ b/src/EventHub.Application/Events/EventAppService.cs @@ -9,6 +9,7 @@ using EventHub.Users; using Microsoft.AspNetCore.Authorization; using Volo.Abp; using Volo.Abp.Application.Dtos; +using Volo.Abp.BlobStoring; using Volo.Abp.Domain.Repositories; using Volo.Abp.Users; @@ -22,6 +23,7 @@ namespace EventHub.Events private readonly IRepository _organizationRepository; private readonly IRepository _userRepository; private readonly IRepository _countriesRepository; + private readonly IBlobContainer _eventBlobContainer; public EventAppService( EventManager eventManager, @@ -29,7 +31,8 @@ namespace EventHub.Events IRepository eventRepository, IRepository organizationRepository, IRepository userRepository, - IRepository countriesRepository) + IRepository countriesRepository, + IBlobContainer eventBlobContainer) { _eventManager = eventManager; _eventRegistrationManager = eventRegistrationManager; @@ -37,6 +40,7 @@ namespace EventHub.Events _organizationRepository = organizationRepository; _userRepository = userRepository; _countriesRepository = countriesRepository; + _eventBlobContainer = eventBlobContainer; } [Authorize] @@ -62,6 +66,11 @@ namespace EventHub.Events @event.Language = input.Language; @event.Capacity = input.Capacity; + if (input.CoverImageContent != null && input.CoverImageContent.Length > 0) + { + await SaveCoverImageAsync(@event.Id, input.CoverImageContent); + } + await _eventRepository.InsertAsync(@event); return ObjectMapper.Map(@event); @@ -107,7 +116,7 @@ namespace EventHub.Events var items = await AsyncExecuter.ToListAsync(query); var now = Clock.Now; - var dtos = items.Select( + var events = items.Select( i => { var dto = ObjectMapper.Map(i.@event); @@ -118,7 +127,12 @@ namespace EventHub.Events } ).ToList(); - return new PagedResultDto(totalCount, dtos); + foreach (var @event in events) + { + @event.CoverImageContent = await GetCoverImageAsync(@event.Id); + } + + return new PagedResultDto(totalCount, events); } public async Task GetByUrlCodeAsync(string urlCode) @@ -130,6 +144,7 @@ namespace EventHub.Events dto.OrganizationName = organization.Name; dto.OrganizationDisplayName = organization.DisplayName; + dto.CoverImageContent = await GetCoverImageAsync(dto.Id); return dto; } @@ -221,5 +236,20 @@ namespace EventHub.Events await _eventRepository.UpdateAsync(@event); } + + [Authorize] + public async Task SaveCoverImageAsync(Guid id, byte[] coverImageContent) + { + var blobName = id.ToString(); + + await _eventBlobContainer.SaveAsync(blobName, coverImageContent, overrideExisting: true); + } + + private async Task GetCoverImageAsync(Guid id) + { + var blobName = id.ToString(); + + return await _eventBlobContainer.GetAllBytesOrNullAsync(blobName); + } } } \ No newline at end of file diff --git a/src/EventHub.Domain.Shared/Events/EventConsts.cs b/src/EventHub.Domain.Shared/Events/EventConsts.cs index a3e9abb..e9a819c 100644 --- a/src/EventHub.Domain.Shared/Events/EventConsts.cs +++ b/src/EventHub.Domain.Shared/Events/EventConsts.cs @@ -22,5 +22,7 @@ public const int MaxLanguageLength = 16; public const int MaxTimingChangeCountForUser = 2; + + public const int MaxCoverImageFileSize = 1024 * 1024; } } diff --git a/src/EventHub.Domain.Shared/Localization/EventHub/en.json b/src/EventHub.Domain.Shared/Localization/EventHub/en.json index 92dcc5a..d9ede49 100644 --- a/src/EventHub.Domain.Shared/Localization/EventHub/en.json +++ b/src/EventHub.Domain.Shared/Localization/EventHub/en.json @@ -64,6 +64,12 @@ "Language": "Language", "EventHub:CapacityCantBeLowerThanRegisteredUserCount": "Capacity can not be lower than the currently registered user count.", "EventHub:NotAuthorizedToUpdateEventProfile": "You are not authorized to update the \"{EventTitle}\" event.", - "EventHub:CantChangeEventTiming": "Can not change the event timing more than {MaxTimingChangeLimit} times." + "CoverImage": "Cover Image", + "EventHub:CantChangeEventTiming": "Can not change the event timing more than {MaxTimingChangeLimit} times.", + "EventCoverImageEditSuccessMessage": "The event's cover image has been changed successfully.", + "ChooseEventCoverImage": "Choose event cover image...", + "EventCoverImageSizeExceedMessage": "The image is too large to upload. Max image size: 1MB.", + "EventCoverImageExtensionNotAllowed": "This image extension is not allowed. Allowed extensions: png, jpg, jpeg", + "ChooseEventCoverImageInfo": "Maximum image size: 1MB." } } diff --git a/src/EventHub.Domain/Events/EventCoverImageContainer.cs b/src/EventHub.Domain/Events/EventCoverImageContainer.cs new file mode 100644 index 0000000..e47884e --- /dev/null +++ b/src/EventHub.Domain/Events/EventCoverImageContainer.cs @@ -0,0 +1,10 @@ +using Volo.Abp.BlobStoring; + +namespace EventHub.Events +{ + [BlobContainerName("event-cover-images")] + public class EventCoverImageContainer + { + + } +} \ No newline at end of file diff --git a/src/EventHub.Web/Controllers/EventController.cs b/src/EventHub.Web/Controllers/EventController.cs index 9766eca..12d92bf 100644 --- a/src/EventHub.Web/Controllers/EventController.cs +++ b/src/EventHub.Web/Controllers/EventController.cs @@ -1,10 +1,11 @@ -using System; +using System.IO; using System.Threading.Tasks; using EventHub.Events; using EventHub.Web.Pages.Events; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Volo.Abp.AspNetCore.Mvc; +using EditPageModel = EventHub.Web.Pages.Events.EditPageModel; namespace EventHub.Web.Controllers { @@ -25,5 +26,24 @@ namespace EventHub.Web.Controllers { await _eventAppService.UpdateEventTimingAsync(input.Id, new UpdateEventTimingDto { StartTime = input.StartTime, EndTime = input.EndTime }); } + + [HttpPost] + [Authorize] + [Route("save-cover-image")] + public async Task SaveCoverImage([FromForm] EventCoverImageInput input) + { + var coverImageContent = new byte[] {}; + + if (input.CoverImageFile.Length > 0) + { + using (var memoryStream = new MemoryStream()) + { + await input.CoverImageFile.CopyToAsync(memoryStream); + coverImageContent = memoryStream.ToArray(); + } + + await _eventAppService.SaveCoverImageAsync(input.EventId, coverImageContent); + } + } } } \ No newline at end of file diff --git a/src/EventHub.Web/Controllers/OrganizationController.cs b/src/EventHub.Web/Controllers/OrganizationController.cs index 14f7667..06a9859 100644 --- a/src/EventHub.Web/Controllers/OrganizationController.cs +++ b/src/EventHub.Web/Controllers/OrganizationController.cs @@ -23,18 +23,18 @@ namespace EventHub.Web.Controllers [Route("save-profile-picture")] public async Task SaveProfilePicture([FromForm] OrganizationProfilePictureInput input) { - byte[] profilePictureContent = new byte[] {}; + var profilePictureContent = new byte[] {}; - if (input.ProfilePictureFile != null && input.ProfilePictureFile.Length > 0) + if (input.ProfilePictureFile.Length > 0) { using (var memoryStream = new MemoryStream()) { await input.ProfilePictureFile.CopyToAsync(memoryStream); profilePictureContent = memoryStream.ToArray(); } - } - await _organizationAppService.SaveProfilePictureAsync(input.OrganizationId, profilePictureContent); + await _organizationAppService.SaveProfilePictureAsync(input.OrganizationId, profilePictureContent); + } } } } \ No newline at end of file diff --git a/src/EventHub.Web/EventHubWebAutoMapperProfile.cs b/src/EventHub.Web/EventHubWebAutoMapperProfile.cs index 82574df..c5a306d 100644 --- a/src/EventHub.Web/EventHubWebAutoMapperProfile.cs +++ b/src/EventHub.Web/EventHubWebAutoMapperProfile.cs @@ -2,6 +2,7 @@ using EventHub.Events; using EventHub.Organizations; using EventHub.Web.Pages.Organizations; +using Volo.Abp.AutoMapper; using EditPageModel = EventHub.Web.Pages.Events.EditPageModel; namespace EventHub.Web @@ -11,7 +12,8 @@ namespace EventHub.Web public EventHubWebAutoMapperProfile() { CreateMap(); - CreateMap(); + CreateMap() + .Ignore(x => x.CoverImageContent); CreateMap(); CreateMap(); CreateMap(); diff --git a/src/EventHub.Web/Pages/Events/Detail.cshtml b/src/EventHub.Web/Pages/Events/Detail.cshtml index ac086ea..75cb342 100644 --- a/src/EventHub.Web/Pages/Events/Detail.cshtml +++ b/src/EventHub.Web/Pages/Events/Detail.cshtml @@ -11,7 +11,14 @@ - @Model.Event.Title + @if (Model.Event.CoverImageContent is null) + { + @Model.Event.Title + } + else + { + @Model.Event.Title + } @if (Model.IsEventOwner) diff --git a/src/EventHub.Web/Pages/Events/Edit.cshtml.cs b/src/EventHub.Web/Pages/Events/Edit.cshtml.cs index 0446285..ee1b9ad 100644 --- a/src/EventHub.Web/Pages/Events/Edit.cshtml.cs +++ b/src/EventHub.Web/Pages/Events/Edit.cshtml.cs @@ -168,7 +168,7 @@ namespace EventHub.Web.Pages.Events [Required] [DataType(DataType.Upload)] - // [MaxFileSize(EventConsts.MaxCoverImageFileSize)] + [MaxFileSize(EventConsts.MaxCoverImageFileSize)] [AllowedExtensions(new string[] { ".jpg", ".png", ".jpeg" })] public IFormFile CoverImageFile { get; set; } } diff --git a/src/EventHub.Web/Pages/Events/New.cshtml b/src/EventHub.Web/Pages/Events/New.cshtml index 395b9bb..32ccba2 100644 --- a/src/EventHub.Web/Pages/Events/New.cshtml +++ b/src/EventHub.Web/Pages/Events/New.cshtml @@ -2,6 +2,7 @@ @inject IHtmlLocalizer L @using EventHub.Localization @using Microsoft.AspNetCore.Mvc.Localization +@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal @model EventHub.Web.Pages.Events.NewPageModel @section scripts { @@ -18,12 +19,13 @@ } else { -
+ +