Browse Source

Admin: Use `IRemoteContentStream` for organization profile picture

pull/62/head
Engincan VESKE 5 years ago
parent
commit
66520d226c
  1. 3
      src/EventHub.Admin.Application.Contracts/Organizations/IOrganizationAppService.cs
  2. 2
      src/EventHub.Admin.Application.Contracts/Organizations/OrganizationProfileDto.cs
  3. 3
      src/EventHub.Admin.Application.Contracts/Organizations/UpdateOrganizationDto.cs
  4. 3
      src/EventHub.Admin.Application/EventHubApplicationAutoMapperProfile.cs
  5. 33
      src/EventHub.Admin.Application/Organizations/OrganizationAppService.cs
  6. 35
      src/EventHub.Admin.HttpApi.Host/Controllers/Organizations/OrganizationController.cs
  7. 1
      src/EventHub.Admin.HttpApi.Host/EventHub.Admin.HttpApi.Host.csproj
  8. 23
      src/EventHub.Admin.HttpApi.Host/EventHubAdminHttpApiHostModule.cs
  9. BIN
      src/EventHub.Admin.HttpApi.Host/Images/eh-organization.png
  10. 3
      src/EventHub.Admin.Web/Pages/OrganizationManagement.razor
  11. 30
      src/EventHub.Admin.Web/Pages/OrganizationManagement.razor.cs
  12. 1
      src/EventHub.Application/Events/EventAppService.cs
  13. 1
      src/EventHub.Application/Organizations/OrganizationAppService.cs

3
src/EventHub.Admin.Application.Contracts/Organizations/IOrganizationAppService.cs

@ -2,6 +2,7 @@ using System;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
using Volo.Abp.Content;
namespace EventHub.Admin.Organizations
{
@ -16,5 +17,7 @@ namespace EventHub.Admin.Organizations
Task<OrganizationProfileDto> UpdateAsync(Guid id, UpdateOrganizationDto input);
Task DeleteAsync(Guid id);
Task<IRemoteStreamContent> GetCoverImageAsync(Guid id);
}
}

2
src/EventHub.Admin.Application.Contracts/Organizations/OrganizationProfileDto.cs

@ -9,8 +9,6 @@ namespace EventHub.Admin.Organizations
public string DisplayName { get; set; }
public byte[] ProfilePictureContent { get; set; }
public string OwnerUserName { get; set; }
public string OwnerEmail { get; set; }

3
src/EventHub.Admin.Application.Contracts/Organizations/UpdateOrganizationDto.cs

@ -1,6 +1,7 @@
using System.ComponentModel.DataAnnotations;
using EventHub.Organizations;
using JetBrains.Annotations;
using Volo.Abp.Content;
namespace EventHub.Admin.Organizations
{
@ -15,7 +16,7 @@ namespace EventHub.Admin.Organizations
public string Description { get; set; }
[CanBeNull]
public byte[] ProfilePictureContent { get; set; }
public RemoteStreamContent ProfilePictureStreamContent { get; set; }
[CanBeNull]
[StringLength(OrganizationConsts.MaxWebsiteLength)]

3
src/EventHub.Admin.Application/EventHubApplicationAutoMapperProfile.cs

@ -22,8 +22,7 @@ namespace EventHub.Admin
CreateMap<Organization, OrganizationProfileDto>()
.Ignore(x => x.OwnerUserName)
.Ignore(x => x.OwnerEmail)
.Ignore(x => x.ProfilePictureContent);
.Ignore(x => x.OwnerEmail);
CreateMap<OrganizationMemberWithDetails, OrganizationMemberDto>();

33
src/EventHub.Admin.Application/Organizations/OrganizationAppService.cs

@ -10,8 +10,8 @@ using Microsoft.AspNetCore.Authorization;
using Volo.Abp;
using Volo.Abp.Application.Dtos;
using Volo.Abp.BlobStoring;
using Volo.Abp.Content;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.Identity;
namespace EventHub.Admin.Organizations
{
@ -106,13 +106,9 @@ namespace EventHub.Admin.Organizations
organization.InstagramUsername = input.InstagramUsername;
organization.MediumUsername = input.MediumUsername;
if (input.ProfilePictureContent?.Length > 0)
if (input.ProfilePictureStreamContent != null && input.ProfilePictureStreamContent.ContentLength > 0)
{
await SaveCoverImageAsync(organization.Id, input.ProfilePictureContent);
}
else
{
await DeleteCoverImageAsync(organization.Id);
await SaveCoverImageAsync(organization.Id, input.ProfilePictureStreamContent);
}
await _organizationRepository.UpdateAsync(organization);
@ -134,29 +130,28 @@ namespace EventHub.Admin.Organizations
dto.OwnerUserName = user.UserName;
dto.OwnerEmail = user.Email;
dto.ProfilePictureContent = await GetCoverImageAsync(organization.Id);
return dto;
}
private async Task<byte[]> GetCoverImageAsync(Guid id)
{
var blobName = id.ToString();
return await _organizationBlobContainer.GetAllBytesOrNullAsync(blobName);
}
private async Task SaveCoverImageAsync(Guid id, byte[] coverImageContent)
[AllowAnonymous]
public async Task<IRemoteStreamContent> GetCoverImageAsync(Guid id)
{
var blobName = id.ToString();
var coverImageStream = await _organizationBlobContainer.GetOrNullAsync(blobName);
if (coverImageStream is null)
{
return null;
}
await _organizationBlobContainer.SaveAsync(blobName, coverImageContent, overrideExisting: true);
return new RemoteStreamContent(coverImageStream, blobName);
}
private async Task DeleteCoverImageAsync(Guid id)
private async Task SaveCoverImageAsync(Guid id, IRemoteStreamContent coverImageContent)
{
var blobName = id.ToString();
await _organizationBlobContainer.DeleteAsync(blobName);
await _organizationBlobContainer.SaveAsync(blobName, coverImageContent.GetStream(), overrideExisting: true);
}
}
}

