Browse Source

Merge branch 'main' into EngincanV/net-6

pull/65/head
Engincan VESKE 5 years ago
parent
commit
49c4fd9f95
  1. 2
      src/EventHub.Admin.Application.Contracts/Events/EventDetailDto.cs
  2. 3
      src/EventHub.Admin.Application.Contracts/Events/IEventAppService.cs
  3. 3
      src/EventHub.Admin.Application.Contracts/Events/UpdateEventDto.cs
  4. 3
      src/EventHub.Admin.Application.Contracts/Organizations/IOrganizationAppService.cs
  5. 2
      src/EventHub.Admin.Application.Contracts/Organizations/OrganizationProfileDto.cs
  6. 3
      src/EventHub.Admin.Application.Contracts/Organizations/UpdateOrganizationDto.cs
  7. 6
      src/EventHub.Admin.Application/EventHubApplicationAutoMapperProfile.cs
  8. 33
      src/EventHub.Admin.Application/Events/EventAppService.cs
  9. 32
      src/EventHub.Admin.Application/Organizations/OrganizationAppService.cs
  10. 26
      src/EventHub.Admin.HttpApi.Host/Controllers/Events/EventController.cs
  11. 30
      src/EventHub.Admin.HttpApi.Host/Controllers/Organizations/OrganizationController.cs
  12. 21
      src/EventHub.Admin.HttpApi.Host/EventHubAdminHttpApiHostModule.cs
  13. 3
      src/EventHub.Admin.Web/EventHub.Admin.Web.csproj
  14. 9
      src/EventHub.Admin.Web/Pages/EventManagement.razor
  15. 64
      src/EventHub.Admin.Web/Pages/EventManagement.razor.cs
  16. 11
      src/EventHub.Admin.Web/Pages/OrganizationManagement.razor
  17. 58
      src/EventHub.Admin.Web/Pages/OrganizationManagement.razor.cs
  18. BIN
      src/EventHub.Admin.Web/wwwroot/assets/eh-event.png
  19. BIN
      src/EventHub.Admin.Web/wwwroot/assets/eh-organization.png
  20. 3
      src/EventHub.Application.Contracts/Events/CreateEventDto.cs
  21. 4
      src/EventHub.Application.Contracts/Events/EventDetailDto.cs
  22. 2
      src/EventHub.Application.Contracts/Events/EventInListDto.cs
  23. 3
      src/EventHub.Application.Contracts/Events/IEventAppService.cs
  24. 3
      src/EventHub.Application.Contracts/Events/UpdateEventDto.cs
  25. 3
      src/EventHub.Application.Contracts/Organizations/CreateOrganizationDto.cs
  26. 3
      src/EventHub.Application.Contracts/Organizations/IOrganizationAppService.cs
  27. 2
      src/EventHub.Application.Contracts/Organizations/OrganizationInListDto.cs
  28. 2
      src/EventHub.Application.Contracts/Organizations/OrganizationProfileDto.cs
  29. 3
      src/EventHub.Application.Contracts/Organizations/UpdateOrganizationDto.cs
  30. 32
      src/EventHub.Application/Events/EventAppService.cs
  31. 60
      src/EventHub.Application/Organizations/OrganizationAppService.cs
  32. 2
      src/EventHub.Domain.Shared/Organizations/OrganizationContst.cs
  33. 28
      src/EventHub.HttpApi.Host/Controllers/Events/EventController.cs
  34. 31
      src/EventHub.HttpApi.Host/Controllers/Organizations/OrganizationController.cs
  35. 1
      src/EventHub.HttpApi.Host/EventHub.HttpApi.Host.csproj
  36. 28
      src/EventHub.HttpApi.Host/EventHubHttpApiHostModule.cs
  37. BIN
      src/EventHub.HttpApi.Host/Images/eh-event.png
  38. BIN
      src/EventHub.HttpApi.Host/Images/eh-organization.png
  39. 15
      src/EventHub.Web/Controllers/EventController.cs
  40. 2
      src/EventHub.Web/EventHubWebAutoMapperProfile.cs
  41. 18
      src/EventHub.Web/Pages/Events/Components/EventsArea/_eventListSection.cshtml
  42. 21
      src/EventHub.Web/Pages/Events/Detail.cshtml
  43. 12
      src/EventHub.Web/Pages/Events/Edit.cshtml
  44. 21
      src/EventHub.Web/Pages/Events/Edit.cshtml.cs
  45. 20
      src/EventHub.Web/Pages/Events/New.cshtml.cs
  46. 26
      src/EventHub.Web/Pages/Index.cshtml
  47. 15
      src/EventHub.Web/Pages/Organizations/Components/OrganizationsArea/_organizationListSection.cshtml
  48. 12
      src/EventHub.Web/Pages/Organizations/Edit.cshtml
  49. 20
      src/EventHub.Web/Pages/Organizations/Edit.cshtml.cs
  50. 22
      src/EventHub.Web/Pages/Organizations/New.cshtml.cs
  51. 12
      src/EventHub.Web/Pages/Organizations/Profile.cshtml

2
src/EventHub.Admin.Application.Contracts/Events/EventDetailDto.cs

@ -13,8 +13,6 @@ namespace EventHub.Admin.Events
public DateTime EndTime { get; set; }
public byte[] CoverImageContent { get; set; }
public bool IsOnline { get; set; }
public string OnlineLink { get; set; }

3
src/EventHub.Admin.Application.Contracts/Events/IEventAppService.cs

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
using Volo.Abp.Content;
namespace EventHub.Admin.Events
{
@ -16,6 +17,6 @@ namespace EventHub.Admin.Events
Task<List<CountryLookupDto>> GetCountriesLookupAsync();
Task<byte[]> GetCoverImageAsync(Guid id);
Task<IRemoteStreamContent> GetCoverImageAsync(Guid id);
}
}

3
src/EventHub.Admin.Application.Contracts/Events/UpdateEventDto.cs

@ -2,6 +2,7 @@
using System.ComponentModel.DataAnnotations;
using EventHub.Events;
using JetBrains.Annotations;
using Volo.Abp.Content;
namespace EventHub.Admin.Events
{
@ -24,7 +25,7 @@ namespace EventHub.Admin.Events
public DateTime EndTime { get; set; }
[CanBeNull]
public byte[] CoverImageContent { get; set; }
public RemoteStreamContent CoverImageStreamContent { get; set; }
public bool IsOnline { get; set; }

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)]

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

@ -22,13 +22,11 @@ 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>();
CreateMap<Event, EventDetailDto>()
.Ignore(x => x.CoverImageContent);
CreateMap<Event, EventDetailDto>();
CreateMap<Country, CountryLookupDto>();

33
src/EventHub.Admin.Application/Events/EventAppService.cs

@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Dynamic.Core;
using System.Threading.Tasks;
using EventHub.Admin.Permissions;
using EventHub.Countries;
@ -9,6 +8,7 @@ using EventHub.Events;
using Microsoft.AspNetCore.Authorization;
using Volo.Abp.Application.Dtos;
using Volo.Abp.BlobStoring;
using Volo.Abp.Content;
using Volo.Abp.Domain.Repositories;
namespace EventHub.Admin.Events
@ -36,9 +36,7 @@ namespace EventHub.Admin.Events
public async Task<EventDetailDto> GetAsync(Guid id)
{
var @event = await _eventRepository.GetAsync(id);
var eventDetailDto = ObjectMapper.Map<Event, EventDetailDto>(@event);
eventDetailDto.CoverImageContent = await GetCoverImageAsync(id);
return eventDetailDto;
}
@ -69,16 +67,30 @@ namespace EventHub.Admin.Events
@event.SetTime(input.StartTime, @event.EndTime);
await _eventManager.SetCapacityAsync(@event, input.Capacity);
await SetCoverImageAsync(blobName: id.ToString(), input.CoverImageContent);
if (input.CoverImageStreamContent != null && input.CoverImageStreamContent.ContentLength > 0)
{
await SetCoverImageAsync(blobName: id.ToString(), input.CoverImageStreamContent);
}
else
{
await DeleteCoverImageAsync(blobName: id.ToString());
}
await _eventRepository.UpdateAsync(@event);
}
public async Task<byte[]> GetCoverImageAsync(Guid id)
[AllowAnonymous]
public async Task<IRemoteStreamContent> GetCoverImageAsync(Guid id)
{
var blobName = id.ToString();
var coverImageStream = await _eventBlobContainer.GetOrNullAsync(blobName);
if (coverImageStream == null)
{
return null;
}
return await _eventBlobContainer.GetAllBytesOrNullAsync(blobName);
return new RemoteStreamContent(coverImageStream);
}
public async Task<List<CountryLookupDto>> GetCountriesLookupAsync()
@ -94,9 +106,14 @@ namespace EventHub.Admin.Events
return ObjectMapper.Map<List<Country>, List<CountryLookupDto>>(countries);
}
private async Task SetCoverImageAsync(string blobName, byte[] coverImageContent, bool overrideExisting = true)
private async Task SetCoverImageAsync(string blobName, IRemoteStreamContent streamContent, bool overrideExisting = true)
{
await _eventBlobContainer.SaveAsync(blobName, streamContent.GetStream(), overrideExisting);
}
private async Task DeleteCoverImageAsync(string blobName)
{
await _eventBlobContainer.SaveAsync(blobName, coverImageContent, overrideExisting);
await _eventBlobContainer.DeleteAsync(blobName);
}
}
}

