Browse Source

Add event cover image

pull/21/head
Berkan 6 years ago
parent
commit
f4ed4780dc
  1. 3
      src/EventHub.Application.Contracts/Events/CreateEventDto.cs
  2. 2
      src/EventHub.Application.Contracts/Events/EventDetailDto.cs
  3. 2
      src/EventHub.Application.Contracts/Events/EventInListDto.cs
  4. 2
      src/EventHub.Application.Contracts/Events/IEventAppService.cs
  5. 36
      src/EventHub.Application/Events/EventAppService.cs
  6. 2
      src/EventHub.Domain.Shared/Events/EventConsts.cs
  7. 8
      src/EventHub.Domain.Shared/Localization/EventHub/en.json
  8. 10
      src/EventHub.Domain/Events/EventCoverImageContainer.cs
  9. 22
      src/EventHub.Web/Controllers/EventController.cs
  10. 8
      src/EventHub.Web/Controllers/OrganizationController.cs
  11. 4
      src/EventHub.Web/EventHubWebAutoMapperProfile.cs
  12. 9
      src/EventHub.Web/Pages/Events/Detail.cshtml
  13. 2
      src/EventHub.Web/Pages/Events/Edit.cshtml.cs
  14. 12
      src/EventHub.Web/Pages/Events/New.cshtml
  15. 20
      src/EventHub.Web/Pages/Events/New.cshtml.cs
  16. 60
      src/EventHub.Web/Pages/Events/New.js
  17. 9
      src/EventHub.Web/Pages/Index.cshtml

3
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; }

2
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; }

2
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; }

2
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);
}
}

36
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<Organization, Guid> _organizationRepository;
private readonly IRepository<AppUser, Guid> _userRepository;
private readonly IRepository<Country, Guid> _countriesRepository;
private readonly IBlobContainer<EventCoverImageContainer> _eventBlobContainer;
public EventAppService(
EventManager eventManager,
@ -29,7 +31,8 @@ namespace EventHub.Events
IRepository<Event, Guid> eventRepository,
IRepository<Organization, Guid> organizationRepository,
IRepository<AppUser, Guid> userRepository,
IRepository<Country, Guid> countriesRepository)
IRepository<Country, Guid> countriesRepository,
IBlobContainer<EventCoverImageContainer> 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, EventDto>(@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<Event, EventInListDto>(i.@event);
@ -118,7 +127,12 @@ namespace EventHub.Events
}
).ToList();
return new PagedResultDto<EventInListDto>(totalCount, dtos);
foreach (var @event in events)
{
@event.CoverImageContent = await GetCoverImageAsync(@event.Id);
}
return new PagedResultDto<EventInListDto>(totalCount, events);
}
public async Task<EventDetailDto> 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<byte[]> GetCoverImageAsync(Guid id)
{
var blobName = id.ToString();
return await _eventBlobContainer.GetAllBytesOrNullAsync(blobName);
}
}
}

2
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;
}
}

8
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."
}
}

10
src/EventHub.Domain/Events/EventCoverImageContainer.cs

@ -0,0 +1,10 @@
using Volo.Abp.BlobStoring;
namespace EventHub.Events
{
[BlobContainerName("event-cover-images")]
public class EventCoverImageContainer
{
}
}

22
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);
}
}
}
}

8
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);
}
}
}
}

4
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<NewPageModel.CreateOrganizationViewModel, CreateOrganizationDto>();
CreateMap<Pages.Events.NewPageModel.NewEventViewModel, CreateEventDto>();
CreateMap<Pages.Events.NewPageModel.NewEventViewModel, CreateEventDto>()
.Ignore(x => x.CoverImageContent);
CreateMap<OrganizationProfileDto, EditOrganizationViewModel>();
CreateMap<EditOrganizationViewModel, UpdateOrganizationDto>();
CreateMap<EventDetailDto, EditPageModel.EditEventViewModel>();

9
src/EventHub.Web/Pages/Events/Detail.cshtml

@ -11,7 +11,14 @@
<abp-row>
<abp-column size-lg="_8" size-md="_6">
<abp-card class="mb-3">
<img abp-card-image="Top" src="https://picsum.photos/seed/@Model.Event.Id.ToString()/400/160?blur=8" alt="@Model.Event.Title"/>
@if (Model.Event.CoverImageContent is null)
{
<img abp-card-image="Top" src="https://picsum.photos/seed/@Model.Event.Id.ToString()/400/160?blur=8" alt="@Model.Event.Title"/>
}
else
{
<img abp-card-image="Top" style="max-height: 300px; min-height: 200px;" src="@($"data:image/png;base64,{Convert.ToBase64String(Model.Event.CoverImageContent)}")" alt="@Model.Event.Title"/>
}
<abp-card-body>
<abp-card-title>
@if (Model.IsEventOwner)

2
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; }
}

12
src/EventHub.Web/Pages/Events/New.cshtml

