diff --git a/eventhub/src/EventHub.Application.Contracts/Organizations/CreateOrganizationDto.cs b/eventhub/src/EventHub.Application.Contracts/Organizations/CreateOrganizationDto.cs new file mode 100644 index 0000000..be5403e --- /dev/null +++ b/eventhub/src/EventHub.Application.Contracts/Organizations/CreateOrganizationDto.cs @@ -0,0 +1,19 @@ +using System.ComponentModel.DataAnnotations; + +namespace EventHub.Organizations +{ + public class CreateOrganizationDto + { + [Required] + [StringLength(OrganizationConsts.MaxNameLength, MinimumLength = OrganizationConsts.MinNameLength)] + public string Name { get; set; } + + [Required] + [StringLength(OrganizationConsts.MaxDisplayNameLength, MinimumLength = OrganizationConsts.MinDisplayNameLength)] + public string DisplayName { get; set; } + + [Required] + [StringLength(OrganizationConsts.MaxDescriptionNameLength, MinimumLength = OrganizationConsts.MinDescriptionNameLength)] + public string Description { get; set; } + } +} diff --git a/eventhub/src/EventHub.Application.Contracts/Organizations/IOrganizationAppService.cs b/eventhub/src/EventHub.Application.Contracts/Organizations/IOrganizationAppService.cs index 3c03da1..f3eec8f 100644 --- a/eventhub/src/EventHub.Application.Contracts/Organizations/IOrganizationAppService.cs +++ b/eventhub/src/EventHub.Application.Contracts/Organizations/IOrganizationAppService.cs @@ -6,6 +6,8 @@ namespace EventHub.Organizations { public interface IOrganizationAppService : IApplicationService { + Task CreateAsync(CreateOrganizationDto input); + Task> GetListAsync(PagedResultRequestDto input); } } diff --git a/eventhub/src/EventHub.Application/Organizations/OrganizationAppService.cs b/eventhub/src/EventHub.Application/Organizations/OrganizationAppService.cs index 21e3166..cb20512 100644 --- a/eventhub/src/EventHub.Application/Organizations/OrganizationAppService.cs +++ b/eventhub/src/EventHub.Application/Organizations/OrganizationAppService.cs @@ -1,18 +1,35 @@ using System; using System.Collections.Generic; using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; using Volo.Abp.Application.Dtos; using Volo.Abp.Domain.Repositories; +using Volo.Abp.Users; namespace EventHub.Organizations { public class OrganizationAppService : EventHubAppService, IOrganizationAppService { private readonly IRepository _organizationRepository; + private readonly OrganizationManager _organizationManager; - public OrganizationAppService(IRepository organizationRepository) + public OrganizationAppService( + IRepository organizationRepository, + OrganizationManager organizationManager) { _organizationRepository = organizationRepository; + _organizationManager = organizationManager; + } + + [Authorize] + public async Task CreateAsync(CreateOrganizationDto input) + { + await _organizationManager.CreateAsync( + CurrentUser.GetId(), + input.Name, + input.DisplayName, + input.Description + ); } public async Task> GetListAsync(PagedResultRequestDto input) diff --git a/eventhub/src/EventHub.Domain.Shared/EventHubDomainErrorCodes.cs b/eventhub/src/EventHub.Domain.Shared/EventHubDomainErrorCodes.cs deleted file mode 100644 index af7a1fc..0000000 --- a/eventhub/src/EventHub.Domain.Shared/EventHubDomainErrorCodes.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace EventHub -{ - public static class EventHubDomainErrorCodes - { - /* You can add your business exception error codes here, as constants */ - } -} diff --git a/eventhub/src/EventHub.Domain.Shared/EventHubErrorCodes.cs b/eventhub/src/EventHub.Domain.Shared/EventHubErrorCodes.cs new file mode 100644 index 0000000..b70ec8c --- /dev/null +++ b/eventhub/src/EventHub.Domain.Shared/EventHubErrorCodes.cs @@ -0,0 +1,7 @@ +namespace EventHub +{ + public static class EventHubErrorCodes + { + public const string OrganizationNameAlreadyExists = "EventHub:OrganizationNameAlreadyExists"; + } +} diff --git a/eventhub/src/EventHub.Domain.Shared/Localization/EventHub/en.json b/eventhub/src/EventHub.Domain.Shared/Localization/EventHub/en.json index dd5e6b1..9e89a08 100644 --- a/eventhub/src/EventHub.Domain.Shared/Localization/EventHub/en.json +++ b/eventhub/src/EventHub.Domain.Shared/Localization/EventHub/en.json @@ -6,6 +6,10 @@ "LongWelcomeMessage": "Welcome to the application. This is a startup project based on the ABP framework. For more information, visit abp.io.", "Create": "Create", "NewOrganization": "New Organization", - "NewEvent": "New Event" + "NewEvent": "New Event", + "DisplayName:Name": "Name", + "DisplayName:DisplayName": "Display Name", + "DisplayName:Description": "Description", + "EventHub:OrganizationNameAlreadyExists": "The organization {Name} already exists. Please use another name." } } diff --git a/eventhub/src/EventHub.Domain.Shared/Organizations/OrganizationContst.cs b/eventhub/src/EventHub.Domain.Shared/Organizations/OrganizationContst.cs index 90b0d64..a8fca4a 100644 --- a/eventhub/src/EventHub.Domain.Shared/Organizations/OrganizationContst.cs +++ b/eventhub/src/EventHub.Domain.Shared/Organizations/OrganizationContst.cs @@ -7,5 +7,8 @@ public const int MinDisplayNameLength = 2; public const int MaxDisplayNameLength = 128; + + public const int MinDescriptionNameLength = 50; + public const int MaxDescriptionNameLength = 1000; } } diff --git a/eventhub/src/EventHub.Domain/Organizations/Organization.cs b/eventhub/src/EventHub.Domain/Organizations/Organization.cs index fd2af2c..9c3bd81 100644 --- a/eventhub/src/EventHub.Domain/Organizations/Organization.cs +++ b/eventhub/src/EventHub.Domain/Organizations/Organization.cs @@ -10,9 +10,9 @@ namespace EventHub.Organizations public string Name { get; private set; } - public string DisplayName { get; set; } + public string DisplayName { get; private set; } - public string Description { get; set; } + public string Description { get; private set; } public string Website { get; set; } @@ -34,12 +34,14 @@ namespace EventHub.Organizations Guid id, Guid ownerUserId, string name, - string displayName) + string displayName, + string description) : base(id) { OwnerUserId = ownerUserId; SetName(name); SetDisplayName(displayName); + SetDescription(description); } internal void SetName(string name) @@ -51,5 +53,10 @@ namespace EventHub.Organizations { DisplayName = Check.NotNullOrWhiteSpace(displayName, nameof(displayName), OrganizationConsts.MaxDisplayNameLength, OrganizationConsts.MinDisplayNameLength); } + + public void SetDescription(string description) + { + Description = Check.NotNullOrWhiteSpace(description, nameof(description), OrganizationConsts.MaxDescriptionNameLength, OrganizationConsts.MinDescriptionNameLength); + } } } diff --git a/eventhub/src/EventHub.Domain/Organizations/OrganizationManager.cs b/eventhub/src/EventHub.Domain/Organizations/OrganizationManager.cs new file mode 100644 index 0000000..4103051 --- /dev/null +++ b/eventhub/src/EventHub.Domain/Organizations/OrganizationManager.cs @@ -0,0 +1,41 @@ +using System; +using System.Threading.Tasks; +using Volo.Abp; +using Volo.Abp.Domain.Repositories; +using Volo.Abp.Domain.Services; + +namespace EventHub.Organizations +{ + public class OrganizationManager : DomainService + { + private readonly IRepository _organizationRepository; + + public OrganizationManager(IRepository organizationRepository) + { + _organizationRepository = organizationRepository; + } + + public async Task CreateAsync( + Guid ownerUserId, + string name, + string displayName, + string description) + { + if (await _organizationRepository.AnyAsync(o => o.Name == name)) + { + throw new BusinessException(EventHubErrorCodes.OrganizationNameAlreadyExists) + .WithData("Name", name); + } + + var organization = new Organization( + GuidGenerator.Create(), + ownerUserId, + name, + displayName, + description + ); + + return await _organizationRepository.InsertAsync(organization); + } + } +} diff --git a/eventhub/src/EventHub.Web/EventHubWebAutoMapperProfile.cs b/eventhub/src/EventHub.Web/EventHubWebAutoMapperProfile.cs index 5eff442..9b40896 100644 --- a/eventhub/src/EventHub.Web/EventHubWebAutoMapperProfile.cs +++ b/eventhub/src/EventHub.Web/EventHubWebAutoMapperProfile.cs @@ -1,4 +1,6 @@ using AutoMapper; +using EventHub.Organizations; +using EventHub.Web.Pages.Organizations; namespace EventHub.Web { @@ -6,7 +8,7 @@ namespace EventHub.Web { public EventHubWebAutoMapperProfile() { - //Define your AutoMapper configuration here for the Web project. + CreateMap(); } } } diff --git a/eventhub/src/EventHub.Web/Pages/Organizations/New.cshtml b/eventhub/src/EventHub.Web/Pages/Organizations/New.cshtml index 3de3a5c..e7f8dee 100644 --- a/eventhub/src/EventHub.Web/Pages/Organizations/New.cshtml +++ b/eventhub/src/EventHub.Web/Pages/Organizations/New.cshtml @@ -4,3 +4,4 @@ @using Microsoft.AspNetCore.Mvc.Localization @model EventHub.Web.Pages.Organizations.New

@L["NewOrganization"]

+ diff --git a/eventhub/src/EventHub.Web/Pages/Organizations/New.cshtml.cs b/eventhub/src/EventHub.Web/Pages/Organizations/New.cshtml.cs index ceffc14..a679061 100644 --- a/eventhub/src/EventHub.Web/Pages/Organizations/New.cshtml.cs +++ b/eventhub/src/EventHub.Web/Pages/Organizations/New.cshtml.cs @@ -1,10 +1,71 @@ -namespace EventHub.Web.Pages.Organizations +using System; +using System.ComponentModel.DataAnnotations; +using System.Threading.Tasks; +using EventHub.Organizations; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; +using Volo.Abp.AspNetCore.ExceptionHandling; +using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form; + +namespace EventHub.Web.Pages.Organizations { + [Authorize] public class New : EventHubPageModel { + [BindProperty] + public CreateOrganizationViewModel Organization { get; set; } + + private readonly IOrganizationAppService _organizationAppService; + private readonly IExceptionToErrorInfoConverter _errorInfoConverter; + + public New( + IOrganizationAppService organizationAppService, + IExceptionToErrorInfoConverter errorInfoConverter) + { + _organizationAppService = organizationAppService; + _errorInfoConverter = errorInfoConverter; + } + public void OnGet() { + Organization = new CreateOrganizationViewModel(); + } + + public async Task OnPostAsync() + { + try + { + ValidateModel(); + + var input = ObjectMapper.Map(Organization); + await _organizationAppService.CreateAsync(input); + + return RedirectToPage("./OrganizationProfile", new {name = Organization.Name}); + } + catch (Exception exception) + { + Logger.LogException(exception); + var errorInfo = _errorInfoConverter.Convert(exception, false); + Alerts.Danger(errorInfo.Message); + return Page(); + } + } + + public class CreateOrganizationViewModel + { + [Required] + [StringLength(OrganizationConsts.MaxNameLength, MinimumLength = OrganizationConsts.MinNameLength)] + public string Name { get; set; } + + [Required] + [StringLength(OrganizationConsts.MaxDisplayNameLength, MinimumLength = OrganizationConsts.MinDisplayNameLength)] + public string DisplayName { get; set; } + [Required] + [StringLength(OrganizationConsts.MaxDescriptionNameLength, MinimumLength = OrganizationConsts.MinDescriptionNameLength)] + [TextArea] + public string Description { get; set; } } } } diff --git a/eventhub/src/EventHub.Web/Pages/Organizations/OrganizationProfile.cshtml b/eventhub/src/EventHub.Web/Pages/Organizations/OrganizationProfile.cshtml new file mode 100644 index 0000000..dd70700 --- /dev/null +++ b/eventhub/src/EventHub.Web/Pages/Organizations/OrganizationProfile.cshtml @@ -0,0 +1,3 @@ +@page "/organizations/{name}" +@model EventHub.Web.Pages.Organizations.OrganizationProfile +

Organization: @Model.Name

diff --git a/eventhub/src/EventHub.Web/Pages/Organizations/OrganizationProfile.cshtml.cs b/eventhub/src/EventHub.Web/Pages/Organizations/OrganizationProfile.cshtml.cs new file mode 100644 index 0000000..4659673 --- /dev/null +++ b/eventhub/src/EventHub.Web/Pages/Organizations/OrganizationProfile.cshtml.cs @@ -0,0 +1,17 @@ +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.RazorPages; + +namespace EventHub.Web.Pages.Organizations +{ + public class OrganizationProfile : PageModel + { + [BindProperty(SupportsGet = true)] + public string Name { get; set; } + + public async Task OnGetAsync() + { + + } + } +}