Düzenleme

This commit is contained in:
Sedat ÖZTÜRK 2025-08-11 09:34:44 +03:00
parent 2be13b33c6
commit 8cc8ed07f9
253 changed files with 50530 additions and 16070 deletions

View file

@ -44,7 +44,7 @@ public static class LanguagesDbContextModelCreatingExtensions
b.Property(a => a.CultureName).HasMaxLength(10).IsRequired(); b.Property(a => a.CultureName).HasMaxLength(10).IsRequired();
b.Property(a => a.ResourceName).HasMaxLength(50); b.Property(a => a.ResourceName).HasMaxLength(50);
b.Property(a => a.Key).HasMaxLength(100); b.Property(a => a.Key).HasMaxLength(100);
b.Property(a => a.Value).HasMaxLength(1000).IsRequired(); b.Property(a => a.Value).HasMaxLength(4000).IsRequired();
}); });
} }
} }

View file

@ -1,7 +1,7 @@
using System; using System;
using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Dtos;
namespace Kurs.Platform.DataSources; namespace Kurs.Platform.AiBots;
public class AiBotDto : FullAuditedEntityDto<Guid> public class AiBotDto : FullAuditedEntityDto<Guid>
{ {

View file

@ -1,6 +1,8 @@
using System; using System;
using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Dtos;
namespace Kurs.Platform.Banks;
public class BankAccountDto : AuditedEntityDto<Guid> public class BankAccountDto : AuditedEntityDto<Guid>
{ {
public string AccountNumber { get; set; } public string AccountNumber { get; set; }

View file

@ -1,6 +1,8 @@
using System; using System;
using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Dtos;
namespace Kurs.Platform.Banks;
public class BankDto : AuditedEntityDto<Guid> public class BankDto : AuditedEntityDto<Guid>
{ {
public string Name { get; set; } public string Name { get; set; }

View file

@ -1,10 +1,10 @@
using System; using System;
using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Dtos;
namespace Kurs.Platform.Blog namespace Kurs.Platform.Blog;
public class BlogCategoryDto : FullAuditedEntityDto<Guid>
{ {
public class BlogCategoryDto : FullAuditedEntityDto<Guid>
{
public Guid? TenantId { get; set; } public Guid? TenantId { get; set; }
public string Name { get; set; } public string Name { get; set; }
public string Slug { get; set; } public string Slug { get; set; }
@ -13,10 +13,10 @@ namespace Kurs.Platform.Blog
public int DisplayOrder { get; set; } public int DisplayOrder { get; set; }
public bool IsActive { get; set; } public bool IsActive { get; set; }
public int PostCount { get; set; } public int PostCount { get; set; }
} }
public class CreateUpdateBlogCategoryDto public class CreateUpdateBlogCategoryDto
{ {
public Guid? TenantId { get; set; } public Guid? TenantId { get; set; }
public string Name { get; set; } public string Name { get; set; }
public string Slug { get; set; } public string Slug { get; set; }
@ -24,5 +24,4 @@ namespace Kurs.Platform.Blog
public string Icon { get; set; } public string Icon { get; set; }
public int DisplayOrder { get; set; } public int DisplayOrder { get; set; }
public bool IsActive { get; set; } public bool IsActive { get; set; }
}
} }

View file

@ -2,10 +2,10 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Dtos;
namespace Kurs.Platform.Blog namespace Kurs.Platform.Blog;
public class BlogPostDto : FullAuditedEntityDto<Guid>
{ {
public class BlogPostDto : FullAuditedEntityDto<Guid>
{
public Guid? TenantId { get; set; } public Guid? TenantId { get; set; }
public string Title { get; set; } public string Title { get; set; }
public string Slug { get; set; } public string Slug { get; set; }
@ -33,17 +33,17 @@ namespace Kurs.Platform.Blog
{ {
Tags = []; Tags = [];
} }
} }
public class AuthorDto public class AuthorDto
{ {
public Guid Id { get; set; } public Guid Id { get; set; }
public string Name { get; set; } public string Name { get; set; }
public string Avatar { get; set; } public string Avatar { get; set; }
} }
public class CreateUpdateBlogPostDto public class CreateUpdateBlogPostDto
{ {
public Guid? TenantId { get; set; } public Guid? TenantId { get; set; }
public string Title { get; set; } public string Title { get; set; }
public string Slug { get; set; } public string Slug { get; set; }
@ -60,10 +60,10 @@ namespace Kurs.Platform.Blog
{ {
Tags = []; Tags = [];
} }
} }
public class BlogPostListDto : EntityDto<Guid> public class BlogPostListDto : EntityDto<Guid>
{ {
public Guid? TenantId { get; set; } public Guid? TenantId { get; set; }
public string Title { get; set; } public string Title { get; set; }
public string Slug { get; set; } public string Slug { get; set; }
@ -82,7 +82,7 @@ namespace Kurs.Platform.Blog
public bool IsPublished { get; set; } public bool IsPublished { get; set; }
public DateTime? PublishedAt { get; set; } public DateTime? PublishedAt { get; set; }
public DateTime CreatedAt { get; set; } public DateTime CreationTime { get; set; }
public List<string> Tags { get; set; } public List<string> Tags { get; set; }
@ -90,5 +90,4 @@ namespace Kurs.Platform.Blog
{ {
Tags = []; Tags = [];
} }
}
} }

View file

@ -4,10 +4,10 @@ using System.Threading.Tasks;
using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services; using Volo.Abp.Application.Services;
namespace Kurs.Platform.Blog namespace Kurs.Platform.Blog;
public interface IBlogAppService : IApplicationService
{ {
public interface IBlogAppService : IApplicationService
{
// Blog Post methods // Blog Post methods
Task<PagedResultDto<BlogPostListDto>> GetPostsAsync(GetBlogPostsInput input); Task<PagedResultDto<BlogPostListDto>> GetPostsAsync(GetBlogPostsInput input);
Task<BlogPostDto> GetPostAsync(Guid id); Task<BlogPostDto> GetPostAsync(Guid id);
@ -24,25 +24,25 @@ namespace Kurs.Platform.Blog
Task<BlogCategoryDto> CreateCategoryAsync(CreateUpdateBlogCategoryDto input); Task<BlogCategoryDto> CreateCategoryAsync(CreateUpdateBlogCategoryDto input);
Task<BlogCategoryDto> UpdateCategoryAsync(Guid id, CreateUpdateBlogCategoryDto input); Task<BlogCategoryDto> UpdateCategoryAsync(Guid id, CreateUpdateBlogCategoryDto input);
Task DeleteCategoryAsync(Guid id); Task DeleteCategoryAsync(Guid id);
} }
public class GetBlogPostsInput : PagedAndSortedResultRequestDto public class GetBlogPostsInput : PagedAndSortedResultRequestDto
{ {
public string Search { get; set; } public string Search { get; set; }
public Guid? CategoryId { get; set; } public Guid? CategoryId { get; set; }
} }
public class SearchBlogPostsInput : PagedAndSortedResultRequestDto public class SearchBlogPostsInput : PagedAndSortedResultRequestDto
{ {
public string Query { get; set; } public string Query { get; set; }
public Guid? CategoryId { get; set; } public Guid? CategoryId { get; set; }
public string Tag { get; set; } public string Tag { get; set; }
public Guid? AuthorId { get; set; } public Guid? AuthorId { get; set; }
public bool? IsPublished { get; set; } public bool? IsPublished { get; set; }
} }
public class BlogStatsDto public class BlogStatsDto
{ {
public int TotalPosts { get; set; } public int TotalPosts { get; set; }
public int PublishedPosts { get; set; } public int PublishedPosts { get; set; }
public int DraftPosts { get; set; } public int DraftPosts { get; set; }
@ -58,5 +58,4 @@ namespace Kurs.Platform.Blog
{ {
PopularTags = new List<string>(); PopularTags = new List<string>();
} }
}
} }

View file

@ -0,0 +1,29 @@
using System;
using Volo.Abp.Application.Dtos;
namespace Kurs.Platform.DeveloperKit;
public class ApiEndpointDto : FullAuditedEntityDto<Guid>
{
public string EntityName { get; set; } = string.Empty;
public string Method { get; set; } = string.Empty;
public string Path { get; set; } = string.Empty;
public string OperationType { get; set; } = string.Empty;
public string CsharpCode { get; set; } = string.Empty;
public bool IsActive { get; set; } = true;
public Guid EntityId { get; set; }
// Navigation property for display purposes
public string? EntityDisplayName { get; set; }
}
public class CreateUpdateApiEndpointDto
{
public string EntityName { get; set; } = string.Empty;
public string Method { get; set; } = string.Empty;
public string Path { get; set; } = string.Empty;
public string OperationType { get; set; } = string.Empty;
public string CsharpCode { get; set; } = string.Empty;
public bool IsActive { get; set; } = true;
public Guid EntityId { get; set; }
}

View file

@ -0,0 +1,27 @@
// Migration DTOs
using System;
using Volo.Abp.Application.Dtos;
namespace Kurs.Platform.DeveloperKit;
public class ApiMigrationDto : AuditedEntityDto<Guid>
{
public Guid EntityId { get; set; }
public string EntityName { get; set; } = string.Empty;
public string FileName { get; set; } = string.Empty;
public string SqlScript { get; set; } = string.Empty;
public string Status { get; set; } = "pending"; // "pending" | "applied" | "failed"
public DateTime? AppliedAt { get; set; }
public string? ErrorMessage { get; set; }
}
public class CreateUpdateApiMigrationDto
{
public Guid EntityId { get; set; }
public string EntityName { get; set; } = string.Empty;
public string FileName { get; set; } = string.Empty;
public string SqlScript { get; set; } = string.Empty;
public string Status { get; set; } = "pending";
public DateTime? AppliedAt { get; set; }
public string? ErrorMessage { get; set; }
}

View file

@ -0,0 +1,24 @@
using System;
using Volo.Abp.Application.Dtos;
namespace Kurs.Platform.DeveloperKit;
public class CustomComponentDto : FullAuditedEntityDto<Guid>
{
public string Name { get; set; } = string.Empty;
public string Code { get; set; } = string.Empty;
public string? Props { get; set; }
public string? Description { get; set; }
public bool IsActive { get; set; } = true;
public string? Dependencies { get; set; } // JSON string of component names
}
public class CreateUpdateCustomComponentDto
{
public string Name { get; set; } = string.Empty;
public string Code { get; set; } = string.Empty;
public string? Props { get; set; }
public string? Description { get; set; }
public bool IsActive { get; set; } = true;
public string? Dependencies { get; set; } // JSON string of component names
}

View file

@ -0,0 +1,59 @@
using System;
using System.Collections.Generic;
using Volo.Abp.Application.Dtos;
namespace Kurs.Platform.DeveloperKit;
public class CustomEntityDto : FullAuditedEntityDto<Guid>
{
public string Name { get; set; } = string.Empty;
public string DisplayName { get; set; } = string.Empty;
public string TableName { get; set; } = string.Empty;
public string? Description { get; set; }
public bool IsActive { get; set; } = true;
public bool HasAuditFields { get; set; } = true;
public bool HasSoftDelete { get; set; } = true;
public string MigrationStatus { get; set; } = "pending";
public Guid? MigrationId { get; set; }
public string EndpointStatus { get; set; } = "pending";
public List<EntityFieldDto> Fields { get; set; } = [];
}
public class CreateUpdateCustomEntityDto
{
public string Name { get; set; } = string.Empty;
public string DisplayName { get; set; } = string.Empty;
public string TableName { get; set; } = string.Empty;
public string? Description { get; set; }
public bool IsActive { get; set; } = true;
public bool HasAuditFields { get; set; } = true;
public bool HasSoftDelete { get; set; } = true;
public List<CreateUpdateCustomEntityFieldDto> Fields { get; set; } = [];
}
public class EntityFieldDto : FullAuditedEntityDto<Guid>
{
public Guid EntityId { get; set; }
public string Name { get; set; } = string.Empty;
public string Type { get; set; } = string.Empty;
public bool IsRequired { get; set; }
public int? MaxLength { get; set; }
public bool IsUnique { get; set; }
public string? DefaultValue { get; set; }
public string? Description { get; set; }
}
public class CreateUpdateCustomEntityFieldDto
{
public Guid? Id { get; set; }
public string Name { get; set; } = string.Empty;
public string Type { get; set; } = string.Empty;
public bool IsRequired { get; set; }
public int? MaxLength { get; set; }
public bool IsUnique { get; set; }
public string? DefaultValue { get; set; }
public string? Description { get; set; }
}

View file

@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
namespace Kurs.Platform.DeveloperKit;
public interface IApiEndpointAppService : ICrudAppService<
ApiEndpointDto,
Guid,
PagedAndSortedResultRequestDto,
CreateUpdateApiEndpointDto>
{
Task<List<ApiEndpointDto>> GetActiveEndpointsAsync();
Task<List<ApiEndpointDto>> GetEndpointsByEntityAsync(Guid entityId);
Task<PagedResultDto<ApiEndpointDto>> GenerateCrudEndpointsAsync(Guid entityId);
}

View file

@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
namespace Kurs.Platform.DeveloperKit;
public interface IApiMigrationAppService : ICrudAppService<
ApiMigrationDto,
Guid,
PagedAndSortedResultRequestDto,
CreateUpdateApiMigrationDto>
{
Task<ApiMigrationDto> ApplyMigrationAsync(Guid id);
Task<List<ApiMigrationDto>> GetPendingMigrationsAsync();
Task<ApiMigrationDto> GenerateMigrationAsync(Guid entityId);
}

View file

@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
namespace Kurs.Platform.DeveloperKit;
public interface ICustomComponentAppService : ICrudAppService<
CustomComponentDto,
Guid,
PagedAndSortedResultRequestDto,
CreateUpdateCustomComponentDto>
{
Task<List<CustomComponentDto>> GetActiveComponentsAsync();
}

View file

@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
namespace Kurs.Platform.DeveloperKit;
public interface ICustomEntityAppService : ICrudAppService<
CustomEntityDto,
Guid,
PagedAndSortedResultRequestDto,
CreateUpdateCustomEntityDto>
{
Task<List<CustomEntityDto>> GetActiveEntitiesAsync();
Task<CustomEntityDto> ToggleActiveStatusAsync(Guid id);
}

View file

@ -0,0 +1,12 @@
using System;
using Volo.Abp.Application.Dtos;
namespace Kurs.Platform.ListForms;
public class ListFormsImportDto : AuditedEntityDto<Guid>
{
public string ListFormCode { get; set; }
public string BlobName { get; set; }
public string Status { get; set; }
public int? TotalRows { get; set; }
}

View file

@ -0,0 +1,16 @@
using System;
using Volo.Abp.Application.Dtos;
namespace Kurs.Platform.ListForms;
public class ListFormImportExecuteDto : AuditedEntityDto<Guid>
{
public Guid ImportId { get; set; }
public string BlobName { get; set; }
public string Status { get; set; }
public int ExecRows { get; set; }
public int ValidRows { get; set; }
public int ErrorRows { get; set; }
public string ErrorsJson { get; set; }
public double Progress { get; set; }
}

View file

@ -7,4 +7,5 @@ public class PermissionCrudDto
public string U { get; set; } public string U { get; set; }
public string D { get; set; } public string D { get; set; }
public string E { get; set; } public string E { get; set; }
public string I { get; set; }
} }

View file

@ -12,11 +12,13 @@ public class CreateUpdateTenantInput
public string AdminPassword { get; set; } public string AdminPassword { get; set; }
public string ConnectionString { get; set; } public string ConnectionString { get; set; }
public string InstitutionName { get; set; } public string InstitutionName { get; set; }
public string Founder { get; set; }
public long VknTckn { get; set; } public long VknTckn { get; set; }
public string TaxOffice { get; set; } public string TaxOffice { get; set; }
public string Address { get; set; } public string Address { get; set; }
public string Address2 { get; set; } public string Address2 { get; set; }
public string District { get; set; } public string District { get; set; }
public string Country { get; set; }
public string City { get; set; } public string City { get; set; }
public string PostalCode { get; set; } public string PostalCode { get; set; }
public long Phone { get; set; } public long Phone { get; set; }

View file

@ -0,0 +1,9 @@
namespace Kurs.Platform.ListForms.ImportManager;
public class ColumnMappingDto
{
public string SourceColumn { get; set; } // CSV/Excel'deki sütun adı
public string TargetField { get; set; } // Hedef Entity içindeki alan
public bool IsRequired { get; set; }
public string DataType { get; set; } // "string", "date", "number", "boolean"
}

View file

@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
namespace Kurs.Platform.ListForms.ImportManager;
public class ExecuteImportRequest
{
public Guid SessionId { get; set; }
public string ListFormCode { get; set; }
public List<Dictionary<string, object>> SelectedRowsData { get; set; }
public List<int> SelectedRowIndices { get; set; }
}

View file

@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using Kurs.Platform.ListForms;
namespace Kurs.Platform.ListForms.ImportManager;
public class GenerateTemplateInput
{
public string GridName { get; set; }
public string Title { get; set; }
public List<ColumnFormatDto> ColumnFormats { get; set; }
public string Format { get; set; } // 'excel' or 'csv'
}
public class ExportDataInput
{
public string GridName { get; set; }
public List<ColumnFormatDto> ColumnFormats { get; set; }
public string Format { get; set; }
public Dictionary<string, object> Filters { get; set; }
}

View file

@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp.Content;
namespace Kurs.Platform.ListForms.ImportManager;
public interface IImportAppService
{
Task<ListFormsImportDto> CreateAsync(string name, IRemoteStreamContent file);
Task<ListFormsImportDto> GetAsync(Guid sessionId);
Task<List<ListFormsImportDto>> GetListByListFormCodeAsync(string name);
Task<ListFormsImportDto> UpdateAsync(Guid sessionId, ListFormsImportDto input);
Task<ListFormImportExecuteDto> ExecuteAsync(ExecuteImportRequest request);
Task DeleteAsync(Guid id);
}

View file

@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
namespace Kurs.Platform.ListForms.ImportManager;
public class ImportPreviewDataDto
{
public Guid SessionId { get; set; }
public List<string> Headers { get; set; } = new();
public List<List<string>> Rows { get; set; } = new(); // raw string olarak dönen veri hücreleri
public int TotalRows { get; set; }
public int SampleSize { get; set; }
public List<ColumnMappingDto> ColumnMappings { get; set; } = new();
public List<ImportValidationErrorDto> ValidationResults { get; set; } = new();
}

View file

@ -0,0 +1,8 @@
public class ImportValidationErrorDto
{
public int Row { get; set; }
public string Column { get; set; }
public string Message { get; set; }
public string Value { get; set; }
public string Severity { get; set; } // örn: "error", "warning"
}

View file

@ -0,0 +1,10 @@
using System;
using Kurs.Platform.ListForms.Select;
namespace Kurs.Platform.ListForms.ImportManager;
public class PreviewInputDto
{
public Guid SessionId { get; set; }
public GridDto GridDto { get; set; }
}

View file

@ -0,0 +1,9 @@
using Volo.Abp.Application.Dtos;
namespace Kurs.Platform.Orders;
public class InstallmentOptionDto : EntityDto<int>
{
public string Name { get; set; }
public decimal Commission { get; set; }
}

View file

@ -0,0 +1,32 @@
using System;
using System.Collections.Generic;
using Kurs.Platform.Tenants;
using Volo.Abp.Application.Dtos;
namespace Kurs.Platform.Orders;
public class OrderDto : EntityDto<Guid>
{
public CustomTenantDto Tenant { get; set; }
public List<OrderItemDto> Items { get; set; }
public decimal Subtotal { get; set; }
public decimal Commission { get; set; }
public decimal Total { get; set; }
public string PaymentMethod { get; set; }
public int? Installments { get; set; }
public string? InstallmentName { get; set; }
public Dictionary<string, object> PaymentData { get; set; }
}
public class OrderItemDto
{
public Guid ProductId { get; set; }
public ProductDto Product { get; set; }
public string BillingCycle { get; set; } // monthly | yearly
public int Quantity { get; set; }
public decimal TotalPrice { get; set; }
}

View file

@ -0,0 +1,10 @@
using Volo.Abp.Application.Dtos;
namespace Kurs.Platform.Orders;
public class PaymentMethodDto : EntityDto<string>
{
public string Name { get; set; }
public decimal Commission { get; set; }
public string Logo { get; set; }
}

View file

@ -0,0 +1,20 @@
using System;
using Volo.Abp.Application.Dtos;
namespace Kurs.Platform.Orders;
public class ProductDto : EntityDto<Guid>
{
public string Name { get; set; }
public string Description { get; set; }
public string Category { get; set; }
public int Order { get; set; }
public decimal? MonthlyPrice { get; set; }
public decimal? YearlyPrice { get; set; }
public bool IsQuantityBased { get; set; }
public string ImageUrl { get; set; }
public string Unit =>
MonthlyPrice.HasValue && YearlyPrice.HasValue && MonthlyPrice != YearlyPrice
? "monthly"
: "yearly";
}

View file

@ -1,14 +1,14 @@
using System; using System;
using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Dtos;
namespace Kurs.Platform.Routes namespace Kurs.Platform.Routes;
public class RouteDto : EntityDto<Guid>
{ {
public class RouteDto : EntityDto<Guid>
{
public string Key { get; set; } public string Key { get; set; }
public string Path { get; set; } public string Path { get; set; }
public string ComponentPath { get; set; } public string ComponentPath { get; set; }
public string RouteType { get; set; } public string RouteType { get; set; }
public string[] Authority { get; set; } public string[] Authority { get; set; }
}
} }

View file

@ -0,0 +1,26 @@
using System;
namespace Kurs.Platform.Tenants;
public class CustomTenantDto
{
public string Name { get; set; }
public bool IsActive { get; set; }
public Guid? Id { get; set; }
public string InstitutionName { get; set; }
public string Founder { get; set; }
public long VknTckn { get; set; }
public string TaxOffice { get; set; }
public string Address { get; set; }
public string Address2 { get; set; }
public string District { get; set; }
public string Country { get; set; }
public string City { get; set; }
public string PostalCode { get; set; }
public long Phone { get; set; }
public long Mobile { get; set; }
public long Fax { get; set; }
public string Email { get; set; }
public string Website { get; set; }
}

View file

@ -1,4 +1,5 @@
using System; using System;
using Kurs.Platform.AiBots;
using Kurs.Platform.Entities; using Kurs.Platform.Entities;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Dtos;

View file

@ -1,4 +1,5 @@
using AutoMapper; using AutoMapper;
using Kurs.Platform.AiBots;
using Kurs.Platform.Entities; using Kurs.Platform.Entities;
namespace Kurs.Platform.DataSources; namespace Kurs.Platform.DataSources;

View file

@ -250,7 +250,7 @@ INSERT INTO [dbo].[Orders]
Guid? TenantId Guid? TenantId
string Name string Name
string Description string Description
string Url -> https://kurs-api.sozsoft.com/api/app/dinamik/yxfgu string Url -> https://api.sozsoft.com/api/app/dinamik/yxfgu
string Method -> GET string Method -> GET
string Params = [ string Params = [
{ Type: 'Static', Name: 'StartDate', DefaultValue: '234' }, { Type: 'Static', Name: 'StartDate', DefaultValue: '234' },
@ -266,17 +266,17 @@ string Permissions = [
] ]
Query Parameter Query Parameter
URL: https://kurs-api.sozsoft.com/api/app/dinamik/yxfgu URL: https://api.sozsoft.com/api/app/dinamik/yxfgu
Method: GET Method: GET
Parameters: ?StartDate=2024-12-31&EndDate=2025-12-31 Parameters: ?StartDate=2024-12-31&EndDate=2025-12-31
Path Parameter Path Parameter
URL: https://kurs-api.sozsoft.com/api/app/dinamik/yxfgu/fatura/467/kalem/357 URL: https://api.sozsoft.com/api/app/dinamik/yxfgu/fatura/467/kalem/357
Method: GET Method: GET
Parameters: FaturaId=467 Parameters: FaturaId=467
Body Parameter Body Parameter
URL: https://kurs-api.sozsoft.com/api/app/dinamik/yxfgu?UrunId=5 URL: https://api.sozsoft.com/api/app/dinamik/yxfgu?UrunId=5
Method: POST Method: POST
Parameters: ?StartDate=2024-12-31&EndDate=2025-12-31 Parameters: ?StartDate=2024-12-31&EndDate=2025-12-31
Body: { Tutar: 2000, Tarih: '2024-12-31' } Body: { Tutar: 2000, Tarih: '2024-12-31' }

View file

@ -0,0 +1,243 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Kurs.Platform.DeveloperKit;
using Kurs.Platform.Entities;
using Microsoft.EntityFrameworkCore;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
using Volo.Abp.Domain.Repositories;
namespace Platform.Api.Application;
public class ApiEndpointAppService : CrudAppService<
ApiEndpoint,
ApiEndpointDto,
Guid,
PagedAndSortedResultRequestDto,
CreateUpdateApiEndpointDto>, IApiEndpointAppService
{
private readonly IRepository<CustomEntity, Guid> _entityRepository;
private readonly IRepository<ApiMigration, Guid> _migrationRepository;
private readonly IRepository<ApiEndpoint, Guid> _endpointRepository;
public ApiEndpointAppService(
IRepository<ApiEndpoint, Guid> repository,
IRepository<CustomEntity, Guid> entityRepository,
IRepository<ApiMigration, Guid> migrationRepository,
IRepository<ApiEndpoint, Guid> endpointRepository)
: base(repository)
{
_entityRepository = entityRepository;
_migrationRepository = migrationRepository;
_endpointRepository = endpointRepository;
}
public virtual async Task<List<ApiEndpointDto>> GetActiveEndpointsAsync()
{
var endpoints = await Repository.GetListAsync(x => x.IsActive);
return await MapToGetListOutputDtosAsync(endpoints);
}
public virtual async Task<List<ApiEndpointDto>> GetEndpointsByEntityAsync(Guid entityId)
{
var endpoints = await _endpointRepository.GetListAsync(x => x.EntityId == entityId);
return ObjectMapper.Map<List<ApiEndpoint>, List<ApiEndpointDto>>(endpoints);
}
public virtual async Task<PagedResultDto<ApiEndpointDto>> GenerateCrudEndpointsAsync(Guid entityId)
{
// Entity + Fields
var entityQueryable = await _entityRepository.GetQueryableAsync();
var entity = await entityQueryable
.Include(x => x.Fields)
.FirstOrDefaultAsync(x => x.Id == entityId);
if (entity == null)
{
throw new Exception($"Entity with ID {entityId} not found");
}
// Migration kontrolü
var migrationQueryable = await _migrationRepository.GetQueryableAsync();
var migration = await migrationQueryable
.Where(x => x.EntityId == entityId && x.Status == "applied")
.FirstOrDefaultAsync();
if (migration == null)
{
throw new Exception($"No applied migration found for entity {entity.Name}. Please apply migration first.");
}
// CRUD endpointleri oluştur
var endpoints = new List<ApiEndpoint>();
var entityName = entity.Name;
var entityDisplayName = entity.DisplayName;
endpoints.Add(new ApiEndpoint
{
EntityId = entityId,
EntityName = entityName,
Method = "GET",
Path = $"/api/app/dynamic/{entityName.ToLower()}",
OperationType = "GetList",
IsActive = true,
CsharpCode = GenerateGetAllCode(entityName, entityDisplayName)
});
endpoints.Add(new ApiEndpoint
{
EntityId = entityId,
EntityName = entityName,
Method = "GET",
Path = $"/api/app/dynamic/{entityName.ToLower()}/{{id}}",
OperationType = "GetById",
IsActive = true,
CsharpCode = GenerateGetByIdCode(entityName, entityDisplayName)
});
endpoints.Add(new ApiEndpoint
{
EntityId = entityId,
EntityName = entityName,
Method = "POST",
Path = $"/api/app/dynamic/{entityName.ToLower()}",
OperationType = "Create",
IsActive = true,
CsharpCode = GenerateCreateCode(entityName, entityDisplayName)
});
endpoints.Add(new ApiEndpoint
{
EntityId = entityId,
EntityName = entityName,
Method = "PUT",
Path = $"/api/app/dynamic/{entityName.ToLower()}/{{id}}",
OperationType = "Update",
IsActive = true,
CsharpCode = GenerateUpdateCode(entityName, entityDisplayName)
});
endpoints.Add(new ApiEndpoint
{
EntityId = entityId,
EntityName = entityName,
Method = "DELETE",
Path = $"/api/app/dynamic/{entityName.ToLower()}/{{id}}",
OperationType = "Delete",
IsActive = true,
CsharpCode = GenerateDeleteCode(entityName, entityDisplayName)
});
// Var olanları sil
var existingEndpoints = await _endpointRepository
.GetListAsync(x => x.EntityId == entityId);
await _endpointRepository.DeleteManyAsync(existingEndpoints);
// Yeni endpointleri ekle
await _endpointRepository.InsertManyAsync(endpoints, autoSave: true);
// Entity endpoint durumu güncelle
entity.EndpointStatus = "applied";
await _entityRepository.UpdateAsync(entity, autoSave: true);
var result = ObjectMapper.Map<List<ApiEndpoint>, List<ApiEndpointDto>>(endpoints);
return new PagedResultDto<ApiEndpointDto>
{
Items = result,
TotalCount = result.Count
};
}
private string GenerateGetAllCode(string entityName, string displayName)
{
return $@"[HttpGet]
public async Task<ActionResult<List<{entityName}>>> GetAll{entityName}sAsync()
{{
var entities = await _context.{entityName}s.ToListAsync();
return Ok(entities);
}}";
}
private string GenerateGetByIdCode(string entityName, string displayName)
{
return $@"[HttpGet(""{{id}}"")]
public async Task<ActionResult<{entityName}>> Get{entityName}Async(Guid id)
{{
var entity = await _context.{entityName}s.FindAsync(id);
if (entity == null)
{{
return NotFound($""{displayName} with ID {{id}} not found"");
}}
return Ok(entity);
}}";
}
private string GenerateCreateCode(string entityName, string displayName)
{
return $@"[HttpPost]
public async Task<ActionResult<{entityName}>> Create{entityName}Async({entityName} {entityName.ToLower()})
{{
_context.{entityName}s.Add({entityName.ToLower()});
await _context.SaveChangesAsync();
return CreatedAtAction(nameof(Get{entityName}Async), new {{ id = {entityName.ToLower()}.Id }}, {entityName.ToLower()});
}}";
}
private string GenerateUpdateCode(string entityName, string displayName)
{
return $@"[HttpPut(""{{id}}"")]
public async Task<IActionResult> Update{entityName}Async(Guid id, {entityName} {entityName.ToLower()})
{{
if (id != {entityName.ToLower()}.Id)
{{
return BadRequest(""ID mismatch"");
}}
_context.Entry({entityName.ToLower()}).State = EntityState.Modified;
try
{{
await _context.SaveChangesAsync();
}}
catch (DbUpdateConcurrencyException)
{{
if (!await {entityName}ExistsAsync(id))
{{
return NotFound($""{displayName} with ID {{id}} not found"");
}}
throw;
}}
return NoContent();
}}";
}
private string GenerateDeleteCode(string entityName, string displayName)
{
return $@"[HttpDelete(""{{id}}"")]
public async Task<IActionResult> Delete{entityName}Async(Guid id)
{{
var {entityName.ToLower()} = await _context.{entityName}s.FindAsync(id);
if ({entityName.ToLower()} == null)
{{
return NotFound($""{displayName} with ID {{id}} not found"");
}}
_context.{entityName}s.Remove({entityName.ToLower()});
await _context.SaveChangesAsync();
return NoContent();
}}
private async Task<bool> {entityName}ExistsAsync(Guid id)
{{
return await _context.{entityName}s.AnyAsync(e => e.Id == id);
}}";
}
}

View file

@ -0,0 +1,206 @@
using Microsoft.EntityFrameworkCore;
using Volo.Abp.Application.Services;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.Application.Dtos;
using System.Text;
using Volo.Abp.Domain.Entities;
using Kurs.Platform.Entities;
using Kurs.Platform.DeveloperKit;
using System;
using System.Threading.Tasks;
using System.Collections.Generic;
using System.Linq;
using Kurs.Platform.Domain.DeveloperKit;
namespace Platform.Api.Application;
public class ApiMigrationAppService : CrudAppService<
ApiMigration,
ApiMigrationDto,
Guid,
PagedAndSortedResultRequestDto,
CreateUpdateApiMigrationDto>, IApiMigrationAppService
{
private readonly IRepository<ApiMigration, Guid> _migrationRepository;
private readonly IRepository<CustomEntity, Guid> _entityRepository;
private readonly IRepository<CustomEntity, Guid> _fieldRepository;
private readonly IApiMigrationRepository _customSqlExecutor;
public ApiMigrationAppService(
IRepository<ApiMigration, Guid> migrationRepository,
IRepository<CustomEntity, Guid> entityRepository,
IRepository<CustomEntity, Guid> fieldRepository,
IApiMigrationRepository customSqlExecutor
) : base(migrationRepository)
{
_migrationRepository = migrationRepository;
_entityRepository = entityRepository;
_fieldRepository = fieldRepository;
_customSqlExecutor = customSqlExecutor;
}
public virtual async Task<ApiMigrationDto> ApplyMigrationAsync(Guid id)
{
var migration = await _migrationRepository.GetAsync(id);
try
{
await _customSqlExecutor.ExecuteSqlAsync(migration.SqlScript);
migration.Status = "applied";
migration.AppliedAt = DateTime.UtcNow;
migration.ErrorMessage = null;
await _migrationRepository.UpdateAsync(migration, autoSave: true);
var entity = await _entityRepository.GetAsync(migration.EntityId);
entity.MigrationStatus = "applied";
await _entityRepository.UpdateAsync(entity, autoSave: true);
return ObjectMapper.Map<ApiMigration, ApiMigrationDto>(migration);
}
catch (Exception ex)
{
migration.Status = "failed";
migration.ErrorMessage = ex.Message;
await _migrationRepository.UpdateAsync(migration, autoSave: true);
var entity = await _entityRepository.GetAsync(migration.EntityId);
entity.MigrationStatus = "failed";
await _entityRepository.UpdateAsync(entity, autoSave: true);
throw;
}
}
public virtual async Task<List<ApiMigrationDto>> GetPendingMigrationsAsync()
{
var queryable = await _migrationRepository.GetQueryableAsync();
var pending = await queryable
.Where(m => m.Status == "pending")
.OrderBy(m => m.CreationTime)
.ToListAsync();
return ObjectMapper.Map<List<ApiMigration>, List<ApiMigrationDto>>(pending);
}
public virtual async Task<ApiMigrationDto> GenerateMigrationAsync(Guid entityId)
{
var queryable = await _entityRepository.GetQueryableAsync();
var entity = await queryable
.Include(x => x.Fields)
.FirstOrDefaultAsync(x => x.Id == entityId);
if (entity == null)
throw new EntityNotFoundException($"CustomEntity with id {entityId} not found");
var fileName = $"{DateTime.UtcNow:yyyyMMddHHmmss}_Create{entity.Name}Table.sql";
var sqlScript = GenerateSqlScript(entity);
var migration = new ApiMigration
{
EntityId = entityId,
EntityName = entity.Name,
FileName = fileName,
SqlScript = sqlScript,
Status = "pending"
};
migration = await _migrationRepository.InsertAsync(migration, autoSave: true);
entity.MigrationId = migration.Id;
entity.MigrationStatus = "pending";
await _entityRepository.UpdateAsync(entity, autoSave: true);
return ObjectMapper.Map<ApiMigration, ApiMigrationDto>(migration);
}
private string GenerateSqlScript(CustomEntity entity)
{
if (entity.Fields == null || !entity.Fields.Any())
throw new InvalidOperationException($"Entity '{entity.Name}' does not have any fields defined.");
var sb = new StringBuilder();
sb.AppendLine($@"/*
# Create {entity.DisplayName} table
1. New Table
- [{entity.TableName}]");
foreach (var field in entity.Fields)
{
sb.AppendLine($" - [{field.Name}] ({field.Type}{(field.IsRequired ? ", required" : "")})");
}
sb.AppendLine("*/");
sb.AppendLine($"\nIF OBJECT_ID(N'{entity.TableName}', N'U') IS NULL");
sb.AppendLine($"CREATE TABLE [{entity.TableName}] (");
sb.AppendLine(" [Id] UNIQUEIDENTIFIER PRIMARY KEY DEFAULT NEWID(),");
foreach (var field in entity.Fields)
{
var sqlType = GetSqlType(field.Type, field.MaxLength);
sb.Append($" [{field.Name}] {sqlType}");
if (field.IsRequired)
sb.Append(" NOT NULL");
if (!string.IsNullOrWhiteSpace(field.DefaultValue))
sb.Append($" DEFAULT {FormatDefaultValue(field.Type, field.DefaultValue)}");
sb.AppendLine(",");
}
if (entity.HasAuditFields)
{
sb.AppendLine(" [CreationTime] DATETIME2 DEFAULT SYSUTCDATETIME() NOT NULL,");
sb.AppendLine(" [CreatorId] UNIQUEIDENTIFIER NULL,");
sb.AppendLine(" [LastModificationTime] DATETIME2 DEFAULT SYSUTCDATETIME() NOT NULL,");
sb.AppendLine(" [LastModifierId] UNIQUEIDENTIFIER NULL,");
}
if (entity.HasSoftDelete)
{
sb.AppendLine(" [IsDeleted] BIT DEFAULT 0 NOT NULL,");
sb.AppendLine(" [DeleterId] UNIQUEIDENTIFIER NULL,");
sb.AppendLine(" [DeletionTime] DATETIME2 DEFAULT SYSUTCDATETIME() NOT NULL,");
}
// Remove last comma
var script = sb.ToString().TrimEnd(',', '\r', '\n');
script += "\n);\n";
return script;
}
private string GetSqlType(string fieldType, int? maxLength)
{
return fieldType.ToLower() switch
{
"string" => maxLength.HasValue ? $"NVARCHAR({maxLength.Value})" : "NVARCHAR(MAX)",
"number" => "INT",
"decimal" => "DECIMAL(18, 2)",
"boolean" => "BIT",
"date" => "DATETIME2",
"guid" => "UNIQUEIDENTIFIER",
_ => "NVARCHAR(MAX)"
};
}
private string FormatDefaultValue(string fieldType, string defaultValue)
{
return fieldType.ToLower() switch
{
"string" => $"N'{defaultValue}'",
"date" => $"'{defaultValue}'", // ISO format beklenir
"guid" => $"'{defaultValue}'",
"boolean" => (defaultValue.ToLower() == "true" || defaultValue == "1") ? "1" : "0",
_ => defaultValue
};
}
}

View file

@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Kurs.Platform.DeveloperKit;
using Kurs.Platform.Entities;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
using Volo.Abp.Domain.Repositories;
namespace Platform.Api.Application;
public class CustomComponentAppService : CrudAppService<
CustomComponent,
CustomComponentDto,
Guid,
PagedAndSortedResultRequestDto,
CreateUpdateCustomComponentDto>, ICustomComponentAppService
{
public CustomComponentAppService(IRepository<CustomComponent, Guid> repository) : base(repository)
{
}
public async Task<List<CustomComponentDto>> GetActiveComponentsAsync()
{
var components = await Repository.GetListAsync(x => x.IsActive);
return await MapToGetListOutputDtosAsync(components);
}
}

View file

@ -0,0 +1,236 @@
using Microsoft.EntityFrameworkCore;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.Domain.Entities;
using System.Text;
using Kurs.Platform.Entities;
using Kurs.Platform.DeveloperKit;
using System;
using System.Threading.Tasks;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Extensions.Logging;
namespace Platform.Api.Application;
public class CustomEntityAppService : CrudAppService<
CustomEntity,
CustomEntityDto,
Guid,
PagedAndSortedResultRequestDto,
CreateUpdateCustomEntityDto>, ICustomEntityAppService
{
private readonly IRepository<CustomEntity, Guid> _repository;
private readonly IRepository<ApiMigration, Guid> _migrationRepository;
private readonly IRepository<ApiEndpoint, Guid> _endpointRepository;
private readonly IRepository<CustomEntityField, Guid> _fieldRepository;
public CustomEntityAppService(
IRepository<CustomEntity, Guid> repository,
IRepository<ApiMigration, Guid> migrationRepository,
IRepository<ApiEndpoint, Guid> endpointRepository,
IRepository<CustomEntityField, Guid> fieldRepository) : base(repository)
{
_repository = repository;
_migrationRepository = migrationRepository;
_endpointRepository = endpointRepository;
}
public override async Task<PagedResultDto<CustomEntityDto>> GetListAsync(PagedAndSortedResultRequestDto input)
{
var query = await _repository.GetQueryableAsync();
var fullQuery = query.Include(x => x.Fields);
var totalCount = await fullQuery.CountAsync();
var entities = await fullQuery
.OrderBy(x => x.CreationTime)
.Skip(input.SkipCount)
.Take(input.MaxResultCount)
.ToListAsync();
var dtos = ObjectMapper.Map<List<CustomEntity>, List<CustomEntityDto>>(entities);
return new PagedResultDto<CustomEntityDto>(totalCount, dtos);
}
public override async Task<CustomEntityDto> GetAsync(Guid id)
{
var query = await _repository.GetQueryableAsync();
var entity = await query
.Include(x => x.Fields)
.FirstOrDefaultAsync(x => x.Id == id);
if (entity == null)
throw new EntityNotFoundException($"CustomEntity with id {id} not found");
return ObjectMapper.Map<CustomEntity, CustomEntityDto>(entity);
}
public async Task<List<CustomEntityDto>> GetActiveEntitiesAsync()
{
var query = await _repository.GetQueryableAsync();
var entities = await query
.Include(x => x.Fields)
.Where(x => x.IsActive)
.ToListAsync();
return ObjectMapper.Map<List<CustomEntity>, List<CustomEntityDto>>(entities);
}
public async Task<CustomEntityDto> ToggleActiveStatusAsync(Guid id)
{
var query = await _repository.GetQueryableAsync();
var entity = await query
.Include(x => x.Fields)
.FirstOrDefaultAsync(x => x.Id == id);
if (entity == null)
throw new EntityNotFoundException($"CustomEntity with id {id} not found");
entity.IsActive = !entity.IsActive;
await _repository.UpdateAsync(entity, autoSave: true);
return ObjectMapper.Map<CustomEntity, CustomEntityDto>(entity);
}
public override async Task<CustomEntityDto> UpdateAsync(Guid id, CreateUpdateCustomEntityDto input)
{
var query = await _repository.GetQueryableAsync();
var entity = await query
.Include(x => x.Fields)
.FirstOrDefaultAsync(e => e.Id == id);
if (entity == null)
throw new EntityNotFoundException(typeof(CustomEntity), id);
entity.Name = input.Name;
entity.DisplayName = input.DisplayName;
entity.TableName = input.TableName;
entity.Description = input.Description;
entity.IsActive = input.IsActive;
entity.HasAuditFields = input.HasAuditFields;
entity.HasSoftDelete = input.HasSoftDelete;
var updatedFields = new List<CustomEntityField>();
foreach (var dtoField in input.Fields)
{
CustomEntityField? existingField = null;
if (dtoField.Id.HasValue)
{
existingField = entity.Fields.FirstOrDefault(f => f.Id == dtoField.Id.Value);
}
if (existingField != null)
{
existingField.Name = dtoField.Name;
existingField.Type = dtoField.Type;
existingField.IsRequired = dtoField.IsRequired;
existingField.MaxLength = dtoField.MaxLength;
existingField.IsUnique = dtoField.IsUnique;
existingField.DefaultValue = dtoField.DefaultValue;
existingField.Description = dtoField.Description;
updatedFields.Add(existingField);
}
else
{
var newField = new CustomEntityField
{
EntityId = entity.Id,
Name = dtoField.Name,
Type = dtoField.Type,
IsRequired = dtoField.IsRequired,
MaxLength = dtoField.MaxLength,
IsUnique = dtoField.IsUnique,
DefaultValue = dtoField.DefaultValue,
Description = dtoField.Description
};
await _fieldRepository.InsertAsync(newField);
updatedFields.Add(newField);
}
}
// Silinecek alanlar
var toRemove = entity.Fields
.Where(existing => updatedFields.All(f => f.Id != existing.Id))
.ToList();
if (toRemove.Any())
{
await _fieldRepository.DeleteManyAsync(toRemove);
}
await _repository.UpdateAsync(entity, autoSave: true);
return ObjectMapper.Map<CustomEntity, CustomEntityDto>(entity);
}
public override async Task<CustomEntityDto> CreateAsync(CreateUpdateCustomEntityDto input)
{
// Entity oluştur
var entity = new CustomEntity
{
Name = input.Name,
DisplayName = input.DisplayName,
TableName = input.TableName,
Description = input.Description,
IsActive = input.IsActive,
HasAuditFields = input.HasAuditFields,
HasSoftDelete = input.HasSoftDelete,
MigrationStatus = "pending"
};
// Fields ekle
foreach (var fieldDto in input.Fields)
{
var field = new CustomEntityField
{
EntityId = entity.Id,
Name = fieldDto.Name,
Type = fieldDto.Type,
IsRequired = fieldDto.IsRequired,
MaxLength = fieldDto.MaxLength,
IsUnique = fieldDto.IsUnique,
DefaultValue = fieldDto.DefaultValue,
Description = fieldDto.Description
};
entity.Fields.Add(field);
}
entity = await _repository.InsertAsync(entity, autoSave: true);
return ObjectMapper.Map<CustomEntity, CustomEntityDto>(entity);
}
public override async Task DeleteAsync(Guid id)
{
// İlgili entity'nin var olup olmadığını kontrol et
var entity = await _repository.GetAsync(id);
// İlgili ApiMigration kayıtlarını sil
var relatedMigrations = await _migrationRepository.GetListAsync(m => m.EntityId == id);
if (relatedMigrations.Any())
{
Logger.LogInformation($"Deleting {relatedMigrations.Count} related migrations for entity {entity.Name} (ID: {id})");
await _migrationRepository.DeleteManyAsync(relatedMigrations);
}
// İlgili ApiEndpoint kayıtlarını sil
var relatedEndpoints = await _endpointRepository.GetListAsync(e => e.EntityId == id);
if (relatedEndpoints.Any())
{
Logger.LogInformation($"Deleting {relatedEndpoints.Count} related API endpoints for entity {entity.Name} (ID: {id})");
await _endpointRepository.DeleteManyAsync(relatedEndpoints);
}
Logger.LogInformation($"Deleting CustomEntity {entity.Name} (ID: {id}) and its fields");
// Ana entity'yi sil (CustomEntityField'lar otomatik silinecek - cascade delete)
await base.DeleteAsync(id);
}
}

View file

@ -0,0 +1,31 @@
using AutoMapper;
using Kurs.Platform.Entities;
namespace Kurs.Platform.DeveloperKit;
public class DeveloperKitAutoMapperProfile : Profile
{
public DeveloperKitAutoMapperProfile()
{
// CustomEntity mappings
CreateMap<CustomEntity, CustomEntityDto>();
CreateMap<CreateUpdateCustomEntityDto, CustomEntity>();
// EntityField mappings
CreateMap<CustomEntityField, EntityFieldDto>();
CreateMap<CreateUpdateCustomEntityFieldDto, CustomEntityField>();
// CustomComponent mappings
CreateMap<CustomComponent, CustomComponentDto>();
CreateMap<CreateUpdateCustomComponentDto, CustomComponent>();
// GeneratedEndpoint mappings
CreateMap<ApiEndpoint, ApiEndpointDto>()
.ForMember(dest => dest.EntityDisplayName, opt => opt.MapFrom(src => src.Entity != null ? src.Entity.DisplayName : null));
CreateMap<CreateUpdateApiEndpointDto, ApiEndpoint>();
// Migration mappings
CreateMap<ApiMigration, ApiMigrationDto>();
CreateMap<CreateUpdateApiMigrationDto, ApiMigration>();
}
}

View file

@ -0,0 +1,75 @@
using Kurs.Platform.Domain.DeveloperKit;
using Kurs.Platform.Entities;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Text.Json;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Application.Services;
using Volo.Abp.Domain.Repositories;
namespace Kurs.Platform.Application;
[RemoteService]
[Route("api/app/dynamic")]
public class DynamicAppService : ApplicationService
{
private readonly IRepository<ApiEndpoint, Guid> _endpointRepository;
private readonly IDynamicEntityManager _dynamicManager;
public DynamicAppService(
IRepository<ApiEndpoint, Guid> endpointRepository,
IDynamicEntityManager dynamicManager)
{
_endpointRepository = endpointRepository;
_dynamicManager = dynamicManager;
}
[HttpGet("{entityName}")]
public async Task<List<object>?> GetEntityListAsync(string entityName)
{
await EnsureEndpointAsync(entityName, "GET", "GetList");
return await _dynamicManager.GetEntityListAsync(entityName);
}
[HttpGet("{entityName}/{id}")]
public async Task<object?> GetEntityByIdAsync(string entityName, Guid id)
{
await EnsureEndpointAsync(entityName, "GET", "GetById");
return await _dynamicManager.GetEntityByIdAsync(entityName, id);
}
[HttpPost("{entityName}")]
public async Task<object?> CreateEntityAsync(string entityName, [FromBody] JsonElement data)
{
await EnsureEndpointAsync(entityName, "POST", "Create");
return await _dynamicManager.CreateEntityAsync(entityName, data);
}
[HttpPut("{entityName}/{id}")]
public async Task<object?> UpdateEntityAsync(string entityName, Guid id, [FromBody] JsonElement data)
{
await EnsureEndpointAsync(entityName, "PUT", "Update");
return await _dynamicManager.UpdateEntityAsync(entityName, id, data);
}
[HttpDelete("{entityName}/{id}")]
public async Task<bool> DeleteEntityAsync(string entityName, Guid id)
{
await EnsureEndpointAsync(entityName, "DELETE", "Delete");
return await _dynamicManager.DeleteEntityAsync(entityName, id);
}
private async Task EnsureEndpointAsync(string entityName, string method, string operation)
{
var exists = await _endpointRepository.AnyAsync(x =>
x.EntityName.ToLower() == entityName.ToLower() &&
x.Method == method &&
x.OperationType == operation &&
x.IsActive);
if (!exists)
throw new UserFriendlyException($"No active endpoint defined for {entityName} {operation}");
}
}

View file

@ -1,6 +1,9 @@
using AutoMapper; using AutoMapper;
using Kurs.Platform.Identity.Dto; using Kurs.Platform.Identity.Dto;
using Kurs.Platform.OrganizationUnits;
using Kurs.Platform.Tenants;
using Volo.Abp.Identity; using Volo.Abp.Identity;
using Volo.Abp.TenantManagement;
namespace Kurs.Platform.Identity; namespace Kurs.Platform.Identity;
@ -9,6 +12,9 @@ public class IdentityAutoMapperProfile : Profile
public IdentityAutoMapperProfile() public IdentityAutoMapperProfile()
{ {
CreateMap<IdentityUser, UserInfoViewModel>(); CreateMap<IdentityUser, UserInfoViewModel>();
CreateMap<OrganizationUnit, OrganizationUnitDto>();
CreateMap<CreateUpdateOrganizationUnitDto, OrganizationUnit>();
CreateMap<Tenant, CustomTenantDto>();
CreateMap<IdentityRoleDto, AssignedRoleViewModel>().ForMember(dest => dest.IsAssigned, opt => opt.Ignore()); CreateMap<IdentityRoleDto, AssignedRoleViewModel>().ForMember(dest => dest.IsAssigned, opt => opt.Ignore());
} }
} }

View file

@ -1,6 +1,7 @@
using AutoMapper; using AutoMapper;
using Kurs.Platform.Entities; using Kurs.Platform.Entities;
using Kurs.Platform.ListForms.Customization; using Kurs.Platform.ListForms.Customization;
using Kurs.Platform.ListForms.ImportManager;
using Kurs.Platform.ListForms.Select; using Kurs.Platform.ListForms.Select;
using Kurs.Platform.Queries; using Kurs.Platform.Queries;
@ -23,8 +24,9 @@ public class ListFormAutoMapperProfile : Profile
CreateMap<CommandColumnDto, CommandColumn>().ReverseMap(); CreateMap<CommandColumnDto, CommandColumn>().ReverseMap();
CreateMap<SubFormDto, SubForm>().ReverseMap(); CreateMap<SubFormDto, SubForm>().ReverseMap();
CreateMap<SubFormRelationDto, SubFormRelation>().ReverseMap(); CreateMap<SubFormRelationDto, SubFormRelation>().ReverseMap();
// CreateMap<EditingFormDto, EditingForm>().ReverseMap();
// CreateMap<EditingFormItemDto, EditingFormItem>().ReverseMap();
CreateMap<ListFormImport, ListFormsImportDto>();
CreateMap<ListFormImportExecute, ListFormImportExecuteDto>();
CreateMap<ImportValidationErrorDto, ImportValidationErrorDto>();
} }
} }

