Compare commits

..

75 Commits

Author SHA1 Message Date
Sebastiaan Janssen a8d7a1d01d Makes the test green: don't add the passed in composition as a dependency to itself.. also added another invariant check 2014-12-15 19:52:28 +01:00
Sebastiaan Janssen e62597521e Remove the renaming to 'title' which would cause a duplicate and make the next test fail 2014-12-15 19:51:37 +01:00
Sebastiaan Janssen fa91321299 Adds test for adding properties to a composition that has been saved and now doesn't allow a new property to be added 2014-12-15 18:56:58 +01:00
Morten Christensen 2d81691407 Adding new test case for renaming PropertyType aliases on indirect references 2014-12-15 16:34:41 +01:00
Morten Christensen 21f08ca491 Refactoring validation and adding new test case for renaming PropertyTypes 2014-12-15 15:33:05 +01:00
Morten Christensen e202f21934 Adds new test, fix, refactoring for adding duplicate PropertyType aliases 2014-12-15 14:29:48 +01:00
Shannon 2936ff0bf9 Makes provider user key type for new membership provider configurable, by default it is int 2014-12-15 20:44:00 +11:00
Sebastiaan Janssen 8e4e575276 Makes sure messages are shown in the user's configured language 2014-12-15 09:30:04 +01:00
Sebastiaan Janssen 84752babc8 Moved both new sections to the bottom so it's easier for upgraders to merge them 2014-12-15 09:04:25 +01:00
Shannon 60a1116acd Fixes: U4-6009 Distributed calls not working in 7.2 2014-12-15 11:45:55 +11:00
Sebastiaan Janssen a480d7bbe6 U4-5959 Getting YSOD when wanting to create partial view in a subfolder in the backoffie
#U4-5959 Fixed Due in version 7.2.1
2014-12-14 17:22:10 +01:00
Sebastiaan Janssen 7316c5462a U4-5928 Umbraco 7.2 RC GetCurrentMemberProfileModel Null Ref
#U4-5928 Fixed Due in version 7.2.1
2014-12-14 16:50:11 +01:00
Morten Christensen 2a9960afb3 Adding UI feedback for invalid compositions 2014-12-12 17:04:53 +01:00
Morten Christensen ed899ec73d Adding additional test coverage for Compositions and updating PropertyTypes and PropertyGroups 2014-12-12 17:04:11 +01:00
Morten Christensen 8f26f9385d Refactoring the logic around saving updates to PropertyTypes and PropertyGroups 2014-12-12 17:02:03 +01:00
Morten Christensen a446cc224d Refactoring the logic in the validation method for when ContentTypes are saved 2014-12-11 17:14:01 +01:00
Morten Christensen 07f9a9700d Ensures that inherited PropertyType aliases are also checked for indirect references 2014-12-11 12:22:49 +01:00
Sebastiaan Janssen 7e7acd0049 Correcting my mistakes to the unit test, using the wrong alias 2014-12-11 11:02:51 +01:00
Morten Christensen 57985c26a2 Updating the name of PropertyGroups in DB to ensure renaming is done properly 2014-12-11 10:55:33 +01:00
Morten Christensen 504c1f7254 Updating tests related to #U4-5986
Conflicts:
	src/Umbraco.Tests/TestHelpers/Entities/MockedContentTypes.cs
