From f4ecb51a7c6e92d4c6145c98ff39ec9d42c5af32 Mon Sep 17 00:00:00 2001 From: aurelio-aot Date: Thu, 26 Mar 2026 15:57:09 -0700 Subject: [PATCH 1/5] AB#24672: Maximum attachment file size for single upload --- applications/Unity.GrantManager/.env.example | 1 + .../Controllers/AttachmentController.cs | 13 +++++++++++++ .../Pages/GrantApplications/Details.cshtml | 1 + .../Pages/GrantApplications/Details.cshtml.cs | 2 ++ .../Views/Shared/Components/EmailsWidget/Default.js | 7 +++++-- 5 files changed, 22 insertions(+), 2 deletions(-) diff --git a/applications/Unity.GrantManager/.env.example b/applications/Unity.GrantManager/.env.example index c2094e4c05..f40023a9f6 100644 --- a/applications/Unity.GrantManager/.env.example +++ b/applications/Unity.GrantManager/.env.example @@ -56,6 +56,7 @@ AuthServer__OidcSignoutCallback="http://localhost:44342/signout-callback-oidc" ##S3__AssessmentS3Folder="Unity/Adjudication" ##S3__DisallowedFileTypes="[ "exe" , "sh" , "ksh" , "bat" , "cmd" ]" ##S3__MaxFileSize="25" +##S3__EmailAttachmentMaxFileSize="20" ## RABBIT MQ UNITY_RABBIT_MQ_HOST="rabbitmq" UNITY_RABBIT_MQ_PORT="5672" diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.HttpApi/Controllers/AttachmentController.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.HttpApi/Controllers/AttachmentController.cs index 42f004ef31..725134d50a 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.HttpApi/Controllers/AttachmentController.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.HttpApi/Controllers/AttachmentController.cs @@ -280,6 +280,19 @@ public async Task UploadEmailAttachments(Guid emailLogId, IList f.Length * 0.000001 > maxFileSizeMB).ToList(); + if (oversizedFiles.Count > 0) + { + var sizeErrors = oversizedFiles.Select(f => + new ValidationResult($"File '{f.FileName}' exceeds the maximum allowed size of {maxFileSizeMB} MB for email attachments.", [f.FileName]) + ).ToList(); + throw new AbpValidationException("One or more files exceed the maximum allowed size for email attachments.", sizeErrors); + } + } + var results = new List(); foreach (var file in files) { diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/GrantApplications/Details.cshtml b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/GrantApplications/Details.cshtml index 57d4866242..a5feb9d8cd 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/GrantApplications/Details.cshtml +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/GrantApplications/Details.cshtml @@ -70,6 +70,7 @@ + diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/GrantApplications/Details.cshtml.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/GrantApplications/Details.cshtml.cs index aaec1bb21e..c0613734cb 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/GrantApplications/Details.cshtml.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/GrantApplications/Details.cshtml.cs @@ -85,6 +85,7 @@ public class DetailsModel : AbpPageModel public string? CurrentUserName { get; set; } public string Extensions { get; set; } public string MaxFileSize { get; set; } + public string EmailAttachmentMaxFileSize { get; set; } [BindProperty(SupportsGet = true)] public List CustomTabs { get; set; } = []; @@ -123,6 +124,7 @@ public DetailsModel( CurrentUserName = currentUser.SurName + ", " + currentUser.Name; Extensions = configuration["S3:DisallowedFileTypes"] ?? ""; MaxFileSize = configuration["S3:MaxFileSize"] ?? ""; + EmailAttachmentMaxFileSize = configuration["S3:EmailAttachmentMaxFileSize"] ?? "20"; IsDevPromptControlsEnabled = aiPromptToolViewOptionsProvider.IsDevPromptControlsEnabled; DefaultPromptVersion = aiPromptToolViewOptionsProvider.DefaultPromptVersion; } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/EmailsWidget/Default.js b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/EmailsWidget/Default.js index 22f3a14fbc..4cae866088 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/EmailsWidget/Default.js +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/EmailsWidget/Default.js @@ -821,7 +821,7 @@ function uploadEmailFiles(inputId) { if (!input?.files?.length) return; const disallowedTypes = JSON.parse(decodeURIComponent($('#Extensions').val())); - const maxFileSize = decodeURIComponent($('#MaxFileSize').val()); + const maxFileSize = decodeURIComponent($('#EmailAttachmentMaxFileSize').val()); let isAllowedTypeError = false; let isMaxFileSizeError = false; @@ -844,7 +844,10 @@ function uploadEmailFiles(inputId) { } if (isMaxFileSizeError) { input.value = ''; - return abp.notify.error('Error', 'File size exceeds ' + maxFileSize + 'MB'); + return abp.notify.error( + 'File Too Large', + 'The selected file exceeds the maximum allowed size of ' + maxFileSize + ' MB for email attachments. Please select a smaller file.' + ); } $.ajax({ From 2ac26ae39ae85577229e67f28a497bcc5a32b4d4 Mon Sep 17 00:00:00 2001 From: aurelio-aot Date: Thu, 26 Mar 2026 17:38:48 -0700 Subject: [PATCH 2/5] AB#24672: File Upload Spinner and Progress Bar --- .../Components/EmailsWidget/Default.cshtml | 11 +++++++++ .../Shared/Components/EmailsWidget/Default.js | 24 +++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/EmailsWidget/Default.cshtml b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/EmailsWidget/Default.cshtml index e050edc3ae..26700a5a70 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/EmailsWidget/Default.cshtml +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/EmailsWidget/Default.cshtml @@ -125,6 +125,17 @@ +
Uploading...') + .prop('disabled', true); + $('#attachment-upload-progress-bar').css('width', '0%').text('0%'); + $('#attachment-upload-progress').show(); + }, success: function () { PubSub.publish('reload_email_attachments_table'); }, @@ -864,6 +884,10 @@ function uploadEmailFiles(inputId) { }, complete: function () { input.value = ''; + $('#email_attachment_upload_btn') + .html('Add Attachments') + .prop('disabled', false); + $('#attachment-upload-progress').hide(); } }); } From 7df06e89ce70da8ba42f22479341fe343fb0e1a7 Mon Sep 17 00:00:00 2001 From: aurelio-aot Date: Thu, 26 Mar 2026 18:55:11 -0700 Subject: [PATCH 3/5] AB#24672: Validation for total file sizes in email attachment --- applications/Unity.GrantManager/.env.example | 1 + .../IEmailLogAttachmentUploadService.cs | 1 + .../Emails/EmailAttachmentService.cs | 7 + .../Emails/EmailLogAttachmentAppService.cs | 10 +- .../Controllers/AttachmentController.cs | 16 ++ .../Pages/GrantApplications/Details.cshtml | 1 + .../Pages/GrantApplications/Details.cshtml.cs | 2 + .../Components/EmailsWidget/Default.cshtml | 7 +- .../Shared/Components/EmailsWidget/Default.js | 227 ++++++++++++------ 9 files changed, 189 insertions(+), 83 deletions(-) diff --git a/applications/Unity.GrantManager/.env.example b/applications/Unity.GrantManager/.env.example index f40023a9f6..c937e86596 100644 --- a/applications/Unity.GrantManager/.env.example +++ b/applications/Unity.GrantManager/.env.example @@ -57,6 +57,7 @@ AuthServer__OidcSignoutCallback="http://localhost:44342/signout-callback-oidc" ##S3__DisallowedFileTypes="[ "exe" , "sh" , "ksh" , "bat" , "cmd" ]" ##S3__MaxFileSize="25" ##S3__EmailAttachmentMaxFileSize="20" +##S3__EmailAttachmentsTotalMaxFileSize="25" ## RABBIT MQ UNITY_RABBIT_MQ_HOST="rabbitmq" UNITY_RABBIT_MQ_PORT="5672" diff --git a/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Application.Contracts/Emails/IEmailLogAttachmentUploadService.cs b/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Application.Contracts/Emails/IEmailLogAttachmentUploadService.cs index 23f2ae4f03..cdea764cb9 100644 --- a/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Application.Contracts/Emails/IEmailLogAttachmentUploadService.cs +++ b/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Application.Contracts/Emails/IEmailLogAttachmentUploadService.cs @@ -6,4 +6,5 @@ namespace Unity.Notifications.Emails; public interface IEmailLogAttachmentUploadService { Task UploadAsync(Guid emailLogId, Guid? tenantId, string fileName, byte[] content, string contentType); + Task GetTotalFileSizeByEmailLogIdAsync(Guid emailLogId); } diff --git a/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Application/Emails/EmailAttachmentService.cs b/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Application/Emails/EmailAttachmentService.cs index 71ca3e02be..6a0172dd08 100644 --- a/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Application/Emails/EmailAttachmentService.cs +++ b/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Application/Emails/EmailAttachmentService.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Linq; using System.Threading.Tasks; using Unity.Notifications.Emails; using Volo.Abp.DependencyInjection; @@ -174,6 +175,12 @@ public async Task> GetAttachmentsAsync(Guid emailLogId) return await _emailLogAttachmentRepository.GetByEmailLogIdAsync(emailLogId); } + public async Task GetTotalFileSizeAsync(Guid emailLogId) + { + var attachments = await _emailLogAttachmentRepository.GetByEmailLogIdAsync(emailLogId); + return attachments.Sum(a => a.FileSize); + } + private static string BuildUserAttachmentS3Key(Guid? tenantId, Guid emailLogId, Guid attachmentId, string fileName) { var basePath = "Email/Attachments"; diff --git a/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Application/Emails/EmailLogAttachmentAppService.cs b/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Application/Emails/EmailLogAttachmentAppService.cs index b7e1c4d75b..31a5a9b20b 100644 --- a/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Application/Emails/EmailLogAttachmentAppService.cs +++ b/applications/Unity.GrantManager/modules/Unity.Notifications/src/Unity.Notifications.Application/Emails/EmailLogAttachmentAppService.cs @@ -27,7 +27,7 @@ public async Task> GetListByEmailLogIdAsync(Guid ema foreach (var attachment in attachments) { - var dto = new EmailLogAttachmentDto + dtos.Add(new EmailLogAttachmentDto { Id = attachment.Id, FileName = attachment.FileName, @@ -37,8 +37,7 @@ public async Task> GetListByEmailLogIdAsync(Guid ema ContentType = attachment.ContentType, S3ObjectKey = attachment.S3ObjectKey, AttachedBy = await ResolveUserNameAsync(attachment.UserId) - }; - dtos.Add(dto); + }); } return dtos; @@ -65,6 +64,11 @@ public async Task DeleteAsync(Guid id) await emailLogAttachmentRepository.DeleteAsync(id); } + public async Task GetTotalFileSizeByEmailLogIdAsync(Guid emailLogId) + { + return await emailAttachmentService.GetTotalFileSizeAsync(emailLogId); + } + public async Task UploadAsync(Guid emailLogId, Guid? tenantId, string fileName, byte[] content, string contentType) { var attachment = await emailAttachmentService.UploadUserAttachmentAsync(emailLogId, tenantId, fileName, content, contentType); diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.HttpApi/Controllers/AttachmentController.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.HttpApi/Controllers/AttachmentController.cs index 725134d50a..cd74758f62 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.HttpApi/Controllers/AttachmentController.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.HttpApi/Controllers/AttachmentController.cs @@ -293,6 +293,22 @@ public async Task UploadEmailAttachments(Guid emailLogId, IList f.Length); + double combinedMB = (existingTotalBytes + newFilesBytes) * 0.000001; + + if (combinedMB > totalMaxSizeMB) + { + throw new AbpValidationException( + $"The total size of all attachments ({combinedMB:F1} MB) would exceed the maximum allowed {totalMaxSizeMB} MB for email attachments. Please remove existing attachments or select a smaller file.", + [new ValidationResult("Total attachment size exceeds the allowed limit.")]); + } + } + var results = new List(); foreach (var file in files) { diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/GrantApplications/Details.cshtml b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/GrantApplications/Details.cshtml index a5feb9d8cd..a62fccad43 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/GrantApplications/Details.cshtml +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/GrantApplications/Details.cshtml @@ -71,6 +71,7 @@ + diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/GrantApplications/Details.cshtml.cs b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/GrantApplications/Details.cshtml.cs index c0613734cb..092b831c63 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/GrantApplications/Details.cshtml.cs +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Pages/GrantApplications/Details.cshtml.cs @@ -86,6 +86,7 @@ public class DetailsModel : AbpPageModel public string Extensions { get; set; } public string MaxFileSize { get; set; } public string EmailAttachmentMaxFileSize { get; set; } + public string TotalEmailAttachmentMaxFileSize { get; set; } [BindProperty(SupportsGet = true)] public List CustomTabs { get; set; } = []; @@ -125,6 +126,7 @@ public DetailsModel( Extensions = configuration["S3:DisallowedFileTypes"] ?? ""; MaxFileSize = configuration["S3:MaxFileSize"] ?? ""; EmailAttachmentMaxFileSize = configuration["S3:EmailAttachmentMaxFileSize"] ?? "20"; + TotalEmailAttachmentMaxFileSize = configuration["S3:EmailAttachmentsTotalMaxFileSize"] ?? "25"; IsDevPromptControlsEnabled = aiPromptToolViewOptionsProvider.IsDevPromptControlsEnabled; DefaultPromptVersion = aiPromptToolViewOptionsProvider.DefaultPromptVersion; } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/EmailsWidget/Default.cshtml b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/EmailsWidget/Default.cshtml index 26700a5a70..3cd452a9c6 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/EmailsWidget/Default.cshtml +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/EmailsWidget/Default.cshtml @@ -136,11 +136,14 @@ aria-valuemax="100">0% +
+ style="display:none" /> = 1 ? mb.toFixed(2) + ' MB' : (data / 1024).toFixed(0) + ' KB'; + } + }, { title: '', data: 'id', @@ -784,11 +795,44 @@ return isDraft ? generateEmailAttachmentButtonContent(data) : ''; } } - ] + ], + drawCallback: function () { + if (isDraft) { + checkTotalAttachmentSize(); + } + } }) ); } + function checkTotalAttachmentSize() { + const totalMaxFileSize = parseFloat( + decodeURIComponent($('#TotalEmailAttachmentMaxFileSize').val()) || '25' + ); + + let totalBytes = 0; + if (emailAttachmentsTable) { + emailAttachmentsTable.rows().data().each(function (row) { + totalBytes += (row.fileSize || 0); + }); + } + + const totalMB = totalBytes * 0.000001; + const isExceeded = totalMB > totalMaxFileSize; + + if (isExceeded) { + $('#email-attachment-size-error-message').text( + 'The total size of all attachments (' + totalMB.toFixed(2) + ' MB) exceeds the ' + + 'maximum allowed ' + totalMaxFileSize + ' MB. Please remove one or more attachments before sending.' + ); + $('#email-attachment-size-error').show(); + $('#btn-send').prop('disabled', true); + } else { + $('#email-attachment-size-error').hide(); + $('#btn-send').prop('disabled', false); + } + } + function reloadEmailAttachmentsTable() { if (emailAttachmentsTable) { emailAttachmentsTable.ajax.reload(); @@ -798,6 +842,110 @@ $('#email_attachment_upload_btn').on('click', function () { $('#email_attachment_upload').click(); }); + + $('#email_attachment_upload').on('change', function () { + uploadEmailFiles('email_attachment_upload'); + }); + + function uploadEmailFiles(inputId) { + const emailLogId = $('#EmailId').val(); + const input = document.getElementById(inputId); + if (!input?.files?.length) return; + + const disallowedTypes = JSON.parse(decodeURIComponent($('#Extensions').val())); + const maxFileSize = decodeURIComponent($('#EmailAttachmentMaxFileSize').val()); + + let isAllowedTypeError = false; + let isMaxFileSizeError = false; + const formData = new FormData(); + + for (let file of input.files) { + const ext = file.name.slice(file.name.lastIndexOf('.') + 1).toLowerCase(); + if (disallowedTypes.includes(ext)) { + isAllowedTypeError = true; + } + if (file.size * 0.000001 > maxFileSize) { + isMaxFileSizeError = true; + } + formData.append('files', file); + } + + if (isAllowedTypeError) { + input.value = ''; + return abp.notify.error('Error', 'File type not supported'); + } + if (isMaxFileSizeError) { + input.value = ''; + return abp.notify.error( + 'File Too Large', + 'The selected file exceeds the maximum allowed size of ' + maxFileSize + ' MB for email attachments. Please select a smaller file.' + ); + } + + const totalMaxFileSize = parseFloat( + decodeURIComponent($('#TotalEmailAttachmentMaxFileSize').val()) || '25' + ); + let existingTotalBytes = 0; + if (emailAttachmentsTable) { + emailAttachmentsTable.rows().data().each(function (row) { + existingTotalBytes += (row.fileSize || 0); + }); + } + let newFilesBytes = 0; + for (let file of input.files) { + newFilesBytes += file.size; + } + const combinedMB = (existingTotalBytes + newFilesBytes) * 0.000001; + if (combinedMB > totalMaxFileSize) { + input.value = ''; + return abp.notify.error( + 'Total Size Exceeded', + 'The total size of all attachments would exceed the maximum allowed ' + totalMaxFileSize + + ' MB. Please remove existing attachments or select a smaller file.' + ); + } + + $.ajax({ + url: `/api/app/attachment/email/${emailLogId}/upload`, + type: 'POST', + data: formData, + processData: false, + contentType: false, + xhr: function () { + const xhr = new globalThis.XMLHttpRequest(); + xhr.upload.addEventListener('progress', function (e) { + if (e.lengthComputable) { + const pct = Math.round((e.loaded / e.total) * 100); + $('#attachment-upload-progress-bar') + .css('width', pct + '%') + .attr('aria-valuenow', pct) + .text(pct + '%'); + } + }); + return xhr; + }, + beforeSend: function () { + $('#email_attachment_upload_btn') + .html('Uploading...') + .prop('disabled', true); + $('#attachment-upload-progress-bar').css('width', '0%').text('0%'); + $('#attachment-upload-progress').show(); + }, + success: function () { + PubSub.publish('reload_email_attachments_table'); + }, + error: function (xhr) { + abp.notify.error(xhr.responseText || 'Failed to upload attachment.'); + }, + complete: function () { + input.value = ''; + $('#email_attachment_upload_btn') + .html('Add Attachments') + .prop('disabled', false); + $('#attachment-upload-progress').hide(); + } + }); + } }); function generateEmailAttachmentButtonContent(attachmentId) { @@ -815,83 +963,6 @@ function generateEmailAttachmentButtonContent(attachmentId) {
`; } -function uploadEmailFiles(inputId) { - const emailLogId = $('#EmailId').val(); - const input = document.getElementById(inputId); - if (!input?.files?.length) return; - - const disallowedTypes = JSON.parse(decodeURIComponent($('#Extensions').val())); - const maxFileSize = decodeURIComponent($('#EmailAttachmentMaxFileSize').val()); - - let isAllowedTypeError = false; - let isMaxFileSizeError = false; - const formData = new FormData(); - - for (let file of input.files) { - const ext = file.name.slice(file.name.lastIndexOf('.') + 1).toLowerCase(); - if (disallowedTypes.includes(ext)) { - isAllowedTypeError = true; - } - if (file.size * 0.000001 > maxFileSize) { - isMaxFileSizeError = true; - } - formData.append('files', file); - } - - if (isAllowedTypeError) { - input.value = ''; - return abp.notify.error('Error', 'File type not supported'); - } - if (isMaxFileSizeError) { - input.value = ''; - return abp.notify.error( - 'File Too Large', - 'The selected file exceeds the maximum allowed size of ' + maxFileSize + ' MB for email attachments. Please select a smaller file.' - ); - } - - $.ajax({ - url: `/api/app/attachment/email/${emailLogId}/upload`, - type: 'POST', - data: formData, - processData: false, - contentType: false, - xhr: function () { - const xhr = new window.XMLHttpRequest(); - xhr.upload.addEventListener('progress', function (e) { - if (e.lengthComputable) { - const pct = Math.round((e.loaded / e.total) * 100); - $('#attachment-upload-progress-bar') - .css('width', pct + '%') - .attr('aria-valuenow', pct) - .text(pct + '%'); - } - }); - return xhr; - }, - beforeSend: function () { - $('#email_attachment_upload_btn') - .html('Uploading...') - .prop('disabled', true); - $('#attachment-upload-progress-bar').css('width', '0%').text('0%'); - $('#attachment-upload-progress').show(); - }, - success: function () { - PubSub.publish('reload_email_attachments_table'); - }, - error: function (xhr) { - abp.notify.error(xhr.responseText || 'Failed to upload attachment.'); - }, - complete: function () { - input.value = ''; - $('#email_attachment_upload_btn') - .html('Add Attachments') - .prop('disabled', false); - $('#attachment-upload-progress').hide(); - } - }); -} - function deleteEmailAttachment(attachmentId) { abp.message.confirm( 'Are you sure you want to delete this attachment?', From 3666da8735a10f2d7e680347afa3886f5f4cf4e5 Mon Sep 17 00:00:00 2001 From: aurelio-aot Date: Thu, 26 Mar 2026 18:57:57 -0700 Subject: [PATCH 4/5] AB#24672: Environment variables for maximum email attachment file size --- .../src/Unity.GrantManager.Web/appsettings.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/appsettings.json b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/appsettings.json index eb29270cfa..eafb73b3c1 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/appsettings.json +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/appsettings.json @@ -77,7 +77,9 @@ "ApplicationS3Folder": "Unity/Application", "AssessmentS3Folder": "Unity/Adjudication", "DisallowedFileTypes": "[ \"exe\",\"sh\",\"ksh\",\"bat\",\"cmd\" ]", - "MaxFileSize": 25 + "MaxFileSize": 25, + "EmailAttachmentMaxFileSize": 20, + "EmailAttachmentsTotalMaxFileSize": 25 }, "Geocoder": { "ElectoralDistrict": { From cd60b7350f325ff9cd3728884ec616bf20f2c559 Mon Sep 17 00:00:00 2001 From: aurelio-aot Date: Thu, 26 Mar 2026 19:15:16 -0700 Subject: [PATCH 5/5] AB#24672: Fix sonarqube issues --- .../Views/Shared/Components/EmailsWidget/Default.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/EmailsWidget/Default.js b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/EmailsWidget/Default.js index 5196795e69..76900ea450 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/EmailsWidget/Default.js +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/EmailsWidget/Default.js @@ -806,7 +806,7 @@ } function checkTotalAttachmentSize() { - const totalMaxFileSize = parseFloat( + const totalMaxFileSize = Number.parseFloat( decodeURIComponent($('#TotalEmailAttachmentMaxFileSize').val()) || '25' ); @@ -882,7 +882,7 @@ ); } - const totalMaxFileSize = parseFloat( + const totalMaxFileSize = Number.parseFloat( decodeURIComponent($('#TotalEmailAttachmentMaxFileSize').val()) || '25' ); let existingTotalBytes = 0;