View file

@ -112,13 +112,15 @@ public class ListFormDynamicApiAppService : PlatformAppService, IListFormDynamic
var tenant = await tenantManager.CreateAsync(input.Data.Name); var tenant = await tenantManager.CreateAsync(input.Data.Name);
var entity = await tenantRepository.InsertAsync(tenant, autoSave: true); var entity = await tenantRepository.InsertAsync(tenant, autoSave: true);
entity.SetIsActiveTenant(input.Data.IsActive); entity.SetIsActive(input.Data.IsActive);
entity.SetInstitutionName(input.Data.InstitutionName); entity.SetInstitutionName(input.Data.InstitutionName);
entity.SetFounder(input.Data.Founder);
entity.SetVknTckn(input.Data.VknTckn); entity.SetVknTckn(input.Data.VknTckn);
entity.SetTaxOffice(input.Data.TaxOffice); entity.SetTaxOffice(input.Data.TaxOffice);
entity.SetAddress(input.Data.Address); entity.SetAddress(input.Data.Address);
entity.SetAddress2(input.Data.Address2); entity.SetAddress2(input.Data.Address2);
entity.SetDistrict(input.Data.District); entity.SetDistrict(input.Data.District);
entity.SetCountry(input.Data.Country);
entity.SetCity(input.Data.City); entity.SetCity(input.Data.City);
entity.SetPostalCode(input.Data.PostalCode); entity.SetPostalCode(input.Data.PostalCode);
entity.SetPhone(input.Data.Phone); entity.SetPhone(input.Data.Phone);
@ -143,13 +145,15 @@ public class ListFormDynamicApiAppService : PlatformAppService, IListFormDynamic
?? throw new EntityNotFoundException(L["RecordNotFound"]); ?? throw new EntityNotFoundException(L["RecordNotFound"]);
await tenantManager.ChangeNameAsync(entity, input.Data.Name); await tenantManager.ChangeNameAsync(entity, input.Data.Name);
entity.SetIsActiveTenant(input.Data.IsActive); entity.SetIsActive(input.Data.IsActive);
entity.SetInstitutionName(input.Data.InstitutionName); entity.SetInstitutionName(input.Data.InstitutionName);
entity.SetFounder(input.Data.Founder);
entity.SetVknTckn(input.Data.VknTckn); entity.SetVknTckn(input.Data.VknTckn);
entity.SetTaxOffice(input.Data.TaxOffice); entity.SetTaxOffice(input.Data.TaxOffice);
entity.SetAddress(input.Data.Address); entity.SetAddress(input.Data.Address);
entity.SetAddress2(input.Data.Address2); entity.SetAddress2(input.Data.Address2);
entity.SetDistrict(input.Data.District); entity.SetDistrict(input.Data.District);
entity.SetCountry(input.Data.Country);
entity.SetCity(input.Data.City); entity.SetCity(input.Data.City);
entity.SetPostalCode(input.Data.PostalCode); entity.SetPostalCode(input.Data.PostalCode);
entity.SetPhone(input.Data.Phone); entity.SetPhone(input.Data.Phone);

