Compare commits
46 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 32ad98cde2 | |||
| f4b1df1ede | |||
| 2b0f2577b5 | |||
| a39557a3a7 | |||
| 2239316889 | |||
| d3582e2296 | |||
| 1a37d88855 | |||
| 2d5ffabe1e | |||
| f61b7579a2 | |||
| 86a3780c61 | |||
| 552909fde2 | |||
| 7adae4d345 | |||
| d747cf69c3 | |||
| bc5e3b4d66 | |||
| febeb82d10 | |||
| 1c2b2c1409 | |||
| b4eb9f333e | |||
| af00a421cd | |||
| fed06c88e8 | |||
| 5dec2861d9 | |||
| 23b3bb37ee | |||
| 4dabb606e7 | |||
| d5f66ebe02 | |||
| c7783d1cd1 | |||
| 2104b109f2 | |||
| 578ca7d41d | |||
| bd38dde1fc | |||
| 42c23da9f5 | |||
| cab1536a30 | |||
| 83f75fdaff | |||
| 487792920b | |||
| 6ae06ad2e0 | |||
| 8387c435d4 | |||
| 5807bbccc4 | |||
| 1bfc041bbe | |||
| a5ca058cb2 | |||
| 88a1ad04aa | |||
| 7c049b55a8 | |||
| 051b3f2e6a | |||
| 21f947efbd | |||
| 9461e35028 | |||
| 9c5526f281 | |||
| 9c803cc234 | |||
| f24fd42a69 | |||
| 9b7f459c44 | |||
| 273a5cef28 |
@@ -1,3 +1,3 @@
|
||||
# Usage: on line 2 put the release version, on line 3 put the version comment (example: beta)
|
||||
7.6.0
|
||||
alpha064
|
||||
alpha070
|
||||
|
||||
+1
-1
@@ -12,4 +12,4 @@ using System.Resources;
|
||||
[assembly: AssemblyVersion("1.0.*")]
|
||||
|
||||
[assembly: AssemblyFileVersion("7.6.0")]
|
||||
[assembly: AssemblyInformationalVersion("7.6.0-alpha064")]
|
||||
[assembly: AssemblyInformationalVersion("7.6.0-alpha070")]
|
||||
@@ -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 "alpha064"; } }
|
||||
public static string CurrentComment { get { return "alpha070"; } }
|
||||
|
||||
// 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
|
||||
|
||||
@@ -109,6 +109,11 @@ namespace Umbraco.Core
|
||||
/// </summary>
|
||||
public const string Member = "39EB0F98-B348-42A1-8662-E7EB18487560";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for a Media Type object.
|
||||
/// </summary>
|
||||
public static readonly Guid MemberGuid = new Guid(Member);
|
||||
|
||||
/// <summary>
|
||||
/// Guid for a Member Group object.
|
||||
/// </summary>
|
||||
|
||||
@@ -16,6 +16,7 @@ namespace Umbraco.Core.Deploy
|
||||
if (udi == null)
|
||||
throw new ArgumentNullException("udi");
|
||||
Udi = udi;
|
||||
Name = Udi.ToString();
|
||||
|
||||
Dependencies = dependencies ?? Enumerable.Empty<ArtifactDependency>();
|
||||
_checksum = new Lazy<string>(GetChecksum);
|
||||
@@ -48,5 +49,8 @@ namespace Umbraco.Core.Deploy
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public string Name { get; set; }
|
||||
public string Alias { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -4,5 +4,8 @@ namespace Umbraco.Core.Deploy
|
||||
/// Represents an artifact ie an object that can be transfered between environments.
|
||||
/// </summary>
|
||||
public interface IArtifact : IArtifactSignature
|
||||
{ }
|
||||
{
|
||||
string Name { get; }
|
||||
string Alias { get; }
|
||||
}
|
||||
}
|
||||
@@ -66,10 +66,20 @@ namespace Umbraco.Core.Deploy
|
||||
/// <returns>The length of the file, or -1 if the file does not exist.</returns>
|
||||
Task<long> GetFileLengthAsync(StringUdi udi, CancellationToken token);
|
||||
|
||||
// fixme - doc
|
||||
void GetFiles(IEnumerable<StringUdi> udis, IFileStore fileStore);
|
||||
/// <summary>
|
||||
/// Gets files and store them using a file store.
|
||||
/// </summary>
|
||||
/// <param name="udis">The udis of the files to get.</param>
|
||||
/// <param name="fileTypes">A collection of file types which can store the files.</param>
|
||||
void GetFiles(IEnumerable<StringUdi> udis, IFileTypeCollection fileTypes);
|
||||
|
||||
Task GetFilesAsync(IEnumerable<StringUdi> udis, IFileStore fileStore, CancellationToken token);
|
||||
/// <summary>
|
||||
/// Gets files and store them using a file store.
|
||||
/// </summary>
|
||||
/// <param name="udis">The udis of the files to get.</param>
|
||||
/// <param name="fileTypes">A collection of file types which can store the files.</param>
|
||||
/// <param name="token">A cancellation token.</param>
|
||||
Task GetFilesAsync(IEnumerable<StringUdi> udis, IFileTypeCollection fileTypes, CancellationToken token);
|
||||
|
||||
///// <summary>
|
||||
///// Gets the content of a file as a bytes array.
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Umbraco.Core.Deploy
|
||||
{
|
||||
public interface IFileStore
|
||||
{
|
||||
void SaveStream(StringUdi udi, Stream stream);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Umbraco.Core.Deploy
|
||||
{
|
||||
public interface IFileType
|
||||
{
|
||||
Stream GetStream(StringUdi udi);
|
||||
|
||||
Task<Stream> GetStreamAsync(StringUdi udi, CancellationToken token);
|
||||
|
||||
Stream GetChecksumStream(StringUdi udi);
|
||||
|
||||
long GetLength(StringUdi udi);
|
||||
|
||||
void SetStream(StringUdi udi, Stream stream);
|
||||
|
||||
Task SetStreamAsync(StringUdi udi, Stream stream, CancellationToken token);
|
||||
|
||||
bool CanSetPhysical { get; }
|
||||
|
||||
void Set(StringUdi udi, string physicalPath, bool copy = false);
|
||||
|
||||
// this is not pretty as *everywhere* in Deploy we take care of ignoring
|
||||
// the physical path and always rely on Core's virtual IFileSystem but
|
||||
// Cloud wants to add some of these files to Git and needs the path...
|
||||
string GetPhysicalPath(StringUdi udi);
|
||||
|
||||
string GetVirtualPath(StringUdi udi);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace Umbraco.Core.Deploy
|
||||
{
|
||||
public interface IFileTypeCollection
|
||||
{
|
||||
IFileType this[string entityType] { get; }
|
||||
|
||||
bool Contains(string entityType);
|
||||
}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
namespace Umbraco.Core.Deploy
|
||||
{
|
||||
public interface IPrettyArtifact
|
||||
{
|
||||
string Name { get; }
|
||||
string Alias { get; }
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
@@ -67,22 +68,15 @@ namespace Umbraco.Core
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>The for each.</summary>
|
||||
/// <param name="items">The items.</param>
|
||||
/// <param name="func">The func.</param>
|
||||
/// <typeparam name="TItem">item type</typeparam>
|
||||
/// <typeparam name="TResult">Result type</typeparam>
|
||||
/// <returns>the Results</returns>
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
[Obsolete("Use a normal foreach loop instead, this adds more allocations than necessary")]
|
||||
public static TResult[] ForEach<TItem, TResult>(this IEnumerable<TItem> items, Func<TItem, TResult> func)
|
||||
{
|
||||
return items.Select(func).ToArray();
|
||||
}
|
||||
|
||||
/// <summary>The for each.</summary>
|
||||
/// <param name="items">The items.</param>
|
||||
/// <param name="action">The action.</param>
|
||||
/// <typeparam name="TItem">Item type</typeparam>
|
||||
/// <returns>list of TItem</returns>
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
[Obsolete("Use a normal foreach loop instead, this adds more allocations than necessary")]
|
||||
public static IEnumerable<TItem> ForEach<TItem>(this IEnumerable<TItem> items, Action<TItem> action)
|
||||
{
|
||||
if (items != null)
|
||||
@@ -101,6 +95,7 @@ namespace Umbraco.Core
|
||||
/// <param name="f">The select child.</param>
|
||||
/// <typeparam name="T">Item type</typeparam>
|
||||
/// <returns>list of TItem</returns>
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
[Obsolete("Do not use, use SelectRecursive instead which has far less potential of re-iterating an iterator which may cause significantly more SQL queries")]
|
||||
public static IEnumerable<T> FlattenList<T>(this IEnumerable<T> e, Func<T, IEnumerable<T>> f)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
using System;
|
||||
using Umbraco.Core.Scoping;
|
||||
|
||||
namespace Umbraco.Core.Events
|
||||
{
|
||||
/// <summary>
|
||||
/// Stores the instance of EventMessages in the current scope.
|
||||
/// </summary>
|
||||
internal class ScopeLifespanMessagesFactory : IEventMessagesFactory
|
||||
{
|
||||
public const string ContextKey = "Umbraco.Core.Events.ScopeLifespanMessagesFactory";
|
||||
|
||||
private readonly IHttpContextAccessor _contextAccessor;
|
||||
private readonly IScopeProviderInternal _scopeProvider;
|
||||
|
||||
public static ScopeLifespanMessagesFactory Current { get; private set; }
|
||||
|
||||
public ScopeLifespanMessagesFactory(IHttpContextAccessor contextAccesor, IScopeProvider scopeProvider)
|
||||
{
|
||||
if (contextAccesor == null) throw new ArgumentNullException("contextAccesor");
|
||||
if (scopeProvider == null) throw new ArgumentNullException("scopeProvider");
|
||||
if (scopeProvider is IScopeProviderInternal == false) throw new ArgumentException("Not IScopeProviderInternal.", "scopeProvider");
|
||||
_contextAccessor = contextAccesor;
|
||||
_scopeProvider = (IScopeProviderInternal) scopeProvider;
|
||||
Current = this;
|
||||
}
|
||||
|
||||
public EventMessages Get()
|
||||
{
|
||||
var messages = GetFromHttpContext();
|
||||
if (messages != null) return messages;
|
||||
|
||||
var scope = _scopeProvider.GetAmbientOrNoScope();
|
||||
return scope.Messages;
|
||||
}
|
||||
|
||||
public EventMessages GetFromHttpContext()
|
||||
{
|
||||
if (_contextAccessor == null || _contextAccessor.Value == null) return null;
|
||||
return (EventMessages)_contextAccessor.Value.Items[ContextKey];
|
||||
}
|
||||
|
||||
public EventMessages TryGet()
|
||||
{
|
||||
var messages = GetFromHttpContext();
|
||||
if (messages != null) return messages;
|
||||
|
||||
var scope = _scopeProvider.AmbientScope;
|
||||
return scope == null ? null : scope.MessagesOrNull;
|
||||
}
|
||||
|
||||
public void Set(EventMessages messages)
|
||||
{
|
||||
if (_contextAccessor.Value == null) return;
|
||||
_contextAccessor.Value.Items[ContextKey] = messages;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using System.Web;
|
||||
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
public interface IHttpContextAccessor
|
||||
{
|
||||
HttpContextBase Value { get; }
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Umbraco.Core.IO
|
||||
{
|
||||
@@ -209,19 +210,20 @@ namespace Umbraco.Core.IO
|
||||
|
||||
public IEnumerable<string> GetFiles(string path)
|
||||
{
|
||||
var normPath = NormPath(path);
|
||||
var shadows = Nodes.Where(kvp => IsChild(normPath, kvp.Key)).ToArray();
|
||||
var files = _fs.GetFiles(path);
|
||||
return files
|
||||
.Except(shadows.Where(kvp => (kvp.Value.IsFile && kvp.Value.IsDelete) || kvp.Value.IsDir)
|
||||
.Select(kvp => kvp.Key))
|
||||
.Union(shadows.Where(kvp => kvp.Value.IsFile && kvp.Value.IsExist).Select(kvp => kvp.Key))
|
||||
.Distinct();
|
||||
return GetFiles(path, null);
|
||||
}
|
||||
|
||||
public IEnumerable<string> GetFiles(string path, string filter)
|
||||
{
|
||||
return _fs.GetFiles(path, filter);
|
||||
var normPath = NormPath(path);
|
||||
var shadows = Nodes.Where(kvp => IsChild(normPath, kvp.Key)).ToArray();
|
||||
var files = filter != null ? _fs.GetFiles(path, filter) : _fs.GetFiles(path);
|
||||
var regexFilter = FilterToRegex(filter);
|
||||
return files
|
||||
.Except(shadows.Where(kvp => (kvp.Value.IsFile && kvp.Value.IsDelete) || kvp.Value.IsDir)
|
||||
.Select(kvp => kvp.Key))
|
||||
.Union(shadows.Where(kvp => kvp.Value.IsFile && kvp.Value.IsExist && FilterByRegex(kvp.Key, regexFilter)).Select(kvp => kvp.Key))
|
||||
.Distinct();
|
||||
}
|
||||
|
||||
public Stream OpenFile(string path)
|
||||
@@ -253,6 +255,9 @@ namespace Umbraco.Core.IO
|
||||
|
||||
public string GetFullPath(string path)
|
||||
{
|
||||
ShadowNode sf;
|
||||
if (Nodes.TryGetValue(NormPath(path), out sf))
|
||||
return sf.IsDir || sf.IsDelete ? null : _sfs.GetFullPath(path);
|
||||
return _fs.GetFullPath(path);
|
||||
}
|
||||
|
||||
@@ -321,5 +326,32 @@ namespace Umbraco.Core.IO
|
||||
_sfs.AddFile(path, physicalPath, overrideIfExists, copy);
|
||||
Nodes[normPath] = new ShadowNode(false, false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper function for filtering keys by Regex if a filter is specified.
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <param name="regexFilter"></param>
|
||||
/// <returns></returns>
|
||||
internal static bool FilterByRegex(string input, string regexFilter)
|
||||
{
|
||||
if (regexFilter == null) return true;
|
||||
return regexFilter != string.Empty && Regex.IsMatch(input, regexFilter);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Transforms a filter pattern into a Regex pattern
|
||||
/// </summary>
|
||||
/// <param name="pattern"></param>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// Appending '$' only if not containing wildcard is stupid and broken.
|
||||
/// It is however what seems to be what they're doing in .NET so we need to match the functionality.
|
||||
/// </remarks>
|
||||
internal static string FilterToRegex(string pattern)
|
||||
{
|
||||
if (pattern == null) return null;
|
||||
return "^" + Regex.Escape(pattern).Replace("\\*", ".*").Replace("\\?", ".") + (pattern.Contains("*") ? string.Empty : "$");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace Umbraco.Core.IO
|
||||
// on ShadowFileSystemsScope.None - and if None is false then we should be running
|
||||
// in a single thread anyways
|
||||
|
||||
var virt = "~/App_Data/Shadow/" + id + "/" + _shadowPath;
|
||||
var virt = "~/App_Data/TEMP/ShadowFs/" + id + "/" + _shadowPath;
|
||||
_shadowDir = IOHelper.MapPath(virt);
|
||||
Directory.CreateDirectory(_shadowDir);
|
||||
var tempfs = new PhysicalFileSystem(virt);
|
||||
|
||||
@@ -30,7 +30,8 @@ namespace Umbraco.Core.Models
|
||||
return descendants;
|
||||
}
|
||||
|
||||
throw new NotSupportedException("The content type must be " + typeof(IContentType) + " or " + typeof(IMediaType));
|
||||
//No other content types have children (i.e. member types)
|
||||
return Enumerable.Empty<IContentTypeBase>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -113,6 +113,11 @@ namespace Umbraco.Core.Models
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// When resolved from EntityService this checks if the entity has the HasChildren flag
|
||||
/// </summary>
|
||||
/// <param name="entity"></param>
|
||||
/// <returns></returns>
|
||||
public static bool HasChildren(this IUmbracoEntity entity)
|
||||
{
|
||||
if (entity.AdditionalData.ContainsKey("HasChildren"))
|
||||
@@ -133,6 +138,11 @@ namespace Umbraco.Core.Models
|
||||
return entity.AdditionalData.GetValueIgnoreCase(key, defaultVal);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// When resolved from EntityService this checks if the entity has the IsContainer flag
|
||||
/// </summary>
|
||||
/// <param name="entity"></param>
|
||||
/// <returns></returns>
|
||||
public static bool IsContainer(this IUmbracoEntity entity)
|
||||
{
|
||||
if (entity.AdditionalData.ContainsKeyIgnoreCase("IsContainer") == false) return false;
|
||||
|
||||
@@ -50,7 +50,7 @@ namespace Umbraco.Core.Persistence.Factories
|
||||
entity.ContentTypeThumbnail = asDictionary.ContainsKey("thumbnail") ? (d.thumbnail ?? string.Empty) : string.Empty;
|
||||
|
||||
var publishedVersion = default(Guid);
|
||||
//some content items don't have a published version
|
||||
//some content items don't have a published/newest version
|
||||
if (asDictionary.ContainsKey("publishedVersion") && asDictionary["publishedVersion"] != null)
|
||||
{
|
||||
Guid.TryParse(d.publishedVersion.ToString(), out publishedVersion);
|
||||
|
||||
@@ -703,7 +703,7 @@ namespace Umbraco.Core.Persistence
|
||||
|
||||
static Regex rxColumns = new Regex(@"\A\s*SELECT\s+((?:\((?>\((?<depth>)|\)(?<-depth>)|.?)*(?(depth)(?!))\)|.)*?)(?<!,\s+)\bFROM\b", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.Compiled);
|
||||
static Regex rxOrderBy = new Regex(@"\bORDER\s+BY\s+(?:\((?>\((?<depth>)|\)(?<-depth>)|.?)*(?(depth)(?!))\)|[\w\(\)\.])+(?:\s+(?:ASC|DESC))?(?:\s*,\s*(?:\((?>\((?<depth>)|\)(?<-depth>)|.?)*(?(depth)(?!))\)|[\w\(\)\.])+(?:\s+(?:ASC|DESC))?)*", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.Compiled);
|
||||
static Regex rxDistinct = new Regex(@"\ADISTINCT\s", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.Compiled);
|
||||
static Regex rxDistinct = new Regex(@"\ADISTINCT\s", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.Compiled);
|
||||
public static bool SplitSqlForPaging(string sql, out string sqlCount, out string sqlSelectRemoved, out string sqlOrderBy)
|
||||
{
|
||||
sqlSelectRemoved = null;
|
||||
@@ -723,10 +723,9 @@ namespace Umbraco.Core.Persistence
|
||||
sqlCount = sql.Substring(0, g.Index) + "COUNT(" + m.Groups[1].ToString().Trim() + ") " + sql.Substring(g.Index + g.Length);
|
||||
else
|
||||
sqlCount = sql.Substring(0, g.Index) + "COUNT(*) " + sql.Substring(g.Index + g.Length);
|
||||
|
||||
|
||||
// Look for an "ORDER BY <whatever>" clause
|
||||
m = rxOrderBy.Match(sqlCount);
|
||||
|
||||
// Look for an "ORDER BY <whatever>" clause
|
||||
m = rxOrderBy.Match(sqlCount);
|
||||
if (!m.Success)
|
||||
{
|
||||
sqlOrderBy = null;
|
||||
@@ -737,8 +736,7 @@ namespace Umbraco.Core.Persistence
|
||||
sqlOrderBy = g.ToString();
|
||||
sqlCount = sqlCount.Substring(0, g.Index) + sqlCount.Substring(g.Index + g.Length);
|
||||
}
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -820,7 +818,7 @@ namespace Umbraco.Core.Persistence
|
||||
result.CurrentPage = page;
|
||||
result.ItemsPerPage = itemsPerPage;
|
||||
result.TotalItems = ExecuteScalar<long>(sqlCount, args);
|
||||
result.TotalPages = result.TotalItems / itemsPerPage;
|
||||
result.TotalPages = result.TotalItems / itemsPerPage;
|
||||
if ((result.TotalItems % itemsPerPage) != 0)
|
||||
result.TotalPages++;
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ using Umbraco.Core.Models;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
using Umbraco.Core.Models.Rdbms;
|
||||
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
|
||||
using Umbraco.Core.Persistence.Factories;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
using Umbraco.Core.Persistence.UnitOfWork;
|
||||
@@ -49,6 +50,124 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
#region Query Methods
|
||||
|
||||
public IEnumerable<IUmbracoEntity> GetPagedResultsByQuery(IQuery<IUmbracoEntity> query, Guid objectTypeId, long pageIndex, int pageSize, out long totalRecords,
|
||||
string orderBy, Direction orderDirection, IQuery<IUmbracoEntity> filter = null)
|
||||
{
|
||||
bool isContent = objectTypeId == new Guid(Constants.ObjectTypes.Document);
|
||||
bool isMedia = objectTypeId == new Guid(Constants.ObjectTypes.Media);
|
||||
var factory = new UmbracoEntityFactory();
|
||||
|
||||
var sqlClause = GetBaseWhere(GetBase, isContent, isMedia, sql =>
|
||||
{
|
||||
if (filter != null)
|
||||
{
|
||||
foreach (var filterClaus in filter.GetWhereClauses())
|
||||
{
|
||||
sql.Where(filterClaus.Item1, filterClaus.Item2);
|
||||
}
|
||||
}
|
||||
}, objectTypeId);
|
||||
var translator = new SqlTranslator<IUmbracoEntity>(sqlClause, query);
|
||||
var entitySql = translator.Translate();
|
||||
var pagedSql = entitySql.Append(GetGroupBy(isContent, isMedia, false)).OrderBy("umbracoNode.id");
|
||||
|
||||
IEnumerable<IUmbracoEntity> result;
|
||||
|
||||
if (isMedia)
|
||||
{
|
||||
//Treat media differently for now, as an Entity it will be returned with ALL of it's properties in the AdditionalData bag!
|
||||
var pagedResult = _work.Database.Page<dynamic>(pageIndex + 1, pageSize, pagedSql);
|
||||
|
||||
var ids = pagedResult.Items.Select(x => (int) x.id).InGroupsOf(2000);
|
||||
var entities = pagedResult.Items.Select(factory.BuildEntityFromDynamic).Cast<IUmbracoEntity>().ToList();
|
||||
|
||||
//Now we need to merge in the property data since we need paging and we can't do this the way that the big media query was working before
|
||||
foreach (var idGroup in ids)
|
||||
{
|
||||
var propSql = GetPropertySql(Constants.ObjectTypes.Media)
|
||||
.Where("contentNodeId IN (@ids)", new {ids = idGroup})
|
||||
.OrderBy("contentNodeId");
|
||||
|
||||
//This does NOT fetch all data into memory in a list, this will read
|
||||
// over the records as a data reader, this is much better for performance and memory,
|
||||
// but it means that during the reading of this data set, nothing else can be read
|
||||
// from SQL server otherwise we'll get an exception.
|
||||
var allPropertyData = _work.Database.Query<dynamic>(propSql);
|
||||
|
||||
//keep track of the current property data item being enumerated
|
||||
var propertyDataSetEnumerator = allPropertyData.GetEnumerator();
|
||||
var hasCurrent = false; // initially there is no enumerator.Current
|
||||
|
||||
try
|
||||
{
|
||||
//This must be sorted by node id (which is done by SQL) because this is how we are sorting the query to lookup property types above,
|
||||
// which allows us to more efficiently iterate over the large data set of property values.
|
||||
foreach (var entity in entities)
|
||||
{
|
||||
// assemble the dtos for this def
|
||||
// use the available enumerator.Current if any else move to next
|
||||
while (hasCurrent || propertyDataSetEnumerator.MoveNext())
|
||||
{
|
||||
if (propertyDataSetEnumerator.Current.contentNodeId == entity.Id)
|
||||
{
|
||||
hasCurrent = false; // enumerator.Current is not available
|
||||
|
||||
//the property data goes into the additional data
|
||||
entity.AdditionalData[propertyDataSetEnumerator.Current.propertyTypeAlias] = new UmbracoEntity.EntityProperty
|
||||
{
|
||||
PropertyEditorAlias = propertyDataSetEnumerator.Current.propertyEditorAlias,
|
||||
Value = StringExtensions.IsNullOrWhiteSpace(propertyDataSetEnumerator.Current.dataNtext)
|
||||
? propertyDataSetEnumerator.Current.dataNvarchar
|
||||
: StringExtensions.ConvertToJsonIfPossible(propertyDataSetEnumerator.Current.dataNtext)
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
hasCurrent = true; // enumerator.Current is available for another def
|
||||
break; // no more propertyDataDto for this def
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
propertyDataSetEnumerator.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
result = entities;
|
||||
}
|
||||
else
|
||||
{
|
||||
var pagedResult = _work.Database.Page<dynamic>(pageIndex + 1, pageSize, pagedSql);
|
||||
result = pagedResult.Items.Select(factory.BuildEntityFromDynamic).Cast<IUmbracoEntity>().ToList();
|
||||
}
|
||||
|
||||
//The total items from the PetaPoco page query will be wrong due to the Outer join used on parent, depending on the search this will
|
||||
//return duplicate results when the COUNT is used in conjuction with it, so we need to get the total on our own.
|
||||
|
||||
//generate a query that does not contain the LEFT Join for parent, this would cause
|
||||
//the COUNT(*) query to return the wrong
|
||||
var sqlCountClause = GetBaseWhere(
|
||||
(isC, isM, f) => GetBase(isC, isM, f, true), //true == is a count query
|
||||
isContent, isMedia, sql =>
|
||||
{
|
||||
if (filter != null)
|
||||
{
|
||||
foreach (var filterClaus in filter.GetWhereClauses())
|
||||
{
|
||||
sql.Where(filterClaus.Item1, filterClaus.Item2);
|
||||
}
|
||||
}
|
||||
}, objectTypeId);
|
||||
var translatorCount = new SqlTranslator<IUmbracoEntity>(sqlCountClause, query);
|
||||
var countSql = translatorCount.Translate();
|
||||
|
||||
totalRecords = _work.Database.ExecuteScalar<int>(countSql);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public IUmbracoEntity GetByKey(Guid key)
|
||||
{
|
||||
var sql = GetBaseWhere(GetBase, false, false, key);
|
||||
@@ -71,8 +190,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
if (isMedia)
|
||||
{
|
||||
//for now treat media differently
|
||||
//TODO: We should really use this methodology for Content/Members too!! since it includes properties and ALL of the dynamic db fields
|
||||
//Treat media differently for now, as an Entity it will be returned with ALL of it's properties in the AdditionalData bag!
|
||||
var entities = _work.Database.Fetch<dynamic, UmbracoPropertyDto, UmbracoEntity>(
|
||||
new UmbracoEntityRelator().Map, sql);
|
||||
|
||||
@@ -115,8 +233,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
if (isMedia)
|
||||
{
|
||||
//for now treat media differently
|
||||
//TODO: We should really use this methodology for Content/Members too!! since it includes properties and ALL of the dynamic db fields
|
||||
//Treat media differently for now, as an Entity it will be returned with ALL of it's properties in the AdditionalData bag!
|
||||
var entities = _work.Database.Fetch<dynamic, UmbracoPropertyDto, UmbracoEntity>(
|
||||
new UmbracoEntityRelator().Map, sql);
|
||||
|
||||
@@ -171,8 +288,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
if (isMedia)
|
||||
{
|
||||
//for now treat media differently
|
||||
//TODO: We should really use this methodology for Content/Members too!! since it includes properties and ALL of the dynamic db fields
|
||||
//Treat media differently for now, as an Entity it will be returned with ALL of it's properties in the AdditionalData bag!
|
||||
var entities = _work.Database.Fetch<dynamic, UmbracoPropertyDto, UmbracoEntity>(
|
||||
new UmbracoEntityRelator().Map, sql);
|
||||
foreach (var entity in entities)
|
||||
@@ -231,8 +347,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
}
|
||||
});
|
||||
|
||||
//treat media differently for now
|
||||
//TODO: We should really use this methodology for Content/Members too!! since it includes properties and ALL of the dynamic db fields
|
||||
//Treat media differently for now, as an Entity it will be returned with ALL of it's properties in the AdditionalData bag!
|
||||
var entities = _work.Database.Fetch<dynamic, UmbracoPropertyDto, UmbracoEntity>(
|
||||
new UmbracoEntityRelator().Map, mediaSql);
|
||||
return entities;
|
||||
@@ -278,11 +393,9 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
return GetFullSqlForMedia(entitySql.Append(GetGroupBy(isContent, true, false)), filter);
|
||||
}
|
||||
|
||||
private Sql GetFullSqlForMedia(Sql entitySql, Action<Sql> filter = null)
|
||||
private Sql GetPropertySql(string nodeObjectType)
|
||||
{
|
||||
//this will add any dataNvarchar property to the output which can be added to the additional properties
|
||||
|
||||
var joinSql = new Sql()
|
||||
var sql = new Sql()
|
||||
.Select("contentNodeId, versionId, dataNvarchar, dataNtext, propertyEditorAlias, alias as propertyTypeAlias")
|
||||
.From<PropertyDataDto>()
|
||||
.InnerJoin<NodeDto>()
|
||||
@@ -291,7 +404,16 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
.On<PropertyTypeDto, PropertyDataDto>(dto => dto.Id, dto => dto.PropertyTypeId)
|
||||
.InnerJoin<DataTypeDto>()
|
||||
.On<PropertyTypeDto, DataTypeDto>(dto => dto.DataTypeId, dto => dto.DataTypeId)
|
||||
.Where("umbracoNode.nodeObjectType = @nodeObjectType", new {nodeObjectType = Constants.ObjectTypes.Media});
|
||||
.Where("umbracoNode.nodeObjectType = @nodeObjectType", new { nodeObjectType = nodeObjectType });
|
||||
|
||||
return sql;
|
||||
}
|
||||
|
||||
private Sql GetFullSqlForMedia(Sql entitySql, Action<Sql> filter = null)
|
||||
{
|
||||
//this will add any dataNvarchar property to the output which can be added to the additional properties
|
||||
|
||||
var joinSql = GetPropertySql(Constants.ObjectTypes.Media);
|
||||
|
||||
if (filter != null)
|
||||
{
|
||||
@@ -310,34 +432,52 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
.OrderBy("sortOrder, id");
|
||||
|
||||
return wrappedSql;
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual Sql GetBase(bool isContent, bool isMedia, Action<Sql> customFilter)
|
||||
{
|
||||
var columns = new List<object>
|
||||
{
|
||||
"umbracoNode.id",
|
||||
"umbracoNode.trashed",
|
||||
"umbracoNode.parentID",
|
||||
"umbracoNode.nodeUser",
|
||||
"umbracoNode.level",
|
||||
"umbracoNode.path",
|
||||
"umbracoNode.sortOrder",
|
||||
"umbracoNode.uniqueID",
|
||||
"umbracoNode.text",
|
||||
"umbracoNode.nodeObjectType",
|
||||
"umbracoNode.createDate",
|
||||
"COUNT(parent.parentID) as children"
|
||||
};
|
||||
return GetBase(isContent, isMedia, customFilter, false);
|
||||
}
|
||||
|
||||
if (isContent || isMedia)
|
||||
protected virtual Sql GetBase(bool isContent, bool isMedia, Action<Sql> customFilter, bool isCount)
|
||||
{
|
||||
var columns = new List<object>();
|
||||
if (isCount)
|
||||
{
|
||||
columns.Add("published.versionId as publishedVersion");
|
||||
columns.Add("latest.versionId as newestVersion");
|
||||
columns.Add("contenttype.alias");
|
||||
columns.Add("contenttype.icon");
|
||||
columns.Add("contenttype.thumbnail");
|
||||
columns.Add("contenttype.isContainer");
|
||||
columns.Add("COUNT(*)");
|
||||
}
|
||||
else
|
||||
{
|
||||
columns.AddRange(new List<object>
|
||||
{
|
||||
"umbracoNode.id",
|
||||
"umbracoNode.trashed",
|
||||
"umbracoNode.parentID",
|
||||
"umbracoNode.nodeUser",
|
||||
"umbracoNode.level",
|
||||
"umbracoNode.path",
|
||||
"umbracoNode.sortOrder",
|
||||
"umbracoNode.uniqueID",
|
||||
"umbracoNode.text",
|
||||
"umbracoNode.nodeObjectType",
|
||||
"umbracoNode.createDate",
|
||||
"COUNT(parent.parentID) as children"
|
||||
});
|
||||
|
||||
if (isContent || isMedia)
|
||||
{
|
||||
if (isContent)
|
||||
{
|
||||
//only content has this info
|
||||
columns.Add("published.versionId as publishedVersion");
|
||||
columns.Add("document.versionId as newestVersion");
|
||||
}
|
||||
|
||||
columns.Add("contenttype.alias");
|
||||
columns.Add("contenttype.icon");
|
||||
columns.Add("contenttype.thumbnail");
|
||||
columns.Add("contenttype.isContainer");
|
||||
}
|
||||
}
|
||||
|
||||
//Creates an SQL query to return a single row for the entity
|
||||
@@ -348,17 +488,24 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
if (isContent || isMedia)
|
||||
{
|
||||
entitySql.InnerJoin("cmsContent content").On("content.nodeId = umbracoNode.id")
|
||||
.LeftJoin("cmsContentType contenttype").On("contenttype.nodeId = content.contentType")
|
||||
.LeftJoin(
|
||||
"(SELECT nodeId, versionId FROM cmsDocument WHERE published = 1 GROUP BY nodeId, versionId) as published")
|
||||
.On("umbracoNode.id = published.nodeId")
|
||||
.LeftJoin(
|
||||
"(SELECT nodeId, versionId FROM cmsDocument WHERE newest = 1 GROUP BY nodeId, versionId) as latest")
|
||||
.On("umbracoNode.id = latest.nodeId");
|
||||
entitySql.InnerJoin("cmsContent content").On("content.nodeId = umbracoNode.id");
|
||||
|
||||
if (isContent)
|
||||
{
|
||||
//only content has this info
|
||||
entitySql
|
||||
.InnerJoin("cmsDocument document").On("document.nodeId = umbracoNode.id")
|
||||
.LeftJoin("(SELECT nodeId, versionId FROM cmsDocument WHERE published = 1) as published")
|
||||
.On("umbracoNode.id = published.nodeId");
|
||||
}
|
||||
|
||||
entitySql.LeftJoin("cmsContentType contenttype").On("contenttype.nodeId = content.contentType");
|
||||
}
|
||||
|
||||
entitySql.LeftJoin("umbracoNode parent").On("parent.parentID = umbracoNode.id");
|
||||
if (isCount == false)
|
||||
{
|
||||
entitySql.LeftJoin("umbracoNode parent").On("parent.parentID = umbracoNode.id");
|
||||
}
|
||||
|
||||
if (customFilter != null)
|
||||
{
|
||||
@@ -372,22 +519,42 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
var sql = baseQuery(isContent, isMedia, filter)
|
||||
.Where("umbracoNode.nodeObjectType = @NodeObjectType", new { NodeObjectType = nodeObjectType });
|
||||
|
||||
if (isContent)
|
||||
{
|
||||
sql.Where("document.newest = 1");
|
||||
}
|
||||
|
||||
return sql;
|
||||
}
|
||||
|
||||
protected virtual Sql GetBaseWhere(Func<bool, bool, Action<Sql>, Sql> baseQuery, bool isContent, bool isMedia, int id)
|
||||
{
|
||||
var sql = baseQuery(isContent, isMedia, null)
|
||||
.Where("umbracoNode.id = @Id", new { Id = id })
|
||||
.Append(GetGroupBy(isContent, isMedia));
|
||||
.Where("umbracoNode.id = @Id", new { Id = id });
|
||||
|
||||
if (isContent)
|
||||
{
|
||||
sql.Where("document.newest = 1");
|
||||
}
|
||||
|
||||
sql.Append(GetGroupBy(isContent, isMedia));
|
||||
|
||||
return sql;
|
||||
}
|
||||
|
||||
protected virtual Sql GetBaseWhere(Func<bool, bool, Action<Sql>, Sql> baseQuery, bool isContent, bool isMedia, Guid key)
|
||||
{
|
||||
var sql = baseQuery(isContent, isMedia, null)
|
||||
.Where("umbracoNode.uniqueID = @UniqueID", new { UniqueID = key })
|
||||
.Append(GetGroupBy(isContent, isMedia));
|
||||
.Where("umbracoNode.uniqueID = @UniqueID", new { UniqueID = key });
|
||||
|
||||
if (isContent)
|
||||
{
|
||||
sql.Where("document.newest = 1");
|
||||
}
|
||||
|
||||
sql.Append(GetGroupBy(isContent, isMedia));
|
||||
|
||||
return sql;
|
||||
}
|
||||
|
||||
@@ -396,6 +563,12 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
var sql = baseQuery(isContent, isMedia, null)
|
||||
.Where("umbracoNode.id = @Id AND umbracoNode.nodeObjectType = @NodeObjectType",
|
||||
new {Id = id, NodeObjectType = nodeObjectType});
|
||||
|
||||
if (isContent)
|
||||
{
|
||||
sql.Where("document.newest = 1");
|
||||
}
|
||||
|
||||
return sql;
|
||||
}
|
||||
|
||||
@@ -404,30 +577,39 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
var sql = baseQuery(isContent, isMedia, null)
|
||||
.Where("umbracoNode.uniqueID = @UniqueID AND umbracoNode.nodeObjectType = @NodeObjectType",
|
||||
new { UniqueID = key, NodeObjectType = nodeObjectType });
|
||||
|
||||
if (isContent)
|
||||
{
|
||||
sql.Where("document.newest = 1");
|
||||
}
|
||||
|
||||
return sql;
|
||||
}
|
||||
|
||||
protected virtual Sql GetGroupBy(bool isContent, bool isMedia, bool includeSort = true)
|
||||
{
|
||||
var columns = new List<object>
|
||||
{
|
||||
"umbracoNode.id",
|
||||
"umbracoNode.trashed",
|
||||
"umbracoNode.parentID",
|
||||
"umbracoNode.nodeUser",
|
||||
"umbracoNode.level",
|
||||
"umbracoNode.path",
|
||||
"umbracoNode.sortOrder",
|
||||
"umbracoNode.uniqueID",
|
||||
"umbracoNode.text",
|
||||
"umbracoNode.nodeObjectType",
|
||||
"umbracoNode.createDate"
|
||||
};
|
||||
{
|
||||
"umbracoNode.id",
|
||||
"umbracoNode.trashed",
|
||||
"umbracoNode.parentID",
|
||||
"umbracoNode.nodeUser",
|
||||
"umbracoNode.level",
|
||||
"umbracoNode.path",
|
||||
"umbracoNode.sortOrder",
|
||||
"umbracoNode.uniqueID",
|
||||
"umbracoNode.text",
|
||||
"umbracoNode.nodeObjectType",
|
||||
"umbracoNode.createDate"
|
||||
};
|
||||
|
||||
if (isContent || isMedia)
|
||||
{
|
||||
columns.Add("published.versionId");
|
||||
columns.Add("latest.versionId");
|
||||
if (isContent)
|
||||
{
|
||||
columns.Add("published.versionId");
|
||||
columns.Add("document.versionId");
|
||||
}
|
||||
columns.Add("contenttype.alias");
|
||||
columns.Add("contenttype.icon");
|
||||
columns.Add("contenttype.thumbnail");
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Repositories
|
||||
@@ -16,6 +17,21 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
IEnumerable<IUmbracoEntity> GetByQuery(IQuery<IUmbracoEntity> query);
|
||||
IEnumerable<IUmbracoEntity> GetByQuery(IQuery<IUmbracoEntity> query, Guid objectTypeId);
|
||||
|
||||
/// <summary>
|
||||
/// Gets paged results
|
||||
/// </summary>
|
||||
/// <param name="query">Query to excute</param>
|
||||
/// <param name="objectTypeId"></param>
|
||||
/// <param name="pageIndex">Page number</param>
|
||||
/// <param name="pageSize">Page size</param>
|
||||
/// <param name="totalRecords">Total records query would return without paging</param>
|
||||
/// <param name="orderBy">Field to order by</param>
|
||||
/// <param name="orderDirection">Direction to order by</param>
|
||||
/// <param name="filter"></param>
|
||||
/// <returns>An Enumerable list of <see cref="IUmbracoEntity"/> objects</returns>
|
||||
IEnumerable<IUmbracoEntity> GetPagedResultsByQuery(IQuery<IUmbracoEntity> query, Guid objectTypeId, long pageIndex, int pageSize, out long totalRecords,
|
||||
string orderBy, Direction orderDirection, IQuery<IUmbracoEntity> filter = null);
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the entity exists
|
||||
/// </summary>
|
||||
|
||||
@@ -73,12 +73,16 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
RelationFactory factory = null;
|
||||
var relationTypeId = -1;
|
||||
|
||||
// the ToList() here is important because we are using _relationTypeRepository and we
|
||||
// cannot wait until the result is actually enumerated to do so, because that would
|
||||
// mean we kinda capture the current unit of work and reuse it after it's been disposed
|
||||
|
||||
return dtos.Select(x =>
|
||||
{
|
||||
if (relationTypeId != x.RelationType)
|
||||
factory = new RelationFactory(_relationTypeRepository.Get(relationTypeId = x.RelationType));
|
||||
return DtoToEntity(x, factory);
|
||||
});
|
||||
}).ToList();
|
||||
}
|
||||
|
||||
private static IRelation DtoToEntity(RelationDto dto, RelationFactory factory)
|
||||
|
||||
@@ -15,6 +15,7 @@ namespace Umbraco.Core.Scoping
|
||||
private bool _disposed;
|
||||
|
||||
private UmbracoDatabase _database;
|
||||
private EventMessages _messages;
|
||||
|
||||
public NoScope(ScopeProvider scopeProvider)
|
||||
{
|
||||
@@ -61,12 +62,42 @@ namespace Umbraco.Core.Scoping
|
||||
/// <inheritdoc />
|
||||
public EventMessages Messages
|
||||
{
|
||||
get { throw new NotSupportedException(); }
|
||||
get
|
||||
{
|
||||
EnsureNotDisposed();
|
||||
if (_messages != null) return _messages;
|
||||
|
||||
// see comments in Scope
|
||||
|
||||
var factory = ScopeLifespanMessagesFactory.Current;
|
||||
if (factory == null)
|
||||
{
|
||||
_messages = new EventMessages();
|
||||
}
|
||||
else
|
||||
{
|
||||
_messages = factory.GetFromHttpContext();
|
||||
if (_messages == null)
|
||||
factory.Set(_messages = new EventMessages());
|
||||
}
|
||||
|
||||
return _messages;
|
||||
}
|
||||
}
|
||||
|
||||
public EventMessages MessagesOrNull
|
||||
{
|
||||
get { throw new NotSupportedException(); }
|
||||
get
|
||||
{
|
||||
EnsureNotDisposed();
|
||||
|
||||
// see comments in Scope
|
||||
|
||||
if (_messages != null) return _messages;
|
||||
|
||||
var factory = ScopeLifespanMessagesFactory.Current;
|
||||
return factory == null ? null : factory.GetFromHttpContext();
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -24,6 +24,7 @@ namespace Umbraco.Core.Scoping
|
||||
|
||||
private IsolatedRuntimeCache _isolatedRuntimeCache;
|
||||
private UmbracoDatabase _database;
|
||||
private EventMessages _messages;
|
||||
private ICompletable _fscope;
|
||||
private IEventDispatcher _eventDispatcher;
|
||||
|
||||
@@ -127,6 +128,7 @@ namespace Umbraco.Core.Scoping
|
||||
{
|
||||
// steal everything from NoScope
|
||||
_database = noScope.DatabaseOrNull;
|
||||
_messages = noScope.MessagesOrNull;
|
||||
|
||||
// make sure the NoScope can be replaced ie not in a transaction
|
||||
if (_database != null && _database.InTransaction)
|
||||
@@ -271,11 +273,27 @@ namespace Umbraco.Core.Scoping
|
||||
{
|
||||
EnsureNotDisposed();
|
||||
if (ParentScope != null) return ParentScope.Messages;
|
||||
//return _messages ?? (_messages = new EventMessages());
|
||||
|
||||
// ok, this isn't pretty, but it works
|
||||
// TODO kill the message factory and let the scope manage it all
|
||||
return ApplicationContext.Current.Services.EventMessagesFactory.Get();
|
||||
if (_messages != null) return _messages;
|
||||
|
||||
// this is ugly - in v7 for backward compatibility reasons, EventMessages need
|
||||
// to survive way longer that the scopes, and kinda resides on its own in http
|
||||
// context, but must also be in scopes for when we do async and lose http context
|
||||
// TODO refactor in v8
|
||||
|
||||
var factory = ScopeLifespanMessagesFactory.Current;
|
||||
if (factory == null)
|
||||
{
|
||||
_messages = new EventMessages();
|
||||
}
|
||||
else
|
||||
{
|
||||
_messages = factory.GetFromHttpContext();
|
||||
if (_messages == null)
|
||||
factory.Set(_messages = new EventMessages());
|
||||
}
|
||||
|
||||
return _messages;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -284,7 +302,14 @@ namespace Umbraco.Core.Scoping
|
||||
get
|
||||
{
|
||||
EnsureNotDisposed();
|
||||
return ParentScope == null ? null : ParentScope.MessagesOrNull;
|
||||
if (ParentScope != null) return ParentScope.MessagesOrNull;
|
||||
|
||||
// see comments in Messages
|
||||
|
||||
if (_messages != null) return _messages;
|
||||
|
||||
var factory = ScopeLifespanMessagesFactory.Current;
|
||||
return factory == null ? null : factory.GetFromHttpContext();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -343,13 +368,13 @@ namespace Umbraco.Core.Scoping
|
||||
#endif
|
||||
}
|
||||
|
||||
var parent = ParentScope;
|
||||
_scopeProvider.AmbientScope = parent;
|
||||
|
||||
#if DEBUG_SCOPES
|
||||
_scopeProvider.Disposed(this);
|
||||
#endif
|
||||
|
||||
var parent = ParentScope;
|
||||
_scopeProvider.AmbientScope = parent;
|
||||
|
||||
if (parent != null)
|
||||
parent.ChildCompleted(_completed);
|
||||
else
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Runtime.Remoting.Messaging;
|
||||
using System.Text;
|
||||
using System.Web;
|
||||
using Umbraco.Core.Events;
|
||||
using Umbraco.Core.Persistence;
|
||||
@@ -99,18 +100,23 @@ namespace Umbraco.Core.Scoping
|
||||
where T : class
|
||||
{
|
||||
var objectKey = CallContext.LogicalGetData(key).AsGuid();
|
||||
if (objectKey == Guid.Empty) return null;
|
||||
|
||||
lock (StaticCallContextObjectsLock)
|
||||
{
|
||||
object callContextObject;
|
||||
if (StaticCallContextObjects.TryGetValue(objectKey, out callContextObject))
|
||||
{
|
||||
#if DEBUG_SCOPES
|
||||
//Logging.LogHelper.Debug<ScopeProvider>("GotObject " + objectKey.ToString("N").Substring(0, 8));
|
||||
Logging.LogHelper.Debug<ScopeProvider>("Got " + typeof(T).Name + " Object " + objectKey.ToString("N").Substring(0, 8));
|
||||
//Logging.LogHelper.Debug<ScopeProvider>("At:\r\n" + Head(Environment.StackTrace, 24));
|
||||
#endif
|
||||
return (T) callContextObject;
|
||||
}
|
||||
|
||||
Logging.LogHelper.Warn<ScopeProvider>("Missed " + typeof(T).Name + " Object " + objectKey.ToString("N").Substring(0, 8));
|
||||
#if DEBUG_SCOPES
|
||||
//Logging.LogHelper.Debug<ScopeProvider>("MissedObject " + objectKey.ToString("N").Substring(0, 8));
|
||||
//Logging.LogHelper.Debug<ScopeProvider>("At:\r\n" + Head(Environment.StackTrace, 24));
|
||||
#endif
|
||||
return null;
|
||||
}
|
||||
@@ -146,7 +152,8 @@ namespace Umbraco.Core.Scoping
|
||||
lock (StaticCallContextObjectsLock)
|
||||
{
|
||||
#if DEBUG_SCOPES
|
||||
//Logging.LogHelper.Debug<ScopeProvider>("RemoveObject " + objectKey.ToString("N").Substring(0, 8));
|
||||
Logging.LogHelper.Debug<ScopeProvider>("Remove Object " + objectKey.ToString("N").Substring(0, 8));
|
||||
//Logging.LogHelper.Debug<ScopeProvider>("At:\r\n" + Head(Environment.StackTrace, 24));
|
||||
#endif
|
||||
StaticCallContextObjects.Remove(objectKey);
|
||||
}
|
||||
@@ -160,7 +167,8 @@ namespace Umbraco.Core.Scoping
|
||||
lock (StaticCallContextObjectsLock)
|
||||
{
|
||||
#if DEBUG_SCOPES
|
||||
//Logging.LogHelper.Debug<ScopeProvider>("AddObject " + objectKey.ToString("N").Substring(0, 8));
|
||||
Logging.LogHelper.Debug<ScopeProvider>("AddObject " + objectKey.ToString("N").Substring(0, 8));
|
||||
//Logging.LogHelper.Debug<ScopeProvider>("At:\r\n" + Head(Environment.StackTrace, 24));
|
||||
#endif
|
||||
StaticCallContextObjects.Add(objectKey, value);
|
||||
}
|
||||
@@ -506,7 +514,7 @@ namespace Umbraco.Core.Scoping
|
||||
lock (StaticScopeInfosLock)
|
||||
{
|
||||
if (StaticScopeInfos.ContainsKey(scope)) throw new Exception("oops: already registered.");
|
||||
//Logging.LogHelper.Debug<ScopeProvider>("Register " + scope.InstanceId.ToString("N").Substring(0, 8));
|
||||
Logging.LogHelper.Debug<ScopeProvider>("Register " + scope.InstanceId.ToString("N").Substring(0, 8));
|
||||
StaticScopeInfos[scope] = new ScopeInfo(scope, Environment.StackTrace);
|
||||
}
|
||||
}
|
||||
@@ -524,14 +532,35 @@ namespace Umbraco.Core.Scoping
|
||||
if (context == null) return;
|
||||
throw new Exception("oops: unregistered scope.");
|
||||
}
|
||||
//Logging.LogHelper.Debug<ScopeProvider>("Register context " + (context ?? "null") + " for " + scope.InstanceId.ToString("N").Substring(0, 8));
|
||||
var sb = new StringBuilder();
|
||||
var s = scope;
|
||||
while (s != null)
|
||||
{
|
||||
if (sb.Length > 0) sb.Append(" < ");
|
||||
sb.Append(s.InstanceId.ToString("N").Substring(0, 8));
|
||||
var ss = s as IScopeInternal;
|
||||
s = ss == null ? null : ss.ParentScope;
|
||||
}
|
||||
Logging.LogHelper.Debug<ScopeProvider>("Register " + (context ?? "null") + " context " + sb);
|
||||
if (context == null) info.NullStack = Environment.StackTrace;
|
||||
//if (context == null)
|
||||
// Logging.LogHelper.Debug<ScopeProvider>("STACK\r\n" + info.NullStack);
|
||||
//Logging.LogHelper.Debug<ScopeProvider>("At:\r\n" + Head(Environment.StackTrace, 16));
|
||||
info.Context = context;
|
||||
}
|
||||
}
|
||||
|
||||
private static string Head(string s, int count)
|
||||
{
|
||||
var pos = 0;
|
||||
var i = 0;
|
||||
while (i < count && pos >= 0)
|
||||
{
|
||||
pos = s.IndexOf("\r\n", pos + 1, StringComparison.OrdinalIgnoreCase);
|
||||
i++;
|
||||
}
|
||||
if (pos < 0) return s;
|
||||
return s.Substring(0, pos);
|
||||
}
|
||||
|
||||
public void Disposed(IScope scope)
|
||||
{
|
||||
lock (StaticScopeInfosLock)
|
||||
@@ -541,7 +570,7 @@ namespace Umbraco.Core.Scoping
|
||||
// enable this by default
|
||||
//Console.WriteLine("unregister " + scope.InstanceId.ToString("N").Substring(0, 8));
|
||||
StaticScopeInfos.Remove(scope);
|
||||
//Logging.LogHelper.Debug<ScopeProvider>("Remove " + scope.InstanceId.ToString("N").Substring(0, 8));
|
||||
Logging.LogHelper.Debug<ScopeProvider>("Remove " + scope.InstanceId.ToString("N").Substring(0, 8));
|
||||
|
||||
// instead, enable this to keep *all* scopes
|
||||
// beware, there can be a lot of scopes!
|
||||
|
||||
@@ -69,7 +69,7 @@ namespace Umbraco.Core.Services
|
||||
repo.AddOrUpdate(container);
|
||||
uow.Commit();
|
||||
|
||||
uow.Events.Dispatch(SavedContentTypeContainer, this, new SaveEventArgs<EntityContainer>(container, evtMsgs));
|
||||
uow.Events.Dispatch(SavedContentTypeContainer, this, new SaveEventArgs<EntityContainer>(container, evtMsgs), "SavedContentTypeContainer");
|
||||
//TODO: Audit trail ?
|
||||
|
||||
return Attempt.Succeed(new OperationStatus<EntityContainer, OperationStatusType>(container, OperationStatusType.Success, evtMsgs));
|
||||
@@ -106,7 +106,7 @@ namespace Umbraco.Core.Services
|
||||
repo.AddOrUpdate(container);
|
||||
uow.Commit();
|
||||
|
||||
uow.Events.Dispatch(SavedMediaTypeContainer, this, new SaveEventArgs<EntityContainer>(container, evtMsgs));
|
||||
uow.Events.Dispatch(SavedMediaTypeContainer, this, new SaveEventArgs<EntityContainer>(container, evtMsgs), "SavedMediaTypeContainer");
|
||||
//TODO: Audit trail ?
|
||||
|
||||
return Attempt.Succeed(new OperationStatus<EntityContainer, OperationStatusType>(container, OperationStatusType.Success, evtMsgs));
|
||||
@@ -122,14 +122,16 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
return SaveContainer(
|
||||
SavingContentTypeContainer, SavedContentTypeContainer,
|
||||
container, Constants.ObjectTypes.DocumentTypeContainerGuid, "document type", userId);
|
||||
container, Constants.ObjectTypes.DocumentTypeContainerGuid, "document type",
|
||||
"SavedContentTypeContainer", userId);
|
||||
}
|
||||
|
||||
public Attempt<OperationStatus> SaveMediaTypeContainer(EntityContainer container, int userId = 0)
|
||||
{
|
||||
return SaveContainer(
|
||||
SavingMediaTypeContainer, SavedMediaTypeContainer,
|
||||
container, Constants.ObjectTypes.MediaTypeContainerGuid, "media type", userId);
|
||||
container, Constants.ObjectTypes.MediaTypeContainerGuid, "media type",
|
||||
"SavedMediaTypeContainer", userId);
|
||||
}
|
||||
|
||||
private Attempt<OperationStatus> SaveContainer(
|
||||
@@ -137,7 +139,9 @@ namespace Umbraco.Core.Services
|
||||
TypedEventHandler<IContentTypeService, SaveEventArgs<EntityContainer>> savedEvent,
|
||||
EntityContainer container,
|
||||
Guid containerObjectType,
|
||||
string objectTypeName, int userId)
|
||||
string objectTypeName,
|
||||
string savedEventName,
|
||||
int userId)
|
||||
{
|
||||
var evtMsgs = EventMessagesFactory.Get();
|
||||
|
||||
@@ -165,7 +169,7 @@ namespace Umbraco.Core.Services
|
||||
var repo = RepositoryFactory.CreateEntityContainerRepository(uow, containerObjectType);
|
||||
repo.AddOrUpdate(container);
|
||||
uow.Commit();
|
||||
uow.Events.Dispatch(savedEvent, this, new SaveEventArgs<EntityContainer>(container, evtMsgs));
|
||||
uow.Events.Dispatch(savedEvent, this, new SaveEventArgs<EntityContainer>(container, evtMsgs), savedEventName);
|
||||
}
|
||||
|
||||
//TODO: Audit trail ?
|
||||
|
||||
@@ -9,6 +9,7 @@ using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
using Umbraco.Core.Models.Rdbms;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
using Umbraco.Core.Persistence.UnitOfWork;
|
||||
|
||||
@@ -91,6 +92,7 @@ namespace Umbraco.Core.Services
|
||||
case UmbracoObjectTypes.Member:
|
||||
case UmbracoObjectTypes.DataType:
|
||||
case UmbracoObjectTypes.DocumentTypeContainer:
|
||||
uow.Commit();
|
||||
return uow.Database.ExecuteScalar<int?>(new Sql().Select("id").From<NodeDto>().Where<NodeDto>(dto => dto.UniqueId == key));
|
||||
case UmbracoObjectTypes.RecycleBin:
|
||||
case UmbracoObjectTypes.Stylesheet:
|
||||
@@ -129,6 +131,7 @@ namespace Umbraco.Core.Services
|
||||
case UmbracoObjectTypes.DocumentType:
|
||||
case UmbracoObjectTypes.Member:
|
||||
case UmbracoObjectTypes.DataType:
|
||||
uow.Commit();
|
||||
return uow.Database.ExecuteScalar<Guid?>(new Sql().Select("uniqueID").From<NodeDto>().Where<NodeDto>(dto => dto.NodeId == id));
|
||||
case UmbracoObjectTypes.RecycleBin:
|
||||
case UmbracoObjectTypes.Stylesheet:
|
||||
@@ -374,6 +377,115 @@ namespace Umbraco.Core.Services
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a paged collection of children
|
||||
/// </summary>
|
||||
/// <param name="parentId">The parent id to return children for</param>
|
||||
/// <param name="umbracoObjectType"></param>
|
||||
/// <param name="pageIndex"></param>
|
||||
/// <param name="pageSize"></param>
|
||||
/// <param name="totalRecords"></param>
|
||||
/// <param name="orderBy"></param>
|
||||
/// <param name="orderDirection"></param>
|
||||
/// <param name="filter"></param>
|
||||
/// <returns></returns>
|
||||
public IEnumerable<IUmbracoEntity> GetPagedChildren(int parentId, UmbracoObjectTypes umbracoObjectType, long pageIndex, int pageSize, out long totalRecords,
|
||||
string orderBy = "SortOrder", Direction orderDirection = Direction.Ascending, string filter = "")
|
||||
{
|
||||
var objectTypeId = umbracoObjectType.GetGuid();
|
||||
using (var uow = UowProvider.GetUnitOfWork())
|
||||
{
|
||||
var repository = RepositoryFactory.CreateEntityRepository(uow);
|
||||
var query = Query<IUmbracoEntity>.Builder.Where(x => x.ParentId == parentId && x.Trashed == false);
|
||||
|
||||
IQuery<IUmbracoEntity> filterQuery = null;
|
||||
if (filter.IsNullOrWhiteSpace() == false)
|
||||
{
|
||||
filterQuery = Query<IUmbracoEntity>.Builder.Where(x => x.Name.Contains(filter));
|
||||
}
|
||||
|
||||
var contents = repository.GetPagedResultsByQuery(query, objectTypeId, pageIndex, pageSize, out totalRecords, orderBy, orderDirection, filterQuery);
|
||||
uow.Commit();
|
||||
return contents;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a paged collection of descendants
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <param name="umbracoObjectType"></param>
|
||||
/// <param name="pageIndex"></param>
|
||||
/// <param name="pageSize"></param>
|
||||
/// <param name="totalRecords"></param>
|
||||
/// <param name="orderBy"></param>
|
||||
/// <param name="orderDirection"></param>
|
||||
/// <param name="filter"></param>
|
||||
/// <returns></returns>
|
||||
public IEnumerable<IUmbracoEntity> GetPagedDescendants(int id, UmbracoObjectTypes umbracoObjectType, long pageIndex, int pageSize, out long totalRecords,
|
||||
string orderBy = "path", Direction orderDirection = Direction.Ascending, string filter = "")
|
||||
{
|
||||
var objectTypeId = umbracoObjectType.GetGuid();
|
||||
using (var uow = UowProvider.GetUnitOfWork())
|
||||
{
|
||||
var repository = RepositoryFactory.CreateEntityRepository(uow);
|
||||
|
||||
var query = Query<IUmbracoEntity>.Builder;
|
||||
//if the id is System Root, then just get all
|
||||
if (id != Constants.System.Root)
|
||||
query.Where(x => x.Path.SqlContains(string.Format(",{0},", id), TextColumnType.NVarchar));
|
||||
|
||||
IQuery<IUmbracoEntity> filterQuery = null;
|
||||
if (filter.IsNullOrWhiteSpace() == false)
|
||||
{
|
||||
filterQuery = Query<IUmbracoEntity>.Builder.Where(x => x.Name.Contains(filter));
|
||||
}
|
||||
|
||||
var contents = repository.GetPagedResultsByQuery(query, objectTypeId, pageIndex, pageSize, out totalRecords, orderBy, orderDirection, filterQuery);
|
||||
uow.Commit();
|
||||
return contents;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a paged collection of descendants from the root
|
||||
/// </summary>
|
||||
/// <param name="umbracoObjectType"></param>
|
||||
/// <param name="pageIndex"></param>
|
||||
/// <param name="pageSize"></param>
|
||||
/// <param name="totalRecords"></param>
|
||||
/// <param name="orderBy"></param>
|
||||
/// <param name="orderDirection"></param>
|
||||
/// <param name="filter"></param>
|
||||
/// <param name="includeTrashed">true/false to include trashed objects</param>
|
||||
/// <returns></returns>
|
||||
public IEnumerable<IUmbracoEntity> GetPagedDescendantsFromRoot(UmbracoObjectTypes umbracoObjectType, long pageIndex, int pageSize, out long totalRecords,
|
||||
string orderBy = "path", Direction orderDirection = Direction.Ascending, string filter = "", bool includeTrashed = true)
|
||||
{
|
||||
var objectTypeId = umbracoObjectType.GetGuid();
|
||||
using (var uow = UowProvider.GetUnitOfWork())
|
||||
{
|
||||
var repository = RepositoryFactory.CreateEntityRepository(uow);
|
||||
|
||||
var query = Query<IUmbracoEntity>.Builder;
|
||||
//don't include trashed if specfied
|
||||
if (includeTrashed == false)
|
||||
{
|
||||
query.Where(x => x.Trashed == false);
|
||||
}
|
||||
|
||||
IQuery<IUmbracoEntity> filterQuery = null;
|
||||
if (filter.IsNullOrWhiteSpace() == false)
|
||||
{
|
||||
filterQuery = Query<IUmbracoEntity>.Builder.Where(x => x.Name.Contains(filter));
|
||||
}
|
||||
|
||||
var contents = repository.GetPagedResultsByQuery(query, objectTypeId, pageIndex, pageSize, out totalRecords, orderBy, orderDirection, filterQuery);
|
||||
uow.Commit();
|
||||
return contents;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a collection of descendents by the parents Id
|
||||
/// </summary>
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
|
||||
|
||||
namespace Umbraco.Core.Services
|
||||
{
|
||||
@@ -137,6 +138,51 @@ namespace Umbraco.Core.Services
|
||||
/// <returns>An enumerable list of <see cref="IUmbracoEntity"/> objects</returns>
|
||||
IEnumerable<IUmbracoEntity> GetChildren(int parentId, UmbracoObjectTypes umbracoObjectType);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a paged collection of children
|
||||
/// </summary>
|
||||
/// <param name="parentId">The parent id to return children for</param>
|
||||
/// <param name="umbracoObjectType"></param>
|
||||
/// <param name="pageIndex"></param>
|
||||
/// <param name="pageSize"></param>
|
||||
/// <param name="totalRecords"></param>
|
||||
/// <param name="orderBy"></param>
|
||||
/// <param name="orderDirection"></param>
|
||||
/// <param name="filter"></param>
|
||||
/// <returns></returns>
|
||||
IEnumerable<IUmbracoEntity> GetPagedChildren(int parentId, UmbracoObjectTypes umbracoObjectType, long pageIndex, int pageSize, out long totalRecords,
|
||||
string orderBy = "SortOrder", Direction orderDirection = Direction.Ascending, string filter = "");
|
||||
|
||||
/// <summary>
|
||||
/// Returns a paged collection of descendants
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <param name="umbracoObjectType"></param>
|
||||
/// <param name="pageIndex"></param>
|
||||
/// <param name="pageSize"></param>
|
||||
/// <param name="totalRecords"></param>
|
||||
/// <param name="orderBy"></param>
|
||||
/// <param name="orderDirection"></param>
|
||||
/// <param name="filter"></param>
|
||||
/// <returns></returns>
|
||||
IEnumerable<IUmbracoEntity> GetPagedDescendants(int id, UmbracoObjectTypes umbracoObjectType, long pageIndex, int pageSize, out long totalRecords,
|
||||
string orderBy = "path", Direction orderDirection = Direction.Ascending, string filter = "");
|
||||
|
||||
/// <summary>
|
||||
/// Returns a paged collection of descendants from the root
|
||||
/// </summary>
|
||||
/// <param name="umbracoObjectType"></param>
|
||||
/// <param name="pageIndex"></param>
|
||||
/// <param name="pageSize"></param>
|
||||
/// <param name="totalRecords"></param>
|
||||
/// <param name="orderBy"></param>
|
||||
/// <param name="orderDirection"></param>
|
||||
/// <param name="filter"></param>
|
||||
/// <param name="includeTrashed">true/false to include trashed objects</param>
|
||||
/// <returns></returns>
|
||||
IEnumerable<IUmbracoEntity> GetPagedDescendantsFromRoot(UmbracoObjectTypes umbracoObjectType, long pageIndex, int pageSize, out long totalRecords,
|
||||
string orderBy = "path", Direction orderDirection = Direction.Ascending, string filter = "", bool includeTrashed = true);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a collection of descendents by the parents Id
|
||||
/// </summary>
|
||||
|
||||
@@ -311,10 +311,13 @@
|
||||
<Compile Include="Deploy\ArtifactSignature.cs" />
|
||||
<Compile Include="Deploy\Difference.cs" />
|
||||
<Compile Include="Deploy\Direction.cs" />
|
||||
<Compile Include="Deploy\IFileStore.cs" />
|
||||
<Compile Include="Deploy\IFileType.cs" />
|
||||
<Compile Include="Deploy\IFileTypeCollection.cs" />
|
||||
<Compile Include="Events\EventDefinitionFilter.cs" />
|
||||
<Compile Include="Events\IDeletingMediaFilesEventArgs.cs" />
|
||||
<Compile Include="Events\ScopeEventDispatcherBase.cs" />
|
||||
<Compile Include="Events\ScopeLifespanMessagesFactory.cs" />
|
||||
<Compile Include="IHttpContextAccessor.cs" />
|
||||
<Compile Include="OrderedHashSet.cs" />
|
||||
<Compile Include="Events\UninstallPackageEventArgs.cs" />
|
||||
<Compile Include="Models\GridValue.cs" />
|
||||
@@ -326,7 +329,6 @@
|
||||
<Compile Include="Deploy\IImageSourceParser.cs" />
|
||||
<Compile Include="Deploy\ILocalLinkParser.cs" />
|
||||
<Compile Include="Deploy\IMacroParser.cs" />
|
||||
<Compile Include="Deploy\IPrettyArtifact.cs" />
|
||||
<Compile Include="Deploy\IPreValueConnector.cs" />
|
||||
<Compile Include="Deploy\IServiceConnector.cs" />
|
||||
<Compile Include="Deploy\IValueConnector.cs" />
|
||||
|
||||
@@ -336,8 +336,9 @@ namespace Umbraco.Tests.IO
|
||||
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
|
||||
ss.AddFile("path/to/some/dir/f1.txt", ms);
|
||||
|
||||
// file is only written to the shadow fs
|
||||
Assert.IsTrue(File.Exists(path + "/ShadowSystem/path/to/some/dir/f1.txt"));
|
||||
|
||||
Assert.IsFalse(File.Exists(path + "/ShadowTests/path/to/some/dir/f1.txt"));
|
||||
// let the shadow fs die
|
||||
}
|
||||
|
||||
@@ -382,7 +383,7 @@ namespace Umbraco.Tests.IO
|
||||
|
||||
var fs = new PhysicalFileSystem(path, "ignore");
|
||||
var sw = new ShadowWrapper(fs, "shadow", scopeProvider);
|
||||
var swa = new[] { sw };
|
||||
var swa = new[] {sw};
|
||||
|
||||
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
|
||||
sw.AddFile("sub/f1.txt", ms);
|
||||
@@ -463,7 +464,7 @@ namespace Umbraco.Tests.IO
|
||||
|
||||
var fs = new PhysicalFileSystem(path, "ignore");
|
||||
var sw = new ShadowWrapper(fs, "shadow", scopeProvider);
|
||||
var swa = new[] { sw };
|
||||
var swa = new[] {sw};
|
||||
|
||||
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
|
||||
sw.AddFile("sub/f1.txt", ms);
|
||||
@@ -512,7 +513,7 @@ namespace Umbraco.Tests.IO
|
||||
|
||||
var fs = new PhysicalFileSystem(path, "ignore");
|
||||
var sw = new ShadowWrapper(fs, "shadow", scopeProvider);
|
||||
var swa = new[] { sw };
|
||||
var swa = new[] {sw};
|
||||
|
||||
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
|
||||
sw.AddFile("sub/f1.txt", ms);
|
||||
@@ -623,5 +624,385 @@ namespace Umbraco.Tests.IO
|
||||
providerMock.Setup(x => x.AmbientScope).Returns(scopeMock.Object);
|
||||
return providerMock.Object;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check that GetFiles will return all files on the shadow, while returning
|
||||
/// just one on each of the filesystems used by the shadow.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void ShadowGetFiles()
|
||||
{
|
||||
// Arrange
|
||||
var path = IOHelper.MapPath("FileSysTests");
|
||||
Directory.CreateDirectory(path);
|
||||
Directory.CreateDirectory(path + "/ShadowTests");
|
||||
Directory.CreateDirectory(path + "/ShadowSystem");
|
||||
|
||||
var fs = new PhysicalFileSystem(path + "/ShadowTests/", "ignore");
|
||||
var sfs = new PhysicalFileSystem(path + "/ShadowSystem/", "ignore");
|
||||
var ss = new ShadowFileSystem(fs, sfs);
|
||||
|
||||
// Act
|
||||
File.WriteAllText(path + "/ShadowTests/f2.txt", "foo");
|
||||
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
|
||||
ss.AddFile("f1.txt", ms);
|
||||
|
||||
// Assert
|
||||
// ensure we get 2 files from the shadow
|
||||
var getFiles = ss.GetFiles(string.Empty);
|
||||
Assert.AreEqual(2, getFiles.Count());
|
||||
|
||||
var fsFiles = fs.GetFiles(string.Empty).ToArray();
|
||||
Assert.AreEqual(1, fsFiles.Length);
|
||||
var sfsFiles = sfs.GetFiles(string.Empty).ToArray();
|
||||
Assert.AreEqual(1, sfsFiles.Length);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check that GetFiles using the filter function with empty string will return expected results
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void ShadowGetFilesUsingEmptyFilter()
|
||||
{
|
||||
// Arrange
|
||||
var path = IOHelper.MapPath("FileSysTests");
|
||||
Directory.CreateDirectory(path);
|
||||
Directory.CreateDirectory(path + "/ShadowTests");
|
||||
Directory.CreateDirectory(path + "/ShadowSystem");
|
||||
|
||||
var fs = new PhysicalFileSystem(path + "/ShadowTests/", "ignore");
|
||||
var sfs = new PhysicalFileSystem(path + "/ShadowSystem/", "ignore");
|
||||
var ss = new ShadowFileSystem(fs, sfs);
|
||||
|
||||
// Act
|
||||
File.WriteAllText(path + "/ShadowTests/f2.txt", "foo");
|
||||
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
|
||||
ss.AddFile("f1.txt", ms);
|
||||
|
||||
// Assert
|
||||
// ensure we get 2 files from the shadow
|
||||
var getFiles = ss.GetFiles(string.Empty);
|
||||
Assert.AreEqual(2, getFiles.Count());
|
||||
// ensure we get 0 files when using a empty filter
|
||||
var getFilesWithEmptyFilter = ss.GetFiles(string.Empty, "");
|
||||
Assert.AreEqual(0, getFilesWithEmptyFilter.Count());
|
||||
|
||||
var fsFiles = fs.GetFiles(string.Empty).ToArray();
|
||||
Assert.AreEqual(1, fsFiles.Length);
|
||||
var sfsFiles = sfs.GetFiles(string.Empty).ToArray();
|
||||
Assert.AreEqual(1, sfsFiles.Length);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check that GetFiles using the filter function with null will return expected results
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void ShadowGetFilesUsingNullFilter()
|
||||
{
|
||||
// Arrange
|
||||
var path = IOHelper.MapPath("FileSysTests");
|
||||
Directory.CreateDirectory(path);
|
||||
Directory.CreateDirectory(path + "/ShadowTests");
|
||||
Directory.CreateDirectory(path + "/ShadowSystem");
|
||||
|
||||
var fs = new PhysicalFileSystem(path + "/ShadowTests/", "ignore");
|
||||
var sfs = new PhysicalFileSystem(path + "/ShadowSystem/", "ignore");
|
||||
var ss = new ShadowFileSystem(fs, sfs);
|
||||
|
||||
// Act
|
||||
File.WriteAllText(path + "/ShadowTests/f2.txt", "foo");
|
||||
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
|
||||
ss.AddFile("f1.txt", ms);
|
||||
|
||||
// Assert
|
||||
// ensure we get 2 files from the shadow
|
||||
var getFiles = ss.GetFiles(string.Empty);
|
||||
Assert.AreEqual(2, getFiles.Count());
|
||||
// ensure we get 2 files when using null in filter parameter
|
||||
var getFilesWithNullFilter = ss.GetFiles(string.Empty, null);
|
||||
Assert.AreEqual(2, getFilesWithNullFilter.Count());
|
||||
|
||||
var fsFiles = fs.GetFiles(string.Empty).ToArray();
|
||||
Assert.AreEqual(1, fsFiles.Length);
|
||||
var sfsFiles = sfs.GetFiles(string.Empty).ToArray();
|
||||
Assert.AreEqual(1, sfsFiles.Length);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ShadowGetFilesUsingWildcardFilter()
|
||||
{
|
||||
// Arrange
|
||||
var path = IOHelper.MapPath("FileSysTests");
|
||||
Directory.CreateDirectory(path);
|
||||
Directory.CreateDirectory(path + "/ShadowTests");
|
||||
Directory.CreateDirectory(path + "/ShadowSystem");
|
||||
|
||||
var fs = new PhysicalFileSystem(path + "/ShadowTests/", "ignore");
|
||||
var sfs = new PhysicalFileSystem(path + "/ShadowSystem/", "ignore");
|
||||
var ss = new ShadowFileSystem(fs, sfs);
|
||||
|
||||
// Act
|
||||
File.WriteAllText(path + "/ShadowTests/f2.txt", "foo");
|
||||
File.WriteAllText(path + "/ShadowTests/f2.doc", "foo");
|
||||
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
|
||||
ss.AddFile("f1.txt", ms);
|
||||
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
|
||||
ss.AddFile("f1.doc", ms);
|
||||
|
||||
// Assert
|
||||
// ensure we get 4 files from the shadow
|
||||
var getFiles = ss.GetFiles(string.Empty);
|
||||
Assert.AreEqual(4, getFiles.Count());
|
||||
// ensure we get only 2 of 4 files from the shadow when using filter
|
||||
var getFilesWithWildcardFilter = ss.GetFiles(string.Empty, "*.doc");
|
||||
Assert.AreEqual(2, getFilesWithWildcardFilter.Count());
|
||||
|
||||
var fsFiles = fs.GetFiles(string.Empty).ToArray();
|
||||
Assert.AreEqual(2, fsFiles.Length);
|
||||
var sfsFiles = sfs.GetFiles(string.Empty).ToArray();
|
||||
Assert.AreEqual(2, sfsFiles.Length);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ShadowGetFilesUsingSingleCharacterFilter()
|
||||
{
|
||||
// Arrange
|
||||
var path = IOHelper.MapPath("FileSysTests");
|
||||
Directory.CreateDirectory(path);
|
||||
Directory.CreateDirectory(path + "/ShadowTests");
|
||||
Directory.CreateDirectory(path + "/ShadowSystem");
|
||||
|
||||
var fs = new PhysicalFileSystem(path + "/ShadowTests/", "ignore");
|
||||
var sfs = new PhysicalFileSystem(path + "/ShadowSystem/", "ignore");
|
||||
var ss = new ShadowFileSystem(fs, sfs);
|
||||
|
||||
// Act
|
||||
File.WriteAllText(path + "/ShadowTests/f2.txt", "foo");
|
||||
File.WriteAllText(path + "/ShadowTests/f2.doc", "foo");
|
||||
File.WriteAllText(path + "/ShadowTests/f2.docx", "foo");
|
||||
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
|
||||
ss.AddFile("f1.txt", ms);
|
||||
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
|
||||
ss.AddFile("f1.doc", ms);
|
||||
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
|
||||
ss.AddFile("f1.docx", ms);
|
||||
|
||||
// Assert
|
||||
// ensure we get 6 files from the shadow
|
||||
var getFiles = ss.GetFiles(string.Empty);
|
||||
Assert.AreEqual(6, getFiles.Count());
|
||||
// ensure we get only 2 of 6 files from the shadow when using filter on shadow
|
||||
var getFilesWithWildcardSinglecharFilter = ss.GetFiles(string.Empty, "f1.d?c");
|
||||
Assert.AreEqual(1, getFilesWithWildcardSinglecharFilter.Count());
|
||||
// ensure we get only 2 of 6 files from the shadow when using filter on disk
|
||||
var getFilesWithWildcardSinglecharFilter2 = ss.GetFiles(string.Empty, "f2.d?c");
|
||||
Assert.AreEqual(1, getFilesWithWildcardSinglecharFilter2.Count());
|
||||
|
||||
var fsFiles = fs.GetFiles(string.Empty).ToArray();
|
||||
Assert.AreEqual(3, fsFiles.Length);
|
||||
var sfsFiles = sfs.GetFiles(string.Empty).ToArray();
|
||||
Assert.AreEqual(3, sfsFiles.Length);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ShadowGetFilesUsingWildcardAndSingleCharacterFilter()
|
||||
{
|
||||
// Arrange
|
||||
var path = IOHelper.MapPath("FileSysTests");
|
||||
Directory.CreateDirectory(path);
|
||||
Directory.CreateDirectory(path + "/ShadowTests");
|
||||
Directory.CreateDirectory(path + "/ShadowSystem");
|
||||
|
||||
var fs = new PhysicalFileSystem(path + "/ShadowTests/", "ignore");
|
||||
var sfs = new PhysicalFileSystem(path + "/ShadowSystem/", "ignore");
|
||||
var ss = new ShadowFileSystem(fs, sfs);
|
||||
|
||||
// Act
|
||||
File.WriteAllText(path + "/ShadowTests/f2.txt", "foo");
|
||||
File.WriteAllText(path + "/ShadowTests/f2.doc", "foo");
|
||||
File.WriteAllText(path + "/ShadowTests/f2.docx", "foo");
|
||||
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
|
||||
ss.AddFile("f1.txt", ms);
|
||||
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
|
||||
ss.AddFile("f1.doc", ms);
|
||||
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
|
||||
ss.AddFile("f1.docx", ms);
|
||||
|
||||
// Assert
|
||||
// ensure we get 6 files from the shadow
|
||||
var getFiles = ss.GetFiles(string.Empty);
|
||||
Assert.AreEqual(6, getFiles.Count());
|
||||
var getFilesWithWildcardSinglecharFilter = ss.GetFiles(string.Empty, "*.d?c");
|
||||
|
||||
Assert.AreEqual(4, getFilesWithWildcardSinglecharFilter.Count());
|
||||
var getFilesWithWildcardSinglecharFilter2 = ss.GetFiles(string.Empty, "*.d?cx");
|
||||
Assert.AreEqual(2, getFilesWithWildcardSinglecharFilter2.Count());
|
||||
|
||||
var fsFiles = fs.GetFiles(string.Empty).ToArray();
|
||||
Assert.AreEqual(3, fsFiles.Length);
|
||||
var sfsFiles = sfs.GetFiles(string.Empty).ToArray();
|
||||
Assert.AreEqual(3, sfsFiles.Length);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ShadowFileSystemFilterIsAsBrokenAsRealFileSystemFilter()
|
||||
{
|
||||
// Arrange
|
||||
var path = IOHelper.MapPath("FileSysTests");
|
||||
Directory.CreateDirectory(path);
|
||||
Directory.CreateDirectory(path + "/filter");
|
||||
// create files on disk and create a "fake" list of files to verify filters against
|
||||
File.WriteAllText(path + "/filter/f1.txt", "foo");
|
||||
File.WriteAllText(path + "/filter/f1.doc", "foo");
|
||||
File.WriteAllText(path + "/filter/f1.docx", "foo");
|
||||
var files = new string[]
|
||||
{
|
||||
"f1.txt",
|
||||
"f1.doc",
|
||||
"f1.docx",
|
||||
};
|
||||
var filter1 = "";
|
||||
var filter2 = "*";
|
||||
var filter3 = "*.doc";
|
||||
var filter4 = "*.d?c";
|
||||
var filter5 = "f1.doc";
|
||||
var filter6 = "f1.d?c";
|
||||
var filter7 = "**.d?c";
|
||||
var filter8 = "f*.doc";
|
||||
|
||||
// Act & Assert
|
||||
var result1Disk = Directory.GetFiles(path + "/filter/", filter1).Select(Path.GetFileName).OrderBy(x => x).ToArray();
|
||||
var result1Fake = files.Where(x => ShadowFileSystem.FilterByRegex(x, ShadowFileSystem.FilterToRegex(filter1))).OrderBy(x => x).ToArray();
|
||||
Assert.AreEqual(result1Disk, result1Fake);
|
||||
var result2Disk = Directory.GetFiles(path + "/filter/", filter2).Select(Path.GetFileName).OrderBy(x => x).ToArray();
|
||||
var result2Fake = files.Where(x => ShadowFileSystem.FilterByRegex(x, ShadowFileSystem.FilterToRegex(filter2))).OrderBy(x => x).ToArray();
|
||||
Assert.AreEqual(result2Disk, result2Fake);
|
||||
var result3Disk = Directory.GetFiles(path + "/filter/", filter3).Select(Path.GetFileName).OrderBy(x => x).ToArray();
|
||||
var result3Fake = files.Where(x => ShadowFileSystem.FilterByRegex(x, ShadowFileSystem.FilterToRegex(filter3))).OrderBy(x => x).ToArray();
|
||||
Assert.AreEqual(result3Disk, result3Fake);
|
||||
var result4Disk = Directory.GetFiles(path + "/filter/", filter4).Select(Path.GetFileName).OrderBy(x => x).ToArray();
|
||||
var result4Fake = files.Where(x => ShadowFileSystem.FilterByRegex(x, ShadowFileSystem.FilterToRegex(filter4))).OrderBy(x => x).ToArray();
|
||||
Assert.AreEqual(result4Disk, result4Fake);
|
||||
var result5Disk = Directory.GetFiles(path + "/filter/", filter5).Select(Path.GetFileName).OrderBy(x => x).ToArray();
|
||||
var result5Fake = files.Where(x => ShadowFileSystem.FilterByRegex(x, ShadowFileSystem.FilterToRegex(filter5))).OrderBy(x => x).ToArray();
|
||||
Assert.AreEqual(result5Disk, result5Fake);
|
||||
var result6Disk = Directory.GetFiles(path + "/filter/", filter6).Select(Path.GetFileName).OrderBy(x => x).ToArray();
|
||||
var result6Fake = files.Where(x => ShadowFileSystem.FilterByRegex(x, ShadowFileSystem.FilterToRegex(filter6))).OrderBy(x => x).ToArray();
|
||||
Assert.AreEqual(result6Disk, result6Fake);
|
||||
var result7Disk = Directory.GetFiles(path + "/filter/", filter7).Select(Path.GetFileName).OrderBy(x => x).ToArray();
|
||||
var result7Fake = files.Where(x => ShadowFileSystem.FilterByRegex(x, ShadowFileSystem.FilterToRegex(filter7))).OrderBy(x => x).ToArray();
|
||||
Assert.AreEqual(result7Disk, result7Fake);
|
||||
var result8Disk = Directory.GetFiles(path + "/filter/", filter8).Select(Path.GetFileName).OrderBy(x => x).ToArray();
|
||||
var result8Fake = files.Where(x => ShadowFileSystem.FilterByRegex(x, ShadowFileSystem.FilterToRegex(filter8))).OrderBy(x => x).ToArray();
|
||||
Assert.AreEqual(result8Disk, result8Fake);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the full paths of the files on the disk.
|
||||
/// Note that this will be the *actual* path of the file, meaning a file existing on the initialized FS
|
||||
/// will be in one location, while a file written after initializing the shadow, will exist at the
|
||||
/// shadow location directory.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void ShadowGetFullPath()
|
||||
{
|
||||
// Arrange
|
||||
var path = IOHelper.MapPath("FileSysTests");
|
||||
Directory.CreateDirectory(path);
|
||||
Directory.CreateDirectory(path + "/ShadowTests");
|
||||
Directory.CreateDirectory(path + "/ShadowSystem");
|
||||
|
||||
var fs = new PhysicalFileSystem(path + "/ShadowTests/", "ignore");
|
||||
var sfs = new PhysicalFileSystem(path + "/ShadowSystem/", "ignore");
|
||||
var ss = new ShadowFileSystem(fs, sfs);
|
||||
|
||||
// Act
|
||||
File.WriteAllText(path + "/ShadowTests/f1.txt", "foo");
|
||||
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
|
||||
ss.AddFile("f2.txt", ms);
|
||||
|
||||
// Assert
|
||||
var f1FullPath = ss.GetFullPath("f1.txt");
|
||||
var f2FullPath = ss.GetFullPath("f2.txt");
|
||||
Assert.AreEqual(Path.Combine(path, "ShadowTests", "f1.txt"), f1FullPath);
|
||||
Assert.AreEqual(Path.Combine(path, "ShadowSystem", "f2.txt"), f2FullPath);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the path relative to the filesystem root
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This file stuff in this test is kinda irrelevant with the current implementation.
|
||||
/// We do tests that the files are written to the correct places and the relative path is returned correct,
|
||||
/// but GetRelativePath is currently really just string manipulation so files are not actually hit by the code.
|
||||
/// Leaving the file stuff in here for now in case the method becomes more clever at some point.
|
||||
/// </remarks>
|
||||
[Test]
|
||||
public void ShadowGetRelativePath()
|
||||
{
|
||||
// Arrange
|
||||
var path = IOHelper.MapPath("FileSysTests");
|
||||
Directory.CreateDirectory(path);
|
||||
Directory.CreateDirectory(path + "/ShadowTests");
|
||||
Directory.CreateDirectory(path + "/ShadowSystem");
|
||||
|
||||
var fs = new PhysicalFileSystem(path + "/ShadowTests/", "ignore");
|
||||
var sfs = new PhysicalFileSystem(path + "/ShadowSystem/", "ignore");
|
||||
var ss = new ShadowFileSystem(fs, sfs);
|
||||
|
||||
// Act
|
||||
File.WriteAllText(path + "/ShadowTests/f1.txt", "foo");
|
||||
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
|
||||
ss.AddFile("f2.txt", ms);
|
||||
|
||||
// Assert
|
||||
var f1RelativePath = ss.GetRelativePath("f1.txt");
|
||||
var f2RelativePath = ss.GetRelativePath("f2.txt");
|
||||
Assert.AreEqual("f1.txt", f1RelativePath);
|
||||
Assert.AreEqual("f2.txt", f2RelativePath);
|
||||
Assert.IsTrue(File.Exists(Path.Combine(path, "ShadowTests", "f1.txt")));
|
||||
Assert.IsFalse(File.Exists(Path.Combine(path, "ShadowTests", "f2.txt")));
|
||||
Assert.IsTrue(File.Exists(Path.Combine(path, "ShadowSystem", "f2.txt")));
|
||||
Assert.IsFalse(File.Exists(Path.Combine(path, "ShadowSystem", "f1.txt")));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensure the url returned contains the path relative to the FS root,
|
||||
/// but including the rootUrl the FS was initialized with.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This file stuff in this test is kinda irrelevant with the current implementation.
|
||||
/// We do tests that the files are written to the correct places and the url is returned correct,
|
||||
/// but GetUrl is currently really just string manipulation so files are not actually hit by the code.
|
||||
/// Leaving the file stuff in here for now in case the method becomes more clever at some point.
|
||||
/// </remarks>
|
||||
[Test]
|
||||
public void ShadowGetUrl()
|
||||
{
|
||||
// Arrange
|
||||
var path = IOHelper.MapPath("FileSysTests");
|
||||
Directory.CreateDirectory(path);
|
||||
Directory.CreateDirectory(path + "/ShadowTests");
|
||||
Directory.CreateDirectory(path + "/ShadowSystem");
|
||||
|
||||
var fs = new PhysicalFileSystem(path + "/ShadowTests/", "rootUrl");
|
||||
var sfs = new PhysicalFileSystem(path + "/ShadowSystem/", "rootUrl");
|
||||
var ss = new ShadowFileSystem(fs, sfs);
|
||||
|
||||
// Act
|
||||
File.WriteAllText(path + "/ShadowTests/f1.txt", "foo");
|
||||
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
|
||||
ss.AddFile("f2.txt", ms);
|
||||
|
||||
// Assert
|
||||
var f1Url = ss.GetUrl("f1.txt");
|
||||
var f2Url = ss.GetUrl("f2.txt");
|
||||
Assert.AreEqual("rootUrl/f1.txt", f1Url);
|
||||
Assert.AreEqual("rootUrl/f2.txt", f2Url);
|
||||
Assert.IsTrue(File.Exists(Path.Combine(path, "ShadowTests", "f1.txt")));
|
||||
Assert.IsFalse(File.Exists(Path.Combine(path, "ShadowTests", "f2.txt")));
|
||||
Assert.IsTrue(File.Exists(Path.Combine(path, "ShadowSystem", "f2.txt")));
|
||||
Assert.IsFalse(File.Exists(Path.Combine(path, "ShadowSystem", "f1.txt")));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
@@ -25,8 +26,368 @@ namespace Umbraco.Tests.Services
|
||||
public override void TearDown()
|
||||
{
|
||||
base.TearDown();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void EntityService_Can_Get_Paged_Content_Children()
|
||||
{
|
||||
|
||||
var contentType = ServiceContext.ContentTypeService.GetContentType("umbTextpage");
|
||||
|
||||
var root = MockedContent.CreateSimpleContent(contentType);
|
||||
ServiceContext.ContentService.Save(root);
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
var c1 = MockedContent.CreateSimpleContent(contentType, Guid.NewGuid().ToString(), root);
|
||||
ServiceContext.ContentService.Save(c1);
|
||||
}
|
||||
|
||||
var service = ServiceContext.EntityService;
|
||||
|
||||
long total;
|
||||
var entities = service.GetPagedChildren(root.Id, UmbracoObjectTypes.Document, 0, 6, out total).ToArray();
|
||||
Assert.That(entities.Length, Is.EqualTo(6));
|
||||
Assert.That(total, Is.EqualTo(10));
|
||||
entities = service.GetPagedChildren(root.Id, UmbracoObjectTypes.Document, 1, 6, out total).ToArray();
|
||||
Assert.That(entities.Length, Is.EqualTo(4));
|
||||
Assert.That(total, Is.EqualTo(10));
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void EntityService_Can_Get_Paged_Content_Descendants()
|
||||
{
|
||||
var contentType = ServiceContext.ContentTypeService.GetContentType("umbTextpage");
|
||||
|
||||
var root = MockedContent.CreateSimpleContent(contentType);
|
||||
ServiceContext.ContentService.Save(root);
|
||||
var count = 0;
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
var c1 = MockedContent.CreateSimpleContent(contentType, Guid.NewGuid().ToString(), root);
|
||||
ServiceContext.ContentService.Save(c1);
|
||||
count++;
|
||||
|
||||
for (int j = 0; j < 5; j++)
|
||||
{
|
||||
var c2 = MockedContent.CreateSimpleContent(contentType, Guid.NewGuid().ToString(), c1);
|
||||
ServiceContext.ContentService.Save(c2);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
var service = ServiceContext.EntityService;
|
||||
|
||||
long total;
|
||||
var entities = service.GetPagedDescendants(root.Id, UmbracoObjectTypes.Document, 0, 31, out total).ToArray();
|
||||
Assert.That(entities.Length, Is.EqualTo(31));
|
||||
Assert.That(total, Is.EqualTo(60));
|
||||
entities = service.GetPagedDescendants(root.Id, UmbracoObjectTypes.Document, 1, 31, out total).ToArray();
|
||||
Assert.That(entities.Length, Is.EqualTo(29));
|
||||
Assert.That(total, Is.EqualTo(60));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void EntityService_Can_Get_Paged_Content_Descendants_Including_Recycled()
|
||||
{
|
||||
var contentType = ServiceContext.ContentTypeService.GetContentType("umbTextpage");
|
||||
|
||||
var root = MockedContent.CreateSimpleContent(contentType);
|
||||
ServiceContext.ContentService.Save(root);
|
||||
var toDelete = new List<IContent>();
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
var c1 = MockedContent.CreateSimpleContent(contentType, Guid.NewGuid().ToString(), root);
|
||||
ServiceContext.ContentService.Save(c1);
|
||||
|
||||
if (i % 2 == 0)
|
||||
{
|
||||
toDelete.Add(c1);
|
||||
}
|
||||
|
||||
for (int j = 0; j < 5; j++)
|
||||
{
|
||||
var c2 = MockedContent.CreateSimpleContent(contentType, Guid.NewGuid().ToString(), c1);
|
||||
ServiceContext.ContentService.Save(c2);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var content in toDelete)
|
||||
{
|
||||
ServiceContext.ContentService.MoveToRecycleBin(content);
|
||||
}
|
||||
|
||||
var service = ServiceContext.EntityService;
|
||||
|
||||
long total;
|
||||
//search at root to see if it returns recycled
|
||||
var entities = service.GetPagedDescendants(-1, UmbracoObjectTypes.Document, 0, 1000, out total)
|
||||
.Select(x => x.Id)
|
||||
.ToArray();
|
||||
|
||||
foreach (var c in toDelete)
|
||||
{
|
||||
Assert.True(entities.Contains(c.Id));
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void EntityService_Can_Get_Paged_Content_Descendants_Without_Recycled()
|
||||
{
|
||||
var contentType = ServiceContext.ContentTypeService.GetContentType("umbTextpage");
|
||||
|
||||
var root = MockedContent.CreateSimpleContent(contentType);
|
||||
ServiceContext.ContentService.Save(root);
|
||||
var toDelete = new List<IContent>();
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
var c1 = MockedContent.CreateSimpleContent(contentType, Guid.NewGuid().ToString(), root);
|
||||
ServiceContext.ContentService.Save(c1);
|
||||
|
||||
if (i % 2 == 0)
|
||||
{
|
||||
toDelete.Add(c1);
|
||||
}
|
||||
|
||||
for (int j = 0; j < 5; j++)
|
||||
{
|
||||
var c2 = MockedContent.CreateSimpleContent(contentType, Guid.NewGuid().ToString(), c1);
|
||||
ServiceContext.ContentService.Save(c2);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var content in toDelete)
|
||||
{
|
||||
ServiceContext.ContentService.MoveToRecycleBin(content);
|
||||
}
|
||||
|
||||
var service = ServiceContext.EntityService;
|
||||
|
||||
long total;
|
||||
//search at root to see if it returns recycled
|
||||
var entities = service.GetPagedDescendantsFromRoot(UmbracoObjectTypes.Document, 0, 1000, out total, includeTrashed:false)
|
||||
.Select(x => x.Id)
|
||||
.ToArray();
|
||||
|
||||
foreach (var c in toDelete)
|
||||
{
|
||||
Assert.IsFalse(entities.Contains(c.Id));
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void EntityService_Can_Get_Paged_Content_Descendants_With_Search()
|
||||
{
|
||||
var contentType = ServiceContext.ContentTypeService.GetContentType("umbTextpage");
|
||||
|
||||
var root = MockedContent.CreateSimpleContent(contentType);
|
||||
ServiceContext.ContentService.Save(root);
|
||||
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
var c1 = MockedContent.CreateSimpleContent(contentType, "ssss" + Guid.NewGuid(), root);
|
||||
ServiceContext.ContentService.Save(c1);
|
||||
|
||||
for (int j = 0; j < 5; j++)
|
||||
{
|
||||
var c2 = MockedContent.CreateSimpleContent(contentType, "tttt" + Guid.NewGuid(), c1);
|
||||
ServiceContext.ContentService.Save(c2);
|
||||
}
|
||||
}
|
||||
|
||||
var service = ServiceContext.EntityService;
|
||||
|
||||
long total;
|
||||
var entities = service.GetPagedDescendants(root.Id, UmbracoObjectTypes.Document, 0, 10, out total, filter: "ssss").ToArray();
|
||||
Assert.That(entities.Length, Is.EqualTo(10));
|
||||
Assert.That(total, Is.EqualTo(10));
|
||||
entities = service.GetPagedDescendants(root.Id, UmbracoObjectTypes.Document, 0, 50, out total, filter: "tttt").ToArray();
|
||||
Assert.That(entities.Length, Is.EqualTo(50));
|
||||
Assert.That(total, Is.EqualTo(50));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void EntityService_Can_Get_Paged_Media_Children()
|
||||
{
|
||||
var folderType = ServiceContext.ContentTypeService.GetMediaType(1031);
|
||||
var imageMediaType = ServiceContext.ContentTypeService.GetMediaType(1032);
|
||||
|
||||
var root = MockedMedia.CreateMediaFolder(folderType, -1);
|
||||
ServiceContext.MediaService.Save(root);
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
var c1 = MockedMedia.CreateMediaImage(imageMediaType, root.Id);
|
||||
ServiceContext.MediaService.Save(c1);
|
||||
}
|
||||
|
||||
var service = ServiceContext.EntityService;
|
||||
|
||||
long total;
|
||||
var entities = service.GetPagedChildren(root.Id, UmbracoObjectTypes.Media, 0, 6, out total).ToArray();
|
||||
Assert.That(entities.Length, Is.EqualTo(6));
|
||||
Assert.That(total, Is.EqualTo(10));
|
||||
entities = service.GetPagedChildren(root.Id, UmbracoObjectTypes.Media, 1, 6, out total).ToArray();
|
||||
Assert.That(entities.Length, Is.EqualTo(4));
|
||||
Assert.That(total, Is.EqualTo(10));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void EntityService_Can_Get_Paged_Media_Descendants()
|
||||
{
|
||||
var folderType = ServiceContext.ContentTypeService.GetMediaType(1031);
|
||||
var imageMediaType = ServiceContext.ContentTypeService.GetMediaType(1032);
|
||||
|
||||
var root = MockedMedia.CreateMediaFolder(folderType, -1);
|
||||
ServiceContext.MediaService.Save(root);
|
||||
var count = 0;
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
var c1 = MockedMedia.CreateMediaImage(imageMediaType, root.Id);
|
||||
ServiceContext.MediaService.Save(c1);
|
||||
count++;
|
||||
|
||||
for (int j = 0; j < 5; j++)
|
||||
{
|
||||
var c2 = MockedMedia.CreateMediaImage(imageMediaType, c1.Id);
|
||||
ServiceContext.MediaService.Save(c2);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
var service = ServiceContext.EntityService;
|
||||
|
||||
long total;
|
||||
var entities = service.GetPagedDescendants(root.Id, UmbracoObjectTypes.Media, 0, 31, out total).ToArray();
|
||||
Assert.That(entities.Length, Is.EqualTo(31));
|
||||
Assert.That(total, Is.EqualTo(60));
|
||||
entities = service.GetPagedDescendants(root.Id, UmbracoObjectTypes.Media, 1, 31, out total).ToArray();
|
||||
Assert.That(entities.Length, Is.EqualTo(29));
|
||||
Assert.That(total, Is.EqualTo(60));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void EntityService_Can_Get_Paged_Media_Descendants_Including_Recycled()
|
||||
{
|
||||
var folderType = ServiceContext.ContentTypeService.GetMediaType(1031);
|
||||
var imageMediaType = ServiceContext.ContentTypeService.GetMediaType(1032);
|
||||
|
||||
var root = MockedMedia.CreateMediaFolder(folderType, -1);
|
||||
ServiceContext.MediaService.Save(root);
|
||||
var toDelete = new List<IMedia>();
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
var c1 = MockedMedia.CreateMediaImage(imageMediaType, root.Id);
|
||||
ServiceContext.MediaService.Save(c1);
|
||||
|
||||
if (i % 2 == 0)
|
||||
{
|
||||
toDelete.Add(c1);
|
||||
}
|
||||
|
||||
for (int j = 0; j < 5; j++)
|
||||
{
|
||||
var c2 = MockedMedia.CreateMediaImage(imageMediaType, c1.Id);
|
||||
ServiceContext.MediaService.Save(c2);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var content in toDelete)
|
||||
{
|
||||
ServiceContext.MediaService.MoveToRecycleBin(content);
|
||||
}
|
||||
|
||||
var service = ServiceContext.EntityService;
|
||||
|
||||
long total;
|
||||
//search at root to see if it returns recycled
|
||||
var entities = service.GetPagedDescendants(-1, UmbracoObjectTypes.Media, 0, 1000, out total)
|
||||
.Select(x => x.Id)
|
||||
.ToArray();
|
||||
|
||||
foreach (var media in toDelete)
|
||||
{
|
||||
Assert.IsTrue(entities.Contains(media.Id));
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void EntityService_Can_Get_Paged_Media_Descendants_Without_Recycled()
|
||||
{
|
||||
var folderType = ServiceContext.ContentTypeService.GetMediaType(1031);
|
||||
var imageMediaType = ServiceContext.ContentTypeService.GetMediaType(1032);
|
||||
|
||||
var root = MockedMedia.CreateMediaFolder(folderType, -1);
|
||||
ServiceContext.MediaService.Save(root);
|
||||
var toDelete = new List<IMedia>();
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
var c1 = MockedMedia.CreateMediaImage(imageMediaType, root.Id);
|
||||
ServiceContext.MediaService.Save(c1);
|
||||
|
||||
if (i % 2 == 0)
|
||||
{
|
||||
toDelete.Add(c1);
|
||||
}
|
||||
|
||||
for (int j = 0; j < 5; j++)
|
||||
{
|
||||
var c2 = MockedMedia.CreateMediaImage(imageMediaType, c1.Id);
|
||||
ServiceContext.MediaService.Save(c2);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var content in toDelete)
|
||||
{
|
||||
ServiceContext.MediaService.MoveToRecycleBin(content);
|
||||
}
|
||||
|
||||
var service = ServiceContext.EntityService;
|
||||
|
||||
long total;
|
||||
//search at root to see if it returns recycled
|
||||
var entities = service.GetPagedDescendantsFromRoot(UmbracoObjectTypes.Media, 0, 1000, out total, includeTrashed:false)
|
||||
.Select(x => x.Id)
|
||||
.ToArray();
|
||||
|
||||
foreach (var media in toDelete)
|
||||
{
|
||||
Assert.IsFalse(entities.Contains(media.Id));
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void EntityService_Can_Get_Paged_Media_Descendants_With_Search()
|
||||
{
|
||||
var folderType = ServiceContext.ContentTypeService.GetMediaType(1031);
|
||||
var imageMediaType = ServiceContext.ContentTypeService.GetMediaType(1032);
|
||||
|
||||
var root = MockedMedia.CreateMediaFolder(folderType, -1);
|
||||
ServiceContext.MediaService.Save(root);
|
||||
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
var c1 = MockedMedia.CreateMediaImage(imageMediaType, root.Id);
|
||||
c1.Name = "ssss" + Guid.NewGuid();
|
||||
ServiceContext.MediaService.Save(c1);
|
||||
|
||||
for (int j = 0; j < 5; j++)
|
||||
{
|
||||
var c2 = MockedMedia.CreateMediaImage(imageMediaType, c1.Id);
|
||||
c2.Name = "tttt" + Guid.NewGuid();
|
||||
ServiceContext.MediaService.Save(c2);
|
||||
}
|
||||
}
|
||||
|
||||
var service = ServiceContext.EntityService;
|
||||
|
||||
long total;
|
||||
var entities = service.GetPagedDescendants(root.Id, UmbracoObjectTypes.Media, 0, 10, out total, filter: "ssss").ToArray();
|
||||
Assert.That(entities.Length, Is.EqualTo(10));
|
||||
Assert.That(total, Is.EqualTo(10));
|
||||
entities = service.GetPagedDescendants(root.Id, UmbracoObjectTypes.Media, 0, 50, out total, filter: "tttt").ToArray();
|
||||
Assert.That(entities.Length, Is.EqualTo(50));
|
||||
Assert.That(total, Is.EqualTo(50));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void EntityService_Can_Find_All_Content_By_UmbracoObjectTypes()
|
||||
{
|
||||
|
||||
+11
-14
@@ -1,7 +1,7 @@
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
function MiniListViewDirective(contentResource, memberResource, mediaResource) {
|
||||
function MiniListViewDirective(entityResource) {
|
||||
|
||||
function link(scope, el, attr, ctrl) {
|
||||
|
||||
@@ -52,22 +52,19 @@
|
||||
|
||||
// start loading animation list view
|
||||
miniListView.loading = true;
|
||||
|
||||
// setup the correct resource depending on section
|
||||
var resource = "";
|
||||
|
||||
if (scope.entityType === "Member") {
|
||||
resource = memberResource.getPagedResults;
|
||||
} else if (scope.entityType === "Media") {
|
||||
resource = mediaResource.getChildren;
|
||||
} else {
|
||||
resource = contentResource.getChildren;
|
||||
}
|
||||
|
||||
resource(miniListView.node.id, miniListView.pagination)
|
||||
|
||||
entityResource.getPagedChildren(miniListView.node.id, scope.entityType, miniListView.pagination)
|
||||
.then(function (data) {
|
||||
// update children
|
||||
miniListView.children = data.items;
|
||||
_.each(miniListView.children, function(c) {
|
||||
if (c.metaData) {
|
||||
c.hasChildren = c.metaData.HasChildren;
|
||||
if(scope.entityType === "Document") {
|
||||
c.published = c.metaData.IsPublished;
|
||||
}
|
||||
}
|
||||
});
|
||||
// update pagination
|
||||
miniListView.pagination.totalItems = data.totalItems;
|
||||
miniListView.pagination.totalPages = data.totalPages;
|
||||
|
||||
@@ -477,20 +477,20 @@ function contentResource($q, $http, umbDataFormatter, umbRequestHelper) {
|
||||
}
|
||||
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"contentApiBaseUrl",
|
||||
"GetChildren",
|
||||
[
|
||||
{ id: parentId },
|
||||
{ pageNumber: options.pageNumber },
|
||||
{ pageSize: options.pageSize },
|
||||
{ orderBy: options.orderBy },
|
||||
{ orderDirection: options.orderDirection },
|
||||
{ orderBySystemField: toBool(options.orderBySystemField) },
|
||||
{ filter: options.filter }
|
||||
])),
|
||||
'Failed to retrieve children for content item ' + parentId);
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"contentApiBaseUrl",
|
||||
"GetChildren",
|
||||
{
|
||||
id: parentId,
|
||||
pageNumber: options.pageNumber,
|
||||
pageSize: options.pageSize,
|
||||
orderBy: options.orderBy,
|
||||
orderDirection: options.orderDirection,
|
||||
orderBySystemField: toBool(options.orderBySystemField),
|
||||
filter: options.filter
|
||||
})),
|
||||
'Failed to retrieve children for content item ' + parentId);
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
@@ -38,6 +38,10 @@ function entityResource($q, $http, umbRequestHelper) {
|
||||
|
||||
getSafeAlias: function (value, camelCase) {
|
||||
|
||||
if (!value) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
@@ -68,6 +72,11 @@ function entityResource($q, $http, umbRequestHelper) {
|
||||
*
|
||||
*/
|
||||
getPath: function (id, type) {
|
||||
|
||||
if (id === -1 || id === "-1") {
|
||||
return "-1";
|
||||
}
|
||||
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
@@ -98,7 +107,12 @@ function entityResource($q, $http, umbRequestHelper) {
|
||||
* @returns {Promise} resourcePromise object containing the url.
|
||||
*
|
||||
*/
|
||||
getUrl: function(id, type) {
|
||||
getUrl: function (id, type) {
|
||||
|
||||
if (id === -1 || id === "-1") {
|
||||
return "";
|
||||
}
|
||||
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
@@ -131,7 +145,12 @@ function entityResource($q, $http, umbRequestHelper) {
|
||||
* @returns {Promise} resourcePromise object containing the entity.
|
||||
*
|
||||
*/
|
||||
getById: function (id, type) {
|
||||
getById: function (id, type) {
|
||||
|
||||
if (id === -1 || id === "-1") {
|
||||
return null;
|
||||
}
|
||||
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
@@ -285,18 +304,19 @@ function entityResource($q, $http, umbRequestHelper) {
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.resources.entityResource#getAncestors
|
||||
* @name umbraco.resources.entityResource#getChildren
|
||||
* @methodOf umbraco.resources.entityResource
|
||||
*
|
||||
* @description
|
||||
* Gets children entities for a given item
|
||||
*
|
||||
*
|
||||
* @param {Int} parentid id of content item to return children of
|
||||
* @param {string} type Object type name
|
||||
* @returns {Promise} resourcePromise object containing the entity.
|
||||
*
|
||||
*/
|
||||
getChildren: function (id, type) {
|
||||
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
@@ -305,6 +325,146 @@ function entityResource($q, $http, umbRequestHelper) {
|
||||
[{ id: id }, { type: type }])),
|
||||
'Failed to retrieve child data for id ' + id);
|
||||
},
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.resources.entityResource#getPagedChildren
|
||||
* @methodOf umbraco.resources.entityResource
|
||||
*
|
||||
* @description
|
||||
* Gets paged children of a content item with a given id
|
||||
*
|
||||
* ##usage
|
||||
* <pre>
|
||||
* entityResource.getPagedChildren(1234, "Content", {pageSize: 10, pageNumber: 2})
|
||||
* .then(function(contentArray) {
|
||||
* var children = contentArray;
|
||||
* alert('they are here!');
|
||||
* });
|
||||
* </pre>
|
||||
*
|
||||
* @param {Int} parentid id of content item to return children of
|
||||
* @param {string} type Object type name
|
||||
* @param {Object} options optional options object
|
||||
* @param {Int} options.pageSize if paging data, number of nodes per page, default = 1
|
||||
* @param {Int} options.pageNumber if paging data, current page index, default = 100
|
||||
* @param {String} options.filter if provided, query will only return those with names matching the filter
|
||||
* @param {String} options.orderDirection can be `Ascending` or `Descending` - Default: `Ascending`
|
||||
* @param {String} options.orderBy property to order items by, default: `SortOrder`
|
||||
* @returns {Promise} resourcePromise object containing an array of content items.
|
||||
*
|
||||
*/
|
||||
getPagedChildren: function (parentId, type, options) {
|
||||
|
||||
var defaults = {
|
||||
pageSize: 1,
|
||||
pageNumber: 100,
|
||||
filter: '',
|
||||
orderDirection: "Ascending",
|
||||
orderBy: "SortOrder"
|
||||
};
|
||||
if (options === undefined) {
|
||||
options = {};
|
||||
}
|
||||
//overwrite the defaults if there are any specified
|
||||
angular.extend(defaults, options);
|
||||
//now copy back to the options we will use
|
||||
options = defaults;
|
||||
//change asc/desct
|
||||
if (options.orderDirection === "asc") {
|
||||
options.orderDirection = "Ascending";
|
||||
}
|
||||
else if (options.orderDirection === "desc") {
|
||||
options.orderDirection = "Descending";
|
||||
}
|
||||
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"entityApiBaseUrl",
|
||||
"GetPagedChildren",
|
||||
{
|
||||
id: parentId,
|
||||
type: type,
|
||||
pageNumber: options.pageNumber,
|
||||
pageSize: options.pageSize,
|
||||
orderBy: options.orderBy,
|
||||
orderDirection: options.orderDirection,
|
||||
filter: encodeURIComponent(options.filter)
|
||||
}
|
||||
)),
|
||||
'Failed to retrieve child data for id ' + parentId);
|
||||
},
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.resources.entityResource#getPagedDescendants
|
||||
* @methodOf umbraco.resources.entityResource
|
||||
*
|
||||
* @description
|
||||
* Gets paged descendants of a content item with a given id
|
||||
*
|
||||
* ##usage
|
||||
* <pre>
|
||||
* entityResource.getPagedDescendants(1234, "Content", {pageSize: 10, pageNumber: 2})
|
||||
* .then(function(contentArray) {
|
||||
* var children = contentArray;
|
||||
* alert('they are here!');
|
||||
* });
|
||||
* </pre>
|
||||
*
|
||||
* @param {Int} parentid id of content item to return descendants of
|
||||
* @param {string} type Object type name
|
||||
* @param {Object} options optional options object
|
||||
* @param {Int} options.pageSize if paging data, number of nodes per page, default = 1
|
||||
* @param {Int} options.pageNumber if paging data, current page index, default = 100
|
||||
* @param {String} options.filter if provided, query will only return those with names matching the filter
|
||||
* @param {String} options.orderDirection can be `Ascending` or `Descending` - Default: `Ascending`
|
||||
* @param {String} options.orderBy property to order items by, default: `SortOrder`
|
||||
* @returns {Promise} resourcePromise object containing an array of content items.
|
||||
*
|
||||
*/
|
||||
getPagedDescendants: function (parentId, type, options) {
|
||||
|
||||
var defaults = {
|
||||
pageSize: 1,
|
||||
pageNumber: 100,
|
||||
filter: '',
|
||||
orderDirection: "Ascending",
|
||||
orderBy: "SortOrder"
|
||||
};
|
||||
if (options === undefined) {
|
||||
options = {};
|
||||
}
|
||||
//overwrite the defaults if there are any specified
|
||||
angular.extend(defaults, options);
|
||||
//now copy back to the options we will use
|
||||
options = defaults;
|
||||
//change asc/desct
|
||||
if (options.orderDirection === "asc") {
|
||||
options.orderDirection = "Ascending";
|
||||
}
|
||||
else if (options.orderDirection === "desc") {
|
||||
options.orderDirection = "Descending";
|
||||
}
|
||||
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"entityApiBaseUrl",
|
||||
"GetPagedDescendants",
|
||||
{
|
||||
id: parentId,
|
||||
type: type,
|
||||
pageNumber: options.pageNumber,
|
||||
pageSize: options.pageSize,
|
||||
orderBy: options.orderBy,
|
||||
orderDirection: options.orderDirection,
|
||||
filter: encodeURIComponent(options.filter)
|
||||
}
|
||||
)),
|
||||
'Failed to retrieve child data for id ' + parentId);
|
||||
},
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
|
||||
@@ -482,7 +482,49 @@ function mediaResource($q, $http, umbDataFormatter, umbRequestHelper) {
|
||||
"mediaApiBaseUrl",
|
||||
"EmptyRecycleBin")),
|
||||
'Failed to empty the recycle bin');
|
||||
},
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.resources.mediaResource#search
|
||||
* @methodOf umbraco.resources.mediaResource
|
||||
*
|
||||
* @description
|
||||
* Empties the media recycle bin
|
||||
*
|
||||
* ##usage
|
||||
* <pre>
|
||||
* mediaResource.search("my search", 1, 100, -1)
|
||||
* .then(function(searchResult) {
|
||||
* alert('it's here!');
|
||||
* });
|
||||
* </pre>
|
||||
*
|
||||
* @param {string} query The search query
|
||||
* @param {int} pageNumber The page number
|
||||
* @param {int} pageSize The number of media items on a page
|
||||
* @param {int} searchFrom Id to search from
|
||||
* @returns {Promise} resourcePromise object.
|
||||
*
|
||||
*/
|
||||
search: function (query, pageNumber, pageSize, searchFrom) {
|
||||
|
||||
var args = [
|
||||
{ "query": query },
|
||||
{ "pageNumber": pageNumber },
|
||||
{ "pageSize": pageSize },
|
||||
{ "searchFrom": searchFrom }
|
||||
];
|
||||
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"mediaApiBaseUrl",
|
||||
"Search",
|
||||
args)),
|
||||
'Failed to retrieve media items for search: ' + query);
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -26,10 +26,35 @@ app.run(['userService', '$log', '$rootScope', '$location', 'navigationService',
|
||||
/** execute code on each successful route */
|
||||
$rootScope.$on('$routeChangeSuccess', function(event, current, previous) {
|
||||
|
||||
if(current.params.section){
|
||||
$rootScope.locationTitle = current.params.section + " - " + $location.$$host;
|
||||
var deployConfig = Umbraco.Sys.ServerVariables.deploy;
|
||||
var deployEnv, deployEnvTitle;
|
||||
if (deployConfig) {
|
||||
deployEnv = Umbraco.Sys.ServerVariables.deploy.CurrentWorkspace;
|
||||
deployEnvTitle = "(" + deployEnv + ") ";
|
||||
}
|
||||
|
||||
if(current.params.section) {
|
||||
|
||||
//Uppercase the current section, content, media, settings, developer, forms
|
||||
var currentSection = current.params.section.charAt(0).toUpperCase() + current.params.section.slice(1);
|
||||
|
||||
var baseTitle = currentSection + " - " + $location.$$host;
|
||||
|
||||
//Check deploy for Global Umbraco.Sys obj workspace
|
||||
if(deployEnv){
|
||||
$rootScope.locationTitle = deployEnvTitle + baseTitle;
|
||||
}
|
||||
else {
|
||||
$rootScope.locationTitle = baseTitle;
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
|
||||
if(deployEnv) {
|
||||
$rootScope.locationTitle = deployEnvTitle + "Umbraco - " + $location.$$host;
|
||||
}
|
||||
|
||||
$rootScope.locationTitle = "Umbraco - " + $location.$$host;
|
||||
}
|
||||
|
||||
|
||||
@@ -288,6 +288,10 @@ input.umb-table__input {
|
||||
color: @black;
|
||||
}
|
||||
|
||||
.umb-table__row-expand--hidden {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.umb-table--condensed {
|
||||
|
||||
.umb-table-cell:first-of-type:not(.not-fixed) {
|
||||
|
||||
+111
-27
@@ -33,6 +33,14 @@ angular.module("umbraco")
|
||||
$scope.acceptedMediatypes = types;
|
||||
});
|
||||
|
||||
$scope.searchOptions = {
|
||||
pageNumber: 1,
|
||||
pageSize: 100,
|
||||
totalItems: 0,
|
||||
totalPages: 0,
|
||||
filter: '',
|
||||
};
|
||||
|
||||
//preload selected item
|
||||
$scope.target = undefined;
|
||||
if (dialogOptions.currentTarget) {
|
||||
@@ -106,35 +114,9 @@ angular.module("umbraco")
|
||||
$scope.path = [];
|
||||
}
|
||||
|
||||
//mediaResource.rootMedia()
|
||||
mediaResource.getChildren(folder.id)
|
||||
.then(function(data) {
|
||||
$scope.searchTerm = "";
|
||||
$scope.images = data.items ? data.items : [];
|
||||
|
||||
// set already selected images to selected
|
||||
for (var folderImageIndex = 0; folderImageIndex < $scope.images.length; folderImageIndex++) {
|
||||
var folderImage = $scope.images[folderImageIndex];
|
||||
var imageIsSelected = false;
|
||||
|
||||
for (var selectedImageIndex = 0;
|
||||
selectedImageIndex < $scope.model.selectedImages.length;
|
||||
selectedImageIndex++) {
|
||||
var selectedImage = $scope.model.selectedImages[selectedImageIndex];
|
||||
|
||||
if (folderImage.key === selectedImage.key) {
|
||||
imageIsSelected = true;
|
||||
}
|
||||
}
|
||||
if (imageIsSelected) {
|
||||
folderImage.selected = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
getChildren(folder.id);
|
||||
$scope.currentFolder = folder;
|
||||
|
||||
localStorageService.set("umbLastOpenedMediaNodeId", folder.id);
|
||||
|
||||
};
|
||||
|
||||
$scope.clickHandler = function(image, event, index) {
|
||||
@@ -238,4 +220,106 @@ angular.module("umbraco")
|
||||
$scope.mediaPickerDetailsOverlay = null;
|
||||
};
|
||||
};
|
||||
|
||||
$scope.changeSearch = function() {
|
||||
$scope.loading = true;
|
||||
debounceSearchMedia();
|
||||
};
|
||||
|
||||
$scope.changePagination = function(pageNumber) {
|
||||
$scope.loading = true;
|
||||
$scope.searchOptions.pageNumber = pageNumber;
|
||||
searchMedia();
|
||||
};
|
||||
|
||||
var debounceSearchMedia = _.debounce(function () {
|
||||
$scope.$apply(function () {
|
||||
if ($scope.searchOptions.filter) {
|
||||
searchMedia();
|
||||
} else {
|
||||
// reset pagination
|
||||
$scope.searchOptions = {
|
||||
pageNumber: 1,
|
||||
pageSize: 100,
|
||||
totalItems: 0,
|
||||
totalPages: 0,
|
||||
filter: ''
|
||||
};
|
||||
getChildren($scope.currentFolder.id);
|
||||
}
|
||||
});
|
||||
}, 500);
|
||||
|
||||
function searchMedia() {
|
||||
$scope.loading = true;
|
||||
entityResource.getPagedDescendants($scope.startNodeId, "Media", $scope.searchOptions)
|
||||
.then(function (data) {
|
||||
// update image data to work with image grid
|
||||
angular.forEach(data.items, function(mediaItem){
|
||||
// set thumbnail and src
|
||||
mediaItem.thumbnail = mediaHelper.resolveFileFromEntity(mediaItem, true);
|
||||
mediaItem.image = mediaHelper.resolveFileFromEntity(mediaItem, false);
|
||||
// set properties to match a media object
|
||||
if (mediaItem.metaData &&
|
||||
mediaItem.metaData.umbracoWidth &&
|
||||
mediaItem.metaData.umbracoHeight) {
|
||||
|
||||
mediaItem.properties = [
|
||||
{
|
||||
alias: "umbracoWidth",
|
||||
value: mediaItem.metaData.umbracoWidth.Value
|
||||
},
|
||||
{
|
||||
alias: "umbracoHeight",
|
||||
value: mediaItem.metaData.umbracoHeight.Value
|
||||
}
|
||||
];
|
||||
}
|
||||
});
|
||||
// update images
|
||||
$scope.images = data.items ? data.items : [];
|
||||
// update pagination
|
||||
if (data.pageNumber > 0)
|
||||
$scope.searchOptions.pageNumber = data.pageNumber;
|
||||
if (data.pageSize > 0)
|
||||
$scope.searchOptions.pageSize = data.pageSize;
|
||||
$scope.searchOptions.totalItems = data.totalItems;
|
||||
$scope.searchOptions.totalPages = data.totalPages;
|
||||
// set already selected images to selected
|
||||
preSelectImages();
|
||||
$scope.loading = false;
|
||||
});
|
||||
}
|
||||
|
||||
function getChildren(id) {
|
||||
$scope.loading = true;
|
||||
mediaResource.getChildren(id)
|
||||
.then(function(data) {
|
||||
$scope.searchOptions.filter = "";
|
||||
$scope.images = data.items ? data.items : [];
|
||||
// set already selected images to selected
|
||||
preSelectImages();
|
||||
$scope.loading = false;
|
||||
});
|
||||
}
|
||||
|
||||
function preSelectImages() {
|
||||
for (var folderImageIndex = 0; folderImageIndex < $scope.images.length; folderImageIndex++) {
|
||||
var folderImage = $scope.images[folderImageIndex];
|
||||
var imageIsSelected = false;
|
||||
|
||||
for (var selectedImageIndex = 0;
|
||||
selectedImageIndex < $scope.model.selectedImages.length;
|
||||
selectedImageIndex++) {
|
||||
var selectedImage = $scope.model.selectedImages[selectedImageIndex];
|
||||
|
||||
if (folderImage.key === selectedImage.key) {
|
||||
imageIsSelected = true;
|
||||
}
|
||||
}
|
||||
if (imageIsSelected) {
|
||||
folderImage.selected = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -10,13 +10,18 @@
|
||||
|
||||
<div class="umb-control-group umb-mediapicker-upload">
|
||||
|
||||
<umb-load-indicator
|
||||
ng-if="loading">
|
||||
</umb-load-indicator>
|
||||
|
||||
<div class="form-search">
|
||||
<i class="icon-search"></i>
|
||||
<input
|
||||
class="umb-search-field search-query"
|
||||
ng-model="searchTerm"
|
||||
class="umb-search-field search-query -full-width-input"
|
||||
ng-model="searchOptions.filter"
|
||||
localize="placeholder"
|
||||
placeholder="@placeholders_filter"
|
||||
placeholder="@placeholders_search"
|
||||
ng-change="changeSearch()"
|
||||
type="text">
|
||||
</div>
|
||||
|
||||
@@ -32,7 +37,7 @@
|
||||
|
||||
</div>
|
||||
|
||||
<div class="row umb-control-group">
|
||||
<div class="row umb-control-group" ng-if="!searchOptions.filter">
|
||||
<ul class="umb-breadcrumbs">
|
||||
<li ng-hide="startNodeId != -1" class="umb-breadcrumbs__ancestor">
|
||||
<a href ng-click="gotoFolder()" prevent-default>Media</a>
|
||||
@@ -63,20 +68,20 @@
|
||||
</div>
|
||||
|
||||
<umb-file-dropzone
|
||||
ng-if="acceptedMediatypes.length > 0"
|
||||
ng-if="acceptedMediatypes.length > 0 && !loading"
|
||||
accepted-mediatypes="acceptedMediatypes"
|
||||
parent-id="{{currentFolder.id}}"
|
||||
files-uploaded="onUploadComplete"
|
||||
files-queued="onFilesQueue"
|
||||
accept="{{acceptedFileTypes}}"
|
||||
max-file-size="{{maxFileSize}}"
|
||||
hide-dropzone="{{!activeDrag && images.length > 0 }}"
|
||||
hide-dropzone="{{!activeDrag && images.length > 0 || searchOptions.filter }}"
|
||||
compact="{{ images.length > 0 }}">
|
||||
</umb-file-dropzone>
|
||||
|
||||
<umb-media-grid
|
||||
ng-if="!loading"
|
||||
items="images"
|
||||
filter-by="searchTerm"
|
||||
on-click="clickHandler"
|
||||
on-click-name="clickItemName"
|
||||
item-max-width="150"
|
||||
@@ -86,6 +91,21 @@
|
||||
only-images={{onlyImages}}>
|
||||
</umb-media-grid>
|
||||
|
||||
<div class="flex justify-center">
|
||||
<umb-pagination
|
||||
ng-if="searchOptions.totalPages > 0 && !loading"
|
||||
page-number="searchOptions.pageNumber"
|
||||
total-pages="searchOptions.totalPages"
|
||||
on-change="changePagination(pageNumber)">
|
||||
</umb-pagination>
|
||||
</div>
|
||||
|
||||
<umb-empty-state
|
||||
ng-if="searchOptions.filter && images.length === 0 && !loading"
|
||||
position="center">
|
||||
<localize key="general_searchNoResult"></localize>
|
||||
</umb-empty-state>
|
||||
|
||||
</div>
|
||||
|
||||
<umb-overlay
|
||||
|
||||
+1
-1
@@ -72,7 +72,7 @@ angular.module("umbraco").controller("Umbraco.Overlays.TreePickerController",
|
||||
$scope.enableSearh = true;
|
||||
|
||||
//if a alternative startnode is used, we need to check if it is a container
|
||||
if (dialogOptions.startNodeId && dialogOptions.startNodeId !== -1) {
|
||||
if (dialogOptions.startNodeId && dialogOptions.startNodeId !== -1 && dialogOptions.startNodeId !== "-1") {
|
||||
entityResource.getById(dialogOptions.startNodeId, $scope.entityType).then(function (node) {
|
||||
if (node.metaData.IsContainer) {
|
||||
openMiniListView(node);
|
||||
|
||||
@@ -62,14 +62,14 @@
|
||||
ng-repeat="child in miniListView.children"
|
||||
ng-click="selectNode(child)"
|
||||
ng-class="{'-selected':child.selected}">
|
||||
<div class="umb-table-cell umb-table-cell--auto-width" ng-class="{'umb-table-cell--faded':!child.published && entityType === 'Document'}">
|
||||
<div class="umb-table-cell umb-table-cell--auto-width" ng-class="{'umb-table-cell--faded':child.published === false}">
|
||||
<div class="flex items-center">
|
||||
<ins class="icon-navigation-right umb-table__row-expand" ng-click="openNode($event, child)"> </ins>
|
||||
<ins class="icon-navigation-right umb-table__row-expand" ng-click="openNode($event, child)" ng-class="{'umb-table__row-expand--hidden': child.hasChildren !== true}"> </ins>
|
||||
<i class="umb-table-body__icon umb-table-body__fileicon {{child.icon}}"></i>
|
||||
<i class="umb-table-body__icon umb-table-body__checkicon icon-check"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="umb-table-cell black" ng-class="{'umb-table-cell--faded':!child.published && entityType === 'Document'}">{{ child.name }}</div>
|
||||
<div class="umb-table-cell black" ng-class="{'umb-table-cell--faded':child.published === false}">{{ child.name }}</div>
|
||||
</div>
|
||||
|
||||
<!-- Load indicator when the list doesn't have items -->
|
||||
|
||||
@@ -483,7 +483,7 @@ function listViewController($rootScope, $scope, $routeParams, $injector, $cookie
|
||||
//we need to do a double sync here: first refresh the node where the content was moved,
|
||||
// then refresh the node where the content was moved from
|
||||
navigationService.syncTree({
|
||||
tree: target.nodeType,
|
||||
tree: target.nodeType ? target.nodeType : (target.metaData.treeAlias),
|
||||
path: newPath,
|
||||
forceReload: true,
|
||||
activate: false
|
||||
|
||||
@@ -136,6 +136,7 @@ namespace Umbraco.Web.Editors
|
||||
var display = Mapper.Map<IPartialView, CodeFileDisplay>(view);
|
||||
display.FileType = Core.Constants.Trees.PartialViews;
|
||||
display.Path = Url.GetTreePathFromFilePath(view.Path);
|
||||
display.Id = System.Web.HttpUtility.UrlEncode(view.Path);
|
||||
return display;
|
||||
}
|
||||
return null;
|
||||
@@ -147,6 +148,7 @@ namespace Umbraco.Web.Editors
|
||||
var display = Mapper.Map<IPartialView, CodeFileDisplay>(viewMacro);
|
||||
display.FileType = Core.Constants.Trees.PartialViewMacros;
|
||||
display.Path = Url.GetTreePathFromFilePath(viewMacro.Path);
|
||||
display.Id = System.Web.HttpUtility.UrlEncode(viewMacro.Path);
|
||||
return display;
|
||||
}
|
||||
return null;
|
||||
@@ -158,6 +160,7 @@ namespace Umbraco.Web.Editors
|
||||
var display = Mapper.Map<Script, CodeFileDisplay>(script);
|
||||
display.FileType = Core.Constants.Trees.Scripts;
|
||||
display.Path = Url.GetTreePathFromFilePath(script.Path);
|
||||
display.Id = System.Web.HttpUtility.UrlEncode(script.Path);
|
||||
return display;
|
||||
}
|
||||
return null;
|
||||
@@ -341,6 +344,7 @@ namespace Umbraco.Web.Editors
|
||||
{
|
||||
display = Mapper.Map(partialViewResult.Result, display);
|
||||
display.Path = Url.GetTreePathFromFilePath(partialViewResult.Result.Path);
|
||||
display.Id = System.Web.HttpUtility.UrlEncode(partialViewResult.Result.Path);
|
||||
return display;
|
||||
}
|
||||
|
||||
@@ -355,6 +359,7 @@ namespace Umbraco.Web.Editors
|
||||
{
|
||||
display = Mapper.Map(partialViewMacroResult.Result, display);
|
||||
display.Path = Url.GetTreePathFromFilePath(partialViewMacroResult.Result.Path);
|
||||
display.Id = System.Web.HttpUtility.UrlEncode(partialViewMacroResult.Result.Path);
|
||||
return display;
|
||||
}
|
||||
|
||||
@@ -371,6 +376,7 @@ namespace Umbraco.Web.Editors
|
||||
script.Path = display.Name;
|
||||
display = Mapper.Map(script, display);
|
||||
display.Path = Url.GetTreePathFromFilePath(script.Path);
|
||||
display.Id = System.Web.HttpUtility.UrlEncode(script.Path);
|
||||
return display;
|
||||
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ using Examine.SearchCriteria;
|
||||
using Umbraco.Web.Dynamics;
|
||||
using umbraco;
|
||||
using System.Text.RegularExpressions;
|
||||
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
|
||||
using System.Web.Http.Controllers;
|
||||
using Umbraco.Core.Xml;
|
||||
|
||||
@@ -54,6 +55,11 @@ namespace Umbraco.Web.Editors
|
||||
public void Initialize(HttpControllerSettings controllerSettings, HttpControllerDescriptor controllerDescriptor)
|
||||
{
|
||||
controllerSettings.Services.Replace(typeof(IHttpActionSelector), new ParameterSwapControllerActionSelector(
|
||||
|
||||
//This is a special case, we'll accept a String here so that we can get page members when the special "all-members"
|
||||
//id is passed in eventually we'll probably want to support GUID + Udi too
|
||||
new ParameterSwapControllerActionSelector.ParameterSwapInfo("GetPagedChildren", "id", typeof(int), typeof(string)),
|
||||
|
||||
new ParameterSwapControllerActionSelector.ParameterSwapInfo("GetById", "id", typeof(int), typeof(Guid), typeof(Udi)),
|
||||
new ParameterSwapControllerActionSelector.ParameterSwapInfo("GetByIds", "ids", typeof(int[]), typeof(Guid[]), typeof(Udi[]))));
|
||||
}
|
||||
@@ -216,7 +222,7 @@ namespace Umbraco.Web.Editors
|
||||
/// <returns></returns>
|
||||
public EntityBasic GetByQuery(string query, int nodeContextId, UmbracoEntityTypes type)
|
||||
{
|
||||
//TODO: Rename this!!! It's a bit misleading, it should be GetByXPath
|
||||
//TODO: Rename this!!! It's misleading, it should be GetByXPath
|
||||
|
||||
|
||||
if (type != UmbracoEntityTypes.Document)
|
||||
@@ -382,6 +388,176 @@ namespace Umbraco.Web.Editors
|
||||
return GetResultForChildren(id, type);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get paged child entities by id
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <param name="type"></param>
|
||||
/// <param name="pageNumber"></param>
|
||||
/// <param name="pageSize"></param>
|
||||
/// <param name="orderBy"></param>
|
||||
/// <param name="orderDirection"></param>
|
||||
/// <param name="filter"></param>
|
||||
/// <returns></returns>
|
||||
public PagedResult<EntityBasic> GetPagedChildren(
|
||||
string id,
|
||||
UmbracoEntityTypes type,
|
||||
int pageNumber,
|
||||
int pageSize,
|
||||
string orderBy = "SortOrder",
|
||||
Direction orderDirection = Direction.Ascending,
|
||||
string filter = "")
|
||||
{
|
||||
int intId;
|
||||
|
||||
if (int.TryParse(id, out intId))
|
||||
{
|
||||
return GetPagedChildren(intId, type, pageNumber, pageSize, orderBy, orderDirection, filter);
|
||||
}
|
||||
|
||||
Guid guidId;
|
||||
if (Guid.TryParse(id, out guidId))
|
||||
{
|
||||
//Not supported currently
|
||||
throw new HttpResponseException(HttpStatusCode.NotFound);
|
||||
}
|
||||
|
||||
Udi udiId;
|
||||
if (Udi.TryParse(id, out udiId))
|
||||
{
|
||||
//Not supported currently
|
||||
throw new HttpResponseException(HttpStatusCode.NotFound);
|
||||
}
|
||||
|
||||
//so we don't have an INT, GUID or UDI, it's just a string, so now need to check if it's a special id or a member type
|
||||
if (id == Constants.Conventions.MemberTypes.AllMembersListId)
|
||||
{
|
||||
//the EntityService can search paged members from the root
|
||||
|
||||
intId = -1;
|
||||
return GetPagedChildren(intId, type, pageNumber, pageSize, orderBy, orderDirection, filter);
|
||||
}
|
||||
|
||||
//the EntityService cannot search members of a certain type, this is currently not supported and would require
|
||||
//quite a bit of plumbing to do in the Services/Repository, we'll revert to a paged search
|
||||
|
||||
int total;
|
||||
var searchResult = ExamineSearch(filter ?? "", type, pageSize, pageNumber - 1, out total, id);
|
||||
|
||||
return new PagedResult<EntityBasic>(total, pageNumber, pageSize)
|
||||
{
|
||||
Items = searchResult
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get paged child entities by id
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <param name="type"></param>
|
||||
/// <param name="pageNumber"></param>
|
||||
/// <param name="pageSize"></param>
|
||||
/// <param name="orderBy"></param>
|
||||
/// <param name="orderDirection"></param>
|
||||
/// <param name="filter"></param>
|
||||
/// <returns></returns>
|
||||
public PagedResult<EntityBasic> GetPagedChildren(
|
||||
int id,
|
||||
UmbracoEntityTypes type,
|
||||
int pageNumber,
|
||||
int pageSize,
|
||||
string orderBy = "SortOrder",
|
||||
Direction orderDirection = Direction.Ascending,
|
||||
string filter = "")
|
||||
{
|
||||
if (pageNumber <= 0)
|
||||
throw new HttpResponseException(HttpStatusCode.NotFound);
|
||||
if (pageSize <= 0)
|
||||
throw new HttpResponseException(HttpStatusCode.NotFound);
|
||||
|
||||
var objectType = ConvertToObjectType(type);
|
||||
if (objectType.HasValue)
|
||||
{
|
||||
long totalRecords;
|
||||
var entities = Services.EntityService.GetPagedChildren(id, objectType.Value, pageNumber - 1, pageSize, out totalRecords, orderBy, orderDirection, filter);
|
||||
|
||||
if (totalRecords == 0)
|
||||
{
|
||||
return new PagedResult<EntityBasic>(0, 0, 0);
|
||||
}
|
||||
|
||||
var pagedResult = new PagedResult<EntityBasic>(totalRecords, pageNumber, pageSize)
|
||||
{
|
||||
Items = entities.Select(Mapper.Map<EntityBasic>)
|
||||
};
|
||||
|
||||
return pagedResult;
|
||||
}
|
||||
|
||||
//now we need to convert the unknown ones
|
||||
switch (type)
|
||||
{
|
||||
case UmbracoEntityTypes.PropertyType:
|
||||
case UmbracoEntityTypes.PropertyGroup:
|
||||
case UmbracoEntityTypes.Domain:
|
||||
case UmbracoEntityTypes.Language:
|
||||
case UmbracoEntityTypes.User:
|
||||
case UmbracoEntityTypes.Macro:
|
||||
default:
|
||||
throw new NotSupportedException("The " + typeof(EntityController) + " does not currently support data for the type " + type);
|
||||
}
|
||||
}
|
||||
|
||||
public PagedResult<EntityBasic> GetPagedDescendants(
|
||||
int id,
|
||||
UmbracoEntityTypes type,
|
||||
int pageNumber,
|
||||
int pageSize,
|
||||
string orderBy = "SortOrder",
|
||||
Direction orderDirection = Direction.Ascending,
|
||||
string filter = "")
|
||||
{
|
||||
if (pageNumber <= 0)
|
||||
throw new HttpResponseException(HttpStatusCode.NotFound);
|
||||
if (pageSize <= 0)
|
||||
throw new HttpResponseException(HttpStatusCode.NotFound);
|
||||
|
||||
var objectType = ConvertToObjectType(type);
|
||||
if (objectType.HasValue)
|
||||
{
|
||||
long totalRecords;
|
||||
//if it's from root, don't return recycled
|
||||
var entities = id == Constants.System.Root
|
||||
? Services.EntityService.GetPagedDescendantsFromRoot(objectType.Value, pageNumber - 1, pageSize, out totalRecords, orderBy, orderDirection, filter, includeTrashed:false)
|
||||
: Services.EntityService.GetPagedDescendants(id, objectType.Value, pageNumber - 1, pageSize, out totalRecords, orderBy, orderDirection, filter);
|
||||
|
||||
if (totalRecords == 0)
|
||||
{
|
||||
return new PagedResult<EntityBasic>(0, 0, 0);
|
||||
}
|
||||
|
||||
var pagedResult = new PagedResult<EntityBasic>(totalRecords, pageNumber, pageSize)
|
||||
{
|
||||
Items = entities.Select(Mapper.Map<EntityBasic>)
|
||||
};
|
||||
|
||||
return pagedResult;
|
||||
}
|
||||
|
||||
//now we need to convert the unknown ones
|
||||
switch (type)
|
||||
{
|
||||
case UmbracoEntityTypes.PropertyType:
|
||||
case UmbracoEntityTypes.PropertyGroup:
|
||||
case UmbracoEntityTypes.Domain:
|
||||
case UmbracoEntityTypes.Language:
|
||||
case UmbracoEntityTypes.User:
|
||||
case UmbracoEntityTypes.Macro:
|
||||
default:
|
||||
throw new NotSupportedException("The " + typeof(EntityController) + " does not currently support data for the type " + type);
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<EntityBasic> GetAncestors(int id, UmbracoEntityTypes type)
|
||||
{
|
||||
return GetResultForAncestors(id, type);
|
||||
@@ -397,12 +573,30 @@ namespace Umbraco.Web.Editors
|
||||
/// </summary>
|
||||
/// <param name="query"></param>
|
||||
/// <param name="entityType"></param>
|
||||
/// <param name="searchFrom">
|
||||
/// A starting point for the search, generally a node id, but for members this is a member type alias
|
||||
/// </param>
|
||||
/// <param name="searchFrom"></param>
|
||||
/// <returns></returns>
|
||||
private IEnumerable<EntityBasic> ExamineSearch(string query, UmbracoEntityTypes entityType, string searchFrom = null)
|
||||
{
|
||||
int total;
|
||||
return ExamineSearch(query, entityType, 200, 0, out total, searchFrom);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Searches for results based on the entity type
|
||||
/// </summary>
|
||||
/// <param name="query"></param>
|
||||
/// <param name="entityType"></param>
|
||||
/// <param name="totalFound"></param>
|
||||
/// <param name="searchFrom">
|
||||
/// A starting point for the search, generally a node id, but for members this is a member type alias
|
||||
/// </param>
|
||||
/// <param name="pageSize"></param>
|
||||
/// <param name="pageIndex"></param>
|
||||
/// <returns></returns>
|
||||
private IEnumerable<EntityBasic> ExamineSearch(string query, UmbracoEntityTypes entityType, int pageSize, int pageIndex, out int totalFound, string searchFrom = null)
|
||||
{
|
||||
//TODO: We need to update this to support paging
|
||||
|
||||
var sb = new StringBuilder();
|
||||
|
||||
string type;
|
||||
@@ -478,91 +672,113 @@ namespace Umbraco.Web.Editors
|
||||
|
||||
query = Lucene.Net.QueryParsers.QueryParser.Escape(query);
|
||||
|
||||
if (query.IsNullOrWhiteSpace())
|
||||
//nothing to search
|
||||
if (searchFrom.IsNullOrWhiteSpace() && query.IsNullOrWhiteSpace())
|
||||
{
|
||||
totalFound = 0;
|
||||
return new List<EntityBasic>();
|
||||
}
|
||||
|
||||
//add back the surrounding quotes
|
||||
query = string.Format("{0}{1}{0}", "\"", query);
|
||||
|
||||
//node name exactly boost x 10
|
||||
sb.Append("+(__nodeName: (");
|
||||
sb.Append(query.ToLower());
|
||||
sb.Append(")^10.0 ");
|
||||
|
||||
foreach (var f in fields)
|
||||
//update the query with the query term
|
||||
if (query.IsNullOrWhiteSpace() == false)
|
||||
{
|
||||
//additional fields normally
|
||||
sb.Append(f);
|
||||
sb.Append(": (");
|
||||
sb.Append(query);
|
||||
//add back the surrounding quotes
|
||||
query = string.Format("{0}{1}{0}", "\"", query);
|
||||
|
||||
//node name exactly boost x 10
|
||||
sb.Append("+(__nodeName: (");
|
||||
sb.Append(query.ToLower());
|
||||
sb.Append(")^10.0 ");
|
||||
|
||||
foreach (var f in fields)
|
||||
{
|
||||
//additional fields normally
|
||||
sb.Append(f);
|
||||
sb.Append(": (");
|
||||
sb.Append(query);
|
||||
sb.Append(") ");
|
||||
}
|
||||
|
||||
sb.Append(") ");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (query.Trim(new[] { '\"', '\'' }).IsNullOrWhiteSpace())
|
||||
var trimmed = query.Trim(new[] {'\"', '\''});
|
||||
|
||||
//nothing to search
|
||||
if (searchFrom.IsNullOrWhiteSpace() && trimmed.IsNullOrWhiteSpace())
|
||||
{
|
||||
totalFound = 0;
|
||||
return new List<EntityBasic>();
|
||||
}
|
||||
|
||||
query = Lucene.Net.QueryParsers.QueryParser.Escape(query);
|
||||
|
||||
var querywords = query.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
//node name exactly boost x 10
|
||||
sb.Append("+(__nodeName:");
|
||||
sb.Append("\"");
|
||||
sb.Append(query.ToLower());
|
||||
sb.Append("\"");
|
||||
sb.Append("^10.0 ");
|
||||
|
||||
//node name normally with wildcards
|
||||
sb.Append(" __nodeName:");
|
||||
sb.Append("(");
|
||||
foreach (var w in querywords)
|
||||
//update the query with the query term
|
||||
if (trimmed.IsNullOrWhiteSpace() == false)
|
||||
{
|
||||
sb.Append(w.ToLower());
|
||||
sb.Append("* ");
|
||||
}
|
||||
sb.Append(") ");
|
||||
query = Lucene.Net.QueryParsers.QueryParser.Escape(query);
|
||||
|
||||
var querywords = query.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
foreach (var f in fields)
|
||||
{
|
||||
//additional fields normally
|
||||
sb.Append(f);
|
||||
sb.Append(":");
|
||||
//node name exactly boost x 10
|
||||
sb.Append("+(__nodeName:");
|
||||
sb.Append("\"");
|
||||
sb.Append(query.ToLower());
|
||||
sb.Append("\"");
|
||||
sb.Append("^10.0 ");
|
||||
|
||||
//node name normally with wildcards
|
||||
sb.Append(" __nodeName:");
|
||||
sb.Append("(");
|
||||
foreach (var w in querywords)
|
||||
{
|
||||
sb.Append(w.ToLower());
|
||||
sb.Append("* ");
|
||||
}
|
||||
sb.Append(")");
|
||||
sb.Append(" ");
|
||||
sb.Append(") ");
|
||||
|
||||
|
||||
foreach (var f in fields)
|
||||
{
|
||||
//additional fields normally
|
||||
sb.Append(f);
|
||||
sb.Append(":");
|
||||
sb.Append("(");
|
||||
foreach (var w in querywords)
|
||||
{
|
||||
sb.Append(w.ToLower());
|
||||
sb.Append("* ");
|
||||
}
|
||||
sb.Append(")");
|
||||
sb.Append(" ");
|
||||
}
|
||||
|
||||
sb.Append(") ");
|
||||
}
|
||||
}
|
||||
|
||||
//must match index type
|
||||
sb.Append(") +__IndexType:");
|
||||
sb.Append("+__IndexType:");
|
||||
sb.Append(type);
|
||||
|
||||
|
||||
var raw = internalSearcher.CreateSearchCriteria().RawQuery(sb.ToString());
|
||||
|
||||
//limit results to 200 to avoid huge over processing (CPU)
|
||||
var result = internalSearcher.Search(raw, 200);
|
||||
var result = internalSearcher
|
||||
//only return the number of items specified to read up to the amount of records to fill from 0 -> the number of items on the page requested
|
||||
.Search(raw, pageSize * (pageIndex + 1));
|
||||
|
||||
totalFound = result.TotalItemCount;
|
||||
|
||||
var pagedResult = result.Skip(pageIndex);
|
||||
|
||||
switch (entityType)
|
||||
{
|
||||
case UmbracoEntityTypes.Member:
|
||||
return MemberFromSearchResults(result);
|
||||
return MemberFromSearchResults(pagedResult.ToArray());
|
||||
case UmbracoEntityTypes.Media:
|
||||
return MediaFromSearchResults(result);
|
||||
return MediaFromSearchResults(pagedResult);
|
||||
case UmbracoEntityTypes.Document:
|
||||
return ContentFromSearchResults(result);
|
||||
return ContentFromSearchResults(pagedResult);
|
||||
default:
|
||||
throw new NotSupportedException("The " + typeof(EntityController) + " currently does not support searching against object type " + entityType);
|
||||
}
|
||||
@@ -573,7 +789,7 @@ namespace Umbraco.Web.Editors
|
||||
/// </summary>
|
||||
/// <param name="results"></param>
|
||||
/// <returns></returns>
|
||||
private IEnumerable<EntityBasic> MemberFromSearchResults(ISearchResults results)
|
||||
private IEnumerable<EntityBasic> MemberFromSearchResults(SearchResult[] results)
|
||||
{
|
||||
var mapped = Mapper.Map<IEnumerable<EntityBasic>>(results).ToArray();
|
||||
//add additional data
|
||||
@@ -607,7 +823,7 @@ namespace Umbraco.Web.Editors
|
||||
/// </summary>
|
||||
/// <param name="results"></param>
|
||||
/// <returns></returns>
|
||||
private IEnumerable<EntityBasic> MediaFromSearchResults(ISearchResults results)
|
||||
private IEnumerable<EntityBasic> MediaFromSearchResults(IEnumerable<SearchResult> results)
|
||||
{
|
||||
var mapped = Mapper.Map<IEnumerable<EntityBasic>>(results).ToArray();
|
||||
//add additional data
|
||||
@@ -627,9 +843,9 @@ namespace Umbraco.Web.Editors
|
||||
/// </summary>
|
||||
/// <param name="results"></param>
|
||||
/// <returns></returns>
|
||||
private IEnumerable<EntityBasic> ContentFromSearchResults(ISearchResults results)
|
||||
private IEnumerable<EntityBasic> ContentFromSearchResults(IEnumerable<SearchResult> results)
|
||||
{
|
||||
var mapped = Mapper.Map<ISearchResults, IEnumerable<EntityBasic>>(results).ToArray();
|
||||
var mapped = Mapper.Map<IEnumerable<EntityBasic>>(results).ToArray();
|
||||
//add additional data
|
||||
foreach (var m in mapped)
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
@@ -28,7 +29,9 @@ using Umbraco.Web.Mvc;
|
||||
using Umbraco.Web.WebApi;
|
||||
using System.Linq;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Web.Http.Controllers;
|
||||
using Examine;
|
||||
using Umbraco.Web.WebApi.Binders;
|
||||
using Umbraco.Web.WebApi.Filters;
|
||||
using umbraco;
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
using System.Web;
|
||||
|
||||
namespace Umbraco.Web
|
||||
{
|
||||
/// <summary>
|
||||
@@ -8,8 +6,6 @@ namespace Umbraco.Web
|
||||
/// <remarks>
|
||||
/// NOTE: This has a singleton lifespan
|
||||
/// </remarks>
|
||||
public interface IHttpContextAccessor
|
||||
{
|
||||
HttpContextBase Value { get; }
|
||||
}
|
||||
public interface IHttpContextAccessor : Core.IHttpContextAccessor
|
||||
{ }
|
||||
}
|
||||
@@ -42,6 +42,10 @@ namespace Umbraco.Web.Models.ContentEditing
|
||||
[ReadOnly(true)]
|
||||
public string Snippet { get; set; }
|
||||
|
||||
[DataMember(Name = "id")]
|
||||
[ReadOnly(true)]
|
||||
public string Id { get; set; }
|
||||
|
||||
public List<Notification> Notifications { get; private set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,17 +84,21 @@ namespace Umbraco.Web.Models.ContentEditing
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The real persisted content object
|
||||
/// The real persisted content object - used during inbound model binding
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is not used for outgoing model information.
|
||||
/// </remarks>
|
||||
[JsonIgnore]
|
||||
internal TPersisted PersistedContent { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The DTO object used to gather all required content data including data type information etc... for use with validation
|
||||
/// The DTO object used to gather all required content data including data type information etc... for use with validation - used during inbound model binding
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// We basically use this object to hydrate all required data from the database into one object so we can validate everything we need
|
||||
/// instead of having to look up all the data individually.
|
||||
/// This is not used for outgoing model information.
|
||||
/// </remarks>
|
||||
[JsonIgnore]
|
||||
internal ContentItemDto<TPersisted> ContentDto { get; set; }
|
||||
|
||||
@@ -21,7 +21,14 @@ namespace Umbraco.Web.Models.Mapping
|
||||
.ForMember(x => x.Udi, expression => expression.MapFrom(x => Udi.Create(UmbracoObjectTypesExtensions.GetUdiType(x.NodeObjectTypeId), x.Key)))
|
||||
.ForMember(basic => basic.Icon, expression => expression.MapFrom(entity => entity.ContentTypeIcon))
|
||||
.ForMember(dto => dto.Trashed, expression => expression.Ignore())
|
||||
.ForMember(x => x.Alias, expression => expression.Ignore());
|
||||
.ForMember(x => x.Alias, expression => expression.Ignore())
|
||||
.AfterMap((entity, basic) =>
|
||||
{
|
||||
if (entity.NodeObjectTypeId == Constants.ObjectTypes.MemberGuid && basic.Icon.IsNullOrWhiteSpace())
|
||||
{
|
||||
basic.Icon = "icon-user";
|
||||
}
|
||||
});
|
||||
|
||||
config.CreateMap<PropertyType, EntityBasic>()
|
||||
.ForMember(x => x.Udi, expression => expression.Ignore())
|
||||
@@ -151,6 +158,9 @@ namespace Umbraco.Web.Models.Mapping
|
||||
|
||||
config.CreateMap<ISearchResults, IEnumerable<EntityBasic>>()
|
||||
.ConvertUsing(results => results.Select(Mapper.Map<EntityBasic>).ToList());
|
||||
|
||||
config.CreateMap<IEnumerable<SearchResult>, IEnumerable<EntityBasic>>()
|
||||
.ConvertUsing(results => results.Select(Mapper.Map<EntityBasic>).ToList());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
using System;
|
||||
using System.Runtime.Remoting.Messaging;
|
||||
using Umbraco.Core.Events;
|
||||
|
||||
namespace Umbraco.Web
|
||||
{
|
||||
/// <summary>
|
||||
/// Stores the instance of EventMessages in the current request so all events will share the same instance
|
||||
/// </summary>
|
||||
internal class RequestLifespanMessagesFactory : IEventMessagesFactory
|
||||
{
|
||||
private const string ContextKey = "Umbraco.Web.RequestLifespanMessagesFactory";
|
||||
private readonly IHttpContextAccessor _httpAccessor;
|
||||
|
||||
public RequestLifespanMessagesFactory(IHttpContextAccessor httpAccessor)
|
||||
{
|
||||
if (httpAccessor == null) throw new ArgumentNullException("httpAccessor");
|
||||
_httpAccessor = httpAccessor;
|
||||
}
|
||||
|
||||
public EventMessages Get()
|
||||
{
|
||||
var httpContext = _httpAccessor.Value;
|
||||
if (httpContext != null)
|
||||
{
|
||||
var eventMessages = httpContext.Items[ContextKey] as EventMessages;
|
||||
if (eventMessages == null) httpContext.Items[ContextKey] = eventMessages = new EventMessages();
|
||||
return eventMessages;
|
||||
}
|
||||
|
||||
var lccContext = CallContext.LogicalGetData(ContextKey) as EventMessages;
|
||||
if (lccContext != null) return lccContext;
|
||||
|
||||
throw new Exception("Could not get messages.");
|
||||
}
|
||||
|
||||
public EventMessages TryGet()
|
||||
{
|
||||
var httpContext = _httpAccessor.Value;
|
||||
return httpContext != null
|
||||
? httpContext.Items[ContextKey] as EventMessages
|
||||
: CallContext.LogicalGetData(ContextKey) as EventMessages;
|
||||
}
|
||||
|
||||
// Deploy wants to execute things outside of a request, where this factory would fail,
|
||||
// so the factory is extended so that Deploy can Set/Clear event messages in the logical
|
||||
// call context (which flows with async) - it needs to be set and cleared because, contrary
|
||||
// to http context, it's not being cleared at the end of anything.
|
||||
//
|
||||
// to be refactored in v8! the whole IEventMessagesFactory is borked anyways
|
||||
|
||||
public void SetLlc()
|
||||
{
|
||||
CallContext.LogicalSetData(ContextKey, new EventMessages());
|
||||
}
|
||||
|
||||
public void ClearLlc()
|
||||
{
|
||||
CallContext.FreeNamedDataSlot(ContextKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -374,7 +374,6 @@
|
||||
<Compile Include="Routing\RedirectTrackingEventHandler.cs" />
|
||||
<Compile Include="Editors\RedirectUrlManagementController.cs" />
|
||||
<Compile Include="Models\ContentEditing\RedirectUrlSearchResults.cs" />
|
||||
<Compile Include="RequestLifespanMessagesFactory.cs" />
|
||||
<Compile Include="RouteDataExtensions.cs" />
|
||||
<Compile Include="Routing\ContentFinderByRedirectUrl.cs" />
|
||||
<Compile Include="Scheduling\LatchedBackgroundTaskBase.cs" />
|
||||
|
||||
@@ -53,7 +53,7 @@ namespace Umbraco.Web
|
||||
/// <returns></returns>
|
||||
public static EventMessages GetCurrentEventMessages(this UmbracoContext umbracoContext)
|
||||
{
|
||||
var eventMessagesFactory = umbracoContext.Application.Services.EventMessagesFactory as RequestLifespanMessagesFactory;
|
||||
var eventMessagesFactory = umbracoContext.Application.Services.EventMessagesFactory as ScopeLifespanMessagesFactory;
|
||||
return eventMessagesFactory == null ? null : eventMessagesFactory.TryGet();
|
||||
}
|
||||
|
||||
|
||||
@@ -42,6 +42,7 @@ using Umbraco.Web.UI.JavaScript;
|
||||
using Umbraco.Web.WebApi;
|
||||
using umbraco.BusinessLogic;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Events;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Persistence.UnitOfWork;
|
||||
using Umbraco.Core.Publishing;
|
||||
@@ -92,7 +93,7 @@ namespace Umbraco.Web
|
||||
protected override ServiceContext CreateServiceContext(DatabaseContext dbContext, IScopeProvider scopeProvider)
|
||||
{
|
||||
//use a request based messaging factory
|
||||
var evtMsgs = new RequestLifespanMessagesFactory(new SingletonHttpContextAccessor());
|
||||
var evtMsgs = new ScopeLifespanMessagesFactory(new SingletonHttpContextAccessor(), scopeProvider);
|
||||
return new ServiceContext(
|
||||
new RepositoryFactory(ApplicationCache, ProfilingLogger.Logger, dbContext.SqlSyntax, UmbracoConfig.For.UmbracoSettings()),
|
||||
new PetaPocoUnitOfWorkProvider(scopeProvider),
|
||||
|
||||
Reference in New Issue
Block a user