Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2963,6 +2963,40 @@ public async Task ImportExcel_EmptyFile_DoesNotImport_RedirectsToListWithError()
_translationServiceMock.Verify(t => t.GetResource("Admin.Common.UploadFile"), Times.Once);
}

// --- ImportExcel: global scope only ---

[TestMethod]
public async Task ImportExcel_StoreScope_DeniesAndNeverCallsImportManager()
{
_scopeMock.Setup(s => s.DefaultStoreId).Returns("store-1");
var fileMock = new Mock<IFormFile>();
fileMock.Setup(f => f.Length).Returns(100);
var importManagerMock = new Mock<IImportManager<ProductDto>>();

var result = await _controller.ImportExcel(fileMock.Object, importManagerMock.Object);

var redirect = Assert.IsInstanceOfType<RedirectToActionResult>(result);
Assert.AreEqual("List", redirect.ActionName);
Comment thread
github-code-quality[bot] marked this conversation as resolved.
Fixed
importManagerMock.Verify(i => i.Import(It.IsAny<Stream>()), Times.Never);
_translationServiceMock.Verify(t => t.GetResource("Admin.AccessDenied.Title"), Times.Once);
}

[TestMethod]
public async Task ImportExcel_VendorScope_DeniesAndNeverCallsImportManager()
{
_scopeMock.Setup(s => s.DefaultVendorId).Returns("vendor-1");
var fileMock = new Mock<IFormFile>();
fileMock.Setup(f => f.Length).Returns(100);
var importManagerMock = new Mock<IImportManager<ProductDto>>();

var result = await _controller.ImportExcel(fileMock.Object, importManagerMock.Object);

var redirect = Assert.IsInstanceOfType<RedirectToActionResult>(result);
Assert.AreEqual("List", redirect.ActionName);
Comment thread
github-code-quality[bot] marked this conversation as resolved.
Fixed
importManagerMock.Verify(i => i.Import(It.IsAny<Stream>()), Times.Never);
_translationServiceMock.Verify(t => t.GetResource("Admin.AccessDenied.Title"), Times.Once);
}

[TestMethod]
public async Task ImportExcel_NullFile_DoesNotImport_RedirectsToListWithError()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1853,13 +1853,8 @@ public async Task<IActionResult> ExportExcelSelected(string selectedIds,
return File(bytes, "text/xls", "products.xlsx");
}

// Not virtual: Vendor's original ProductController has no ImportExcel action at all, and Vendor is
// never granted the "Products" permission's Import action (grep across src/Web/Grand.Web.Vendor found
// no PermissionActionName.Import usage anywhere) - vendors are deliberately not allowed to bulk-import
// products. [PermissionAuthorizeAction(PermissionActionName.Import)] below already 403s for any host
// whose role has no Import grant for Products, so this is safe to expose unconditionally on the base
// class; Vendor's (future) subclass simply never routes a view to it, same as any other
// permission-gated action already in this file.
// Global scope only, as for brands, categories and collections: the importer is not store- or
// vendor-aware.
//
// Concern (flagged, not fixed - out of scope for this row): ImportExcel only checks
// `importexcelfile.Length > 0` before handing the raw stream to IImportManager<ProductDto>.Import.
Expand All @@ -1875,6 +1870,12 @@ public async Task<IActionResult> ImportExcel(IFormFile importexcelfile,
{
try
{
if (Scope.DefaultStoreId is not null || Scope.DefaultVendorId is not null)
{
Error(translationService.GetResource("Admin.AccessDenied.Title"));
return RedirectToAction("List");
}

if (importexcelfile is { Length: > 0 })
{
await importManager.Import(importexcelfile.OpenReadStream());
Expand Down
Loading