View file

@ -0,0 +1,238 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.Json;
using System.Threading.Tasks;
using Kurs.Platform.BlobStoring;
using Kurs.Platform.Entities;
using Kurs.Platform.Enums;
using Kurs.Platform.Queries;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Volo.Abp;
using Volo.Abp.BlobStoring;
using Volo.Abp.Content;
using Volo.Abp.Domain.Entities;
using Volo.Abp.Domain.Repositories;
using static Kurs.Platform.PlatformConsts;
namespace Kurs.Platform.ListForms.ImportManager;
[Authorize()]
public class ListFormImportAppService : PlatformAppService, IImportAppService
{
private readonly IRepository<ListFormImport, Guid> _importSessionRepository;
private readonly IRepository<ListFormImportExecute, Guid> _importSessionExecuteRepository;
private readonly IBlobContainer<ImportBlobContainer> _importBlobContainer;
private readonly IListFormAuthorizationManager _authManager;
private readonly IQueryManager _qManager;
public ListFormImportAppService(
IRepository<ListFormImport, Guid> importSessionRepository,
IRepository<ListFormImportExecute, Guid> importSessionExecuteRepository,
IBlobContainer<ImportBlobContainer> importBlobContainer,
IListFormAuthorizationManager authManager,
IQueryManager qManager
)
{
_importSessionRepository = importSessionRepository;
_importSessionExecuteRepository = importSessionExecuteRepository;
_importBlobContainer = importBlobContainer;
_authManager = authManager;
_qManager = qManager;
}
public async Task<ListFormsImportDto> CreateAsync(
[FromForm] string listFormCode,
[FromForm] IRemoteStreamContent file)
{
if (!await _authManager.CanAccess(listFormCode, AuthorizationTypeEnum.Import))
throw new Volo.Abp.UserFriendlyException(L[AppErrorCodes.NoAuth]);
if (string.IsNullOrWhiteSpace(file.FileName))
{
throw new UserFriendlyException("Geçersiz dosya adı.");
}
// Uygunsuz karakterleri temizle
var originalFileName = file.FileName.Trim();
var extension = Path.GetExtension(originalFileName) ?? ".dat";
var fileName = listFormCode
.Replace(" ", "_")
.Replace(".", "_");
var blobName = $"{fileName}-{Guid.NewGuid()}{extension}";
var session = new ListFormImport
{
ListFormCode = listFormCode,
BlobName = blobName,
Status = "uploading",
TotalRows = 0,
};
try
{
await _importBlobContainer.SaveAsync(blobName, file.GetStream(), overrideExisting: true);
}
catch (Exception ex)
{
// Upload başarısız olursa status'ı failed yap
session.Status = "failed";
Logger.LogError(ex, "File upload failed for session {SessionId}, blob: {BlobName}", session.Id, blobName);
}
await _importSessionRepository.InsertAsync(session, autoSave: true);
return ObjectMapper.Map<ListFormImport, ListFormsImportDto>(session);
}
public async Task<ListFormsImportDto> GetAsync(Guid id)
{
var session = await _importSessionRepository.FirstOrDefaultAsync(a => a.Id == id)
?? throw new EntityNotFoundException(typeof(ListFormImport), id);
if (!await _authManager.CanAccess(session.ListFormCode, AuthorizationTypeEnum.Import))
throw new Volo.Abp.UserFriendlyException(L[AppErrorCodes.NoAuth]);
return ObjectMapper.Map<ListFormImport, ListFormsImportDto>(session);
}
public async Task<List<ListFormsImportDto>> GetListByListFormCodeAsync(string listFormCode)
{
if (!await _authManager.CanAccess(listFormCode, AuthorizationTypeEnum.Import))
throw new Volo.Abp.UserFriendlyException(L[AppErrorCodes.NoAuth]);
var sessions = await _importSessionRepository.GetListAsync(x => x.ListFormCode == listFormCode);
var ordered = sessions.OrderByDescending(x => x.CreationTime).ToList();
return ObjectMapper.Map<List<ListFormImport>, List<ListFormsImportDto>>(ordered);
}
public async Task<ListFormsImportDto> UpdateAsync(Guid id, ListFormsImportDto input)
{
// Izin logic process
if (!await _authManager.CanAccess(input.ListFormCode, AuthorizationTypeEnum.Import))
throw new Volo.Abp.UserFriendlyException(L[AppErrorCodes.NoAuth]);
var session = await _importSessionRepository.FirstOrDefaultAsync(a => a.Id == id)
?? throw new EntityNotFoundException(typeof(ListFormImport), id);
if (!string.IsNullOrEmpty(input.Status)) session.Status = input.Status;
if (input.TotalRows.HasValue) session.TotalRows = input.TotalRows.Value;
await _importSessionRepository.UpdateAsync(session, autoSave: true);
return ObjectMapper.Map<ListFormImport, ListFormsImportDto>(session);
}
public async Task<ListFormImportExecuteDto> ExecuteAsync([FromBody] ExecuteImportRequest request)
{
var session = await _importSessionRepository.FirstOrDefaultAsync(a => a.Id == request.SessionId)
?? throw new UserFriendlyException("Import session not found.");
// Izin logic process
if (!await _authManager.CanAccess(request.ListFormCode, AuthorizationTypeEnum.Import))
throw new Volo.Abp.UserFriendlyException(L[AppErrorCodes.NoAuth]);
var execute = new ListFormImportExecute
{
ImportId = request.SessionId,
BlobName = session.BlobName,
Status = "processing",
ExecRows = 0,
ValidRows = 0,
ErrorRows = 0,
Progress = 0
};
await _importSessionExecuteRepository.InsertAsync(execute, autoSave: true);
try
{
// Process the selected rows data
var processedCount = request.SelectedRowsData?.Count ?? 0;
var validCount = 0;
var errorCount = 0;
if (processedCount > 0)
{
execute.Progress = 20;
await _importSessionExecuteRepository.UpdateAsync(execute, autoSave: true);
// Process each row individually
for (int i = 0; i < request.SelectedRowsData.Count; i++)
{
var rowData = request.SelectedRowsData[i];
try
{
// Insert each row into database
// Serialize Dictionary to JSON string as the method expects dynamic input
var jsonData = JsonSerializer.Serialize(rowData);
await _qManager.GenerateAndRunQueryAsync<dynamic>(request.ListFormCode, OperationEnum.Insert, jsonData);
validCount++;
}
catch (Exception ex)
{
// If database insert fails, count as error
errorCount++;
// Log the error if needed
Logger.LogWarning("Error inserting row {0} during import for session {1}: {2}", i, session.Id, ex.Message);
}
// Update progress
var progressPercentage = 20 + (int)((double)(i + 1) / processedCount * 70); // Progress from 20% to 90%
execute.Progress = progressPercentage;
// Update progress every 10 rows or on last row to avoid too many database updates
if ((i + 1) % 10 == 0 || i == processedCount - 1)
{
await _importSessionExecuteRepository.UpdateAsync(execute, autoSave: true);
}
}
}
// Update session with final results
execute.Status = "completed";
execute.Progress = 100;
execute.ExecRows = processedCount;
execute.ValidRows = validCount;
execute.ErrorRows = errorCount;
await _importSessionExecuteRepository.UpdateAsync(execute, autoSave: true);
return ObjectMapper.Map<ListFormImportExecute, ListFormImportExecuteDto>(execute);
}
catch (Exception ex)
{
// Update session status to failed
execute.Status = "failed";
execute.Progress = 0;
await _importSessionExecuteRepository.UpdateAsync(execute, autoSave: true);
throw new UserFriendlyException($"Import failed: {ex.Message}");
}
}
public async Task<List<ListFormImportExecuteDto>> GetListExecutesAsync(Guid sessionId)
{
var sessions = await _importSessionExecuteRepository.GetListAsync(x => x.ImportId == sessionId);
var ordered = sessions.OrderByDescending(x => x.CreationTime).ToList();
return ObjectMapper.Map<List<ListFormImportExecute>, List<ListFormImportExecuteDto>>(ordered);
}
public async Task DeleteAsync(Guid id)
{
var session = await _importSessionRepository.FirstOrDefaultAsync(a => a.Id == id)
?? throw new EntityNotFoundException(typeof(ListFormImport), id);
// Izin logic process
if (!await _authManager.CanAccess(session.ListFormCode, AuthorizationTypeEnum.Import))
throw new Volo.Abp.UserFriendlyException(L[AppErrorCodes.NoAuth]);
await _importSessionRepository.DeleteAsync(id);
}
}

