From 4740e89c22383e6d09b5cc58d5b30fe56f3cc544 Mon Sep 17 00:00:00 2001 From: Hamid Reza Mohammadi Date: Fri, 10 Jul 2026 15:56:40 +0330 Subject: [PATCH 1/9] .net 10 publish profiles --- .../Properties/PublishProfiles/FolderProfile.pubxml | 8 +++----- .../Properties/PublishProfiles/FolderProfile.pubxml | 8 +++----- .../Properties/PublishProfiles/FolderProfile.pubxml | 12 +++++++----- TajikGanjoor/dotnet-tools.json | 13 +++++++++++++ 4 files changed, 26 insertions(+), 15 deletions(-) create mode 100644 TajikGanjoor/dotnet-tools.json diff --git a/GanjooRazor/Properties/PublishProfiles/FolderProfile.pubxml b/GanjooRazor/Properties/PublishProfiles/FolderProfile.pubxml index 737b3459..a4383cad 100644 --- a/GanjooRazor/Properties/PublishProfiles/FolderProfile.pubxml +++ b/GanjooRazor/Properties/PublishProfiles/FolderProfile.pubxml @@ -1,7 +1,5 @@  - + true @@ -10,11 +8,11 @@ https://go.microsoft.com/fwlink/?LinkID=208121. Release Any CPU FileSystem - bin\Release\net9.0-windows7.0\publish\ + bin\Release\net10.0-windows7.0\publish\ FileSystem <_TargetId>Folder - net9.0-windows7.0 + net10.0-windows7.0 48f9cdfa-625f-4743-bf21-bd556f6f33e8 false diff --git a/RMuseum/Properties/PublishProfiles/FolderProfile.pubxml b/RMuseum/Properties/PublishProfiles/FolderProfile.pubxml index 7c3068bb..a8930b28 100644 --- a/RMuseum/Properties/PublishProfiles/FolderProfile.pubxml +++ b/RMuseum/Properties/PublishProfiles/FolderProfile.pubxml @@ -1,7 +1,5 @@  - + true @@ -10,11 +8,11 @@ https://go.microsoft.com/fwlink/?LinkID=208121. Release Any CPU FileSystem - bin\Release\net9.0-windows7.0\publish\ + bin\Release\net10.0-windows7.0\publish\ FileSystem <_TargetId>Folder - net9.0-windows7.0 + net10.0-windows7.0 113ef3de-e8a9-40ef-9da0-8dfabb3cdd68 false diff --git a/TajikGanjoor/Properties/PublishProfiles/FolderProfile.pubxml b/TajikGanjoor/Properties/PublishProfiles/FolderProfile.pubxml index d6c4b49f..7b0b3cf8 100644 --- a/TajikGanjoor/Properties/PublishProfiles/FolderProfile.pubxml +++ b/TajikGanjoor/Properties/PublishProfiles/FolderProfile.pubxml @@ -1,17 +1,19 @@  - + - false + true false true Release Any CPU FileSystem - bin\Release\net8.0-windows\publish\ + bin\Release\net10.0-windows7.0\publish\ FileSystem <_TargetId>Folder + + net10.0-windows7.0 + 1c51eb06-5190-4646-84c7-5ee712c86f57 + false \ No newline at end of file diff --git a/TajikGanjoor/dotnet-tools.json b/TajikGanjoor/dotnet-tools.json new file mode 100644 index 00000000..807729e4 --- /dev/null +++ b/TajikGanjoor/dotnet-tools.json @@ -0,0 +1,13 @@ +{ + "version": 1, + "isRoot": true, + "tools": { + "dotnet-ef": { + "version": "10.0.9", + "commands": [ + "dotnet-ef" + ], + "rollForward": false + } + } +} \ No newline at end of file From 0b861243389a1caea51065c042b2d3ae16367e35 Mon Sep 17 00:00:00 2001 From: Hamid Reza Mohammadi Date: Fri, 10 Jul 2026 15:59:51 +0330 Subject: [PATCH 2/9] #494 backup ftp server --- .../Implementation/RecitationService.cs | 25 +++++++++++++++++++ RMuseum/appsettings.json | 10 ++++++++ 2 files changed, 35 insertions(+) diff --git a/RMuseum/Services/Implementation/RecitationService.cs b/RMuseum/Services/Implementation/RecitationService.cs index 1b05ac38..a6db5af4 100644 --- a/RMuseum/Services/Implementation/RecitationService.cs +++ b/RMuseum/Services/Implementation/RecitationService.cs @@ -1338,6 +1338,31 @@ namespace RMuseum.Services.Implementationa await ftpClient.Disconnect(); } + if (bool.Parse(Configuration.GetSection("BackupFTPServer")["UploadEnabled"])) + { + var ftpClient = new AsyncFtpClient + ( + Configuration.GetSection("BackupFTPServer")["Host"], + Configuration.GetSection("BackupFTPServer")["Username"], + Configuration.GetSection("BackupFTPServer")["Password"] + ); + ftpClient.ValidateCertificate += FtpClient_ValidateCertificate; + await ftpClient.AutoConnect(); + ftpClient.Config.RetryAttempts = 3; + + await ftpClient.UploadFile(narration.LocalXmlFilePath, $"{Configuration.GetSection("BackupFTPServer")["RootPath"]}{narration.RemoteXMLFilePath}", createRemoteDir: true); + tracker.XmlFileCopied = true; + context.RecitationPublishingTrackers.Update(tracker); + await context.SaveChangesAsync(); + + await ftpClient.UploadFile(narration.LocalMp3FilePath, $"{Configuration.GetSection("BackupFTPServer")["RootPath"]}{narration.RemoteMp3FilePath}", createRemoteDir: true); + tracker.Mp3FileCopied = true; + context.RecitationPublishingTrackers.Update(tracker); + await context.SaveChangesAsync(); + + await ftpClient.Disconnect(); + } + narration.AudioSyncStatus = AudioSyncStatus.SynchronizedOrRejected; context.Recitations.Update(narration); await context.SaveChangesAsync(); diff --git a/RMuseum/appsettings.json b/RMuseum/appsettings.json index a7713948..a1ea04ae 100644 --- a/RMuseum/appsettings.json +++ b/RMuseum/appsettings.json @@ -77,6 +77,16 @@ "RootUrl": "https://i.ganjoor.net/images", "LoadFromExternalServer": "True" }, + "BackupFTPServer": { + "Host": "localhost", + "Port": "22", + "Username": "root", + "Password": "", + "RootPath": "/home", + "UploadEnabled": "False", + "RootUrl": "https://i.ganjoor.net/images", + "LoadFromExternalServer": "True" + }, "WebServiceUrl": "http://localhost:3439", "ReadOnlyMode": "False", "TransilerateFormData": "ctl00%24ContentPlaceHolder2%24ScriptManager1=ctl00%24ContentPlaceHolder2%24UpdatePanel1%7Cctl00%24ContentPlaceHolder2%24btnConvert&__EVENTTARGET=&__EVENTARGUMENT=&__VIEWSTATE=50SiwtZgcWB3spddjuBb6BloHj933fgmboKNaKJBIwGTAAKq9eDHSPq%2FLjZZI2sJIMOfywb%2FVO3ZWSadvUsRVLOnxPleQwkf3EHhZT9mSeNvEFld9VKQZ0ben0y15vOMMCfoPQ%3D%3D&__VIEWSTATEGENERATOR=82B657B9&__EVENTVALIDATION=wcYH3JuIbMl7ulzDUUsJdcDMJwjBkZ%2BEyx5Gwv7F31G5yIN75QiuxDkD7acnJpR6cBC8VNNEowaHZB5xRMOF7%2BMhsiZ3AugxyWjaeeiiAUvv1BugkbhRft4aXkJpVd3%2FaeYBHFAyDrKDkYIA2jFrmtjkj1NrtRl5uSvsFY5fPVt9antJQ8kgNRfDEeNtsBzU6BH%2FCw%3D%3D&ctl00%24ContentPlaceHolder2%24txtPersian=%D8%AD%D8%B3%D9%86&ctl00%24ContentPlaceHolder2%24txtSuggest=&__ASYNCPOST=true&ctl00%24ContentPlaceHolder2%24btnConvert=%D8%A8%D8%B1%DA%AF%D8%B1%D8%AF%D8%A7%D9%86", From 440031ce01a2939d453b82c7d00ef7b148a724a1 Mon Sep 17 00:00:00 2001 From: Hamid Reza Mohammadi Date: Fri, 10 Jul 2026 16:15:56 +0330 Subject: [PATCH 3/9] #494 backup ftp server --- .../Implementation/RecitationService.cs | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/RMuseum/Services/Implementation/RecitationService.cs b/RMuseum/Services/Implementation/RecitationService.cs index a6db5af4..73d2f8d9 100644 --- a/RMuseum/Services/Implementation/RecitationService.cs +++ b/RMuseum/Services/Implementation/RecitationService.cs @@ -1450,6 +1450,31 @@ namespace RMuseum.Services.Implementationa await ftpClient.Disconnect(); } + if (bool.Parse(Configuration.GetSection("BackupFTPServer")["UploadEnabled"])) + { + var ftpClient = new AsyncFtpClient + ( + Configuration.GetSection("BackupFTPServer")["Host"], + Configuration.GetSection("BackupFTPServer")["Username"], + Configuration.GetSection("BackupFTPServer")["Password"] + ); + ftpClient.ValidateCertificate += FtpClient_ValidateCertificate; + await ftpClient.AutoConnect(); + ftpClient.Config.RetryAttempts = 3; + + if (true == await ftpClient.FileExists($"{Configuration.GetSection("BackupFTPServer")["RootPath"]}{narration.RemoteXMLFilePath}")) + { + await ftpClient.DeleteFile($"{Configuration.GetSection("BackupFTPServer")["RootPath"]}{narration.RemoteXMLFilePath}"); + } + + if (true == await ftpClient.FileExists($"{Configuration.GetSection("BackupFTPServer")["RootPath"]}{narration.RemoteXMLFilePath}")) + { + await ftpClient.DeleteFile($"{Configuration.GetSection("BackupFTPServer")["RootPath"]}{narration.RemoteXMLFilePath}"); + } + + await ftpClient.Disconnect(); + } + string audioTitle = narration.AudioTitle; int GanjoorPostId = narration.GanjoorPostId; Guid userId = narration.OwnerId; From 220203a97c916268952222cd4439baef7bb56351 Mon Sep 17 00:00:00 2001 From: Hamid Reza Mohammadi Date: Fri, 10 Jul 2026 16:23:41 +0330 Subject: [PATCH 4/9] #494 backup ftp server --- .../ArtificatService-AI-ImageCreate.cs | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/RMuseum/Services/Implementation/ArtifactService-Partials/ArtificatService-AI-ImageCreate.cs b/RMuseum/Services/Implementation/ArtifactService-Partials/ArtificatService-AI-ImageCreate.cs index 44c558b3..a2fdc9b6 100644 --- a/RMuseum/Services/Implementation/ArtifactService-Partials/ArtificatService-AI-ImageCreate.cs +++ b/RMuseum/Services/Implementation/ArtifactService-Partials/ArtificatService-AI-ImageCreate.cs @@ -472,6 +472,52 @@ namespace RMuseum.Services.Implementation } + if (bool.Parse(Configuration.GetSection("BackupFTPServer")["UploadEnabled"])) + { + var ftpClient = new AsyncFtpClient + ( + Configuration.GetSection("BackupFTPServer")["Host"], + Configuration.GetSection("BackupFTPServer")["Username"], + Configuration.GetSection("BackupFTPServer")["Password"] + ); + + + + if (!skipUpload) + { + ftpClient.ValidateCertificate += FtpClient_ValidateCertificate; + await ftpClient.AutoConnect(); + ftpClient.Config.RetryAttempts = 3; + } + + + foreach (var image in item.Images) + { + foreach (var imageSizeString in new string[] { "orig", "norm", "thumb" }) + { + var localFilePath = _pictureFileService.GetImagePath(image, imageSizeString).Result; + if (imageSizeString == "norm") + { + image.ExternalNormalSizeImageUrl = $"{Configuration.GetSection("BackupFTPServer")["RootUrl"]}/{image.FolderName}/{imageSizeString}/{Path.GetFileName(localFilePath)}"; + context.Update(image); + } + if (!skipUpload) + { + await jobProgressServiceEF.UpdateJob(job.Id, 0, localFilePath); + var remoteFilePath = $"{Configuration.GetSection("BackupFTPServer")["RootPath"]}/images/{bookFriendlyUrl}/{imageSizeString}/{Path.GetFileName(localFilePath)}"; + await ftpClient.UploadFile(localFilePath, remoteFilePath, createRemoteDir: true); + } + } + } + + if (!skipUpload) + { + await ftpClient.Disconnect(); + } + await jobProgressServiceEF.DeleteJob(job.Id); + + } + return new RServiceResult(true); } catch (Exception exp) From 5fc1238069d63e61737c1d5ec732da03cfba122d Mon Sep 17 00:00:00 2001 From: Hamid Reza Mohammadi Date: Fri, 10 Jul 2026 16:26:42 +0330 Subject: [PATCH 5/9] #494 backup ftp server --- .../Implementation/ArtifactService.cs | 107 +++++++++++++++++- 1 file changed, 106 insertions(+), 1 deletion(-) diff --git a/RMuseum/Services/Implementation/ArtifactService.cs b/RMuseum/Services/Implementation/ArtifactService.cs index bcf8e1b7..36676c59 100644 --- a/RMuseum/Services/Implementation/ArtifactService.cs +++ b/RMuseum/Services/Implementation/ArtifactService.cs @@ -1430,13 +1430,94 @@ namespace RMuseum.Services.Implementation await context.SaveChangesAsync();//redundant } - return new RServiceResult(true); + } catch (Exception exp) { await jobProgressServiceEF.UpdateJob(job.Id, 100, "", false, exp.ToString()); return new RServiceResult(false, exp.ToString()); } + + try + { + if (bool.Parse(Configuration.GetSection("BackupFTPServer")["UploadEnabled"])) + { + var ftpClient = new AsyncFtpClient + ( + Configuration.GetSection("BackupFTPServer")["Host"], + Configuration.GetSection("BackupFTPServer")["Username"], + Configuration.GetSection("BackupFTPServer")["Password"] + ); + + + + if (!skipUpload) + { + ftpClient.ValidateCertificate += FtpClient_ValidateCertificate; + await ftpClient.AutoConnect(); + ftpClient.Config.RetryAttempts = 3; + } + + + foreach (var imageSizeString in new string[] { "orig", "norm", "thumb" }) + { + var localFilePath = _pictureFileService.GetImagePath(book.CoverImage, imageSizeString).Result; + if (imageSizeString == "norm") + { + book.CoverImage.ExternalNormalSizeImageUrl = $"{Configuration.GetSection("BackupFTPServer")["RootUrl"]}/{book.CoverImage.FolderName}/{imageSizeString}/{Path.GetFileName(localFilePath)}"; + context.Update(book.CoverImage); + } + if (!skipUpload) + { + await jobProgressServiceEF.UpdateJob(job.Id, 0, localFilePath); + + var remoteFilePath = $"{Configuration.GetSection("BackupFTPServer")["RootPath"]}/images/{book.CoverImage.FolderName}/{imageSizeString}/{Path.GetFileName(localFilePath)}"; + await ftpClient.UploadFile(localFilePath, remoteFilePath, createRemoteDir: true); + } + + } + + + foreach (var item in book.Items) + { + foreach (var image in item.Images) + { + foreach (var imageSizeString in new string[] { "orig", "norm", "thumb" }) + { + var localFilePath = _pictureFileService.GetImagePath(image, imageSizeString).Result; + if (imageSizeString == "norm") + { + image.ExternalNormalSizeImageUrl = $"{Configuration.GetSection("BackupFTPServer")["RootUrl"]}/{image.FolderName}/{imageSizeString}/{Path.GetFileName(localFilePath)}"; + context.Update(image); + } + if (!skipUpload) + { + await jobProgressServiceEF.UpdateJob(job.Id, 0, localFilePath); + var remoteFilePath = $"{Configuration.GetSection("BackupFTPServer")["RootPath"]}/images/{book.CoverImage.FolderName}/{imageSizeString}/{Path.GetFileName(localFilePath)}"; + await ftpClient.UploadFile(localFilePath, remoteFilePath, createRemoteDir: true); + } + + } + } + } + + if (!skipUpload) + { + await ftpClient.Disconnect(); + } + await jobProgressServiceEF.UpdateJob(job.Id, 100, "", true); + await context.SaveChangesAsync();//redundant + } + + + } + catch (Exception exp) + { + await jobProgressServiceEF.UpdateJob(job.Id, 100, "", false, exp.ToString()); + return new RServiceResult(false, exp.ToString()); + } + + return new RServiceResult(true); } @@ -3472,6 +3553,30 @@ namespace RMuseum.Services.Implementation await ftpClient.Disconnect(); } + if (bool.Parse(Configuration.GetSection("BackupFTPServer")["UploadEnabled"])) + { + var ftpClient = new AsyncFtpClient + ( + Configuration.GetSection("BackupFTPServer")["Host"], + Configuration.GetSection("BackupFTPServer")["Username"], + Configuration.GetSection("BackupFTPServer")["Password"] + ); + ftpClient.ValidateCertificate += FtpClient_ValidateCertificate; + await ftpClient.AutoConnect(); + ftpClient.Config.RetryAttempts = 3; + foreach (var imageSizeString in new string[] { "orig", "norm", "thumb" }) + { + var localFilePath = _pictureFileService.GetImagePath(picture.Result, imageSizeString).Result; + if (imageSizeString == "norm") + { + picture.Result.ExternalNormalSizeImageUrl = $"{Configuration.GetSection("BackupFTPServer")["RootUrl"]}/Pinterest/{imageSizeString}/{Path.GetFileName(localFilePath)}"; + } + var remoteFilePath = $"{Configuration.GetSection("BackupFTPServer")["RootPath"]}/images/Pinterest/{imageSizeString}/{Path.GetFileName(localFilePath)}"; + await ftpClient.UploadFile(localFilePath, remoteFilePath); + } + await ftpClient.Disconnect(); + } + RArtifactMasterRecord book = new RArtifactMasterRecord(titleInToc, titleInToc) { From 56d7f0f25c6aa8cad4b19196fe3c0764ae27e2aa Mon Sep 17 00:00:00 2001 From: Hamid Reza Mohammadi Date: Fri, 10 Jul 2026 16:30:51 +0330 Subject: [PATCH 6/9] #494 backup ftp server --- .../GanjoorService-CatUtils.cs | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/RMuseum/Services/Implementation/GanjoorService-Partials/GanjoorService-CatUtils.cs b/RMuseum/Services/Implementation/GanjoorService-Partials/GanjoorService-CatUtils.cs index 765705c9..f4cb8ad5 100644 --- a/RMuseum/Services/Implementation/GanjoorService-Partials/GanjoorService-CatUtils.cs +++ b/RMuseum/Services/Implementation/GanjoorService-Partials/GanjoorService-CatUtils.cs @@ -336,6 +336,27 @@ namespace RMuseum.Services.Implementation await ftpClient.UploadFile(localFilePath, remoteFilePath); await ftpClient.Disconnect(); } + + if (bool.Parse(Configuration.GetSection("BackupFTPServer")["UploadEnabled"])) + { + var ftpClient = new AsyncFtpClient + ( + Configuration.GetSection("BackupFTPServer")["Host"], + Configuration.GetSection("BackupFTPServer")["Username"], + Configuration.GetSection("BackupFTPServer")["Password"] + ); + ftpClient.ValidateCertificate += FtpClient_ValidateCertificate; + await ftpClient.AutoConnect(); + ftpClient.Config.RetryAttempts = 3; + RServiceResult imgPath = _imageFileService.GetImagePath(img.Result); + if (!string.IsNullOrEmpty(imgPath.ExceptionString)) + return new RServiceResult(null, imgPath.ExceptionString); + + var localFilePath = imgPath.Result; + var remoteFilePath = $"{Configuration.GetSection("BackupFTPServer")["RootPath"]}/images/CategoryImages/{Path.GetFileName(localFilePath)}"; + await ftpClient.UploadFile(localFilePath, remoteFilePath); + await ftpClient.Disconnect(); + } } cat.BookName = bookName; cat.RImageId = imageId; From d48b6cd3a7d8c123c5b3c1e5e9755b1e51ece4e4 Mon Sep 17 00:00:00 2001 From: Hamid Reza Mohammadi Date: Fri, 10 Jul 2026 16:35:23 +0330 Subject: [PATCH 7/9] #494 backup ftp server --- .../GanjoorService-SQLiteExport.cs | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/RMuseum/Services/Implementation/GanjoorService-Partials/GanjoorService-SQLiteExport.cs b/RMuseum/Services/Implementation/GanjoorService-Partials/GanjoorService-SQLiteExport.cs index a86c419b..350d1e5b 100644 --- a/RMuseum/Services/Implementation/GanjoorService-Partials/GanjoorService-SQLiteExport.cs +++ b/RMuseum/Services/Implementation/GanjoorService-Partials/GanjoorService-SQLiteExport.cs @@ -196,6 +196,42 @@ namespace RMuseum.Services.Implementation await ftpClient.Disconnect(); } + if (bool.Parse(Configuration.GetSection("BackupFTPServer")["UploadEnabled"])) + { + var ftpClient = new AsyncFtpClient + ( + Configuration.GetSection("BackupFTPServer")["Host"], + Configuration.GetSection("BackupFTPServer")["Username"], + Configuration.GetSection("BackupFTPServer")["Password"] + ); + ftpClient.ValidateCertificate += FtpClient_ValidateCertificate; + await ftpClient.AutoConnect(); + ftpClient.Config.RetryAttempts = 3; + + string dir = Path.GetDirectoryName(xmlFile); + + string rootDirName = Path.GetFileName(dir); + string gdbDirName = Path.GetFileName(Path.GetDirectoryName(outDir)); + + foreach (var localFilePath in Directory.GetFiles(Path.Combine(dir, gdbDirName), "*.zip")) + { + var remoteFilePath = $"{Configuration.GetSection("BackupFTPServer")["RootPath"]}/{rootDirName}/{gdbDirName}/{Path.GetFileName(localFilePath)}"; + await ftpClient.UploadFile(localFilePath, remoteFilePath, createRemoteDir: true); + } + + string imgDirName = Path.GetFileName(Path.GetDirectoryName(imgDir)); + foreach (var localFilePath in Directory.GetFiles(Path.Combine(dir, imgDirName), "*.png")) + { + + var remoteFilePath = $"{Configuration.GetSection("BackupFTPServer")["RootPath"]}/{rootDirName}/{imgDirName}/{Path.GetFileName(localFilePath)}"; + await ftpClient.UploadFile(localFilePath, remoteFilePath, createRemoteDir: true); + } + + await ftpClient.UploadFile(xmlFile, $"{Configuration.GetSection("BackupFTPServer")["RootPath"]}/{rootDirName}/{Path.GetFileName(xmlFile)}", createRemoteDir: true); + + await ftpClient.Disconnect(); + } + await jobProgressServiceEF.UpdateJob(job.Id, 100, "", true); } catch (Exception exp) From 01dbdd539cef33e00905f9ddccf4e5bd6e5e71dc Mon Sep 17 00:00:00 2001 From: Hamid Reza Mohammadi Date: Fri, 10 Jul 2026 16:36:36 +0330 Subject: [PATCH 8/9] #494 backup ftp server --- .../Services/Implementation/GanjoorService.cs | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/RMuseum/Services/Implementation/GanjoorService.cs b/RMuseum/Services/Implementation/GanjoorService.cs index f4b5d802..46203978 100644 --- a/RMuseum/Services/Implementation/GanjoorService.cs +++ b/RMuseum/Services/Implementation/GanjoorService.cs @@ -3537,6 +3537,26 @@ namespace RMuseum.Services.Implementation await ftpClient.UploadFile(localFilePath, remoteFilePath); await ftpClient.Disconnect(); } + if (bool.Parse(Configuration.GetSection("BackupFTPServer")["UploadEnabled"])) + { + var ftpClient = new AsyncFtpClient + ( + Configuration.GetSection("BackupFTPServer")["Host"], + Configuration.GetSection("BackupFTPServer")["Username"], + Configuration.GetSection("BackupFTPServer")["Password"] + ); + ftpClient.ValidateCertificate += FtpClient_ValidateCertificate; + await ftpClient.AutoConnect(); + ftpClient.Config.RetryAttempts = 3; + RServiceResult imgPath = _imageFileService.GetImagePath(img.Result); + if (!string.IsNullOrEmpty(imgPath.ExceptionString)) + return new RServiceResult(false, imgPath.ExceptionString); + + var localFilePath = imgPath.Result; + var remoteFilePath = $"{Configuration.GetSection("BackupFTPServer")["RootPath"]}/images/PoetImages/{Path.GetFileName(localFilePath)}"; + await ftpClient.UploadFile(localFilePath, remoteFilePath); + await ftpClient.Disconnect(); + } var dbPoet = await _context.GanjoorPoets.Where(p => p.Id == poetId).SingleAsync(); dbPoet.RImageId = imageId; _context.GanjoorPoets.Update(dbPoet); From 1405b5373a51665caa119a0b557ae1b470ecf811 Mon Sep 17 00:00:00 2001 From: Hamid Reza Mohammadi Date: Fri, 10 Jul 2026 16:39:54 +0330 Subject: [PATCH 9/9] #494 backup ftp server --- .../Implementation/PictureFileService.cs | 65 +++++++++++++++++++ .../PoetPhotoSuggestionService.cs | 26 +++++++- 2 files changed, 90 insertions(+), 1 deletion(-) diff --git a/RMuseum/Services/Implementation/PictureFileService.cs b/RMuseum/Services/Implementation/PictureFileService.cs index 5779ee74..e7ee16e2 100644 --- a/RMuseum/Services/Implementation/PictureFileService.cs +++ b/RMuseum/Services/Implementation/PictureFileService.cs @@ -277,6 +277,28 @@ namespace RMuseum.Services.Implementation await ftpClient.Disconnect(); } + if (bool.Parse(Configuration.GetSection("BackupFTPServer")["UploadEnabled"])) + { + var ftpClient = new AsyncFtpClient + ( + Configuration.GetSection("BackupFTPServer")["Host"], + Configuration.GetSection("BackupFTPServer")["Username"], + Configuration.GetSection("BackupFTPServer")["Password"] + ); + ftpClient.ValidateCertificate += FtpClient_ValidateCertificate; + await ftpClient.AutoConnect(); + ftpClient.Config.RetryAttempts = 3; + + foreach (var imageSizeString in new string[] { "orig", "norm", "thumb" }) + { + var localFilePath = GetImagePath(rPictureFile, imageSizeString).Result; + var remoteFilePath = $"{Configuration.GetSection("BackupFTPServer")["RootPath"]}/images/{rPictureFile.FolderName}/{imageSizeString}/{Path.GetFileName(localFilePath)}"; + await ftpClient.UploadFile(localFilePath, remoteFilePath, createRemoteDir: true); + } + + await ftpClient.Disconnect(); + } + return result; } } @@ -359,6 +381,30 @@ namespace RMuseum.Services.Implementation } + if (bool.Parse(Configuration.GetSection("BackupFTPServer")["UploadEnabled"])) + { + var ftpClient = new AsyncFtpClient + ( + Configuration.GetSection("BackupFTPServer")["Host"], + Configuration.GetSection("BackupFTPServer")["Username"], + Configuration.GetSection("BackupFTPServer")["Password"] + ); + ftpClient.ValidateCertificate += FtpClient_ValidateCertificate; + await ftpClient.AutoConnect(); + ftpClient.Config.RetryAttempts = 3; + + foreach (var imageSizeString in new string[] { "orig", "norm", "thumb" }) + { + var localFilePath = GetImagePath(rPictureFile, imageSizeString).Result; + var remoteFilePath = $"{Configuration.GetSection("BackupFTPServer")["RootPath"]}/images/{rPictureFile.FolderName}/{imageSizeString}/{Path.GetFileName(localFilePath)}"; + await ftpClient.UploadFile(localFilePath, remoteFilePath, createRemoteDir: true); + } + + await ftpClient.Disconnect(); + await jobProgressServiceEF.UpdateJob(job.Id, 100, "", true); + + } + return result; } @@ -672,6 +718,25 @@ namespace RMuseum.Services.Implementation await ftpClient.Disconnect(); } + + if (bool.Parse(Configuration.GetSection("BackupFTPServer")["UploadEnabled"])) + { + var ftpClient = new AsyncFtpClient + ( + Configuration.GetSection("BackupFTPServer")["Host"], + Configuration.GetSection("BackupFTPServer")["Username"], + Configuration.GetSection("BackupFTPServer")["Password"] + ); + ftpClient.ValidateCertificate += FtpClient_ValidateCertificate; + await ftpClient.AutoConnect(); + ftpClient.Config.RetryAttempts = 3; + + var localFilePath = _simpleImageStorage.GetImagePath(image).Result; + var remoteFilePath = $"{Configuration.GetSection("BackupFTPServer")["RootPath"]}/images/CroppedImages/{Path.GetFileName(localFilePath)}"; + await ftpClient.UploadFile(localFilePath, remoteFilePath, createRemoteDir: true); + + await ftpClient.Disconnect(); + } return new RServiceResult(image); } return res; diff --git a/RMuseum/Services/Implementation/PoetPhotoSuggestionService.cs b/RMuseum/Services/Implementation/PoetPhotoSuggestionService.cs index a3796fe6..29513039 100644 --- a/RMuseum/Services/Implementation/PoetPhotoSuggestionService.cs +++ b/RMuseum/Services/Implementation/PoetPhotoSuggestionService.cs @@ -268,7 +268,31 @@ namespace RMuseum.Services.Implementation } await ftpClient.Disconnect(); } - + + if (model.Published && bool.Parse(Configuration.GetSection("BackupFTPServer")["UploadEnabled"])) + { + var ftpClient = new AsyncFtpClient + ( + Configuration.GetSection("BackupFTPServer")["Host"], + Configuration.GetSection("BackupFTPServer")["Username"], + Configuration.GetSection("BackupFTPServer")["Password"] + ); + ftpClient.ValidateCertificate += FtpClient_ValidateCertificate; + await ftpClient.AutoConnect(); + ftpClient.Config.RetryAttempts = 3; + foreach (var imageSizeString in new string[] { "orig", "norm", "thumb" }) + { + var localFilePath = _pictureFileService.GetImagePath(dbModel.Picture, imageSizeString).Result; + if (imageSizeString == "norm") + { + dbModel.Picture.ExternalNormalSizeImageUrl = $"{Configuration.GetSection("BackupFTPServer")["RootUrl"]}/PoetsPhotoSuggestions/{imageSizeString}/{Path.GetFileName(localFilePath)}"; + } + var remoteFilePath = $"{Configuration.GetSection("BackupFTPServer")["RootPath"]}/images/PoetsPhotoSuggestions/{imageSizeString}/{Path.GetFileName(localFilePath)}"; + await ftpClient.UploadFile(localFilePath, remoteFilePath); + } + await ftpClient.Disconnect(); + } + bool publishIsChanged = model.Published != dbModel.Published; if(publishIsChanged) {