32
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
{
@ -78,7 +78,7 @@ namespace EventHub.Admin.Organizations
return await CreateOrganizationProfileDto(organization);
}
public async Task<OrganizationProfileDto> GetByNameAsync(string name)
{
var organization = await _organizationRepository.FindAsync(x => x.Name.ToLower() == name.ToLower());
@ -106,13 +106,13 @@ 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);
await SaveCoverImageAsync(organization.Id, input.ProfilePictureStreamContent);
}
else
{
await DeleteCoverImageAsync(organization.Id);
await DeleteCoverImageAsync(blobName: id.ToString());
}
await _organizationRepository.UpdateAsync(organization);
@ -125,7 +125,7 @@ namespace EventHub.Admin.Organizations
{
await _organizationRepository.DeleteAsync(id);
}
private async Task<OrganizationProfileDto> CreateOrganizationProfileDto(Organization organization)
{
var dto = ObjectMapper.Map<Organization, OrganizationProfileDto>(organization);
@ -134,28 +134,32 @@ 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)
[AllowAnonymous]
public async Task<IRemoteStreamContent> GetCoverImageAsync(Guid id)
{
var blobName = id.ToString();
var coverImageStream = await _organizationBlobContainer.GetOrNullAsync(blobName);
return await _organizationBlobContainer.GetAllBytesOrNullAsync(blobName);
if (coverImageStream is null)
{
return null;
}
return new RemoteStreamContent(coverImageStream, blobName);
}
private async Task SaveCoverImageAsync(Guid id, byte[] coverImageContent)
private async Task SaveCoverImageAsync(Guid id, IRemoteStreamContent coverImageContent)
{
var blobName = id.ToString();
await _organizationBlobContainer.SaveAsync(blobName, coverImageContent, overrideExisting: true);
await _organizationBlobContainer.SaveAsync(blobName, coverImageContent.GetStream(), overrideExisting: true);
}
private async Task DeleteCoverImageAsync(Guid id)
private async Task DeleteCoverImageAsync(string blobName)
{
var blobName = id.ToString();
await _organizationBlobContainer.DeleteAsync(blobName);
}
}

26
src/EventHub.Admin.HttpApi.Host/Controllers/Events/EventController.cs

@ -2,10 +2,14 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using EventHub.Admin.Events;
using EventHub.Events;
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.Events
{
@ -17,10 +21,12 @@ namespace EventHub.Admin.Controllers.Events
public class EventController : AbpController, IEventAppService
{
private readonly IEventAppService _eventAppService;
public EventController(IEventAppService eventAppService)
private readonly IVirtualFileProvider _virtualFileProvider;
public EventController(IEventAppService eventAppService, IVirtualFileProvider virtualFileProvider)
{
_eventAppService = eventAppService;
_virtualFileProvider = virtualFileProvider;
}
[HttpGet("{id}")]
@ -36,9 +42,19 @@ namespace EventHub.Admin.Controllers.Events
}
[HttpGet("cover-image/{id}")]
public Task<byte[]> GetCoverImageAsync(Guid id)
[AllowAnonymous]
public async Task<IRemoteStreamContent> GetCoverImageAsync(Guid id)
{
return _eventAppService.GetCoverImageAsync(id);
var remoteStreamContent = await _eventAppService.GetCoverImageAsync(id);
if (remoteStreamContent is null)
{
return null;
}
Response.Headers.Add("Accept-Ranges", "bytes");
Response.ContentType = remoteStreamContent.ContentType;
return remoteStreamContent;
}
[HttpGet]
@ -48,7 +64,7 @@ namespace EventHub.Admin.Controllers.Events
}
[HttpPut]
public Task UpdateAsync(Guid id, UpdateEventDto input)
public Task UpdateAsync(Guid id, [FromForm] UpdateEventDto input)
{
return _eventAppService.UpdateAsync(id, input);
}

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

@ -1,10 +1,15 @@
using System;
using System.IO;
using System.Threading.Tasks;
using EventHub.Admin.Organizations;
using EventHub.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 +21,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]
@ -43,7 +50,7 @@ namespace EventHub.Admin.Controllers.Organizations
}
[HttpPut]
public Task<OrganizationProfileDto> UpdateAsync(Guid id, UpdateOrganizationDto input)
public Task<OrganizationProfileDto> UpdateAsync(Guid id, [FromForm] UpdateOrganizationDto input)
{
return _organizationAppService.UpdateAsync(id, input);
}
@ -54,5 +61,22 @@ 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)
{
return null;
}
Response.Headers.Add("Accept-Ranges", "bytes");
Response.ContentType = remoteStreamContent.ContentType;
return remoteStreamContent;
}
}
}

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

@ -3,6 +3,8 @@ using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using EventHub.Admin.Events;
using EventHub.Admin.Organizations;
using EventHub.Admin.Utils;
using EventHub.EntityFrameworkCore;
using EventHub.Web;
@ -17,6 +19,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 +62,16 @@ namespace EventHub.Admin
ConfigureCookies(context);
ConfigureSwaggerServices(context, configuration);
ConfigureBackgroundJobs();
ConfigureAutoApiControllers();
}
private void ConfigureAutoApiControllers()
{
Configure<AbpAspNetCoreMvcOptions>(options =>
{
options.ConventionalControllers.FormBodyBindingIgnoredTypes.Add(typeof(UpdateOrganizationDto));
options.ConventionalControllers.FormBodyBindingIgnoredTypes.Add(typeof(UpdateEventDto));
});
}
private void ConfigureBackgroundJobs()
@ -78,9 +91,9 @@ namespace EventHub.Admin
{
var hostingEnvironment = context.Services.GetHostingEnvironment();
if (hostingEnvironment.IsDevelopment())
Configure<AbpVirtualFileSystemOptions>(options =>
{
Configure<AbpVirtualFileSystemOptions>(options =>
if (hostingEnvironment.IsDevelopment())
{
options.FileSets.ReplaceEmbeddedByPhysical<EventHubDomainSharedModule>(
Path.Combine(hostingEnvironment.ContentRootPath,
@ -94,8 +107,8 @@ namespace EventHub.Admin
options.FileSets.ReplaceEmbeddedByPhysical<EventHubAdminApplicationModule>(
Path.Combine(hostingEnvironment.ContentRootPath,
$"..{Path.DirectorySeparatorChar}EventHub.Admin.Application"));
});
}
}
});
}
private void ConfigureAuthentication(ServiceConfigurationContext context, IConfiguration configuration)

3
src/EventHub.Admin.Web/EventHub.Admin.Web.csproj

@ -22,4 +22,7 @@
<PackageReference Include="Volo.Abp.Identity.Blazor.WebAssembly" Version="5.0.0-beta.1" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="wwwroot\**\*.*" />
</ItemGroup>
</Project>

