Tenantlı uygulama için Login düzenlemesi
This commit is contained in:
parent
67286232da
commit
f9c5910813
25 changed files with 226 additions and 131 deletions
|
|
@ -19,7 +19,6 @@
|
|||
<ItemGroup>
|
||||
<PackageReference Include="MailKit" Version="4.16.0" PrivateAssets="all" />
|
||||
<PackageReference Include="MimeKit" Version="4.16.0" PrivateAssets="all" />
|
||||
<PackageReference Include="Scriban" Version="7.2.0" PrivateAssets="all" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@
|
|||
</PackageReference>
|
||||
<PackageReference Include="MailKit" Version="4.16.0" PrivateAssets="all" />
|
||||
<PackageReference Include="MimeKit" Version="4.16.0" PrivateAssets="all" />
|
||||
<PackageReference Include="Scriban" Version="7.2.0" PrivateAssets="all" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -31,6 +31,8 @@ public class MailTrackingManager : DomainService
|
|||
/// <returns></returns>
|
||||
public async Task StartAsync()
|
||||
{
|
||||
// https://us-east-1.console.aws.amazon.com/iam/home?region=eu-central-1#/users
|
||||
// https://eu-central-1.console.aws.amazon.com/ses/home?region=eu-central-1#/identities/system%40sozsoft.com?tabId=authentication
|
||||
var accessKey = configuration.GetValue<string>(AmazonSesEmailSettingNames.AccessKey);
|
||||
var accessKeyId = configuration.GetValue<string>(AmazonSesEmailSettingNames.AccessKeyId);
|
||||
var region = configuration.GetValue<string>(AmazonSesEmailSettingNames.Region);
|
||||
|
|
|
|||
|
|
@ -30,7 +30,6 @@
|
|||
<PackageReference Include="Volo.Abp.TextTemplating.Razor" Version="10.0.0" />
|
||||
<PackageReference Include="MailKit" Version="4.16.0" PrivateAssets="all" />
|
||||
<PackageReference Include="MimeKit" Version="4.16.0" PrivateAssets="all" />
|
||||
<PackageReference Include="Scriban" Version="7.2.0" PrivateAssets="all" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@
|
|||
</PackageReference>
|
||||
<PackageReference Include="MailKit" Version="4.16.0" PrivateAssets="all" />
|
||||
<PackageReference Include="MimeKit" Version="4.16.0" PrivateAssets="all" />
|
||||
<PackageReference Include="Scriban" Version="7.2.0" PrivateAssets="all" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -65,6 +65,7 @@ public class AmazonSesEmailSender : EmailSenderBase, ISozsoftEmailSender, ITrans
|
|||
await BackgroundJobManager.EnqueueAsync(
|
||||
new ErpBackgroundEmailSendingJobArgs
|
||||
{
|
||||
TenantId = CurrentTenant.Id,
|
||||
To = to,
|
||||
Sender = sender,
|
||||
Params = @params,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using Volo.Abp.BackgroundJobs;
|
||||
using Volo.Abp.BackgroundJobs;
|
||||
using Volo.Abp.DependencyInjection;
|
||||
using Volo.Abp.MultiTenancy;
|
||||
|
||||
namespace Sozsoft.Sender.Mail;
|
||||
|
||||
|
|
@ -7,13 +8,19 @@ public class ErpBackgroundEmailSendingJob :
|
|||
AsyncBackgroundJob<ErpBackgroundEmailSendingJobArgs>, ITransientDependency
|
||||
{
|
||||
protected ISozsoftEmailSender EmailSender { get; }
|
||||
protected ICurrentTenant CurrentTenant { get; }
|
||||
|
||||
public ErpBackgroundEmailSendingJob(ISozsoftEmailSender emailSender)
|
||||
public ErpBackgroundEmailSendingJob(
|
||||
ISozsoftEmailSender emailSender,
|
||||
ICurrentTenant currentTenant)
|
||||
{
|
||||
EmailSender = emailSender;
|
||||
CurrentTenant = currentTenant;
|
||||
}
|
||||
|
||||
public override async Task ExecuteAsync(ErpBackgroundEmailSendingJobArgs args)
|
||||
{
|
||||
using (CurrentTenant.Change(args.TenantId))
|
||||
{
|
||||
//await EmailSender.SendEmailAsync(args.Template, args.To, args.Params, args.Subject);
|
||||
await EmailSender.SendEmailAsync(
|
||||
|
|
@ -24,5 +31,5 @@ public class ErpBackgroundEmailSendingJob :
|
|||
args.Subject,
|
||||
args.Attachments);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,12 @@
|
|||
namespace Sozsoft.Sender.Mail;
|
||||
using Volo.Abp.MultiTenancy;
|
||||
|
||||
namespace Sozsoft.Sender.Mail;
|
||||
|
||||
[Serializable]
|
||||
public class ErpBackgroundEmailSendingJobArgs
|
||||
public class ErpBackgroundEmailSendingJobArgs : IMultiTenant
|
||||
{
|
||||
public Guid? TenantId { get; set; }
|
||||
|
||||
public string[] To { get; set; }
|
||||
|
||||
public KeyValuePair<string, string>? Sender { get; set; }
|
||||
|
|
@ -14,6 +18,4 @@ public class ErpBackgroundEmailSendingJobArgs
|
|||
public Dictionary<string, string>? Attachments { get; set; }
|
||||
|
||||
public string? TextContent { get; set; }
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@
|
|||
<PackageReference Include="Microsoft.Extensions.Http" Version="10.0.0" />
|
||||
<PackageReference Include="MailKit" Version="4.16.0" PrivateAssets="all" />
|
||||
<PackageReference Include="MimeKit" Version="4.16.0" PrivateAssets="all" />
|
||||
<PackageReference Include="Scriban" Version="7.2.0" PrivateAssets="all" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -5,10 +5,9 @@ using System.Threading.Tasks;
|
|||
using Sozsoft.Languages;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Volo.Abp.Application.Services;
|
||||
using Volo.Abp.Domain.Repositories;
|
||||
using Volo.Abp.MultiTenancy;
|
||||
using Volo.Abp.SettingManagement;
|
||||
using Volo.Abp.Settings;
|
||||
using SettingDefinition = Sozsoft.Settings.Entities.SettingDefinition;
|
||||
|
||||
namespace Sozsoft.Settings;
|
||||
|
||||
|
|
@ -20,17 +19,20 @@ public class SettingUiAppService : ApplicationService, ISettingUiAppService
|
|||
private readonly ISettingDefinitionManager settingDefinitionManager;
|
||||
private readonly ISettingManager settingManager;
|
||||
private readonly ErpSettingDefinitionManager ErpSettingDefinitionManager;
|
||||
private readonly ICurrentTenant currentTenant;
|
||||
|
||||
public SettingUiAppService(
|
||||
ILanguageKeyIntegrationService languageKeyIntegrationService,
|
||||
ISettingDefinitionManager settingDefinitionManager,
|
||||
ISettingManager settingManager,
|
||||
ErpSettingDefinitionManager ErpSettingDefinitionManager)
|
||||
ErpSettingDefinitionManager ErpSettingDefinitionManager,
|
||||
ICurrentTenant currentTenant)
|
||||
{
|
||||
this.languageKeyIntegrationService = languageKeyIntegrationService;
|
||||
this.settingDefinitionManager = settingDefinitionManager;
|
||||
this.settingManager = settingManager;
|
||||
this.ErpSettingDefinitionManager = ErpSettingDefinitionManager;
|
||||
this.currentTenant = currentTenant;
|
||||
}
|
||||
|
||||
public virtual async Task<List<MainGroupedSettingDto>> GetListAsync()
|
||||
|
|
@ -95,15 +97,18 @@ public class SettingUiAppService : ApplicationService, ISettingUiAppService
|
|||
{
|
||||
if (setting.Providers.IsNullOrEmpty())
|
||||
{
|
||||
await settingManager.SetForCurrentUserAsync(setting.Name, value);
|
||||
if (currentTenant.Id.HasValue)
|
||||
{
|
||||
await settingManager.SetForCurrentTenantAsync(setting.Name, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (setting.Providers.Any(p => p == UserSettingValueProvider.ProviderName))
|
||||
{
|
||||
await settingManager.SetForCurrentUserAsync(setting.Name, value);
|
||||
await settingManager.SetGlobalAsync(setting.Name, value);
|
||||
}
|
||||
else if (setting.Providers.Any(p => p == TenantSettingValueProvider.ProviderName))
|
||||
}
|
||||
else
|
||||
{
|
||||
if (setting.Providers.Any(p => p == TenantSettingValueProvider.ProviderName) && currentTenant.Id.HasValue)
|
||||
{
|
||||
await settingManager.SetForCurrentTenantAsync(setting.Name, value);
|
||||
}
|
||||
|
|
@ -111,6 +116,10 @@ public class SettingUiAppService : ApplicationService, ISettingUiAppService
|
|||
{
|
||||
await settingManager.SetGlobalAsync(setting.Name, value);
|
||||
}
|
||||
else if (setting.Providers.Any(p => p == UserSettingValueProvider.ProviderName))
|
||||
{
|
||||
await settingManager.SetForCurrentUserAsync(setting.Name, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@
|
|||
</PackageReference>
|
||||
<PackageReference Include="MailKit" Version="4.16.0" PrivateAssets="all" />
|
||||
<PackageReference Include="MimeKit" Version="4.16.0" PrivateAssets="all" />
|
||||
<PackageReference Include="Scriban" Version="7.2.0" PrivateAssets="all" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@
|
|||
</PackageReference>
|
||||
<PackageReference Include="MailKit" Version="4.16.0" PrivateAssets="all" />
|
||||
<PackageReference Include="MimeKit" Version="4.16.0" PrivateAssets="all" />
|
||||
<PackageReference Include="Scriban" Version="7.2.0" PrivateAssets="all" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -258,7 +258,7 @@
|
|||
"code": "App.SiteManagement.General.NewMemberNotificationEmails",
|
||||
"nameKey": "App.SiteManagement.General.NewMemberNotificationEmails",
|
||||
"descriptionKey": "App.SiteManagement.General.NewMemberNotificationEmails.Description",
|
||||
"defaultValue": "SYSTEM@SOZSOFT.COM",
|
||||
"defaultValue": "system@sozsoft.com",
|
||||
"isVisibleToClients": false,
|
||||
"providers": "G|D",
|
||||
"isInherited": false,
|
||||
|
|
@ -274,7 +274,7 @@
|
|||
"code": "App.SiteManagement.General.TimedLoginEmails",
|
||||
"nameKey": "App.SiteManagement.General.TimedLoginEmails",
|
||||
"descriptionKey": "App.SiteManagement.General.TimedLoginEmails.Description",
|
||||
"defaultValue": "SYSTEM@SOZSOFT.COM",
|
||||
"defaultValue": "system@sozsoft.com",
|
||||
"isVisibleToClients": false,
|
||||
"providers": "G|D",
|
||||
"isInherited": false,
|
||||
|
|
@ -466,7 +466,7 @@
|
|||
"code": "Abp.Mailing.DefaultFromAddress",
|
||||
"nameKey": "Abp.Mailing.DefaultFromAddress",
|
||||
"descriptionKey": "Abp.Mailing.DefaultFromAddress.Description",
|
||||
"defaultValue": "SYSTEM@SOZSOFT.COM",
|
||||
"defaultValue": "system@sozsoft.com",
|
||||
"isVisibleToClients": false,
|
||||
"providers": "T|G|D",
|
||||
"isInherited": false,
|
||||
|
|
@ -482,7 +482,7 @@
|
|||
"code": "Abp.Mailing.Smtp.UserName",
|
||||
"nameKey": "Abp.Mailing.Smtp.UserName",
|
||||
"descriptionKey": "Abp.Mailing.Smtp.UserName.Description",
|
||||
"defaultValue": "SYSTEM@SOZSOFT.COM",
|
||||
"defaultValue": "system@sozsoft.com",
|
||||
"isVisibleToClients": false,
|
||||
"providers": "T|G|D",
|
||||
"isInherited": false,
|
||||
|
|
@ -610,7 +610,7 @@
|
|||
"code": "Abp.Mailing.AWS.AccessKey",
|
||||
"nameKey": "Abp.Mailing.AWS.AccessKey",
|
||||
"descriptionKey": "Abp.Mailing.AWS.AccessKey.Description",
|
||||
"defaultValue": "aXW8L21rP6dPO6Txj76Be2FCpWRBa25EMrSAVL76",
|
||||
"defaultValue": "SibFBAMiSApvz+NChYmlgZmx25JNbximemIDOFps",
|
||||
"isVisibleToClients": false,
|
||||
"providers": "T|G|D",
|
||||
"isInherited": false,
|
||||
|
|
@ -626,7 +626,7 @@
|
|||
"code": "Abp.Mailing.AWS.AccessKeyId",
|
||||
"nameKey": "Abp.Mailing.AWS.AccessKeyId",
|
||||
"descriptionKey": "Abp.Mailing.AWS.AccessKeyId.Description",
|
||||
"defaultValue": "AKIATULUYBLX4IY3S2P1",
|
||||
"defaultValue": "AKIA5OCSDJB5KOQY74NV",
|
||||
"isVisibleToClients": false,
|
||||
"providers": "T|G|D",
|
||||
"isInherited": false,
|
||||
|
|
@ -722,7 +722,7 @@
|
|||
"code": "Abp.Account.Captcha.SiteKey",
|
||||
"nameKey": "Abp.Account.Captcha.SiteKey",
|
||||
"descriptionKey": "Abp.Account.Captcha.SiteKey.Description",
|
||||
"defaultValue": "0x4AAAAAAAGadwQME-GSYuJU",
|
||||
"defaultValue": "0x4AAAAAABdEjmiXxcl0j7jp",
|
||||
"isVisibleToClients": false,
|
||||
"providers": "G|D",
|
||||
"isInherited": false,
|
||||
|
|
@ -738,7 +738,7 @@
|
|||
"code": "Abp.Account.Captcha.SecretKey",
|
||||
"nameKey": "Abp.Account.Captcha.SecretKey",
|
||||
"descriptionKey": "Abp.Account.Captcha.SecretKey.Description",
|
||||
"defaultValue": "0x4AAAAAAAGad_f_WP47IcNBs9FTu5DhNX8",
|
||||
"defaultValue": "0x4AAAAAABdEjhw1A8sJZUvQX8-CgqvB3mE",
|
||||
"isVisibleToClients": false,
|
||||
"providers": "G|D",
|
||||
"isInherited": false,
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ public class PlatformBackgroundWorkerTemplateDefinitionProvider : TemplateDefini
|
|||
foreach (var worker in workers.Where(a =>
|
||||
a.IsActive &&
|
||||
a.WorkerType == WorkerTypeEnum.MailQueueWorker &&
|
||||
a.Options != null && a.Options != string.Empty).ToList())
|
||||
a.Options != null).ToList().Where(a => !a.Options.IsNullOrWhiteSpace()))
|
||||
{
|
||||
var Options = JsonSerializer.Deserialize<MailQueueWorkerOptions>(worker.Options);
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ const Captcha = forwardRef((props: CaptchaProps, ref: Ref<TurnstileInstance>) =>
|
|||
const { className, onError, onExpire, onSuccess } = props
|
||||
|
||||
return (
|
||||
<>
|
||||
<Turnstile
|
||||
ref={ref}
|
||||
className={className ?? 'mb-4 mx-auto'}
|
||||
|
|
@ -21,7 +20,6 @@ const Captcha = forwardRef((props: CaptchaProps, ref: Ref<TurnstileInstance>) =>
|
|||
onExpire={onExpire}
|
||||
onSuccess={onSuccess}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
})
|
||||
Captcha.displayName = 'Captcha'
|
||||
|
|
|
|||
148
ui/src/components/shared/TenantSelector.tsx
Normal file
148
ui/src/components/shared/TenantSelector.tsx
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
import Input from '@/components/ui/Input'
|
||||
import { getTenantByNameDetail } from '@/services/tenant.service'
|
||||
import { useStoreActions, useStoreState } from '@/store'
|
||||
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||
import { defaultDomain, getSubdomain } from '@/utils/subdomain'
|
||||
import type { CSSProperties } from 'react'
|
||||
import { useCallback, useEffect, useRef } from 'react'
|
||||
|
||||
const hiddenTenantStyle: CSSProperties = {
|
||||
opacity: 0,
|
||||
position: 'absolute',
|
||||
pointerEvents: 'none',
|
||||
height: 0,
|
||||
margin: 0,
|
||||
padding: 0,
|
||||
border: 'none',
|
||||
}
|
||||
|
||||
const TenantSelector = () => {
|
||||
const { translate } = useLocalization()
|
||||
const isMultiTenant = useStoreState((state) => state.abpConfig.config?.multiTenancy.isEnabled)
|
||||
const tenantName = useStoreState((state) => state.locale.currentTenantName)
|
||||
const { setTenantName } = useStoreActions((actions) => actions.locale)
|
||||
const { setTenant } = useStoreActions((actions) => actions.auth.tenant)
|
||||
const { setWarning } = useStoreActions((actions) => actions.base.messages)
|
||||
const requestIdRef = useRef(0)
|
||||
const lastRequestedTenantNameRef = useRef<string>()
|
||||
|
||||
const subDomainName = getSubdomain()
|
||||
const isSubdomainTenant = !!subDomainName && subDomainName !== defaultDomain
|
||||
const tenantStyle = isSubdomainTenant ? hiddenTenantStyle : undefined
|
||||
|
||||
const setWarningTimeout = useCallback(
|
||||
(message: string) => {
|
||||
setTimeout(() => {
|
||||
setWarning(message)
|
||||
}, 100)
|
||||
},
|
||||
[setWarning],
|
||||
)
|
||||
|
||||
const redirectToMainDomain = useCallback(
|
||||
(name: string) => {
|
||||
setTenantName(undefined)
|
||||
const parts = window.location.hostname.split('.')
|
||||
const mainDomain = parts.length >= 3 ? parts.slice(1).join('.') : window.location.hostname
|
||||
setWarningTimeout(
|
||||
`"${name}" kurumuna ait kayıt bulunamadı.\nAna sayfaya yönlendiriliyorsunuz...`,
|
||||
)
|
||||
setTimeout(() => {
|
||||
window.location.href = `${window.location.protocol}//${mainDomain}`
|
||||
}, 3000)
|
||||
},
|
||||
[setTenantName, setWarningTimeout],
|
||||
)
|
||||
|
||||
const fetchDataByName = useCallback(
|
||||
async (name: string, isSubdomain = false) => {
|
||||
if (!isSubdomain && name === lastRequestedTenantNameRef.current) {
|
||||
return
|
||||
}
|
||||
|
||||
lastRequestedTenantNameRef.current = name
|
||||
const requestId = requestIdRef.current + 1
|
||||
requestIdRef.current = requestId
|
||||
|
||||
if (name) {
|
||||
try {
|
||||
const response = await getTenantByNameDetail(name)
|
||||
|
||||
if (requestId !== requestIdRef.current) {
|
||||
return
|
||||
}
|
||||
|
||||
if (response.data) {
|
||||
setTenant({
|
||||
tenantId: response.data.id,
|
||||
tenantName: response.data.name,
|
||||
menuGroup: response.data.menuGroup,
|
||||
})
|
||||
} else {
|
||||
setTenant(undefined)
|
||||
if (isSubdomain) redirectToMainDomain(name)
|
||||
}
|
||||
} catch {
|
||||
if (requestId !== requestIdRef.current) {
|
||||
return
|
||||
}
|
||||
|
||||
setTenant(undefined)
|
||||
if (isSubdomain) redirectToMainDomain(name)
|
||||
}
|
||||
} else {
|
||||
setTenant(undefined)
|
||||
}
|
||||
},
|
||||
[redirectToMainDomain, setTenant],
|
||||
)
|
||||
|
||||
const handleTenantNameChange = (value: string) => {
|
||||
setTenantName(value)
|
||||
}
|
||||
|
||||
const handleTenantNameBlur = () => {
|
||||
if (subDomainName) {
|
||||
return
|
||||
}
|
||||
|
||||
fetchDataByName(tenantName || '')
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (!isMultiTenant) {
|
||||
setTenant(undefined)
|
||||
return
|
||||
}
|
||||
|
||||
if (subDomainName) {
|
||||
setTenantName(subDomainName)
|
||||
fetchDataByName(subDomainName, true)
|
||||
}
|
||||
}, [fetchDataByName, isMultiTenant, setTenant, setTenantName, subDomainName])
|
||||
|
||||
if (!isMultiTenant) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<label className="form-label mb-2" style={tenantStyle}>
|
||||
{translate('::Organization')}
|
||||
</label>
|
||||
<div className="mb-4">
|
||||
<Input
|
||||
placeholder={translate('::Organization')}
|
||||
value={tenantName ?? ''}
|
||||
onChange={(event) => handleTenantNameChange(event.target.value)}
|
||||
onBlur={handleTenantNameBlur}
|
||||
style={tenantStyle}
|
||||
aria-hidden={isSubdomainTenant ? 'true' : 'false'}
|
||||
autoFocus={!isSubdomainTenant}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default TenantSelector
|
||||
|
|
@ -19,6 +19,7 @@ export { default as SegmentItemOption } from './SegmentItemOption'
|
|||
export { default as StickyFooter } from './StickyFooter'
|
||||
export { default as SvgIcon } from './SvgIcon'
|
||||
export { default as TableRowSkeleton } from './loaders/TableRowSkeleton'
|
||||
export { default as TenantSelector } from './TenantSelector'
|
||||
export { default as TextBlockSkeleton } from './loaders/TextBlockSkeleton'
|
||||
export { default as TextEllipsis } from './TextEllipsis'
|
||||
export { default as UsersAvatarGroup } from './UsersAvatarGroup'
|
||||
|
|
|
|||
|
|
@ -456,13 +456,15 @@ function OrgChartNode({
|
|||
style={{ cursor: dragging ? 'grabbing' : 'grab' }}
|
||||
>
|
||||
{/* Header bar */}
|
||||
<div data-header="" className={`${headerBg} rounded-t-xl px-3 py-2 flex items-center gap-2`}>
|
||||
<div data-header="" className={`${headerBg} rounded-t-xl px-3 py-2 flex items-center gap-2 dark:bg-gray-900 dark:text-gray-100`}>
|
||||
{mode === 'department' ? (
|
||||
<FaBuilding className="w-3 h-3 text-white opacity-80 flex-shrink-0" />
|
||||
) : (
|
||||
<FaBriefcase className="w-3 h-3 text-white opacity-80 flex-shrink-0" />
|
||||
)}
|
||||
<span data-node-name="" className="text-white font-semibold text-xs truncate flex-1">{node.name}</span>
|
||||
<span data-node-name="" className="text-white font-semibold text-xs truncate flex-1 dark:bg-gray-900 dark:text-gray-100">
|
||||
{node.name}
|
||||
</span>
|
||||
{hasChildren && (
|
||||
<button
|
||||
data-stop-drag="true"
|
||||
|
|
@ -514,7 +516,7 @@ function OrgChartNode({
|
|||
|
||||
{/* Child count badge */}
|
||||
{hasChildren && (
|
||||
<div className="absolute -bottom-2.5 left-1/2 -translate-x-1/2 bg-white border border-slate-200 rounded-full px-2 py-0.5 text-xs text-slate-500 shadow-sm whitespace-nowrap z-10">
|
||||
<div className="absolute -bottom-2.5 left-1/2 -translate-x-1/2 bg-white border border-slate-200 rounded-full px-2 py-0.5 text-xs text-slate-500 shadow-sm whitespace-nowrap z-10 dark:bg-gray-800 dark:border-gray-700 dark:text-gray-100">
|
||||
{node.children.length}
|
||||
</div>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -38,9 +38,9 @@ const LoginHistoryIcon = ({ type }: { type: string }) => {
|
|||
}
|
||||
|
||||
const validationSchema = Yup.object().shape({
|
||||
password: Yup.string().required('Password Required'),
|
||||
password: Yup.string().required(),
|
||||
newPassword: Yup.string()
|
||||
.required('Enter your new password')
|
||||
.required()
|
||||
.min(6, 'Too Short!')
|
||||
.matches(
|
||||
/^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!@#$%^&*])(?=.{6,})/,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import ActionLink from '@/components/shared/ActionLink'
|
||||
import Captcha from '@/components/shared/Captcha'
|
||||
import TenantSelector from '@/components/shared/TenantSelector'
|
||||
import Alert from '@/components/ui/Alert'
|
||||
import Button from '@/components/ui/Button'
|
||||
import { FormContainer, FormItem } from '@/components/ui/Form'
|
||||
|
|
@ -84,6 +85,7 @@ const ExtendLogin = () => {
|
|||
{message}
|
||||
</Alert>
|
||||
)}
|
||||
<TenantSelector />
|
||||
<Formik
|
||||
initialValues={{
|
||||
email: userName,
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import { TenantSelector } from '@/components/shared'
|
||||
import ActionLink from '@/components/shared/ActionLink'
|
||||
import Captcha from '@/components/shared/Captcha'
|
||||
import Alert from '@/components/ui/Alert'
|
||||
|
|
@ -87,6 +88,7 @@ const ForgotPassword = () => {
|
|||
{message}
|
||||
</Alert>
|
||||
)}
|
||||
<TenantSelector />
|
||||
<Formik
|
||||
initialValues={{
|
||||
email: userName,
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import { FailedSignInResponse } from '@/proxy/auth/models'
|
|||
import ActionLink from '@/components/shared/ActionLink'
|
||||
import Captcha from '@/components/shared/Captcha'
|
||||
import PasswordInput from '@/components/shared/PasswordInput'
|
||||
import TenantSelector from '@/components/shared/TenantSelector'
|
||||
import Alert from '@/components/ui/Alert'
|
||||
import Button from '@/components/ui/Button'
|
||||
import Checkbox from '@/components/ui/Checkbox'
|
||||
|
|
@ -9,7 +10,6 @@ import { FormContainer, FormItem } from '@/components/ui/Form'
|
|||
import Input from '@/components/ui/Input'
|
||||
import PlatformLoginResultType from '@/constants/login.result.enum'
|
||||
import { ROUTES_ENUM } from '@/routes/route.constant'
|
||||
import { getTenantByNameDetail } from '@/services/tenant.service'
|
||||
import { useStoreActions, useStoreState } from '@/store'
|
||||
import useAuth from '@/utils/hooks/useAuth'
|
||||
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||
|
|
@ -17,10 +17,9 @@ import useTimeOutMessage from '@/utils/hooks/useTimeOutMessage'
|
|||
import { TurnstileInstance } from '@marsidev/react-turnstile'
|
||||
import { Field, Form, Formik } from 'formik'
|
||||
import { motion } from 'framer-motion'
|
||||
import { useEffect, useRef, useState } from 'react'
|
||||
import { useRef, useState } from 'react'
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
import * as Yup from 'yup'
|
||||
import { defaultDomain, getSubdomain } from '@/utils/subdomain'
|
||||
import { Helmet } from 'react-helmet'
|
||||
import { APP_NAME } from '@/constants/app.constant'
|
||||
|
||||
|
|
@ -33,28 +32,23 @@ type SignInFormSchema = {
|
|||
}
|
||||
|
||||
const validationSchema = Yup.object().shape({
|
||||
userName: Yup.string().required('Please enter your user name'),
|
||||
password: Yup.string().required('Please enter your password'),
|
||||
userName: Yup.string().required(),
|
||||
password: Yup.string().required(),
|
||||
rememberMe: Yup.bool(),
|
||||
twoFactor: Yup.boolean(),
|
||||
twoFactorCode: Yup.string().when('twoFactor', {
|
||||
is: true,
|
||||
then: (schema) => schema.required('Mail adresinize gönderilen doğrulama kodunu giriniz'),
|
||||
then: (schema) => schema.required(),
|
||||
otherwise: (schema) => schema.notRequired(),
|
||||
}),
|
||||
})
|
||||
|
||||
const Login = () => {
|
||||
const navigate = useNavigate()
|
||||
const isMultiTenant = useStoreState((a) => a.abpConfig.config?.multiTenancy.isEnabled)
|
||||
const { setTenant } = useStoreActions((a) => a.auth.tenant)
|
||||
|
||||
const UiVersion = useStoreState((state) => state.locale.currentUiVersion)
|
||||
const { setUiVersion } = useStoreActions((a) => a.locale)
|
||||
|
||||
const tenantName = useStoreState((state) => state.locale.currentTenantName)
|
||||
const { setTenantName } = useStoreActions((actions) => actions.locale)
|
||||
|
||||
const [message, setMessage] = useState('')
|
||||
const [error, setError] = useTimeOutMessage(300000)
|
||||
const [twoFactor, setTwoFactor] = useState(false)
|
||||
|
|
@ -93,9 +87,6 @@ const Login = () => {
|
|||
setError(result.message)
|
||||
} else {
|
||||
setError('')
|
||||
|
||||
//Tenant belirlenmişse
|
||||
fetchDataByName(tenantName || '')
|
||||
}
|
||||
|
||||
if (result.status === 'failed') {
|
||||
|
|
@ -165,57 +156,6 @@ const Login = () => {
|
|||
setSubmitting(false)
|
||||
}
|
||||
|
||||
const fetchDataByName = async (name: string, isSubdomain = false) => {
|
||||
if (name) {
|
||||
try {
|
||||
const response = await getTenantByNameDetail(name)
|
||||
|
||||
if (response.data) {
|
||||
setTenant({ tenantId: response.data.id, tenantName: response.data.name, menuGroup: response.data.menuGroup });
|
||||
} else {
|
||||
setTenant(undefined)
|
||||
if (isSubdomain) redirectToMainDomain(name)
|
||||
}
|
||||
} catch {
|
||||
setTenant(undefined)
|
||||
if (isSubdomain) redirectToMainDomain(name)
|
||||
}
|
||||
} else {
|
||||
setTenant(undefined)
|
||||
}
|
||||
}
|
||||
|
||||
const redirectToMainDomain = (name: string) => {
|
||||
setTenantName(undefined)
|
||||
const parts = window.location.hostname.split('.')
|
||||
const mainDomain = parts.length >= 3 ? parts.slice(1).join('.') : window.location.hostname
|
||||
setWarningTimeout(`"${name}" kurumuna ait kayıt bulunamadı. Ana sayfaya yönlendiriliyorsunuz...`)
|
||||
setTimeout(() => {
|
||||
window.location.href = `${window.location.protocol}//${mainDomain}`
|
||||
}, 3000)
|
||||
}
|
||||
|
||||
const subDomainName = getSubdomain()
|
||||
useEffect(() => {
|
||||
if (subDomainName) {
|
||||
setTenantName(subDomainName)
|
||||
fetchDataByName(subDomainName, true)
|
||||
}
|
||||
}, [subDomainName])
|
||||
|
||||
const tenantStyle: React.CSSProperties | undefined =
|
||||
subDomainName && subDomainName !== defaultDomain
|
||||
? {
|
||||
opacity: 0,
|
||||
position: 'absolute',
|
||||
pointerEvents: 'none',
|
||||
height: 0,
|
||||
margin: 0,
|
||||
padding: 0,
|
||||
border: 'none',
|
||||
}
|
||||
: undefined
|
||||
|
||||
const findUiVersion = async () => {
|
||||
try {
|
||||
const res = await fetch(`/version.json?ts=${Date.now()}`)
|
||||
|
|
@ -246,22 +186,7 @@ const Login = () => {
|
|||
<p>{translate('::Abp.Account.WelcomeBack.Message')}</p>
|
||||
</div>
|
||||
|
||||
{isMultiTenant && (
|
||||
<>
|
||||
<label className="form-label mb-2" style={tenantStyle}>
|
||||
{translate('::Organization')}
|
||||
</label>
|
||||
<div className="mb-4">
|
||||
<Input
|
||||
placeholder={translate('::Organization')}
|
||||
value={tenantName}
|
||||
onChange={(e) => setTenantName(e.target.value)}
|
||||
style={tenantStyle}
|
||||
aria-hidden={subDomainName && subDomainName !== defaultDomain ? 'true' : 'false'}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
<TenantSelector />
|
||||
<div>
|
||||
<Formik
|
||||
initialValues={{
|
||||
|
|
@ -289,7 +214,7 @@ const Login = () => {
|
|||
name="userName"
|
||||
placeholder={translate('::Abp.Account.EmailAddress')}
|
||||
component={Input}
|
||||
inputClassName="dark:bg-gray-900 dark:text-gray-100"
|
||||
className="dark:bg-gray-900 dark:text-gray-100"
|
||||
/>
|
||||
</FormItem>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import ActionLink from '@/components/shared/ActionLink'
|
||||
import PasswordInput from '@/components/shared/PasswordInput'
|
||||
import TenantSelector from '@/components/shared/TenantSelector'
|
||||
import Alert from '@/components/ui/Alert'
|
||||
import Button from '@/components/ui/Button'
|
||||
import { FormContainer, FormItem } from '@/components/ui/Form'
|
||||
|
|
@ -83,6 +84,7 @@ const Register = () => {
|
|||
{error}
|
||||
</Alert>
|
||||
)}
|
||||
<TenantSelector />
|
||||
<Formik
|
||||
initialValues={{
|
||||
email: '',
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ type ResetPasswordFormSchema = {
|
|||
}
|
||||
|
||||
const validationSchema = Yup.object().shape({
|
||||
password: Yup.string().required('Please enter your password'),
|
||||
password: Yup.string().required(),
|
||||
confirmPassword: Yup.string().oneOf([Yup.ref('password')], 'Your passwords do not match'),
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import useAccount from '@/utils/hooks/useAccount'
|
|||
import { Alert, Button, FormContainer, FormItem, Input } from '@/components/ui'
|
||||
import { Field, Form, Formik } from 'formik'
|
||||
import * as Yup from 'yup'
|
||||
import { ActionLink } from '@/components/shared'
|
||||
import { ActionLink, TenantSelector } from '@/components/shared'
|
||||
import { ROUTES_ENUM } from '@/routes/route.constant'
|
||||
import { store } from '@/store'
|
||||
import Captcha from '@/components/shared/Captcha'
|
||||
|
|
@ -57,6 +57,7 @@ const SendConfirmationCode = () => {
|
|||
{error}
|
||||
</Alert>
|
||||
)}
|
||||
<TenantSelector />
|
||||
<Formik
|
||||
initialValues={{
|
||||
email: userName,
|
||||
|
|
|
|||
Loading…
Reference in a new issue