View file

@ -0,0 +1,113 @@
using System;
using Volo.Abp.Domain.Repositories;
using Kurs.Platform.Entities;
using System.Threading.Tasks;
using Volo.Abp.Application.Services;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
namespace Kurs.Platform.Orders;
public interface IOrderAppService : IApplicationService
{
Task<List<ProductDto>> GetProductListAsync();
Task<List<PaymentMethodDto>> GetPaymentMethodListAsync();
Task<List<InstallmentOptionDto>> GetInstallmentOptionListAsync();
Task<OrderDto> CreateAsync(OrderDto input);
}
public class OrderAppService : ApplicationService, IOrderAppService
{
private readonly IRepository<Product, Guid> _productRepository;
private readonly IRepository<PaymentMethod, string> _paymentMethodRepository;
private readonly IRepository<InstallmentOption, int> _installmentOptionRepository;
private readonly IRepository<Order, Guid> _orderRepository;
public OrderAppService(IRepository<Product, Guid> productRepository,
IRepository<PaymentMethod, string> paymentMethodRepository,
IRepository<InstallmentOption, int> installmentOptionRepository,
IRepository<Order, Guid> orderRepository)
{
_productRepository = productRepository;
_paymentMethodRepository = paymentMethodRepository;
_installmentOptionRepository = installmentOptionRepository;
_orderRepository = orderRepository;
}
public async Task<List<ProductDto>> GetProductListAsync()
{
var products = await _productRepository.GetListAsync();
return ObjectMapper.Map<List<Product>, List<ProductDto>>(products.OrderBy(p => p.Order).ToList());
}
public async Task<List<PaymentMethodDto>> GetPaymentMethodListAsync()
{
var paymentMethods = await _paymentMethodRepository.GetListAsync();
return ObjectMapper.Map<List<PaymentMethod>, List<PaymentMethodDto>>(paymentMethods);
}
public async Task<List<InstallmentOptionDto>> GetInstallmentOptionListAsync()
{
var installmentOptions = await _installmentOptionRepository.GetListAsync();
return ObjectMapper.Map<List<InstallmentOption>, List<InstallmentOptionDto>>(installmentOptions);
}
public async Task<OrderDto> CreateAsync(OrderDto input)
{
var entity = new Order()
{
TenantId = input.Tenant.Id,
InstitutionName = input.Tenant.InstitutionName,
Founder = input.Tenant.Founder,
VknTckn = input.Tenant.VknTckn,
TaxOffice = input.Tenant.TaxOffice,
Address = input.Tenant.Address,
Address2 = input.Tenant.Address2,
District = input.Tenant.District,
Country = input.Tenant.Country,
City = input.Tenant.City,
PostalCode = input.Tenant.PostalCode,
Phone = input.Tenant.Phone,
Mobile = input.Tenant.Mobile,
Fax = input.Tenant.Fax,
Email = input.Tenant.Email,
Website = input.Tenant.Website,
Subtotal = input.Subtotal,
Commission = input.Commission,
Total = input.Total,
PaymentMethod = input.PaymentMethod,
Installments = input.Installments,
InstallmentName = input.InstallmentName,
PaymentDataJson = JsonConvert.SerializeObject(input.PaymentData),
};
foreach (var item in input.Items)
{
entity.Items.Add(new OrderItem
{
OrderId = entity.Id,
Order = entity,
ProductId = item.Product.Id,
ProductName = item.Product.Name,
BillingCycle = item.BillingCycle,
Quantity = item.Quantity,
TotalPrice = item.TotalPrice
});
}
await _orderRepository.InsertAsync(entity, autoSave: true);
return new OrderDto
{
Id = entity.Id,
Total = entity.Total,
PaymentMethod = entity.PaymentMethod
};
}
}

View file

@ -0,0 +1,15 @@
using AutoMapper;
using Kurs.Platform.Entities;
namespace Kurs.Platform.Orders;
public class OrderApplicationAutoMapperProfile : Profile
{
public OrderApplicationAutoMapperProfile()
{
CreateMap<Product, ProductDto>().ReverseMap();
CreateMap<PaymentMethod, PaymentMethodDto>();
CreateMap<InstallmentOption, InstallmentOptionDto>();
CreateMap<Order, OrderDto>();
}
}

View file

@ -1,5 +1,6 @@
using System; using System;
using System.Threading.Tasks; using System.Threading.Tasks;
using Kurs.Platform.Extensions;
using Kurs.Platform.ListForms.DynamicApi; using Kurs.Platform.ListForms.DynamicApi;
using Kurs.Platform.Localization; using Kurs.Platform.Localization;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
@ -61,6 +62,38 @@ public class PlatformTenantAppService : TenantAppService, IPlatformTenantAppServ
//TODO: Update ve Delete ConnectionString: Validation vt varsa değiştireceği zaman uyarı verilmeli //TODO: Update ve Delete ConnectionString: Validation vt varsa değiştireceği zaman uyarı verilmeli
[AllowAnonymous]
public async Task<CustomTenantDto> GetByNameDetailAsync(string name)
{
var tenant = await TenantRepository.FindByNameAsync(name);
if (tenant == null)
{
return null;
//throw new EntityNotFoundException($"Tenant bulunamadı: {name}");
}
var dto = ObjectMapper.Map<Tenant, CustomTenantDto>(tenant);
dto.IsActive = tenant.GetIsActive();
dto.InstitutionName = tenant.GetInstitutionName();
dto.Founder = tenant.GetFounder();
dto.VknTckn = tenant.GetVknTckn();
dto.TaxOffice = tenant.GetTaxOffice();
dto.Address = tenant.GetAddress();
dto.Address2 = tenant.GetAddress2();
dto.District = tenant.GetDistrict();
dto.Country = tenant.GetCountry();
dto.City = tenant.GetCity();
dto.PostalCode = tenant.GetPostalCode();
dto.Phone = tenant.GetPhone();
dto.Mobile = tenant.GetMobile();
dto.Fax = tenant.GetFax();
dto.Email = tenant.GetEmail();
dto.Website = tenant.GetWebsite();
return dto;
}
[Authorize(TenantManagementPermissions.Tenants.Update)] [Authorize(TenantManagementPermissions.Tenants.Update)]
public async Task PostSeedTenantDataAsync(CreateUpdateTenantInput input) public async Task PostSeedTenantDataAsync(CreateUpdateTenantInput input)
{ {

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,4 @@
using System; using System;
using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
@ -12,7 +11,6 @@ using Kurs.Platform.Entities;
using Kurs.Platform.Enums; using Kurs.Platform.Enums;
using Kurs.Platform.Forum; using Kurs.Platform.Forum;
using Kurs.Platform.ListForms; using Kurs.Platform.ListForms;
using Kurs.Platform.Routes;
using Kurs.Platform.Seeds; using Kurs.Platform.Seeds;
using Kurs.Settings.Entities; using Kurs.Settings.Entities;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
@ -57,6 +55,10 @@ public class PlatformDataSeeder : IDataSeedContributor, ITransientDependency
private readonly IRepository<AiBot, Guid> _aiBotRepository; private readonly IRepository<AiBot, Guid> _aiBotRepository;
private readonly IRepository<Route, Guid> _routeRepository; private readonly IRepository<Route, Guid> _routeRepository;
private readonly IRepository<CustomEndpoint, Guid> _customEndpointRepository; private readonly IRepository<CustomEndpoint, Guid> _customEndpointRepository;
private readonly IRepository<Product, Guid> _productRepository;
private readonly IRepository<PaymentMethod, String> _paymentMethodRepository;
private readonly IRepository<InstallmentOption, int> _installmentOptionRepository;
public PlatformDataSeeder( public PlatformDataSeeder(
IRepository<Language, Guid> languages, IRepository<Language, Guid> languages,
@ -88,7 +90,10 @@ public class PlatformDataSeeder : IDataSeedContributor, ITransientDependency
IRepository<ForumCategory, Guid> forumCategoryRepository, IRepository<ForumCategory, Guid> forumCategoryRepository,
IRepository<AiBot, Guid> aiBotRepository, IRepository<AiBot, Guid> aiBotRepository,
IRepository<Route, Guid> RouteRepository, IRepository<Route, Guid> RouteRepository,
IRepository<CustomEndpoint, Guid> CustomEndpointRepository IRepository<CustomEndpoint, Guid> CustomEndpointRepository,
IRepository<Product, Guid> ProductRepository,
IRepository<PaymentMethod, String> PaymentMethodRepository,
IRepository<InstallmentOption, int> InstallmentOptionRepository
) )
{ {
_languages = languages; _languages = languages;
@ -121,6 +126,9 @@ public class PlatformDataSeeder : IDataSeedContributor, ITransientDependency
_aiBotRepository = aiBotRepository; _aiBotRepository = aiBotRepository;
_routeRepository = RouteRepository; _routeRepository = RouteRepository;
_customEndpointRepository = CustomEndpointRepository; _customEndpointRepository = CustomEndpointRepository;
_productRepository = ProductRepository;
_paymentMethodRepository = PaymentMethodRepository;
_installmentOptionRepository = InstallmentOptionRepository;
} }
private static IConfigurationRoot BuildConfiguration() private static IConfigurationRoot BuildConfiguration()
@ -674,5 +682,53 @@ public class PlatformDataSeeder : IDataSeedContributor, ITransientDependency
)); ));
} }
} }
foreach (var item in items.Products)
{
var exists = await _productRepository.AnyAsync(x => x.Name == item.Name);
if (!exists)
{
await _productRepository.InsertAsync(new Product(
item.Id,
item.Name,
item.Description,
item.Category,
item.Order,
item.MonthlyPrice,
item.YearlyPrice,
item.IsQuantityBased,
item.ImageUrl
));
}
}
foreach (var item in items.PaymentMethods)
{
var exists = await _paymentMethodRepository.AnyAsync(x => x.Name == item.Name);
if (!exists)
{
await _paymentMethodRepository.InsertAsync(new PaymentMethod(
item.Id,
item.Name,
item.Commission,
item.Logo
));
}
}
foreach (var item in items.InstallmentOptions)
{
var exists = await _installmentOptionRepository.AnyAsync(x => x.Name == item.Name);
if (!exists)
{
await _installmentOptionRepository.InsertAsync(new InstallmentOption(
item.Id,
item.Name,
item.Commission));
}
}
} }
} }

File diff suppressed because it is too large Load diff

View file

@ -39,6 +39,9 @@ public class SeederDto
public List<AiBotSeedDto> AiBots { get; set; } public List<AiBotSeedDto> AiBots { get; set; }
public List<RouteSeedDto> Routes { get; set; } public List<RouteSeedDto> Routes { get; set; }
public List<CustomEndpointSeedDto> CustomEndpoints { get; set; } public List<CustomEndpointSeedDto> CustomEndpoints { get; set; }
public List<ProductSeedDto> Products { get; set; }
public List<PaymentMethodSeedDto> PaymentMethods { get; set; }
public List<InstallmentOptionSeedDto> InstallmentOptions { get; set; }
} }
public class ChartsSeedDto public class ChartsSeedDto
@ -268,3 +271,30 @@ public class CustomEndpointSeedDto
public List<CustomEndpointPermission> PermissionsJson { get; set; } public List<CustomEndpointPermission> PermissionsJson { get; set; }
} }
public class ProductSeedDto
{
public Guid Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string Category { get; set; }
public int Order { get; set; }
public decimal? MonthlyPrice { get; set; }
public decimal? YearlyPrice { get; set; }
public bool IsQuantityBased { get; set; }
public string ImageUrl { get; set; }
}
public class PaymentMethodSeedDto
{
public string Id { get; set; } // e.g. "credit-card", "bank-transfer"
public string Name { get; set; }
public decimal Commission { get; set; }
public string Logo { get; set; }
}
public class InstallmentOptionSeedDto
{
public int Id { get; set; } // e.g. 1, 2, 3, 6, 12
public string Name { get; set; } // e.g. "Tek Çekim", "2 Taksit"
public decimal Commission { get; set; }
}

View file

@ -12,21 +12,21 @@
"Platform_Web": { "Platform_Web": {
"ClientId": "Platform_Web", "ClientId": "Platform_Web",
"ClientSecret": "1q2w3e*", "ClientSecret": "1q2w3e*",
"RootUrl": "https://kurs-dev-api.sozsoft.com" "RootUrl": "https://dev-api.sozsoft.com"
}, },
"Platform_App": { "Platform_App": {
"ClientId": "Platform_App", "ClientId": "Platform_App",
"RootUrl": "https://kurs-dev.sozsoft.com", "RootUrl": "https://dev.sozsoft.com",
"TokenLifeTime": 2, "TokenLifeTime": 2,
"RefreshTokenLifeTime": 8760 "RefreshTokenLifeTime": 8760
}, },
"Platform_Swagger": { "Platform_Swagger": {
"ClientId": "Platform_Swagger", "ClientId": "Platform_Swagger",
"RootUrl": "https://kurs-dev-api.sozsoft.com" "RootUrl": "https://dev-api.sozsoft.com"
}, },
"Platform_PublicApi": { "Platform_PublicApi": {
"ClientId": "Platform_PublicApi", "ClientId": "Platform_PublicApi",
"RootUrl": "https://kurs-dev.sozsoft.com", "RootUrl": "https://dev.sozsoft.com",
"TokenLifeTime": 2, "TokenLifeTime": 2,
"RefreshTokenLifeTime": 8760 "RefreshTokenLifeTime": 8760
} }

View file

@ -12,21 +12,21 @@
"Platform_Web": { "Platform_Web": {
"ClientId": "Platform_Web", "ClientId": "Platform_Web",
"ClientSecret": "1q2w3e*", "ClientSecret": "1q2w3e*",
"RootUrl": "https://kurs-api.sozsoft.com" "RootUrl": "https://api.sozsoft.com"
}, },
"Platform_App": { "Platform_App": {
"ClientId": "Platform_App", "ClientId": "Platform_App",
"RootUrl": "https://kurs.sozsoft.com", "RootUrl": "https://sozsoft.com",
"TokenLifeTime": 2, "TokenLifeTime": 2,
"RefreshTokenLifeTime": 8760 "RefreshTokenLifeTime": 8760
}, },
"Platform_Swagger": { "Platform_Swagger": {
"ClientId": "Platform_Swagger", "ClientId": "Platform_Swagger",
"RootUrl": "https://kurs-api.sozsoft.com" "RootUrl": "https://api.sozsoft.com"
}, },
"Platform_PublicApi": { "Platform_PublicApi": {
"ClientId": "Platform_PublicApi", "ClientId": "Platform_PublicApi",
"RootUrl": "https://kurs.sozsoft.com", "RootUrl": "https://sozsoft.com",
"TokenLifeTime": 2, "TokenLifeTime": 2,
"RefreshTokenLifeTime": 8760 "RefreshTokenLifeTime": 8760
} }

View file

@ -8,4 +8,5 @@ public enum AuthorizationTypeEnum
Update = 3, Update = 3,
Delete = 4, Delete = 4,
Export = 5, Export = 5,
Import = 6,
} }

View file

@ -29,6 +29,7 @@ public static class PlatformConsts
public const string IsActive = "IsActive"; public const string IsActive = "IsActive";
public const string InstitutionName = "InstitutionName"; public const string InstitutionName = "InstitutionName";
public const string VknTckn = "VknTckn"; public const string VknTckn = "VknTckn";
public const string Founder = "Founder";
public const string TaxOffice = "TaxOffice"; public const string TaxOffice = "TaxOffice";
public const string Address = "Address"; public const string Address = "Address";
public const string Address2 = "Address2"; public const string Address2 = "Address2";
@ -361,6 +362,10 @@ public static class PlatformConsts
public const string BlogCategory = "list-blogcategory"; public const string BlogCategory = "list-blogcategory";
public const string BlogPost = "list-blogpost"; public const string BlogPost = "list-blogpost";
public const string Route = "list-route"; public const string Route = "list-route";
public const string Product = "list-product";
public const string PaymentMethod = "list-paymentmethod";
public const string InstallmentOption = "list-installmentoption";
public const string PurchaseOrder = "list-purchaseorder";
public const string ListformField = "list-listformfield"; public const string ListformField = "list-listformfield";
} }
@ -1208,6 +1213,7 @@ public static class PlatformConsts
public static class BlobContainers public static class BlobContainers
{ {
public const string AvatarContainer = "Avatar"; public const string AvatarContainer = "Avatar";
public const string ImportContainer = "Import";
} }
public static readonly ReadOnlyCollection<LanguageInfo> Languages = new( public static readonly ReadOnlyCollection<LanguageInfo> Languages = new(

View file

@ -0,0 +1,8 @@
using Volo.Abp.BlobStoring;
namespace Kurs.Platform.BlobStoring;
[BlobContainerName(PlatformConsts.BlobContainers.ImportContainer)]
public class ImportBlobContainer
{
}

View file

@ -27,6 +27,7 @@ public static class SeedConsts
public const string Update = Default + ".Update"; public const string Update = Default + ".Update";
public const string Delete = Default + ".Delete"; public const string Delete = Default + ".Delete";
public const string Export = Default + ".Export"; public const string Export = Default + ".Export";
public const string Import = Default + ".Import";
} }
public static class Permissions public static class Permissions
@ -36,6 +37,7 @@ public static class SeedConsts
public const string Update = Default + ".Update"; public const string Update = Default + ".Update";
public const string Delete = Default + ".Delete"; public const string Delete = Default + ".Delete";
public const string Export = Default + ".Export"; public const string Export = Default + ".Export";
public const string Import = Default + ".Import";
} }
public static class Preferences public static class Preferences
@ -384,6 +386,14 @@ public static class SeedConsts
public const string Routes = Prefix.App + ".Routes"; public const string Routes = Prefix.App + ".Routes";
public static class Orders
{
public const string Default = Prefix.App + ".Orders";
public const string Products = Default + ".Products";
public const string PaymentMethods = Default + ".PaymentMethods";
public const string InstallmentOptions = Default + ".InstallmentOptions";
public const string PurchaseOrders = Default + ".PurchaseOrders";
}
} }
public static class DataSources public static class DataSources

View file

@ -0,0 +1,11 @@
using System;
using System.Threading.Tasks;
using Kurs.Platform.Entities;
using Volo.Abp.Domain.Repositories;
namespace Kurs.Platform.Domain.DeveloperKit;
public interface IApiMigrationRepository : IRepository<ApiMigration, Guid>
{
Task ExecuteSqlAsync(string sql);
}

View file

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Text.Json;
using System.Threading.Tasks;
namespace Kurs.Platform.Domain.DeveloperKit;
public interface IDynamicEntityManager
{
Task<List<object>?> GetEntityListAsync(string entityName);
Task<object?> GetEntityByIdAsync(string entityName, Guid id);
Task<object?> CreateEntityAsync(string entityName, JsonElement data);
Task<object?> UpdateEntityAsync(string entityName, Guid id, JsonElement data);
Task<bool> DeleteEntityAsync(string entityName, Guid id);
}

View file

@ -0,0 +1,24 @@
using System;
using Volo.Abp.Domain.Entities.Auditing;
using Volo.Abp.MultiTenancy;
namespace Kurs.Platform.Entities;
public class ApiEndpoint : FullAuditedEntity<Guid>, IMultiTenant
{
public virtual Guid? TenantId { get; protected set; }
public string EntityName { get; set; } = string.Empty;
public string Method { get; set; } = string.Empty;
public string Path { get; set; } = string.Empty;
public string OperationType { get; set; } = string.Empty;
public string CsharpCode { get; set; } = string.Empty;
public bool IsActive { get; set; } = true;
// Foreign key to CustomEntity
public Guid EntityId { get; set; }
public virtual CustomEntity Entity { get; set; } = null!;
public ApiEndpoint()
{
Id = Guid.NewGuid();
}
}

