Merge branch 'dev-v7.8' into dev-v7.9
This commit is contained in:
@@ -17,7 +17,7 @@
|
||||
<dependencies>
|
||||
<dependency id="UmbracoCms.Core" version="[$version$]" />
|
||||
<dependency id="Newtonsoft.Json" version="[10.0.2, 11.0.0)" />
|
||||
<dependency id="Umbraco.ModelsBuilder" version="[3.0.8, 4.0.0)" />
|
||||
<dependency id="Umbraco.ModelsBuilder" version="[3.0.10, 4.0.0)" />
|
||||
<dependency id="Microsoft.AspNet.SignalR.Core" version="[2.2.1, 3.0.0)" />
|
||||
<dependency id="ImageProcessor.Web.Config" version="[2.3.1, 3.0.0)" />
|
||||
</dependencies>
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace Umbraco.Core.Collections
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="CompositeTypeTypeKey"/> struct.
|
||||
/// </summary>
|
||||
public CompositeTypeTypeKey(Type type1, Type type2)
|
||||
public CompositeTypeTypeKey(Type type1, Type type2) : this()
|
||||
{
|
||||
Type1 = type1;
|
||||
Type2 = type2;
|
||||
@@ -19,26 +19,35 @@ namespace Umbraco.Core.Collections
|
||||
/// <summary>
|
||||
/// Gets the first type.
|
||||
/// </summary>
|
||||
public Type Type1 { get; }
|
||||
public Type Type1 { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the second type.
|
||||
/// </summary>
|
||||
public Type Type2 { get; }
|
||||
public Type Type2 { get; private set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool Equals(CompositeTypeTypeKey other)
|
||||
=> Type1 == other.Type1 && Type2 == other.Type2;
|
||||
{
|
||||
return Type1 == other.Type1 && Type2 == other.Type2;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool Equals(object obj)
|
||||
=> obj is CompositeTypeTypeKey other && Type1 == other.Type1 && Type2 == other.Type2;
|
||||
{
|
||||
var other = obj is CompositeTypeTypeKey ? (CompositeTypeTypeKey)obj : default(CompositeTypeTypeKey);
|
||||
return Type1 == other.Type1 && Type2 == other.Type2;
|
||||
}
|
||||
|
||||
public static bool operator ==(CompositeTypeTypeKey key1, CompositeTypeTypeKey key2)
|
||||
=> key1.Type1 == key2.Type1 && key1.Type2 == key2.Type2;
|
||||
{
|
||||
return key1.Type1 == key2.Type1 && key1.Type2 == key2.Type2;
|
||||
}
|
||||
|
||||
public static bool operator !=(CompositeTypeTypeKey key1, CompositeTypeTypeKey key2)
|
||||
=> key1.Type1 != key2.Type1 || key1.Type2 != key2.Type2;
|
||||
{
|
||||
return key1.Type1 != key2.Type1 || key1.Type2 != key2.Type2;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override int GetHashCode()
|
||||
|
||||
@@ -140,7 +140,8 @@ namespace Umbraco.Core
|
||||
if (underlying != null)
|
||||
{
|
||||
// Special case for empty strings for bools/dates which should return null if an empty string.
|
||||
if (input is string inputString)
|
||||
var inputString = input as string;
|
||||
if (inputString != null)
|
||||
{
|
||||
if (string.IsNullOrEmpty(inputString) && (underlying == typeof(DateTime) || underlying == typeof(bool)))
|
||||
{
|
||||
@@ -166,7 +167,8 @@ namespace Umbraco.Core
|
||||
{
|
||||
// target is not a generic type
|
||||
|
||||
if (input is string inputString)
|
||||
var inputString = input as string;
|
||||
if (inputString != null)
|
||||
{
|
||||
// Try convert from string, returns an Attempt if the string could be
|
||||
// processed (either succeeded or failed), else null if we need to try
|
||||
@@ -207,7 +209,8 @@ namespace Umbraco.Core
|
||||
}
|
||||
|
||||
// Re-check convertables since we altered the input through recursion
|
||||
if (input is IConvertible convertible2)
|
||||
var convertible2 = input as IConvertible;
|
||||
if (convertible2 != null)
|
||||
{
|
||||
return Attempt.Succeed(Convert.ChangeType(convertible2, target));
|
||||
}
|
||||
@@ -265,7 +268,8 @@ namespace Umbraco.Core
|
||||
{
|
||||
if (target == typeof(int))
|
||||
{
|
||||
if (int.TryParse(input, out var value))
|
||||
int value;
|
||||
if (int.TryParse(input, out value))
|
||||
{
|
||||
return Attempt<object>.Succeed(value);
|
||||
}
|
||||
@@ -273,26 +277,30 @@ namespace Umbraco.Core
|
||||
// Because decimal 100.01m will happily convert to integer 100, it
|
||||
// makes sense that string "100.01" *also* converts to integer 100.
|
||||
var input2 = NormalizeNumberDecimalSeparator(input);
|
||||
return Attempt<object>.SucceedIf(decimal.TryParse(input2, out var value2), Convert.ToInt32(value2));
|
||||
decimal value2;
|
||||
return Attempt<object>.SucceedIf(decimal.TryParse(input2, out value2), Convert.ToInt32(value2));
|
||||
}
|
||||
|
||||
if (target == typeof(long))
|
||||
{
|
||||
if (long.TryParse(input, out var value))
|
||||
long value;
|
||||
if (long.TryParse(input, out value))
|
||||
{
|
||||
return Attempt<object>.Succeed(value);
|
||||
}
|
||||
|
||||
// Same as int
|
||||
var input2 = NormalizeNumberDecimalSeparator(input);
|
||||
return Attempt<object>.SucceedIf(decimal.TryParse(input2, out var value2), Convert.ToInt64(value2));
|
||||
decimal value2;
|
||||
return Attempt<object>.SucceedIf(decimal.TryParse(input2, out value2), Convert.ToInt64(value2));
|
||||
}
|
||||
|
||||
// TODO: Should we do the decimal trick for short, byte, unsigned?
|
||||
|
||||
if (target == typeof(bool))
|
||||
{
|
||||
if (bool.TryParse(input, out var value))
|
||||
bool value;
|
||||
if (bool.TryParse(input, out value))
|
||||
{
|
||||
return Attempt<object>.Succeed(value);
|
||||
}
|
||||
@@ -305,42 +313,53 @@ namespace Umbraco.Core
|
||||
switch (Type.GetTypeCode(target))
|
||||
{
|
||||
case TypeCode.Int16:
|
||||
return Attempt<object>.SucceedIf(short.TryParse(input, out var value), value);
|
||||
short value;
|
||||
return Attempt<object>.SucceedIf(short.TryParse(input, out value), value);
|
||||
|
||||
case TypeCode.Double:
|
||||
var input2 = NormalizeNumberDecimalSeparator(input);
|
||||
return Attempt<object>.SucceedIf(double.TryParse(input2, out var valueD), valueD);
|
||||
double valueD;
|
||||
return Attempt<object>.SucceedIf(double.TryParse(input2, out valueD), valueD);
|
||||
|
||||
case TypeCode.Single:
|
||||
var input3 = NormalizeNumberDecimalSeparator(input);
|
||||
return Attempt<object>.SucceedIf(float.TryParse(input3, out var valueF), valueF);
|
||||
float valueF;
|
||||
return Attempt<object>.SucceedIf(float.TryParse(input3, out valueF), valueF);
|
||||
|
||||
case TypeCode.Char:
|
||||
return Attempt<object>.SucceedIf(char.TryParse(input, out var valueC), valueC);
|
||||
char valueC;
|
||||
return Attempt<object>.SucceedIf(char.TryParse(input, out valueC), valueC);
|
||||
|
||||
case TypeCode.Byte:
|
||||
return Attempt<object>.SucceedIf(byte.TryParse(input, out var valueB), valueB);
|
||||
byte valueB;
|
||||
return Attempt<object>.SucceedIf(byte.TryParse(input, out valueB), valueB);
|
||||
|
||||
case TypeCode.SByte:
|
||||
return Attempt<object>.SucceedIf(sbyte.TryParse(input, out var valueSb), valueSb);
|
||||
sbyte valueSb;
|
||||
return Attempt<object>.SucceedIf(sbyte.TryParse(input, out valueSb), valueSb);
|
||||
|
||||
case TypeCode.UInt32:
|
||||
return Attempt<object>.SucceedIf(uint.TryParse(input, out var valueU), valueU);
|
||||
uint valueU;
|
||||
return Attempt<object>.SucceedIf(uint.TryParse(input, out valueU), valueU);
|
||||
|
||||
case TypeCode.UInt16:
|
||||
return Attempt<object>.SucceedIf(ushort.TryParse(input, out var valueUs), valueUs);
|
||||
ushort valueUs;
|
||||
return Attempt<object>.SucceedIf(ushort.TryParse(input, out valueUs), valueUs);
|
||||
|
||||
case TypeCode.UInt64:
|
||||
return Attempt<object>.SucceedIf(ulong.TryParse(input, out var valueUl), valueUl);
|
||||
ulong valueUl;
|
||||
return Attempt<object>.SucceedIf(ulong.TryParse(input, out valueUl), valueUl);
|
||||
}
|
||||
}
|
||||
else if (target == typeof(Guid))
|
||||
{
|
||||
return Attempt<object>.SucceedIf(Guid.TryParse(input, out var value), value);
|
||||
Guid value;
|
||||
return Attempt<object>.SucceedIf(Guid.TryParse(input, out value), value);
|
||||
}
|
||||
else if (target == typeof(DateTime))
|
||||
{
|
||||
if (DateTime.TryParse(input, out var value))
|
||||
DateTime value;
|
||||
if (DateTime.TryParse(input, out value))
|
||||
{
|
||||
switch (value.Kind)
|
||||
{
|
||||
@@ -360,20 +379,24 @@ namespace Umbraco.Core
|
||||
}
|
||||
else if (target == typeof(DateTimeOffset))
|
||||
{
|
||||
return Attempt<object>.SucceedIf(DateTimeOffset.TryParse(input, out var value), value);
|
||||
DateTimeOffset value;
|
||||
return Attempt<object>.SucceedIf(DateTimeOffset.TryParse(input, out value), value);
|
||||
}
|
||||
else if (target == typeof(TimeSpan))
|
||||
{
|
||||
return Attempt<object>.SucceedIf(TimeSpan.TryParse(input, out var value), value);
|
||||
TimeSpan value;
|
||||
return Attempt<object>.SucceedIf(TimeSpan.TryParse(input, out value), value);
|
||||
}
|
||||
else if (target == typeof(decimal))
|
||||
{
|
||||
var input2 = NormalizeNumberDecimalSeparator(input);
|
||||
return Attempt<object>.SucceedIf(decimal.TryParse(input2, out var value), value);
|
||||
decimal value;
|
||||
return Attempt<object>.SucceedIf(decimal.TryParse(input2, out value), value);
|
||||
}
|
||||
else if (input != null && target == typeof(Version))
|
||||
{
|
||||
return Attempt<object>.SucceedIf(Version.TryParse(input, out var value), value);
|
||||
Version value;
|
||||
return Attempt<object>.SucceedIf(Version.TryParse(input, out value), value);
|
||||
}
|
||||
|
||||
// E_NOTIMPL IPAddress, BigInteger
|
||||
@@ -658,7 +681,8 @@ namespace Umbraco.Core
|
||||
{
|
||||
var key = new CompositeTypeTypeKey(source, target);
|
||||
|
||||
if (InputTypeConverterCache.TryGetValue(key, out TypeConverter typeConverter))
|
||||
TypeConverter typeConverter;
|
||||
if (InputTypeConverterCache.TryGetValue(key, out typeConverter))
|
||||
{
|
||||
return typeConverter;
|
||||
}
|
||||
@@ -678,7 +702,8 @@ namespace Umbraco.Core
|
||||
{
|
||||
var key = new CompositeTypeTypeKey(source, target);
|
||||
|
||||
if (DestinationTypeConverterCache.TryGetValue(key, out TypeConverter typeConverter))
|
||||
TypeConverter typeConverter;
|
||||
if (DestinationTypeConverterCache.TryGetValue(key, out typeConverter))
|
||||
{
|
||||
return typeConverter;
|
||||
}
|
||||
@@ -696,7 +721,8 @@ namespace Umbraco.Core
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static Type GetCachedGenericNullableType(Type type)
|
||||
{
|
||||
if (NullableGenericCache.TryGetValue(type, out Type underlyingType))
|
||||
Type underlyingType;
|
||||
if (NullableGenericCache.TryGetValue(type, out underlyingType))
|
||||
{
|
||||
return underlyingType;
|
||||
}
|
||||
@@ -715,7 +741,8 @@ namespace Umbraco.Core
|
||||
private static bool GetCachedCanAssign(object input, Type source, Type target)
|
||||
{
|
||||
var key = new CompositeTypeTypeKey(source, target);
|
||||
if (AssignableTypeCache.TryGetValue(key, out bool canConvert))
|
||||
bool canConvert;
|
||||
if (AssignableTypeCache.TryGetValue(key, out canConvert))
|
||||
{
|
||||
return canConvert;
|
||||
}
|
||||
@@ -734,7 +761,8 @@ namespace Umbraco.Core
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static bool GetCachedCanConvertToBoolean(Type type)
|
||||
{
|
||||
if (BoolConvertCache.TryGetValue(type, out bool result))
|
||||
bool result;
|
||||
if (BoolConvertCache.TryGetValue(type, out result))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -401,9 +401,10 @@ namespace Umbraco.Core.Publishing
|
||||
content.Name, content.Id));
|
||||
}
|
||||
|
||||
// if newest is published, unpublish
|
||||
if (content.Published)
|
||||
content.ChangePublishedState(PublishedState.Unpublished);
|
||||
// make sure we dirty .Published and always unpublish
|
||||
// the version we have here could be the newest, !Published
|
||||
content.ChangePublishedState(PublishedState.Published);
|
||||
content.ChangePublishedState(PublishedState.Unpublished);
|
||||
|
||||
_logger.Info<PublishingStrategy>(
|
||||
string.Format("Content '{0}' with Id '{1}' has been unpublished.",
|
||||
|
||||
@@ -884,8 +884,8 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
|
||||
{
|
||||
var repository = RepositoryFactory.CreateContentRepository(uow);
|
||||
var query = Query<IContent>.Builder.Where(x => x.Published && x.ExpireDate <= DateTime.Now);
|
||||
return repository.GetByQuery(query);
|
||||
var query = Query<IContent>.Builder.Where(x => x.ExpireDate <= DateTime.Now);
|
||||
return repository.GetByQuery(query).Where(x => x.HasPublishedVersion);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@ namespace Umbraco.Core.Sync
|
||||
if (newApplicationUrl)
|
||||
{
|
||||
appContext._umbracoApplicationDomains.Add(applicationUrl);
|
||||
LogHelper.Info(typeof(ApplicationUrlHelper), $"New ApplicationUrl detected: {applicationUrl}");
|
||||
LogHelper.Info(typeof(ApplicationUrlHelper), string.Format("New ApplicationUrl detected: {0}", applicationUrl));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -37,7 +37,8 @@ namespace Umbraco.Tests.Benchmarks
|
||||
{
|
||||
// This method is 10% faster
|
||||
var key = new CompositeTypeTypeKey(source, target);
|
||||
if (AssignableTypeCache.TryGetValue(key, out bool canConvert))
|
||||
bool canConvert;
|
||||
if (AssignableTypeCache.TryGetValue(key, out canConvert))
|
||||
{
|
||||
return canConvert;
|
||||
}
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 440 KiB After Width: | Height: | Size: 386 KiB |
@@ -25,6 +25,7 @@ The tour object consist of two parts - The overall tour configuration and a list
|
||||
"group": "My Custom Group" // Used to group tours in the help drawer
|
||||
"groupOrder": 200 // Control the order of tour groups
|
||||
"allowDisable": // Adds a "Don't" show this tour again"-button to the intro step
|
||||
"requiredSections":["content", "media", "mySection"] // Sections that the tour will access while running, if the user does not have access to the required tour sections, the tour will not load.
|
||||
"steps": [] // tour steps - see next example
|
||||
}
|
||||
</pre>
|
||||
|
||||
@@ -212,6 +212,9 @@
|
||||
throw "Tour " + tour.alias + " is missing tour steps";
|
||||
}
|
||||
|
||||
if (tour.requiredSections.length === 0) {
|
||||
throw "Tour " + tour.alias + " is missing the required sections";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -14,7 +14,6 @@ function SearchController($scope, searchService, $log, $location, navigationServ
|
||||
$scope.isSearching = false;
|
||||
$scope.selectedResult = -1;
|
||||
|
||||
|
||||
$scope.navigateResults = function (ev) {
|
||||
//38: up 40: down, 13: enter
|
||||
|
||||
@@ -34,24 +33,37 @@ function SearchController($scope, searchService, $log, $location, navigationServ
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
var group = undefined;
|
||||
var groupNames = [];
|
||||
var groupIndex = -1;
|
||||
var itemIndex = -1;
|
||||
$scope.selectedItem = undefined;
|
||||
|
||||
|
||||
$scope.clearSearch = function () {
|
||||
$scope.searchTerm = null;
|
||||
};
|
||||
function iterateResults(up) {
|
||||
//default group
|
||||
if (!group) {
|
||||
group = $scope.groups[0];
|
||||
|
||||
for (var g in $scope.groups) {
|
||||
if ($scope.groups.hasOwnProperty(g)) {
|
||||
groupNames.push(g);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//Sorting to match the groups order
|
||||
groupNames.sort();
|
||||
|
||||
group = $scope.groups[groupNames[0]];
|
||||
groupIndex = 0;
|
||||
}
|
||||
|
||||
if (up) {
|
||||
if (itemIndex === 0) {
|
||||
if (groupIndex === 0) {
|
||||
gotoGroup($scope.groups.length - 1, true);
|
||||
gotoGroup(Object.keys($scope.groups).length - 1, true);
|
||||
} else {
|
||||
gotoGroup(groupIndex - 1, true);
|
||||
}
|
||||
@@ -62,7 +74,7 @@ function SearchController($scope, searchService, $log, $location, navigationServ
|
||||
if (itemIndex < group.results.length - 1) {
|
||||
gotoItem(itemIndex + 1);
|
||||
} else {
|
||||
if (groupIndex === $scope.groups.length - 1) {
|
||||
if (groupIndex === Object.keys($scope.groups).length - 1) {
|
||||
gotoGroup(0);
|
||||
} else {
|
||||
gotoGroup(groupIndex + 1);
|
||||
@@ -73,7 +85,7 @@ function SearchController($scope, searchService, $log, $location, navigationServ
|
||||
|
||||
function gotoGroup(index, up) {
|
||||
groupIndex = index;
|
||||
group = $scope.groups[groupIndex];
|
||||
group = $scope.groups[groupNames[groupIndex]];
|
||||
|
||||
if (up) {
|
||||
gotoItem(group.results.length - 1);
|
||||
@@ -95,6 +107,13 @@ function SearchController($scope, searchService, $log, $location, navigationServ
|
||||
$scope.hasResults = false;
|
||||
if ($scope.searchTerm) {
|
||||
if (newVal !== null && newVal !== undefined && newVal !== oldVal) {
|
||||
|
||||
//Resetting for brand new search
|
||||
group = undefined;
|
||||
groupNames = [];
|
||||
groupIndex = -1;
|
||||
itemIndex = -1;
|
||||
|
||||
$scope.isSearching = true;
|
||||
navigationService.showSearch();
|
||||
$scope.selectedItem = undefined;
|
||||
@@ -114,7 +133,7 @@ function SearchController($scope, searchService, $log, $location, navigationServ
|
||||
var filtered = {};
|
||||
_.each(result, function (value, key) {
|
||||
if (value.results.length > 0) {
|
||||
filtered[key] = value;
|
||||
filtered[key] = value;
|
||||
}
|
||||
});
|
||||
$scope.groups = filtered;
|
||||
|
||||
@@ -332,8 +332,8 @@
|
||||
<Name>umbraco.providers</Name>
|
||||
</ProjectReference>
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="Umbraco.ModelsBuilder, Version=3.0.8.100, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Umbraco.ModelsBuilder.3.0.8\lib\Umbraco.ModelsBuilder.dll</HintPath>
|
||||
<Reference Include="Umbraco.ModelsBuilder, Version=3.0.10.102, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Umbraco.ModelsBuilder.3.0.10\lib\Umbraco.ModelsBuilder.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
@@ -1027,9 +1027,9 @@ xcopy "$(ProjectDir)"..\packages\SqlServerCE.4.0.0.1\x86\*.* "$(TargetDir)x86\"
|
||||
<DevelopmentServerPort>7800</DevelopmentServerPort>
|
||||
<DevelopmentServerVPath>/</DevelopmentServerVPath>
|
||||
<IISUrl>http://localhost:7800</IISUrl>
|
||||
<DevelopmentServerPort>7790</DevelopmentServerPort>
|
||||
<DevelopmentServerPort>7800</DevelopmentServerPort>
|
||||
<DevelopmentServerVPath>/</DevelopmentServerVPath>
|
||||
<IISUrl>http://localhost:7790</IISUrl>
|
||||
<IISUrl>http://localhost:7800</IISUrl>
|
||||
<NTLMAuthentication>False</NTLMAuthentication>
|
||||
<UseCustomServer>False</UseCustomServer>
|
||||
<CustomServerUrl>
|
||||
|
||||
@@ -5,6 +5,15 @@
|
||||
"group": "Getting Started",
|
||||
"groupOrder": 100,
|
||||
"allowDisable": true,
|
||||
"requiredSections": [
|
||||
"content",
|
||||
"media",
|
||||
"settings",
|
||||
"developer",
|
||||
"users",
|
||||
"member",
|
||||
"forms"
|
||||
],
|
||||
"steps": [
|
||||
{
|
||||
"title": "Welcome to Umbraco - The Friendly CMS",
|
||||
@@ -25,7 +34,6 @@
|
||||
"content": "Each area in Umbraco is called a <b>Section</b>. Right now you are in the Content section, when you want to go to another section simply click on the appropriate icon in the main menu and you'll be there in no time.",
|
||||
"backdropOpacity": 0.6
|
||||
},
|
||||
|
||||
{
|
||||
"element": "#tree",
|
||||
"elementPreventClick": true,
|
||||
@@ -88,6 +96,15 @@
|
||||
"alias": "umbIntroCreateDocType",
|
||||
"group": "Getting Started",
|
||||
"groupOrder": 100,
|
||||
"requiredSections": [
|
||||
"content",
|
||||
"media",
|
||||
"settings",
|
||||
"developer",
|
||||
"users",
|
||||
"member",
|
||||
"forms"
|
||||
],
|
||||
"steps": [
|
||||
{
|
||||
"title": "Create your first Document Type",
|
||||
@@ -203,6 +220,15 @@
|
||||
"alias": "umbIntroCreateContent",
|
||||
"group": "Getting Started",
|
||||
"groupOrder": 100,
|
||||
"requiredSections": [
|
||||
"content",
|
||||
"media",
|
||||
"settings",
|
||||
"developer",
|
||||
"users",
|
||||
"member",
|
||||
"forms"
|
||||
],
|
||||
"steps": [
|
||||
{
|
||||
"title": "Creating your first content node",
|
||||
@@ -253,6 +279,15 @@
|
||||
"alias": "umbIntroRenderInTemplate",
|
||||
"group": "Getting Started",
|
||||
"groupOrder": 100,
|
||||
"requiredSections": [
|
||||
"content",
|
||||
"media",
|
||||
"settings",
|
||||
"developer",
|
||||
"users",
|
||||
"member",
|
||||
"forms"
|
||||
],
|
||||
"steps": [
|
||||
{
|
||||
"title": "Render your content in a template",
|
||||
@@ -299,6 +334,15 @@
|
||||
"alias": "umbIntroViewHomePage",
|
||||
"group": "Getting Started",
|
||||
"groupOrder": 100,
|
||||
"requiredSections": [
|
||||
"content",
|
||||
"media",
|
||||
"settings",
|
||||
"developer",
|
||||
"users",
|
||||
"member",
|
||||
"forms"
|
||||
],
|
||||
"steps": [
|
||||
{
|
||||
"title": "View your Umbraco site",
|
||||
@@ -339,6 +383,15 @@
|
||||
"alias": "umbIntroMediaSection",
|
||||
"group": "Getting Started",
|
||||
"groupOrder": 100,
|
||||
"requiredSections": [
|
||||
"content",
|
||||
"media",
|
||||
"settings",
|
||||
"developer",
|
||||
"users",
|
||||
"member",
|
||||
"forms"
|
||||
],
|
||||
"steps": [
|
||||
{
|
||||
"title": "How to use the media library",
|
||||
|
||||
@@ -36,5 +36,5 @@
|
||||
<package id="SqlServerCE" version="4.0.0.1" targetFramework="net45" />
|
||||
<package id="System.Collections.Immutable" version="1.1.36" targetFramework="net45" />
|
||||
<package id="System.Reflection.Metadata" version="1.0.21" targetFramework="net45" />
|
||||
<package id="Umbraco.ModelsBuilder" version="3.0.8" targetFramework="net45" />
|
||||
<package id="Umbraco.ModelsBuilder" version="3.0.10" targetFramework="net45" />
|
||||
</packages>
|
||||
@@ -43,6 +43,7 @@
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta name="robots" content="noindex, nofollow">
|
||||
<meta name="pinterest" content="nopin" />
|
||||
|
||||
<title ng-bind="$root.locationTitle">Umbraco</title>
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Web.Script.Serialization;
|
||||
using System.Web;
|
||||
using Newtonsoft.Json;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Cache;
|
||||
@@ -83,36 +83,28 @@ namespace Umbraco.Web.Cache
|
||||
|
||||
public override void Refresh(string jsonPayload)
|
||||
{
|
||||
ClearCache(DeserializeFromJsonPayload(jsonPayload));
|
||||
ClearCache();
|
||||
base.Refresh(jsonPayload);
|
||||
}
|
||||
|
||||
public override void Refresh(int id)
|
||||
{
|
||||
ClearCache(FromMemberGroup(ApplicationContext.Current.Services.MemberGroupService.GetById(id)));
|
||||
ClearCache();
|
||||
base.Refresh(id);
|
||||
}
|
||||
|
||||
public override void Remove(int id)
|
||||
{
|
||||
ClearCache(FromMemberGroup(ApplicationContext.Current.Services.MemberGroupService.GetById(id)));
|
||||
ClearCache();
|
||||
base.Remove(id);
|
||||
}
|
||||
|
||||
private void ClearCache(params JsonPayload[] payloads)
|
||||
private void ClearCache()
|
||||
{
|
||||
if (payloads == null) return;
|
||||
|
||||
var memberGroupCache = ApplicationContext.Current.ApplicationCache.IsolatedRuntimeCache.GetCache<IMemberGroup>();
|
||||
payloads.ForEach(payload =>
|
||||
{
|
||||
if (payload != null && memberGroupCache)
|
||||
{
|
||||
memberGroupCache.Result.ClearCacheByKeySearch(string.Format("{0}.{1}", typeof(IMemberGroup).FullName, payload.Name));
|
||||
memberGroupCache.Result.ClearCacheItem(RepositoryBase.GetCacheIdKey<IMemberGroup>(payload.Id));
|
||||
}
|
||||
});
|
||||
|
||||
// Since we cache by group name, it could be problematic when renaming to
|
||||
// previously existing names - see http://issues.umbraco.org/issue/U4-10846.
|
||||
// To work around this, just clear all the cache items
|
||||
ApplicationContext.Current.ApplicationCache.IsolatedRuntimeCache.ClearCache<IMemberGroup>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,8 +7,6 @@ using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Web.Models;
|
||||
using Umbraco.Web.Mvc;
|
||||
using Umbraco.Web.WebApi.Filters;
|
||||
using Constants = Umbraco.Core.Constants;
|
||||
|
||||
namespace Umbraco.Web.Editors
|
||||
{
|
||||
@@ -64,8 +62,28 @@ namespace Umbraco.Web.Editors
|
||||
}
|
||||
}
|
||||
}
|
||||
//Get all allowed sections for the current user
|
||||
var allowedSections = UmbracoContext.Current.Security.CurrentUser.AllowedSections.ToList();
|
||||
|
||||
return result.OrderBy(x => x.FileName, StringComparer.InvariantCultureIgnoreCase);
|
||||
var toursToBeRemoved = new List<BackOfficeTourFile>();
|
||||
|
||||
//Checking to see if the user has access to the required tour sections, else we remove the tour
|
||||
foreach (var backOfficeTourFile in result)
|
||||
{
|
||||
foreach (var tour in backOfficeTourFile.Tours)
|
||||
{
|
||||
foreach (var toursRequiredSection in tour.RequiredSections)
|
||||
{
|
||||
if (allowedSections.Contains(toursRequiredSection) == false)
|
||||
{
|
||||
toursToBeRemoved.Add(backOfficeTourFile);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result.Except(toursToBeRemoved).OrderBy(x => x.FileName, StringComparer.InvariantCultureIgnoreCase);
|
||||
}
|
||||
|
||||
private void TryParseTourFile(string tourFile,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Runtime.Serialization;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Umbraco.Web.Models
|
||||
{
|
||||
@@ -18,6 +19,8 @@ namespace Umbraco.Web.Models
|
||||
public int GroupOrder { get; set; }
|
||||
[DataMember(Name = "allowDisable")]
|
||||
public bool AllowDisable { get; set; }
|
||||
[DataMember(Name = "requiredSections")]
|
||||
public List<string> RequiredSections { get; set; }
|
||||
[DataMember(Name = "steps")]
|
||||
public BackOfficeTourStep[] Steps { get; set; }
|
||||
}
|
||||
|
||||
@@ -47,7 +47,6 @@ using System.Security;
|
||||
[assembly: InternalsVisibleTo("Umbraco.Forms.Core.Providers")]
|
||||
[assembly: InternalsVisibleTo("Umbraco.Forms.Web")]
|
||||
|
||||
[assembly: InternalsVisibleTo("Umbraco.Headless")]
|
||||
|
||||
//allow custom unit-testing code to access internals through custom adapters
|
||||
[assembly: InternalsVisibleTo("Umbraco.VisualStudio")] // backwards compat.
|
||||
|
||||
27
src/Umbraco.Web/Security/OwinExtensions.cs
Normal file
27
src/Umbraco.Web/Security/OwinExtensions.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
using System;
|
||||
using System.Web;
|
||||
using Microsoft.AspNet.Identity.Owin;
|
||||
using Microsoft.Owin;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Models.Identity;
|
||||
using Umbraco.Core.Security;
|
||||
using Umbraco.Web.Security.Identity;
|
||||
|
||||
namespace Umbraco.Web.Security
|
||||
{
|
||||
internal static class OwinExtensions
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Nasty little hack to get httpcontextbase from an owin context
|
||||
/// </summary>
|
||||
/// <param name="owinContext"></param>
|
||||
/// <returns></returns>
|
||||
internal static Attempt<HttpContextBase> TryGetHttpContext(this IOwinContext owinContext)
|
||||
{
|
||||
var ctx = owinContext.Get<HttpContextBase>(typeof(HttpContextBase).FullName);
|
||||
return ctx == null ? Attempt<HttpContextBase>.Fail() : Attempt.Succeed(ctx);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.27004.2005
|
||||
VisualStudioVersion = 14.0.25420.1
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Umbraco.Web.UI", "Umbraco.Web.UI\Umbraco.Web.UI.csproj", "{4C4C194C-B5E4-4991-8F87-4373E24CC19F}"
|
||||
EndProject
|
||||
|
||||
Reference in New Issue
Block a user