9
src/EventHub.Admin.Web/Pages/EventManagement.razor

@ -3,11 +3,14 @@
@using EventHub.Admin.Permissions
@using EventHub.Admin.Events
@using EventHub.Events
@using EventHub.Web
@using Microsoft.Extensions.Options
@using Volo.Abp.AspNetCore.Components.Notifications
@inherits EventHubComponentBase
@attribute [Authorize(EventHubPermissions.Events.Default)]
@inject IEventAppService EventAppService
@inject NavigationManager NavigationManager
@inject IOptions<EventHubUrlOptions> UrlOptions
<Card>
<CardHeader>
@ -263,13 +266,13 @@
<FileEdit MaxMessageSize="@EventConsts.MaxCoverImageFileSize" Filter="@string.Join(", ", EventConsts.AllowedCoverImageExtensions)" Changed="@OnCoverImageFileChanged" AutoReset="true"/>
</FieldBody>
<Column ColumnSize="ColumnSize.Is3">
@if (!string.IsNullOrEmpty(CoverImageUrl))
@if (DisabledCoverImageButton)
{
<Button Color="Color.Warning" Clicked="@OnDeleteCoverImageButtonClicked">@L["DeleteCoverImage"]</Button>
<Button disabled Color="Color.Secondary" Clicked="@OnDeleteCoverImageButtonClicked">@L["DeleteCoverImage"]</Button>
}
else
{
<Button disabled Color="Color.Secondary" Clicked="@OnDeleteCoverImageButtonClicked">@L["DeleteCoverImage"]</Button>
<Button Color="Color.Warning" Clicked="@OnDeleteCoverImageButtonClicked">@L["DeleteCoverImage"]</Button>
}
</Column>
</Field>

64
src/EventHub.Admin.Web/Pages/EventManagement.razor.cs

@ -10,7 +10,9 @@ using System.ComponentModel;
using Microsoft.AspNetCore.Components.Web;
using System.IO;
using System.Globalization;
using EventHub.Events;
using Volo.Abp;
using Volo.Abp.Content;
namespace EventHub.Admin.Web.Pages
{
@ -31,6 +33,7 @@ namespace EventHub.Admin.Web.Pages
private IFileEntry FileEntry { get; set; }
private List<CountryLookupDto> Countries { get; set; }
private List<Language> Languages { get; set; }
private bool DisabledCoverImageButton { get; set; }
public EventManagement()
{
@ -91,9 +94,10 @@ namespace EventHub.Admin.Web.Pages
{
EditingEventId = input.Id;
Event = await EventAppService.GetAsync(EditingEventId);
EditingEvent = ObjectMapper.Map<EventDetailDto, UpdateEventDto>(Event);
FillCoverImageUrl(EditingEvent.CoverImageContent);
FileEntry = new FileEntry();
await SetCoverImageUrlAsync();
EditEventModal.Show();
}
@ -119,6 +123,7 @@ namespace EventHub.Admin.Web.Pages
await GetEventsAsync();
CoverImageUrl = string.Empty;
DisabledCoverImageButton = false;
EditEventModal.Hide();
}
@ -142,18 +147,6 @@ namespace EventHub.Admin.Web.Pages
await GetEventsAsync();
}
private void FillCoverImageUrl(byte[] content)
{
if (content.IsNullOrEmpty())
{
return;
}
var imageBase64Data = Convert.ToBase64String(content);
var imageDataUrl = $"data:image/png;base64,{imageBase64Data}";
CoverImageUrl = imageDataUrl;
}
private async Task OnCoverImageFileChanged(FileChangedEventArgs e)
{
FileEntry = e.Files.FirstOrDefault();
@ -162,28 +155,57 @@ namespace EventHub.Admin.Web.Pages
return;
}
using (var stream = new MemoryStream())
var stream = new MemoryStream();
await FileEntry.WriteToStreamAsync(stream);
stream.Seek(0, SeekOrigin.Begin);
EditingEvent.CoverImageStreamContent = new RemoteStreamContent(stream)
{
await FileEntry.WriteToStreamAsync(stream);
ContentType = FileEntry.Type,
FileName = FileEntry.Name
};
stream.Seek(0, SeekOrigin.Begin);
EditingEvent.CoverImageContent = stream.ToArray();
FillCoverImageUrl(EditingEvent.CoverImageContent);
await InvokeAsync(StateHasChanged);
void SetCoverImageUrl(string contentType, byte[] content)
{
if (content.IsNullOrEmpty())
{
return;
}
contentType = string.IsNullOrWhiteSpace(contentType) ? "image/png" : contentType;
CoverImageUrl = $"data:{contentType};base64,{Convert.ToBase64String(content)}";
DisabledCoverImageButton = false;
}
SetCoverImageUrl(FileEntry.Type, stream.ToArray());
await InvokeAsync(StateHasChanged);
}
private void OnDeleteCoverImageButtonClicked()
{
EditingEvent.CoverImageContent = null;
EditingEvent.CoverImageStreamContent = null;
FileEntry = new FileEntry();
CoverImageUrl = null;
DisabledCoverImageButton = true;
}
private async Task FillCountriesAsync()
{
Countries = await EventAppService.GetCountriesLookupAsync();
}
private async Task SetCoverImageUrlAsync()
{
var imageRemoteStreamContent = await EventAppService.GetCoverImageAsync(id: EditingEventId);
if (imageRemoteStreamContent.ContentLength <= 0)
{
CoverImageUrl = "/assets/eh-event.png";
DisabledCoverImageButton = true;
return;
}
CoverImageUrl = UrlOptions.Value.AdminApi.EnsureEndsWith('/') + "api/eventhub/admin/event/cover-image/" + EditingEventId;
}
private enum EventEditTabs : byte
{

11
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>
@ -235,16 +238,16 @@
<Field Horizontal="true">
<FieldLabel ColumnSize="ColumnSize.Is3">@L["ChooseProfileImage"]</FieldLabel>
<FieldBody ColumnSize="ColumnSize.Is6">
<FileEdit MaxMessageSize="@OrganizationConsts.MaxProfilePictureFileSize" Filter=".jpg, .png" Changed="@OnProfileImageFileChanged" Progressed="@OnProgressedForProfileImage" AutoReset="true"/>
<FileEdit MaxMessageSize="@OrganizationConsts.MaxProfilePictureFileSize" Filter="@string.Join(", ", OrganizationConsts.AllowedProfilePictureExtensions)" Changed="@OnProfileImageFileChanged" Progressed="@OnProgressedForProfileImage" AutoReset="true"/>
</FieldBody>
<Column ColumnSize="ColumnSize.Is3">
@if (!ProfileImageUrl.IsNullOrWhiteSpace())
@if (DisabledProfileImageButton)
{
<Button Color="Color.Warning" Clicked="@OnDeleteCoverImageButtonClicked">@L["DeleteCoverImage"]</Button>
<Button disabled Color="Color.Secondary" Clicked="@OnDeleteCoverImageButtonClicked">@L["DeleteCoverImage"]</Button>
}
else
{
<Button disabled Color="Color.Secondary" Clicked="@OnDeleteCoverImageButtonClicked">@L["DeleteCoverImage"]</Button>
<Button Color="Color.Warning" Clicked="@OnDeleteCoverImageButtonClicked">@L["DeleteCoverImage"]</Button>
}
</Column>
</Field>

58
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
{
@ -30,6 +31,7 @@ namespace EventHub.Admin.Web.Pages
private IFileEntry FileEntry { get; set; }
private bool IsLoadingProfileImage { get; set; }
private string SelectedTabInEditModal { get; set; }
private bool DisabledProfileImageButton { get; set; }
public OrganizationManagement()
{
@ -73,7 +75,9 @@ namespace EventHub.Admin.Web.Pages
{
EditingOrganizationId = input.Id;
Organization = await OrganizationAppService.GetAsync(EditingOrganizationId);
FillProfileImageUrl(Organization.ProfilePictureContent);
FileEntry = new FileEntry();
await SetProfileImageUrlAsync();
EditingOrganization = ObjectMapper.Map<OrganizationProfileDto, UpdateOrganizationDto>(Organization);
EditOrganizationModal.Show();
@ -84,13 +88,17 @@ namespace EventHub.Admin.Web.Pages
await OrganizationAppService.UpdateAsync(EditingOrganizationId, EditingOrganization);
await GetOrganizationsAsync();
EditOrganizationModal.Hide();
ProfileImageUrl = null;
DisabledProfileImageButton = false;
}
private void OnDeleteCoverImageButtonClicked()
{
EditingOrganization.ProfilePictureContent = null;
EditingOrganization.ProfilePictureStreamContent = null;
FileEntry = new FileEntry();
ProfileImageUrl = null;
DisabledProfileImageButton = true;
IsLoadingProfileImage = false;
}
@ -110,25 +118,29 @@ namespace EventHub.Admin.Web.Pages
IsLoadingProfileImage = true;
using (var stream = new MemoryStream())
{
await FileEntry.WriteToStreamAsync(stream);
var stream = new MemoryStream();
await FileEntry.WriteToStreamAsync(stream);
stream.Seek(0, SeekOrigin.Begin);
stream.Seek(0, SeekOrigin.Begin);
EditingOrganization.ProfilePictureContent = stream.ToArray();
FillProfileImageUrl(EditingOrganization.ProfilePictureContent);
await InvokeAsync(StateHasChanged);
}
}
EditingOrganization.ProfilePictureStreamContent = new RemoteStreamContent(stream)
{
ContentType = FileEntry.Type,
FileName = FileEntry.Name
};
private void FillProfileImageUrl(byte[] content)
{
if (content != null)
void SetProfileImageUrl(string contentType, byte[] content)
{
var imageBase64Data = Convert.ToBase64String(content);
var imageDataUrl = $"data:image/png;base64,{imageBase64Data}";
ProfileImageUrl = imageDataUrl;
if (content != null)
{
contentType = string.IsNullOrWhiteSpace(contentType) ? "image/png" : contentType;
var imageDataUrl = $"data:{contentType};base64,{Convert.ToBase64String(content)}";
ProfileImageUrl = imageDataUrl;
DisabledProfileImageButton = false;
}
}
SetProfileImageUrl(FileEntry.Type, stream.ToArray());
await InvokeAsync(StateHasChanged);
}
private void OnProgressedForProfileImage(FileProgressedEventArgs e)
@ -157,6 +169,18 @@ namespace EventHub.Admin.Web.Pages
await GetOrganizationsAsync();
}
}
private async Task SetProfileImageUrlAsync()
{
var imageRemoteStreamContent = await OrganizationAppService.GetCoverImageAsync(id: EditingOrganizationId);
if (imageRemoteStreamContent.ContentLength <= 0)
{
ProfileImageUrl = "assets/eh-organization.png";
DisabledProfileImageButton = true;
return;
}
ProfileImageUrl = UrlOptions.Value.AdminApi.EnsureEndsWith('/') + "api/eventhub/admin/organization/cover-image/" + EditingOrganizationId;
}
}
public enum TabContentInEditModal : byte