View file

@ -0,0 +1,18 @@
using System;
using Volo.Abp.Domain.Entities.Auditing;
using Volo.Abp.MultiTenancy;
namespace Kurs.Platform.Entities;
public class ApiMigration : AuditedEntity<Guid>, IMultiTenant
{
public virtual Guid? TenantId { get; protected set; }
public Guid EntityId { get; set; }
public string EntityName { get; set; } = string.Empty;
public string FileName { get; set; } = string.Empty;
public string SqlScript { get; set; } = string.Empty;
public string Status { get; set; } = "pending"; // "pending" | "applied" | "failed"
public DateTime? AppliedAt { get; set; }
public string? ErrorMessage { get; set; }
public virtual CustomEntity Entity { get; set; } = null!;
}

View file

@ -0,0 +1,16 @@
using System;
using Volo.Abp.Domain.Entities.Auditing;
using Volo.Abp.MultiTenancy;
namespace Kurs.Platform.Entities;
public class CustomComponent : FullAuditedEntity<Guid>, IMultiTenant
{
public virtual Guid? TenantId { get; protected set; }
public string Name { get; set; } = string.Empty;
public string Code { get; set; } = string.Empty;
public string? Props { get; set; }
public string? Description { get; set; }
public bool IsActive { get; set; } = true;
public string? Dependencies { get; set; } // JSON string of component names
}

View file

@ -0,0 +1,47 @@
using System;
using System.Collections.Generic;
using Volo.Abp.Domain.Entities.Auditing;
using Volo.Abp.MultiTenancy;
namespace Kurs.Platform.Entities;
public class CustomEntity : FullAuditedEntity<Guid>, IMultiTenant
{
public virtual Guid? TenantId { get; protected set; }
public string Name { get; set; } = string.Empty;
public string DisplayName { get; set; } = string.Empty;
public string TableName { get; set; } = string.Empty;
public string? Description { get; set; }
public bool IsActive { get; set; } = true;
public bool HasAuditFields { get; set; } = true;
public bool HasSoftDelete { get; set; } = true;
public string MigrationStatus { get; set; } = "pending";
public Guid? MigrationId { get; set; }
public string EndpointStatus { get; set; } = "pending"; // "pending" | "applied" | "failed"
public virtual ICollection<CustomEntityField> Fields { get; set; } = [];
public CustomEntity()
{
Id = Guid.NewGuid(); // Burada erişim mümkün çünkü sınıfın içi
}
}
public class CustomEntityField : FullAuditedEntity<Guid>
{
public Guid EntityId { get; set; } = Guid.NewGuid();
public string Name { get; set; } = string.Empty;
public string Type { get; set; } = string.Empty;
public bool IsRequired { get; set; }
public int? MaxLength { get; set; }
public bool IsUnique { get; set; }
public string? DefaultValue { get; set; }
public string? Description { get; set; }
public virtual CustomEntity Entity { get; set; } = null!;
public CustomEntityField()
{
Id = Guid.NewGuid(); // Burada erişim mümkün çünkü sınıfın içi
}
}

View file

@ -0,0 +1,18 @@
using Volo.Abp.Domain.Entities;
namespace Kurs.Platform.Entities;
public class InstallmentOption : Entity<int>
{
public string Name { get; set; }
public decimal Commission { get; set; }
public InstallmentOption() { }
public InstallmentOption(int id, string name, decimal commission)
{
Id = id;
Name = name;
Commission = commission;
}
}

View file

@ -0,0 +1,12 @@
using System;
using Volo.Abp.Domain.Entities.Auditing;
namespace Kurs.Platform.Entities;
public class ListFormImport : FullAuditedEntity<Guid>
{
public string ListFormCode { get; set; }
public string BlobName { get; set; }
public string Status { get; set; }
public int TotalRows { get; set; }
}

View file

@ -0,0 +1,16 @@
using System;
using Volo.Abp.Domain.Entities.Auditing;
namespace Kurs.Platform.Entities;
public class ListFormImportExecute : FullAuditedEntity<Guid>
{
public Guid ImportId { get; set; }
public string BlobName { get; set; }
public string Status { get; set; }
public int ExecRows { get; set; }
public int ValidRows { get; set; }
public int ErrorRows { get; set; }
public double Progress { get; set; }
public string ErrorsJson { get; set; }
}

View file

@ -0,0 +1,20 @@
using Volo.Abp.Domain.Entities;
namespace Kurs.Platform.Entities;
public class PaymentMethod : Entity<string>
{
public string Name { get; set; }
public decimal Commission { get; set; }
public string Logo { get; set; }
public PaymentMethod() { }
public PaymentMethod(string id, string name, decimal commission, string logo)
{
Id = id;
Name = name;
Commission = commission;
Logo = logo;
}
}

View file

@ -0,0 +1,42 @@
using System;
using Volo.Abp.Domain.Entities.Auditing;
namespace Kurs.Platform.Entities;
public class Product : FullAuditedAggregateRoot<Guid>
{
public string Name { get; set; }
public string Description { get; set; }
public string Category { get; set; }
public int Order { get; set; }
public decimal? MonthlyPrice { get; set; }
public decimal? YearlyPrice { get; set; }
public bool IsQuantityBased { get; set; }
public string ImageUrl { get; set; }
public Product()
{
}
public Product(
Guid id,
string name,
string description,
string category,
int order,
decimal? monthlyPrice,
decimal? yearlyPrice,
bool isQuantityBased,
string imageUrl
) : base(id)
{
Name = name;
Description = description;
Category = category;
Order = order;
MonthlyPrice = monthlyPrice;
YearlyPrice = yearlyPrice;
IsQuantityBased = isQuantityBased;
ImageUrl = imageUrl;
}
}

View file

@ -7,11 +7,11 @@ namespace Kurs.Platform.Extensions;
public static class AbpTenantExtensions public static class AbpTenantExtensions
{ {
//IsActive Tenant //IsActive Tenant
public static void SetIsActiveTenant(this Tenant tenant, bool isActive) public static void SetIsActive(this Tenant tenant, bool isActive)
{ {
tenant.SetProperty(PlatformConsts.Tenants.IsActive, isActive); tenant.SetProperty(PlatformConsts.Tenants.IsActive, isActive);
} }
public static bool GetIsActiveTenant(this Tenant tenant) public static bool GetIsActive(this Tenant tenant)
{ {
return tenant.GetProperty<bool>(PlatformConsts.Tenants.IsActive); return tenant.GetProperty<bool>(PlatformConsts.Tenants.IsActive);
} }
@ -25,13 +25,22 @@ public static class AbpTenantExtensions
return tenant.GetProperty<string>(PlatformConsts.Tenants.InstitutionName); return tenant.GetProperty<string>(PlatformConsts.Tenants.InstitutionName);
} }
public static void SetFounder(this Tenant tenant, string founder)
{
tenant.SetProperty(PlatformConsts.Tenants.Founder, founder);
}
public static string GetFounder(this Tenant tenant)
{
return tenant.GetProperty<string>(PlatformConsts.Tenants.Founder);
}
public static void SetVknTckn(this Tenant tenant, long vknTckn) public static void SetVknTckn(this Tenant tenant, long vknTckn)
{ {
tenant.SetProperty(PlatformConsts.Tenants.VknTckn, vknTckn); tenant.SetProperty(PlatformConsts.Tenants.VknTckn, vknTckn);
} }
public static long GetVknTckn(this Tenant tenant) public static long GetVknTckn(this Tenant tenant)
{ {
return tenant.GetProperty<int>(PlatformConsts.Tenants.VknTckn); return tenant.GetProperty<long>(PlatformConsts.Tenants.VknTckn);
} }
public static void SetTaxOffice(this Tenant tenant, string taxOffice) public static void SetTaxOffice(this Tenant tenant, string taxOffice)

View file

@ -0,0 +1,57 @@
using System;
using System.Collections.Generic;
using Volo.Abp.Domain.Entities;
using Volo.Abp.Domain.Entities.Auditing;
namespace Kurs.Platform.Orders;
public class Order : FullAuditedAggregateRoot<Guid>
{
public Guid? TenantId { get; set; }
public string InstitutionName { get; set; }
public string Founder { get; set; }
public long VknTckn { get; set; }
public string TaxOffice { get; set; }
public string Address { get; set; }
public string Address2 { get; set; }
public string District { get; set; }
public string Country { get; set; }
public string City { get; set; }
public string PostalCode { get; set; }
public long Phone { get; set; }
public long Mobile { get; set; }
public long Fax { get; set; }
public string Email { get; set; }
public string Website { get; set; }
public List<OrderItem> Items { get; set; } = new();
public decimal Subtotal { get; set; }
public decimal Commission { get; set; }
public decimal Total { get; set; }
public string PaymentMethod { get; set; }
public int? Installments { get; set; }
public string? InstallmentName { get; set; }
public string PaymentDataJson { get; set; } // JSON olarak saklanacak
public Order()
{
}
}
public class OrderItem : FullAuditedAggregateRoot<Guid>
{
public Guid OrderId { get; set; }
public Order Order { get; set; }
public Guid ProductId { get; set; }
public string ProductName { get; set; }
public string BillingCycle { get; set; }
public int Quantity { get; set; }
public decimal TotalPrice { get; set; }
public OrderItem()
{
Id = Guid.NewGuid();
}
}

View file

@ -0,0 +1,23 @@
using System;
using System.Threading.Tasks;
using Kurs.Platform.Entities;
using Kurs.Platform.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using Volo.Abp.Domain.Repositories.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore;
namespace Kurs.Platform.Domain.DeveloperKit;
public class PlatformApiMigrationRepository : EfCoreRepository<PlatformDbContext, ApiMigration, Guid>, IApiMigrationRepository
{
public PlatformApiMigrationRepository(IDbContextProvider<PlatformDbContext> dbContextProvider)
: base(dbContextProvider)
{
}
public async Task ExecuteSqlAsync(string sql)
{
var dbContext = await GetDbContextAsync();
await dbContext.Database.ExecuteSqlRawAsync(sql);
}
}

View file

@ -0,0 +1,187 @@
using Kurs.Platform.Domain.DeveloperKit;
using Kurs.Platform.Entities;
using Kurs.Platform.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Storage;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.EntityFrameworkCore;
public class DynamicEntityManager : IDynamicEntityManager
{
private readonly IDbContextProvider<PlatformDbContext> _dbContextProvider;
private readonly IRepository<CustomEntity, Guid> _customEntityRepository;
public DynamicEntityManager(
IDbContextProvider<PlatformDbContext> dbContextProvider,
IRepository<CustomEntity, Guid> customEntityRepository)
{
_dbContextProvider = dbContextProvider;
_customEntityRepository = customEntityRepository;
}
public async Task<List<object>?> GetEntityListAsync(string entityName)
{
return await ExecuteDynamicQuery(entityName, "GetList", null);
}
public async Task<object?> GetEntityByIdAsync(string entityName, Guid id)
{
var result = await ExecuteDynamicQuery(entityName, "GetById", id);
return result?.FirstOrDefault();
}
public async Task<object?> CreateEntityAsync(string entityName, JsonElement data)
{
var entity = await GetEntityDefinitionAsync(entityName);
var tableName = entity.TableName;
var newId = Guid.NewGuid();
var columns = new List<string> { "Id" };
var values = new List<string> { $"'{newId}'" };
foreach (var field in entity.Fields)
{
if (data.TryGetProperty(field.Name, out var fieldValue))
{
columns.Add($"[{field.Name}]");
values.Add(FormatValueForSql(fieldValue, field.Type));
}
}
if (entity.HasAuditFields)
{
columns.AddRange(new[] { "[CreationTime]", "[LastModificationTime]" });
values.AddRange(new[] { "SYSUTCDATETIME()", "SYSUTCDATETIME()" });
}
var insertQuery = $"INSERT INTO [{tableName}] ({string.Join(", ", columns)}) VALUES ({string.Join(", ", values)})";
var dbContext = await _dbContextProvider.GetDbContextAsync();
await dbContext.Database.ExecuteSqlRawAsync(insertQuery);
return await GetEntityByIdAsync(entityName, newId);
}
public async Task<object?> UpdateEntityAsync(string entityName, Guid id, JsonElement data)
{
var entity = await GetEntityDefinitionAsync(entityName);
var tableName = entity.TableName;
var existing = await GetEntityByIdAsync(entityName, id);
if (existing == null)
return null;
var setParts = new List<string>();
foreach (var field in entity.Fields)
{
if (data.TryGetProperty(field.Name, out var fieldValue))
{
setParts.Add($"[{field.Name}] = {FormatValueForSql(fieldValue, field.Type)}");
}
}
if (entity.HasAuditFields)
setParts.Add("[LastModificationTime] = SYSUTCDATETIME()");
var updateQuery = $"UPDATE [{tableName}] SET {string.Join(", ", setParts)} WHERE Id = '{id}'";
var dbContext = await _dbContextProvider.GetDbContextAsync();
await dbContext.Database.ExecuteSqlRawAsync(updateQuery);
return await GetEntityByIdAsync(entityName, id);
}
public async Task<bool> DeleteEntityAsync(string entityName, Guid id)
{
var entity = await GetEntityDefinitionAsync(entityName);
var tableName = entity.TableName;
var existing = await GetEntityByIdAsync(entityName, id);
if (existing == null)
return false;
string deleteQuery;
if (entity.HasSoftDelete)
{
var parts = new List<string> { "[IsDeleted] = 1" };
if (entity.HasAuditFields)
parts.Add("[DeletionTime] = SYSUTCDATETIME()");
deleteQuery = $"UPDATE [{tableName}] SET {string.Join(", ", parts)} WHERE Id = '{id}'";
}
else
{
deleteQuery = $"DELETE FROM [{tableName}] WHERE Id = '{id}'";
}
var dbContext = await _dbContextProvider.GetDbContextAsync();
var affected = await dbContext.Database.ExecuteSqlRawAsync(deleteQuery);
return affected > 0;
}
private async Task<List<object>> ExecuteDynamicQuery(string entityName, string operation, Guid? id)
{
var entity = await GetEntityDefinitionAsync(entityName);
var tableName = entity.TableName;
var query = operation == "GetList"
? $"SELECT * FROM [{tableName}]"
: $"SELECT * FROM [{tableName}] WHERE Id = '{id}'";
var dbContext = await _dbContextProvider.GetDbContextAsync();
var connection = dbContext.Database.GetDbConnection();
await dbContext.Database.OpenConnectionAsync();
try
{
using var command = connection.CreateCommand();
command.CommandText = query;
// ⭐️⭐️⭐️ Kritik satır:
command.Transaction = dbContext.Database.CurrentTransaction?.GetDbTransaction();
using var reader = await command.ExecuteReaderAsync();
var result = new List<object>();
while (await reader.ReadAsync())
{
var item = new Dictionary<string, object?>();
for (int i = 0; i < reader.FieldCount; i++)
item[reader.GetName(i)] = reader.IsDBNull(i) ? null : reader.GetValue(i);
result.Add(item);
}
return result;
}
finally
{
await dbContext.Database.CloseConnectionAsync();
}
}
private async Task<CustomEntity> GetEntityDefinitionAsync(string entityName)
{
var entity = await _customEntityRepository.WithDetails(x => x.Fields)
.FirstOrDefaultAsync(x => x.Name.ToLower() == entityName.ToLower());
return entity ?? throw new UserFriendlyException($"Entity '{entityName}' not found.");
}
private static string FormatValueForSql(JsonElement value, string type)
{
return type.ToLower() switch
{
"string" => $"'{value.GetString()?.Replace("'", "''")}'",
"number" => value.GetInt32().ToString(),
"decimal" => value.GetDecimal().ToString(System.Globalization.CultureInfo.InvariantCulture),
"boolean" => value.GetBoolean() ? "1" : "0",
"date" => $"'{value.GetDateTime():yyyy-MM-dd HH:mm:ss}'",
"guid" => $"'{value.GetGuid()}'",
_ => $"'{value.GetString()?.Replace("'", "''")}'",
};
}
}

View file

@ -22,6 +22,7 @@ using Kurs.Platform.Forum;
using Microsoft.EntityFrameworkCore.ChangeTracking; using Microsoft.EntityFrameworkCore.ChangeTracking;
using System; using System;
using System.Linq; using System.Linq;
using Kurs.Platform.Orders;
namespace Kurs.Platform.EntityFrameworkCore; namespace Kurs.Platform.EntityFrameworkCore;
@ -63,11 +64,25 @@ public class PlatformDbContext :
public DbSet<BlogPost> BlogPosts { get; set; } public DbSet<BlogPost> BlogPosts { get; set; }
public DbSet<BlogCategory> BlogCategories { get; set; } public DbSet<BlogCategory> BlogCategories { get; set; }
public DbSet<Route> Routes { get; set; } public DbSet<Route> Routes { get; set; }
public DbSet<CustomEntity> CustomEntities { get; set; }
public DbSet<CustomEntityField> EntityFields { get; set; }
public DbSet<ApiMigration> Migrations { get; set; }
public DbSet<ApiEndpoint> GeneratedEndpoints { get; set; }
public DbSet<CustomComponent> CustomComponents { get; set; }
// Forum Entities // Forum Entities
public DbSet<ForumCategory> ForumCategories { get; set; } public DbSet<ForumCategory> ForumCategories { get; set; }
public DbSet<ForumTopic> ForumTopics { get; set; } public DbSet<ForumTopic> ForumTopics { get; set; }
public DbSet<ForumPost> ForumPosts { get; set; } public DbSet<ForumPost> ForumPosts { get; set; }
public DbSet<Product> Products { get; set; }
public DbSet<PaymentMethod> PaymentMethods { get; set; }
public DbSet<InstallmentOption> InstallmentOptions { get; set; }
public DbSet<Order> Orders { get; set; }
public DbSet<OrderItem> OrderItems { get; set; }
public DbSet<ListFormImport> ListFormImports { get; set; }
public DbSet<ListFormImportExecute> ListFormImportExecutes { get; set; }
#region Entities from the modules #region Entities from the modules
@ -517,5 +532,158 @@ public class PlatformDbContext :
) )
); );
}); });
builder.Entity<CustomEntity>(b =>
{
b.ToTable(PlatformConsts.DbTablePrefix + nameof(CustomEntity), PlatformConsts.DbSchema);
b.ConfigureByConvention();
b.HasKey(x => x.Id);
b.Property(x => x.Name).IsRequired().HasMaxLength(100);
b.Property(x => x.DisplayName).IsRequired().HasMaxLength(100);
b.Property(x => x.TableName).IsRequired().HasMaxLength(100);
b.Property(x => x.Description).HasMaxLength(500);
b.Property(x => x.MigrationStatus).IsRequired().HasMaxLength(50);
b.Property(x => x.EndpointStatus).IsRequired().HasMaxLength(50);
b.HasMany(x => x.Fields).WithOne(x => x.Entity).HasForeignKey(x => x.EntityId);
});
builder.Entity<CustomEntityField>(b =>
{
b.ToTable(PlatformConsts.DbTablePrefix + nameof(CustomEntityField), PlatformConsts.DbSchema);
b.ConfigureByConvention();
b.HasKey(x => x.Id);
b.Property(x => x.Name).IsRequired().HasMaxLength(100);
b.Property(x => x.Type).IsRequired().HasMaxLength(50);
b.Property(x => x.Description).HasMaxLength(500);
});
builder.Entity<ApiMigration>(b =>
{
b.ToTable(PlatformConsts.DbTablePrefix + nameof(ApiMigration), PlatformConsts.DbSchema);
b.ConfigureByConvention();
b.HasKey(x => x.Id);
b.Property(x => x.EntityName).IsRequired().HasMaxLength(100);
b.Property(x => x.FileName).IsRequired().HasMaxLength(200);
b.Property(x => x.SqlScript).IsRequired();
b.Property(x => x.Status).IsRequired().HasMaxLength(50);
b.HasOne(x => x.Entity).WithMany().HasForeignKey(x => x.EntityId).IsRequired(false);
});
builder.Entity<ApiEndpoint>(b =>
{
b.ToTable(PlatformConsts.DbTablePrefix + nameof(ApiEndpoint), PlatformConsts.DbSchema);
b.ConfigureByConvention();
b.HasKey(x => x.Id);
b.Property(x => x.EntityName).IsRequired().HasMaxLength(100);
b.Property(x => x.Method).IsRequired().HasMaxLength(10);
b.Property(x => x.Path).IsRequired().HasMaxLength(200);
b.Property(x => x.OperationType).IsRequired().HasMaxLength(50);
b.Property(x => x.CsharpCode).IsRequired();
b.HasOne(x => x.Entity).WithMany().HasForeignKey(x => x.EntityId);
});
builder.Entity<CustomComponent>(b =>
{
b.ToTable(PlatformConsts.DbTablePrefix + nameof(CustomComponent), PlatformConsts.DbSchema);
b.ConfigureByConvention();
b.HasKey(x => x.Id);
b.Property(x => x.Name).IsRequired().HasMaxLength(100);
b.Property(x => x.Code).IsRequired();
b.Property(x => x.Props).HasMaxLength(1000);
b.Property(x => x.Description).HasMaxLength(500);
});
builder.Entity<Product>(b =>
{
b.ToTable(PlatformConsts.DbTablePrefix + nameof(Product), PlatformConsts.DbSchema);
b.ConfigureByConvention();
b.HasKey(x => x.Id);
b.Property(x => x.Name).IsRequired().HasMaxLength(128);
b.Property(x => x.Description).HasMaxLength(1000);
b.Property(x => x.Category).IsRequired().HasMaxLength(64);
b.Property(x => x.MonthlyPrice).HasPrecision(18, 2);
b.Property(x => x.YearlyPrice).HasPrecision(18, 2);
b.Property(x => x.ImageUrl).HasMaxLength(300);
});
// PaymentMethod
builder.Entity<PaymentMethod>(b =>
{
b.ToTable(PlatformConsts.DbTablePrefix + nameof(PaymentMethod), PlatformConsts.DbSchema);
b.ConfigureByConvention();
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);
});
// InstallmentOption
builder.Entity<InstallmentOption>(b =>
{
b.ToTable(PlatformConsts.DbTablePrefix + nameof(InstallmentOption), PlatformConsts.DbSchema);
b.ConfigureByConvention();
b.HasKey(x => x.Id);
b.Property(x => x.Name).IsRequired().HasMaxLength(32);
b.Property(x => x.Commission).HasPrecision(5, 3); // örn. %0.275 gibi değerler için
});
builder.Entity<Order>(b =>
{
b.ToTable(PlatformConsts.DbTablePrefix + nameof(Order), PlatformConsts.DbSchema);
b.ConfigureByConvention();
b.Property(o => o.Subtotal).IsRequired().HasPrecision(18, 2);
b.Property(o => o.Commission).IsRequired().HasPrecision(18, 2);
b.Property(o => o.Total).IsRequired().HasPrecision(18, 2);
b.Property(o => o.PaymentMethod).IsRequired().HasMaxLength(64);
b.Property(o => o.InstallmentName).HasMaxLength(128);
b.Property(o => o.PaymentDataJson).HasMaxLength(4000);
builder.Entity<Order>()
.HasMany(o => o.Items)
.WithOne(i => i.Order)
.IsRequired(false)
.HasForeignKey(i => i.OrderId)
.OnDelete(DeleteBehavior.Cascade);
});
builder.Entity<OrderItem>(b =>
{
b.ToTable(PlatformConsts.DbTablePrefix + nameof(OrderItem), PlatformConsts.DbSchema);
b.ConfigureByConvention();
b.Property(i => i.ProductName).IsRequired().HasMaxLength(128);
b.Property(i => i.BillingCycle).IsRequired().HasMaxLength(32);
b.Property(i => i.TotalPrice).IsRequired().HasPrecision(18, 2);
});
builder.Entity<ListFormImport>(b =>
{
b.ToTable(PlatformConsts.DbTablePrefix + nameof(ListFormImport), PlatformConsts.DbSchema);
b.ConfigureByConvention();
b.Property(x => x.ListFormCode).IsRequired().HasMaxLength(128);
b.Property(x => x.BlobName).IsRequired().HasMaxLength(256);
b.Property(x => x.Status).IsRequired().HasMaxLength(64);
});
builder.Entity<ListFormImportExecute>(b =>
{
b.ToTable(PlatformConsts.DbTablePrefix + nameof(ListFormImportExecute), PlatformConsts.DbSchema);
b.ConfigureByConvention();
b.Property(x => x.ImportId).IsRequired();
b.Property(x => x.BlobName).IsRequired().HasMaxLength(256);
b.Property(x => x.Status).IsRequired().HasMaxLength(64);
b.Property(x => x.ErrorsJson).HasColumnType("text");
});
} }
} }

