mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-10-15 19:54:57 +08:00
Validating content type names, and displaying technical names
Work Item: 16471 --HG-- branch : dev
This commit is contained in:
84
src/Orchard.Specs/ContentTypes.feature
Normal file
84
src/Orchard.Specs/ContentTypes.feature
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
Feature: Content Types
|
||||||
|
In order to add new types to my site
|
||||||
|
As an adminitrator
|
||||||
|
I want to create create content types
|
||||||
|
|
||||||
|
Scenario: I can create a new content type
|
||||||
|
Given I have installed Orchard
|
||||||
|
And I have installed "Orchard.ContentTypes"
|
||||||
|
When I go to "Admin/ContentTypes"
|
||||||
|
Then I should see "<a[^>]*>.*?Create new type</a>"
|
||||||
|
When I go to "Admin/ContentTypes/Create"
|
||||||
|
And I fill in
|
||||||
|
| name | value |
|
||||||
|
| DisplayName | Event |
|
||||||
|
| Name | Event |
|
||||||
|
And I hit "Create"
|
||||||
|
And I go to "Admin/ContentTypes/"
|
||||||
|
Then I should see "Event"
|
||||||
|
|
||||||
|
Scenario: I can't create a content type with an already existing name
|
||||||
|
Given I have installed Orchard
|
||||||
|
And I have installed "Orchard.ContentTypes"
|
||||||
|
When I go to "Admin/ContentTypes/Create"
|
||||||
|
And I fill in
|
||||||
|
| name | value |
|
||||||
|
| DisplayName | Event |
|
||||||
|
| Name | Event |
|
||||||
|
And I hit "Create"
|
||||||
|
And I go to "Admin/ContentTypes/"
|
||||||
|
Then I should see "Event"
|
||||||
|
When I go to "Admin/ContentTypes/Create"
|
||||||
|
And I fill in
|
||||||
|
| name | value |
|
||||||
|
| DisplayName | Event |
|
||||||
|
| Name | Event-2 |
|
||||||
|
And I hit "Create"
|
||||||
|
Then I should see "<h1[^>]*>.*?New Content Type.*?</h1>"
|
||||||
|
And I should see "validation-summary-errors"
|
||||||
|
|
||||||
|
Scenario: I can't create a content type with an already existing technical name
|
||||||
|
Given I have installed Orchard
|
||||||
|
And I have installed "Orchard.ContentTypes"
|
||||||
|
When I go to "Admin/ContentTypes/Create"
|
||||||
|
And I fill in
|
||||||
|
| name | value |
|
||||||
|
| DisplayName | Dinner |
|
||||||
|
| Name | Dinner |
|
||||||
|
And I hit "Create"
|
||||||
|
And I go to "Admin/ContentTypes/"
|
||||||
|
Then I should see "Dinner"
|
||||||
|
When I go to "Admin/ContentTypes/Create"
|
||||||
|
And I fill in
|
||||||
|
| name | value |
|
||||||
|
| DisplayName | Dinner2 |
|
||||||
|
| Name | Dinner |
|
||||||
|
And I hit "Create"
|
||||||
|
Then I should see "<h1[^>]*>.*?New Content Type.*?</h1>"
|
||||||
|
And I should see "validation-summary-errors"
|
||||||
|
|
||||||
|
Scenario: I can't rename a content type with an already existing name
|
||||||
|
Given I have installed Orchard
|
||||||
|
And I have installed "Orchard.ContentTypes"
|
||||||
|
When I go to "Admin/ContentTypes/Create"
|
||||||
|
And I fill in
|
||||||
|
| name | value |
|
||||||
|
| DisplayName | Dinner |
|
||||||
|
| Name | Dinner |
|
||||||
|
And I hit "Create"
|
||||||
|
And I go to "Admin/ContentTypes/"
|
||||||
|
Then I should see "Dinner"
|
||||||
|
When I go to "Admin/ContentTypes/Create"
|
||||||
|
And I fill in
|
||||||
|
| name | value |
|
||||||
|
| DisplayName | Event |
|
||||||
|
| Name | Event |
|
||||||
|
And I hit "Create"
|
||||||
|
And I go to "Admin/ContentTypes/"
|
||||||
|
Then I should see "Event"
|
||||||
|
When I go to "Admin/ContentTypes/Edit/Dinner"
|
||||||
|
And I fill in
|
||||||
|
| name | value |
|
||||||
|
| DisplayName | Event |
|
||||||
|
And I hit "Save"
|
||||||
|
Then I should see "validation-summary-errors"
|
276
src/Orchard.Specs/ContentTypes.feature.cs
generated
Normal file
276
src/Orchard.Specs/ContentTypes.feature.cs
generated
Normal file
@@ -0,0 +1,276 @@
|
|||||||
|
// ------------------------------------------------------------------------------
|
||||||
|
// <auto-generated>
|
||||||
|
// This code was generated by SpecFlow (http://www.specflow.org/).
|
||||||
|
// SpecFlow Version:1.3.0.0
|
||||||
|
// Runtime Version:4.0.30319.1
|
||||||
|
//
|
||||||
|
// Changes to this file may cause incorrect behavior and will be lost if
|
||||||
|
// the code is regenerated.
|
||||||
|
// </auto-generated>
|
||||||
|
// ------------------------------------------------------------------------------
|
||||||
|
#region Designer generated code
|
||||||
|
namespace Orchard.Specs
|
||||||
|
{
|
||||||
|
using TechTalk.SpecFlow;
|
||||||
|
|
||||||
|
|
||||||
|
[System.CodeDom.Compiler.GeneratedCodeAttribute("TechTalk.SpecFlow", "1.3.0.0")]
|
||||||
|
[System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||||
|
[NUnit.Framework.TestFixtureAttribute()]
|
||||||
|
[NUnit.Framework.DescriptionAttribute("Content Types")]
|
||||||
|
public partial class ContentTypesFeature
|
||||||
|
{
|
||||||
|
|
||||||
|
private static TechTalk.SpecFlow.ITestRunner testRunner;
|
||||||
|
|
||||||
|
#line 1 "ContentTypes.feature"
|
||||||
|
#line hidden
|
||||||
|
|
||||||
|
[NUnit.Framework.TestFixtureSetUpAttribute()]
|
||||||
|
public virtual void FeatureSetup()
|
||||||
|
{
|
||||||
|
testRunner = TechTalk.SpecFlow.TestRunnerManager.GetTestRunner();
|
||||||
|
TechTalk.SpecFlow.FeatureInfo featureInfo = new TechTalk.SpecFlow.FeatureInfo(new System.Globalization.CultureInfo("en-US"), "Content Types", "In order to add new types to my site\r\nAs an adminitrator\r\nI want to create create" +
|
||||||
|
" content types", ((string[])(null)));
|
||||||
|
testRunner.OnFeatureStart(featureInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
[NUnit.Framework.TestFixtureTearDownAttribute()]
|
||||||
|
public virtual void FeatureTearDown()
|
||||||
|
{
|
||||||
|
testRunner.OnFeatureEnd();
|
||||||
|
testRunner = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void ScenarioSetup(TechTalk.SpecFlow.ScenarioInfo scenarioInfo)
|
||||||
|
{
|
||||||
|
testRunner.OnScenarioStart(scenarioInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
[NUnit.Framework.TearDownAttribute()]
|
||||||
|
public virtual void ScenarioTearDown()
|
||||||
|
{
|
||||||
|
testRunner.OnScenarioEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
[NUnit.Framework.TestAttribute()]
|
||||||
|
[NUnit.Framework.DescriptionAttribute("I can create a new content type")]
|
||||||
|
public virtual void ICanCreateANewContentType()
|
||||||
|
{
|
||||||
|
TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("I can create a new content type", ((string[])(null)));
|
||||||
|
#line 6
|
||||||
|
this.ScenarioSetup(scenarioInfo);
|
||||||
|
#line 7
|
||||||
|
testRunner.Given("I have installed Orchard");
|
||||||
|
#line 8
|
||||||
|
testRunner.And("I have installed \"Orchard.ContentTypes\"");
|
||||||
|
#line 9
|
||||||
|
testRunner.When("I go to \"Admin/ContentTypes\"");
|
||||||
|
#line 10
|
||||||
|
testRunner.Then("I should see \"<a[^>]*>.*?Create new type</a>\"");
|
||||||
|
#line 11
|
||||||
|
testRunner.When("I go to \"Admin/ContentTypes/Create\"");
|
||||||
|
#line hidden
|
||||||
|
TechTalk.SpecFlow.Table table1 = new TechTalk.SpecFlow.Table(new string[] {
|
||||||
|
"name",
|
||||||
|
"value"});
|
||||||
|
table1.AddRow(new string[] {
|
||||||
|
"DisplayName",
|
||||||
|
"Event"});
|
||||||
|
table1.AddRow(new string[] {
|
||||||
|
"Name",
|
||||||
|
"Event"});
|
||||||
|
#line 12
|
||||||
|
testRunner.And("I fill in", ((string)(null)), table1);
|
||||||
|
#line 16
|
||||||
|
testRunner.And("I hit \"Create\"");
|
||||||
|
#line 17
|
||||||
|
testRunner.And("I go to \"Admin/ContentTypes/\"");
|
||||||
|
#line 18
|
||||||
|
testRunner.Then("I should see \"Event\"");
|
||||||
|
#line hidden
|
||||||
|
testRunner.CollectScenarioErrors();
|
||||||
|
}
|
||||||
|
|
||||||
|
[NUnit.Framework.TestAttribute()]
|
||||||
|
[NUnit.Framework.DescriptionAttribute("I can\'t create a content type with an already existing name")]
|
||||||
|
public virtual void ICanTCreateAContentTypeWithAnAlreadyExistingName()
|
||||||
|
{
|
||||||
|
TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("I can\'t create a content type with an already existing name", ((string[])(null)));
|
||||||
|
#line 20
|
||||||
|
this.ScenarioSetup(scenarioInfo);
|
||||||
|
#line 21
|
||||||
|
testRunner.Given("I have installed Orchard");
|
||||||
|
#line 22
|
||||||
|
testRunner.And("I have installed \"Orchard.ContentTypes\"");
|
||||||
|
#line 23
|
||||||
|
testRunner.When("I go to \"Admin/ContentTypes/Create\"");
|
||||||
|
#line hidden
|
||||||
|
TechTalk.SpecFlow.Table table2 = new TechTalk.SpecFlow.Table(new string[] {
|
||||||
|
"name",
|
||||||
|
"value"});
|
||||||
|
table2.AddRow(new string[] {
|
||||||
|
"DisplayName",
|
||||||
|
"Event"});
|
||||||
|
table2.AddRow(new string[] {
|
||||||
|
"Name",
|
||||||
|
"Event"});
|
||||||
|
#line 24
|
||||||
|
testRunner.And("I fill in", ((string)(null)), table2);
|
||||||
|
#line 28
|
||||||
|
testRunner.And("I hit \"Create\"");
|
||||||
|
#line 29
|
||||||
|
testRunner.And("I go to \"Admin/ContentTypes/\"");
|
||||||
|
#line 30
|
||||||
|
testRunner.Then("I should see \"Event\"");
|
||||||
|
#line 31
|
||||||
|
testRunner.When("I go to \"Admin/ContentTypes/Create\"");
|
||||||
|
#line hidden
|
||||||
|
TechTalk.SpecFlow.Table table3 = new TechTalk.SpecFlow.Table(new string[] {
|
||||||
|
"name",
|
||||||
|
"value"});
|
||||||
|
table3.AddRow(new string[] {
|
||||||
|
"DisplayName",
|
||||||
|
"Event"});
|
||||||
|
table3.AddRow(new string[] {
|
||||||
|
"Name",
|
||||||
|
"Event-2"});
|
||||||
|
#line 32
|
||||||
|
testRunner.And("I fill in", ((string)(null)), table3);
|
||||||
|
#line 36
|
||||||
|
testRunner.And("I hit \"Create\"");
|
||||||
|
#line 37
|
||||||
|
testRunner.Then("I should see \"<h1[^>]*>.*?New Content Type.*?</h1>\"");
|
||||||
|
#line 38
|
||||||
|
testRunner.And("I should see \"validation-summary-errors\"");
|
||||||
|
#line hidden
|
||||||
|
testRunner.CollectScenarioErrors();
|
||||||
|
}
|
||||||
|
|
||||||
|
[NUnit.Framework.TestAttribute()]
|
||||||
|
[NUnit.Framework.DescriptionAttribute("I can\'t create a content type with an already existing technical name")]
|
||||||
|
public virtual void ICanTCreateAContentTypeWithAnAlreadyExistingTechnicalName()
|
||||||
|
{
|
||||||
|
TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("I can\'t create a content type with an already existing technical name", ((string[])(null)));
|
||||||
|
#line 40
|
||||||
|
this.ScenarioSetup(scenarioInfo);
|
||||||
|
#line 41
|
||||||
|
testRunner.Given("I have installed Orchard");
|
||||||
|
#line 42
|
||||||
|
testRunner.And("I have installed \"Orchard.ContentTypes\"");
|
||||||
|
#line 43
|
||||||
|
testRunner.When("I go to \"Admin/ContentTypes/Create\"");
|
||||||
|
#line hidden
|
||||||
|
TechTalk.SpecFlow.Table table4 = new TechTalk.SpecFlow.Table(new string[] {
|
||||||
|
"name",
|
||||||
|
"value"});
|
||||||
|
table4.AddRow(new string[] {
|
||||||
|
"DisplayName",
|
||||||
|
"Dinner"});
|
||||||
|
table4.AddRow(new string[] {
|
||||||
|
"Name",
|
||||||
|
"Dinner"});
|
||||||
|
#line 44
|
||||||
|
testRunner.And("I fill in", ((string)(null)), table4);
|
||||||
|
#line 48
|
||||||
|
testRunner.And("I hit \"Create\"");
|
||||||
|
#line 49
|
||||||
|
testRunner.And("I go to \"Admin/ContentTypes/\"");
|
||||||
|
#line 50
|
||||||
|
testRunner.Then("I should see \"Dinner\"");
|
||||||
|
#line 51
|
||||||
|
testRunner.When("I go to \"Admin/ContentTypes/Create\"");
|
||||||
|
#line hidden
|
||||||
|
TechTalk.SpecFlow.Table table5 = new TechTalk.SpecFlow.Table(new string[] {
|
||||||
|
"name",
|
||||||
|
"value"});
|
||||||
|
table5.AddRow(new string[] {
|
||||||
|
"DisplayName",
|
||||||
|
"Dinner2"});
|
||||||
|
table5.AddRow(new string[] {
|
||||||
|
"Name",
|
||||||
|
"Dinner"});
|
||||||
|
#line 52
|
||||||
|
testRunner.And("I fill in", ((string)(null)), table5);
|
||||||
|
#line 56
|
||||||
|
testRunner.And("I hit \"Create\"");
|
||||||
|
#line 57
|
||||||
|
testRunner.Then("I should see \"<h1[^>]*>.*?New Content Type.*?</h1>\"");
|
||||||
|
#line 58
|
||||||
|
testRunner.And("I should see \"validation-summary-errors\"");
|
||||||
|
#line hidden
|
||||||
|
testRunner.CollectScenarioErrors();
|
||||||
|
}
|
||||||
|
|
||||||
|
[NUnit.Framework.TestAttribute()]
|
||||||
|
[NUnit.Framework.DescriptionAttribute("I can\'t rename a content type with an already existing name")]
|
||||||
|
public virtual void ICanTRenameAContentTypeWithAnAlreadyExistingName()
|
||||||
|
{
|
||||||
|
TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("I can\'t rename a content type with an already existing name", ((string[])(null)));
|
||||||
|
#line 60
|
||||||
|
this.ScenarioSetup(scenarioInfo);
|
||||||
|
#line 61
|
||||||
|
testRunner.Given("I have installed Orchard");
|
||||||
|
#line 62
|
||||||
|
testRunner.And("I have installed \"Orchard.ContentTypes\"");
|
||||||
|
#line 63
|
||||||
|
testRunner.When("I go to \"Admin/ContentTypes/Create\"");
|
||||||
|
#line hidden
|
||||||
|
TechTalk.SpecFlow.Table table6 = new TechTalk.SpecFlow.Table(new string[] {
|
||||||
|
"name",
|
||||||
|
"value"});
|
||||||
|
table6.AddRow(new string[] {
|
||||||
|
"DisplayName",
|
||||||
|
"Dinner"});
|
||||||
|
table6.AddRow(new string[] {
|
||||||
|
"Name",
|
||||||
|
"Dinner"});
|
||||||
|
#line 64
|
||||||
|
testRunner.And("I fill in", ((string)(null)), table6);
|
||||||
|
#line 68
|
||||||
|
testRunner.And("I hit \"Create\"");
|
||||||
|
#line 69
|
||||||
|
testRunner.And("I go to \"Admin/ContentTypes/\"");
|
||||||
|
#line 70
|
||||||
|
testRunner.Then("I should see \"Dinner\"");
|
||||||
|
#line 71
|
||||||
|
testRunner.When("I go to \"Admin/ContentTypes/Create\"");
|
||||||
|
#line hidden
|
||||||
|
TechTalk.SpecFlow.Table table7 = new TechTalk.SpecFlow.Table(new string[] {
|
||||||
|
"name",
|
||||||
|
"value"});
|
||||||
|
table7.AddRow(new string[] {
|
||||||
|
"DisplayName",
|
||||||
|
"Event"});
|
||||||
|
table7.AddRow(new string[] {
|
||||||
|
"Name",
|
||||||
|
"Event"});
|
||||||
|
#line 72
|
||||||
|
testRunner.And("I fill in", ((string)(null)), table7);
|
||||||
|
#line 76
|
||||||
|
testRunner.And("I hit \"Create\"");
|
||||||
|
#line 77
|
||||||
|
testRunner.And("I go to \"Admin/ContentTypes/\"");
|
||||||
|
#line 78
|
||||||
|
testRunner.Then("I should see \"Event\"");
|
||||||
|
#line 79
|
||||||
|
testRunner.When("I go to \"Admin/ContentTypes/Edit/Dinner\"");
|
||||||
|
#line hidden
|
||||||
|
TechTalk.SpecFlow.Table table8 = new TechTalk.SpecFlow.Table(new string[] {
|
||||||
|
"name",
|
||||||
|
"value"});
|
||||||
|
table8.AddRow(new string[] {
|
||||||
|
"DisplayName",
|
||||||
|
"Event"});
|
||||||
|
#line 80
|
||||||
|
testRunner.And("I fill in", ((string)(null)), table8);
|
||||||
|
#line 83
|
||||||
|
testRunner.And("I hit \"Save\"");
|
||||||
|
#line 84
|
||||||
|
testRunner.Then("I should see \"validation-summary-errors\"");
|
||||||
|
#line hidden
|
||||||
|
testRunner.CollectScenarioErrors();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
@@ -142,6 +142,11 @@
|
|||||||
<AutoGen>True</AutoGen>
|
<AutoGen>True</AutoGen>
|
||||||
<DesignTime>True</DesignTime>
|
<DesignTime>True</DesignTime>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Include="ContentTypes.feature.cs">
|
||||||
|
<DependentUpon>ContentTypes.feature</DependentUpon>
|
||||||
|
<AutoGen>True</AutoGen>
|
||||||
|
<DesignTime>True</DesignTime>
|
||||||
|
</Compile>
|
||||||
<Compile Include="Hosting\ExtensionDeploymentOptions.cs" />
|
<Compile Include="Hosting\ExtensionDeploymentOptions.cs" />
|
||||||
<Compile Include="SiteCompilation.feature.cs">
|
<Compile Include="SiteCompilation.feature.cs">
|
||||||
<DependentUpon>SiteCompilation.feature</DependentUpon>
|
<DependentUpon>SiteCompilation.feature</DependentUpon>
|
||||||
@@ -228,6 +233,10 @@
|
|||||||
<Generator>SpecFlowSingleFileGenerator</Generator>
|
<Generator>SpecFlowSingleFileGenerator</Generator>
|
||||||
<LastGenOutput>ContentRights.feature.cs</LastGenOutput>
|
<LastGenOutput>ContentRights.feature.cs</LastGenOutput>
|
||||||
</None>
|
</None>
|
||||||
|
<None Include="ContentTypes.feature">
|
||||||
|
<Generator>SpecFlowSingleFileGenerator</Generator>
|
||||||
|
<LastGenOutput>ContentTypes.feature.cs</LastGenOutput>
|
||||||
|
</None>
|
||||||
<None Include="SiteCompilation.feature">
|
<None Include="SiteCompilation.feature">
|
||||||
<Generator>SpecFlowSingleFileGenerator</Generator>
|
<Generator>SpecFlowSingleFileGenerator</Generator>
|
||||||
<LastGenOutput>SiteCompilation.feature.cs</LastGenOutput>
|
<LastGenOutput>SiteCompilation.feature.cs</LastGenOutput>
|
||||||
|
@@ -47,8 +47,12 @@ namespace Orchard.ContentTypes.Controllers {
|
|||||||
if(String.IsNullOrWhiteSpace(viewModel.DisplayName)) {
|
if(String.IsNullOrWhiteSpace(viewModel.DisplayName)) {
|
||||||
ModelState.AddModelError("DisplayName", T("The Content Type name can't be empty.").ToString());
|
ModelState.AddModelError("DisplayName", T("The Content Type name can't be empty.").ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( _contentDefinitionService.GetTypes().Any(t => String.Equals(t.Name.Trim(), viewModel.Name.Trim(), StringComparison.OrdinalIgnoreCase)) ) {
|
||||||
|
ModelState.AddModelError("Name", T("A type with the same technical name already exists.").ToString());
|
||||||
|
}
|
||||||
|
|
||||||
if(_contentDefinitionService.GetTypes().Any(t => t.DisplayName == viewModel.DisplayName)) {
|
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());
|
ModelState.AddModelError("DisplayName", T("A type with the same name already exists.").ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,13 +61,19 @@ namespace Orchard.ContentTypes.Controllers {
|
|||||||
return View(viewModel);
|
return View(viewModel);
|
||||||
}
|
}
|
||||||
|
|
||||||
var typeViewModel = _contentDefinitionService.AddType(viewModel);
|
var contentTypeDefinition = _contentDefinitionService.AddType(viewModel.Name, viewModel.DisplayName);
|
||||||
|
var typeViewModel = new EditTypeViewModel(contentTypeDefinition);
|
||||||
|
|
||||||
|
|
||||||
Services.Notifier.Information(T("The \"{0}\" content type has been created.", typeViewModel.DisplayName));
|
Services.Notifier.Information(T("The \"{0}\" content type has been created.", typeViewModel.DisplayName));
|
||||||
|
|
||||||
return RedirectToAction("Edit", new { id = typeViewModel.Name });
|
return RedirectToAction("Edit", new { id = typeViewModel.Name });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ActionResult ContentTypeName(string displayName) {
|
||||||
|
return Json(_contentDefinitionService.GenerateName(displayName));
|
||||||
|
}
|
||||||
|
|
||||||
public ActionResult Edit(string id) {
|
public ActionResult Edit(string id) {
|
||||||
if (!Services.Authorizer.Authorize(Permissions.CreateContentTypes, T("Not allowed to edit a content type.")))
|
if (!Services.Authorizer.Authorize(Permissions.CreateContentTypes, T("Not allowed to edit a content type.")))
|
||||||
return new HttpUnauthorizedResult();
|
return new HttpUnauthorizedResult();
|
||||||
@@ -90,9 +100,18 @@ namespace Orchard.ContentTypes.Controllers {
|
|||||||
TryUpdateModel(edited);
|
TryUpdateModel(edited);
|
||||||
typeViewModel.DisplayName = edited.DisplayName;
|
typeViewModel.DisplayName = edited.DisplayName;
|
||||||
|
|
||||||
|
if ( String.IsNullOrWhiteSpace(typeViewModel.DisplayName) ) {
|
||||||
|
ModelState.AddModelError("DisplayName", T("The Content Type name can't be empty.").ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( _contentDefinitionService.GetTypes().Any(t => String.Equals(t.DisplayName.Trim(), typeViewModel.DisplayName.Trim(), StringComparison.OrdinalIgnoreCase) && !String.Equals(t.Name, id)) ) {
|
||||||
|
ModelState.AddModelError("DisplayName", T("A type with the same name already exists.").ToString());
|
||||||
|
}
|
||||||
|
|
||||||
if (!ModelState.IsValid)
|
if (!ModelState.IsValid)
|
||||||
return View(typeViewModel);
|
return View(typeViewModel);
|
||||||
|
|
||||||
|
|
||||||
_contentDefinitionService.AlterType(typeViewModel, this);
|
_contentDefinitionService.AlterType(typeViewModel, this);
|
||||||
|
|
||||||
if (!ModelState.IsValid) {
|
if (!ModelState.IsValid) {
|
||||||
|
@@ -65,18 +65,24 @@ namespace Orchard.ContentTypes.Services {
|
|||||||
return viewModel;
|
return viewModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
public EditTypeViewModel AddType(CreateTypeViewModel typeViewModel) {
|
public ContentTypeDefinition AddType(string name, string displayName) {
|
||||||
var name = GenerateName(typeViewModel.DisplayName);
|
if(String.IsNullOrWhiteSpace(displayName)) {
|
||||||
|
throw new ArgumentException("displayName");
|
||||||
|
}
|
||||||
|
|
||||||
while (_contentDefinitionManager.GetTypeDefinition(name) != null)
|
if(String.IsNullOrWhiteSpace(name)) {
|
||||||
|
name = GenerateName(displayName);
|
||||||
|
}
|
||||||
|
|
||||||
|
while ( _contentDefinitionManager.GetTypeDefinition(name) != null )
|
||||||
name = VersionName(name);
|
name = VersionName(name);
|
||||||
|
|
||||||
var contentTypeDefinition = new ContentTypeDefinition(name, typeViewModel.DisplayName);
|
var contentTypeDefinition = new ContentTypeDefinition(name, displayName);
|
||||||
_contentDefinitionManager.StoreTypeDefinition(contentTypeDefinition);
|
_contentDefinitionManager.StoreTypeDefinition(contentTypeDefinition);
|
||||||
_contentDefinitionManager.AlterTypeDefinition(name,
|
_contentDefinitionManager.AlterTypeDefinition(name,
|
||||||
cfg => cfg.Creatable().Draftable());
|
cfg => cfg.Creatable().Draftable());
|
||||||
|
|
||||||
return new EditTypeViewModel(contentTypeDefinition);
|
return contentTypeDefinition;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AlterType(EditTypeViewModel typeViewModel, IUpdateModel updateModel) {
|
public void AlterType(EditTypeViewModel typeViewModel, IUpdateModel updateModel) {
|
||||||
@@ -210,20 +216,21 @@ namespace Orchard.ContentTypes.Services {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//gratuitously stolen from the RoutableService
|
//gratuitously stolen from the RoutableService
|
||||||
private static string GenerateName(string displayName) {
|
public string GenerateName(string name) {
|
||||||
if (string.IsNullOrWhiteSpace(displayName))
|
if ( string.IsNullOrWhiteSpace(name) )
|
||||||
return "";
|
return String.Empty;
|
||||||
|
|
||||||
var name = displayName;
|
var dissallowed = new Regex(@"[/:?#\[\]@!$&'()*+,;=\s\""<>]+");
|
||||||
//todo: might need to be made more restrictive depending on how name is used (like as an XML node name, for instance)
|
|
||||||
var dissallowed = new Regex(@"[/:?#\[\]@!$&'()*+,;=\s]+");
|
|
||||||
|
|
||||||
name = dissallowed.Replace(name, "-");
|
name = dissallowed.Replace(name, String.Empty);
|
||||||
name = name.Trim('-');
|
name = name.Trim();
|
||||||
|
|
||||||
if (name.Length > 128)
|
if (name.Length > 128)
|
||||||
name = name.Substring(0, 128);
|
name = name.Substring(0, 128);
|
||||||
|
|
||||||
|
while ( _contentDefinitionManager.GetTypeDefinition(name) != null )
|
||||||
|
name = VersionName(name);
|
||||||
|
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,17 +1,19 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Orchard.ContentManagement;
|
using Orchard.ContentManagement;
|
||||||
using Orchard.ContentManagement.MetaData;
|
using Orchard.ContentManagement.MetaData;
|
||||||
|
using Orchard.ContentManagement.MetaData.Models;
|
||||||
using Orchard.ContentTypes.ViewModels;
|
using Orchard.ContentTypes.ViewModels;
|
||||||
|
|
||||||
namespace Orchard.ContentTypes.Services {
|
namespace Orchard.ContentTypes.Services {
|
||||||
public interface IContentDefinitionService : IDependency {
|
public interface IContentDefinitionService : IDependency {
|
||||||
IEnumerable<EditTypeViewModel> GetTypes();
|
IEnumerable<EditTypeViewModel> GetTypes();
|
||||||
EditTypeViewModel GetType(string name);
|
EditTypeViewModel GetType(string name);
|
||||||
EditTypeViewModel AddType(CreateTypeViewModel typeViewModel);
|
ContentTypeDefinition AddType(string name, string displayName);
|
||||||
void AlterType(EditTypeViewModel typeViewModel, IUpdateModel updater);
|
void AlterType(EditTypeViewModel typeViewModel, IUpdateModel updater);
|
||||||
void RemoveType(string name);
|
void RemoveType(string name);
|
||||||
void AddPartToType(string partName, string typeName);
|
void AddPartToType(string partName, string typeName);
|
||||||
void RemovePartFromType(string partName, string typeName);
|
void RemovePartFromType(string partName, string typeName);
|
||||||
|
string GenerateName(string displayName);
|
||||||
|
|
||||||
IEnumerable<EditPartViewModel> GetParts();
|
IEnumerable<EditPartViewModel> GetParts();
|
||||||
EditPartViewModel GetPart(string name);
|
EditPartViewModel GetPart(string name);
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
namespace Orchard.ContentTypes.ViewModels {
|
namespace Orchard.ContentTypes.ViewModels {
|
||||||
public class CreateTypeViewModel {
|
public class CreateTypeViewModel {
|
||||||
public string DisplayName { get; set; }
|
public string DisplayName { get; set; }
|
||||||
|
public string Name { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,10 +1,40 @@
|
|||||||
@model Orchard.ContentTypes.ViewModels.CreateTypeViewModel
|
@model Orchard.ContentTypes.ViewModels.CreateTypeViewModel
|
||||||
|
|
||||||
<h1>@Html.TitleForPage(T("New Content Type").ToString())</h1>@using (Html.BeginFormAntiForgeryPost()) {
|
<h1>@Html.TitleForPage(T("New Content Type").ToString())</h1>@using (Html.BeginFormAntiForgeryPost()) {
|
||||||
@Html.ValidationSummary()
|
@Html.ValidationSummary()
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<label for="DisplayName">@T("Display Name")</label>
|
<label for="DisplayName">@T("Display Name")</label>
|
||||||
@Html.TextBoxFor(m => m.DisplayName, new {@class = "textMedium", autofocus = "autofocus"})
|
@Html.TextBoxFor(m => m.DisplayName, new {@class = "textMedium", autofocus = "autofocus"})
|
||||||
|
<label for="Name">@T("Technical Name")</label>
|
||||||
|
@Html.TextBoxFor(m => m.Name, new {@class = "text"})
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<button class="primaryAction" type="submit">@T("Create")</button>
|
<button class="primaryAction" type="submit">@T("Create")</button>
|
||||||
</fieldset>}
|
</fieldset>}
|
||||||
|
|
||||||
|
@using(Script.Foot()){
|
||||||
|
<script type="text/javascript">
|
||||||
|
//<![CDATA[
|
||||||
|
$(function(){
|
||||||
|
//pull slug input from tab order
|
||||||
|
$("#@Html.FieldIdFor(m=>m.Name)").attr("tabindex",-1);
|
||||||
|
$("#@Html.FieldIdFor(m=>m.DisplayName)").blur(function(){
|
||||||
|
var name = $("#@Html.FieldIdFor(m=>m.Name)");
|
||||||
|
if (name.val()) { return true; }
|
||||||
|
var displayName = $("#@Html.FieldIdFor(m=>m.DisplayName)").val();
|
||||||
|
jQuery.post(
|
||||||
|
"@Url.Action("ContentTypeName","Admin",new RouteValueDictionary{{"Area","Orchard.ContentTypes"}})",
|
||||||
|
{
|
||||||
|
displayName: $("#@Html.FieldIdFor(m=>m.DisplayName)").val(),
|
||||||
|
__RequestVerificationToken: $("input[name=__RequestVerificationToken]").val()
|
||||||
|
},
|
||||||
|
function(data) {
|
||||||
|
name.val(data);
|
||||||
|
},
|
||||||
|
"json"
|
||||||
|
);
|
||||||
|
})
|
||||||
|
})
|
||||||
|
//]]>
|
||||||
|
</script>
|
||||||
|
}
|
@@ -12,7 +12,7 @@
|
|||||||
@Html.ValidationSummary()
|
@Html.ValidationSummary()
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<label for="DisplayName">@T("Display Name")</label>
|
<label for="DisplayName">@T("Display Name")</label>
|
||||||
@Html.TextBoxFor(m => m.DisplayName, new { @class = "textMedium" })
|
@Html.TextBoxFor(m => m.DisplayName, new { @class = "textMedium" }) @T("Technical name: {0}", Model.Name)
|
||||||
@* todo: if we continue to go down the midrodata route, some helpers would be nice *@
|
@* todo: if we continue to go down the midrodata route, some helpers would be nice *@
|
||||||
<meta itemprop="DisplayName" content="@Model.DisplayName" />
|
<meta itemprop="DisplayName" content="@Model.DisplayName" />
|
||||||
@* has unintended consequences (renamging the type) - changing the name creates a new type of that name *@
|
@* has unintended consequences (renamging the type) - changing the name creates a new type of that name *@
|
||||||
|
Reference in New Issue
Block a user