BIN
src/EventHub.Admin.Web/wwwroot/assets/eh-event.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 184 KiB

BIN
src/EventHub.Admin.Web/wwwroot/assets/eh-organization.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 544 KiB

3
src/EventHub.Application.Contracts/Events/CreateEventDto.cs

@ -1,6 +1,7 @@
using System;
using System.ComponentModel.DataAnnotations;
using JetBrains.Annotations;
using Volo.Abp.Content;
namespace EventHub.Events
{
@ -24,7 +25,7 @@ namespace EventHub.Events
public string Description { get; set; }
[CanBeNull]
public byte[] CoverImageContent { get; set; }
public IRemoteStreamContent CoverImageStreamContent { get; set; }
public bool IsOnline { get; set; }

4
src/EventHub.Application.Contracts/Events/EventDetailDto.cs

@ -22,9 +22,7 @@ namespace EventHub.Events
public DateTime StartTime { get; set; }
public DateTime EndTime { get; set; }
public byte[] CoverImageContent { get; set; }
public bool IsOnline { get; set; }
public string OnlineLink { get; set; }

2
src/EventHub.Application.Contracts/Events/EventInListDto.cs

@ -16,8 +16,6 @@ namespace EventHub.Events
public DateTime StartTime { get; set; }
public DateTime EndTime { get; set; }
public byte[] CoverImageContent { get; set; }
public bool IsOnline { get; set; }

3
src/EventHub.Application.Contracts/Events/IEventAppService.cs

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
using Volo.Abp.Content;
namespace EventHub.Events
{
@ -22,6 +23,6 @@ namespace EventHub.Events
Task UpdateAsync(Guid id, UpdateEventDto input);
Task<byte[]> GetCoverImageAsync(Guid id);
Task<IRemoteStreamContent> GetCoverImageAsync(Guid id);
}
}

3
src/EventHub.Application.Contracts/Events/UpdateEventDto.cs

@ -1,6 +1,7 @@
using System;
using System.ComponentModel.DataAnnotations;
using JetBrains.Annotations;
using Volo.Abp.Content;
namespace EventHub.Events
{
@ -15,7 +16,7 @@ namespace EventHub.Events
public string Description { get; set; }
[CanBeNull]
public byte[] CoverImageContent { get; set; }
public IRemoteStreamContent CoverImageStreamContent { get; set; }
[Required]
[DataType(DataType.DateTime)]

3
src/EventHub.Application.Contracts/Organizations/CreateOrganizationDto.cs

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

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

@ -2,6 +2,7 @@
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
using Volo.Abp.Content;
namespace EventHub.Organizations
{
@ -18,5 +19,7 @@ namespace EventHub.Organizations
Task<bool> IsOrganizationOwnerAsync(Guid organizationId);
Task UpdateAsync(Guid id, UpdateOrganizationDto input);
Task<IRemoteStreamContent> GetProfilePictureAsync(Guid id);
}
}

2
src/EventHub.Application.Contracts/Organizations/OrganizationInListDto.cs

@ -10,7 +10,5 @@ namespace EventHub.Organizations
public string DisplayName { get; set; }
public string Description { get; set; }
public byte[] ProfilePictureContent { get; set; }
}
}

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

@ -26,7 +26,5 @@ namespace EventHub.Organizations
public string InstagramUsername { get; set; }
public string MediumUsername { get; set; }
public byte[] ProfilePictureContent { get; set; }
}
}

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

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

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

@ -10,6 +10,7 @@ using Microsoft.AspNetCore.Authorization;
using Volo.Abp.Application.Dtos;
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;
@ -73,9 +74,9 @@ namespace EventHub.Events
await _eventManager.SetCapacityAsync(@event, input.Capacity);
if (input.CoverImageContent != null && input.CoverImageContent.Length > 0)
if (input.CoverImageStreamContent != null && input.CoverImageStreamContent.ContentLength > 0)
{
await SaveCoverImageAsync(@event.Id, input.CoverImageContent);
await SaveCoverImageAsync(@event.Id, input.CoverImageStreamContent);
}
await _eventRepository.InsertAsync(@event);
@ -161,11 +162,6 @@ namespace EventHub.Events
}
).ToList();
foreach (var @event in events)
{
@event.CoverImageContent = await GetCoverImageAsync(@event.Id);
}
return new PagedResultDto<EventInListDto>(totalCount, events);
}
@ -179,8 +175,7 @@ namespace EventHub.Events
dto.OrganizationId = organization.Id;
dto.OrganizationName = organization.Name;
dto.OrganizationDisplayName = organization.DisplayName;
dto.CoverImageContent = await GetCoverImageAsync(dto.Id);
var user = await _userRepository.GetAsync(organization.OwnerUserId);
dto.OwnerUserName = user.UserName;
dto.OwnerEmail = user.Email;
@ -254,26 +249,33 @@ namespace EventHub.Events
@event.SetTime(input.StartTime, input.EndTime);
await _eventManager.SetCapacityAsync(@event, input.Capacity);
if (input.CoverImageContent != null && input.CoverImageContent.Length > 0)
if (input.CoverImageStreamContent != null && input.CoverImageStreamContent.ContentLength > 0)
{
await SaveCoverImageAsync(@event.Id, input.CoverImageContent);
await SaveCoverImageAsync(@event.Id, input.CoverImageStreamContent);
}
await _eventRepository.UpdateAsync(@event);
}
public async Task<byte[]> GetCoverImageAsync(Guid id)
public async Task<IRemoteStreamContent> GetCoverImageAsync(Guid id)
{
var blobName = id.ToString();
return await _eventBlobContainer.GetAllBytesOrNullAsync(blobName);
var coverImageStream = await _eventBlobContainer.GetOrNullAsync(blobName);
if (coverImageStream is null)
{
return null;
}
return new RemoteStreamContent(coverImageStream, blobName);
}
private async Task SaveCoverImageAsync(Guid id, byte[] coverImageContent)
private async Task SaveCoverImageAsync(Guid id, IRemoteStreamContent streamContent)
{
var blobName = id.ToString();
await _eventBlobContainer.SaveAsync(blobName, coverImageContent, overrideExisting: true);
await _eventBlobContainer.SaveAsync(blobName, streamContent.GetStream(), overrideExisting: true);
}
}
}

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

