diff --git a/.github/README.md b/.github/README.md index 5316ad0604..83de27c859 100644 --- a/.github/README.md +++ b/.github/README.md @@ -48,4 +48,5 @@ Umbraco is contribution focused and community driven. If you want to contribute Another way you can contribute to Umbraco is by providing issue reports. For information on how to submit an issue report refer to our [online guide for reporting issues](CONTRIBUTING_DETAILED.md#reporting-bugs). -To view existing issues, please visit [http://issues.umbraco.org](http://issues.umbraco.org). +You can comment and report issues on the [github issue tracker](https://github.com/umbraco/Umbraco-CMS/issues). +Since [September 2018](https://umbraco.com/blog/a-second-take-on-umbraco-issue-tracker-hello-github-issues/) the old issue tracker is in read only mode, but can still be found at [http://issues.umbraco.org](http://issues.umbraco.org). diff --git a/build/NuSpecs/tools/Readme.txt b/build/NuSpecs/tools/Readme.txt index dd8874cce7..53915436ac 100644 --- a/build/NuSpecs/tools/Readme.txt +++ b/build/NuSpecs/tools/Readme.txt @@ -21,6 +21,6 @@ The following items will now be automatically included when creating a deploy pa system: umbraco, config\splashes and global.asax. Please read the release notes on our.umbraco.com: -http://our.umbraco.com/contribute/releases +https://our.umbraco.com/download/releases - Umbraco diff --git a/src/Umbraco.Core/Configuration/UmbracoSettings/ContentElement.cs b/src/Umbraco.Core/Configuration/UmbracoSettings/ContentElement.cs index 332de45734..39861ac4e9 100644 --- a/src/Umbraco.Core/Configuration/UmbracoSettings/ContentElement.cs +++ b/src/Umbraco.Core/Configuration/UmbracoSettings/ContentElement.cs @@ -81,6 +81,12 @@ namespace Umbraco.Core.Configuration.UmbracoSettings [ConfigurationProperty("loginBackgroundImage")] internal InnerTextConfigurationElement LoginBackgroundImage => GetOptionalTextElement("loginBackgroundImage", string.Empty); + [ConfigurationProperty("StripUdiAttributes")] + internal InnerTextConfigurationElement StripUdiAttributes + { + get { return GetOptionalTextElement("StripUdiAttributes", true); } + } + string IContentSection.NotificationEmailAddress => Notifications.NotificationEmailAddress; @@ -136,6 +142,8 @@ namespace Umbraco.Core.Configuration.UmbracoSettings bool IContentSection.EnableInheritedMediaTypes => EnableInheritedMediaTypes; + bool IContentSection.StripUdiAttributes => StripUdiAttributes; + string IContentSection.LoginBackgroundImage => LoginBackgroundImage; } } diff --git a/src/Umbraco.Core/Configuration/UmbracoSettings/IContentSection.cs b/src/Umbraco.Core/Configuration/UmbracoSettings/IContentSection.cs index 7f6f57f4cf..ef9ffeb014 100644 --- a/src/Umbraco.Core/Configuration/UmbracoSettings/IContentSection.cs +++ b/src/Umbraco.Core/Configuration/UmbracoSettings/IContentSection.cs @@ -14,7 +14,7 @@ namespace Umbraco.Core.Configuration.UmbracoSettings IEnumerable ImageTagAllowedAttributes { get; } IEnumerable ImageAutoFillProperties { get; } - + string ScriptFolderPath { get; } IEnumerable ScriptFileTypes { get; } @@ -66,5 +66,7 @@ namespace Umbraco.Core.Configuration.UmbracoSettings bool EnableInheritedMediaTypes { get; } string LoginBackgroundImage { get; } + bool StripUdiAttributes { get; } + } } diff --git a/src/Umbraco.Core/Constants-Conventions.cs b/src/Umbraco.Core/Constants-Conventions.cs index 2930cf1fff..eb1a6e2925 100644 --- a/src/Umbraco.Core/Constants-Conventions.cs +++ b/src/Umbraco.Core/Constants-Conventions.cs @@ -91,6 +91,11 @@ namespace Umbraco.Core /// Property alias for the Media's file extension. /// public const string Extension = "umbracoExtension"; + + /// + /// The default height/width of an image file if the size can't be determined from the metadata + /// + public const int DefaultSize = 200; } /// diff --git a/src/Umbraco.Core/Constants-System.cs b/src/Umbraco.Core/Constants-System.cs index eaceff275e..abb92298f4 100644 --- a/src/Umbraco.Core/Constants-System.cs +++ b/src/Umbraco.Core/Constants-System.cs @@ -58,6 +58,7 @@ /// public const string RecycleBinMediaPathPrefix = "-1,-21,"; + public const int DefaultLabelDataTypeId = -92; public const string UmbracoConnectionName = "umbracoDbDSN"; public const string UmbracoUpgradePlanName = "Umbraco.Core"; } diff --git a/src/Umbraco.Core/Media/Exif/SVGFile.cs b/src/Umbraco.Core/Media/Exif/SVGFile.cs new file mode 100644 index 0000000000..bc4d94749c --- /dev/null +++ b/src/Umbraco.Core/Media/Exif/SVGFile.cs @@ -0,0 +1,37 @@ +using System; +using System.Drawing; +using System.IO; +using System.Linq; +using System.Xml.Linq; + +namespace Umbraco.Core.Media.Exif +{ + internal class SVGFile : ImageFile + { + public SVGFile(Stream fileStream) + { + fileStream.Position = 0; + + var document = XDocument.Load(fileStream); //if it throws an exception the ugly try catch in MediaFileSystem will catch it + + var width = document.Root?.Attributes().Where(x => x.Name == "width").Select(x => x.Value).FirstOrDefault(); + var height = document.Root?.Attributes().Where(x => x.Name == "height").Select(x => x.Value).FirstOrDefault(); + + Properties.Add(new ExifSInt(ExifTag.PixelYDimension, + height == null ? Constants.Conventions.Media.DefaultSize : int.Parse(height))); + Properties.Add(new ExifSInt(ExifTag.PixelXDimension, + width == null ? Constants.Conventions.Media.DefaultSize : int.Parse(width))); + + Format = ImageFileFormat.SVG; + } + + public override void Save(Stream stream) + { + } + + public override Image ToImage() + { + throw new NotImplementedException(); + } + } +} diff --git a/src/Umbraco.Core/Media/TypeDetector/JpegDetector.cs b/src/Umbraco.Core/Media/TypeDetector/JpegDetector.cs new file mode 100644 index 0000000000..5b68f6ad88 --- /dev/null +++ b/src/Umbraco.Core/Media/TypeDetector/JpegDetector.cs @@ -0,0 +1,14 @@ +using System.IO; + +namespace Umbraco.Core.Media.TypeDetector +{ + public class JPEGDetector : RasterizedTypeDetector + { + public static bool IsOfType(Stream fileStream) + { + var header = GetFileHeader(fileStream); + + return header[0] == 0xff && header[1] == 0xD8; + } + } +} diff --git a/src/Umbraco.Core/Media/TypeDetector/RasterizedTypeDetector.cs b/src/Umbraco.Core/Media/TypeDetector/RasterizedTypeDetector.cs new file mode 100644 index 0000000000..9777d55c20 --- /dev/null +++ b/src/Umbraco.Core/Media/TypeDetector/RasterizedTypeDetector.cs @@ -0,0 +1,16 @@ +using System.IO; + +namespace Umbraco.Core.Media.TypeDetector +{ + public abstract class RasterizedTypeDetector + { + public static byte[] GetFileHeader(Stream fileStream) + { + fileStream.Seek(0, SeekOrigin.Begin); + byte[] header = new byte[8]; + fileStream.Seek(0, SeekOrigin.Begin); + + return header; + } + } +} diff --git a/src/Umbraco.Core/Media/TypeDetector/SVGDetector.cs b/src/Umbraco.Core/Media/TypeDetector/SVGDetector.cs new file mode 100644 index 0000000000..ab9659ca1e --- /dev/null +++ b/src/Umbraco.Core/Media/TypeDetector/SVGDetector.cs @@ -0,0 +1,24 @@ +using System.IO; +using System.Xml.Linq; + +namespace Umbraco.Core.Media.TypeDetector +{ + public class SVGDetector + { + public static bool IsOfType(Stream fileStream) + { + var document = new XDocument(); + + try + { + document = XDocument.Load(fileStream); + } + catch (System.Exception ex) + { + return false; + } + + return document.Root?.Name.LocalName == "svg"; + } + } +} diff --git a/src/Umbraco.Core/Media/TypeDetector/TIFFDetector.cs b/src/Umbraco.Core/Media/TypeDetector/TIFFDetector.cs new file mode 100644 index 0000000000..2a6e42d0e0 --- /dev/null +++ b/src/Umbraco.Core/Media/TypeDetector/TIFFDetector.cs @@ -0,0 +1,24 @@ +using System.IO; +using System.Text; + +namespace Umbraco.Core.Media.TypeDetector +{ + public class TIFFDetector + { + public static bool IsOfType(Stream fileStream) + { + string tiffHeader = GetFileHeader(fileStream); + + return tiffHeader == "MM\x00\x2a" || tiffHeader == "II\x2a\x00"; + } + + public static string GetFileHeader(Stream fileStream) + { + var header = RasterizedTypeDetector.GetFileHeader(fileStream); + + string tiffHeader = Encoding.ASCII.GetString(header, 0, 4); + + return tiffHeader; + } + } +} diff --git a/src/Umbraco.Core/Security/AuthenticationExtensions.cs b/src/Umbraco.Core/Security/AuthenticationExtensions.cs index 3b497bff86..fa504cc8f5 100644 --- a/src/Umbraco.Core/Security/AuthenticationExtensions.cs +++ b/src/Umbraco.Core/Security/AuthenticationExtensions.cs @@ -1,7 +1,9 @@ using System; using System.Collections.Concurrent; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Globalization; +using System.Globalization; using System.Linq; using System.Security.Claims; using System.Security.Principal; @@ -63,5 +65,23 @@ namespace Umbraco.Core.Security /// Used so that we aren't creating a new CultureInfo object for every single request /// private static readonly ConcurrentDictionary UserCultures = new ConcurrentDictionary(); + + /// + /// Ensures that the thread culture is set based on the back office user's culture + /// + /// + internal static void EnsureCulture(this IIdentity identity) + { + if (identity is UmbracoBackOfficeIdentity umbIdentity && umbIdentity.IsAuthenticated) + { + Thread.CurrentThread.CurrentUICulture = + Thread.CurrentThread.CurrentCulture = + UserCultures.GetOrAdd(umbIdentity.Culture, s => new CultureInfo(s)); + } + } + /// + /// Used so that we aren't creating a new CultureInfo object for every single request + /// + private static readonly ConcurrentDictionary UserCultures = new ConcurrentDictionary(); } } diff --git a/src/Umbraco.Core/Security/BackOfficeUserStore.cs b/src/Umbraco.Core/Security/BackOfficeUserStore.cs index 63970aca8f..2dc14c727f 100644 --- a/src/Umbraco.Core/Security/BackOfficeUserStore.cs +++ b/src/Umbraco.Core/Security/BackOfficeUserStore.cs @@ -635,7 +635,9 @@ namespace Umbraco.Core.Security || identityUser.LastLoginDateUtc.HasValue && user.LastLoginDate.ToUniversalTime() != identityUser.LastLoginDateUtc.Value) { anythingChanged = true; - user.LastLoginDate = identityUser.LastLoginDateUtc.Value.ToLocalTime(); + //if the LastLoginDate is being set to MinValue, don't convert it ToLocalTime + var dt = identityUser.LastLoginDateUtc == DateTime.MinValue ? DateTime.MinValue : identityUser.LastLoginDateUtc.Value.ToLocalTime(); + user.LastLoginDate = dt; } if (identityUser.IsPropertyDirty("LastPasswordChangeDateUtc") || (user.LastPasswordChangeDate != default(DateTime) && identityUser.LastPasswordChangeDateUtc.HasValue == false) diff --git a/src/Umbraco.Core/Services/Implement/PackagingService.cs b/src/Umbraco.Core/Services/Implement/PackagingService.cs index ef22861947..744262f7f7 100644 --- a/src/Umbraco.Core/Services/Implement/PackagingService.cs +++ b/src/Umbraco.Core/Services/Implement/PackagingService.cs @@ -52,6 +52,7 @@ namespace Umbraco.Core.Services.Implement private readonly IAuditRepository _auditRepository; private readonly IContentTypeRepository _contentTypeRepository; private readonly PropertyEditorCollection _propertyEditors; + private static HttpClient _httpClient; public PackagingService( ILogger logger, diff --git a/src/Umbraco.Core/Sync/ServerRole.cs b/src/Umbraco.Core/Sync/ServerRole.cs index fb8dd784ca..21091e41c5 100644 --- a/src/Umbraco.Core/Sync/ServerRole.cs +++ b/src/Umbraco.Core/Sync/ServerRole.cs @@ -16,7 +16,7 @@ Single = 1, /// - /// In a multi-servers environment, the server is a slave server. + /// In a multi-servers environment, the server is a replica server. /// Replica = 2, diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index d1303c37e5..e15fa503b7 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -1,6 +1,7 @@  + v4.7.2 false @@ -34,6 +35,61 @@ latest + + ..\packages\AutoMapper.3.3.1\lib\net40\AutoMapper.dll + + + ..\packages\AutoMapper.3.3.1\lib\net40\AutoMapper.Net4.dll + + + ..\packages\ClientDependency.1.9.7\lib\net45\ClientDependency.Core.dll + + + ..\packages\HtmlAgilityPack.1.4.9.5\lib\Net45\HtmlAgilityPack.dll + + + ..\packages\ImageProcessor.2.5.6\lib\net45\ImageProcessor.dll + + + ..\packages\log4net.2.0.8\lib\net45-full\log4net.dll + + + ..\packages\Log4Net.Async.2.0.4\lib\net40\Log4Net.Async.dll + + + ..\packages\Microsoft.AspNet.Identity.Core.2.2.1\lib\net45\Microsoft.AspNet.Identity.Core.dll + + + ..\packages\Microsoft.AspNet.Identity.Owin.2.2.1\lib\net45\Microsoft.AspNet.Identity.Owin.dll + + + ..\packages\Microsoft.Owin.3.1.0\lib\net45\Microsoft.Owin.dll + + + ..\packages\Microsoft.Owin.Security.3.1.0\lib\net45\Microsoft.Owin.Security.dll + + + ..\packages\Microsoft.Owin.Security.Cookies.3.1.0\lib\net45\Microsoft.Owin.Security.Cookies.dll + + + ..\packages\Microsoft.Owin.Security.OAuth.3.1.0\lib\net45\Microsoft.Owin.Security.OAuth.dll + + + ..\packages\MiniProfiler.2.1.0\lib\net40\MiniProfiler.dll + + + ..\packages\MySql.Data.6.9.9\lib\net45\MySql.Data.dll + True + + + ..\packages\Newtonsoft.Json.10.0.2\lib\net45\Newtonsoft.Json.dll + + + ..\packages\Owin.1.0\lib\net40\Owin.dll + + + ..\packages\semver.1.1.2\lib\net45\Semver.dll + @@ -467,6 +523,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -662,6 +772,440 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1503,4 +2047,12 @@ + + \ No newline at end of file diff --git a/src/Umbraco.Tests/Persistence/Repositories/AuditRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/AuditRepositoryTest.cs index 3bb4a42ba4..855c844949 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/AuditRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/AuditRepositoryTest.cs @@ -60,6 +60,46 @@ namespace Umbraco.Tests.Persistence.Repositories } } + [Test] + public void Get_Paged_Items_By_User_Id_With_Query_And_Filter() + { + var provider = new PetaPocoUnitOfWorkProvider(Logger); + var unitOfWork = provider.GetUnitOfWork(); + using (var repo = new AuditRepository(unitOfWork, CacheHelper, Logger, SqlSyntax)) + { + for (int i = 0; i < 100; i++) + { + repo.AddOrUpdate(new AuditItem(i, string.Format("Content {0} created", i), AuditType.New, 0)); + repo.AddOrUpdate(new AuditItem(i, string.Format("Content {0} published", i), AuditType.Publish, 0)); + } + unitOfWork.Commit(); + } + + using (var repo = new AuditRepository(unitOfWork, CacheHelper, Logger, SqlSyntax)) + { + var query = Query.Builder.Where(x => x.UserId == 0); + + try + { + DatabaseContext.Database.EnableSqlTrace = true; + DatabaseContext.Database.EnableSqlCount(); + + var page = repo.GetPagedResultsByQuery(query, 0, 10, out var total, Direction.Descending, + new[] { AuditType.Publish }, + Query.Builder.Where(x => x.UserId > -1)); + + Assert.AreEqual(10, page.Count()); + Assert.AreEqual(100, total); + } + finally + { + DatabaseContext.Database.EnableSqlTrace = false; + DatabaseContext.Database.DisableSqlCount(); + } + } + } + + [Test] public void Get_Paged_Items_With_AuditType_Filter() { diff --git a/src/Umbraco.Tests/Persistence/Repositories/UserRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/UserRepositoryTest.cs index 1ee8d8fe00..4fca3cb566 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/UserRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/UserRepositoryTest.cs @@ -8,6 +8,7 @@ using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Models.Membership; using Umbraco.Core.Persistence.Mappers; +using Umbraco.Core.Persistence.DatabaseModelDefinitions; using Umbraco.Core.Persistence.Repositories; using Umbraco.Core.Persistence.Repositories.Implement; using Umbraco.Core.Scoping; @@ -338,7 +339,71 @@ namespace Umbraco.Tests.Persistence.Repositories var result = repository.Count(query); // Assert - Assert.That(result, Is.GreaterThanOrEqualTo(2)); + Assert.AreEqual(2, result); + } + } + + [Test] + public void Can_Get_Paged_Results_By_Query_And_Filter_And_Groups() + { + // Arrange + var provider = new PetaPocoUnitOfWorkProvider(Logger); + var unitOfWork = provider.GetUnitOfWork(); + using (var repository = CreateRepository(unitOfWork)) + { + var users = CreateAndCommitMultipleUsers(repository, unitOfWork); + var query = Query.Builder.Where(x => x.Username == "TestUser1" || x.Username == "TestUser2"); + + try + { + DatabaseContext.Database.EnableSqlTrace = true; + DatabaseContext.Database.EnableSqlCount(); + + // Act + var result = repository.GetPagedResultsByQuery(query, 0, 10, out var totalRecs, user => user.Id, Direction.Ascending, + excludeUserGroups: new[] { Constants.Security.TranslatorGroupAlias }, + filter: Query.Builder.Where(x => x.Id > -1)); + + // Assert + Assert.AreEqual(2, totalRecs); + } + finally + { + DatabaseContext.Database.EnableSqlTrace = false; + DatabaseContext.Database.DisableSqlCount(); + } + } + } + + [Test] + public void Can_Get_Paged_Results_With_Filter_And_Groups() + { + // Arrange + var provider = new PetaPocoUnitOfWorkProvider(Logger); + var unitOfWork = provider.GetUnitOfWork(); + using (var repository = CreateRepository(unitOfWork)) + { + var users = CreateAndCommitMultipleUsers(repository, unitOfWork); + + try + { + DatabaseContext.Database.EnableSqlTrace = true; + DatabaseContext.Database.EnableSqlCount(); + + // Act + var result = repository.GetPagedResultsByQuery(null, 0, 10, out var totalRecs, user => user.Id, Direction.Ascending, + includeUserGroups: new[] { Constants.Security.AdminGroupAlias, Constants.Security.SensitiveDataGroupAlias }, + excludeUserGroups: new[] { Constants.Security.TranslatorGroupAlias }, + filter: Query.Builder.Where(x => x.Id == 0)); + + // Assert + Assert.AreEqual(1, totalRecs); + } + finally + { + DatabaseContext.Database.EnableSqlTrace = false; + DatabaseContext.Database.DisableSqlCount(); + } } } diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index 8938d5a409..968f0bc736 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -599,4 +599,827 @@ + + + + Debug + AnyCPU + 8.0.30703 + 2.0 + {5D3B8245-ADA6-453F-A008-50ED04BFE770} + Library + Properties + Umbraco.Tests + Umbraco.Tests + v4.5 + 512 + ..\ + true + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + + $(SolutionDir)\packages + latest + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + false + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + false + + + + ..\packages\AutoMapper.3.3.1\lib\net40\AutoMapper.dll + + + ..\packages\AutoMapper.3.3.1\lib\net40\AutoMapper.Net4.dll + + + ..\packages\Castle.Core.4.0.0\lib\net45\Castle.Core.dll + + + ..\packages\Examine.0.1.89\lib\net45\Examine.dll + + + ..\packages\HtmlAgilityPack.1.4.9.5\lib\Net45\HtmlAgilityPack.dll + + + ..\packages\SharpZipLib.0.86.0\lib\20\ICSharpCode.SharpZipLib.dll + + + ..\packages\log4net.2.0.8\lib\net45-full\log4net.dll + + + ..\packages\Log4Net.Async.2.0.4\lib\net40\Log4Net.Async.dll + + + ..\packages\Lucene.Net.2.9.4.1\lib\net40\Lucene.Net.dll + + + ..\packages\Microsoft.AspNet.Identity.Core.2.2.1\lib\net45\Microsoft.AspNet.Identity.Core.dll + + + ..\packages\Microsoft.Owin.3.1.0\lib\net45\Microsoft.Owin.dll + + + ..\packages\Microsoft.Owin.Host.HttpListener.3.1.0\lib\net45\Microsoft.Owin.Host.HttpListener.dll + + + ..\packages\Microsoft.Owin.Host.SystemWeb.3.1.0\lib\net45\Microsoft.Owin.Host.SystemWeb.dll + + + ..\packages\Microsoft.Owin.Hosting.3.1.0\lib\net45\Microsoft.Owin.Hosting.dll + + + ..\packages\Microsoft.Owin.Security.3.1.0\lib\net45\Microsoft.Owin.Security.dll + + + ..\packages\Microsoft.Owin.Testing.3.1.0\lib\net45\Microsoft.Owin.Testing.dll + + + ..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll + + + ..\packages\MiniProfiler.2.1.0\lib\net40\MiniProfiler.dll + + + ..\packages\Moq.4.1.1309.0919\lib\net40\Moq.dll + + + ..\packages\Newtonsoft.Json.10.0.2\lib\net45\Newtonsoft.Json.dll + + + ..\packages\NUnit.2.6.2\lib\nunit.framework.dll + + + ..\packages\Owin.1.0\lib\net40\Owin.dll + + + ..\packages\semver.1.1.2\lib\net45\Semver.dll + + + + + + + + + ..\packages\SqlServerCE.4.0.0.1\lib\System.Data.SqlServerCe.dll + + + ..\packages\SqlServerCE.4.0.0.1\lib\System.Data.SqlServerCe.Entity.dll + + + + + ..\packages\Microsoft.AspNet.WebApi.Client.5.2.3\lib\net45\System.Net.Http.Formatting.dll + + + + + + + + ..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.Helpers.dll + + + ..\packages\Microsoft.AspNet.WebApi.Core.5.2.3\lib\net45\System.Web.Http.dll + + + ..\packages\Microsoft.AspNet.WebApi.Owin.5.2.3\lib\net45\System.Web.Http.Owin.dll + + + ..\packages\Microsoft.AspNet.WebApi.SelfHost.5.2.3\lib\net45\System.Web.Http.SelfHost.dll + + + ..\packages\Microsoft.AspNet.WebApi.Tracing.5.2.3\lib\net45\System.Web.Http.Tracing.dll + + + ..\packages\Microsoft.AspNet.WebApi.WebHost.5.2.3\lib\net45\System.Web.Http.WebHost.dll + + + ..\packages\Microsoft.AspNet.Mvc.5.2.3\lib\net45\System.Web.Mvc.dll + + + ..\packages\Microsoft.AspNet.Razor.3.2.3\lib\net45\System.Web.Razor.dll + + + + ..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.dll + + + ..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Deployment.dll + + + ..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Razor.dll + + + + + + + + ..\packages\Selenium.WebDriver.2.32.0\lib\net40\WebDriver.dll + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + True + True + SqlResources.resx + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + True + True + ResourceFiles.resx + + + + + + + + + + + + + + + + + + + + + + + + + + + + + True + True + ImportResources.resx + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + True + True + TestFiles.resx + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Designer + + + Designer + Always + + + Designer + Always + + + Designer + Always + + + Designer + Always + + + + + + + Designer + + + + Always + + + + + {5BA5425F-27A7-4677-865E-82246498AA2E} + SqlCE4Umbraco + + + {E469A9CE-1BEC-423F-AC44-713CD72457EA} + umbraco.businesslogic + + + {CCD75EC3-63DB-4184-B49D-51C1DD337230} + umbraco.cms + + + {6EDD2061-82F2-461B-BB6E-879245A832DE} + umbraco.controls + + + {31785BC3-256C-4613-B2F5-A1B0BDDED8C1} + Umbraco.Core + + + {C7CB79F0-1C97-4B33-BFA7-00731B579AE2} + umbraco.datalayer + + + {255F5DF1-4E43-4758-AC05-7A0B68EB021B} + umbraco.editorControls + + + {511F6D8D-7717-440A-9A57-A507E9A8B27F} + umbraco.interfaces + + + {89C09045-1064-466B-B94A-DB3AFE2A5853} + umbraco.MacroEngines + + + {d7636876-0756-43cb-a192-138c6f0d5e42} + umbraco.providers + + + {651E1350-91B6-44B7-BD60-7207006D7003} + Umbraco.Web + + + {07fbc26b-2927-4a22-8d96-d644c667fecc} + UmbracoExamine + + + + + ResXFileCodeGenerator + SqlResources.Designer.cs + Designer + + + ResXFileCodeGenerator + ImportResources.Designer.cs + Designer + + + ResXFileCodeGenerator + ResourceFiles.Designer.cs + + + ResXFileCodeGenerator + TestFiles.Designer.cs + Designer + + + + + False + Microsoft .NET Framework 4 %28x86 and x64%29 + true + + + False + .NET Framework 3.5 SP1 Client Profile + false + + + False + .NET Framework 3.5 SP1 + false + + + False + SQL Server Compact 4.0 SP1 + true + + + False + Windows Installer 4.5 + true + + + + + Designer + Always + + + + + + + Designer + + + Designer + + + + + + + + + + Designer + + + + + + + + + + + + + + + + + xcopy "$(NugetPackages)\SqlServerCE.4.0.0.1\amd64\*.*" "$(TargetDir)amd64\" /Y /F /E /I /C /D +xcopy "$(NugetPackages)\SqlServerCE.4.0.0.1\x86\*.*" "$(TargetDir)x86\" /Y /F /E /I /C /D + + + \ No newline at end of file diff --git a/src/Umbraco.Tests/Web/TemplateUtilitiesTests.cs b/src/Umbraco.Tests/Web/TemplateUtilitiesTests.cs index 0a9638fc30..946e043bab 100644 --- a/src/Umbraco.Tests/Web/TemplateUtilitiesTests.cs +++ b/src/Umbraco.Tests/Web/TemplateUtilitiesTests.cs @@ -1,8 +1,8 @@ using System; using System.Globalization; -using System.Linq; using System.Web; using LightInject; +using HtmlAgilityPack; using Moq; using NUnit.Framework; using Umbraco.Core; @@ -12,7 +12,6 @@ using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; -using Umbraco.Core.Services; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.TestHelpers.Stubs; using Umbraco.Tests.Testing.Objects.Accessors; @@ -62,6 +61,14 @@ namespace Umbraco.Tests.Web [TestCase("hello href=\"{localLink:umb://document-type/9931BDE0AAC34BABB838909A7B47570E}\" world ", "hello href=\"/my-test-url\" world ")] //this one has an invalid char so won't match [TestCase("hello href=\"{localLink:umb^://document-type/9931BDE0-AAC3-4BAB-B838-909A7B47570E}\" world ", "hello href=\"{localLink:umb^://document-type/9931BDE0-AAC3-4BAB-B838-909A7B47570E}\" world ")] + // with a-tag with data-udi attribute, that needs to be stripped + [TestCase("hello world ", "hello world ")] + // with a-tag with data-udi attribute spelled wrong, so don't need stripping + [TestCase("hello world ", "hello world ")] + // with a img-tag with data-udi id, that needs to be strippde + [TestCase("hello world ", "hello world ")] + // with a img-tag with data-udi id spelled wrong, so don't need stripping + [TestCase("hello world ", "hello world ")] public void ParseLocalLinks(string input, string result) { var serviceCtxMock = new TestObjects(null).GetServiceContextMock(); @@ -102,7 +109,7 @@ namespace Umbraco.Tests.Web //setup a quick mock of the WebRouting section Mock.Of(section => section.WebRouting == Mock.Of(routingSection => routingSection.UrlProviderMode == "AutoLegacy")), //pass in the custom url provider - new[]{ testUrlProvider.Object }, + new[] { testUrlProvider.Object }, globalSettings, new TestVariationContextAccessor(), true)) @@ -112,5 +119,27 @@ namespace Umbraco.Tests.Web Assert.AreEqual(result, output); } } + + [Test] + public void StripDataUdiAttributesUsingSrtringOnLinks() + { + var input = "hello world "; + var expected = "hello world "; + + var result = TemplateUtilities.StripUdiDataAttributes(input); + + Assert.AreEqual(expected, result); + } + + [Test] + public void StripDataUdiAttributesUsingStringOnImages() + { + var input = "hello world "; + var expected = "hello world "; + + var result = TemplateUtilities.StripUdiDataAttributes(input); + + Assert.AreEqual(expected, result); + } } } diff --git a/src/Umbraco.Web.UI.Client/package.json b/src/Umbraco.Web.UI.Client/package.json index c4b4ac0350..562564e272 100644 --- a/src/Umbraco.Web.UI.Client/package.json +++ b/src/Umbraco.Web.UI.Client/package.json @@ -9,7 +9,7 @@ "url": "https://github.com/umbraco/Umbraco-CMS.git" }, "bugs": { - "url": "https://issues.umbraco.org" + "url": "https://github.com/umbraco/Umbraco-CMS/issues" }, "engines": { "node": ">= 0.8.4" diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbcontentnodeinfo.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbcontentnodeinfo.directive.js index 7c5cdc8857..74b806fceb 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbcontentnodeinfo.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbcontentnodeinfo.directive.js @@ -1,7 +1,7 @@ (function () { 'use strict'; - function ContentNodeInfoDirective($timeout, $location, logResource, eventsService, userService, localizationService, dateHelper, editorService) { + function ContentNodeInfoDirective($timeout, $location, logResource, eventsService, userService, localizationService, dateHelper, editorService, redirectUrlsResource) { function link(scope, element, attrs, ctrl) { @@ -72,6 +72,9 @@ // make sure dates are formatted to the user's locale formatDatesToLocal(); + //default setting for redirect url management + scope.urlTrackerDisabled = false; + // Declare a fallback URL for the directive if (scope.documentType !== null) { scope.previewOpenUrl = '#/settings/documenttypes/edit/' + scope.documentType.id; @@ -139,7 +142,7 @@ // get current backoffice user and format dates userService.getCurrentUser().then(function (currentUser) { - angular.forEach(data.items, function(item) { + angular.forEach(data.items, function (item) { item.timestampFormatted = dateHelper.getLocalDate(item.timestamp, currentUser.locale, 'LLL'); }); }); @@ -156,6 +159,25 @@ }); } + function loadRedirectUrls() { + scope.loadingRedirectUrls = true; + //check if Redirect Url Management is enabled + redirectUrlsResource.getEnableState().then(function (response) { + scope.urlTrackerDisabled = response.enabled !== true; + if (scope.urlTrackerDisabled === false) { + + redirectUrlsResource.getRedirectsForContentItem(scope.node.udi) + .then(function (data) { + scope.redirectUrls = data.searchResults; + scope.hasRedirects = (typeof data.searchResults !== 'undefined' && data.searchResults.length > 0); + scope.loadingRedirectUrls = false; + }); + } + else { + scope.loadingRedirectUrls = false; + } + }); + } function setAuditTrailLogTypeColor(auditTrail) { angular.forEach(auditTrail, function (item) { @@ -312,12 +334,13 @@ }); } - // load audit trail when on the info tab + // load audit trail and redirects when on the info tab evts.push(eventsService.on("app.tabChange", function (event, args) { - $timeout(function(){ + $timeout(function () { if (args.alias === "umbInfo") { isInfoTab = true; loadAuditTrail(); + loadRedirectUrls(); } else { isInfoTab = false; } @@ -325,13 +348,14 @@ })); // watch for content state updates - scope.$watch('node.updateDate', function(newValue, oldValue){ + scope.$watch('node.updateDate', function (newValue, oldValue) { - if(!newValue) { return; } - if(newValue === oldValue) { return; } + if (!newValue) { return; } + if (newValue === oldValue) { return; } if(isInfoTab) { loadAuditTrail(); + loadRedirectUrls(); formatDatesToLocal(); setNodePublishStatus(scope.node); } diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/hexbackgroundcolor.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/hexbackgroundcolor.directive.js index 5a425b7c90..eb64439e0b 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/hexbackgroundcolor.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/hexbackgroundcolor.directive.js @@ -11,32 +11,36 @@ function hexBgColor() { restrict: "A", link: function (scope, element, attr, formCtrl) { - var origColor = null; - if (attr.hexBgOrig) { - //set the orig based on the attribute if there is one - origColor = attr.hexBgOrig; - } - - attr.$observe("hexBgColor", function (newVal) { - if (newVal) { - if (!origColor) { - //get the orig color before changing it - origColor = element.css("border-color"); - } - //validate it - test with and without the leading hash. - if (/^([0-9a-f]{3}|[0-9a-f]{6})$/i.test(newVal)) { - element.css("background-color", "#" + newVal); - return; - } - if (/^#([0-9a-f]{3}|[0-9a-f]{6})$/i.test(newVal)) { - element.css("background-color", newVal); - return; - } - } - element.css("background-color", origColor); - }); + // Only add inline hex background color if defined and not "true". + if (attr.hexBgInline === undefined || (attr.hexBgInline !== undefined && attr.hexBgInline === "true")) { + var origColor = null; + if (attr.hexBgOrig) { + // Set the orig based on the attribute if there is one. + origColor = attr.hexBgOrig; + } + + attr.$observe("hexBgColor", function (newVal) { + if (newVal) { + if (!origColor) { + // Get the orig color before changing it. + origColor = element.css("border-color"); + } + // Validate it - test with and without the leading hash. + if (/^([0-9a-f]{3}|[0-9a-f]{6})$/i.test(newVal)) { + element.css("background-color", "#" + newVal); + return; + } + if (/^#([0-9a-f]{3}|[0-9a-f]{6})$/i.test(newVal)) { + element.css("background-color", newVal); + return; + } + } + + element.css("background-color", origColor); + }); + } } }; } -angular.module('umbraco.directives').directive("hexBgColor", hexBgColor); \ No newline at end of file +angular.module('umbraco.directives').directive("hexBgColor", hexBgColor); diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/imaging/umbimagegravity.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/imaging/umbimagegravity.directive.js index 4f783ac9a9..ee341dc892 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/imaging/umbimagegravity.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/imaging/umbimagegravity.directive.js @@ -41,7 +41,6 @@ }; function setFocalPoint (event) { - $scope.$emit("imageFocalPointStart"); var offsetX = event.offsetX - 10; @@ -50,7 +49,6 @@ calculateGravity(offsetX, offsetY); lazyEndEvent(); - }; /** Initializes the component */ diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/umbcolorswatches.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/umbcolorswatches.directive.js index 2b4004da11..89f6ebcd6a 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/umbcolorswatches.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/umbcolorswatches.directive.js @@ -1,5 +1,4 @@ - -/** +/** @ngdoc directive @name umbraco.directives.directive:umbColorSwatches @restrict E @@ -15,9 +14,10 @@ Use this directive to generate color swatches to pick from. @param {array} colors (attribute): The array of colors. -@param {string} colors (attribute): The array of colors. @param {string} selectedColor (attribute): The selected color. @param {string} size (attribute): The size (s, m). +@param {string} useLabel (attribute): Specify if labels should be used. +@param {string} useColorClass (attribute): Specify if color values are css classes. @param {function} onSelect (expression): Callback function when the item is selected. **/ @@ -28,6 +28,11 @@ Use this directive to generate color swatches to pick from. function link(scope, el, attr, ctrl) { + // Set default to true if not defined + if (angular.isUndefined(scope.useColorClass)) { + scope.useColorClass = false; + } + scope.setColor = function (color) { scope.selectedColor = color; if (scope.onSelect) { @@ -45,7 +50,9 @@ Use this directive to generate color swatches to pick from. colors: '=?', size: '@', selectedColor: '=', - onSelect: '&' + onSelect: '&', + useLabel: '=', + useColorClass: '=?' }, link: link }; diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/umbmediagrid.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/umbmediagrid.directive.js index af562e04e3..b14f8418c5 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/umbmediagrid.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/umbmediagrid.directive.js @@ -125,6 +125,14 @@ Use this directive to generate a thumbnail grid of media items. i--; } + if (scope.includeSubFolders !== 'true') { + if (item.parentId !== parseInt(scope.currentFolderId)) { + scope.items.splice(i, 1); + i--; + } + } + + } if (scope.items.length > 0) { @@ -316,7 +324,9 @@ Use this directive to generate a thumbnail grid of media items. itemMaxHeight: "@", itemMinWidth: "@", itemMinHeight: "@", - onlyImages: "@" + onlyImages: "@", + includeSubFolders: "@", + currentFolderId: "@" }, link: link }; diff --git a/src/Umbraco.Web.UI.Client/src/common/resources/log.resource.js b/src/Umbraco.Web.UI.Client/src/common/resources/log.resource.js index 5eeaf5644b..dad5345e6c 100644 --- a/src/Umbraco.Web.UI.Client/src/common/resources/log.resource.js +++ b/src/Umbraco.Web.UI.Client/src/common/resources/log.resource.js @@ -7,10 +7,60 @@ **/ function logResource($q, $http, umbRequestHelper) { + function isValidDate(input) { + if (input) { + if (Object.prototype.toString.call(input) === "[object Date]" && !isNaN(input.getTime())) { + return true; + } + } + + return false; + }; + + function dateToValidIsoString(input) { + if (isValidDate(input)) { + return input.toISOString(); + } + + return ''; + }; + //the factory object returned return { - getPagedEntityLog: function (options) { + /** + * @ngdoc method + * @name umbraco.resources.logResource#getPagedEntityLog + * @methodOf umbraco.resources.logResource + * + * @description + * Gets a paginated log history for a entity + * + * ##usage + *
+        * var options = {
+        *      id : 1234
+        *      pageSize : 10,
+        *      pageNumber : 1,
+        *      orderDirection : "Descending",
+        *      sinceDate : new Date(2018,0,1)
+        * };
+        * logResource.getPagedEntityLog(options)
+        *    .then(function(log) {
+        *        alert('its here!');
+        *    });
+        * 
+ * + * @param {Object} options options object + * @param {Int} options.id the id of the entity + * @param {Int} options.pageSize if paging data, number of nodes per page, default = 10, set to 0 to disable paging + * @param {Int} options.pageNumber if paging data, current page index, default = 1 + * @param {String} options.orderDirection can be `Ascending` or `Descending` - Default: `Descending` + * @param {Date} options.sinceDate if provided this will only get log entries going back to this date + * @returns {Promise} resourcePromise object containing the log. + * + */ + getPagedEntityLog: function(options) { var defaults = { pageSize: 10, @@ -24,11 +74,15 @@ function logResource($q, $http, umbRequestHelper) { angular.extend(defaults, options); //now copy back to the options we will use options = defaults; + + if (options.hasOwnProperty('sinceDate')) { + options.sinceDate = dateToValidIsoString(options.sinceDate); + } + //change asc/desct if (options.orderDirection === "asc") { options.orderDirection = "Ascending"; - } - else if (options.orderDirection === "desc") { + } else if (options.orderDirection === "desc") { options.orderDirection = "Descending"; } @@ -45,7 +99,37 @@ function logResource($q, $http, umbRequestHelper) { 'Failed to retrieve log data for id'); }, - getPagedUserLog: function (options) { + /** + * @ngdoc method + * @name umbraco.resources.logResource#getPagedUserLog + * @methodOf umbraco.resources.logResource + * + * @description + * Gets a paginated log history for the current user + * + * ##usage + *
+         * var options = {
+         *      pageSize : 10,
+         *      pageNumber : 1,
+         *      orderDirection : "Descending",
+         *      sinceDate : new Date(2018,0,1)
+         * };
+         * logResource.getPagedUserLog(options)
+         *    .then(function(log) {
+         *        alert('its here!');
+         *    });
+         * 
+ * + * @param {Object} options options object + * @param {Int} options.pageSize if paging data, number of nodes per page, default = 10, set to 0 to disable paging + * @param {Int} options.pageNumber if paging data, current page index, default = 1 + * @param {String} options.orderDirection can be `Ascending` or `Descending` - Default: `Descending` + * @param {Date} options.sinceDate if provided this will only get log entries going back to this date + * @returns {Promise} resourcePromise object containing the log. + * + */ + getPagedUserLog: function(options) { var defaults = { pageSize: 10, @@ -59,11 +143,15 @@ function logResource($q, $http, umbRequestHelper) { angular.extend(defaults, options); //now copy back to the options we will use options = defaults; + + if (options.hasOwnProperty('sinceDate')) { + options.sinceDate = dateToValidIsoString(options.sinceDate); + } + //change asc/desct if (options.orderDirection === "asc") { options.orderDirection = "Ascending"; - } - else if (options.orderDirection === "desc") { + } else if (options.orderDirection === "desc") { options.orderDirection = "Descending"; } @@ -71,7 +159,7 @@ function logResource($q, $http, umbRequestHelper) { $http.get( umbRequestHelper.getApiUrl( "logApiBaseUrl", - "GetPagedEntityLog", + "GetPagedCurrentUserLog", options)), 'Failed to retrieve log data for id'); }, @@ -82,6 +170,7 @@ function logResource($q, $http, umbRequestHelper) { * @methodOf umbraco.resources.logResource * * @description + * [OBSOLETE] use getPagedEntityLog instead
* Gets the log history for a give entity id * * ##usage @@ -96,23 +185,24 @@ function logResource($q, $http, umbRequestHelper) { * @returns {Promise} resourcePromise object containing the log. * */ - getEntityLog: function (id) { + getEntityLog: function(id) { return umbRequestHelper.resourcePromise( - $http.get( - umbRequestHelper.getApiUrl( - "logApiBaseUrl", - "GetEntityLog", - [{ id: id }])), - 'Failed to retrieve user data for id ' + id); + $http.get( + umbRequestHelper.getApiUrl( + "logApiBaseUrl", + "GetEntityLog", + [{ id: id }])), + 'Failed to retrieve user data for id ' + id); }, - + /** * @ngdoc method * @name umbraco.resources.logResource#getUserLog * @methodOf umbraco.resources.logResource * * @description - * Gets the current users' log history for a given type of log entry + * [OBSOLETE] use getPagedUserLog instead
+ * Gets the current user's log history for a given type of log entry * * ##usage *
@@ -127,14 +217,14 @@ function logResource($q, $http, umbRequestHelper) {
          * @returns {Promise} resourcePromise object containing the log.
          *
          */
-        getUserLog: function (type, since) {            
+        getUserLog: function(type, since) {
             return umbRequestHelper.resourcePromise(
-               $http.get(
-                   umbRequestHelper.getApiUrl(
-                       "logApiBaseUrl",
-                       "GetCurrentUserLog",
-                       [{ logtype: type}, {sinceDate: since }])),
-               'Failed to retrieve log data for current user of type ' + type + ' since ' + since);
+                $http.get(
+                    umbRequestHelper.getApiUrl(
+                        "logApiBaseUrl",
+                        "GetCurrentUserLog",
+                        [{ logtype: type }, { sinceDate:  dateToValidIsoString(since) }])),
+                'Failed to retrieve log data for current user of type ' + type + ' since ' + since);
         },
 
         /**
@@ -158,16 +248,16 @@ function logResource($q, $http, umbRequestHelper) {
          * @returns {Promise} resourcePromise object containing the log.
          *
          */
-        getLog: function (type, since) {            
+        getLog: function(type, since) {
             return umbRequestHelper.resourcePromise(
-               $http.get(
-                   umbRequestHelper.getApiUrl(
-                       "logApiBaseUrl",
-                       "GetLog",
-                       [{ logtype: type}, {sinceDate: since }])),
-               'Failed to retrieve log data of type ' + type + ' since ' + since);
-        }
-    };
+                $http.get(
+                    umbRequestHelper.getApiUrl(
+                        "logApiBaseUrl",
+                        "GetLog",
+                        [{ logtype: type }, { sinceDate: dateToValidIsoString(since) }])),
+                'Failed to retrieve log data of type ' + type + ' since ' + since);
+        }      
+};
 }
 
 angular.module('umbraco.resources').factory('logResource', logResource);
diff --git a/src/Umbraco.Web.UI.Client/src/common/resources/redirecturls.resource.js b/src/Umbraco.Web.UI.Client/src/common/resources/redirecturls.resource.js
index ea40c066f0..fb145418ed 100644
--- a/src/Umbraco.Web.UI.Client/src/common/resources/redirecturls.resource.js
+++ b/src/Umbraco.Web.UI.Client/src/common/resources/redirecturls.resource.js
@@ -40,6 +40,32 @@
                         { searchTerm: searchTerm, page: pageIndex, pageSize: pageSize })),
                 'Failed to retrieve data for searching redirect urls');
         }
