diff --git a/src/Orchard.Web/Modules/Orchard.ContentTypes/Controllers/AdminController.cs b/src/Orchard.Web/Modules/Orchard.ContentTypes/Controllers/AdminController.cs index 78ec18c63..df8589a95 100644 --- a/src/Orchard.Web/Modules/Orchard.ContentTypes/Controllers/AdminController.cs +++ b/src/Orchard.Web/Modules/Orchard.ContentTypes/Controllers/AdminController.cs @@ -53,12 +53,16 @@ namespace Orchard.ContentTypes.Controllers { if (String.IsNullOrWhiteSpace(viewModel.DisplayName)) { ModelState.AddModelError("DisplayName", T("The Display Name name can't be empty.").ToString()); } - - if ( _contentDefinitionService.GetTypes().Any(t => String.Equals(t.Name.Trim(), viewModel.Name.Trim(), StringComparison.OrdinalIgnoreCase)) ) { + + if (_contentDefinitionService.GetTypes().Any(t => String.Equals(t.Name.Trim(), viewModel.Name.Trim(), StringComparison.OrdinalIgnoreCase))) { ModelState.AddModelError("Name", T("A type with the same Id already exists.").ToString()); } - if ( _contentDefinitionService.GetTypes().Any(t => String.Equals(t.DisplayName.Trim(), viewModel.DisplayName.Trim(), StringComparison.OrdinalIgnoreCase)) ) { + if (!String.IsNullOrWhiteSpace(viewModel.Name) && !ContentDefinitionService.IsLetter(viewModel.Name[0])) { + ModelState.AddModelError("Name", T("The technical name must start with a letter.").ToString()); + } + + if (_contentDefinitionService.GetTypes().Any(t => String.Equals(t.DisplayName.Trim(), viewModel.DisplayName.Trim(), StringComparison.OrdinalIgnoreCase))) { ModelState.AddModelError("DisplayName", T("A type with the same Name already exists.").ToString()); } diff --git a/src/Orchard.Web/Modules/Orchard.ContentTypes/Services/ContentDefinitionService.cs b/src/Orchard.Web/Modules/Orchard.ContentTypes/Services/ContentDefinitionService.cs index 5d4ab98ca..fe04b5f86 100644 --- a/src/Orchard.Web/Modules/Orchard.ContentTypes/Services/ContentDefinitionService.cs +++ b/src/Orchard.Web/Modules/Orchard.ContentTypes/Services/ContentDefinitionService.cs @@ -71,6 +71,11 @@ namespace Orchard.ContentTypes.Services { if(String.IsNullOrWhiteSpace(name)) { name = GenerateContentTypeNameFromDisplayName(displayName); } + else { + if(!IsLetter(name[0])) { + throw new ArgumentException("Content type name must start with a letter", "name"); + } + } while ( _contentDefinitionManager.GetTypeDefinition(name) != null ) name = VersionName(name); @@ -235,11 +240,23 @@ namespace Orchard.ContentTypes.Services { name = dissallowed.Replace(name, String.Empty); name = name.Trim(); + // don't allow non A-Z chars as first letter, as they are not allowed in prefixes + if(name.Length > 0) { + if (!IsLetter(name[0])) { + name = name.Substring(1); + } + } + if (name.Length > 128) name = name.Substring(0, 128); + return name; } + public static bool IsLetter(char c) { + return ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z'); + } + //gratuitously stolen from the RoutableService public string GenerateContentTypeNameFromDisplayName(string displayName) { displayName = SafeName(displayName);