@ -8,6 +8,7 @@ using Microsoft.AspNetCore.Authorization;
using Volo.Abp.Application.Dtos;
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;
@ -52,12 +53,12 @@ namespace EventHub.Organizations
organization.FacebookUsername = input.FacebookUsername;
organization.InstagramUsername = input.InstagramUsername;
organization.MediumUsername = input.MediumUsername;
await _organizationRepository.InsertAsync(organization, true);
if (input.ProfilePictureContent != null && input.ProfilePictureContent.Length > 0)
if (input.ProfilePictureStreamContent != null && input.ProfilePictureStreamContent.ContentLength > 0)
{
await SaveProfilePictureAsync(organization.Id, input.ProfilePictureContent);
await SaveProfilePictureAsync(organization.Id, input.ProfilePictureStreamContent);
}
}
@ -67,13 +68,13 @@ namespace EventHub.Organizations
var organizationMemberQueryable = await _organizationMembershipsRepository.GetQueryableAsync();
var query = organizationQueryable;
if (input.RegisteredUserId.HasValue)
{
var registeredOrganization = organizationMemberQueryable
.Where(x => x.UserId == input.RegisteredUserId)
.Select(x => x.OrganizationId);
var organizationIds = await AsyncExecuter.ToListAsync(registeredOrganization);
query = query.Where(x => organizationIds.Contains(x.Id));
}
@ -84,11 +85,6 @@ namespace EventHub.Organizations
var organizationDto = ObjectMapper
.Map<List<Organization>, List<OrganizationInListDto>>(await AsyncExecuter.ToListAsync(query));
foreach (var organization in organizationDto)
{
organization.ProfilePictureContent = await GetProfilePictureAsync(organization.Id);
}
return new PagedResultDto<OrganizationInListDto>(
totalCount,
@ -104,7 +100,6 @@ namespace EventHub.Organizations
var owner = await _userRepository.GetAsync(u => u.Id == organization.OwnerUserId);
organizationProfileDto.OwnerUserName = owner.UserName;
organizationProfileDto.OwnerEmail = owner.Email;
organizationProfileDto.ProfilePictureContent = await GetProfilePictureAsync(organizationProfileDto.Id);
return organizationProfileDto;
}
@ -116,17 +111,13 @@ namespace EventHub.Organizations
var organizationDto = ObjectMapper.Map<List<Organization>, List<OrganizationInListDto>>(organizations);
foreach (var organization in organizationDto)
{
organization.ProfilePictureContent = await GetProfilePictureAsync(organization.Id);
}
return new ListResultDto<OrganizationInListDto>(organizationDto);
}
public async Task<bool> IsOrganizationOwnerAsync(Guid organizationId)
{
return CurrentUser.Id.HasValue && await _organizationRepository.AnyAsync(x => x.Id == organizationId && x.OwnerUserId == CurrentUser.Id.Value);
return CurrentUser.Id.HasValue && await _organizationRepository
.AnyAsync(x => x.Id == organizationId && x.OwnerUserId == CurrentUser.Id.Value);
}
[Authorize]
@ -148,35 +139,34 @@ namespace EventHub.Organizations
organization.InstagramUsername = input.InstagramUsername;
organization.FacebookUsername = input.FacebookUsername;
organization.MediumUsername = input.MediumUsername;
if (input.ProfilePictureContent != null && input.ProfilePictureContent.Length > 0)
if (input.ProfilePictureStreamContent != null && input.ProfilePictureStreamContent.ContentLength > 0)
{
await SaveProfilePictureAsync(organization.Id, input.ProfilePictureContent);
await SaveProfilePictureAsync(organization.Id, input.ProfilePictureStreamContent);
}
await _organizationRepository.UpdateAsync(organization);
}
private async Task SaveProfilePictureAsync(Guid id, byte[] bytes)
public async Task<IRemoteStreamContent> GetProfilePictureAsync(Guid id)
{
var organization = await _organizationRepository.GetAsync(x => x.Id == id);
var blobName = id.ToString();
var pictureContent = await _organizationBlobContainer.GetOrNullAsync(blobName);
if (organization.OwnerUserId != CurrentUser.GetId())
if (pictureContent is null)
{
throw new AbpAuthorizationException(EventHubErrorCodes.NotAuthorizedToUpdateOrganizationProfile)
.WithData("Name", organization.DisplayName);
return null;
}
var blobName = id.ToString();
await _organizationBlobContainer.SaveAsync(blobName, bytes, overrideExisting: true);
return new RemoteStreamContent(pictureContent, blobName);
}
private async Task<byte[]> GetProfilePictureAsync(Guid id)
private async Task SaveProfilePictureAsync(Guid id, IRemoteStreamContent streamContent)
{
var blobName = id.ToString();
return await _organizationBlobContainer.GetAllBytesOrNullAsync(blobName);
await _organizationBlobContainer.SaveAsync(blobName, streamContent.GetStream(), overrideExisting: true);
}
}
}
}

2
src/EventHub.Domain.Shared/Organizations/OrganizationContst.cs

@ -26,5 +26,7 @@
public const int MaxInstagramUsernameLength = 24;
public const int MaxMediumUsernameLength = 24;
public static string[] AllowedProfilePictureExtensions = { ".jpg", ".png" };
}
}

28
src/EventHub.HttpApi.Host/Controllers/Events/EventController.cs