+        /**
+   * @ngdoc function
+   * @name umbraco.resources.redirectUrlResource#getRedirectsForContentItem
+   * @methodOf umbraco.resources.redirectUrlResource
+   * @function
+   *
+   * @description
+   * Used to retrieve RedirectUrls for a specific item of content for Information tab
+   * ##usage
+   * 
+   * redirectUrlsResource.getRedirectsForContentItem("udi:123456")
+   *    .then(function(response) {
+   *
+   *    });
+   * 
+ * @param {String} contentUdi identifier for the content item to retrieve redirects for + */ + function getRedirectsForContentItem(contentUdi) { + return umbRequestHelper.resourcePromise( + $http.get( + umbRequestHelper.getApiUrl( + "redirectUrlManagementApiBaseUrl", + "RedirectUrlsForContentItem", + { contentUdi: contentUdi })), + 'Failed to retrieve redirects for content: ' + contentUdi); + } function getEnableState() { @@ -50,7 +76,7 @@ "GetEnableState")), 'Failed to retrieve data to check if the 301 redirect is enabled'); } - + /** * @ngdoc function * @name umbraco.resources.redirectUrlResource#deleteRedirectUrl @@ -107,7 +133,8 @@ searchRedirectUrls: searchRedirectUrls, deleteRedirectUrl: deleteRedirectUrl, toggleUrlTracker: toggleUrlTracker, - getEnableState: getEnableState + getEnableState: getEnableState, + getRedirectsForContentItem: getRedirectsForContentItem }; return resource; diff --git a/src/Umbraco.Web.UI.Client/src/common/services/navigation.service.js b/src/Umbraco.Web.UI.Client/src/common/services/navigation.service.js index ffcf9f2eef..cb416e3974 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/navigation.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/navigation.service.js @@ -85,6 +85,7 @@ function navigationService($rootScope, $route, $routeParams, $log, $location, $q appState.setSectionState("showSearchResults", false); appState.setGlobalState("stickyNavigation", false); appState.setGlobalState("showTray", false); + appState.setMenuState("currentNode", null); if (appState.getGlobalState("isTablet") === true) { appState.setGlobalState("showNavigation", false); @@ -365,7 +366,8 @@ function navigationService($rootScope, $route, $routeParams, $log, $location, $q if (appState.getGlobalState("isTablet") === true && !appState.getGlobalState("stickyNavigation")) { //reset it to whatever is in the url - appState.setSectionState("currentSection", $routeParams.section); + appState.setSectionState("currentSection", $routeParams.section); + setMode("default-hidesectiontree"); } diff --git a/src/Umbraco.Web.UI.Client/src/common/services/user.service.js b/src/Umbraco.Web.UI.Client/src/common/services/user.service.js index 5b723d9328..064234c99b 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/user.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/user.service.js @@ -143,7 +143,6 @@ angular.module('umbraco.services') /** Called to update the current user's timeout */ function setUserTimeoutInternal(newTimeout) { - var asNumber = parseFloat(newTimeout); if (!isNaN(asNumber) && currentUser && angular.isNumber(asNumber)) { currentUser.remainingAuthSeconds = newTimeout; @@ -151,6 +150,29 @@ angular.module('umbraco.services') } } + function getMomentLocales(locales, supportedLocales) { + + var localeUrls = []; + var locales = locales.split(','); + for (var i = 0; i < locales.length; i++) { + var locale = locales[i].toString().toLowerCase(); + if (locale !== 'en-us') { + + if (supportedLocales.indexOf(locale + '.js') > -1) { + localeUrls.push('lib/moment/' + locale + '.js'); + } + if (locale.indexOf('-') > -1) { + var majorLocale = locale.split('-')[0] + '.js'; + if (supportedLocales.indexOf(majorLocale) > -1) { + localeUrls.push('lib/moment/' + majorLocale); + } + } + } + } + + return localeUrls; + } + /** resets all user data, broadcasts the notAuthenticated event and shows the login dialog */ function userAuthExpired(isLogout) { //store the last user id and clear the user diff --git a/src/Umbraco.Web.UI.Client/src/less/belle.less b/src/Umbraco.Web.UI.Client/src/less/belle.less index e02cfed493..cc98ec306b 100644 --- a/src/Umbraco.Web.UI.Client/src/less/belle.less +++ b/src/Umbraco.Web.UI.Client/src/less/belle.less @@ -138,6 +138,7 @@ @import "components/umb-querybuilder.less"; @import "components/umb-pagination.less"; @import "components/umb-mini-list-view.less"; +@import "components/umb-multiple-textbox.less"; @import "components/umb-badge.less"; @import "components/umb-nested-content.less"; @import "components/umb-checkmark.less"; diff --git a/src/Umbraco.Web.UI.Client/src/less/canvas-designer.less b/src/Umbraco.Web.UI.Client/src/less/canvas-designer.less index 7410c09580..78c1616bc6 100644 --- a/src/Umbraco.Web.UI.Client/src/less/canvas-designer.less +++ b/src/Umbraco.Web.UI.Client/src/less/canvas-designer.less @@ -790,13 +790,13 @@ h4.panel-title { } .smartphone-portrait { - width: 320px; - height: 504px; + width: 360px; + height: 640px; } .smartphone-landscape { - width: 480px; - height: 256px; + width: 640px; + height: 360px; } .border { diff --git a/src/Umbraco.Web.UI.Client/src/less/components/card.less b/src/Umbraco.Web.UI.Client/src/less/components/card.less index c0aa4fa9b7..e8b8325183 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/card.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/card.less @@ -96,7 +96,6 @@ font-size: 12px; text-align: center; width: 100px; - height: 105px; box-sizing: border-box; position: relative; } @@ -114,6 +113,7 @@ width: 100%; height: 100%; border-radius: 3px; + padding-bottom: 5px; } diff --git a/src/Umbraco.Web.UI.Client/src/less/components/prevalues/multivalues.less b/src/Umbraco.Web.UI.Client/src/less/components/prevalues/multivalues.less index 5363a8db9b..43f6697eb1 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/prevalues/multivalues.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/prevalues/multivalues.less @@ -10,6 +10,7 @@ .umb-prevalues-multivalues__left { display: flex; flex: 1 1 auto; + overflow: hidden; } .umb-prevalues-multivalues__right { diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-color-swatches.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-color-swatches.less index c7905879d8..a987c5daa3 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/umb-color-swatches.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-color-swatches.less @@ -1,18 +1,22 @@ .umb-color-swatches { + display: flex; + flex-flow: row wrap; .umb-color-box { border: none; color: white; cursor: pointer; - padding: 5px; + padding: 1px; text-align: center; text-decoration: none; - display: inline-block; margin: 5px; border-radius: 3px; width: 30px; height: 30px; transition: box-shadow .3s; + display: flex; + align-items: center; + justify-content: center; &:hover, &:focus { box-shadow: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24); @@ -28,4 +32,55 @@ } } } + + &.with-labels { + + .umb-color-box { + width: 120px; + height: 100%; + display: flex; + flex-flow: row wrap; + + .umb-color-box-inner { + display: flex; + flex-flow: column wrap; + flex: 0 0 100%; + max-width: 100%; + min-height: 80px; + padding-top: 10px; + + .umb-color-box__label { + background: #fff; + font-size: 14px; + display: flex; + flex-flow: column wrap; + flex: 0 0 100%; + padding: 1px 5px; + max-width: 100%; + margin-top: auto; + margin-bottom: -3px; + margin-left: -1px; + margin-right: -1px; + text-indent: 0; + text-align: left; + border: 1px solid @gray-8; + border-bottom-left-radius: 3px; + border-bottom-right-radius: 3px; + overflow: hidden; + + .umb-color-box__name { + color: @black; + font-weight: bold; + margin-top: 3px; + } + + .umb-color-box__description { + font-size: 12px; + line-height: 1.5em; + color: @gray-3; + } + } + } + } + } } diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-media-grid.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-media-grid.less index 0a49755915..3356c1de68 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/umb-media-grid.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-media-grid.less @@ -33,6 +33,18 @@ background-color: @white; } +.umb-media-grid__item-file-icon > span { + color: @white; + background: @gray-4; + padding: 1px 3px; + font-size: 10px; + line-height: 130%; + display: block; + margin-top: -30px; + margin-left: -10px; + position: relative; +} + .umb-media-grid__item.-selected { box-shadow: 0 2px 8px 0 rgba(0,0,0,.35); } diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-multiple-textbox.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-multiple-textbox.less new file mode 100644 index 0000000000..21f59a3e2d --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-multiple-textbox.less @@ -0,0 +1,34 @@ +.umb-multiple-textbox .textbox-wrapper { + align-items: center; + margin-bottom: 15px; +} + +.umb-multiple-textbox .textbox-wrapper .umb-editor { + margin-bottom: 0; +} + +.umb-multiple-textbox .textbox-wrapper i { + margin-right: 5px; +} + +.umb-multiple-textbox .textbox-wrapper i.handle { + margin-left: 5px; +} + +.umb-multiple-textbox .textbox-wrapper a.remove { + margin-left: 5px; + text-decoration: none; +} + +.umb-multiple-textbox .add-link { + &:extend(.umb-node-preview-add); +} + +.umb-editor-wrapper .umb-multiple-textbox .add-link { + &:extend(.umb-editor-wrapper .umb-node-preview); +} + +.umb-modal .umb-multiple-textbox .textbox-wrapper .umb-editor { + flex: 1 1 auto; + width: auto; +} diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-table.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-table.less index b302ed2654..b729aa92bc 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/umb-table.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-table.less @@ -166,7 +166,7 @@ input.umb-table__input { } -.-content .-unpublished { +.-content :not(.with-unpublished-version).-unpublished { .umb-table__name > * { opacity: .4; } diff --git a/src/Umbraco.Web.UI.Client/src/less/property-editors.less b/src/Umbraco.Web.UI.Client/src/less/property-editors.less index 2b716b9b9f..43f5aa5a9a 100644 --- a/src/Umbraco.Web.UI.Client/src/less/property-editors.less +++ b/src/Umbraco.Web.UI.Client/src/less/property-editors.less @@ -133,27 +133,6 @@ div.umb-codeeditor .umb-btn-toolbar { // // Color picker // -------------------------------------------------- -ul.color-picker li { - padding: 2px; - margin: 3px; - border: 2px solid transparent; - width: 60px; - - .thumbnail{ - min-width: auto; - width: inherit; - padding: 0; - } - - a { - height: 50px; - display:flex; - align-items: center; - justify-content: center; - cursor:pointer; - margin: 0 0 5px; - } -} /* pre-value editor */ .control-group.color-picker-preval { @@ -174,7 +153,7 @@ ul.color-picker li { div.color-picker-prediv { display: inline-flex; align-items: center; - max-width: 80%; + max-width: 85%; pre { display: inline-flex; @@ -357,13 +336,30 @@ ul.color-picker li { text-align: center; } -.umb-sortable-thumbnails .umb-icon-holder .icon{ +.umb-sortable-thumbnails .umb-icon-holder .icon { font-size: 40px; line-height: 50px; color: @gray-3; display: block; } +.umb-sortable-thumbnails .umb-icon-holder .file-icon > span { + color: @white; + background: @gray-4; + padding: 1px 3px; + font-size: 10px; + line-height: 130%; + display: block; + margin-top: -30px; + width: 2em; +} + +.umb-sortable-thumbnails .umb-icon-holder .file-icon + small { + display: block; + margin-top: 1em; +} + + .umb-sortable-thumbnails .umb-sortable-thumbnails__wrapper { width: 124px; height: 124px; diff --git a/src/Umbraco.Web.UI.Client/src/views/common/dialogs/login.controller.js b/src/Umbraco.Web.UI.Client/src/views/common/dialogs/login.controller.js index fdd438e9cf..c965d16c0d 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/dialogs/login.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/common/dialogs/login.controller.js @@ -29,6 +29,7 @@ function init() { // Check if it is a new user var inviteVal = $location.search().invite; + //1 = enter password, 2 = password set, 3 = invalid token if (inviteVal && (inviteVal === "1" || inviteVal === "2")) { $q.all([ @@ -58,6 +59,8 @@ $scope.inviteStep = Number(inviteVal); }); + } else if (inviteVal && inviteVal === "3") { + $scope.inviteStep = Number(inviteVal); } } diff --git a/src/Umbraco.Web.UI.Client/src/views/common/dialogs/login.html b/src/Umbraco.Web.UI.Client/src/views/common/dialogs/login.html index e16bb2375b..eab74994e6 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/dialogs/login.html +++ b/src/Umbraco.Web.UI.Client/src/views/common/dialogs/login.html @@ -104,10 +104,18 @@ - + + diff --git a/src/Umbraco.Web.UI.Client/src/views/components/umb-table.html b/src/Umbraco.Web.UI.Client/src/views/components/umb-table.html index 003ab9832c..e8a8b97f8c 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/umb-table.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/umb-table.html @@ -35,7 +35,8 @@ ng-class="{ '-selected':item.selected, '-published':item.published, - '-unpublished':!item.published + '-unpublished':!item.published, + 'with-unpublished-version':!item.published && item.hasPublishedVersion }" ng-click="vm.selectItem(item, $index, $event)"> diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/colorpicker/colorpicker.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/colorpicker/colorpicker.html index f726800696..e209d0cb60 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/colorpicker/colorpicker.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/colorpicker/colorpicker.html @@ -1,20 +1,15 @@ 
-
- You haven't defined any colors -
+
+ You haven't defined any colors +
- + + - +
diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/contentpicker/contentpicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/contentpicker/contentpicker.controller.js index 5a8396776e..70572a5bcf 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/contentpicker/contentpicker.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/contentpicker/contentpicker.controller.js @@ -33,6 +33,7 @@ function contentPickerController($scope, entityResource, editorState, iconHelper /** Performs validation based on the renderModel data */ function validate() { if ($scope.contentPickerForm) { + angularHelper.getCurrentForm($scope).$setDirty(); //Validate! if ($scope.model.config && $scope.model.config.minNumber && parseInt($scope.model.config.minNumber) > $scope.renderModel.length) { $scope.contentPickerForm.minCount.$setValidity("minCount", false); @@ -199,6 +200,7 @@ function contentPickerController($scope, entityResource, editorState, iconHelper _.each(model.selection, function (item, i) { $scope.add(item); }); + angularHelper.getCurrentForm($scope).$setDirty(); } angularHelper.getCurrentForm($scope).$setDirty(); editorService.close(); diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/imagecropper/imagecropper.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/imagecropper/imagecropper.html index bc84f1b64f..5e920cee01 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/imagecropper/imagecropper.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/imagecropper/imagecropper.html @@ -42,8 +42,9 @@ Remove file - -
    + + +
    • diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.controller.js index 2dc8eb25d7..7ef6c117f2 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.controller.js @@ -227,10 +227,6 @@ function listViewController($scope, $routeParams, $injector, $timeout, currentUs }, 500); - if (reload === true) { - $scope.reloadView($scope.contentId, true); - } - if (successMsg) { localizationService.localize("bulk_done") .then(function (v) { @@ -260,12 +256,13 @@ function listViewController($scope, $routeParams, $injector, $timeout, currentUs with simple values */ $scope.getContent = function (contentId) { - $scope.reloadView($scope.contentId, true); + + $scope.reloadView($scope.contentId); } - $scope.reloadView = function (id, reloadFolders) { - + $scope.reloadView = function (id) { $scope.viewLoaded = false; + $scope.folders = []; listViewHelper.clearSelection($scope.listViewResultSet.items, $scope.folders, $scope.selection); @@ -278,20 +275,13 @@ function listViewController($scope, $routeParams, $injector, $timeout, currentUs if ($scope.listViewResultSet.items) { _.each($scope.listViewResultSet.items, function (e, index) { setPropertyValues(e); - }); - } + if (e.contentTypeAlias === 'Folder') { + $scope.folders.push(e); + } + }); + } - if (reloadFolders && $scope.entityType === 'media') { - //The folders aren't loaded - we only need to do this once since we're never changing node ids - mediaResource.getChildFolders($scope.contentId) - .then(function (page) { - $scope.folders = page.items; - $scope.viewLoaded = true; - }); - - } else { - $scope.viewLoaded = true; - } + $scope.viewLoaded = true; //NOTE: This might occur if we are requesting a higher page number than what is actually available, for example // if you have more than one page and you delete all items on the last page. In this case, we need to reset to the last @@ -609,7 +599,7 @@ function listViewController($scope, $routeParams, $injector, $timeout, currentUs $scope.options.allowBulkMove || $scope.options.allowBulkDelete; - $scope.reloadView($scope.contentId, true); + $scope.reloadView($scope.contentId); } function getLocalizedKey(alias) { diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/mediapicker/mediapicker.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/mediapicker/mediapicker.html index 3658f828f0..002ade8902 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/mediapicker/mediapicker.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/mediapicker/mediapicker.html @@ -21,7 +21,10 @@ - + + + .{{image.extension}} + {{image.name}} diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/rte.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/rte.controller.js index 07dffea75e..93083bf2a6 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/rte.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/rte.controller.js @@ -395,7 +395,9 @@ angular.module("umbraco") var unsubscribe = $scope.$on("formSubmitting", function () { //TODO: Here we should parse out the macro rendered content so we can save on a lot of bytes in data xfer // we do parse it out on the server side but would be nice to do that on the client side before as well. - $scope.model.value = tinyMceEditor ? tinyMceEditor.getContent() : null; + if (tinyMceEditor !== undefined && tinyMceEditor != null && !$scope.isLoading) { + $scope.model.value = tinyMceEditor.getContent(); + } }); //when the element is disposed we need to unsubscribe! diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/textarea/textarea.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/textarea/textarea.html index bf4a25d020..2fdca5d654 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/textarea/textarea.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/textarea/textarea.html @@ -1,6 +1,6 @@
      - + Required diff --git a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj index 413305d4dc..8fae702009 100644 --- a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj +++ b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj @@ -40,6 +40,85 @@ TRACE;DEBUG prompt 4 + + + + + + 9.0.30729 + 2.0 + {4C4C194C-B5E4-4991-8F87-4373E24CC19F} + {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} + Debug + AnyCPU + + + + + Umbraco.Web.UI + + + JScript + Grid + IE50 + false + Library + Umbraco.Web.UI + OnBuildSuccess + + + + + + + + + + + + + + + 4.0 + v4.5 + + true + + + enabled + disabled + false + ..\ + true + true + + + + + + + bin\ + false + 285212672 + false + + + TRACE;DEBUG + + + true + 4096 + false + + + false + false + false + false + 4 + full + prompt + AllRules.ruleset false ..\bin\Debug\ true @@ -112,6 +191,221 @@ + + + bin\ + false + 285212672 + false + + + TRACE + bin\Umbraco.Web.UI.XML + true + 4096 + false + + + true + false + false + false + 4 + pdbonly + prompt + AllRules.ruleset + false + ..\bin\Release\ + + + + {07fbc26b-2927-4a22-8d96-d644c667fecc} + UmbracoExamine + + + ..\packages\AutoMapper.3.3.1\lib\net40\AutoMapper.dll + True + + + ..\packages\AutoMapper.3.3.1\lib\net40\AutoMapper.Net4.dll + True + + + ..\packages\ClientDependency.1.9.7\lib\net45\ClientDependency.Core.dll + + + ..\packages\ClientDependency-Mvc5.1.8.0.0\lib\net45\ClientDependency.Core.Mvc.dll + True + + + ..\packages\dotless.1.5.2\lib\dotless.Core.dll + + + ..\packages\Examine.0.1.89\lib\net45\Examine.dll + + + ..\packages\SharpZipLib.0.86.0\lib\20\ICSharpCode.SharpZipLib.dll + + + ..\packages\ImageProcessor.2.5.6\lib\net45\ImageProcessor.dll + + + ..\packages\ImageProcessor.Web.4.8.7\lib\net45\ImageProcessor.Web.dll + + + ..\packages\log4net.2.0.8\lib\net45-full\log4net.dll + + + ..\packages\Lucene.Net.2.9.4.1\lib\net40\Lucene.Net.dll + + + ..\packages\Microsoft.AspNet.Identity.Core.2.2.1\lib\net45\Microsoft.AspNet.Identity.Core.dll + True + + + False + ..\packages\Microsoft.AspNet.Identity.Owin.2.2.1\lib\net45\Microsoft.AspNet.Identity.Owin.dll + + + ..\packages\Microsoft.CodeAnalysis.Common.1.0.0\lib\net45\Microsoft.CodeAnalysis.dll + + + ..\packages\Microsoft.CodeAnalysis.CSharp.1.0.0\lib\net45\Microsoft.CodeAnalysis.CSharp.dll + + + ..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.2.0.0\lib\net45\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.dll + + + + ..\packages\Microsoft.IO.RecyclableMemoryStream.1.2.2\lib\net45\Microsoft.IO.RecyclableMemoryStream.dll + + + ..\packages\Microsoft.Owin.3.1.0\lib\net45\Microsoft.Owin.dll + + + ..\packages\Microsoft.Owin.Host.SystemWeb.3.1.0\lib\net45\Microsoft.Owin.Host.SystemWeb.dll + + + ..\packages\Microsoft.Owin.Security.3.1.0\lib\net45\Microsoft.Owin.Security.dll + + + ..\packages\Microsoft.Owin.Security.Cookies.3.1.0\lib\net45\Microsoft.Owin.Security.Cookies.dll + + + ..\packages\Microsoft.Owin.Security.OAuth.3.1.0\lib\net45\Microsoft.Owin.Security.OAuth.dll + + + True + ..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll + + + False + ..\packages\MiniProfiler.2.1.0\lib\net40\MiniProfiler.dll + + + ..\packages\MySql.Data.6.9.9\lib\net45\MySql.Data.dll + + + ..\packages\Newtonsoft.Json.10.0.2\lib\net45\Newtonsoft.Json.dll + + + ..\packages\Owin.1.0\lib\net40\Owin.dll + True + + + System + + + ..\packages\System.Collections.Immutable.1.1.36\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll + + + + + System.Data + + + + ..\packages\SqlServerCE.4.0.0.1\lib\System.Data.SqlServerCe.dll + True + + + ..\packages\SqlServerCE.4.0.0.1\lib\System.Data.SqlServerCe.Entity.dll + True + + + + + + + False + False + + + False + ..\packages\Microsoft.AspNet.WebApi.Client.5.2.3\lib\net45\System.Net.Http.Formatting.dll + + + False + False + + + ..\packages\System.Reflection.Metadata.1.0.21\lib\portable-net45+win8\System.Reflection.Metadata.dll + + + + + System.Web + + + 3.5 + + + + + + + + ..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.Helpers.dll + True + + + False + ..\packages\Microsoft.AspNet.WebApi.Core.5.2.3\lib\net45\System.Web.Http.dll + + + False + ..\packages\Microsoft.AspNet.WebApi.WebHost.5.2.3\lib\net45\System.Web.Http.WebHost.dll + + + ..\packages\Microsoft.AspNet.Mvc.5.2.3\lib\net45\System.Web.Mvc.dll + True + + + ..\packages\Microsoft.AspNet.Razor.3.2.3\lib\net45\System.Web.Razor.dll + True + + + System.Web.Services + + + ..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.dll + True + + + ..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Deployment.dll + True + + + ..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Razor.dll + True + + + System.XML + + + {5BA5425F-27A7-4677-865E-82246498AA2E} + SqlCE4Umbraco + {31785bc3-256c-4613-b2f5-a1b0bdded8c1} Umbraco.Core @@ -124,6 +418,48 @@ {651e1350-91b6-44b7-bd60-7207006d7003} Umbraco.Web + + {255F5DF1-4E43-4758-AC05-7A0B68EB021B} + umbraco.editorControls + + + {89C09045-1064-466B-B94A-DB3AFE2A5853} + umbraco.MacroEngines + + + {6EDD2061-82F2-461B-BB6E-879245A832DE} + umbraco.controls + + + umbraco.businesslogic + {E469A9CE-1BEC-423F-AC44-713CD72457EA} + {FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + + + {CCD75EC3-63DB-4184-B49D-51C1DD337230} + umbraco.cms + + + {C7CB79F0-1C97-4B33-BFA7-00731B579AE2} + umbraco.datalayer + + + umbraco.interfaces + {511F6D8D-7717-440A-9A57-A507E9A8B27F} + {FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + + + {651E1350-91B6-44B7-BD60-7207006D7003} + Umbraco.Web + + + {D7636876-0756-43CB-A192-138C6F0D5E42} + umbraco.providers + + + + ..\packages\Umbraco.ModelsBuilder.3.0.10\lib\Umbraco.ModelsBuilder.dll + @@ -150,6 +486,13 @@ create.aspx + + xslt.ascx + ASPXCodeBehind + + + xslt.ascx + UserControlProxy.aspx ASPXCodeBehind @@ -178,6 +521,28 @@ ChangeDocType.aspx + + EditMacro.aspx + ASPXCodeBehind + + + sort.aspx + ASPXCodeBehind + + + sort.aspx + ASPXCodeBehind + + + EditMacro.aspx + + + publish.aspx + ASPXCodeBehind + + + publish.aspx + default.Master ASPXCodeBehind @@ -197,6 +562,27 @@ umbracoPage.Master + + QuickSearch.ascx + ASPXCodeBehind + + + QuickSearch.ascx + + + editstylesheet.aspx + ASPXCodeBehind + + + editstylesheet.aspx + + + EditStyleSheetProperty.aspx + ASPXCodeBehind + + + EditStyleSheetProperty.aspx + treeInit.aspx ASPXCodeBehind @@ -233,6 +619,9 @@ + + + umbraco.aspx ASPXCodeBehind @@ -243,20 +632,34 @@ + + + + 404handlers.config + ClientDependency.config Designer + + Designer + + + BaseRestExtensions.config + Designer + + log4net.config + FileSystemProviders.config @@ -306,6 +709,9 @@ + + Designer + SettingsSingleFileGenerator Settings.Designer.cs @@ -318,6 +724,9 @@ Designer + + + @@ -341,6 +750,112 @@ + + + ASPXCodeBehind + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -360,11 +875,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Designer + + + + + Designer @@ -388,6 +954,9 @@ + + Code + @@ -424,6 +993,19 @@ + + + + + + + + + + + + + Web.Template.config @@ -454,6 +1036,132 @@ + + + + + + + + + + + + UserControl + + + + UserControl + + + + + + + + + + + + + + + + Form + + + Form + + + Form + + + + + + + + + + + + + + Form + + + + + + + Form + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Designer @@ -472,6 +1180,18 @@ + + + + + + + + + + + + 11.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v11.0 @@ -497,6 +1217,15 @@ + + + xcopy "$(ProjectDir)"..\packages\SqlServerCE.4.0.0.1\amd64\*.* "$(TargetDir)amd64\" /Y /F /E /I /C /D +xcopy "$(ProjectDir)"..\packages\SqlServerCE.4.0.0.1\x86\*.* "$(TargetDir)x86\" /Y /F /E /I /C /D + + + + + @@ -506,6 +1235,11 @@ 8000 / http://localhost:8000 + True + True + 7130 + / + http://localhost:7130 False False @@ -581,5 +1315,54 @@ --> + + + + $(MSBuildExtensionsPath)\Microsoft\VisualStudio\v15.0\Web\Microsoft.Web.Publishing.Tasks.dll + + + $(MSBuildExtensionsPath)\Microsoft\VisualStudio\v14.0\Web\Microsoft.Web.Publishing.Tasks.dll + + + $(MSBuildExtensionsPath)\Microsoft\VisualStudio\v12.0\Web\Microsoft.Web.Publishing.Tasks.dll + + + $(MSBuildExtensionsPath)\Microsoft\VisualStudio\v11.0\Web\Microsoft.Web.Publishing.Tasks.dll + + + $(MSBuildExtensionsPath)\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web.Publishing.Tasks.dll + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + \ No newline at end of file diff --git a/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml b/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml index cc2d0343a2..22a7db7e0c 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml @@ -687,6 +687,7 @@ Embed Retrieve selected + Include subfolders in search @@ -1688,8 +1689,8 @@ To manage your website, simply open the Umbraco back office and start adding con tab has no sort order - Where is this composition used? - This composition is currently used in the composition of the following content types: + Where is this composition used? + This composition is currently used in the composition of the following content types: @@ -1863,7 +1864,7 @@ To manage your website, simply open the Umbraco back office and start adding con Go to user profile Add groups to assign access and permissions Invite another user - Invite new users to give them access to Umbraco. An invite email will be sent to the user with information on how to log in to Umbraco. + Invite new users to give them access to Umbraco. An invite email will be sent to the user with information on how to log in to Umbraco. Invites last for 72 hours. Language Set the language you will see in menus and dialogs Last lockout date @@ -1927,6 +1928,7 @@ To manage your website, simply open the Umbraco back office and start adding con has been invited An invitation has been sent to the new user with details about how to log in to Umbraco. Hello there and welcome to Umbraco! In just 1 minute you’ll be good to go, we just need you to setup a password and add a picture for your avatar. + Welcome to Umbraco! Unfortunately your invite has expired. Please contact your administrator and ask them to resend it. Upload a picture to make it easy for other users to recognize you. Writer Translator @@ -2185,6 +2187,8 @@ To manage your website, simply open the Umbraco back office and start adding con Enable URL tracker Original URL Redirected To + Redirect Url Management + The following URLs redirect to this content item: No redirects have been made When a published page gets renamed or moved a redirect will automatically be made to the new page. Remove diff --git a/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml b/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml index 835bf6b884..a6ccd30923 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml @@ -700,6 +700,7 @@ Embed Retrieve selected + Include subfolders in search Black @@ -1700,8 +1701,8 @@ To manage your website, simply open the Umbraco back office and start adding con tab has no sort order - Where is this composition used? - This composition is currently used in the composition of the following content types: + Where is this composition used? + This composition is currently used in the composition of the following content types: @@ -1884,7 +1885,7 @@ To manage your website, simply open the Umbraco back office and start adding con Go to user profile Add groups to assign access and permissions Invite another user - Invite new users to give them access to Umbraco. An invite email will be sent to the user with information on how to log in to Umbraco. + Invite new users to give them access to Umbraco. An invite email will be sent to the user with information on how to log in to Umbraco. Invites last for 72 hours. Language Set the language you will see in menus and dialogs Last lockout date @@ -1948,6 +1949,7 @@ To manage your website, simply open the Umbraco back office and start adding con has been invited An invitation has been sent to the new user with details about how to log in to Umbraco. Hello there and welcome to Umbraco! In just 1 minute you’ll be good to go, we just need you to setup a password and add a picture for your avatar. + Welcome to Umbraco! Unfortunately your invite has expired. Please contact your administrator and ask them to resend it. Upload a picture to make it easy for other users to recognize you. Writer Translator @@ -2208,6 +2210,8 @@ To manage your website, simply open the Umbraco back office and start adding con Enable URL tracker Original URL Redirected To + Redirect Url Management + The following URLs redirect to this content item: No redirects have been made When a published page gets renamed or moved a redirect will automatically be made to the new page. Remove diff --git a/src/Umbraco.Web.UI/config/umbracoSettings.Release.config b/src/Umbraco.Web.UI/config/umbracoSettings.Release.config index d1630186ad..42c8b01e24 100644 --- a/src/Umbraco.Web.UI/config/umbracoSettings.Release.config +++ b/src/Umbraco.Web.UI/config/umbracoSettings.Release.config @@ -53,7 +53,7 @@ throw - ashx,aspx,ascx,config,cshtml,vbhtml,asmx,air,axd,swf,xml,xhtml,html,htm,svg,php,htaccess + ashx,aspx,ascx,config,cshtml,vbhtml,asmx,air,axd,swf,xml,xhtml,html,htm,php,htaccess Textstring diff --git a/src/Umbraco.Web.UI/config/umbracoSettings.config b/src/Umbraco.Web.UI/config/umbracoSettings.config index 4a51c2a7e9..7a8019f5e1 100644 --- a/src/Umbraco.Web.UI/config/umbracoSettings.config +++ b/src/Umbraco.Web.UI/config/umbracoSettings.config @@ -8,7 +8,7 @@ - jpeg,jpg,gif,bmp,png,tiff,tif + jpeg,jpg,gif,bmp,png,tiff,tif,svg src,alt,border,class,style,align,id,name,onclick,usemap @@ -94,7 +94,7 @@ throw - ashx,aspx,ascx,config,cshtml,vbhtml,asmx,air,axd,swf,xml,xhtml,html,htm,svg,php,htaccess + ashx,aspx,ascx,config,cshtml,vbhtml,asmx,air,axd,swf,xml,xhtml,html,htm,php,htaccess diff --git a/src/Umbraco.Web.UI/web.Template.config b/src/Umbraco.Web.UI/web.Template.config index 47ae79ab8c..844855f10f 100644 --- a/src/Umbraco.Web.UI/web.Template.config +++ b/src/Umbraco.Web.UI/web.Template.config @@ -122,7 +122,7 @@ - + diff --git a/src/Umbraco.Web/Editors/AuthenticationController.cs b/src/Umbraco.Web/Editors/AuthenticationController.cs index 1f02137caf..4e56685300 100644 --- a/src/Umbraco.Web/Editors/AuthenticationController.cs +++ b/src/Umbraco.Web/Editors/AuthenticationController.cs @@ -421,6 +421,34 @@ namespace Umbraco.Web.Editors } } + //They've successfully set their password, we can now update their user account to be confirmed + //if user was only invited, then they have not been approved + //but a successful forgot password flow (e.g. if their token had expired and they did a forgot password instead of request new invite) + //means we have verified their email + if (!UserManager.IsEmailConfirmed(model.UserId)) + { + await UserManager.ConfirmEmailAsync(model.UserId, model.ResetCode); + } + + //if the user is invited, enable their account on forgot password + var identityUser = await UserManager.FindByIdAsync(model.UserId); + //invited is not approved, never logged in, invited date present + /* + if (LastLoginDate == default && IsApproved == false && InvitedDate != null) + return UserState.Invited; + */ + if (identityUser != null && !identityUser.IsApproved) + { + var user = Services.UserService.GetByUsername(identityUser.UserName); + //also check InvitedDate and never logged in, otherwise this would allow a disabled user to reactivate their account with a forgot password + if (user.LastLoginDate == default && user.InvitedDate != null) + { + user.IsApproved = true; + user.InvitedDate = null; + Services.UserService.Save(user); + } + } + UserManager.RaiseForgotPasswordChangedSuccessEvent(model.UserId); return Request.CreateResponse(HttpStatusCode.OK); } diff --git a/src/Umbraco.Web/Editors/BackOfficeController.cs b/src/Umbraco.Web/Editors/BackOfficeController.cs index ab89390bf6..f3bda66b51 100644 --- a/src/Umbraco.Web/Editors/BackOfficeController.cs +++ b/src/Umbraco.Web/Editors/BackOfficeController.cs @@ -82,6 +82,16 @@ namespace Umbraco.Web.Editors [HttpGet] public async Task VerifyInvite(string invite) { + //if you are hitting VerifyInvite, you're already signed in as a different user, and the token is invalid + //you'll exit on one of the return RedirectToAction("Default") but you're still logged in so you just get + //dumped at the default admin view with no detail + if(Security.IsAuthenticated()) + { + AuthenticationManager.SignOut( + Core.Constants.Security.BackOfficeAuthenticationType, + Core.Constants.Security.BackOfficeExternalAuthenticationType); + } + if (invite == null) { Logger.Warn("VerifyUser endpoint reached with invalid token: NULL"); @@ -125,16 +135,15 @@ namespace Umbraco.Web.Editors if (result.Succeeded == false) { Logger.Warn("Could not verify email, Error: " + string.Join(",", result.Errors) + ", Token: " + invite); - return RedirectToAction("Default"); + return new RedirectResult(Url.Action("Default") + "#/login/false?invite=3"); } //sign the user in - - AuthenticationManager.SignOut( - Core.Constants.Security.BackOfficeAuthenticationType, - Core.Constants.Security.BackOfficeExternalAuthenticationType); - + DateTime? previousLastLoginDate = identityUser.LastLoginDateUtc; await SignInManager.SignInAsync(identityUser, false, false); + //reset the lastlogindate back to previous as the user hasn't actually logged in, to add a flag or similar to SignInManager would be a breaking change + identityUser.LastLoginDateUtc = previousLastLoginDate; + await UserManager.UpdateAsync(identityUser); return new RedirectResult(Url.Action("Default") + "#/login/false?invite=1"); } diff --git a/src/Umbraco.Web/Editors/ContentController.cs b/src/Umbraco.Web/Editors/ContentController.cs index 8e46b86105..040d45f90a 100644 --- a/src/Umbraco.Web/Editors/ContentController.cs +++ b/src/Umbraco.Web/Editors/ContentController.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Globalization; +using System.IO; using System.Linq; using System.Net; using System.Net.Http; @@ -585,6 +586,17 @@ namespace Umbraco.Web.Editors private ContentItemDisplay PostSaveInternal(ContentItemSave contentItem, Func saveMethod) { + //Recent versions of IE/Edge may send in the full clientside file path instead of just the file name. + //To ensure similar behavior across all browsers no matter what they do - we strip the FileName property of all + //uploaded files to being *only* the actual file name (as it should be). + if (contentItem.UploadedFiles != null && contentItem.UploadedFiles.Any()) + { + foreach (var file in contentItem.UploadedFiles) + { + file.FileName = Path.GetFileName(file.FileName); + } + } + //If we've reached here it means: // * Our model has been bound // * and validated diff --git a/src/Umbraco.Web/Editors/DashboardController.cs b/src/Umbraco.Web/Editors/DashboardController.cs index 85ba534dfd..e88b9975e7 100644 --- a/src/Umbraco.Web/Editors/DashboardController.cs +++ b/src/Umbraco.Web/Editors/DashboardController.cs @@ -27,6 +27,8 @@ namespace Umbraco.Web.Editors [WebApi.UmbracoAuthorize] public class DashboardController : UmbracoApiController { + //we have just one instance of HttpClient shared for the entire application + private static readonly HttpClient HttpClient = new HttpClient(); //we have baseurl as a param to make previewing easier, so we can test with a dev domain from client side [ValidateAngularAntiForgeryToken] public async Task GetRemoteDashboardContent(string section, string baseUrl = "https://dashboard.umbraco.org/") @@ -54,13 +56,10 @@ namespace Umbraco.Web.Editors //content is null, go get it try { - using (var web = new HttpClient()) - { - //fetch dashboard json and parse to JObject - var json = await web.GetStringAsync(url); - content = JObject.Parse(json); - result = content; - } + //fetch dashboard json and parse to JObject + var json = await HttpClient.GetStringAsync(url); + content = JObject.Parse(json); + result = content; ApplicationCache.RuntimeCache.InsertCacheItem(key, () => result, new TimeSpan(0, 30, 0)); } @@ -93,17 +92,14 @@ namespace Umbraco.Web.Editors //content is null, go get it try { - using (var web = new HttpClient()) - { - //fetch remote css - content = await web.GetStringAsync(url); + //fetch remote css + content = await HttpClient.GetStringAsync(url); - //can't use content directly, modified closure problem - result = content; + //can't use content directly, modified closure problem + result = content; - //save server content for 30 mins + //save server content for 30 mins ApplicationCache.RuntimeCache.InsertCacheItem(key, () => result, new TimeSpan(0, 30, 0)); - } } catch (HttpRequestException ex) { diff --git a/src/Umbraco.Web/Editors/HelpController.cs b/src/Umbraco.Web/Editors/HelpController.cs index 50e6547e36..ccbbcaeee8 100644 --- a/src/Umbraco.Web/Editors/HelpController.cs +++ b/src/Umbraco.Web/Editors/HelpController.cs @@ -7,20 +7,22 @@ using System.Threading.Tasks; namespace Umbraco.Web.Editors { public class HelpController : UmbracoAuthorizedJsonController - { + { + private static HttpClient _httpClient; public async Task> GetContextHelpForPage(string section, string tree, string baseUrl = "https://our.umbraco.com") { var url = string.Format(baseUrl + "/Umbraco/Documentation/Lessons/GetContextHelpDocs?sectionAlias={0}&treeAlias={1}", section, tree); - using (var web = new HttpClient()) - { - //fetch dashboard json and parse to JObject - var json = await web.GetStringAsync(url); - var result = JsonConvert.DeserializeObject>(json); - if (result != null) - return result; - return new List(); - } + if (_httpClient == null) + _httpClient = new HttpClient(); + + //fetch dashboard json and parse to JObject + var json = await _httpClient.GetStringAsync(url); + var result = JsonConvert.DeserializeObject>(json); + if (result != null) + return result; + + return new List(); } } diff --git a/src/Umbraco.Web/Editors/LogController.cs b/src/Umbraco.Web/Editors/LogController.cs index e36fe05de3..1205226b8f 100644 --- a/src/Umbraco.Web/Editors/LogController.cs +++ b/src/Umbraco.Web/Editors/LogController.cs @@ -1,10 +1,11 @@ -using System; +using AutoMapper; +using System; using System.Collections.Generic; using System.Linq; -using AutoMapper; -using Umbraco.Web.Models.ContentEditing; +using Umbraco.Core; using Umbraco.Core.Models; using Umbraco.Core.Persistence.DatabaseModelDefinitions; +using Umbraco.Web.Models.ContentEditing; using Umbraco.Web.Mvc; namespace Umbraco.Web.Editors @@ -45,7 +46,7 @@ namespace Umbraco.Web.Editors var userId = Security.GetUserId().ResultOr(0); var result = Services.AuditService.GetPagedItemsByUser(userId, pageNumber - 1, pageSize, out totalRecords, orderDirection, customFilter:dateQuery); var mapped = Mapper.Map>(result); - return new PagedResult(totalRecords, pageNumber + 1, pageSize) + return new PagedResult(totalRecords, pageNumber, pageSize) { Items = MapAvatarsAndNames(mapped) }; diff --git a/src/Umbraco.Web/Editors/MediaController.cs b/src/Umbraco.Web/Editors/MediaController.cs index 40f62c9cfd..635cdfaa17 100644 --- a/src/Umbraco.Web/Editors/MediaController.cs +++ b/src/Umbraco.Web/Editors/MediaController.cs @@ -439,6 +439,17 @@ namespace Umbraco.Web.Editors [ModelBinder(typeof(MediaItemBinder))] MediaItemSave contentItem) { + //Recent versions of IE/Edge may send in the full clientside file path instead of just the file name. + //To ensure similar behavior across all browsers no matter what they do - we strip the FileName property of all + //uploaded files to being *only* the actual file name (as it should be). + if (contentItem.UploadedFiles != null && contentItem.UploadedFiles.Any()) + { + foreach (var file in contentItem.UploadedFiles) + { + file.FileName = Path.GetFileName(file.FileName); + } + } + //If we've reached here it means: // * Our model has been bound // * and validated @@ -688,15 +699,7 @@ namespace Umbraco.Web.Editors mediaType = result.FormData["contentTypeAlias"]; } - //TODO: make the media item name "nice" since file names could be pretty ugly, we have - // string extensions to do much of this but we'll need: - // * Pascalcase the name (use string extensions) - // * strip the file extension - // * underscores to spaces - // * probably remove 'ugly' characters - let's discuss - // All of this logic should exist in a string extensions method and be unit tested - // http://issues.umbraco.org/issue/U4-5572 - var mediaItemName = fileName; + var mediaItemName = fileName.ToFriendlyName(); var f = mediaService.CreateMedia(mediaItemName, parentId, mediaType, Security.CurrentUser.Id); @@ -910,4 +913,4 @@ namespace Umbraco.Web.Editors return hasPathAccess; } } -} +} \ No newline at end of file diff --git a/src/Umbraco.Web/Editors/RedirectUrlManagementController.cs b/src/Umbraco.Web/Editors/RedirectUrlManagementController.cs index d63eaa2b48..377b76f52a 100644 --- a/src/Umbraco.Web/Editors/RedirectUrlManagementController.cs +++ b/src/Umbraco.Web/Editors/RedirectUrlManagementController.cs @@ -12,6 +12,7 @@ using Umbraco.Web.Models.ContentEditing; using Umbraco.Web.Mvc; using Umbraco.Web.WebApi; using File = System.IO.File; +using Umbraco.Core; namespace Umbraco.Web.Editors { @@ -63,7 +64,28 @@ namespace Umbraco.Web.Editors return searchResult; } - + /// + /// This lists the RedirectUrls for a particular content item + /// Do we need to consider paging here? + /// + /// Udi of content item to retrieve RedirectUrls for + /// + [HttpGet] + public RedirectUrlSearchResult RedirectUrlsForContentItem(string contentUdi) + { + var redirectsResult = new RedirectUrlSearchResult(); + if (GuidUdi.TryParse(contentUdi, out var guidIdi)) + { + var redirectUrlService = Services.RedirectUrlService; + var redirects = redirectUrlService.GetContentRedirectUrls(guidIdi.Guid); + redirectsResult.SearchResults = Mapper.Map>(redirects).ToArray(); + //not doing paging 'yet' + redirectsResult.TotalCount = redirects.Count(); + redirectsResult.CurrentPage = 1; + redirectsResult.PageCount = 1; + } + return redirectsResult; + } [HttpPost] public IHttpActionResult DeleteRedirectUrl(Guid id) { diff --git a/src/Umbraco.Web/Install/InstallHelper.cs b/src/Umbraco.Web/Install/InstallHelper.cs index fe8be890fe..476f23ea8e 100644 --- a/src/Umbraco.Web/Install/InstallHelper.cs +++ b/src/Umbraco.Web/Install/InstallHelper.cs @@ -26,6 +26,7 @@ namespace Umbraco.Web.Install { public sealed class InstallHelper { + private static HttpClient _httpClient; private readonly DatabaseBuilder _databaseBuilder; private readonly HttpContextBase _httpContext; private readonly ILogger _logger; @@ -168,16 +169,17 @@ namespace Umbraco.Web.Install internal IEnumerable GetStarterKits() { - var packages = new List(); + if (_httpClient == null) + _httpClient = new HttpClient(); + var packages = new List(); try { var requestUri = $"https://our.umbraco.com/webapi/StarterKit/Get/?umbracoVersion={UmbracoVersion.Current}"; using (var request = new HttpRequestMessage(HttpMethod.Get, requestUri)) - using (var httpClient = new HttpClient()) - using (var response = httpClient.SendAsync(request).Result) { + var response = _httpClient.SendAsync(request).Result; packages = response.Content.ReadAsAsync>().Result.ToList(); } } diff --git a/src/Umbraco.Web/Install/InstallSteps/NewInstallStep.cs b/src/Umbraco.Web/Install/InstallSteps/NewInstallStep.cs index 8a67001cc6..0b225e158b 100644 --- a/src/Umbraco.Web/Install/InstallSteps/NewInstallStep.cs +++ b/src/Umbraco.Web/Install/InstallSteps/NewInstallStep.cs @@ -1,13 +1,15 @@ using System; -using System.Collections.Generic; using System.Collections.Specialized; using System.Configuration; +using System.Net; +using System.Net.Http; +using System.Text; using System.Web; using System.Web.Security; +using Newtonsoft.Json; using Umbraco.Core; using Umbraco.Core.Configuration; using Umbraco.Core.Migrations.Install; -using Umbraco.Core.Persistence; using Umbraco.Core.Services; using Umbraco.Web.Install.Models; @@ -27,6 +29,7 @@ namespace Umbraco.Web.Install.InstallSteps private readonly HttpContextBase _http; private readonly IUserService _userService; private readonly DatabaseBuilder _databaseBuilder; + private static HttpClient _httpClient; private readonly IGlobalSettings _globalSettings; public NewInstallStep(HttpContextBase http, IUserService userService, DatabaseBuilder databaseBuilder, IGlobalSettings globalSettings) @@ -79,15 +82,18 @@ namespace Umbraco.Web.Install.InstallSteps admin.Username = user.Email.Trim(); _userService.Save(admin); - - + if (user.SubscribeToNewsLetter) { + if (_httpClient == null) + _httpClient = new HttpClient(); + + var values = new NameValueCollection { { "name", admin.Name }, { "email", admin.Email } }; + var content = new StringContent(JsonConvert.SerializeObject(values), Encoding.UTF8, "application/json"); + try { - var client = new System.Net.WebClient(); - var values = new NameValueCollection { { "name", admin.Name }, { "email", admin.Email} }; - client.UploadValues("https://shop.umbraco.com/base/Ecom/SubmitEmail/installer.aspx", values); + var response = _httpClient.PostAsync("https://shop.umbraco.com/base/Ecom/SubmitEmail/installer.aspx", content).Result; } catch { /* fail in silence */ } } @@ -114,11 +120,14 @@ namespace Umbraco.Web.Install.InstallSteps public override string View { - get { return RequiresExecution(null) - //the user UI + get + { + return RequiresExecution(null) + //the user UI ? "user" - //the continue install UI - : "continueinstall"; } + //the continue install UI + : "continueinstall"; + } } public override bool RequiresExecution(UserModel model) diff --git a/src/Umbraco.Web/Media/EmbedProviders/AbstractOEmbedProvider.cs b/src/Umbraco.Web/Media/EmbedProviders/AbstractOEmbedProvider.cs index cec9de7404..921036c75a 100644 --- a/src/Umbraco.Web/Media/EmbedProviders/AbstractOEmbedProvider.cs +++ b/src/Umbraco.Web/Media/EmbedProviders/AbstractOEmbedProvider.cs @@ -12,18 +12,20 @@ namespace Umbraco.Web.Media.EmbedProviders { //TODO: Make all Http calls async - public abstract class AbstractOEmbedProvider: IEmbedProvider + public abstract class AbstractOEmbedProvider : IEmbedProvider { + private static HttpClient _httpClient; + public virtual bool SupportsDimensions { get { return true; } } [ProviderSetting] - public string APIEndpoint{ get;set; } + public string APIEndpoint { get; set; } [ProviderSetting] - public Dictionary RequestParams{ get;set; } + public Dictionary RequestParams { get; set; } public abstract string GetMarkup(string url, int maxWidth, int maxHeight); @@ -51,9 +53,13 @@ namespace Umbraco.Web.Media.EmbedProviders public virtual string DownloadResponse(string url) { - using (var webClient = new WebClient()) + if (_httpClient == null) + _httpClient = new HttpClient(); + + using (var request = new HttpRequestMessage(HttpMethod.Get, url)) { - return webClient.DownloadString(url); + var response = _httpClient.SendAsync(request).Result; + return response.Content.ReadAsStringAsync().Result; } } diff --git a/src/Umbraco.Web/Media/Exif/ImageFileFormat.cs b/src/Umbraco.Web/Media/Exif/ImageFileFormat.cs index 0e3cb5010f..364877f7da 100644 --- a/src/Umbraco.Web/Media/Exif/ImageFileFormat.cs +++ b/src/Umbraco.Web/Media/Exif/ImageFileFormat.cs @@ -17,5 +17,9 @@ /// The file is a TIFF File. /// TIFF, + /// + /// The file is a SVG File. + /// + SVG, } } diff --git a/src/Umbraco.Web/Scheduling/HealthCheckNotifier.cs b/src/Umbraco.Web/Scheduling/HealthCheckNotifier.cs index e52b46a42d..89fba7717d 100644 --- a/src/Umbraco.Web/Scheduling/HealthCheckNotifier.cs +++ b/src/Umbraco.Web/Scheduling/HealthCheckNotifier.cs @@ -38,7 +38,7 @@ namespace Umbraco.Web.Scheduling switch (_runtimeState.ServerRole) { case ServerRole.Replica: - _logger.Debug("Does not run on slave servers."); + _logger.Debug("Does not run on replica servers."); return true; // DO repeat, server role can change case ServerRole.Unknown: _logger.Debug("Does not run on servers with unknown role."); diff --git a/src/Umbraco.Web/Scheduling/KeepAlive.cs b/src/Umbraco.Web/Scheduling/KeepAlive.cs index 7100b1a03b..546d1c83ab 100644 --- a/src/Umbraco.Web/Scheduling/KeepAlive.cs +++ b/src/Umbraco.Web/Scheduling/KeepAlive.cs @@ -32,7 +32,7 @@ namespace Umbraco.Web.Scheduling switch (_runtime.ServerRole) { case ServerRole.Replica: - _logger.Debug("Does not run on slave servers."); + _logger.Debug("Does not run on replica servers."); return true; // role may change! case ServerRole.Unknown: _logger.Debug("Does not run on servers with unknown role."); diff --git a/src/Umbraco.Web/Scheduling/LogScrubber.cs b/src/Umbraco.Web/Scheduling/LogScrubber.cs index d2feb9923e..ae73da04c8 100644 --- a/src/Umbraco.Web/Scheduling/LogScrubber.cs +++ b/src/Umbraco.Web/Scheduling/LogScrubber.cs @@ -69,7 +69,7 @@ namespace Umbraco.Web.Scheduling switch (_runtime.ServerRole) { case ServerRole.Replica: - _logger.Debug("Does not run on slave servers."); + _logger.Debug("Does not run on replica servers."); return true; // DO repeat, server role can change case ServerRole.Unknown: _logger.Debug("Does not run on servers with unknown role."); diff --git a/src/Umbraco.Web/Scheduling/ScheduledPublishing.cs b/src/Umbraco.Web/Scheduling/ScheduledPublishing.cs index 13a99daaea..471eb213c0 100644 --- a/src/Umbraco.Web/Scheduling/ScheduledPublishing.cs +++ b/src/Umbraco.Web/Scheduling/ScheduledPublishing.cs @@ -32,7 +32,7 @@ namespace Umbraco.Web.Scheduling switch (_runtime.ServerRole) { case ServerRole.Replica: - _logger.Debug("Does not run on slave servers."); + _logger.Debug("Does not run on replica servers."); return true; // DO repeat, server role can change case ServerRole.Unknown: _logger.Debug("Does not run on servers with unknown role."); diff --git a/src/Umbraco.Web/Scheduling/ScheduledTasks.cs b/src/Umbraco.Web/Scheduling/ScheduledTasks.cs index 76a909095a..c9c3869f30 100644 --- a/src/Umbraco.Web/Scheduling/ScheduledTasks.cs +++ b/src/Umbraco.Web/Scheduling/ScheduledTasks.cs @@ -17,6 +17,7 @@ namespace Umbraco.Web.Scheduling internal class ScheduledTasks : RecurringTaskBase { + private static HttpClient _httpClient; private readonly IRuntimeState _runtime; private readonly IUmbracoSettingsSection _settings; private readonly ILogger _logger; @@ -65,27 +66,28 @@ namespace Umbraco.Web.Scheduling private async Task GetTaskByHttpAync(string url, CancellationToken token) { - using (var wc = new HttpClient()) + if (_httpClient == null) + _httpClient = new HttpClient(); + + if (Uri.TryCreate(_runtime.ApplicationUrl, UriKind.Absolute, out var baseUri)) + _httpClient.BaseAddress = baseUri; + + var request = new HttpRequestMessage(HttpMethod.Get, url); + + //TODO: pass custom the authorization header, currently these aren't really secured! + //request.Headers.Authorization = AdminTokenAuthorizeAttribute.GetAuthenticationHeaderValue(_appContext); + + try { - // url could be relative, so better set a base url for the http client - wc.BaseAddress = _runtime.ApplicationUrl; - - var request = new HttpRequestMessage(HttpMethod.Get, url); - - //TODO: pass custom the authorization header, currently these aren't really secured! - //request.Headers.Authorization = AdminTokenAuthorizeAttribute.GetAuthenticationHeaderValue(_appContext); - - try - { - var result = await wc.SendAsync(request, token).ConfigureAwait(false); // ConfigureAwait(false) is recommended? http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html - return result.StatusCode == HttpStatusCode.OK; - } - catch (Exception ex) - { - _logger.Error(ex, "An error occurred calling web task for url: {Url}", url); - } - return false; + var result = await _httpClient.SendAsync(request, token).ConfigureAwait(false); // ConfigureAwait(false) is recommended? http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html + return result.StatusCode == HttpStatusCode.OK; } + catch (Exception ex) + { + _logger.Error(ex, "An error occurred calling web task for url: {Url}", url); + + } + return false; } public override async Task PerformRunAsync(CancellationToken token) @@ -93,7 +95,7 @@ namespace Umbraco.Web.Scheduling switch (_runtime.ServerRole) { case ServerRole.Replica: - _logger.Debug("Does not run on slave servers."); + _logger.Debug("Does not run on replica servers."); return true; // DO repeat, server role can change case ServerRole.Unknown: _logger.Debug("Does not run on servers with unknown role."); diff --git a/src/Umbraco.Web/Security/BackOfficeUserManager.cs b/src/Umbraco.Web/Security/BackOfficeUserManager.cs index 828aed588c..ce51f82c43 100644 --- a/src/Umbraco.Web/Security/BackOfficeUserManager.cs +++ b/src/Umbraco.Web/Security/BackOfficeUserManager.cs @@ -191,7 +191,10 @@ namespace Umbraco.Web.Security if (dataProtectionProvider != null) { - manager.UserTokenProvider = new DataProtectorTokenProvider(dataProtectionProvider.Create("ASP.NET Identity")); + manager.UserTokenProvider = new DataProtectorTokenProvider(dataProtectionProvider.Create("ASP.NET Identity")) + { + TokenLifespan = TimeSpan.FromDays(3) + }; } manager.UserLockoutEnabledByDefault = true; @@ -703,6 +706,7 @@ namespace Umbraco.Web.Security var httpContext = HttpContext.Current == null ? (HttpContextBase)null : new HttpContextWrapper(HttpContext.Current); return httpContext.GetCurrentRequestIpAddress(); } + } } diff --git a/src/Umbraco.Web/Templates/TemplateUtilities.cs b/src/Umbraco.Web/Templates/TemplateUtilities.cs index 91548e44f1..9c13429b44 100644 --- a/src/Umbraco.Web/Templates/TemplateUtilities.cs +++ b/src/Umbraco.Web/Templates/TemplateUtilities.cs @@ -1,4 +1,6 @@ -using System; +using HtmlAgilityPack; +using System; +using System.Runtime.CompilerServices; using System.Text.RegularExpressions; using Umbraco.Core; using Umbraco.Core.Configuration; @@ -36,6 +38,11 @@ namespace Umbraco.Web.Templates { if (urlProvider == null) throw new ArgumentNullException("urlProvider"); + if(string.IsNullOrEmpty(text)) + { + return text; + } + // Parse internal links var tags = LocalLinkPattern.Matches(text); foreach (Match tag in tags) @@ -64,6 +71,11 @@ namespace Umbraco.Web.Templates } } + if (UmbracoConfig.For.UmbracoSettings().Content.StripUdiAttributes) + { + text = StripUdiDataAttributes(text); + } + return text; } @@ -75,6 +87,9 @@ namespace Umbraco.Web.Templates private static readonly Regex ResolveUrlPattern = new Regex("(=[\"\']?)(\\W?\\~(?:.(?![\"\']?\\s+(?:\\S+)=|[>\"\']))+.)[\"\']?", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace); + private static readonly Regex UdiDataAttributePattern = new Regex("data-udi=\"[^\\\"]*\"", + RegexOptions.IgnoreCase | RegexOptions.Compiled); + /// /// The RegEx matches any HTML attribute values that start with a tilde (~), those that match are passed to ResolveUrl to replace the tilde with the application path. /// @@ -118,5 +133,21 @@ namespace Umbraco.Web.Templates { return text.CleanForXss(ignoreFromClean); } + + /// + /// Strips data-udi attributes from rich text + /// + /// A html string + /// A string stripped from the data-uid attributes + public static string StripUdiDataAttributes(string input) + { + if (string.IsNullOrEmpty(input)) + { + return string.Empty; + } + + + return UdiDataAttributePattern.Replace(input, string.Empty); + } } } diff --git a/src/Umbraco.Web/Trees/DataTypeTreeController.cs b/src/Umbraco.Web/Trees/DataTypeTreeController.cs index 99b94b544c..d63a14af35 100644 --- a/src/Umbraco.Web/Trees/DataTypeTreeController.cs +++ b/src/Umbraco.Web/Trees/DataTypeTreeController.cs @@ -46,8 +46,8 @@ namespace Umbraco.Web.Trees //if the request is for folders only then just return if (queryStrings["foldersonly"].IsNullOrWhiteSpace() == false && queryStrings["foldersonly"] == "1") return nodes; - //Normal nodes - var sysIds = GetSystemIds(); + //System ListView nodes + var systemListViewDataTypeIds = GetNonDeletableSystemListViewDataTypeIds(); nodes.AddRange( Services.EntityService.GetChildren(intId.Result, UmbracoObjectTypes.DataType) @@ -56,7 +56,7 @@ namespace Umbraco.Web.Trees { var node = CreateTreeNode(dt.Id.ToInvariantString(), id, queryStrings, dt.Name, "icon-autofill", false); node.Path = dt.Path; - if (sysIds.Contains(dt.Id)) + if (systemListViewDataTypeIds.Contains(dt.Id)) { node.Icon = "icon-thumbnail-list"; } @@ -66,15 +66,31 @@ namespace Umbraco.Web.Trees return nodes; } - private IEnumerable GetSystemIds() + /// + /// Get all integer identifiers for the non-deletable system datatypes. + /// + private static IEnumerable GetNonDeletableSystemDataTypeIds() { var systemIds = new[] + { + Constants.System.DefaultLabelDataTypeId + }; + + return systemIds.Concat(GetNonDeletableSystemListViewDataTypeIds()); + } + + /// + /// Get all integer identifiers for the non-deletable system listviews. + /// + private static IEnumerable GetNonDeletableSystemListViewDataTypeIds() + { + return new[] { Constants.DataTypes.DefaultContentListView, Constants.DataTypes.DefaultMediaListView, Constants.DataTypes.DefaultMembersListView + }; - return systemIds; } protected override MenuItemCollection GetMenuForNode(string id, FormDataCollection queryStrings) @@ -87,7 +103,7 @@ namespace Umbraco.Web.Trees menu.DefaultMenuAlias = ActionNew.Instance.Alias; // root actions - menu.Items.Add(Services.TextService.Localize(string.Format("actions/{0}", ActionNew.Instance.Alias))); + menu.Items.Add(Services.TextService.Localize($"actions/{ActionNew.Instance.Alias}")); menu.Items.Add(Services.TextService.Localize("actions", ActionRefresh.Instance.Alias), true); return menu; } @@ -98,30 +114,27 @@ namespace Umbraco.Web.Trees //set the default to create menu.DefaultMenuAlias = ActionNew.Instance.Alias; - menu.Items.Add(Services.TextService.Localize(string.Format("actions/{0}", ActionNew.Instance.Alias))); + menu.Items.Add(Services.TextService.Localize($"actions/{ActionNew.Instance.Alias}")); - menu.Items.Add(new MenuItem("rename", Services.TextService.Localize(String.Format("actions/{0}", "rename"))) + menu.Items.Add(new MenuItem("rename", Services.TextService.Localize("actions/rename")) { Icon = "icon icon-edit" }); if (container.HasChildren == false) - { //can delete data type - menu.Items.Add(Services.TextService.Localize(string.Format("actions/{0}", ActionDelete.Instance.Alias))); + menu.Items.Add(Services.TextService.Localize($"actions/{ActionDelete.Instance.Alias}")); } - menu.Items.Add(Services.TextService.Localize(string.Format("actions/{0}", ActionRefresh.Instance.Alias)), hasSeparator: true); + menu.Items.Add(Services.TextService.Localize($"actions/{ActionRefresh.Instance.Alias}"), hasSeparator: true); } else { - var sysIds = GetSystemIds(); + var nonDeletableSystemDataTypeIds = GetNonDeletableSystemDataTypeIds(); - if (sysIds.Contains(int.Parse(id)) == false) - { - menu.Items.Add(Services.TextService.Localize(string.Format("actions/{0}", ActionDelete.Instance.Alias))); - } + if (nonDeletableSystemDataTypeIds.Contains(int.Parse(id)) == false) + menu.Items.Add(Services.TextService.Localize($"actions/{ActionDelete.Instance.Alias}")); - menu.Items.Add(Services.TextService.Localize(string.Format("actions/{0}", ActionMove.Instance.Alias)), hasSeparator: true); + menu.Items.Add(Services.TextService.Localize($"actions/{ActionMove.Instance.Alias}"), hasSeparator: true); } return menu; diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index c2a420b3d6..ddd91ba983 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -1568,4 +1568,2034 @@ + + + + + 9.0.30729 + 2.0 + {651E1350-91B6-44B7-BD60-7207006D7003} + Debug + AnyCPU + + + + + umbraco + + + JScript + Grid + IE50 + false + Library + Umbraco.Web + OnBuildSuccess + + + + + + + + + + + + + + + 4.0 + v4.5 + + ..\ + true + latest + + + bin\Debug\ + false + 285212672 + false + + + DEBUG;TRACE + + + true + 4096 + false + + + false + false + false + false + 4 + full + prompt + AllRules.ruleset + false + Off + latest + + + bin\Release\ + false + 285212672 + false + + + TRACE + bin\Release\umbraco.xml + true + 4096 + false + + + true + false + false + false + 4 + pdbonly + prompt + AllRules.ruleset + false + Off + + + + {07fbc26b-2927-4a22-8d96-d644c667fecc} + UmbracoExamine + + + ..\packages\AutoMapper.3.3.1\lib\net40\AutoMapper.dll + True + + + ..\packages\AutoMapper.3.3.1\lib\net40\AutoMapper.Net4.dll + True + + + ..\packages\ClientDependency.1.9.7\lib\net45\ClientDependency.Core.dll + + + ..\packages\dotless.1.5.2\lib\dotless.Core.dll + + + ..\packages\Examine.0.1.89\lib\net45\Examine.dll + + + ..\packages\HtmlAgilityPack.1.4.9.5\lib\Net45\HtmlAgilityPack.dll + True + + + ..\packages\SharpZipLib.0.86.0\lib\20\ICSharpCode.SharpZipLib.dll + + + ..\packages\Lucene.Net.2.9.4.1\lib\net40\Lucene.Net.dll + + + ..\packages\Markdown.1.14.7\lib\net45\MarkdownSharp.dll + True + + + ..\packages\Microsoft.AspNet.Identity.Core.2.2.1\lib\net45\Microsoft.AspNet.Identity.Core.dll + True + + + ..\packages\Microsoft.AspNet.Identity.Owin.2.2.1\lib\net45\Microsoft.AspNet.Identity.Owin.dll + True + + + ..\packages\Microsoft.AspNet.SignalR.Core.2.2.1\lib\net45\Microsoft.AspNet.SignalR.Core.dll + True + + + + ..\packages\Microsoft.Owin.3.1.0\lib\net45\Microsoft.Owin.dll + + + ..\packages\Microsoft.Owin.Host.SystemWeb.3.1.0\lib\net45\Microsoft.Owin.Host.SystemWeb.dll + + + ..\packages\Microsoft.Owin.Security.3.1.0\lib\net45\Microsoft.Owin.Security.dll + + + ..\packages\Microsoft.Owin.Security.Cookies.3.1.0\lib\net45\Microsoft.Owin.Security.Cookies.dll + + + ..\packages\Microsoft.Owin.Security.OAuth.3.1.0\lib\net45\Microsoft.Owin.Security.OAuth.dll + + + ..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll + True + + + ..\packages\MiniProfiler.2.1.0\lib\net40\MiniProfiler.dll + True + + + ..\packages\Newtonsoft.Json.10.0.2\lib\net45\Newtonsoft.Json.dll + + + ..\packages\Owin.1.0\lib\net40\Owin.dll + True + + + ..\packages\semver.1.1.2\lib\net45\Semver.dll + + + System + + + + + + System.Data + + + + + System.Drawing + + + + + + ..\packages\Microsoft.AspNet.WebApi.Client.5.2.3\lib\net45\System.Net.Http.Formatting.dll + True + + + + + ..\packages\System.Threading.Tasks.Dataflow.4.7.0\lib\portable-net45+win8+wpa81\System.Threading.Tasks.Dataflow.dll + + + ..\packages\System.ValueTuple.4.4.0\lib\netstandard1.0\System.ValueTuple.dll + + + + 3.5 + + + + + + + + ..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.Helpers.dll + True + + + ..\packages\Microsoft.AspNet.WebApi.Core.5.2.3\lib\net45\System.Web.Http.dll + True + + + ..\packages\Microsoft.AspNet.WebApi.WebHost.5.2.3\lib\net45\System.Web.Http.WebHost.dll + True + + + ..\packages\Microsoft.AspNet.Mvc.5.2.3\lib\net45\System.Web.Mvc.dll + True + + + ..\packages\Microsoft.AspNet.Razor.3.2.3\lib\net45\System.Web.Razor.dll + True + + + System.Web.Services + + + ..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.dll + True + + + ..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Deployment.dll + True + + + ..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Razor.dll + True + + + + System.XML + + + + {5BA5425F-27A7-4677-865E-82246498AA2E} + SqlCE4Umbraco + + + {31785BC3-256C-4613-B2F5-A1B0BDDED8C1} + Umbraco.Core + + + {6EDD2061-82F2-461B-BB6E-879245A832DE} + umbraco.controls + + + umbraco.businesslogic + {E469A9CE-1BEC-423F-AC44-713CD72457EA} + {FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + + + {CCD75EC3-63DB-4184-B49D-51C1DD337230} + umbraco.cms + + + {C7CB79F0-1C97-4B33-BFA7-00731B579AE2} + umbraco.datalayer + + + umbraco.interfaces + {511F6D8D-7717-440A-9A57-A507E9A8B27F} + {FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + + + {D7636876-0756-43CB-A192-138C6F0D5E42} + umbraco.providers + + + + + Properties\SolutionInfo.cs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ASPXCodeBehind + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ASPXCodeBehind + + + ASPXCodeBehind + + + ASPXCodeBehind + + + + + + True + True + Reference.map + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + True + True + Resources.resx + + + + + + + + + + + + + + ASPXCodeBehind + + + ASPXCodeBehind + + + ASPXCodeBehind + + + ASPXCodeBehind + + + ASPXCodeBehind + + + AssignDomain2.aspx + ASPXCodeBehind + + + AssignDomain2.aspx + + + + ASPXCodeBehind + + + ASPXCodeBehind + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ASPXCodeBehind + + + + + + + + + + + + + + + + + + + + + True + True + Strings.resx + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ASPXCodeBehind + + + ASPXCodeBehind + + + + ASPXCodeBehind + + + + + ASPXCodeBehind + + + + + ASPXCodeBehind + + + ASPXCodeBehind + + + ASPXCodeBehind + + + ASPXCodeBehind + + + ASPXCodeBehind + + + ASPXCodeBehind + + + ASPXCodeBehind + + + ASPXCodeBehind + + + ASPXCodeBehind + + + ASPXCodeBehind + + + ASPXCodeBehind + + + ASPXCodeBehind + + + ASPXCodeBehind + + + ASPXCodeBehind + + + ASPXCodeBehind + + + + ASPXCodeBehind + + + ASPXCodeBehind + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ASPXCodeBehind + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Code + + + + Code + + + Code + + + Code + + + Code + + + Code + + + + Code + + + True + True + Settings.settings + + + Code + + + + + Code + + + Code + + + Code + + + Code + + + + ASPXCodeBehind + + + Code + + + Code + + + Code + + + + delete.aspx + ASPXCodeBehind + + + delete.aspx + + + editContent.aspx + ASPXCodeBehind + + + editContent.aspx + + + preview.aspx + ASPXCodeBehind + + + preview.aspx + + + publish.aspx + ASPXCodeBehind + + + publish.aspx + + + + + + ASPXCodeBehind + + + + + + + ProgressBar.ascx + ASPXCodeBehind + + + ProgressBar.ascx + + + + ASPXCodeBehind + + + Component + + + + + Code + + + + + + + + + + FeedProxy.aspx + ASPXCodeBehind + + + FeedProxy.aspx + + + EditRelationType.aspx + ASPXCodeBehind + + + EditRelationType.aspx + + + NewRelationType.aspx + ASPXCodeBehind + + + NewRelationType.aspx + + + + RelationTypesWebService.asmx + Component + + + + + Preview.aspx + ASPXCodeBehind + + + Preview.aspx + + + MemberSearch.ascx + ASPXCodeBehind + + + MemberSearch.ascx + + + + + + xsltVisualize.aspx + ASPXCodeBehind + + + xsltVisualize.aspx + + + insertMasterpageContent.aspx + ASPXCodeBehind + + + insertMasterpageContent.aspx + + + insertMasterpagePlaceholder.aspx + ASPXCodeBehind + + + insertMasterpagePlaceholder.aspx + + + republish.aspx + ASPXCodeBehind + + + republish.aspx + + + search.aspx + ASPXCodeBehind + + + search.aspx + + + SendPublish.aspx + ASPXCodeBehind + + + SendPublish.aspx + + + Code + + + Code + + + assemblyBrowser.aspx + ASPXCodeBehind + + + assemblyBrowser.aspx + + + editPackage.aspx + ASPXCodeBehind + + + editPackage.aspx + + + getXsltStatus.asmx + Component + + + xsltChooseExtension.aspx + ASPXCodeBehind + + + xsltChooseExtension.aspx + + + xsltInsertValueOf.aspx + ASPXCodeBehind + + + xsltInsertValueOf.aspx + + + exportDocumenttype.aspx + ASPXCodeBehind + + + importDocumenttype.aspx + ASPXCodeBehind + + + rollBack.aspx + ASPXCodeBehind + + + rollBack.aspx + + + sendToTranslation.aspx + ASPXCodeBehind + + + sendToTranslation.aspx + + + viewAuditTrail.aspx + ASPXCodeBehind + + + viewAuditTrail.aspx + + + EditMemberGroup.aspx + ASPXCodeBehind + + + EditMemberGroup.aspx + + + search.aspx + ASPXCodeBehind + + + search.aspx + + + ViewMembers.aspx + ASPXCodeBehind + + + ViewMembers.aspx + + + Code + + + + + + + + + + tinymce3tinymceCompress.aspx + ASPXCodeBehind + + + tinymce3tinymceCompress.aspx + + + QuickSearchHandler.ashx + + + DictionaryItemList.aspx + ASPXCodeBehind + + + DictionaryItemList.aspx + + + editLanguage.aspx + ASPXCodeBehind + + + editLanguage.aspx + + + + + + Code + + + + + + + + + + + + + + + + + MacroContainerService.asmx + Component + + + TagsAutoCompleteHandler.ashx + + + TreeClientService.asmx + Component + + + + + + + + True + True + Resources.resx + + + default.aspx + ASPXCodeBehind + + + default.aspx + + + details.aspx + ASPXCodeBehind + + + details.aspx + + + preview.aspx + ASPXCodeBehind + + + preview.aspx + + + xml.aspx + ASPXCodeBehind + + + xml.aspx + + + ASPXCodeBehind + + + + + + + + + + + + + + + + + + + + + + + + + + + + TreeDataService.ashx + + + + + + + XmlTree.xsd + + + + + CacheRefresher.asmx + Component + + + CheckForUpgrade.asmx + Component + + + CMSNode.asmx + Component + + + codeEditorSave.asmx + Component + + + legacyAjaxCalls.asmx + Component + + + nodeSorter.asmx + Component + + + progressStatus.asmx + Component + + + publication.asmx + Component + + + + ASPXCodeBehind + + + + uQuery.cs + + + uQuery.cs + + + uQuery.cs + + + uQuery.cs + + + uQuery.cs + + + uQuery.cs + + + uQuery.cs + + + uQuery.cs + + + uQuery.cs + + + + + + + + True + True + Reference.map + + + + + + + + + + + + Component + + + + Component + + + + + Mvc\web.config + + + + MSDiscoCodeGenerator + Reference.cs + + + + + + + + + + + + ASPXCodeBehind + + + ASPXCodeBehind + + + + ASPXCodeBehind + + + + + ASPXCodeBehind + + + ASPXCodeBehind + + + + + + ASPXCodeBehind + + + + + + + + ASPXCodeBehind + + + + + ASPXCodeBehind + + + + + + + + + Reference.map + + + Reference.map + + + SettingsSingleFileGenerator + Settings1.Designer.cs + + + + + + ASPXCodeBehind + + + + + + + + + + Form + + + Designer + + + + + Form + + + + + + + Form + + + + + + + + + + XmlTree.xsd + + + + + + MSDiscoCodeGenerator + Reference.cs + + + ResXFileCodeGenerator + Resources.Designer.cs + Designer + + + ResXFileCodeGenerator + Strings.Designer.cs + + + ResXFileCodeGenerator + Resources.Designer.cs + Designer + + + + + + + package.xsd + + + umbraco.xsd + + + umbraco.xsd + + + umbraco.xsd + + + + + + + + Dynamic + Web References\org.umbraco.our\ + https://our.umbraco.com/umbraco/webservices/api/repository.asmx + + + + + Settings + umbraco_org_umbraco_our_Repository + + + Dynamic + Web References\org.umbraco.update\ + http://update.umbraco.org/checkforupgrade.asmx + + + + + Settings + umbraco_org_umbraco_update_CheckForUpgrade + + + + + + + 11.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v11.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v12.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v14.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v15.0 + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Umbraco.Web/_Legacy/Packager/Installer.cs b/src/Umbraco.Web/_Legacy/Packager/Installer.cs index 3613fc7f87..2581e3ad48 100644 --- a/src/Umbraco.Web/_Legacy/Packager/Installer.cs +++ b/src/Umbraco.Web/_Legacy/Packager/Installer.cs @@ -11,6 +11,7 @@ using Umbraco.Core.Logging; using System.Diagnostics; using Umbraco.Core.Models; using Umbraco.Core.Composing; +using System.Net; using Umbraco.Core.Events; using Umbraco.Core.Models.Packaging; using Umbraco.Core.Services.Implement; @@ -43,6 +44,7 @@ namespace umbraco.cms.businesslogic.packager private readonly List _binaryFileErrors = new List(); private int _currentUserId = -1; + private static WebClient _webClient; public string Name { get; private set; } @@ -684,9 +686,10 @@ namespace umbraco.cms.businesslogic.packager if (Directory.Exists(IOHelper.MapPath(SystemDirectories.Packages)) == false) Directory.CreateDirectory(IOHelper.MapPath(SystemDirectories.Packages)); - var wc = new System.Net.WebClient(); + if (_webClient == null) + _webClient = new WebClient(); - wc.DownloadFile( + _webClient.DownloadFile( "http://" + PackageServer + "/fetch?package=" + Package.ToString(), IOHelper.MapPath(SystemDirectories.Packages + "/" + Package + ".umb")); diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/dashboard/FeedProxy.aspx.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/dashboard/FeedProxy.aspx.cs index 0e21605fbb..cfa60b79a4 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/dashboard/FeedProxy.aspx.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/dashboard/FeedProxy.aspx.cs @@ -1,10 +1,10 @@ -using Umbraco.Core; +using System.Net.Http; +using Umbraco.Core; using Umbraco.Core.Logging; using Umbraco.Web; using Umbraco.Web.UI.Pages; using System; using System.Linq; -using System.Net; using System.Net.Mime; using Umbraco.Core.IO; using Umbraco.Core.Xml; @@ -16,42 +16,45 @@ namespace dashboardUtilities public partial class FeedProxy : UmbracoEnsuredPage { + private static HttpClient _httpClient; + protected void Page_Load(object sender, EventArgs e) { try { - if (Request.QueryString.AllKeys.Contains("url") && Request.QueryString["url"] != null) - { - var url = Request.QueryString["url"]; - if (!string.IsNullOrWhiteSpace(url) && !url.StartsWith("/")) - { - Uri requestUri; - if (Uri.TryCreate(url, UriKind.Absolute, out requestUri)) - { - var feedProxyXml = XmlHelper.OpenAsXmlDocument(IOHelper.MapPath(SystemFiles.FeedProxyConfig)); - if (feedProxyXml != null - && feedProxyXml.SelectSingleNode(string.Concat("//allow[@host = '", requestUri.Host, "']")) != null - && requestUri.Port == 80) - { - using (var client = new WebClient()) - { - var response = client.DownloadString(requestUri); + if (Request.QueryString.AllKeys.Contains("url") == false || Request.QueryString["url"] == null) + return; - if (string.IsNullOrEmpty(response) == false) - { - Response.Clear(); - Response.ContentType = Request.CleanForXss("type") ?? MediaTypeNames.Text.Xml; - Response.Write(response); - } - } - } - else - { - Current.Logger.Debug("Access to unallowed feedproxy attempted: {RequestUrl}", requestUri); - } - } + var url = Request.QueryString["url"]; + if (string.IsNullOrWhiteSpace(url) || url.StartsWith("/")) + return; + + if (Uri.TryCreate(url, UriKind.Absolute, out var requestUri) == false) + return; + + var feedProxyXml = XmlHelper.OpenAsXmlDocument(IOHelper.MapPath(SystemFiles.FeedProxyConfig)); + if (feedProxyXml?.SelectSingleNode($"//allow[@host = '{requestUri.Host}']") != null && requestUri.Port == 80) + { + if (_httpClient == null) + _httpClient = new HttpClient(); + + using (var request = new HttpRequestMessage(HttpMethod.Get, requestUri)) + { + var response = _httpClient.SendAsync(request).Result; + var result = response.Content.ReadAsStringAsync().Result; + + if (string.IsNullOrEmpty(result)) + return; + + Response.Clear(); + Response.ContentType = Request.CleanForXss("type") ?? MediaTypeNames.Text.Xml; + Response.Write(result); } } + else + { + Current.Logger.Debug("Access to unallowed feedproxy attempted: {RequestUrl}", requestUri); + } } catch (Exception ex) {