2014-12-11 10:55:21 +01:00
Shannon 52ad36a6c2 removes commented out code form PR 2014-12-11 10:49:41 +01:00
Peter Gregory 01670e0832 Fixes issue U4-5925 GetMedia returning nothing
Removed the use of FromXElement that was only used by GetMedia.  The change introduced in commit f3f6504398 caused GetMedia to return nothing due to the introduction of the FromXElement method.
2014-12-11 10:49:30 +01:00
Stephan 99c96bce86 U4-5986 - reject ppty alias used by ancestor 2014-12-10 13:01:51 +01:00
Sebastiaan Janssen da2bc6764b Version also updates in the csproj 2014-12-10 12:59:08 +01:00
Shannon d11a377f0f bump version 2014-12-10 12:28:06 +01:00
Stephan d445f7cb0d U4-5986 - reject ppty alias used by descendant 2014-12-10 12:27:55 +01:00
Sebastiaan Janssen 899d325ca1 Updates unit tests to use the newer new ContentType method and obsoletes the old one 2014-12-10 11:52:03 +01:00
Sebastiaan Janssen f1107b7a91 Fixes U4-5986 Compositions: Possible to get stuck in document type ysod's
#U4-5986 Fixed Due in version 7.2.1
2014-12-10 11:51:53 +01:00
Stephan a3f171e7b3 U4-5931 - fix DocType inheritance issue 2014-12-10 11:51:42 +01:00
Sebastiaan Janssen 788a0241d8 Remove Forms preview notice 2014-12-04 13:17:29 +01:00
Sebastiaan Janssen 25237995eb It's nice to unzip a build in the build folder, so just ignore it for git :) 2014-12-04 12:41:39 +01:00
per ploug ed75109829 Removes textstring editor controller - not needed
functionality moved to directive
2014-12-04 12:27:33 +01:00
per ploug 6738a25bfa Fxes grid datatype config to handle cols > 12 and <= 0 2014-12-04 12:27:10 +01:00
per ploug aa9c753455 Forms installer cookie check fixed 2014-12-04 12:26:32 +01:00
per ploug 0e5f9b92e8 adds autocomplete=off to installer password
To avoid autocomplete to pick up peoples secret passwords
2014-12-04 12:26:05 +01:00
per ploug 77fd4d383b Fixes grid cell resizing timing bug 2014-12-04 12:25:33 +01:00
Sebastiaan Janssen 98a03a0127 Fixes nonodes a:visited bug 2014-12-04 08:55:19 +01:00
Shannon 464130a102 Fixes: U4-5930 Lock "Save and publish" once activated 2014-12-04 13:09:28 +11:00
Shannon dfb324b003 Fixes: U4-5706 Listview search bar enter button in IE11 submits form 2014-12-04 12:44:46 +11:00
Shannon 966b8565ba publicizes Mandate 2014-12-04 11:36:15 +11:00
Shannon 2b774dbdf2 Revert "Revert "Fixes PetaPoco to support Medium trust." - This revert back to original peta poco actually causes issues with some custom multi-poco queries, turns out the med trust fix also fixes a few other things! We've been running with this fix for a very long time now so it is definitely stable and correct. 2014-12-04 11:35:42 +11:00
Sebastiaan Janssen cae600ac2f Merge pull request #574 from readingdancer/Fix_for_U4-4125
Fix for U4 4125 - Spanish Localization file updated.
2014-12-03 17:12:23 +01:00
Chris Houston 5e4702a4ab Final changes (for now) for the Spanish localization file. 2014-12-03 16:04:26 +00:00
Sebastiaan Janssen 8442b2e8e7 Updates installer backgrounnd and nonodes page 2014-12-03 16:51:16 +01:00
Morten Christensen 64efd0abbc #U4-5913 Fixed Media Type composition panel so it shows the right types 2014-12-03 16:40:46 +01:00
Chris Houston b8f3f93d83 Added more Spanish translations. 2014-12-03 14:24:13 +00:00
per ploug ce9e851087 Merge branch '7.2.0' of https://github.com/umbraco/Umbraco-CMS into 7.2.0 2014-12-03 14:11:08 +01:00
per ploug 53d9a34996 Makes the forms installer reload hard 2014-12-03 14:10:44 +01:00
Sebastiaan Janssen 2f79d4a71d Better replacement of examine management ascx to html 2014-12-03 11:27:02 +01:00
per ploug 98d72da622 Removes .Syntax from grid macro editor
This is never used and should not be stored
2014-12-03 10:33:52 +01:00
Sebastiaan Janssen c563629756 Bump version 2014-12-03 10:25:08 +01:00
Sebastiaan Janssen acb3ecbbf7 Updates NuGet Readme 2014-12-03 09:57:22 +01:00
Shannon Deminick 2cbe6f5543 Merge pull request #571 from umbraco/starterkit
Implements new starterkit rest call
2014-12-03 18:58:40 +11:00
Sebastiaan Janssen 9beaaa825e Use the UmbracoContext property instead of the singleton 2014-12-03 08:56:21 +01:00
per ploug bf90edb5be Fixed U4-5906 7.2.0 RC - other values than 12 in Grid Columns config mess up styling 2014-12-03 08:17:02 +01:00
Shannon 94a506f8e8 Merge branch '7.2.0' of https://github.com/umbraco/Umbraco-CMS into 7.2.0 2014-12-03 15:24:22 +11:00
Shannon 4f68941f98 Fixes: U4-5701 Upgrade to 7.2 beta error. Cannot alter column of type NTEXT or IMAGE. 2014-12-03 15:24:10 +11:00
Morten Christensen 25de56a98b Ensuring that imported data types raise events with PreValues saved. 2014-12-02 16:11:59 +01:00
Morten Christensen b11135a096 Fixes #U4-5921 Import of Document Type fails, if dependencies are not part of the import. 2014-12-02 13:35:58 +01:00
Sebastiaan Janssen d4db32c0f2 Don't ship with or require dotLess install 2014-12-02 11:44:15 +01:00
Sebastiaan Janssen d54f35f5f7 Merge pull request #570 from readingdancer/Fix_for_U4-5911
Fixed issue U4-5911 & part of U4-5101 - Allow descriptions on property editors to be localized
2014-12-02 11:25:21 +01:00
Shannon f163381399 Fixes: U4-4756 Error Uploading images to Media section 2014-12-02 17:47:16 +11:00
Morten Christensen 86cb3e8695 Adding a unit test for importing the Fanoe package xml 2014-12-01 15:40:52 +01:00
Morten Christensen dcc50c3b53 Adding optional ctor overload for ContentType to enable passing an Alias 2014-12-01 15:26:20 +01:00
Sebastiaan Janssen 0209b71182 Fixes problem where Umbraco "thinks" it's a brand new install when upgrading sites on UaaS 2014-12-01 13:44:50 +01:00
Sebastiaan Janssen 6b92e47631 Unfortunately, we HAVE to point to MVC 4.0.0.0 else you get YSODs on machines with 4.0.0.1 in the GAC (and we can't point to 4.0.0.1 because 4.0.0.0 might be in the GAC and then it'll YSOD for THOSE people). BOOOO 2014-12-01 10:57:24 +01:00
Sebastiaan Janssen 36ffebbb49 Adds usings for the http request, client and response 2014-12-01 08:17:37 +01:00
Chris Houston d0bafc6184 Removed "description" as Shaz pointed out this was not required.
Fixed a couple of UK English spelling mistakes.
2014-11-30 23:54:46 +00:00
Sebastiaan Janssen 801828df70 Update test URL to live URL 2014-11-30 17:02:25 +01:00
Sebastiaan Janssen 953c371580 Get starterkits in new way so we can support version compatibility (Fanoe is only compatible with 7.2+) 2014-11-30 15:50:55 +01:00
Chris Houston 83d3882b9a - Added the GRID localization strings to the US English file.
- Updated the umbControlGroup directive so that the Description files are now localized, for some reason only the label was being localized even though the text had been added to the UK English file?
2014-11-30 01:27:26 +00:00
Morten Christensen c37777b289 It should not be possible for a ContentType to add itself as a composition 2014-11-28 13:11:11 +01:00
Sebastiaan Janssen ef6a4139de Whoops, period should've been comma 2014-11-28 07:44:19 +01:00
Sebastiaan Janssen 98ceabaf7e Don't point web.config to MVC 4.0.0.1, it may not be installed (merge fail..) 2014-11-27 20:44:48 +01:00
Sebastiaan Janssen 85bcb7ad2b Update migration 2014-11-27 20:20:56 +01:00
78 changed files with 6755 additions and 581 deletions
+1
View File
@@ -128,3 +128,4 @@ src/*.boltdata/
/src/Umbraco.Web.UI/Umbraco/Js/canvasdesigner.config.js
/src/Umbraco.Web.UI/Umbraco/Js/canvasdesigner.front.js
src/umbraco.sln.ide/*
build/UmbracoCms.*/
+2 -2
View File
@@ -156,8 +156,8 @@
<Target Name="ZipWebApp" DependsOnTargets="ZipUmbracoExaminePDF" >
<Message Text="Starting to zip to $(buildDate)-$(BuildZipFileName)" Importance="high" />
<Exec Command="..\tools\7zip\7za.exe a -r %22$(BuildZipFileNameBin)%22 %22$(SolutionBinFolderAbsolutePath)*%22" />
<Exec Command="..\tools\7zip\7za.exe a -r %22$(BuildZipFileName)%22 %22$(WebAppFolderAbsolutePath)*%22" />
<Exec Command="..\tools\7zip\7za.exe a -r %22$(BuildZipFileNameBin)%22 %22$(SolutionBinFolderAbsolutePath)*%22 -x!dotLess.Core.dll" />
<Exec Command="..\tools\7zip\7za.exe a -r %22$(BuildZipFileName)%22 %22$(WebAppFolderAbsolutePath)*%22 -x!dotLess.Core.dll" />
<Message Text="Finished zipping to build\$(BuildFolder)\$(buildDate)-$(BuildZipFileName)" Importance="high" />
</Target>
-1
View File
@@ -35,7 +35,6 @@
<dependency id="Examine" version="[0.1.57, 1.0.0)" />
<dependency id="ImageProcessor" version="[1.9.5, 3.0.0)" />
<dependency id="ImageProcessor.Web" version="[3.3.1, 5.0.0)" />
<dependency id="dotless" version="[1.4.1, 2.0.0)" />
</dependencies>
</metadata>
<files>
@@ -26,11 +26,15 @@
views/dashboard/developer/developerdashboardvideos.html
</control>
</tab>
<tab caption="Examine Management" xdt:Locator="Match(caption)" xdt:Transform="InsertIfMissing">
<tab caption="Examine Management" xdt:Locator="Match(caption)" xdt:Transform="Remove" />
</section>
<section alias="StartupDeveloperDashboardSection" xdt:Locator="Match(alias)">
<tab caption="Examine Management" xdt:Locator="Match(caption)" xdt:Transform="InsertIfMissing">
<control>
views/dashboard/developer/examinemanagement.html
</control>
</tab>
</tab>
</section>
<section alias="StartupMediaDashboardSection" xdt:Locator="Match(alias)">
+10 -12
View File
@@ -2,24 +2,22 @@ A note about running Umbraco from Visual Studio.
Don't forget to build!
BETA Notice: We've done our best to transform your config files, we are testing this in 7.2 beta and would love to
hear back if it didn't work so we can improve this feature. We'd love to see your before and after config files
(make sure to delete sensitive data like passwords and API keys) in the issue tracker at http://issues.umbraco.org/
Remember, we backed up your files in App_Data\NuGetBackup so you can find the original file before it was transformed.
When upgrading your website using NuGet you should answer "No" to the questions to overwrite the Web.config
file (and config files in the config folder).
We've overwritten all the files in the Umbraco and Umbraco_Client folder, these have been backed up in
App_Data\NuGetBackup. We didn't overwrite the UI.xml file nor did we remove any files or folders that you or a package
might have added. Only the existing files were overwritten. If you customized anything then make sure to do a compare
and merge with the NuGetBackup folder.
We've done our best to transform your configuration files but in case something is not quite right: remember we
backed up your files in App_Data\NuGetBackup so you can find the original files before they were transformed.
This nuget package includes build targets that extends the creation of a deploy package, which is generated by
We've overwritten all the files in the Umbraco and Umbraco_Client folder, these have been backed up in
App_Data\NuGetBackup. We didn't overwrite the UI.xml file nor did we remove any files or folders that you or
a package might have added. Only the existing files were overwritten. If you customized anything then make
sure to do a compare and merge with the NuGetBackup folder.
This NuGet package includes build targets that extend the creation of a deploy package, which is generated by
Publishing from Visual Studio. The targets will only work once Publishing is configured, so if you don't use
Publish this won't affect you.
These things will now be automatically included when creating a deploy package or publishing to the file system:
umbraco, umbraco_client, config\splashes and global.asax.
The following items will now be automatically included when creating a deploy package or publishing to the file
system: umbraco, umbraco_client, config\splashes and global.asax.
Please read the release notes on our.umbraco.org:
http://our.umbraco.org/contribute/releases
+1 -1
View File
@@ -156,7 +156,7 @@
</dependentAssembly>
<dependentAssembly xdt:Transform="Insert">
<assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.0.0" newVersion="4.0.0.1" />
<bindingRedirect oldVersion="0.0.0.0-4.0.0.0" newVersion="4.0.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
+1 -2
View File
@@ -1,3 +1,2 @@
# Usage: on line 2 put the release version, on line 3 put the version comment (example: beta)
7.2.0
RC
7.2.1
@@ -5,7 +5,7 @@ namespace Umbraco.Core.Configuration
{
public class UmbracoVersion
{
private static readonly Version Version = new Version("7.2.0");
private static readonly Version Version = new Version("7.2.1");
/// <summary>
/// Gets the current version of Umbraco.
@@ -23,7 +23,7 @@ namespace Umbraco.Core.Configuration
/// Gets the version comment (like beta or RC).
/// </summary>
/// <value>The version comment.</value>
public static string CurrentComment { get { return "RC"; } }
public static string CurrentComment { get { return ""; } }
// Get the version of the umbraco.dll by looking at a class in that dll
// Had to do it like this due to medium trust issues, see: http://haacked.com/archive/2010/11/04/assembly-location-and-medium-trust.aspx
+1 -1
View File
@@ -8,7 +8,7 @@ namespace Umbraco.Core
/// <summary>
/// Helper class for mandating values, for example on method parameters.
/// </summary>
internal static class Mandate
public static class Mandate
{
/// <summary>
/// Mandates that the specified parameter is not null.
+22 -10
View File
@@ -15,11 +15,11 @@ namespace Umbraco.Core.Models
{
private int _defaultTemplate;
private IEnumerable<ITemplate> _allowedTemplates;
/// <summary>
/// Constuctor for creating a ContentType with the parent's id.
/// </summary>
/// <remarks>You usually only want to use this for creating ContentTypes at the root.</remarks>
/// <remarks>Only use this for creating ContentTypes at the root (with ParentId -1).</remarks>
/// <param name="parentId"></param>
public ContentType(int parentId) : base(parentId)
{
@@ -31,14 +31,26 @@ namespace Umbraco.Core.Models
/// </summary>
/// <remarks>Use this to ensure inheritance from parent.</remarks>
/// <param name="parent"></param>
public ContentType(IContentType parent) : base(parent)
{
_allowedTemplates = new List<ITemplate>();
}
[Obsolete("This method is obsolete, use ContentType(IContentType parent, string alias) instead.", false)]
public ContentType(IContentType parent) : this(parent, null)
{
}
/// <summary>
/// Constuctor for creating a ContentType with the parent as an inherited type.
/// </summary>
/// <remarks>Use this to ensure inheritance from parent.</remarks>
/// <param name="parent"></param>
/// <param name="alias"></param>
public ContentType(IContentType parent, string alias)
: base(parent, alias)
{
_allowedTemplates = new List<ITemplate>();
}
private static readonly PropertyInfo DefaultTemplateSelector = ExpressionHelper.GetPropertyInfo<ContentType, int>(x => x.DefaultTemplateId);
private static readonly PropertyInfo AllowedTemplatesSelector = ExpressionHelper.GetPropertyInfo<ContentType, IEnumerable<ITemplate>>(x => x.AllowedTemplates);
/// <summary>
/// Gets or sets the alias of the default Template.
/// </summary>
@@ -95,7 +107,7 @@ namespace Umbraco.Core.Models
}
DefaultTemplateId = template.Id;
if(_allowedTemplates.Any(x => x != null && x.Id == template.Id) == false)
if (_allowedTemplates.Any(x => x != null && x.Id == template.Id) == false)
{
var templates = AllowedTemplates.ToList();
templates.Add(template);
@@ -129,7 +141,7 @@ namespace Umbraco.Core.Models
{
base.AddingEntity();
if(Key == Guid.Empty)
if (Key == Guid.Empty)
Key = Guid.NewGuid();
}
@@ -140,7 +152,7 @@ namespace Umbraco.Core.Models
/// <returns></returns>
[Obsolete("Use DeepCloneWithResetIdentities instead")]
public IContentType Clone(string alias)
{
{
return DeepCloneWithResetIdentities(alias);
}
+14 -7
View File
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;
@@ -15,6 +16,7 @@ namespace Umbraco.Core.Models
/// </summary>
[Serializable]
[DataContract(IsReference = true)]
[DebuggerDisplay("Id: {Id}, Name: {Name}, Alias: {Alias}")]
public abstract class ContentTypeBase : Entity, IContentTypeBase
{
private Lazy<int> _parentId;
@@ -48,17 +50,22 @@ namespace Umbraco.Core.Models
_additionalData = new Dictionary<string, object>();
}
protected ContentTypeBase(IContentTypeBase parent)
protected ContentTypeBase(IContentTypeBase parent) : this(parent, null)
{
Mandate.ParameterNotNull(parent, "parent");
}
_parentId = new Lazy<int>(() => parent.Id);
_allowedContentTypes = new List<ContentTypeSort>();
_propertyGroups = new PropertyGroupCollection();
protected ContentTypeBase(IContentTypeBase parent, string alias)
{
Mandate.ParameterNotNull(parent, "parent");
_alias = alias;
_parentId = new Lazy<int>(() => parent.Id);
_allowedContentTypes = new List<ContentTypeSort>();
_propertyGroups = new PropertyGroupCollection();
_propertyTypes = new PropertyTypeCollection();
_propertyTypes.CollectionChanged += PropertyTypesChanged;
_additionalData = new Dictionary<string, object>();
}
}
private static readonly PropertyInfo NameSelector = ExpressionHelper.GetPropertyInfo<ContentTypeBase, string>(x => x.Name);
private static readonly PropertyInfo ParentIdSelector = ExpressionHelper.GetPropertyInfo<ContentTypeBase, int>(x => x.ParentId);
@@ -492,7 +499,6 @@ namespace Umbraco.Core.Models
/// <param name="propertyTypeAlias">Alias of the <see cref="PropertyType"/> to remove</param>
public void RemovePropertyType(string propertyTypeAlias)
{
//check if the property exist in one of our collections
if (PropertyGroups.Any(group => group.PropertyTypes.Any(pt => pt.Alias == propertyTypeAlias))
|| _propertyTypes.Any(x => x.Alias == propertyTypeAlias))
@@ -519,6 +525,7 @@ namespace Umbraco.Core.Models
public void RemovePropertyGroup(string propertyGroupName)
{
PropertyGroups.RemoveItem(propertyGroupName);
OnPropertyChanged(PropertyGroupCollectionSelector);
}
/// <summary>
@@ -22,11 +22,16 @@ namespace Umbraco.Core.Models
}
protected ContentTypeCompositionBase(IContentTypeComposition parent)
: base(parent)
: this(parent, null)
{
AddContentType(parent);
}
protected ContentTypeCompositionBase(IContentTypeComposition parent, string alias)
: base(parent, alias)
{
AddContentType(parent);
}
private static readonly PropertyInfo ContentTypeCompositionSelector =
ExpressionHelper.GetPropertyInfo<ContentTypeCompositionBase, IEnumerable<IContentTypeComposition>>(
x => x.ContentTypeComposition);
@@ -76,6 +81,9 @@ namespace Umbraco.Core.Models
if (contentType.ContentTypeComposition.Any(x => x.CompositionAliases().Any(ContentTypeCompositionExists)))
return false;
if (string.IsNullOrEmpty(Alias) == false && Alias.Equals(contentType.Alias))
return false;
if (ContentTypeCompositionExists(contentType.Alias) == false)
{
//Before we actually go ahead and add the ContentType as a Composition we ensure that we don't
+13 -2
View File
@@ -13,7 +13,7 @@ namespace Umbraco.Core.Models
/// <summary>
/// Constuctor for creating a MediaType with the parent's id.
/// </summary>
/// <remarks>You usually only want to use this for creating MediaTypes at the root.</remarks>
/// <remarks>Only use this for creating MediaTypes at the root (with ParentId -1).</remarks>
/// <param name="parentId"></param>
public MediaType(int parentId) : base(parentId)
{
@@ -24,10 +24,21 @@ namespace Umbraco.Core.Models
/// </summary>
/// <remarks>Use this to ensure inheritance from parent.</remarks>
/// <param name="parent"></param>
public MediaType(IMediaType parent) : base(parent)
public MediaType(IMediaType parent) : this(parent, null)
{
}
/// <summary>
/// Constuctor for creating a MediaType with the parent as an inherited type.
/// </summary>
/// <remarks>Use this to ensure inheritance from parent.</remarks>
/// <param name="parent"></param>
/// <param name="alias"></param>
public MediaType(IMediaType parent, string alias)
: base(parent, alias)
{
}
/// <summary>
/// Method to call when Entity is being saved
/// </summary>
+1 -34
View File
@@ -20,7 +20,6 @@ namespace Umbraco.Core.Models
private string _email;
private string _rawPasswordValue;
private object _providerUserKey;
private Type _userTypeKey;
/// <summary>
/// Constructor for creating an empty Member object
@@ -114,7 +113,6 @@ namespace Umbraco.Core.Models
private static readonly PropertyInfo EmailSelector = ExpressionHelper.GetPropertyInfo<Member, string>(x => x.Email);
private static readonly PropertyInfo PasswordSelector = ExpressionHelper.GetPropertyInfo<Member, string>(x => x.RawPasswordValue);
private static readonly PropertyInfo ProviderUserKeySelector = ExpressionHelper.GetPropertyInfo<Member, object>(x => x.ProviderUserKey);
private static readonly PropertyInfo UserTypeKeySelector = ExpressionHelper.GetPropertyInfo<Member, Type>(x => x.ProviderUserKeyType);
/// <summary>
/// Gets or sets the Username
@@ -502,38 +500,7 @@ namespace Umbraco.Core.Models
}
}
/// <summary>
/// Gets or sets the type of the provider user key.
/// </summary>
/// <value>
/// The type of the provider user key.
/// </value>
[IgnoreDataMember]
internal Type ProviderUserKeyType
{
get
{
return _userTypeKey;
}
private set
{
SetPropertyValueAndDetectChanges(o =>
{
_userTypeKey = value;
return _userTypeKey;
}, _userTypeKey, UserTypeKeySelector);
}
}
/// <summary>
/// Sets the type of the provider user key.
/// </summary>
/// <param name="type">The type.</param>
internal void SetProviderUserKeyType(Type type)
{
ProviderUserKeyType = type;
}
/// <summary>
/// Method to call when Entity is being saved
/// </summary>
+6 -2
View File
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;
@@ -21,7 +20,12 @@ namespace Umbraco.Core.Models
MemberTypePropertyTypes = new Dictionary<string, MemberTypePropertyProfileAccess>();
}
public MemberType(IContentTypeComposition parent) : base(parent)
public MemberType(IContentTypeComposition parent) : this(parent, null)
{
}
public MemberType(IContentTypeComposition parent, string alias)
: base(parent, alias)
{
MemberTypePropertyTypes = new Dictionary<string, MemberTypePropertyProfileAccess>();
}
@@ -7,9 +7,9 @@ namespace Umbraco.Core.Models.Membership
{
internal static class MembershipUserExtensions
{
internal static UmbracoMembershipMember AsConcreteMembershipUser(this IMembershipUser member, string providerName)
internal static UmbracoMembershipMember AsConcreteMembershipUser(this IMembershipUser member, string providerName, bool providerKeyAsGuid = false)
{
var membershipMember = new UmbracoMembershipMember(member, providerName);
var membershipMember = new UmbracoMembershipMember(member, providerName, providerKeyAsGuid);
return membershipMember;
}
@@ -1,5 +1,6 @@
using System;
using System.Web.Security;
using Umbraco.Core.Configuration;
namespace Umbraco.Core.Models.Membership
{
@@ -25,7 +26,7 @@ namespace Umbraco.Core.Models.Membership
//NOTE: We are not calling the base constructor which will validate that a provider with the specified name exists which causes issues with unit tests. The ctor
// validation for that doesn't need to be there anyways (have checked the source).
public UmbracoMembershipMember(IMembershipUser member, string providerName)
public UmbracoMembershipMember(IMembershipUser member, string providerName, bool providerKeyAsGuid = false)
{
_member = member;
//NOTE: We are copying the values here so that everything is consistent with how the underlying built-in ASP.Net membership user
@@ -37,7 +38,7 @@ namespace Umbraco.Core.Models.Membership
if (member.PasswordQuestion != null)
_passwordQuestion = member.PasswordQuestion.Trim();
_providerName = providerName;
_providerUserKey = member.ProviderUserKey;
_providerUserKey = providerKeyAsGuid ? member.ProviderUserKey : member.Id;
_comment = member.Comments;
_isApproved = member.IsApproved;
_isLockedOut = member.IsLockedOut;
@@ -58,7 +58,6 @@ namespace Umbraco.Core.Models.Membership
private IUserType _userType;
private string _name;
private Type _userTypeKey;
private List<string> _addedSections;
private List<string> _removedSections;
private ObservableCollection<string> _sectionCollection;
@@ -80,7 +79,6 @@ namespace Umbraco.Core.Models.Membership
private static readonly PropertyInfo StartMediaIdSelector = ExpressionHelper.GetPropertyInfo<User, int>(x => x.StartMediaId);
private static readonly PropertyInfo AllowedSectionsSelector = ExpressionHelper.GetPropertyInfo<User, IEnumerable<string>>(x => x.AllowedSections);
private static readonly PropertyInfo NameSelector = ExpressionHelper.GetPropertyInfo<User, string>(x => x.Name);
private static readonly PropertyInfo UserTypeKeySelector = ExpressionHelper.GetPropertyInfo<User, Type>(x => x.ProviderUserKeyType);
private static readonly PropertyInfo UsernameSelector = ExpressionHelper.GetPropertyInfo<User, string>(x => x.Username);
private static readonly PropertyInfo EmailSelector = ExpressionHelper.GetPropertyInfo<User, string>(x => x.Email);
@@ -101,37 +99,6 @@ namespace Umbraco.Core.Models.Membership
set { throw new NotSupportedException("Cannot set the provider user key for a user"); }
}
/// <summary>
/// Gets or sets the type of the provider user key.
/// </summary>
/// <value>
/// The type of the provider user key.
/// </value>
[IgnoreDataMember]
internal Type ProviderUserKeyType
{
get
{
return _userTypeKey;
}
private set
{
SetPropertyValueAndDetectChanges(o =>
{
_userTypeKey = value;
return _userTypeKey;
}, _userTypeKey, UserTypeKeySelector);
}
}
/// <summary>
/// Sets the type of the provider user key.
/// </summary>
/// <param name="type">The type.</param>
internal void SetProviderUserKeyType(Type type)
{
ProviderUserKeyType = type;
}
[DataMember]
public string Username
@@ -71,16 +71,34 @@ namespace Umbraco.Core.Models
{
using (new WriteLock(_addLocker))
{
var key = GetKeyForItem(item);
if (key != null)
//Note this is done to ensure existig groups can be renamed
if (item.HasIdentity && item.Id > 0)
{
var exists = this.Contains(key);
var exists = this.Contains(item.Id);
if (exists)
{
SetItem(IndexOfKey(key), item);
var keyExists = this.Contains(item.Name);
if(keyExists)
throw new Exception(string.Format("Naming conflict: Changing the name of PropertyGroup '{0}' would result in duplicates", item.Name));
SetItem(IndexOfKey(item.Id), item);
return;
}
}
else
{
var key = GetKeyForItem(item);
if (key != null)
{
var exists = this.Contains(key);
if (exists)
{
SetItem(IndexOfKey(key), item);
return;
}
}
}
base.Add(item);
OnAdd.IfNotNull(x => x.Invoke());//Could this not be replaced by a Mandate/Contract for ensuring item is not null
@@ -99,6 +117,11 @@ namespace Umbraco.Core.Models
return this.Any(x => x.Name == groupName);
}
public bool Contains(int id)
{
return this.Any(x => x.Id == id);
}
public void RemoveItem(string propertyGroupName)
{
var key = IndexOfKey(propertyGroupName);
@@ -119,6 +142,18 @@ namespace Umbraco.Core.Models
return -1;
}
public int IndexOfKey(int id)
{
for (var i = 0; i < this.Count; i++)
{
if (this[i].Id == id)
{
return i;
}
}
return -1;
}
protected override string GetKeyForItem(PropertyGroup item)
{
return item.Name;
+2 -1
View File
@@ -1,9 +1,9 @@
using System;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.Serialization;
using System.Text.RegularExpressions;
using Umbraco.Core.Models.EntityBase;
using Umbraco.Core.Persistence;
using Umbraco.Core.PropertyEditors;
using Umbraco.Core.Strings;
@@ -14,6 +14,7 @@ namespace Umbraco.Core.Models
/// </summary>
[Serializable]
[DataContract(IsReference = true)]
[DebuggerDisplay("Id: {Id}, Name: {Name}, Alias: {Alias}")]
public class PropertyType : Entity, IEquatable<PropertyType>
{
private readonly bool _isExplicitDbType;
@@ -33,7 +33,7 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenTwoZero
//make sure it doesn't already exist
if (dbIndexes.Any(x => x.IndexName.InvariantEquals("IX_umbracoNodeUniqueID")) == false)
{
Create.Index("IX_umbracoNodeUniqueID").OnTable("umbracoNode").OnColumn("uniqueID").Unique();
Create.Index("IX_umbracoNodeUniqueID").OnTable("umbracoNode").OnColumn("uniqueID").Ascending().WithOptions().NonClustered();
}
}
@@ -1,3 +1,5 @@
using System.Linq;
using AutoMapper;
using Umbraco.Core.Configuration;
using Umbraco.Core.Persistence.DatabaseAnnotations;
using Umbraco.Core.Persistence.SqlSyntax;
@@ -11,9 +13,20 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenTwoZero
{
public override void Up()
{
//To text
var textType = SqlSyntaxContext.SqlSyntaxProvider.GetSpecialDbType(SpecialDbTypes.NTEXT);
Alter.Table("cmsDataTypePreValues").AlterColumn("value").AsCustom(textType).Nullable();
var columns = SqlSyntaxContext.SqlSyntaxProvider.GetColumnsInSchema(Context.Database).Distinct().ToArray();
//Check if it's already text
if (columns.Any(x => x.ColumnName.InvariantEquals("value") && x.TableName.InvariantEquals("cmsDataTypePreValues")
//mysql check
&& (x.DataType.InvariantEquals("longtext") == false
//sql server check
&& x.DataType.InvariantEquals("ntext") == false)))
{
//To text
var textType = SqlSyntaxContext.SqlSyntaxProvider.GetSpecialDbType(SpecialDbTypes.NTEXT);
Alter.Table("cmsDataTypePreValues").AlterColumn("value").AsCustom(textType).Nullable();
}
}
public override void Down()
+63 -41
View File
@@ -850,7 +850,7 @@ namespace Umbraco.Core.Persistence
public IEnumerable<T1> Query<T1, T2, T3, T4>(Sql sql) { return Query<T1>(new Type[] { typeof(T1), typeof(T2), typeof(T3), typeof(T4) }, null, sql.SQL, sql.Arguments); }
// Automagically guess the property relationships between various POCOs and create a delegate that will set them up
object GetAutoMapper(Type[] types)
Delegate GetAutoMapper(Type[] types)
{
// Build a key
var kb = new StringBuilder();
@@ -865,7 +865,7 @@ namespace Umbraco.Core.Persistence
RWLock.EnterReadLock();
try
{
object mapper;
Delegate mapper;
if (AutoMappers.TryGetValue(key, out mapper))
return mapper;
}
@@ -879,7 +879,7 @@ namespace Umbraco.Core.Persistence
try
{
// Try again
object mapper;
Delegate mapper;
if (AutoMappers.TryGetValue(key, out mapper))
return mapper;
@@ -952,22 +952,53 @@ namespace Umbraco.Core.Persistence
throw new InvalidOperationException(string.Format("Couldn't find split point between {0} and {1}", typeThis, typeNext));
}
// Instance data used by the Multipoco factory delegate - essentially a list of the nested poco factories to call
public class MultiPocoFactory
{
public List<Delegate> m_Delegates;
public Delegate GetItem(int index) { return m_Delegates[index]; }
public MultiPocoFactory(IEnumerable<Delegate> dels)
{
Delegates = new List<Delegate>(dels);
}
private List<Delegate> Delegates { get; set; }
private Delegate GetItem(int index) { return Delegates[index]; }
/// <summary>
/// Calls the delegate at the specified index and returns its values
/// </summary>
/// <param name="index"></param>
/// <param name="reader"></param>
/// <returns></returns>
private object CallDelegate(int index, IDataReader reader)
{
var d = GetItem(index);
var output = d.DynamicInvoke(reader);
return output;
}
/// <summary>
/// Calls the callback delegate and passes in the output of all delegates as the parameters
/// </summary>
/// <typeparam name="TRet"></typeparam>
/// <param name="callback"></param>
/// <param name="dr"></param>
/// <param name="count"></param>
/// <returns></returns>
public TRet CallCallback<TRet>(Delegate callback, IDataReader dr, int count)
{
var args = new List<object>();
for(var i = 0;i<count;i++)
{
args.Add(CallDelegate(i, dr));
}
return (TRet)callback.DynamicInvoke(args.ToArray());
}
}
// Create a multi-poco factory
Func<IDataReader, object, TRet> CreateMultiPocoFactory<TRet>(Type[] types, string sql, IDataReader r)
{
var m = new DynamicMethod("petapoco_multipoco_factory", typeof(TRet), new Type[] { typeof(MultiPocoFactory), typeof(IDataReader), typeof(object) }, typeof(MultiPocoFactory));
var il = m.GetILGenerator();
// Load the callback
il.Emit(OpCodes.Ldarg_2);
Func<IDataReader, Delegate, TRet> CreateMultiPocoFactory<TRet>(Type[] types, string sql, IDataReader r)
{
// Call each delegate
var dels = new List<Delegate>();
int pos = 0;
@@ -976,33 +1007,19 @@ namespace Umbraco.Core.Persistence
// Add to list of delegates to call
var del = FindSplitPoint(types[i], i + 1 < types.Length ? types[i + 1] : null, sql, r, ref pos);
dels.Add(del);
// Get the delegate
il.Emit(OpCodes.Ldarg_0); // callback,this
il.Emit(OpCodes.Ldc_I4, i); // callback,this,Index
il.Emit(OpCodes.Callvirt, typeof(MultiPocoFactory).GetMethod("GetItem")); // callback,Delegate
il.Emit(OpCodes.Ldarg_1); // callback,delegate, datareader
// Call Invoke
var tDelInvoke = del.GetType().GetMethod("Invoke");
il.Emit(OpCodes.Callvirt, tDelInvoke); // Poco left on stack
}
// By now we should have the callback and the N pocos all on the stack. Call the callback and we're done
il.Emit(OpCodes.Callvirt, Expression.GetFuncType(types.Concat(new Type[] { typeof(TRet) }).ToArray()).GetMethod("Invoke"));
il.Emit(OpCodes.Ret);
// Finish up
return (Func<IDataReader, object, TRet>)m.CreateDelegate(typeof(Func<IDataReader, object, TRet>), new MultiPocoFactory() { m_Delegates = dels });
var mpFactory = new MultiPocoFactory(dels);
return (reader, arg3) => mpFactory.CallCallback<TRet>(arg3, reader, types.Length);
}
// Various cached stuff
static Dictionary<string, object> MultiPocoFactories = new Dictionary<string, object>();
static Dictionary<string, object> AutoMappers = new Dictionary<string, object>();
static Dictionary<string, Delegate> AutoMappers = new Dictionary<string, Delegate>();
static System.Threading.ReaderWriterLockSlim RWLock = new System.Threading.ReaderWriterLockSlim();
// Get (or create) the multi-poco factory for a query
Func<IDataReader, object, TRet> GetMultiPocoFactory<TRet>(Type[] types, string sql, IDataReader r)
// Get (or create) the multi-poco factory for a query
Func<IDataReader, Delegate, TRet> GetMultiPocoFactory<TRet>(Type[] types, string sql, IDataReader r)
{
// Build a key string (this is crap, should address this at some point)
var kb = new StringBuilder();
@@ -1024,7 +1041,10 @@ namespace Umbraco.Core.Persistence
{
object oFactory;
if (MultiPocoFactories.TryGetValue(key, out oFactory))
return (Func<IDataReader, object, TRet>)oFactory;
{
//mpFactory = oFactory;
return (Func<IDataReader, Delegate, TRet>)oFactory;
}
}
finally
{
@@ -1036,15 +1056,17 @@ namespace Umbraco.Core.Persistence
try
{
// Check again
object oFactory;
object oFactory; ;
if (MultiPocoFactories.TryGetValue(key, out oFactory))
return (Func<IDataReader, object, TRet>)oFactory;
{
return (Func<IDataReader, Delegate, TRet>)oFactory;
}
// Create the factory
var factory = CreateMultiPocoFactory<TRet>(types, sql, r);
// Create the factory
var Factory = CreateMultiPocoFactory<TRet>(types, sql, r);
MultiPocoFactories.Add(key, Factory);
return Factory;
MultiPocoFactories.Add(key, factory);
return factory;
}
finally
{
@@ -1054,7 +1076,7 @@ namespace Umbraco.Core.Persistence
}
// Actual implementation of the multi-poco query
public IEnumerable<TRet> Query<TRet>(Type[] types, object cb, string sql, params object[] args)
public IEnumerable<TRet> Query<TRet>(Type[] types, Delegate cb, string sql, params object[] args)
{
OpenSharedConnection();
try
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Text;
@@ -297,9 +298,38 @@ AND umbracoNode.id <> @id",
//Delete Tabs/Groups by excepting entries from db with entries from collections
var dbPropertyGroups =
Database.Fetch<PropertyTypeGroupDto>("WHERE contenttypeNodeId = @Id", new {Id = entity.Id})
.Select(x => new Tuple<int, string>(x.Id, x.Text));
var entityPropertyGroups = entity.PropertyGroups.Select(x => new Tuple<int, string>(x.Id, x.Name));
var tabs = dbPropertyGroups.Except(entityPropertyGroups);
.Select(x => new Tuple<int, string>(x.Id, x.Text))
.ToList();
var entityPropertyGroups = entity.PropertyGroups.Select(x => new Tuple<int, string>(x.Id, x.Name)).ToList();
var tabsToDelete = dbPropertyGroups.Select(x => x.Item1).Except(entityPropertyGroups.Select(x => x.Item1));
var tabs = dbPropertyGroups.Where(x => tabsToDelete.Any(y => y == x.Item1));
//Update Tab name downstream to ensure renaming is done properly
foreach (var propertyGroup in entityPropertyGroups)
{
Database.Update<PropertyTypeGroupDto>("SET Text = @TabName WHERE parentGroupId = @TabId",
new { TabName = propertyGroup.Item2, TabId = propertyGroup.Item1 });
var childGroups = Database.Fetch<PropertyTypeGroupDto>("WHERE parentGroupId = @TabId", new { TabId = propertyGroup.Item1 });
foreach (var childGroup in childGroups)
{
var sibling = Database.Fetch<PropertyTypeGroupDto>("WHERE contenttypeNodeId = @Id AND text = @Name",
new { Id = childGroup.ContentTypeNodeId, Name = propertyGroup.Item2 })
.FirstOrDefault(x => x.ParentGroupId.HasValue == false || x.ParentGroupId.Value.Equals(propertyGroup.Item1) == false);
//If the child group doesn't have a sibling there is no chance of duplicates and we continue
if (sibling == null || (sibling.ParentGroupId.HasValue && sibling.ParentGroupId.Value.Equals(propertyGroup.Item1))) continue;
//Since the child group has a sibling with the same name we need to point any PropertyTypes to the sibling
//as this child group is about to leave the party.
Database.Update<PropertyTypeDto>(
"SET propertyTypeGroupId = @PropertyTypeGroupId WHERE propertyTypeGroupId = @PropertyGroupId AND ContentTypeId = @ContentTypeId",
new { PropertyTypeGroupId = sibling.Id, PropertyGroupId = childGroup.Id, ContentTypeId = childGroup.ContentTypeNodeId });
//Since the parent group has been renamed and we have duplicates we remove this group
//and leave our sibling in charge of the part.
Database.Delete(childGroup);
}
}
//Do Tab updates
foreach (var tab in tabs)
{
Database.Update<PropertyTypeDto>("SET propertyTypeGroupId = NULL WHERE propertyTypeGroupId = @PropertyGroupId",
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Xml.Linq;
@@ -8,11 +9,13 @@ using System.Threading;
using Umbraco.Core.Auditing;
using Umbraco.Core.Configuration;
using Umbraco.Core.Events;
using Umbraco.Core.Exceptions;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Rdbms;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.Querying;
using Umbraco.Core.Persistence.Repositories;
using Umbraco.Core.Persistence.UnitOfWork;
namespace Umbraco.Core.Services
@@ -273,6 +276,74 @@ namespace Umbraco.Core.Services
}
public void Validate(IContentTypeComposition compo)
{
using (new WriteLock(Locker))
{
ValidateLocked(compo);
}
}
private void ValidateLocked(IContentTypeComposition compositionContentType)
{
// performs business-level validation of the composition
// should ensure that it is absolutely safe to save the composition
// eg maybe a property has been added, with an alias that's OK (no conflict with ancestors)
// but that cannot be used (conflict with descendants)
var contentType = compositionContentType as IContentType;
var mediaType = compositionContentType as IMediaType;
IContentTypeComposition[] allContentTypes;
if (contentType != null)
allContentTypes = GetAllContentTypes().Cast<IContentTypeComposition>().ToArray();
else if (mediaType != null)
allContentTypes = GetAllMediaTypes().Cast<IContentTypeComposition>().ToArray();
else
throw new Exception("Composition is neither IContentType nor IMediaType?");
var compositionAliases = compositionContentType.CompositionAliases();
var compositions = allContentTypes.Where(x => compositionAliases.Any(y => x.Alias.Equals(y)));
var propertyTypeAliases = compositionContentType.PropertyTypes.Select(x => x.Alias.ToLowerInvariant()).ToArray();
var indirectReferences = allContentTypes.Where(x => x.ContentTypeComposition.Any(y => y.Id == compositionContentType.Id));
var comparer = new DelegateEqualityComparer<IContentTypeComposition>((x, y) => x.Id == y.Id, x => x.Id);
var dependencies = new HashSet<IContentTypeComposition>(compositions, comparer);
var stack = new Stack<IContentTypeComposition>();
indirectReferences.ForEach(stack.Push);//Push indirect references to a stack, so we can add recursively
while (stack.Count > 0)
{
var indirectReference = stack.Pop();
dependencies.Add(indirectReference);
//Get all compositions for the current indirect reference
var directReferences = indirectReference.ContentTypeComposition;
foreach (var directReference in directReferences)
{
if (directReference.Id == compositionContentType.Id || directReference.Alias.Equals(compositionContentType.Alias)) continue;
dependencies.Add(directReference);
//A direct reference has compositions of its own - these also need to be taken into account
var directReferenceGraph = directReference.CompositionAliases();
allContentTypes.Where(x => directReferenceGraph.Any(y => x.Alias.Equals(y, StringComparison.InvariantCultureIgnoreCase))).ForEach(c => dependencies.Add(c));
}
//Recursive lookup of indirect references
allContentTypes.Where(x => x.ContentTypeComposition.Any(y => y.Id == indirectReference.Id)).ForEach(stack.Push);
}
foreach (var dependency in dependencies)
{
if (dependency.Id == compositionContentType.Id) continue;
var contentTypeDependency = allContentTypes.FirstOrDefault(x => x.Alias.Equals(dependency.Alias, StringComparison.InvariantCultureIgnoreCase));
if (contentTypeDependency == null) continue;
var intersect = contentTypeDependency.PropertyTypes.Select(x => x.Alias.ToLowerInvariant()).Intersect(propertyTypeAliases).ToArray();
if (intersect.Length == 0) continue;
var message = string.Format("The following PropertyType aliases from the current ContentType conflict with existing PropertyType aliases: {0}.",
string.Join(", ", intersect));
throw new Exception(message);
}
}
/// <summary>
/// Saves a single <see cref="IContentType"/> object
/// </summary>
@@ -288,6 +359,7 @@ namespace Umbraco.Core.Services
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateContentTypeRepository(uow))
{
ValidateLocked(contentType); // throws if invalid
contentType.CreatorId = userId;
repository.AddOrUpdate(contentType);
@@ -317,6 +389,11 @@ namespace Umbraco.Core.Services
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateContentTypeRepository(uow))
{
// all-or-nothing, validate them all first
foreach (var contentType in asArray)
{
ValidateLocked(contentType); // throws if invalid
}
foreach (var contentType in asArray)
{
contentType.CreatorId = userId;
@@ -487,6 +564,7 @@ namespace Umbraco.Core.Services
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateMediaTypeRepository(uow))
{
ValidateLocked(mediaType); // throws if invalid
mediaType.CreatorId = userId;
repository.AddOrUpdate(mediaType);
uow.Commit();
@@ -517,7 +595,11 @@ namespace Umbraco.Core.Services
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateMediaTypeRepository(uow))
{
// all-or-nothing, validate them all first
foreach (var mediaType in asArray)
{
ValidateLocked(mediaType); // throws if invalid
}
foreach (var mediaType in asArray)
{
mediaType.CreatorId = userId;
+18 -3
View File
@@ -200,8 +200,22 @@ namespace Umbraco.Core.Services
/// <param name="userId">Id of the user issueing the save</param>
public void Save(IEnumerable<IDataTypeDefinition> dataTypeDefinitions, int userId = 0)
{
if (Saving.IsRaisedEventCancelled(new SaveEventArgs<IDataTypeDefinition>(dataTypeDefinitions), this))
return;
Save(dataTypeDefinitions, userId, true);
}
/// <summary>
/// Saves a collection of <see cref="IDataTypeDefinition"/>
/// </summary>
/// <param name="dataTypeDefinitions"><see cref="IDataTypeDefinition"/> to save</param>
/// <param name="userId">Id of the user issueing the save</param>
/// <param name="raiseEvents">Boolean indicating whether or not to raise events</param>
public void Save(IEnumerable<IDataTypeDefinition> dataTypeDefinitions, int userId, bool raiseEvents)
{
if (raiseEvents)
{
if (Saving.IsRaisedEventCancelled(new SaveEventArgs<IDataTypeDefinition>(dataTypeDefinitions), this))
return;
}
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateDataTypeDefinitionRepository(uow))
@@ -213,7 +227,8 @@ namespace Umbraco.Core.Services
}
uow.Commit();
Saved.RaiseEvent(new SaveEventArgs<IDataTypeDefinition>(dataTypeDefinitions, false), this);
if (raiseEvents)
Saved.RaiseEvent(new SaveEventArgs<IDataTypeDefinition>(dataTypeDefinitions, false), this);
}
Audit.Add(AuditTypes.Save, string.Format("Save DataTypeDefinition performed by user"), userId, -1);
@@ -52,6 +52,14 @@ namespace Umbraco.Core.Services
/// <param name="userId">Id of the user issueing the save</param>
void Save(IEnumerable<IDataTypeDefinition> dataTypeDefinitions, int userId = 0);
/// <summary>
/// Saves a collection of <see cref="IDataTypeDefinition"/>
/// </summary>
/// <param name="dataTypeDefinitions"><see cref="IDataTypeDefinition"/> to save</param>
/// <param name="userId">Id of the user issueing the save</param>
/// <param name="raiseEvents">Boolean indicating whether or not to raise events</param>
void Save(IEnumerable<IDataTypeDefinition> dataTypeDefinitions, int userId, bool raiseEvents);
/// <summary>
/// Deletes an <see cref="IDataTypeDefinition"/>
/// </summary>
+50 -41
View File
@@ -336,48 +336,56 @@ namespace Umbraco.Core.Services
? (from doc in element.Elements("DocumentType") select doc).ToList()
: new List<XElement> { element };
//NOTE Here we sort the doctype XElements based on dependencies
//before creating the doc types - this should also allow for a better structure/inheritance support.
//When you are importing a single doc type we have to assume that the depedencies are already there.
//Otherwise something like uSync won't work.
var fields = new List<TopologicalSorter.DependencyField<XElement>>();
foreach (var documentType in unsortedDocumentTypes)
var isSingleDocTypeImport = unsortedDocumentTypes.Count == 1;
if (isSingleDocTypeImport == false)
{
var elementCopy = documentType;
var infoElement = elementCopy.Element("Info");
var dependencies = new List<string>();
//Add the Master as a dependency
if (elementCopy.Element("Master") != null &&
string.IsNullOrEmpty(elementCopy.Element("Master").Value) == false)
//NOTE Here we sort the doctype XElements based on dependencies
//before creating the doc types - this should also allow for a better structure/inheritance support.
foreach (var documentType in unsortedDocumentTypes)
{
dependencies.Add(elementCopy.Element("Master").Value);
}
var elementCopy = documentType;
var infoElement = elementCopy.Element("Info");
var dependencies = new List<string>();
//Add compositions as dependencies
var compositionsElement = infoElement.Element("Compositions");
if (compositionsElement != null && compositionsElement.HasElements)
{
var compositions = compositionsElement.Elements("Composition");
if (compositions.Any())
//Add the Master as a dependency
if (elementCopy.Element("Master") != null &&
string.IsNullOrEmpty(elementCopy.Element("Master").Value) == false)
{
foreach (var composition in compositions)
dependencies.Add(elementCopy.Element("Master").Value);
}
//Add compositions as dependencies
var compositionsElement = infoElement.Element("Compositions");
if (compositionsElement != null && compositionsElement.HasElements)
{
var compositions = compositionsElement.Elements("Composition");
if (compositions.Any())
{
dependencies.Add(composition.Value);
foreach (var composition in compositions)
{
dependencies.Add(composition.Value);
}
}
}
}
var field = new TopologicalSorter.DependencyField<XElement>
{
Alias = infoElement.Element("Alias").Value,
Item = new Lazy<XElement>(() => elementCopy),
DependsOn = dependencies.ToArray()
};
fields.Add(field);
var field = new TopologicalSorter.DependencyField<XElement>
{
Alias = infoElement.Element("Alias").Value,
Item = new Lazy<XElement>(() => elementCopy),
DependsOn = dependencies.ToArray()
};
fields.Add(field);
}
}
//Sorting the Document Types based on dependencies
var documentTypes = TopologicalSorter.GetSortedItems(fields).ToList();
//Sorting the Document Types based on dependencies - if its not a single doc type import ref. #U4-5921
var documentTypes = isSingleDocTypeImport
? unsortedDocumentTypes.ToList()
: TopologicalSorter.GetSortedItems(fields).ToList();
//Iterate the sorted document types and create them as IContentType objects
foreach (var documentType in documentTypes)
@@ -438,15 +446,10 @@ namespace Umbraco.Core.Services
: _contentTypeService.GetContentType(masterAlias);
}
var alias = infoElement.Element("Alias").Value;
var contentType = parent == null
? new ContentType(-1)
{
Alias = infoElement.Element("Alias").Value
}
: new ContentType(parent)
{
Alias = infoElement.Element("Alias").Value
};
? new ContentType(-1) { Alias = alias }
: new ContentType(parent, alias);
if (parent != null)
contentType.AddContentType(parent);
@@ -843,9 +846,15 @@ namespace Umbraco.Core.Services
var list = dataTypes.Select(x => x.Value).ToList();
if (list.Any())
{
_dataTypeService.Save(list, userId);
//NOTE: As long as we have to deal with the two types of PreValue lists (with/without Keys)
//this is a bit of a pain to handle while ensuring that the imported DataTypes has PreValues
//place when triggering the save event.
SavePrevaluesFromXml(list, dataTypeElements);
_dataTypeService.Save(list, userId, false);//Save without raising events
SavePrevaluesFromXml(list, dataTypeElements);//Save the PreValues for the current list of DataTypes
_dataTypeService.Save(list, userId, true);//Re-save and raise events
}
if (raiseEvents)
@@ -74,7 +74,8 @@ namespace Umbraco.Tests.PublishedContent
{
var contentTypeService = ctx.Application.Services.ContentTypeService;
var baseType = new ContentType(-1) {Alias = "base", Name = "Base"};
var inheritedType = new ContentType(baseType) {Alias = "inherited", Name = "Inherited"};
const string contentTypeAlias = "inherited";
var inheritedType = new ContentType(baseType, contentTypeAlias) {Alias = contentTypeAlias, Name = "Inherited"};
contentTypeService.Save(baseType);
contentTypeService.Save(inheritedType);
createContentTypes = false;
@@ -1,3 +1,4 @@
using System.Runtime.Remoting;
using NUnit.Framework;
using System;
using System.Collections.Generic;
@@ -5,6 +6,8 @@ using System.Linq;
using Umbraco.Core;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Rdbms;
using Umbraco.Core.Persistence.Caching;
using Umbraco.Tests.CodeFirst.TestModels.Composition;
using Umbraco.Tests.TestHelpers;
using Umbraco.Tests.TestHelpers.Entities;
@@ -178,10 +181,11 @@ namespace Umbraco.Tests.Services
/*,"Navigation"*/);
cts.Save(ctBase);
var ctHomePage = new ContentType(ctBase)
const string contentTypeAlias = "HomePage";
var ctHomePage = new ContentType(ctBase, contentTypeAlias)
{
Name = "Home Page",
Alias = "HomePage",
Alias = contentTypeAlias,
Icon = "settingDomain.gif",
Thumbnail = "folder.png",
AllowedAsRoot = true
@@ -191,7 +195,7 @@ namespace Umbraco.Tests.Services
cts.Save(ctHomePage);
// Act
var homeDoc = cs.CreateContent("Home Page", -1, "HomePage");
var homeDoc = cs.CreateContent("Home Page", -1, contentTypeAlias);
cs.SaveAndPublishWithStatus(homeDoc);
// Assert
@@ -243,13 +247,13 @@ namespace Umbraco.Tests.Services
var global = MockedContentTypes.CreateSimpleContentType("global", "Global");
service.Save(global);
var components = MockedContentTypes.CreateSimpleContentType("components", "Components", global);
var components = MockedContentTypes.CreateSimpleContentType("components", "Components", global, true);
service.Save(components);
var component = MockedContentTypes.CreateSimpleContentType("component", "Component", components);
var component = MockedContentTypes.CreateSimpleContentType("component", "Component", components, true);
service.Save(component);
var category = MockedContentTypes.CreateSimpleContentType("category", "Category", global);
var category = MockedContentTypes.CreateSimpleContentType("category", "Category", global, true);
service.Save(category);
var success = category.AddContentType(component);
@@ -464,6 +468,766 @@ namespace Umbraco.Tests.Services
Assert.AreNotEqual(clonedContentType.PropertyGroups.First(x => x.Name.StartsWith("Content")).Id, originalContentType.PropertyGroups.First(x => x.Name.StartsWith("Content")).Id);
}
[Test]
public void Cannot_Add_Duplicate_PropertyType_Alias_To_Referenced_Composition()
{
//Related the second issue in screencast from this post http://issues.umbraco.org/issue/U4-5986
// Arrange
var service = ServiceContext.ContentTypeService;
var parent = MockedContentTypes.CreateSimpleContentType();
service.Save(parent);
var child = MockedContentTypes.CreateSimpleContentType("simpleChildPage", "Simple Child Page", parent, true);
service.Save(child);
var composition = MockedContentTypes.CreateMetaContentType();
service.Save(composition);
//Adding Meta-composition to child doc type
child.AddContentType(composition);
service.Save(child);
// Act
var duplicatePropertyType = new PropertyType(Constants.PropertyEditors.TextboxAlias, DataTypeDatabaseType.Ntext)
{
Alias = "title", Name = "Title", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88
};
var added = composition.AddPropertyType(duplicatePropertyType, "Meta");
// Assert
Assert.That(added, Is.True);
Assert.Throws<Exception>(() => service.Save(composition));
Assert.DoesNotThrow(() => service.GetContentType("simpleChildPage"));
}
[Test]
public void Cannot_Add_Duplicate_PropertyType_Alias_In_Composition_Graph()
{
// Arrange
var service = ServiceContext.ContentTypeService;
var basePage = MockedContentTypes.CreateSimpleContentType("basePage", "Base Page", null, true);
service.Save(basePage);
var contentPage = MockedContentTypes.CreateSimpleContentType("contentPage", "Content Page", basePage);
service.Save(contentPage);
var advancedPage = MockedContentTypes.CreateSimpleContentType("advancedPage", "Advanced Page", contentPage, true);
service.Save(advancedPage);
var metaComposition = MockedContentTypes.CreateMetaContentType();
service.Save(metaComposition);
var seoComposition = MockedContentTypes.CreateSeoContentType();
service.Save(seoComposition);
var metaAdded = contentPage.AddContentType(metaComposition);
service.Save(contentPage);
var seoAdded = advancedPage.AddContentType(seoComposition);
service.Save(advancedPage);
// Act
var duplicatePropertyType = new PropertyType(Constants.PropertyEditors.TextboxAlias, DataTypeDatabaseType.Ntext)
{
Alias = "title", Name = "Title", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88
};
var addedToBasePage = basePage.AddPropertyType(duplicatePropertyType, "Content");
var addedToAdvancedPage = advancedPage.AddPropertyType(duplicatePropertyType, "Content");
var addedToMeta = metaComposition.AddPropertyType(duplicatePropertyType, "Meta");
var addedToSeo = seoComposition.AddPropertyType(duplicatePropertyType, "Seo");
// Assert
Assert.That(metaAdded, Is.True);
Assert.That(seoAdded, Is.True);
Assert.That(addedToBasePage, Is.True);
Assert.That(addedToAdvancedPage, Is.False);
Assert.That(addedToMeta, Is.True);
Assert.That(addedToSeo, Is.True);
Assert.Throws<Exception>(() => service.Save(basePage));
Assert.Throws<Exception>(() => service.Save(metaComposition));
Assert.Throws<Exception>(() => service.Save(seoComposition));
Assert.DoesNotThrow(() => service.GetContentType("contentPage"));
Assert.DoesNotThrow(() => service.GetContentType("advancedPage"));
Assert.DoesNotThrow(() => service.GetContentType("meta"));
Assert.DoesNotThrow(() => service.GetContentType("seo"));
}
[Test]
public void Cannot_Add_Duplicate_PropertyType_Alias_At_Root_Which_Conflicts_With_Third_Levels_Composition()
{
/*
* BasePage, gets 'Title' added but should not be allowed
* -- Content Page
* ---- Advanced Page -> Content Meta
* Content Meta :: Composition, has 'Title'
*
* Content Meta has 'Title' PropertyType
* Adding 'Title' to BasePage should fail
*/
// Arrange
var service = ServiceContext.ContentTypeService;
var basePage = MockedContentTypes.CreateBasicContentType();
service.Save(basePage);
var contentPage = MockedContentTypes.CreateBasicContentType("contentPage", "Content Page", basePage);
service.Save(contentPage);
var advancedPage = MockedContentTypes.CreateBasicContentType("advancedPage", "Advanced Page", contentPage);
service.Save(advancedPage);
var contentMetaComposition = MockedContentTypes.CreateContentMetaContentType();
service.Save(contentMetaComposition);
// Act
var bodyTextPropertyType = new PropertyType(Constants.PropertyEditors.TextboxAlias, DataTypeDatabaseType.Ntext)
{
Alias = "bodyText", Name = "Body Text", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88
};
var bodyTextAdded = basePage.AddPropertyType(bodyTextPropertyType, "Content");
service.Save(basePage);
var authorPropertyType = new PropertyType(Constants.PropertyEditors.TextboxAlias, DataTypeDatabaseType.Ntext)
{
Alias = "author", Name = "Author", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88
};
var authorAdded = contentPage.AddPropertyType(authorPropertyType, "Content");
service.Save(contentPage);
var compositionAdded = advancedPage.AddContentType(contentMetaComposition);
service.Save(advancedPage);
//NOTE: It should not be possible to Save 'BasePage' with the Title PropertyType added
var titlePropertyType = new PropertyType(Constants.PropertyEditors.TextboxAlias, DataTypeDatabaseType.Ntext)
{
Alias = "title", Name = "Title", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88
};
var titleAdded = basePage.AddPropertyType(titlePropertyType, "Content");
// Assert
Assert.That(bodyTextAdded, Is.True);
Assert.That(authorAdded, Is.True);
Assert.That(titleAdded, Is.True);
Assert.That(compositionAdded, Is.True);
Assert.Throws<Exception>(() => service.Save(basePage));
Assert.DoesNotThrow(() => service.GetContentType("contentPage"));
Assert.DoesNotThrow(() => service.GetContentType("advancedPage"));
}
[Test]
public void Cannot_Rename_PropertyType_Alias_On_Composition_Which_Would_Cause_Conflict_In_Other_Composition()
{
/*
* Meta renames alias to 'title'
* Seo has 'Title'
* BasePage
* -- ContentPage
* ---- AdvancedPage -> Seo
* ------ MoreAdvanedPage -> Meta
*/
// Arrange
var service = ServiceContext.ContentTypeService;
var basePage = MockedContentTypes.CreateBasicContentType();
service.Save(basePage);
var contentPage = MockedContentTypes.CreateBasicContentType("contentPage", "Content Page", basePage);
service.Save(contentPage);
var advancedPage = MockedContentTypes.CreateBasicContentType("advancedPage", "Advanced Page", contentPage);
service.Save(advancedPage);
var moreAdvancedPage = MockedContentTypes.CreateBasicContentType("moreAdvancedPage", "More Advanced Page", advancedPage);
service.Save(moreAdvancedPage);
var seoComposition = MockedContentTypes.CreateSeoContentType();
service.Save(seoComposition);
var metaComposition = MockedContentTypes.CreateMetaContentType();
service.Save(metaComposition);
// Act
var bodyTextPropertyType = new PropertyType(Constants.PropertyEditors.TextboxAlias, DataTypeDatabaseType.Ntext)
{
Alias = "bodyText", Name = "Body Text", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88
};
var bodyTextAdded = basePage.AddPropertyType(bodyTextPropertyType, "Content");
service.Save(basePage);
var authorPropertyType = new PropertyType(Constants.PropertyEditors.TextboxAlias, DataTypeDatabaseType.Ntext)
{
Alias = "author", Name = "Author", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88
};
var authorAdded = contentPage.AddPropertyType(authorPropertyType, "Content");
service.Save(contentPage);
var subtitlePropertyType = new PropertyType(Constants.PropertyEditors.TextboxAlias, DataTypeDatabaseType.Ntext)
{
Alias = "subtitle", Name = "Subtitle", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88
};
var subtitleAdded = advancedPage.AddPropertyType(subtitlePropertyType, "Content");
service.Save(advancedPage);
var titlePropertyType = new PropertyType(Constants.PropertyEditors.TextboxAlias, DataTypeDatabaseType.Ntext)
{
Alias = "title", Name = "Title", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88
};
var titleAdded = seoComposition.AddPropertyType(titlePropertyType, "Content");
service.Save(seoComposition);
var seoCompositionAdded = advancedPage.AddContentType(seoComposition);
var metaCompositionAdded = moreAdvancedPage.AddContentType(metaComposition);
service.Save(advancedPage);
service.Save(moreAdvancedPage);
var keywordsPropertyType = metaComposition.PropertyTypes.First(x => x.Alias.Equals("metakeywords"));
keywordsPropertyType.Alias = "title";
// Assert
Assert.That(bodyTextAdded, Is.True);
Assert.That(subtitleAdded, Is.True);
Assert.That(authorAdded, Is.True);
Assert.That(titleAdded, Is.True);
Assert.That(seoCompositionAdded, Is.True);
Assert.That(metaCompositionAdded, Is.True);
Assert.Throws<Exception>(() => service.Save(metaComposition));
Assert.DoesNotThrow(() => service.GetContentType("contentPage"));
Assert.DoesNotThrow(() => service.GetContentType("advancedPage"));
Assert.DoesNotThrow(() => service.GetContentType("moreAdvancedPage"));
}
[Test]
public void Can_Add_Additional_Properties_On_Composition_Once_Composition_Has_Been_Saved()
{
/*
* Meta renames alias to 'title'
* Seo has 'Title'
* BasePage
* -- ContentPage
* ---- AdvancedPage -> Seo
* ------ MoreAdvancedPage -> Meta
*/
// Arrange
var service = ServiceContext.ContentTypeService;
var basePage = MockedContentTypes.CreateBasicContentType();
service.Save(basePage);
var contentPage = MockedContentTypes.CreateBasicContentType("contentPage", "Content Page", basePage);
service.Save(contentPage);
var advancedPage = MockedContentTypes.CreateBasicContentType("advancedPage", "Advanced Page", contentPage);
service.Save(advancedPage);
var moreAdvancedPage = MockedContentTypes.CreateBasicContentType("moreAdvancedPage", "More Advanced Page", advancedPage);
service.Save(moreAdvancedPage);
var seoComposition = MockedContentTypes.CreateSeoContentType();
service.Save(seoComposition);
var metaComposition = MockedContentTypes.CreateMetaContentType();
service.Save(metaComposition);
// Act
var bodyTextPropertyType = new PropertyType(Constants.PropertyEditors.TextboxAlias, DataTypeDatabaseType.Ntext)
{
Alias = "bodyText", Name = "Body Text", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88
};
var bodyTextAdded = basePage.AddPropertyType(bodyTextPropertyType, "Content");
service.Save(basePage);
var authorPropertyType = new PropertyType(Constants.PropertyEditors.TextboxAlias, DataTypeDatabaseType.Ntext)
{
Alias = "author", Name = "Author", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88
};
var authorAdded = contentPage.AddPropertyType(authorPropertyType, "Content");
service.Save(contentPage);
var subtitlePropertyType = new PropertyType(Constants.PropertyEditors.TextboxAlias, DataTypeDatabaseType.Ntext)
{
Alias = "subtitle", Name = "Subtitle", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88
};
var subtitleAdded = advancedPage.AddPropertyType(subtitlePropertyType, "Content");
service.Save(advancedPage);
var titlePropertyType = new PropertyType(Constants.PropertyEditors.TextboxAlias, DataTypeDatabaseType.Ntext)
{
Alias = "title", Name = "Title", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88
};
var titleAdded = seoComposition.AddPropertyType(titlePropertyType, "Content");
service.Save(seoComposition);
var seoCompositionAdded = advancedPage.AddContentType(seoComposition);
var metaCompositionAdded = moreAdvancedPage.AddContentType(metaComposition);
service.Save(advancedPage);
service.Save(moreAdvancedPage);
// Assert
Assert.That(bodyTextAdded, Is.True);
Assert.That(subtitleAdded, Is.True);
Assert.That(authorAdded, Is.True);
Assert.That(titleAdded, Is.True);
Assert.That(seoCompositionAdded, Is.True);
Assert.That(metaCompositionAdded, Is.True);
var testPropertyType = new PropertyType(Constants.PropertyEditors.TextboxAlias, DataTypeDatabaseType.Ntext)
{
Alias = "test", Name = "Test", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88
};
var testAdded = seoComposition.AddPropertyType(testPropertyType, "Content");
service.Save(seoComposition);
Assert.That(testAdded, Is.True);
Assert.DoesNotThrow(() => service.GetContentType("contentPage"));
Assert.DoesNotThrow(() => service.GetContentType("advancedPage"));
Assert.DoesNotThrow(() => service.GetContentType("moreAdvancedPage"));
}
[Test]
public void Cannot_Rename_PropertyGroup_On_Child_Avoiding_Conflict_With_Parent_PropertyGroup()
{
// Arrange
var service = ServiceContext.ContentTypeService;
var page = MockedContentTypes.CreateSimpleContentType("page", "Page", null, true, "Content");
service.Save(page);
var contentPage = MockedContentTypes.CreateSimpleContentType("contentPage", "Content Page", page, true, "Content_");
service.Save(contentPage);
var advancedPage = MockedContentTypes.CreateSimpleContentType("advancedPage", "Advanced Page", contentPage, true, "Details");
service.Save(advancedPage);
var contentMetaComposition = MockedContentTypes.CreateContentMetaContentType();
service.Save(contentMetaComposition);
// Act
var subtitlePropertyType = new PropertyType(Constants.PropertyEditors.TextboxAlias, DataTypeDatabaseType.Ntext)
{
Alias = "subtitle", Name = "Subtitle", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88
};
var authorPropertyType = new PropertyType(Constants.PropertyEditors.TextboxAlias, DataTypeDatabaseType.Ntext)
{
Alias = "author", Name = "Author", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88
};
var subtitleAdded = contentPage.AddPropertyType(subtitlePropertyType, "Content");
var authorAdded = contentPage.AddPropertyType(authorPropertyType, "Content");
service.Save(contentPage);
var compositionAdded = contentPage.AddContentType(contentMetaComposition);
service.Save(contentPage);
//Change the name of the tab on the "root" content type 'page'.
var propertyGroup = contentPage.PropertyGroups["Content_"];
Assert.Throws<Exception>(() => contentPage.PropertyGroups.Add(new PropertyGroup
{
Id = propertyGroup.Id,
Name = "Content",
SortOrder = 0
}));
// Assert
Assert.That(compositionAdded, Is.True);
Assert.That(subtitleAdded, Is.True);
Assert.That(authorAdded, Is.True);
Assert.DoesNotThrow(() => service.GetContentType("contentPage"));
Assert.DoesNotThrow(() => service.GetContentType("advancedPage"));
}
[Test]
public void Cannot_Rename_PropertyType_Alias_Causing_Conflicts_With_Parents()
{
// Arrange
var service = ServiceContext.ContentTypeService;
var basePage = MockedContentTypes.CreateBasicContentType();
service.Save(basePage);
var contentPage = MockedContentTypes.CreateBasicContentType("contentPage", "Content Page", basePage);
service.Save(contentPage);
var advancedPage = MockedContentTypes.CreateBasicContentType("advancedPage", "Advanced Page", contentPage);
service.Save(advancedPage);
// Act
var titlePropertyType = new PropertyType(Constants.PropertyEditors.TextboxAlias, DataTypeDatabaseType.Ntext)
{
Alias = "title", Name = "Title", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88
};
var titleAdded = basePage.AddPropertyType(titlePropertyType, "Content");
var bodyTextPropertyType = new PropertyType(Constants.PropertyEditors.TextboxAlias, DataTypeDatabaseType.Ntext)
{
Alias = "bodyText", Name = "Body Text", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88
};
var bodyTextAdded = contentPage.AddPropertyType(bodyTextPropertyType, "Content");
var subtitlePropertyType = new PropertyType(Constants.PropertyEditors.TextboxAlias, DataTypeDatabaseType.Ntext)
{
Alias = "subtitle", Name = "Subtitle", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88
};
var subtitleAdded = contentPage.AddPropertyType(subtitlePropertyType, "Content");
var authorPropertyType = new PropertyType(Constants.PropertyEditors.TextboxAlias, DataTypeDatabaseType.Ntext)
{
Alias = "author", Name = "Author", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88
};
var authorAdded = advancedPage.AddPropertyType(authorPropertyType, "Content");
service.Save(basePage);
service.Save(contentPage);
service.Save(advancedPage);
//Rename the PropertyType to something that already exists in the Composition - NOTE this should not be allowed and Saving should throw an exception
var authorPropertyTypeToRename = advancedPage.PropertyTypes.First(x => x.Alias.Equals("author"));
authorPropertyTypeToRename.Alias = "title";
// Assert
Assert.That(bodyTextAdded, Is.True);
Assert.That(authorAdded, Is.True);
Assert.That(titleAdded, Is.True);
Assert.That(subtitleAdded, Is.True);
Assert.Throws<Exception>(() => service.Save(advancedPage));
Assert.DoesNotThrow(() => service.GetContentType("contentPage"));
Assert.DoesNotThrow(() => service.GetContentType("advancedPage"));
}
[Test]
public void Can_Add_PropertyType_Alias_Which_Exists_In_Composition_Outside_Graph()
{
/*
* Meta (Composition)
* Content Meta (Composition) has 'Title' -> Meta
* BasePage
* -- ContentPage gets 'Title' added -> Meta
* ---- Advanced Page
*/
// Arrange
var service = ServiceContext.ContentTypeService;
var basePage = MockedContentTypes.CreateSimpleContentType("basePage", "Base Page", null, true);
service.Save(basePage);
var contentPage = MockedContentTypes.CreateSimpleContentType("contentPage", "Content Page", basePage, true);
service.Save(contentPage);
var advancedPage = MockedContentTypes.CreateSimpleContentType("advancedPage", "Advanced Page", contentPage, true);
service.Save(advancedPage);
var metaComposition = MockedContentTypes.CreateMetaContentType();
service.Save(metaComposition);
var contentMetaComposition = MockedContentTypes.CreateContentMetaContentType();
service.Save(contentMetaComposition);
var metaAdded = contentPage.AddContentType(metaComposition);
service.Save(contentPage);
var metaAddedToComposition = contentMetaComposition.AddContentType(metaComposition);
service.Save(contentMetaComposition);
// Act
var propertyType = new PropertyType(Constants.PropertyEditors.TextboxAlias, DataTypeDatabaseType.Ntext)
{
Alias = "title", Name = "Title", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88
};
var addedToContentPage = contentPage.AddPropertyType(propertyType, "Content");
// Assert
Assert.That(metaAdded, Is.True);
Assert.That(metaAddedToComposition, Is.True);
Assert.That(addedToContentPage, Is.True);
Assert.DoesNotThrow(() => service.Save(contentPage));
}
[Test]
public void Can_Rename_PropertyGroup_With_Inherited_PropertyGroups()
{
//Related the first issue in screencast from this post http://issues.umbraco.org/issue/U4-5986
// Arrange
var service = ServiceContext.ContentTypeService;
var page = MockedContentTypes.CreateSimpleContentType("page", "Page", null, false, "Content_");
service.Save(page);
var contentPage = MockedContentTypes.CreateSimpleContentType("contentPage", "Content Page", page, true);
service.Save(contentPage);
var composition = MockedContentTypes.CreateMetaContentType();
composition.AddPropertyGroup("Content");
service.Save(composition);
//Adding Meta-composition to child doc type
contentPage.AddContentType(composition);
service.Save(contentPage);
// Act
var propertyTypeOne = new PropertyType(Constants.PropertyEditors.TextboxAlias, DataTypeDatabaseType.Ntext)
{
Alias = "testTextbox", Name = "Test Textbox", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88
};
var firstOneAdded = contentPage.AddPropertyType(propertyTypeOne, "Content_");
var propertyTypeTwo = new PropertyType(Constants.PropertyEditors.TextboxAlias, DataTypeDatabaseType.Ntext)
{
Alias = "anotherTextbox", Name = "Another Test Textbox", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88
};
var secondOneAdded = contentPage.AddPropertyType(propertyTypeTwo, "Content");
service.Save(contentPage);
Assert.That(page.PropertyGroups.Contains("Content_"), Is.True);
var propertyGroup = page.PropertyGroups["Content_"];
page.PropertyGroups.Add(new PropertyGroup{ Id = propertyGroup.Id, Name = "ContentTab", SortOrder = 0});
service.Save(page);
// Assert
Assert.That(firstOneAdded, Is.True);
Assert.That(secondOneAdded, Is.True);
var contentType = service.GetContentType("contentPage");
Assert.That(contentType, Is.Not.Null);
var compositionPropertyGroups = contentType.CompositionPropertyGroups;
Assert.That(compositionPropertyGroups.Count(x => x.Name.Equals("Content_")), Is.EqualTo(0));
var propertyTypeCount = contentType.PropertyTypes.Count();
var compPropertyTypeCount = contentType.CompositionPropertyTypes.Count();
Assert.That(propertyTypeCount, Is.EqualTo(5));
Assert.That(compPropertyTypeCount, Is.EqualTo(10));
}
[Test]
public void Can_Rename_PropertyGroup_On_Parent_Without_Causing_Duplicate_PropertyGroups()
{
// Arrange
var service = ServiceContext.ContentTypeService;
var page = MockedContentTypes.CreateSimpleContentType("page", "Page", null, true, "Content_");
service.Save(page);
var contentPage = MockedContentTypes.CreateSimpleContentType("contentPage", "Content Page", page, true, "Contentx");
service.Save(contentPage);
var advancedPage = MockedContentTypes.CreateSimpleContentType("advancedPage", "Advanced Page", contentPage, true, "Contenty");
service.Save(advancedPage);
var contentMetaComposition = MockedContentTypes.CreateContentMetaContentType();
service.Save(contentMetaComposition);
var compositionAdded = contentPage.AddContentType(contentMetaComposition);
service.Save(contentPage);
// Act
var bodyTextPropertyType = new PropertyType(Constants.PropertyEditors.TextboxAlias, DataTypeDatabaseType.Ntext)
{
Alias = "bodyText", Name = "Body Text", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88
};
var subtitlePropertyType = new PropertyType(Constants.PropertyEditors.TextboxAlias, DataTypeDatabaseType.Ntext)
{
Alias = "subtitle", Name = "Subtitle", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88
};
var bodyTextAdded = contentPage.AddPropertyType(bodyTextPropertyType, "Content_");//Will be added to the parent tab
var subtitleAdded = contentPage.AddPropertyType(subtitlePropertyType, "Content");//Will be added to the "Content Meta" composition
service.Save(contentPage);
var authorPropertyType = new PropertyType(Constants.PropertyEditors.TextboxAlias, DataTypeDatabaseType.Ntext)
{
Alias = "author", Name = "Author", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88
};
var descriptionPropertyType = new PropertyType(Constants.PropertyEditors.TextboxAlias, DataTypeDatabaseType.Ntext)
{
Alias = "description", Name = "Description", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88
};
var keywordsPropertyType = new PropertyType(Constants.PropertyEditors.TextboxAlias, DataTypeDatabaseType.Ntext)
{
Alias = "keywords", Name = "Keywords", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88
};
var authorAdded = advancedPage.AddPropertyType(authorPropertyType, "Content_");//Will be added to an ancestor tab
var descriptionAdded = advancedPage.AddPropertyType(descriptionPropertyType, "Contentx");//Will be added to a parent tab
var keywordsAdded = advancedPage.AddPropertyType(keywordsPropertyType, "Content");//Will be added to the "Content Meta" composition
service.Save(advancedPage);
//Change the name of the tab on the "root" content type 'page'.
var propertyGroup = page.PropertyGroups["Content_"];
page.PropertyGroups.Add(new PropertyGroup { Id = propertyGroup.Id, Name = "Content", SortOrder = 0 });
service.Save(page);
// Assert
Assert.That(compositionAdded, Is.True);
Assert.That(bodyTextAdded, Is.True);
Assert.That(subtitleAdded, Is.True);
Assert.That(authorAdded, Is.True);
Assert.That(descriptionAdded, Is.True);
Assert.That(keywordsAdded, Is.True);
Assert.DoesNotThrow(() => service.GetContentType("contentPage"));
Assert.DoesNotThrow(() => service.GetContentType("advancedPage"));
var advancedPageReloaded = service.GetContentType("advancedPage");
var contentUnderscoreTabExists = advancedPageReloaded.CompositionPropertyGroups.Any(x => x.Name.Equals("Content_"));
Assert.That(contentUnderscoreTabExists, Is.False);
var numberOfContentTabs = advancedPageReloaded.CompositionPropertyGroups.Count(x => x.Name.Equals("Content"));
Assert.That(numberOfContentTabs, Is.EqualTo(4));
}
[Test]
public void Can_Rename_PropertyGroup_On_Parent_Without_Causing_Duplicate_PropertyGroups_v2()
{
// Arrange
var service = ServiceContext.ContentTypeService;
var page = MockedContentTypes.CreateSimpleContentType("page", "Page", null, true, "Content_");
service.Save(page);
var contentPage = MockedContentTypes.CreateSimpleContentType("contentPage", "Content Page", page, true, "Content");
service.Save(contentPage);
var contentMetaComposition = MockedContentTypes.CreateContentMetaContentType();
service.Save(contentMetaComposition);
// Act
var bodyTextPropertyType = new PropertyType(Constants.PropertyEditors.TextboxAlias, DataTypeDatabaseType.Ntext)
{
Alias = "bodyText", Name = "Body Text", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88
};
var subtitlePropertyType = new PropertyType(Constants.PropertyEditors.TextboxAlias, DataTypeDatabaseType.Ntext)
{
Alias = "subtitle", Name = "Subtitle", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88
};
var authorPropertyType = new PropertyType(Constants.PropertyEditors.TextboxAlias, DataTypeDatabaseType.Ntext)
{
Alias = "author", Name = "Author", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88
};
var bodyTextAdded = page.AddPropertyType(bodyTextPropertyType, "Content_");
var subtitleAdded = contentPage.AddPropertyType(subtitlePropertyType, "Content");
var authorAdded = contentPage.AddPropertyType(authorPropertyType, "Content_");
service.Save(page);
service.Save(contentPage);
var compositionAdded = contentPage.AddContentType(contentMetaComposition);
service.Save(contentPage);
//Change the name of the tab on the "root" content type 'page'.
var propertyGroup = page.PropertyGroups["Content_"];
page.PropertyGroups.Add(new PropertyGroup { Id = propertyGroup.Id, Name = "Content", SortOrder = 0 });
service.Save(page);
// Assert
Assert.That(compositionAdded, Is.True);
Assert.That(bodyTextAdded, Is.True);
Assert.That(subtitleAdded, Is.True);
Assert.That(authorAdded, Is.True);
Assert.DoesNotThrow(() => service.GetContentType("contentPage"));
}
[Test]
public void Can_Remove_PropertyGroup_On_Parent_Without_Causing_Duplicate_PropertyGroups()
{
// Arrange
var service = ServiceContext.ContentTypeService;
var basePage = MockedContentTypes.CreateBasicContentType();
service.Save(basePage);
var contentPage = MockedContentTypes.CreateBasicContentType("contentPage", "Content Page", basePage);
service.Save(contentPage);
var advancedPage = MockedContentTypes.CreateBasicContentType("advancedPage", "Advanced Page", contentPage);
service.Save(advancedPage);
var contentMetaComposition = MockedContentTypes.CreateContentMetaContentType();
service.Save(contentMetaComposition);
// Act
var bodyTextPropertyType = new PropertyType(Constants.PropertyEditors.TextboxAlias, DataTypeDatabaseType.Ntext)
{
Alias = "bodyText", Name = "Body Text", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88
};
var bodyTextAdded = basePage.AddPropertyType(bodyTextPropertyType, "Content");
service.Save(basePage);
var authorPropertyType = new PropertyType(Constants.PropertyEditors.TextboxAlias, DataTypeDatabaseType.Ntext)
{
Alias = "author", Name = "Author", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88
};
var authorAdded = contentPage.AddPropertyType(authorPropertyType, "Content");
service.Save(contentPage);
var compositionAdded = contentPage.AddContentType(contentMetaComposition);
service.Save(contentPage);
basePage.RemovePropertyGroup("Content");
service.Save(basePage);
// Assert
Assert.That(bodyTextAdded, Is.True);
Assert.That(authorAdded, Is.True);
Assert.That(compositionAdded, Is.True);
Assert.DoesNotThrow(() => service.GetContentType("contentPage"));
Assert.DoesNotThrow(() => service.GetContentType("advancedPage"));
var contentType = service.GetContentType("contentPage");
var propertyGroup = contentType.PropertyGroups["Content"];
Assert.That(propertyGroup.ParentId.HasValue, Is.False);
}
[Test]
public void Can_Add_PropertyGroup_With_Same_Name_On_Parent_and_Child()
{
/*
* BasePage
* - Content Page
* -- Advanced Page
* Content Meta :: Composition
*/
// Arrange
var service = ServiceContext.ContentTypeService;
var basePage = MockedContentTypes.CreateBasicContentType();
service.Save(basePage);
var contentPage = MockedContentTypes.CreateBasicContentType("contentPage", "Content Page", basePage);
service.Save(contentPage);
var advancedPage = MockedContentTypes.CreateBasicContentType("advancedPage", "Advanced Page", contentPage);
service.Save(advancedPage);
var contentMetaComposition = MockedContentTypes.CreateContentMetaContentType();
service.Save(contentMetaComposition);
// Act
var authorPropertyType = new PropertyType(Constants.PropertyEditors.TextboxAlias, DataTypeDatabaseType.Ntext)
{
Alias = "author", Name = "Author", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88
};
var authorAdded = contentPage.AddPropertyType(authorPropertyType, "Content");
service.Save(contentPage);
var bodyTextPropertyType = new PropertyType(Constants.PropertyEditors.TextboxAlias, DataTypeDatabaseType.Ntext)
{
Alias = "bodyText", Name = "Body Text", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88
};
var bodyTextAdded = basePage.AddPropertyType(bodyTextPropertyType, "Content");
service.Save(basePage);
var compositionAdded = contentPage.AddContentType(contentMetaComposition);
service.Save(contentPage);
// Assert
Assert.That(bodyTextAdded, Is.True);
Assert.That(authorAdded, Is.True);
Assert.That(compositionAdded, Is.True);
Assert.DoesNotThrow(() => service.GetContentType("contentPage"));
Assert.DoesNotThrow(() => service.GetContentType("advancedPage"));
var contentType = service.GetContentType("contentPage");
var propertyGroup = contentType.PropertyGroups["Content"];
Assert.That(propertyGroup.ParentId.HasValue, Is.False);
var numberOfContentTabs = contentType.CompositionPropertyGroups.Count(x => x.Name.Equals("Content"));
Assert.That(numberOfContentTabs, Is.EqualTo(3));
//Ensure that adding a new PropertyType to the "Content"-tab also adds it to the right group
var descriptionPropertyType = new PropertyType(Constants.PropertyEditors.TextboxAlias, DataTypeDatabaseType.Ntext)
{
Alias = "description", Name = "Description", Description = "", HelpText = "", Mandatory = false, SortOrder = 1,DataTypeDefinitionId = -88
};
var descriptionAdded = contentType.AddPropertyType(descriptionPropertyType, "Content");
service.Save(contentType);
Assert.That(descriptionAdded, Is.True);
var contentPageReloaded = service.GetContentType("contentPage");
var propertyGroupReloaded = contentPageReloaded.PropertyGroups["Content"];
var hasDescriptionPropertyType = propertyGroupReloaded.PropertyTypes.Contains("description");
Assert.That(hasDescriptionPropertyType, Is.True);
Assert.That(propertyGroupReloaded.ParentId.HasValue, Is.False);
var descriptionPropertyTypeReloaded = propertyGroupReloaded.PropertyTypes["description"];
Assert.That(descriptionPropertyTypeReloaded.PropertyGroupId.IsValueCreated, Is.False);
}
private ContentType CreateComponent()
{
var component = new ContentType(-1)
@@ -487,9 +1251,10 @@ namespace Umbraco.Tests.Services
private ContentType CreateBannerComponent(ContentType parent)
{
var banner = new ContentType(parent)
const string contentTypeAlias = "banner";
var banner = new ContentType(parent, contentTypeAlias)
{
Alias = "banner",
Alias = contentTypeAlias,
Name = "Banner Component",
Description = "ContentType used for Banner Component",
Icon = ".sprTreeDoc3",
@@ -535,9 +1300,10 @@ namespace Umbraco.Tests.Services
private ContentType CreateHomepage(ContentType parent)
{
var contentType = new ContentType(parent)
const string contentTypeAlias = "homepage";
var contentType = new ContentType(parent, contentTypeAlias)
{
Alias = "homepage",
Alias = contentTypeAlias,
Name = "Homepage",
Description = "ContentType used for the Homepage",
Icon = ".sprTreeDoc3",
File diff suppressed because one or more lines are too long
@@ -196,6 +196,34 @@ namespace Umbraco.Tests.Services.Importing {
}
}
/// <summary>
/// Looks up a localized string similar to &lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;
///&lt;umbPackage&gt;
/// &lt;files&gt;
/// &lt;file&gt;
/// &lt;guid&gt;bootstrap.min.js&lt;/guid&gt;
/// &lt;orgPath&gt;/js&lt;/orgPath&gt;
/// &lt;orgName&gt;bootstrap.min.js&lt;/orgName&gt;
/// &lt;/file&gt;
/// &lt;file&gt;
/// &lt;guid&gt;jquery.min.js&lt;/guid&gt;
/// &lt;orgPath&gt;/js&lt;/orgPath&gt;
/// &lt;orgName&gt;jquery.min.js&lt;/orgName&gt;
/// &lt;/file&gt;
/// &lt;file&gt;
/// &lt;guid&gt;top-image.jpg&lt;/guid&gt;
/// &lt;orgPath&gt;/Media/1001&lt;/orgPath&gt;
/// &lt;orgName&gt;top-image.jpg&lt;/orgName&gt;
/// &lt;/file&gt;
/// &lt;file&gt;
/// &lt;guid&gt;top-im [rest of string was truncated]&quot;;.
/// </summary>
internal static string Fanoe_Package {
get {
return ResourceManager.GetString("Fanoe_Package", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to &lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;
///&lt;umbPackage&gt;
@@ -154,4 +154,7 @@
<data name="CompositionsTestPackage_Random" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>compositionstestpackage-random.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data>
<data name="Fanoe_Package" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>fanoe-package.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data>
</root>
@@ -211,6 +211,30 @@ namespace Umbraco.Tests.Services.Importing
Assert.That(templates.Any(), Is.True);
}
[Test]
public void PackagingService_Can_Import_Fanoe_Starterkit_ContentTypes_And_Templates_Xml()
{
// Arrange
string strXml = ImportResources.Fanoe_Package;
var xml = XElement.Parse(strXml);
var dataTypeElement = xml.Descendants("DataTypes").First();
var templateElement = xml.Descendants("Templates").First();
var docTypeElement = xml.Descendants("DocumentTypes").First();
// Act
var dataTypeDefinitions = ServiceContext.PackagingService.ImportDataTypeDefinitions(dataTypeElement);
var templates = ServiceContext.PackagingService.ImportTemplates(templateElement);
var contentTypes = ServiceContext.PackagingService.ImportContentTypes(docTypeElement);
var numberOfDocTypes = (from doc in docTypeElement.Elements("DocumentType") select doc).Count();
//Assert - Re-Import contenttypes doesn't throw
Assert.DoesNotThrow(() => ServiceContext.PackagingService.ImportContentTypes(docTypeElement));
Assert.That(contentTypes.Count(), Is.EqualTo(numberOfDocTypes));
Assert.That(dataTypeDefinitions, Is.Not.Null);
Assert.That(dataTypeDefinitions.Any(), Is.True);
Assert.That(templates.Any(), Is.True);
}
[Test]
public void PackagingService_Can_Import_Content_Package_Xml()
{
@@ -6,7 +6,25 @@ namespace Umbraco.Tests.TestHelpers.Entities
{
public class MockedContentTypes
{
public static ContentType CreateBasicContentType(string alias = "basePage", string name = "Base Page",
ContentType parent = null)
{
var contentType = parent == null ? new ContentType(-1) : new ContentType(parent, alias);
contentType.Alias = alias;
contentType.Name = name;
contentType.Description = "ContentType used for basic pages";
contentType.Icon = ".sprTreeDoc3";
contentType.Thumbnail = "doc2.png";
contentType.SortOrder = 1;
contentType.CreatorId = 0;
contentType.Trashed = false;
//ensure that nothing is marked as dirty
contentType.ResetDirtyProperties(false);
return contentType;
}
public static ContentType CreateTextpageContentType(string alias = "textPage", string name = "Text Page")
{
@@ -65,6 +83,57 @@ namespace Umbraco.Tests.TestHelpers.Entities
return contentType;
}
public static ContentType CreateContentMetaContentType()
{
var contentType = new ContentType(-1)
{
Alias = "contentMeta",
Name = "Content Meta",
Description = "ContentType used for Content Meta",
Icon = ".sprTreeDoc3",
Thumbnail = "doc.png",
SortOrder = 1,
CreatorId = 0,
Trashed = false
};
var metaCollection = new PropertyTypeCollection();
metaCollection.Add(new PropertyType("test", DataTypeDatabaseType.Ntext) { Alias = "title", Name = "Title", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88 });
contentType.PropertyGroups.Add(new PropertyGroup(metaCollection) { Name = "Content", SortOrder = 2 });
//ensure that nothing is marked as dirty
contentType.ResetDirtyProperties(false);
return contentType;
}
public static ContentType CreateSeoContentType()
{
var contentType = new ContentType(-1)
{
Alias = "seo",
Name = "Seo",
Description = "ContentType used for Seo",
Icon = ".sprTreeDoc3",
Thumbnail = "doc.png",
SortOrder = 1,
CreatorId = 0,
Trashed = false
};
var metaCollection = new PropertyTypeCollection();
metaCollection.Add(new PropertyType("seotest", DataTypeDatabaseType.Ntext) { Alias = "seokeywords", Name = "Seo Keywords", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88 });
metaCollection.Add(new PropertyType("seotest", DataTypeDatabaseType.Ntext) { Alias = "seodescription", Name = "Seo Description", Description = "", HelpText = "", Mandatory = false, SortOrder = 2, DataTypeDefinitionId = -89 });
contentType.PropertyGroups.Add(new PropertyGroup(metaCollection) { Name = "Seo", SortOrder = 5 });
//ensure that nothing is marked as dirty
contentType.ResetDirtyProperties(false);
return contentType;
}
public static ContentType CreateSimpleContentType()
{
var contentType = new ContentType(-1)
@@ -92,9 +161,9 @@ namespace Umbraco.Tests.TestHelpers.Entities
return contentType;
}
public static ContentType CreateSimpleContentType(string alias, string name, IContentType parent = null, bool randomizeAliases = false)
public static ContentType CreateSimpleContentType(string alias, string name, IContentType parent = null, bool randomizeAliases = false, string propertyGroupName = "Content")
{
var contentType = parent == null ? new ContentType(-1) : new ContentType(parent);
var contentType = parent == null ? new ContentType(-1) : new ContentType(parent, alias);
contentType.Alias = alias;
contentType.Name = name;
@@ -110,7 +179,7 @@ namespace Umbraco.Tests.TestHelpers.Entities
contentCollection.Add(new PropertyType(Constants.PropertyEditors.TinyMCEAlias, DataTypeDatabaseType.Ntext) { Alias = RandomAlias("bodyText", randomizeAliases), Name = "Body Text", Description = "", HelpText = "", Mandatory = false, SortOrder = 2, DataTypeDefinitionId = -87 });
contentCollection.Add(new PropertyType(Constants.PropertyEditors.TextboxAlias, DataTypeDatabaseType.Ntext) { Alias = RandomAlias("author", randomizeAliases) , Name = "Author", Description = "Name of the author", HelpText = "", Mandatory = false, SortOrder = 3, DataTypeDefinitionId = -88 });
contentType.PropertyGroups.Add(new PropertyGroup(contentCollection) { Name = "Content", SortOrder = 1 });
contentType.PropertyGroups.Add(new PropertyGroup(contentCollection) { Name = propertyGroupName, SortOrder = 1 });
//ensure that nothing is marked as dirty
contentType.ResetDirtyProperties(false);
@@ -167,6 +236,27 @@ namespace Umbraco.Tests.TestHelpers.Entities
return contentType;
}
public static ContentType CreateSimpleContentType(string alias, string name, PropertyTypeCollection collection, string propertyGroupName, IContentType parent = null)
{
var contentType = parent == null ? new ContentType(-1) : new ContentType(parent, alias);
contentType.Alias = alias;
contentType.Name = name;
contentType.Description = "ContentType used for simple text pages";
contentType.Icon = ".sprTreeDoc3";
contentType.Thumbnail = "doc2.png";
contentType.SortOrder = 1;
contentType.CreatorId = 0;
contentType.Trashed = false;
contentType.PropertyGroups.Add(new PropertyGroup(collection) { Name = propertyGroupName, SortOrder = 1 });
//ensure that nothing is marked as dirty
contentType.ResetDirtyProperties(false);
return contentType;
}
public static ContentType CreateSimpleContentType(string alias, string name, PropertyTypeCollection groupedCollection, PropertyTypeCollection nonGroupedCollection)
{
var contentType = CreateSimpleContentType(alias, name, groupedCollection);
+1
View File
@@ -697,6 +697,7 @@
<Content Include="Services\Importing\CompositionsTestPackage-Random.xml" />
<Content Include="Services\Importing\CompositionsTestPackage.xml" />
<Content Include="Services\Importing\Dictionary-Package.xml" />
<Content Include="Services\Importing\Fanoe-Package.xml" />
<Content Include="UmbracoExamine\TestFiles\media.xml" />
<Content Include="Services\Importing\InheritedDocTypes-Package.xml" />
<Content Include="Services\Importing\SingleDocType.xml" />
@@ -0,0 +1 @@
abbr,address,article,aside,audio,b,blockquote,body,canvas,caption,cite,code,dd,del,details,dfn,div,dl,dt,em,fieldset,figcaption,figure,footer,form,h1,h2,h3,h4,h5,h6,header,hgroup,html,i,iframe,img,ins,kbd,label,legend,li,mark,menu,nav,object,ol,p,pre,q,samp,section,small,span,strong,sub,summary,sup,table,tbody,td,tfoot,th,thead,time,tr,ul,var,video{margin:0;padding:0;outline:0;border:0;background:0 0;vertical-align:baseline;font-size:100%}article,aside,details,figcaption,figure,footer,header,hgroup,menu,nav,section{display:block}nav ul{list-style:none}blockquote,q{quotes:none}blockquote:after,blockquote:before,q:after,q:before{content:'';content:none}a{margin:0;padding:0;background:0 0;vertical-align:baseline;font-size:100%}ins{background-color:#ff9;color:#000;text-decoration:none}mark{background-color:#ff9;color:#000;font-weight:700;font-style:italic}del{text-decoration:line-through}abbr[title],dfn[title]{border-bottom:1px dotted;cursor:help}table{border-spacing:0;border-collapse:collapse}hr{display:block;margin:1em 0;padding:0;height:1px;border:0;border-top:1px solid #ccc}input,select{vertical-align:middle}html{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}*,:after,:before{box-sizing:border-box}body,html{height:100%;width:100%;color:#fff;font-family:'Open Sans',sans-serif;font-weight:400;font-size:.9375em;line-height:1.5}h1{font-size:1.7em;margin:40px auto 10px;font-weight:700}h2{font-size:1.35em;margin:0 auto .4em;font-weight:700}h3{font-size:1em;font-weight:400;font-style:italic}p{font-size:1em;line-height:1.6}p+a{margin-top:1rem;display:inline-block}a,a:active,a:visited{text-decoration:none}.cta{margin:4.5em auto 1.5em;padding-bottom:4.5em}.button,.button:visited{padding:.9375em 1.875em;border-radius:.1em;font-weight:600;font-size:1.2em;background:#2e99f4;color:#fff;display:inline-block;border:none;transition:all 200ms ease-in-out}.button:hover,.button:visited:hover{border-bottom:none;background:#0c80e3}section{background:url(../img/nonodesbg.jpg) center center/cover;height:100%;width:100%;display:table;padding:3em 1.75em}section a,section a:focus,section a:visited{color:#46a5f5;font-size:1.1625em;border-bottom:1px solid transparent;transition:border-bottom 100ms ease-in-out}section a:focus:hover,section a:hover,section a:visited:hover{border-bottom:1px solid}section:after{content:"";position:absolute;top:0;right:0;bottom:0;left:0;background:rgba(0,0,0,.17);background:linear-gradient(45deg,rgba(85,98,112,.1) 10%,rgba(255,107,107,.1) 95%);z-index:0}section article{display:table-cell;vertical-align:middle;margin:0 auto;text-align:center;position:relative;z-index:100}section article>div{max-width:60em;margin:0 auto}section .logo{background:url(../img/logo.png) no-repeat;width:91px;height:91px;margin:0 auto}section .row{overflow:hidden}section .row .col{text-align:left;width:100%}section .row .col:nth-child(2){margin-top:3em}@media screen and (min-width:48em){body,html{font-size:1em}h1{font-size:2.5em;margin:70px auto 0;letter-spacing:.5px}h2{font-size:1.4375em;margin:0 auto 1em}h3{font-size:1.2em}a{font-size:1.1rem;font-weight:600}p+a{margin-top:3rem}.cta{margin:7.5em auto 2.5em;border-bottom:1px solid rgba(255,255,255,.5);padding-bottom:7.5em}section{padding:0 15px}section .row .col{float:left;width:50%;padding-right:5%;display:inline-block}section .row .col:nth-child(2){padding-right:0;padding-left:5%;margin-top:0}.button{font-size:1.1625em}}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 116 KiB

After

Width:  |  Height:  |  Size: 685 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 309 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 232 KiB

@@ -18,8 +18,8 @@ angular.module("umbraco.directives")
element.bind('blur', function(){ update(true); });
$timeout(function() {
update();
}, 100);
update(true);
}, 200);
//I hate bootstrap tabs
@@ -33,6 +33,14 @@ angular.module("umbraco.directives.html")
else {
scope.labelstring = scope.label;
}
if (scope.description && scope.description[0] === "@") {
scope.descriptionstring = localizationService.localize(scope.description.substring(1));
}
else {
scope.descriptionstring = scope.description;
}
}
};
});
@@ -0,0 +1,25 @@
/**
* @ngdoc directive
* @name umbraco.directives.directive:preventEnterSubmit
* @description prevents a form from submitting when the enter key is pressed on an input field
**/
angular.module("umbraco.directives")
.directive('preventEnterSubmit', function() {
return function(scope, element, attrs) {
var enabled = true;
//check if there's a value for the attribute, if there is and it's false then we conditionally don't
//prevent default.
if (attrs.preventEnterSubmit) {
attrs.$observe("preventEnterSubmit", function (newVal) {
enabled = (newVal === "false" || newVal === 0 || newVal === false) ? false : true;
});
}
$(element).keypress(function (event) {
if (event.which === 13) {
event.preventDefault();
}
});
};
});
@@ -31,7 +31,10 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, notifica
var deferred = $q.defer();
if (formHelper.submitForm({ scope: args.scope, statusMessage: args.statusMessage })) {
if (!args.scope.busy && formHelper.submitForm({ scope: args.scope, statusMessage: args.statusMessage })) {
args.scope.busy = true;
args.saveMethod(args.content, $routeParams.create, fileManager.getFiles())
.then(function (data) {
@@ -42,6 +45,8 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, notifica
savedContent: data,
rebindCallback: self.reBindChangedProperties(args.content, data)
});
args.scope.busy = false;
deferred.resolve(data);
}, function (err) {
@@ -50,6 +55,7 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, notifica
err: err,
rebindCallback: self.reBindChangedProperties(args.content, err.data)
});
args.scope.busy = false;
deferred.reject(err);
});
}
@@ -32,6 +32,7 @@
ng-pattern="passwordPattern"
autocorrect="off"
autocapitalize="off"
autocomplete="off"
required
ng-model="installer.current.model.password" id="password" />
<small class="inline-help">At least {{installer.current.model.minCharLength}} characters long</small>
@@ -5,7 +5,7 @@
overflow-y:hidden!important;
}
IFRAME {overflow:hidden;}
IFRAME {overflow:hidden;}
// Sortabel
@@ -500,7 +500,7 @@
.usky-grid .usky-templates-columns{
margin-top: 30px;
}
.usky-grid .usky-row-inner{
margin-right: 45px;
border: 1px dashed transparent;
@@ -598,7 +598,7 @@
-moz-box-sizing: border-box;
box-sizing: border-box;
width: 125px;
margin: 35px 40px 15px 0;
margin: 35px 40px 15px 0;
border: 2px solid @grayLight; /* @grayLight */
transition: border 200ms linear;
@@ -618,7 +618,7 @@
border-color: @blue;
cursor: pointer;
}
.preview-row {
display: inline-block;
width: 100%;
@@ -627,7 +627,6 @@
}
.preview-rows.layout {
height: 180px;
padding: 2px;
.preview-row {
@@ -635,7 +634,7 @@
}
.preview-col {
height: 100%;
height: 180px;
border: dashed 1px @grayLight;
}
@@ -806,7 +805,7 @@
}
.usky-grid-configuration .uSky-templates-column.last{
margin-right: -1px;
margin-right: -1px;
}
.usky-grid-configuration .uSky-templates-column.add{
@@ -12,16 +12,13 @@ function ContentEditDialogController($scope, editorState, $routeParams, $q, $tim
scope: $scope,
content: $scope.content
}).then(function (content) {
//success
$scope.busy = false;
//success
if (dialogOptions.closeOnSave) {
$scope.submit(content);
}
}, function(err) {
//error
$scope.busy = false;
});
}
@@ -73,13 +73,11 @@ function ContentEditController($scope, $rootScope, $routeParams, $q, $timeout, $
scope: $scope,
content: $scope.content
}).then(function (data) {
//success
$scope.busy = false;
//success
init($scope.content);
syncTreeNode($scope.content, data.path);
}, function (err) {
//error
$scope.busy = false;
if (err) {
editorState.set($scope.content);
}
@@ -17,8 +17,7 @@ function startUpVideosDashboardController($scope, xmlhelper, $log, $http) {
angular.module("umbraco").controller("Umbraco.Dashboard.StartupVideosController", startUpVideosDashboardController);
function FormsController($scope, $route, packageResource) {
function FormsController($scope, $route, $cookieStore, packageResource) {
$scope.installForms = function(){
$scope.state = "Installng package";
packageResource
@@ -44,9 +43,8 @@ function FormsController($scope, $route, packageResource) {
$scope.complete = function(result){
var url = window.location.href + "?init=true";
window.location.href = url;
//window.location.reload();
$cookieStore.put("umbPackageInstallId", result.packageGuid);
window.location.reload(true);
};
$scope.error = function(err){
@@ -19,7 +19,6 @@
<p style="font-size: 16px; line-height: 1.5; color: #4c4c4c;">Create forms using an intuitive drag and drop interface. From simple contact forms that sends e-mails to advanced questionaires that integrate with CRM systems. Your clients will love it!</p>
<button class="btn publish btn-install" ng-click="installForms()">Install</button>
<small>Preview version should not be used in production</small>
</div>
<div class="step-two" ng-if="state"> <!-- STEP two -->
@@ -3,7 +3,7 @@
<div class="umb-el-wrap">
<label ng-if="hideLabel!=='true'" class="control-label" for="{{alias}}">
{{labelstring}}
<small>{{description}}</small>
<small>{{descriptionstring}}</small>
</label>
<div class="controls controls-row" ng-transclude>
@@ -11,14 +11,12 @@ angular.module("umbraco")
macroData: $scope.control.value
},
callback: function (data) {
$scope.control.value = {
syntax: data.syntax,
macroAlias: data.macroAlias,
macroParamsDictionary: data.macroParamsDictionary
};
$scope.setPreview(data);
$scope.setPreview($scope.control.value );
}
});
};
@@ -40,8 +38,7 @@ angular.module("umbraco")
if($scope.control.$initializing){
$scope.setMacro();
}else if($scope.control.value){
var parsed = macroService.parseMacroSyntax($scope.control.value.syntax);
$scope.setPreview(parsed);
$scope.setPreview($scope.control.value);
}
}, 200);
});
@@ -1,4 +1,4 @@
<div ng-controller="Umbraco.PropertyEditors.Grid.TextStringController">
<div>
<textarea
rows="1"
umb-auto-resize
@@ -149,6 +149,9 @@ angular.module("umbraco")
return ((spans / $scope.model.value.columns) * 100).toFixed(1);
};
$scope.zeroWidthFilter = function (cell) {
return cell.grid > 0;
};
/****************
Config
@@ -12,17 +12,17 @@
<li ng-repeat="template in model.value.templates">
<div ng-click="configureTemplate(template)"
class="preview-rows layout" style="height: 60px; margin-top: 5px; margin-bottom: 20px; float:left">
class="preview-rows layout" style="margin-top: 5px; margin-bottom: 20px; float:left">
<div class="preview-row">
<div class="preview-col"
ng-class="{last:$last}"
ng-repeat="section in template.sections"
ng-style="{width: percentage(section.grid) + '%'}">
ng-repeat="section in template.sections | filter:zeroWidthFilter"
ng-style="{width: percentage(section.grid) + '%', height: '60px'}">
<div class="preview-cell"></div>
</div>
</div>
</div>
</div>
<div>
{{template.name}} <br/>
@@ -57,25 +57,25 @@
<li ng-repeat="layout in model.value.layouts">
<div ng-click="configureLayout(layout)"
<div ng-click="configureLayout(layout)"
class="preview-rows columns" style="margin-top: 5px; margin-bottom: 25px; float:left">
<div class="preview-row">
<div class="preview-col"
ng-class="{last:$last}"
ng-repeat="area in layout.areas"
ng-repeat="area in layout.areas | filter:zeroWidthFilter"
ng-style="{width: percentage(area.grid) + '%'}">
<div class="preview-cell"></div>
</div>
</div>
</div>
</div>
<div>
{{layout.name}}<br />
<i class="icon-delete red"></i>
<a class="btn btn-small btn-link" href ng-click="deleteLayout($index)">
<localize key="general_delete" />
<localize key="general_delete" />
</a>
</div>
@@ -95,13 +95,13 @@
<div style="max-width: 600px">
<umb-control-group
label="@grid_columns"
<umb-control-group
label="@grid_columns"
description="@grid_columnsDetails">
<input type="text" class="" ng-model="model.value.columns" />
</umb-control-group>
<umb-control-group
<umb-control-group
label="@grid_settings"
description="@grid_settingsDetails">
@@ -64,7 +64,7 @@
<td>
<form class="pull-right" novalidate>
<i class="icon-search" ng-click="enterSearch($event)"></i>
<input type="text" ng-model="options.filter" on-keyup="search()" no-dirty-check>
<input type="text" ng-model="options.filter" on-keyup="search()" prevent-enter-submit no-dirty-check>
</form>
</td>
</tr>
+2 -2
View File
@@ -2542,9 +2542,9 @@ xcopy "$(ProjectDir)"..\packages\SqlServerCE.4.0.0.0\x86\*.* "$(TargetDir)x86\"
<WebProjectProperties>
<UseIIS>True</UseIIS>
<AutoAssignPort>True</AutoAssignPort>
<DevelopmentServerPort>7200</DevelopmentServerPort>
<DevelopmentServerPort>7210</DevelopmentServerPort>
<DevelopmentServerVPath>/</DevelopmentServerVPath>
<IISUrl>http://localhost:7200</IISUrl>
<IISUrl>http://localhost:7210</IISUrl>
<NTLMAuthentication>False</NTLMAuthentication>
<UseCustomServer>False</UseCustomServer>
<CustomServerUrl>
+48 -129
View File
@@ -2,148 +2,67 @@
<%@ Import Namespace="Umbraco.Core.Configuration" %>
<%@ Import Namespace="Umbraco.Core.IO" %>
<!DOCTYPE html>
<html>
<head runat="server">
<!doctype html>
<!--[if lt IE 7]> <html class="no-js ie6 oldie" lang="en"> <![endif]-->
<!--[if IE 7]> <html class="no-js ie7 oldie" lang="en"> <![endif]-->
<!--[if IE 8]> <html class="no-js ie8 oldie" lang="en"> <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js" lang="en"> <!--<![endif]-->
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title></title>
<meta name="description" content="">
<meta name="author" content="">
<meta charset="utf-8">
<link href='//fonts.googleapis.com/css?family=Open+Sans:300,400,700,600' rel='stylesheet' type='text/css'>
<link href='//fonts.googleapis.com/css?family=Asap:400,700,400italic,700italic' rel='stylesheet' type='text/css'>
<title>Umbraco - no pages found</title>
<link rel="icon" type="image/png" href="<%=umbraco.GlobalSettings.Path + "/Images/PinnedIcons/umb.ico" %>" />
<link rel="stylesheet" href="../../Umbraco/assets/css/nonodes.style.min.css" />
<link media="all" rel="stylesheet" href="../../umbraco_client/installer/css/jquery-ui-1.8.6.custom.css" />
<!--[if lt IE 9]>
<script src="//cdnjs.cloudflare.com/ajax/libs/modernizr/2.7.1/modernizr.min.js"></script>
<![endif]-->
<link media="all" type="text/css" rel="stylesheet" href="../../umbraco_client/installer/css/reset.css" />
<link media="all" rel="stylesheet" href="../../umbraco_client/installer/css/all.css" />
<link media="all" type="text/css" rel="stylesheet" href="../../umbraco_client/installer/css/form.css" />
<script src="../../umbraco_client/installer/js/jquery.1.4.4.js" type="text/javascript"></script>
<script src="../../umbraco_client/installer/js/jquery.ui.selectmenu.js" type="text/javascript"></script>
<script src="../../umbraco_client/installer/js/jquery.main.js" type="text/javascript"></script>
<script src="../../umbraco_client/passwordStrength/passwordstrength.js" type="text/javascript"></script>
<!--[if lt IE 9]>
<link media="all" rel="stylesheet" href="../../umbraco_client/installer/css/lt7.css" />
<script src="//html5shim.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<!--[if lt IE 7]><script type="text/javascript" src="../../umbraco_client/installer/js/ie-png.js"></script><![endif]-->
</head>
<body class="theend">
<form id="Form1" method="post" runat="server">
<body>
<!-- all page -->
<section>
<article>
<div>
<div class="logo"></div>
<section id="wrapper">
<h1>Welcome to your Umbraco installation</h1>
<h3>You're seeing the wonderful page because your website doesn't contain any published content yet.</h3>
<div class="wholder">
<div class="cta">
<a href="<%= IOHelper.ResolveUrl(SystemDirectories.Umbraco) %>" class="button">Open Umbraco</a>
</div>
<!-- header -->
<header id="header">
<div class="holder">
<strong class="logo"><a href="#">Umbraco</a></strong>
</div>
</header>
<div class="row">
<div class="col">
<h2>Easy start with Umbraco.tv</h2>
<p>We have created a bunch of 'how-to' videos, to get you easily started with Umbraco. Learn how to build projects in just a couple of minutes. Easiest CMS in the world.</p>
<a href="http://umbraco.tv?ref=tvFromInstaller" target="_blank">Umbraco.tv &rarr;</a>
</div>
<!-- all content -->
<div class="col">
<h2>Be a part of the community</h2>
<p>The Umbraco community is the best of its kind, be sure to visit, and if you have any questions, were sure that you can get your answers from the community.</p>
<a href="http://our.umbraco.org?ref=ourFromInstaller" target="_blank">our.Umbraco &rarr;</a>
</div>
</div>
<section id="main">
<!-- content -->
</div>
</article>
<section class="content">
</section>
<script type="text/javascript">
jQuery(document).ready(function () {
$.post("../../install/InstallerRestService.aspx?feed=sitebuildervids",
function(data) {
jQuery("#ajax-sitebuildervids").html(data);
});
<script src="//code.jquery.com/jquery-latest.min.js"></script>
$.post("../../install/InstallerRestService.aspx?feed=developervids",
function(data) {
jQuery("#ajax-developervids").html(data);
});
});
</script>
<!-- done box -->
<div class="tab main-tabinfo">
<div class="container">
<h1>Looks like there's still work to do</h1>
<p>
You're seeing the wonderful page because your website doesn't contain any <strong>published</strong> content yet.
</p>
<p>
So get rid of this page by starting umbraco and publishing some content. You can do this by clicking the "set up your new website" button below.
</p>
<ul class="btn-web">
<li class="btn-set"><a href="<%= IOHelper.ResolveUrl(SystemDirectories.Umbraco) %>"><span>Launch umbraco</span></a></li>
</ul>
</div>
<div class="threcol">
<div class="t">
&nbsp;
</div>
<div class="hold">
<aside class="col1">
<h2>Useful links</h2>
<p>Weve put together some useful links to help you get started with Umbraco.</p>
<nav class="links">
<ul>
<li><a href="http://our.umbraco.org?ref=ourFromInstaller">our.umbraco.org</a></li>
</ul>
<ul>
<li><a href="http://our.umbraco.org/wiki?ref=LatestDocsFromInstaller">New documentation</a></li>
<li><a href="http://our.umbraco.org/projects?ref=LatestProjectsFromInstaller">New Projects</a></li>
<li><a href="http://our.umbraco.org/forum?ref=LatesTalkFromInstaller">Forum Talk</a></li>
</ul>
</nav>
</aside>
<aside class="col2">
<h2>Sitebuilder introduction</h2>
<div id="ajax-sitebuildervids"><small>Loading...</small></div>
</aside>
<aside class="col3">
<h2>Developer introduction</h2>
<div id="ajax-developervids"><small>Loading...</small></div>
</aside>
</div>
</div>
</div>
</section>
</section>
</div>
</section>
<!-- bg page -->
<div class="bg-main">
<div class="color2">
<div class="bg-c"></div>
</div>
<div class="color3">
<div class="bg-c"></div>
</div>
<div class="color1">
<div class="bg-c"></div>
</div>
<div class="color4">
<div class="bg-c"></div>
</div>
<div class="color5">
<div class="bg-c"></div>
</div>
</div>
</form>
</body>
</html>
</html>
@@ -45,7 +45,7 @@
<MacroErrors>inline</MacroErrors>
<!-- These file types will not be allowed to be uploaded via the upload control for media and content -->
<disallowedUploadFiles>ashx,aspx,ascx,config,cshtml,vbhtml,asmx,air,axd,swf,xml,html.htm,svg,php,htaccess</disallowedUploadFiles>
<disallowedUploadFiles>ashx,aspx,ascx,config,cshtml,vbhtml,asmx,air,axd,swf,xml,html,htm,svg,php,htaccess</disallowedUploadFiles>
<!-- Defines the default document type property used when adding properties in the back-office (if missing or empty, defaults to Textstring -->
<defaultDocumentTypeProperty>Textstring</defaultDocumentTypeProperty>
@@ -98,7 +98,7 @@
<MacroErrors>throw</MacroErrors>
<!-- These file types will not be allowed to be uploaded via the upload control for media and content -->
<disallowedUploadFiles>ashx,aspx,ascx,config,cshtml,vbhtml,asmx,air,axd,swf,xml,html.htm,svg,php,htaccess</disallowedUploadFiles>
<disallowedUploadFiles>ashx,aspx,ascx,config,cshtml,vbhtml,asmx,air,axd,swf,xml,html,htm,svg,php,htaccess</disallowedUploadFiles>
<!-- Defines the default document type property used when adding properties in the back-office (if missing or empty, defaults to Textstring -->
<defaultDocumentTypeProperty>Textstring</defaultDocumentTypeProperty>
@@ -130,7 +130,7 @@
<create assembly="umbraco" type="MediaTypeTasks" />
<delete assembly="umbraco" type="MediaTypeTasks" />
</tasks>
</nodeType>
</nodeType>
<nodeType alias="initmember">
<header>member</header>
<usercontrol>/create/member.ascx</usercontrol>
@@ -324,7 +324,7 @@
</nodeType>
<nodeType alias="partialViews">
<header>Macro</header>
<usercontrol>/Create/PartialView.ascx</usercontrol>
<usercontrol>/Create/PartialView.ascx</usercontrol>
<tasks>
<create assembly="umbraco" type="PartialViewTasks" />
<delete assembly="umbraco" type="PartialViewTasks" />
@@ -338,4 +338,20 @@
<delete assembly="umbraco" type="PartialViewMacroTasks" />
</tasks>
</nodeType>
<nodeType alias="partialViewsFolder">
<header>Macro</header>
<usercontrol>/Create/PartialView.ascx</usercontrol>
<tasks>
<create assembly="umbraco" type="PartialViewTasks" />
<delete assembly="umbraco" type="PartialViewTasks" />
</tasks>
</nodeType>
<nodeType alias="partialViewMacrosFolder">
<header>Macro</header>
<usercontrol>/Create/PartialViewMacro.ascx</usercontrol>
<tasks>
<create assembly="umbraco" type="PartialViewMacroTasks" />
<delete assembly="umbraco" type="PartialViewMacroTasks" />
</tasks>
</nodeType>
</createUI>
@@ -330,14 +330,6 @@
<delete assembly="umbraco" type="PartialViewTasks" />
</tasks>
</nodeType>
<nodeType alias="partialViewsFolder">
<header>Macro</header>
<usercontrol>/Create/PartialView.ascx</usercontrol>
<tasks>
<create assembly="umbraco" type="PartialViewTasks" />
<delete assembly="umbraco" type="PartialViewTasks" />
</tasks>
</nodeType>
<nodeType alias="partialViewMacros">
<header>Macro</header>
<usercontrol>/Create/PartialViewMacro.ascx</usercontrol>
@@ -346,6 +338,14 @@
<delete assembly="umbraco" type="PartialViewMacroTasks" />
</tasks>
</nodeType>
<nodeType alias="partialViewsFolder">
<header>Macro</header>
<usercontrol>/Create/PartialView.ascx</usercontrol>
<tasks>
<create assembly="umbraco" type="PartialViewTasks" />
<delete assembly="umbraco" type="PartialViewTasks" />
</tasks>
</nodeType>
<nodeType alias="partialViewMacrosFolder">
<header>Macro</header>
<usercontrol>/Create/PartialViewMacro.ascx</usercontrol>
@@ -410,9 +410,9 @@
<key alias="searchResults">Search results</key>
</area>
<area alias="graphicheadline">
<key alias="backgroundcolor">Background color</key>
<key alias="backgroundcolor">Background colour</key>
<key alias="bold">Bold</key>
<key alias="color">Text color</key>
<key alias="color">Text colour</key>
<key alias="font">Font</key>
<key alias="text">Text</key>
</area>
@@ -702,7 +702,7 @@ To manage your website, simply open the Umbraco back office and start adding con
]]></key>
</area>
<area alias="colorpicker">
<key alias="noColors">You have not configured any approved colors</key>
<key alias="noColors">You have not configured any approved colours</key>
</area>
<area alias="relatedlinks">
<key alias="addExternal">Add external link</key>
@@ -854,6 +854,36 @@ To manage your website, simply open the Umbraco back office and start adding con
<key alias="quickGuide">Quick Guide to Umbraco template tags</key>
<key alias="template">Template</key>
</area>
<area alias="grid">
<key alias="insertControl">Insert control</key>
<key alias="addRows">Add rows to your layout</key>
<key alias="addElement"><![CDATA[To start, click the <i class="icon icon-add blue"></i> below and add your first element]]></key>
<key alias="gridLayouts">Grid layouts</key>
<key alias="gridLayoutsDetail">Layouts are the overall work area for the grid editor, usually you only need one or two differnt layouts</key>
<key alias="addGridLayout">Add grid layout</key>
<key alias="addGridLayoutDetail">Adjust the layout by setting column widths and adding additional sections</key>
<key alias="rowConfigurations">Row configurations</key>
<key alias="rowConfigurationsDetail">Rows are predefined cells arranged horizontally</key>
<key alias="addRowConfiguration">Add row configuration</key>
<key alias="addRowConfigurationDetail">Adjust the row by setting cell widths and adding additional cells</key>
<key alias="columns">Columns</key>
<key alias="columnsDetails">Total combined number of columns in the grid layout</key>
<key alias="settings">Settings</key>
<key alias="settingsDetails">Configure what settings editors can change</key>
<key alias="styles">Styles</key>
<key alias="stylesDetails">Configure what styling editors can change</key>
<key alias="settingDialogDetails">Settings will only save if the entered json configuration is valid</key>
<key alias="allowAllEditors">Allow all editors</key>
<key alias="allowAllRowConfigurations">Allow all row configurations</key>
</area>
<area alias="templateEditor">
<key alias="alternativeField">Alternative field</key>
<key alias="alternativeText">Alternative Text</key>
+67 -65
View File
@@ -35,15 +35,15 @@
<key alias="toPublish">Enviar a publicación</key>
<key alias="translate">Traducir</key>
<key alias="update">Actualizar</key>
<key alias="defaultValue">Default value</key>
<key alias="defaultValue">Valor por defecto</key>
</area>
<area alias="assignDomain">
<key alias="permissionDenied">Permission denied.</key>
<key alias="permissionDenied">Permiso denegado.</key>
<key alias="addNew">Añadir nuevo dominio</key>
<key alias="remove">remove</key>
<key alias="invalidNode">Invalid node.</key>
<key alias="invalidDomain">Invalid domain format.</key>
<key alias="duplicateDomain">Domain has already been assigned.</key>
<key alias="remove">quitar</key>
<key alias="invalidNode">Nodo no válido.</key>
<key alias="invalidDomain">Formato de dominio no válido.</key>
<key alias="duplicateDomain">Este dominio ya ha sido asignado.</key>
<key alias="language">Language</key>
<key alias="domain">Dominio</key>
<key alias="domainCreated">El nuevo dominio %0% ha sido creado</key>
@@ -52,15 +52,14 @@
<key alias="domainUpdated">El dominio %0% ha sido actualizado</key>
<key alias="orEdit">Editar dominios actuales</key>
<key alias="domainHelp">
<![CDATA[Valid domain names are: "example.com", "www.example.com", "example.com:8080" or
"https://www.example.com/".<br /><br />One-level paths in domains are supported, eg. "example.com/en". However, they
should be avoided. Better use the culture setting above.]]>
<![CDATA[p.ej.: "tudominio.com", "www.tudominio.com", "tudominio.com:8080" o
"https://www.tudominio.com/".<br /><br />Los dominios de un nivel están soportados, por ej. "example.com/en". De todas formas deberían de evitarse. Mejor usar la configuración cultural especificada arriba.]]>
</key>
<key alias="inherit">Inherit</key>
<key alias="setLanguage">Culture</key>
<key alias="inherit">Heredar</key>
<key alias="setLanguage">Cultura</key>
<key alias="setLanguageHelp">
<![CDATA[Set the culture for nodes below the current node,<br /> or inherit culture from parent nodes. Will also apply<br />
to the current node, unless a domain below applies too.]]>
<![CDATA[Configura la cultura para los nodos por debajo del nodo actual,<br /> o hereda la cultura de los nodos padres. También se aplicará<br />
para el nodo actual, a menos que un dominio por debajo lo aplique también.]]>
</key>
<key alias="setDomains">Domains</key>
</area>
@@ -68,9 +67,9 @@
<key alias="atViewingFor">Visualización de</key>
</area>
<area alias="buttons">
<key alias="select">Select</key>
<key alias="selectCurrentFolder">Select current folder</key>
<key alias="somethingElse">Do something else</key>
<key alias="select">Seleccionar</key>
<key alias="selectCurrentFolder">Selecciona la carpeta actual</key>
<key alias="somethingElse">Hacer otra cosa</key>
<key alias="bold">Negrita</key>
<key alias="deindent">Cancelar Sangría del Párrafo </key>
<key alias="formFieldInsert">Insertar campo de formulario</key>
@@ -92,30 +91,30 @@
<key alias="saveAndPublish">Guardar y publicar</key>
<key alias="saveToPublish">Guardar y enviar para aprobación</key>
<key alias="showPage">Previsualizar</key>
<key alias="showPageDisabled">Preview is disabled because there's no template assigned</key>
<key alias="showPageDisabled">La previsualización está deshabilitada porque no hay ninguna plantilla asignada</key>
<key alias="styleChoose">Elegir estilo</key>
<key alias="styleShow">Mostrar estilos</key>
<key alias="tableInsert">Insertar tabla</key>
</area>
<area alias="changeDocType">
<key alias="changeDocTypeInstruction">To change the document type for the selected content, first select from the list of valid types for this location.</key>
<key alias="changeDocTypeInstruction2">Then confirm and/or amend the mapping of properties from the current type to the new, and click Save.</key>
<key alias="contentRepublished">The content has been re-published.</key>
<key alias="currentProperty">Current Property</key>
<key alias="currentType">Current type</key>
<key alias="docTypeCannotBeChanged">The document type cannot be changed, as there are no alternatives valid for this location.</key>
<key alias="docTypeChanged">Document Type Changed</key>
<key alias="mapProperties">Map Properties</key>
<key alias="mapToProperty">Map to Property</key>
<key alias="newTemplate">New Template</key>
<key alias="newType">New Type</key>
<key alias="none">none</key>
<key alias="selectedContent">Content</key>
<key alias="selectNewDocType">Select New Document Type</key>
<key alias="successMessage">The document type of the selected content has been successfully changed to [new type] and the following properties mapped:</key>
<key alias="to">to</key>
<key alias="validationErrorPropertyWithMoreThanOneMapping">Could not complete property mapping as one or more properties have more than one mapping defined.</key>
<key alias="validDocTypesNote">Only alternate types valid for the current location are displayed.</key>
<key alias="changeDocTypeInstruction">Para cambiar el tipo de documento al contenido seleccionado, primero selecciona uno de la lista de tipos válidos.</key>
<key alias="changeDocTypeInstruction2">Entonces confirma el mapeo de propiedades del tipo actual al nuevo y haz click en Guardar.</key>
<key alias="contentRepublished">El contenido se ha vuelto a publicar.</key>
<key alias="currentProperty">Propiedad actual</key>
<key alias="currentType">Tipo actual</key>
<key alias="docTypeCannotBeChanged">El tipo de contenido no se puede cambiar, porque no hay alternativas válidas para este contenido.</key>
<key alias="docTypeChanged">Tipo de documento cambiado</key>
<key alias="mapProperties">Mapeo de propiedades</key>
<key alias="mapToProperty">Mapea a la propiedad</key>
<key alias="newTemplate">Nueva plantilla</key>
<key alias="newType">Nuevo tipo</key>
<key alias="none">ninguno</key>
<key alias="selectedContent">Contenido</key>
<key alias="selectNewDocType">Selecciona un nuevo Tipo de Documento</key>
<key alias="successMessage">El tipo de documento del contenido seleccionado ha sido cambiado correctamente a [new type] y las siguientes propiedades mapeadas:</key>
<key alias="to">a</key>
<key alias="validationErrorPropertyWithMoreThanOneMapping">No se ha podido completar el mapeo de propiedades porque uno o más propiedades tienen más de un mapeo definido.</key>
<key alias="validDocTypesNote">Solo se muestran otros tipos válidos para el contenido actual.</key>
</area>
<area alias="content">
<key alias="about">Acerca de</key>
@@ -142,7 +141,7 @@
<key alias="nodeName">Título de la página</key>
<key alias="otherElements">Propiedades</key>
<key alias="parentNotPublished">Este documento ha sido publicado pero no es visible porque el padre '%0%' no esta publicado</key>
<key alias="parentNotPublishedAnomaly">Oops: this document is published but is not in the cache (internal error)</key>
<key alias="parentNotPublishedAnomaly">Upss: este documento está publicado pero no está en la caché (error interno)</key>
<key alias="publish">Publicar</key>
<key alias="publishStatus">Estado de la Publicación</key>
<key alias="releaseDate">Publicar el</key>
@@ -158,21 +157,21 @@
<key alias="updateDateDesc" version="7.0">Fecha/hora este documento fue modificado</key>
<key alias="uploadClear">Eliminar archivo</key>
<key alias="urls">Vínculo al documento</key>
<key alias="memberof">Member of group(s)</key>
<key alias="notmemberof">Not a member of group(s)</key>
<key alias="childItems" version="7.0">Child items</key>
<key alias="memberof">Miembro de grupo(s)</key>
<key alias="notmemberof">No es miembreo de grupo(s)</key>
<key alias="childItems" version="7.0">Nodos hijo</key>
<key alias="target" version="7.0">Target</key>
</area>
<area alias="media">
<key alias="clickToUpload">Click to upload</key>
<key alias="dropFilesHere">Drop your files here...</key>
<key alias="clickToUpload">Haz click para subir archivos</key>
<key alias="dropFilesHere">Arrastra los archivos aquí...</key>
</area>
<area alias="create">
<key alias="chooseNode">¿Dónde quieres crear el nuevo %0%</key>
<key alias="createUnder">Crear debajo de</key>
<key alias="updateData">Elije un tipo y un título</key>
<key alias="noDocumentTypes" version="7.0"><![CDATA[There are no allowed document types available. You must enable these in the settings section under <strong>"document types"</strong>.]]></key>
<key alias="noMediaTypes" version="7.0"><![CDATA[There are no allowed media types available. You must enable these in the settings section under <strong>"media types"</strong>.]]></key>
<key alias="noDocumentTypes" version="7.0"><![CDATA[No hay disponibles tipos de documentos permitidos. Debes habilitarlos en la sección "Ajustes" en <strong>"Tipos de documentos"</strong>.]]></key>
<key alias="noMediaTypes" version="7.0"><![CDATA[No hay disponibles tipos de medios permitidos. Debes habilitarlos en la sección "Ajustes" en <strong>"Tipos de medios"</strong>.]]></key>
</area>
<area alias="dashboard">
<key alias="browser">Navega en tu sitio Web</key>
@@ -235,23 +234,23 @@
]]></key>
</area>
<area alias="placeholders">
<key alias="username">Introduzca su nombre de usuario</key>
<key alias="password">Introduzca su contraseña</key>
<key alias="nameentity">Nombre de %0%...</key>
<key alias="entername">Introduzca un nombre ...</key>
<key alias="search">Buscar ...</key>
<key alias="filter">Filtrar ...</key>
<key alias="username">Escribe tu nombre de usuario</key>
<key alias="password">Escribe tu contraseña</key>
<key alias="nameentity">Nombre del %0%...</key>
<key alias="entername">Escribe un nombre...</key>
<key alias="search">Escribe tu búsqueda...</key>
<key alias="filter">Escribe para filtrar resultados...</key>
</area>
<area alias="editcontenttype">
<key alias="allowedchildnodetypes">Tipos de nodos hijos permitidos</key>
<key alias="contenttypecompositions">Document Type Compositions</key>
<key alias="contenttypecompositions">Composiciones de Tipo de Documento</key>
<key alias="create">Crear</key>
<key alias="deletetab">Borrar pestaña</key>
<key alias="description">Descripción</key>
<key alias="newtab">Nueva pestaña</key>
<key alias="tab">Pestaña</key>
<key alias="thumbnail">Miniatura</key>
<key alias="hasListView">Enable list view</key>
<key alias="hasListView">Permitir vista de listado</key>
</area>
<area alias="editdatatype">
<key alias="addPrevalue">añadir prevalor</key>
@@ -450,8 +449,7 @@
<key alias="runwayInstalledText"><![CDATA[Tienes puestos los cimientos. Selecciona los módulos que desees instalar sobre ellos.<br /> Esta es nuestra lista de módulos recomendados, selecciona los que desees instalar, o mira la <a href="#" onclick="toggleModules(); return false;" id="toggleModuleList">lista completa de módulos</a> ]]></key>
<key alias="runwayOnlyProUsers">Sólo recomendado para usuarios expertos</key>
<key alias="runwaySimpleSite">Quiero empezar con un sitio web sencillo</key>
<key alias="runwaySimpleSiteText"><![CDATA[<p> "Runway" es un sitio web sencillo que contiene unos tipos de documentos y plantillas básicos. El instalador puede configurar Runway por ti de forma automática, pero fácilmente puedes editarlo, extenderlo o eliminarlo. No es necesario y puedes usar Umbrao perfectamente sin él. Sin embargo, Runway ofrece unos cimientos sencillos basados en buenas prácticas para iniciarte más rápido que nunca. Si eliges instalar Runway, puedes seleccionar bloques de construcción básicos llamados Módulos de Runway de forma opcional para realzar tus páginas de Runway. </> <small> <em>Incluido con Runway:</em> Página de inicio, página de Cómo empezar, página de Instalación de módulos.<br /> <em>Módulos opcionales:</em> Navegación superior, Mapa del sitio, Contacto, Galería. </small>
However, Runway offers an easy foundation based on best practices to get you started faster than ever. If you choose to install Runway, you can optionally select basic building blocks called Runway Modules to enhance your Runway pages. </p> <small> <em>Included with Runway:</em> Home page, Getting Started page, Installing Modules page.<br /> <em>Optional Modules:</em> Top Navigation, Sitemap, Contact, Gallery. </small> ]]></key>
<key alias="runwaySimpleSiteText"><![CDATA[<p> "Runway" es un sitio web sencillo que contiene unos tipos de documentos y plantillas básicos. El instalador puede configurar Runway por ti de forma automática, pero fácilmente puedes editarlo, extenderlo o eliminarlo. No es necesario y puedes usar Umbrao perfectamente sin él. Sin embargo, Runway ofrece unos cimientos sencillos basados en buenas prácticas para iniciarte más rápido que nunca. Si eliges instalar Runway, puedes seleccionar bloques de construcción básicos llamados Módulos de Runway de forma opcional para realzar tus páginas de Runway. </> <small> <em>Incluido con Runway:</em> Página de inicio, página de Cómo empezar, página de Instalación de módulos.<br /> <em>Módulos opcionales:</em> Navegación superior, Mapa del sitio, Contacto, Galería. </small> ]]></key>
<key alias="runwayWhatIsRunway">¿Qué es Runway?</key>
<key alias="step1">Paso 1 de 5. Aceptar los términos de la licencia</key>
<key alias="step2">Paso 2 de 5. Configuración de la base de datos</key>
@@ -480,15 +478,15 @@ However, Runway offers an easy foundation based on best practices to get you sta
<key alias="renewSession">Renovar su sessión para guardar sus cambios</key>
</area>
<area alias="login">
<key alias="greeting0">Happy super Sunday</key>
<key alias="greeting1">Happy manic Monday </key>
<key alias="greeting2">Happy tubular Tuesday</key>
<key alias="greeting3">Happy wonderful Wednesday</key>
<key alias="greeting4">Happy thunderous Thursday</key>
<key alias="greeting5">Happy funky Friday</key>
<key alias="greeting6">Happy Caturday</key>
<key alias="instruction">Log in below</key>
<key alias="timeout">Session timed out</key>
<key alias="greeting0">Feliz super domingo</key>
<key alias="greeting1">Feliz lunes</key>
<key alias="greeting2">Tremendo martes</key>
<key alias="greeting3">Maravilloso miércoles</key>
<key alias="greeting4">Fantástico jueves</key>
<key alias="greeting5">¡Ya es viernes!</key>
<key alias="greeting6">Resplandeciente sábado</key>
<key alias="instruction">Iniciar sesión</key>
<key alias="timeout">La sesión ha caducado</key>
<key alias="bottomText"><![CDATA[<p style="text-align:right;">&copy; 2001 - %0% <br /><a href="http://umbraco.com" style="text-decoration: none" target="_blank">umbraco.com</a></p> ]]></key>
</area>
@@ -628,6 +626,10 @@ However, Runway offers an easy foundation based on best practices to get you sta
<key alias="tab">Pestaña</key>
<key alias="tabname">Nombre de la pestaña</key>
<key alias="tabs">Pestañas</key>
<key alias="contentTypeEnabled">Tipo de Contenido Maestro activado</key>
<key alias="contentTypeUses">Este Tipo de Contenido usa</key>
<key alias="asAContentMasterType">como Tipo de Contenido Maestro. Las pestañas para los Tipos de Contenido Maestros no se muestran y solo se pueden modificar desde el Tipo de Contenido Maestro</key>
<key alias="noPropertiesDefinedOnTab">No existen propiedades para esta pestaña. Haga clic en el enlace "añadir nueva propiedad" para crear una nueva propiedad.</key>
<key alias="masterDocumentType">Tipo de documento Maestro</key>
<key alias="createMatchingTemplate">Crear template correspondiente</key>
</area>
@@ -842,8 +844,8 @@ However, Runway offers an easy foundation based on best practices to get you sta
<key alias="usertype">Tipo de usuario</key>
<key alias="userTypes">Tipos de usuarios</key>
<key alias="writer">Redactor</key>
<key alias="yourProfile" version="7.0">Your profile</key>
<key alias="yourHistory" version="7.0">Your recent history</key>
<key alias="sessionExpires" version="7.0">Session expires in</key>
<key alias="yourProfile" version="7.0">Tu perfil</key>
<key alias="yourHistory" version="7.0">Tu historial reciente</key>
<key alias="sessionExpires" version="7.0">La sesión caduca en</key>
</area>
</language>
+6 -4
View File
@@ -233,10 +233,6 @@
<assemblyIdentity name="System.Web.Helpers" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="0.0.0.0-2.0.0.0" newVersion="2.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="0.0.0.0-4.0.0.1" newVersion="4.0.0.1" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.WebPages" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="0.0.0.0-2.0.0.0" newVersion="2.0.0.0" />
@@ -261,6 +257,12 @@
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="0.0.0.0-4.0.0.0" newVersion="4.0.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
@@ -84,15 +84,9 @@ namespace Umbraco.Web.Install.Controllers
public IEnumerable<Package> GetPackages()
{
var r = new org.umbraco.our.Repository();
var modules = r.Modules();
return modules.Select(package => new Package()
{
Id = package.RepoGuid,
Name = package.Text,
Thumbnail = package.Thumbnail
});
var installHelper = new InstallHelper(UmbracoContext);
var starterKits = installHelper.GetStarterKits();
return starterKits;
}
/// <summary>
+33 -5
View File
@@ -4,6 +4,7 @@ using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Web;
using System.Web.Script.Serialization;
using System.Web.UI;
@@ -11,6 +12,7 @@ using umbraco.BusinessLogic;
using Umbraco.Core;
using Umbraco.Core.Configuration;
using Umbraco.Core.IO;
using Umbraco.Core.Logging;
using Umbraco.Core.Persistence;
using Umbraco.Web.Install.InstallSteps;
using Umbraco.Web.Install.Models;
@@ -39,7 +41,7 @@ namespace Umbraco.Web.Install
public IEnumerable<InstallSetupStep> GetAllSteps()
{
return new List<InstallSetupStep>
{
{
new NewInstallStep(_umbContext.Application),
new UpgradeStep(),
new FilePermissionsStep(),
@@ -85,12 +87,12 @@ namespace Umbraco.Web.Install
{
Directory.Move(IOHelper.MapPath(SystemDirectories.Install), IOHelper.MapPath("~/app_data/temp/install_backup"));
}
}
}
if (Directory.Exists(IOHelper.MapPath("~/Areas/UmbracoInstall")))
{
{
Directory.Delete(IOHelper.MapPath("~/Areas/UmbracoInstall"), true);
}
}
}
internal void InstallStatus(bool isCompleted, string errorMsg)
@@ -165,7 +167,9 @@ namespace Umbraco.Web.Install
if (result == 1)
{
//the user has not been configured
return true;
//this is always true on UaaS, need to check if there's multiple users too
var usersResult = _umbContext.Application.DatabaseContext.Database.ExecuteScalar<int>("SELECT COUNT(*) FROM umbracoUser");
return usersResult == 1;
}
// //check if there are any content types configured, if there isn't then we will consider this a new install
@@ -182,5 +186,29 @@ namespace Umbraco.Web.Install
return false;
}
}
internal IEnumerable<Package> GetStarterKits()
{
var packages = new List<Package>();
try
{
var requestUri = string.Format("http://our.umbraco.org/webapi/StarterKit/Get/?umbracoVersion={0}",
UmbracoVersion.Current);
using (var request = new HttpRequestMessage(HttpMethod.Get, requestUri))
using (var httpClient = new HttpClient())
using (var response = httpClient.SendAsync(request).Result)
{
packages = response.Content.ReadAsAsync<IEnumerable<Package>>().Result.ToList();
}
}
catch (AggregateException ex)
{
LogHelper.Error<InstallHelper>("Could not download list of available starter kits", ex);
}
return packages;
}
}
}
@@ -21,16 +21,17 @@ namespace Umbraco.Web.Install.InstallSteps
private const string RepoGuid = "65194810-1f85-11dd-bd0b-0800200c9a66";
//adding a package guid hardcoded, so we can change the sent package remotely, currently this just points to txt kit
//but a future starterkit will be inserted under the same guid on our.
private const string PackageGuid = "69E44BEB-15FF-4CEE-8B64-0A7DAE498657";
public override InstallSetupResult Execute(Guid? starterKitId)
{
//if there is no value assigned then use the default starter kit
if (starterKitId.HasValue == false)
{
starterKitId = Guid.Parse(PackageGuid);
var installHelper = new InstallHelper(UmbracoContext.Current);
var starterKits = installHelper.GetStarterKits().FirstOrDefault();
if (starterKits != null)
starterKitId = starterKits.Id;
else
return null;
}
else if (starterKitId.Value == Guid.Empty)
{
@@ -57,7 +58,7 @@ namespace Umbraco.Web.Install.InstallSteps
}
if (repo.HasConnection() == false)
{
throw new InstallException("Cannot connect to repository");
throw new InstallException("Cannot connect to repository");
}
var installer = new Installer();
@@ -76,7 +77,7 @@ namespace Umbraco.Web.Install.InstallSteps
var installer = new Installer();
installer.LoadConfig(packageFile);
installer.InstallFiles(manifestId, packageFile);
}
public override string View
@@ -223,9 +223,13 @@ namespace Umbraco.Web.PropertyEditors
{
json = JObject.Parse((string)p.Value);
}
catch (JsonException ex)
catch (JsonException)
{
LogHelper.Error<ImageCropperPropertyEditor>("Could not parse the value into a JSON structure! Value: " + p.Value, ex);
//note: we are swallowing this exception because in some cases a normal string/non json value will be passed in which will just be the
// file path like /media/23454/hello.jpg
// This will happen everytime an image is uploaded via the folder browser and we don't really want to pollute the log since it's not actually
// a problem and we take care of this below.
// see: http://issues.umbraco.org/issue/U4-4756
}
if (json != null && json["src"] != null)
{
+1 -1
View File
@@ -415,7 +415,7 @@ namespace Umbraco.Web.Security
if (member != null)
{
var propValue = member.Properties[prop.Alias];
if (propValue != null)
if (propValue != null && propValue.Value != null)
{
value = propValue.Value.ToString();
}
@@ -42,6 +42,7 @@ namespace Umbraco.Web.Security.Providers
private string _defaultMemberTypeAlias = "Member";
private volatile bool _hasDefaultMember = false;
private static readonly object Locker = new object();
private bool _providerKeyAsGuid = false;
public override string ProviderName
{
@@ -58,7 +59,7 @@ namespace Umbraco.Web.Security.Providers
protected override MembershipUser ConvertToMembershipUser(IMember entity)
{
return entity.AsConcreteMembershipUser(Name);
return entity.AsConcreteMembershipUser(Name, _providerKeyAsGuid);
}
public string LockPropertyTypeAlias { get; private set; }
@@ -85,6 +86,15 @@ namespace Umbraco.Web.Security.Providers
}
_hasDefaultMember = true;
}
//devs can configure the provider user key to be a guid if they want, by default it is int
if (config["providerKeyType"] != null)
{
if (config["providerKeyType"] == "guid")
{
_providerKeyAsGuid = true;
}
}
}
public override string DefaultMemberTypeAlias
@@ -47,7 +47,7 @@ namespace Umbraco.Web.Security.Providers
protected override MembershipUser ConvertToMembershipUser(IUser entity)
{
//the provider user key is always the int id
return entity.AsConcreteMembershipUser(Name);
return entity.AsConcreteMembershipUser(Name, true);
}
public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config)
@@ -500,15 +500,18 @@ namespace umbraco
() => GetMediaDo(MediaId, Deep));
if (xml != null)
{
return FromXElement(xml, xml.Attribute("nodeTypeAlias").Value);
{
//returning the root element of the Media item fixes the problem
return xml.CreateNavigator().Select("/");
}
}
else
{
var xml = GetMediaDo(MediaId, Deep);
return FromXElement(xml, xml.Attribute("nodeTypeAlias").Value);
//returning the root element of the Media item fixes the problem
return xml.CreateNavigator().Select("/");
}
}
catch(Exception ex)
@@ -536,15 +539,6 @@ namespace umbraco
return serialized;
}
private static XPathNodeIterator FromXElement(XNode xml, string mediaContentType)
{
var xp = xml.CreateNavigator();
var xpath = UmbracoConfig.For.UmbracoSettings().Content.UseLegacyXmlSchema
? "/node"
: String.Format("/{0}", Casing.SafeAliasWithForcingCheck(mediaContentType));
return xp.Select(xpath);
}
/// <summary>
/// Get a member as an xml object
/// </summary>
@@ -16,6 +16,7 @@ using System.Web.UI.WebControls;
using ClientDependency.Core;
using Umbraco.Core;
using Umbraco.Core.Configuration;
using Umbraco.Core.Exceptions;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Strings;
@@ -296,6 +297,8 @@ namespace umbraco.controls
IconType = BasePage.speechBubbleIcon.success
}, _contentType.Alias, _contentType.Text, txtAlias.Text, txtName.Text, _contentType.PropertyTypes.Select(x => x.Alias).ToArray());
var isMediaType = Request.Path.ToLowerInvariant().Contains("editmediatype.aspx");
//Add the async operation to the page
//NOTE: Must pass in a null and do not pass in a true to the 'executeInParallel', this is changed in .net 4.5 for the better, otherwise you'll get a ysod.
Page.RegisterAsyncTask(new PageAsyncTask(BeginAsyncSaveOperation, EndAsyncSaveOperation, null, state));
@@ -306,7 +309,7 @@ namespace umbraco.controls
Trace.Write("ContentTypeControlNew", "executing task");
//we need to re-set the UmbracoContext since it will be nulled and our cache handlers need it
//global::Umbraco.Web.UmbracoContext.Current = asyncState.UmbracoContext;
global::Umbraco.Web.UmbracoContext.Current = asyncState.UmbracoContext;
_contentType.ContentTypeItem.Name = txtName.Text;
_contentType.ContentTypeItem.Alias = txtAlias.Text; // raw, contentType.Alias takes care of it
@@ -320,47 +323,73 @@ namespace umbraco.controls
var ids = SaveAllowedChildTypes();
_contentType.ContentTypeItem.AllowedContentTypes = ids.Select(x => new ContentTypeSort {Id = new Lazy<int>(() => x), SortOrder = i++});
//Saving ContentType Compositions
var compositionIds = SaveCompositionContentTypes();
var existingCompsitionIds = _contentType.ContentTypeItem.CompositionIds().ToList();
if (compositionIds.Any())
// figure out whether compositions are locked
var allContentTypes = Request.Path.ToLowerInvariant().Contains("editmediatype.aspx")
? ApplicationContext.Services.ContentTypeService.GetAllMediaTypes().Cast<IContentTypeComposition>().ToArray()
: ApplicationContext.Services.ContentTypeService.GetAllContentTypes().Cast<IContentTypeComposition>().ToArray();
var isUsing = allContentTypes.Where(x => x.ContentTypeComposition.Any(y => y.Id == _contentType.Id)).ToArray();
// if compositions are locked, do nothing (leave them as they are)
// else process the checkbox list and add/remove compositions accordingly
if (isUsing.Length == 0)
{
//Iterate ContentType Ids from the save-collection
foreach (var compositionId in compositionIds)
//Saving ContentType Compositions
var compositionIds = SaveCompositionContentTypes();
var existingCompsitionIds = _contentType.ContentTypeItem.CompositionIds().ToList();
if (compositionIds.Any())
{
//If the compositionId is the Id of the current ContentType we skip it
if(_contentType.Id.Equals(compositionId)) continue;
// if some compositions were checked in the list, iterate over them
foreach (var compositionId in compositionIds)
{
// ignore if it is the current content type
if (_contentType.Id.Equals(compositionId)) continue;
//If the Id already exists we'll just skip it
if (existingCompsitionIds.Any(x => x.Equals(compositionId))) continue;
// ignore if it is already a composition of the content type
if (existingCompsitionIds.Any(x => x.Equals(compositionId))) continue;
//New Ids will get added to the collection
var compositionType = Services.ContentTypeService.GetContentType(compositionId);
var added = _contentType.ContentTypeItem.AddContentType(compositionType);
//TODO if added=false then return error message
// add to the content type compositions
var compositionType = isMediaType
? Services.ContentTypeService.GetMediaType(compositionId).SafeCast<IContentTypeComposition>()
: Services.ContentTypeService.GetContentType(compositionId).SafeCast<IContentTypeComposition>();
try
{
//TODO if added=false then return error message
var added = _contentType.ContentTypeItem.AddContentType(compositionType);
}
catch (InvalidCompositionException ex)
{
state.SaveArgs.IconType = BasePage.speechBubbleIcon.error;
state.SaveArgs.Message = ex.Message;
}
}
// then iterate over removed = existing except checked
var removeIds = existingCompsitionIds.Except(compositionIds);
foreach (var removeId in removeIds)
{
// and remove from the content type composition
var compositionType = isMediaType
? Services.ContentTypeService.GetMediaType(removeId).SafeCast<IContentTypeComposition>()
: Services.ContentTypeService.GetContentType(removeId).SafeCast<IContentTypeComposition>();
var removed = _contentType.ContentTypeItem.RemoveContentType(compositionType.Alias);
}
}
//Iterate the set except of existing and new Ids
var removeIds = existingCompsitionIds.Except(compositionIds);
foreach (var removeId in removeIds)
else if (existingCompsitionIds.Any())
{
//Remove ContentTypes that was deselected in the list
var compositionType = Services.ContentTypeService.GetContentType(removeId);
var removed = _contentType.ContentTypeItem.RemoveContentType(compositionType.Alias);
// else none were checked - if the content type had compositions,
// iterate over them all and remove them
var removeIds = existingCompsitionIds.Except(compositionIds); // except here makes no sense?
foreach (var removeId in removeIds)
{
// remove existing
var compositionType = isMediaType
? Services.ContentTypeService.GetMediaType(removeId).SafeCast<IContentTypeComposition>()
: Services.ContentTypeService.GetContentType(removeId).SafeCast<IContentTypeComposition>();
var removed = _contentType.ContentTypeItem.RemoveContentType(compositionType.Alias);
}
}
}
else if (existingCompsitionIds.Any())
{
//Iterate the set except of existing and new Ids
var removeIds = existingCompsitionIds.Except(compositionIds);
foreach (var removeId in removeIds)
{
//Remove ContentTypes that was deselected in the list
var compositionType = Services.ContentTypeService.GetContentType(removeId);
var removed = _contentType.ContentTypeItem.RemoveContentType(compositionType.Alias);
}
}
var tabs = SaveTabs();
foreach (var tab in tabs)
@@ -406,6 +435,11 @@ namespace umbraco.controls
state.SaveArgs.Message = ex.Message;
return;
}
catch (Exception ex)
{
state.SaveArgs.IconType = BasePage.speechBubbleIcon.error;
state.SaveArgs.Message = ex.Message;
}
Trace.Write("ContentTypeControlNew", "task completing");
};
@@ -676,7 +710,9 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }});
if (Page.IsPostBack == false)
{
var allContentTypes = ApplicationContext.Services.ContentTypeService.GetAllContentTypes().ToArray();
var allContentTypes = Request.Path.ToLowerInvariant().Contains("editmediatype.aspx")
? ApplicationContext.Services.ContentTypeService.GetAllMediaTypes().Cast<IContentTypeComposition>().ToArray()
: ApplicationContext.Services.ContentTypeService.GetAllContentTypes().Cast<IContentTypeComposition>().ToArray();
// note: there are many sanity checks missing here and there ;-((
// make sure once and for all
@@ -695,7 +731,7 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }});
DualContentTypeCompositions.Value = "";
PlaceHolderContentTypeCompositions.Controls.Add(new Literal { Text = "<em>This content type is used as a parent and/or in "
+ "a composition, and therefore cannot be composed itself.<br /><br />"
+ "a composition, and therefore cannot be composed itself.<br /><br />Used by: "
+ string.Join(", ", isUsing.Select(x => x.Name))
+ "</em>" });
}
@@ -780,16 +816,10 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }});
private int[] SaveCompositionContentTypes()
{
var tmp = new ArrayList();
foreach (ListItem li in lstContentTypeCompositions.Items)
{
if (li.Selected)
tmp.Add(int.Parse(li.Value));
}
var ids = new int[tmp.Count];
for (int i = 0; i < tmp.Count; i++) ids[i] = (int)tmp[i];
return ids;
return lstContentTypeCompositions.Items.Cast<ListItem>()
.Where(x => x.Selected)
.Select(x => int.Parse(x.Value))
.ToArray();
}
#endregion
@@ -1052,7 +1082,7 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }});
private string GetHtmlForNoPropertiesMessageListItem()
{
return @"<li class=""no-properties-on-tab"">" + ui.Text("settings", "noPropertiesDefinedOnTab") + "</li></ul>";
return @"<li class=""no-properties-on-tab"">" + ui.Text("settings", "noPropertiesDefinedOnTab", Security.CurrentUser) + "</li></ul>";
}
private void SavePropertyType(SaveClickEventArgs e, IContentTypeComposition contentTypeItem)
@@ -1106,7 +1136,7 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }});
}
else
{
e.Message = ui.Text("contentTypeDublicatePropertyType");
e.Message = ui.Text("contentTypeDublicatePropertyType", Security.CurrentUser);
e.IconType = BasePage.speechBubbleIcon.warning;
}
}
@@ -1409,7 +1439,7 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }});
LoadContentType();
var ea = new SaveClickEventArgs(ui.Text("contentTypeTabCreated"));
var ea = new SaveClickEventArgs(ui.Text("contentTypeTabCreated", Security.CurrentUser));
ea.IconType = BasePage.speechBubbleIcon.success;
RaiseBubbleEvent(new object(), ea);
@@ -1448,7 +1478,7 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }});
LoadContentType();
var ea = new SaveClickEventArgs(ui.Text("contentTypeTabDeleted"));
var ea = new SaveClickEventArgs(ui.Text("contentTypeTabDeleted", Security.CurrentUser));
ea.IconType = BasePage.speechBubbleIcon.success;
RaiseBubbleEvent(new object(), ea);
@@ -24,13 +24,18 @@ namespace umbraco
//NOTE: TypeID is the parent id!
//NOTE: ParentID is aparently a flag to determine if we are to create a template! Hack much ?! :P
var parentId = TypeID != 0 ? TypeID : -1;
var contentType = parentId == -1
? new ContentType(-1)
: new ContentType(ApplicationContext.Current.Services.ContentTypeService.GetContentType(parentId));
contentType.CreatorId = User.Id;
// when creating a content type, enforce PascalCase
// preserve separator because contentType.Alias will re-alias it
contentType.Alias = Alias.ToCleanString(CleanStringType.Alias | CleanStringType.PascalCase, ' ');
var cleanAlias = Alias.ToCleanString(CleanStringType.Alias | CleanStringType.PascalCase, ' ');
var contentType = parentId == -1
? new ContentType(-1)
: new ContentType(ApplicationContext.Current.Services.ContentTypeService.GetContentType(parentId), cleanAlias);
contentType.CreatorId = User.Id;
contentType.Alias = cleanAlias;
contentType.Name = Alias.Replace("'", "''");
contentType.Icon = ".sprTreeFolder";