diff --git a/src/EventHub.Application.Contracts/Events/AddSessionDto.cs b/src/EventHub.Application.Contracts/Events/AddSessionDto.cs new file mode 100644 index 0000000..6a8d3ac --- /dev/null +++ b/src/EventHub.Application.Contracts/Events/AddSessionDto.cs @@ -0,0 +1,23 @@ +using System; +using System.ComponentModel.DataAnnotations; + +namespace EventHub.Events; + +public class AddSessionDto +{ + public Guid TrackId { get; set; } + + [Required] + [StringLength(SessionConsts.MaxTitleLength, MinimumLength = SessionConsts.MinTitleLength)] + public string Title { get; set; } + + public DateTime StartTime { get; set; } + + public DateTime EndTime { get; set; } + + [Required] + [StringLength(SessionConsts.MaxDescriptionLength, MinimumLength = SessionConsts.MinDescriptionLength)] + public string Description { get; set; } + + public string Language { get; set; } +} diff --git a/src/EventHub.Application.Contracts/Events/AddTractDto.cs b/src/EventHub.Application.Contracts/Events/AddTractDto.cs new file mode 100644 index 0000000..a0e2663 --- /dev/null +++ b/src/EventHub.Application.Contracts/Events/AddTractDto.cs @@ -0,0 +1,10 @@ +using System.ComponentModel.DataAnnotations; + +namespace EventHub.Events; + +public class AddTractDto +{ + [Required] + [StringLength(TrackConsts.MaxNameLength)] + public string Name { get; set; } +} diff --git a/src/EventHub.Application.Contracts/Events/EventDetailDto.cs b/src/EventHub.Application.Contracts/Events/EventDetailDto.cs index ddb3eec..9adea00 100644 --- a/src/EventHub.Application.Contracts/Events/EventDetailDto.cs +++ b/src/EventHub.Application.Contracts/Events/EventDetailDto.cs @@ -1,4 +1,6 @@ using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; using Volo.Abp.Application.Dtos; namespace EventHub.Events @@ -40,5 +42,12 @@ namespace EventHub.Events public string Language { get; set; } public int? Capacity { get; set; } + + public List Tracks { get; set; } + + public EventDetailDto() + { + Tracks = new List(); + } } } diff --git a/src/EventHub.Application.Contracts/Events/EventInListDto.cs b/src/EventHub.Application.Contracts/Events/EventInListDto.cs index a2235ac..413779c 100644 --- a/src/EventHub.Application.Contracts/Events/EventInListDto.cs +++ b/src/EventHub.Application.Contracts/Events/EventInListDto.cs @@ -1,9 +1,10 @@ using System; using Volo.Abp.Application.Dtos; +using Volo.Abp.Auditing; namespace EventHub.Events { - public class EventInListDto : EntityDto + public class EventInListDto : EntityDto, IHasModificationTime, IHasCreationTime { public string OrganizationName { get; set; } @@ -30,5 +31,9 @@ namespace EventHub.Events public string UrlCode { get; set; } public string Url { get; set; } + + public DateTime CreationTime { get; } + + public DateTime? LastModificationTime { get; set; } } } diff --git a/src/EventHub.Application.Contracts/Events/IEventAppService.cs b/src/EventHub.Application.Contracts/Events/IEventAppService.cs index 8296d9b..dfae239 100644 --- a/src/EventHub.Application.Contracts/Events/IEventAppService.cs +++ b/src/EventHub.Application.Contracts/Events/IEventAppService.cs @@ -1,11 +1,9 @@ using System; using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; using System.Threading.Tasks; using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Services; using Volo.Abp.Content; -using Volo.Abp.SettingManagement; namespace EventHub.Events { @@ -15,6 +13,8 @@ namespace EventHub.Events Task> GetListAsync(EventListFilterDto input); + Task> GetDraftEventsByUserId(Guid userId); + Task GetByUrlCodeAsync(string urlCode); Task GetLocationAsync(Guid id); @@ -25,24 +25,12 @@ namespace EventHub.Events Task UpdateAsync(Guid id, UpdateEventDto input); + Task AddTrackAsync(Guid id, AddTractDto input); + + Task> GetTracksAsync(Guid id); + Task AddSessionAsync(Guid id, AddSessionDto input); Task GetCoverImageAsync(Guid id); } - - public class AddSessionDto - { - public Guid TrackId { get; set; } - [Required] - [StringLength(SessionConsts.MaxTitleLength, - MinimumLength = SessionConsts.MinTitleLength)] - public string Title { get; set; } - public DateTime StartTime { get; set; } - public DateTime EndTime { get; set; } - [Required] - [StringLength(SessionConsts.MaxDescriptionLength, - MinimumLength = SessionConsts.MinDescriptionLength)] - public string Description { get; set; } - public string Language { get; set; } - } } diff --git a/src/EventHub.Application.Contracts/Events/TrackDto.cs b/src/EventHub.Application.Contracts/Events/TrackDto.cs new file mode 100644 index 0000000..9e9e18b --- /dev/null +++ b/src/EventHub.Application.Contracts/Events/TrackDto.cs @@ -0,0 +1,9 @@ +using System; +using Volo.Abp.Application.Dtos; + +namespace EventHub.Events; + +public class TrackDto : EntityDto +{ + public string Name { get; set; } +} diff --git a/src/EventHub.Application.Contracts/Events/UpdateEventDto.cs b/src/EventHub.Application.Contracts/Events/UpdateEventDto.cs index 0e1edf6..49a1a49 100644 --- a/src/EventHub.Application.Contracts/Events/UpdateEventDto.cs +++ b/src/EventHub.Application.Contracts/Events/UpdateEventDto.cs @@ -7,6 +7,8 @@ namespace EventHub.Events { public class UpdateEventDto { + //TODO: Add OrganizationId + [Required] [StringLength(EventConsts.MaxTitleLength, MinimumLength = EventConsts.MinTitleLength)] public string Title { get; set; } @@ -45,4 +47,4 @@ namespace EventHub.Events [Range(1, int.MaxValue)] public int? Capacity { get; set; } } -} \ No newline at end of file +} diff --git a/src/EventHub.Application/EventHubApplicationAutoMapperProfile.cs b/src/EventHub.Application/EventHubApplicationAutoMapperProfile.cs index 72e16f2..f73087a 100644 --- a/src/EventHub.Application/EventHubApplicationAutoMapperProfile.cs +++ b/src/EventHub.Application/EventHubApplicationAutoMapperProfile.cs @@ -27,10 +27,13 @@ namespace EventHub .Ignore(x => x.OrganizationDisplayName) .Ignore(x => x.IsLiveNow); CreateMap() + .ForMember(x => x.Tracks, memberOptions => memberOptions.MapFrom(m => m.Tracks)) .Ignore(x => x.OrganizationId) .Ignore(x => x.OrganizationName) .Ignore(x => x.OrganizationDisplayName); + CreateMap(); + CreateMap(); CreateMap() diff --git a/src/EventHub.Application/Events/EventAppService.cs b/src/EventHub.Application/Events/EventAppService.cs index b70bd38..f8f08b7 100644 --- a/src/EventHub.Application/Events/EventAppService.cs +++ b/src/EventHub.Application/Events/EventAppService.cs @@ -12,7 +12,6 @@ using Volo.Abp.Authorization; using Volo.Abp.BlobStoring; using Volo.Abp.Content; using Volo.Abp.Domain.Repositories; -using Volo.Abp.Identity; using Volo.Abp.Users; namespace EventHub.Events @@ -79,6 +78,8 @@ namespace EventHub.Events await SaveCoverImageAsync(@event.Id, input.CoverImageStreamContent); } + @event.Publish(false); + await _eventRepository.InsertAsync(@event); return ObjectMapper.Map(@event); @@ -92,7 +93,8 @@ namespace EventHub.Events var query = from @event in eventQueryable join organization in organizationQueryable on @event.OrganizationId equals organization.Id - select new {@event, organization}; + where !@event.IsDraft + select new { @event, organization }; if (input.RegisteredUserId.HasValue) { @@ -147,27 +149,32 @@ namespace EventHub.Events query = query.OrderBy(x => x.@event.StartTime); } - var items = await AsyncExecuter.ToListAsync(query); - var now = Clock.Now; + var items = (await AsyncExecuter.ToListAsync(query)).Select(a => (a.@event, a.organization)).ToList(); - var events = items.Select( - i => - { - var dto = ObjectMapper.Map(i.@event); - dto.OrganizationName = i.organization.Name; - dto.OrganizationDisplayName = i.organization.DisplayName; - dto.IsLiveNow = now.IsBetween(i.@event.StartTime, i.@event.EndTime); - dto.Country = i.@event.CountryName; - return dto; - } - ).ToList(); + var events = GetEventInListDtoFromEventAndOrganizationTupleList(items); return new PagedResultDto(totalCount, events); } + [Authorize] + public async Task> GetDraftEventsByUserId(Guid userId) + { + var eventQueryable = await _eventRepository.GetQueryableAsync(); + var organizationQueryable = await _organizationRepository.GetQueryableAsync(); + + var query = from @event in eventQueryable + join organization in organizationQueryable on @event.OrganizationId equals organization.Id + where organization.OwnerUserId == userId && @event.IsDraft + select new { @event, organization }; + + var items = (await AsyncExecuter.ToListAsync(query)).Select(a => (a.@event, a.organization)).ToList(); + + return GetEventInListDtoFromEventAndOrganizationTupleList(items); + } + public async Task GetByUrlCodeAsync(string urlCode) { - var @event = await _eventRepository.GetAsync(x => x.UrlCode == urlCode); + var @event = await _eventRepository.GetAsync(x => x.UrlCode == urlCode, true); var organization = await _organizationRepository.GetAsync(@event.OrganizationId); var dto = ObjectMapper.Map(@event); @@ -175,7 +182,7 @@ namespace EventHub.Events dto.OrganizationId = organization.Id; dto.OrganizationName = organization.Name; dto.OrganizationDisplayName = organization.DisplayName; - + var user = await _userRepository.GetAsync(organization.OwnerUserId); dto.OwnerUserName = user.UserName; dto.OwnerEmail = user.Email; @@ -232,15 +239,7 @@ namespace EventHub.Events 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 AbpAuthorizationException( - L["EventHub:NotAuthorizedToUpdateEvent", @event.Title], - EventHubErrorCodes.NotAuthorizedToUpdateEvent - ); - } + await CheckOwnerControlAsync(@event); await _eventManager.SetLocationAsync(@event, input.IsOnline, input.OnlineLink, input.CountryId, input.City); @event.SetTitle(input.Title); @@ -257,6 +256,29 @@ namespace EventHub.Events await _eventRepository.UpdateAsync(@event); } + [Authorize] + public async Task AddTrackAsync(Guid id, AddTractDto input) + { + var @event = await _eventRepository.GetAsync(id, true); + await CheckOwnerControlAsync(@event); + + @event.AddTract( + GuidGenerator.Create(), + input.Name + ); + + await _eventRepository.UpdateAsync(@event); + } + + [Authorize] + public async Task> GetTracksAsync(Guid id) + { + var @event = await _eventRepository.GetAsync(id, true); + + return ObjectMapper.Map, List>(@event.Tracks.ToList()); + } + + [Authorize] public async Task AddSessionAsync(Guid id, AddSessionDto input) { var @event = await _eventRepository.GetAsync(id); @@ -277,7 +299,7 @@ namespace EventHub.Events var blobName = id.ToString(); var coverImageStream = await _eventBlobContainer.GetOrNullAsync(blobName); - + if (coverImageStream is null) { return null; @@ -292,5 +314,36 @@ namespace EventHub.Events await _eventBlobContainer.SaveAsync(blobName, streamContent.GetStream(), overrideExisting: true); } + + private async Task CheckOwnerControlAsync(Event @event) + { + var organization = await _organizationRepository.GetAsync(@event.OrganizationId); + + if (organization.OwnerUserId != CurrentUser.GetId()) + { + throw new AbpAuthorizationException( + L["EventHub:NotAuthorizedToUpdateEvent", @event.Title], + EventHubErrorCodes.NotAuthorizedToUpdateEvent + ); + } + } + + private List GetEventInListDtoFromEventAndOrganizationTupleList(List<(Event @event, Organization organization)> items) + { + var now = Clock.Now; + var events = items.Select( + i => + { + var dto = ObjectMapper.Map(i.@event); + dto.OrganizationName = i.organization.Name; + dto.OrganizationDisplayName = i.organization.DisplayName; + dto.IsLiveNow = now.IsBetween(i.@event.StartTime, i.@event.EndTime); + dto.Country = i.@event.CountryName; + return dto; + } + ).ToList(); + + return events; + } } -} \ No newline at end of file +} diff --git a/src/EventHub.Domain.Shared/EventHubErrorCodes.cs b/src/EventHub.Domain.Shared/EventHubErrorCodes.cs index f1650b6..951de36 100644 --- a/src/EventHub.Domain.Shared/EventHubErrorCodes.cs +++ b/src/EventHub.Domain.Shared/EventHubErrorCodes.cs @@ -16,5 +16,6 @@ public const string SessionTimeConflictsWithAnExistingSession = "EventHub:SessionTimeConflictsWithAnExistingSession"; public const string UserNotFound = "EventHub:UserNotFound"; public const string OrganizationNotFound = "EventHub:OrganizationNotFound"; + public const string TrackNameAlreadyExist = "EventHub:TrackNameAlreadyExist"; } } diff --git a/src/EventHub.Domain.Shared/Localization/EventHub/en.json b/src/EventHub.Domain.Shared/Localization/EventHub/en.json index 557c460..f21596f 100644 --- a/src/EventHub.Domain.Shared/Localization/EventHub/en.json +++ b/src/EventHub.Domain.Shared/Localization/EventHub/en.json @@ -152,6 +152,7 @@ "MaxStartTime": "Max Start Time", "Online": "Online", "InPerson": "In Person", - "UpgradeToPremium": "Upgrade To Premium" + "UpgradeToPremium": "Upgrade To Premium", + "EventHub:TrackNameAlreadyExist": "The track {Name} already exists" } } diff --git a/src/EventHub.Domain/Events/Event.cs b/src/EventHub.Domain/Events/Event.cs index eced286..3a1a756 100644 --- a/src/EventHub.Domain/Events/Event.cs +++ b/src/EventHub.Domain/Events/Event.cs @@ -46,7 +46,7 @@ namespace EventHub.Events public bool IsTimingChangeEmailSent { get; set; } - public bool IsDraft { get; set; } + public bool IsDraft { get; private set; } public ICollection Tracks { get; private set; } @@ -127,6 +127,19 @@ namespace EventHub.Events return this; } + public Event AddTract(Guid trackId, string name) + { + if (Tracks.Any(x => x.Name == name)) + { + throw new BusinessException(EventHubErrorCodes.TrackNameAlreadyExist) + .WithData("Name", name); + } + + Tracks.Add(new Track(trackId, this.Id, name)); + + return this; + } + public Event AddSession( Guid trackId, Guid sessionId, @@ -150,6 +163,13 @@ namespace EventHub.Events track.AddSession(sessionId, title, startTime, endTime, description, language); return this; } + + public Event Publish(bool isPublish) + { + IsDraft = isPublish; + + return this; + } private Track GetTrack(Guid trackId) { diff --git a/src/EventHub.Domain/Events/Track.cs b/src/EventHub.Domain/Events/Track.cs index 96970ae..408efb9 100644 --- a/src/EventHub.Domain/Events/Track.cs +++ b/src/EventHub.Domain/Events/Track.cs @@ -26,7 +26,7 @@ namespace EventHub.Events : base(id) { EventId = eventId; - Name = name; + SetName(name); Sessions = new Collection(); } @@ -63,4 +63,4 @@ namespace EventHub.Events return this; } } -} \ No newline at end of file +} diff --git a/src/EventHub.EntityFrameworkCore/EntityFrameworkCore/Events/EventRepository.cs b/src/EventHub.EntityFrameworkCore/EntityFrameworkCore/Events/EventRepository.cs index 603824c..e6219b8 100644 --- a/src/EventHub.EntityFrameworkCore/EntityFrameworkCore/Events/EventRepository.cs +++ b/src/EventHub.EntityFrameworkCore/EntityFrameworkCore/Events/EventRepository.cs @@ -98,5 +98,10 @@ namespace EventHub.EntityFrameworkCore.Events return await query.ToListAsync(GetCancellationToken(cancellationToken)); } + + public override async Task> WithDetailsAsync() + { + return (await GetQueryableAsync()).Include(x => x.Tracks).ThenInclude(x => x.Sessions); + } } } diff --git a/src/EventHub.HttpApi.Client/EventHubHttpApiClientModule.cs b/src/EventHub.HttpApi.Client/EventHubHttpApiClientModule.cs index 5b3604c..ae2e0fd 100644 --- a/src/EventHub.HttpApi.Client/EventHubHttpApiClientModule.cs +++ b/src/EventHub.HttpApi.Client/EventHubHttpApiClientModule.cs @@ -2,6 +2,7 @@ using Volo.Abp.Http.Client; using Volo.Abp.Modularity; using Payment; +using Volo.Abp.VirtualFileSystem; namespace EventHub { @@ -20,6 +21,11 @@ namespace EventHub typeof(EventHubApplicationContractsModule).Assembly, RemoteServiceName ); + + Configure(options => + { + options.FileSets.AddEmbedded(); + }); } } } diff --git a/src/EventHub.HttpApi.Host/Controllers/Events/EventController.cs b/src/EventHub.HttpApi.Host/Controllers/Events/EventController.cs deleted file mode 100644 index fb63a95..0000000 --- a/src/EventHub.HttpApi.Host/Controllers/Events/EventController.cs +++ /dev/null @@ -1,104 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Threading.Tasks; -using EventHub.Events; -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.Controllers.Events -{ - [RemoteService(Name = EventHubRemoteServiceConsts.RemoteServiceName)] - [Area("eventhub")] - [ControllerName("Event")] - [Route("api/eventhub/event")] - public class EventController : AbpController, IEventAppService - { - private readonly IEventAppService _eventAppService; - private readonly IVirtualFileProvider _virtualFileProvider; - - public EventController( - IEventAppService eventAppService, - IVirtualFileProvider virtualFileProvider) - { - _eventAppService = eventAppService; - _virtualFileProvider = virtualFileProvider; - } - - [HttpPost] - public async Task CreateAsync([FromForm] CreateEventDto input) - { - return await _eventAppService.CreateAsync(input); - } - - [HttpGet] - public async Task> GetListAsync(EventListFilterDto input) - { - return await _eventAppService.GetListAsync(input); - } - - [HttpGet] - [Route("by-url-code/{urlCode}")] - public async Task GetByUrlCodeAsync(string urlCode) - { - return await _eventAppService.GetByUrlCodeAsync(urlCode); - } - - [HttpGet] - [Route("location/{id}")] - public async Task GetLocationAsync(Guid id) - { - return await _eventAppService.GetLocationAsync(id); - } - - [HttpGet] - [Route("lookup/countries")] - public async Task> GetCountriesLookupAsync() - { - return await _eventAppService.GetCountriesLookupAsync(); - } - - [HttpGet] - [Route("is-event-owner/{id}")] - public async Task IsEventOwnerAsync(Guid id) - { - return await _eventAppService.IsEventOwnerAsync(id); - } - - [HttpPut] - [Route("{id}")] - public async Task UpdateAsync(Guid id, [FromForm] UpdateEventDto input) - { - await _eventAppService.UpdateAsync(id, input); - } - - [HttpPost] - [Route("{id}/sessions")] - public async Task AddSessionAsync(Guid id, AddSessionDto input) - { - await _eventAppService.AddSessionAsync(id, input); - } - - [HttpGet] - [Route("cover-image/{id}")] - public async Task GetCoverImageAsync(Guid id) - { - var remoteStreamContent = await _eventAppService.GetCoverImageAsync(id); - - if (remoteStreamContent is null) - { - var stream = _virtualFileProvider.GetFileInfo("/Images/eh-event.png").CreateReadStream(); - remoteStreamContent = new RemoteStreamContent(stream); - await stream.FlushAsync(); - } - - Response.Headers.Add("Accept-Ranges", "bytes"); - Response.ContentType = remoteStreamContent.ContentType; - - return remoteStreamContent; - } - } -} \ No newline at end of file diff --git a/src/EventHub.HttpApi.Host/EventHubHttpApiHostModule.cs b/src/EventHub.HttpApi.Host/EventHubHttpApiHostModule.cs index a9eceb1..c944a54 100644 --- a/src/EventHub.HttpApi.Host/EventHubHttpApiHostModule.cs +++ b/src/EventHub.HttpApi.Host/EventHubHttpApiHostModule.cs @@ -52,7 +52,6 @@ namespace EventHub public override void ConfigureServices(ServiceConfigurationContext context) { var configuration = context.Services.GetConfiguration(); - var hostingEnvironment = context.Services.GetHostingEnvironment(); ConfigureAuthentication(context, configuration); ConfigureLocalization(); diff --git a/src/EventHub.HttpApi/Controllers/EventHubController.cs b/src/EventHub.HttpApi/Controllers/EventHubController.cs index cd809a1..118b647 100644 --- a/src/EventHub.HttpApi/Controllers/EventHubController.cs +++ b/src/EventHub.HttpApi/Controllers/EventHubController.cs @@ -3,13 +3,11 @@ using Volo.Abp.AspNetCore.Mvc; namespace EventHub.Controllers { - /* Inherit your controllers from this class. - */ - public abstract class EventHubController : AbpController + public abstract class EventHubController : AbpControllerBase { protected EventHubController() { LocalizationResource = typeof(EventHubResource); } } -} \ No newline at end of file +} diff --git a/src/EventHub.HttpApi/Controllers/Events/EventController.cs b/src/EventHub.HttpApi/Controllers/Events/EventController.cs new file mode 100644 index 0000000..59a5249 --- /dev/null +++ b/src/EventHub.HttpApi/Controllers/Events/EventController.cs @@ -0,0 +1,124 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using EventHub.Events; +using Microsoft.AspNetCore.Mvc; +using Volo.Abp; +using Volo.Abp.Application.Dtos; +using Volo.Abp.Content; +using Volo.Abp.VirtualFileSystem; + +namespace EventHub.Controllers.Events +{ + [RemoteService(Name = EventHubRemoteServiceConsts.RemoteServiceName)] + [Area("eventhubm")] + [ControllerName("Event")] + [Route("api/eventhub/event")] + public class EventController : EventHubController, IEventAppService + { + private readonly IEventAppService _eventAppService; + private readonly IVirtualFileProvider _virtualFileProvider; + + public EventController( + IEventAppService eventAppService, + IVirtualFileProvider virtualFileProvider) + { + _eventAppService = eventAppService; + _virtualFileProvider = virtualFileProvider; + } + + [HttpPost] + public async Task CreateAsync([FromForm] CreateEventDto input) + { + return await _eventAppService.CreateAsync(input); + } + + [HttpGet] + public async Task> GetListAsync(EventListFilterDto input) + { + return await _eventAppService.GetListAsync(input); + } + + [HttpGet] + [Route("draft-events-by-user-id/{userId}")] + public async Task> GetDraftEventsByUserId(Guid userId) + { + return await _eventAppService.GetDraftEventsByUserId(userId); + } + + [HttpGet] + [Route("by-url-code/{urlCode}")] + public async Task GetByUrlCodeAsync(string urlCode) + { + return await _eventAppService.GetByUrlCodeAsync(urlCode); + } + + [HttpGet] + [Route("location/{id}")] + public async Task GetLocationAsync(Guid id) + { + return await _eventAppService.GetLocationAsync(id); + } + + [HttpGet] + [Route("lookup/countries")] + public async Task> GetCountriesLookupAsync() + { + return await _eventAppService.GetCountriesLookupAsync(); + } + + [HttpGet] + [Route("is-event-owner/{id}")] + public async Task IsEventOwnerAsync(Guid id) + { + return await _eventAppService.IsEventOwnerAsync(id); + } + + [HttpPut] + [Route("{id}")] + public async Task UpdateAsync(Guid id, [FromForm] UpdateEventDto input) + { + await _eventAppService.UpdateAsync(id, input); + } + + [HttpPost] + [Route("{id}/tracks")] + public async Task AddTrackAsync(Guid id, AddTractDto input) + { + await _eventAppService.AddTrackAsync(id, input); + } + + [HttpGet] + [Route("{id}/tracks")] + public async Task> GetTracksAsync(Guid id) + { + return await _eventAppService.GetTracksAsync(id); + } + + [HttpPost] + [Route("{id}/sessions")] + public async Task AddSessionAsync(Guid id, AddSessionDto input) + { + await _eventAppService.AddSessionAsync(id, input); + } + + [HttpGet] + [Route("cover-image/{id}")] + public async Task GetCoverImageAsync(Guid id) + { + var remoteStreamContent = await _eventAppService.GetCoverImageAsync(id); + + if (remoteStreamContent is null) + { + var stream = _virtualFileProvider.GetFileInfo("/Images/eh-event.png").CreateReadStream(); + remoteStreamContent = new RemoteStreamContent(stream); + await stream.FlushAsync(); + } + + Response.Headers.Add("Accept-Ranges", "bytes"); + Response.ContentType = remoteStreamContent.ContentType; + + return remoteStreamContent; + } + } +} diff --git a/src/EventHub.HttpApi.Host/Controllers/Events/Registrations/EventRegistrationController.cs b/src/EventHub.HttpApi/Controllers/Events/Registrations/EventRegistrationController.cs similarity index 94% rename from src/EventHub.HttpApi.Host/Controllers/Events/Registrations/EventRegistrationController.cs rename to src/EventHub.HttpApi/Controllers/Events/Registrations/EventRegistrationController.cs index 8eb8341..da392a0 100644 --- a/src/EventHub.HttpApi.Host/Controllers/Events/Registrations/EventRegistrationController.cs +++ b/src/EventHub.HttpApi/Controllers/Events/Registrations/EventRegistrationController.cs @@ -12,7 +12,7 @@ namespace EventHub.Controllers.Events.Registrations [Area("eventhub")] [ControllerName("EventRegistration")] [Route("api/eventhub/event-registration")] - public class EventRegistrationController : AbpController, IEventRegistrationAppService + public class EventRegistrationController : EventHubController, IEventRegistrationAppService { private readonly IEventRegistrationAppService _eventRegistrationAppService; @@ -55,4 +55,4 @@ namespace EventHub.Controllers.Events.Registrations return await _eventRegistrationAppService.IsPastEventAsync(eventId); } } -} \ No newline at end of file +} diff --git a/src/EventHub.HttpApi.Host/Controllers/Organizations/Memberships/OrganizationMembershipController.cs b/src/EventHub.HttpApi/Controllers/Organizations/Memberships/OrganizationMembershipController.cs similarity index 94% rename from src/EventHub.HttpApi.Host/Controllers/Organizations/Memberships/OrganizationMembershipController.cs rename to src/EventHub.HttpApi/Controllers/Organizations/Memberships/OrganizationMembershipController.cs index ac1d710..500cdd4 100644 --- a/src/EventHub.HttpApi.Host/Controllers/Organizations/Memberships/OrganizationMembershipController.cs +++ b/src/EventHub.HttpApi/Controllers/Organizations/Memberships/OrganizationMembershipController.cs @@ -12,7 +12,7 @@ namespace EventHub.Controllers.Organizations.Memberships [Area("eventhub")] [ControllerName("OrganizationMembership")] [Route("api/eventhub/organization-membership")] - public class OrganizationMembershipController : AbpController, IOrganizationMembershipAppService + public class OrganizationMembershipController : EventHubController, IOrganizationMembershipAppService { private readonly IOrganizationMembershipAppService _organizationMembershipAppService; @@ -49,4 +49,4 @@ namespace EventHub.Controllers.Organizations.Memberships return await _organizationMembershipAppService.GetMembersAsync(input); } } -} \ No newline at end of file +} diff --git a/src/EventHub.HttpApi.Host/Controllers/Organizations/OrganizationController.cs b/src/EventHub.HttpApi/Controllers/Organizations/OrganizationController.cs similarity index 96% rename from src/EventHub.HttpApi.Host/Controllers/Organizations/OrganizationController.cs rename to src/EventHub.HttpApi/Controllers/Organizations/OrganizationController.cs index 8b4a7b4..be22d10 100644 --- a/src/EventHub.HttpApi.Host/Controllers/Organizations/OrganizationController.cs +++ b/src/EventHub.HttpApi/Controllers/Organizations/OrganizationController.cs @@ -11,10 +11,10 @@ using Volo.Abp.VirtualFileSystem; namespace EventHub.Controllers.Organizations { [RemoteService(Name = EventHubRemoteServiceConsts.RemoteServiceName)] - [Area("eventhub")] + [Area("eventhubm")] [ControllerName("Organization")] [Route("api/eventhub/organization")] - public class OrganizationController : AbpController, IOrganizationAppService + public class OrganizationController : EventHubController, IOrganizationAppService { private readonly IOrganizationAppService _organizationAppService; private readonly IVirtualFileProvider _virtualFileProvider; @@ -86,4 +86,4 @@ namespace EventHub.Controllers.Organizations return remoteStreamContent; } } -} \ No newline at end of file +} diff --git a/src/EventHub.HttpApi.Host/Controllers/Users/UserController.cs b/src/EventHub.HttpApi/Controllers/Users/UserController.cs similarity index 88% rename from src/EventHub.HttpApi.Host/Controllers/Users/UserController.cs rename to src/EventHub.HttpApi/Controllers/Users/UserController.cs index 5364c88..0ac1a38 100644 --- a/src/EventHub.HttpApi.Host/Controllers/Users/UserController.cs +++ b/src/EventHub.HttpApi/Controllers/Users/UserController.cs @@ -8,10 +8,10 @@ using Volo.Abp.AspNetCore.Mvc; namespace EventHub.Controllers.Users { [RemoteService(Name = EventHubRemoteServiceConsts.RemoteServiceName)] - [Area("eventhub")] + [Area("eventhubm")] [ControllerName("User")] [Route("/api/eventhub/user")] - public class UserController : AbpController, IUserAppService + public class UserController : EventHubController, IUserAppService { private readonly IUserAppService _userAppService; @@ -27,4 +27,4 @@ namespace EventHub.Controllers.Users return await _userAppService.FindByUserNameAsync(username); } } -} \ No newline at end of file +} diff --git a/src/EventHub.Web/Controllers/EventController.cs b/src/EventHub.Web/Controllers/EventController.cs index fcc385b..3b010fd 100644 --- a/src/EventHub.Web/Controllers/EventController.cs +++ b/src/EventHub.Web/Controllers/EventController.cs @@ -1,3 +1,5 @@ +using System; +using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using EventHub.Events; @@ -28,5 +30,18 @@ namespace EventHub.Web.Controllers ViewData = ViewData }; } + + [HttpGet] + [Route("{id}/tracks")] + public async Task GetTracksSection(Guid id) + { + ViewData.Model = await _eventAppService.GetTracksAsync(id); + + return await Task.FromResult(new PartialViewResult + { + ViewName = "~/Pages/Events/Components/CreateEventArea/_addTrackSection.cshtml", + ViewData = ViewData + }); + } } -} \ No newline at end of file +} diff --git a/src/EventHub.Web/Controllers/EventRegistrationController.cs b/src/EventHub.Web/Controllers/EventRegistrationController.cs index 8548ffb..80cfd8c 100644 --- a/src/EventHub.Web/Controllers/EventRegistrationController.cs +++ b/src/EventHub.Web/Controllers/EventRegistrationController.cs @@ -1,7 +1,6 @@ using System; using System.Threading.Tasks; using EventHub.Events.Registrations; -using EventHub.Web.Pages.Events.Components.RegistrationArea; using Microsoft.AspNetCore.Mvc; using Volo.Abp.AspNetCore.Mvc; @@ -29,14 +28,5 @@ namespace EventHub.Web.Controllers await _eventRegistrationAppService.UnregisterAsync(eventId); return NoContent(); } - - [HttpGet] - public IActionResult Widget(Guid eventId) - { - return ViewComponent( - typeof(RegistrationAreaViewComponent), - new {eventId} - ); - } } } diff --git a/src/EventHub.Web/Controllers/OrganizationMembershipController.cs b/src/EventHub.Web/Controllers/OrganizationMembershipController.cs index 7e05755..2f95118 100644 --- a/src/EventHub.Web/Controllers/OrganizationMembershipController.cs +++ b/src/EventHub.Web/Controllers/OrganizationMembershipController.cs @@ -2,7 +2,6 @@ using System; using System.Linq; using System.Threading.Tasks; using EventHub.Organizations.Memberships; -using EventHub.Web.Pages.Organizations.Components.JoinArea; using Microsoft.AspNetCore.Mvc; using Volo.Abp.AspNetCore.Mvc; @@ -43,14 +42,5 @@ namespace EventHub.Web.Controllers await _organizationMembershipAppService.LeaveAsync(organizationId); return NoContent(); } - - [HttpGet] - public IActionResult Widget(Guid organizationId) - { - return ViewComponent( - typeof(JoinAreaViewComponent), - new {organizationId} - ); - } } -} \ No newline at end of file +} diff --git a/src/EventHub.Web/Controllers/WidgetsController.cs b/src/EventHub.Web/Controllers/WidgetsController.cs index be191a4..ec3e0dd 100644 --- a/src/EventHub.Web/Controllers/WidgetsController.cs +++ b/src/EventHub.Web/Controllers/WidgetsController.cs @@ -1,6 +1,9 @@ using System; using EventHub.Web.Pages.Events.Components.AttendeesArea; +using EventHub.Web.Pages.Events.Components.CreateEventArea; using EventHub.Web.Pages.Events.Components.LocationArea; +using EventHub.Web.Pages.Events.Components.RegistrationArea; +using EventHub.Web.Pages.Organizations.Components.JoinArea; using EventHub.Web.Pages.Organizations.Components.MembersArea; using Microsoft.AspNetCore.Mvc; using Volo.Abp.AspNetCore.Mvc; @@ -47,5 +50,32 @@ namespace EventHub.Web.Controllers new {eventId} ); } + + [HttpGet] + public IActionResult RegistrationArea(Guid eventId) + { + return ViewComponent( + typeof(RegistrationAreaViewComponent), + new {eventId} + ); + } + + [HttpGet] + public IActionResult JoinArea(Guid organizationId) + { + return ViewComponent( + typeof(JoinAreaViewComponent), + new {organizationId} + ); + } + + [HttpGet] + public IActionResult CreateEventArea(string eventUrlCode) + { + return ViewComponent( + typeof(CreateEventAreaViewComponent), + new {eventUrlCode} + ); + } } } diff --git a/src/EventHub.Web/EventHubWebAutoMapperProfile.cs b/src/EventHub.Web/EventHubWebAutoMapperProfile.cs index 014ea33..f036314 100644 --- a/src/EventHub.Web/EventHubWebAutoMapperProfile.cs +++ b/src/EventHub.Web/EventHubWebAutoMapperProfile.cs @@ -1,6 +1,7 @@ using AutoMapper; using EventHub.Events; using EventHub.Organizations; +using EventHub.Web.Pages.Events.Components.CreateEventArea; using EventHub.Web.Pages.Organizations; using Volo.Abp.AutoMapper; using EditPageModel = EventHub.Web.Pages.Events.EditPageModel; @@ -12,10 +13,11 @@ namespace EventHub.Web public EventHubWebAutoMapperProfile() { CreateMap(); - CreateMap() + CreateMap() .Ignore(x => x.CoverImageStreamContent); CreateMap(); CreateMap(); + CreateMap(); CreateMap(); CreateMap(); } diff --git a/src/EventHub.Web/Pages/Events/Components/CreateEventArea/CreateEventAreaViewComponent.cs b/src/EventHub.Web/Pages/Events/Components/CreateEventArea/CreateEventAreaViewComponent.cs new file mode 100644 index 0000000..1e211a7 --- /dev/null +++ b/src/EventHub.Web/Pages/Events/Components/CreateEventArea/CreateEventAreaViewComponent.cs @@ -0,0 +1,175 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +using System.Globalization; +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 Volo.Abp.AspNetCore.Mvc; +using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form; +using Volo.Abp.AspNetCore.Mvc.UI.Widgets; +using Volo.Abp.Users; + +namespace EventHub.Web.Pages.Events.Components.CreateEventArea; + +[Widget( + AutoInitialize = true, + RefreshUrl = "/Widgets/CreateEventArea", + ScriptFiles = new[] { "/Pages/Events/Components/CreateEventArea/create-event-area.js" } +)] +public class CreateEventAreaViewComponent : AbpViewComponent +{ + private readonly IEventAppService _eventAppService; + private readonly IOrganizationAppService _organizationAppService; + + private readonly ICurrentUser _currentUser; + + public CreateEventAreaViewComponent( + IEventAppService eventAppService, + IOrganizationAppService organizationAppService, + ICurrentUser currentUser) + { + _eventAppService = eventAppService; + _organizationAppService = organizationAppService; + _currentUser = currentUser; + } + + public async Task InvokeAsync(string eventUrlCode) + { + NewEventViewModel model = null; + if (!eventUrlCode.IsNullOrWhiteSpace()) + { + var @event = await _eventAppService.GetByUrlCodeAsync(eventUrlCode); + model = ObjectMapper.Map(@event); + ViewData["EventId"] = @event.Id; + } + + model ??= new NewEventViewModel + { + StartTime = DateTime.Now.ClearTime().AddDays(1).AddHours(19), + EndTime = DateTime.Now.ClearTime().AddDays(1).AddHours(21) + }; + + ViewData["Organizations"] = await GetOrganizationsSelectItemAsync(); + ViewData["Countries"] = await GetCountriesSelectItemAsync(); + ViewData["Languages"] = GetLanguagesSelectItem(); + + return View("~/Pages/Events/Components/CreateEventArea/Default.cshtml", model); + } + + private async Task> GetOrganizationsSelectItemAsync() + { + var result = await _organizationAppService.GetOrganizationsByUserIdAsync(_currentUser.GetId()); + + return result.Items.Select( + organization => new SelectListItem + { + Value = organization.Id.ToString(), + Text = organization.DisplayName + } + ).ToList(); + } + + private async Task> GetCountriesSelectItemAsync() + { + var result = await _eventAppService.GetCountriesLookupAsync(); + + return result.Select( + country => new SelectListItem + { + Value = country.Id.ToString(), + Text = country.Name + } + ).ToList(); + } + + private List GetLanguagesSelectItem() + { + 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 + + return result.Select( + cultureInfo => new SelectListItem + { + Value = cultureInfo.TwoLetterISOLanguageName, + Text = cultureInfo.EnglishName + } + ).ToList(); + } + + public class NewEventViewModel + { + [SelectItems(nameof(Organizations))] + [DisplayName("Organization")] + public Guid OrganizationId { get; set; } + + [Required] + [StringLength(EventConsts.MaxTitleLength, MinimumLength = EventConsts.MinTitleLength)] + public string Title { get; set; } + + [Required] + [DataType(DataType.DateTime)] + public DateTime StartTime { get; set; } = DateTime.Now; + + [Required] + [DataType(DataType.DateTime)] + public DateTime EndTime { get; set; } = DateTime.Now; + + [Required] + [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; } + + [Required] 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; } + + [DisplayName("Language")] + public string Language { get; set; } + + [Range(1, int.MaxValue)] + public int? Capacity { get; set; } + + public List Tracks { get; set; } + + public NewEventViewModel() + { + Tracks = new List(); + } + } + + public enum ProgressStepType : byte + { + NewEvent = 0, + NewTrack, + NewSession + } +} diff --git a/src/EventHub.Web/Pages/Events/Components/CreateEventArea/Default.cshtml b/src/EventHub.Web/Pages/Events/Components/CreateEventArea/Default.cshtml new file mode 100644 index 0000000..5ad93a9 --- /dev/null +++ b/src/EventHub.Web/Pages/Events/Components/CreateEventArea/Default.cshtml @@ -0,0 +1,21 @@ +@using Microsoft.AspNetCore.Http +@model EventHub.Web.Pages.Events.Components.CreateEventArea.CreateEventAreaViewComponent.NewEventViewModel + +@{ + if (Model is null) + { + throw new BadHttpRequestException(""); + } + + var eventId = ViewData["EventId"] as Guid?; +} + +
+ +
+ + + + diff --git a/src/EventHub.Web/Pages/Events/Components/CreateEventArea/_addTrackSection.cshtml b/src/EventHub.Web/Pages/Events/Components/CreateEventArea/_addTrackSection.cshtml new file mode 100644 index 0000000..87ec346 --- /dev/null +++ b/src/EventHub.Web/Pages/Events/Components/CreateEventArea/_addTrackSection.cshtml @@ -0,0 +1,71 @@ +@using EventHub.Web.Pages.Events.Components.CreateEventArea +@model List + + + +@if (Model is not null) +{ +
+
+
+
+

Add Track

+
+ @foreach (var track in Model) + { +
+
+ @track.Name + Edit +
+
+ } +
+ +
+
+
+ + +
+
+
+ + @* Add Track modal *@ + +} + diff --git a/src/EventHub.Web/Pages/Events/Components/CreateEventArea/_newEventSection.cshtml b/src/EventHub.Web/Pages/Events/Components/CreateEventArea/_newEventSection.cshtml new file mode 100644 index 0000000..fa1d7f0 --- /dev/null +++ b/src/EventHub.Web/Pages/Events/Components/CreateEventArea/_newEventSection.cshtml @@ -0,0 +1,143 @@ +@using EventHub.Web.Pages.Events.Components.CreateEventArea +@using Microsoft.AspNetCore.Http +@model EventHub.Web.Pages.Events.Components.CreateEventArea.CreateEventAreaViewComponent.NewEventViewModel + +@{ + var organizations = ViewData["Organizations"] as IList; + if (organizations is null || !organizations.Any()) + { + throw new BadHttpRequestException("There is no organization"); + } + + var countries = ViewData["Countries"] as IList; + if (countries is null || !countries.Any()) + { + throw new BadHttpRequestException("There is no country"); + } + + var languages = ViewData["Languages"] as IList; + if (languages is null || !languages.Any()) + { + throw new BadHttpRequestException("There is no language"); + } +} + + + +
+
+
+
+
+
+

Create New Event

+
+
+
+
+ + +
+
+
+
+ + + +
+
+
+
+ + + +
+
+
+
+ + + +
+
+
+
+ + +
+
+
+

Cover Image

+
+
+
+
+
+
+

For horizontal format 600x400 sized upload images.

+ + + +
+
+
+
+
+ + +
+ +
+
+ + + +
+
+
+ + +
+
+
+ + + +
+
+
+ + +
+
+ +
+
+
+
+
+
+
+
+
diff --git a/src/EventHub.Web/Pages/Events/Components/CreateEventArea/_progressSection.cshtml b/src/EventHub.Web/Pages/Events/Components/CreateEventArea/_progressSection.cshtml new file mode 100644 index 0000000..7d99cc8 --- /dev/null +++ b/src/EventHub.Web/Pages/Events/Components/CreateEventArea/_progressSection.cshtml @@ -0,0 +1,15 @@ +@using EventHub.Web.Pages.Events.Components.CreateEventArea +@model EventHub.Web.Pages.Events.Components.CreateEventArea.CreateEventAreaViewComponent.ProgressStepType + +
+
+
    +
  • 1New Event
  • +
  • 2Add Track
  • +
  • 3Add Session
  • +
+
+
+
+
+
diff --git a/src/EventHub.Web/Pages/Events/Components/CreateEventArea/create-event-area.js b/src/EventHub.Web/Pages/Events/Components/CreateEventArea/create-event-area.js new file mode 100644 index 0000000..a044a02 --- /dev/null +++ b/src/EventHub.Web/Pages/Events/Components/CreateEventArea/create-event-area.js @@ -0,0 +1,69 @@ +(function () { + abp.widgets.CreateEventArea = function ($wrapper) { + var eventApiService = eventHub.controllers.events.event; + var eventIdInput = $('#EventId'); + + if (eventIdInput.val().length === 36) { + // TODO: Add organization in UppdateEventDto + $('#OrganizationId').prop("disabled", true).removeAttr('name'); + } + + $("#CreateEventForm").submit(function (e) { + e.preventDefault(); + if (!$(this).valid()) { + return false; + } + var input = $(this).serializeFormToObject(); + + if (eventIdInput.val().length === 36) { + eventApiService.update(eventIdInput.val(), input).then(function (eventUpdatedResponse) { + abp.notify.success('Updated event'); + SwitchToTrackCreation() + ScrollToWrapperBegin(); + }); + } else { + eventApiService.create(input).then(function (eventCreatedResponse) { + abp.notify.success('Created event as a draft'); + eventIdInput.val(eventCreatedResponse.id); + SwitchToTrackCreation() + ScrollToWrapperBegin(); + }); + } + }); + + + function ScrollToWrapperBegin() { + $([document.documentElement, document.body]).animate({ + scrollTop: $wrapper.offset().top + }, 100); + } + + function SwitchToTrackCreation() { + $('#CreateEventContainer').css('display', 'none'); + $('#CreateTrackContainer').css('display', ''); + AddNewTrackButtonClickEventHandler(); + } + + function AddNewTrackButtonClickEventHandler() { + var addNewTrackButton = $('#AddNewTrackButton'); + addNewTrackButton.click(function (e) { + e.preventDefault(); + var trackName = $('#TrackName').val().trim(); + eventApiService.addTrack(eventIdInput.val(), {name: trackName}).then(function () { + var url = addNewTrackButton.attr('data-url').replace("eventIdPlaceholder", eventIdInput.val()); + abp.ajax({ + type: 'GET', dataType: 'html', contentType: 'text/html; charset=utf-8', url: url + }).then(function (getTracksResponse) { + $('#AddTrackModal').modal('hide'); + var createTrackContainer = $wrapper.find('#CreateTrackContainer'); + createTrackContainer.text(""); + createTrackContainer.append(getTracksResponse); + AddNewTrackButtonClickEventHandler(); + }); + + abp.notify.success('Added the track'); + }); + }); + } + } +})(); diff --git a/src/EventHub.Web/Pages/Events/Components/RegistrationArea/RegistrationAreaViewComponent.cs b/src/EventHub.Web/Pages/Events/Components/RegistrationArea/RegistrationAreaViewComponent.cs index 0582c11..6318f7d 100644 --- a/src/EventHub.Web/Pages/Events/Components/RegistrationArea/RegistrationAreaViewComponent.cs +++ b/src/EventHub.Web/Pages/Events/Components/RegistrationArea/RegistrationAreaViewComponent.cs @@ -10,7 +10,7 @@ namespace EventHub.Web.Pages.Events.Components.RegistrationArea { [Widget( AutoInitialize = true, - RefreshUrl = "/EventRegistration/Widget", + RefreshUrl = "/Widgets/RegistrationArea", ScriptFiles = new[] {"/Pages/Events/Components/RegistrationArea/registration-area.js"} )] public class RegistrationAreaViewComponent : AbpViewComponent diff --git a/src/EventHub.Web/Pages/Events/New.cshtml b/src/EventHub.Web/Pages/Events/New.cshtml index 28d668e..de343d8 100644 --- a/src/EventHub.Web/Pages/Events/New.cshtml +++ b/src/EventHub.Web/Pages/Events/New.cshtml @@ -1,6 +1,7 @@ -@page "/events/new" +@page "/events/new/{eventUrlCode?}" @inject IHtmlLocalizer L @using EventHub.Localization +@using EventHub.Web.Pages.Events.Components.CreateEventArea @using Microsoft.AspNetCore.Mvc.Localization @model EventHub.Web.Pages.Events.NewPageModel @@ -8,138 +9,86 @@ } -@if (!Model.Organizations.Any()) -{ -
-
-
-
-
-

@L["NewEventYouHaveNoOrganizationYetMessage"]

- @L["CreateAnOrganization"] +
+ @if (!Model.IsHasOrganizations) + { +
+
+
+
+

@L["NewEventYouHaveNoOrganizationYetMessage"]

+ @L["CreateAnOrganization"] +
-
+
-
-
-} -else -{ -
-
-
-
-
-
-

Create New Event

-
-
-
-
- - -
-
-
-
- - -
-
-
-
- - - -
-
-
-
- - - -
-
-
-
- - -
-
-
-

Cover Image

-
-
-
-
-
-
-

For horizontal format 600x400 sized upload images.

- - - -
-
-
-
-
- - -
- -
-
- - - -
-
-
- - -
-
-
- - - -
-
-
- - -
-
- -
-
-
-
-
-
-
-} \ No newline at end of file +
+ } + else + { + @await Component.InvokeAsync(typeof(CreateEventAreaViewComponent), new + { + eventUrlCode = Model.EventUrlCode + }) + } +
diff --git a/src/EventHub.Web/Pages/Events/New.cshtml.cs b/src/EventHub.Web/Pages/Events/New.cshtml.cs index d663a90..8e89c1b 100644 --- a/src/EventHub.Web/Pages/Events/New.cshtml.cs +++ b/src/EventHub.Web/Pages/Events/New.cshtml.cs @@ -1,180 +1,52 @@ using System; 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 Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form; -using Volo.Abp.Content; using Volo.Abp.Users; namespace EventHub.Web.Pages.Events { public class NewPageModel : EventHubPageModel { - [BindProperty] - public NewEventViewModel Event { get; set; } + [BindProperty(SupportsGet = true)] + public string EventUrlCode { get; set; } - public List Organizations { get; private set; } - public List Countries { get; private set; } - public List Languages { get; private set; } + [BindProperty(SupportsGet = true)] + public bool IsCreateNew { get; set; } + + public bool IsHasOrganizations { get; set; } + + public List DraftEventList { get; set; } private readonly IEventAppService _eventAppService; private readonly IOrganizationAppService _organizationAppService; public NewPageModel( - IEventAppService eventAppService, + IEventAppService eventAppService, IOrganizationAppService organizationAppService) { _eventAppService = eventAppService; _organizationAppService = organizationAppService; + + DraftEventList = new List(); } public async Task OnGetAsync() { - Event = new NewEventViewModel - { - StartTime = DateTime.Now.ClearTime().AddDays(1).AddHours(19), - EndTime = DateTime.Now.ClearTime().AddDays(1).AddHours(21) - }; + IsHasOrganizations = (await _organizationAppService.GetOrganizationsByUserIdAsync(CurrentUser.GetId())).Items.Any(); - await FillOrganizationsAsync(); - await FillCountriesAsync(); - FillLanguages(); - } - - public async Task OnPostAsync() - { - try + if (!EventUrlCode.IsNullOrWhiteSpace()) { - ValidateModel(); - - var createEventDto = ObjectMapper.Map(Event); - - await using var memoryStream = new MemoryStream(); - if (Event.CoverImageFile != null && Event.CoverImageFile.Length > 0) - { - await Event.CoverImageFile.CopyToAsync(memoryStream); - memoryStream.Position = 0; - - createEventDto.CoverImageStreamContent = new RemoteStreamContent(memoryStream, fileName: Event.CoverImageFile.FileName, contentType: Event.CoverImageFile.ContentType); - } - - var eventDto = await _eventAppService.CreateAsync(createEventDto); - await memoryStream.DisposeAsync(); - - return RedirectToPage("/Events/Detail", new {url = eventDto.UrlCode}); + return; } - catch (Exception exception) + + if (IsHasOrganizations && !IsCreateNew) { - ShowAlert(exception); - await FillOrganizationsAsync(); - await FillCountriesAsync(); - FillLanguages(); - return Page(); + DraftEventList = await _eventAppService.GetDraftEventsByUserId(CurrentUser.GetId()); } } - - private async Task FillOrganizationsAsync() - { - var result = await _organizationAppService.GetOrganizationsByUserIdAsync(CurrentUser.GetId()); - Organizations = result.Items.Select( - organization => new SelectListItem - { - Value = organization.Id.ToString(), - Text = organization.DisplayName - } - ).ToList(); - } - - 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(); - } - - public class NewEventViewModel - { - [SelectItems(nameof(Organizations))] - [DisplayName("Organization")] - public Guid OrganizationId { get; set; } - - [Required] - [StringLength(EventConsts.MaxTitleLength, MinimumLength = EventConsts.MinTitleLength)] - public string Title { get; set; } - - [Required] - [DataType(DataType.DateTime)] - public DateTime StartTime { get; set; } = DateTime.Now; - - [Required] - [DataType(DataType.DateTime)] - public DateTime EndTime { get; set; } = DateTime.Now; - - [Required] - [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; } - - [Required] 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; } - } } -} \ No newline at end of file +} diff --git a/src/EventHub.Web/Pages/Organizations/Components/JoinArea/JoinAreaViewComponent.cs b/src/EventHub.Web/Pages/Organizations/Components/JoinArea/JoinAreaViewComponent.cs index 12a1096..fec6dbb 100644 --- a/src/EventHub.Web/Pages/Organizations/Components/JoinArea/JoinAreaViewComponent.cs +++ b/src/EventHub.Web/Pages/Organizations/Components/JoinArea/JoinAreaViewComponent.cs @@ -10,7 +10,7 @@ namespace EventHub.Web.Pages.Organizations.Components.JoinArea { [Widget( AutoInitialize = true, - RefreshUrl = "/OrganizationMembership/Widget", + RefreshUrl = "/Widgets/JoinArea", ScriptFiles = new[] {"/Pages/Organizations/Components/JoinArea/join-area.js"} )] public class JoinAreaViewComponent : AbpViewComponent @@ -49,4 +49,4 @@ namespace EventHub.Web.Pages.Organizations.Components.JoinArea public bool IsJoined { get; set; } } } -} \ No newline at end of file +} diff --git a/src/EventHub.Web/Pages/Pricing.cshtml b/src/EventHub.Web/Pages/Pricing.cshtml index 02da933..135bd4d 100644 --- a/src/EventHub.Web/Pages/Pricing.cshtml +++ b/src/EventHub.Web/Pages/Pricing.cshtml @@ -9,7 +9,7 @@ }
-

Eventhub Pricing List

+

Pricing

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam ut nulla consequat, tempus sapien in, pellentesque nunc. Sed at nunc pellentesque, fermentum mi et, fermentum massa.