Merge branch 'dev-v7' into temp-U4-5963
Conflicts: src/Umbraco.Web.UI.Client/src/controllers/main.controller.js
This commit is contained in:
@@ -36,7 +36,7 @@ namespace Umbraco.Core.Configuration
|
||||
//make this volatile so that we can ensure thread safety with a double check lock
|
||||
private static volatile string _reservedUrlsCache;
|
||||
private static string _reservedPathsCache;
|
||||
private static StartsWithContainer _reservedList = new StartsWithContainer();
|
||||
private static HashSet<string> _reservedList = new HashSet<string>();
|
||||
private static string _reservedPaths;
|
||||
private static string _reservedUrls;
|
||||
//ensure the built on (non-changeable) reserved paths are there at all times
|
||||
@@ -768,37 +768,30 @@ namespace Umbraco.Core.Configuration
|
||||
_reservedPathsCache = GlobalSettings.ReservedPaths;
|
||||
_reservedUrlsCache = GlobalSettings.ReservedUrls;
|
||||
|
||||
string _root = SystemDirectories.Root.Trim().ToLower();
|
||||
|
||||
// add URLs and paths to a new list
|
||||
StartsWithContainer _newReservedList = new StartsWithContainer();
|
||||
foreach (string reservedUrl in _reservedUrlsCache.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries))
|
||||
var newReservedList = new HashSet<string>();
|
||||
foreach (var reservedUrlTrimmed in _reservedUrlsCache
|
||||
.Split(new[] {","}, StringSplitOptions.RemoveEmptyEntries)
|
||||
.Select(x => x.Trim().ToLowerInvariant())
|
||||
.Where(x => x.IsNullOrWhiteSpace() == false)
|
||||
.Select(reservedUrl => IOHelper.ResolveUrl(reservedUrl).Trim().EnsureStartsWith("/"))
|
||||
.Where(reservedUrlTrimmed => reservedUrlTrimmed.IsNullOrWhiteSpace() == false))
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(reservedUrl))
|
||||
continue;
|
||||
|
||||
|
||||
//resolves the url to support tilde chars
|
||||
string reservedUrlTrimmed = IOHelper.ResolveUrl(reservedUrl.Trim()).Trim().ToLower();
|
||||
if (reservedUrlTrimmed.Length > 0)
|
||||
_newReservedList.Add(reservedUrlTrimmed);
|
||||
newReservedList.Add(reservedUrlTrimmed);
|
||||
}
|
||||
|
||||
foreach (string reservedPath in _reservedPathsCache.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries))
|
||||
foreach (var reservedPathTrimmed in _reservedPathsCache
|
||||
.Split(new[] {","}, StringSplitOptions.RemoveEmptyEntries)
|
||||
.Select(x => x.Trim().ToLowerInvariant())
|
||||
.Where(x => x.IsNullOrWhiteSpace() == false)
|
||||
.Select(reservedPath => IOHelper.ResolveUrl(reservedPath).Trim().EnsureStartsWith("/").EnsureEndsWith("/"))
|
||||
.Where(reservedPathTrimmed => reservedPathTrimmed.IsNullOrWhiteSpace() == false))
|
||||
{
|
||||
bool trimEnd = !reservedPath.EndsWith("/");
|
||||
if (string.IsNullOrWhiteSpace(reservedPath))
|
||||
continue;
|
||||
|
||||
//resolves the url to support tilde chars
|
||||
string reservedPathTrimmed = IOHelper.ResolveUrl(reservedPath.Trim()).Trim().ToLower();
|
||||
|
||||
if (reservedPathTrimmed.Length > 0)
|
||||
_newReservedList.Add(reservedPathTrimmed + (reservedPathTrimmed.EndsWith("/") ? "" : "/"));
|
||||
newReservedList.Add(reservedPathTrimmed);
|
||||
}
|
||||
|
||||
// use the new list from now on
|
||||
_reservedList = _newReservedList;
|
||||
_reservedList = newReservedList;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -806,107 +799,17 @@ namespace Umbraco.Core.Configuration
|
||||
//The url should be cleaned up before checking:
|
||||
// * If it doesn't contain an '.' in the path then we assume it is a path based URL, if that is the case we should add an trailing '/' because all of our reservedPaths use a trailing '/'
|
||||
// * We shouldn't be comparing the query at all
|
||||
var pathPart = url.Split('?')[0];
|
||||
if (!pathPart.Contains(".") && !pathPart.EndsWith("/"))
|
||||
var pathPart = url.Split(new[] {'?'}, StringSplitOptions.RemoveEmptyEntries)[0].ToLowerInvariant();
|
||||
if (pathPart.Contains(".") == false)
|
||||
{
|
||||
pathPart += "/";
|
||||
pathPart = pathPart.EnsureEndsWith('/');
|
||||
}
|
||||
|
||||
// return true if url starts with an element of the reserved list
|
||||
return _reservedList.StartsWith(pathPart.ToLowerInvariant());
|
||||
return _reservedList.Any(x => pathPart.InvariantStartsWith(x));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Structure that checks in logarithmic time
|
||||
/// if a given string starts with one of the added keys.
|
||||
/// </summary>
|
||||
private class StartsWithContainer
|
||||
{
|
||||
/// <summary>Internal sorted list of keys.</summary>
|
||||
public SortedList<string, string> _list
|
||||
= new SortedList<string, string>(StartsWithComparator.Instance);
|
||||
|
||||
/// <summary>
|
||||
/// Adds the specified new key.
|
||||
/// </summary>
|
||||
/// <param name="newKey">The new key.</param>
|
||||
public void Add(string newKey)
|
||||
{
|
||||
// if the list already contains an element that begins with newKey, return
|
||||
if (String.IsNullOrEmpty(newKey) || StartsWith(newKey))
|
||||
return;
|
||||
|
||||
// create a new collection, so the old one can still be accessed
|
||||
SortedList<string, string> newList
|
||||
= new SortedList<string, string>(_list.Count + 1, StartsWithComparator.Instance);
|
||||
|
||||
// add only keys that don't already start with newKey, others are unnecessary
|
||||
foreach (string key in _list.Keys)
|
||||
if (!key.StartsWith(newKey))
|
||||
newList.Add(key, null);
|
||||
// add the new key
|
||||
newList.Add(newKey, null);
|
||||
|
||||
// update the list (thread safe, _list was never in incomplete state)
|
||||
_list = newList;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the given string starts with any of the added keys.
|
||||
/// </summary>
|
||||
/// <param name="target">The target.</param>
|
||||
/// <returns>true if a key is found that matches the start of target</returns>
|
||||
/// <remarks>
|
||||
/// Runs in O(s*log(n)), with n the number of keys and s the length of target.
|
||||
/// </remarks>
|
||||
public bool StartsWith(string target)
|
||||
{
|
||||
return _list.ContainsKey(target);
|
||||
}
|
||||
|
||||
/// <summary>Comparator that tests if a string starts with another.</summary>
|
||||
/// <remarks>Not a real comparator, since it is not reflexive. (x==y does not imply y==x)</remarks>
|
||||
private sealed class StartsWithComparator : IComparer<string>
|
||||
{
|
||||
/// <summary>Default string comparer.</summary>
|
||||
private readonly static Comparer<string> _stringComparer = Comparer<string>.Default;
|
||||
|
||||
/// <summary>Gets an instance of the StartsWithComparator.</summary>
|
||||
public static readonly StartsWithComparator Instance = new StartsWithComparator();
|
||||
|
||||
/// <summary>
|
||||
/// Tests if whole begins with all characters of part.
|
||||
/// </summary>
|
||||
/// <param name="part">The part.</param>
|
||||
/// <param name="whole">The whole.</param>
|
||||
/// <returns>
|
||||
/// Returns 0 if whole starts with part, otherwise performs standard string comparison.
|
||||
/// </returns>
|
||||
public int Compare(string part, string whole)
|
||||
{
|
||||
// let the default string comparer deal with null or when part is not smaller then whole
|
||||
if (part == null || whole == null || part.Length >= whole.Length)
|
||||
return _stringComparer.Compare(part, whole);
|
||||
|
||||
////ensure both have a / on the end
|
||||
//part = part.EndsWith("/") ? part : part + "/";
|
||||
//whole = whole.EndsWith("/") ? whole : whole + "/";
|
||||
//if (part.Length >= whole.Length)
|
||||
// return _stringComparer.Compare(part, whole);
|
||||
|
||||
// loop through all characters that part and whole have in common
|
||||
int pos = 0;
|
||||
bool match;
|
||||
do
|
||||
{
|
||||
match = (part[pos] == whole[pos]);
|
||||
} while (match && ++pos < part.Length);
|
||||
|
||||
// return result of last comparison
|
||||
return match ? 0 : (part[pos] < whole[pos] ? -1 : 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models.Rdbms;
|
||||
using Umbraco.Core.Persistence.SqlSyntax;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenThreeOne
|
||||
{
|
||||
/// <summary>
|
||||
/// This fixes the storage of user languages from the old format like en_us to en-US
|
||||
/// </summary>
|
||||
[Migration("7.3.1", 0, GlobalSettings.UmbracoMigrationName)]
|
||||
public class UpdateUserLanguagesToIsoCode : MigrationBase
|
||||
{
|
||||
public UpdateUserLanguagesToIsoCode(ISqlSyntaxProvider sqlSyntax, ILogger logger) : base(sqlSyntax, logger)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Up()
|
||||
{
|
||||
var userData = Context.Database.Fetch<UserDto>(new Sql().Select("*").From<UserDto>(SqlSyntax));
|
||||
foreach (var user in userData.Where(x => x.UserLanguage.Contains("_")))
|
||||
{
|
||||
var languageParts = user.UserLanguage.Split('_');
|
||||
if (languageParts.Length == 2)
|
||||
{
|
||||
Update.Table("umbracoUser")
|
||||
.Set(new {userLanguage = languageParts[0] + "-" + languageParts[1].ToUpperInvariant()})
|
||||
.Where(new {id = user.Id});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void Down()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ using System;
|
||||
|
||||
namespace Umbraco.Core.PropertyEditors
|
||||
{
|
||||
/// <summary>
|
||||
/// Maps a property source value to a data object.
|
||||
/// </summary>
|
||||
// todo: drop IPropertyEditorValueConverter support (when?).
|
||||
|
||||
@@ -187,7 +187,13 @@ namespace Umbraco.Core.Sync
|
||||
using (_profilingLogger.DebugDuration<DatabaseServerMessenger>("Syncing from database..."))
|
||||
{
|
||||
ProcessDatabaseInstructions();
|
||||
switch (_appContext.GetCurrentServerRole())
|
||||
{
|
||||
case ServerRole.Single:
|
||||
case ServerRole.Master:
|
||||
PruneOldInstructions();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
|
||||
@@ -15,7 +15,12 @@ namespace Umbraco.Core.Sync
|
||||
// but at the moment it is exposed in CacheRefresher webservice
|
||||
// so for the time being we keep it as-is for backward compatibility reasons
|
||||
|
||||
// need the public one so it can be de-serialized
|
||||
// need this public, parameter-less constructor so the web service messenger
|
||||
// can de-serialize the instructions it receives
|
||||
public RefreshInstruction()
|
||||
{ }
|
||||
|
||||
// need this public one so it can be de-serialized - used by the Json thing
|
||||
// otherwise, should use GetInstructions(...)
|
||||
public RefreshInstruction(Guid refresherId, RefreshMethodType refreshType, Guid guidId, int intId, string jsonIds, string jsonPayload)
|
||||
{
|
||||
|
||||
@@ -435,6 +435,7 @@
|
||||
<Compile Include="Media\Exif\TIFFHeader.cs" />
|
||||
<Compile Include="Media\Exif\TIFFStrip.cs" />
|
||||
<Compile Include="Media\Exif\Utility.cs" />
|
||||
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenThreeOne\UpdateUserLanguagesToIsoCode.cs" />
|
||||
<Compile Include="Persistence\RecordPersistenceType.cs" />
|
||||
<Compile Include="Persistence\Relators\AccessRulesRelator.cs" />
|
||||
<Compile Include="Persistence\Repositories\AuditRepository.cs" />
|
||||
|
||||
@@ -1163,6 +1163,36 @@ namespace Umbraco.Tests.Services
|
||||
Assert.That(propertyGroup.ParentId.HasValue, Is.False);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Can_Remove_PropertyGroup_Without_Removing_Property_Types()
|
||||
{
|
||||
var service = ServiceContext.ContentTypeService;
|
||||
var basePage = (IContentType)MockedContentTypes.CreateBasicContentType();
|
||||
service.Save(basePage);
|
||||
|
||||
var authorPropertyType = new PropertyType(Constants.PropertyEditors.TextboxAlias, DataTypeDatabaseType.Ntext, "author")
|
||||
{
|
||||
Name = "Author",
|
||||
Description = "",
|
||||
Mandatory = false,
|
||||
SortOrder = 1,
|
||||
DataTypeDefinitionId = -88
|
||||
};
|
||||
var authorAdded = basePage.AddPropertyType(authorPropertyType, "Content");
|
||||
service.Save(basePage);
|
||||
|
||||
basePage = service.GetContentType(basePage.Id);
|
||||
|
||||
var totalPt = basePage.PropertyTypes.Count();
|
||||
|
||||
basePage.RemovePropertyGroup("Content");
|
||||
service.Save(basePage);
|
||||
|
||||
basePage = service.GetContentType(basePage.Id);
|
||||
|
||||
Assert.AreEqual(totalPt, basePage.PropertyTypes.Count());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Can_Add_PropertyGroup_With_Same_Name_On_Parent_and_Child()
|
||||
{
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace Umbraco.Tests.TestHelpers.Entities
|
||||
{
|
||||
public static Content CreateSimpleContent(IContentType contentType)
|
||||
{
|
||||
var content = new Content("Home", -1, contentType) { Language = "en-US", Level = 1, SortOrder = 1, CreatorId = 0, WriterId = 0 };
|
||||
var content = new Content("Home", -1, contentType) { Language = "en-US", Level = 1, SortOrder = 1, CreatorId = 0, WriterId = 0, Path = "-1" };
|
||||
object obj =
|
||||
new
|
||||
{
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 367 B |
BIN
src/Umbraco.Web.UI.Client/src/assets/img/application/logo@2x.png
Normal file
BIN
src/Umbraco.Web.UI.Client/src/assets/img/application/logo@2x.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.6 KiB |
BIN
src/Umbraco.Web.UI.Client/src/assets/img/application/logo@3x.png
Normal file
BIN
src/Umbraco.Web.UI.Client/src/assets/img/application/logo@3x.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.5 KiB |
@@ -13,7 +13,9 @@ angular.module("umbraco.directives")
|
||||
restrict: 'E',
|
||||
replace: true,
|
||||
templateUrl: 'views/directives/umb-property.html',
|
||||
|
||||
link: function(scope) {
|
||||
scope.propertyAlias = Umbraco.Sys.ServerVariables.isDebuggingEnabled === true ? scope.property.alias : null;
|
||||
},
|
||||
//Define a controller for this directive to expose APIs to other directives
|
||||
controller: function ($scope, $timeout) {
|
||||
|
||||
|
||||
@@ -139,6 +139,12 @@ function entityResource($q, $http, umbRequestHelper) {
|
||||
_.each(ids, function(item) {
|
||||
query += "ids=" + item + "&";
|
||||
});
|
||||
|
||||
// if ids array is empty we need a empty variable in the querystring otherwise the service returns a error
|
||||
if (ids.length === 0) {
|
||||
query += "ids=&";
|
||||
}
|
||||
|
||||
query += "type=" + type;
|
||||
|
||||
return umbRequestHelper.resourcePromise(
|
||||
|
||||
@@ -13,7 +13,11 @@ function MainController($scope, $rootScope, $location, $routeParams, $timeout, $
|
||||
//the null is important because we do an explicit bool check on this in the view
|
||||
//the avatar is by default the umbraco logo
|
||||
$scope.authenticated = null;
|
||||
$scope.avatar = "assets/img/application/logo.png";
|
||||
$scope.avatar = [
|
||||
{ value: "assets/img/application/logo.png" },
|
||||
{ value: "assets/img/application/logo@2x.png" },
|
||||
{ value: "assets/img/application/logo@3x.png" }
|
||||
];
|
||||
$scope.touchDevice = appState.getGlobalState("touchDevice");
|
||||
|
||||
|
||||
@@ -95,7 +99,14 @@ function MainController($scope, $rootScope, $location, $routeParams, $timeout, $
|
||||
$scope.$apply(function () {
|
||||
//this can be null if they time out
|
||||
if ($scope.user && $scope.user.emailHash) {
|
||||
$scope.avatar = "https://www.gravatar.com/avatar/" + $scope.user.emailHash + ".jpg?s=64&d=mm";
|
||||
var avatarBaseUrl = "https://www.gravatar.com/avatar/",
|
||||
hash = $scope.user.emailHash;
|
||||
|
||||
$scope.avatar = [
|
||||
{ value: avatarBaseUrl + hash + ".jpg?s=30&d=mm" },
|
||||
{ value: avatarBaseUrl + hash + ".jpg?s=60&d=mm" },
|
||||
{ value: avatarBaseUrl + hash + ".jpg?s=90&d=mm" }
|
||||
];
|
||||
}
|
||||
});
|
||||
$("#avatar-img").fadeTo(1000, 1);
|
||||
|
||||
@@ -81,8 +81,8 @@ ul.sections li.avatar a {
|
||||
}
|
||||
|
||||
ul.sections li.avatar a img {
|
||||
border-radius: 16px;
|
||||
width: 30px
|
||||
border-radius: 50%;
|
||||
width: 30px;
|
||||
}
|
||||
|
||||
.faded ul.sections li {
|
||||
|
||||
@@ -7,6 +7,7 @@ angular.module("umbraco").controller("Umbraco.Editors.Content.CopyController",
|
||||
searchText = value + "...";
|
||||
});
|
||||
|
||||
$scope.recursive = true;
|
||||
$scope.relateToOriginal = false;
|
||||
$scope.dialogTreeEventHandler = $({});
|
||||
$scope.busy = false;
|
||||
@@ -95,7 +96,7 @@ angular.module("umbraco").controller("Umbraco.Editors.Content.CopyController",
|
||||
$scope.busy = true;
|
||||
$scope.error = false;
|
||||
|
||||
contentResource.copy({ parentId: $scope.target.id, id: node.id, relateToOriginal: $scope.relateToOriginal })
|
||||
contentResource.copy({ parentId: $scope.target.id, id: node.id, relateToOriginal: $scope.relateToOriginal, recursive: $scope.recursive })
|
||||
.then(function (path) {
|
||||
$scope.error = false;
|
||||
$scope.success = true;
|
||||
|
||||
@@ -56,6 +56,12 @@
|
||||
</umb-control-group>
|
||||
</umb-pane>
|
||||
|
||||
<umb-pane>
|
||||
<umb-control-group label="Include descendants">
|
||||
<input type="checkbox" ng-model="$parent.$parent.recursive" />
|
||||
</umb-control-group>
|
||||
</umb-pane>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<val-property-msg property="property"></val-property-msg>
|
||||
|
||||
<div class="umb-el-wrap">
|
||||
<label class="control-label" ng-hide="property.hideLabel" for="{{property.alias}}">
|
||||
<label class="control-label" ng-hide="property.hideLabel" for="{{property.alias}}" ng-attr-title="{{propertyAlias}}">
|
||||
{{property.label}}
|
||||
<small ng-bind-html="property.description"></small>
|
||||
</label>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<ul class="sections">
|
||||
<li class="avatar">
|
||||
<a href="#" ng-click="avatarClick()" hotkey="ctrl+shift+u" title="{{user.name}}" prevent-default>
|
||||
<img id="avatar-img" ng-src="{{avatar}}" />
|
||||
<img id="avatar-img" ng-src="{{avatar[0].value}}" ng-srcset="{{avatar[1].value}} 2x, {{avatar[2].value}} 3x" />
|
||||
</a>
|
||||
</li>
|
||||
<li ng-repeat="section in sections | limitTo: maxSections" ng-class="{current: section.alias == currentSection}">
|
||||
|
||||
@@ -2,13 +2,29 @@ angular.module('umbraco').controller("Umbraco.PropertyEditors.UrlListController"
|
||||
function($rootScope, $scope, $filter) {
|
||||
|
||||
function formatDisplayValue() {
|
||||
if (angular.isArray($scope.model.value)) {
|
||||
//it's the json value
|
||||
$scope.renderModel = _.map($scope.model.value, function (item) {
|
||||
return {
|
||||
url: item.url,
|
||||
linkText: item.linkText,
|
||||
urlTarget: (item.target) ? item.target : "_blank",
|
||||
icon: (item.icon) ? item.icon : "icon-out"
|
||||
};
|
||||
});
|
||||
}
|
||||
else {
|
||||
//it's the default csv value
|
||||
$scope.renderModel = _.map($scope.model.value.split(","), function (item) {
|
||||
return {
|
||||
url: item,
|
||||
urlTarget: ($scope.config && $scope.config.target) ? $scope.config.target : "_blank"
|
||||
linkText: "",
|
||||
urlTarget: ($scope.config && $scope.config.target) ? $scope.config.target : "_blank",
|
||||
icon: ($scope.config && $scope.config.icon) ? $scope.config.icon : "icon-out"
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
$scope.getUrl = function(valueUrl) {
|
||||
if (valueUrl.indexOf("/") >= 0) {
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
<div ng-controller="Umbraco.PropertyEditors.UrlListController">
|
||||
<ul class="nav nav-stacked">
|
||||
<li ng-repeat="value in renderModel">
|
||||
<a href="{{getUrl(value.url)}}" prevent-default="{{value.url.indexOf('/') == -1}}" target="{{value.urlTarget}}"><i class="icon-out"></i> {{value.url}}</a>
|
||||
<a href="{{getUrl(value.url)}}" prevent-default="{{value.url.indexOf('/') == -1}}" target="{{value.urlTarget}}">
|
||||
<i ng-class="value.icon"></i>
|
||||
<span ng-if="value.linkText">{{value.linkText}}</span>
|
||||
<span ng-if="!value.linkText">{{value.url}}</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
@@ -7,7 +7,7 @@
|
||||
</root>
|
||||
|
||||
<appender name="rollingFile" type="log4net.Appender.RollingFileAppender">
|
||||
<file value="App_Data\Logs\UmbracoTraceLog.txt" />
|
||||
<file type="log4net.Util.PatternString" value="App_Data\Logs\UmbracoTraceLog.%property{log4net:HostName}.txt" />
|
||||
<lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
|
||||
<appendToFile value="true" />
|
||||
<rollingStyle value="Date" />
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
</root>
|
||||
|
||||
<appender name="rollingFile" type="log4net.Appender.RollingFileAppender">
|
||||
<file value="App_Data\Logs\UmbracoTraceLog.txt" />
|
||||
<file type="log4net.Util.PatternString" value="App_Data\Logs\UmbracoTraceLog.%property{log4net:HostName}.txt" />
|
||||
<lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
|
||||
<appendToFile value="true" />
|
||||
<rollingStyle value="Date" />
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
<key alias="domainUpdated">Domain '%0%' has been updated</key>
|
||||
<key alias="orEdit">Edit Current Domains</key>
|
||||
<key alias="domainHelp"><![CDATA[Valid domain names are: "example.com", "www.example.com", "example.com:8080" or
|
||||
"https://www.example.com/".<br /><br />One-level paths in domains are supported, eg. "example.com/en". However, they
|
||||
"https://www.example.com/". One-level paths in domains are supported, eg. "example.com/en". However, they
|
||||
should be avoided. Better use the culture setting above.]]></key>
|
||||
<key alias="inherit">Inherit</key>
|
||||
<key alias="setLanguage">Culture</key>
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
<key alias="domainUpdated">Domain '%0%' has been updated</key>
|
||||
<key alias="orEdit">Edit Current Domains</key>
|
||||
<key alias="domainHelp"><![CDATA[Valid domain names are: "example.com", "www.example.com", "example.com:8080" or
|
||||
"https://www.example.com/".<br /><br />One-level paths in domains are supported, eg. "example.com/en". However, they
|
||||
"https://www.example.com/". One-level paths in domains are supported, eg. "example.com/en". However, they
|
||||
should be avoided. Better use the culture setting above.]]></key>
|
||||
<key alias="inherit">Inherit</key>
|
||||
<key alias="setLanguage">Culture</key>
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
|
||||
|
||||
<cc1:Pane runat="server" ID="pane_domains">
|
||||
<small class="help-inline"><%=umbraco.ui.Text("assignDomain", "domainHelp") %></small>
|
||||
<cc1:PropertyPanel runat="server">
|
||||
<table class="table domains" data-bind="visible: domains().length > 0">
|
||||
<thead>
|
||||
@@ -51,7 +52,7 @@
|
||||
</thead>
|
||||
<tbody data-bind="foreach: domains">
|
||||
<tr>
|
||||
<td valign="top"><input class="domain" data-bind="value: Name, uniqueName: true" /><input type="hidden" value="0" data-bind="uniqueName: true"/></td>
|
||||
<td valign="top"><input class="domain duplicate" data-bind="value: Name, uniqueName: true" /><input type="hidden" value="" data-bind="uniqueName: true"/></td>
|
||||
<td valign="top"><select class="language" data-bind="options: $parent.languages, optionsText: 'Code', optionsValue: 'Id', value: Lang, uniqueName: true"></select></td>
|
||||
<td valign="top"><a href="#" class="btn btn-danger" data-bind="click: $parent.removeDomain"><i class="icon icon-trash"></i></a></td>
|
||||
</tr>
|
||||
@@ -60,7 +61,6 @@
|
||||
</cc1:PropertyPanel>
|
||||
|
||||
<cc1:PropertyPanel runat="server">
|
||||
<small data-bind="visible: domains().length == 0" class="help-inline"><%=umbraco.ui.Text("assignDomain", "domainHelp") %></small>
|
||||
<button class="btn" data-bind="click: addDomain"><%=umbraco.ui.Text("assignDomain", "addNew") %></button>
|
||||
</cc1:PropertyPanel>
|
||||
|
||||
|
||||
@@ -63,9 +63,17 @@
|
||||
return ret;
|
||||
}, self._opts.invalidDomain);
|
||||
|
||||
function getDuplicateMessage(val, el) {
|
||||
var other = $(el).nextAll('input').val();
|
||||
var msg = self._opts.duplicateDomain
|
||||
if (other != "" && other != "!!!")
|
||||
msg = msg + ' (' + other + ')';
|
||||
return msg;
|
||||
}
|
||||
|
||||
$.validator.addMethod("duplicate", function (value, element, param) {
|
||||
return $(element).nextAll('input').val() == 0 && !self._isRepeated($(element));
|
||||
}, self._opts.duplicateDomain);
|
||||
return $(element).nextAll('input').val() == "" && !self._isRepeated($(element));
|
||||
}, getDuplicateMessage);
|
||||
|
||||
$.validator.addClassRules({
|
||||
domain: { domain: true },
|
||||
@@ -80,7 +88,7 @@
|
||||
|
||||
$('form input.domain').live('focus', function(event) {
|
||||
if (event.type != 'focusin') return;
|
||||
$(this).nextAll('input').val(0);
|
||||
$(this).nextAll('input').val("");
|
||||
});
|
||||
|
||||
// force validation *now*
|
||||
@@ -105,14 +113,14 @@
|
||||
}
|
||||
else {
|
||||
var inputs = $('form input.domain');
|
||||
inputs.each(function() { $(this).nextAll('input').val(0); });
|
||||
inputs.each(function() { $(this).nextAll('input').val(""); });
|
||||
for (var i = 0; i < json.Domains.length; i++) {
|
||||
var d = json.Domains[i];
|
||||
if (d.Duplicate == 1)
|
||||
if (d.Duplicate)
|
||||
inputs.each(function() {
|
||||
var input = $(this);
|
||||
if (input.val() == d.Name)
|
||||
input.nextAll('input').val(1);
|
||||
input.nextAll('input').val(d.Other ? d.Other : "!!!");
|
||||
});
|
||||
}
|
||||
$('form').valid();
|
||||
|
||||
@@ -189,8 +189,12 @@
|
||||
|
||||
top.UmbSpeechBubble.ShowMessage('save', header, msg);
|
||||
|
||||
if (args && args.name) {
|
||||
this._opts.originalFileName = args.name;
|
||||
}
|
||||
if (args && args.path) {
|
||||
this._opts.treeSyncPath = args.path;
|
||||
}
|
||||
|
||||
UmbClientMgr.mainTree().syncTree(path, true, null, newFilePath.split("/")[1]);
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ using Umbraco.Core.Events;
|
||||
using Umbraco.Core.Models;
|
||||
using umbraco;
|
||||
using umbraco.cms.businesslogic.web;
|
||||
using Umbraco.Core.Persistence.Repositories;
|
||||
|
||||
namespace Umbraco.Web.Cache
|
||||
{
|
||||
@@ -400,6 +401,12 @@ namespace Umbraco.Web.Cache
|
||||
dc.Remove(DistributedCache.DomainCacheRefresherGuid, domain.Id);
|
||||
}
|
||||
|
||||
public static void ClearDomainCacheOnCurrentServer(this DistributedCache dc)
|
||||
{
|
||||
var key = RepositoryBase.GetCacheTypeKey<IDomain>();
|
||||
ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheByKeySearch(key);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Language Cache
|
||||
|
||||
@@ -79,6 +79,7 @@ namespace Umbraco.Web.Cache
|
||||
{
|
||||
ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes<IContent>();
|
||||
ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes<PublicAccessEntry>();
|
||||
DistributedCache.Instance.ClearDomainCacheOnCurrentServer();
|
||||
base.RefreshAll();
|
||||
}
|
||||
|
||||
@@ -87,6 +88,7 @@ namespace Umbraco.Web.Cache
|
||||
ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheItem(RepositoryBase.GetCacheIdKey<IContent>(id));
|
||||
ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes<PublicAccessEntry>();
|
||||
content.Instance.UpdateSortOrder(id);
|
||||
DistributedCache.Instance.ClearDomainCacheOnCurrentServer();
|
||||
base.Refresh(id);
|
||||
}
|
||||
|
||||
@@ -94,6 +96,7 @@ namespace Umbraco.Web.Cache
|
||||
{
|
||||
ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheItem(RepositoryBase.GetCacheIdKey<IContent>(id));
|
||||
ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes<PublicAccessEntry>();
|
||||
DistributedCache.Instance.ClearDomainCacheOnCurrentServer();
|
||||
base.Remove(id);
|
||||
}
|
||||
|
||||
@@ -103,6 +106,7 @@ namespace Umbraco.Web.Cache
|
||||
ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheItem(RepositoryBase.GetCacheIdKey<IContent>(instance.Id));
|
||||
ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes<PublicAccessEntry>();
|
||||
content.Instance.UpdateSortOrder(instance);
|
||||
DistributedCache.Instance.ClearDomainCacheOnCurrentServer();
|
||||
base.Refresh(instance);
|
||||
}
|
||||
|
||||
@@ -110,6 +114,7 @@ namespace Umbraco.Web.Cache
|
||||
{
|
||||
ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheItem(RepositoryBase.GetCacheIdKey<IContent>(instance.Id));
|
||||
ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes<PublicAccessEntry>();
|
||||
DistributedCache.Instance.ClearDomainCacheOnCurrentServer();
|
||||
base.Remove(instance);
|
||||
}
|
||||
|
||||
@@ -127,6 +132,8 @@ namespace Umbraco.Web.Cache
|
||||
content.Instance.UpdateSortOrder(payload.Id);
|
||||
}
|
||||
|
||||
DistributedCache.Instance.ClearDomainCacheOnCurrentServer();
|
||||
|
||||
OnCacheUpdated(Instance, new CacheRefresherEventArgs(jsonPayload, MessageType.RefreshByJson));
|
||||
}
|
||||
|
||||
|
||||
@@ -349,7 +349,9 @@ namespace Umbraco.Web.Editors
|
||||
{"trees", GetTreePluginsMetaData()}
|
||||
}
|
||||
},
|
||||
{"isDebuggingEnabled", HttpContext.IsDebuggingEnabled},
|
||||
{
|
||||
"isDebuggingEnabled", HttpContext.IsDebuggingEnabled
|
||||
},
|
||||
{
|
||||
"application", GetApplicationState()
|
||||
},
|
||||
|
||||
@@ -491,7 +491,7 @@ namespace Umbraco.Web.Editors
|
||||
{
|
||||
var toCopy = ValidateMoveOrCopy(copy);
|
||||
|
||||
var c = Services.ContentService.Copy(toCopy, copy.ParentId, copy.RelateToOriginal);
|
||||
var c = Services.ContentService.Copy(toCopy, copy.ParentId, copy.RelateToOriginal, copy.Recursive);
|
||||
|
||||
var response = Request.CreateResponse(HttpStatusCode.OK);
|
||||
response.Content = new StringContent(c.Path, Encoding.UTF8, "application/json");
|
||||
|
||||
@@ -471,7 +471,7 @@ namespace Umbraco.Web.Editors
|
||||
{
|
||||
tempFiles.Notifications.Add(new Notification(
|
||||
Services.TextService.Localize("speechBubbles/operationFailedHeader"),
|
||||
"Cannot upload file " + file + ", it is not an approved file type",
|
||||
"Cannot upload file " + file.Headers.ContentDisposition.FileName + ", it is not an approved file type",
|
||||
SpeechBubbleIcon.Warning));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Web;
|
||||
@@ -11,10 +10,12 @@ using Umbraco.Core;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Dynamics;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Profiling;
|
||||
using Umbraco.Web.Models;
|
||||
using Umbraco.Web.Mvc;
|
||||
using umbraco;
|
||||
using umbraco.cms.businesslogic.member;
|
||||
using Constants = Umbraco.Core.Constants;
|
||||
using Member = umbraco.cms.businesslogic.member.Member;
|
||||
|
||||
namespace Umbraco.Web
|
||||
{
|
||||
@@ -194,6 +195,117 @@ namespace Umbraco.Web
|
||||
return htmlHelper.Action(actionName, metaData.ControllerName, routeVals);
|
||||
}
|
||||
|
||||
#region GetCropUrl
|
||||
|
||||
/// <summary>
|
||||
/// Gets the ImageProcessor Url of a media item by the crop alias (using default media item property alias of "umbracoFile")
|
||||
/// </summary>
|
||||
/// <param name="htmlHelper"></param>
|
||||
/// <param name="mediaItem"></param>
|
||||
/// <param name="cropAlias"></param>
|
||||
/// <returns></returns>
|
||||
public static IHtmlString GetCropUrl(this HtmlHelper htmlHelper, IPublishedContent mediaItem, string cropAlias)
|
||||
{
|
||||
return new HtmlString(mediaItem.GetCropUrl(cropAlias: cropAlias, useCropDimensions: true));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the ImageProcessor Url of a media item by the property alias and crop alias.
|
||||
/// </summary>
|
||||
/// <param name="htmlHelper"></param>
|
||||
/// <param name="mediaItem"></param>
|
||||
/// <param name="propertyAlias"></param>
|
||||
/// <param name="cropAlias"></param>
|
||||
/// <returns></returns>
|
||||
public static IHtmlString GetCropUrl(this HtmlHelper htmlHelper, IPublishedContent mediaItem, string propertyAlias, string cropAlias)
|
||||
{
|
||||
return new HtmlString(mediaItem.GetCropUrl(propertyAlias: propertyAlias, cropAlias: cropAlias, useCropDimensions: true));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the ImageProcessor Url of a media item
|
||||
/// </summary>
|
||||
/// <param name="htmlHelper"></param>
|
||||
/// <param name="mediaItem"></param>
|
||||
/// <param name="width"></param>
|
||||
/// <param name="height"></param>
|
||||
/// <param name="propertyAlias"></param>
|
||||
/// <param name="cropAlias"></param>
|
||||
/// <param name="quality"></param>
|
||||
/// <param name="imageCropMode"></param>
|
||||
/// <param name="imageCropAnchor"></param>
|
||||
/// <param name="preferFocalPoint"></param>
|
||||
/// <param name="useCropDimensions"></param>
|
||||
/// <param name="cacheBuster"></param>
|
||||
/// <param name="furtherOptions"></param>
|
||||
/// <param name="ratioMode"></param>
|
||||
/// <param name="upScale"></param>
|
||||
/// <returns></returns>
|
||||
public static IHtmlString GetCropUrl(this HtmlHelper htmlHelper,
|
||||
IPublishedContent mediaItem,
|
||||
int? width = null,
|
||||
int? height = null,
|
||||
string propertyAlias = Constants.Conventions.Media.File,
|
||||
string cropAlias = null,
|
||||
int? quality = null,
|
||||
ImageCropMode? imageCropMode = null,
|
||||
ImageCropAnchor? imageCropAnchor = null,
|
||||
bool preferFocalPoint = false,
|
||||
bool useCropDimensions = false,
|
||||
bool cacheBuster = true,
|
||||
string furtherOptions = null,
|
||||
ImageCropRatioMode? ratioMode = null,
|
||||
bool upScale = true)
|
||||
{
|
||||
return
|
||||
new HtmlString(mediaItem.GetCropUrl(width, height, propertyAlias, cropAlias, quality, imageCropMode,
|
||||
imageCropAnchor, preferFocalPoint, useCropDimensions, cacheBuster, furtherOptions, ratioMode,
|
||||
upScale));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the ImageProcessor Url from the media path
|
||||
/// </summary>
|
||||
/// <param name="htmlHelper"></param>
|
||||
/// <param name="imageUrl"></param>
|
||||
/// <param name="width"></param>
|
||||
/// <param name="height"></param>
|
||||
/// <param name="imageCropperValue"></param>
|
||||
/// <param name="cropAlias"></param>
|
||||
/// <param name="quality"></param>
|
||||
/// <param name="imageCropMode"></param>
|
||||
/// <param name="imageCropAnchor"></param>
|
||||
/// <param name="preferFocalPoint"></param>
|
||||
/// <param name="useCropDimensions"></param>
|
||||
/// <param name="cacheBusterValue"></param>
|
||||
/// <param name="furtherOptions"></param>
|
||||
/// <param name="ratioMode"></param>
|
||||
/// <param name="upScale"></param>
|
||||
/// <returns></returns>
|
||||
public static IHtmlString GetCropUrl(this HtmlHelper htmlHelper,
|
||||
string imageUrl,
|
||||
int? width = null,
|
||||
int? height = null,
|
||||
string imageCropperValue = null,
|
||||
string cropAlias = null,
|
||||
int? quality = null,
|
||||
ImageCropMode? imageCropMode = null,
|
||||
ImageCropAnchor? imageCropAnchor = null,
|
||||
bool preferFocalPoint = false,
|
||||
bool useCropDimensions = false,
|
||||
string cacheBusterValue = null,
|
||||
string furtherOptions = null,
|
||||
ImageCropRatioMode? ratioMode = null,
|
||||
bool upScale = true)
|
||||
{
|
||||
return
|
||||
new HtmlString(imageUrl.GetCropUrl(width, height, imageCropperValue, cropAlias, quality, imageCropMode,
|
||||
imageCropAnchor, preferFocalPoint, useCropDimensions, cacheBusterValue, furtherOptions, ratioMode,
|
||||
upScale));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region BeginUmbracoForm
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -33,6 +33,13 @@ namespace Umbraco.Web.Models.ContentEditing
|
||||
[DataMember(Name = "relateToOriginal", IsRequired = true)]
|
||||
[Required]
|
||||
public bool RelateToOriginal { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Boolean indicating whether copying the object should be recursive
|
||||
/// </summary>
|
||||
[DataMember(Name = "recursive", IsRequired = true)]
|
||||
[Required]
|
||||
public bool Recursive { get; set; }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,22 +2,16 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Threading;
|
||||
using System.Web;
|
||||
using System.Web.Mvc;
|
||||
using System.Web.Routing;
|
||||
using AutoMapper;
|
||||
using Newtonsoft.Json;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.Mapping;
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Web.Models.ContentEditing;
|
||||
using Umbraco.Web.Trees;
|
||||
using umbraco;
|
||||
using Umbraco.Web.Routing;
|
||||
using umbraco.BusinessLogic.Actions;
|
||||
|
||||
@@ -51,11 +45,7 @@ namespace Umbraco.Web.Models.Mapping
|
||||
.ForMember(
|
||||
dto => dto.IsContainer,
|
||||
expression => expression.MapFrom(content => content.ContentType.IsContainer))
|
||||
.ForMember(
|
||||
dto => dto.IsChildOfListView,
|
||||
//TODO: Fix this shorthand .Parent() lookup, at least have an overload to use the current
|
||||
// application context so it's testable!
|
||||
expression => expression.MapFrom(content => content.Parent().ContentType.IsContainer))
|
||||
.ForMember(display => display.IsChildOfListView, expression => expression.Ignore())
|
||||
.ForMember(
|
||||
dto => dto.Trashed,
|
||||
expression => expression.MapFrom(content => content.Trashed))
|
||||
@@ -78,7 +68,8 @@ namespace Umbraco.Web.Models.Mapping
|
||||
.ForMember(display => display.Tabs, expression => expression.ResolveUsing<TabsAndPropertiesResolver>())
|
||||
.ForMember(display => display.AllowedActions, expression => expression.ResolveUsing(
|
||||
new ActionButtonsResolver(new Lazy<IUserService>(() => applicationContext.Services.UserService))))
|
||||
.AfterMap((media, display) => AfterMap(media, display, applicationContext.Services.DataTypeService, applicationContext.Services.TextService));
|
||||
.AfterMap((media, display) => AfterMap(media, display, applicationContext.Services.DataTypeService, applicationContext.Services.TextService,
|
||||
applicationContext.Services.ContentTypeService));
|
||||
|
||||
//FROM IContent TO ContentItemBasic<ContentPropertyBasic, IContent>
|
||||
config.CreateMap<IContent, ContentItemBasic<ContentPropertyBasic, IContent>>()
|
||||
@@ -119,8 +110,15 @@ namespace Umbraco.Web.Models.Mapping
|
||||
/// <param name="display"></param>
|
||||
/// <param name="dataTypeService"></param>
|
||||
/// <param name="localizedText"></param>
|
||||
private static void AfterMap(IContent content, ContentItemDisplay display, IDataTypeService dataTypeService, ILocalizedTextService localizedText)
|
||||
/// <param name="contentTypeService"></param>
|
||||
private static void AfterMap(IContent content, ContentItemDisplay display, IDataTypeService dataTypeService,
|
||||
ILocalizedTextService localizedText, IContentTypeService contentTypeService)
|
||||
{
|
||||
//map the IsChildOfListView (this is actually if it is a descendant of a list view!)
|
||||
//TODO: Fix this shorthand .Ancestors() lookup, at least have an overload to use the current
|
||||
var ancesctorListView = content.Ancestors().FirstOrDefault(x => x.ContentType.IsContainer);
|
||||
display.IsChildOfListView = ancesctorListView != null;
|
||||
|
||||
//map the tree node url
|
||||
if (HttpContext.Current != null)
|
||||
{
|
||||
@@ -142,8 +140,8 @@ namespace Umbraco.Web.Models.Mapping
|
||||
TabsAndPropertiesResolver.AddListView(display, "content", dataTypeService);
|
||||
}
|
||||
|
||||
TabsAndPropertiesResolver.MapGenericProperties(
|
||||
content, display,
|
||||
var properties = new List<ContentPropertyDisplay>
|
||||
{
|
||||
new ContentPropertyDisplay
|
||||
{
|
||||
Alias = string.Format("{0}releasedate", Constants.PropertyEditors.InternalGenericPropertiesPrefix),
|
||||
@@ -175,10 +173,43 @@ namespace Umbraco.Web.Models.Mapping
|
||||
Label = localizedText.Localize("content/urls"),
|
||||
Value = string.Join(",", display.Urls),
|
||||
View = "urllist" //TODO: Hard coding this because the templatepicker doesn't necessarily need to be a resolvable (real) property editor
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
TabsAndPropertiesResolver.MapGenericProperties(content, display, properties.ToArray(),
|
||||
genericProperties =>
|
||||
{
|
||||
//TODO: This would be much nicer with the IUmbracoContextAccessor so we don't use singletons
|
||||
//If this is a web request and debugging is enabled and there's a user signed in and the
|
||||
// user has access tot he settings section, we will
|
||||
if (HttpContext.Current != null && HttpContext.Current.IsDebuggingEnabled
|
||||
&& UmbracoContext.Current != null && UmbracoContext.Current.Security.CurrentUser != null
|
||||
&& UmbracoContext.Current.Security.CurrentUser.AllowedSections.Any(x => x.Equals(Constants.Applications.Settings)))
|
||||
{
|
||||
var currentDocumentType = contentTypeService.GetContentType(display.ContentTypeAlias);
|
||||
var currentDocumentTypeName = currentDocumentType == null ? string.Empty : currentDocumentType.Name;
|
||||
|
||||
var currentDocumentTypeId = currentDocumentType == null ? string.Empty : currentDocumentType.Id.ToString(CultureInfo.InvariantCulture);
|
||||
//TODO: Hard coding this is not good
|
||||
var docTypeLink = string.Format("#/settings/framed/%252Fumbraco%252Fsettings%252FeditNodeTypeNew.aspx%253Fid%253D{0}", currentDocumentTypeId);
|
||||
|
||||
//Replace the doc type property
|
||||
var docTypeProp = genericProperties.First(x => x.Alias == string.Format("{0}doctype", Constants.PropertyEditors.InternalGenericPropertiesPrefix));
|
||||
docTypeProp.Value = new List<object>
|
||||
{
|
||||
new
|
||||
{
|
||||
linkText = currentDocumentTypeName,
|
||||
url = docTypeLink,
|
||||
target = "_self", icon = "icon-item-arrangement"
|
||||
}
|
||||
};
|
||||
//TODO: Hard coding this because the templatepicker doesn't necessarily need to be a resolvable (real) property editor
|
||||
docTypeProp.View = "urllist";
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the published date value for the IContent object
|
||||
|
||||
@@ -35,11 +35,7 @@ namespace Umbraco.Web.Models.Mapping
|
||||
.ForMember(
|
||||
dto => dto.ContentTypeAlias,
|
||||
expression => expression.MapFrom(content => content.ContentType.Alias))
|
||||
.ForMember(
|
||||
dto => dto.IsChildOfListView,
|
||||
//TODO: Fix this shorthand .Parent() lookup, at least have an overload to use the current
|
||||
// application context so it's testable!
|
||||
expression => expression.MapFrom(content => content.Parent().ContentType.IsContainer))
|
||||
.ForMember(display => display.IsChildOfListView, expression => expression.Ignore())
|
||||
.ForMember(
|
||||
dto => dto.Trashed,
|
||||
expression => expression.MapFrom(content => content.Trashed))
|
||||
|
||||
@@ -178,8 +178,8 @@ namespace Umbraco.Web.Models.Mapping
|
||||
display.TreeNodeUrl = url;
|
||||
}
|
||||
|
||||
TabsAndPropertiesResolver.MapGenericProperties(
|
||||
member, display,
|
||||
var genericProperties = new List<ContentPropertyDisplay>
|
||||
{
|
||||
GetLoginProperty(memberService, member, display),
|
||||
new ContentPropertyDisplay
|
||||
{
|
||||
@@ -187,7 +187,7 @@ namespace Umbraco.Web.Models.Mapping
|
||||
Label = ui.Text("general", "email"),
|
||||
Value = display.Email,
|
||||
View = "email",
|
||||
Validation = { Mandatory = true }
|
||||
Validation = {Mandatory = true}
|
||||
},
|
||||
new ContentPropertyDisplay
|
||||
{
|
||||
@@ -197,8 +197,8 @@ namespace Umbraco.Web.Models.Mapping
|
||||
// only when creating a new member and we want to have a generated password pre-filled.
|
||||
Value = new Dictionary<string, object>
|
||||
{
|
||||
{"generatedPassword", member.GetAdditionalDataValueIgnoreCase("GeneratedPassword", null) },
|
||||
{"newPassword", member.GetAdditionalDataValueIgnoreCase("NewPassword", null) },
|
||||
{"generatedPassword", member.GetAdditionalDataValueIgnoreCase("GeneratedPassword", null)},
|
||||
{"newPassword", member.GetAdditionalDataValueIgnoreCase("NewPassword", null)},
|
||||
},
|
||||
//TODO: Hard coding this because the changepassword doesn't necessarily need to be a resolvable (real) property editor
|
||||
View = "changepassword",
|
||||
@@ -215,8 +215,11 @@ namespace Umbraco.Web.Models.Mapping
|
||||
Label = ui.Text("content", "membergroup"),
|
||||
Value = GetMemberGroupValue(display.Username),
|
||||
View = "membergroups",
|
||||
Config = new Dictionary<string, object> { { "IsRequired", true } }
|
||||
});
|
||||
Config = new Dictionary<string, object> {{"IsRequired", true}}
|
||||
}
|
||||
};
|
||||
|
||||
TabsAndPropertiesResolver.MapGenericProperties(member, display, genericProperties);
|
||||
|
||||
//check if there's an approval field
|
||||
var provider = membersProvider as global::umbraco.providers.members.UmbracoMembershipProvider;
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using AutoMapper;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Dictionary;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
using Umbraco.Core.Services;
|
||||
@@ -40,6 +41,7 @@ namespace Umbraco.Web.Models.Mapping
|
||||
/// <param name="customProperties">
|
||||
/// Any additional custom properties to assign to the generic properties tab.
|
||||
/// </param>
|
||||
/// <param name="onGenericPropertiesMapped"></param>
|
||||
/// <remarks>
|
||||
/// The generic properties tab is mapped during AfterMap and is responsible for
|
||||
/// setting up the properties such as Created date, updated date, template selected, etc...
|
||||
@@ -47,11 +49,10 @@ namespace Umbraco.Web.Models.Mapping
|
||||
public static void MapGenericProperties<TPersisted>(
|
||||
TPersisted content,
|
||||
ContentItemDisplayBase<ContentPropertyDisplay, TPersisted> display,
|
||||
params ContentPropertyDisplay[] customProperties)
|
||||
IEnumerable<ContentPropertyDisplay> customProperties = null,
|
||||
Action<List<ContentPropertyDisplay>> onGenericPropertiesMapped = null)
|
||||
where TPersisted : IContentBase
|
||||
{
|
||||
|
||||
|
||||
var genericProps = display.Tabs.Single(x => x.Id == 0);
|
||||
|
||||
//store the current props to append to the newly inserted ones
|
||||
@@ -101,15 +102,26 @@ namespace Umbraco.Web.Models.Mapping
|
||||
}
|
||||
};
|
||||
|
||||
if (customProperties != null)
|
||||
{
|
||||
//add the custom ones
|
||||
contentProps.AddRange(customProperties);
|
||||
}
|
||||
|
||||
//now add the user props
|
||||
contentProps.AddRange(currProps);
|
||||
|
||||
//callback
|
||||
if (onGenericPropertiesMapped != null)
|
||||
{
|
||||
onGenericPropertiesMapped(contentProps);
|
||||
}
|
||||
|
||||
//re-assign
|
||||
genericProps.Properties = contentProps;
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web.Mvc;
|
||||
using System.Web.Mvc.Async;
|
||||
|
||||
@@ -11,9 +12,6 @@ namespace Umbraco.Web.Mvc
|
||||
/// </summary>
|
||||
public class RenderActionInvoker : AsyncControllerActionInvoker
|
||||
{
|
||||
|
||||
private static readonly ConcurrentDictionary<Type, ReflectedActionDescriptor> IndexDescriptors = new ConcurrentDictionary<Type, ReflectedActionDescriptor>();
|
||||
|
||||
/// <summary>
|
||||
/// Ensures that if an action for the Template name is not explicitly defined by a user, that the 'Index' action will execute
|
||||
/// </summary>
|
||||
@@ -31,16 +29,7 @@ namespace Umbraco.Web.Mvc
|
||||
//check if the controller is an instance of IRenderMvcController
|
||||
if (controllerContext.Controller is IRenderMvcController)
|
||||
{
|
||||
return IndexDescriptors.GetOrAdd(controllerContext.Controller.GetType(),
|
||||
type => new ReflectedActionDescriptor(
|
||||
controllerContext.Controller.GetType().GetMethods()
|
||||
.First(x => x.Name == "Index" &&
|
||||
x.GetCustomAttributes(typeof (NonActionAttribute), false).Any() == false),
|
||||
"Index",
|
||||
controllerDescriptor));
|
||||
|
||||
|
||||
|
||||
return controllerDescriptor.FindAction(controllerContext, "Index");
|
||||
}
|
||||
}
|
||||
return ad;
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Web.Http;
|
||||
using System.Web.Services.Description;
|
||||
using Umbraco.Core;
|
||||
@@ -113,7 +114,25 @@ namespace Umbraco.Web.WebServices
|
||||
if (domain != null)
|
||||
domain.LanguageId = language.Id;
|
||||
else if (Services.DomainService.Exists(domainModel.Name))
|
||||
{
|
||||
domainModel.Duplicate = true;
|
||||
var xdomain = Services.DomainService.GetByName(domainModel.Name);
|
||||
var xrcid = xdomain.RootContentId;
|
||||
if (xrcid.HasValue)
|
||||
{
|
||||
var xcontent = Services.ContentService.GetById(xrcid.Value);
|
||||
var xnames = new List<string>();
|
||||
while (xcontent != null)
|
||||
{
|
||||
xnames.Add(xcontent.Name);
|
||||
if (xcontent.ParentId < -1)
|
||||
xnames.Add("Recycle Bin");
|
||||
xcontent = xcontent.Parent();
|
||||
}
|
||||
xnames.Reverse();
|
||||
domainModel.Other = "/" + string.Join("/", xnames);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// yet there is a race condition here...
|
||||
@@ -159,6 +178,7 @@ namespace Umbraco.Web.WebServices
|
||||
public string Name { get; private set; }
|
||||
public int Lang { get; private set; }
|
||||
public bool Duplicate { get; set; }
|
||||
public string Other { get; set; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -258,9 +258,16 @@ namespace Umbraco.Web.WebServices
|
||||
//ignore these properties
|
||||
.Where(x => new[] {"IndexerData", "Description", "WorkingFolder"}.InvariantContains(x.Name) == false)
|
||||
.OrderBy(x => x.Name);
|
||||
|
||||
foreach (var p in props)
|
||||
{
|
||||
indexerModel.ProviderProperties.Add(p.Name, p.GetValue(indexer, null).ToString());
|
||||
var val = p.GetValue(indexer, null);
|
||||
if (val == null)
|
||||
{
|
||||
LogHelper.Warn<ExamineManagementApiController>("Property value was null when setting up property on indexer: " + indexer.Name + " property: " + p.Name);
|
||||
val = string.Empty;
|
||||
}
|
||||
indexerModel.ProviderProperties.Add(p.Name, val.ToString());
|
||||
}
|
||||
|
||||
var luceneIndexer = indexer as LuceneIndexer;
|
||||
|
||||
@@ -97,22 +97,25 @@ namespace Umbraco.Web.WebServices
|
||||
oldname = oldname.TrimStart(pathPrefix);
|
||||
}
|
||||
|
||||
var view = get(svce, oldname);
|
||||
if (view == null)
|
||||
view = new PartialView(filename);
|
||||
var currentView = oldname.IsNullOrWhiteSpace()
|
||||
? get(svce, filename)
|
||||
: get(svce, oldname);
|
||||
|
||||
if (currentView == null)
|
||||
currentView = new PartialView(filename);
|
||||
else
|
||||
view.Path = filename;
|
||||
view.Content = contents;
|
||||
currentView.Path = filename;
|
||||
currentView.Content = contents;
|
||||
|
||||
Attempt<IPartialView> attempt;
|
||||
try
|
||||
{
|
||||
var partialView = view as PartialView;
|
||||
var partialView = currentView as PartialView;
|
||||
if (partialView != null && validate != null && validate(svce, partialView) == false)
|
||||
return Failed(ui.Text("speechBubbles", "partialViewErrorText"), ui.Text("speechBubbles", "partialViewErrorHeader"),
|
||||
new FileSecurityException("File '" + view.Path + "' is not a valid partial view file."));
|
||||
new FileSecurityException("File '" + currentView.Path + "' is not a valid partial view file."));
|
||||
|
||||
attempt = save(svce, view);
|
||||
attempt = save(svce, currentView);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
||||
@@ -602,7 +602,7 @@ namespace umbraco
|
||||
XmlDocument mXml = new XmlDocument();
|
||||
mXml.LoadXml(m.ToXml(mXml, false).OuterXml);
|
||||
XPathNavigator xp = mXml.CreateNavigator();
|
||||
return xp.Select("/node");
|
||||
return xp.Select("/node()");
|
||||
}
|
||||
|
||||
XmlDocument xd = new XmlDocument();
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Web;
|
||||
@@ -71,7 +72,7 @@ namespace umbraco
|
||||
else
|
||||
tmp = new Dictionary.DictionaryItem(this.id).Children;
|
||||
|
||||
foreach (Dictionary.DictionaryItem di in tmp)
|
||||
foreach (Dictionary.DictionaryItem di in tmp.OrderBy(a => a.key))
|
||||
{
|
||||
XmlTreeNode xNode = XmlTreeNode.Create(this);
|
||||
xNode.NodeID = di.id.ToString(); //dictionary_ + id..
|
||||
|
||||
@@ -79,7 +79,7 @@ namespace umbraco.presentation.umbraco.dialogs
|
||||
|
||||
if (IsPostBack == false)
|
||||
{
|
||||
if (Access.IsProtected(documentId, documentObject.Path) && Access.GetProtectionType(documentId) != ProtectionType.NotProtected)
|
||||
if (Access.IsProtected(documentId) && Access.GetProtectionType(documentId) != ProtectionType.NotProtected)
|
||||
{
|
||||
bt_buttonRemoveProtection.Visible = true;
|
||||
bt_buttonRemoveProtection.Attributes.Add("onClick", "return confirm('" + ui.Text("areyousure") + "')");
|
||||
@@ -263,10 +263,11 @@ namespace umbraco.presentation.umbraco.dialogs
|
||||
p_buttons.Visible = false;
|
||||
pane_advanced.Visible = false;
|
||||
pane_simple.Visible = false;
|
||||
|
||||
var content = ApplicationContext.Current.Services.ContentService.GetById(pageId);
|
||||
//reloads the current node in the tree
|
||||
ClientTools.SyncTree(content.Path, true);
|
||||
|
||||
//reloads the current node's children in the tree
|
||||
ClientTools.ReloadActionNode(false, true);
|
||||
feedback.type = global::umbraco.uicontrols.Feedback.feedbacktype.success;
|
||||
}
|
||||
}
|
||||
@@ -284,8 +285,10 @@ namespace umbraco.presentation.umbraco.dialogs
|
||||
feedback.Text = ui.Text("publicAccess", "paIsRemoved", new cms.businesslogic.CMSNode(pageId).Text) + "</p><p><a href='#' onclick='" + ClientTools.Scripts.CloseModalWindow() + "'>" + ui.Text("closeThisWindow") + "</a>";
|
||||
|
||||
var content = ApplicationContext.Current.Services.ContentService.GetById(pageId);
|
||||
//reloads the current node in the tree
|
||||
ClientTools.SyncTree(content.Path, true);
|
||||
|
||||
//reloads the current node's children in the tree
|
||||
ClientTools.ReloadActionNode(false, true);
|
||||
feedback.type = global::umbraco.uicontrols.Feedback.feedbacktype.success;
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,6 @@ using umbraco.BasePages;
|
||||
using umbraco.BusinessLogic;
|
||||
using umbraco.businesslogic.Exceptions;
|
||||
using umbraco.cms.businesslogic.media;
|
||||
using umbraco.cms.businesslogic.propertytype;
|
||||
using umbraco.cms.businesslogic.web;
|
||||
using umbraco.controls;
|
||||
using umbraco.presentation.channels.businesslogic;
|
||||
@@ -28,7 +27,9 @@ using umbraco.providers;
|
||||
using umbraco.cms.presentation.Trees;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Services;
|
||||
using PropertyType = umbraco.cms.businesslogic.propertytype.PropertyType;
|
||||
|
||||
namespace umbraco.cms.presentation.user
|
||||
{
|
||||
@@ -107,7 +108,7 @@ namespace umbraco.cms.presentation.user
|
||||
}
|
||||
}
|
||||
|
||||
var userCulture = Services.TextService.ConvertToSupportedCultureWithRegionCode(new CultureInfo(u.Language));
|
||||
var userCulture = UserExtensions.GetUserCulture(u.Language, Services.TextService);
|
||||
|
||||
// Populate ui language lsit
|
||||
foreach (var lang in Services.TextService.GetSupportedCultures())
|
||||
|
||||
@@ -161,7 +161,7 @@ namespace umbraco.presentation.umbraco.webservices
|
||||
var ext = uploadFile.FileName.Substring(uploadFile.FileName.LastIndexOf('.') + 1).ToLower();
|
||||
if (UmbracoConfig.For.UmbracoSettings().Content.DisallowedUploadFiles.Contains(ext))
|
||||
{
|
||||
LogHelper.Warn<MediaUploader>("Cannot upload file " + uploadFile + ", it is not an approved file type");
|
||||
LogHelper.Warn<MediaUploader>("Cannot upload file " + uploadFile.FileName + ", it is not approved in `disallowedUploadFiles` in ~/config/UmbracoSettings.config");
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -213,7 +213,7 @@ namespace umbraco.cms.businesslogic.web
|
||||
var noAccessContent = ApplicationContext.Current.Services.ContentService.GetById(ErrorDocumentId);
|
||||
if (noAccessContent == null) throw new NullReferenceException("No content item found with id " + ErrorDocumentId);
|
||||
|
||||
var entry = ApplicationContext.Current.Services.PublicAccessService.GetEntryForContent(doc.ContentEntity);
|
||||
var entry = ApplicationContext.Current.Services.PublicAccessService.GetEntryForContent(doc.ContentEntity.Id.ToString());
|
||||
if (entry != null)
|
||||
{
|
||||
if (Simple)
|
||||
@@ -420,6 +420,12 @@ namespace umbraco.cms.businesslogic.web
|
||||
return ApplicationContext.Current.Services.PublicAccessService.IsProtected(Path.EnsureEndsWith("," + DocumentId));
|
||||
}
|
||||
|
||||
//return the protection status of this exact document - not based on inheritance
|
||||
public static bool IsProtected(int DocumentId)
|
||||
{
|
||||
return ApplicationContext.Current.Services.PublicAccessService.IsProtected(DocumentId.ToString());
|
||||
}
|
||||
|
||||
public static int GetErrorPage(string Path)
|
||||
{
|
||||
var entry = ApplicationContext.Current.Services.PublicAccessService.GetEntryForContent(Path);
|
||||
|
||||
Reference in New Issue
Block a user