Merge remote-tracking branch 'origin/v7/dev' into v8/dev - Iniital commit (broken)

# Conflicts:
#	build/NuSpecs/tools/Web.config.install.xdt
#	src/Umbraco.Core/Constants-DataTypes.cs
#	src/Umbraco.Core/Models/DataTypeDefinition.cs
#	src/Umbraco.Core/Models/DataTypeExtensions.cs
#	src/Umbraco.Core/Models/IDataTypeDefinition.cs
#	src/Umbraco.Core/Models/UmbracoEntity.cs
#	src/Umbraco.Core/Models/UserExtensions.cs
#	src/Umbraco.Core/Persistence/Factories/DataTypeDefinitionFactory.cs
#	src/Umbraco.Core/Persistence/Factories/UmbracoEntityFactory.cs
#	src/Umbraco.Core/Persistence/Migrations/Initial/BaseDataCreation.cs
#	src/Umbraco.Core/Persistence/Repositories/EntityRepository.cs
#	src/Umbraco.Core/Services/ContentService.cs
#	src/Umbraco.Core/Services/DataTypeService.cs
#	src/Umbraco.Core/Services/EntityService.cs
#	src/Umbraco.Core/Services/IContentService.cs
#	src/Umbraco.Core/Services/IDataTypeService.cs
#	src/Umbraco.Core/Services/IEntityService.cs
#	src/Umbraco.Core/Services/IRelationService.cs
#	src/Umbraco.Core/Services/Implement/RelationService.cs
#	src/Umbraco.Tests/Models/UmbracoEntityTests.cs
#	src/Umbraco.Tests/Plugins/PluginManagerTests.cs
#	src/Umbraco.Tests/Services/EntityServiceTests.cs
#	src/Umbraco.Web.UI.Client/src/common/resources/content.resource.js
#	src/Umbraco.Web.UI.Client/src/common/resources/entity.resource.js
#	src/Umbraco.Web.UI.Client/src/common/resources/media.resource.js
#	src/Umbraco.Web.UI.Client/src/common/services/mediahelper.service.js
#	src/Umbraco.Web.UI.Client/src/common/services/search.service.js
#	src/Umbraco.Web.UI.Client/src/common/services/tinymce.service.js
#	src/Umbraco.Web.UI.Client/src/views/common/dialogs/linkpicker.controller.js
#	src/Umbraco.Web.UI.Client/src/views/common/dialogs/linkpicker.html
#	src/Umbraco.Web.UI.Client/src/views/common/dialogs/mediapicker.controller.js
#	src/Umbraco.Web.UI.Client/src/views/common/dialogs/treepicker.controller.js
#	src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/mediapicker/mediapicker.controller.js
#	src/Umbraco.Web.UI.Client/src/views/common/overlays/contentpicker/contentpicker.html
#	src/Umbraco.Web.UI.Client/src/views/common/overlays/linkpicker/linkpicker.controller.js
#	src/Umbraco.Web.UI.Client/src/views/common/overlays/linkpicker/linkpicker.html
#	src/Umbraco.Web.UI.Client/src/views/common/overlays/treepicker/treepicker.controller.js
#	src/Umbraco.Web.UI.Client/src/views/common/overlays/treepicker/treepicker.html
#	src/Umbraco.Web.UI.Client/src/views/propertyeditors/contentpicker/contentpicker.controller.js
#	src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/editors/media.controller.js
#	src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/editors/rte.controller.js
#	src/Umbraco.Web.UI.Client/src/views/propertyeditors/mediapicker/mediapicker.controller.js
#	src/Umbraco.Web.UI.Client/src/views/propertyeditors/multiurlpicker/multiurlpicker.controller.js
#	src/Umbraco.Web.UI.Client/src/views/propertyeditors/relatedlinks/relatedlinks.controller.js
#	src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/rte.controller.js
#	src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/rte.prevalues.html
#	src/Umbraco.Web.UI/packages.config
#	src/Umbraco.Web.UI/web.Template.config
#	src/Umbraco.Web/Editors/ContentController.cs
#	src/Umbraco.Web/Editors/EntityController.cs
#	src/Umbraco.Web/Editors/MediaController.cs
#	src/Umbraco.Web/HtmlHelperRenderExtensions.cs
#	src/Umbraco.Web/Models/ContentEditing/ContentPropertyBasic.cs
#	src/Umbraco.Web/Models/Mapping/ContentPropertyBasicConverter.cs
#	src/Umbraco.Web/Models/Mapping/ContentPropertyDisplayConverter.cs
#	src/Umbraco.Web/Models/Mapping/ContentPropertyDtoConverter.cs
#	src/Umbraco.Web/Models/Mapping/ContentPropertyModelMapper.cs
#	src/Umbraco.Web/Models/Mapping/PreValueDisplayResolver.cs
#	src/Umbraco.Web/Mvc/RenderRouteHandler.cs
#	src/Umbraco.Web/PropertyEditors/ContentPicker2PropertyEditor.cs
#	src/Umbraco.Web/PropertyEditors/GridPropertyEditor.cs
#	src/Umbraco.Web/PropertyEditors/MediaPicker2PropertyEditor.cs
#	src/Umbraco.Web/PropertyEditors/MultiNodeTreePicker2PropertyEditor.cs
#	src/Umbraco.Web/PropertyEditors/MultiUrlPickerPropertyEditor.cs
#	src/Umbraco.Web/PropertyEditors/RelatedLinks2PropertyEditor.cs
#	src/Umbraco.Web/PropertyEditors/RichTextPreValueEditor.cs
#	src/Umbraco.Web/Search/UmbracoTreeSearcher.cs
#	src/Umbraco.Web/Security/UmbracoAntiForgeryAdditionalDataProvider.cs
#	src/Umbraco.Web/Trees/ContentTreeController.cs
#	src/Umbraco.Web/Trees/ContentTreeControllerBase.cs
#	src/Umbraco.Web/Trees/MediaTreeController.cs
#	src/Umbraco.Web/Trees/TreeControllerBase.cs
#	src/Umbraco.Web/Trees/TreeQueryStringParameters.cs
#	src/Umbraco.Web/UmbracoHelper.cs
#	src/Umbraco.Web/WebApi/Filters/EnsureUserPermissionForContentAttribute.cs
#	src/Umbraco.Web/WebBootManager.cs
#	src/Umbraco.Web/umbraco.presentation/umbraco/Trees/BaseMediaTree.cs
#	src/Umbraco.Web/umbraco.presentation/umbraco/Trees/BaseTree.cs
#	src/umbraco.cms/businesslogic/web/Access.cs
This commit is contained in:
Shannon
2019-06-28 13:03:36 +10:00
parent 7b99e55148
commit 84aa861a5b
29 changed files with 1469 additions and 896 deletions
@@ -8,7 +8,7 @@
</configSections>
<system.web.webPages.razor>
<host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" xdt:Locator="Match(factoryType)" xdt:Transform="SetAttributes(factoryType)" />
<host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=5.2.7.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" xdt:Locator="Match(factoryType)" xdt:Transform="SetAttributes(factoryType)" />
<pages pageBaseType="System.Web.Mvc.WebViewPage">
<namespaces>
<add namespace="Umbraco.Web.PublishedContentModels" xdt:Transform="InsertIfMissing" />
@@ -18,13 +18,13 @@
<system.web>
<pages
pageParserFilterType="System.Web.Mvc.ViewTypeParserFilter, System.Web.Mvc, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
pageBaseType="System.Web.Mvc.ViewPage, System.Web.Mvc, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
userControlBaseType="System.Web.Mvc.ViewUserControl, System.Web.Mvc, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
pageParserFilterType="System.Web.Mvc.ViewTypeParserFilter, System.Web.Mvc, Version=5.2.7.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
pageBaseType="System.Web.Mvc.ViewPage, System.Web.Mvc, Version=5.2.7.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
userControlBaseType="System.Web.Mvc.ViewUserControl, System.Web.Mvc, Version=5.2.7.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
xdt:Locator="Match(pageParserFilterType,pageBaseType,userControlBaseType)"
xdt:Transform="SetAttributes(pageParserFilterType,pageBaseType,userControlBaseType)">
<controls>
<add assembly="System.Web.Mvc, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" namespace="System.Web.Mvc" xdt:Locator="Match(namespace)" xdt:Transform="SetAttributes(assembly)" />
<add assembly="System.Web.Mvc, Version=5.2.7.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" namespace="System.Web.Mvc" xdt:Locator="Match(namespace)" xdt:Transform="SetAttributes(assembly)" />
</controls>
</pages>
</system.web>
+291 -1
View File
@@ -1,4 +1,6 @@
namespace Umbraco.Core
using System;
namespace Umbraco.Core
{
public static partial class Constants
{
@@ -22,6 +24,294 @@
public const int DefaultMembersListView = -97;
public const int Tags = 1041;
/// <summary>
/// Defines the identifiers for Umbraco data types as constants for easy centralized access/management.
/// </summary>
internal static class BuiltInDataTypes
{
public static class ReservedPreValueKeys
{
public const string IgnoreUserStartNodes = "ignoreUserStartNodes";
}
/// <summary>
/// Guid for Content Picker as string
/// </summary>
public const string ContentPicker = "FD1E0DA5-5606-4862-B679-5D0CF3A52A59";
/// <summary>
/// Guid for Content Picker
/// </summary>
public static readonly Guid ContentPickerGuid = new Guid(ContentPicker);
/// <summary>
/// Guid for Member Picker as string
/// </summary>
public const string MemberPicker = "1EA2E01F-EBD8-4CE1-8D71-6B1149E63548";
/// <summary>
/// Guid for Member Picker
/// </summary>
public static readonly Guid MemberPickerGuid = new Guid(MemberPicker);
/// <summary>
/// Guid for Media Picker as string
/// </summary>
public const string MediaPicker = "135D60E0-64D9-49ED-AB08-893C9BA44AE5";
/// <summary>
/// Guid for Media Picker
/// </summary>
public static readonly Guid MediaPickerGuid = new Guid(MediaPicker);
/// <summary>
/// Guid for Multiple Media Picker as string
/// </summary>
public const string MultipleMediaPicker = "9DBBCBBB-2327-434A-B355-AF1B84E5010A";
/// <summary>
/// Guid for Multiple Media Picker
/// </summary>
public static readonly Guid MultipleMediaPickerGuid = new Guid(MultipleMediaPicker);
/// <summary>
/// Guid for Related Links as string
/// </summary>
public const string RelatedLinks = "B4E3535A-1753-47E2-8568-602CF8CFEE6F";
/// <summary>
/// Guid for Related Links
/// </summary>
public static readonly Guid RelatedLinksGuid = new Guid(RelatedLinks);
/// <summary>
/// Guid for Member as string
/// </summary>
public const string Member = "d59be02f-1df9-4228-aa1e-01917d806cda";
/// <summary>
/// Guid for Member
/// </summary>
public static readonly Guid MemberGuid = new Guid(Member);
/// <summary>
/// Guid for Image Cropper as string
/// </summary>
public const string ImageCropper = "1df9f033-e6d4-451f-b8d2-e0cbc50a836f";
/// <summary>
/// Guid for Image Cropper
/// </summary>
public static readonly Guid ImageCropperGuid = new Guid(ImageCropper);
/// <summary>
/// Guid for Tags as string
/// </summary>
public const string Tags = "b6b73142-b9c1-4bf8-a16d-e1c23320b549";
/// <summary>
/// Guid for Tags
/// </summary>
public static readonly Guid TagsGuid = new Guid(Tags);
/// <summary>
/// Guid for List View - Content as string
/// </summary>
public const string ListViewContent = "C0808DD3-8133-4E4B-8CE8-E2BEA84A96A4";
/// <summary>
/// Guid for List View - Content
/// </summary>
public static readonly Guid ListViewContentGuid = new Guid(ListViewContent);
/// <summary>
/// Guid for List View - Media as string
/// </summary>
public const string ListViewMedia = "3A0156C4-3B8C-4803-BDC1-6871FAA83FFF";
/// <summary>
/// Guid for List View - Media
/// </summary>
public static readonly Guid ListViewMediaGuid = new Guid(ListViewMedia);
/// <summary>
/// Guid for List View - Members as string
/// </summary>
public const string ListViewMembers = "AA2C52A0-CE87-4E65-A47C-7DF09358585D";
/// <summary>
/// Guid for List View - Members
/// </summary>
public static readonly Guid ListViewMembersGuid = new Guid(ListViewMembers);
/// <summary>
/// Guid for Date Picker with time as string
/// </summary>
public const string DatePickerWithTime = "e4d66c0f-b935-4200-81f0-025f7256b89a";
/// <summary>
/// Guid for Date Picker with time
/// </summary>
public static readonly Guid DatePickerWithTimeGuid = new Guid(DatePickerWithTime);
/// <summary>
/// Guid for Approved Color as string
/// </summary>
public const string ApprovedColor = "0225af17-b302-49cb-9176-b9f35cab9c17";
/// <summary>
/// Guid for Approved Color
/// </summary>
public static readonly Guid ApprovedColorGuid = new Guid(ApprovedColor);
/// <summary>
/// Guid for Dropdown multiple as string
/// </summary>
public const string DropdownMultiple = "f38f0ac7-1d27-439c-9f3f-089cd8825a53";
/// <summary>
/// Guid for Dropdown multiple
/// </summary>
public static readonly Guid DropdownMultipleGuid = new Guid(DropdownMultiple);
/// <summary>
/// Guid for Radiobox as string
/// </summary>
public const string Radiobox = "bb5f57c9-ce2b-4bb9-b697-4caca783a805";
/// <summary>
/// Guid for Radiobox
/// </summary>
public static readonly Guid RadioboxGuid = new Guid(Radiobox);
/// <summary>
/// Guid for Date Picker as string
/// </summary>
public const string DatePicker = "5046194e-4237-453c-a547-15db3a07c4e1";
/// <summary>
/// Guid for Date Picker
/// </summary>
public static readonly Guid DatePickerGuid = new Guid(DatePicker);
/// <summary>
/// Guid for Dropdown as string
/// </summary>
public const string Dropdown = "0b6a45e7-44ba-430d-9da5-4e46060b9e03";
/// <summary>
/// Guid for Dropdown
/// </summary>
public static readonly Guid DropdownGuid = new Guid(Dropdown);
/// <summary>
/// Guid for Checkbox list as string
/// </summary>
public const string CheckboxList = "fbaf13a8-4036-41f2-93a3-974f678c312a";
/// <summary>
/// Guid for Checkbox list
/// </summary>
public static readonly Guid CheckboxListGuid = new Guid(CheckboxList);
/// <summary>
/// Guid for Checkbox as string
/// </summary>
public const string Checkbox = "92897bc6-a5f3-4ffe-ae27-f2e7e33dda49";
/// <summary>
/// Guid for Checkbox
/// </summary>
public static readonly Guid CheckboxGuid = new Guid(Checkbox);
/// <summary>
/// Guid for Numeric as string
/// </summary>
public const string Numeric = "2e6d3631-066e-44b8-aec4-96f09099b2b5";
/// <summary>
/// Guid for Dropdown
/// </summary>
public static readonly Guid NumericGuid = new Guid(Numeric);
/// <summary>
/// Guid for Richtext editor as string
/// </summary>
public const string RichtextEditor = "ca90c950-0aff-4e72-b976-a30b1ac57dad";
/// <summary>
/// Guid for Richtext editor
/// </summary>
public static readonly Guid RichtextEditorGuid = new Guid(RichtextEditor);
/// <summary>
/// Guid for Textstring as string
/// </summary>
public const string Textstring = "0cc0eba1-9960-42c9-bf9b-60e150b429ae";
/// <summary>
/// Guid for Textstring
/// </summary>
public static readonly Guid TextstringGuid = new Guid(Textstring);
/// <summary>
/// Guid for Textarea as string
/// </summary>
public const string Textarea = "c6bac0dd-4ab9-45b1-8e30-e4b619ee5da3";
/// <summary>
/// Guid for Dropdown
/// </summary>
public static readonly Guid TextareaGuid = new Guid(Textarea);
/// <summary>
/// Guid for Upload as string
/// </summary>
public const string Upload = "84c6b441-31df-4ffe-b67e-67d5bc3ae65a";
/// <summary>
/// Guid for Upload
/// </summary>
public static readonly Guid UploadGuid = new Guid(Upload);
/// <summary>
/// Guid for Label as string
/// </summary>
public const string Label = "f0bc4bfb-b499-40d6-ba86-058885a5178c";
/// <summary>
/// Guid for Label
/// </summary>
public static readonly Guid LabelGuid = new Guid(Label);
}
}
}
}
@@ -35,5 +35,53 @@ namespace Umbraco.Core.Models
throw new InvalidCastException($"Cannot cast dataType configuration, of type {configuration.GetType().Name}, to {typeof(T).Name}.");
}
private static readonly ISet<Guid> IdsOfBuildInDataTypes = new HashSet<Guid>()
{
Constants.DataTypes.ContentPickerGuid,
Constants.DataTypes.MemberPickerGuid,
Constants.DataTypes.MediaPickerGuid,
Constants.DataTypes.MultipleMediaPickerGuid,
Constants.DataTypes.RelatedLinksGuid,
Constants.DataTypes.MemberGuid,
Constants.DataTypes.ImageCropperGuid,
Constants.DataTypes.TagsGuid,
Constants.DataTypes.ListViewContentGuid,
Constants.DataTypes.ListViewMediaGuid,
Constants.DataTypes.ListViewMembersGuid,
Constants.DataTypes.DatePickerWithTimeGuid,
Constants.DataTypes.ApprovedColorGuid,
Constants.DataTypes.DropdownMultipleGuid,
Constants.DataTypes.RadioboxGuid,
Constants.DataTypes.DatePickerGuid,
Constants.DataTypes.DropdownGuid,
Constants.DataTypes.CheckboxListGuid,
Constants.DataTypes.CheckboxGuid,
Constants.DataTypes.NumericGuid,
Constants.DataTypes.RichtextEditorGuid,
Constants.DataTypes.TextstringGuid,
Constants.DataTypes.TextareaGuid,
Constants.DataTypes.UploadGuid,
Constants.DataTypes.LabelGuid,
};
/// <summary>
/// Returns true if this date type is build-in/default.
/// </summary>
/// <param name="dataType">The data type definition.</param>
/// <returns></returns>
internal static bool IsBuildInDataType(this IDataTypeDefinition dataType)
{
return IsBuildInDataType(dataType.Key);
}
/// <summary>
/// Returns true if this date type is build-in/default.
/// </summary>
internal static bool IsBuildInDataType(Guid key)
{
return IdsOfBuildInDataTypes.Contains(key);
}
}
}
-13
View File
@@ -193,19 +193,6 @@ namespace Umbraco.Core.Models
return ContentPermissionsHelper.HasPathAccess(entity.Path, user.CalculateMediaStartNodeIds(entityService), Constants.System.RecycleBinMedia);
}
internal static bool IsInBranchOfStartNode(this IUser user, IUmbracoEntity entity, IEntityService entityService, int recycleBinId, out bool hasPathAccess)
{
switch (recycleBinId)
{
case Constants.System.RecycleBinMedia:
return ContentPermissionsHelper.IsInBranchOfStartNode(entity.Path, user.CalculateMediaStartNodeIds(entityService), user.GetMediaStartNodePaths(entityService), out hasPathAccess);
case Constants.System.RecycleBinContent:
return ContentPermissionsHelper.IsInBranchOfStartNode(entity.Path, user.CalculateContentStartNodeIds(entityService), user.GetContentStartNodePaths(entityService), out hasPathAccess);
default:
throw new NotSupportedException("Path access is only determined on content or media");
}
}
/// <summary>
/// Determines whether this user has access to view sensitive data
/// </summary>
@@ -526,5 +526,8 @@ namespace Umbraco.Core.Services
OperationResult Rollback(int id, int versionId, string culture = "*", int userId = Constants.Security.SuperUserId);
#endregion
IEnumerable<string> GetAnchorValuesFromRTEs(int id);
IEnumerable<string> GetAnchorValuesFromRTEContent(string rteContent);
}
}
@@ -327,7 +327,7 @@ AnotherContentFinder
public void Resolves_RestExtensions()
{
var types = _manager.ResolveRestExtensions();
Assert.AreEqual(3, types.Count());
Assert.AreEqual(2, types.Count());
}
[Test]
@@ -12,6 +12,7 @@ function treeSearchBox(localizationService, searchService, $q) {
searchFromName: "@",
showSearch: "@",
section: "@",
datatypeId: "@",
hideSearchCallback: "=",
searchCallback: "="
},
@@ -34,6 +35,7 @@ function treeSearchBox(localizationService, searchService, $q) {
scope.showSearch = "false";
}
//used to cancel any request in progress if another one needs to take it's place
var canceler = null;
@@ -60,6 +62,11 @@ function treeSearchBox(localizationService, searchService, $q) {
searchArgs["searchFrom"] = scope.searchFromId;
}
//append dataTypeId value if there is one
if (scope.datatypeId) {
searchArgs["dataTypeId"] = scope.datatypeId;
}
searcher(searchArgs).then(function (data) {
scope.searchCallback(data);
//set back to null so it can be re-created
@@ -1,27 +1,27 @@
/**
* @ngdoc service
* @name umbraco.resources.contentResource
* @description Handles all transactions of content data
* from the angular application to the Umbraco database, using the Content WebApi controller
*
* all methods returns a resource promise async, so all operations won't complete untill .then() is completed.
*
* @requires $q
* @requires $http
* @requires umbDataFormatter
* @requires umbRequestHelper
*
* ##usage
* To use, simply inject the contentResource into any controller or service that needs it, and make
* sure the umbraco.resources module is accesible - which it should be by default.
*
* <pre>
* contentResource.getById(1234)
* .then(function(data) {
* $scope.content = data;
* @ngdoc service
* @name umbraco.resources.contentResource
* @description Handles all transactions of content data
* from the angular application to the Umbraco database, using the Content WebApi controller
*
* all methods returns a resource promise async, so all operations won't complete untill .then() is completed.
*
* @requires $q
* @requires $http
* @requires umbDataFormatter
* @requires umbRequestHelper
*
* ##usage
* To use, simply inject the contentResource into any controller or service that needs it, and make
* sure the umbraco.resources module is accesible - which it should be by default.
*
* <pre>
* contentResource.getById(1234)
* .then(function(data) {
* $scope.content = data;
* });
* </pre>
**/
**/
function contentResource($q, $http, umbDataFormatter, umbRequestHelper) {
@@ -79,27 +79,27 @@ function contentResource($q, $http, umbDataFormatter, umbRequestHelper) {
},
/**
* @ngdoc method
* @name umbraco.resources.contentResource#sort
* @methodOf umbraco.resources.contentResource
*
* @description
* Sorts all children below a given parent node id, based on a collection of node-ids
*
* ##usage
* <pre>
* var ids = [123,34533,2334,23434];
* contentResource.sort({ parentId: 1244, sortedIds: ids })
* .then(function() {
* $scope.complete = true;
* });
* @ngdoc method
* @name umbraco.resources.contentResource#sort
* @methodOf umbraco.resources.contentResource
*
* @description
* Sorts all children below a given parent node id, based on a collection of node-ids
*
* ##usage
* <pre>
* var ids = [123,34533,2334,23434];
* contentResource.sort({ parentId: 1244, sortedIds: ids })
* .then(function() {
* $scope.complete = true;
* });
* </pre>
* @param {Object} args arguments object
* @param {Int} args.parentId the ID of the parent node
* @param {Array} options.sortedIds array of node IDs as they should be sorted
* @returns {Promise} resourcePromise object.
*
*/
* @param {Object} args arguments object
* @param {Int} args.parentId the ID of the parent node
* @param {Array} options.sortedIds array of node IDs as they should be sorted
* @returns {Promise} resourcePromise object.
*
*/
sort: function (args) {
if (!args) {
throw "args cannot be null";
@@ -121,28 +121,28 @@ function contentResource($q, $http, umbDataFormatter, umbRequestHelper) {
},
/**
* @ngdoc method
* @name umbraco.resources.contentResource#move
* @methodOf umbraco.resources.contentResource
*
* @description
* Moves a node underneath a new parentId
*
* ##usage
* <pre>
* contentResource.move({ parentId: 1244, id: 123 })
* .then(function() {
* alert("node was moved");
* }, function(err){
* @ngdoc method
* @name umbraco.resources.contentResource#move
* @methodOf umbraco.resources.contentResource
*
* @description
* Moves a node underneath a new parentId
*
* ##usage
* <pre>
* contentResource.move({ parentId: 1244, id: 123 })
* .then(function() {
* alert("node was moved");
* }, function(err){
* alert("node didnt move:" + err.data.Message);
* });
* });
* </pre>
* @param {Object} args arguments object
* @param {Int} args.idd the ID of the node to move
* @param {Int} args.parentId the ID of the parent node to move to
* @returns {Promise} resourcePromise object.
*
*/
* @param {Object} args arguments object
* @param {Int} args.idd the ID of the node to move
* @param {Int} args.parentId the ID of the parent node to move to
* @returns {Promise} resourcePromise object.
*
*/
move: function (args) {
if (!args) {
throw "args cannot be null";
@@ -164,29 +164,29 @@ function contentResource($q, $http, umbDataFormatter, umbRequestHelper) {
},
/**
* @ngdoc method
* @name umbraco.resources.contentResource#copy
* @methodOf umbraco.resources.contentResource
*
* @description
* Copies a node underneath a new parentId
*
* ##usage
* <pre>
* contentResource.copy({ parentId: 1244, id: 123 })
* .then(function() {
* alert("node was copied");
* }, function(err){
* @ngdoc method
* @name umbraco.resources.contentResource#copy
* @methodOf umbraco.resources.contentResource
*
* @description
* Copies a node underneath a new parentId
*
* ##usage
* <pre>
* contentResource.copy({ parentId: 1244, id: 123 })
* .then(function() {
* alert("node was copied");
* }, function(err){
* alert("node wasnt copy:" + err.data.Message);
* });
* });
* </pre>
* @param {Object} args arguments object
* @param {Int} args.id the ID of the node to copy
* @param {Int} args.parentId the ID of the parent node to copy to
* @param {Boolean} args.relateToOriginal if true, relates the copy to the original through the relation api
* @returns {Promise} resourcePromise object.
*
*/
* @param {Object} args arguments object
* @param {Int} args.id the ID of the node to copy
* @param {Int} args.parentId the ID of the parent node to copy to
* @param {Boolean} args.relateToOriginal if true, relates the copy to the original through the relation api
* @returns {Promise} resourcePromise object.
*
*/
copy: function (args) {
if (!args) {
throw "args cannot be null";
@@ -205,26 +205,26 @@ function contentResource($q, $http, umbDataFormatter, umbRequestHelper) {
},
/**
* @ngdoc method
* @ngdoc method
* @name umbraco.resources.contentResource#unpublish
* @methodOf umbraco.resources.contentResource
*
* @description
* Unpublishes a content item with a given Id
*
* ##usage
* <pre>
* @methodOf umbraco.resources.contentResource
*
* @description
* Unpublishes a content item with a given Id
*
* ##usage
* <pre>
* contentResource.unpublish(1234)
* .then(function() {
* alert("node was unpulished");
* }, function(err){
* .then(function() {
* alert("node was unpulished");
* }, function(err){
* alert("node wasnt unpublished:" + err.data.Message);
* });
* });
* </pre>
* @param {Int} id the ID of the node to unpublish
* @returns {Promise} resourcePromise object.
*
*/
* @param {Int} id the ID of the node to unpublish
* @returns {Promise} resourcePromise object.
*
*/
unpublish: function (id, cultures) {
if (!id) {
throw "id cannot be null";
@@ -242,7 +242,7 @@ function contentResource($q, $http, umbDataFormatter, umbRequestHelper) {
'Failed to publish content with id ' + id);
},
/**
* @ngdoc method
* @ngdoc method
* @name umbraco.resources.contentResource#getCultureAndDomains
* @methodOf umbraco.resources.contentResource
*
@@ -281,23 +281,23 @@ function contentResource($q, $http, umbDataFormatter, umbRequestHelper) {
},
/**
* @ngdoc method
* @name umbraco.resources.contentResource#emptyRecycleBin
* @methodOf umbraco.resources.contentResource
*
* @description
* Empties the content recycle bin
*
* ##usage
* <pre>
* contentResource.emptyRecycleBin()
* .then(function() {
* alert('its empty!');
* });
* @name umbraco.resources.contentResource#emptyRecycleBin
* @methodOf umbraco.resources.contentResource
*
* @description
* Empties the content recycle bin
*
* ##usage
* <pre>
* contentResource.emptyRecycleBin()
* .then(function() {
* alert('its empty!');
* });
* </pre>
*
* @returns {Promise} resourcePromise object.
*
*/
* @returns {Promise} resourcePromise object.
*
*/
emptyRecycleBin: function () {
return umbRequestHelper.resourcePromise(
$http.post(
@@ -308,25 +308,25 @@ function contentResource($q, $http, umbDataFormatter, umbRequestHelper) {
},
/**
* @ngdoc method
* @name umbraco.resources.contentResource#deleteById
* @methodOf umbraco.resources.contentResource
*
* @description
* Deletes a content item with a given id
*
* ##usage
* <pre>
* contentResource.deleteById(1234)
* .then(function() {
* alert('its gone!');
* });
* @ngdoc method
* @name umbraco.resources.contentResource#deleteById
* @methodOf umbraco.resources.contentResource
*
* @description
* Deletes a content item with a given id
*
* ##usage
* <pre>
* contentResource.deleteById(1234)
* .then(function() {
* alert('its gone!');
* });
* </pre>
*
* @param {Int} id id of content item to delete
* @returns {Promise} resourcePromise object.
*
*/
* @returns {Promise} resourcePromise object.
*
*/
deleteById: function (id) {
return umbRequestHelper.resourcePromise(
$http.post(
@@ -348,27 +348,27 @@ function contentResource($q, $http, umbDataFormatter, umbRequestHelper) {
},
/**
* @ngdoc method
* @name umbraco.resources.contentResource#getById
* @methodOf umbraco.resources.contentResource
*
* @description
* Gets a content item with a given id
*
* ##usage
* <pre>
* contentResource.getById(1234)
* .then(function(content) {
* @ngdoc method
* @name umbraco.resources.contentResource#getById
* @methodOf umbraco.resources.contentResource
*
* @description
* Gets a content item with a given id
*
* ##usage
* <pre>
* contentResource.getById(1234)
* .then(function(content) {
* var myDoc = content;
* alert('its here!');
* });
* alert('its here!');
* });
* </pre>
*
* @param {Int} id id of content item to return
* @param {Int} culture optional culture to retrieve the item in
* @returns {Promise} resourcePromise object containing the content item.
*
*/
* @returns {Promise} resourcePromise object containing the content item.
*
*/
getById: function (id) {
return umbRequestHelper.resourcePromise(
$http.get(
@@ -419,26 +419,26 @@ function contentResource($q, $http, umbDataFormatter, umbRequestHelper) {
},
/**
* @ngdoc method
* @name umbraco.resources.contentResource#getByIds
* @methodOf umbraco.resources.contentResource
*
* @description
* Gets an array of content items, given a collection of ids
*
* ##usage
* <pre>
* contentResource.getByIds( [1234,2526,28262])
* .then(function(contentArray) {
* @ngdoc method
* @name umbraco.resources.contentResource#getByIds
* @methodOf umbraco.resources.contentResource
*
* @description
* Gets an array of content items, given a collection of ids
*
* ##usage
* <pre>
* contentResource.getByIds( [1234,2526,28262])
* .then(function(contentArray) {
* var myDoc = contentArray;
* alert('they are here!');
* });
* alert('they are here!');
* });
* </pre>
*
* @param {Array} ids ids of content items to return as an array
* @returns {Promise} resourcePromise object containing the content items array.
*
*/
* @returns {Promise} resourcePromise object containing the content items array.
*
*/
getByIds: function (ids) {
var idQuery = "";
@@ -464,37 +464,37 @@ function contentResource($q, $http, umbDataFormatter, umbRequestHelper) {
/**
* @ngdoc method
* @name umbraco.resources.contentResource#getScaffold
* @methodOf umbraco.resources.contentResource
* @ngdoc method
* @name umbraco.resources.contentResource#getScaffold
* @methodOf umbraco.resources.contentResource
*
* @description
* Returns a scaffold of an empty content item, given the id of the content item to place it underneath and the content type alias.
*
* @description
* Returns a scaffold of an empty content item, given the id of the content item to place it underneath and the content type alias.
*
* - Parent Id must be provided so umbraco knows where to store the content
* - Parent Id must be provided so umbraco knows where to store the content
* - Content Type alias must be provided so umbraco knows which properties to put on the content scaffold
*
* The scaffold is used to build editors for content that has not yet been populated with data.
* The scaffold is used to build editors for content that has not yet been populated with data.
*
* ##usage
* <pre>
* contentResource.getScaffold(1234, 'homepage')
* .then(function(scaffold) {
* var myDoc = scaffold;
* ##usage
* <pre>
* contentResource.getScaffold(1234, 'homepage')
* .then(function(scaffold) {
* var myDoc = scaffold;
* myDoc.name = "My new document";
*
* contentResource.publish(myDoc, true)
* .then(function(content){
* alert("Retrieved, updated and published again");
* });
* });
*
* contentResource.publish(myDoc, true)
* .then(function(content){
* alert("Retrieved, updated and published again");
* });
* });
* </pre>
*
* @param {Int} parentId id of content item to return
* @param {Int} parentId id of content item to return
* @param {String} alias contenttype alias to base the scaffold on
* @returns {Promise} resourcePromise object containing the content scaffold.
*
*/
* @returns {Promise} resourcePromise object containing the content scaffold.
*
*/
getScaffold: function (parentId, alias) {
return umbRequestHelper.resourcePromise(
@@ -524,25 +524,25 @@ function contentResource($q, $http, umbDataFormatter, umbRequestHelper) {
},
/**
* @ngdoc method
* @name umbraco.resources.contentResource#getNiceUrl
* @methodOf umbraco.resources.contentResource
*
* @description
* Returns a url, given a node ID
*
* ##usage
* <pre>
* contentResource.getNiceUrl(id)
* .then(function(url) {
* alert('its here!');
* });
* @ngdoc method
* @name umbraco.resources.contentResource#getNiceUrl
* @methodOf umbraco.resources.contentResource
*
* @description
* Returns a url, given a node ID
*
* ##usage
* <pre>
* contentResource.getNiceUrl(id)
* .then(function(url) {
* alert('its here!');
* });
* </pre>
*
* @param {Int} id Id of node to return the public url to
* @returns {Promise} resourcePromise object containing the url.
*
*/
* @param {Int} id Id of node to return the public url to
* @returns {Promise} resourcePromise object containing the url.
*
*/
getNiceUrl: function (id) {
return umbRequestHelper.resourcePromise(
$http.get(
@@ -554,33 +554,33 @@ function contentResource($q, $http, umbDataFormatter, umbRequestHelper) {
},
/**
* @ngdoc method
* @name umbraco.resources.contentResource#getChildren
* @methodOf umbraco.resources.contentResource
*
* @description
* Gets children of a content item with a given id
*
* ##usage
* <pre>
* contentResource.getChildren(1234, {pageSize: 10, pageNumber: 2})
* .then(function(contentArray) {
* @ngdoc method
* @name umbraco.resources.contentResource#getChildren
* @methodOf umbraco.resources.contentResource
*
* @description
* Gets children of a content item with a given id
*
* ##usage
* <pre>
* contentResource.getChildren(1234, {pageSize: 10, pageNumber: 2})
* .then(function(contentArray) {
* var children = contentArray;
* alert('they are here!');
* });
* alert('they are here!');
* });
* </pre>
*
* @param {Int} parentid id of content item to return children of
* @param {Object} options optional options object
* @param {Int} options.pageSize if paging data, number of nodes per page, default = 0
* @param {Int} options.pageNumber if paging data, current page index, default = 0
* @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`
* @param {Int} parentid id of content item to return children of
* @param {Object} options optional options object
* @param {Int} options.pageSize if paging data, number of nodes per page, default = 0
* @param {Int} options.pageNumber if paging data, current page index, default = 0
* @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`
* @param {String} options.cultureName if provided, the results will be for this specific culture/variant
* @returns {Promise} resourcePromise object containing an array of content items.
*
*/
* @returns {Promise} resourcePromise object containing an array of content items.
*
*/
getChildren: function (parentId, options) {
var defaults = {
@@ -651,34 +651,34 @@ function contentResource($q, $http, umbDataFormatter, umbRequestHelper) {
},
/**
* @ngdoc method
* @name umbraco.resources.contentResource#save
* @methodOf umbraco.resources.contentResource
*
* @description
* Saves changes made to a content item to its current version, if the content item is new, the isNew paramater must be passed to force creation
* @ngdoc method
* @name umbraco.resources.contentResource#save
* @methodOf umbraco.resources.contentResource
*
* @description
* Saves changes made to a content item to its current version, if the content item is new, the isNew paramater must be passed to force creation
* if the content item needs to have files attached, they must be provided as the files param and passed separately
*
*
* ##usage
* <pre>
* contentResource.getById(1234)
* .then(function(content) {
* content.name = "I want a new name!";
* contentResource.save(content, false)
* .then(function(content){
* alert("Retrieved, updated and saved again");
* });
* });
* ##usage
* <pre>
* contentResource.getById(1234)
* .then(function(content) {
* content.name = "I want a new name!";
* contentResource.save(content, false)
* .then(function(content){
* alert("Retrieved, updated and saved again");
* });
* });
* </pre>
*
* @param {Object} content The content item object with changes applied
* @param {Object} content The content item object with changes applied
* @param {Bool} isNew set to true to create a new item or to update an existing
* @param {Array} files collection of files for the document
* @param {Bool} showNotifications an option to disable/show notifications (default is true)
* @returns {Promise} resourcePromise object containing the saved content item.
*
*/
* @returns {Promise} resourcePromise object containing the saved content item.
*
*/
save: function (content, isNew, files, showNotifications) {
var endpoint = umbRequestHelper.getApiUrl(
"contentApiBaseUrl",
@@ -694,34 +694,34 @@ function contentResource($q, $http, umbDataFormatter, umbRequestHelper) {
},
/**
* @ngdoc method
* @name umbraco.resources.contentResource#publish
* @methodOf umbraco.resources.contentResource
*
* @description
* Saves and publishes changes made to a content item to a new version, if the content item is new, the isNew paramater must be passed to force creation
* @ngdoc method
* @name umbraco.resources.contentResource#publish
* @methodOf umbraco.resources.contentResource
*
* @description
* Saves and publishes changes made to a content item to a new version, if the content item is new, the isNew paramater must be passed to force creation
* if the content item needs to have files attached, they must be provided as the files param and passed separately
*
*
* ##usage
* <pre>
* contentResource.getById(1234)
* .then(function(content) {
* content.name = "I want a new name, and be published!";
* contentResource.publish(content, false)
* .then(function(content){
* alert("Retrieved, updated and published again");
* });
* });
* ##usage
* <pre>
* contentResource.getById(1234)
* .then(function(content) {
* content.name = "I want a new name, and be published!";
* contentResource.publish(content, false)
* .then(function(content){
* alert("Retrieved, updated and published again");
* });
* });
* </pre>
*
* @param {Object} content The content item object with changes applied
* @param {Object} content The content item object with changes applied
* @param {Bool} isNew set to true to create a new item or to update an existing
* @param {Array} files collection of files for the document
* @param {Bool} showNotifications an option to disable/show notifications (default is true)
* @returns {Promise} resourcePromise object containing the saved content item.
*
*/
* @returns {Promise} resourcePromise object containing the saved content item.
*
*/
publish: function (content, isNew, files, showNotifications) {
var endpoint = umbRequestHelper.getApiUrl(
"contentApiBaseUrl",
@@ -743,31 +743,31 @@ function contentResource($q, $http, umbDataFormatter, umbRequestHelper) {
},
/**
* @ngdoc method
* @name umbraco.resources.contentResource#sendToPublish
* @methodOf umbraco.resources.contentResource
* @ngdoc method
* @name umbraco.resources.contentResource#sendToPublish
* @methodOf umbraco.resources.contentResource
*
* @description
* Saves changes made to a content item, and notifies any subscribers about a pending publication
*
* @description
* Saves changes made to a content item, and notifies any subscribers about a pending publication
*
* ##usage
* <pre>
* contentResource.getById(1234)
* .then(function(content) {
* content.name = "I want a new name, and be published!";
* contentResource.sendToPublish(content, false)
* .then(function(content){
* alert("Retrieved, updated and notication send off");
* });
* });
* ##usage
* <pre>
* contentResource.getById(1234)
* .then(function(content) {
* content.name = "I want a new name, and be published!";
* contentResource.sendToPublish(content, false)
* .then(function(content){
* alert("Retrieved, updated and notication send off");
* });
* });
* </pre>
*
* @param {Object} content The content item object with changes applied
* @param {Object} content The content item object with changes applied
* @param {Bool} isNew set to true to create a new item or to update an existing
* @param {Array} files collection of files for the document
* @returns {Promise} resourcePromise object containing the saved content item.
*
*/
* @returns {Promise} resourcePromise object containing the saved content item.
*
*/
sendToPublish: function (content, isNew, files, showNotifications) {
var endpoint = umbRequestHelper.getApiUrl(
"contentApiBaseUrl",
@@ -797,25 +797,25 @@ function contentResource($q, $http, umbDataFormatter, umbRequestHelper) {
},
/**
* @ngdoc method
* @name umbraco.resources.contentResource#publishByid
* @methodOf umbraco.resources.contentResource
* @ngdoc method
* @name umbraco.resources.contentResource#publishByid
* @methodOf umbraco.resources.contentResource
*
* @description
* Publishes a content item with a given ID
*
* @description
* Publishes a content item with a given ID
*
* ##usage
* <pre>
* contentResource.publishById(1234)
* .then(function(content) {
* alert("published");
* });
* ##usage
* <pre>
* contentResource.publishById(1234)
* .then(function(content) {
* alert("published");
* });
* </pre>
*
* @param {Int} id The ID of the conten to publish
* @returns {Promise} resourcePromise object containing the published content item.
*
*/
* @param {Int} id The ID of the conten to publish
* @returns {Promise} resourcePromise object containing the published content item.
*
*/
publishById: function (id) {
if (!id) {
@@ -2,10 +2,10 @@
* @ngdoc service
* @name umbraco.resources.entityResource
* @description Loads in basic data for all entities
*
*
* ##What is an entity?
* An entity is a basic **read-only** representation of an Umbraco node. It contains only the most
* basic properties used to display the item in trees, lists and navigation.
* basic properties used to display the item in trees, lists and navigation.
*
* ##What is the difference between entity and content/media/etc...?
* the entity only contains the basic node data, name, id and guid, whereas content
@@ -15,7 +15,7 @@
*
* ##Entity object types?
* You need to specify the type of object you want returned.
*
*
* The core object types are:
*
* - Document
@@ -35,7 +35,7 @@ function entityResource($q, $http, umbRequestHelper) {
//the factory object returned
return {
getSafeAlias: function (value, camelCase) {
if (!value) {
@@ -64,10 +64,10 @@ function entityResource($q, $http, umbRequestHelper) {
* .then(function(pathArray) {
* alert('its here!');
* });
* </pre>
*
* </pre>
*
* @param {Int} id Id of node to return the public url to
* @param {string} type Object type name
* @param {string} type Object type name
* @returns {Promise} resourcePromise object containing the url.
*
*/
@@ -100,8 +100,8 @@ function entityResource($q, $http, umbRequestHelper) {
* .then(function(url) {
* alert('its here!');
* });
* </pre>
*
* </pre>
*
* @param {Int} id Id of node to return the public url to
* @param {string} type Object type name
* @returns {Promise} resourcePromise object containing the url.
@@ -135,17 +135,17 @@ function entityResource($q, $http, umbRequestHelper) {
* //get media by id
* entityResource.getEntityById(0, "Media")
* .then(function(ent) {
* var myDoc = ent;
* var myDoc = ent;
* alert('its here!');
* });
* </pre>
*
* </pre>
*
* @param {Int} id id of entity to return
* @param {string} type Object type name
* @param {string} type Object type name
* @returns {Promise} resourcePromise object containing the entity.
*
*/
getById: function (id, type) {
getById: function (id, type) {
if (id === -1 || id === "-1") {
return null;
@@ -160,6 +160,40 @@ function entityResource($q, $http, umbRequestHelper) {
'Failed to retrieve entity data for id ' + id);
},
getUrlAndAnchors: function (id) {
if (id === -1 || id === "-1") {
return null;
}
return umbRequestHelper.resourcePromise(
$http.get(
umbRequestHelper.getApiUrl(
"entityApiBaseUrl",
"GetUrlAndAnchors",
{ id: id })),
'Failed to retrieve url and anchors data for id ' + id);
},
getAnchors: function (rteContent) {
if (!rteContent || rteContent.length === 0) {
return [];
}
return umbRequestHelper.resourcePromise(
$http.post(
umbRequestHelper.getApiUrl(
"entityApiBaseUrl",
'GetAnchors'),
{
rteContent: rteContent
}),
'Failed to anchors data for rte content ' + rteContent);
},
/**
* @ngdoc method
* @name umbraco.resources.entityResource#getByIds
@@ -173,18 +207,18 @@ function entityResource($q, $http, umbRequestHelper) {
* //Get templates for ids
* entityResource.getEntitiesByIds( [1234,2526,28262], "Template")
* .then(function(templateArray) {
* var myDoc = contentArray;
* var myDoc = contentArray;
* alert('they are here!');
* });
* </pre>
*
* </pre>
*
* @param {Array} ids ids of entities to return as an array
* @param {string} type type name
* @param {string} type type name
* @returns {Promise} resourcePromise object containing the entity array.
*
*/
getByIds: function (ids, type) {
var query = "type=" + type;
return umbRequestHelper.resourcePromise(
@@ -212,14 +246,14 @@ function entityResource($q, $http, umbRequestHelper) {
* //get content by xpath
* entityResource.getByQuery("$current", -1, "Document")
* .then(function(ent) {
* var myDoc = ent;
* var myDoc = ent;
* alert('its here!');
* });
* </pre>
*
* </pre>
*
* @param {string} query xpath to use in query
* @param {Int} nodeContextId id id to start from
* @param {string} type Object type name
* @param {string} type Object type name
* @returns {Promise} resourcePromise object containing the entity.
*
*/
@@ -247,12 +281,12 @@ function entityResource($q, $http, umbRequestHelper) {
* //Only return media
* entityResource.getAll("Media")
* .then(function(ent) {
* var myDoc = ent;
* var myDoc = ent;
* alert('its here!');
* });
* </pre>
*
* @param {string} type Object type name
* </pre>
*
* @param {string} type Object type name
* @param {string} postFilter optional filter expression which will execute a dynamic where clause on the server
* @returns {Promise} resourcePromise object containing the entity.
*
@@ -277,24 +311,33 @@ function entityResource($q, $http, umbRequestHelper) {
*
* @description
* Gets ancestor entities for a given item
*
*
*
*
* @param {string} type Object type name
* @param {string} culture Culture
* @returns {Promise} resourcePromise object containing the entity.
*
*/
getAncestors: function (id, type, culture) {
getAncestors: function (id, type, culture, options) {
if (culture === undefined) culture = "";
var args = [
{ id: id },
{ type: type },
{ culture: culture}
];
if (options && options.dataTypeId) {
args.push({ dataTypeId: options.dataTypeId });
}
return umbRequestHelper.resourcePromise(
$http.get(
umbRequestHelper.getApiUrl(
"entityApiBaseUrl",
"GetAncestors",
[{ id: id }, { type: type }, { culture: culture }])),
'Failed to retrieve ancestor data for id ' + id);
args)),
'Failed to retrieve ancestor data for id ' + id);
},
/**
* @ngdoc method
* @name umbraco.resources.entityResource#getChildren
@@ -302,20 +345,25 @@ function entityResource($q, $http, umbRequestHelper) {
*
* @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
* @param {string} type Object type name
* @returns {Promise} resourcePromise object containing the entity.
*
*/
getChildren: function (id, type) {
getChildren: function (id, type, options) {
var args = [{ id: id }, { type: type }];
if (options && options.dataTypeId) {
args.push({ dataTypeId: options.dataTypeId });
}
return umbRequestHelper.resourcePromise(
$http.get(
umbRequestHelper.getApiUrl(
"entityApiBaseUrl",
"GetChildren",
[{ id: id }, { type: type }])),
args)),
'Failed to retrieve child data for id ' + id);
},
@@ -331,11 +379,11 @@ function entityResource($q, $http, umbRequestHelper) {
* <pre>
* entityResource.getPagedChildren(1234, "Content", {pageSize: 10, pageNumber: 2})
* .then(function(contentArray) {
* var children = contentArray;
* var children = contentArray;
* alert('they are here!');
* });
* </pre>
*
* </pre>
*
* @param {Int} parentid id of content item to return children of
* @param {string} type Object type name
* @param {Object} options optional options object
@@ -383,7 +431,8 @@ function entityResource($q, $http, umbRequestHelper) {
pageSize: options.pageSize,
orderBy: options.orderBy,
orderDirection: options.orderDirection,
filter: encodeURIComponent(options.filter)
filter: encodeURIComponent(options.filter),
dataTypeId: options.dataTypeId
}
)),
'Failed to retrieve child data for id ' + parentId);
@@ -401,11 +450,11 @@ function entityResource($q, $http, umbRequestHelper) {
* <pre>
* entityResource.getPagedDescendants(1234, "Document", {pageSize: 10, pageNumber: 2})
* .then(function(contentArray) {
* var children = contentArray;
* var children = contentArray;
* alert('they are here!');
* });
* </pre>
*
* </pre>
*
* @param {Int} parentid id of content item to return descendants of
* @param {string} type Object type name
* @param {Object} options optional options object
@@ -424,7 +473,8 @@ function entityResource($q, $http, umbRequestHelper) {
pageNumber: 1,
filter: '',
orderDirection: "Ascending",
orderBy: "SortOrder"
orderBy: "SortOrder",
dataTypeId: null
};
if (options === undefined) {
options = {};
@@ -453,12 +503,14 @@ function entityResource($q, $http, umbRequestHelper) {
pageSize: options.pageSize,
orderBy: options.orderBy,
orderDirection: options.orderDirection,
filter: encodeURIComponent(options.filter)
filter: encodeURIComponent(options.filter),
dataTypeId: options.dataTypeId
}
)),
'Failed to retrieve child data for id ' + parentId);
},
/**
* @ngdoc method
* @name umbraco.resources.entityResource#search
@@ -471,23 +523,27 @@ function entityResource($q, $http, umbRequestHelper) {
* <pre>
* entityResource.search("news", "Media")
* .then(function(mediaArray) {
* var myDoc = mediaArray;
* var myDoc = mediaArray;
* alert('they are here!');
* });
* </pre>
*
* @param {String} Query search query
* @param {String} Type type of conten to search
* </pre>
*
* @param {String} Query search query
* @param {String} Type type of conten to search
* @returns {Promise} resourcePromise object containing the entity array.
*
*/
search: function (query, type, searchFrom, canceler) {
search: function (query, type, searchFrom, canceler, dataTypeId) {
var args = [{ query: query }, { type: type }];
if (searchFrom) {
args.push({ searchFrom: searchFrom });
}
if (dataTypeId) {
args.push({ dataTypeId: dataTypeId });
}
var httpConfig = {};
if (canceler) {
httpConfig["timeout"] = canceler;
@@ -502,7 +558,7 @@ function entityResource($q, $http, umbRequestHelper) {
httpConfig),
'Failed to retrieve entity data for query ' + query);
},
/**
* @ngdoc method
@@ -516,12 +572,12 @@ function entityResource($q, $http, umbRequestHelper) {
* <pre>
* entityResource.searchAll("bob")
* .then(function(array) {
* var myDoc = array;
* var myDoc = array;
* alert('they are here!');
* });
* </pre>
*
* @param {String} Query search query
* </pre>
*
* @param {String} Query search query
* @returns {Promise} resourcePromise object containing the entity array.
*
*/
@@ -541,7 +597,9 @@ function entityResource($q, $http, umbRequestHelper) {
httpConfig),
'Failed to retrieve entity data for query ' + query);
}
};
}
@@ -1,16 +1,16 @@
/**
* @ngdoc service
* @name umbraco.resources.mediaResource
* @description Loads in data for media
**/
* @ngdoc service
* @name umbraco.resources.mediaResource
* @description Loads in data for media
**/
function mediaResource($q, $http, umbDataFormatter, umbRequestHelper) {
/** internal method process the saving of data and post processing the result */
function saveMediaItem(content, action, files) {
return umbRequestHelper.postSaveContent({
restApiUrl: umbRequestHelper.getApiUrl(
"mediaApiBaseUrl",
"PostSave"),
"mediaApiBaseUrl",
"PostSave"),
content: content,
action: action,
files: files,
@@ -24,35 +24,35 @@ function mediaResource($q, $http, umbDataFormatter, umbRequestHelper) {
getRecycleBin: function () {
return umbRequestHelper.resourcePromise(
$http.get(
umbRequestHelper.getApiUrl(
"mediaApiBaseUrl",
"GetRecycleBin")),
'Failed to retrieve data for media recycle bin');
$http.get(
umbRequestHelper.getApiUrl(
"mediaApiBaseUrl",
"GetRecycleBin")),
'Failed to retrieve data for media recycle bin');
},
/**
* @ngdoc method
* @name umbraco.resources.mediaResource#sort
* @methodOf umbraco.resources.mediaResource
*
* @description
* Sorts all children below a given parent node id, based on a collection of node-ids
*
* ##usage
* <pre>
* var ids = [123,34533,2334,23434];
* mediaResource.sort({ sortedIds: ids })
* .then(function() {
* $scope.complete = true;
* });
* </pre>
* @param {Object} args arguments object
* @param {Int} args.parentId the ID of the parent node
* @param {Array} options.sortedIds array of node IDs as they should be sorted
* @returns {Promise} resourcePromise object.
*
*/
* @ngdoc method
* @name umbraco.resources.mediaResource#sort
* @methodOf umbraco.resources.mediaResource
*
* @description
* Sorts all children below a given parent node id, based on a collection of node-ids
*
* ##usage
* <pre>
* var ids = [123,34533,2334,23434];
* mediaResource.sort({ sortedIds: ids })
* .then(function() {
* $scope.complete = true;
* });
* </pre>
* @param {Object} args arguments object
* @param {Int} args.parentId the ID of the parent node
* @param {Array} options.sortedIds array of node IDs as they should be sorted
* @returns {Promise} resourcePromise object.
*
*/
sort: function (args) {
if (!args) {
throw "args cannot be null";
@@ -65,37 +65,37 @@ function mediaResource($q, $http, umbDataFormatter, umbRequestHelper) {
}
return umbRequestHelper.resourcePromise(
$http.post(umbRequestHelper.getApiUrl("mediaApiBaseUrl", "PostSort"),
{
parentId: args.parentId,
idSortOrder: args.sortedIds
}),
'Failed to sort media');
$http.post(umbRequestHelper.getApiUrl("mediaApiBaseUrl", "PostSort"),
{
parentId: args.parentId,
idSortOrder: args.sortedIds
}),
'Failed to sort media');
},
/**
* @ngdoc method
* @name umbraco.resources.mediaResource#move
* @methodOf umbraco.resources.mediaResource
*
* @description
* Moves a node underneath a new parentId
*
* ##usage
* <pre>
* mediaResource.move({ parentId: 1244, id: 123 })
* .then(function() {
* alert("node was moved");
* }, function(err){
* alert("node didnt move:" + err.data.Message);
* });
* </pre>
* @param {Object} args arguments object
* @param {Int} args.idd the ID of the node to move
* @param {Int} args.parentId the ID of the parent node to move to
* @returns {Promise} resourcePromise object.
*
*/
* @ngdoc method
* @name umbraco.resources.mediaResource#move
* @methodOf umbraco.resources.mediaResource
*
* @description
* Moves a node underneath a new parentId
*
* ##usage
* <pre>
* mediaResource.move({ parentId: 1244, id: 123 })
* .then(function() {
* alert("node was moved");
* }, function(err){
* alert("node didnt move:" + err.data.Message);
* });
* </pre>
* @param {Object} args arguments object
* @param {Int} args.idd the ID of the node to move
* @param {Int} args.parentId the ID of the parent node to move to
* @returns {Promise} resourcePromise object.
*
*/
move: function (args) {
if (!args) {
throw "args cannot be null";
@@ -108,121 +108,121 @@ function mediaResource($q, $http, umbDataFormatter, umbRequestHelper) {
}
return umbRequestHelper.resourcePromise(
$http.post(umbRequestHelper.getApiUrl("mediaApiBaseUrl", "PostMove"),
{
parentId: args.parentId,
id: args.id
$http.post(umbRequestHelper.getApiUrl("mediaApiBaseUrl", "PostMove"),
{
parentId: args.parentId,
id: args.id
}, {responseType: 'text'}),
{
error: function(data){
var errorMsg = 'Failed to move media';
if (data.id !== undefined && data.parentId !== undefined) {
if (data.id === data.parentId) {
errorMsg = 'Media can\'t be moved into itself';
}
}
else if (data.notifications !== undefined) {
if (data.notifications.length > 0) {
if (data.notifications[0].header.length > 0) {
errorMsg = data.notifications[0].header;
}
if (data.notifications[0].message.length > 0) {
errorMsg = errorMsg + ": " + data.notifications[0].message;
}
{
error: function(data){
var errorMsg = 'Failed to move media';
if (data.id !== undefined && data.parentId !== undefined) {
if (data.id === data.parentId) {
errorMsg = 'Media can\'t be moved into itself';
}
}
else if (data.notifications !== undefined) {
if (data.notifications.length > 0) {
if (data.notifications[0].header.length > 0) {
errorMsg = data.notifications[0].header;
}
if (data.notifications[0].message.length > 0) {
errorMsg = errorMsg + ": " + data.notifications[0].message;
}
}
}
return {
errorMsg: errorMsg
};
}
});
return {
errorMsg: errorMsg
};
}
});
},
/**
* @ngdoc method
* @name umbraco.resources.mediaResource#getById
* @methodOf umbraco.resources.mediaResource
*
* @description
* Gets a media item with a given id
*
* ##usage
* <pre>
* mediaResource.getById(1234)
* .then(function(media) {
* var myMedia = media;
* alert('its here!');
* });
* </pre>
*
* @param {Int} id id of media item to return
* @returns {Promise} resourcePromise object containing the media item.
*
*/
* @ngdoc method
* @name umbraco.resources.mediaResource#getById
* @methodOf umbraco.resources.mediaResource
*
* @description
* Gets a media item with a given id
*
* ##usage
* <pre>
* mediaResource.getById(1234)
* .then(function(media) {
* var myMedia = media;
* alert('its here!');
* });
* </pre>
*
* @param {Int} id id of media item to return
* @returns {Promise} resourcePromise object containing the media item.
*
*/
getById: function (id) {
return umbRequestHelper.resourcePromise(
$http.get(
umbRequestHelper.getApiUrl(
"mediaApiBaseUrl",
"GetById",
[{ id: id }])),
'Failed to retrieve data for media id ' + id);
$http.get(
umbRequestHelper.getApiUrl(
"mediaApiBaseUrl",
"GetById",
[{ id: id }])),
'Failed to retrieve data for media id ' + id);
},
/**
* @ngdoc method
* @name umbraco.resources.mediaResource#deleteById
* @methodOf umbraco.resources.mediaResource
*
* @description
* Deletes a media item with a given id
*
* ##usage
* <pre>
* mediaResource.deleteById(1234)
* .then(function() {
* alert('its gone!');
* });
* </pre>
*
* @param {Int} id id of media item to delete
* @returns {Promise} resourcePromise object.
*
*/
* @ngdoc method
* @name umbraco.resources.mediaResource#deleteById
* @methodOf umbraco.resources.mediaResource
*
* @description
* Deletes a media item with a given id
*
* ##usage
* <pre>
* mediaResource.deleteById(1234)
* .then(function() {
* alert('its gone!');
* });
* </pre>
*
* @param {Int} id id of media item to delete
* @returns {Promise} resourcePromise object.
*
*/
deleteById: function (id) {
return umbRequestHelper.resourcePromise(
$http.post(
umbRequestHelper.getApiUrl(
"mediaApiBaseUrl",
"DeleteById",
[{ id: id }])),
'Failed to delete item ' + id);
$http.post(
umbRequestHelper.getApiUrl(
"mediaApiBaseUrl",
"DeleteById",
[{ id: id }])),
'Failed to delete item ' + id);
},
/**
* @ngdoc method
* @name umbraco.resources.mediaResource#getByIds
* @methodOf umbraco.resources.mediaResource
*
* @description
* Gets an array of media items, given a collection of ids
*
* ##usage
* <pre>
* mediaResource.getByIds( [1234,2526,28262])
* .then(function(mediaArray) {
* var myDoc = contentArray;
* alert('they are here!');
* });
* </pre>
*
* @param {Array} ids ids of media items to return as an array
* @returns {Promise} resourcePromise object containing the media items array.
*
*/
* @ngdoc method
* @name umbraco.resources.mediaResource#getByIds
* @methodOf umbraco.resources.mediaResource
*
* @description
* Gets an array of media items, given a collection of ids
*
* ##usage
* <pre>
* mediaResource.getByIds( [1234,2526,28262])
* .then(function(mediaArray) {
* var myDoc = contentArray;
* alert('they are here!');
* });
* </pre>
*
* @param {Array} ids ids of media items to return as an array
* @returns {Promise} resourcePromise object containing the media items array.
*
*/
getByIds: function (ids) {
var idQuery = "";
@@ -231,96 +231,96 @@ function mediaResource($q, $http, umbDataFormatter, umbRequestHelper) {
});
return umbRequestHelper.resourcePromise(
$http.get(
umbRequestHelper.getApiUrl(
"mediaApiBaseUrl",
"GetByIds",
idQuery)),
'Failed to retrieve data for media ids ' + ids);
$http.get(
umbRequestHelper.getApiUrl(
"mediaApiBaseUrl",
"GetByIds",
idQuery)),
'Failed to retrieve data for media ids ' + ids);
},
/**
* @ngdoc method
* @name umbraco.resources.mediaResource#getScaffold
* @methodOf umbraco.resources.mediaResource
*
* @description
* Returns a scaffold of an empty media item, given the id of the media item to place it underneath and the media type alias.
*
* - Parent Id must be provided so umbraco knows where to store the media
* - Media Type alias must be provided so umbraco knows which properties to put on the media scaffold
*
* The scaffold is used to build editors for media that has not yet been populated with data.
*
* ##usage
* <pre>
* mediaResource.getScaffold(1234, 'folder')
* .then(function(scaffold) {
* var myDoc = scaffold;
* myDoc.name = "My new media item";
*
* mediaResource.save(myDoc, true)
* .then(function(media){
* alert("Retrieved, updated and saved again");
* });
* });
* </pre>
*
* @param {Int} parentId id of media item to return
* @param {String} alias mediatype alias to base the scaffold on
* @returns {Promise} resourcePromise object containing the media scaffold.
*
*/
* @ngdoc method
* @name umbraco.resources.mediaResource#getScaffold
* @methodOf umbraco.resources.mediaResource
*
* @description
* Returns a scaffold of an empty media item, given the id of the media item to place it underneath and the media type alias.
*
* - Parent Id must be provided so umbraco knows where to store the media
* - Media Type alias must be provided so umbraco knows which properties to put on the media scaffold
*
* The scaffold is used to build editors for media that has not yet been populated with data.
*
* ##usage
* <pre>
* mediaResource.getScaffold(1234, 'folder')
* .then(function(scaffold) {
* var myDoc = scaffold;
* myDoc.name = "My new media item";
*
* mediaResource.save(myDoc, true)
* .then(function(media){
* alert("Retrieved, updated and saved again");
* });
* });
* </pre>
*
* @param {Int} parentId id of media item to return
* @param {String} alias mediatype alias to base the scaffold on
* @returns {Promise} resourcePromise object containing the media scaffold.
*
*/
getScaffold: function (parentId, alias) {
return umbRequestHelper.resourcePromise(
$http.get(
umbRequestHelper.getApiUrl(
"mediaApiBaseUrl",
"GetEmpty",
[{ contentTypeAlias: alias }, { parentId: parentId }])),
'Failed to retrieve data for empty media item type ' + alias);
$http.get(
umbRequestHelper.getApiUrl(
"mediaApiBaseUrl",
"GetEmpty",
[{ contentTypeAlias: alias }, { parentId: parentId }])),
'Failed to retrieve data for empty media item type ' + alias);
},
rootMedia: function () {
return umbRequestHelper.resourcePromise(
$http.get(
umbRequestHelper.getApiUrl(
"mediaApiBaseUrl",
"GetRootMedia")),
'Failed to retrieve data for root media');
$http.get(
umbRequestHelper.getApiUrl(
"mediaApiBaseUrl",
"GetRootMedia")),
'Failed to retrieve data for root media');
},
/**
* @ngdoc method
* @name umbraco.resources.mediaResource#getChildren
* @methodOf umbraco.resources.mediaResource
*
* @description
* Gets children of a media item with a given id
*
* ##usage
* <pre>
* mediaResource.getChildren(1234, {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 {Object} options optional options object
* @param {Int} options.pageSize if paging data, number of nodes per page, default = 0
* @param {Int} options.pageNumber if paging data, current page index, default = 0
* @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.
*
*/
* @ngdoc method
* @name umbraco.resources.mediaResource#getChildren
* @methodOf umbraco.resources.mediaResource
*
* @description
* Gets children of a media item with a given id
*
* ##usage
* <pre>
* mediaResource.getChildren(1234, {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 {Object} options optional options object
* @param {Int} options.pageSize if paging data, number of nodes per page, default = 0
* @param {Int} options.pageNumber if paging data, current page index, default = 0
* @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.
*
*/
getChildren: function (parentId, options) {
var defaults = {
@@ -361,111 +361,111 @@ function mediaResource($q, $http, umbDataFormatter, umbRequestHelper) {
}
return umbRequestHelper.resourcePromise(
$http.get(
umbRequestHelper.getApiUrl(
"mediaApiBaseUrl",
"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 media item ' + parentId);
$http.get(
umbRequestHelper.getApiUrl(
"mediaApiBaseUrl",
"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 media item ' + parentId);
},
/**
* @ngdoc method
* @name umbraco.resources.mediaResource#save
* @methodOf umbraco.resources.mediaResource
*
* @description
* Saves changes made to a media item, if the media item is new, the isNew paramater must be passed to force creation
* if the media item needs to have files attached, they must be provided as the files param and passed separately
*
*
* ##usage
* <pre>
* mediaResource.getById(1234)
* .then(function(media) {
* media.name = "I want a new name!";
* mediaResource.save(media, false)
* .then(function(media){
* alert("Retrieved, updated and saved again");
* });
* });
* </pre>
*
* @param {Object} media The media item object with changes applied
* @param {Bool} isNew set to true to create a new item or to update an existing
* @param {Array} files collection of files for the media item
* @returns {Promise} resourcePromise object containing the saved media item.
*
*/
* @ngdoc method
* @name umbraco.resources.mediaResource#save
* @methodOf umbraco.resources.mediaResource
*
* @description
* Saves changes made to a media item, if the media item is new, the isNew paramater must be passed to force creation
* if the media item needs to have files attached, they must be provided as the files param and passed separately
*
*
* ##usage
* <pre>
* mediaResource.getById(1234)
* .then(function(media) {
* media.name = "I want a new name!";
* mediaResource.save(media, false)
* .then(function(media){
* alert("Retrieved, updated and saved again");
* });
* });
* </pre>
*
* @param {Object} media The media item object with changes applied
* @param {Bool} isNew set to true to create a new item or to update an existing
* @param {Array} files collection of files for the media item
* @returns {Promise} resourcePromise object containing the saved media item.
*
*/
save: function (media, isNew, files) {
return saveMediaItem(media, "save" + (isNew ? "New" : ""), files);
},
/**
* @ngdoc method
* @name umbraco.resources.mediaResource#addFolder
* @methodOf umbraco.resources.mediaResource
*
* @description
* Shorthand for adding a media item of the type "Folder" under a given parent ID
*
* ##usage
* <pre>
* mediaResource.addFolder("My gallery", 1234)
* .then(function(folder) {
* alert('New folder');
* });
* </pre>
*
* @param {string} name Name of the folder to create
* @param {int} parentId Id of the media item to create the folder underneath
* @returns {Promise} resourcePromise object.
*
*/
* @ngdoc method
* @name umbraco.resources.mediaResource#addFolder
* @methodOf umbraco.resources.mediaResource
*
* @description
* Shorthand for adding a media item of the type "Folder" under a given parent ID
*
* ##usage
* <pre>
* mediaResource.addFolder("My gallery", 1234)
* .then(function(folder) {
* alert('New folder');
* });
* </pre>
*
* @param {string} name Name of the folder to create
* @param {int} parentId Id of the media item to create the folder underneath
* @returns {Promise} resourcePromise object.
*
*/
addFolder: function (name, parentId) {
return umbRequestHelper.resourcePromise(
$http.post(umbRequestHelper
.getApiUrl("mediaApiBaseUrl", "PostAddFolder"),
{
name: name,
parentId: parentId
}),
'Failed to add folder');
$http.post(umbRequestHelper
.getApiUrl("mediaApiBaseUrl", "PostAddFolder"),
{
name: name,
parentId: parentId
}),
'Failed to add folder');
},
/**
* @ngdoc method
* @name umbraco.resources.mediaResource#getChildFolders
* @methodOf umbraco.resources.mediaResource
*
* @description
* Retrieves all media children with types used as folders.
* Uses the convention of looking for media items with mediaTypes ending in
* *Folder so will match "Folder", "bannerFolder", "secureFolder" etc,
*
* @ngdoc method
* @name umbraco.resources.mediaResource#getChildFolders
* @methodOf umbraco.resources.mediaResource
*
* @description
* Retrieves all media children with types used as folders.
* Uses the convention of looking for media items with mediaTypes ending in
* *Folder so will match "Folder", "bannerFolder", "secureFolder" etc,
*
* NOTE: This will return a page of max 500 folders, if more is required it needs to be paged
* and then folders are in the .items property of the returned promise data
*
* ##usage
* <pre>
* mediaResource.getChildFolders(1234)
*
* ##usage
* <pre>
* mediaResource.getChildFolders(1234)
* .then(function(page) {
* alert('folders');
* });
* </pre>
*
* @param {int} parentId Id of the media item to query for child folders
* @returns {Promise} resourcePromise object.
*
*/
* alert('folders');
* });
* </pre>
*
* @param {int} parentId Id of the media item to query for child folders
* @returns {Promise} resourcePromise object.
*
*/
getChildFolders: function (parentId) {
if (!parentId) {
parentId = -1;
@@ -473,69 +473,69 @@ function mediaResource($q, $http, umbDataFormatter, umbRequestHelper) {
//NOTE: This will return a max of 500 folders, if more is required it needs to be paged
return umbRequestHelper.resourcePromise(
$http.get(
umbRequestHelper.getApiUrl(
"mediaApiBaseUrl",
"GetChildFolders",
{
$http.get(
umbRequestHelper.getApiUrl(
"mediaApiBaseUrl",
"GetChildFolders",
{
id: parentId,
pageNumber: 1,
pageSize: 500
})),
})),
'Failed to retrieve child folders for media item ' + parentId);
},
/**
* @ngdoc method
* @name umbraco.resources.mediaResource#emptyRecycleBin
* @methodOf umbraco.resources.mediaResource
*
* @description
* Empties the media recycle bin
*
* ##usage
* <pre>
* mediaResource.emptyRecycleBin()
* .then(function() {
* alert('its empty!');
* });
* </pre>
*
* @returns {Promise} resourcePromise object.
*
*/
* @ngdoc method
* @name umbraco.resources.mediaResource#emptyRecycleBin
* @methodOf umbraco.resources.mediaResource
*
* @description
* Empties the media recycle bin
*
* ##usage
* <pre>
* mediaResource.emptyRecycleBin()
* .then(function() {
* alert('its empty!');
* });
* </pre>
*
* @returns {Promise} resourcePromise object.
*
*/
emptyRecycleBin: function () {
return umbRequestHelper.resourcePromise(
$http.post(
umbRequestHelper.getApiUrl(
"mediaApiBaseUrl",
"EmptyRecycleBin")),
'Failed to empty the recycle bin');
$http.post(
umbRequestHelper.getApiUrl(
"mediaApiBaseUrl",
"EmptyRecycleBin")),
'Failed to empty the recycle bin');
},
/**
* @ngdoc method
* @name umbraco.resources.mediaResource#search
* @methodOf umbraco.resources.mediaResource
*
* @description
* Paginated search for media items starting on the supplied nodeId
*
* ##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 NodeId to search from (-1 for root)
* @returns {Promise} resourcePromise object.
*
*/
* @ngdoc method
* @name umbraco.resources.mediaResource#search
* @methodOf umbraco.resources.mediaResource
*
* @description
* Paginated search for media items starting on the supplied nodeId
*
* ##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 NodeId to search from (-1 for root)
* @returns {Promise} resourcePromise object.
*
*/
search: function (query, pageNumber, pageSize, searchFrom) {
var args = [
@@ -546,12 +546,12 @@ function mediaResource($q, $http, umbDataFormatter, umbRequestHelper) {
];
return umbRequestHelper.resourcePromise(
$http.get(
umbRequestHelper.getApiUrl(
"mediaApiBaseUrl",
"Search",
args)),
'Failed to retrieve media items for search: ' + query);
$http.get(
umbRequestHelper.getApiUrl(
"mediaApiBaseUrl",
"Search",
args)),
'Failed to retrieve media items for search: ' + query);
}
};
@@ -3,7 +3,7 @@
* @name umbraco.services.mediaHelper
* @description A helper object used for dealing with media items
**/
function mediaHelper(umbRequestHelper) {
function mediaHelper(umbRequestHelper, $log) {
//container of fileresolvers
var _mediaFileResolvers = {};
@@ -13,11 +13,11 @@ function mediaHelper(umbRequestHelper) {
* @ngdoc function
* @name umbraco.services.mediaHelper#getImagePropertyValue
* @methodOf umbraco.services.mediaHelper
* @function
* @function
*
* @description
* Returns the file path associated with the media property if there is one
*
*
* @param {object} options Options object
* @param {object} options.mediaModel The media object to retrieve the image path from
* @param {object} options.imageOnly Optional, if true then will only return a path if the media item is an image
@@ -80,11 +80,11 @@ function mediaHelper(umbRequestHelper) {
* @ngdoc function
* @name umbraco.services.mediaHelper#getImagePropertyValue
* @methodOf umbraco.services.mediaHelper
* @function
* @function
*
* @description
* Returns the actual image path associated with the image property if there is one
*
*
* @param {object} options Options object
* @param {object} options.imageModel The media object to retrieve the image path from
*/
@@ -104,11 +104,11 @@ function mediaHelper(umbRequestHelper) {
* @ngdoc function
* @name umbraco.services.mediaHelper#getThumbnail
* @methodOf umbraco.services.mediaHelper
* @function
* @function
*
* @description
* formats the display model used to display the content to the model used to save the content
*
*
* @param {object} options Options object
* @param {object} options.imageModel The media object to retrieve the image path from
*/
@@ -133,18 +133,20 @@ function mediaHelper(umbRequestHelper) {
* @ngdoc function
* @name umbraco.services.mediaHelper#resolveFileFromEntity
* @methodOf umbraco.services.mediaHelper
* @function
* @function
*
* @description
* Gets the media file url for a media entity returned with the entityResource
*
*
* @param {object} mediaEntity A media Entity returned from the entityResource
* @param {boolean} thumbnail Whether to return the thumbnail url or normal url
*/
resolveFileFromEntity: function (mediaEntity, thumbnail) {
if (!angular.isObject(mediaEntity.metaData) || !mediaEntity.metaData.MediaPath) {
throw "Cannot resolve the file url from the mediaEntity, it does not contain the required metaData";
//don't throw since this image legitimately might not contain a media path, but output a warning
$log.warn("Cannot resolve the file url from the mediaEntity, it does not contain the required metaData");
return null;
}
if (thumbnail) {
@@ -164,11 +166,11 @@ function mediaHelper(umbRequestHelper) {
* @ngdoc function
* @name umbraco.services.mediaHelper#resolveFile
* @methodOf umbraco.services.mediaHelper
* @function
* @function
*
* @description
* Gets the media file url for a media object returned with the mediaResource
*
*
* @param {object} mediaEntity A media Entity returned from the entityResource
* @param {boolean} thumbnail Whether to return the thumbnail url or normal url
*/
@@ -240,11 +242,11 @@ function mediaHelper(umbRequestHelper) {
* @ngdoc function
* @name umbraco.services.mediaHelper#scaleToMaxSize
* @methodOf umbraco.services.mediaHelper
* @function
* @function
*
* @description
* Finds the corrct max width and max height, given maximum dimensions and keeping aspect ratios
*
*
* @param {number} maxSize Maximum width & height
* @param {number} width Current width
* @param {number} height Current height
@@ -283,11 +285,11 @@ function mediaHelper(umbRequestHelper) {
* @ngdoc function
* @name umbraco.services.mediaHelper#getThumbnailFromPath
* @methodOf umbraco.services.mediaHelper
* @function
* @function
*
* @description
* Returns the path to the thumbnail version of a given media library image path
*
*
* @param {string} imagePath Image path, ex: /media/1234/my-image.jpg
*/
getThumbnailFromPath: function (imagePath) {
@@ -310,11 +312,11 @@ function mediaHelper(umbRequestHelper) {
* @ngdoc function
* @name umbraco.services.mediaHelper#detectIfImageByExtension
* @methodOf umbraco.services.mediaHelper
* @function
* @function
*
* @description
* Returns true/false, indicating if the given path has an allowed image extension
*
*
* @param {string} imagePath Image path, ex: /media/1234/my-image.jpg
*/
detectIfImageByExtension: function (imagePath) {
@@ -2,7 +2,7 @@
* @ngdoc service
* @name umbraco.services.searchService
*
*
*
* @description
* Service for handling the main application search, can currently search content, media and members
*
@@ -15,10 +15,10 @@
* angular.forEach(results, function(result){
* //returns:
* {name: "name", id: 1234, menuUrl: "url", editorPath: "url", metaData: {}, subtitle: "/path/etc" }
* })
* var result =
* })
* </pre>
* })
* var result =
* })
* </pre>
*/
angular.module('umbraco.services')
.factory('searchService', function ($q, $log, entityResource, contentResource, umbRequestHelper, $injector, searchResultFormatter) {
@@ -67,7 +67,7 @@ angular.module('umbraco.services')
throw "args.term is required";
}
return entityResource.search(args.term, "Document", args.searchFrom, args.canceler).then(function (data) {
return entityResource.search(args.term, "Document", args.searchFrom, args.canceler, args.dataTypeId).then(function (data) {
_.each(data, function (item) {
searchResultFormatter.configureContentResult(item);
});
@@ -92,7 +92,7 @@ angular.module('umbraco.services')
throw "args.term is required";
}
return entityResource.search(args.term, "Media", args.searchFrom).then(function (data) {
return entityResource.search(args.term, "Media", args.searchFrom, args.canceler, args.dataTypeId).then(function (data) {
_.each(data, function (item) {
searchResultFormatter.configureMediaResult(item);
});
@@ -122,7 +122,7 @@ angular.module('umbraco.services')
_.each(data, function (resultByType) {
//we need to format the search result data to include things like the subtitle, urls, etc...
// this is done with registered angular services as part of the SearchableTreeAttribute, if that
// this is done with registered angular services as part of the SearchableTreeAttribute, if that
// is not found, than we format with the default formatter
var formatterMethod = searchResultFormatter.configureDefaultResult;
//check if a custom formatter is specified...
@@ -143,7 +143,7 @@ angular.module('umbraco.services')
_.each(resultByType.results, function (item) {
formatterMethod.apply(this, [item, resultByType.treeAlias, resultByType.appAlias]);
});
});
return data;
@@ -157,4 +157,4 @@ angular.module('umbraco.services')
var currentSection = sectionAlias;
}
};
});
});
@@ -895,38 +895,6 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s
},
/**
* @ngdoc method
* @name umbraco.services.tinyMceService#getAnchorNames
* @methodOf umbraco.services.tinyMceService
*
* @description
* From the given string, generates a string array where each item is the id attribute value from a named anchor
* 'some string <a id="anchor"></a>with a named anchor' returns ['anchor']
*
* @param {string} input the string to parse
*/
getAnchorNames: function (input) {
var anchors = [];
if (!input) {
return anchors;
}
var anchorPattern = /<a id=\\"(.*?)\\">/gi;
var matches = input.match(anchorPattern);
if (matches) {
anchors = matches.map(function (v) {
return v.substring(v.indexOf('"') + 1, v.lastIndexOf('\\'));
});
}
return anchors.filter(function(val, i, self) {
return self.indexOf(val) === i;
});
},
insertLinkInEditor: function (editor, target, anchorElm) {
var href = target.url;
@@ -1,7 +1,7 @@
//used for the media picker dialog
angular.module("umbraco")
.controller("Umbraco.Editors.MediaPickerController",
function($scope, mediaResource, entityResource, mediaHelper, mediaTypeHelper, eventsService, treeService, localStorageService, localizationService, editorService) {
function($scope, mediaResource, entityResource, userService, mediaHelper, mediaTypeHelper, eventsService, treeService, localStorageService, localizationService, editorService) {
if (!$scope.model.title) {
localizationService.localizeMany(["defaultdialogs_selectMedia", "general_includeFromsubFolders"])
@@ -25,6 +25,8 @@ angular.module("umbraco")
$scope.lockedFolder = true;
$scope.allowMediaEdit = dialogOptions.allowMediaEdit ? dialogOptions.allowMediaEdit : false;
var userStartNodes = [];
var umbracoSettings = Umbraco.Sys.ServerVariables.umbracoSettings;
var allowedUploadFiles = mediaHelper.formatFileTypes(umbracoSettings.allowedUploadFiles);
if ($scope.onlyImages) {
@@ -54,7 +56,8 @@ angular.module("umbraco")
pageSize: 100,
totalItems: 0,
totalPages: 0,
filter: ''
filter: '',
dataTypeId: $scope.model.dataTypeId
};
//preload selected item
@@ -64,15 +67,19 @@ angular.module("umbraco")
}
function onInit() {
if ($scope.startNodeId !== -1) {
entityResource.getById($scope.startNodeId, "media")
.then(function (ent) {
$scope.startNodeId = ent.id;
run();
});
} else {
run();
}
userService.getCurrentUser().then(function (userData) {
userStartNodes = userData.startMediaIds;
if ($scope.startNodeId !== -1) {
entityResource.getById($scope.startNodeId, "media")
.then(function (ent) {
$scope.startNodeId = ent.id;
run();
});
} else {
run();
}
});
}
function run() {
@@ -89,7 +96,7 @@ angular.module("umbraco")
//media object so we need to look it up
var id = $scope.target.udi ? $scope.target.udi : $scope.target.id;
var altText = $scope.target.altText;
mediaResource.getById(id)
entityResource.getById(id, "Media")
.then(function (node) {
$scope.target = node;
if (ensureWithinStartNode(node)) {
@@ -153,7 +160,7 @@ angular.module("umbraco")
}
if (folder.id > 0) {
entityResource.getAncestors(folder.id, "media")
entityResource.getAncestors(folder.id, "media", { dataTypeId: $scope.model.dataTypeId })
.then(function(anc) {
$scope.path = _.filter(anc,
function(f) {
@@ -169,7 +176,7 @@ angular.module("umbraco")
$scope.path = [];
}
$scope.lockedFolder = folder.id === -1 && $scope.model.startNodeIsVirtual;
$scope.lockedFolder = (folder.id === -1 && $scope.model.startNodeIsVirtual) || hasFolderAccess(folder) === false;
$scope.currentFolder = folder;
localStorageService.set("umbLastOpenedMediaNodeId", folder.id);
@@ -265,6 +272,17 @@ angular.module("umbraco")
}
}
function hasFolderAccess(node) {
var nodePath = node.path ? node.path.split(',') : [node.id];
for (var i = 0; i < nodePath.length; i++) {
if (userStartNodes.indexOf(parseInt(nodePath[i])) !== -1)
return true;
}
return false;
}
function gotoStartNode(err) {
$scope.gotoFolder({ id: $scope.startNodeId, name: "Media", icon: "icon-folder" });
}
@@ -299,7 +317,8 @@ angular.module("umbraco")
pageSize: 100,
totalItems: 0,
totalPages: 0,
filter: ''
filter: '',
dataTypeId: $scope.model.dataTypeId
};
getChildren($scope.currentFolder.id);
}
@@ -369,10 +388,17 @@ angular.module("umbraco")
function getChildren(id) {
$scope.loading = true;
return mediaResource.getChildren(id)
return entityResource.getChildren(id, "Media", $scope.searchOptions)
.then(function(data) {
for (i=0;i<data.length;i++){
if(data[i].metaData.MediaPath !== null){
data[i].thumbnail = mediaHelper.resolveFileFromEntity(data[i], true);
data[i].image = mediaHelper.resolveFileFromEntity(data[i], false);
}
}
$scope.searchOptions.filter = "";
$scope.images = data.items ? data.items : [];
$scope.images = data ? data : [];
// set already selected images to selected
preSelectImages();
$scope.loading = false;
@@ -80,6 +80,7 @@ function contentPickerController($scope, entityResource, editorState, iconHelper
showOpenButton: false,
showEditButton: false,
showPathOnHover: false,
dataTypeId: null,
maxNumber: 1,
minNumber: 0,
startNode: {
@@ -150,7 +151,7 @@ function contentPickerController($scope, entityResource, editorState, iconHelper
idType: "udi"
};
//since most of the pre-value config's are used in the dialog options (i.e. maxNumber, minNumber, etc...) we'll merge the
//since most of the pre-value config's are used in the dialog options (i.e. maxNumber, minNumber, etc...) we'll merge the
// pre-value config on to the dialog options
angular.extend(dialogOptions, $scope.model.config);
@@ -181,7 +182,7 @@ function contentPickerController($scope, entityResource, editorState, iconHelper
if (!currFilter) {
return false;
}
//now we need to filter based on what is stored in the pre-vals, this logic duplicates what is in the treepicker.controller,
//now we need to filter based on what is stored in the pre-vals, this logic duplicates what is in the treepicker.controller,
// but not much we can do about that since members require special filtering.
var filterItem = currFilter.toLowerCase().split(',');
var found = filterItem.indexOf(i.metaData.contentType.toLowerCase()) >= 0;
@@ -210,6 +211,7 @@ function contentPickerController($scope, entityResource, editorState, iconHelper
//dialog
$scope.openCurrentPicker = function () {
$scope.currentPicker = dialogOptions;
$scope.contentPickerOverlay.dataTypeId = $scope.model.dataTypeId;
$scope.currentPicker.submit = function (model) {
if (angular.isArray(model.selection)) {
@@ -401,7 +403,7 @@ function contentPickerController($scope, entityResource, editorState, iconHelper
// get url for content and media items
if (entityType !== "Member") {
entityResource.getUrl(entity.id, entityType).then(function (data) {
// update url
// update url
angular.forEach($scope.renderModel, function (item) {
if (item.id === entity.id) {
if (entity.trashed) {
@@ -447,7 +449,7 @@ function contentPickerController($scope, entityResource, editorState, iconHelper
"url": item.url,
"trashed": item.trashed,
"published": (item.metaData && item.metaData.IsPublished === false && entityType === "Document") ? false : true
// only content supports published/unpublished content so we set everything else to published so the UI looks correct
// only content supports published/unpublished content so we set everything else to published so the UI looks correct
});
setEntityUrl(item);
@@ -7,15 +7,22 @@ angular.module("umbraco")
if (!$scope.model.config.startNodeId) {
userService.getCurrentUser().then(function (userData) {
$scope.model.config.startNodeId = userData.startMediaIds.length !== 1 ? -1 : userData.startMediaIds[0];
$scope.model.config.startNodeIsVirtual = userData.startMediaIds.length !== 1;
});
if ($scope.model.config.ignoreUserStartNodes === "1" ) {
$scope.model.config.startNodeId = -1;
$scope.model.config.startNodeIsVirtual = true;
} else {
userService.getCurrentUser().then(function (userData) {
$scope.model.config.startNodeId = userData.startMediaIds.length !== 1 ? -1 : userData.startMediaIds[0];
$scope.model.config.startNodeIsVirtual = userData.startMediaIds.length !== 1;
});
}
}
$scope.setImage = function(){
var startNodeId = $scope.model.config && $scope.model.config.startNodeId ? $scope.model.config.startNodeId : undefined;
var startNodeIsVirtual = startNodeId ? $scope.model.config.startNodeIsVirtual : undefined;
$scope.mediaPickerOverlay.dataTypeId = $scope.model.dataTypeId;
var mediaPicker = {
startNodeId: startNodeId,
@@ -71,6 +71,8 @@ function multiUrlPickerController($scope, angularHelper, localizationService, en
var linkPicker = {
currentTarget: target,
dataTypeId: $scope.model.dataTypeId,
ignoreUserStartNodes : $scope.model.config.ignoreUserStartNodes,
submit: function (model) {
if (model.target.url || model.target.anchor) {
// if an anchor exists, check that it is appropriately prefixed
@@ -47,4 +47,5 @@
</select>
</div>
</umb-control-group>
</div>
+163 -41
View File
@@ -36,7 +36,12 @@ namespace Umbraco.Web.Editors
/// The API controller used for getting entity objects, basic name, icon, id representation of umbraco objects that are based on CMSNode
/// </summary>
/// <remarks>
/// Some objects such as macros are not based on CMSNode
/// <para>
/// This controller allows resolving basic entity data for various entities without placing the hard restrictions on users that may not have access
/// to the sections these entities entities exist in. This is to allow pickers, etc... of data to work for all users. In some cases such as accessing
/// Members, more explicit security checks are done.
/// </para>
/// <para>Some objects such as macros are not based on CMSNode</para>
/// </remarks>
[EntityControllerConfiguration]
[PluginController("UmbracoApi")]
@@ -98,19 +103,20 @@ namespace Umbraco.Web.Editors
/// <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="dataTypeId">If set used to look up whether user and group start node permissions will be ignored.</param>
/// <returns></returns>
[HttpGet]
public IEnumerable<EntityBasic> Search(string query, UmbracoEntityTypes type, string searchFrom = null)
public IEnumerable<EntityBasic> Search(string query, UmbracoEntityTypes type, string searchFrom = null, Guid? dataTypeId = null)
{
// TODO: Should we restrict search results based on what app the user has access to?
// - Theoretically you shouldn't be able to see member data if you don't have access to members right?
// NOTE: Theoretically you shouldn't be able to see member data if you don't have access to members right? ... but there is a member picker, so can't really do that
if (string.IsNullOrEmpty(query))
return Enumerable.Empty<EntityBasic>();
//TODO: This uses the internal UmbracoTreeSearcher, this instead should delgate to the ISearchableTree implementation for the type
return ExamineSearch(query, type, searchFrom);
var ignoreUserStartNodes = dataTypeId.HasValue && Services.DataTypeService.IsDataTypeIgnoringUserStartNodes(dataTypeId.Value);
return ExamineSearch(query, type, searchFrom, ignoreUserStartNodes);
}
/// <summary>
@@ -204,6 +210,9 @@ namespace Umbraco.Web.Editors
/// <param name="id">Int id of the entity to fetch URL for</param>
/// <param name="type">The type of entity such as Document, Media, Member</param>
/// <returns>The URL or path to the item</returns>
/// <remarks>
/// We are not restricting this with security because there is no sensitive data
/// </remarks>
public HttpResponseMessage GetUrl(int id, UmbracoEntityTypes type)
{
var returnUrl = string.Empty;
@@ -277,6 +286,29 @@ namespace Umbraco.Web.Editors
publishedContentExists: i => Umbraco.Content(i) != null);
}
[HttpGet]
public UrlAndAnchors GetUrlAndAnchors([FromUri]int id)
{
var url = Umbraco.Url(id);
var anchorValues = Services.ContentService.GetAnchorValuesFromRTEs(id);
return new UrlAndAnchors(url, anchorValues);
}
public class AnchorsModel
{
public string RteContent { get; set; }
}
[HttpGet]
[HttpPost]
public IEnumerable<string> GetAnchors(AnchorsModel model)
{
var anchorValues = Services.ContentService.GetAnchorValuesFromRTEContent(model.RteContent);
return anchorValues;
}
#region GetById
/// <summary>
@@ -397,9 +429,52 @@ namespace Umbraco.Web.Editors
}
#endregion
public IEnumerable<EntityBasic> GetChildren(int id, UmbracoEntityTypes type)
public IEnumerable<EntityBasic> GetChildren(int id, UmbracoEntityTypes type, Guid? dataTypeId = null)
{
return GetResultForChildren(id, type);
var objectType = ConvertToObjectType(type);
if (objectType.HasValue)
{
//TODO: Need to check for Object types that support hierarchy here, some might not.
int[] startNodes = null;
switch (type)
{
case UmbracoEntityTypes.Document:
startNodes = Security.CurrentUser.CalculateContentStartNodeIds(Services.EntityService);
break;
case UmbracoEntityTypes.Media:
startNodes = Security.CurrentUser.CalculateMediaStartNodeIds(Services.EntityService);
break;
}
var ignoreUserStartNodes = IsDataTypeIgnoringUserStartNodes(dataTypeId);
// root is special: we reduce it to start nodes if the user's start node is not the default, then we need to return their start nodes
if (id == Constants.System.Root && startNodes.Length > 0 && startNodes.Contains(Constants.System.Root) == false && !ignoreUserStartNodes)
{
var nodes = Services.EntityService.GetAll(objectType.Value, startNodes).ToArray();
if (nodes.Length == 0)
return Enumerable.Empty<EntityBasic>();
var pr = new List<EntityBasic>(nodes.Select(Mapper.Map<EntityBasic>));
return pr;
}
// else proceed as usual
return Services.EntityService.GetChildren(id, objectType.Value)
.WhereNotNull()
.Select(Mapper.Map<EntityBasic>);
}
//now we need to convert the unknown ones
switch (type)
{
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);
}
}
/// <summary>
@@ -420,7 +495,8 @@ namespace Umbraco.Web.Editors
int pageSize,
string orderBy = "SortOrder",
Direction orderDirection = Direction.Ascending,
string filter = "")
string filter = "",
Guid? dataTypeId = null)
{
if (int.TryParse(id, out var intId))
{
@@ -445,7 +521,7 @@ namespace Umbraco.Web.Editors
//the EntityService can search paged members from the root
intId = -1;
return GetPagedChildren(intId, type, pageNumber, pageSize, orderBy, orderDirection, filter);
return GetPagedChildren(intId, type, pageNumber, pageSize, orderBy, orderDirection, filter, dataTypeId);
}
//the EntityService cannot search members of a certain type, this is currently not supported and would require
@@ -480,7 +556,8 @@ namespace Umbraco.Web.Editors
int pageSize,
string orderBy = "SortOrder",
Direction orderDirection = Direction.Ascending,
string filter = "")
string filter = "",
Guid? dataTypeId = null)
{
if (pageNumber <= 0)
throw new HttpResponseException(HttpStatusCode.NotFound);
@@ -490,12 +567,47 @@ namespace Umbraco.Web.Editors
var objectType = ConvertToObjectType(type);
if (objectType.HasValue)
{
var entities = Services.EntityService.GetPagedChildren(id, objectType.Value, pageNumber - 1, pageSize, out var totalRecords,
IEnumerable<IUmbracoEntity> entities;
long totalRecords;
int[] startNodes = null;
switch (type)
{
case UmbracoEntityTypes.Document:
startNodes = Security.CurrentUser.CalculateContentStartNodeIds(Services.EntityService);
break;
case UmbracoEntityTypes.Media:
startNodes = Security.CurrentUser.CalculateMediaStartNodeIds(Services.EntityService);
break;
}
var ignoreUserStartNodes = IsDataTypeIgnoringUserStartNodes(dataTypeId);
// root is special: we reduce it to start nodes if the user's start node is not the default, then we need to return their start nodes
if (id == Constants.System.Root && startNodes.Length > 0 && startNodes.Contains(Constants.System.Root) == false && !ignoreUserStartNodes)
{
if (pageNumber > 0)
return new PagedResult<EntityBasic>(0, 0, 0);
var nodes = Services.EntityService.GetAll(objectType.Value, startNodes).ToArray();
if (nodes.Length == 0)
return new PagedResult<EntityBasic>(0, 0, 0);
if (pageSize < nodes.Length) pageSize = nodes.Length; // bah
var pr = new PagedResult<EntityBasic>(nodes.Length, pageNumber, pageSize)
{
Items = nodes.Select(Mapper.Map<EntityBasic>)
};
return pr;
}
// else proceed as usual
//entities = Services.EntityService.GetPagedChildren(id, objectType.Value, pageNumber - 1, pageSize, out totalRecords, orderBy, orderDirection, filter);
entities = Services.EntityService.GetPagedChildren(id, objectType.Value, pageNumber - 1, pageSize, out var totalRecords,
filter.IsNullOrWhiteSpace()
? null
: SqlContext.Query<IUmbracoEntity>().Where(x => x.Name.Contains(filter)),
Ordering.By(orderBy, orderDirection));
if (totalRecords == 0)
{
return new PagedResult<EntityBasic>(0, 0, 0);
@@ -532,6 +644,7 @@ namespace Umbraco.Web.Editors
}
}
public PagedResult<EntityBasic> GetPagedDescendants(
int id,
UmbracoEntityTypes type,
@@ -539,7 +652,8 @@ namespace Umbraco.Web.Editors
int pageSize,
string orderBy = "SortOrder",
Direction orderDirection = Direction.Ascending,
string filter = "")
string filter = "",
Guid? dataTypeId = null)
{
if (pageNumber <= 0)
throw new HttpResponseException(HttpStatusCode.NotFound);
@@ -567,7 +681,8 @@ namespace Umbraco.Web.Editors
break;
}
entities = aids == null || aids.Contains(Constants.System.Root)
var ignoreUserStartNodes = IsDataTypeIgnoringUserStartNodes(dataTypeId);
entities = aids == null || aids.Contains(Constants.System.Root) || ignoreUserStartNodes
? Services.EntityService.GetPagedDescendants(objectType.Value, pageNumber - 1, pageSize, out totalRecords,
SqlContext.Query<IUmbracoEntity>().Where(x => x.Name.Contains(filter)),
Ordering.By(orderBy, orderDirection), includeTrashed: false)
@@ -609,6 +724,8 @@ namespace Umbraco.Web.Editors
}
}
private bool IsDataTypeIgnoringUserStartNodes(Guid? dataTypeId) => dataTypeId.HasValue && Services.DataTypeService.IsDataTypeIgnoringUserStartNodes(dataTypeId.Value);
public IEnumerable<EntityBasic> GetAncestors(int id, UmbracoEntityTypes type, [ModelBinder(typeof(HttpQueryStringModelBinder))]FormDataCollection queryStrings)
{
return GetResultForAncestors(id, type, queryStrings);
@@ -620,10 +737,11 @@ namespace Umbraco.Web.Editors
/// <param name="query"></param>
/// <param name="entityType"></param>
/// <param name="searchFrom"></param>
/// <param name="ignoreUserStartNodes">If set to true, user and group start node permissions will be ignored.</param>
/// <returns></returns>
private IEnumerable<SearchResultEntity> ExamineSearch(string query, UmbracoEntityTypes entityType, string searchFrom = null)
private IEnumerable<SearchResultEntity> ExamineSearch(string query, UmbracoEntityTypes entityType, string searchFrom = null, bool ignoreUserStartNodes = false)
{
return _treeSearcher.ExamineSearch(query, entityType, 200, 0, out _, searchFrom);
return _treeSearcher.ExamineSearch(query, entityType, 200, 0, out _, searchFrom, ignoreUserStartNodes);
}
private IEnumerable<EntityBasic> GetResultForChildren(int id, UmbracoEntityTypes entityType)
@@ -658,35 +776,39 @@ namespace Umbraco.Web.Editors
var ids = Services.EntityService.Get(id).Path.Split(',').Select(int.Parse).Distinct().ToArray();
int[] aids = null;
switch (entityType)
var ignoreUserStartNodes = IsDataTypeIgnoringUserStartNodes(dataTypeId);
if (ignoreUserStartNodes == false)
{
case UmbracoEntityTypes.Document:
aids = Security.CurrentUser.CalculateContentStartNodeIds(Services.EntityService);
break;
case UmbracoEntityTypes.Media:
aids = Security.CurrentUser.CalculateMediaStartNodeIds(Services.EntityService);
break;
}
if (aids != null)
{
var lids = new List<int>();
var ok = false;
foreach (var i in ids)
int[] aids = null;
switch (entityType)
{
if (ok)
{
lids.Add(i);
continue;
}
if (aids.Contains(i))
{
lids.Add(i);
ok = true;
}
case UmbracoEntityTypes.Document:
aids = Security.CurrentUser.CalculateContentStartNodeIds(Services.EntityService);
break;
case UmbracoEntityTypes.Media:
aids = Security.CurrentUser.CalculateMediaStartNodeIds(Services.EntityService);
break;
}
if (aids != null)
{
var lids = new List<int>();
var ok = false;
foreach (var i in ids)
{
if (ok)
{
lids.Add(i);
continue;
}
if (aids.Contains(i))
{
lids.Add(i);
ok = true;
}
}
ids = lids.ToArray();
}
ids = lids.ToArray();
}
var culture = queryStrings?.GetValue<string>("culture");
@@ -230,8 +230,10 @@ namespace Umbraco.Web
//that each token is unique to the controller/action/area instead of the default ASP.Net implementation which is that the token is unique
//per user.
_viewContext.HttpContext.Items["ufprt"] = _encryptedString;
}
private readonly ViewContext _viewContext;
private readonly FormMethod _method;
private bool _disposed;
@@ -243,7 +245,6 @@ namespace Umbraco.Web
if (this._disposed)
return;
this._disposed = true;
//Detect if the call is targeting UmbRegisterController/UmbProfileController/UmbLoginStatusController/UmbLoginController and if it is we automatically output a AntiForgeryToken()
// We have a controllerName and area so we can match
if (_controllerName == "UmbRegister"
@@ -251,7 +252,7 @@ namespace Umbraco.Web
|| _controllerName == "UmbLoginStatus"
|| _controllerName == "UmbLogin")
{
_viewContext.Writer.Write(AntiForgery.GetHtml().ToString());
_viewContext.Writer.Write(AntiForgery.GetHtml().ToString());
}
//write out the hidden surface form routes
@@ -1,4 +1,5 @@
using System.ComponentModel;
using System;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Runtime.Serialization;
using Umbraco.Core.PropertyEditors;
@@ -21,6 +22,9 @@ namespace Umbraco.Web.Models.ContentEditing
[Required]
public int Id { get; set; }
[DataMember(Name = "dataTypeId", IsRequired = false)]
public Guid? DataTypeId { get; set; }
[DataMember(Name = "value")]
public object Value { get; set; }
@@ -155,6 +155,8 @@ namespace Umbraco.Web.Mvc
};
}
/// <summary>
/// Handles a posted form to an Umbraco Url and ensures the correct controller is routed to and that
/// the right DataTokens are set.
@@ -49,6 +49,7 @@ namespace Umbraco.Web.Search
/// </param>
/// <param name="pageSize"></param>
/// <param name="pageIndex"></param>
/// <param name="ignoreUserStartNodes">If set to true, user and group start node permissions will be ignored.</param>
/// <returns></returns>
public IEnumerable<SearchResultEntity> ExamineSearch(
string query,
@@ -85,12 +86,12 @@ namespace Umbraco.Web.Search
case UmbracoEntityTypes.Media:
type = "media";
var allMediaStartNodes = _umbracoContext.Security.CurrentUser.CalculateMediaStartNodeIds(_entityService);
AppendPath(sb, UmbracoObjectTypes.Media, allMediaStartNodes, searchFrom, _entityService);
AppendPath(sb, UmbracoObjectTypes.Media, allMediaStartNodes, searchFrom, ignoreUserStartNodes, _entityService);
break;
case UmbracoEntityTypes.Document:
type = "content";
var allContentStartNodes = _umbracoContext.Security.CurrentUser.CalculateContentStartNodeIds(_entityService);
AppendPath(sb, UmbracoObjectTypes.Document, allContentStartNodes, searchFrom, _entityService);
AppendPath(sb, UmbracoObjectTypes.Document, allContentStartNodes, searchFrom, ignoreUserStartNodes, _entityService);
break;
default:
throw new NotSupportedException("The " + typeof(UmbracoTreeSearcher) + " currently does not support searching against object type " + entityType);
@@ -288,7 +289,7 @@ namespace Umbraco.Web.Search
}
}
private void AppendPath(StringBuilder sb, UmbracoObjectTypes objectType, int[] startNodeIds, string searchFrom, IEntityService entityService)
private void AppendPath(StringBuilder sb, UmbracoObjectTypes objectType, int[] startNodeIds, string searchFrom, bool ignoreUserStartNodes, IEntityService entityService)
{
if (sb == null) throw new ArgumentNullException(nameof(sb));
if (entityService == null) throw new ArgumentNullException(nameof(entityService));
@@ -311,7 +312,7 @@ namespace Umbraco.Web.Search
// make sure we don't find anything
sb.Append("+__Path:none ");
}
else if (startNodeIds.Contains(-1) == false) // -1 = no restriction
else if (startNodeIds.Contains(-1) == false && ignoreUserStartNodes == false) // -1 = no restriction
{
var entityPaths = entityService.GetAllPaths(objectType, startNodeIds);
@@ -217,7 +217,6 @@ namespace Umbraco.Web.Trees
return result;
}
/// <summary>
/// Returns a collection of all menu items that can be on a content node
/// </summary>
@@ -69,7 +69,7 @@ namespace Umbraco.Web.Trees
{
var node = base.CreateRootNode(queryStrings);
if (IsDialog(queryStrings) && UserStartNodes.Contains(Constants.System.Root) == false)
if (IsDialog(queryStrings) && UserStartNodes.Contains(Constants.System.Root) == false && IgnoreUserStartNodes(queryStrings) == false)
{
node.AdditionalData["noAccess"] = true;
}
@@ -87,7 +87,8 @@ namespace Umbraco.Web.Trees
/// <param name="parentId"></param>
/// <param name="queryStrings"></param>
/// <returns></returns>
internal TreeNode GetSingleTreeNodeWithAccessCheck(IEntitySlim e, string parentId, FormDataCollection queryStrings)
internal TreeNode GetSingleTreeNodeWithAccessCheck(IEntitySlim e, string parentId, FormDataCollection queryStrings,
int[] startNodeIds, string[] startNodePaths, bool ignoreUserStartNodes)
{
var entityIsAncestorOfStartNodes = Security.CurrentUser.IsInBranchOfStartNode(e, Services.EntityService, RecycleBinId, out var hasPathAccess);
if (entityIsAncestorOfStartNodes == false)
@@ -101,6 +102,23 @@ namespace Umbraco.Web.Trees
return treeNode;
}
private void GetUserStartNodes(out int[] startNodeIds, out string[] startNodePaths)
{
switch (RecycleBinId)
{
case Constants.System.RecycleBinMedia:
startNodeIds = Security.CurrentUser.CalculateMediaStartNodeIds(Services.EntityService);
startNodePaths = Security.CurrentUser.GetMediaStartNodePaths(Services.EntityService);
break;
case Constants.System.RecycleBinContent:
startNodeIds = Security.CurrentUser.CalculateContentStartNodeIds(Services.EntityService);
startNodePaths = Security.CurrentUser.GetContentStartNodePaths(Services.EntityService);
break;
default:
throw new NotSupportedException("Path access is only determined on content or media");
}
}
/// <summary>
/// Returns the
/// </summary>
@@ -127,6 +145,8 @@ namespace Umbraco.Web.Trees
? queryStrings.GetValue<string>(TreeQueryStringParameters.StartNodeId)
: string.Empty;
var ignoreUserStartNodes = IgnoreUserStartNodes(queryStrings);
if (string.IsNullOrEmpty(startNodeId) == false && startNodeId != "undefined" && startNodeId != rootIdString)
{
// request has been made to render from a specific, non-root, start node
@@ -134,7 +154,7 @@ namespace Umbraco.Web.Trees
// ensure that the user has access to that node, otherwise return the empty tree nodes collection
// TODO: in the future we could return a validation statement so we can have some UI to notify the user they don't have access
if (HasPathAccess(id, queryStrings) == false)
if (ignoreUserStartNodes == false && HasPathAccess(id, queryStrings) == false)
{
Logger.Warn<ContentTreeControllerBase>("User {Username} does not have access to node with id {Id}", Security.CurrentUser.Username, id);
return nodes;
@@ -152,7 +172,11 @@ namespace Umbraco.Web.Trees
// get child entities - if id is root, but user's start nodes do not contain the
// root node, this returns the start nodes instead of root's children
var entities = GetChildEntities(id, queryStrings).ToList();
nodes.AddRange(entities.Select(x => GetSingleTreeNodeWithAccessCheck(x, id, queryStrings)).Where(x => x != null));
//get the current user start node/paths
GetUserStartNodes(out var userStartNodes, out var userStartNodePaths);
nodes.AddRange(entities.Select(x => GetSingleTreeNodeWithAccessCheck(x, id, queryStrings, userStartNodes, userStartNodePaths, ignoreUserStartNodes)).Where(x => x != null));
// if the user does not have access to the root node, what we have is the start nodes,
// but to provide some context we also need to add their topmost nodes when they are not
@@ -163,7 +187,7 @@ namespace Umbraco.Web.Trees
if (topNodeIds.Length > 0)
{
var topNodes = Services.EntityService.GetAll(UmbracoObjectType, topNodeIds.ToArray());
nodes.AddRange(topNodes.Select(x => GetSingleTreeNodeWithAccessCheck(x, id, queryStrings)).Where(x => x != null));
nodes.AddRange(topNodes.Select(x => GetSingleTreeNodeWithAccessCheck(x, id, queryStrings, userStartNodes, userStartNodePaths, ignoreUserStartNodes)).Where(x => x != null));
}
}
@@ -504,5 +528,21 @@ namespace Umbraco.Web.Trees
}
private readonly ConcurrentDictionary<string, IEntitySlim> _entityCache = new ConcurrentDictionary<string, IEntitySlim>();
/// <summary>
/// If the request should allows a user to choose nodes that they normally don't have access to
/// </summary>
/// <param name="queryStrings"></param>
/// <returns></returns>
internal bool IgnoreUserStartNodes(FormDataCollection queryStrings)
{
var dataTypeId = queryStrings.GetValue<Guid?>(TreeQueryStringParameters.DataTypeId);
if (dataTypeId.HasValue)
{
return Services.DataTypeService.IsDataTypeIgnoringUserStartNodes(dataTypeId.Value);
}
return false;
}
}
}
+1 -1
View File
@@ -166,6 +166,6 @@ namespace Umbraco.Web.Trees
{
return _treeSearcher.ExamineSearch(query, UmbracoEntityTypes.Media, pageSize, pageIndex, out totalFound, searchFrom);
}
}
}
@@ -15,6 +15,7 @@ using Umbraco.Core.Services;
using Umbraco.Web.Models.Trees;
using Umbraco.Web.WebApi;
using Umbraco.Web.WebApi.Filters;
using Umbraco.Core.Services;
namespace Umbraco.Web.Trees
{
@@ -8,6 +8,7 @@
public const string Use = "use";
public const string Application = "application";
public const string StartNodeId = "startNodeId";
public const string DataTypeId = "dataTypeId";
//public const string OnNodeClick = "OnNodeClick";
//public const string RenderParent = "RenderParent";
}
+1
View File
@@ -5,6 +5,7 @@ using System.Web;
using System.Xml.XPath;
using Umbraco.Core;
using Umbraco.Core.Dictionary;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.Xml;