Browse Source

Create event edit page

pull/21/head
EngincanV 6 years ago
parent
commit
abdc71d5c3
  1. 4
      src/EventHub.Application.Contracts/Events/IEventAppService.cs
  2. 36
      src/EventHub.Application.Contracts/Events/UpdateEventDto.cs
  3. 34
      src/EventHub.Application/Events/EventAppService.cs
  4. 2
      src/EventHub.Domain.Shared/EventHubErrorCodes.cs
  5. 4
      src/EventHub.Domain.Shared/Localization/EventHub/en.json
  6. 3
      src/EventHub.Domain/Events/Event.cs
  7. 43
      src/EventHub.Domain/Events/EventManager.cs
  8. 3
      src/EventHub.Web/EventHubWebAutoMapperProfile.cs
  9. 16
      src/EventHub.Web/Pages/Events/Detail.cshtml
  10. 4
      src/EventHub.Web/Pages/Events/Detail.cshtml.cs
  11. 49
      src/EventHub.Web/Pages/Events/Edit.cshtml
  12. 147
      src/EventHub.Web/Pages/Events/Edit.cshtml.cs
  13. 19
      src/EventHub.Web/Pages/Events/Edit.js
  14. 4
      src/EventHub.Web/Pages/Organizations/Edit.cshtml

4
src/EventHub.Application.Contracts/Events/IEventAppService.cs

@ -17,5 +17,9 @@ namespace EventHub.Events
Task<EventLocationDto> GetLocationAsync(Guid id);
Task<List<CountryLookupDto>> GetCountriesLookupAsync();
Task<bool> IsEventOwnerAsync(Guid id);
Task UpdateAsync(Guid id, UpdateEventDto input);
}
}

36
src/EventHub.Application.Contracts/Events/UpdateEventDto.cs

@ -0,0 +1,36 @@
using System;
using System.ComponentModel.DataAnnotations;
using JetBrains.Annotations;
namespace EventHub.Events
{
public class UpdateEventDto
{
[Required]
[StringLength(EventConsts.MaxTitleLength, MinimumLength = EventConsts.MinTitleLength)]
public string Title { get; set; }
[Required]
[StringLength(EventConsts.MaxDescriptionLength, MinimumLength = EventConsts.MinDescriptionLength)]
public string Description { get; set; }
public bool IsOnline { get; set; }
[CanBeNull]
[StringLength(EventConsts.MaxOnlineLinkLength, MinimumLength = EventConsts.MinOnlineLinkLength)]
public string OnlineLink { get; set; }
public Guid? CountryId { get; set; }
[CanBeNull]
[StringLength(EventConsts.MaxCityLength, MinimumLength = EventConsts.MinCityLength)]
public string City { get; set; }
[CanBeNull]
[StringLength(EventConsts.MaxLanguageLength, MinimumLength = EventConsts.MinLanguageLength)]
public string Language { get; set; }
[Range(1, int.MaxValue)]
public int? Capacity { get; set; }
}
}

34
src/EventHub.Application/Events/EventAppService.cs

@ -171,5 +171,39 @@ namespace EventHub.Events
return ObjectMapper.Map<List<Country>, List<CountryLookupDto>>(countries);
}
public async Task<bool> IsEventOwnerAsync(Guid id)
{
var @event = await _eventRepository.GetAsync(id);
var organization = await _organizationRepository.GetAsync(@event.OrganizationId);
return CurrentUser.Id.HasValue && organization.OwnerUserId == CurrentUser.GetId();
}
public async Task UpdateAsync(Guid id, UpdateEventDto input)
{
var @event = await _eventRepository.GetAsync(id);
var organization = await _organizationRepository.GetAsync(@event.OrganizationId);
if (organization.OwnerUserId != CurrentUser.GetId())
{
throw new BusinessException(EventHubErrorCodes.NotAuthorizedToUpdateEventProfile)
.WithData("EventTitle", @event.Title);
}
var updatedEvent = await _eventManager.UpdateAsync(
id,
input.CountryId,
input.Title,
input.Description,
input.Language,
input.IsOnline,
input.OnlineLink,
input.City,
input.Capacity
);
await _eventRepository.UpdateAsync(updatedEvent);
}
}
}