@ -6,6 +6,8 @@ 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
{
@ -16,14 +18,18 @@ namespace EventHub.Controllers.Events
public class EventController : AbpController, IEventAppService
{
private readonly IEventAppService _eventAppService;
private readonly IVirtualFileProvider _virtualFileProvider;
public EventController(IEventAppService eventAppService)
public EventController(
IEventAppService eventAppService,
IVirtualFileProvider virtualFileProvider)
{
_eventAppService = eventAppService;
_virtualFileProvider = virtualFileProvider;
}
[HttpPost]
public async Task<EventDto> CreateAsync(CreateEventDto input)
public async Task<EventDto> CreateAsync([FromForm] CreateEventDto input)
{
return await _eventAppService.CreateAsync(input);
}
@ -64,16 +70,28 @@ namespace EventHub.Controllers.Events
[HttpPut]
[Route("{id}")]
public async Task UpdateAsync(Guid id, UpdateEventDto input)
public async Task UpdateAsync(Guid id, [FromForm] UpdateEventDto input)
{
await _eventAppService.UpdateAsync(id, input);
}
[HttpGet]
[Route("cover-image/{id}")]
public async Task<byte[]> GetCoverImageAsync(Guid id)
public async Task<IRemoteStreamContent> GetCoverImageAsync(Guid id)
{
return await _eventAppService.GetCoverImageAsync(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;
}
}
}

31
src/EventHub.HttpApi.Host/Controllers/Organizations/OrganizationController.cs

@ -5,6 +5,8 @@ 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.Organizations
{
@ -15,14 +17,18 @@ namespace EventHub.Controllers.Organizations
public class OrganizationController : AbpController, IOrganizationAppService
{
private readonly IOrganizationAppService _organizationAppService;
private readonly IVirtualFileProvider _virtualFileProvider;
public OrganizationController(IOrganizationAppService organizationAppService)
public OrganizationController(
IOrganizationAppService organizationAppService,
IVirtualFileProvider virtualFileProvider)
{
_organizationAppService = organizationAppService;
_virtualFileProvider = virtualFileProvider;
}
[HttpPost]
public async Task CreateAsync(CreateOrganizationDto input)
public async Task CreateAsync([FromForm] CreateOrganizationDto input)
{
await _organizationAppService.CreateAsync(input);
}
@ -56,9 +62,28 @@ namespace EventHub.Controllers.Organizations
[HttpPut]
[Route("{id}")]
public async Task UpdateAsync(Guid id, UpdateOrganizationDto input)
public async Task UpdateAsync(Guid id, [FromForm] UpdateOrganizationDto input)
{
await _organizationAppService.UpdateAsync(id, input);
}
[HttpGet]
[Route("profile-picture/{id}")]
public async Task<IRemoteStreamContent> GetProfilePictureAsync(Guid id)
{
var remoteStreamContent = await _organizationAppService.GetProfilePictureAsync(id);
if (remoteStreamContent is null)
{
var stream = _virtualFileProvider.GetFileInfo("/Images/eh-organization.png").CreateReadStream();
remoteStreamContent = new RemoteStreamContent(stream);
await stream.FlushAsync();
}
Response.Headers.Add("Accept-Ranges", "bytes");
Response.ContentType = remoteStreamContent.ContentType;
return remoteStreamContent;
}
}
}

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

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

28
src/EventHub.HttpApi.Host/EventHubHttpApiHostModule.cs

@ -11,6 +11,8 @@ using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using EventHub.EntityFrameworkCore;
using EventHub.Events;
using EventHub.Organizations;
using EventHub.Utils;
using EventHub.Web;
using Microsoft.AspNetCore.Localization;
@ -61,6 +63,18 @@ namespace EventHub
ConfigureCookies(context);
ConfigureSwaggerServices(context, configuration);
ConfigureBackgroundJobs();
ConfigureAutoApiControllers();
}
private void ConfigureAutoApiControllers()
{
Configure<AbpAspNetCoreMvcOptions>(options =>
{
options.ConventionalControllers.FormBodyBindingIgnoredTypes.Add(typeof(CreateOrganizationDto));
options.ConventionalControllers.FormBodyBindingIgnoredTypes.Add(typeof(UpdateOrganizationDto));
options.ConventionalControllers.FormBodyBindingIgnoredTypes.Add(typeof(CreateEventDto));
options.ConventionalControllers.FormBodyBindingIgnoredTypes.Add(typeof(UpdateEventDto));
});
}
private void ConfigureBackgroundJobs()
@ -79,10 +93,14 @@ namespace EventHub
private void ConfigureVirtualFileSystem(ServiceConfigurationContext context)
{
var hostingEnvironment = context.Services.GetHostingEnvironment();
if (hostingEnvironment.IsDevelopment())
Configure<AbpVirtualFileSystemOptions>(options =>
{
Configure<AbpVirtualFileSystemOptions>(options =>
options.FileSets.AddEmbedded<EventHubHttpApiHostModule>(
baseNamespace: "EventHub",
baseFolder: "/Images");
if (hostingEnvironment.IsDevelopment())
{
options.FileSets.ReplaceEmbeddedByPhysical<EventHubDomainSharedModule>(
Path.Combine(hostingEnvironment.ContentRootPath,
@ -96,8 +114,8 @@ namespace EventHub
options.FileSets.ReplaceEmbeddedByPhysical<EventHubApplicationModule>(
Path.Combine(hostingEnvironment.ContentRootPath,
$"..{Path.DirectorySeparatorChar}EventHub.Application"));
});
}
}
});
}
private void ConfigureAuthentication(ServiceConfigurationContext context, IConfiguration configuration)

BIN
src/EventHub.HttpApi.Host/Images/eh-event.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 184 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 544 KiB

15
src/EventHub.Web/Controllers/EventController.cs

@ -1,4 +1,3 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using EventHub.Events;
@ -29,19 +28,5 @@ namespace EventHub.Web.Controllers
ViewData = ViewData
};
}
[HttpGet]
[Route("cover-picture-source/{eventId}")]
public async Task<IActionResult> GetArticleCoverImageAsync(Guid eventId)
{
var coverImageContent = await _eventAppService.GetCoverImageAsync(eventId);
if (coverImageContent == null)
{
return NotFound();
}
return File(coverImageContent, "image/jpeg");
}
}
}

2
src/EventHub.Web/EventHubWebAutoMapperProfile.cs