View file

@ -64,6 +64,15 @@ public static class PlatformEfCoreEntityExtensionMappings
} }
); );
ObjectExtensionManager.Instance
.MapEfCoreProperty<Tenant, string>(
PlatformConsts.Tenants.Founder,
(entityBuilder, propertyBuilder) =>
{
propertyBuilder.HasDefaultValue(null);
}
);
ObjectExtensionManager.Instance ObjectExtensionManager.Instance
.MapEfCoreProperty<Tenant, long>( .MapEfCoreProperty<Tenant, long>(
PlatformConsts.Tenants.VknTckn, PlatformConsts.Tenants.VknTckn,

View file

@ -16,6 +16,7 @@ using Volo.Abp.OpenIddict.EntityFrameworkCore;
using Volo.Abp.PermissionManagement.EntityFrameworkCore; using Volo.Abp.PermissionManagement.EntityFrameworkCore;
using Volo.Abp.TenantManagement.EntityFrameworkCore; using Volo.Abp.TenantManagement.EntityFrameworkCore;
using static Kurs.Settings.SettingsConsts; using static Kurs.Settings.SettingsConsts;
using Kurs.Platform.Domain.DeveloperKit;
namespace Kurs.Platform.EntityFrameworkCore; namespace Kurs.Platform.EntityFrameworkCore;
@ -52,6 +53,8 @@ public class PlatformEntityFrameworkCoreModule : AbpModule
options.AddDefaultRepositories(includeAllEntities: true); options.AddDefaultRepositories(includeAllEntities: true);
}); });
context.Services.AddTransient<IDynamicEntityManager, DynamicEntityManager>();
Configure<AbpDbContextOptions>(options => Configure<AbpDbContextOptions>(options =>
{ {
/* The main point to change your DBMS dynamically. */ /* The main point to change your DBMS dynamically. */

View file

@ -0,0 +1,38 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Kurs.Platform.Migrations
{
/// <inheritdoc />
public partial class LanguageTextVarchar4000 : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<string>(
name: "Value",
table: "PLanguageText",
type: "nvarchar(4000)",
maxLength: 4000,
nullable: false,
oldClrType: typeof(string),
oldType: "nvarchar(1000)",
oldMaxLength: 1000);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<string>(
name: "Value",
table: "PLanguageText",
type: "nvarchar(1000)",
maxLength: 1000,
nullable: false,
oldClrType: typeof(string),
oldType: "nvarchar(4000)",
oldMaxLength: 4000);
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,195 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Kurs.Platform.Migrations
{
/// <inheritdoc />
public partial class DeveloperKit : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "PCustomComponent",
columns: table => new
{
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
TenantId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
Name = table.Column<string>(type: "nvarchar(100)", maxLength: 100, nullable: false),
Code = table.Column<string>(type: "nvarchar(max)", nullable: false),
Props = table.Column<string>(type: "nvarchar(1000)", maxLength: 1000, nullable: true),
Description = table.Column<string>(type: "nvarchar(500)", maxLength: 500, nullable: true),
IsActive = table.Column<bool>(type: "bit", nullable: false),
Dependencies = table.Column<string>(type: "nvarchar(max)", nullable: true),
CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false),
CreatorId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
LastModificationTime = table.Column<DateTime>(type: "datetime2", nullable: true),
LastModifierId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
IsDeleted = table.Column<bool>(type: "bit", nullable: false, defaultValue: false),
DeleterId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
DeletionTime = table.Column<DateTime>(type: "datetime2", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_PCustomComponent", x => x.Id);
});
migrationBuilder.CreateTable(
name: "PCustomEntity",
columns: table => new
{
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
TenantId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
Name = table.Column<string>(type: "nvarchar(100)", maxLength: 100, nullable: false),
DisplayName = table.Column<string>(type: "nvarchar(100)", maxLength: 100, nullable: false),
TableName = table.Column<string>(type: "nvarchar(100)", maxLength: 100, nullable: false),
Description = table.Column<string>(type: "nvarchar(500)", maxLength: 500, nullable: true),
IsActive = table.Column<bool>(type: "bit", nullable: false),
HasAuditFields = table.Column<bool>(type: "bit", nullable: false),
HasSoftDelete = table.Column<bool>(type: "bit", nullable: false),
MigrationStatus = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: false),
MigrationId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
EndpointStatus = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: false),
CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false),
CreatorId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
LastModificationTime = table.Column<DateTime>(type: "datetime2", nullable: true),
LastModifierId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
IsDeleted = table.Column<bool>(type: "bit", nullable: false, defaultValue: false),
DeleterId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
DeletionTime = table.Column<DateTime>(type: "datetime2", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_PCustomEntity", x => x.Id);
});
migrationBuilder.CreateTable(
name: "PApiEndpoint",
columns: table => new
{
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
TenantId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
EntityName = table.Column<string>(type: "nvarchar(100)", maxLength: 100, nullable: false),
Method = table.Column<string>(type: "nvarchar(10)", maxLength: 10, nullable: false),
Path = table.Column<string>(type: "nvarchar(200)", maxLength: 200, nullable: false),
OperationType = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: false),
CsharpCode = table.Column<string>(type: "nvarchar(max)", nullable: false),
IsActive = table.Column<bool>(type: "bit", nullable: false),
EntityId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false),
CreatorId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
LastModificationTime = table.Column<DateTime>(type: "datetime2", nullable: true),
LastModifierId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
IsDeleted = table.Column<bool>(type: "bit", nullable: false, defaultValue: false),
DeleterId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
DeletionTime = table.Column<DateTime>(type: "datetime2", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_PApiEndpoint", x => x.Id);
table.ForeignKey(
name: "FK_PApiEndpoint_PCustomEntity_EntityId",
column: x => x.EntityId,
principalTable: "PCustomEntity",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "PApiMigration",
columns: table => new
{
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
TenantId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
EntityId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
EntityName = table.Column<string>(type: "nvarchar(100)", maxLength: 100, nullable: false),
FileName = table.Column<string>(type: "nvarchar(200)", maxLength: 200, nullable: false),
SqlScript = table.Column<string>(type: "nvarchar(max)", nullable: false),
Status = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: false),
AppliedAt = table.Column<DateTime>(type: "datetime2", nullable: true),
ErrorMessage = table.Column<string>(type: "nvarchar(max)", nullable: true),
CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false),
CreatorId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
LastModificationTime = table.Column<DateTime>(type: "datetime2", nullable: true),
LastModifierId = table.Column<Guid>(type: "uniqueidentifier", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_PApiMigration", x => x.Id);
table.ForeignKey(
name: "FK_PApiMigration_PCustomEntity_EntityId",
column: x => x.EntityId,
principalTable: "PCustomEntity",
principalColumn: "Id");
});
migrationBuilder.CreateTable(
name: "PCustomEntityField",
columns: table => new
{
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
EntityId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
Name = table.Column<string>(type: "nvarchar(100)", maxLength: 100, nullable: false),
Type = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: false),
IsRequired = table.Column<bool>(type: "bit", nullable: false),
MaxLength = table.Column<int>(type: "int", nullable: true),
IsUnique = table.Column<bool>(type: "bit", nullable: false),
DefaultValue = table.Column<string>(type: "nvarchar(max)", nullable: true),
Description = table.Column<string>(type: "nvarchar(500)", maxLength: 500, nullable: true),
CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false),
CreatorId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
LastModificationTime = table.Column<DateTime>(type: "datetime2", nullable: true),
LastModifierId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
IsDeleted = table.Column<bool>(type: "bit", nullable: false, defaultValue: false),
DeleterId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
DeletionTime = table.Column<DateTime>(type: "datetime2", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_PCustomEntityField", x => x.Id);
table.ForeignKey(
name: "FK_PCustomEntityField_PCustomEntity_EntityId",
column: x => x.EntityId,
principalTable: "PCustomEntity",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "IX_PApiEndpoint_EntityId",
table: "PApiEndpoint",
column: "EntityId");
migrationBuilder.CreateIndex(
name: "IX_PApiMigration_EntityId",
table: "PApiMigration",
column: "EntityId");
migrationBuilder.CreateIndex(
name: "IX_PCustomEntityField_EntityId",
table: "PCustomEntityField",
column: "EntityId");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "PApiEndpoint");
migrationBuilder.DropTable(
name: "PApiMigration");
migrationBuilder.DropTable(
name: "PCustomComponent");
migrationBuilder.DropTable(
name: "PCustomEntityField");
migrationBuilder.DropTable(
name: "PCustomEntity");
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,180 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Kurs.Platform.Migrations
{
/// <inheritdoc />
public partial class Orders : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "Founder",
table: "AbpTenants",
type: "nvarchar(max)",
nullable: true);
migrationBuilder.CreateTable(
name: "PInstallmentOption",
columns: table => new
{
Id = table.Column<int>(type: "int", nullable: false)
.Annotation("SqlServer:Identity", "1, 1"),
Name = table.Column<string>(type: "nvarchar(32)", maxLength: 32, nullable: false),
Commission = table.Column<decimal>(type: "decimal(5,3)", precision: 5, scale: 3, nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_PInstallmentOption", x => x.Id);
});
migrationBuilder.CreateTable(
name: "POrder",
columns: table => new
{
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
TenantId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
InstitutionName = table.Column<string>(type: "nvarchar(max)", nullable: true),
Founder = table.Column<string>(type: "nvarchar(max)", nullable: true),
VknTckn = table.Column<long>(type: "bigint", nullable: false),
TaxOffice = table.Column<string>(type: "nvarchar(max)", nullable: true),
Address = table.Column<string>(type: "nvarchar(max)", nullable: true),
Address2 = table.Column<string>(type: "nvarchar(max)", nullable: true),
District = table.Column<string>(type: "nvarchar(max)", nullable: true),
Country = table.Column<string>(type: "nvarchar(max)", nullable: true),
City = table.Column<string>(type: "nvarchar(max)", nullable: true),
PostalCode = table.Column<string>(type: "nvarchar(max)", nullable: true),
Phone = table.Column<long>(type: "bigint", nullable: false),
Mobile = table.Column<long>(type: "bigint", nullable: false),
Fax = table.Column<long>(type: "bigint", nullable: false),
Email = table.Column<string>(type: "nvarchar(max)", nullable: true),
Website = table.Column<string>(type: "nvarchar(max)", nullable: true),
Subtotal = table.Column<decimal>(type: "decimal(18,2)", precision: 18, scale: 2, nullable: false),
Commission = table.Column<decimal>(type: "decimal(18,2)", precision: 18, scale: 2, nullable: false),
Total = table.Column<decimal>(type: "decimal(18,2)", precision: 18, scale: 2, nullable: false),
PaymentMethod = table.Column<string>(type: "nvarchar(64)", maxLength: 64, nullable: false),
Installments = table.Column<int>(type: "int", nullable: true),
InstallmentName = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: true),
PaymentDataJson = table.Column<string>(type: "nvarchar(4000)", maxLength: 4000, nullable: true),
ExtraProperties = table.Column<string>(type: "nvarchar(max)", nullable: false),
ConcurrencyStamp = table.Column<string>(type: "nvarchar(40)", maxLength: 40, nullable: false),
CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false),
CreatorId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
LastModificationTime = table.Column<DateTime>(type: "datetime2", nullable: true),
LastModifierId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
IsDeleted = table.Column<bool>(type: "bit", nullable: false, defaultValue: false),
DeleterId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
DeletionTime = table.Column<DateTime>(type: "datetime2", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_POrder", x => x.Id);
});
migrationBuilder.CreateTable(
name: "PPaymentMethod",
columns: table => new
{
Id = table.Column<string>(type: "nvarchar(450)", nullable: false),
Name = table.Column<string>(type: "nvarchar(64)", maxLength: 64, nullable: false),
Commission = table.Column<decimal>(type: "decimal(5,3)", precision: 5, scale: 3, nullable: false),
Logo = table.Column<string>(type: "nvarchar(32)", maxLength: 32, nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_PPaymentMethod", x => x.Id);
});
migrationBuilder.CreateTable(
name: "PProduct",
columns: table => new
{
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
Name = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: false),
Description = table.Column<string>(type: "nvarchar(1000)", maxLength: 1000, nullable: true),
Category = table.Column<string>(type: "nvarchar(64)", maxLength: 64, nullable: false),
Order = table.Column<int>(type: "int", nullable: false),
MonthlyPrice = table.Column<decimal>(type: "decimal(18,2)", precision: 18, scale: 2, nullable: true),
YearlyPrice = table.Column<decimal>(type: "decimal(18,2)", precision: 18, scale: 2, nullable: true),
IsQuantityBased = table.Column<bool>(type: "bit", nullable: false),
ImageUrl = table.Column<string>(type: "nvarchar(300)", maxLength: 300, nullable: true),
ExtraProperties = table.Column<string>(type: "nvarchar(max)", nullable: false),
ConcurrencyStamp = table.Column<string>(type: "nvarchar(40)", maxLength: 40, nullable: false),
CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false),
CreatorId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
LastModificationTime = table.Column<DateTime>(type: "datetime2", nullable: true),
LastModifierId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
IsDeleted = table.Column<bool>(type: "bit", nullable: false, defaultValue: false),
DeleterId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
DeletionTime = table.Column<DateTime>(type: "datetime2", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_PProduct", x => x.Id);
});
migrationBuilder.CreateTable(
name: "POrderItem",
columns: table => new
{
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
OrderId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
ProductId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
ProductName = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: false),
BillingCycle = table.Column<string>(type: "nvarchar(32)", maxLength: 32, nullable: false),
Quantity = table.Column<int>(type: "int", nullable: false),
TotalPrice = table.Column<decimal>(type: "decimal(18,2)", precision: 18, scale: 2, nullable: false),
ExtraProperties = table.Column<string>(type: "nvarchar(max)", nullable: false),
ConcurrencyStamp = table.Column<string>(type: "nvarchar(40)", maxLength: 40, nullable: false),
CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false),
CreatorId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
LastModificationTime = table.Column<DateTime>(type: "datetime2", nullable: true),
LastModifierId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
IsDeleted = table.Column<bool>(type: "bit", nullable: false, defaultValue: false),
DeleterId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
DeletionTime = table.Column<DateTime>(type: "datetime2", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_POrderItem", x => x.Id);
table.ForeignKey(
name: "FK_POrderItem_POrder_OrderId",
column: x => x.OrderId,
principalTable: "POrder",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "IX_POrderItem_OrderId",
table: "POrderItem",
column: "OrderId");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "PInstallmentOption");
migrationBuilder.DropTable(
name: "POrderItem");
migrationBuilder.DropTable(
name: "PPaymentMethod");
migrationBuilder.DropTable(
name: "PProduct");
migrationBuilder.DropTable(
name: "POrder");
migrationBuilder.DropColumn(
name: "Founder",
table: "AbpTenants");
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,73 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Kurs.Platform.Migrations
{
/// <inheritdoc />
public partial class ListFormImport : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "PListFormImport",
columns: table => new
{
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
ListFormCode = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: false),
BlobName = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: false),
Status = table.Column<string>(type: "nvarchar(64)", maxLength: 64, nullable: false),
TotalRows = table.Column<int>(type: "int", nullable: false),
CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false),
CreatorId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
LastModificationTime = table.Column<DateTime>(type: "datetime2", nullable: true),
LastModifierId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
IsDeleted = table.Column<bool>(type: "bit", nullable: false, defaultValue: false),
DeleterId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
DeletionTime = table.Column<DateTime>(type: "datetime2", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_PListFormImport", x => x.Id);
});
migrationBuilder.CreateTable(
name: "PListFormImportExecute",
columns: table => new
{
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
ImportId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
BlobName = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: false),
Status = table.Column<string>(type: "nvarchar(64)", maxLength: 64, nullable: false),
ExecRows = table.Column<int>(type: "int", nullable: false),
ValidRows = table.Column<int>(type: "int", nullable: false),
ErrorRows = table.Column<int>(type: "int", nullable: false),
Progress = table.Column<double>(type: "float", nullable: false),
ErrorsJson = table.Column<string>(type: "text", nullable: true),
CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false),
CreatorId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
LastModificationTime = table.Column<DateTime>(type: "datetime2", nullable: true),
LastModifierId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
IsDeleted = table.Column<bool>(type: "bit", nullable: false, defaultValue: false),
DeleterId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
DeletionTime = table.Column<DateTime>(type: "datetime2", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_PListFormImportExecute", x => x.Id);
});
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "PListFormImport");
migrationBuilder.DropTable(
name: "PListFormImportExecute");
}
}
}

View file