2
src/EventHub.Domain.Shared/EventHubErrorCodes.cs

@ -8,5 +8,7 @@
public const string CantRegisterOrUnregisterForAPastEvent = "EventHub:CantRegisterOrUnregisterForAPastEvent";
public const string NotAuthorizedToUpdateOrganizationProfile = "EventHub:NotAuthorizedToUpdateOrganizationProfile";
public const string CapacityOfEventFull = "EventHub:CapacityOfEventFull";
public const string CapacityCantBeLowerThanRegisteredUserCount = "EventHub:CapacityCantBeLowerThanRegisteredUserCount";
public const string NotAuthorizedToUpdateEventProfile = "EventHub:NotAuthorizedToUpdateEventProfile";
}
}

4
src/EventHub.Domain.Shared/Localization/EventHub/en.json

@ -61,6 +61,8 @@
"AttendeesCanSeeEventLocation": "Only attendees can see the event's {0}.",
"LoginToSeeLocation": "Login to see location",
"LocationHasNotSpecifiedYet": "Event {0} has not been specified yet.",
"Language": "Language"
"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."
}
}

3
src/EventHub.Domain/Events/Event.cs

@ -94,6 +94,8 @@ namespace EventHub.Events
OnlineLink = onlineLink;
}
CountryId = null;
City = null;
return this;
}
@ -103,6 +105,7 @@ namespace EventHub.Events
City = city;
}
OnlineLink = null;
return this;
}
}

43
src/EventHub.Domain/Events/EventManager.cs

@ -1,6 +1,10 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using EventHub.Events.Registrations;
using EventHub.Organizations;
using Volo.Abp;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.Domain.Services;
namespace EventHub.Events
@ -8,10 +12,18 @@ namespace EventHub.Events
public class EventManager : DomainService
{
private readonly EventUrlCodeGenerator _eventUrlCodeGenerator;
private readonly IRepository<Event, Guid> _eventRepository;
private readonly IRepository<EventRegistration, Guid> _eventRegistrationRepository;
public EventManager(EventUrlCodeGenerator eventUrlCodeGenerator)
public EventManager(
EventUrlCodeGenerator eventUrlCodeGenerator,
IRepository<Event, Guid> eventRepository,
IRepository<EventRegistration, Guid> eventRegistrationRepository
)
{
_eventUrlCodeGenerator = eventUrlCodeGenerator;
_eventRepository = eventRepository;
_eventRegistrationRepository = eventRegistrationRepository;
}
public async Task<Event> CreateAsync(
@ -31,5 +43,34 @@ namespace EventHub.Events
description
);
}
public async Task<Event> UpdateAsync(
Guid id,
Guid? countryId,
string title,
string description,
string language,
bool isOnline,
string onlineLink,
string city,
int? capacity
)
{
var @event = await _eventRepository.GetAsync(id);
var registeredUserCount = await _eventRegistrationRepository.CountAsync(x => x.EventId == @event.Id);
if (capacity < registeredUserCount)
{
throw new BusinessException(EventHubErrorCodes.CapacityCantBeLowerThanRegisteredUserCount);
}
@event.SetTitle(title);
@event.SetDescription(description);
@event.SetLocation(isOnline, onlineLink, countryId, city);
@event.Capacity = capacity;
@event.Language = language;
return @event;
}
}
}

3
src/EventHub.Web/EventHubWebAutoMapperProfile.cs

@ -2,6 +2,7 @@
using EventHub.Events;
using EventHub.Organizations;
using EventHub.Web.Pages.Organizations;
using EditPageModel = EventHub.Web.Pages.Events.EditPageModel;
namespace EventHub.Web
{
@ -13,6 +14,8 @@ namespace EventHub.Web
CreateMap<Pages.Events.NewPageModel.NewEventViewModel, CreateEventDto>();
CreateMap<OrganizationProfileDto, EditOrganizationViewModel>();
CreateMap<EditOrganizationViewModel, UpdateOrganizationDto>();
CreateMap<EventDetailDto, EditPageModel.EditEventViewModel>();
CreateMap<EditPageModel.EditEventViewModel, UpdateEventDto>();
}
}
}

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

