diff --git a/api/src/Sozsoft.Platform.Domain/Entities/Tenant/Administration/Website/PaymentMethod.cs b/api/src/Sozsoft.Platform.Domain/Entities/Tenant/Administration/Website/PaymentMethod.cs index 1edac03..7c0c712 100644 --- a/api/src/Sozsoft.Platform.Domain/Entities/Tenant/Administration/Website/PaymentMethod.cs +++ b/api/src/Sozsoft.Platform.Domain/Entities/Tenant/Administration/Website/PaymentMethod.cs @@ -12,6 +12,8 @@ public class PaymentMethod : FullAuditedEntity, IMultiTenant public decimal Commission { get; set; } public string Logo { get; set; } + Guid? IMultiTenant.TenantId => TenantId; + public PaymentMethod(string id) { Id = id; diff --git a/api/src/Sozsoft.Platform.Domain/Queries/SelectQueryManager.cs b/api/src/Sozsoft.Platform.Domain/Queries/SelectQueryManager.cs index 5c5bcd2..97d9456 100644 --- a/api/src/Sozsoft.Platform.Domain/Queries/SelectQueryManager.cs +++ b/api/src/Sozsoft.Platform.Domain/Queries/SelectQueryManager.cs @@ -401,7 +401,7 @@ public class SelectQueryManager : PlatformDomainService, ISelectQueryManager } else { - whereParts.Add($"\"TenantId\" IS NULL"); + whereParts.Add($"(\"TenantId\" IS NULL OR \"TenantId\" = '{Guid.Empty}')"); } } diff --git a/api/src/Sozsoft.Platform.EntityFrameworkCore/EntityFrameworkCore/PlatformDbContext.cs b/api/src/Sozsoft.Platform.EntityFrameworkCore/EntityFrameworkCore/PlatformDbContext.cs index 5315c93..d82cd55 100644 --- a/api/src/Sozsoft.Platform.EntityFrameworkCore/EntityFrameworkCore/PlatformDbContext.cs +++ b/api/src/Sozsoft.Platform.EntityFrameworkCore/EntityFrameworkCore/PlatformDbContext.cs @@ -756,6 +756,7 @@ public class PlatformDbContext : b.ToTable(TableNameResolver.GetFullTableName(nameof(TableNameEnum.WorkHour)), Prefix.DbSchema); b.ConfigureByConvention(); + b.HasKey(x => new { x.Id, x.TenantId }); b.Property(x => x.Id).HasMaxLength(64); b.Property(x => x.Name).HasMaxLength(64).IsRequired(); b.Property(x => x.StartTime).HasMaxLength(8).IsRequired(); @@ -824,8 +825,8 @@ public class PlatformDbContext : { b.ToTable(TableNameResolver.GetFullTableName(nameof(TableNameEnum.PaymentMethod)), Prefix.DbSchema); b.ConfigureByConvention(); + b.HasKey(x => new { x.Id, x.TenantId }); - b.HasKey(x => x.Id); b.Property(x => x.Name).IsRequired().HasMaxLength(64); b.Property(x => x.Logo).HasMaxLength(32); b.Property(x => x.Commission).HasPrecision(5, 3); diff --git a/api/src/Sozsoft.Platform.EntityFrameworkCore/Migrations/20260302191746_Initial.Designer.cs b/api/src/Sozsoft.Platform.EntityFrameworkCore/Migrations/20260310134051_Initial.Designer.cs similarity index 99% rename from api/src/Sozsoft.Platform.EntityFrameworkCore/Migrations/20260302191746_Initial.Designer.cs rename to api/src/Sozsoft.Platform.EntityFrameworkCore/Migrations/20260310134051_Initial.Designer.cs index a1c053a..d934833 100644 --- a/api/src/Sozsoft.Platform.EntityFrameworkCore/Migrations/20260302191746_Initial.Designer.cs +++ b/api/src/Sozsoft.Platform.EntityFrameworkCore/Migrations/20260310134051_Initial.Designer.cs @@ -13,7 +13,7 @@ using Volo.Abp.EntityFrameworkCore; namespace Sozsoft.Platform.Migrations { [DbContext(typeof(PlatformDbContext))] - [Migration("20260302191746_Initial")] + [Migration("20260310134051_Initial")] partial class Initial { /// @@ -3166,6 +3166,10 @@ namespace Sozsoft.Platform.Migrations b.Property("Id") .HasColumnType("nvarchar(450)"); + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + b.Property("Commission") .HasPrecision(5, 3) .HasColumnType("decimal(5,3)"); @@ -3209,11 +3213,7 @@ namespace Sozsoft.Platform.Migrations .HasMaxLength(64) .HasColumnType("nvarchar(64)"); - b.Property("TenantId") - .HasColumnType("uniqueidentifier") - .HasColumnName("TenantId"); - - b.HasKey("Id"); + b.HasKey("Id", "TenantId"); b.ToTable("Adm_T_PaymentMethod", (string)null); }); @@ -3894,6 +3894,10 @@ namespace Sozsoft.Platform.Migrations .HasMaxLength(64) .HasColumnType("nvarchar(64)"); + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + b.Property("CreationTime") .HasColumnType("datetime2") .HasColumnName("CreationTime"); @@ -3949,10 +3953,6 @@ namespace Sozsoft.Platform.Migrations b.Property("Sunday") .HasColumnType("bit"); - b.Property("TenantId") - .HasColumnType("uniqueidentifier") - .HasColumnName("TenantId"); - b.Property("Thursday") .HasColumnType("bit"); @@ -3962,7 +3962,7 @@ namespace Sozsoft.Platform.Migrations b.Property("Wednesday") .HasColumnType("bit"); - b.HasKey("Id"); + b.HasKey("Id", "TenantId"); b.ToTable("Adm_T_WorkHour", (string)null); }); diff --git a/api/src/Sozsoft.Platform.EntityFrameworkCore/Migrations/20260302191746_Initial.cs b/api/src/Sozsoft.Platform.EntityFrameworkCore/Migrations/20260310134051_Initial.cs similarity index 99% rename from api/src/Sozsoft.Platform.EntityFrameworkCore/Migrations/20260302191746_Initial.cs rename to api/src/Sozsoft.Platform.EntityFrameworkCore/Migrations/20260310134051_Initial.cs index 5522c3c..20a37a6 100644 --- a/api/src/Sozsoft.Platform.EntityFrameworkCore/Migrations/20260302191746_Initial.cs +++ b/api/src/Sozsoft.Platform.EntityFrameworkCore/Migrations/20260310134051_Initial.cs @@ -877,7 +877,7 @@ namespace Sozsoft.Platform.Migrations columns: table => new { Id = table.Column(type: "nvarchar(450)", nullable: false), - TenantId = table.Column(type: "uniqueidentifier", nullable: true), + TenantId = table.Column(type: "uniqueidentifier", nullable: false), Name = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: false), Commission = table.Column(type: "decimal(5,3)", precision: 5, scale: 3, nullable: false), Logo = table.Column(type: "nvarchar(32)", maxLength: 32, nullable: true), @@ -891,7 +891,7 @@ namespace Sozsoft.Platform.Migrations }, constraints: table => { - table.PrimaryKey("PK_Adm_T_PaymentMethod", x => x.Id); + table.PrimaryKey("PK_Adm_T_PaymentMethod", x => new { x.Id, x.TenantId }); }); migrationBuilder.CreateTable( @@ -1036,7 +1036,7 @@ namespace Sozsoft.Platform.Migrations columns: table => new { Id = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: false), - TenantId = table.Column(type: "uniqueidentifier", nullable: true), + TenantId = table.Column(type: "uniqueidentifier", nullable: false), Name = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: false), StartTime = table.Column(type: "datetime2", maxLength: 8, nullable: false), EndTime = table.Column(type: "datetime2", maxLength: 8, nullable: false), @@ -1057,7 +1057,7 @@ namespace Sozsoft.Platform.Migrations }, constraints: table => { - table.PrimaryKey("PK_Adm_T_WorkHour", x => x.Id); + table.PrimaryKey("PK_Adm_T_WorkHour", x => new { x.Id, x.TenantId }); }); migrationBuilder.CreateTable( diff --git a/api/src/Sozsoft.Platform.EntityFrameworkCore/Migrations/PlatformDbContextModelSnapshot.cs b/api/src/Sozsoft.Platform.EntityFrameworkCore/Migrations/PlatformDbContextModelSnapshot.cs index ee5bea1..6a487d2 100644 --- a/api/src/Sozsoft.Platform.EntityFrameworkCore/Migrations/PlatformDbContextModelSnapshot.cs +++ b/api/src/Sozsoft.Platform.EntityFrameworkCore/Migrations/PlatformDbContextModelSnapshot.cs @@ -3163,6 +3163,10 @@ namespace Sozsoft.Platform.Migrations b.Property("Id") .HasColumnType("nvarchar(450)"); + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + b.Property("Commission") .HasPrecision(5, 3) .HasColumnType("decimal(5,3)"); @@ -3206,11 +3210,7 @@ namespace Sozsoft.Platform.Migrations .HasMaxLength(64) .HasColumnType("nvarchar(64)"); - b.Property("TenantId") - .HasColumnType("uniqueidentifier") - .HasColumnName("TenantId"); - - b.HasKey("Id"); + b.HasKey("Id", "TenantId"); b.ToTable("Adm_T_PaymentMethod", (string)null); }); @@ -3891,6 +3891,10 @@ namespace Sozsoft.Platform.Migrations .HasMaxLength(64) .HasColumnType("nvarchar(64)"); + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + b.Property("CreationTime") .HasColumnType("datetime2") .HasColumnName("CreationTime"); @@ -3946,10 +3950,6 @@ namespace Sozsoft.Platform.Migrations b.Property("Sunday") .HasColumnType("bit"); - b.Property("TenantId") - .HasColumnType("uniqueidentifier") - .HasColumnName("TenantId"); - b.Property("Thursday") .HasColumnType("bit"); @@ -3959,7 +3959,7 @@ namespace Sozsoft.Platform.Migrations b.Property("Wednesday") .HasColumnType("bit"); - b.HasKey("Id"); + b.HasKey("Id", "TenantId"); b.ToTable("Adm_T_WorkHour", (string)null); }); diff --git a/api/src/Sozsoft.Platform.EntityFrameworkCore/Seeds/TenantDataSeeder.cs b/api/src/Sozsoft.Platform.EntityFrameworkCore/Seeds/TenantDataSeeder.cs index 4e793d5..46da4b5 100644 --- a/api/src/Sozsoft.Platform.EntityFrameworkCore/Seeds/TenantDataSeeder.cs +++ b/api/src/Sozsoft.Platform.EntityFrameworkCore/Seeds/TenantDataSeeder.cs @@ -13,6 +13,7 @@ using Microsoft.EntityFrameworkCore; using Volo.Abp.Identity; using Volo.Abp.Timing; using System.Collections.Generic; +using Volo.Abp.MultiTenancy; namespace Sozsoft.Platform.Data.Seeds; @@ -267,6 +268,7 @@ public class TenantDataSeeder : IDataSeedContributor, ITransientDependency private readonly OrganizationUnitManager _organizationUnitManager; private readonly IIdentityUserRepository _repositoryUser; private readonly IRepository _productRepository; + private readonly ICurrentTenant _currentTenant; public TenantDataSeeder( IClock clock, @@ -294,7 +296,8 @@ public class TenantDataSeeder : IDataSeedContributor, ITransientDependency IRepository forumCategoryRepository, IRepository currencyRepository, IRepository organizationUnitRepository, - OrganizationUnitManager organizationUnitManager + OrganizationUnitManager organizationUnitManager, + ICurrentTenant currentTenant ) { _clock = clock; @@ -323,6 +326,7 @@ public class TenantDataSeeder : IDataSeedContributor, ITransientDependency _currencyRepository = currencyRepository; _organizationUnitRepository = organizationUnitRepository; _organizationUnitManager = organizationUnitManager; + _currentTenant = currentTenant; } public async Task SeedAsync(DataSeedContext context) @@ -488,7 +492,7 @@ public class TenantDataSeeder : IDataSeedContributor, ITransientDependency foreach (var item in items.PaymentMethods) { - var exists = await _paymentMethodRepository.AnyAsync(x => x.Name == item.Name); + var exists = await _paymentMethodRepository.AnyAsync(x => x.Id == item.Name); if (!exists) { @@ -496,8 +500,9 @@ public class TenantDataSeeder : IDataSeedContributor, ITransientDependency { Name = item.Name, Commission = item.Commission, - Logo = item.Logo - }); + Logo = item.Logo, + TenantId = _currentTenant.Id ?? Guid.Empty + }, autoSave: true); } } @@ -619,12 +624,13 @@ public class TenantDataSeeder : IDataSeedContributor, ITransientDependency foreach (var item in items.WorkHours) { - var exists = await _workHourRepository.AnyAsync(x => x.Name == item.Name); + var exists = await _workHourRepository.AnyAsync(x => x.Id == item.Name); if (!exists) { await _workHourRepository.InsertAsync(new WorkHour(item.Name) { + TenantId = _currentTenant.Id ?? Guid.Empty, Name = item.Name, StartTime = item.StartTime, EndTime = item.EndTime, diff --git a/ui/src/services/platformApi.service.ts b/ui/src/services/platformApi.service.ts index 5fe47a2..39bf216 100644 --- a/ui/src/services/platformApi.service.ts +++ b/ui/src/services/platformApi.service.ts @@ -47,6 +47,27 @@ platformApiService.interceptors.request.use(async (config) => { platformApiService.interceptors.response.use( (response) => response, async (error) => { + // Geçersiz tenant seçilmişse Host olarak tekrar bağlan. + // __tenant header'ı gönderilmiş bir isteğe 404 geliyorsa tenant bulunamadı demektir. + const hasTenantHeader = !!error.config?.headers?.['__tenant'] + const responseText = JSON.stringify(error.response?.data ?? '').toLowerCase() + + const isTenantNotFound = + error.response?.status === 404 && + hasTenantHeader && + responseText.includes('tenant') + + console.log('Found', isTenantNotFound) + console.log('Error', error.response?.data?.error?.code) + + if (isTenantNotFound && !error.config._tenantRetried) { + store.getActions().locale.setTenantName(undefined) + error.config._tenantRetried = true + error.config.headers.delete('__tenant') + error.silent = true + return platformApiService.request(error.config) + } + if (unauthorizedCode.includes(error.response?.status)) { const { signIn, signOut, setIsRefreshing } = store.getActions().auth const { auth } = store.getState() diff --git a/ui/src/views/auth/Login.tsx b/ui/src/views/auth/Login.tsx index c7055d3..d6fcd39 100644 --- a/ui/src/views/auth/Login.tsx +++ b/ui/src/views/auth/Login.tsx @@ -93,6 +93,9 @@ const Login = () => { setError(result.message) } else { setError('') + + //Tenant belirlenmişse + fetchDataByName(tenantName || '') } if (result.status === 'failed') { @@ -155,9 +158,6 @@ const Login = () => { setError('') setMessage('') - //Tenant belirlenmişse - fetchDataByName(tenantName || '') - // Versiyon kontrolü findUiVersion() } @@ -165,25 +165,41 @@ const Login = () => { setSubmitting(false) } - const fetchDataByName = async (name: string) => { + const fetchDataByName = async (name: string, isSubdomain = false) => { if (name) { - const response = await getTenantByNameDetail(name) + try { + const response = await getTenantByNameDetail(name) - if (response.data) { - setTenant({ tenantId: response.data.id, tenantName: response.data.name, menuGroup: response.data.menuGroup }); - } else { + 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) + fetchDataByName(subDomainName, true) } }, [subDomainName])