@ -283,8 +283,8 @@ namespace Kurs.Platform.Migrations
b.Property<string>("Value") b.Property<string>("Value")
.IsRequired() .IsRequired()
.HasMaxLength(1000) .HasMaxLength(4000)
.HasColumnType("nvarchar(1000)"); .HasColumnType("nvarchar(4000)");
b.HasKey("Id"); b.HasKey("Id");
@ -660,6 +660,142 @@ namespace Kurs.Platform.Migrations
b.ToTable("PAiBot", (string)null); b.ToTable("PAiBot", (string)null);
}); });
modelBuilder.Entity("Kurs.Platform.Entities.ApiEndpoint", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uniqueidentifier");
b.Property<DateTime>("CreationTime")
.HasColumnType("datetime2")
.HasColumnName("CreationTime");
b.Property<Guid?>("CreatorId")
.HasColumnType("uniqueidentifier")
.HasColumnName("CreatorId");
b.Property<string>("CsharpCode")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<Guid?>("DeleterId")
.HasColumnType("uniqueidentifier")
.HasColumnName("DeleterId");
b.Property<DateTime?>("DeletionTime")
.HasColumnType("datetime2")
.HasColumnName("DeletionTime");
b.Property<Guid>("EntityId")
.HasColumnType("uniqueidentifier");
b.Property<string>("EntityName")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("nvarchar(100)");
b.Property<bool>("IsActive")
.HasColumnType("bit");
b.Property<bool>("IsDeleted")
.ValueGeneratedOnAdd()
.HasColumnType("bit")
.HasDefaultValue(false)
.HasColumnName("IsDeleted");
b.Property<DateTime?>("LastModificationTime")
.HasColumnType("datetime2")
.HasColumnName("LastModificationTime");
b.Property<Guid?>("LastModifierId")
.HasColumnType("uniqueidentifier")
.HasColumnName("LastModifierId");
b.Property<string>("Method")
.IsRequired()
.HasMaxLength(10)
.HasColumnType("nvarchar(10)");
b.Property<string>("OperationType")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("nvarchar(50)");
b.Property<string>("Path")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.Property<Guid?>("TenantId")
.HasColumnType("uniqueidentifier")
.HasColumnName("TenantId");
b.HasKey("Id");
b.HasIndex("EntityId");
b.ToTable("PApiEndpoint", (string)null);
});
modelBuilder.Entity("Kurs.Platform.Entities.ApiMigration", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uniqueidentifier");
b.Property<DateTime?>("AppliedAt")
.HasColumnType("datetime2");
b.Property<DateTime>("CreationTime")
.HasColumnType("datetime2")
.HasColumnName("CreationTime");
b.Property<Guid?>("CreatorId")
.HasColumnType("uniqueidentifier")
.HasColumnName("CreatorId");
b.Property<Guid>("EntityId")
.HasColumnType("uniqueidentifier");
b.Property<string>("EntityName")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("nvarchar(100)");
b.Property<string>("ErrorMessage")
.HasColumnType("nvarchar(max)");
b.Property<string>("FileName")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.Property<DateTime?>("LastModificationTime")
.HasColumnType("datetime2")
.HasColumnName("LastModificationTime");
b.Property<Guid?>("LastModifierId")
.HasColumnType("uniqueidentifier")
.HasColumnName("LastModifierId");
b.Property<string>("SqlScript")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("Status")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("nvarchar(50)");
b.Property<Guid?>("TenantId")
.HasColumnType("uniqueidentifier")
.HasColumnName("TenantId");
b.HasKey("Id");
b.HasIndex("EntityId");
b.ToTable("PApiMigration", (string)null);
});
modelBuilder.Entity("Kurs.Platform.Entities.BackgroundWorker", b => modelBuilder.Entity("Kurs.Platform.Entities.BackgroundWorker", b =>
{ {
b.Property<Guid>("Id") b.Property<Guid>("Id")
@ -1557,6 +1693,73 @@ namespace Kurs.Platform.Migrations
b.ToTable("PCurrency", (string)null); b.ToTable("PCurrency", (string)null);
}); });
modelBuilder.Entity("Kurs.Platform.Entities.CustomComponent", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uniqueidentifier");
b.Property<string>("Code")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<DateTime>("CreationTime")
.HasColumnType("datetime2")
.HasColumnName("CreationTime");
b.Property<Guid?>("CreatorId")
.HasColumnType("uniqueidentifier")
.HasColumnName("CreatorId");
b.Property<Guid?>("DeleterId")
.HasColumnType("uniqueidentifier")
.HasColumnName("DeleterId");
b.Property<DateTime?>("DeletionTime")
.HasColumnType("datetime2")
.HasColumnName("DeletionTime");
b.Property<string>("Dependencies")
.HasColumnType("nvarchar(max)");
b.Property<string>("Description")
.HasMaxLength(500)
.HasColumnType("nvarchar(500)");
b.Property<bool>("IsActive")
.HasColumnType("bit");
b.Property<bool>("IsDeleted")
.ValueGeneratedOnAdd()
.HasColumnType("bit")
.HasDefaultValue(false)
.HasColumnName("IsDeleted");
b.Property<DateTime?>("LastModificationTime")
.HasColumnType("datetime2")
.HasColumnName("LastModificationTime");
b.Property<Guid?>("LastModifierId")
.HasColumnType("uniqueidentifier")
.HasColumnName("LastModifierId");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("nvarchar(100)");
b.Property<string>("Props")
.HasMaxLength(1000)
.HasColumnType("nvarchar(1000)");
b.Property<Guid?>("TenantId")
.HasColumnType("uniqueidentifier")
.HasColumnName("TenantId");
b.HasKey("Id");
b.ToTable("PCustomComponent", (string)null);
});
modelBuilder.Entity("Kurs.Platform.Entities.CustomEndpoint", b => modelBuilder.Entity("Kurs.Platform.Entities.CustomEndpoint", b =>
{ {
b.Property<Guid>("Id") b.Property<Guid>("Id")
@ -1625,6 +1828,162 @@ namespace Kurs.Platform.Migrations
b.ToTable("PCustomEndpoint", (string)null); b.ToTable("PCustomEndpoint", (string)null);
}); });
modelBuilder.Entity("Kurs.Platform.Entities.CustomEntity", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uniqueidentifier");
b.Property<DateTime>("CreationTime")
.HasColumnType("datetime2")
.HasColumnName("CreationTime");
b.Property<Guid?>("CreatorId")
.HasColumnType("uniqueidentifier")
.HasColumnName("CreatorId");
b.Property<Guid?>("DeleterId")
.HasColumnType("uniqueidentifier")
.HasColumnName("DeleterId");
b.Property<DateTime?>("DeletionTime")
.HasColumnType("datetime2")
.HasColumnName("DeletionTime");
b.Property<string>("Description")
.HasMaxLength(500)
.HasColumnType("nvarchar(500)");
b.Property<string>("DisplayName")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("nvarchar(100)");
b.Property<string>("EndpointStatus")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("nvarchar(50)");
b.Property<bool>("HasAuditFields")
.HasColumnType("bit");
b.Property<bool>("HasSoftDelete")
.HasColumnType("bit");
b.Property<bool>("IsActive")
.HasColumnType("bit");
b.Property<bool>("IsDeleted")
.ValueGeneratedOnAdd()
.HasColumnType("bit")
.HasDefaultValue(false)
.HasColumnName("IsDeleted");
b.Property<DateTime?>("LastModificationTime")
.HasColumnType("datetime2")
.HasColumnName("LastModificationTime");
b.Property<Guid?>("LastModifierId")
.HasColumnType("uniqueidentifier")
.HasColumnName("LastModifierId");
b.Property<Guid?>("MigrationId")
.HasColumnType("uniqueidentifier");
b.Property<string>("MigrationStatus")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("nvarchar(50)");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("nvarchar(100)");
b.Property<string>("TableName")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("nvarchar(100)");
b.Property<Guid?>("TenantId")
.HasColumnType("uniqueidentifier")
.HasColumnName("TenantId");
b.HasKey("Id");
b.ToTable("PCustomEntity", (string)null);
});
modelBuilder.Entity("Kurs.Platform.Entities.CustomEntityField", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uniqueidentifier");
b.Property<DateTime>("CreationTime")
.HasColumnType("datetime2")
.HasColumnName("CreationTime");
b.Property<Guid?>("CreatorId")
.HasColumnType("uniqueidentifier")
.HasColumnName("CreatorId");
b.Property<string>("DefaultValue")
.HasColumnType("nvarchar(max)");
b.Property<Guid?>("DeleterId")
.HasColumnType("uniqueidentifier")
.HasColumnName("DeleterId");
b.Property<DateTime?>("DeletionTime")
.HasColumnType("datetime2")
.HasColumnName("DeletionTime");
b.Property<string>("Description")
.HasMaxLength(500)
.HasColumnType("nvarchar(500)");
b.Property<Guid>("EntityId")
.HasColumnType("uniqueidentifier");
b.Property<bool>("IsDeleted")
.ValueGeneratedOnAdd()
.HasColumnType("bit")
.HasDefaultValue(false)
.HasColumnName("IsDeleted");
b.Property<bool>("IsRequired")
.HasColumnType("bit");
b.Property<bool>("IsUnique")
.HasColumnType("bit");
b.Property<DateTime?>("LastModificationTime")
.HasColumnType("datetime2")
.HasColumnName("LastModificationTime");
b.Property<Guid?>("LastModifierId")
.HasColumnType("uniqueidentifier")
.HasColumnName("LastModifierId");
b.Property<int?>("MaxLength")
.HasColumnType("int");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("nvarchar(100)");
b.Property<string>("Type")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("nvarchar(50)");
b.HasKey("Id");
b.HasIndex("EntityId");
b.ToTable("PCustomEntityField", (string)null);
});
modelBuilder.Entity("Kurs.Platform.Entities.DataSource", b => modelBuilder.Entity("Kurs.Platform.Entities.DataSource", b =>
{ {
b.Property<Guid>("Id") b.Property<Guid>("Id")
@ -1711,6 +2070,28 @@ namespace Kurs.Platform.Migrations
b.ToTable("PGlobalSearch", (string)null); b.ToTable("PGlobalSearch", (string)null);
}); });
modelBuilder.Entity("Kurs.Platform.Entities.InstallmentOption", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<decimal>("Commission")
.HasPrecision(5, 3)
.HasColumnType("decimal(5,3)");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(32)
.HasColumnType("nvarchar(32)");
b.HasKey("Id");
b.ToTable("PInstallmentOption", (string)null);
});
modelBuilder.Entity("Kurs.Platform.Entities.IpRestriction", b => modelBuilder.Entity("Kurs.Platform.Entities.IpRestriction", b =>
{ {
b.Property<Guid>("Id") b.Property<Guid>("Id")
@ -2173,6 +2554,133 @@ namespace Kurs.Platform.Migrations
b.ToTable("PListFormField", (string)null); b.ToTable("PListFormField", (string)null);
}); });
modelBuilder.Entity("Kurs.Platform.Entities.ListFormImport", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uniqueidentifier");
b.Property<string>("BlobName")
.IsRequired()
.HasMaxLength(256)
.HasColumnType("nvarchar(256)");
b.Property<DateTime>("CreationTime")
.HasColumnType("datetime2")
.HasColumnName("CreationTime");
b.Property<Guid?>("CreatorId")
.HasColumnType("uniqueidentifier")
.HasColumnName("CreatorId");
b.Property<Guid?>("DeleterId")
.HasColumnType("uniqueidentifier")
.HasColumnName("DeleterId");
b.Property<DateTime?>("DeletionTime")
.HasColumnType("datetime2")
.HasColumnName("DeletionTime");
b.Property<bool>("IsDeleted")
.ValueGeneratedOnAdd()
.HasColumnType("bit")
.HasDefaultValue(false)
.HasColumnName("IsDeleted");
b.Property<DateTime?>("LastModificationTime")
.HasColumnType("datetime2")
.HasColumnName("LastModificationTime");
b.Property<Guid?>("LastModifierId")
.HasColumnType("uniqueidentifier")
.HasColumnName("LastModifierId");
b.Property<string>("ListFormCode")
.IsRequired()
.HasMaxLength(128)
.HasColumnType("nvarchar(128)");
b.Property<string>("Status")
.IsRequired()
.HasMaxLength(64)
.HasColumnType("nvarchar(64)");
b.Property<int>("TotalRows")
.HasColumnType("int");
b.HasKey("Id");
b.ToTable("PListFormImport", (string)null);
});
modelBuilder.Entity("Kurs.Platform.Entities.ListFormImportExecute", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uniqueidentifier");
b.Property<string>("BlobName")
.IsRequired()
.HasMaxLength(256)
.HasColumnType("nvarchar(256)");
b.Property<DateTime>("CreationTime")
.HasColumnType("datetime2")
.HasColumnName("CreationTime");
b.Property<Guid?>("CreatorId")
.HasColumnType("uniqueidentifier")
.HasColumnName("CreatorId");
b.Property<Guid?>("DeleterId")
.HasColumnType("uniqueidentifier")
.HasColumnName("DeleterId");
b.Property<DateTime?>("DeletionTime")
.HasColumnType("datetime2")
.HasColumnName("DeletionTime");
b.Property<int>("ErrorRows")
.HasColumnType("int");
b.Property<string>("ErrorsJson")
.HasColumnType("text");
b.Property<int>("ExecRows")
.HasColumnType("int");
b.Property<Guid>("ImportId")
.HasColumnType("uniqueidentifier");
b.Property<bool>("IsDeleted")
.ValueGeneratedOnAdd()
.HasColumnType("bit")
.HasDefaultValue(false)
.HasColumnName("IsDeleted");
b.Property<DateTime?>("LastModificationTime")
.HasColumnType("datetime2")
.HasColumnName("LastModificationTime");
b.Property<Guid?>("LastModifierId")
.HasColumnType("uniqueidentifier")
.HasColumnName("LastModifierId");
b.Property<double>("Progress")
.HasColumnType("float");
b.Property<string>("Status")
.IsRequired()
.HasMaxLength(64)
.HasColumnType("nvarchar(64)");
b.Property<int>("ValidRows")
.HasColumnType("int");
b.HasKey("Id");
b.ToTable("PListFormImportExecute", (string)null);
});
modelBuilder.Entity("Kurs.Platform.Entities.Menu", b => modelBuilder.Entity("Kurs.Platform.Entities.Menu", b =>
{ {
b.Property<Guid>("Id") b.Property<Guid>("Id")
@ -2269,6 +2777,113 @@ namespace Kurs.Platform.Migrations
b.ToTable("PMenu", (string)null); b.ToTable("PMenu", (string)null);
}); });
modelBuilder.Entity("Kurs.Platform.Entities.PaymentMethod", b =>
{
b.Property<string>("Id")
.HasColumnType("nvarchar(450)");
b.Property<decimal>("Commission")
.HasPrecision(5, 3)
.HasColumnType("decimal(5,3)");
b.Property<string>("Logo")
.HasMaxLength(32)
.HasColumnType("nvarchar(32)");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(64)
.HasColumnType("nvarchar(64)");
b.HasKey("Id");
b.ToTable("PPaymentMethod", (string)null);
});
modelBuilder.Entity("Kurs.Platform.Entities.Product", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uniqueidentifier");
b.Property<string>("Category")
.IsRequired()
.HasMaxLength(64)
.HasColumnType("nvarchar(64)");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.IsRequired()
.HasMaxLength(40)
.HasColumnType("nvarchar(40)")
.HasColumnName("ConcurrencyStamp");
b.Property<DateTime>("CreationTime")
.HasColumnType("datetime2")
.HasColumnName("CreationTime");
b.Property<Guid?>("CreatorId")
.HasColumnType("uniqueidentifier")
.HasColumnName("CreatorId");
b.Property<Guid?>("DeleterId")
.HasColumnType("uniqueidentifier")
.HasColumnName("DeleterId");
b.Property<DateTime?>("DeletionTime")
.HasColumnType("datetime2")
.HasColumnName("DeletionTime");
b.Property<string>("Description")
.HasMaxLength(1000)
.HasColumnType("nvarchar(1000)");
b.Property<string>("ExtraProperties")
.IsRequired()
.HasColumnType("nvarchar(max)")
.HasColumnName("ExtraProperties");
b.Property<string>("ImageUrl")
.HasMaxLength(300)
.HasColumnType("nvarchar(300)");
b.Property<bool>("IsDeleted")
.ValueGeneratedOnAdd()
.HasColumnType("bit")
.HasDefaultValue(false)
.HasColumnName("IsDeleted");
b.Property<bool>("IsQuantityBased")
.HasColumnType("bit");
b.Property<DateTime?>("LastModificationTime")
.HasColumnType("datetime2")
.HasColumnName("LastModificationTime");
b.Property<Guid?>("LastModifierId")
.HasColumnType("uniqueidentifier")
.HasColumnName("LastModifierId");
b.Property<decimal?>("MonthlyPrice")
.HasPrecision(18, 2)
.HasColumnType("decimal(18,2)");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(128)
.HasColumnType("nvarchar(128)");
b.Property<int>("Order")
.HasColumnType("int");
b.Property<decimal?>("YearlyPrice")
.HasPrecision(18, 2)
.HasColumnType("decimal(18,2)");
b.HasKey("Id");
b.ToTable("PProduct", (string)null);
});
modelBuilder.Entity("Kurs.Platform.Entities.Route", b => modelBuilder.Entity("Kurs.Platform.Entities.Route", b =>
{ {
b.Property<Guid>("Id") b.Property<Guid>("Id")
@ -2764,6 +3379,211 @@ namespace Kurs.Platform.Migrations
b.ToTable("PForumTopic", (string)null); b.ToTable("PForumTopic", (string)null);
}); });
modelBuilder.Entity("Kurs.Platform.Orders.Order", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uniqueidentifier");
b.Property<string>("Address")
.HasColumnType("nvarchar(max)");
b.Property<string>("Address2")
.HasColumnType("nvarchar(max)");
b.Property<string>("City")
.HasColumnType("nvarchar(max)");
b.Property<decimal>("Commission")
.HasPrecision(18, 2)
.HasColumnType("decimal(18,2)");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.IsRequired()
.HasMaxLength(40)
.HasColumnType("nvarchar(40)")
.HasColumnName("ConcurrencyStamp");
b.Property<string>("Country")
.HasColumnType("nvarchar(max)");
b.Property<DateTime>("CreationTime")
.HasColumnType("datetime2")
.HasColumnName("CreationTime");
b.Property<Guid?>("CreatorId")
.HasColumnType("uniqueidentifier")
.HasColumnName("CreatorId");
b.Property<Guid?>("DeleterId")
.HasColumnType("uniqueidentifier")
.HasColumnName("DeleterId");
b.Property<DateTime?>("DeletionTime")
.HasColumnType("datetime2")
.HasColumnName("DeletionTime");
b.Property<string>("District")
.HasColumnType("nvarchar(max)");
b.Property<string>("Email")
.HasColumnType("nvarchar(max)");
b.Property<string>("ExtraProperties")
.IsRequired()
.HasColumnType("nvarchar(max)")
.HasColumnName("ExtraProperties");
b.Property<long>("Fax")
.HasColumnType("bigint");
b.Property<string>("Founder")
.HasColumnType("nvarchar(max)");
b.Property<string>("InstallmentName")
.HasMaxLength(128)
.HasColumnType("nvarchar(128)");
b.Property<int?>("Installments")
.HasColumnType("int");
b.Property<string>("InstitutionName")
.HasColumnType("nvarchar(max)");
b.Property<bool>("IsDeleted")
.ValueGeneratedOnAdd()
.HasColumnType("bit")
.HasDefaultValue(false)
.HasColumnName("IsDeleted");
b.Property<DateTime?>("LastModificationTime")
.HasColumnType("datetime2")
.HasColumnName("LastModificationTime");
b.Property<Guid?>("LastModifierId")
.HasColumnType("uniqueidentifier")
.HasColumnName("LastModifierId");
b.Property<long>("Mobile")
.HasColumnType("bigint");
b.Property<string>("PaymentDataJson")
.HasMaxLength(4000)
.HasColumnType("nvarchar(4000)");
b.Property<string>("PaymentMethod")
.IsRequired()
.HasMaxLength(64)
.HasColumnType("nvarchar(64)");
b.Property<long>("Phone")
.HasColumnType("bigint");
b.Property<string>("PostalCode")
.HasColumnType("nvarchar(max)");
b.Property<decimal>("Subtotal")
.HasPrecision(18, 2)
.HasColumnType("decimal(18,2)");
b.Property<string>("TaxOffice")
.HasColumnType("nvarchar(max)");
b.Property<Guid?>("TenantId")
.HasColumnType("uniqueidentifier");
b.Property<decimal>("Total")
.HasPrecision(18, 2)
.HasColumnType("decimal(18,2)");
b.Property<long>("VknTckn")
.HasColumnType("bigint");
b.Property<string>("Website")
.HasColumnType("nvarchar(max)");
b.HasKey("Id");
b.ToTable("POrder", (string)null);
});
modelBuilder.Entity("Kurs.Platform.Orders.OrderItem", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uniqueidentifier");
b.Property<string>("BillingCycle")
.IsRequired()
.HasMaxLength(32)
.HasColumnType("nvarchar(32)");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.IsRequired()
.HasMaxLength(40)
.HasColumnType("nvarchar(40)")
.HasColumnName("ConcurrencyStamp");
b.Property<DateTime>("CreationTime")
.HasColumnType("datetime2")
.HasColumnName("CreationTime");
b.Property<Guid?>("CreatorId")
.HasColumnType("uniqueidentifier")
.HasColumnName("CreatorId");
b.Property<Guid?>("DeleterId")
.HasColumnType("uniqueidentifier")
.HasColumnName("DeleterId");
b.Property<DateTime?>("DeletionTime")
.HasColumnType("datetime2")
.HasColumnName("DeletionTime");
b.Property<string>("ExtraProperties")
.IsRequired()
.HasColumnType("nvarchar(max)")
.HasColumnName("ExtraProperties");
b.Property<bool>("IsDeleted")
.ValueGeneratedOnAdd()
.HasColumnType("bit")
.HasDefaultValue(false)
.HasColumnName("IsDeleted");
b.Property<DateTime?>("LastModificationTime")
.HasColumnType("datetime2")
.HasColumnName("LastModificationTime");
b.Property<Guid?>("LastModifierId")
.HasColumnType("uniqueidentifier")
.HasColumnName("LastModifierId");
b.Property<Guid>("OrderId")
.HasColumnType("uniqueidentifier");
b.Property<Guid>("ProductId")
.HasColumnType("uniqueidentifier");
b.Property<string>("ProductName")
.IsRequired()
.HasMaxLength(128)
.HasColumnType("nvarchar(128)");
b.Property<int>("Quantity")
.HasColumnType("int");
b.Property<decimal>("TotalPrice")
.HasPrecision(18, 2)
.HasColumnType("decimal(18,2)");
b.HasKey("Id");
b.HasIndex("OrderId");
b.ToTable("POrderItem", (string)null);
});
modelBuilder.Entity("Kurs.Settings.Entities.SettingDefinition", b => modelBuilder.Entity("Kurs.Settings.Entities.SettingDefinition", b =>
{ {
b.Property<Guid>("Id") b.Property<Guid>("Id")
@ -4751,6 +5571,9 @@ namespace Kurs.Platform.Migrations
b.Property<long>("Fax") b.Property<long>("Fax")
.HasColumnType("bigint"); .HasColumnType("bigint");
b.Property<string>("Founder")
.HasColumnType("nvarchar(max)");
b.Property<string>("InstitutionName") b.Property<string>("InstitutionName")
.HasMaxLength(64) .HasMaxLength(64)
.HasColumnType("nvarchar(64)"); .HasColumnType("nvarchar(64)");
@ -4841,6 +5664,26 @@ namespace Kurs.Platform.Migrations
.OnDelete(DeleteBehavior.SetNull); .OnDelete(DeleteBehavior.SetNull);
}); });
modelBuilder.Entity("Kurs.Platform.Entities.ApiEndpoint", b =>
{
b.HasOne("Kurs.Platform.Entities.CustomEntity", "Entity")
.WithMany()
.HasForeignKey("EntityId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Entity");
});
modelBuilder.Entity("Kurs.Platform.Entities.ApiMigration", b =>
{
b.HasOne("Kurs.Platform.Entities.CustomEntity", "Entity")
.WithMany()
.HasForeignKey("EntityId");
b.Navigation("Entity");
});
modelBuilder.Entity("Kurs.Platform.Entities.BankAccount", b => modelBuilder.Entity("Kurs.Platform.Entities.BankAccount", b =>
{ {
b.HasOne("Kurs.Platform.Entities.Bank", "Bank") b.HasOne("Kurs.Platform.Entities.Bank", "Bank")
@ -4889,6 +5732,17 @@ namespace Kurs.Platform.Migrations
.OnDelete(DeleteBehavior.Restrict); .OnDelete(DeleteBehavior.Restrict);
}); });
modelBuilder.Entity("Kurs.Platform.Entities.CustomEntityField", b =>
{
b.HasOne("Kurs.Platform.Entities.CustomEntity", "Entity")
.WithMany("Fields")
.HasForeignKey("EntityId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Entity");
});
modelBuilder.Entity("Kurs.Platform.Entities.ListFormCustomization", b => modelBuilder.Entity("Kurs.Platform.Entities.ListFormCustomization", b =>
{ {
b.HasOne("Kurs.Platform.Entities.ListForm", null) b.HasOne("Kurs.Platform.Entities.ListForm", null)
@ -4950,6 +5804,16 @@ namespace Kurs.Platform.Migrations
b.Navigation("Category"); b.Navigation("Category");
}); });
modelBuilder.Entity("Kurs.Platform.Orders.OrderItem", b =>
{
b.HasOne("Kurs.Platform.Orders.Order", "Order")
.WithMany("Items")
.HasForeignKey("OrderId")
.OnDelete(DeleteBehavior.Cascade);
b.Navigation("Order");
});
modelBuilder.Entity("Skill", b => modelBuilder.Entity("Skill", b =>
{ {
b.HasOne("SkillType", null) b.HasOne("SkillType", null)
@ -5121,6 +5985,11 @@ namespace Kurs.Platform.Migrations
b.Navigation("Cities"); b.Navigation("Cities");
}); });
modelBuilder.Entity("Kurs.Platform.Entities.CustomEntity", b =>
{
b.Navigation("Fields");
});
modelBuilder.Entity("Kurs.Platform.Entities.UomCategory", b => modelBuilder.Entity("Kurs.Platform.Entities.UomCategory", b =>
{ {
b.Navigation("Units"); b.Navigation("Units");
@ -5141,6 +6010,11 @@ namespace Kurs.Platform.Migrations
b.Navigation("Posts"); b.Navigation("Posts");
}); });
modelBuilder.Entity("Kurs.Platform.Orders.Order", b =>
{
b.Navigation("Items");
});
modelBuilder.Entity("SkillType", b => modelBuilder.Entity("SkillType", b =>
{ {
b.Navigation("Levels"); b.Navigation("Levels");

View file

@ -1,15 +1,20 @@
using System.Threading.Tasks; using System;
using System.Threading.Tasks;
using Kurs.Platform.Entities;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
using Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations; using Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations;
using Volo.Abp.Data; using Volo.Abp.Data;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain.Entities;
using Volo.Abp.Domain.Repositories;
namespace Kurs.Platform.Extensions; namespace Kurs.Platform.Extensions;
public class PlatformApplicationConfigurationContributor : IApplicationConfigurationContributor public class PlatformApplicationConfigurationContributor : IApplicationConfigurationContributor, ITransientDependency
{ {
public Task ContributeAsync(ApplicationConfigurationContributorContext context) public async Task ContributeAsync(ApplicationConfigurationContributorContext context)
{ {
var hostEnvironment = context.ServiceProvider.GetRequiredService<IHostEnvironment>(); var hostEnvironment = context.ServiceProvider.GetRequiredService<IHostEnvironment>();
context.ApplicationConfiguration.SetProperty("environment", hostEnvironment.EnvironmentName); context.ApplicationConfiguration.SetProperty("environment", hostEnvironment.EnvironmentName);
@ -17,6 +22,12 @@ public class PlatformApplicationConfigurationContributor : IApplicationConfigura
var configuration = context.ServiceProvider.GetRequiredService<IConfiguration>(); var configuration = context.ServiceProvider.GetRequiredService<IConfiguration>();
context.ApplicationConfiguration.SetProperty("version", configuration.GetValue<string>("App:Version")); context.ApplicationConfiguration.SetProperty("version", configuration.GetValue<string>("App:Version"));
return Task.CompletedTask; var routeRepository = context.ServiceProvider.GetRequiredService<IRepository<Route, Guid>>();
var items = await routeRepository.GetListAsync() ?? throw new EntityNotFoundException("RecordNotFound");
context.ApplicationConfiguration.SetProperty("routes", items);
var customComponentRepository = context.ServiceProvider.GetRequiredService<IRepository<CustomComponent, Guid>>();
var customComponents = await customComponentRepository.GetListAsync() ?? throw new EntityNotFoundException("RecordNotFound");
context.ApplicationConfiguration.SetProperty("customComponents", customComponents);
} }
} }

View file

@ -125,7 +125,7 @@ public class PlatformSignInManager : AbpSignInManager, IPlatformSignInManager
return false; return false;
} }
if (!tenant.GetIsActiveTenant()) if (!tenant.GetIsActive())
{ {
Logger.LogWarning(PlatformEventIds.UserCannotSignInTenantIsPassive, "Tenant is inactive."); Logger.LogWarning(PlatformEventIds.UserCannotSignInTenantIsPassive, "Tenant is inactive.");
return false; return false;

View file

@ -329,6 +329,14 @@ public class PlatformHttpApiHostModule : AbpModule
fileSystem.BasePath = configuration["App:CdnPath"]; fileSystem.BasePath = configuration["App:CdnPath"];
}); });
}); });
options.Containers.Configure<ImportBlobContainer>(container =>
{
container.UseFileSystem(fileSystem =>
{
fileSystem.BasePath = configuration["App:ImportPath"];
});
});
}); });
} }