@ -14,7 +14,21 @@
<img abp-card-image="Top" src="https://picsum.photos/seed/@Model.Event.Id.ToString()/400/160?blur=8" alt="@Model.Event.Title"/>
<abp-card-body>
<abp-card-title>
<h2>@Model.Event.Title</h2>
@if (Model.IsEventOwner)
{
<div class="row">
<div class="col-9">
<h2>@Model.Event.Title</h2>
</div>
<div class="col-3 text-right">
<a href="/event/edit/@Model.Event.Url" class="btn btn-primary text-white">@L["Edit"] <i class="far fa-edit"></i></a>
</div>
</div>
}
else
{
<h2>@Model.Event.Title</h2>
}
</abp-card-title>
<abp-card-subtitle>
@EventDateHelper.GetDateRangeText(Model.Event.StartTime, Model.Event.EndTime) <br/>

4
src/EventHub.Web/Pages/Events/Detail.cshtml.cs

@ -11,6 +11,8 @@ namespace EventHub.Web.Pages.Events
[BindProperty(SupportsGet = true)]
public string Url { get; set; }
public bool IsEventOwner { get; set; }
public EventDetailDto Event { get; set; }
private readonly IEventAppService _eventAppService;
@ -43,6 +45,8 @@ namespace EventHub.Web.Pages.Events
);
}
IsEventOwner = await _eventAppService.IsEventOwnerAsync(Event.Id);
return Page();
}
}

49
src/EventHub.Web/Pages/Events/Edit.cshtml

@ -0,0 +1,49 @@
@page "/event/edit/{url}"
@inject IHtmlLocalizer<EventHubResource> L
@using EventHub.Localization
@using Microsoft.AspNetCore.Mvc.Localization
@model EventHub.Web.Pages.Events.EditPageModel
@section scripts {
<abp-script src="/Pages/Events/Edit.js"/>
}
<div class="container mb-4">
<h1>Edit Event</h1>
<ul class="nav nav-pills mt-3 mb-3" id="pills-tab" role="tablist">
<li class="nav-item">
<a class="nav-link active" id="event-info-tab" data-toggle="pill" href="#event-info" role="tab" aria-controls="event-info" aria-selected="true">Event Information</a>
</li>
<li class="nav-item">
<a class="nav-link" id="event-timing-tab" data-toggle="pill" href="#event-timing" role="tab" aria-controls="event-timing" aria-selected="false">Event Timing</a>
</li>
</ul>
<div class="tab-content" id="pills-tabContent">
<div class="tab-pane fade show active" id="event-info" role="tabpanel" aria-labelledby="event-info-tab">
<form method="post">
<abp-input asp-for="Event.Id" />
<abp-input asp-for="Event.Title"/>
<abp-input asp-for="Event.Description"/>
<abp-input asp-for="Event.IsOnline"/>
<div id="event-link-group" style="display: none">
<abp-input asp-for="Event.OnlineLink"/>
</div>
<div id="event-location-group">
<abp-select asp-for="Event.CountryId"/>
<abp-input asp-for="Event.City"/>
</div>
<abp-select asp-for="Event.Language"/>
<abp-input asp-for="Event.Capacity"/>
<abp-button size="Large" button-type="Primary" type="submit" text="@L["Submit"].Value"/>
</form>
</div>
<div class="tab-pane fade" id="event-timing" role="tabpanel" aria-labelledby="event-timing-tab">
//TODO
</div>
</div>
</div>

147
src/EventHub.Web/Pages/Events/Edit.cshtml.cs