35
src/EventHub.Admin.HttpApi.Host/Controllers/Organizations/OrganizationController.cs

@ -1,10 +1,14 @@
using System;
using System.IO;
using System.Threading.Tasks;
using EventHub.Admin.Organizations;
using Microsoft.AspNetCore.Authorization;
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.Admin.Controllers.Organizations
{
@ -16,10 +20,12 @@ namespace EventHub.Admin.Controllers.Organizations
public class OrganizationController : AbpController, IOrganizationAppService
{
private readonly IOrganizationAppService _organizationAppService;
public OrganizationController(IOrganizationAppService organizationAppService)
private readonly IVirtualFileProvider _virtualFileProvider;
public OrganizationController(IOrganizationAppService organizationAppService, IVirtualFileProvider virtualFileProvider)
{
_organizationAppService = organizationAppService;
_virtualFileProvider = virtualFileProvider;
}
[HttpGet]
@ -54,5 +60,30 @@ namespace EventHub.Admin.Controllers.Organizations
{
return _organizationAppService.DeleteAsync(id);
}
[HttpGet]
[AllowAnonymous]
[Route("cover-image/{id}")]
public async Task<IRemoteStreamContent> GetCoverImageAsync(Guid id)
{
var remoteStreamContent = await _organizationAppService.GetCoverImageAsync(id);
if (remoteStreamContent is null)
{
var stream = _virtualFileProvider
.GetFileInfo("/Images/eh-organization.png")
.CreateReadStream();
remoteStreamContent = new RemoteStreamContent(stream)
{
ContentType = "image/png"
};
await stream.FlushAsync();
}
Response.Headers.Add("Accept-Ranges", "bytes");
Response.ContentType = remoteStreamContent.ContentType;
return remoteStreamContent;
}
}
}

1
src/EventHub.Admin.HttpApi.Host/EventHub.Admin.HttpApi.Host.csproj

@ -33,6 +33,7 @@
<Content Remove="Logs\**" />
<EmbeddedResource Remove="Logs\**" />
<None Remove="Logs\**" />
<EmbeddedResource Include="Images\**\*.*" />
</ItemGroup>
</Project>

23
src/EventHub.Admin.HttpApi.Host/EventHubAdminHttpApiHostModule.cs

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using EventHub.Admin.Organizations;
using EventHub.Admin.Utils;
using EventHub.EntityFrameworkCore;
using EventHub.Web;
@ -17,6 +18,7 @@ using Microsoft.Extensions.Hosting;
using Microsoft.OpenApi.Models;
using StackExchange.Redis;
using Volo.Abp;
using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic;
using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared;
using Volo.Abp.AspNetCore.Serilog;
@ -59,6 +61,15 @@ namespace EventHub.Admin
ConfigureCookies(context);
ConfigureSwaggerServices(context, configuration);
ConfigureBackgroundJobs();
ConfigureAutoApiControllers();
}
private void ConfigureAutoApiControllers()
{
Configure<AbpAspNetCoreMvcOptions>(options =>
{
options.ConventionalControllers.FormBodyBindingIgnoredTypes.Add(typeof(UpdateOrganizationDto));
});
}
private void ConfigureBackgroundJobs()
@ -78,9 +89,13 @@ namespace EventHub.Admin
{
var hostingEnvironment = context.Services.GetHostingEnvironment();
if (hostingEnvironment.IsDevelopment())
Configure<AbpVirtualFileSystemOptions>(options =>
{
Configure<AbpVirtualFileSystemOptions>(options =>
options.FileSets.AddEmbedded<EventHubAdminHttpApiHostModule>(
baseNamespace: "EventHub.Admin",
baseFolder: "/Images");
if (hostingEnvironment.IsDevelopment())
{
options.FileSets.ReplaceEmbeddedByPhysical<EventHubDomainSharedModule>(
Path.Combine(hostingEnvironment.ContentRootPath,
@ -94,8 +109,8 @@ namespace EventHub.Admin
options.FileSets.ReplaceEmbeddedByPhysical<EventHubAdminApplicationModule>(
Path.Combine(hostingEnvironment.ContentRootPath,
$"..{Path.DirectorySeparatorChar}EventHub.Admin.Application"));
});
}
}
});
}
private void ConfigureAuthentication(ServiceConfigurationContext context, IConfiguration configuration)

