public void Should_remove_illegal_chars() { SeoExtensions.GetSeName("test!@#$%^&*()+<>?/", false, false).ShouldEqual("test"); }
public void Should_return_lowercase() { SeoExtensions.GetSeName("tEsT", false, false).ShouldEqual("test"); }
public void Should_allow_all_latin_chars() { SeoExtensions.GetSeName("abcdefghijklmnopqrstuvwxyz1234567890", false, false).ShouldEqual("abcdefghijklmnopqrstuvwxyz1234567890"); }
private async Task From430To440() { #region Install String resources await InstallStringResources("430_440.nopres.xml"); #endregion #region Permisions IPermissionProvider provider = new StandardPermissionProvider(); await _serviceProvider.GetRequiredService <IPermissionService>().InstallPermissions(provider); #endregion #region Update tags on the products var productTagService = _serviceProvider.GetRequiredService <IProductTagService>(); var productRepository = _serviceProvider.GetRequiredService <IRepository <Product> >(); foreach (var tag in await productTagService.GetAllProductTags()) { var builder = Builders <Product> .Filter; var filter = new BsonDocument { new BsonElement("ProductTags", tag.Id) }; var update = Builders <Product> .Update .Set(x => x.ProductTags.ElementAt(-1), tag.Name); await productRepository.Collection.UpdateManyAsync(filter, update); tag.SeName = SeoExtensions.GetSeName(tag.Name, false, false); await productTagService.UpdateProductTag(tag); } #endregion #region User api _serviceProvider.GetRequiredService <IRepository <UserApi> >().Collection.Indexes.CreateOne(new CreateIndexModel <UserApi>((Builders <UserApi> .IndexKeys.Ascending(x => x.Email)), new CreateIndexOptions() { Name = "Email", Unique = true, Background = true })); #endregion #region Update message templates (tokens) string ReplaceValue(string value) { string Evaluator(Match match) { return($"{{{{{match.Value.Replace("%", "")}}}}}"); } var evaluator = new MatchEvaluator(Evaluator); return(Regex.Replace(value, @"%([A-Za-z0-9_.]*?)%", new MatchEvaluator(Evaluator))); } var orderProducts = File.ReadAllText(CommonHelper.MapPath("~/App_Data/Upgrade/Order.Products.txt")); var shipmentProducts = File.ReadAllText(CommonHelper.MapPath("~/App_Data/Upgrade/Shipment.Products.txt")); var messagetemplateService = _serviceProvider.GetRequiredService <Grand.Services.Messages.IMessageTemplateService>(); var messagetemplates = await messagetemplateService.GetAllMessageTemplates(string.Empty); foreach (var messagetemplate in messagetemplates) { messagetemplate.Subject = ReplaceValue(messagetemplate.Subject); if (messagetemplate.Body.Contains("%Order.Product(s)%")) { messagetemplate.Body = messagetemplate.Body.Replace("%Order.Product(s)%", orderProducts); } if (messagetemplate.Body.Contains("%Shipment.Product(s)%")) { messagetemplate.Body = messagetemplate.Body.Replace("%Shipment.Product(s)%", shipmentProducts); } messagetemplate.Body = ReplaceValue(messagetemplate.Body); await messagetemplateService.UpdateMessageTemplate(messagetemplate); } #endregion #region Insert message template var eaGeneral = _serviceProvider.GetRequiredService <IRepository <EmailAccount> >().Table.FirstOrDefault(); if (eaGeneral == null) { throw new Exception("Default email account cannot be loaded"); } var messageTemplates = new List <MessageTemplate> { new MessageTemplate { Name = "AuctionExpired.StoreOwnerNotification", Subject = "Your auction to product {{Product.Name}} has expired.", Body = "Hello, <br> Your auction to product {{Product.Name}} has expired without bid.", //this template is disabled by default IsActive = false, EmailAccountId = eaGeneral.Id, } }; await _serviceProvider.GetRequiredService <IRepository <MessageTemplate> >().InsertAsync(messageTemplates); #endregion }
/// <summary> /// Get picture SEO friendly name /// </summary> /// <param name="name">Name</param> /// <returns>Result</returns> public virtual string GetPictureSeName(string name) { return(SeoExtensions.GetSeName(name, true, false)); }
/// <summary> /// Route request to the particular action /// </summary> /// <param name="context">A route context object</param> /// <returns>Task of the routing</returns> public override async Task RouteAsync(RouteContext context) { if (!DataSettingsHelper.DatabaseIsInstalled()) { return; } //try to get slug from the route data var routeValues = await GetRouteValues(context); if (!routeValues.TryGetValue("GenericSeName", out object slugValue) || string.IsNullOrEmpty(slugValue as string)) { return; } var slug = slugValue as string; //virtual directory path var pathBase = context.HttpContext.Request.PathBase; //performance optimization, we load a cached verion here. It reduces number of SQL requests for each page load var urlRecordService = context.HttpContext.RequestServices.GetRequiredService <IUrlRecordService>(); var urlRecord = await urlRecordService.GetBySlugCached(slug); //no URL record found if (urlRecord == null) { return; } //if URL record is not active let's find the latest one if (!urlRecord.IsActive) { var activeSlug = await urlRecordService.GetActiveSlug(urlRecord.EntityId, urlRecord.EntityName, urlRecord.LanguageId); if (string.IsNullOrEmpty(activeSlug)) { return; } //redirect to active slug if found var redirectionRouteData = new RouteData(context.RouteData); redirectionRouteData.Values["controller"] = "Common"; redirectionRouteData.Values["action"] = "InternalRedirect"; redirectionRouteData.Values["url"] = $"{pathBase}/{activeSlug}{context.HttpContext.Request.QueryString}"; redirectionRouteData.Values["permanentRedirect"] = true; context.HttpContext.Items["grand.RedirectFromGenericPathRoute"] = true; context.RouteData = redirectionRouteData; await _target.RouteAsync(context); return; } //ensure that the slug is the same for the current language, //otherwise it can cause some issues when customers choose a new language but a slug stays the same var workContext = context.HttpContext.RequestServices.GetRequiredService <IWorkContext>(); var slugForCurrentLanguage = await SeoExtensions.GetSeName(urlRecordService, context.HttpContext, urlRecord.EntityId, urlRecord.EntityName, workContext.WorkingLanguage.Id); if (!string.IsNullOrEmpty(slugForCurrentLanguage) && !slugForCurrentLanguage.Equals(slug, StringComparison.OrdinalIgnoreCase)) { //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 var redirectionRouteData = new RouteData(context.RouteData); redirectionRouteData.Values["controller"] = "Common"; redirectionRouteData.Values["action"] = "InternalRedirect"; redirectionRouteData.Values["url"] = $"{pathBase}/{slugForCurrentLanguage}{context.HttpContext.Request.QueryString}"; redirectionRouteData.Values["permanentRedirect"] = false; context.HttpContext.Items["grand.RedirectFromGenericPathRoute"] = true; context.RouteData = redirectionRouteData; await _target.RouteAsync(context); return; } //since we are here, all is ok with the slug, so process URL var currentRouteData = new RouteData(context.RouteData); switch (urlRecord.EntityName.ToLowerInvariant()) { case "product": currentRouteData.Values["controller"] = "Product"; currentRouteData.Values["action"] = "ProductDetails"; currentRouteData.Values["productid"] = urlRecord.EntityId; currentRouteData.Values["SeName"] = urlRecord.Slug; break; case "category": currentRouteData.Values["controller"] = "Catalog"; currentRouteData.Values["action"] = "Category"; currentRouteData.Values["categoryid"] = urlRecord.EntityId; currentRouteData.Values["SeName"] = urlRecord.Slug; break; case "manufacturer": currentRouteData.Values["controller"] = "Catalog"; currentRouteData.Values["action"] = "Manufacturer"; currentRouteData.Values["manufacturerid"] = urlRecord.EntityId; currentRouteData.Values["SeName"] = urlRecord.Slug; break; case "vendor": currentRouteData.Values["controller"] = "Catalog"; currentRouteData.Values["action"] = "Vendor"; currentRouteData.Values["vendorid"] = urlRecord.EntityId; currentRouteData.Values["SeName"] = urlRecord.Slug; break; case "newsitem": currentRouteData.Values["controller"] = "News"; currentRouteData.Values["action"] = "NewsItem"; currentRouteData.Values["newsItemId"] = urlRecord.EntityId; currentRouteData.Values["SeName"] = urlRecord.Slug; break; case "blogpost": currentRouteData.Values["controller"] = "Blog"; currentRouteData.Values["action"] = "BlogPost"; currentRouteData.Values["blogPostId"] = urlRecord.EntityId; currentRouteData.Values["SeName"] = urlRecord.Slug; break; case "topic": currentRouteData.Values["controller"] = "Topic"; currentRouteData.Values["action"] = "TopicDetails"; currentRouteData.Values["topicId"] = urlRecord.EntityId; currentRouteData.Values["SeName"] = urlRecord.Slug; break; case "knowledgebasearticle": currentRouteData.Values["controller"] = "Knowledgebase"; currentRouteData.Values["action"] = "KnowledgebaseArticle"; currentRouteData.Values["articleId"] = urlRecord.EntityId; currentRouteData.Values["SeName"] = urlRecord.Slug; break; case "knowledgebasecategory": currentRouteData.Values["controller"] = "Knowledgebase"; currentRouteData.Values["action"] = "ArticlesByCategory"; currentRouteData.Values["categoryId"] = urlRecord.EntityId; currentRouteData.Values["SeName"] = urlRecord.Slug; break; case "course": currentRouteData.Values["controller"] = "Course"; currentRouteData.Values["action"] = "Details"; currentRouteData.Values["courseId"] = urlRecord.EntityId; currentRouteData.Values["SeName"] = urlRecord.Slug; break; default: //no record found, thus generate an event this way developers could insert their own types await context.HttpContext.RequestServices.GetRequiredService <IMediator>().Publish(new CustomUrlRecordEntityNameRequested(currentRouteData, urlRecord)); break; } context.RouteData = currentRouteData; //route request await _target.RouteAsync(context); }
/// <summary> /// Returns information about the requested route. /// </summary> /// <param name="httpContext">An object that encapsulates information about the HTTP request.</param> /// <returns> /// An object that contains the values from the route definition. /// </returns> public override RouteData GetRouteData(HttpContextBase httpContext) { RouteData data = base.GetRouteData(httpContext); if (data != null && DataSettingsHelper.DatabaseIsInstalled()) { var urlRecordService = EngineContext.Current.Resolve <IUrlRecordService>(); var slug = data.Values["generic_se_name"] as string; //performance optimization. //we load a cached verion here. it reduces number of SQL requests for each page load var urlRecord = urlRecordService.GetBySlugCached(slug); //comment the line above and uncomment the line below in order to disable this performance "workaround" //var urlRecord = urlRecordService.GetBySlug(slug); if (urlRecord == null) { //no URL record found //var webHelper = EngineContext.Current.Resolve<IWebHelper>(); //var response = httpContext.Response; //response.Status = "302 Found"; //response.RedirectLocation = webHelper.GetStoreLocation(false); //response.End(); //return null; data.Values["controller"] = "Common"; data.Values["action"] = "PageNotFound"; return(data); } //ensre that URL record is active if (!urlRecord.IsActive) { //URL record is not active. let's find the latest one var activeSlug = urlRecordService.GetActiveSlug(urlRecord.EntityId, urlRecord.EntityName, urlRecord.LanguageId); if (string.IsNullOrWhiteSpace(activeSlug)) { //no active slug found //var webHelper = EngineContext.Current.Resolve<IWebHelper>(); //var response = httpContext.Response; //response.Status = "302 Found"; //response.RedirectLocation = webHelper.GetStoreLocation(false); //response.End(); //return null; data.Values["controller"] = "Common"; data.Values["action"] = "PageNotFound"; return(data); } //the active one is found var webHelper = EngineContext.Current.Resolve <IWebHelper>(); var response = httpContext.Response; response.Status = "301 Moved Permanently"; response.RedirectLocation = string.Format("{0}{1}", webHelper.GetStoreLocation(false), activeSlug); response.End(); return(null); } //ensure that the slug is the same for the current language //otherwise, it can cause some issues when customers choose a new language but a slug stays the same var workContext = EngineContext.Current.Resolve <IWorkContext>(); var slugForCurrentLanguage = SeoExtensions.GetSeName(urlRecord.EntityId, urlRecord.EntityName, workContext.WorkingLanguage.Id); if (!String.IsNullOrEmpty(slugForCurrentLanguage) && !slugForCurrentLanguage.Equals(slug, StringComparison.InvariantCultureIgnoreCase)) { //we should make not null or "" validation above because some entities does not have SeName for standard (ID=0) language (e.g. news, blog posts) var webHelper = EngineContext.Current.Resolve <IWebHelper>(); var response = httpContext.Response; //response.Status = "302 Found"; response.Status = "302 Moved Temporarily"; response.RedirectLocation = string.Format("{0}{1}", webHelper.GetStoreLocation(false), slugForCurrentLanguage); response.End(); return(null); } //process URL switch (urlRecord.EntityName.ToLowerInvariant()) { case "product": { data.Values["controller"] = "Product"; data.Values["action"] = "ProductDetails"; data.Values["productid"] = urlRecord.EntityId; data.Values["SeName"] = urlRecord.Slug; } break; case "category": { data.Values["controller"] = "Catalog"; data.Values["action"] = "Category"; data.Values["categoryid"] = urlRecord.EntityId; data.Values["SeName"] = urlRecord.Slug; } break; case "manufacturer": { data.Values["controller"] = "Catalog"; data.Values["action"] = "Manufacturer"; data.Values["manufacturerid"] = urlRecord.EntityId; data.Values["SeName"] = urlRecord.Slug; } break; case "vendor": { data.Values["controller"] = "Catalog"; data.Values["action"] = "Vendor"; data.Values["vendorid"] = urlRecord.EntityId; data.Values["SeName"] = urlRecord.Slug; } break; case "newsitem": { data.Values["controller"] = "News"; data.Values["action"] = "NewsItem"; data.Values["newsItemId"] = urlRecord.EntityId; data.Values["SeName"] = urlRecord.Slug; } break; case "blogpost": { data.Values["controller"] = "Blog"; data.Values["action"] = "BlogPost"; data.Values["blogPostId"] = urlRecord.EntityId; data.Values["SeName"] = urlRecord.Slug; } break; case "topic": { data.Values["controller"] = "Topic"; data.Values["action"] = "TopicDetails"; data.Values["topicId"] = urlRecord.EntityId; data.Values["SeName"] = urlRecord.Slug; } break; default: { //no record found //generate an event this way developers could insert their own types EngineContext.Current.Resolve <IEventPublisher>() .Publish(new CustomUrlRecordEntityNameRequested(data, urlRecord)); } break; } } return(data); }
public void Can_convert_non_western_chars() { //german letters with diacritics SeoExtensions.GetSeName("testäöü", true, false).ShouldEqual("testaou"); SeoExtensions.GetSeName("testäöü", false, false).ShouldEqual("test"); }
public void Can_allow_unicode_chars() { //russian letters SeoExtensions.GetSeName("testтест", true, true).ShouldEqual("testтест"); SeoExtensions.GetSeName("testтест", true, false).ShouldEqual("test"); }
public IViewComponentResult Invoke(string widgetZone, object additionalData) { IViewComponentResult viewComponent; EmptyResult emptyResult = new EmptyResult(); VendorDetailsSettings VendorDetailsSetting = _settingService.LoadSetting <VendorDetailsSettings>(_storeContext.CurrentStore.Id); if (VendorDetailsSetting != null) { int productId = Convert.ToInt32(additionalData); if (productId != 0) { var P = _customersInfo.GetCount(productId); Product productById = _productService.GetProductById(productId); if (productById == null ? false : productById.VendorId == 0) { PublicInfoModel yom = new PublicInfoModel(); yom.Name = productById.Name; yom.SoldCount = P.Count; PublicInfoModel email1 = yom; viewComponent = base.View("~/Plugins/Widgets.VendorDetails/Views/raw.cshtml", email1); } else if (productById == null ? false : productById.VendorId != 0) { var VendorIds = this._vendorService.GetVendorById(productById.VendorId).Id; var CustomerIds = _customersInfo.GetCustomerId(VendorIds); Vendor vendorById = this._vendorService.GetVendorById(productById.VendorId); PublicInfoModel Model = new PublicInfoModel(); //Model.Id(vendorById.get_Id()); Model.Name = vendorById.Name; Model.Description = vendorById.Description; //Model.Rating = productById.ApprovedRatingSum; //Model.SoldCount = P.Count; //Model.Phone = CustomerIds.GetAttribute<String>(SystemCustomerAttributeNames.Phone); Model.SeName = SeoExtensions.GetSeName(vendorById); PublicInfoModel email = Model; if (VendorDetailsSetting.ShowVendorEmail) { email.Email = vendorById.Email; } if (VendorDetailsSetting.ShowProductRating) { email.Rating = productById.ApprovedRatingSum; } if (VendorDetailsSetting.ShowProductSoldCount) { email.SoldCount = P.Count; } if (VendorDetailsSetting.ShowVendorPhoneNumer) { email.Phone = CustomerIds.GetAttribute <String>(SystemCustomerAttributeNames.Phone); } viewComponent = base.View("~/Plugins/Widgets.VendorDetails/Views/PublicInfo.cshtml", email); } else { viewComponent = null; } } else { viewComponent = null; } } else { viewComponent = null; } return(viewComponent); }
public void Should_replace_space_with_dash() { SeoExtensions.GetSeName("test test", false, false).ShouldEqual("test-test"); SeoExtensions.GetSeName("test test", false, false).ShouldEqual("test-test"); }
public ActionResult Edit(EventPageModel model, bool continueEditing) { //todo: add later //if (!_permissionService.Authorize(MobSocialPermissionProvider.ManageEventPages)) // return AccessDeniedView(); var item = _eventPageService.GetById(model.Id); if (item == null) { //No product found with the specified id return(RedirectToAction("List")); } if (ModelState.IsValid) { item.Name = model.Name; item.LocationName = model.LocationName; item.LocationAddress1 = model.Address1; item.LocationAddress2 = model.Address2; item.LocationCity = model.City; item.LocationState = model.LocationState; item.LocationZipPostalCode = model.ZipPostalCode; item.LocationCountry = model.LocationCountry; item.LocationPhone = model.Phone; item.LocationWebsite = model.Website; item.LocationEmail = model.Email; item.StartDate = model.StartDate; item.EndDate = model.EndDate; item.Description = model.Description; item.MetaKeywords = model.MetaKeywords; item.MetaDescription = model.MetaDescription; item.DateUpdated = DateTime.Now; _eventPageService.Update(item); //search engine name model.SeName = SeoExtensions.GetSeName(item, _workContext.WorkingLanguage.Id); _urlRecordService.SaveSlug(item, model.SeName, _workContext.WorkingLanguage.Id); //picture seo names //UpdatePictureSeoNames(product); SuccessNotification(_localizationService.GetResource("Admin.MobSocial.EventPage.Updated")); if (continueEditing) { //selected tab SaveSelectedTabName(); return(RedirectToAction("Edit", new { id = item.Id })); } else { return(RedirectToAction("List")); } } return(View("~/Plugins/Widgets.mobSocial/Views/mobSocial/Admin/ManageEventPage/Edit.cshtml", model)); }
/// <summary> /// Route request to the particular action /// </summary> /// <param name="context">A route context object</param> /// <returns>Task of the routing</returns> public override Task RouteAsync(RouteContext context) { if (!DataSettingsHelper.DatabaseIsInstalled()) { return(Task.CompletedTask); } //get current route data var urlRecordService = EngineContextExperimental.Current.Resolve <IUrlRecordService>(); //get slug from path var currentRouteData = new RouteData(context.RouteData); //tbh string slug = string.Empty; #if NET451 slug = currentRouteData.Values["generic_se_name"] as string; #endif #if NETCOREAPP1_1 //temporary solution until we can get currentRouteData.Values string path = context.HttpContext.Request.Path.Value; if (!string.IsNullOrEmpty(path) && path[0] == '/') { path = path.Substring(1); } var pathParts = path.Split('/'); slug = pathParts.Length > 1 ? pathParts[0] : path; #endif //performance optimization //we load a cached verion here. It reduces number of SQL requests for each page load var urlRecord = urlRecordService.GetBySlugCached(slug); //comment the line above and uncomment the line below in order to disable this performance "workaround" //var urlRecord = urlRecordService.GetBySlug(slug); //no URL record found if (urlRecord == null) { return(Task.CompletedTask); } if (!urlRecord.IsActive) { //URL record is not active. let's find the latest one var activeSlug = urlRecordService.GetActiveSlug(urlRecord.EntityId, urlRecord.EntityName, urlRecord.LanguageId); //no active slug found if (string.IsNullOrEmpty(activeSlug)) { return(Task.CompletedTask); } //the active one is found var webHelper = EngineContextExperimental.Current.Resolve <IWebHelper>(); var location = string.Format("{0}{1}", webHelper.GetStoreLocation(), activeSlug); context.HttpContext.Response.Redirect(location, true); return(Task.CompletedTask); } //ensure that the slug is the same for the current language //otherwise, it can cause some issues when customers choose a new language but a slug stays the same var workContext = EngineContextExperimental.Current.Resolve <IWorkContext>(); var slugForCurrentLanguage = SeoExtensions.GetSeName(urlRecord.EntityId, urlRecord.EntityName, workContext.WorkingLanguage.Id); if (!string.IsNullOrEmpty(slugForCurrentLanguage) && !slugForCurrentLanguage.Equals(slug, StringComparison.OrdinalIgnoreCase)) { //we should make validation above because some entities does not have SeName for standard (Id = 0) language (e.g. news, blog posts) var webHelper = EngineContextExperimental.Current.Resolve <IWebHelper>(); var location = string.Format("{0}{1}", webHelper.GetStoreLocation(), slugForCurrentLanguage); context.HttpContext.Response.Redirect(location, false); return(Task.CompletedTask); } //process URL switch (urlRecord.EntityName.ToLowerInvariant()) { case "product": currentRouteData.Values["controller"] = "Product"; currentRouteData.Values["action"] = "ProductDetails"; currentRouteData.Values["productid"] = urlRecord.EntityId; currentRouteData.Values["SeName"] = urlRecord.Slug; break; case "category": currentRouteData.Values["controller"] = "Catalog"; currentRouteData.Values["action"] = "Category"; currentRouteData.Values["categoryid"] = urlRecord.EntityId; currentRouteData.Values["SeName"] = urlRecord.Slug; break; case "manufacturer": currentRouteData.Values["controller"] = "Catalog"; currentRouteData.Values["action"] = "Manufacturer"; currentRouteData.Values["manufacturerid"] = urlRecord.EntityId; currentRouteData.Values["SeName"] = urlRecord.Slug; break; case "vendor": currentRouteData.Values["controller"] = "Catalog"; currentRouteData.Values["action"] = "Vendor"; currentRouteData.Values["vendorid"] = urlRecord.EntityId; currentRouteData.Values["SeName"] = urlRecord.Slug; break; case "newsitem": currentRouteData.Values["controller"] = "News"; currentRouteData.Values["action"] = "NewsItem"; currentRouteData.Values["newsItemId"] = urlRecord.EntityId; currentRouteData.Values["SeName"] = urlRecord.Slug; break; case "blogpost": currentRouteData.Values["controller"] = "Blog"; currentRouteData.Values["action"] = "BlogPost"; currentRouteData.Values["blogPostId"] = urlRecord.EntityId; currentRouteData.Values["SeName"] = urlRecord.Slug; break; case "topic": currentRouteData.Values["controller"] = "Topic"; currentRouteData.Values["action"] = "TopicDetails"; currentRouteData.Values["topicId"] = urlRecord.EntityId; currentRouteData.Values["SeName"] = urlRecord.Slug; break; default: //no record found //thus generate an event this way developers could insert their own types EngineContextExperimental.Current.Resolve <IEventPublisher>().Publish(new CustomUrlRecordEntityNameRequested(currentRouteData, urlRecord)); break; } context.RouteData = currentRouteData; //route request return(_target.RouteAsync(context)); }
private async Task From460To470() { #region Install String resources await InstallStringResources("EN_460_470.nopres.xml"); #endregion #region MessageTemplates var emailAccount = _serviceProvider.GetRequiredService <IRepository <EmailAccount> >().Table.FirstOrDefault(); if (emailAccount == null) { throw new Exception("Default email account cannot be loaded"); } var messageTemplates = new List <MessageTemplate> { new MessageTemplate { Name = "Customer.EmailTokenValidationMessage", Subject = "{{Store.Name}} - Email Verification Code", Body = "Hello {{Customer.FullName}}, <br /><br />\r\n Enter this 6 digit code on the sign in page to confirm your identity:<br /><br /> \r\n <b>{{Customer.Token}}</b><br /><br />\r\n Yours securely, <br /> \r\n Team", IsActive = true, EmailAccountId = emailAccount.Id, }, new MessageTemplate { Name = "OrderCancelled.VendorNotification", Subject = "{{Store.Name}}. Order #{{Order.OrderNumber}} cancelled", Body = "<p><a href=\"{{Store.URL}}\">{{Store.Name}}</a> <br /><br />Order #{{Order.OrderNumber}} has been cancelled. <br /><br />Order Number: {{Order.OrderNumber}}<br /> Date Ordered: {{Order.CreatedOn}} <br /><br /> ", IsActive = false, EmailAccountId = emailAccount.Id, }, }; await _serviceProvider.GetRequiredService <IRepository <MessageTemplate> >().InsertAsync(messageTemplates); #endregion #region Update store var storeService = _serviceProvider.GetRequiredService <IStoreService>(); foreach (var store in await storeService.GetAllStores()) { store.Shortcut = "Store"; await storeService.UpdateStore(store); } #endregion #region Update specification - sename field var specification = _serviceProvider.GetRequiredService <IRepository <SpecificationAttribute> >(); foreach (var specificationAttribute in specification.Table.ToList()) { specificationAttribute.SeName = SeoExtensions.GetSeName(specificationAttribute.Name, false, false); specificationAttribute.SpecificationAttributeOptions.ToList().ForEach(x => { x.SeName = SeoExtensions.GetSeName(x.Name, false, false); }); await specification.UpdateAsync(specificationAttribute); } #endregion #region Update product attributes - sename field var attributes = _serviceProvider.GetRequiredService <IRepository <ProductAttribute> >(); foreach (var attribute in attributes.Table.ToList()) { attribute.SeName = SeoExtensions.GetSeName(attribute.Name, false, false); await attributes.UpdateAsync(attribute); } #endregion #region Update blog category - sename field var blogcategories = _serviceProvider.GetRequiredService <IRepository <BlogCategory> >(); foreach (var category in blogcategories.Table.ToList()) { category.SeName = SeoExtensions.GetSeName(category.Name, false, false); await blogcategories.UpdateAsync(category); } #endregion #region Update media settings var settingsService = _serviceProvider.GetRequiredService <ISettingService>(); var storeInDB = settingsService.GetSettingByKey("Media.Images.StoreInDB", true); await settingsService.SetSetting("MediaSettings.StoreInDb", storeInDB); #endregion }
private void HookObject(BaseEntity baseEntity, IHookedEntity entry) { var type = entry.EntityType; if (!_candidateTypes.Contains(type)) { throw new NotSupportedException(); } if (type == typeof(SpecificationAttribute)) { if (HasAliasDuplicate <ProductAttribute, SpecificationAttribute>(entry, baseEntity)) { return; } if (IsPropertyModified(entry, "Alias")) { _catalogSearchQueryAliasMapper.Value.ClearAttributeCache(); } } else if (type == typeof(SpecificationAttributeOption)) { var entity = (SpecificationAttributeOption)baseEntity; if (HasEntityDuplicate <SpecificationAttributeOption>(entry, baseEntity, x => x.Name, x => x.SpecificationAttributeId == entity.SpecificationAttributeId && x.Name == entity.Name)) { return; } if (HasAliasDuplicate <SpecificationAttributeOption>(entry, baseEntity)) { return; } if (IsPropertyModified(entry, "Alias")) { _catalogSearchQueryAliasMapper.Value.ClearAttributeCache(); } } else if (type == typeof(ProductSpecificationAttribute)) { var entity = (ProductSpecificationAttribute)baseEntity; if (HasEntityDuplicate <ProductSpecificationAttribute>(entry, baseEntity, x => x.SpecificationAttributeOption?.Name, x => x.ProductId == entity.ProductId && x.SpecificationAttributeOptionId == entity.SpecificationAttributeOptionId)) { return; } } else if (type == typeof(ProductAttribute)) { if (HasAliasDuplicate <ProductAttribute, SpecificationAttribute>(entry, baseEntity)) { return; } if (IsPropertyModified(entry, "Alias")) { _catalogSearchQueryAliasMapper.Value.ClearVariantCache(); } } else if (type == typeof(ProductAttributeOption)) { var entity = (ProductAttributeOption)baseEntity; if (HasEntityDuplicate <ProductAttributeOption>(entry, baseEntity, x => x.Name, x => x.ProductAttributeOptionsSetId == entity.ProductAttributeOptionsSetId && x.Name == entity.Name)) { return; } // ClearVariantCache() not necessary if (HasAliasDuplicate <ProductAttributeOption>(entry, baseEntity)) { return; } } else if (type == typeof(ProductVariantAttribute)) { var entity = (ProductVariantAttribute)baseEntity; if (HasEntityDuplicate <ProductVariantAttribute>(entry, baseEntity, x => x.ProductAttribute?.Name, x => x.ProductId == entity.ProductId && x.ProductAttributeId == entity.ProductAttributeId)) { return; } } else if (type == typeof(ProductVariantAttributeValue)) { var entity = (ProductVariantAttributeValue)baseEntity; if (HasEntityDuplicate <ProductVariantAttributeValue>(entry, baseEntity, x => x.Name, x => x.ProductVariantAttributeId == entity.ProductVariantAttributeId && x.Name == entity.Name)) { return; } if (HasAliasDuplicate <ProductVariantAttributeValue>(entry, baseEntity, (all, e) => all.Any(x => x.Id != e.Id && x.ProductVariantAttributeId == e.ProductVariantAttributeId && x.Alias == e.Alias))) { return; } if (IsPropertyModified(entry, "Alias")) { _catalogSearchQueryAliasMapper.Value.ClearVariantCache(); } } else if (type == typeof(LocalizedProperty)) { // note: not fired when SpecificationAttribute or SpecificationAttributeOption deleted. // not necessary anyway because cache cleared by above code. var prop = (LocalizedProperty)baseEntity; var keyGroup = prop.LocaleKeyGroup; if (!prop.LocaleKey.IsCaseInsensitiveEqual("Alias")) { return; } // validating ProductVariantAttributeValue goes too far here. if (!keyGroup.IsCaseInsensitiveEqual("SpecificationAttribute") && !keyGroup.IsCaseInsensitiveEqual("SpecificationAttributeOption") && !keyGroup.IsCaseInsensitiveEqual("ProductAttribute") && !keyGroup.IsCaseInsensitiveEqual("ProductAttributeOption")) { return; } // check alias duplicate if (entry.InitialState == EntityState.Added || entry.InitialState == EntityState.Modified) { prop.LocaleValue = SeoExtensions.GetSeName(prop.LocaleValue); if (prop.LocaleValue.HasValue() && HasAliasDuplicate(prop)) { RevertChanges(entry, string.Concat(T("Common.Error.AliasAlreadyExists", prop.LocaleValue), " ", T("Common.Error.ChooseDifferentValue"))); return; } } if (IsPropertyModified(entry, "LocaleValue")) { if (keyGroup.IsCaseInsensitiveEqual("SpecificationAttribute") || keyGroup.IsCaseInsensitiveEqual("SpecificationAttributeOption")) { _catalogSearchQueryAliasMapper.Value.ClearAttributeCache(); } else if (keyGroup.IsCaseInsensitiveEqual("ProductAttribute") || keyGroup.IsCaseInsensitiveEqual("ProductVariantAttributeValue")) { // not necessary for ProductAttributeOption _catalogSearchQueryAliasMapper.Value.ClearVariantCache(); } } } }
public void Can_encode_for_url() { //russian letters т should be encoded as "%d1%82" SeoExtensions.GetSeName("testт", true, true, true).ShouldEqual("test%d1%82"); }