Skip to content
Open
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
13 changes: 13 additions & 0 deletions src/.idea/.idea.NopCommerce/.idea/.gitignore

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions src/.idea/.idea.NopCommerce/.idea/.name

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions src/.idea/.idea.NopCommerce/.idea/encodings.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions src/.idea/.idea.NopCommerce/.idea/indexLayout.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 12 additions & 0 deletions src/.idea/.idea.NopCommerce/.idea/material_theme_project_new.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions src/.idea/.idea.NopCommerce/.idea/vcs.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 6 additions & 1 deletion src/Libraries/Nop.Core/Http/NopRouteNames.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public static partial class General
/// <summary>
/// Gets the product search route name
/// </summary>
public const string SEARCH = "ProductSearch";
public const string SEARCH = "ProductSearch";

/// <summary>
/// Gets the compare products route name
Expand Down Expand Up @@ -703,6 +703,11 @@ public static partial class Ajax
/// </summary>
public const string DELETE_CUSTOM_WISHLIST = "DeleteCustomWishlist";

/// <summary>
/// Gets the edit custom wishlist route name
/// </summary>
public const string RENAME_CUSTOM_WISHLIST = "RenameCustomWishlist";

/// <summary>
/// Gets the estimate shipping route name
/// </summary>
Expand Down
25 changes: 23 additions & 2 deletions src/Libraries/Nop.Services/Orders/CustomWishlistService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public partial class CustomWishlistService : ICustomWishlistService

#region Ctor

public CustomWishlistService(IRepository<CustomWishlist> customWishlistRepository,
public CustomWishlistService(IRepository<CustomWishlist> customWishlistRepository,
ShoppingCartSettings shoppingCartSettings)
{
_customWishlistRepository = customWishlistRepository;
Expand Down Expand Up @@ -56,6 +56,26 @@ public virtual async Task AddCustomWishlistAsync(CustomWishlist item)
await _customWishlistRepository.InsertAsync(item);
}

public virtual async Task EditCustomWishlistAsync(int wishlistId, string newName, int customerId)
{
var wishlist = await _customWishlistRepository.GetByIdAsync(wishlistId);
if (wishlist == null)
throw new ArgumentException($"Custom wishlist with ID {wishlistId} not found.");

// Verify ownership
if (wishlist.CustomerId != customerId)
throw new UnauthorizedAccessException("You are not allowed to edit this wishlist.");

// Validate new name
if (string.IsNullOrWhiteSpace(newName))
throw new ArgumentException("Wishlist name cannot be empty.");

wishlist.Name = newName.Trim();

await _customWishlistRepository.UpdateAsync(wishlist);
}


/// <summary>
/// Removes a custom wishlist item with the specified identifier.
/// </summary>
Expand All @@ -69,6 +89,7 @@ public virtual async Task RemoveCustomWishlistAsync(int itemId)
}
}


/// <summary>
/// Retrieves a custom wishlist by its unique identifier.
/// </summary>
Expand All @@ -81,4 +102,4 @@ public virtual async Task<CustomWishlist> GetCustomWishlistByIdAsync(int itemId)
}

#endregion
}
}
3 changes: 2 additions & 1 deletion src/Libraries/Nop.Services/Orders/ICustomWishlistService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ public partial interface ICustomWishlistService
/// </summary>
/// <param name="itemId">The unique identifier of the custom wishlist item to remove. Must be a valid identifier of an existing item.</param>
Task RemoveCustomWishlistAsync(int itemId);
Task EditCustomWishlistAsync(int wishlistId, string newName, int customer);