@ -2,6 +2,7 @@
@inject IHtmlLocalizer<EventHubResource> 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
{
<form method="post">
<form method="post" enctype="multipart/form-data">
<abp-select asp-for="Event.OrganizationId" />
<abp-input asp-for="Event.Title" />
<abp-input asp-for="Event.StartTime" />
<abp-input asp-for="Event.EndTime" />
<abp-input asp-for="Event.Description" />
<abp-input asp-for="Event.CoverImageFile" />
<abp-input asp-for="Event.IsOnline" />
<div id="event-link-group" style="display: none">
<abp-input asp-for="Event.OnlineLink" />
@ -36,4 +38,12 @@ else
<abp-input asp-for="Event.Capacity" />
<abp-button size="Large" button-type="Primary" type="submit" text="@L["Submit"].Value" />
</form>
<abp-modal centered="true" scrollable="true" size="Small" id="cover-image-preview-modal">
<abp-modal-header title="Cover Image Preview"></abp-modal-header>
<abp-modal-body>
<img class="img-fluid" id="img-upload" alt="event-cover-image-preview"/>
</abp-modal-body>
<abp-modal-footer buttons="@(AbpModalButtons.Close)"></abp-modal-footer>
</abp-modal>
}

20
src/EventHub.Web/Pages/Events/New.cshtml.cs

@ -3,11 +3,14 @@ using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using EventHub.Events;
using EventHub.Organizations;
using EventHub.Web.Helpers;
using JetBrains.Annotations;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using NUglify.Helpers;
@ -96,6 +99,16 @@ namespace EventHub.Web.Pages.Events
ValidateModel();
var input = ObjectMapper.Map<NewEventViewModel, CreateEventDto>(Event);
if (Event.CoverImageFile != null && Event.CoverImageFile.Length > 0)
{
using (var memoryStream = new MemoryStream())
{
await Event.CoverImageFile.CopyToAsync(memoryStream);
input.CoverImageContent = memoryStream.ToArray();
}
}
var eventDto = await _eventAppService.CreateAsync(input);
return RedirectToPage("/Events/Detail", new {url = eventDto.UrlCode});
@ -130,6 +143,13 @@ namespace EventHub.Web.Pages.Events
[StringLength(EventConsts.MaxDescriptionLength, MinimumLength = EventConsts.MinDescriptionLength)]
[TextArea]
public string Description { get; set; }
[CanBeNull]
[Display(Name = "Cover Image")]
[DataType(DataType.Upload)]
[MaxFileSize(EventConsts.MaxCoverImageFileSize)]
[AllowedExtensions(new string[] { ".jpg", ".png", ".jpeg" })]
public IFormFile CoverImageFile { get; set; }
public bool IsOnline { get; set; }

60
src/EventHub.Web/Pages/Events/New.js

@ -1,4 +1,6 @@
$(function () {
var l = abp.localization.getResource('EventHub');
$("#Event_CountryId").prepend("<option value='' selected='selected'></option>");
$("#Event_Language").prepend("<option value='' selected='selected'></option>");
@ -11,4 +13,62 @@ $(function () {
$("#event-location-group").show();
}
});
var fileInput = document.getElementById('Event_CoverImageFile');
var file;
fileInput.addEventListener('change', function () {
var showModal = true;
file = fileInput.files[0];
var permittedExtensions = ["jpg", "jpeg", "png"]
var fileExtension = $(this).val().split('.').pop();
if (permittedExtensions.indexOf(fileExtension) === -1) {
showModal = false;
abp.message.error(l('EventCoverImageExtensionNotAllowed'))
.then(() => {
$('#Event_CoverImageFile').val('');
file = null;
});
}
else if(file.size > 1024*1024) {
showModal = false;
abp.message.error(l('EventCoverImageSizeExceedMessage'))
.then(() => {
$('#Event_CoverImageFile').val('');
file = null;
});
}
var img = new Image();
img.onload = function() {
var imageError = true;
var sizes = {
width: this.width,
height: this.height
};
URL.revokeObjectURL(this.src);
if(showModal && imageError) {
readURL(file);
$('#cover-image-preview-modal').modal('show');
}
}
var objectURL = URL.createObjectURL(file);
img.src = objectURL;
});
function readURL(input) {
if (input) {
var reader = new FileReader();
reader.onload = function (e) {
$('#img-upload').attr('src', e.target.result);
}
reader.readAsDataURL(input);
}
}
});

9
src/EventHub.Web/Pages/Index.cshtml

@ -24,7 +24,14 @@
{
<abp-column size-lg="_4" size-md="_6">
<abp-card class="mb-3">
<img abp-card-image="Top" src="https://picsum.photos/seed/@eventItem.Id.ToString()/400/160?blur=8" alt="@eventItem.Title"/>
@if (eventItem.CoverImageContent is null)
{
<img abp-card-image="Top" src="https://picsum.photos/seed/@eventItem.Id.ToString()/400/160?blur=8" alt="@eventItem.Title"/>
}
else
{
<img abp-card-image="Top" style="max-height: 300px; min-height: 200px;" src="@($"data:image/png;base64,{Convert.ToBase64String(eventItem.CoverImageContent)}")" alt="@eventItem.Title"/>
}
<abp-card-body>
<abp-card-title>@eventItem.Title</abp-card-title>
<abp-card-subtitle>

Loading…
Cancel
Save