BIN
src/EventHub.Admin.HttpApi.Host/Images/eh-organization.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 544 KiB

3
src/EventHub.Admin.Web/Pages/OrganizationManagement.razor

@ -4,12 +4,15 @@
@using Microsoft.AspNetCore.Authorization
@using EventHub.Admin.Organizations
@using EventHub.Organizations
@using EventHub.Web
@using Microsoft.Extensions.Options
@using Volo.Abp.AspNetCore.Components.Notifications
@inherits EventHubComponentBase
@inject NavigationManager NavigationManager
@attribute [Authorize(EventHubPermissions.Organizations.Default)]
@inject IOrganizationAppService OrganizationAppService
@inject IUiNotificationService UiNotificationService
@inject IOptions<EventHubUrlOptions> UrlOptions
<Card>
<CardHeader>

30
src/EventHub.Admin.Web/Pages/OrganizationManagement.razor.cs

@ -9,6 +9,7 @@ using Blazorise.DataGrid;
using EventHub.Admin.Organizations;
using Microsoft.AspNetCore.Components.Web;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Content;
namespace EventHub.Admin.Web.Pages
{
@ -73,7 +74,9 @@ namespace EventHub.Admin.Web.Pages
{
EditingOrganizationId = input.Id;
Organization = await OrganizationAppService.GetAsync(EditingOrganizationId);
FillProfileImageUrl(Organization.ProfilePictureContent);
FileEntry = new FileEntry();
ProfileImageUrl = UrlOptions.Value.AdminApi.EnsureEndsWith('/') + "api/eventhub/admin/organization/cover-image/" + EditingOrganizationId;
EditingOrganization = ObjectMapper.Map<OrganizationProfileDto, UpdateOrganizationDto>(Organization);
EditOrganizationModal.Show();
@ -88,7 +91,7 @@ namespace EventHub.Admin.Web.Pages
private void OnDeleteCoverImageButtonClicked()
{
EditingOrganization.ProfilePictureContent = null;
EditingOrganization.ProfilePictureStreamContent = null;
FileEntry = new FileEntry();
ProfileImageUrl = null;
IsLoadingProfileImage = false;
@ -110,23 +113,26 @@ namespace EventHub.Admin.Web.Pages
IsLoadingProfileImage = true;
using (var stream = new MemoryStream())
var stream = new MemoryStream();
await FileEntry.WriteToStreamAsync(stream);
stream.Seek(0, SeekOrigin.Begin);
EditingOrganization.ProfilePictureStreamContent = new RemoteStreamContent(stream)
{
await FileEntry.WriteToStreamAsync(stream);
ContentType = FileEntry.Type,
FileName = FileEntry.Name
};
stream.Seek(0, SeekOrigin.Begin);
EditingOrganization.ProfilePictureContent = stream.ToArray();
FillProfileImageUrl(EditingOrganization.ProfilePictureContent);
await InvokeAsync(StateHasChanged);
}
SetProfileImageUrl(FileEntry.Type, stream.ToArray());
await InvokeAsync(StateHasChanged);
}
private void FillProfileImageUrl(byte[] content)
private void SetProfileImageUrl(string contentType, byte[] content)
{
if (content != null)
{
var imageBase64Data = Convert.ToBase64String(content);
var imageDataUrl = $"data:image/png;base64,{imageBase64Data}";
contentType = string.IsNullOrWhiteSpace(contentType) ? "image/png" : contentType;
var imageDataUrl = $"data:{contentType};base64,{Convert.ToBase64String(content)}";
ProfileImageUrl = imageDataUrl;
}
}

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

@ -5,6 +5,7 @@ using System.Threading.Tasks;
using EventHub.Countries;
using EventHub.Events.Registrations;
using EventHub.Organizations;
using EventHub.Users;
using Microsoft.AspNetCore.Authorization;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Authorization;

1
src/EventHub.Application/Organizations/OrganizationAppService.cs

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using EventHub.Organizations.Memberships;
using EventHub.Users;
using Microsoft.AspNetCore.Authorization;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Authorization;

Loading…
Cancel
Save