/// <summary>
/// Retrieves a custom wishlist by its unique identifier.
Expand All @@ -35,4 +36,4 @@ public partial interface ICustomWishlistService
/// <returns>A <see cref="CustomWishlist"/> object representing the custom wishlist with the specified identifier. Returns
/// null if no wishlist is found with the given identifier.</returns>
Task<CustomWishlist> GetCustomWishlistByIdAsync(int itemId);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -92,14 +92,12 @@ protected virtual async Task SingleSlugRoutingAsync(HttpContext httpContext, Rou
var store = await _storeContext.GetCurrentStoreAsync();
var languages = await _languageService.GetAllLanguagesAsync(storeId: store.Id);
var language = languages
.FirstOrDefault(lang => lang.Published && lang.UniqueSeoCode.Equals(langValue?.ToString(), StringComparison.InvariantCultureIgnoreCase))
?? languages.FirstOrDefault();
.FirstOrDefault(lang => lang.UniqueSeoCode.Equals(langValue?.ToString(), StringComparison.InvariantCultureIgnoreCase))
?? languages.FirstOrDefault();

var slugLocalized = await _urlRecordService.GetActiveSlugAsync(urlRecord.EntityId, urlRecord.EntityName, language.Id);
var slugLocalized = await _urlRecordService.GetSeNameAsync(urlRecord.EntityId, urlRecord.EntityName, language.Id, true, false);
if (!string.IsNullOrEmpty(slugLocalized) && !slugLocalized.Equals(slug, StringComparison.InvariantCultureIgnoreCase))
{
//we should make validation above because some entities does not have SeName for standard (Id = 0) language (e.g. news, blog posts)

//redirect to the page for current language
InternalRedirect(httpContext, values, $"/{language.UniqueSeoCode}/{slugLocalized}", false);
return;
Expand Down Expand Up @@ -208,11 +206,11 @@ protected virtual async Task<bool> TryProductCatalogRoutingAsync(HttpContext htt
var store = await _storeContext.GetCurrentStoreAsync();
var languages = await _languageService.GetAllLanguagesAsync(storeId: store.Id);
var language = languages
.FirstOrDefault(lang => lang.Published && lang.UniqueSeoCode.Equals(langValue?.ToString(), StringComparison.InvariantCultureIgnoreCase))
?? languages.FirstOrDefault();
.FirstOrDefault(lang => lang.UniqueSeoCode.Equals(langValue?.ToString(), StringComparison.InvariantCultureIgnoreCase))
?? languages.FirstOrDefault();

var slugLocalized = await _urlRecordService.GetActiveSlugAsync(urlRecord.EntityId, urlRecord.EntityName, language.Id);
var catalogSlugLocalized = await _urlRecordService.GetActiveSlugAsync(catalogUrlRecord.EntityId, catalogUrlRecord.EntityName, language.Id);
var slugLocalized = await _urlRecordService.GetSeNameAsync(urlRecord.EntityId, urlRecord.EntityName, language.Id, true, false);
var catalogSlugLocalized = await _urlRecordService.GetSeNameAsync(catalogUrlRecord.EntityId, catalogUrlRecord.EntityName, language.Id, true, false);
if ((!string.IsNullOrEmpty(slugLocalized) && !slugLocalized.Equals(slug, StringComparison.InvariantCultureIgnoreCase)) ||
(!string.IsNullOrEmpty(catalogSlugLocalized) && !catalogSlugLocalized.Equals(catalogUrlRecord.Slug, StringComparison.InvariantCultureIgnoreCase)))
{
Expand Down
45 changes: 45 additions & 0 deletions src/Presentation/Nop.Web/Controllers/ShoppingCartController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1888,6 +1888,51 @@ public virtual async Task<IActionResult> MoveToCustomWishlist(int shoppingCartIt
});
}

[HttpPost]
public virtual async Task<IActionResult> RenameWishlist(int wishlistId, string name)
{
var customer = await _workContext.GetCurrentCustomerAsync();
var isGuest = await _customerService.IsGuestAsync(customer);

if (isGuest)
{
return Json(new
{
success = false,
message = await _localizationService.GetResourceAsync("Wishlist.MultipleWishlistNotForGuest")
});
}

if (!_shoppingCartSettings.AllowMultipleWishlist)
{
return Json(new
{
success = false,
message = await _localizationService.GetResourceAsync("Wishlist.NotAllowMultipleWishlist")
});
}

try
{
await _customWishlistService.EditCustomWishlistAsync(wishlistId, name, customer.Id);

return Json(new
{
success = true,
message = await _localizationService.GetResourceAsync("Wishlist.Rename.Success")
});
}
catch (Exception ex)
{
return Json(new
{
success = false,
message = ex.Message
});
}
}


[HttpPost]
public virtual async Task<IActionResult> DeleteWishlist(int wishlistId)
{
Expand Down
8 changes: 6 additions & 2 deletions src/Presentation/Nop.Web/Infrastructure/RouteProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,10 @@ public virtual void RegisterRoutes(IEndpointRouteBuilder endpointRouteBuilder)
pattern: $"addcustomwishlist",
defaults: new { controller = "ShoppingCart", action = "AddWishlist" });

endpointRouteBuilder.MapControllerRoute(name: NopRouteNames.Ajax.RENAME_CUSTOM_WISHLIST,
pattern: $"renamecustomwishlist",
defaults: new { controller = "ShoppingCart", action = "RenameWishlist" });

//comparing products (AJAX)
endpointRouteBuilder.MapControllerRoute(name: NopRouteNames.Ajax.ADD_PRODUCT_TO_COMPARE,
pattern: $"compareproducts/add/{{productId:min(0)}}",
Expand Down Expand Up @@ -508,12 +512,12 @@ public virtual void RegisterRoutes(IEndpointRouteBuilder endpointRouteBuilder)
pattern: $"{lang}/customer/gdpr",
defaults: new { controller = "Customer", action = "GdprTools" });

//customer check gift card balance
//customer check gift card balance
endpointRouteBuilder.MapControllerRoute(name: NopRouteNames.General.CHECK_GIFT_CARD_BALANCE,
pattern: $"{lang}/customer/checkgiftcardbalance",
defaults: new { controller = "Customer", action = "CheckGiftCardBalance" });

//customer multi-factor authentication settings
//customer multi-factor authentication settings
endpointRouteBuilder.MapControllerRoute(name: NopRouteNames.Standard.MULTI_FACTOR_AUTHENTICATION_SETTINGS,
pattern: $"{lang}/customer/multifactorauthentication",
defaults: new { controller = "Customer", action = "MultiFactorAuthentication" });
Expand Down