@ -0,0 +1,147 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Globalization;
using System.Linq;
using System.Threading.Tasks;
using EventHub.Events;
using JetBrains.Annotations;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using NUglify.Helpers;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form;
namespace EventHub.Web.Pages.Events
{
public class EditPageModel : EventHubPageModel
{
[BindProperty(SupportsGet = true)]
public string Url { get; set; }
[BindProperty]
public EditEventViewModel Event { get; set; }
public List<SelectListItem> Countries { get; private set; }
public List<SelectListItem> Languages { get; private set; }
private readonly IEventAppService _eventAppService;
public EditPageModel(IEventAppService eventAppService)
{
_eventAppService = eventAppService;
}
public async Task OnGetAsync()
{
var urlCode = EventUrlCodeHelper.GetCodeFromUrl(Url);
var eventDetailDto = await _eventAppService.GetByUrlCodeAsync(urlCode);
Event = ObjectMapper.Map<EventDetailDto, EditEventViewModel>(eventDetailDto);
FillLanguages();
await FillCountriesAsync();
await GetLocationInfoAsync();
}
public async Task<IActionResult> OnPostAsync()
{
try
{
ValidateModel();
var input = ObjectMapper.Map<EditEventViewModel, UpdateEventDto>(Event);
await _eventAppService.UpdateAsync(Event.Id, input);
return RedirectToPage("./Detail", new { url = Url });
}
catch (Exception exception)
{
ShowAlert(exception);
FillLanguages();
await FillCountriesAsync();
return Page();
}
}
private async Task FillCountriesAsync()
{
var result = await _eventAppService.GetCountriesLookupAsync();
Countries = result.Select(
country => new SelectListItem
{
Value = country.Id.ToString(),
Text = country.Name
}
).ToList();
}
private void FillLanguages()
{
var result = CultureInfo.GetCultures(CultureTypes.NeutralCultures)
.DistinctBy(x => x.EnglishName)
.OrderBy(x => x.EnglishName)
.ToList();
result.Remove(result.Single(x => x.TwoLetterISOLanguageName == "iv")); // Invariant Language
Languages = result.Select(
cultureInfo => new SelectListItem
{
Value = cultureInfo.TwoLetterISOLanguageName,
Text = cultureInfo.EnglishName
}
).ToList();
}
private async Task GetLocationInfoAsync()
{
var eventLocationDto = await _eventAppService.GetLocationAsync(Event.Id);
Event.City = eventLocationDto.City;
Event.OnlineLink = eventLocationDto.OnlineLink;
Event.CountryId = Guid.TryParse(
Countries.FirstOrDefault(x => x.Text == eventLocationDto.Country)?.Value,
out var countryId
)
? countryId
: null;
}
public class EditEventViewModel
{
[HiddenInput]
public Guid Id { get; set; }
[Required]
[StringLength(EventConsts.MaxTitleLength, MinimumLength = EventConsts.MinTitleLength)]
public string Title { get; set; }
[Required]
[StringLength(EventConsts.MaxDescriptionLength, MinimumLength = EventConsts.MinDescriptionLength)]
[TextArea]
public string Description { get; set; }
public bool IsOnline { get; set; }
[CanBeNull]
[StringLength(EventConsts.MaxOnlineLinkLength, MinimumLength = EventConsts.MinOnlineLinkLength)]
public string OnlineLink { get; set; }
[SelectItems(nameof(Countries))]
[DisplayName("Country")]
public Guid? CountryId { get; set; }
[CanBeNull]
[StringLength(EventConsts.MaxCityLength, MinimumLength = EventConsts.MinCityLength)]
public string City { get; set; }
[SelectItems(nameof(Languages))]
[DisplayName("Language")]
public string Language { get; set; }
[Range(1, int.MaxValue)]
public int? Capacity { get; set; }
}
}
}

19
src/EventHub.Web/Pages/Events/Edit.js

@ -0,0 +1,19 @@
$(function () {
$("#Event_CountryId").prepend("<option value=''></option>");
$("#Event_Language").prepend("<option value=''></option>");
if($("#Event_IsOnline").is(":checked")) {
$("#event-link-group").show();
$("#event-location-group").hide();
}
$('#Event_IsOnline').click(function() {
if ($(this).is(':checked')) {
$("#event-link-group").show();
$("#event-location-group").hide();
}else{
$("#event-link-group").hide();
$("#event-location-group").show();
}
});
});

4
src/EventHub.Web/Pages/Organizations/Edit.cshtml

@ -5,9 +5,7 @@
@model EventHub.Web.Pages.Organizations.EditPageModel
@section scripts {
<abp-script-bundle>
<abp-script src="/Pages/Organizations/Edit.js"/>
</abp-script-bundle>
<abp-script src="/Pages/Organizations/Edit.js"/>
}
<div class="container mb-4">

Loading…
Cancel
Save