diff --git a/.gitignore b/.gitignore index 79c4662..8e0c015 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ configs/**/data/** - +*.bak **/node_modules **/.DS_Store logs/ \ No newline at end of file diff --git a/api/src/Sozsoft.Platform.Application/BackgroundWorker/BackgroundWorkerAppService.cs b/api/src/Sozsoft.Platform.Application/BackgroundWorker/BackgroundWorkerAppService.cs index a69f61f..a025419 100644 --- a/api/src/Sozsoft.Platform.Application/BackgroundWorker/BackgroundWorkerAppService.cs +++ b/api/src/Sozsoft.Platform.Application/BackgroundWorker/BackgroundWorkerAppService.cs @@ -59,12 +59,12 @@ public class BackgroundWorkerAppService : PlatformAppService foreach (var worker in workers) { - var w = LazyServiceProvider.GetRequiredService(); + var workerId = worker.Id; - RecurringJob.AddOrUpdate( + RecurringJob.AddOrUpdate( $"{worker.WorkerType}:{worker.Name}", "platform", - () => w.StartAsync(worker.Id, default), + (w) => w.StartAsync(workerId, default), worker.Cron, new RecurringJobOptions { diff --git a/api/src/Sozsoft.Platform.Application/FileManagement/FileManagementAppService.cs b/api/src/Sozsoft.Platform.Application/FileManagement/FileManagementAppService.cs index 3691118..5349985 100644 --- a/api/src/Sozsoft.Platform.Application/FileManagement/FileManagementAppService.cs +++ b/api/src/Sozsoft.Platform.Application/FileManagement/FileManagementAppService.cs @@ -35,6 +35,7 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe // BlobContainerNames.Import, // BlobContainerNames.Note, // BlobContainerNames.Intranet + // BlobContainerNames.Backup }; public FileManagementAppService( diff --git a/api/src/Sozsoft.Platform.DbMigrator/Seeds/HostDataSeeder.cs b/api/src/Sozsoft.Platform.DbMigrator/Seeds/HostDataSeeder.cs index caf4ab2..3a26fca 100644 --- a/api/src/Sozsoft.Platform.DbMigrator/Seeds/HostDataSeeder.cs +++ b/api/src/Sozsoft.Platform.DbMigrator/Seeds/HostDataSeeder.cs @@ -42,6 +42,8 @@ public class BackgroundWorkerSeedDto public string WorkerType { get; set; } public bool IsActive { get; set; } public string DataSourceCode { get; set; } + public string BeforeSp { get; set; } + public string AfterSp { get; set; } } public class NotificationRuleSeedDto @@ -435,7 +437,9 @@ public class HostDataSeeder : IDataSeedContributor, ITransientDependency Cron = item.Cron, WorkerType = Enum.Parse(item.WorkerType), IsActive = item.IsActive, - DataSourceCode = item.DataSourceCode + DataSourceCode = item.DataSourceCode, + BeforeSp = item.BeforeSp, + AfterSp = item.AfterSp }); } } diff --git a/api/src/Sozsoft.Platform.Domain/BackgroundWorkers/PlatformBackgroundWorker.cs b/api/src/Sozsoft.Platform.Domain/BackgroundWorkers/PlatformBackgroundWorker.cs index 474fd60..b004aef 100644 --- a/api/src/Sozsoft.Platform.Domain/BackgroundWorkers/PlatformBackgroundWorker.cs +++ b/api/src/Sozsoft.Platform.Domain/BackgroundWorkers/PlatformBackgroundWorker.cs @@ -20,6 +20,7 @@ using Volo.Abp.Settings; using Volo.Abp.Users; using Microsoft.Extensions.Configuration; using System.IO; +using Volo.Abp.Uow; namespace Sozsoft.Platform.BackgroundWorkers; @@ -56,6 +57,8 @@ public class PlatformBackgroundWorker : PlatformDomainService, IPlatformBackgrou public async Task StartAsync(Guid WorkerId, CancellationToken cancellationToken = default) { + using var uow = LazyServiceProvider.LazyGetRequiredService().Begin(requiresNew: true, isTransactional: false); + var Worker = await Repository.GetAsync(a => a.Id == WorkerId); var LogPrefix = $"{Clock.Now:s}_{Worker.Name}: {{0}}"; @@ -80,7 +83,7 @@ public class PlatformBackgroundWorker : PlatformDomainService, IPlatformBackgrou // Backup Worker için yedeklerin saklanacağı klasörün oluşturulması if (Worker.WorkerType == WorkerTypeEnum.BackupWorker) { - backupPath = Path.Combine(Configuration["App:CdnPath"], "host", "backup"); + backupPath = Configuration["App:BackupPath"]; if (!Directory.Exists(backupPath)) { Directory.CreateDirectory(backupPath); diff --git a/api/src/Sozsoft.Platform.Domain/BlobStoring/BlobContainerNames.cs b/api/src/Sozsoft.Platform.Domain/BlobStoring/BlobContainerNames.cs index 8959728..962cbed 100644 --- a/api/src/Sozsoft.Platform.Domain/BlobStoring/BlobContainerNames.cs +++ b/api/src/Sozsoft.Platform.Domain/BlobStoring/BlobContainerNames.cs @@ -6,4 +6,5 @@ public static class BlobContainerNames public const string Avatar = "avatar"; public const string Import = "import"; public const string Note = "note"; + public const string Backup = "backup"; } diff --git a/api/src/Sozsoft.Platform.HttpApi.Host/appsettings.Production.json b/api/src/Sozsoft.Platform.HttpApi.Host/appsettings.Production.json index cdd0b1a..4001ed9 100644 --- a/api/src/Sozsoft.Platform.HttpApi.Host/appsettings.Production.json +++ b/api/src/Sozsoft.Platform.HttpApi.Host/appsettings.Production.json @@ -7,6 +7,7 @@ "AttachmentsPath": "/etc/api/mail-queue/attachments", "CdnPath": "/etc/api/cdn", "BaseDomain": "sozsoft.com", + "BackupPath": "/var/opt/mssql/backup", "BackupDeleteAfterDays": 3 }, "ConnectionStrings": { diff --git a/configs/deployment/docker-compose-app.yml b/configs/deployment/docker-compose-app.yml index b196a7b..593884d 100644 --- a/configs/deployment/docker-compose-app.yml +++ b/configs/deployment/docker-compose-app.yml @@ -8,6 +8,9 @@ networks: volumes: cdn: api-keys: + sql-backups: + external: true + name: sozsoft-platform-data_sql-backups services: migrator: @@ -31,6 +34,7 @@ services: - 8080:8080 volumes: - cdn:/etc/api/cdn + - sql-backups:/etc/api/cdn/host/backup - api-keys:/root/.aspnet/DataProtection-Keys networks: - db @@ -53,7 +57,8 @@ services: profiles: ["ui"] working_dir: /srv/http-server volumes: - - cdn:/public:ro + - cdn:/public + - sql-backups:/public/host/backup command: "/public -c10 --cors" ports: - 8081:8080 diff --git a/configs/deployment/docker-compose-data.yml b/configs/deployment/docker-compose-data.yml index 4010fda..dda3064 100644 --- a/configs/deployment/docker-compose-data.yml +++ b/configs/deployment/docker-compose-data.yml @@ -9,6 +9,7 @@ networks: volumes: pg: mssql: + sql-backups: services: redis: @@ -46,5 +47,6 @@ services: - 1433:1433 volumes: - mssql:/var/opt/mssql + - sql-backups:/var/opt/mssql/backup networks: - db diff --git a/configs/docker/docker-compose-data.yml b/configs/docker/docker-compose-data.yml index 51052da..3a63f0a 100644 --- a/configs/docker/docker-compose-data.yml +++ b/configs/docker/docker-compose-data.yml @@ -46,4 +46,4 @@ services: - 1433:1433 volumes: - mssql:/var/opt/mssql - - /etc/api/cdn/host/backup:/var/opt/mssql/backup \ No newline at end of file + - ./data/cdn/host/backup:/var/opt/mssql/backup \ No newline at end of file diff --git a/ui/src/views/admin/files/FileManager.tsx b/ui/src/views/admin/files/FileManager.tsx index a2b768f..f5d465b 100644 --- a/ui/src/views/admin/files/FileManager.tsx +++ b/ui/src/views/admin/files/FileManager.tsx @@ -39,6 +39,8 @@ import type { import classNames from 'classnames' import { APP_NAME } from '@/constants/app.constant' +const { VITE_CDN_URL } = import.meta.env + // Select options for sorting const FileManager = () => { @@ -134,7 +136,7 @@ const FileManager = () => { const items = response.data.items || [] // Manual protection for system folders const protectedItems = items.map((item) => { - const isSystemFolder = ['avatar', 'import', 'note'].includes(item.name.toLowerCase()) + const isSystemFolder = ['intranet', 'avatar', 'import', 'note', 'backup'].includes(item.name.toLowerCase()) return { ...item, isReadOnly: item.isReadOnly || isSystemFolder, @@ -373,21 +375,18 @@ const FileManager = () => { } } - const handleDownload = async (item: FileItemType) => { - try { - const blob = await fileManagementService.downloadFile(item.id, selectedTenant?.id) - const url = URL.createObjectURL(blob) - const a = document.createElement('a') - a.href = url - a.download = item.name - document.body.appendChild(a) - a.click() - document.body.removeChild(a) - URL.revokeObjectURL(url) - } catch (error) { - console.error('Download failed:', error) - toast.push(Failed to download file) - } + const handleDownload = (item: FileItemType) => { + const tenantSegment = selectedTenant?.id ? `tenants/${selectedTenant.id}` : 'host' + const filePath = item.id.replace(/\|/g, '/') + const url = `${VITE_CDN_URL}/${tenantSegment}/${filePath}` + const a = document.createElement('a') + a.href = url + a.download = item.name + a.target = '_blank' + a.rel = 'noopener noreferrer' + document.body.appendChild(a) + a.click() + document.body.removeChild(a) } // Action handlers