diff --git a/src/EventHub.Application.Contracts/Events/IEventAppService.cs b/src/EventHub.Application.Contracts/Events/IEventAppService.cs index 0b4ec1b..c119029 100644 --- a/src/EventHub.Application.Contracts/Events/IEventAppService.cs +++ b/src/EventHub.Application.Contracts/Events/IEventAppService.cs @@ -33,6 +33,8 @@ namespace EventHub.Events Task AddSessionAsync(Guid id, AddSessionDto input); + Task UpdateSessionAsync(Guid id, Guid trackId, Guid sessionId, UpdateSessionDto input); + Task GetCoverImageAsync(Guid id); } } diff --git a/src/EventHub.Application.Contracts/Events/UpdateSessionDto.cs b/src/EventHub.Application.Contracts/Events/UpdateSessionDto.cs new file mode 100644 index 0000000..f32acf5 --- /dev/null +++ b/src/EventHub.Application.Contracts/Events/UpdateSessionDto.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; + +namespace EventHub.Events; + +public class UpdateSessionDto +{ + [Required] + [StringLength(SessionConsts.MaxTitleLength, MinimumLength = SessionConsts.MinTitleLength)] + public string Title { get; set; } + + [Required] + [DataType(DataType.DateTime)] + public DateTime StartTime { get; set; } + + [Required] + [DataType(DataType.DateTime)] + public DateTime EndTime { get; set; } + + [Required] + [StringLength(SessionConsts.MaxDescriptionLength, MinimumLength = SessionConsts.MinDescriptionLength)] + public string Description { get; set; } + + public string Language { get; set; } + + public List SpeakerUserNames { get; set; } + + public UpdateSessionDto() + { + SpeakerUserNames = new List(); + } +} diff --git a/src/EventHub.Application/Events/EventAppService.cs b/src/EventHub.Application/Events/EventAppService.cs index cdb36f0..938548a 100644 --- a/src/EventHub.Application/Events/EventAppService.cs +++ b/src/EventHub.Application/Events/EventAppService.cs @@ -13,6 +13,7 @@ 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 @@ -64,8 +65,8 @@ namespace EventHub.Events var @event = await _eventManager.CreateAsync( organization, input.Title, - input.StartTime, - input.EndTime, + Clock.Normalize(input.StartTime), + Clock.Normalize(input.EndTime), input.Description ); @@ -259,7 +260,7 @@ namespace EventHub.Events @event.SetTitle(input.Title); @event.SetDescription(input.Description); @event.Language = input.Language; - @event.SetTime(input.StartTime, input.EndTime); + @event.SetTime(Clock.Normalize(input.StartTime), Clock.Normalize(input.EndTime)); await _eventManager.SetCapacityAsync(@event, input.Capacity); if (input.CoverImageStreamContent != null && input.CoverImageStreamContent.ContentLength > 0) @@ -311,13 +312,13 @@ namespace EventHub.Events public async Task AddSessionAsync(Guid id, AddSessionDto input) { var @event = await _eventRepository.GetAsync(id); - + @event.AddSession( input.TrackId, GuidGenerator.Create(), input.Title, - input.StartTime, - input.EndTime, + Clock.Normalize(input.StartTime), + Clock.Normalize(input.EndTime), input.Description, input.Language, await GetUserIdsByUserNamesAsync(input.SpeakerUserNames) @@ -326,6 +327,25 @@ namespace EventHub.Events await _eventRepository.UpdateAsync(@event); } + [Authorize] + public async Task UpdateSessionAsync(Guid id, Guid trackId, Guid sessionId, UpdateSessionDto input) + { + var @event = await _eventRepository.GetAsync(id); + + @event.UpdateSession( + trackId, + sessionId, + input.Title, + Clock.Normalize(input.StartTime), + Clock.Normalize(input.EndTime), + input.Description, + input.Language, + await GetUserIdsByUserNamesAsync(input.SpeakerUserNames) + ); + + await _eventRepository.UpdateAsync(@event, true); + } + public async Task GetCoverImageAsync(Guid id) { var blobName = id.ToString(); @@ -349,20 +369,13 @@ namespace EventHub.Events private async Task> GetUserIdsByUserNamesAsync(List userNames) { - var speakerUserIDs = new List(); - foreach (var userName in userNames.Where(userName => !userName.IsNullOrWhiteSpace())) - { - var user = await _userRepository.FindAsync(x => x.UserName == userName.Trim()); - if (user is null) - { - throw new BusinessException(EventHubErrorCodes.UserNotFound) - .WithData("UserName", userName); - } + var userQueryable = await _userRepository.GetQueryableAsync(); - speakerUserIDs.Add(user.Id); - } - - return speakerUserIDs; + var query = userQueryable + .Where(u => userNames.Any(p => p == u.UserName)) + .Select(x => x.Id); + + return await AsyncExecuter.ToListAsync(query); } private async Task CheckOwnerControlAsync(Event @event) diff --git a/src/EventHub.Domain.Shared/EventHubDomainSharedModule.cs b/src/EventHub.Domain.Shared/EventHubDomainSharedModule.cs index 25829cb..8d03059 100644 --- a/src/EventHub.Domain.Shared/EventHubDomainSharedModule.cs +++ b/src/EventHub.Domain.Shared/EventHubDomainSharedModule.cs @@ -62,4 +62,4 @@ namespace EventHub Configure(configuration.GetSection("AppUrls")); } } -} \ No newline at end of file +} diff --git a/src/EventHub.Domain.Shared/EventHubErrorCodes.cs b/src/EventHub.Domain.Shared/EventHubErrorCodes.cs index 572a9f4..b68dbce 100644 --- a/src/EventHub.Domain.Shared/EventHubErrorCodes.cs +++ b/src/EventHub.Domain.Shared/EventHubErrorCodes.cs @@ -18,5 +18,6 @@ public const string OrganizationNotFound = "EventHub:OrganizationNotFound"; public const string TrackNameAlreadyExist = "EventHub:TrackNameAlreadyExist"; public const string TrackNotFound = "EventHub:TrackNotFound"; + public const string SessionNotFound = "EventHub:SessionNotFound"; } } diff --git a/src/EventHub.Domain.Shared/Localization/EventHub/en.json b/src/EventHub.Domain.Shared/Localization/EventHub/en.json index f933d5e..bd4e774 100644 --- a/src/EventHub.Domain.Shared/Localization/EventHub/en.json +++ b/src/EventHub.Domain.Shared/Localization/EventHub/en.json @@ -154,6 +154,8 @@ "InPerson": "In Person", "UpgradeToPremium": "Upgrade To Premium", "EventHub:TrackNameAlreadyExist": "The track {Name} already exists", - "EventHub:TrackNotFound": "The track not found!" + "EventHub:TrackNotFound": "The track not found!", + "EventHub:SessionNotFound": "The session not found!", + "EventHub:SessionTimeShouldBeInTheEventTime": "Session time should be in the event time!" } } diff --git a/src/EventHub.Domain/Events/Event.cs b/src/EventHub.Domain/Events/Event.cs index ddc8758..9394e71 100644 --- a/src/EventHub.Domain/Events/Event.cs +++ b/src/EventHub.Domain/Events/Event.cs @@ -196,6 +196,23 @@ namespace EventHub.Events track.AddSession(sessionId, title, startTime, endTime, description, language, speakerUserIds); return this; } + + public Event UpdateSession( + Guid trackId, + Guid sessionId, + string title, + DateTime startTime, + DateTime endTime, + string description, + string language, + ICollection speakerUserIds) + { + var track = GetTrack(trackId); + + track.RemoveSession(sessionId); + AddSession(trackId, sessionId, title, startTime, endTime, description, language, speakerUserIds); + return this; + } public Event Publish(bool isPublish = true) { diff --git a/src/EventHub.Domain/Events/Track.cs b/src/EventHub.Domain/Events/Track.cs index 1c3783e..5744f85 100644 --- a/src/EventHub.Domain/Events/Track.cs +++ b/src/EventHub.Domain/Events/Track.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.Linq; using Volo.Abp; using Volo.Abp.Domain.Entities; @@ -63,5 +64,18 @@ namespace EventHub.Events return this; } + + internal Track RemoveSession(Guid sessionId) + { + var session = Sessions.SingleOrDefault(x => x.Id == sessionId); + if (session is null) + { + throw new BusinessException(EventHubErrorCodes.SessionNotFound); + } + + Sessions.Remove(session); + + return this; + } } } diff --git a/src/EventHub.HttpApi.Host/EventHubHttpApiHostModule.cs b/src/EventHub.HttpApi.Host/EventHubHttpApiHostModule.cs index c944a54..d2e5674 100644 --- a/src/EventHub.HttpApi.Host/EventHubHttpApiHostModule.cs +++ b/src/EventHub.HttpApi.Host/EventHubHttpApiHostModule.cs @@ -30,6 +30,7 @@ using Volo.Abp.Caching.StackExchangeRedis; using Volo.Abp.Localization; using Volo.Abp.Modularity; using Volo.Abp.Swashbuckle; +using Volo.Abp.Timing; using Volo.Abp.UI.Navigation.Urls; using Volo.Abp.VirtualFileSystem; @@ -63,6 +64,7 @@ namespace EventHub ConfigureSwaggerServices(context, configuration); ConfigureBackgroundJobs(); ConfigureAutoApiControllers(); + ConfigureTiming(); } private void ConfigureAutoApiControllers() @@ -185,6 +187,11 @@ namespace EventHub { context.Services.AddSameSiteCookiePolicy(); } + + private void ConfigureTiming() + { + Configure(options => { options.Kind = DateTimeKind.Utc; }); + } public override void OnApplicationInitialization(ApplicationInitializationContext context) { diff --git a/src/EventHub.HttpApi/Controllers/Events/EventController.cs b/src/EventHub.HttpApi/Controllers/Events/EventController.cs index f9909e5..fe826d7 100644 --- a/src/EventHub.HttpApi/Controllers/Events/EventController.cs +++ b/src/EventHub.HttpApi/Controllers/Events/EventController.cs @@ -109,6 +109,13 @@ namespace EventHub.Controllers.Events await _eventAppService.AddSessionAsync(id, input); } + [HttpPut] + [Route("{id}/tracks/{trackId}/sessions/{sessionId}")] + public async Task UpdateSessionAsync(Guid id, Guid trackId, Guid sessionId, UpdateSessionDto input) + { + await _eventAppService.UpdateSessionAsync(id, trackId, sessionId, input); + } + [HttpGet] [Route("cover-image/{id}")] public async Task GetCoverImageAsync(Guid id) diff --git a/src/EventHub.Web/Pages/Events/Components/CreateEventArea/CreateEventAreaViewComponent.cs b/src/EventHub.Web/Pages/Events/Components/CreateEventArea/CreateEventAreaViewComponent.cs index a7f5b8e..27dbc4c 100644 --- a/src/EventHub.Web/Pages/Events/Components/CreateEventArea/CreateEventAreaViewComponent.cs +++ b/src/EventHub.Web/Pages/Events/Components/CreateEventArea/CreateEventAreaViewComponent.cs @@ -59,7 +59,7 @@ public class CreateEventAreaViewComponent : AbpViewComponent model ??= new NewEventViewModel { StartTime = DateTime.Now.ClearTime().AddDays(1).AddHours(19), - EndTime = DateTime.Now.ClearTime().AddDays(1).AddHours(21) + EndTime = DateTime.Now.ClearTime().AddDays(2).AddHours(21) }; ViewData["StepType"] = stepType.ToString(); diff --git a/src/EventHub.Web/Pages/Events/Components/CreateEventArea/_addSessionSection.cshtml b/src/EventHub.Web/Pages/Events/Components/CreateEventArea/_addSessionSection.cshtml index d88b94e..e8df55e 100644 --- a/src/EventHub.Web/Pages/Events/Components/CreateEventArea/_addSessionSection.cshtml +++ b/src/EventHub.Web/Pages/Events/Components/CreateEventArea/_addSessionSection.cshtml @@ -47,6 +47,13 @@ @foreach (var session in track.Sessions) { + + + + + + x.UserName)).EnsureEndsWith(',').EnsureEndsWith(' ') : "")"/> +
@session.Title @EventDateHelper.GetTimeRangeText(TimeOnly.FromDateTime(session.StartTime), TimeOnly.FromDateTime(session.EndTime)) | @session.Language @@ -54,7 +61,7 @@ { @speaker.UserName } - + Edit
@@ -135,39 +142,49 @@ -