User Insert ve Update için Avatar

This commit is contained in:
Sedat ÖZTÜRK 2026-06-11 16:52:35 +03:00
parent 0f46de0381
commit 0c202ece24
8 changed files with 65 additions and 17 deletions

View file

@ -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();
}

View file

@ -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(),

View file

@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

View file

@ -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

View file

@ -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>

View file

@ -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>

View file

@ -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 = ''