Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 82c18955b0 | |||
| 308a61895e |
@@ -1,3 +1,3 @@
|
||||
# Usage: on line 2 put the release version, on line 3 put the version comment (example: beta)
|
||||
7.6.0
|
||||
alpha061
|
||||
alpha060
|
||||
|
||||
+1
-1
@@ -12,4 +12,4 @@ using System.Resources;
|
||||
[assembly: AssemblyVersion("1.0.*")]
|
||||
|
||||
[assembly: AssemblyFileVersion("7.6.0")]
|
||||
[assembly: AssemblyInformationalVersion("7.6.0-alpha061")]
|
||||
[assembly: AssemblyInformationalVersion("7.6.0-alpha060")]
|
||||
@@ -24,7 +24,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 "alpha061"; } }
|
||||
public static string CurrentComment { get { return "alpha060"; } }
|
||||
|
||||
// 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
|
||||
|
||||
@@ -23,11 +23,6 @@ namespace Umbraco.Core.Events
|
||||
{
|
||||
get { return _packageMetaData; }
|
||||
}
|
||||
|
||||
public IEnumerable<TEntity> InstallationSummary
|
||||
{
|
||||
get { return EventObject; }
|
||||
}
|
||||
|
||||
public bool Equals(ImportPackageEventArgs<TEntity> other)
|
||||
{
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.Packaging.Models;
|
||||
|
||||
namespace Umbraco.Core.Events
|
||||
{
|
||||
internal class UninstallPackageEventArgs<TEntity> : CancellableObjectEventArgs<IEnumerable<TEntity>>
|
||||
{
|
||||
private readonly MetaData _packageMetaData;
|
||||
|
||||
public UninstallPackageEventArgs(TEntity eventObject, bool canCancel)
|
||||
: base(new[] { eventObject }, canCancel)
|
||||
{
|
||||
}
|
||||
|
||||
public UninstallPackageEventArgs(TEntity eventObject, MetaData packageMetaData)
|
||||
: base(new[] { eventObject })
|
||||
{
|
||||
_packageMetaData = packageMetaData;
|
||||
}
|
||||
|
||||
public MetaData PackageMetaData
|
||||
{
|
||||
get { return _packageMetaData; }
|
||||
}
|
||||
|
||||
public IEnumerable<TEntity> UninstallationSummary
|
||||
{
|
||||
get { return EventObject; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -109,5 +109,24 @@ namespace Umbraco.Core.IO
|
||||
var wrapped2 = Wrapped as IFileSystem2;
|
||||
return wrapped2 == null ? Wrapped.GetSize(path) : wrapped2.GetSize(path);
|
||||
}
|
||||
|
||||
// explicitely implementing - not breaking
|
||||
bool IFileSystem2.CanAddPhysical
|
||||
{
|
||||
get
|
||||
{
|
||||
var wrapped2 = Wrapped as IFileSystem2;
|
||||
return wrapped2 != null && wrapped2.CanAddPhysical;
|
||||
}
|
||||
}
|
||||
|
||||
// explicitely implementing - not breaking
|
||||
void IFileSystem2.AddFile(string path, string physicalPath, bool overrideIfExists, bool copy)
|
||||
{
|
||||
var wrapped2 = Wrapped as IFileSystem2;
|
||||
if (wrapped2 == null)
|
||||
throw new NotSupportedException();
|
||||
wrapped2.AddFile(path, physicalPath, overrideIfExists, copy);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -44,6 +44,10 @@ namespace Umbraco.Core.IO
|
||||
{
|
||||
long GetSize(string path);
|
||||
|
||||
bool CanAddPhysical { get; }
|
||||
|
||||
void AddFile(string path, string physicalPath, bool overrideIfExists = true, bool copy = false);
|
||||
|
||||
// TODO: implement these
|
||||
//
|
||||
//void CreateDirectory(string path);
|
||||
|
||||
@@ -4,11 +4,11 @@ using System.Globalization;
|
||||
using System.Reflection;
|
||||
using System.IO;
|
||||
using System.Configuration;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Web.Hosting;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Logging;
|
||||
|
||||
namespace Umbraco.Core.IO
|
||||
{
|
||||
@@ -351,54 +351,7 @@ namespace Umbraco.Core.IO
|
||||
writer.Write(contents);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if a given path is a full path including drive letter
|
||||
/// </summary>
|
||||
/// <param name="path"></param>
|
||||
/// <returns></returns>
|
||||
// From: http://stackoverflow.com/a/35046453/5018
|
||||
internal static bool IsFullPath(this string path)
|
||||
{
|
||||
return string.IsNullOrWhiteSpace(path) == false
|
||||
&& path.IndexOfAny(Path.GetInvalidPathChars().ToArray()) == -1
|
||||
&& Path.IsPathRooted(path)
|
||||
&& Path.GetPathRoot(path).Equals(Path.DirectorySeparatorChar.ToString(), StringComparison.Ordinal) == false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get properly formatted relative path from an existing absolute or relative path
|
||||
/// </summary>
|
||||
/// <param name="path"></param>
|
||||
/// <returns></returns>
|
||||
internal static string GetRelativePath(this string path)
|
||||
{
|
||||
if (path.IsFullPath())
|
||||
{
|
||||
var rootDirectory = GetRootDirectorySafe();
|
||||
var relativePath = path.ToLowerInvariant().Replace(rootDirectory.ToLowerInvariant(), string.Empty);
|
||||
path = relativePath;
|
||||
}
|
||||
|
||||
return path.EnsurePathIsApplicationRootPrefixed();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensures that a path has `~/` as prefix
|
||||
/// </summary>
|
||||
/// <param name="path"></param>
|
||||
/// <returns></returns>
|
||||
internal static string EnsurePathIsApplicationRootPrefixed(this string path)
|
||||
{
|
||||
if (path.StartsWith("~/"))
|
||||
return path;
|
||||
if (path.StartsWith("/") == false && path.StartsWith("\\") == false)
|
||||
path = string.Format("/{0}", path);
|
||||
if (path.StartsWith("~") == false)
|
||||
path = string.Format("~{0}", path);
|
||||
return path;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -364,6 +364,29 @@ namespace Umbraco.Core.IO
|
||||
return file.Exists ? file.Length : -1;
|
||||
}
|
||||
|
||||
public bool CanAddPhysical { get { return true; } }
|
||||
|
||||
public void AddFile(string path, string physicalPath, bool overrideIfExists = true, bool copy = false)
|
||||
{
|
||||
var fullPath = GetFullPath(path);
|
||||
|
||||
if (File.Exists(fullPath))
|
||||
{
|
||||
if (overrideIfExists == false)
|
||||
throw new InvalidOperationException(string.Format("A file at path '{0}' already exists", path));
|
||||
File.Delete(fullPath);
|
||||
}
|
||||
|
||||
var directory = Path.GetDirectoryName(fullPath);
|
||||
if (directory == null) throw new InvalidOperationException("Could not get directory.");
|
||||
Directory.CreateDirectory(directory); // ensure it exists
|
||||
|
||||
if (copy)
|
||||
File.Copy(physicalPath, fullPath);
|
||||
else
|
||||
File.Move(physicalPath, fullPath);
|
||||
}
|
||||
|
||||
#region Helper Methods
|
||||
|
||||
protected virtual void EnsureDirectory(string path)
|
||||
|
||||
@@ -33,8 +33,16 @@ namespace Umbraco.Core.IO
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var stream = _sfs.OpenFile(kvp.Key))
|
||||
_fs.AddFile(kvp.Key, stream, true);
|
||||
var fs2 = _fs as IFileSystem2;
|
||||
if (fs2 != null && fs2.CanAddPhysical)
|
||||
{
|
||||
fs2.AddFile(kvp.Key, _sfs.GetFullPath(kvp.Key)); // overwrite, move
|
||||
}
|
||||
else
|
||||
{
|
||||
using (var stream = _sfs.OpenFile(kvp.Key))
|
||||
_fs.AddFile(kvp.Key, stream, true);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -282,5 +290,36 @@ namespace Umbraco.Core.IO
|
||||
if (sf.IsDelete || sf.IsDir) throw new InvalidOperationException("Invalid path.");
|
||||
return _sfs.GetSize(path);
|
||||
}
|
||||
|
||||
public bool CanAddPhysical { get { return true; } }
|
||||
|
||||
public void AddFile(string path, string physicalPath, bool overrideIfExists = true, bool copy = false)
|
||||
{
|
||||
ShadowNode sf;
|
||||
var normPath = NormPath(path);
|
||||
if (Nodes.TryGetValue(normPath, out sf) && sf.IsExist && (sf.IsDir || overrideIfExists == false))
|
||||
throw new InvalidOperationException(string.Format("A file at path '{0}' already exists", path));
|
||||
|
||||
var parts = normPath.Split('/');
|
||||
for (var i = 0; i < parts.Length - 1; i++)
|
||||
{
|
||||
var dirPath = string.Join("/", parts.Take(i + 1));
|
||||
ShadowNode sd;
|
||||
if (Nodes.TryGetValue(dirPath, out sd))
|
||||
{
|
||||
if (sd.IsFile) throw new InvalidOperationException("Invalid path.");
|
||||
if (sd.IsDelete) Nodes[dirPath] = new ShadowNode(false, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_fs.DirectoryExists(dirPath)) continue;
|
||||
if (_fs.FileExists(dirPath)) throw new InvalidOperationException("Invalid path.");
|
||||
Nodes[dirPath] = new ShadowNode(false, true);
|
||||
}
|
||||
}
|
||||
|
||||
_sfs.AddFile(path, physicalPath, overrideIfExists, copy);
|
||||
Nodes[normPath] = new ShadowNode(false, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,5 +164,22 @@ namespace Umbraco.Core.IO
|
||||
var filesystem2 = filesystem as IFileSystem2;
|
||||
return filesystem2 == null ? filesystem.GetSize(path) : filesystem2.GetSize(path);
|
||||
}
|
||||
|
||||
public bool CanAddPhysical
|
||||
{
|
||||
get
|
||||
{
|
||||
var fileSystem2 = FileSystem as IFileSystem2;
|
||||
return fileSystem2 != null && fileSystem2.CanAddPhysical;
|
||||
}
|
||||
}
|
||||
|
||||
public void AddFile(string path, string physicalPath, bool overrideIfExists = true, bool copy = false)
|
||||
{
|
||||
var fileSystem2 = FileSystem as IFileSystem2;
|
||||
if (fileSystem2 == null)
|
||||
throw new NotSupportedException();
|
||||
fileSystem2.AddFile(path, physicalPath, overrideIfExists, copy);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,7 +22,6 @@ namespace Umbraco.Core.Models.Rdbms
|
||||
[Column("LoginName")]
|
||||
[Length(1000)]
|
||||
[Constraint(Default = "''")]
|
||||
[Index(IndexTypes.NonClustered, Name = "IX_cmsMember_LoginName")]
|
||||
public string LoginName { get; set; }
|
||||
|
||||
[Column("Password")]
|
||||
|
||||
@@ -16,7 +16,6 @@ namespace Umbraco.Core.Models.Rdbms
|
||||
|
||||
[Column("parentId")]
|
||||
[ForeignKey(typeof(NodeDto), Name = "FK_umbracoRelation_umbracoNode")]
|
||||
[Index(IndexTypes.UniqueNonClustered, Name = "IX_umbracoRelation_parentChildType", ForColumns = "parentId,childId,relType")]
|
||||
public int ParentId { get; set; }
|
||||
|
||||
[Column("childId")]
|
||||
|
||||
@@ -29,13 +29,11 @@ namespace Umbraco.Core.Models.Rdbms
|
||||
public Guid ChildObjectType { get; set; }
|
||||
|
||||
[Column("name")]
|
||||
[Index(IndexTypes.UniqueNonClustered, Name = "IX_umbracoRelationType_name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
[Column("alias")]
|
||||
[NullSetting(NullSetting = NullSettings.Null)]
|
||||
[Length(100)]
|
||||
[Index(IndexTypes.UniqueNonClustered, Name = "IX_umbracoRelationType_alias")]
|
||||
public string Alias { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core.Models;
|
||||
|
||||
namespace Umbraco.Core.Packaging.Models
|
||||
{
|
||||
[Serializable]
|
||||
[DataContract(IsReference = true)]
|
||||
internal class UninstallationSummary
|
||||
{
|
||||
public MetaData MetaData { get; set; }
|
||||
public IEnumerable<IDataTypeDefinition> DataTypesUninstalled { get; set; }
|
||||
public IEnumerable<ILanguage> LanguagesUninstalled { get; set; }
|
||||
public IEnumerable<IDictionaryItem> DictionaryItemsUninstalled { get; set; }
|
||||
public IEnumerable<IMacro> MacrosUninstalled { get; set; }
|
||||
public IEnumerable<string> FilesUninstalled { get; set; }
|
||||
public IEnumerable<ITemplate> TemplatesUninstalled { get; set; }
|
||||
public IEnumerable<IContentType> ContentTypesUninstalled { get; set; }
|
||||
public IEnumerable<IFile> StylesheetsUninstalled { get; set; }
|
||||
public IEnumerable<IContent> ContentUninstalled { get; set; }
|
||||
public bool PackageUninstalled { get; set; }
|
||||
}
|
||||
|
||||
internal static class UninstallationSummaryExtentions
|
||||
{
|
||||
public static UninstallationSummary InitEmpty(this UninstallationSummary summary)
|
||||
{
|
||||
summary.ContentUninstalled = new List<IContent>();
|
||||
summary.ContentTypesUninstalled = new List<IContentType>();
|
||||
summary.DataTypesUninstalled = new List<IDataTypeDefinition>();
|
||||
summary.DictionaryItemsUninstalled = new List<IDictionaryItem>();
|
||||
summary.FilesUninstalled = new List<string>();
|
||||
summary.LanguagesUninstalled = new List<ILanguage>();
|
||||
summary.MacrosUninstalled = new List<IMacro>();
|
||||
summary.MetaData = new MetaData();
|
||||
summary.TemplatesUninstalled = new List<ITemplate>();
|
||||
summary.PackageUninstalled = false;
|
||||
return summary;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,20 +27,7 @@ namespace Umbraco.Core.Persistence.Factories
|
||||
|
||||
#region Implementation of IEntityFactory<IContent,DocumentDto>
|
||||
|
||||
/// <summary>
|
||||
/// Builds a IContent item from the dto(s) and content type
|
||||
/// </summary>
|
||||
/// <param name="dto">
|
||||
/// This DTO can contain all of the information to build an IContent item, however in cases where multiple entities are being built,
|
||||
/// a separate <see cref="DocumentPublishedReadOnlyDto"/> publishedDto entity will be supplied in place of the <see cref="DocumentDto"/>'s own
|
||||
/// ResultColumn DocumentPublishedReadOnlyDto
|
||||
/// </param>
|
||||
/// <param name="contentType"></param>
|
||||
/// <param name="publishedDto">
|
||||
/// When querying for multiple content items the main DTO will not contain the ResultColumn DocumentPublishedReadOnlyDto and a separate publishedDto instance will be supplied
|
||||
/// </param>
|
||||
/// <returns></returns>
|
||||
public static IContent BuildEntity(DocumentDto dto, IContentType contentType, DocumentPublishedReadOnlyDto publishedDto = null)
|
||||
public static IContent BuildEntity(DocumentDto dto, IContentType contentType)
|
||||
{
|
||||
var content = new Content(dto.Text, dto.ContentVersionDto.ContentDto.NodeDto.ParentId, contentType);
|
||||
|
||||
@@ -65,13 +52,8 @@ namespace Umbraco.Core.Persistence.Factories
|
||||
content.ExpireDate = dto.ExpiresDate.HasValue ? dto.ExpiresDate.Value : (DateTime?)null;
|
||||
content.ReleaseDate = dto.ReleaseDate.HasValue ? dto.ReleaseDate.Value : (DateTime?)null;
|
||||
content.Version = dto.ContentVersionDto.VersionId;
|
||||
|
||||
content.PublishedState = dto.Published ? PublishedState.Published : PublishedState.Unpublished;
|
||||
|
||||
//Check if the publishedDto has been supplied, if not the use the dto's own DocumentPublishedReadOnlyDto value
|
||||
content.PublishedVersionGuid = publishedDto == null
|
||||
? (dto.DocumentPublishedReadOnlyDto == null ? default(Guid) : dto.DocumentPublishedReadOnlyDto.VersionId)
|
||||
: publishedDto.VersionId;
|
||||
content.PublishedVersionGuid = dto.DocumentPublishedReadOnlyDto == null ? default(Guid) : dto.DocumentPublishedReadOnlyDto.VersionId;
|
||||
|
||||
//on initial construction we don't want to have dirty properties tracked
|
||||
// http://issues.umbraco.org/issue/U4-1946
|
||||
|
||||
-42
@@ -1,42 +0,0 @@
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
|
||||
using Umbraco.Core.Persistence.SqlSyntax;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenSixZero
|
||||
{
|
||||
[Migration("7.6.0", 0, Constants.System.UmbracoMigrationName)]
|
||||
public class AddIndexToCmsMemberLoginName : MigrationBase
|
||||
{
|
||||
public AddIndexToCmsMemberLoginName(ISqlSyntaxProvider sqlSyntax, ILogger logger)
|
||||
: base(sqlSyntax, logger)
|
||||
{ }
|
||||
|
||||
public override void Up()
|
||||
{
|
||||
var dbIndexes = SqlSyntax.GetDefinedIndexes(Context.Database)
|
||||
.Select(x => new DbIndexDefinition()
|
||||
{
|
||||
TableName = x.Item1,
|
||||
IndexName = x.Item2,
|
||||
ColumnName = x.Item3,
|
||||
IsUnique = x.Item4
|
||||
}).ToArray();
|
||||
|
||||
//make sure it doesn't already exist
|
||||
if (dbIndexes.Any(x => x.IndexName.InvariantEquals("IX_cmsMember_LoginName")) == false)
|
||||
{
|
||||
Create.Index("IX_cmsMember_LoginName").OnTable("cmsMember")
|
||||
.OnColumn("LoginName")
|
||||
.Ascending()
|
||||
.WithOptions()
|
||||
.NonClustered();
|
||||
}
|
||||
}
|
||||
|
||||
public override void Down()
|
||||
{
|
||||
Delete.Index("IX_cmsMember_LoginName").OnTable("cmsMember");
|
||||
}
|
||||
}
|
||||
}
|
||||
+8
-1
@@ -14,7 +14,14 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenSixZero
|
||||
|
||||
public override void Up()
|
||||
{
|
||||
var dbIndexes = SqlSyntax.GetDefinedIndexesDefinitions(Context.Database);
|
||||
var dbIndexes = SqlSyntax.GetDefinedIndexes(Context.Database)
|
||||
.Select(x => new DbIndexDefinition()
|
||||
{
|
||||
TableName = x.Item1,
|
||||
IndexName = x.Item2,
|
||||
ColumnName = x.Item3,
|
||||
IsUnique = x.Item4
|
||||
}).ToArray();
|
||||
|
||||
//make sure it doesn't already exist
|
||||
if (dbIndexes.Any(x => x.IndexName.InvariantEquals("IX_umbracoNodePath")) == false)
|
||||
|
||||
-91
@@ -1,91 +0,0 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Persistence.SqlSyntax;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenSixZero
|
||||
{
|
||||
[Migration("7.6.0", 0, Constants.System.UmbracoMigrationName)]
|
||||
public class AddIndexesToUmbracoRelationTables : MigrationBase
|
||||
{
|
||||
public AddIndexesToUmbracoRelationTables(ISqlSyntaxProvider sqlSyntax, ILogger logger)
|
||||
: base(sqlSyntax, logger)
|
||||
{ }
|
||||
|
||||
public override void Up()
|
||||
{
|
||||
var dbIndexes = SqlSyntax.GetDefinedIndexesDefinitions(Context.Database).ToArray();
|
||||
|
||||
//make sure it doesn't already exist
|
||||
if (dbIndexes.Any(x => x.IndexName.InvariantEquals("IX_umbracoRelation_parentChildType")) == false)
|
||||
{
|
||||
//This will remove any corrupt/duplicate data in the relation table before the index is applied
|
||||
//Ensure this executes in a defered block which will be done inside of the migration transaction
|
||||
this.Execute.Code(database =>
|
||||
{
|
||||
//We need to check if this index has corrupted data and then clear that data
|
||||
var duplicates = database.Fetch<dynamic>("SELECT parentId,childId,relType FROM umbracoRelation GROUP BY parentId,childId,relType HAVING COUNT(*) > 1");
|
||||
if (duplicates.Count > 0)
|
||||
{
|
||||
//need to fix this there cannot be duplicates so we'll take the latest entries, it's really not going to matter though
|
||||
foreach (var duplicate in duplicates)
|
||||
{
|
||||
var ids = database.Fetch<int>("SELECT id FROM umbracoRelation WHERE parentId=@parentId AND childId=@childId AND relType=@relType ORDER BY datetime DESC",
|
||||
new { parentId = duplicate.parentId, childId = duplicate.childId, relType = duplicate.relType });
|
||||
|
||||
if (ids.Count == 1)
|
||||
{
|
||||
//this is just a safety check, this should absolutely never happen
|
||||
throw new InvalidOperationException("Duplicates were detected but could not be discovered");
|
||||
}
|
||||
|
||||
//delete the others
|
||||
ids = ids.Skip(0).ToList();
|
||||
|
||||
//iterate in groups of 2000 to avoid the max sql parameter limit
|
||||
foreach (var idGroup in ids.InGroupsOf(2000))
|
||||
{
|
||||
database.Execute("DELETE FROM umbracoRelation WHERE id IN (@ids)", new { ids = idGroup });
|
||||
}
|
||||
}
|
||||
}
|
||||
return "";
|
||||
});
|
||||
|
||||
//unique index to prevent duplicates - and for better perf
|
||||
Create.Index("IX_umbracoRelation_parentChildType").OnTable("umbracoRelation")
|
||||
.OnColumn("parentId").Ascending()
|
||||
.OnColumn("childId").Ascending()
|
||||
.OnColumn("relType").Ascending()
|
||||
.WithOptions()
|
||||
.Unique();
|
||||
}
|
||||
|
||||
//need indexes on alias and name for relation type since these are queried against
|
||||
|
||||
//make sure it doesn't already exist
|
||||
if (dbIndexes.Any(x => x.IndexName.InvariantEquals("IX_umbracoRelationType_alias")) == false)
|
||||
{
|
||||
Create.Index("IX_umbracoRelationType_alias").OnTable("umbracoRelationType")
|
||||
.OnColumn("alias")
|
||||
.Ascending()
|
||||
.WithOptions()
|
||||
.NonClustered();
|
||||
}
|
||||
if (dbIndexes.Any(x => x.IndexName.InvariantEquals("IX_umbracoRelationType_name")) == false)
|
||||
{
|
||||
Create.Index("IX_umbracoRelationType_name").OnTable("umbracoRelationType")
|
||||
.OnColumn("name")
|
||||
.Ascending()
|
||||
.WithOptions()
|
||||
.NonClustered();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public override void Down()
|
||||
{
|
||||
Delete.Index("IX_umbracoNodePath").OnTable("umbracoNode");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,30 +2,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
internal enum BaseQueryType
|
||||
{
|
||||
/// <summary>
|
||||
/// A query to return all information for a single item
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// In some cases this will be the same as <see cref="FullMultiple"/>
|
||||
/// </remarks>
|
||||
FullSingle,
|
||||
|
||||
/// <summary>
|
||||
/// A query to return all information for multiple items
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// In some cases this will be the same as <see cref="FullSingle"/>
|
||||
/// </remarks>
|
||||
FullMultiple,
|
||||
|
||||
/// <summary>
|
||||
/// A query to return the ids for items
|
||||
/// </summary>
|
||||
Full,
|
||||
Ids,
|
||||
|
||||
/// <summary>
|
||||
/// A query to return the count for items
|
||||
/// </summary>
|
||||
Count
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Xml;
|
||||
@@ -54,7 +53,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
protected override IContent PerformGet(int id)
|
||||
{
|
||||
var sql = GetBaseQuery(BaseQueryType.FullSingle)
|
||||
var sql = GetBaseQuery(false)
|
||||
.Where(GetBaseWhereClause(), new { Id = id })
|
||||
.Where<DocumentDto>(x => x.Newest, SqlSyntax)
|
||||
.OrderByDescending<ContentVersionDto>(x => x.VersionDate, SqlSyntax);
|
||||
@@ -82,15 +81,15 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
return s;
|
||||
};
|
||||
|
||||
var sqlBaseFull = GetBaseQuery(BaseQueryType.FullMultiple);
|
||||
var sqlBaseFull = GetBaseQuery(BaseQueryType.Full);
|
||||
var sqlBaseIds = GetBaseQuery(BaseQueryType.Ids);
|
||||
|
||||
return ProcessQuery(translate(sqlBaseFull), new PagingSqlQuery(translate(sqlBaseIds)));
|
||||
return ProcessQuery(translate(sqlBaseFull), translate(sqlBaseIds));
|
||||
}
|
||||
|
||||
protected override IEnumerable<IContent> PerformGetByQuery(IQuery<IContent> query)
|
||||
{
|
||||
var sqlBaseFull = GetBaseQuery(BaseQueryType.FullMultiple);
|
||||
var sqlBaseFull = GetBaseQuery(BaseQueryType.Full);
|
||||
var sqlBaseIds = GetBaseQuery(BaseQueryType.Ids);
|
||||
|
||||
Func<SqlTranslator<IContent>, Sql> translate = (translator) =>
|
||||
@@ -104,25 +103,13 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
var translatorFull = new SqlTranslator<IContent>(sqlBaseFull, query);
|
||||
var translatorIds = new SqlTranslator<IContent>(sqlBaseIds, query);
|
||||
|
||||
return ProcessQuery(translate(translatorFull), new PagingSqlQuery(translate(translatorIds)));
|
||||
return ProcessQuery(translate(translatorFull), translate(translatorIds));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Overrides of PetaPocoRepositoryBase<IContent>
|
||||
|
||||
/// <summary>
|
||||
/// Returns the base query to return Content
|
||||
/// </summary>
|
||||
/// <param name="queryType"></param>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// Content queries will differ depending on what needs to be returned:
|
||||
/// * FullSingle: When querying for a single document, this will include the Outer join to fetch the content item's published version info
|
||||
/// * FullMultiple: When querying for multiple documents, this will exclude the Outer join to fetch the content item's published version info - this info would need to be fetched separately
|
||||
/// * Ids: This would essentially be the same as FullMultiple however the columns specified will only return the Ids for the documents
|
||||
/// * Count: A query to return the count for documents
|
||||
/// </remarks>
|
||||
protected override Sql GetBaseQuery(BaseQueryType queryType)
|
||||
{
|
||||
var sql = new Sql();
|
||||
@@ -135,14 +122,14 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
.InnerJoin<NodeDto>(SqlSyntax)
|
||||
.On<ContentDto, NodeDto>(SqlSyntax, left => left.NodeId, right => right.NodeId);
|
||||
|
||||
if (queryType == BaseQueryType.FullSingle)
|
||||
if (queryType == BaseQueryType.Full)
|
||||
{
|
||||
//The only reason we apply this left outer join is to be able to pull back the DocumentPublishedReadOnlyDto
|
||||
//information with the entire data set, so basically this will get both the latest document and also it's published
|
||||
//version if it has one. When performing a count or when retrieving Ids like in paging, this is unecessary
|
||||
//version if it has one. When performing a count or when just retrieving Ids like in paging, this is unecessary
|
||||
//and causes huge performance overhead for the SQL server, especially when sorting the result.
|
||||
//We also don't include this outer join when querying for multiple entities since it is much faster to fetch this information
|
||||
//in a separate query. For a single entity this is ok.
|
||||
//To fix this perf overhead we'd need another index on :
|
||||
// CREATE NON CLUSTERED INDEX ON cmsDocument.node + cmsDocument.published
|
||||
|
||||
var sqlx = string.Format("LEFT OUTER JOIN {0} {1} ON ({1}.{2}={0}.{2} AND {1}.{3}=1)",
|
||||
SqlSyntax.GetQuotedTableName("cmsDocument"),
|
||||
@@ -164,7 +151,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
protected override Sql GetBaseQuery(bool isCount)
|
||||
{
|
||||
return GetBaseQuery(isCount ? BaseQueryType.Count : BaseQueryType.FullSingle);
|
||||
return GetBaseQuery(isCount ? BaseQueryType.Count : BaseQueryType.Full);
|
||||
}
|
||||
|
||||
protected override string GetBaseWhereClause()
|
||||
@@ -235,10 +222,10 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
while (true)
|
||||
{
|
||||
// get the next group of nodes
|
||||
var sqlFull = translate(baseId, GetBaseQuery(BaseQueryType.FullMultiple));
|
||||
var sqlFull = translate(baseId, GetBaseQuery(BaseQueryType.Full));
|
||||
var sqlIds = translate(baseId, GetBaseQuery(BaseQueryType.Ids));
|
||||
|
||||
var xmlItems = ProcessQuery(SqlSyntax.SelectTop(sqlFull, groupSize), new PagingSqlQuery(SqlSyntax.SelectTop(sqlIds, groupSize)))
|
||||
var xmlItems = ProcessQuery(SqlSyntax.SelectTop(sqlFull, groupSize), SqlSyntax.SelectTop(sqlIds, groupSize))
|
||||
.Select(x => new ContentXmlDto { NodeId = x.Id, Xml = serializer(x).ToString() })
|
||||
.ToList();
|
||||
|
||||
@@ -258,7 +245,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
Logger.Error<MediaRepository>("Could not rebuild XML for nodeId=" + xmlItem.NodeId, e);
|
||||
}
|
||||
}
|
||||
baseId = xmlItems[xmlItems.Count - 1].NodeId;
|
||||
baseId = xmlItems.Last().NodeId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -270,15 +257,15 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
.OrderByDescending<ContentVersionDto>(x => x.VersionDate, SqlSyntax);
|
||||
};
|
||||
|
||||
var sqlFull = translate(GetBaseQuery(BaseQueryType.FullMultiple));
|
||||
var sqlFull = translate(GetBaseQuery(BaseQueryType.Full));
|
||||
var sqlIds = translate(GetBaseQuery(BaseQueryType.Ids));
|
||||
|
||||
return ProcessQuery(sqlFull, new PagingSqlQuery(sqlIds), true);
|
||||
return ProcessQuery(sqlFull, sqlIds, true);
|
||||
}
|
||||
|
||||
public override IContent GetByVersion(Guid versionId)
|
||||
{
|
||||
var sql = GetBaseQuery(BaseQueryType.FullSingle);
|
||||
var sql = GetBaseQuery(false);
|
||||
sql.Where("cmsContentVersion.VersionId = @VersionId", new { VersionId = versionId });
|
||||
sql.OrderByDescending<ContentVersionDto>(x => x.VersionDate, SqlSyntax);
|
||||
|
||||
@@ -688,12 +675,12 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
// ORDER BY substring(path, 1, len(path) - charindex(',', reverse(path))), sortOrder
|
||||
// but that's probably an overkill - sorting by level,sortOrder should be enough
|
||||
|
||||
var sqlFull = GetBaseQuery(BaseQueryType.FullMultiple);
|
||||
var sqlFull = GetBaseQuery(BaseQueryType.Full);
|
||||
var translatorFull = new SqlTranslator<IContent>(sqlFull, query);
|
||||
var sqlIds = GetBaseQuery(BaseQueryType.Ids);
|
||||
var translatorIds = new SqlTranslator<IContent>(sqlIds, query);
|
||||
|
||||
return ProcessQuery(translate(translatorFull), new PagingSqlQuery(translate(translatorIds)), true);
|
||||
return ProcessQuery(translate(translatorFull), translate(translatorIds), true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -873,7 +860,7 @@ order by umbracoNode.{2}, umbracoNode.parentID, umbracoNode.sortOrder",
|
||||
|
||||
return GetPagedResultsByQuery<DocumentDto>(query, pageIndex, pageSize, out totalRecords,
|
||||
new Tuple<string, string>("cmsDocument", "nodeId"),
|
||||
(sqlFull, pagingSqlQuery) => ProcessQuery(sqlFull, pagingSqlQuery), orderBy, orderDirection, orderBySystemField,
|
||||
(sqlFull, sqlIds) => ProcessQuery(sqlFull, sqlIds), orderBy, orderDirection, orderBySystemField,
|
||||
filterCallback);
|
||||
|
||||
}
|
||||
@@ -903,58 +890,23 @@ order by umbracoNode.{2}, umbracoNode.parentID, umbracoNode.sortOrder",
|
||||
|
||||
return base.GetDatabaseFieldNameForOrderBy(orderBy);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// This is the underlying method that processes most queries for this repository
|
||||
/// </summary>
|
||||
/// <param name="sqlFull">
|
||||
/// The FullMultiple SQL without the outer join to return all data required to create an IContent excluding it's published state data which this will query separately
|
||||
/// The full SQL with the outer join to return all data required to create an IContent
|
||||
/// </param>
|
||||
/// <param name="pagingSqlQuery">
|
||||
/// <param name="sqlIds">
|
||||
/// The Id SQL without the outer join to just return all document ids - used to process the properties for the content item
|
||||
/// </param>
|
||||
/// <param name="withCache"></param>
|
||||
/// <returns></returns>
|
||||
private IEnumerable<IContent> ProcessQuery(Sql sqlFull, PagingSqlQuery pagingSqlQuery, bool withCache = false)
|
||||
private IEnumerable<IContent> ProcessQuery(Sql sqlFull, Sql sqlIds, bool withCache = false)
|
||||
{
|
||||
// fetch returns a list so it's ok to iterate it in this method
|
||||
var dtos = Database.Fetch<DocumentDto, ContentVersionDto, ContentDto, NodeDto>(sqlFull);
|
||||
var dtos = Database.Fetch<DocumentDto, ContentVersionDto, ContentDto, NodeDto, DocumentPublishedReadOnlyDto>(sqlFull);
|
||||
if (dtos.Count == 0) return Enumerable.Empty<IContent>();
|
||||
|
||||
//Go and get all of the published version data separately for this data, this is because when we are querying
|
||||
//for multiple content items we don't include the outer join to fetch this data in the same query because
|
||||
//it is insanely slow. Instead we just fetch the published version data separately in one query.
|
||||
|
||||
//we need to parse the original SQL statement and reduce the columns to just cmsDocument.nodeId so that we can use
|
||||
// the statement to go get the published data for all of the items by using an inner join
|
||||
var parsedOriginalSql = "SELECT cmsDocument.nodeId " + sqlFull.SQL.Substring(sqlFull.SQL.IndexOf("FROM", StringComparison.Ordinal));
|
||||
//now remove everything from an Orderby clause and beyond
|
||||
if (parsedOriginalSql.InvariantContains("ORDER BY "))
|
||||
{
|
||||
parsedOriginalSql = parsedOriginalSql.Substring(0, parsedOriginalSql.LastIndexOf("ORDER BY ", StringComparison.Ordinal));
|
||||
}
|
||||
|
||||
var publishedSql = new Sql(@"SELECT *
|
||||
FROM cmsDocument AS doc2
|
||||
INNER JOIN
|
||||
(" + parsedOriginalSql + @") as docData
|
||||
ON doc2.nodeId = docData.nodeId
|
||||
WHERE doc2.published = 1
|
||||
ORDER BY doc2.nodeId
|
||||
", sqlFull.Arguments);
|
||||
|
||||
//go and get the published version data, we do a Query here and not a Fetch so we are
|
||||
//not allocating a whole list to memory just to allocate another list in memory since
|
||||
//we are assigning this data to a keyed collection for fast lookup below
|
||||
var publishedData = Database.Query<DocumentPublishedReadOnlyDto>(publishedSql);
|
||||
var publishedDataCollection = new DocumentPublishedReadOnlyDtoCollection();
|
||||
foreach (var publishedDto in publishedData)
|
||||
{
|
||||
//double check that there's no corrupt db data, there should only be a single published item
|
||||
if (publishedDataCollection.Contains(publishedDto.NodeId) == false)
|
||||
publishedDataCollection.Add(publishedDto);
|
||||
}
|
||||
|
||||
|
||||
var content = new IContent[dtos.Count];
|
||||
var defs = new List<DocumentDefinition>();
|
||||
@@ -968,8 +920,6 @@ ORDER BY doc2.nodeId
|
||||
for (var i = 0; i < dtos.Count; i++)
|
||||
{
|
||||
var dto = dtos[i];
|
||||
DocumentPublishedReadOnlyDto publishedDto;
|
||||
publishedDataCollection.TryGetValue(dto.NodeId, out publishedDto);
|
||||
|
||||
// if the cache contains the published version, use it
|
||||
if (withCache)
|
||||
@@ -997,7 +947,7 @@ ORDER BY doc2.nodeId
|
||||
contentTypes[dto.ContentVersionDto.ContentDto.ContentTypeId] = contentType;
|
||||
}
|
||||
|
||||
content[i] = ContentFactory.BuildEntity(dto, contentType, publishedDto);
|
||||
content[i] = ContentFactory.BuildEntity(dto, contentType);
|
||||
|
||||
// need template
|
||||
if (dto.TemplateId.HasValue && dto.TemplateId.Value > 0)
|
||||
@@ -1018,7 +968,7 @@ ORDER BY doc2.nodeId
|
||||
.ToDictionary(x => x.Id, x => x);
|
||||
|
||||
// load all properties for all documents from database in 1 query
|
||||
var propertyData = GetPropertyCollection(pagingSqlQuery, defs);
|
||||
var propertyData = GetPropertyCollection(sqlIds, defs);
|
||||
|
||||
// assign
|
||||
var dtoIndex = 0;
|
||||
@@ -1106,7 +1056,7 @@ ORDER BY doc2.nodeId
|
||||
|
||||
return currentName;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Dispose disposable properties
|
||||
/// </summary>
|
||||
@@ -1121,26 +1071,5 @@ ORDER BY doc2.nodeId
|
||||
_contentPreviewRepository.Dispose();
|
||||
_contentXmlRepository.Dispose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A keyed collection for fast lookup when retrieving a separate list of published version data
|
||||
/// </summary>
|
||||
private class DocumentPublishedReadOnlyDtoCollection : KeyedCollection<int, DocumentPublishedReadOnlyDto>
|
||||
{
|
||||
protected override int GetKeyForItem(DocumentPublishedReadOnlyDto item)
|
||||
{
|
||||
return item.NodeId;
|
||||
}
|
||||
|
||||
public bool TryGetValue(int key, out DocumentPublishedReadOnlyDto val)
|
||||
{
|
||||
if (Dictionary == null)
|
||||
{
|
||||
val = null;
|
||||
return false;
|
||||
}
|
||||
return Dictionary.TryGetValue(key, out val);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -68,7 +68,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
sql.Where("umbracoNode.id in (@ids)", new { ids = ids });
|
||||
}
|
||||
|
||||
return ProcessQuery(sql, new PagingSqlQuery(sql));
|
||||
return ProcessQuery(sql);
|
||||
}
|
||||
|
||||
protected override IEnumerable<IMedia> PerformGetByQuery(IQuery<IMedia> query)
|
||||
@@ -78,7 +78,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
var sql = translator.Translate()
|
||||
.OrderBy<NodeDto>(x => x.SortOrder, SqlSyntax);
|
||||
|
||||
return ProcessQuery(sql, new PagingSqlQuery(sql));
|
||||
return ProcessQuery(sql);
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -100,7 +100,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
protected override Sql GetBaseQuery(bool isCount)
|
||||
{
|
||||
return GetBaseQuery(isCount ? BaseQueryType.Count : BaseQueryType.FullSingle);
|
||||
return GetBaseQuery(isCount ? BaseQueryType.Count : BaseQueryType.Full);
|
||||
}
|
||||
|
||||
protected override string GetBaseWhereClause()
|
||||
@@ -143,24 +143,13 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
var sql = GetBaseQuery(false)
|
||||
.Where(GetBaseWhereClause(), new { Id = id })
|
||||
.OrderByDescending<ContentVersionDto>(x => x.VersionDate, SqlSyntax);
|
||||
return ProcessQuery(sql, new PagingSqlQuery(sql), true);
|
||||
return ProcessQuery(sql, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This is the underlying method that processes most queries for this repository
|
||||
/// </summary>
|
||||
/// <param name="sqlFull">
|
||||
/// The full SQL to select all media data
|
||||
/// </param>
|
||||
/// <param name="pagingSqlQuery">
|
||||
/// The Id SQL to just return all media ids - used to process the properties for the media item
|
||||
/// </param>
|
||||
/// <param name="withCache"></param>
|
||||
/// <returns></returns>
|
||||
private IEnumerable<IMedia> ProcessQuery(Sql sqlFull, PagingSqlQuery pagingSqlQuery, bool withCache = false)
|
||||
private IEnumerable<IMedia> ProcessQuery(Sql sql, bool withCache = false)
|
||||
{
|
||||
// fetch returns a list so it's ok to iterate it in this method
|
||||
var dtos = Database.Fetch<ContentVersionDto, ContentDto, NodeDto>(sqlFull);
|
||||
var dtos = Database.Fetch<ContentVersionDto, ContentDto, NodeDto>(sql);
|
||||
var content = new IMedia[dtos.Count];
|
||||
var defs = new List<DocumentDefinition>();
|
||||
|
||||
@@ -211,7 +200,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
}
|
||||
|
||||
// load all properties for all documents from database in 1 query
|
||||
var propertyData = GetPropertyCollection(pagingSqlQuery, defs);
|
||||
var propertyData = GetPropertyCollection(sql, defs);
|
||||
|
||||
// assign
|
||||
var dtoIndex = 0;
|
||||
@@ -268,8 +257,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
query = query
|
||||
.Where<NodeDto>(x => x.NodeId > baseId, SqlSyntax)
|
||||
.OrderBy<NodeDto>(x => x.NodeId, SqlSyntax);
|
||||
var sql = SqlSyntax.SelectTop(query, groupSize);
|
||||
var xmlItems = ProcessQuery(sql, new PagingSqlQuery(sql))
|
||||
var xmlItems = ProcessQuery(SqlSyntax.SelectTop(query, groupSize))
|
||||
.Select(x => new ContentXmlDto { NodeId = x.Id, Xml = serializer(x).ToString() })
|
||||
.ToList();
|
||||
|
||||
@@ -517,7 +505,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
return GetPagedResultsByQuery<ContentVersionDto>(query, pageIndex, pageSize, out totalRecords,
|
||||
new Tuple<string, string>("cmsContentVersion", "contentId"),
|
||||
(sqlFull, pagingSqlQuery) => ProcessQuery(sqlFull, pagingSqlQuery), orderBy, orderDirection, orderBySystemField,
|
||||
(sqlFull, sqlIds) => ProcessQuery(sqlFull), orderBy, orderDirection, orderBySystemField,
|
||||
filterCallback);
|
||||
|
||||
}
|
||||
@@ -525,7 +513,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
/// <summary>
|
||||
/// Private method to create a media object from a ContentDto
|
||||
/// </summary>
|
||||
/// <param name="dto"></param>
|
||||
/// <param name="d"></param>
|
||||
/// <param name="versionId"></param>
|
||||
/// <param name="docSql"></param>
|
||||
/// <returns></returns>
|
||||
@@ -537,7 +525,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
var docDef = new DocumentDefinition(dto.NodeId, versionId, media.UpdateDate, media.CreateDate, contentType);
|
||||
|
||||
var properties = GetPropertyCollection(new PagingSqlQuery(docSql), new[] { docDef });
|
||||
var properties = GetPropertyCollection(docSql, new[] { docDef });
|
||||
|
||||
media.Properties = properties[dto.NodeId];
|
||||
|
||||
|
||||
@@ -68,7 +68,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
sql.Where("umbracoNode.id in (@ids)", new { ids = ids });
|
||||
}
|
||||
|
||||
return ProcessQuery(sql, new PagingSqlQuery(sql));
|
||||
return ProcessQuery(sql);
|
||||
|
||||
}
|
||||
|
||||
@@ -90,7 +90,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
baseQuery.Append(new Sql("WHERE umbracoNode.id IN (" + sql.SQL + ")", sql.Arguments))
|
||||
.OrderBy<NodeDto>(x => x.SortOrder);
|
||||
|
||||
return ProcessQuery(baseQuery, new PagingSqlQuery(baseQuery));
|
||||
return ProcessQuery(baseQuery);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -98,7 +98,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
var sql = translator.Translate()
|
||||
.OrderBy<NodeDto>(x => x.SortOrder);
|
||||
|
||||
return ProcessQuery(sql, new PagingSqlQuery(sql));
|
||||
return ProcessQuery(sql);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -129,7 +129,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
protected override Sql GetBaseQuery(bool isCount)
|
||||
{
|
||||
return GetBaseQuery(isCount ? BaseQueryType.Count : BaseQueryType.FullSingle);
|
||||
return GetBaseQuery(isCount ? BaseQueryType.Count : BaseQueryType.Full);
|
||||
}
|
||||
|
||||
protected override string GetBaseWhereClause()
|
||||
@@ -385,7 +385,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
var sql = GetBaseQuery(false)
|
||||
.Where(GetBaseWhereClause(), new { Id = id })
|
||||
.OrderByDescending<ContentVersionDto>(x => x.VersionDate, SqlSyntax);
|
||||
return ProcessQuery(sql, new PagingSqlQuery(sql), true);
|
||||
return ProcessQuery(sql, true);
|
||||
}
|
||||
|
||||
public void RebuildXmlStructures(Func<IMember, XElement> serializer, int groupSize = 200, IEnumerable<int> contentTypeIds = null)
|
||||
@@ -408,8 +408,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
query = query
|
||||
.Where<NodeDto>(x => x.NodeId > baseId)
|
||||
.OrderBy<NodeDto>(x => x.NodeId, SqlSyntax);
|
||||
var sql = SqlSyntax.SelectTop(query, groupSize);
|
||||
var xmlItems = ProcessQuery(sql, new PagingSqlQuery(sql))
|
||||
var xmlItems = ProcessQuery(SqlSyntax.SelectTop(query, groupSize))
|
||||
.Select(x => new ContentXmlDto { NodeId = x.Id, Xml = serializer(x).ToString() })
|
||||
.ToList();
|
||||
|
||||
@@ -450,7 +449,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
var factory = new MemberFactory(memberType, NodeObjectTypeId, dto.NodeId);
|
||||
var media = factory.BuildEntity(dto);
|
||||
|
||||
var properties = GetPropertyCollection(new PagingSqlQuery(sql), new[] { new DocumentDefinition(dto.NodeId, dto.ContentVersionDto.VersionId, media.UpdateDate, media.CreateDate, memberType) });
|
||||
var properties = GetPropertyCollection(sql, new[] { new DocumentDefinition(dto.NodeId, dto.ContentVersionDto.VersionId, media.UpdateDate, media.CreateDate, memberType) });
|
||||
|
||||
media.Properties = properties[dto.NodeId];
|
||||
|
||||
@@ -541,7 +540,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
.OrderByDescending<ContentVersionDto>(x => x.VersionDate)
|
||||
.OrderBy<NodeDto>(x => x.SortOrder);
|
||||
|
||||
return ProcessQuery(sql, new PagingSqlQuery(sql));
|
||||
return ProcessQuery(sql);
|
||||
|
||||
}
|
||||
|
||||
@@ -602,7 +601,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
return GetPagedResultsByQuery<MemberDto>(query, pageIndex, pageSize, out totalRecords,
|
||||
new Tuple<string, string>("cmsMember", "nodeId"),
|
||||
(sqlFull, sqlIds) => ProcessQuery(sqlFull, sqlIds), orderBy, orderDirection, orderBySystemField,
|
||||
(sqlFull, sqlIds) => ProcessQuery(sqlFull), orderBy, orderDirection, orderBySystemField,
|
||||
filterCallback);
|
||||
}
|
||||
|
||||
@@ -642,21 +641,10 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
return base.GetEntityPropertyNameForOrderBy(orderBy);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This is the underlying method that processes most queries for this repository
|
||||
/// </summary>
|
||||
/// <param name="sqlFull">
|
||||
/// The full SQL to select all member data
|
||||
/// </param>
|
||||
/// <param name="pagingSqlQuery">
|
||||
/// The Id SQL to just return all member ids - used to process the properties for the member item
|
||||
/// </param>
|
||||
/// <param name="withCache"></param>
|
||||
/// <returns></returns>
|
||||
private IEnumerable<IMember> ProcessQuery(Sql sqlFull, PagingSqlQuery pagingSqlQuery, bool withCache = false)
|
||||
private IEnumerable<IMember> ProcessQuery(Sql sql, bool withCache = false)
|
||||
{
|
||||
// fetch returns a list so it's ok to iterate it in this method
|
||||
var dtos = Database.Fetch<MemberDto, ContentVersionDto, ContentDto, NodeDto>(sqlFull);
|
||||
var dtos = Database.Fetch<MemberDto, ContentVersionDto, ContentDto, NodeDto>(sql);
|
||||
|
||||
var content = new IMember[dtos.Count];
|
||||
var defs = new List<DocumentDefinition>();
|
||||
@@ -693,7 +681,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
}
|
||||
|
||||
// load all properties for all documents from database in 1 query
|
||||
var propertyData = GetPropertyCollection(pagingSqlQuery, defs);
|
||||
var propertyData = GetPropertyCollection(sql, defs);
|
||||
|
||||
// assign
|
||||
var dtoIndex = 0;
|
||||
|
||||
@@ -432,7 +432,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
/// <exception cref="System.ArgumentNullException">orderBy</exception>
|
||||
protected IEnumerable<TEntity> GetPagedResultsByQuery<TDto>(IQuery<TEntity> query, long pageIndex, int pageSize, out long totalRecords,
|
||||
Tuple<string, string> nodeIdSelect,
|
||||
Func<Sql, PagingSqlQuery<TDto>, IEnumerable<TEntity>> processQuery,
|
||||
Func<Sql, Sql, IEnumerable<TEntity>> processQuery,
|
||||
string orderBy,
|
||||
Direction orderDirection,
|
||||
bool orderBySystemField,
|
||||
@@ -443,7 +443,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
// Get base query for returning IDs
|
||||
var sqlBaseIds = GetBaseQuery(BaseQueryType.Ids);
|
||||
// Get base query for returning all data
|
||||
var sqlBaseFull = GetBaseQuery(BaseQueryType.FullMultiple);
|
||||
var sqlBaseFull = GetBaseQuery(BaseQueryType.Full);
|
||||
|
||||
if (query == null) query = new Query<TEntity>();
|
||||
var translatorIds = new SqlTranslator<TEntity>(sqlBaseIds, query);
|
||||
@@ -466,7 +466,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
// the pageResult, then the GetAll will actually return ALL records in the db.
|
||||
if (pagedResult.Items.Any())
|
||||
{
|
||||
//Create the inner paged query that was used above to get the paged result, we'll use that as the inner sub query
|
||||
//Crete the inner paged query that was used above to get the paged result, we'll use that as the inner sub query
|
||||
var args = sqlNodeIdsWithSort.Arguments;
|
||||
string sqlStringCount, sqlStringPage;
|
||||
Database.BuildPageQueries<TDto>(pageIndex * pageSize, pageSize, sqlNodeIdsWithSort.SQL, ref args, out sqlStringCount, out sqlStringPage);
|
||||
@@ -486,8 +486,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
var fullQuery = GetSortedSqlForPagedResults(
|
||||
GetFilteredSqlForPagedResults(fullQueryWithPagedInnerJoin, defaultFilter),
|
||||
orderDirection, orderBy, orderBySystemField, nodeIdSelect);
|
||||
|
||||
return processQuery(fullQuery, new PagingSqlQuery<TDto>(Database, sqlNodeIdsWithSort, pageIndex, pageSize));
|
||||
|
||||
return processQuery(fullQuery, sqlNodeIdsWithSort);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -497,47 +497,18 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the property collection for a non-paged query
|
||||
/// </summary>
|
||||
/// <param name="sql"></param>
|
||||
/// <param name="documentDefs"></param>
|
||||
/// <returns></returns>
|
||||
protected IDictionary<int, PropertyCollection> GetPropertyCollection(
|
||||
Sql sql,
|
||||
IReadOnlyCollection<DocumentDefinition> documentDefs)
|
||||
{
|
||||
return GetPropertyCollection(new PagingSqlQuery(sql), documentDefs);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the property collection for a query
|
||||
/// </summary>
|
||||
/// <param name="pagingSqlQuery"></param>
|
||||
/// <param name="documentDefs"></param>
|
||||
/// <returns></returns>
|
||||
protected IDictionary<int, PropertyCollection> GetPropertyCollection(
|
||||
PagingSqlQuery pagingSqlQuery,
|
||||
Sql docSql,
|
||||
IReadOnlyCollection<DocumentDefinition> documentDefs)
|
||||
{
|
||||
if (documentDefs.Count == 0) return new Dictionary<int, PropertyCollection>();
|
||||
|
||||
//initialize to the query passed in
|
||||
var docSql = pagingSqlQuery.PrePagedSql;
|
||||
|
||||
//we need to parse the original SQL statement and reduce the columns to just cmsContent.nodeId, cmsContentVersion.VersionId so that we can use
|
||||
// the statement to go get the property data for all of the items by using an inner join
|
||||
var parsedOriginalSql = "SELECT {0} " + docSql.SQL.Substring(docSql.SQL.IndexOf("FROM", StringComparison.Ordinal));
|
||||
|
||||
if (pagingSqlQuery.HasPaging)
|
||||
//now remove everything from an Orderby clause and beyond
|
||||
if (parsedOriginalSql.InvariantContains("ORDER BY "))
|
||||
{
|
||||
//if this is a paged query, build the paged query with the custom column substitution, then re-assign
|
||||
docSql = pagingSqlQuery.BuildPagedQuery("{0}");
|
||||
parsedOriginalSql = docSql.SQL;
|
||||
}
|
||||
else if (parsedOriginalSql.InvariantContains("ORDER BY "))
|
||||
{
|
||||
//now remove everything from an Orderby clause and beyond if this is unpaged data
|
||||
parsedOriginalSql = parsedOriginalSql.Substring(0, parsedOriginalSql.LastIndexOf("ORDER BY ", StringComparison.Ordinal));
|
||||
}
|
||||
|
||||
@@ -554,7 +525,7 @@ WHERE EXISTS(
|
||||
INNER JOIN cmsPropertyType
|
||||
ON b.datatypeNodeId = cmsPropertyType.dataTypeId
|
||||
INNER JOIN
|
||||
(" + string.Format(parsedOriginalSql, "cmsContent.contentType") + @") as docData
|
||||
(" + string.Format(parsedOriginalSql, "DISTINCT cmsContent.contentType") + @") as docData
|
||||
ON cmsPropertyType.contentTypeId = docData.contentType
|
||||
WHERE a.id = b.id)", docSql.Arguments);
|
||||
|
||||
@@ -675,7 +646,28 @@ ORDER BY contentNodeId, propertytypeid
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
|
||||
public class DocumentDefinition
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="T:System.Object"/> class.
|
||||
/// </summary>
|
||||
public DocumentDefinition(int id, Guid version, DateTime versionDate, DateTime createDate, IContentTypeComposition composition)
|
||||
{
|
||||
Id = id;
|
||||
Version = version;
|
||||
VersionDate = versionDate;
|
||||
CreateDate = createDate;
|
||||
Composition = composition;
|
||||
}
|
||||
|
||||
public int Id { get; set; }
|
||||
public Guid Version { get; set; }
|
||||
public DateTime VersionDate { get; set; }
|
||||
public DateTime CreateDate { get; set; }
|
||||
public IContentTypeComposition Composition { get; set; }
|
||||
}
|
||||
|
||||
protected virtual string GetDatabaseFieldNameForOrderBy(string orderBy)
|
||||
{
|
||||
// Translate the passed order by field (which were originally defined for in-memory object sorting
|
||||
@@ -771,92 +763,5 @@ ORDER BY contentNodeId, propertytypeid
|
||||
/// <param name="queryType"></param>
|
||||
/// <returns></returns>
|
||||
protected abstract Sql GetBaseQuery(BaseQueryType queryType);
|
||||
|
||||
internal class DocumentDefinition
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="T:System.Object"/> class.
|
||||
/// </summary>
|
||||
public DocumentDefinition(int id, Guid version, DateTime versionDate, DateTime createDate, IContentTypeComposition composition)
|
||||
{
|
||||
Id = id;
|
||||
Version = version;
|
||||
VersionDate = versionDate;
|
||||
CreateDate = createDate;
|
||||
Composition = composition;
|
||||
}
|
||||
|
||||
public int Id { get; set; }
|
||||
public Guid Version { get; set; }
|
||||
public DateTime VersionDate { get; set; }
|
||||
public DateTime CreateDate { get; set; }
|
||||
public IContentTypeComposition Composition { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An object representing a query that may contain paging information
|
||||
/// </summary>
|
||||
internal class PagingSqlQuery
|
||||
{
|
||||
public Sql PrePagedSql { get; private set; }
|
||||
|
||||
public PagingSqlQuery(Sql prePagedSql)
|
||||
{
|
||||
PrePagedSql = prePagedSql;
|
||||
}
|
||||
|
||||
public virtual bool HasPaging
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
public virtual Sql BuildPagedQuery(string selectColumns)
|
||||
{
|
||||
throw new InvalidOperationException("This query has no paging information");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An object representing a query that contains paging information
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
internal class PagingSqlQuery<T> : PagingSqlQuery
|
||||
{
|
||||
private readonly Database _db;
|
||||
private readonly long _pageIndex;
|
||||
private readonly int _pageSize;
|
||||
|
||||
public PagingSqlQuery(Database db, Sql prePagedSql, long pageIndex, int pageSize) : base(prePagedSql)
|
||||
{
|
||||
_db = db;
|
||||
_pageIndex = pageIndex;
|
||||
_pageSize = pageSize;
|
||||
}
|
||||
|
||||
public override bool HasPaging
|
||||
{
|
||||
get { return _pageSize > 0; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a paged query based on the original query and subtitutes the selectColumns specified
|
||||
/// </summary>
|
||||
/// <param name="selectColumns"></param>
|
||||
/// <returns></returns>
|
||||
public override Sql BuildPagedQuery(string selectColumns)
|
||||
{
|
||||
if (HasPaging == false) throw new InvalidOperationException("This query has no paging information");
|
||||
|
||||
var resultSql = string.Format("SELECT {0} {1}", selectColumns, PrePagedSql.SQL.Substring(PrePagedSql.SQL.IndexOf("FROM", StringComparison.Ordinal)));
|
||||
|
||||
//this query is meant to be paged so we need to generate the paging syntax
|
||||
//Create the inner paged query that was used above to get the paged result, we'll use that as the inner sub query
|
||||
var args = PrePagedSql.Arguments;
|
||||
string sqlStringCount, sqlStringPage;
|
||||
_db.BuildPageQueries<T>(_pageIndex * _pageSize, _pageSize, resultSql, ref args, out sqlStringCount, out sqlStringPage);
|
||||
|
||||
return new Sql(sqlStringPage, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,23 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
|
||||
|
||||
namespace Umbraco.Core.Persistence.SqlSyntax
|
||||
namespace Umbraco.Core.Persistence.SqlSyntax
|
||||
{
|
||||
internal static class SqlSyntaxProviderExtensions
|
||||
{
|
||||
public static IEnumerable<DbIndexDefinition> GetDefinedIndexesDefinitions(this ISqlSyntaxProvider sql, Database db)
|
||||
{
|
||||
return sql.GetDefinedIndexes(db)
|
||||
.Select(x => new DbIndexDefinition()
|
||||
{
|
||||
TableName = x.Item1,
|
||||
IndexName = x.Item2,
|
||||
ColumnName = x.Item3,
|
||||
IsUnique = x.Item4
|
||||
}).ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the quotes tableName.columnName combo
|
||||
/// </summary>
|
||||
|
||||
@@ -735,26 +735,6 @@ namespace Umbraco.Core.Services
|
||||
return empty.Union(files.Except(empty));
|
||||
}
|
||||
|
||||
public void CreatePartialViewFolder(string folderPath)
|
||||
{
|
||||
var uow = _fileUowProvider.GetUnitOfWork();
|
||||
using (var repository = RepositoryFactory.CreatePartialViewRepository(uow))
|
||||
{
|
||||
((PartialViewRepository)repository).AddFolder(folderPath);
|
||||
uow.Commit();
|
||||
}
|
||||
}
|
||||
|
||||
public void CreatePartialViewMacroFolder(string folderPath)
|
||||
{
|
||||
var uow = _fileUowProvider.GetUnitOfWork();
|
||||
using (var repository = RepositoryFactory.CreatePartialViewMacroRepository(uow))
|
||||
{
|
||||
((PartialViewMacroRepository)repository).AddFolder(folderPath);
|
||||
uow.Commit();
|
||||
}
|
||||
}
|
||||
|
||||
public void DeletePartialViewFolder(string folderPath)
|
||||
{
|
||||
using (var uow = _fileUowProvider.GetUnitOfWork())
|
||||
|
||||
@@ -11,8 +11,6 @@ namespace Umbraco.Core.Services
|
||||
public interface IFileService : IService
|
||||
{
|
||||
IEnumerable<string> GetPartialViewSnippetNames(params string[] filterNames);
|
||||
void CreatePartialViewFolder(string folderPath);
|
||||
void CreatePartialViewMacroFolder(string folderPath);
|
||||
void DeletePartialViewFolder(string folderPath);
|
||||
void DeletePartialViewMacroFolder(string folderPath);
|
||||
IPartialView GetPartialView(string path);
|
||||
|
||||
@@ -1716,24 +1716,6 @@ namespace Umbraco.Core.Services
|
||||
#region Package Building
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// This method can be used to trigger the 'ImportedPackage' event when a package is installed by something else but this service.
|
||||
/// </summary>
|
||||
/// <param name="args"></param>
|
||||
internal static void OnImportedPackage(ImportPackageEventArgs<InstallationSummary> args)
|
||||
{
|
||||
ImportedPackage.RaiseEvent(args, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method can be used to trigger the 'UninstalledPackage' event when a package is uninstalled by something else but this service.
|
||||
/// </summary>
|
||||
/// <param name="args"></param>
|
||||
internal static void OnUninstalledPackage(UninstallPackageEventArgs<UninstallationSummary> args)
|
||||
{
|
||||
UninstalledPackage.RaiseEvent(args, null);
|
||||
}
|
||||
|
||||
#region Event Handlers
|
||||
/// <summary>
|
||||
/// Occurs before Importing Content
|
||||
@@ -1894,15 +1876,10 @@ namespace Umbraco.Core.Services
|
||||
internal static event TypedEventHandler<IPackagingService, ImportPackageEventArgs<string>> ImportingPackage;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs after a package is imported
|
||||
/// Occurs after a apckage is imported
|
||||
/// </summary>
|
||||
internal static event TypedEventHandler<IPackagingService, ImportPackageEventArgs<InstallationSummary>> ImportedPackage;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs after a package is uninstalled
|
||||
/// </summary>
|
||||
internal static event TypedEventHandler<IPackagingService, UninstallPackageEventArgs<UninstallationSummary>> UninstalledPackage;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -215,7 +215,7 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.GetUnitOfWork(commit: true))
|
||||
{
|
||||
var repository = RepositoryFactory.CreateRelationRepository(uow);
|
||||
var query = new Query<IRelation>().Where(x => x.ParentId == id || x.ChildId == id);
|
||||
var query = new Query<IRelation>().Where(x => x.ChildId == id || x.ParentId == id);
|
||||
return repository.GetByQuery(query);
|
||||
}
|
||||
}
|
||||
@@ -230,7 +230,7 @@ namespace Umbraco.Core.Services
|
||||
if (relationType == null) return Enumerable.Empty<IRelation>();
|
||||
|
||||
var relationRepo = RepositoryFactory.CreateRelationRepository(uow);
|
||||
var query = new Query<IRelation>().Where(x => (x.ParentId == id || x.ChildId == id) && x.RelationTypeId == relationType.Id);
|
||||
var query = new Query<IRelation>().Where(x => (x.ChildId == id || x.ParentId == id) && x.RelationTypeId == relationType.Id);
|
||||
return relationRepo.GetByQuery(query);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -285,30 +285,18 @@ namespace Umbraco.Core
|
||||
var member = entity as IMember;
|
||||
if (member != null) return member.GetUdi();
|
||||
|
||||
var stylesheet = entity as Stylesheet;
|
||||
if (stylesheet != null) return stylesheet.GetUdi();
|
||||
|
||||
var script = entity as Script;
|
||||
if (script != null) return script.GetUdi();
|
||||
|
||||
var dictionaryItem = entity as IDictionaryItem;
|
||||
if (dictionaryItem != null) return dictionaryItem.GetUdi();
|
||||
var contentBase = entity as IContentBase;
|
||||
if (contentBase != null) return contentBase.GetUdi();
|
||||
|
||||
var macro = entity as IMacro;
|
||||
if (macro != null) return macro.GetUdi();
|
||||
|
||||
var partialView = entity as IPartialView;
|
||||
if (partialView != null) return partialView.GetUdi();
|
||||
|
||||
var xsltFile = entity as IXsltFile;
|
||||
if (xsltFile != null) return xsltFile.GetUdi();
|
||||
|
||||
var contentBase = entity as IContentBase;
|
||||
if (contentBase != null) return contentBase.GetUdi();
|
||||
|
||||
var relationType = entity as IRelationType;
|
||||
if (relationType != null) return relationType.GetUdi();
|
||||
|
||||
var dictionaryItem = entity as IDictionaryItem;
|
||||
if (dictionaryItem != null) return dictionaryItem.GetUdi();
|
||||
|
||||
throw new NotSupportedException(string.Format("Entity type {0} is not supported.", entity.GetType().FullName));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -314,7 +314,6 @@
|
||||
<Compile Include="Deploy\IFileStore.cs" />
|
||||
<Compile Include="Events\EventDefinitionFilter.cs" />
|
||||
<Compile Include="OrderedHashSet.cs" />
|
||||
<Compile Include="Events\UninstallPackageEventArgs.cs" />
|
||||
<Compile Include="Models\GridValue.cs" />
|
||||
<Compile Include="Deploy\IArtifact.cs" />
|
||||
<Compile Include="Deploy\IArtifactSignature.cs" />
|
||||
@@ -451,7 +450,6 @@
|
||||
<Compile Include="Models\DoNotCloneAttribute.cs" />
|
||||
<Compile Include="Models\IDomain.cs" />
|
||||
<Compile Include="NamedUdiRange.cs" />
|
||||
<Compile Include="Packaging\Models\UninstallationSummary.cs" />
|
||||
<Compile Include="Persistence\BulkDataReader.cs" />
|
||||
<Compile Include="Persistence\Constants-Locks.cs" />
|
||||
<Compile Include="Persistence\DatabaseNodeLockExtensions.cs" />
|
||||
@@ -481,8 +479,6 @@
|
||||
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenFourZero\AddUniqueIdPropertyTypeGroupColumn.cs" />
|
||||
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenFourZero\RemoveParentIdPropertyTypeGroupColumn.cs" />
|
||||
<Compile Include="Persistence\Mappers\TaskTypeMapper.cs" />
|
||||
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenSixZero\AddIndexToCmsMemberLoginName.cs" />
|
||||
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenSixZero\AddIndexesToUmbracoRelationTables.cs" />
|
||||
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenSixZero\AddIndexToUmbracoNodePath.cs" />
|
||||
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenSixZero\AddRelationTypeUniqueIdColumn.cs" />
|
||||
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenSixZero\AddMacroUniqueIdColumn.cs" />
|
||||
|
||||
@@ -56,14 +56,5 @@ namespace Umbraco.Tests.IO
|
||||
Assert.AreEqual(IOHelper.MapPath(SystemDirectories.WebServices, true), IOHelper.MapPath(SystemDirectories.WebServices, false));
|
||||
Assert.AreEqual(IOHelper.MapPath(SystemDirectories.Xslt, true), IOHelper.MapPath(SystemDirectories.Xslt, false));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void EnsurePathIsApplicationRootPrefixed()
|
||||
{
|
||||
//Assert
|
||||
Assert.AreEqual("~/Views/Template.cshtml", IOHelper.EnsurePathIsApplicationRootPrefixed("Views/Template.cshtml"));
|
||||
Assert.AreEqual("~/Views/Template.cshtml", IOHelper.EnsurePathIsApplicationRootPrefixed("/Views/Template.cshtml"));
|
||||
Assert.AreEqual("~/Views/Template.cshtml", IOHelper.EnsurePathIsApplicationRootPrefixed("~/Views/Template.cshtml"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -364,7 +364,8 @@ namespace Umbraco.Tests.IO
|
||||
|
||||
ss.Complete();
|
||||
|
||||
Assert.IsTrue(File.Exists(path + "/ShadowSystem/path/to/some/dir/f1.txt")); // *not* cleaning
|
||||
// yes we are cleaning now
|
||||
//Assert.IsTrue(File.Exists(path + "/ShadowSystem/path/to/some/dir/f1.txt")); // *not* cleaning
|
||||
Assert.IsTrue(File.Exists(path + "/ShadowTests/path/to/some/dir/f1.txt"));
|
||||
Assert.IsFalse(File.Exists(path + "/ShadowTests/sub/sub/f2.txt"));
|
||||
}
|
||||
@@ -558,7 +559,7 @@ namespace Umbraco.Tests.IO
|
||||
Assert.AreEqual(1, ae.InnerExceptions.Count);
|
||||
e = ae.InnerExceptions[0];
|
||||
Assert.IsNotNull(e.InnerException);
|
||||
Assert.IsInstanceOf<UnauthorizedAccessException>(e.InnerException);
|
||||
Assert.IsInstanceOf<Exception>(e.InnerException);
|
||||
}
|
||||
|
||||
// still, the rest of the changes has been applied ok
|
||||
|
||||
@@ -121,19 +121,6 @@ WHERE (([umbracoNode].[nodeObjectType] = @0))) x)".Replace(Environment.NewLine,
|
||||
Assert.AreEqual("CREATE UNIQUE NONCLUSTERED INDEX [IX_A] ON [TheTable] ([A])", createExpression.ToString());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CreateIndexBuilder_SqlServer_Unique_CreatesUniqueNonClusteredIndex_Multi_Columnn()
|
||||
{
|
||||
var sqlSyntax = new SqlServerSyntaxProvider();
|
||||
var createExpression = new CreateIndexExpression(DatabaseProviders.SqlServer, new[] { DatabaseProviders.SqlServer }, sqlSyntax)
|
||||
{
|
||||
Index = { Name = "IX_AB" }
|
||||
};
|
||||
var builder = new CreateIndexBuilder(createExpression);
|
||||
builder.OnTable("TheTable").OnColumn("A").Ascending().OnColumn("B").Ascending().WithOptions().Unique();
|
||||
Assert.AreEqual("CREATE UNIQUE NONCLUSTERED INDEX [IX_AB] ON [TheTable] ([A],[B])", createExpression.ToString());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CreateIndexBuilder_SqlServer_Clustered_CreatesClusteredIndex()
|
||||
{
|
||||
|
||||
@@ -205,38 +205,6 @@ function codefileResource($q, $http, umbDataFormatter, umbRequestHelper) {
|
||||
"codeFileApiBaseUrl",
|
||||
"GetScaffold?type=" + type + "&id=" + id + "&snippetName=" + snippetName)),
|
||||
"Failed to get scaffold for" + type);
|
||||
},
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.resources.codefileResource#createContainer
|
||||
* @methodOf umbraco.resources.codefileResource
|
||||
*
|
||||
* @description
|
||||
* Creates a container/folder
|
||||
*
|
||||
* ##usage
|
||||
* <pre>
|
||||
* codefileResource.createContainer("partialViews", "folder%2ffolder", "folder")
|
||||
* .then(function(data) {
|
||||
* alert('its here!');
|
||||
* });
|
||||
* </pre>
|
||||
*
|
||||
* @param {string} File type: (scripts, partialViews, partialViewMacros).
|
||||
* @param {string} Parent Id: url encoded path
|
||||
* @param {string} Container name
|
||||
* @returns {Promise} resourcePromise object.
|
||||
*
|
||||
*/
|
||||
|
||||
createContainer: function(type, parentId, name) {
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.post(umbRequestHelper.getApiUrl(
|
||||
"codeFileApiBaseUrl",
|
||||
"PostCreateContainer",
|
||||
{ type: type, parentId: parentId, name: encodeURIComponent(name) })),
|
||||
'Failed to create a folder under parent id ' + parentId);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@@ -1,17 +1,14 @@
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
function PartialViewMacrosCreateController($scope, codefileResource, $location, navigationService, formHelper, localizationService, appState) {
|
||||
function PartialViewMacrosCreateController($scope, codefileResource, $location, navigationService) {
|
||||
|
||||
var vm = this;
|
||||
var node = $scope.dialogOptions.currentNode;
|
||||
var localizeCreateFolder = localizationService.localize("defaultdialog_createFolder");
|
||||
|
||||
vm.snippets = [];
|
||||
vm.showSnippets = false;
|
||||
vm.creatingFolder = false;
|
||||
vm.createFolderError = "";
|
||||
vm.folderName = "";
|
||||
|
||||
vm.createPartialViewMacro = createPartialViewMacro;
|
||||
vm.showCreateFolder = showCreateFolder;
|
||||
@@ -42,38 +39,8 @@
|
||||
vm.creatingFolder = true;
|
||||
}
|
||||
|
||||
function createFolder(form) {
|
||||
if (formHelper.submitForm({scope: $scope, formCtrl: form, statusMessage: localizeCreateFolder})) {
|
||||
function createFolder() {
|
||||
|
||||
codefileResource.createContainer("partialViewMacros", node.id, vm.folderName).then(function (saved) {
|
||||
|
||||
navigationService.hideMenu();
|
||||
|
||||
navigationService.syncTree({
|
||||
tree: "partialViewMacros",
|
||||
path: saved.path,
|
||||
forceReload: true,
|
||||
activate: true
|
||||
});
|
||||
|
||||
formHelper.resetForm({
|
||||
scope: $scope
|
||||
});
|
||||
|
||||
var section = appState.getSectionState("currentSection");
|
||||
|
||||
}, function(err) {
|
||||
|
||||
vm.createFolderError = err;
|
||||
|
||||
//show any notifications
|
||||
if (angular.isArray(err.data.notifications)) {
|
||||
for (var i = 0; i < err.data.notifications.length; i++) {
|
||||
notificationsService.showNotification(err.data.notifications[i]);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function showCreateFromSnippet() {
|
||||
|
||||
@@ -47,12 +47,12 @@
|
||||
<!-- Create folder -->
|
||||
<div class="umb-pane" ng-if="vm.creatingFolder">
|
||||
<form novalidate name="createFolderForm"
|
||||
ng-submit="vm.createFolder(createFolderForm)"
|
||||
val-form-manager>
|
||||
ng-submit="vm.createFolder()"
|
||||
val-form-manager>
|
||||
|
||||
<div ng-show="vm.createFolderError">
|
||||
<h5 class="text-error">{{vm.createFolderError.errorMsg}}</h5>
|
||||
<p class="text-error">{{vm.createFolderError.data.message}}</p>
|
||||
<div ng-show="error">
|
||||
<h5 class="text-error">{{error.errorMsg}}</h5>
|
||||
<p class="text-error">{{error.data.message}}</p>
|
||||
</div>
|
||||
|
||||
<umb-control-group label="Enter a folder name" hide-label="false">
|
||||
|
||||
@@ -1,17 +1,14 @@
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
function PartialViewsCreateController($scope, codefileResource, $location, navigationService, formHelper, localizationService, appState) {
|
||||
function PartialViewsCreateController($scope, codefileResource, $location, navigationService) {
|
||||
|
||||
var vm = this;
|
||||
var node = $scope.dialogOptions.currentNode;
|
||||
var localizeCreateFolder = localizationService.localize("defaultdialog_createFolder");
|
||||
|
||||
vm.snippets = [];
|
||||
vm.showSnippets = false;
|
||||
vm.creatingFolder = false;
|
||||
vm.createFolderError = "";
|
||||
vm.folderName = "";
|
||||
|
||||
vm.createPartialView = createPartialView;
|
||||
vm.showCreateFolder = showCreateFolder;
|
||||
@@ -42,38 +39,8 @@
|
||||
vm.creatingFolder = true;
|
||||
}
|
||||
|
||||
function createFolder(form) {
|
||||
if (formHelper.submitForm({scope: $scope, formCtrl: form, statusMessage: localizeCreateFolder})) {
|
||||
function createFolder() {
|
||||
|
||||
codefileResource.createContainer("partialViews", node.id, vm.folderName).then(function(saved) {
|
||||
|
||||
navigationService.hideMenu();
|
||||
|
||||
navigationService.syncTree({
|
||||
tree: "partialViews",
|
||||
path: saved.path,
|
||||
forceReload: true,
|
||||
activate: true
|
||||
});
|
||||
|
||||
formHelper.resetForm({
|
||||
scope: $scope
|
||||
});
|
||||
|
||||
var section = appState.getSectionState("currentSection");
|
||||
|
||||
}, function(err) {
|
||||
|
||||
vm.createFolderError = err;
|
||||
|
||||
//show any notifications
|
||||
if (angular.isArray(err.data.notifications)) {
|
||||
for (var i = 0; i < err.data.notifications.length; i++) {
|
||||
notificationsService.showNotification(err.data.notifications[i]);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function showCreateFromSnippet() {
|
||||
|
||||
@@ -47,12 +47,12 @@
|
||||
<!-- Create folder -->
|
||||
<div class="umb-pane" ng-if="vm.creatingFolder">
|
||||
<form novalidate name="createFolderForm"
|
||||
ng-submit="vm.createFolder(createFolderForm)"
|
||||
val-form-manager>
|
||||
ng-submit="vm.createFolder()"
|
||||
val-form-manager>
|
||||
|
||||
<div ng-show="vm.createFolderError">
|
||||
<h5 class="text-error">{{vm.createFolderError.errorMsg}}</h5>
|
||||
<p class="text-error">{{vm.createFolderError.data.message}}</p>
|
||||
<div ng-show="error">
|
||||
<h5 class="text-error">{{error.errorMsg}}</h5>
|
||||
<p class="text-error">{{error.data.message}}</p>
|
||||
</div>
|
||||
|
||||
<umb-control-group label="Enter a folder name" hide-label="false">
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
function ScriptsCreateController($scope, $location, navigationService, formHelper, codefileResource, localizationService, appState) {
|
||||
function ScriptsCreateController($scope, $location, navigationService) {
|
||||
|
||||
var vm = this;
|
||||
var node = $scope.dialogOptions.currentNode;
|
||||
var localizeCreateFolder = localizationService.localize("defaultdialog_createFolder");
|
||||
|
||||
vm.creatingFolder = false;
|
||||
vm.folderName = "";
|
||||
vm.createFolderError = "";
|
||||
vm.fileExtension = "";
|
||||
|
||||
vm.createFile = createFile;
|
||||
@@ -25,40 +23,8 @@
|
||||
vm.creatingFolder = true;
|
||||
}
|
||||
|
||||
function createFolder(form) {
|
||||
|
||||
if (formHelper.submitForm({scope: $scope, formCtrl: form, statusMessage: localizeCreateFolder})) {
|
||||
|
||||
codefileResource.createContainer("scripts", node.id, vm.folderName).then(function (saved) {
|
||||
|
||||
navigationService.hideMenu();
|
||||
|
||||
navigationService.syncTree({
|
||||
tree: "scripts",
|
||||
path: saved.path,
|
||||
forceReload: true,
|
||||
activate: true
|
||||
});
|
||||
|
||||
formHelper.resetForm({
|
||||
scope: $scope
|
||||
});
|
||||
|
||||
var section = appState.getSectionState("currentSection");
|
||||
|
||||
}, function(err) {
|
||||
|
||||
vm.createFolderError = err;
|
||||
|
||||
//show any notifications
|
||||
if (angular.isArray(err.data.notifications)) {
|
||||
for (var i = 0; i < err.data.notifications.length; i++) {
|
||||
notificationsService.showNotification(err.data.notifications[i]);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function createFolder() {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -22,12 +22,12 @@
|
||||
|
||||
<div class="umb-pane" ng-if="vm.creatingFolder">
|
||||
<form novalidate name="createFolderForm"
|
||||
ng-submit="vm.createFolder(createFolderForm)"
|
||||
ng-submit="vm.createFolder()"
|
||||
val-form-manager>
|
||||
|
||||
<div ng-show="vm.createFolderError">
|
||||
<h5 class="text-error">{{vm.createFolderError.errorMsg}}</h5>
|
||||
<p class="text-error">{{vm.createFolderError.data.message}}</p>
|
||||
<div ng-show="error">
|
||||
<h5 class="text-error">{{error.errorMsg}}</h5>
|
||||
<p class="text-error">{{error.data.message}}</p>
|
||||
</div>
|
||||
|
||||
<umb-control-group label="Enter a folder name" hide-label="false">
|
||||
|
||||
@@ -56,61 +56,6 @@ namespace Umbraco.Web.Editors
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used to create a container/folder in 'partialViews', 'partialViewMacros' or 'scripts'
|
||||
/// </summary>
|
||||
/// <param name="type">'partialViews', 'partialViewMacros' or 'scripts'</param>
|
||||
/// <param name="parentId">The virtual path of the parent.</param>
|
||||
/// <param name="name">The name of the container/folder</param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
public CodeFileDisplay PostCreateContainer(string type, string parentId, string name)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(type) || string.IsNullOrWhiteSpace(name))
|
||||
{
|
||||
throw new HttpResponseException(HttpStatusCode.BadRequest);
|
||||
}
|
||||
|
||||
// if the parentId is root (-1) then we just need an empty string as we are
|
||||
// creating the path below and we don't wan't -1 in the path
|
||||
if (parentId == Core.Constants.System.Root.ToInvariantString())
|
||||
{
|
||||
parentId = string.Empty;
|
||||
}
|
||||
|
||||
name = System.Web.HttpUtility.UrlDecode(name);
|
||||
|
||||
if (parentId.IsNullOrWhiteSpace() == false)
|
||||
{
|
||||
parentId = System.Web.HttpUtility.UrlDecode(parentId);
|
||||
name = parentId.EnsureEndsWith("/") + name;
|
||||
}
|
||||
|
||||
var virtualPath = string.Empty;
|
||||
switch (type)
|
||||
{
|
||||
case Core.Constants.Trees.PartialViews:
|
||||
virtualPath = NormalizeVirtualPath(name, SystemDirectories.PartialViews);
|
||||
Services.FileService.CreatePartialViewFolder(virtualPath);
|
||||
break;
|
||||
case Core.Constants.Trees.PartialViewMacros:
|
||||
virtualPath = NormalizeVirtualPath(name, SystemDirectories.MacroPartials);
|
||||
Services.FileService.CreatePartialViewMacroFolder(virtualPath);
|
||||
break;
|
||||
case Core.Constants.Trees.Scripts:
|
||||
virtualPath = NormalizeVirtualPath(name, SystemDirectories.Scripts);
|
||||
Services.FileService.CreateScriptFolder(virtualPath);
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
return new CodeFileDisplay
|
||||
{
|
||||
VirtualPath = virtualPath,
|
||||
Path = Url.GetTreePathFromFilePath(virtualPath)
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used to get a specific file from disk via the FileService
|
||||
/// </summary>
|
||||
@@ -125,6 +70,7 @@ namespace Umbraco.Web.Editors
|
||||
}
|
||||
|
||||
virtualPath = System.Web.HttpUtility.UrlDecode(virtualPath);
|
||||
|
||||
|
||||
switch (type)
|
||||
{
|
||||
|
||||
@@ -15,11 +15,9 @@ using umbraco.cms.presentation.Trees;
|
||||
using umbraco.presentation.developer.packages;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Events;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Packaging.Models;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Web.Models;
|
||||
using Umbraco.Web.Models.ContentEditing;
|
||||
@@ -83,14 +81,7 @@ namespace Umbraco.Web.Editors
|
||||
if (pack == null) throw new ArgumentNullException("pack");
|
||||
|
||||
var refreshCache = false;
|
||||
|
||||
var removedTemplates = new List<ITemplate>();
|
||||
var removedMacros = new List<IMacro>();
|
||||
var removedContentTypes = new List<IContentType>();
|
||||
var removedDictionaryItems = new List<IDictionaryItem>();
|
||||
var removedDataTypes = new List<IDataTypeDefinition>();
|
||||
var removedFiles = new List<string>();
|
||||
|
||||
|
||||
//Uninstall templates
|
||||
foreach (var item in pack.Data.Templates.ToArray())
|
||||
{
|
||||
@@ -99,7 +90,6 @@ namespace Umbraco.Web.Editors
|
||||
var found = Services.FileService.GetTemplate(nId);
|
||||
if (found != null)
|
||||
{
|
||||
removedTemplates.Add(found);
|
||||
ApplicationContext.Services.FileService.DeleteTemplate(found.Alias, Security.GetUserId());
|
||||
}
|
||||
pack.Data.Templates.Remove(nId.ToString());
|
||||
@@ -113,9 +103,8 @@ namespace Umbraco.Web.Editors
|
||||
var macro = Services.MacroService.GetById(nId);
|
||||
if (macro != null)
|
||||
{
|
||||
removedMacros.Add(macro);
|
||||
Services.MacroService.Delete(macro);
|
||||
}
|
||||
}
|
||||
pack.Data.Macros.Remove(nId.ToString());
|
||||
}
|
||||
|
||||
@@ -139,9 +128,8 @@ namespace Umbraco.Web.Editors
|
||||
{
|
||||
//TODO: I don't think this ordering is necessary
|
||||
var orderedTypes = from contentType in contentTypes
|
||||
orderby contentType.ParentId descending, contentType.Id descending
|
||||
select contentType;
|
||||
removedContentTypes.AddRange(orderedTypes);
|
||||
orderby contentType.ParentId descending, contentType.Id descending
|
||||
select contentType;
|
||||
contentTypeService.Delete(orderedTypes);
|
||||
}
|
||||
|
||||
@@ -153,9 +141,8 @@ namespace Umbraco.Web.Editors
|
||||
var di = Services.LocalizationService.GetDictionaryItemById(nId);
|
||||
if (di != null)
|
||||
{
|
||||
removedDictionaryItems.Add(di);
|
||||
Services.LocalizationService.Delete(di);
|
||||
}
|
||||
}
|
||||
pack.Data.DictionaryItems.Remove(nId.ToString());
|
||||
}
|
||||
|
||||
@@ -167,9 +154,8 @@ namespace Umbraco.Web.Editors
|
||||
var dtd = Services.DataTypeService.GetDataTypeDefinitionById(nId);
|
||||
if (dtd != null)
|
||||
{
|
||||
removedDataTypes.Add(dtd);
|
||||
Services.DataTypeService.Delete(dtd);
|
||||
}
|
||||
}
|
||||
pack.Data.DataTypes.Remove(nId.ToString());
|
||||
}
|
||||
|
||||
@@ -210,45 +196,30 @@ namespace Umbraco.Web.Editors
|
||||
//Remove files
|
||||
foreach (var item in pack.Data.Files.ToArray())
|
||||
{
|
||||
removedFiles.Add(item.GetRelativePath());
|
||||
|
||||
//here we need to try to find the file in question as most packages does not support the tilde char
|
||||
var file = IOHelper.FindFile(item);
|
||||
if (file != null)
|
||||
{
|
||||
if (file.StartsWith("/") == false)
|
||||
file = string.Format("/{0}", file);
|
||||
var filePath = IOHelper.MapPath(file);
|
||||
|
||||
var filePath = IOHelper.MapPath(file);
|
||||
if (File.Exists(filePath))
|
||||
{
|
||||
File.Delete(filePath);
|
||||
|
||||
}
|
||||
}
|
||||
pack.Data.Files.Remove(file);
|
||||
}
|
||||
pack.Save();
|
||||
pack.Delete(Security.GetUserId());
|
||||
|
||||
// create a summary of what was actually removed, for PackagingService.UninstalledPackage
|
||||
var summary = new UninstallationSummary
|
||||
{
|
||||
MetaData = pack.GetMetaData(),
|
||||
TemplatesUninstalled = removedTemplates,
|
||||
MacrosUninstalled = removedMacros,
|
||||
ContentTypesUninstalled = removedContentTypes,
|
||||
DictionaryItemsUninstalled = removedDictionaryItems,
|
||||
DataTypesUninstalled = removedDataTypes,
|
||||
FilesUninstalled = removedFiles,
|
||||
PackageUninstalled = true
|
||||
};
|
||||
|
||||
// trigger the UninstalledPackage event
|
||||
PackagingService.OnUninstalledPackage(new UninstallPackageEventArgs<UninstallationSummary>(summary, false));
|
||||
|
||||
|
||||
//TODO: Legacy - probably not needed
|
||||
if (refreshCache)
|
||||
{
|
||||
library.RefreshContent();
|
||||
}
|
||||
}
|
||||
TreeDefinitionCollection.Instance.ReRegisterTrees();
|
||||
global::umbraco.BusinessLogic.Actions.Action.ReRegisterActionsAndHandlers();
|
||||
}
|
||||
@@ -268,8 +239,8 @@ namespace Umbraco.Web.Editors
|
||||
{
|
||||
Version pckVersion;
|
||||
return Version.TryParse(pck.Data.Version, out pckVersion)
|
||||
? new { package = pck, version = pckVersion }
|
||||
: new { package = pck, version = new Version(0, 0, 0) };
|
||||
? new {package = pck, version = pckVersion}
|
||||
: new {package = pck, version = new Version(0, 0, 0)};
|
||||
})
|
||||
.Select(grouping =>
|
||||
{
|
||||
@@ -340,7 +311,7 @@ namespace Umbraco.Web.Editors
|
||||
model.UmbracoVersion = ins.RequirementsType == RequirementsType.Strict
|
||||
? string.Format("{0}.{1}.{2}", ins.RequirementsMajor, ins.RequirementsMinor, ins.RequirementsPatch)
|
||||
: string.Empty;
|
||||
|
||||
|
||||
//now we need to check for version comparison
|
||||
model.IsCompatible = true;
|
||||
if (ins.RequirementsType == RequirementsType.Strict)
|
||||
@@ -420,7 +391,7 @@ namespace Umbraco.Web.Editors
|
||||
{
|
||||
//TODO: Currently it has to be here, it's not ideal but that's the way it is right now
|
||||
var packageTempDir = IOHelper.MapPath(SystemDirectories.Data);
|
||||
|
||||
|
||||
//ensure it's there
|
||||
Directory.CreateDirectory(packageTempDir);
|
||||
|
||||
@@ -436,14 +407,14 @@ namespace Umbraco.Web.Editors
|
||||
PopulateFromPackageData(model);
|
||||
|
||||
var validate = ValidateInstalledInternal(model.Name, model.Version);
|
||||
|
||||
|
||||
if (validate == false)
|
||||
{
|
||||
//this package is already installed
|
||||
throw new HttpResponseException(Request.CreateNotificationValidationErrorResponse(
|
||||
Services.TextService.Localize("packager/packageAlreadyInstalled")));
|
||||
Services.TextService.Localize("packager/packageAlreadyInstalled")));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -452,7 +423,7 @@ namespace Umbraco.Web.Editors
|
||||
Services.TextService.Localize("media/disallowedFileType"),
|
||||
SpeechBubbleIcon.Warning));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
return model;
|
||||
@@ -474,7 +445,7 @@ namespace Umbraco.Web.Editors
|
||||
//our repo guid
|
||||
using (var our = Repository.getByGuid("65194810-1f85-11dd-bd0b-0800200c9a66"))
|
||||
{
|
||||
path = our.fetch(packageGuid, Security.CurrentUser.Id);
|
||||
path = our.fetch(packageGuid, Security.CurrentUser.Id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -518,12 +489,12 @@ namespace Umbraco.Web.Editors
|
||||
if (UmbracoVersion.Current < packageMinVersion)
|
||||
{
|
||||
throw new HttpResponseException(Request.CreateNotificationValidationErrorResponse(
|
||||
Services.TextService.Localize("packager/targetVersionMismatch", new[] { packageMinVersion.ToString() })));
|
||||
Services.TextService.Localize("packager/targetVersionMismatch", new[] {packageMinVersion.ToString()})));
|
||||
}
|
||||
}
|
||||
|
||||
model.TemporaryDirectoryPath = Path.Combine(SystemDirectories.Data, tempPath);
|
||||
model.Id = ins.CreateManifest(IOHelper.MapPath(model.TemporaryDirectoryPath), model.PackageGuid.ToString(), model.RepositoryGuid.ToString());
|
||||
model.Id = ins.CreateManifest( IOHelper.MapPath(model.TemporaryDirectoryPath), model.PackageGuid.ToString(), model.RepositoryGuid.ToString());
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
@@ -14,18 +14,16 @@ using Umbraco.Core.Packaging;
|
||||
using umbraco.cms.businesslogic.web;
|
||||
using umbraco.BusinessLogic;
|
||||
using System.Diagnostics;
|
||||
using umbraco.cms.businesslogic.macro;
|
||||
using umbraco.cms.businesslogic.template;
|
||||
using umbraco.interfaces;
|
||||
using Umbraco.Core.Events;
|
||||
using Umbraco.Core.Packaging.Models;
|
||||
using Umbraco.Core.Services;
|
||||
|
||||
namespace umbraco.cms.businesslogic.packager
|
||||
{
|
||||
/// <summary>
|
||||
/// The packager is a component which enables sharing of both data and functionality components between different umbraco installations.
|
||||
///
|
||||
/// The output is a .umb (a zip compressed file) which contains the exported documents/medias/macros/documenttypes (etc.)
|
||||
/// The output is a .umb (a zip compressed file) which contains the exported documents/medias/macroes/documenttypes (etc.)
|
||||
/// in a Xml document, along with the physical files used (images/usercontrols/xsl documents etc.)
|
||||
///
|
||||
/// Partly implemented, import of packages is done, the export is *under construction*.
|
||||
@@ -509,7 +507,6 @@ namespace umbraco.cms.businesslogic.packager
|
||||
}
|
||||
|
||||
OnPackageBusinessLogicInstalled(insPack);
|
||||
OnPackageInstalled(insPack);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -520,7 +517,6 @@ namespace umbraco.cms.businesslogic.packager
|
||||
/// <param name="tempDir"></param>
|
||||
public void InstallCleanUp(int packageId, string tempDir)
|
||||
{
|
||||
|
||||
if (Directory.Exists(tempDir))
|
||||
{
|
||||
Directory.Delete(tempDir, true);
|
||||
@@ -818,21 +814,5 @@ namespace umbraco.cms.businesslogic.packager
|
||||
EventHandler<InstalledPackage> handler = PackageBusinessLogicInstalled;
|
||||
if (handler != null) handler(null, e);
|
||||
}
|
||||
|
||||
private void OnPackageInstalled(InstalledPackage insPack)
|
||||
{
|
||||
// getting an InstallationSummary for sending to the PackagingService.ImportedPackage event
|
||||
var fileService = ApplicationContext.Current.Services.FileService;
|
||||
var macroService = ApplicationContext.Current.Services.MacroService;
|
||||
var contentTypeService = ApplicationContext.Current.Services.ContentTypeService;
|
||||
var dataTypeService = ApplicationContext.Current.Services.DataTypeService;
|
||||
var localizationService = ApplicationContext.Current.Services.LocalizationService;
|
||||
|
||||
var installationSummary = insPack.GetInstallationSummary(contentTypeService, dataTypeService, fileService, localizationService, macroService);
|
||||
installationSummary.PackageInstalled = true;
|
||||
|
||||
var args = new ImportPackageEventArgs<InstallationSummary>(installationSummary, false);
|
||||
PackagingService.OnImportedPackage(args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Auditing;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Packaging.Models;
|
||||
using Umbraco.Core.Services;
|
||||
|
||||
namespace umbraco.cms.businesslogic.packager {
|
||||
public class InstalledPackage
|
||||
@@ -127,70 +124,5 @@ namespace umbraco.cms.businesslogic.packager {
|
||||
if (AfterDelete != null)
|
||||
AfterDelete(this, e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used internally for creating an InstallationSummary (used in new PackagingService) representation of this InstalledPackage object.
|
||||
/// </summary>
|
||||
/// <param name="contentTypeService"></param>
|
||||
/// <param name="dataTypeService"></param>
|
||||
/// <param name="fileService"></param>
|
||||
/// <param name="localizationService"></param>
|
||||
/// <param name="macroService"></param>
|
||||
/// <returns></returns>
|
||||
internal InstallationSummary GetInstallationSummary(IContentTypeService contentTypeService, IDataTypeService dataTypeService, IFileService fileService, ILocalizationService localizationService, IMacroService macroService)
|
||||
{
|
||||
var macros = TryGetIntegerIds(Data.Macros).Select(macroService.GetById).ToList();
|
||||
var templates = TryGetIntegerIds(Data.Templates).Select(fileService.GetTemplate).ToList();
|
||||
var contentTypes = TryGetIntegerIds(Data.Documenttypes).Select(contentTypeService.GetContentType).ToList();
|
||||
var dataTypes = TryGetIntegerIds(Data.DataTypes).Select(dataTypeService.GetDataTypeDefinitionById).ToList();
|
||||
var dictionaryItems = TryGetIntegerIds(Data.DictionaryItems).Select(localizationService.GetDictionaryItemById).ToList();
|
||||
var languages = TryGetIntegerIds(Data.Languages).Select(localizationService.GetLanguageById).ToList();
|
||||
|
||||
for (var i = 0; i < Data.Files.Count; i++)
|
||||
{
|
||||
var filePath = Data.Files[i];
|
||||
Data.Files[i] = filePath.GetRelativePath();
|
||||
}
|
||||
|
||||
return new InstallationSummary
|
||||
{
|
||||
ContentTypesInstalled = contentTypes,
|
||||
DataTypesInstalled = dataTypes,
|
||||
DictionaryItemsInstalled = dictionaryItems,
|
||||
FilesInstalled = Data.Files,
|
||||
LanguagesInstalled = languages,
|
||||
MacrosInstalled = macros,
|
||||
MetaData = GetMetaData(),
|
||||
TemplatesInstalled = templates,
|
||||
};
|
||||
}
|
||||
|
||||
internal MetaData GetMetaData()
|
||||
{
|
||||
return new MetaData()
|
||||
{
|
||||
AuthorName = Data.Author,
|
||||
AuthorUrl = Data.AuthorUrl,
|
||||
Control = Data.LoadControl,
|
||||
License = Data.License,
|
||||
LicenseUrl = Data.LicenseUrl,
|
||||
Name = Data.Name,
|
||||
Readme = Data.Readme,
|
||||
Url = Data.Url,
|
||||
Version = Data.Version
|
||||
};
|
||||
}
|
||||
|
||||
private static IEnumerable<int> TryGetIntegerIds(IEnumerable<string> ids)
|
||||
{
|
||||
var intIds = new List<int>();
|
||||
foreach (var id in ids)
|
||||
{
|
||||
int parsed;
|
||||
if (int.TryParse(id, out parsed))
|
||||
intIds.Add(parsed);
|
||||
}
|
||||
return intIds;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,14 +72,13 @@ namespace umbraco.cms.businesslogic.propertytype
|
||||
_tabId = _propertyTypeGroup;
|
||||
}
|
||||
|
||||
//Fixed issue U4-9493 Case issues
|
||||
_sortOrder = found.sortOrder;
|
||||
_alias = found.Alias;
|
||||
_name = found.Name;
|
||||
_alias = found.alias;
|
||||
_name = found.name;
|
||||
_validationRegExp = found.validationRegExp;
|
||||
_DataTypeId = found.dataTypeId;
|
||||
_DataTypeId = found.DataTypeId;
|
||||
_contenttypeid = found.contentTypeId;
|
||||
_description = found.Description;
|
||||
_description = found.description;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
Reference in New Issue
Block a user