@ -13,7 +13,7 @@ namespace EventHub.Web
{
CreateMap<NewPageModel.CreateOrganizationViewModel, CreateOrganizationDto>();
CreateMap<Pages.Events.NewPageModel.NewEventViewModel, CreateEventDto>()
.Ignore(x => x.CoverImageContent);
.Ignore(x => x.CoverImageStreamContent);
CreateMap<OrganizationProfileDto, EditOrganizationViewModel>();
CreateMap<EditOrganizationViewModel, UpdateOrganizationDto>();
CreateMap<EventDetailDto, EditPageModel.EditEventViewModel>();

18
src/EventHub.Web/Pages/Events/Components/EventsArea/_eventListSection.cshtml

@ -1,22 +1,16 @@
@using System.Globalization
@using EventHub.Web.Helpers
@using EventHub.Web
@using EventHub.Web.Pages.Events
@using Microsoft.Extensions.Options
@model List<EventHub.Events.EventInListDto>
@inject IOptions<EventHubUrlOptions> UrlOptions
@foreach (var eventDto in Model)
{
<div class="col-lg-4 col-md-6 event">
<div class="card">
@if (eventDto.CoverImageContent is null)
{
<div class="event-thumbnail" style="background-image: url(/assets/eh-event.png);" alt="@eventDto.Title">
</div>
}
else
{
<div class="event-thumbnail" style="background-image: url( @($"data:image/png;base64,{Convert.ToBase64String(eventDto.CoverImageContent)}")" alt="@eventDto.Title">
</div>
}
<div class="event-thumbnail" style="background-image: url(@(UrlOptions.Value.Api.EnsureEndsWith('/') + $"api/eventhub/event/cover-image/{eventDto.Id}")" alt="@eventDto.Title">
</div>
<div class="card-body">
<div class="event-container">
<div class="form-row">
@ -32,7 +26,7 @@
<small>@eventDto.StartTime.ToString("hh tt", CultureInfo.InvariantCulture) - @eventDto.EndTime.ToString("hh tt", CultureInfo.InvariantCulture) | @EventDateHelper.GetLocationInfo(eventDto)</small>
<p>@eventDto.Description</p>
</div>
<a href="@Url.Page("/Events/Detail", new {url = eventDto.Url})" class="btn btn-link p-0">Learn More <img src="/assets/more-btn.svg"></a>
<a href="@Url.Page("/Events/Detail", new { url = eventDto.Url })" class="btn btn-link p-0">Learn More <img src="/assets/more-btn.svg"></a>
</div>
</div>
</div>

21
src/EventHub.Web/Pages/Events/Detail.cshtml

@ -24,17 +24,7 @@
@{
string description = Model.Event.Description.Length >= 160 ? Model.Event.Description.TruncateWithPostfix(155) : Model.Event.Description;
string title = Model.Event.Title;
string coverImageUrl;
if (Model.Event.CoverImageContent is null)
{
// TODO(berkansasmaz): Get a default image from the design team to be used in social media posts
coverImageUrl = UrlOptions.Value.Www + "/assets/slide.jpg";
}
else
{
coverImageUrl = $"{UrlOptions.Value.Www}/api/event/cover-picture-source/{Model.Event.Id}";
}
string coverImageUrl = UrlOptions.Value.Api.EnsureEndsWith('/') + $"api/eventhub/event/cover-image/{Model.Event.Id}";
ViewBag.Title = title;
ViewBag.Description = description;
@ -52,14 +42,7 @@
<div class="row">
<div class="col-md-7">
<div class="detail-image">
@if (Model.Event.CoverImageContent == null)
{
<img src="/assets/eh-event.png" class="detail-img" alt="@Model.Event.Title">
}
else
{
<img class="detail-img" src="@($"data:image/png;base64,{Convert.ToBase64String(Model.Event.CoverImageContent)}")" alt="@Model.Event.Title">
}
<img class="detail-img" src="@(UrlOptions.Value.Api.EnsureEndsWith('/') + $"api/eventhub/event/cover-image/{Model.Event.Id}")" alt="@Model.Event.Title">
</div>
</div>

12
src/EventHub.Web/Pages/Events/Edit.cshtml

@ -1,8 +1,11 @@
@page "/event/edit/{url}"
@inject IHtmlLocalizer<EventHubResource> L
@using EventHub.Localization
@using EventHub.Web
@using Microsoft.AspNetCore.Mvc.Localization
@using Microsoft.Extensions.Options
@model EventHub.Web.Pages.Events.EditPageModel
@inject IOptions<EventHubUrlOptions> UrlOptions
@section scripts {
<abp-script src="/Pages/Events/Edit.js"/>
@ -62,14 +65,7 @@
<div class="row">
<div class="col-5">
<div class="image-area">
@if (Model.CoverImageContent != null && Model.CoverImageContent.Length > 0)
{
<img id="imageResult" src="@($"data:image/png;base64,{Convert.ToBase64String(Model.CoverImageContent)}")" alt="" class="img-fluid rounded shadow-sm mx-auto d-block">
}
else
{
<img id="imageResult" src="#" alt="" class="img-fluid rounded shadow-sm mx-auto d-block">
}
<img id="imageResult" src="@(UrlOptions.Value.Api.EnsureEndsWith('/') + $"api/eventhub/event/cover-image/{Model.Event.Id}")" alt="" class="img-fluid rounded shadow-sm mx-auto d-block">
</div>
</div>
<div class="col-7">

21
src/EventHub.Web/Pages/Events/Edit.cshtml.cs

@ -14,6 +14,7 @@ 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
@ -29,7 +30,6 @@ namespace EventHub.Web.Pages.Events
public List<SelectListItem> Organizations { get; private set; }
public List<SelectListItem> Countries { get; private set; }
public List<SelectListItem> Languages { get; private set; }
public byte[] CoverImageContent { get; private set; }
private readonly IEventAppService _eventAppService;
private readonly IOrganizationAppService _organizationAppService;
@ -46,7 +46,7 @@ namespace EventHub.Web.Pages.Events
{
var urlCode = EventUrlCodeHelper.GetCodeFromUrl(Url);
var eventDetailDto = await _eventAppService.GetByUrlCodeAsync(urlCode);
CoverImageContent = eventDetailDto.CoverImageContent;
Event = ObjectMapper.Map<EventDetailDto, EditEventViewModel>(eventDetailDto);
await FillOrganizationsAsync();
@ -60,19 +60,22 @@ namespace EventHub.Web.Pages.Events
{
ValidateModel();
var input = ObjectMapper.Map<EditEventViewModel, UpdateEventDto>(Event);
var updateEventDto = ObjectMapper.Map<EditEventViewModel, UpdateEventDto>(Event);
await using var memoryStream = new MemoryStream();
if (Event.CoverImageFile != null && Event.CoverImageFile.Length > 0)
{
using (var memoryStream = new MemoryStream())
await Event.CoverImageFile.CopyToAsync(memoryStream);
updateEventDto.CoverImageStreamContent = new RemoteStreamContent(memoryStream)
{
await Event.CoverImageFile.CopyToAsync(memoryStream);
input.CoverImageContent = memoryStream.ToArray();
}
ContentType = Event.CoverImageFile.ContentType,
FileName = Event.CoverImageFile.FileName,
};
}
await _eventAppService.UpdateAsync(Event.Id, input);
await _eventAppService.UpdateAsync(Event.Id, updateEventDto);
await memoryStream.DisposeAsync();
return RedirectToPage("./Detail", new { url = Url });
}
catch (Exception exception)

20
src/EventHub.Web/Pages/Events/New.cshtml.cs

@ -14,13 +14,15 @@ 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]
public NewEventViewModel Event { get; set; }
public List<SelectListItem> Organizations { get; private set; }
public List<SelectListItem> Countries { get; private set; }
@ -56,18 +58,22 @@ namespace EventHub.Web.Pages.Events
{
ValidateModel();
var input = ObjectMapper.Map<NewEventViewModel, CreateEventDto>(Event);
var createEventDto = ObjectMapper.Map<NewEventViewModel, CreateEventDto>(Event);
await using var memoryStream = new MemoryStream();
if (Event.CoverImageFile != null && Event.CoverImageFile.Length > 0)
{
using (var memoryStream = new MemoryStream())
await Event.CoverImageFile.CopyToAsync(memoryStream);
createEventDto.CoverImageStreamContent = new RemoteStreamContent(memoryStream)
{
await Event.CoverImageFile.CopyToAsync(memoryStream);
input.CoverImageContent = memoryStream.ToArray();
}
ContentType = Event.CoverImageFile.ContentType,
FileName = Event.CoverImageFile.FileName
};
}
var eventDto = await _eventAppService.CreateAsync(input);
var eventDto = await _eventAppService.CreateAsync(createEventDto);
await memoryStream.DisposeAsync();
return RedirectToPage("/Events/Detail", new {url = eventDto.UrlCode});
}

26
src/EventHub.Web/Pages/Index.cshtml

@ -152,16 +152,8 @@
<div class="card mb-3">
<div class="row no-glutters">
<div class="col-5 pr-0">
@if (Model.OnlineEvents[i].CoverImageContent is null)
{
<div class="event-thumbnail-left" style="background-image: url(/assets/eh-event.png);">
</div>
}
else
{
<div class="event-thumbnail-left" style="background-image: url( @($"data:image/png;base64,{Convert.ToBase64String(Model.OnlineEvents[i].CoverImageContent)}") );" alt="@Model.OnlineEvents[i].Title">
</div>
}
<div class="event-thumbnail-left" style="background-image: url( @(UrlOptions.Value.Api.EnsureEndsWith('/') + $"api/eventhub/event/cover-image/{Model.OnlineEvents[i].Id}") );" alt="@Model.OnlineEvents[i].Title">
</div>
</div>
<div class="col-7">
<div class="card-body">
@ -171,7 +163,7 @@
<small>@Model.OnlineEvents[i].StartTime.ToString("MMMM dd, yyyy dddd") <br /> @Model.OnlineEvents[i].StartTime.ToString("hh tt", CultureInfo.InvariantCulture) - @Model.OnlineEvents[i].EndTime.ToString("hh tt", CultureInfo.InvariantCulture) | Online</small>
<p>@Model.OnlineEvents[i].Description</p>
</div>
<a href="@Url.Page("/Events/Detail", new {url = @Model.OnlineEvents[i].Url})" class="btn btn-link p-0">Learn More <img src="/assets/more-btn.svg"></a>
<a href="@Url.Page("/Events/Detail", new {url = Model.OnlineEvents[i].Url})" class="btn btn-link p-0">Learn More <img src="/assets/more-btn.svg"></a>
</div>
</div>
</div>
@ -182,16 +174,8 @@
<div class="card mb-3">
<div class="row no-glutters">
<div class="col-5 pr-0">
@if (Model.OnlineEvents[i + 1].CoverImageContent is null)
{
<div class="event-thumbnail-left" style="background-image: url(/assets/eh-event.png);">
</div>
}
else
{
<div class="event-thumbnail-left" style="background-image: url( @($"data:image/png;base64,{Convert.ToBase64String(Model.OnlineEvents[i + 1].CoverImageContent)}") );" alt="@Model.OnlineEvents[i + 1].Title">
</div>
}
<div class="event-thumbnail-left" style="background-image: url( @(UrlOptions.Value.Api.EnsureEndsWith('/') + $"api/eventhub/event/cover-image/{Model.OnlineEvents[i + 1].Id}") );" alt="@Model.OnlineEvents[i + 1].Title">
</div>
</div>
<div class="col-7">
<div class="card-body">

15
src/EventHub.Web/Pages/Organizations/Components/OrganizationsArea/_organizationListSection.cshtml

@ -1,19 +1,14 @@
@using EventHub.Web
@using Microsoft.Extensions.Options
@model List<EventHub.Organizations.OrganizationInListDto>
@inject IOptions<EventHubUrlOptions> UrlOptions
@foreach (var organization in Model)
{
<div class="col-lg-4 col-md-6 organization">
<div class="card">
@if (organization.ProfilePictureContent == null)
{
<div class="event-thumbnail" style="background-image: url(/assets/eh-organization.png);" alt="@organization.Name">
</div>
}
else
{
<div class="event-thumbnail" style="background-image: url(@($"data:image/png;base64,{Convert.ToBase64String(organization.ProfilePictureContent)}"));" alt="@organization.Name">
</div>
}
<div class="event-thumbnail" style="background-image: url(@(UrlOptions.Value.ApiInternal.EnsureEndsWith('/') + $"api/eventhub/organization/profile-picture/{organization.Id}"));" alt="@organization.Name">
</div>
<div class="card-body">
<div class="event-container">
<div class="event-info">

12
src/EventHub.Web/Pages/Organizations/Edit.cshtml

@ -2,9 +2,12 @@
@inject IHtmlLocalizer<EventHubResource> L
@using EventHub.Localization
@using EventHub.Organizations
@using EventHub.Web
@using Microsoft.AspNetCore.Mvc.Localization
@using Microsoft.Extensions.Options
@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal
@model EventHub.Web.Pages.Organizations.EditPageModel
@inject IOptions<EventHubUrlOptions> UrlOptions
@section scripts {
<abp-script src="/Pages/Organizations/Edit.js"/>
@ -26,14 +29,7 @@
<div class="row">
<div class="col-4">
<div class="image-area">
@if (Model.ProfilePictureContent != null && Model.ProfilePictureContent.Length > 0)
{
<img id="imageResult" src="@($"data:image/png;base64,{Convert.ToBase64String(Model.ProfilePictureContent)}")" alt="" class="img-fluid rounded shadow-sm mx-auto d-block">
}
else
{
<img id="imageResult" src="#" alt="" class="img-fluid rounded shadow-sm mx-auto d-block">
}
<img id="imageResult" src="@(UrlOptions.Value.ApiInternal.EnsureEndsWith('/') + $"api/eventhub/organization/profile-picture/{Model.Organization.Id}")" alt="" class="img-fluid rounded shadow-sm mx-auto d-block">
</div>
</div>

20
src/EventHub.Web/Pages/Organizations/Edit.cshtml.cs

@ -9,6 +9,7 @@ using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form;
using Volo.Abp.Content;
namespace EventHub.Web.Pages.Organizations
{
@ -20,7 +21,6 @@ namespace EventHub.Web.Pages.Organizations
[BindProperty]
public EditOrganizationViewModel Organization { get; set; }
public byte[] ProfilePictureContent { get; private set; }
private readonly IOrganizationAppService _organizationAppService;
@ -32,7 +32,6 @@ namespace EventHub.Web.Pages.Organizations
public async Task OnGetAsync()
{
var organizationProfileDto = await _organizationAppService.GetProfileAsync(Name);
ProfilePictureContent = organizationProfileDto.ProfilePictureContent;
Organization = ObjectMapper.Map<OrganizationProfileDto, EditOrganizationViewModel>(organizationProfileDto);
}
@ -43,18 +42,21 @@ namespace EventHub.Web.Pages.Organizations
{
ValidateModel();
var input = ObjectMapper.Map<EditOrganizationViewModel, UpdateOrganizationDto>(Organization);
var updateOrganizationDto = ObjectMapper.Map<EditOrganizationViewModel, UpdateOrganizationDto>(Organization);
await using var memoryStream = new MemoryStream();
if (Organization.ProfilePictureFile != null && Organization.ProfilePictureFile.Length > 0)
{
using (var memoryStream = new MemoryStream())
await Organization.ProfilePictureFile.CopyToAsync(memoryStream);
updateOrganizationDto.ProfilePictureStreamContent = new RemoteStreamContent(memoryStream)
{
await Organization.ProfilePictureFile.CopyToAsync(memoryStream);
input.ProfilePictureContent = memoryStream.ToArray();
}
ContentType = Organization.ProfilePictureFile.ContentType,
FileName = Organization.ProfilePictureFile.FileName,
};
}
await _organizationAppService.UpdateAsync(Organization.Id, input);
await _organizationAppService.UpdateAsync(Organization.Id, updateOrganizationDto);
await memoryStream.DisposeAsync();
return RedirectToPage("./Profile", new { name = Name });
}

22
src/EventHub.Web/Pages/Organizations/New.cshtml.cs

@ -9,13 +9,15 @@ using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form;
using Volo.Abp.Content;
namespace EventHub.Web.Pages.Organizations
{
[Authorize]
public class NewPageModel : EventHubPageModel
{
[BindProperty] public CreateOrganizationViewModel Organization { get; set; }
[BindProperty]
public CreateOrganizationViewModel Organization { get; set; }
private readonly IOrganizationAppService _organizationAppService;
@ -35,18 +37,22 @@ namespace EventHub.Web.Pages.Organizations
{
ValidateModel();
var input = ObjectMapper.Map<CreateOrganizationViewModel, CreateOrganizationDto>(Organization);
var createOrganizationDto = ObjectMapper.Map<CreateOrganizationViewModel, CreateOrganizationDto>(Organization);
await using var memoryStream = new MemoryStream();
if (Organization.ProfilePictureFile != null && Organization.ProfilePictureFile.Length > 0)
{
using (var memoryStream = new MemoryStream())
await Organization.ProfilePictureFile.CopyToAsync(memoryStream);
createOrganizationDto.ProfilePictureStreamContent = new RemoteStreamContent(memoryStream)
{
await Organization.ProfilePictureFile.CopyToAsync(memoryStream);
input.ProfilePictureContent = memoryStream.ToArray();
}
ContentType = Organization.ProfilePictureFile.ContentType,
FileName = Organization.ProfilePictureFile.FileName
};
}
await _organizationAppService.CreateAsync(input);
await _organizationAppService.CreateAsync(createOrganizationDto);
await memoryStream.DisposeAsync();
return RedirectToPage("./Profile", new {name = Organization.Name});
}

12
src/EventHub.Web/Pages/Organizations/Profile.cshtml

@ -1,13 +1,16 @@
@page "/organizations/{name}"
@inject IHtmlLocalizer<EventHubResource> L
@using EventHub.Localization
@using EventHub.Web
@using EventHub.Web.Pages.Events.Components.EventsArea
@using EventHub.Web.Pages.Organizations.Components.JoinArea
@using EventHub.Web.Pages.Organizations.Components.MembersArea
@using Microsoft.AspNetCore.Mvc.Localization
@using Microsoft.Extensions.Options
@using Volo.Abp.Timing
@model EventHub.Web.Pages.Organizations.ProfilePageModel
@inject IClock Clock
@inject IOptions<EventHubUrlOptions> UrlOptions
@section scripts {
<abp-script src="/Pages/Organizations/Profile.js"/>
@ -18,14 +21,7 @@
<div class="row">
<div class="col-md-12">
<div class="detail-image">
@if (Model.Organization.ProfilePictureContent == null)
{
<img class="detail-img" src="/assets/eh-organization-big.png" alt="@Model.Organization.Name">
}
else
{
<img class="detail-img" src="@($"data:image/png;base64,{Convert.ToBase64String(Model.Organization.ProfilePictureContent)}")" alt="@Model.Organization.Name">
}
<img class="detail-img" src="@(UrlOptions.Value.ApiInternal.EnsureEndsWith('/') + $"api/eventhub/organization/profile-picture/{Model.Organization.Id}")" alt="@Model.Organization.Name">
</div>
</div>

Loading…
Cancel
Save