From 3b80d9c607b1e53552981382bd94a74e5b321df7 Mon Sep 17 00:00:00 2001 From: Berkan Sasmaz Date: Mon, 10 May 2021 23:51:31 +0300 Subject: [PATCH] Revise organization edit page --- .../Organizations/IOrganizationAppService.cs | 2 - .../Organizations/UpdateOrganizationDto.cs | 26 +++- .../Organizations/OrganizationAppService.cs | 15 ++- .../Controllers/OrganizationController.cs | 23 ---- .../Pages/Organizations/Edit.cshtml | 125 +++++++++++++----- .../Pages/Organizations/Edit.cshtml.cs | 58 ++++---- src/EventHub.Web/Pages/Organizations/Edit.js | 99 +++----------- .../Pages/Organizations/Profile.cshtml | 6 + 8 files changed, 183 insertions(+), 171 deletions(-) diff --git a/src/EventHub.Application.Contracts/Organizations/IOrganizationAppService.cs b/src/EventHub.Application.Contracts/Organizations/IOrganizationAppService.cs index 6c9e49e..8e94ddb 100644 --- a/src/EventHub.Application.Contracts/Organizations/IOrganizationAppService.cs +++ b/src/EventHub.Application.Contracts/Organizations/IOrganizationAppService.cs @@ -18,7 +18,5 @@ namespace EventHub.Organizations Task IsOrganizationOwnerAsync(Guid organizationId); Task UpdateAsync(Guid id, UpdateOrganizationDto input); - - Task SaveProfilePictureAsync(Guid id, byte[] bytes); } } diff --git a/src/EventHub.Application.Contracts/Organizations/UpdateOrganizationDto.cs b/src/EventHub.Application.Contracts/Organizations/UpdateOrganizationDto.cs index 32516a0..8d43241 100644 --- a/src/EventHub.Application.Contracts/Organizations/UpdateOrganizationDto.cs +++ b/src/EventHub.Application.Contracts/Organizations/UpdateOrganizationDto.cs @@ -1,4 +1,5 @@ using System.ComponentModel.DataAnnotations; +using JetBrains.Annotations; namespace EventHub.Organizations { @@ -12,16 +13,31 @@ namespace EventHub.Organizations [StringLength(OrganizationConsts.MaxDescriptionNameLength, MinimumLength = OrganizationConsts.MinDescriptionNameLength)] public string Description { get; set; } + [CanBeNull] + public byte[] ProfilePictureContent { get; set; } + + [CanBeNull] + [StringLength(OrganizationConsts.MaxWebsiteLength)] public string Website { get; set; } - + + [CanBeNull] + [StringLength(OrganizationConsts.MaxTwitterUsernameLength)] public string TwitterUsername { get; set; } - + + [CanBeNull] + [StringLength(OrganizationConsts.MaxGitHubUsernameLength)] public string GitHubUsername { get; set; } - + + [CanBeNull] + [StringLength(OrganizationConsts.MaxFacebookUsernameLength)] public string FacebookUsername { get; set; } - + + [CanBeNull] + [StringLength(OrganizationConsts.MaxInstagramUsernameLength)] public string InstagramUsername { get; set; } - + + [CanBeNull] + [StringLength(OrganizationConsts.MaxMediumUsernameLength)] public string MediumUsername { get; set; } } } \ No newline at end of file diff --git a/src/EventHub.Application/Organizations/OrganizationAppService.cs b/src/EventHub.Application/Organizations/OrganizationAppService.cs index 32cc81b..afbb847 100644 --- a/src/EventHub.Application/Organizations/OrganizationAppService.cs +++ b/src/EventHub.Application/Organizations/OrganizationAppService.cs @@ -7,6 +7,7 @@ using EventHub.Users; using Microsoft.AspNetCore.Authorization; using Volo.Abp; using Volo.Abp.Application.Dtos; +using Volo.Abp.Authorization; using Volo.Abp.BlobStoring; using Volo.Abp.Domain.Repositories; using Volo.Abp.Users; @@ -137,8 +138,7 @@ namespace EventHub.Organizations if (organization.OwnerUserId != CurrentUser.GetId()) { - //TODO: throw AbpAuthorizationException instead - throw new BusinessException(EventHubErrorCodes.NotAuthorizedToUpdateOrganizationProfile) + throw new AbpAuthorizationException(EventHubErrorCodes.NotAuthorizedToUpdateOrganizationProfile) .WithData("OrganizationName", organization.DisplayName); } @@ -151,18 +151,21 @@ namespace EventHub.Organizations organization.FacebookUsername = input.FacebookUsername; organization.MediumUsername = input.MediumUsername; + if (input.ProfilePictureContent != null && input.ProfilePictureContent.Length > 0) + { + await SaveProfilePictureAsync(organization.Id, input.ProfilePictureContent); + } + await _organizationRepository.UpdateAsync(organization); } - [Authorize] - public async Task SaveProfilePictureAsync(Guid id, byte[] bytes) + private async Task SaveProfilePictureAsync(Guid id, byte[] bytes) { var organization = await _organizationRepository.GetAsync(x => x.Id == id); if (organization.OwnerUserId != CurrentUser.GetId()) { - //TODO: throw AbpAuthorizationException instead - throw new BusinessException(EventHubErrorCodes.NotAuthorizedToUpdateOrganizationProfile) + throw new AbpAuthorizationException(EventHubErrorCodes.NotAuthorizedToUpdateOrganizationProfile) .WithData("Name", organization.DisplayName); } diff --git a/src/EventHub.Web/Controllers/OrganizationController.cs b/src/EventHub.Web/Controllers/OrganizationController.cs index 1ef1aba..1ac5474 100644 --- a/src/EventHub.Web/Controllers/OrganizationController.cs +++ b/src/EventHub.Web/Controllers/OrganizationController.cs @@ -1,11 +1,7 @@ -using System.IO; using System.Linq; using System.Threading.Tasks; using EventHub.Organizations; -using EventHub.Web.Pages.Organizations; -using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; -using Volo.Abp.Application.Dtos; using Volo.Abp.AspNetCore.Mvc; namespace EventHub.Web.Controllers @@ -32,24 +28,5 @@ namespace EventHub.Web.Controllers ViewData = ViewData }; } - - [HttpPost] - [Authorize] - [Route("save-profile-picture")] - public async Task SaveProfilePicture([FromForm] OrganizationProfilePictureInput input) - { - var profilePictureContent = new byte[] {}; - - if (input.ProfilePictureFile.Length > 0) - { - using (var memoryStream = new MemoryStream()) - { - await input.ProfilePictureFile.CopyToAsync(memoryStream); - profilePictureContent = memoryStream.ToArray(); - } - - await _organizationAppService.SaveProfilePictureAsync(input.OrganizationId, profilePictureContent); - } - } } } \ No newline at end of file diff --git a/src/EventHub.Web/Pages/Organizations/Edit.cshtml b/src/EventHub.Web/Pages/Organizations/Edit.cshtml index 4b5253f..307f0e3 100644 --- a/src/EventHub.Web/Pages/Organizations/Edit.cshtml +++ b/src/EventHub.Web/Pages/Organizations/Edit.cshtml @@ -1,6 +1,7 @@ @page "/organization/edit/{name}" @inject IHtmlLocalizer L @using EventHub.Localization +@using EventHub.Organizations @using Microsoft.AspNetCore.Mvc.Localization @using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal @model EventHub.Web.Pages.Organizations.EditPageModel @@ -9,41 +10,97 @@ } -
-

@L["EditOrganization"]

+
+
+
+
+
+

Edit Organization

+
+
+
+ - - - - - - - - - - -
- -
- - - @L["OrganizationProfilePictureInfo"] +
+

Profile Image

+
+
+
+ +
+
+ +
+
+

Photo size should be max @(OrganizationConsts.MaxProfilePictureFileSize / (1024 * 1024)) MB.

+ + +
+
+
+
+ +
+
+ + +
+
+ +
+
+ + +
+
+ +
+
+ + +
+
+ +
+
+ + +
+
+
+
+ + +
+
+
+
+ + +
+
+
+
+ + +
+
+
+
+ + +
+
+
+ +
-
-
- - -
-
- - - - - - - - + +
+
+
+
\ No newline at end of file diff --git a/src/EventHub.Web/Pages/Organizations/Edit.cshtml.cs b/src/EventHub.Web/Pages/Organizations/Edit.cshtml.cs index fb7d634..8937ef7 100644 --- a/src/EventHub.Web/Pages/Organizations/Edit.cshtml.cs +++ b/src/EventHub.Web/Pages/Organizations/Edit.cshtml.cs @@ -1,11 +1,14 @@ using System; using System.ComponentModel.DataAnnotations; +using System.IO; using System.Threading.Tasks; using EventHub.Organizations; using EventHub.Web.Helpers; +using JetBrains.Annotations; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; +using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form; namespace EventHub.Web.Pages.Organizations { @@ -27,7 +30,9 @@ namespace EventHub.Web.Pages.Organizations public async Task OnGetAsync() { - await GetOrganizationAsync(); + var organizationProfileDto = await _organizationAppService.GetProfileAsync(Name); + + Organization = ObjectMapper.Map(organizationProfileDto); } public async Task OnPostAsync() @@ -37,6 +42,16 @@ namespace EventHub.Web.Pages.Organizations ValidateModel(); var input = ObjectMapper.Map(Organization); + + if (Organization.ProfilePictureFile != null && Organization.ProfilePictureFile.Length > 0) + { + using (var memoryStream = new MemoryStream()) + { + await Organization.ProfilePictureFile.CopyToAsync(memoryStream); + input.ProfilePictureContent = memoryStream.ToArray(); + } + } + await _organizationAppService.UpdateAsync(Organization.Id, input); return RedirectToPage("./Profile", new { name = Name }); @@ -47,12 +62,6 @@ namespace EventHub.Web.Pages.Organizations return Page(); } } - - private async Task GetOrganizationAsync() - { - var organizationProfileDto = await _organizationAppService.GetProfileAsync(Name); - Organization = ObjectMapper.Map(organizationProfileDto); - } } public class EditOrganizationViewModel @@ -65,31 +74,32 @@ namespace EventHub.Web.Pages.Organizations public string DisplayName { get; set; } [Required] + [DataType(DataType.MultilineText)] [StringLength(OrganizationConsts.MaxDescriptionNameLength, MinimumLength = OrganizationConsts.MinDescriptionNameLength)] public string Description { get; set; } + [CanBeNull] + [DataType(DataType.Upload)] + [MaxFileSize(OrganizationConsts.MaxProfilePictureFileSize)] + [AllowedExtensions(new string[] { ".jpg", ".png", ".jpeg" })] + public IFormFile ProfilePictureFile { get; set; } + + [StringLength(OrganizationConsts.MaxWebsiteLength)] public string Website { get; set; } - + + [StringLength(OrganizationConsts.MaxTwitterUsernameLength)] public string TwitterUsername { get; set; } - + + [StringLength(OrganizationConsts.MaxGitHubUsernameLength)] public string GitHubUsername { get; set; } - + + [StringLength(OrganizationConsts.MaxFacebookUsernameLength)] public string FacebookUsername { get; set; } - + + [StringLength(OrganizationConsts.MaxInstagramUsernameLength)] public string InstagramUsername { get; set; } - + + [StringLength(OrganizationConsts.MaxMediumUsernameLength)] public string MediumUsername { get; set; } } - - public class OrganizationProfilePictureInput - { - [Required] - public Guid OrganizationId { get; set; } - - [Required] - [DataType(DataType.Upload)] - [MaxFileSize(OrganizationConsts.MaxProfilePictureFileSize)] - [AllowedExtensions(new string[] { ".jpg", ".png", ".jpeg" })] - public IFormFile ProfilePictureFile { get; set; } - } } \ No newline at end of file diff --git a/src/EventHub.Web/Pages/Organizations/Edit.js b/src/EventHub.Web/Pages/Organizations/Edit.js index abbfe4b..9020a73 100644 --- a/src/EventHub.Web/Pages/Organizations/Edit.js +++ b/src/EventHub.Web/Pages/Organizations/Edit.js @@ -1,43 +1,39 @@ $(function () { var l = abp.localization.getResource('EventHub'); - var fileInput = document.getElementById("organization-profile-picture"); + var infoArea = document.getElementById( 'upload-label' ); + var fileInput = document.getElementById('Organization_ProfilePictureFile'); var file; - + fileInput.addEventListener('change', function () { - var showModal = true; - + var showFile = true; file = fileInput.files[0]; - - if(file == undefined) { - $("#choose-cover-image").html(l("ChooseOrganizationProfilePicture")); + + if (file === undefined){ + $('#Organization_ProfilePictureFile').val(''); + $('#imageResult').attr('src', '#'); + infoArea.textContent = 'Choose file' return; } - else { - $("#choose-cover-image").html(file.name); - } var permittedExtensions = ["jpg", "jpeg", "png"] var fileExtension = $(this).val().split('.').pop(); - if (permittedExtensions.indexOf(fileExtension) === -1) { - showModal = false; - abp.message.error(l("OrganizationProfilePictureExtensionNotAllowed")) - .then(() => { - $("#choose-cover-image").html(l("ChooseOrganizationProfilePicture")); + showFile = false; + abp.message.error(l('OrganizationProfilePictureExtensionNotAllowed')) + .then(() => { + $('#Organization_ProfilePictureFile').val(''); file = null; }); - } - //1mb - else if(file.size > 1024 * 1024) { - showModal = false; - abp.message.error(l("OrganizationProfilePictureSizeExceedMessage")) + } else if (file.size > 1024 * 1024) { + showFile = false; + abp.message.error(l('OrganizationProfilePictureSizeExceedMessage')) .then(() => { - $("#choose-cover-image").html(l("ChooseOrganizationProfilePicture")); + $('#Organization_ProfilePictureFile').val(''); file = null; }); } - + var img = new Image(); img.onload = function () { var imageError = true; @@ -45,12 +41,10 @@ $(function () { width: this.width, height: this.height }; - URL.revokeObjectURL(this.src); - - if(showModal && imageError) { + + if (showFile && imageError) { readURL(file); - $("#picturePreviewModal").modal('show'); } } @@ -63,60 +57,11 @@ $(function () { var reader = new FileReader(); reader.onload = function (e) { - $('#img-upload').attr('src', e.target.result); + $('#imageResult').attr('src', e.target.result); + infoArea.textContent = 'File name: ' + input.name; } reader.readAsDataURL(input); } } - - $("form#EditOrganizationProfileForm").submit(function (e) { - e.preventDefault(); - - var organizationId = document.getElementById("organization-id").value; - var organizationName = document.getElementById("organization-name").value; - - if(!$(this).valid()) { - return false; - } - - if(file === undefined) { - file = null; - } - - var formData = new FormData(); - formData.append("OrganizationId", organizationId); - formData.append("ProfilePictureFile", file); - - $.ajax({ - xhr: function() { - var xhr = new window.XMLHttpRequest(); - xhr.upload.addEventListener("progress", function(evt) { - if (evt.lengthComputable) { - var percentage = evt.loaded / evt.total; - percentage = parseInt(percentage * 100); - if(percentage !== 100){ - $('#btnSubmit').prop("disabled", true); - } - } - }, false); - - return xhr; - }, - url: `/api/organization/save-profile-picture`, - data: formData, - type: 'POST', - contentType: false, - processData: false, - success: function(data){ - abp.message - .success(l("OrganizationProfilePictureEditSuccessMessage")) - .then(data => window.location.href = "/Organizations/" + organizationName); - }, - error: function (data) { - abp.message.error(data.responseJSON.error.message); - } - }); - - }); }); \ No newline at end of file diff --git a/src/EventHub.Web/Pages/Organizations/Profile.cshtml b/src/EventHub.Web/Pages/Organizations/Profile.cshtml index 9f498a5..447c1aa 100644 --- a/src/EventHub.Web/Pages/Organizations/Profile.cshtml +++ b/src/EventHub.Web/Pages/Organizations/Profile.cshtml @@ -58,6 +58,12 @@
+ @if (Model.IsOrganizationOwner) + { + + Edit + + } @await Component.InvokeAsync(typeof(JoinAreaViewComponent), new {organizationId = Model.Organization.Id}) @await Component.InvokeAsync(typeof(MembersAreaViewComponent), new