View file

@ -1,11 +1,12 @@
{ {
"App": { "App": {
"SelfUrl": "https://kurs-dev-api.sozsoft.com", "SelfUrl": "https://dev-api.sozsoft.com",
"ClientUrl": "https://kurs-dev.sozsoft.com", "ClientUrl": "https://dev.sozsoft.com",
"CorsOrigins": "https://sozsoft.com,https://kurs-dev.sozsoft.com", "CorsOrigins": "https://sozsoft.com,https://dev.sozsoft.com",
"RedirectAllowedUrls": "https://kurs-dev.sozsoft.com,https://kurs-dev.sozsoft.com/authentication/callback", "RedirectAllowedUrls": "https://dev.sozsoft.com,https://dev.sozsoft.com/authentication/callback",
"AttachmentsPath": "/etc/api/mail-queue/attachments", "AttachmentsPath": "/etc/api/mail-queue/attachments",
"CdnPath": "/etc/api/cdn" "CdnPath": "/etc/api/cdn",
"ImportPath": "/etc/api/import"
}, },
"ConnectionStrings": { "ConnectionStrings": {
"SqlServer": "Server=sql;Database=KURS;User Id=sa;password=NvQp8s@l;Trusted_Connection=False;TrustServerCertificate=True;", "SqlServer": "Server=sql;Database=KURS;User Id=sa;password=NvQp8s@l;Trusted_Connection=False;TrustServerCertificate=True;",
@ -16,7 +17,7 @@
"Configuration": "redis:6379,abortConnect=false,connectTimeout=30000,responseTimeout=30000" "Configuration": "redis:6379,abortConnect=false,connectTimeout=30000,responseTimeout=30000"
}, },
"AuthServer": { "AuthServer": {
"Authority": "https://kurs-dev-api.sozsoft.com", "Authority": "https://dev-api.sozsoft.com",
"RequireHttpsMetadata": false, "RequireHttpsMetadata": false,
"SwaggerClientId": "Platform_Swagger" "SwaggerClientId": "Platform_Swagger"
}, },

View file

@ -1,11 +1,12 @@
{ {
"App": { "App": {
"SelfUrl": "https://kurs-api.sozsoft.com", "SelfUrl": "https://api.sozsoft.com",
"ClientUrl": "https://kurs.sozsoft.com", "ClientUrl": "https://sozsoft.com",
"CorsOrigins": "https://sozsoft.com,https://kurs.sozsoft.com,https://demo.sozsoft.com", "CorsOrigins": "https://sozsoft.com,https://sozsoft.com,https://demo.sozsoft.com",
"RedirectAllowedUrls": "https://kurs.sozsoft.com,https://kurs.sozsoft.com/authentication/callback", "RedirectAllowedUrls": "https://sozsoft.com,https://sozsoft.com/authentication/callback",
"AttachmentsPath": "/etc/api/mail-queue/attachments", "AttachmentsPath": "/etc/api/mail-queue/attachments",
"CdnPath": "/etc/api/cdn" "CdnPath": "/etc/api/cdn",
"ImportPath": "/etc/api/import"
}, },
"ConnectionStrings": { "ConnectionStrings": {
"SqlServer": "Server=sql;Database=KURS;User Id=sa;password=NvQp8s@l;Trusted_Connection=False;TrustServerCertificate=True;", "SqlServer": "Server=sql;Database=KURS;User Id=sa;password=NvQp8s@l;Trusted_Connection=False;TrustServerCertificate=True;",
@ -16,7 +17,7 @@
"Configuration": "redis:6379,abortConnect=false,connectTimeout=30000,responseTimeout=30000" "Configuration": "redis:6379,abortConnect=false,connectTimeout=30000,responseTimeout=30000"
}, },
"AuthServer": { "AuthServer": {
"Authority": "https://kurs-api.sozsoft.com", "Authority": "https://api.sozsoft.com",
"RequireHttpsMetadata": false, "RequireHttpsMetadata": false,
"SwaggerClientId": "Platform_Swagger" "SwaggerClientId": "Platform_Swagger"
}, },

View file

@ -2,10 +2,11 @@
"App": { "App": {
"SelfUrl": "https://localhost:44344", "SelfUrl": "https://localhost:44344",
"ClientUrl": "http://localhost:3000", "ClientUrl": "http://localhost:3000",
"CorsOrigins": "http://localhost,http://localhost:3000,http://localhost:3003,http://localhost:4200,http://localhost:5173", "CorsOrigins": "http://localhost,http://localhost:3000,http://localhost:3001,http://localhost:3003,http://localhost:4200,http://localhost:5173",
"RedirectAllowedUrls": "http://localhost:4200,http://localhost:4200/authentication/callback", "RedirectAllowedUrls": "http://localhost:4200,http://localhost:4200/authentication/callback",
"AttachmentsPath": "C:\\Private\\Projects\\sozsoft\\configs\\mail-queue\\attachments", "AttachmentsPath": "C:\\Private\\Projects\\sozsoft\\configs\\mail-queue\\attachments",
"CdnPath": "C:\\Private\\Projects\\sozsoft\\configs\\docker\\data\\cdn", "CdnPath": "C:\\Private\\Projects\\sozsoft\\configs\\docker\\data\\cdn",
"ImportPath": "C:\\Private\\Projects\\sozsoft\\configs\\docker\\data\\import",
"Version": "1.0.4" "Version": "1.0.4"
}, },
"ConnectionStrings": { "ConnectionStrings": {

View file

@ -1,4 +0,0 @@
VITE_APPLICATION_BASEURL='http://localhost:3003/'
VITE_API_URL='https://localhost:44344'
VITE_KURS_URL='http://localhost:3000/'
VITE_CDN_URL='http://localhost:4005'

View file

@ -1,4 +0,0 @@
VITE_APPLICATION_BASEURL='https://sozsoft.com'
VITE_API_URL='https://kurs-dev-api.sozsoft.com'
VITE_KURS_URL='https://kurs-dev.sozsoft.com'
VITE_CDN_URL='https://kurs-dev-cdn.sozsoft.com'

View file

@ -1,4 +0,0 @@
VITE_APPLICATION_BASEURL='https://sozsoft.com'
VITE_API_URL='https://kurs-api.sozsoft.com'
VITE_KURS_URL='https://kurs.sozsoft.com'
VITE_CDN_URL='https://kurs-cdn.sozsoft.com'

24
company/.gitignore vendored
View file

@ -1,24 +0,0 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

View file

@ -1,12 +0,0 @@
ARG ENV="dev"
FROM node:22-alpine
ARG ENV=$ENV
ENV GENERATE_SOURCEMAP=false
ENV NODE_OPTIONS=--max-old-space-size=16384
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm i
COPY . .
RUN npm run build -- --mode $ENV
CMD ["npm", "run", "preview"]

View file

@ -1 +0,0 @@
# website

View file

@ -1,159 +0,0 @@
# Company Uygulaması API Entegrasyonu
Bu dokümantasyon, Company uygulamasına yapılan API entegrasyonu, üyelik sistemi, forum ve dinamik blog özelliklerini açıklamaktadır.
## 🚀 Yapılan Değişiklikler
### 1. API Entegrasyonu
- **Axios** ve **React Query** kullanılarak API yapısı kuruldu
- API servis katmanı oluşturuldu (`/src/services/`)
- Interceptor'lar ile otomatik token yönetimi eklendi
### 2. Üyelik Sistemi
- **Zustand** ile state management kuruldu
- Login ve Register sayfaları oluşturuldu
- JWT token tabanlı authentication sistemi entegre edildi
- Protected route yapısı kuruldu
### 3. Forum Sistemi
- Kapsamlı forum sayfası oluşturuldu
- Kategori, konu ve mesaj yönetimi
- Like, pin, lock gibi özellikler
- Etiket sistemi
### 4. Dinamik Blog
- Static blog yapısı dinamik hale getirildi
- Kategori filtreleme
- Arama özelliği
- Sayfalama (pagination)
- Etiket sistemi
## 📦 Yeni Eklenen Paketler
```json
{
"axios": "^1.6.5",
"@tanstack/react-query": "^5.17.9",
"zustand": "^4.4.7",
"react-hook-form": "^7.48.2",
"date-fns": "^3.2.0",
"react-markdown": "^9.0.1",
"react-hot-toast": "^2.4.1"
}
```
## 🛠️ Kurulum
1. Paketleri yükleyin:
```bash
cd company
npm install
```
2. Environment değişkenlerini ayarlayın:
```env
VITE_API_URL=http://localhost:44328
```
## 📁 Yeni Dosya Yapısı
```
company/src/
├── services/
│ └── api/
│ ├── config.ts # Axios yapılandırması
│ ├── auth.service.ts # Authentication servisi
│ ├── blog.service.ts # Blog API servisi
│ └── forum.service.ts # Forum API servisi
├── store/
│ └── authStore.ts # Zustand auth store
├── pages/
│ ├── Login.tsx # Giriş sayfası
│ ├── Register.tsx # Kayıt sayfası
│ ├── Forum.tsx # Forum ana sayfası
│ └── Blog.tsx # Dinamik blog sayfası (güncellendi)
└── components/
└── layout/
└── Header.tsx # Auth butonları eklendi
```
## 🔐 Authentication Akışı (UI Uygulaması ile Aynı)
1. Kullanıcı login sayfasından giriş yapar
2. OAuth2 `/connect/token` endpoint'i kullanılarak token alınır
3. Access token ve refresh token localStorage'a kaydedilir
4. `/api/abp/application-configuration` endpoint'inden kullanıcı bilgileri çekilir
5. Axios interceptor ile her istekte:
- Authorization header'a Bearer token eklenir
- `__tenant` header'a tenant ID eklenir (multi-tenancy desteği)
6. Protected route'lar için authentication kontrolü yapılır
7. Token expire olduğunda refresh token ile yenilenir
8. Refresh token da expire olduysa otomatik logout
### OAuth2 Parametreleri
- **grant_type**: password
- **scope**: offline_access Platform
- **client_id**: Platform_App
- **client_secret**: 1q2w3e*
## 🌟 Özellikler
### Forum
- Kategori bazlı konu listeleme
- Yeni konu açma
- Konulara cevap yazma
- Like/Unlike
- Pin/Unpin (moderatör)
- Lock/Unlock (moderatör)
- Çözüldü olarak işaretleme
- Etiket sistemi
- Arama özelliği
### Blog
- Dinamik içerik yönetimi
- Kategori filtreleme
- Arama
- Sayfalama
- Yorum sistemi
- Like sistemi
- Etiketler
## 🔄 API Endpoints
### Authentication (UI ile Aynı Endpoint'ler)
- `POST /connect/token` - OAuth2 token endpoint (Login & Refresh)
- `POST /api/account/register` - Register
- `GET /api/abp/application-configuration` - Current user & app config
### Blog
- `GET /api/app/blog/posts` - Blog listesi
- `GET /api/app/blog/posts/:id` - Blog detay
- `GET /api/app/blog/categories` - Kategoriler
- `POST /api/app/blog/comments` - Yorum ekle
### Forum
- `GET /api/app/forum/categories` - Forum kategorileri
- `GET /api/app/forum/topics` - Konu listesi
- `POST /api/app/forum/topics` - Yeni konu
- `GET /api/app/forum/topics/:id/posts` - Konu mesajları
- `POST /api/app/forum/posts` - Yeni mesaj
## ⚠️ Dikkat Edilmesi Gerekenler
1. **UI uygulaması ile aynı auth yapısı kullanılıyor** - Aynı token'lar ve endpoint'ler
2. Blog ve Forum API endpoint'leri henüz backend'de implement edilmemiş olabilir
3. CORS ayarlarının yapılması gerekebilir (Company domain'i için)
4. Production için environment değişkenlerinin güncellenmesi gerekir
5. Error handling mekanizmaları geliştirilmeli
6. Multi-tenancy desteği aktif - Tenant header'ı otomatik ekleniyor
## 🚧 Yapılacaklar
- [ ] Backend API endpoint'lerinin implement edilmesi
- [ ] Profil sayfası oluşturulması
- [ ] Forum moderasyon paneli
- [ ] Blog admin paneli
- [ ] Bildirim sistemi
- [ ] Real-time özellikler (WebSocket)
- [ ] Dosya yükleme sistemi
- [ ] Gelişmiş arama özellikleri

View file

@ -1,28 +0,0 @@
import js from '@eslint/js';
import globals from 'globals';
import reactHooks from 'eslint-plugin-react-hooks';
import reactRefresh from 'eslint-plugin-react-refresh';
import tseslint from 'typescript-eslint';
export default tseslint.config(
{ ignores: ['dist'] },
{
extends: [js.configs.recommended, ...tseslint.configs.recommended],
files: ['**/*.{ts,tsx}'],
languageOptions: {
ecmaVersion: 2020,
globals: globals.browser,
},
plugins: {
'react-hooks': reactHooks,
'react-refresh': reactRefresh,
},
rules: {
...reactHooks.configs.recommended.rules,
'react-refresh/only-export-components': [
'warn',
{ allowConstantExport: true },
],
},
}
);

Some files were not shown because too many files have changed in this diff Show more