User Insert ve Update için Avatar
This commit is contained in:
parent
0f46de0381
commit
0c202ece24
8 changed files with 65 additions and 17 deletions
|
|
@ -1,5 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using Sozsoft.Platform.Extensions;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
|
|
@ -10,17 +12,26 @@ using Volo.Abp.Domain.Entities;
|
|||
using Volo.Abp.Identity;
|
||||
using Volo.Abp.TenantManagement;
|
||||
using IdentityUser = Volo.Abp.Identity.IdentityUser;
|
||||
using Sozsoft.Platform.BlobStoring;
|
||||
using Sozsoft.Platform.Identity;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
|
||||
namespace Sozsoft.Platform.ListForms.DynamicApi;
|
||||
|
||||
[Authorize]
|
||||
public class ListFormDynamicApiAppService : PlatformAppService, IListFormDynamicApiAppService
|
||||
{
|
||||
private static readonly Regex DataUrlRegex = new(
|
||||
@"^data:(?<contentType>image\/[a-zA-Z0-9.+-]+);base64,(?<data>.+)$",
|
||||
RegexOptions.Compiled);
|
||||
|
||||
private readonly ITenantRepository tenantRepository;
|
||||
private readonly ITenantManager tenantManager;
|
||||
private readonly IIdentityUserAppService identityUserAppService;
|
||||
private readonly IIdentityRoleAppService identityRoleAppService;
|
||||
private readonly IdentityUserManager userManager;
|
||||
private readonly BlobManager blobCdnManager;
|
||||
private readonly IConfiguration configuration;
|
||||
private readonly IOptions<IdentityOptions> identityOptions;
|
||||
|
||||
public ListFormDynamicApiAppService(
|
||||
|
|
@ -29,6 +40,8 @@ public class ListFormDynamicApiAppService : PlatformAppService, IListFormDynamic
|
|||
IIdentityUserAppService identityUserAppService,
|
||||
IIdentityRoleAppService identityRoleAppService,
|
||||
IdentityUserManager userManager,
|
||||
BlobManager blobCdnManager,
|
||||
IConfiguration configuration,
|
||||
IOptions<IdentityOptions> identityOptions)
|
||||
{
|
||||
this.tenantRepository = tenantRepository;
|
||||
|
|
@ -36,6 +49,8 @@ public class ListFormDynamicApiAppService : PlatformAppService, IListFormDynamic
|
|||
this.identityUserAppService = identityUserAppService;
|
||||
this.identityRoleAppService = identityRoleAppService;
|
||||
this.userManager = userManager;
|
||||
this.blobCdnManager = blobCdnManager;
|
||||
this.configuration = configuration;
|
||||
this.identityOptions = identityOptions;
|
||||
}
|
||||
|
||||
|
|
@ -44,6 +59,41 @@ public class ListFormDynamicApiAppService : PlatformAppService, IListFormDynamic
|
|||
return Guid.TryParse(value, out var id) ? id : Guid.Empty;
|
||||
}
|
||||
|
||||
private async Task SaveAvatarAsync(IdentityUser user, string avatar)
|
||||
{
|
||||
if (avatar.IsNullOrWhiteSpace())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var base64 = avatar.Trim();
|
||||
var match = DataUrlRegex.Match(base64);
|
||||
if (match.Success)
|
||||
{
|
||||
base64 = match.Groups["data"].Value;
|
||||
}
|
||||
else if (avatar.StartsWith("http", StringComparison.OrdinalIgnoreCase) ||
|
||||
avatar.StartsWith("/", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
byte[] bytes;
|
||||
try
|
||||
{
|
||||
bytes = Convert.FromBase64String(base64);
|
||||
}
|
||||
catch (FormatException)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var fileName = $"{user.Id}.jpg";
|
||||
await using var stream = new MemoryStream(bytes);
|
||||
await blobCdnManager.SaveAsync(BlobContainerNames.Avatar, fileName, stream);
|
||||
user.SetAvatar(AvatarProvider.GetAvatar(configuration, user.TenantId?.ToString(), user.Id.ToString()));
|
||||
}
|
||||
|
||||
[Authorize(IdentityPermissions.Users.Create)]
|
||||
public async Task PostUserInsertAsync(DynamicApiBaseInput<CreateUpdateUserInput> input)
|
||||
{
|
||||
|
|
@ -68,7 +118,8 @@ public class ListFormDynamicApiAppService : PlatformAppService, IListFormDynamic
|
|||
user.SetDepartmentId(ParseGuid(input.Data.DepartmentId));
|
||||
user.SetJobPositionId(ParseGuid(input.Data.JobPositionId));
|
||||
user.SetIsVerified(verify);
|
||||
user.SetAvatar(input.Data.Avatar);
|
||||
|
||||
await SaveAvatarAsync(user, input.Data.Avatar);
|
||||
|
||||
(await userManager.CreateAsync(user, input.Data.Password)).CheckErrors();
|
||||
await userManager.SetLockoutEnabledAsync(user, true);
|
||||
|
|
@ -139,11 +190,7 @@ public class ListFormDynamicApiAppService : PlatformAppService, IListFormDynamic
|
|||
user.SetJobPositionId(ParseGuid(input.Data.JobPositionId));
|
||||
}
|
||||
|
||||
if (input.Data.Avatar != null)
|
||||
{
|
||||
user.SetJobPositionId(ParseGuid(input.Data.Avatar));
|
||||
}
|
||||
|
||||
await SaveAvatarAsync(user, input.Data.Avatar);
|
||||
|
||||
(await userManager.UpdateAsync(user)).CheckErrors();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -809,7 +809,7 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep
|
|||
EditingOptionJson = DefaultEditingOptionJson(listFormName, 500, 710, true, true, true, true, false),
|
||||
EditingFormJson = JsonSerializer.Serialize(new List<EditingFormDto>() {
|
||||
new () { Order=1,ColCount=1,ColSpan=1,ItemType="group",Items=[
|
||||
new EditingFormItemDto { Order=1, DataField="Avatar", ColSpan=1, EditorType2=EditorTypes.dxImageViewer },
|
||||
new EditingFormItemDto { Order=1, DataField="Avatar", ColSpan=1, EditorType2=EditorTypes.dxImageViewer, EditorOptions=EditorOptionValues.ImageUploadOptions(false) },
|
||||
new EditingFormItemDto { Order=2, DataField="Email", ColSpan=1, EditorType2=EditorTypes.dxTextBox },
|
||||
new EditingFormItemDto { Order=3, DataField="Name", ColSpan=1, EditorType2=EditorTypes.dxTextBox },
|
||||
new EditingFormItemDto { Order=4, DataField="Surname", ColSpan=1, EditorType2=EditorTypes.dxTextBox },
|
||||
|
|
@ -2703,7 +2703,7 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep
|
|||
DeleteCommand = DefaultDeleteCommand(nameof(TableNameEnum.Announcement)),
|
||||
DeleteFieldsDefaultValueJson = DefaultDeleteFieldsDefaultValueJson(),
|
||||
PagerOptionJson = DefaultPagerOptionJson,
|
||||
EditingOptionJson = DefaultEditingOptionJson(listFormName, 750, 600, true, true, true, true, false),
|
||||
EditingOptionJson = DefaultEditingOptionJson(listFormName, 750, 700, true, true, true, true, false),
|
||||
InsertFieldsDefaultValueJson = DefaultInsertFieldsDefaultValueJson(),
|
||||
EditingFormJson = JsonSerializer.Serialize(new List<EditingFormDto>()
|
||||
{
|
||||
|
|
@ -2717,7 +2717,7 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep
|
|||
new EditingFormItemDto { Order = 6, DataField = "PublishDate", ColSpan=1, EditorType2 = EditorTypes.dxDateBox },
|
||||
new EditingFormItemDto { Order = 7, DataField = "ExpiryDate", ColSpan=1, EditorType2 = EditorTypes.dxDateBox },
|
||||
new EditingFormItemDto { Order = 8, DataField = "IsPinned", ColSpan=1, EditorType2 = EditorTypes.dxCheckBox },
|
||||
new EditingFormItemDto { Order = 9, DataField = "ImageUrl", ColSpan=1, EditorType2 = EditorTypes.dxImageUpload, EditorOptions = EditorOptionValues.ImageUploadOptions},
|
||||
new EditingFormItemDto { Order = 9, DataField = "ImageUrl", ColSpan=1, EditorType2 = EditorTypes.dxImageUpload, EditorOptions = EditorOptionValues.ImageUploadOptions()},
|
||||
]}
|
||||
}),
|
||||
FormFieldsDefaultValueJson = JsonSerializer.Serialize(new FieldsDefaultValue[]
|
||||
|
|
@ -4218,7 +4218,7 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep
|
|||
new EditingFormItemDto { Order = 7, DataField = "Status", ColSpan = 1, EditorType2 = EditorTypes.dxSelectBox, EditorOptions=EditorOptionValues.ShowClearButton },
|
||||
new EditingFormItemDto { Order = 8, DataField = "ParticipantsCount", ColSpan = 1, EditorType2 = EditorTypes.dxNumberBox },
|
||||
new EditingFormItemDto { Order = 9, DataField = "Description", ColSpan = 2, EditorType2 = EditorTypes.dxTextBox },
|
||||
new EditingFormItemDto { Order = 10, DataField = "Photos", ColSpan = 1, EditorType2 = EditorTypes.dxImageUpload, EditorOptions = EditorOptionValues.ImageUploadOptions },
|
||||
new EditingFormItemDto { Order = 10, DataField = "Photos", ColSpan = 1, EditorType2 = EditorTypes.dxImageUpload, EditorOptions = EditorOptionValues.ImageUploadOptions() },
|
||||
]}
|
||||
}),
|
||||
InsertFieldsDefaultValueJson = DefaultInsertFieldsDefaultValueJson(),
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ public static class PlatformConsts
|
|||
public static string DateFormat = "{ \"format\": \"dd/MM/yyyy\", \"displayFormat\" : \"dd/MM/yyyy\" }";
|
||||
public static string DateTimeFormat = "{ \"format\": \"dd/MM/yyyy HH:mm\", \"displayFormat\" : \"dd/MM/yyyy HH:mm\" }";
|
||||
public static string SliderOptions = "{\"tooltip\": { \"enabled\": true }}";
|
||||
public static string ImageUploadOptions = "{\"width\": 80, \"height\": 80, \"multiple\": true}";
|
||||
public static string ImageUploadOptions(bool multiple = true) => $"{{\"width\": 80, \"height\": 80, \"multiple\": {multiple.ToString().ToLower()}}}";
|
||||
}
|
||||
|
||||
public static class EditorScriptValues
|
||||
|
|
|
|||
BIN
ui/public/img/others/no-image.png
Normal file
BIN
ui/public/img/others/no-image.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.8 KiB |
|
|
@ -137,6 +137,7 @@ export interface UserInfoViewModel extends ExtensibleObject {
|
|||
phoneNumberConfirmed: boolean
|
||||
accessFailedCount: number
|
||||
shouldChangePasswordOnNextLogin: boolean
|
||||
avatar: string
|
||||
rocketUsername?: string
|
||||
creationTime: Date | string
|
||||
lastModificationTime: Date | string
|
||||
|
|
|
|||
|
|
@ -145,7 +145,7 @@ const ImageViewerEditorComponent = ({
|
|||
}}
|
||||
onError={({ currentTarget }) => {
|
||||
currentTarget.onerror = null
|
||||
currentTarget.src = '/img/others/default-profile.png'
|
||||
currentTarget.src = '/img/others/no-image.png'
|
||||
}}
|
||||
/>
|
||||
</button>
|
||||
|
|
|
|||
|
|
@ -189,7 +189,7 @@ const ImageViewerEditorComponent = (templateData: any): ReactElement => {
|
|||
}}
|
||||
onError={({ currentTarget }) => {
|
||||
currentTarget.onerror = null
|
||||
currentTarget.src = '/img/others/default-profile.png'
|
||||
currentTarget.src = '/img/others/no-image.png'
|
||||
}}
|
||||
/>
|
||||
</button>
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ import {
|
|||
} from '@/proxy/form/models'
|
||||
import { addCss } from './Utils'
|
||||
|
||||
const DEFAULT_PROFILE_IMAGE = '/img/others/default-profile.png'
|
||||
const NO_IMAGE = '/img/others/no-image.png'
|
||||
|
||||
const cellTemplateMultiValue = (
|
||||
cellElement: HTMLElement,
|
||||
|
|
@ -92,7 +92,7 @@ function getImgPreview(): HTMLDivElement {
|
|||
].join(';')
|
||||
const img = document.createElement('img')
|
||||
img.onerror = null
|
||||
img.src = DEFAULT_PROFILE_IMAGE
|
||||
img.src = NO_IMAGE
|
||||
img.style.cssText =
|
||||
'display:block;max-width:312px;max-height:312px;object-fit:contain;border-radius:4px;'
|
||||
el.appendChild(img)
|
||||
|
|
@ -107,7 +107,7 @@ function showImgPreview(src: string, e: MouseEvent) {
|
|||
const imgEl = el.querySelector('img') as HTMLImageElement
|
||||
imgEl.onerror = () => {
|
||||
imgEl.onerror = null
|
||||
imgEl.src = DEFAULT_PROFILE_IMAGE
|
||||
imgEl.src = NO_IMAGE
|
||||
}
|
||||
if (imgEl.src !== src) imgEl.src = src
|
||||
|
||||
|
|
@ -158,7 +158,7 @@ const cellTemplateImage = (
|
|||
const img = document.createElement('img')
|
||||
img.onerror = () => {
|
||||
img.onerror = null
|
||||
img.src = DEFAULT_PROFILE_IMAGE
|
||||
img.src = NO_IMAGE
|
||||
}
|
||||
img.src = url
|
||||
img.alt = ''
|
||||
|
|
|
|||
Loading…
Reference in a new issue