Merge branch temp8 into temp8-di2690

This commit is contained in:
Stephan
2018-09-06 16:22:13 +02:00
262 changed files with 4905 additions and 3984 deletions
+7 -1
View File
@@ -27,4 +27,10 @@ dotnet_naming_symbols.private_fields.applicable_kinds = field
dotnet_naming_symbols.private_fields.applicable_accessibilities = private
dotnet_naming_style.prefix_underscore.capitalization = camel_case
dotnet_naming_style.prefix_underscore.required_prefix = _
dotnet_naming_style.prefix_underscore.required_prefix = _
# https://github.com/MicrosoftDocs/visualstudio-docs/blob/master/docs/ide/editorconfig-code-style-settings-reference.md
[*.cs]
csharp_style_var_for_built_in_types = true:suggestion
csharp_style_var_when_type_is_apparent = true:suggestion
csharp_style_var_elsewhere = true:suggestion
View File
View File
@@ -129,7 +129,7 @@ We like to use [Gitflow as much as possible](https://jeffkreeftmeijer.com/git-fl
The easiest way to get started is to run `build.bat` which will build both the backoffice (also known as "Belle") and the Umbraco core. You can then easily start debugging from Visual Studio, or if you need to debug Belle you can run `gulp dev` in `src\Umbraco.Web.UI.Client`. See [this page](BUILD.md) for more details.
Alternatively, you can open `src\umbraco.sln` in Visual Studio 2017 ([the community edition is free](https://www.visualstudio.com/thank-you-downloading-visual-studio/?sku=Community&rel=15) for you to use to contribute to Open Source projects). In Visual Studio, find the Task Runner Explorer (in the View menu under Other Windows) and run the build task under the gulpfile.
Alternatively, you can open `src\umbraco.sln` in Visual Studio 2017 (version 15.3 or higher, [the community edition is free](https://www.visualstudio.com/thank-you-downloading-visual-studio/?sku=Community&rel=15) for you to use to contribute to Open Source projects). In Visual Studio, find the Task Runner Explorer (in the View menu under Other Windows) and run the build task under the gulpfile.
![Gulp build in Visual Studio](img/gulpbuild.png)
@@ -156,4 +156,4 @@ git rebase upstream/dev-v7
In this command we're syncing with the `dev-v7` branch, but you can of course choose another one if needed.
(More info on how this works: [http://robots.thoughtbot.com/post/5133345960/keeping-a-git-fork-updated](http://robots.thoughtbot.com/post/5133345960/keeping-a-git-fork-updated))
(More info on how this works: [http://robots.thoughtbot.com/post/5133345960/keeping-a-git-fork-updated](http://robots.thoughtbot.com/post/5133345960/keeping-a-git-fork-updated))
+66
View File
@@ -0,0 +1,66 @@
---
name: 🐛 Bug Report
about: File a bug report, if you've discovered a problem in Umbraco.
---
A brief description of the issue goes here.
<!--
If you haven't yet done so, please read the "contributing guidelines"
thoroughly. Then, proceed by filling out the rest of the details in the issue
template below. The more details you can give us, the easier it will be for us
to determine the cause of a problem.
See: https://github.com/umbraco/Umbraco-CMS/blob/dev-v7/.github/CONTRIBUTING.md
-->
Reproduction
------------
If you're filing a bug, please describe how to reproduce it. Include as much
relevant information as possible, such as:
### Bug summary
<!--
* Write a short summary of the bug
* Try to pinpoint it as much as possible
* Try to state the _actual problem_, and not just what you _think_ the
solution might be.
-->
### Specifics
<!--
* Mention the URL where this bug occurs, if applicable
* What version of Umbraco are you using (down to the very last digit!)
* What browser and version you are using
* Please mention if you've checked it in other browsers as well
* Please include *full error messages* and *screenshots* if possible
-->
### Steps to reproduce
<!--
* Clearly mention the steps to reproduce the bug
-->
### Expected result
<!--
* What did you _expect_ that would happen on your Umbraco site?
* Describe the intended/desired outcome after you did the steps mentioned.
-->
### Actual result
<!--
* What is the actual result of the above steps?
* Describe the behaviour of the bug
* Please, please include **error messages** and screenshots. They might mean
nothing to you, but they are _very_ helpful to us.
-->
@@ -0,0 +1,31 @@
---
name: 📮 Feature Request
about: Open a feature request, if you want to propose a new feature.
---
A brief description of your feature request goes here.
<!--
If you want to discuss the feature you're imagining, please make sure to keep
those discussions on the forum at https://our.umbraco.com/ (choose the
category "Contributing to Umbraco", Umbraco HQ follows all new topics there).
Once you've come to a conclusion in the discussion, feel free to propose the
new feature here.
-->
How can you help?
-------------------------------
<!--
The resources (read: available time and effort) of Umbraco's core team are
limited.
If we can not work on your suggestion, please don't take it personally. Most
likely, it's either:
- We think your idea is valid, but we can't find the time to work on it.
- Your idea might be better suited as a package, if it's not suitable for
the majority of users.
-->
@@ -0,0 +1,9 @@
---
name: ⁉️ Support Question
about: Having trouble with Umbraco? -> https://our.umbraco.com
---
This issue tracker is NOT meant for support questions. If you have a question,
please join us on the forum at https://our.umbraco.com.
Thanks!
@@ -0,0 +1,9 @@
---
name: 📖 Documentation Issue
about: See https://github.com/umbraco/UmbracoDocs/issues for documentation issues
---
The Umbraco documentation has its own dedicated repository. Please open your
documentation-related issue at https://github.com/umbraco/UmbracoDocs/issues
Thanks!
@@ -0,0 +1,31 @@
---
name: 🔐 Security Issue
about: Discovered a Security Issue in Umbraco?
---
⚠️ PLEASE DON'T DISCLOSE SECURITY-RELATED ISSUES PUBLICLY, SEE BELOW.
If you have found a security issue in Umbraco, please send the details to
security@umbraco.com and don't disclose it publicly until we can provide a fix for
it. If you wish, we'll credit you for finding verified issues, when we release
the patched version.
❗ Please read more about how to report security issues on https://umbraco.com/security
A note on "Self XSS"
--------------------
Umbraco is a CMS, that allows users to edit content on a website. As such,
all _authenticated users_ can:
- Edit content, and (depending on the field types) insert HTML and CSS in that
content, with a variety of allowed attributes.
- Depending on the user level: Edit template files, and insert C#, HTML, CSS and
javascript in so on.
- Upload files to the site, which will become publicly available.
We see these functionalities as _features_, and not as security issues. Please
report the mentioned items only if they can be performed by non-authorized
users, or other exploitable vulnerabilities.
Thanks!
+11
View File
@@ -0,0 +1,11 @@
### Prerequisites
- [ ] I have [created an issue](https://github.com/umbraco/Umbraco-CMS/issues) for the proposed changes in this PR, the link is:
- [ ] I have added steps to test this contribution in the description below
### Description
<!-- A description of the changes proposed in the pull-request -->
<!-- Make sure to link to the related issue number so we can easily find it in the issue tracker -->
<!-- Thanks for contributing to Umbraco CMS! -->

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 26 KiB

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 27 KiB

+51 -87
View File
@@ -1,92 +1,56 @@
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata minClientVersion="3.4.4">
<id>UmbracoCms.Core</id>
<version>8.0.0</version>
<title>Umbraco Cms Core Binaries</title>
<authors>Umbraco HQ</authors>
<owners>Umbraco HQ</owners>
<licenseUrl>http://opensource.org/licenses/MIT</licenseUrl>
<projectUrl>http://umbraco.com/</projectUrl>
<iconUrl>http://umbraco.com/media/357769/100px_transparent.png</iconUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>Contains the core assemblies needed to run Umbraco Cms. This package only contains assemblies and can be used for package development. Use the UmbracoCms-package to setup Umbraco in Visual Studio as an ASP.NET project.</description>
<summary>Contains the core assemblies needed to run Umbraco Cms</summary>
<language>en-US</language>
<tags>umbraco</tags>
<dependencies>
<!--
note: dependencies are specified as [x.y.z,x.999999) eg [2.1.0,2.999999) and NOT [2.1.0,3.0.0) because
the latter would pick anything below 3.0.0 and that includes prereleases such as 3.0.0-alpha, and we do
not want this to happen as the alpha of the next major is, really, the next major already.
-->
<dependency id="AutoMapper" version="[7.0.1,7.999999)" />
<dependency id="ClientDependency" version="[1.9.6,1.999999)" />
<dependency id="ClientDependency-Mvc5" version="[1.8.0,1.999999)" />
<dependency id="CSharpTest.Net.Collections" version="[14.906.1403.1082,14.999999)" />
<dependency id="Examine" version="[1.0.0-beta025,1.999999)" />
<dependency id="HtmlAgilityPack" version="[1.7.2,1.999999)" />
<dependency id="ImageProcessor" version="[2.6.1.19,2.999999)" />
<dependency id="ImageProcessor.Web" version="[4.9.2.19,4.999999)" />
<dependency id="ImageProcessor.Web.Config" version="[2.4.1.19,2.999999)" />
<dependency id="LightInject" version="[5.1.2,5.999999)" />
<dependency id="LightInject.Annotation" version="[1.1.0,1.999999)" />
<dependency id="LightInject.Mvc" version="[2.0.0,2.999999)" />
<dependency id="LightInject.WebApi" version="[2.0.0,2.999999)" />
<dependency id="Lucene.Net.Contrib" version="[3.0.3,3.999999)" />
<dependency id="Markdown" version="[2.2.1,2.999999)" />
<dependency id="Microsoft.AspNet.Identity.Owin" version="[2.2.1,2.999999)" />
<dependency id="Microsoft.AspNet.Mvc" version="[5.2.6,5.999999)" />
<dependency id="Microsoft.AspNet.SignalR.Core" version="[2.2.3,2.999999)" />
<dependency id="Microsoft.AspNet.WebApi" version="[5.2.6,5.999999)" />
<dependency id="Microsoft.CodeAnalysis.CSharp" version="[2.8.0,2.999999)" />
<dependency id="Microsoft.CodeDom.Providers.DotNetCompilerPlatform" version="[1.0.8,1.999999)" />
<dependency id="Microsoft.Net.Compilers" version="[2.8.0,2.999999)" />
<dependency id="Microsoft.Owin.Host.SystemWeb" version="[4.0.0,4.999999)" />
<dependency id="Microsoft.Owin.Security.Cookies" version="[4.0.0,4.999999)" />
<dependency id="Microsoft.Owin.Security.OAuth" version="[4.0.0,4.999999)" />
<dependency id="Microsoft.Web.Xdt" version="[2.1.2,2.999999)" />
<dependency id="MiniProfiler" version="[3.2.0.157,3.999999)" />
<dependency id="MySql.Data" version="[6.10.7,6.999999)" />
<dependency id="Newtonsoft.Json" version="[11.0.2,11.999999)" />
<dependency id="NPoco" version="[3.9.3,3.999999)" />
<dependency id="Semver" version="[2.0.4,2.999999)" />
<dependency id="Serilog" version="[2.7.1,2.999999)" />
<dependency id="Serilog.Enrichers.Process" version="[2.0.1,2.999999)" />
<dependency id="Serilog.Enrichers.Thread" version="[3.0.0,3.999999)" />
<dependency id="Serilog.Filters.Expressions" version="[2.0.0,2.999999)" />
<dependency id="Serilog.Formatting.Compact" version="[1.0.0,1.999999)" />
<dependency id="Serilog.Settings.AppSettings" version="[2.1.2,2.999999)" />
<dependency id="Serilog.Sinks.File" version="[4.0.0,4.999999)" />
<dependency id="System.Reflection.Primitives" version="[4.3.0,4.999999)" />
<dependency id="System.Runtime.Handles" version="[4.3.0,4.999999)" />
<dependency id="System.Security.Cryptography.X509Certificates" version="[4.3.2,4.999999)" />
<dependency id="System.Threading.Tasks.Dataflow" version="[4.8.0,4.999999)" />
<dependency id="Umbraco.SqlServerCE" version="[4.0.0.1,4.999999)" />
</dependencies>
</metadata>
<files>
<file src="$BuildTmp$\WebApp\bin\Umbraco.Core.dll" target="lib\net472\Umbraco.Core.dll" />
<file src="$BuildTmp$\WebApp\bin\Umbraco.Web.dll" target="lib\net472\Umbraco.Web.dll" />
<file src="$BuildTmp$\WebApp\bin\Umbraco.Web.UI.dll" target="lib\net472\Umbraco.Web.UI.dll" />
<file src="$BuildTmp$\WebApp\bin\Umbraco.Examine.dll" target="lib\net472\Umbraco.Examine.dll" />
<metadata minClientVersion="3.4.4">
<id>UmbracoCms.Core</id>
<version>8.0.0</version>
<title>Umbraco Cms Core Binaries</title>
<authors>Umbraco HQ</authors>
<owners>Umbraco HQ</owners>
<licenseUrl>http://opensource.org/licenses/MIT</licenseUrl>
<projectUrl>http://umbraco.com/</projectUrl>
<iconUrl>http://umbraco.com/media/357769/100px_transparent.png</iconUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>Contains the core assemblies needed to run Umbraco Cms. This package only contains assemblies and can be used for package development. Use the UmbracoCms package to setup Umbraco in Visual Studio as an ASP.NET project.</description>
<summary>Contains the core assemblies needed to run Umbraco Cms</summary>
<language>en-US</language>
<tags>umbraco</tags>
<dependencies>
<!--
note: dependencies are specified as [x.y.z,x.999999) eg [2.1.0,2.999999) and NOT [2.1.0,3.0.0) because
the latter would pick anything below 3.0.0 and that includes prereleases such as 3.0.0-alpha, and we do
not want this to happen as the alpha of the next major is, really, the next major already.
-->
<dependency id="AutoMapper" version="[7.0.1,7.999999)" />
<dependency id="LightInject" version="[5.1.2,5.999999)" />
<dependency id="LightInject.Annotation" version="[1.1.0,1.999999)" />
<dependency id="LightInject.Web" version="[2.0.0,2.999999)" />
<dependency id="Microsoft.AspNet.Identity.Core" version="[2.2.2,2.999999)" />
<dependency id="Microsoft.AspNet.WebApi.Client" version="[5.2.6,5.999999)" />
<dependency id="Microsoft.Owin" version="[4.0.0,4.999999)" />
<dependency id="MiniProfiler" version="[3.2.0.157,3.999999)" />
<dependency id="MySql.Data" version="[6.10.7,6.999999)" />
<dependency id="Newtonsoft.Json" version="[11.0.2,11.999999)" />
<dependency id="Semver" version="[2.0.4,2.999999)" />
<dependency id="Serilog" version="[2.7.1,2.999999)" />
<dependency id="Serilog.Enrichers.Process" version="[2.0.1,2.999999)" />
<dependency id="Serilog.Enrichers.Thread" version="[3.0.0,3.999999)" />
<dependency id="Serilog.Filters.Expressions" version="[2.0.0,2.999999)" />
<dependency id="Serilog.Formatting.Compact" version="[1.0.0,1.999999)" />
<dependency id="Serilog.Settings.AppSettings" version="[2.1.2,2.999999)" />
<dependency id="Serilog.Sinks.File" version="[4.0.0,4.999999)" />
<dependency id="Umbraco.SqlServerCE" version="[4.0.0.1,4.999999)" />
<dependency id="NPoco" version="[3.9.4,3.999999)" />
</dependencies>
</metadata>
<files>
<!-- libs -->
<file src="$BuildTmp$\WebApp\bin\Umbraco.Core.dll" target="lib\net472\Umbraco.Core.dll" />
<!-- docs -->
<file src="$BuildTmp$\WebApp\bin\Umbraco.Core.xml" target="lib\Umbraco.Core.xml" />
<file src="$BuildTmp$\WebApp\bin\Umbraco.Web.xml" target="lib\Umbraco.Web.xml" />
<file src="$BuildTmp$\WebApp\bin\Umbraco.Web.UI.xml" target="lib\Umbraco.Web.UI.xml" />
<file src="$BuildTmp$\WebApp\bin\Umbraco.Examine.xml" target="lib\Umbraco.Examine.xml" />
<!-- docs -->
<file src="$BuildTmp$\WebApp\bin\Umbraco.Core.xml" target="lib\Umbraco.Core.xml" />
<file src="tools\install.core.ps1" target="tools\install.ps1" />
<!-- symbols -->
<file src="$BuildTmp$\bin\Umbraco.Core.pdb" target="lib" />
<file src="$BuildTmp$\..\src\Umbraco.Core\**\*.cs" exclude="$BuildTmp$\..\src\**\TemporaryGeneratedFile*.cs" target="src\Umbraco.Core" />
<file src="$BuildTmp$\bin\Umbraco.Web.pdb" target="lib" />
<file src="$BuildTmp$\..\src\Umbraco.Web\**\*.cs" exclude="$BuildTmp$\..\src\**\TemporaryGeneratedFile*.cs" target="src\Umbraco.Web" />
<file src="$BuildTmp$\bin\Umbraco.Web.UI.pdb" target="lib" />
<file src="$BuildTmp$\..\src\Umbraco.Web.UI\**\*.cs" exclude="$BuildTmp$\..\src\**\TemporaryGeneratedFile*.cs" target="src\Umbraco.Web.UI" />
<file src="$BuildTmp$\bin\Umbraco.Examine.pdb" target="lib" />
<file src="$BuildTmp$\..\src\Umbraco.Examine\**\*.cs" exclude="$BuildTmp$\..\src\**\TemporaryGeneratedFile*.cs" target="src\Umbraco.Examine" />
</files>
<!-- symbols -->
<file src="$BuildTmp$\bin\Umbraco.Core.pdb" target="lib" />
<file src="$BuildTmp$\..\src\Umbraco.Core\**\*.cs" exclude="$BuildTmp$\..\src\**\TemporaryGeneratedFile*.cs" target="src\Umbraco.Core" />
</files>
</package>
+62
View File
@@ -0,0 +1,62 @@
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata minClientVersion="3.4.4">
<id>UmbracoCms.Web</id>
<version>8.0.0</version>
<title>Umbraco Cms Core Binaries</title>
<authors>Umbraco HQ</authors>
<owners>Umbraco HQ</owners>
<licenseUrl>http://opensource.org/licenses/MIT</licenseUrl>
<projectUrl>http://umbraco.com/</projectUrl>
<iconUrl>http://umbraco.com/media/357769/100px_transparent.png</iconUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>Contains the web assemblies needed to run Umbraco Cms. This package only contains assemblies and can be used for package development. Use the UmbracoCms package to setup Umbraco in Visual Studio as an ASP.NET project.</description>
<summary>Contains the core assemblies needed to run Umbraco Cms</summary>
<language>en-US</language>
<tags>umbraco</tags>
<dependencies>
<!--
note: dependencies are specified as [x.y.z,x.999999) eg [2.1.0,2.999999) and NOT [2.1.0,3.0.0) because
the latter would pick anything below 3.0.0 and that includes prereleases such as 3.0.0-alpha, and we do
not want this to happen as the alpha of the next major is, really, the next major already.
-->
<dependency id="UmbracoCms.Core" version="[$version$]" />
<dependency id="AutoMapper" version="[7.0.1,7.999999)" />
<dependency id="ClientDependency" version="[1.9.6,1.999999)" />
<dependency id="ClientDependency-Mvc5" version="[1.8.0,1.999999)" />
<dependency id="CSharpTest.Net.Collections" version="[14.906.1403.1082,14.999999)" />
<dependency id="Examine" version="[1.0.0-beta025,1.999999)" />
<dependency id="Lucene.Net.Contrib" version="[3.0.3,3.999999)" />
<dependency id="HtmlAgilityPack" version="[1.7.2,1.999999)" />
<dependency id="ImageProcessor" version="[2.6.2.25,2.999999)" />
<dependency id="LightInject.Mvc" version="[2.0.0,2.999999)" />
<dependency id="LightInject.WebApi" version="[2.0.0,2.999999)" />
<dependency id="Markdown" version="[2.2.1,2.999999)" />
<dependency id="Microsoft.AspNet.Identity.Owin" version="[2.2.2,2.999999)" />
<dependency id="Microsoft.AspNet.Mvc" version="[5.2.6,5.999999)" />
<dependency id="Microsoft.AspNet.SignalR.Core" version="[2.2.3,2.999999)" />
<dependency id="Microsoft.AspNet.WebApi" version="[5.2.6,5.999999)" />
<dependency id="Microsoft.Owin.Host.SystemWeb" version="[4.0.0,4.999999)" />
<dependency id="Microsoft.Owin.Security.Cookies" version="[4.0.0,4.999999)" />
<dependency id="Microsoft.Owin.Security.OAuth" version="[4.0.0,4.999999)" />
<dependency id="System.Threading.Tasks.Dataflow" version="[4.8.0,4.999999)" />
</dependencies>
</metadata>
<files>
<!-- libs -->
<file src="$BuildTmp$\WebApp\bin\Umbraco.Web.dll" target="lib\net472\Umbraco.Web.dll" />
<file src="$BuildTmp$\WebApp\bin\Umbraco.Web.UI.dll" target="lib\net472\Umbraco.Web.UI.dll" />
<file src="$BuildTmp$\WebApp\bin\Umbraco.Examine.dll" target="lib\net472\Umbraco.Examine.dll" />
<!-- docs -->
<file src="$BuildTmp$\WebApp\bin\Umbraco.Web.xml" target="lib\Umbraco.Web.xml" />
<file src="$BuildTmp$\WebApp\bin\Umbraco.Web.UI.xml" target="lib\Umbraco.Web.UI.xml" />
<file src="$BuildTmp$\WebApp\bin\Umbraco.Examine.xml" target="lib\Umbraco.Examine.xml" />
<!-- symbols -->
<file src="$BuildTmp$\bin\Umbraco.Web.pdb" target="lib" />
<file src="$BuildTmp$\..\src\Umbraco.Web\**\*.cs" exclude="$BuildTmp$\..\src\**\TemporaryGeneratedFile*.cs" target="src\Umbraco.Web" />
<file src="$BuildTmp$\bin\Umbraco.Examine.pdb" target="lib" />
<file src="$BuildTmp$\..\src\Umbraco.Examine\**\*.cs" exclude="$BuildTmp$\..\src\**\TemporaryGeneratedFile*.cs" target="src\Umbraco.Examine" />
</files>
</package>
+60 -52
View File
@@ -1,58 +1,66 @@
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata minClientVersion="3.4.4">
<id>UmbracoCms</id>
<version>8.0.0</version>
<title>Umbraco Cms</title>
<authors>Umbraco HQ</authors>
<owners>Umbraco HQ</owners>
<licenseUrl>http://opensource.org/licenses/MIT</licenseUrl>
<projectUrl>http://umbraco.com/</projectUrl>
<iconUrl>http://umbraco.com/media/357769/100px_transparent.png</iconUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>Installs Umbraco Cms in your Visual Studio ASP.NET project</description>
<summary>Installs Umbraco Cms in your Visual Studio ASP.NET project</summary>
<language>en-US</language>
<tags>umbraco</tags>
<dependencies>
<dependency id="UmbracoCms.Core" version="[$version$]" />
<!--
note: dependencies are specified as [x.y.z,x.999999) eg [2.1.0,2.999999) and NOT [2.1.0,3.0.0) because
the latter would pick anything below 3.0.0 and that includes prereleases such as 3.0.0-alpha, and we do
not want this to happen as the alpha of the next major is, really, the next major already.
-->
<dependency id="Microsoft.AspNet.SignalR.Core" version="[2.2.3, 2.999999)" />
<dependency id="Umbraco.ModelsBuilder.Ui" version="[8.0.0-alpha.22]" />
</dependencies>
</metadata>
<files>
<file src="$BuildTmp$\Configs\**" target="Content\Config" exclude="$BuildTmp$\Configs\Web.config.transform" />
<file src="$BuildTmp$\WebApp\Views\**" target="Content\Views" exclude="$BuildTmp$\WebApp\Views\Web.config" />
<file src="$BuildTmp$\WebApp\default.aspx" target="Content\default.aspx" />
<file src="$BuildTmp$\WebApp\Global.asax" target="Content\Global.asax" />
<file src="$BuildTmp$\WebApp\Web.config" target="UmbracoFiles\Web.config" />
<file src="$BuildTmp$\WebApp\App_Browsers\**" target="UmbracoFiles\App_Browsers" />
<file src="$BuildTmp$\WebApp\config\splashes\**" target="UmbracoFiles\Config\splashes" />
<file src="$BuildTmp$\WebApp\config\BackOfficeTours\**" target="Content\Config\BackOfficeTours" />
<file src="$BuildTmp$\WebApp\umbraco\**" target="UmbracoFiles\umbraco" />
<file src="$BuildTmp$\WebApp\Media\Web.config" target="Content\Media\Web.config" />
<metadata minClientVersion="3.4.4">
<id>UmbracoCms</id>
<version>8.0.0</version>
<title>Umbraco Cms</title>
<authors>Umbraco HQ</authors>
<owners>Umbraco HQ</owners>
<licenseUrl>http://opensource.org/licenses/MIT</licenseUrl>
<projectUrl>http://umbraco.com/</projectUrl>
<iconUrl>http://umbraco.com/media/357769/100px_transparent.png</iconUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>Installs Umbraco Cms in your Visual Studio ASP.NET project</description>
<summary>Installs Umbraco Cms in your Visual Studio ASP.NET project</summary>
<language>en-US</language>
<tags>umbraco</tags>
<dependencies>
<dependency id="UmbracoCms.Web" version="[$version$]" />
<!--
note: dependencies are specified as [x.y.z,x.999999) eg [2.1.0,2.999999) and NOT [2.1.0,3.0.0) because
the latter would pick anything below 3.0.0 and that includes prereleases such as 3.0.0-alpha, and we do
not want this to happen as the alpha of the next major is, really, the next major already.
-->
<dependency id="Microsoft.AspNet.SignalR.Core" version="[2.2.3, 2.999999)" />
<dependency id="Umbraco.ModelsBuilder.Ui" version="[8.0.0-alpha.22]" />
<dependency id="ImageProcessor.Web" version="[4.9.3.25,4.999999)" />
<dependency id="ImageProcessor.Web.Config" version="[2.4.1.19,2.999999)" />
<dependency id="Microsoft.CodeDom.Providers.DotNetCompilerPlatform" version="[2.0.0,2.999999)" />
<dependency id="Microsoft.Net.Compilers" version="[2.9.0,2.999999)" />
</dependencies>
</metadata>
<files>
<!-- files -->
<file src="$BuildTmp$\Configs\**" target="Content\Config" exclude="$BuildTmp$\Configs\Web.config.transform" />
<file src="$BuildTmp$\WebApp\Views\**" target="Content\Views" exclude="$BuildTmp$\WebApp\Views\Web.config" />
<file src="$BuildTmp$\WebApp\default.aspx" target="Content\default.aspx" />
<file src="$BuildTmp$\WebApp\Global.asax" target="Content\Global.asax" />
<file src="$BuildTmp$\WebApp\config\BackOfficeTours\**" target="Content\Config\BackOfficeTours" />
<file src="$BuildTmp$\WebApp\Media\Web.config" target="Content\Media\Web.config" />
<file src="$BuildTmp$\WebApp\App_Plugins\ModelsBuilder\modelsbuilder.htm" target="Content\App_Plugins\ModelsBuilder\modelsbuilder.htm" />
<file src="$BuildTmp$\WebApp\App_Plugins\ModelsBuilder\modelsbuilder.controller.js" target="Content\App_Plugins\ModelsBuilder\modelsbuilder.controller.js" />
<file src="$BuildTmp$\WebApp\App_Plugins\ModelsBuilder\modelsbuilder.resource.js" target="Content\App_Plugins\ModelsBuilder\modelsbuilder.resource.js" />
<file src="$BuildTmp$\WebApp\App_Plugins\ModelsBuilder\package.manifest" target="Content\App_Plugins\ModelsBuilder\package.manifest" />
<!-- these files are copied by install.ps1 -->
<file src="$BuildTmp$\WebApp\Web.config" target="UmbracoFiles\Web.config" />
<file src="$BuildTmp$\WebApp\App_Browsers\**" target="UmbracoFiles\App_Browsers" />
<file src="$BuildTmp$\WebApp\umbraco\**" target="UmbracoFiles\umbraco" />
<file src="$BuildTmp$\WebApp\config\splashes\**" target="UmbracoFiles\Config\splashes" />
<file src="tools\install.ps1" target="tools\install.ps1" />
<file src="tools\Readme.txt" target="tools\Readme.txt" />
<file src="tools\ReadmeUpgrade.txt" target="tools\ReadmeUpgrade.txt" />
<file src="tools\Web.config.install.xdt" target="Content\Web.config.install.xdt" />
<file src="tools\applications.config.install.xdt" target="Content\config\applications.config.install.xdt" />
<file src="tools\ClientDependency.config.install.xdt" target="Content\config\ClientDependency.config.install.xdt" />
<file src="tools\Dashboard.config.install.xdt" target="Content\config\Dashboard.config.install.xdt" />
<file src="tools\trees.config.install.xdt" target="Content\config\trees.config.install.xdt" />
<file src="tools\umbracoSettings.config.install.xdt" target="Content\config\umbracoSettings.config.install.xdt" />
<file src="tools\Views.Web.config.install.xdt" target="Views\Web.config.install.xdt" />
<!-- tools -->
<!-- beware! install.ps1 not supported by PackageReference -->
<file src="tools\install.ps1" target="tools\install.ps1" />
<file src="tools\Readme.txt" target="tools\Readme.txt" />
<file src="tools\ReadmeUpgrade.txt" target="tools\ReadmeUpgrade.txt" />
<file src="build\**" target="build" />
</files>
<!-- config transforms -->
<!-- beware! config transforms not supported by PackageReference -->
<file src="tools\Web.config.install.xdt" target="Content\Web.config.install.xdt" />
<file src="tools\applications.config.install.xdt" target="Content\config\applications.config.install.xdt" />
<file src="tools\ClientDependency.config.install.xdt" target="Content\config\ClientDependency.config.install.xdt" />
<file src="tools\Dashboard.config.install.xdt" target="Content\config\Dashboard.config.install.xdt" />
<file src="tools\trees.config.install.xdt" target="Content\config\trees.config.install.xdt" />
<file src="tools\umbracoSettings.config.install.xdt" target="Content\config\umbracoSettings.config.install.xdt" />
<file src="tools\Views.Web.config.install.xdt" target="Views\Web.config.install.xdt" /> <!-- FIXME Content\ !! and then... transform?! -->
<!-- UmbracoCms props and targets -->
<file src="build\**" target="build" />
</files>
</package>
-3
View File
@@ -47,9 +47,6 @@
<CustomFilesToInclude Include=".\umbraco\**\*">
<Dir>umbraco</Dir>
</CustomFilesToInclude>
<CustomFilesToInclude Include=".\umbraco_client\**\*">
<Dir>umbraco_client</Dir>
</CustomFilesToInclude>
<CustomFilesToInclude Include=".\Global.asax">
<Dir>.</Dir>
</CustomFilesToInclude>
+10 -10
View File
@@ -1,26 +1,26 @@
_ _ __ __ ____ _____ _____ ____
| | | | \/ | _ \| __ \ /\ / ____/ __ \
_ _ __ __ ____ _____ _____ ____
| | | | \/ | _ \| __ \ /\ / ____/ __ \
| | | | \ / | |_) | |__) | / \ | | | | | |
| | | | |\/| | _ <| _ / / /\ \| | | | | |
| |__| | | | | |_) | | \ \ / ____ | |___| |__| |
\____/|_| |_|____/|_| \_/_/ \_\_____\____/
\____/|_| |_|____/|_| \_/_/ \_\_____\____/
----------------------------------------------------
Don't forget to build!
When upgrading your website using NuGet you should answer "No" to the questions to overwrite the Web.config
file (and config files in the config folder).
When upgrading your website using NuGet you should answer "No" to the questions to overwrite the Web.config
file (and config files in the config folder).
This NuGet package includes build targets that extend the creation of a deploy package, which is generated by
This NuGet package includes build targets that extend the creation of a deploy package, which is generated by
Publishing from Visual Studio. The targets will only work once Publishing is configured, so if you don't use
Publish this won't affect you.
The following items will now be automatically included when creating a deploy package or publishing to the file
system: umbraco, umbraco_client, config\splashes and global.asax.
The following items will now be automatically included when creating a deploy package or publishing to the file
system: umbraco, config\splashes and global.asax.
Please read the release notes on our.umbraco.com:
http://our.umbraco.com/contribute/releases
- Umbraco
- Umbraco
+11 -20
View File
@@ -1,39 +1,30 @@
_ _ __ __ ____ _____ _____ ____
| | | | \/ | _ \| __ \ /\ / ____/ __ \
_ _ __ __ ____ _____ _____ ____
| | | | \/ | _ \| __ \ /\ / ____/ __ \
| | | | \ / | |_) | |__) | / \ | | | | | |
| | | | |\/| | _ <| _ / / /\ \| | | | | |
| |__| | | | | |_) | | \ \ / ____ | |___| |__| |
\____/|_| |_|____/|_| \_/_/ \_\_____\____/
\____/|_| |_|____/|_| \_/_/ \_\_____\____/
----------------------------------------------------
*** IMPORTANT NOTICE FOR UPGRADES FROM VERSIONS BELOW 7.7.0 ***
Be sure to read the version specific upgrade information before proceeding:
https://our.umbraco.com/documentation/Getting-Started/Setup/Upgrading/version-specific#version-7-7-0
Depending on the version you are upgrading from, you may need to make some changes to your web.config
and you will need to be aware of the breaking changes listed there to see if these affect your installation.
Don't forget to build!
We've done our best to transform your configuration files but in case something is not quite right: remember we
backed up your files in App_Data\NuGetBackup so you can find the original files before they were transformed.
We've overwritten all the files in the Umbraco and Umbraco_Client folder, these have been backed up in
App_Data\NuGetBackup. We didn't overwrite the UI.xml file nor did we remove any files or folders that you or
a package might have added. Only the existing files were overwritten. If you customized anything then make
We've overwritten all the files in the Umbraco folder, these have been backed up in
App_Data\NuGetBackup. We didn't overwrite the UI.xml file nor did we remove any files or folders that you or
a package might have added. Only the existing files were overwritten. If you customized anything then make
sure to do a compare and merge with the NuGetBackup folder.
This NuGet package includes build targets that extend the creation of a deploy package, which is generated by
This NuGet package includes build targets that extend the creation of a deploy package, which is generated by
Publishing from Visual Studio. The targets will only work once Publishing is configured, so if you don't use
Publish this won't affect you.
The following items will now be automatically included when creating a deploy package or publishing to the file
system: umbraco, umbraco_client, config\splashes and global.asax.
The following items will now be automatically included when creating a deploy package or publishing to the file
system: umbraco, config\splashes and global.asax.
Please read the release notes on our.umbraco.com:
http://our.umbraco.com/contribute/releases
- Umbraco
- Umbraco
@@ -150,10 +150,6 @@
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly xdt:Transform="Insert">
<assemblyIdentity name="log4net" publicKeyToken="669e0ddf0bb1aa2a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.0.8.0" newVersion="2.0.8.0" />
</dependentAssembly>
<dependentAssembly xdt:Transform="Insert">
<assemblyIdentity name="Microsoft.Owin" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.0.0" newVersion="4.0.0.0" />
+2 -18
View File
@@ -44,14 +44,6 @@ if ($project) {
robocopy $umbracoFolder $umbracoBackupPath /e /LOG:$copyLogsPath\UmbracoBackup.log
robocopy $umbracoFolderSource $umbracoFolder /is /it /e /xf UI.xml /LOG:$copyLogsPath\UmbracoCopy.log
$umbracoClientFolder = Join-Path $projectPath "Umbraco_Client"
New-Item -ItemType Directory -Force -Path $umbracoClientFolder
$umbracoClientFolderSource = Join-Path $installPath "UmbracoFiles\Umbraco_Client"
$umbracoClientBackupPath = Join-Path $backupPath "Umbraco_Client"
New-Item -ItemType Directory -Force -Path $umbracoClientBackupPath
robocopy $umbracoClientFolder $umbracoClientBackupPath /e /LOG:$copyLogsPath\UmbracoClientBackup.log
robocopy $umbracoClientFolderSource $umbracoClientFolder /is /it /e /LOG:$copyLogsPath\UmbracoClientCopy.log
$copyWebconfig = $true
$destinationWebConfig = Join-Path $projectPath "Web.config"
@@ -85,15 +77,7 @@ if ($project) {
$splashesDestination = Join-Path $projectPath "Config\splashes\"
New-Item $splashesDestination -Type directory
Copy-Item $splashesSource $splashesDestination -Force
$sqlCe64Source = Join-Path $installPath "UmbracoFiles\bin\amd64\*"
$sqlCe64Destination = Join-Path $projectPath "bin\amd64\"
Copy-Item $sqlCe64Source $sqlCe64Destination -Force
$sqlCex86Source = Join-Path $installPath "UmbracoFiles\bin\x86\*"
$sqlCex86Destination = Join-Path $projectPath "bin\x86\"
Copy-Item $sqlCex86source $sqlCex86Destination -Force
$umbracoUIXMLSource = Join-Path $installPath "UmbracoFiles\Umbraco\Config\Create\UI.xml"
$umbracoUIXMLDestination = Join-Path $projectPath "Umbraco\Config\Create\UI.xml"
Copy-Item $umbracoUIXMLSource $umbracoUIXMLDestination -Force
@@ -159,4 +143,4 @@ if ($project) {
{
$DTE.ItemOperations.OpenFile($toolsPath + '\ReadmeUpgrade.txt')
}
}
}
+16 -5
View File
@@ -69,6 +69,9 @@
$global:node_nodepath = $this.ClearEnvVar("NODEPATH")
$global:node_npmcache = $this.ClearEnvVar("NPM_CONFIG_CACHE")
$global:node_npmprefix = $this.ClearEnvVar("NPM_CONFIG_PREFIX")
# https://github.com/gruntjs/grunt-contrib-connect/issues/235
$this.SetEnvVar("NODE_NO_HTTP2", "1")
})
$ubuild.DefineMethod("RestoreNode",
@@ -78,6 +81,8 @@
$this.SetEnvVar("NODEPATH", $node_nodepath)
$this.SetEnvVar("NPM_CONFIG_CACHE", $node_npmcache)
$this.SetEnvVar("NPM_CONFIG_PREFIX", $node_npmprefix)
$ignore = $this.ClearEnvVar("NODE_NO_HTTP2")
})
$ubuild.DefineMethod("CompileBelle",
@@ -124,7 +129,7 @@
Write-Output "### install gulp-cli" >> $log 2>&1
&npm install -g gulp-cli --quiet >> $log 2>&1
if (-not $?) { throw "Failed to install gulp-cli" } # that one is expected to work
$error.Clear() # that one fails 'cos some files not being removed - ignore
Write-Output "### gulp build for version $($this.Version.Release)" >> $log 2>&1
&gulp build --buildversion=$this.Version.Release >> $log 2>&1
@@ -399,9 +404,15 @@
-Symbols -Verbosity detailed -outputDirectory "$($this.BuildOutput)" > "$($this.BuildTemp)\nupack.cmscore.log"
if (-not $?) { throw "Failed to pack NuGet UmbracoCms.Core." }
&$this.BuildEnv.NuGet Pack "$nuspecs\UmbracoCms.Web.nuspec" `
-Properties BuildTmp="$($this.BuildTemp)" `
-Version "$($this.Version.Semver.ToString())" `
-Symbols -Verbosity detailed -outputDirectory "$($this.BuildOutput)" > "$($this.BuildTemp)\nupack.cmsweb.log"
if (-not $?) { throw "Failed to pack NuGet UmbracoCms.Web." }
&$this.BuildEnv.NuGet Pack "$nuspecs\UmbracoCms.nuspec" `
-Properties BuildTmp="$($this.BuildTemp)" `
-Version $this.Version.Semver.ToString() `
-Version "$($this.Version.Semver.ToString())" `
-Verbosity detailed -outputDirectory "$($this.BuildOutput)" > "$($this.BuildTemp)\nupack.cms.log"
if (-not $?) { throw "Failed to pack NuGet UmbracoCms." }
@@ -417,7 +428,7 @@
$ubuild.DefineMethod("VerifyNuGet",
{
$this.VerifyNuGetConsistency(
("UmbracoCms", "UmbracoCms.Core"),
("UmbracoCms", "UmbracoCms.Core", "UmbracoCms.Web"),
("Umbraco.Core", "Umbraco.Web", "Umbraco.Web.UI", "Umbraco.Examine"))
if ($this.OnError()) { return }
})
@@ -427,7 +438,7 @@
Write-Host "Prepare Azure Gallery"
$this.CopyFile("$($this.SolutionRoot)\build\Azure\azuregalleryrelease.ps1", $this.BuildOutput)
})
$ubuild.DefineMethod("Build",
{
$error.Clear()
@@ -457,6 +468,7 @@
if ($this.OnError()) { return }
$this.PrepareAzureGallery()
if ($this.OnError()) { return }
Write-Host "Done"
})
# ################################################################
@@ -472,5 +484,4 @@
$ubuild.Build()
if ($ubuild.OnError()) { return }
}
Write-Host "Done"
if ($get) { return $ubuild }
-11
View File
@@ -1,11 +0,0 @@
### Prerequisites
- [ ] I have written a descriptive pull-request title
- [ ] I have linked this PR to an issue on the tracker at http://issues.umbraco.org
### Description
<!-- A description of the changes proposed in the pull-request -->
<!-- Thanks for contributing to Umbraco CMS! -->
+1 -1
View File
@@ -19,4 +19,4 @@ using System.Resources;
// these are FYI and changed automatically
[assembly: AssemblyFileVersion("8.0.0")]
[assembly: AssemblyInformationalVersion("8.0.0-alpha.49")]
[assembly: AssemblyInformationalVersion("8.0.0-alpha.50")]
@@ -3,7 +3,6 @@ using System.Linq;
using System.Text;
using System.Threading;
using System.Web;
using Umbraco.Core.Components;
using Umbraco.Core.Events;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Membership;
@@ -11,7 +10,7 @@ using Umbraco.Core.Security;
using Umbraco.Core.Services;
using Umbraco.Core.Services.Implement;
namespace Umbraco.Core.Auditing
namespace Umbraco.Core.Components
{
public sealed class AuditEventsComponent : UmbracoComponentBase, IUmbracoCoreComponent
{
@@ -53,18 +52,6 @@ namespace Umbraco.Core.Auditing
_userService = userService;
_entityService = entityService;
//BackOfficeUserManager.AccountLocked += ;
//BackOfficeUserManager.AccountUnlocked += ;
BackOfficeUserManager.ForgotPasswordRequested += OnForgotPasswordRequest;
BackOfficeUserManager.ForgotPasswordChangedSuccess += OnForgotPasswordChange;
BackOfficeUserManager.LoginFailed += OnLoginFailed;
//BackOfficeUserManager.LoginRequiresVerification += ;
BackOfficeUserManager.LoginSuccess += OnLoginSuccess;
BackOfficeUserManager.LogoutSuccess += OnLogoutSuccess;
BackOfficeUserManager.PasswordChanged += OnPasswordChanged;
BackOfficeUserManager.PasswordReset += OnPasswordReset;
//BackOfficeUserManager.ResetAccessFailedCount += ;
UserService.SavedUserGroup += OnSavedUserGroupWithUsers;
UserService.SavedUser += OnSavedUser;
@@ -255,64 +242,6 @@ namespace Umbraco.Core.Auditing
"umbraco/user/delete", "delete user");
}
private void OnLoginSuccess(object sender, EventArgs args)
{
if (args is IdentityAuditEventArgs identityArgs)
{
var performingUser = GetPerformingUser(identityArgs.PerformingUser);
WriteAudit(performingUser, identityArgs.AffectedUser, identityArgs.IpAddress, "umbraco/user/sign-in/login", "login success");
}
}
private void OnLogoutSuccess(object sender, EventArgs args)
{
if (args is IdentityAuditEventArgs identityArgs)
{
var performingUser = GetPerformingUser(identityArgs.PerformingUser);
WriteAudit(performingUser, identityArgs.AffectedUser, identityArgs.IpAddress, "umbraco/user/sign-in/logout", "logout success");
}
}
private void OnPasswordReset(object sender, EventArgs args)
{
if (args is IdentityAuditEventArgs identityArgs && identityArgs.PerformingUser >= 0)
{
WriteAudit(identityArgs.PerformingUser, identityArgs.AffectedUser, identityArgs.IpAddress, "umbraco/user/password/reset", "password reset");
}
}
private void OnPasswordChanged(object sender, EventArgs args)
{
if (args is IdentityAuditEventArgs identityArgs && identityArgs.PerformingUser >= 0)
{
WriteAudit(identityArgs.PerformingUser, identityArgs.AffectedUser, identityArgs.IpAddress, "umbraco/user/password/change", "password change");
}
}
private void OnLoginFailed(object sender, EventArgs args)
{
if (args is IdentityAuditEventArgs identityArgs && identityArgs.PerformingUser >= 0)
{
WriteAudit(identityArgs.PerformingUser, 0, identityArgs.IpAddress, "umbraco/user/sign-in/failed", "login failed", affectedDetails: "");
}
}
private void OnForgotPasswordChange(object sender, EventArgs args)
{
if (args is IdentityAuditEventArgs identityArgs && identityArgs.PerformingUser >= 0)
{
WriteAudit(identityArgs.PerformingUser, identityArgs.AffectedUser, identityArgs.IpAddress, "umbraco/user/password/forgot/change", "password forgot/change");
}
}
private void OnForgotPasswordRequest(object sender, EventArgs args)
{
if (args is IdentityAuditEventArgs identityArgs && identityArgs.PerformingUser >= 0)
{
WriteAudit(identityArgs.PerformingUser, identityArgs.AffectedUser, identityArgs.IpAddress, "umbraco/user/password/forgot/request", "password forgot/request");
}
}
private void WriteAudit(int performingId, int affectedId, string ipAddress, string eventType, string eventDetails, string affectedDetails = null)
{
var performingUser = _userService.GetUserById(performingId);
@@ -1,11 +1,9 @@
using System.IO;
using Umbraco.Core.Components;
using Umbraco.Core.Composing;
using Umbraco.Core.IO;
using Umbraco.Core.Logging;
using Umbraco.Core.Manifest;
namespace Umbraco.Core.Strategies
namespace Umbraco.Core.Components
{
[RuntimeLevel(MinLevel = RuntimeLevel.Run)]
public class ManifestWatcherComponent : UmbracoComponentBase, IUmbracoCoreComponent
@@ -1,11 +1,9 @@
using System;
using Umbraco.Core.Components;
using Umbraco.Core.Composing;
using Umbraco.Core.Composing;
using Umbraco.Core.Models;
using Umbraco.Core.Services;
using Umbraco.Core.Services.Implement;
namespace Umbraco.Core.Strategies
namespace Umbraco.Core.Components
{
//TODO: This should just exist in the content service/repo!
[RuntimeLevel(MinLevel = RuntimeLevel.Run)]
@@ -1,13 +1,11 @@
using System;
using System.Linq;
using Umbraco.Core.Components;
using System.Linq;
using Umbraco.Core.Composing;
using Umbraco.Core.Events;
using Umbraco.Core.Models;
using Umbraco.Core.Services;
using Umbraco.Core.Services.Implement;
namespace Umbraco.Core.Strategies
namespace Umbraco.Core.Components
{
[RuntimeLevel(MinLevel = RuntimeLevel.Run)]
public sealed class RelateOnTrashComponent : UmbracoComponentBase, IUmbracoCoreComponent
@@ -1,9 +1,24 @@
using System.Linq;
using System;
using System.Linq;
namespace Umbraco.Core.Configuration.UmbracoSettings
{
public static class ContentSectionExtensions
{
/// <summary>
/// Gets a value indicating whether the file extension corresponds to an image.
/// </summary>
/// <param name="extension">The file extension.</param>
/// <param name="contentConfig"></param>
/// <returns>A value indicating whether the file extension corresponds to an image.</returns>
public static bool IsImageFile(this IContentSection contentConfig, string extension)
{
if (contentConfig == null) throw new ArgumentNullException(nameof(contentConfig));
if (extension == null) return false;
extension = extension.TrimStart('.');
return contentConfig.ImageFileTypes.InvariantContains(extension);
}
/// <summary>
/// Determines if file extension is allowed for upload based on (optional) white list and black list
/// held in settings.
@@ -15,5 +30,17 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
(contentSection.AllowedUploadFiles.Any() == false &&
contentSection.DisallowedUploadFiles.Any(x => x.InvariantEquals(extension)) == false);
}
/// <summary>
/// Gets the auto-fill configuration for a specified property alias.
/// </summary>
/// <param name="contentSection"></param>
/// <param name="propertyTypeAlias">The property type alias.</param>
/// <returns>The auto-fill configuration for the specified property alias, or null.</returns>
public static IImagingAutoFillUploadField GetConfig(this IContentSection contentSection, string propertyTypeAlias)
{
var autoFillConfigs = contentSection.ImageAutoFillProperties;
return autoFillConfigs?.FirstOrDefault(x => x.Alias == propertyTypeAlias);
}
}
}
@@ -8,6 +8,8 @@
bool DisableAlternativeTemplates { get; }
bool ValidateAlternativeTemplates { get; }
bool DisableFindContentByIdPath { get; }
bool DisableRedirectUrlTracking { get; }
@@ -16,5 +18,4 @@
string UmbracoApplicationUrl { get; }
}
}
@@ -5,44 +5,27 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
internal class WebRoutingElement : ConfigurationElement, IWebRoutingSection
{
[ConfigurationProperty("trySkipIisCustomErrors", DefaultValue = "false")]
public bool TrySkipIisCustomErrors
{
get { return (bool) base["trySkipIisCustomErrors"]; }
}
public bool TrySkipIisCustomErrors => (bool) base["trySkipIisCustomErrors"];
[ConfigurationProperty("internalRedirectPreservesTemplate", DefaultValue = "false")]
public bool InternalRedirectPreservesTemplate
{
get { return (bool) base["internalRedirectPreservesTemplate"]; }
}
public bool InternalRedirectPreservesTemplate => (bool) base["internalRedirectPreservesTemplate"];
[ConfigurationProperty("disableAlternativeTemplates", DefaultValue = "false")]
public bool DisableAlternativeTemplates
{
get { return (bool) base["disableAlternativeTemplates"]; }
}
public bool DisableAlternativeTemplates => (bool) base["disableAlternativeTemplates"];
[ConfigurationProperty("validateAlternativeTemplates", DefaultValue = "false")]
public bool ValidateAlternativeTemplates => (bool) base["validateAlternativeTemplates"];
[ConfigurationProperty("disableFindContentByIdPath", DefaultValue = "false")]
public bool DisableFindContentByIdPath
{
get { return (bool) base["disableFindContentByIdPath"]; }
}
public bool DisableFindContentByIdPath => (bool) base["disableFindContentByIdPath"];
[ConfigurationProperty("disableRedirectUrlTracking", DefaultValue = "false")]
public bool DisableRedirectUrlTracking
{
get { return (bool) base["disableRedirectUrlTracking"]; }
}
public bool DisableRedirectUrlTracking => (bool) base["disableRedirectUrlTracking"];
[ConfigurationProperty("urlProviderMode", DefaultValue = "AutoLegacy")]
public string UrlProviderMode
{
get { return (string) base["urlProviderMode"]; }
}
public string UrlProviderMode => (string) base["urlProviderMode"];
[ConfigurationProperty("umbracoApplicationUrl", DefaultValue = null)]
public string UmbracoApplicationUrl
{
get { return (string)base["umbracoApplicationUrl"]; }
}
public string UmbracoApplicationUrl => (string)base["umbracoApplicationUrl"];
}
}
@@ -22,7 +22,7 @@ namespace Umbraco.Core.Configuration
/// <summary>
/// Gets the version comment of the executing code (eg "beta").
/// </summary>
public static string CurrentComment => "alpha.49";
public static string CurrentComment => "alpha.50";
/// <summary>
/// Gets the assembly version of Umbraco.Code.dll.
@@ -7,12 +7,13 @@ using System.Web;
using System.Xml.Linq;
using Umbraco.Core.Composing;
using Umbraco.Core.IO;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Entities;
using Umbraco.Core.Models.Membership;
using Umbraco.Core.Services;
using Umbraco.Core.Services.Implement;
namespace Umbraco.Core.Models
namespace Umbraco.Core
{
public static class ContentExtensions
{
@@ -241,30 +242,6 @@ namespace Umbraco.Core.Models
#region SetValue for setting file contents
/// <summary>
/// Sets the posted file value of a property.
/// </summary>
public static void SetValue(this IContentBase content, string propertyTypeAlias, HttpPostedFileBase value, string culture = null, string segment = null)
{
// ensure we get the filename without the path in IE in intranet mode
// http://stackoverflow.com/questions/382464/httppostedfile-filename-different-from-ie
var filename = value.FileName;
var pos = filename.LastIndexOf(@"\", StringComparison.InvariantCulture);
if (pos > 0)
filename = filename.Substring(pos + 1);
// strip any directory info
pos = filename.LastIndexOf(IOHelper.DirSepChar);
if (pos > 0)
filename = filename.Substring(pos + 1);
// get a safe & clean filename
filename = IOHelper.SafeFileName(filename);
if (string.IsNullOrWhiteSpace(filename)) return;
filename = filename.ToLower(); // fixme - er... why?
MediaFileSystem.SetUploadFile(content, propertyTypeAlias, filename, value.InputStream, culture, segment);
}
/// <summary>
/// Sets the posted file value of a property.
@@ -281,7 +258,31 @@ namespace Umbraco.Core.Models
if (string.IsNullOrWhiteSpace(filename)) return;
filename = filename.ToLower(); // fixme - er... why?
MediaFileSystem.SetUploadFile(content, propertyTypeAlias, filename, filestream, culture, segment);
SetUploadFile(content, propertyTypeAlias, filename, filestream, culture, segment);
}
private static void SetUploadFile(this IContentBase content, string propertyTypeAlias, string filename, Stream filestream, string culture = null, string segment = null)
{
var property = GetProperty(content, propertyTypeAlias);
var oldpath = property.GetValue(culture, segment) is string svalue ? MediaFileSystem.GetRelativePath(svalue) : null;
var filepath = MediaFileSystem.StoreFile(content, property.PropertyType, filename, filestream, oldpath);
property.SetValue(MediaFileSystem.GetUrl(filepath), culture, segment);
}
// gets or creates a property for a content item.
private static Property GetProperty(IContentBase content, string propertyTypeAlias)
{
var property = content.Properties.FirstOrDefault(x => x.Alias.InvariantEquals(propertyTypeAlias));
if (property != null) return property;
var propertyType = content.GetContentType().CompositionPropertyTypes
.FirstOrDefault(x => x.Alias.InvariantEquals(propertyTypeAlias));
if (propertyType == null)
throw new Exception("No property type exists with alias " + propertyTypeAlias + ".");
property = new Property(propertyType);
content.Properties.Add(property);
return property;
}
/// <summary>
+3 -113
View File
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
@@ -8,7 +7,6 @@ using Umbraco.Core.Configuration.UmbracoSettings;
using Umbraco.Core.Exceptions;
using Umbraco.Core.Logging;
using Umbraco.Core.Media;
using Umbraco.Core.Media.Exif;
using Umbraco.Core.Models;
namespace Umbraco.Core.IO
@@ -26,8 +24,6 @@ namespace Umbraco.Core.IO
Logger = logger;
MediaPathScheme = mediaPathScheme;
MediaPathScheme.Initialize(this);
UploadAutoFillProperties = new UploadAutoFillProperties(this, Logger, ContentConfig);
}
private IMediaPathScheme MediaPathScheme { get; }
@@ -35,9 +31,7 @@ namespace Umbraco.Core.IO
private IContentSection ContentConfig { get; }
private ILogger Logger { get; }
internal UploadAutoFillProperties UploadAutoFillProperties { get; }
/// <summary>
/// Deletes all files passed in.
/// </summary>
@@ -204,113 +198,9 @@ namespace Umbraco.Core.IO
return filepath;
}
// gets or creates a property for a content item.
private static Property GetProperty(IContentBase content, string propertyTypeAlias)
{
var property = content.Properties.FirstOrDefault(x => x.Alias.InvariantEquals(propertyTypeAlias));
if (property != null) return property;
var propertyType = content.GetContentType().CompositionPropertyTypes
.FirstOrDefault(x => x.Alias.InvariantEquals(propertyTypeAlias));
if (propertyType == null)
throw new Exception("No property type exists with alias " + propertyTypeAlias + ".");
property = new Property(propertyType);
content.Properties.Add(property);
return property;
}
// fixme - what's below belongs to the upload property editor, not the media filesystem!
public void SetUploadFile(IContentBase content, string propertyTypeAlias, string filename, Stream filestream, string culture = null, string segment = null)
{
var property = GetProperty(content, propertyTypeAlias);
var oldpath = property.GetValue(culture, segment) is string svalue ? GetRelativePath(svalue) : null;
var filepath = StoreFile(content, property.PropertyType, filename, filestream, oldpath);
property.SetValue(GetUrl(filepath), culture, segment);
SetUploadFile(content, property, filepath, filestream, culture, segment);
}
public void SetUploadFile(IContentBase content, string propertyTypeAlias, string filepath, string culture = null, string segment = null)
{
var property = GetProperty(content, propertyTypeAlias);
// fixme delete?
var oldpath = property.GetValue(culture, segment) is string svalue ? GetRelativePath(svalue) : null;
if (string.IsNullOrWhiteSpace(oldpath) == false && oldpath != filepath)
DeleteFile(oldpath);
property.SetValue(GetUrl(filepath), culture, segment);
using (var filestream = OpenFile(filepath))
{
SetUploadFile(content, property, filepath, filestream, culture, segment);
}
}
// sets a file for the FileUpload property editor
// ie generates thumbnails and populates autofill properties
private void SetUploadFile(IContentBase content, Property property, string filepath, Stream filestream, string culture = null, string segment = null)
{
// will use filepath for extension, and filestream for length
UploadAutoFillProperties.Populate(content, property.Alias, filepath, filestream, culture, segment);
}
#endregion
#region Image
/// <summary>
/// Gets a value indicating whether the file extension corresponds to an image.
/// </summary>
/// <param name="extension">The file extension.</param>
/// <returns>A value indicating whether the file extension corresponds to an image.</returns>
public bool IsImageFile(string extension)
{
if (extension == null) return false;
extension = extension.TrimStart('.');
return ContentConfig.ImageFileTypes.InvariantContains(extension);
}
/// <summary>
/// Gets the dimensions of an image.
/// </summary>
/// <param name="stream">A stream containing the image bytes.</param>
/// <returns>The dimension of the image.</returns>
/// <remarks>First try with EXIF as it is faster and does not load the entire image
/// in memory. Fallback to GDI which means loading the image in memory and thus
/// use potentially large amounts of memory.</remarks>
public Size GetDimensions(Stream stream)
{
//Try to load with exif
try
{
var jpgInfo = ImageFile.FromStream(stream);
if (jpgInfo.Format != ImageFileFormat.Unknown
&& jpgInfo.Properties.ContainsKey(ExifTag.PixelYDimension)
&& jpgInfo.Properties.ContainsKey(ExifTag.PixelXDimension))
{
var height = Convert.ToInt32(jpgInfo.Properties[ExifTag.PixelYDimension].Value);
var width = Convert.ToInt32(jpgInfo.Properties[ExifTag.PixelXDimension].Value);
if (height > 0 && width > 0)
{
return new Size(width, height);
}
}
}
catch (Exception)
{
//We will just swallow, just means we can't read exif data, we don't want to log an error either
}
//we have no choice but to try to read in via GDI
using (var image = Image.FromStream(stream))
{
var fileWidth = image.Width;
var fileHeight = image.Height;
return new Size(fileWidth, fileHeight);
}
}
#endregion
}
}
+1
View File
@@ -40,6 +40,7 @@ namespace Umbraco.Core.IO
public static string Umbraco => IOHelper.ReturnPath("umbracoPath", "~/umbraco");
[Obsolete("This will be removed, there is no more umbraco_client folder")]
public static string UmbracoClient => IOHelper.ReturnPath("umbracoClientPath", "~/umbraco_client");
public static string UserControls => IOHelper.ReturnPath("umbracoUsercontrolsPath", "~/usercontrols");
-21
View File
@@ -1,21 +0,0 @@
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
namespace Umbraco.Core.Media
{
public static class ImageExtensions
{
/// <summary>
/// Gets the MIME type of an image.
/// </summary>
/// <param name="image">The image.</param>
/// <returns>The MIME type of the image.</returns>
public static string GetMimeType(this Image image)
{
var format = image.RawFormat;
var codec = ImageCodecInfo.GetImageDecoders().First(c => c.FormatID == format.Guid);
return codec.MimeType;
}
}
}
-20
View File
@@ -280,26 +280,6 @@ namespace Umbraco.Core.Models
Properties.Add(property);
}
// HttpPostedFileBase is the base class that can be mocked
// HttpPostedFile is what we get in ASP.NET
// HttpPostedFileWrapper wraps sealed HttpPostedFile as HttpPostedFileBase
/// <summary>
/// Sets the posted file value of a property.
/// </summary>
public virtual void SetValue(string propertyTypeAlias, HttpPostedFile value, string culture = null, string segment = null)
{
ContentExtensions.SetValue(this, propertyTypeAlias, new HttpPostedFileWrapper(value), culture, segment);
}
/// <summary>
/// Sets the posted file value of a property.
/// </summary>
public virtual void SetValue(string propertyTypeAlias, HttpPostedFileBase value, string culture = null, string segment = null)
{
ContentExtensions.SetValue(this, propertyTypeAlias, value, culture, segment);
}
#endregion
#region Copy
+24
View File
@@ -98,6 +98,30 @@ namespace Umbraco.Core.Models
}
}
/// <summary>
/// Determines if AllowedTemplates contains templateId
/// </summary>
/// <param name="templateId">The template id to check</param>
/// <returns>True if AllowedTemplates contains the templateId else False</returns>
public bool IsAllowedTemplate(int templateId)
{
return AllowedTemplates == null
? false
: AllowedTemplates.Any(t => t.Id == templateId);
}
/// <summary>
/// Determines if AllowedTemplates contains templateId
/// </summary>
/// <param name="templateAlias">The template alias to check</param>
/// <returns>True if AllowedTemplates contains the templateAlias else False</returns>
public bool IsAllowedTemplate(string templateAlias)
{
return AllowedTemplates == null
? false
: AllowedTemplates.Any(t => t.Alias.Equals(templateAlias, StringComparison.InvariantCultureIgnoreCase));
}
/// <summary>
/// Sets the default template for the ContentType
/// </summary>
+1 -2
View File
@@ -172,10 +172,9 @@ namespace Umbraco.Core.Models
/// </summary>
/// <returns>A value indicating whether the culture can be published.</returns>
/// <remarks>
/// <para>Fails if values cannot be published, e.g. if some values are not valid.</para>
/// <para>Fails if properties don't pass variant validtion rules.</para>
/// <para>Publishing must be finalized via the content service SavePublishing method.</para>
/// </remarks>
// fixme - should return an attempt with error results
bool PublishCulture(string culture = "*");
/// <summary>
+1 -1
View File
@@ -139,7 +139,7 @@ namespace Umbraco.Core.Models
// fixme validate published cultures?
/// <summary>
/// Validates the content item's properties.
/// Validates the content item's properties pass variant rules
/// </summary>
/// <para>If the content type is variant, then culture can be either '*' or an actual culture, but neither 'null' nor
/// 'empty'. If the content type is invariant, then culture can be either '*' or null or empty.</para>
+14
View File
@@ -17,6 +17,20 @@ namespace Umbraco.Core.Models
/// </summary>
IEnumerable<ITemplate> AllowedTemplates { get; set; }
/// <summary>
/// Determines if AllowedTemplates contains templateId
/// </summary>
/// <param name="templateId">The template id to check</param>
/// <returns>True if AllowedTemplates contains the templateId else False</returns>
bool IsAllowedTemplate(int templateId);
/// <summary>
/// Determines if AllowedTemplates contains templateId
/// </summary>
/// <param name="templateAlias">The template alias to check</param>
/// <returns>True if AllowedTemplates contains the templateAlias else False</returns>
bool IsAllowedTemplate(string templateAlias);
/// <summary>
/// Sets the default template for the ContentType
/// </summary>
@@ -93,14 +93,6 @@ namespace Umbraco.Core.Models.Identity
_roles.CollectionChanged += _roles_CollectionChanged;
}
public virtual async Task<ClaimsIdentity> GenerateUserIdentityAsync(BackOfficeUserManager<BackOfficeIdentityUser> manager)
{
// NOTE the authenticationType must match the umbraco one
// defined in CookieAuthenticationOptions.AuthenticationType
var userIdentity = await manager.CreateIdentityAsync(this, Constants.Security.BackOfficeAuthenticationType);
return userIdentity;
}
/// <summary>
/// Returns true if an Id has been set on this object this will be false if the object is new and not peristed to the database
/// </summary>
+5 -1
View File
@@ -260,7 +260,7 @@ namespace Umbraco.Core.Models.Membership
{
get
{
if (LastLoginDate == default(DateTime) && IsApproved == false && InvitedDate != null)
if (LastLoginDate == default && IsApproved == false && InvitedDate != null)
return UserState.Invited;
if (IsLockedOut)
@@ -268,6 +268,10 @@ namespace Umbraco.Core.Models.Membership
if (IsApproved == false)
return UserState.Disabled;
// User is not disabled or locked and has never logged in before
if (LastLoginDate == default && IsApproved && IsLockedOut == false)
return UserState.Inactive;
return UserState.Active;
}
}
@@ -9,6 +9,7 @@
Active = 0,
Disabled = 1,
LockedOut = 2,
Invited = 3
Invited = 3,
Inactive = 4
}
}
-8
View File
@@ -1,14 +1,6 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Reflection;
using System.Runtime.Serialization;
using System.Text;
using Umbraco.Core.Configuration;
using Umbraco.Core.Configuration.UmbracoSettings;
using Umbraco.Core.IO;
using Umbraco.Core.Services;
using Umbraco.Core.Strings;
namespace Umbraco.Core.Models
-3
View File
@@ -10,9 +10,6 @@ namespace Umbraco.Core
/// <summary>
/// Returns the machine name that is safe to use in file paths.
/// </summary>
/// <remarks>
/// see: https://github.com/Shandem/ClientDependency/issues/4
/// </remarks>
public static string FileSafeMachineName
{
get { return MachineName.ReplaceNonAlphanumericChars('-'); }
@@ -150,6 +150,8 @@ UNION
SELECT '4CountOfLockedOut' AS colName, COUNT(id) AS num FROM umbracoUser WHERE userNoConsole = 1
UNION
SELECT '5CountOfInvited' AS colName, COUNT(id) AS num FROM umbracoUser WHERE lastLoginDate IS NULL AND userDisabled = 1 AND invitedDate IS NOT NULL
UNION
SELECT '6CountOfDisabled' AS colName, COUNT(id) AS num FROM umbracoUser WHERE userDisabled = 0 AND userNoConsole = 0 AND lastLoginDate IS NULL
ORDER BY colName";
var result = Database.Fetch<dynamic>(sql);
@@ -160,7 +162,8 @@ ORDER BY colName";
{UserState.Active, (int) result[1].num},
{UserState.Disabled, (int) result[2].num},
{UserState.LockedOut, (int) result[3].num},
{UserState.Invited, (int) result[4].num}
{UserState.Invited, (int) result[4].num},
{UserState.Inactive, (int) result[5].num}
};
}
@@ -766,6 +769,12 @@ ORDER BY colName";
sb.Append("(userDisabled = 0 AND userNoConsole = 0 AND lastLoginDate IS NOT NULL)");
appended = true;
}
if (userState.Contains(UserState.Inactive))
{
if (appended) sb.Append(" OR ");
sb.Append("(userDisabled = 0 AND userNoConsole = 0 AND lastLoginDate IS NULL)");
appended = true;
}
if (userState.Contains(UserState.Disabled))
{
if (appended) sb.Append(" OR ");
@@ -143,19 +143,19 @@ namespace Umbraco.Core.Persistence.SqlSyntax
/// <returns></returns>
public IEnumerable<Tuple<string, string, string, string>> GetDefaultConstraintsPerColumn(IDatabase db)
{
var items = db.Fetch<dynamic>("SELECT TableName = t.Name,ColumnName = c.Name,dc.Name,dc.[Definition] FROM sys.tables t INNER JOIN sys.default_constraints dc ON t.object_id = dc.parent_object_id INNER JOIN sys.columns c ON dc.parent_object_id = c.object_id AND c.column_id = dc.parent_column_id");
var items = db.Fetch<dynamic>("SELECT TableName = t.Name, ColumnName = c.Name, dc.Name, dc.[Definition] FROM sys.tables t INNER JOIN sys.default_constraints dc ON t.object_id = dc.parent_object_id INNER JOIN sys.columns c ON dc.parent_object_id = c.object_id AND c.column_id = dc.parent_column_id INNER JOIN sys.schemas as s on t.[schema_id] = s.[schema_id] WHERE s.name = (SELECT SCHEMA_NAME())");
return items.Select(x => new Tuple<string, string, string, string>(x.TableName, x.ColumnName, x.Name, x.Definition));
}
public override IEnumerable<string> GetTablesInSchema(IDatabase db)
{
var items = db.Fetch<dynamic>("SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES");
var items = db.Fetch<dynamic>("SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = (SELECT SCHEMA_NAME())");
return items.Select(x => x.TABLE_NAME).Cast<string>().ToList();
}
public override IEnumerable<ColumnInfo> GetColumnsInSchema(IDatabase db)
{
var items = db.Fetch<dynamic>("SELECT TABLE_NAME, COLUMN_NAME, ORDINAL_POSITION, COLUMN_DEFAULT, IS_NULLABLE, DATA_TYPE FROM INFORMATION_SCHEMA.COLUMNS");
var items = db.Fetch<dynamic>("SELECT TABLE_NAME, COLUMN_NAME, ORDINAL_POSITION, COLUMN_DEFAULT, IS_NULLABLE, DATA_TYPE FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = (SELECT SCHEMA_NAME())");
return
items.Select(
item =>
@@ -168,7 +168,7 @@ namespace Umbraco.Core.Persistence.SqlSyntax
{
var items =
db.Fetch<dynamic>(
"SELECT TABLE_NAME, CONSTRAINT_NAME FROM INFORMATION_SCHEMA.CONSTRAINT_TABLE_USAGE");
"SELECT TABLE_NAME, CONSTRAINT_NAME FROM INFORMATION_SCHEMA.CONSTRAINT_TABLE_USAGE WHERE TABLE_SCHEMA = (SELECT SCHEMA_NAME())");
return items.Select(item => new Tuple<string, string>(item.TABLE_NAME, item.CONSTRAINT_NAME)).ToList();
}
@@ -177,7 +177,7 @@ namespace Umbraco.Core.Persistence.SqlSyntax
{
var items =
db.Fetch<dynamic>(
"SELECT TABLE_NAME, COLUMN_NAME, CONSTRAINT_NAME FROM INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE");
"SELECT TABLE_NAME, COLUMN_NAME, CONSTRAINT_NAME FROM INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE WHERE TABLE_SCHEMA = (SELECT SCHEMA_NAME())");
return items.Select(item => new Tuple<string, string, string>(item.TABLE_NAME, item.COLUMN_NAME, item.CONSTRAINT_NAME)).ToList();
}
@@ -191,7 +191,8 @@ CASE WHEN I.is_unique_constraint = 1 OR I.is_unique = 1 THEN 1 ELSE 0 END AS [U
from sys.tables as T inner join sys.indexes as I on T.[object_id] = I.[object_id]
inner join sys.index_columns as IC on IC.[object_id] = I.[object_id] and IC.[index_id] = I.[index_id]
inner join sys.all_columns as AC on IC.[object_id] = AC.[object_id] and IC.[column_id] = AC.[column_id]
WHERE I.is_primary_key = 0
inner join sys.schemas as S on T.[schema_id] = S.[schema_id]
WHERE S.name = (SELECT SCHEMA_NAME()) AND I.is_primary_key = 0
order by T.name, I.name");
return items.Select(item => new Tuple<string, string, string, bool>(item.TABLE_NAME, item.INDEX_NAME, item.COLUMN_NAME,
item.UNIQUE == 1)).ToList();
@@ -201,7 +202,7 @@ order by T.name, I.name");
public override bool DoesTableExist(IDatabase db, string tableName)
{
var result =
db.ExecuteScalar<long>("SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = @TableName",
db.ExecuteScalar<long>("SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = @TableName AND TABLE_SCHEMA = (SELECT SCHEMA_NAME())",
new { TableName = tableName });
return result > 0;
@@ -138,7 +138,7 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters // fixme MOVE TO MODELS O
/// </summary>
/// <returns></returns>
public bool HasFocalPoint()
=> FocalPoint != null && FocalPoint.Left != 0.5m && FocalPoint.Top != 0.5m;
=> FocalPoint != null && (FocalPoint.Left != 0.5m || FocalPoint.Top != 0.5m);
/// <summary>
/// Determines whether the value has a specified crop.
@@ -720,7 +720,7 @@ namespace Umbraco.Core.Security
}
else
{
//if the salt bytes is too long for the required key length for the algorithm, extend it
//if the salt bytes is too short for the required key length for the algorithm, extend it
var numArray2 = new byte[keyedHashAlgorithm.Key.Length];
var dstOffset = 0;
while (dstOffset < numArray2.Length)
@@ -645,7 +645,7 @@ namespace Umbraco.Core.Services.Implement
{
using (var scope = ScopeProvider.CreateScope(autoComplete: true))
{
return _userRepository.GetPagedResultsByQuery(null, pageIndex, pageSize, out totalRecords, member => member.Username);
return _userRepository.GetPagedResultsByQuery(null, pageIndex, pageSize, out totalRecords, member => member.Name);
}
}
+10 -1
View File
@@ -11,6 +11,10 @@ namespace Umbraco.Core.Services
/// Represents the result of a service operation.
/// </summary>
/// <typeparam name="TResultType">The type of the result type.</typeparam>
/// <remarks>Type <typeparamref name="TResultType"/> must be an enumeration, and its
/// underlying type must be byte. Values indicating success should be in the 0-127
/// range, while values indicating failure should be in the 128-255 range. See
/// <see cref="OperationResultType"/> for a base implementation.</remarks>
public class OperationResult<TResultType>
where TResultType : struct
{
@@ -56,6 +60,10 @@ namespace Umbraco.Core.Services
/// </summary>
/// <typeparam name="TResultType">The type of the result type.</typeparam>
/// <typeparam name="TEntity">The type of the entity.</typeparam>
/// <remarks>Type <typeparamref name="TResultType"/> must be an enumeration, and its
/// underlying type must be byte. Values indicating success should be in the 0-127
/// range, while values indicating failure should be in the 128-255 range. See
/// <see cref="OperationResultType"/> for a base implementation.</remarks>
public class OperationResult<TResultType, TEntity> : OperationResult<TResultType>
where TResultType : struct
{
@@ -111,7 +119,8 @@ namespace Umbraco.Core.Services
return new OperationResult(OperationResultType.FailedCancelledByEvent, eventMessages);
}
// fixme wtf?
// fixme - this exists to support services that still return Attempt<OperationResult>
// these services should directly return an OperationResult, and then this static class should be deleted
internal static class Attempt
{
/// <summary>
+18 -63
View File
@@ -38,8 +38,6 @@
<Reference Include="System.ComponentModel.DataAnnotations" />
<Reference Include="System.Configuration" />
<Reference Include="System.Data.Entity" />
<Reference Include="System.DirectoryServices.AccountManagement" />
<Reference Include="System.Drawing" />
<Reference Include="System.IO.Compression" />
<Reference Include="System.IO.Compression.FileSystem" />
<Reference Include="System.Runtime.Caching" />
@@ -58,21 +56,22 @@
<ItemGroup>
<!-- note: NuGet deals with transitive references now -->
<PackageReference Include="AutoMapper" Version="7.0.1" />
<PackageReference Include="ClientDependency" Version="1.9.6" />
<PackageReference Include="HtmlAgilityPack" Version="1.7.2" />
<PackageReference Include="ImageProcessor" Version="2.6.1.19" />
<PackageReference Include="LightInject" Version="5.1.2" />
<PackageReference Include="LightInject.Annotation" Version="1.1.0" />
<PackageReference Include="LightInject.Web" Version="2.0.0" />
<PackageReference Include="Microsoft.AspNet.Identity.Owin" Version="2.2.1" />
<PackageReference Include="Microsoft.AspNet.WebApi.Client" Version="5.2.6" />
<PackageReference Include="Microsoft.Owin.Security.Cookies" Version="4.0.0" />
<PackageReference Include="Microsoft.Owin.Security.OAuth" Version="4.0.0" />
<PackageReference Include="Microsoft.Web.Xdt" Version="2.1.2" />
<PackageReference Include="Microsoft.AspNet.Identity.Core">
<Version>2.2.2</Version>
</PackageReference>
<PackageReference Include="Microsoft.AspNet.WebApi.Client">
<Version>5.2.6</Version>
</PackageReference>
<PackageReference Include="Microsoft.Owin">
<Version>4.0.0</Version>
</PackageReference>
<PackageReference Include="MiniProfiler" Version="3.2.0.157" />
<PackageReference Include="MySql.Data" Version="6.10.7" />
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
<PackageReference Include="NPoco" Version="3.9.3" />
<PackageReference Include="NPoco" Version="3.9.4" />
<PackageReference Include="Semver" Version="2.0.4" />
<PackageReference Include="Serilog">
<Version>2.7.1</Version>
@@ -110,8 +109,7 @@
<Compile Include="Attempt.cs" />
<Compile Include="AttemptOfTResult.cs" />
<Compile Include="AttemptOfTResultTStatus.cs" />
<Compile Include="Auditing\AuditEventsComponent.cs" />
<Compile Include="Auditing\IdentityAuditEventArgs.cs" />
<Compile Include="Components\AuditEventsComponent.cs" />
<Compile Include="BindingRedirects.cs" />
<Compile Include="ByteArrayExtensions.cs" />
<Compile Include="Cache\CacheHelper.cs" />
@@ -200,7 +198,6 @@
<Compile Include="Composing\WeightAttribute.cs" />
<Compile Include="Composing\WeightedCollectionBuilderBase.cs" />
<Compile Include="Configuration\CaseInsensitiveEnumConfigConverter.cs" />
<Compile Include="Configuration\ClientDependencyConfiguration.cs" />
<Compile Include="Configuration\CommaDelimitedConfigurationElement.cs" />
<Compile Include="Configuration\CoreDebug.cs" />
<Compile Include="Configuration\Dashboard\AccessElement.cs" />
@@ -576,7 +573,6 @@
<Compile Include="ListExtensions.cs" />
<Compile Include="Logging\DebugDiagnosticsLogger.cs" />
<Compile Include="Logging\ILogger.cs" />
<Compile Include="Logging\ImageProcessorLogger.cs" />
<Compile Include="Logging\IProfiler.cs" />
<Compile Include="Logging\Serilog\SerilogLogger.cs" />
<Compile Include="Logging\LoggerExtensions.cs" />
@@ -591,49 +587,17 @@
<Compile Include="Logging\WebProfilerComponent.cs" />
<Compile Include="Logging\WebProfilerProvider.cs" />
<Compile Include="Macros\MacroErrorBehaviour.cs" />
<Compile Include="Macros\MacroTagParser.cs" />
<Compile Include="MainDom.cs" />
<Compile Include="Manifest\ManifestParser.cs" />
<Compile Include="Manifest\ValueValidatorConverter.cs" />
<Compile Include="Manifest\ManifestWatcher.cs" />
<Compile Include="Manifest\PackageManifest.cs" />
<Compile Include="Manifest\DataEditorConverter.cs" />
<Compile Include="Media\Exif\BitConverterEx.cs" />
<Compile Include="Media\Exif\ExifBitConverter.cs" />
<Compile Include="Media\Exif\ExifEnums.cs" />
<Compile Include="Media\Exif\ExifExceptions.cs" />
<Compile Include="Media\Exif\ExifExtendedProperty.cs" />
<Compile Include="Media\Exif\ExifFileTypeDescriptor.cs" />
<Compile Include="Media\Exif\ExifInterOperability.cs" />
<Compile Include="Media\Exif\ExifProperty.cs" />
<Compile Include="Media\Exif\ExifPropertyCollection.cs" />
<Compile Include="Media\Exif\ExifPropertyFactory.cs" />
<Compile Include="Media\Exif\ExifTag.cs" />
<Compile Include="Media\Exif\ExifTagFactory.cs" />
<Compile Include="Media\Exif\IFD.cs" />
<Compile Include="Media\Exif\ImageFile.cs" />
<Compile Include="Media\Exif\ImageFileDirectory.cs" />
<Compile Include="Media\Exif\ImageFileDirectoryEntry.cs" />
<Compile Include="Media\Exif\ImageFileFormat.cs" />
<Compile Include="Media\Exif\JFIFEnums.cs" />
<Compile Include="Media\Exif\JFIFExtendedProperty.cs" />
<Compile Include="Media\Exif\JFIFThumbnail.cs" />
<Compile Include="Media\Exif\JPEGExceptions.cs" />
<Compile Include="Media\Exif\JPEGFile.cs" />
<Compile Include="Media\Exif\JPEGMarker.cs" />
<Compile Include="Media\Exif\JPEGSection.cs" />
<Compile Include="Media\Exif\MathEx.cs" />
<Compile Include="Media\Exif\TIFFFile.cs" />
<Compile Include="Media\Exif\TIFFHeader.cs" />
<Compile Include="Media\Exif\TIFFStrip.cs" />
<Compile Include="Media\Exif\Utility.cs" />
<Compile Include="Media\IEmbedProvider.cs" />
<Compile Include="Media\IEmbedSettingProvider.cs" />
<Compile Include="Media\ImageExtensions.cs" />
<Compile Include="Media\ProviderSetting.cs" />
<Compile Include="Media\Result.cs" />
<Compile Include="Media\Status.cs" />
<Compile Include="Media\UploadAutoFillProperties.cs" />
<Compile Include="Migrations\IPostMigration.cs" />
<Compile Include="Migrations\MigrationBuilder.cs" />
<Compile Include="Migrations\MigrationPlan.cs" />
@@ -650,7 +614,7 @@
<Compile Include="Models\AuditType.cs" />
<Compile Include="Models\Content.cs" />
<Compile Include="Models\ContentBase.cs" />
<Compile Include="Models\ContentExtensions.cs" />
<Compile Include="ContentExtensions.cs" />
<Compile Include="Models\ContentStatus.cs" />
<Compile Include="Models\ContentType.cs" />
<Compile Include="Models\ContentTypeAvailableCompositionsResult.cs" />
@@ -1315,19 +1279,10 @@
<Compile Include="Scoping\ScopeContextualBase.cs" />
<Compile Include="Scoping\ScopeProvider.cs" />
<Compile Include="Scoping\ScopeReference.cs" />
<Compile Include="Security\ActiveDirectoryBackOfficeUserPasswordChecker.cs" />
<Compile Include="Security\AuthenticationExtensions.cs" />
<Compile Include="Security\BackOfficeClaimsIdentityFactory.cs" />
<Compile Include="Security\BackOfficeCookieAuthenticationProvider.cs" />
<Compile Include="Security\BackOfficeSignInManager.cs" />
<Compile Include="Security\BackOfficeUserManager.cs" />
<Compile Include="Security\BackOfficeUserManagerMarker.cs" />
<Compile Include="Security\BackOfficeUserPasswordCheckerResult.cs" />
<Compile Include="Security\BackOfficeUserStore.cs" />
<Compile Include="Security\BackOfficeUserValidator.cs" />
<Compile Include="Security\EmailService.cs" />
<Compile Include="Security\IBackOfficeUserManagerMarker.cs" />
<Compile Include="Security\IBackOfficeUserPasswordChecker.cs" />
<Compile Include="Security\IMembershipProviderPasswordHasher.cs" />
<Compile Include="Security\IUmbracoMemberTypeMembershipProvider.cs" />
<Compile Include="Security\IUserAwarePasswordHasher.cs" />
@@ -1338,8 +1293,6 @@
<Compile Include="Security\MembershipProviderExtensions.cs" />
<Compile Include="Security\MembershipProviderPasswordHasher.cs" />
<Compile Include="Security\MembershipProviderPasswordValidator.cs" />
<Compile Include="Security\OwinExtensions.cs" />
<Compile Include="Security\SessionIdValidator.cs" />
<Compile Include="Security\UmbracoBackOfficeIdentity.cs" />
<Compile Include="Security\UmbracoEmailMessage.cs" />
<Compile Include="Security\UmbracoMembershipProviderBase.cs" />
@@ -1456,9 +1409,9 @@
<Compile Include="Services\UnpublishResultType.cs" />
<Compile Include="Services\UserServiceExtensions.cs" />
<Compile Include="Settable.cs" />
<Compile Include="Strategies\ManifestWatcherComponent.cs" />
<Compile Include="Strategies\RelateOnCopyComponent.cs" />
<Compile Include="Strategies\RelateOnTrashComponent.cs" />
<Compile Include="Components\ManifestWatcherComponent.cs" />
<Compile Include="Components\RelateOnCopyComponent.cs" />
<Compile Include="Components\RelateOnTrashComponent.cs" />
<Compile Include="StringExtensions.cs" />
<Compile Include="Strings\CleanStringType.cs" />
<Compile Include="Strings\ContentBaseExtensions.cs" />
@@ -1540,6 +1493,8 @@
<ItemGroup>
<EmbeddedResource Include="FileResources\Files.resx" />
</ItemGroup>
<ItemGroup />
<ItemGroup>
<Folder Include="Auditing\" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
+1 -1
View File
@@ -50,7 +50,7 @@
<!-- note: NuGet deals with transitive references now -->
<PackageReference Include="Examine" Version="1.0.0-beta025" />
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
<PackageReference Include="NPoco" Version="3.9.3" />
<PackageReference Include="NPoco" Version="3.9.4" />
</ItemGroup>
<ItemGroup>
<Compile Include="Config\ConfigIndexCriteria.cs" />
@@ -62,18 +62,16 @@
<PackageReference Include="BenchmarkDotNet.Toolchains.Roslyn" Version="0.10.13" />
<PackageReference Include="Castle.Core" Version="4.2.1" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="2.9.0" />
<PackageReference Include="Microsoft.CodeAnalysis.Common" Version="2.8.0" />
<PackageReference Include="Microsoft.Diagnostics.Tracing.TraceEvent" Version="2.0.11" />
<PackageReference Include="Microsoft.DotNet.InternalAbstractions" Version="1.0.0" />
<PackageReference Include="Microsoft.DotNet.PlatformAbstractions" Version="2.0.4" />
<PackageReference Include="Microsoft.Win32.Registry" Version="4.4.0" />
<PackageReference Include="Moq" Version="4.8.2" />
<PackageReference Include="NPoco" Version="3.9.3" />
<PackageReference Include="NPoco" Version="3.9.4" />
<PackageReference Include="Umbraco.SqlServerCE" Version="4.0.0.1" />
<PackageReference Include="System.AppContext" Version="4.3.0" />
<PackageReference Include="System.Collections" Version="4.3.0" />
<PackageReference Include="System.Collections.Concurrent" Version="4.3.0" />
<PackageReference Include="System.Collections.Immutable" Version="1.4.0" />
<PackageReference Include="System.Console" Version="4.3.0" />
<PackageReference Include="System.Diagnostics.Debug" Version="4.3.0" />
<PackageReference Include="System.Diagnostics.FileVersionInfo" Version="4.3.0" />
@@ -87,7 +85,6 @@
<PackageReference Include="System.Linq" Version="4.3.0" />
<PackageReference Include="System.Linq.Expressions" Version="4.3.0" />
<PackageReference Include="System.Reflection" Version="4.3.0" />
<PackageReference Include="System.Reflection.Metadata" Version="1.5.0" />
<PackageReference Include="System.Reflection.Primitives" Version="4.3.0" />
<PackageReference Include="System.Resources.ResourceManager" Version="4.3.0" />
<PackageReference Include="System.Runtime" Version="4.3.0" />
+5 -5
View File
@@ -7,11 +7,11 @@
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Microsoft.CodeAnalysis" publicKeyToken="31bf3856ad364e35" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-2.8.0.0" newVersion="2.8.0.0"/>
<bindingRedirect oldVersion="0.0.0.0-2.9.0.0" newVersion="2.9.0.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.CodeAnalysis.CSharp" publicKeyToken="31bf3856ad364e35" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-2.8.0.0" newVersion="2.8.0.0"/>
<bindingRedirect oldVersion="0.0.0.0-2.9.0.0" newVersion="2.9.0.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Diagnostics.Tracing.TraceEvent" publicKeyToken="b03f5f7f11d50a3a" culture="neutral"/>
@@ -55,7 +55,7 @@
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Collections.Immutable" publicKeyToken="b03f5f7f11d50a3a" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-1.2.2.0" newVersion="1.2.2.0"/>
<bindingRedirect oldVersion="0.0.0.0-1.2.3.0" newVersion="1.2.3.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.ComponentModel" publicKeyToken="b03f5f7f11d50a3a" culture="neutral"/>
@@ -167,7 +167,7 @@
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Reflection.Metadata" publicKeyToken="b03f5f7f11d50a3a" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-1.4.2.0" newVersion="1.4.2.0"/>
<bindingRedirect oldVersion="0.0.0.0-1.4.3.0" newVersion="1.4.3.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Reflection.Primitives" publicKeyToken="b03f5f7f11d50a3a" culture="neutral"/>
@@ -267,7 +267,7 @@
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.ValueTuple" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0"/>
<bindingRedirect oldVersion="0.0.0.0-4.0.3.0" newVersion="4.0.3.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.Http" publicKeyToken="31bf3856ad364e35" culture="neutral"/>
@@ -23,6 +23,12 @@ namespace Umbraco.Tests.Configurations.UmbracoSettings
Assert.IsTrue(SettingsSection.WebRouting.DisableAlternativeTemplates == false);
}
[Test]
public void ValidateAlternativeTemplates()
{
Assert.IsTrue(SettingsSection.WebRouting.ValidateAlternativeTemplates == false);
}
[Test]
public void DisableFindContentByIdPath()
{
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using NUnit.Framework;
using Umbraco.Core.Macros;
using Umbraco.Web.Macros;
namespace Umbraco.Tests.Macros
{
@@ -1,6 +1,7 @@
using System;
using System.Linq;
using NUnit.Framework;
using Umbraco.Core;
using Umbraco.Core.Models;
using Umbraco.Tests.TestHelpers.Entities;
using Umbraco.Tests.Testing;
+1
View File
@@ -8,6 +8,7 @@ using System.Web;
using Moq;
using Umbraco.Core;
using NUnit.Framework;
using Umbraco.Core;
using Umbraco.Core.Cache;
using Umbraco.Core.Composing;
using Umbraco.Core.Configuration.UmbracoSettings;
@@ -13,6 +13,7 @@ using Umbraco.Core.Models;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.PropertyEditors;
using Umbraco.Core.PropertyEditors.ValueConverters;
using Umbraco.Core.Services;
using Umbraco.Tests.TestHelpers;
using Umbraco.Web.Models;
using Umbraco.Web;
@@ -74,7 +75,7 @@ namespace Umbraco.Tests.PropertyEditors
var mediaFileSystem = new MediaFileSystem(Mock.Of<IFileSystem>(), Mock.Of<IContentSection>(), Mock.Of<IMediaPathScheme>(), Mock.Of<ILogger>());
var dataTypeService = new TestObjects.TestDataTypeService(
new DataType(new ImageCropperPropertyEditor(Mock.Of<ILogger>(), mediaFileSystem, Mock.Of<IContentSection>())) { Id = 1 });
new DataType(new ImageCropperPropertyEditor(Mock.Of<ILogger>(), mediaFileSystem, Mock.Of<IContentSection>(), Mock.Of<IDataTypeService>())) { Id = 1 });
var factory = new PublishedContentTypeFactory(Mock.Of<IPublishedModelFactory>(), new PropertyValueConverterCollection(Array.Empty<IPropertyValueConverter>()), dataTypeService);
@@ -14,7 +14,7 @@ using Umbraco.Web;
using Umbraco.Web.PublishedCache;
using Umbraco.Web.Routing;
using Umbraco.Web.Security;
using Umbraco.Web.Security.Identity;
namespace Umbraco.Tests.Security
{
@@ -89,7 +89,11 @@ namespace Umbraco.Tests.TestHelpers.ControllerTesting
var httpContext = Mock.Of<HttpContextBase>(
http => http.User == owinContext.Authentication.User
//ensure the request exists with a cookies collection
&& http.Request == Mock.Of<HttpRequestBase>(r => r.Cookies == new HttpCookieCollection())
&& http.Request == Mock.Of<HttpRequestBase>(r => r.Cookies == new HttpCookieCollection()
&& r.RequestContext == new System.Web.Routing.RequestContext
{
RouteData = new System.Web.Routing.RouteData()
})
//ensure the request exists with an items collection
&& http.Items == httpContextItems);
//chuck it into the props since this is what MS does when hosted and it's needed there
@@ -58,14 +58,14 @@ namespace Umbraco.Tests.TestHelpers.ControllerTesting
var response = await server.HttpClient.SendAsync(request);
Console.WriteLine(response);
var json = "";
if (response.IsSuccessStatusCode == false)
{
WriteResponseError(response);
}
else
var json = (await ((StreamContent)response.Content).ReadAsStringAsync()).TrimStart(AngularJsonMediaTypeFormatter.XsrfPrefix);
if (!json.IsNullOrWhiteSpace())
{
json = (await ((StreamContent) response.Content).ReadAsStringAsync()).TrimStart(AngularJsonMediaTypeFormatter.XsrfPrefix);
var deserialized = JsonConvert.DeserializeObject(json);
Console.Write(JsonConvert.SerializeObject(deserialized, Formatting.Indented));
}
+2 -2
View File
@@ -82,7 +82,7 @@
<PackageReference Include="LightInject.Annotation" Version="1.1.0" />
<PackageReference Include="Lucene.Net" Version="3.0.3" />
<PackageReference Include="Lucene.Net.Contrib" Version="3.0.3" />
<PackageReference Include="Microsoft.AspNet.Identity.Core" Version="2.2.1" />
<PackageReference Include="Microsoft.AspNet.Identity.Core" Version="2.2.2" />
<PackageReference Include="Microsoft.AspNet.Mvc" Version="5.2.6" />
<PackageReference Include="Microsoft.AspNet.WebApi" Version="5.2.6" />
<PackageReference Include="Microsoft.AspNet.WebApi.Client" Version="5.2.6" />
@@ -96,7 +96,7 @@
<PackageReference Include="Microsoft.Web.Infrastructure" Version="1.0.0.0" />
<PackageReference Include="MiniProfiler" Version="3.2.0.157" />
<PackageReference Include="Moq" Version="4.8.2" />
<PackageReference Include="NPoco" Version="3.9.3" />
<PackageReference Include="NPoco" Version="3.9.4" />
<PackageReference Include="NUnit" Version="3.10.1" />
<PackageReference Include="NUnit3TestAdapter" Version="3.10.0" />
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
@@ -24,6 +24,12 @@ using Umbraco.Web.Models.ContentEditing;
using Umbraco.Web.PublishedCache;
using Umbraco.Web._Legacy.Actions;
using Task = System.Threading.Tasks.Task;
using Umbraco.Core.Dictionary;
using Umbraco.Web.PropertyEditors;
using System;
using Umbraco.Web.WebApi;
using Umbraco.Web.Trees;
using System.Globalization;
namespace Umbraco.Tests.Web.Controllers
{
@@ -40,6 +46,8 @@ namespace Umbraco.Tests.Web.Controllers
var userServiceMock = new Mock<IUserService>();
userServiceMock.Setup(service => service.GetUserById(It.IsAny<int>()))
.Returns((int id) => id == 1234 ? new User(1234, "Test", "test@test.com", "test@test.com", "", new List<IReadOnlyUserGroup>(), new int[0], new int[0]) : null);
userServiceMock.Setup(x => x.GetProfileById(It.IsAny<int>()))
.Returns((int id) => id == 1234 ? new User(1234, "Test", "test@test.com", "test@test.com", "", new List<IReadOnlyUserGroup>(), new int[0], new int[0]) : null);
userServiceMock.Setup(service => service.GetPermissionsForPath(It.IsAny<IUser>(), It.IsAny<string>()))
.Returns(new EntityPermissionSet(123, new EntityPermissionCollection(new[]
{
@@ -54,23 +62,34 @@ namespace Umbraco.Tests.Web.Controllers
var entityService = new Mock<IEntityService>();
entityService.Setup(x => x.GetAllPaths(UmbracoObjectTypes.Document, It.IsAny<int[]>()))
.Returns((UmbracoObjectTypes objType, int[] ids) => ids.Select(x => new TreeEntityPath {Path = $"-1,{x}", Id = x}).ToList());
.Returns((UmbracoObjectTypes objType, int[] ids) => ids.Select(x => new TreeEntityPath { Path = $"-1,{x}", Id = x }).ToList());
var dataTypeService = new Mock<IDataTypeService>();
dataTypeService.Setup(service => service.GetDataType(It.IsAny<int>()))
.Returns(MockedDataType());
.Returns(Mock.Of<IDataType>(type => type.Id == 9876 && type.Name == "text"));
dataTypeService.Setup(service => service.GetDataType(-87)) //the RTE
.Returns(Mock.Of<IDataType>(type => type.Id == -87 && type.Name == "Rich text" && type.Configuration == new RichTextConfiguration()));
var langService = new Mock<ILocalizationService>();
langService.Setup(x => x.GetAllLanguages()).Returns(new[] {
Mock.Of<ILanguage>(x => x.IsoCode == "en-US"),
Mock.Of<ILanguage>(x => x.IsoCode == "es-ES"),
Mock.Of<ILanguage>(x => x.IsoCode == "fr-FR")
});
var textService = new Mock<ILocalizedTextService>();
textService.Setup(x => x.Localize(It.IsAny<string>(), It.IsAny<CultureInfo>(), It.IsAny<IDictionary<string, string>>())).Returns("");
Container.RegisterSingleton(f => Mock.Of<IContentService>());
Container.RegisterSingleton(f => userServiceMock.Object);
Container.RegisterSingleton(f => entityService.Object);
Container.RegisterSingleton(f => dataTypeService.Object);
Container.RegisterSingleton(f => langService.Object);
Container.RegisterSingleton(f => textService.Object);
Container.RegisterSingleton(f => Mock.Of<ICultureDictionaryFactory>());
Container.RegisterSingleton(f => new UmbracoApiControllerTypeCollection(new[] { typeof(ContentTreeController) }));
}
private IDataType MockedDataType()
{
return Mock.Of<IDataType>(type => type.Id == 9876 && type.Name == "text");
}
private MultipartFormDataContent GetMultiPartRequestContent(string json)
{
var multiPartBoundary = "----WebKitFormBoundary123456789";
@@ -89,14 +108,34 @@ namespace Umbraco.Tests.Web.Controllers
};
}
private const string PublishJson1 = @"{
private IContent GetMockedContent()
{
var content = MockedContent.CreateSimpleContent(MockedContentTypes.CreateSimpleContentType());
content.Id = 123;
content.Path = "-1,123";
//ensure things have ids
var ids = 888;
foreach (var g in content.PropertyGroups)
{
g.Id = ids;
ids++;
}
foreach (var p in content.PropertyTypes)
{
p.Id = ids;
ids++;
}
return content;
}
private const string PublishJsonInvariant = @"{
""id"": 123,
""contentTypeAlias"": ""page"",
""parentId"": -1,
""action"": ""save"",
""variants"": [
{
""name"": null,
""name"": ""asdf"",
""properties"": [
{
""id"": 1,
@@ -104,10 +143,34 @@ namespace Umbraco.Tests.Web.Controllers
""value"": ""asdf""
}
],
""culture"": ""en-US""
""culture"": null,
""save"": true,
""publish"": true
}
]
}";
private const string PublishJsonVariant = @"{
""id"": 123,
""contentTypeAlias"": ""page"",
""parentId"": -1,
""action"": ""save"",
""variants"": [
{
""name"": ""asdf"",
""properties"": [
{
""id"": 1,
""alias"": ""title"",
""value"": ""asdf""
}
],
""culture"": ""en-US"",
""save"": true,
""publish"": true
},
{
""name"": null,
""name"": ""asdf"",
""properties"": [
{
""id"": 1,
@@ -115,7 +178,9 @@ namespace Umbraco.Tests.Web.Controllers
""value"": ""asdf""
}
],
""culture"": ""fr-FR""
""culture"": ""fr-FR"",
""save"": true,
""publish"": true
},
{
""name"": ""asdf"",
@@ -142,12 +207,8 @@ namespace Umbraco.Tests.Web.Controllers
{
ApiController Factory(HttpRequestMessage message, UmbracoHelper helper)
{
//var content = MockedContent.CreateSimpleContent(MockedContentTypes.CreateSimpleContentType());
//content.Id = 999999999; //this will not be found
//content.Path = "-1,999999999";
var contentServiceMock = Mock.Get(Current.Services.ContentService);
contentServiceMock.Setup(x => x.GetById(123)).Returns(() => null);
contentServiceMock.Setup(x => x.GetById(123)).Returns(() => null); //do not find it
var publishedSnapshot = Mock.Of<IPublishedSnapshotService>();
var propertyEditorCollection = new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty<DataEditor>()));
@@ -157,7 +218,7 @@ namespace Umbraco.Tests.Web.Controllers
var runner = new TestRunner(Factory);
var response = await runner.Execute("Content", "PostSave", HttpMethod.Post,
content: GetMultiPartRequestContent(PublishJson1),
content: GetMultiPartRequestContent(PublishJsonInvariant),
mediaTypeHeader: new MediaTypeWithQualityHeaderValue("multipart/form-data"),
assertOkResponse: false);
@@ -174,7 +235,7 @@ namespace Umbraco.Tests.Web.Controllers
ApiController Factory(HttpRequestMessage message, UmbracoHelper helper)
{
var contentServiceMock = Mock.Get(Current.Services.ContentService);
contentServiceMock.Setup(x => x.GetById(123)).Returns(() => null);
contentServiceMock.Setup(x => x.GetById(123)).Returns(() => GetMockedContent());
var publishedSnapshot = Mock.Of<IPublishedSnapshotService>();
var propertyEditorCollection = new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty<DataEditor>()));
@@ -182,9 +243,9 @@ namespace Umbraco.Tests.Web.Controllers
return usersController;
}
var json = JsonConvert.DeserializeObject<JObject>(PublishJson1);
var json = JsonConvert.DeserializeObject<JObject>(PublishJsonInvariant);
//remove all save flaggs
((JArray)json["variants"])[2]["save"] = false;
((JArray)json["variants"])[0]["save"] = false;
var runner = new TestRunner(Factory);
var response = await runner.Execute("Content", "PostSave", HttpMethod.Post,
@@ -200,20 +261,52 @@ namespace Umbraco.Tests.Web.Controllers
/// Returns 404 if any of the posted properties dont actually exist
/// </summary>
/// <returns></returns>
[Test, Ignore("Not implemented yet")]
[Test]
public async Task PostSave_Validate_Properties_Exist()
{
//TODO: Make this work! to finish it, we need to include a property in the POST data that doesn't exist on the content type
// or change the content type below to not include one of the posted ones
ApiController Factory(HttpRequestMessage message, UmbracoHelper helper)
{
var contentServiceMock = Mock.Get(Current.Services.ContentService);
contentServiceMock.Setup(x => x.GetById(123)).Returns(() => GetMockedContent());
var publishedSnapshot = Mock.Of<IPublishedSnapshotService>();
var propertyEditorCollection = new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty<DataEditor>()));
var usersController = new ContentController(publishedSnapshot, propertyEditorCollection);
Container.InjectProperties(usersController);
return usersController;
}
var json = JsonConvert.DeserializeObject<JObject>(PublishJsonInvariant);
//add a non-existent property to a variant being saved
var variantProps = (JArray)json["variants"].ElementAt(0)["properties"];
variantProps.Add(JObject.FromObject(new
{
id = 2,
alias = "doesntExist",
value = "hello"
}));
var runner = new TestRunner(Factory);
var response = await runner.Execute("Content", "PostSave", HttpMethod.Post,
content: GetMultiPartRequestContent(JsonConvert.SerializeObject(json)),
mediaTypeHeader: new MediaTypeWithQualityHeaderValue("multipart/form-data"),
assertOkResponse: false);
Assert.AreEqual(HttpStatusCode.NotFound, response.Item1.StatusCode);
}
[Test]
public async Task PostSave_Simple_Invariant()
{
var content = GetMockedContent();
ApiController Factory(HttpRequestMessage message, UmbracoHelper helper)
{
var content = MockedContent.CreateSimpleContent(MockedContentTypes.CreateSimpleContentType());
content.Id = 123;
content.Path = "-1,123";
var contentServiceMock = Mock.Get(Current.Services.ContentService);
contentServiceMock.Setup(x => x.GetById(123)).Returns(() => null);
contentServiceMock.Setup(x => x.GetById(123)).Returns(() => content);
contentServiceMock.Setup(x => x.Save(It.IsAny<IContent>(), It.IsAny<int>(), It.IsAny<bool>()))
.Returns(new OperationResult(OperationResultType.Success, new Core.Events.EventMessages())); //success
var publishedSnapshot = Mock.Of<IPublishedSnapshotService>();
var propertyEditorCollection = new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty<DataEditor>()));
@@ -223,14 +316,92 @@ namespace Umbraco.Tests.Web.Controllers
var runner = new TestRunner(Factory);
var response = await runner.Execute("Content", "PostSave", HttpMethod.Post,
content: GetMultiPartRequestContent(PublishJson1),
content: GetMultiPartRequestContent(PublishJsonInvariant),
mediaTypeHeader: new MediaTypeWithQualityHeaderValue("multipart/form-data"),
assertOkResponse: false);
Assert.AreEqual(HttpStatusCode.NotFound, response.Item1.StatusCode);
//var obj = JsonConvert.DeserializeObject<PagedResult<UserDisplay>>(response.Item2);
//Assert.AreEqual(0, obj.TotalItems);
Assert.AreEqual(HttpStatusCode.OK, response.Item1.StatusCode);
var display = JsonConvert.DeserializeObject<ContentItemDisplay>(response.Item2);
Assert.AreEqual(1, display.Variants.Count());
Assert.AreEqual(content.PropertyGroups.Count(), display.Variants.ElementAt(0).Tabs.Count());
Assert.AreEqual(content.PropertyTypes.Count(), display.Variants.ElementAt(0).Tabs.ElementAt(0).Properties.Count());
}
[Test]
public async Task PostSave_Validate_Empty_Name()
{
var content = GetMockedContent();
ApiController Factory(HttpRequestMessage message, UmbracoHelper helper)
{
var contentServiceMock = Mock.Get(Current.Services.ContentService);
contentServiceMock.Setup(x => x.GetById(123)).Returns(() => content);
contentServiceMock.Setup(x => x.Save(It.IsAny<IContent>(), It.IsAny<int>(), It.IsAny<bool>()))
.Returns(new OperationResult(OperationResultType.Success, new Core.Events.EventMessages())); //success
var publishedSnapshot = Mock.Of<IPublishedSnapshotService>();
var propertyEditorCollection = new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty<DataEditor>()));
var usersController = new ContentController(publishedSnapshot, propertyEditorCollection);
Container.InjectProperties(usersController);
return usersController;
}
//clear out the name
var json = JsonConvert.DeserializeObject<JObject>(PublishJsonInvariant);
json["variants"].ElementAt(0)["name"] = null;
var runner = new TestRunner(Factory);
var response = await runner.Execute("Content", "PostSave", HttpMethod.Post,
content: GetMultiPartRequestContent(JsonConvert.SerializeObject(json)),
mediaTypeHeader: new MediaTypeWithQualityHeaderValue("multipart/form-data"),
assertOkResponse: false);
Assert.AreEqual(HttpStatusCode.BadRequest, response.Item1.StatusCode);
var display = JsonConvert.DeserializeObject<ContentItemDisplay>(response.Item2);
Assert.AreEqual(1, display.Errors.Count());
Assert.IsTrue(display.Errors.ContainsKey("Variants[0].Name"));
//ModelState":{"Variants[0].Name":["Required"]}
}
[Test]
public async Task PostSave_Validate_Variants_Empty_Name()
{
var content = GetMockedContent();
ApiController Factory(HttpRequestMessage message, UmbracoHelper helper)
{
var contentServiceMock = Mock.Get(Current.Services.ContentService);
contentServiceMock.Setup(x => x.GetById(123)).Returns(() => content);
contentServiceMock.Setup(x => x.Save(It.IsAny<IContent>(), It.IsAny<int>(), It.IsAny<bool>()))
.Returns(new OperationResult(OperationResultType.Success, new Core.Events.EventMessages())); //success
var publishedSnapshot = Mock.Of<IPublishedSnapshotService>();
var propertyEditorCollection = new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty<DataEditor>()));
var usersController = new ContentController(publishedSnapshot, propertyEditorCollection);
Container.InjectProperties(usersController);
return usersController;
}
//clear out one of the names
var json = JsonConvert.DeserializeObject<JObject>(PublishJsonVariant);
json["variants"].ElementAt(0)["name"] = null;
var runner = new TestRunner(Factory);
var response = await runner.Execute("Content", "PostSave", HttpMethod.Post,
content: GetMultiPartRequestContent(JsonConvert.SerializeObject(json)),
mediaTypeHeader: new MediaTypeWithQualityHeaderValue("multipart/form-data"),
assertOkResponse: false);
Assert.AreEqual(HttpStatusCode.BadRequest, response.Item1.StatusCode);
var display = JsonConvert.DeserializeObject<ContentItemDisplay>(response.Item2);
Assert.AreEqual(2, display.Errors.Count());
Assert.IsTrue(display.Errors.ContainsKey("Variants[0].Name"));
Assert.IsTrue(display.Errors.ContainsKey("_content_variant_en-US_"));
}
//TODO: There are SOOOOO many more tests we should write - a lot of them to do with validation
}
}
@@ -18,7 +18,7 @@ namespace Umbraco.Tests.Web.Mvc
[Test]
public void ReplaceLineBreaksWithHtmlBreak()
{
var output = _htmlStringUtilities.ReplaceLineBreaksForHtml("<div><h1>hello world</h1><p>hello world\r\nhello world\rhello world\nhello world</p></div>");
var output = _htmlStringUtilities.ReplaceLineBreaksForHtml("<div><h1>hello world</h1><p>hello world\r\nhello world\rhello world\nhello world</p></div>").ToString();
var expected = "<div><h1>hello world</h1><p>hello world<br />hello world<br />hello world<br />hello world</p></div>";
Assert.AreEqual(expected, output);
}
@@ -58,4 +58,4 @@ namespace Umbraco.Tests.Web.Mvc
}
}
}
-1
View File
@@ -1 +0,0 @@
src/common/services/util.service.js
File diff suppressed because one or more lines are too long
+2187 -2187
View File
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<staticContent>
<clientCache cacheControlMode="UseMaxAge" cacheControlMaxAge="7.00:00:00" />
</staticContent>
</system.webServer>
</configuration>
@@ -455,13 +455,28 @@ In the following example you see how to run some custom logic before a step goes
function waitForPendingRerequests() {
var deferred = $q.defer();
var timer = window.setInterval(function(){
var requestsReady = false;
var animationsDone = false;
// check for pending requests both in angular and on the document
if($http.pendingRequests.length === 0 && document.readyState === "complete") {
requestsReady = true;
}
// check for animations. ng-enter and ng-leave are default angular animations.
// Also check for infinite editors animating
if(document.querySelectorAll(".ng-enter, .ng-leave, .umb-editor--animating").length === 0) {
animationsDone = true;
}
if(requestsReady && animationsDone) {
$timeout(function(){
deferred.resolve();
clearInterval(timer);
});
}
}, 50);
return deferred.promise;
}
@@ -25,11 +25,6 @@
$scope.page.hideChangeVariant = infiniteMode ? true : false;
$scope.allowOpen = true;
// add all editors to an editors array to support split view
$scope.editors = [];
$scope.initVariant = initVariant;
$scope.splitViewChanged = splitViewChanged;
function init(content) {
if (infiniteMode) {
@@ -55,17 +50,10 @@
// set first app to active
// We need to track active
$scope.content.apps[0].active = true;
setActiveCulture();
resetVariantFlags();
}
/** This is called when the split view changes based on the umb-variant-content */
function splitViewChanged() {
//send an event downwards
$scope.$broadcast("editors.content.splitViewChanged", { editors: $scope.editors });
}
/**
* This will reset isDirty flags if save is true.
@@ -91,123 +79,12 @@
$scope.content.variants[0].publish = false;
}
}
function countDirtyVariants() {
var count = 0;
for (var i = 0; i < $scope.content.variants.length; i++) {
var v = $scope.content.variants[i];
if (v.isDirty) {
count++;
}
}
return count;
}
/** Returns true if the save/publish dialog should be shown when pressing the button */
function showSaveOrPublishDialog() {
return $scope.content.variants.length > 1;
}
/**
* The content item(s) are loaded into an array and this will set the active content item based on the current culture (query string).
* If the content item is invariant, then only one item exists in the array.
*/
function setActiveCulture() {
// set the active variant
var activeVariant = null;
_.each($scope.content.variants, function (v) {
if (v.language && v.language.culture === $scope.culture) {
v.active = true;
activeVariant = v;
}
else {
v.active = false;
}
});
if (!activeVariant) {
// set the first variant to active
$scope.content.variants[0].active = true;
activeVariant = $scope.content.variants[0];
}
initVariant(activeVariant);
//If there are no editors yet then create one with the current content.
//if there's already a main editor then update it with the current content.
if ($scope.editors.length === 0) {
var editor = {
content: activeVariant
};
$scope.editors.push(editor);
}
else {
//this will mean there is only one
$scope.editors[0].content = activeVariant;
if ($scope.editors.length > 1) {
//now re-sync any other editor content (i.e. if split view is open)
for (var s = 1; s < $scope.editors.length; s++) {
//get the variant from the scope model
var variant = _.find($scope.content.variants, function (v) {
return v.language.culture === $scope.editors[s].content.language.culture;
});
$scope.editors[s].content = initVariant(variant);
}
}
}
}
function initVariant(variant) {
//The model that is assigned to the editor contains the current content variant along
//with a copy of the contentApps. This is required because each editor renders it's own
//header and content apps section and the content apps contains the view for editing content itself
//and we need to assign a view model to the subView so that it is scoped to the current
//editor so that split views work.
//copy the apps from the main model if not assigned yet to the variant
if (!variant.apps) {
variant.apps = angular.copy($scope.content.apps);
}
//if this is a variant has a culture/language than we need to assign the language drop down info
if (variant.language) {
//if the variant list that defines the header drop down isn't assigned to the variant then assign it now
if (!variant.variants) {
variant.variants = _.map($scope.content.variants,
function (v) {
return _.pick(v, "active", "language", "state");
});
}
else {
//merge the scope variants on top of the header variants collection (handy when needing to refresh)
angular.extend(variant.variants,
_.map($scope.content.variants,
function (v) {
return _.pick(v, "active", "language", "state");
}));
}
//ensure the current culture is set as the active one
for (var i = 0; i < variant.variants.length; i++) {
if (variant.variants[i].language.culture === variant.language.culture) {
variant.variants[i].active = true;
}
else {
variant.variants[i].active = false;
}
}
}
//then assign the variant to a view model to the content app
var contentApp = _.find(variant.apps, function (a) {
return a.alias === "content";
});
contentApp.viewModel = variant;
return variant;
}
function bindEvents() {
//bindEvents can be called more than once and we don't want to have multiple bound events
for (var e in evts) {
@@ -249,9 +126,7 @@
init($scope.content);
if (!infiniteMode) {
syncTreeNode($scope.content, true);
}
syncTreeNode($scope.content, $scope.content.path, true);
resetLastListPageNumber($scope.content);
@@ -300,10 +175,12 @@
}
/** Syncs the content item to it's tree node - this occurs on first load and after saving */
function syncTreeNode(content, initialLoad) {
var path = content.path;
function syncTreeNode(content, path, initialLoad) {
if (infiniteMode || !path) {
return;
}
if (!$scope.content.isChildOfListView) {
navigationService.syncTree({ tree: $scope.treeAlias, path: path.split(","), forceReload: initialLoad !== true }).then(function (syncArgs) {
$scope.page.menu.currentNode = syncArgs.node;
@@ -341,9 +218,7 @@
//success
init($scope.content);
if (!infiniteMode) {
syncTreeNode($scope.content);
}
syncTreeNode($scope.content, data.path);
$scope.page.buttonGroupState = "success";
@@ -353,8 +228,7 @@
},
function (err) {
setActiveCulture();
syncTreeNode($scope.content);
syncTreeNode($scope.content, $scope.content.path);
//error
if (err) {
@@ -367,6 +241,19 @@
});
}
function clearNotifications(content) {
if (content.notifications) {
content.notifications = [];
}
if (content.variants) {
for (var i = 0; i < content.variants.length; i++) {
if (content.variants[i].notifications) {
content.variants[i].notifications = [];
}
}
}
}
function resetLastListPageNumber(content) {
// We're using rootScope to store the page number for list views, so if returning to the list
// we can restore the page. If we've moved on to edit a piece of content that's not the list or it's children
@@ -376,6 +263,24 @@
}
}
/**
* Used to clear the dirty state for successfully saved variants when not all variant saving was successful
* @param {any} variants
*/
function clearDirtyState(variants) {
for (var i = 0; i < variants.length; i++) {
var v = variants[i];
if (v.notifications) {
var isSuccess = _.find(v.notifications, function (n) {
return n.type === 3; //this is a success notification
});
if (isSuccess) {
v.isDirty = false;
}
}
}
}
if ($scope.page.isNew) {
$scope.page.loading = true;
@@ -438,9 +343,7 @@
init($scope.content);
if (!infiniteMode) {
syncTreeNode($scope.content);
}
syncTreeNode($scope.content, data.path);
$scope.page.buttonGroupState = "success";
@@ -458,35 +361,40 @@
};
$scope.saveAndPublish = function () {
clearNotifications($scope.content);
// TODO: Add "..." to publish button label if there are more than one variant to publish - currently it just adds the elipses if there's more than 1 variant
if (showSaveOrPublishDialog()) {
//before we launch the dialog we want to execute all client side validations first
if (formHelper.submitForm({ scope: $scope, action: "publish" })) {
var dialog = {
parentScope: $scope,
view: "views/content/overlays/publish.html",
variants: $scope.content.variants, //set a model property for the dialog
skipFormValidation: true, //when submitting the overlay form, skip any client side validation
submitButtonLabel: "Publish",
submit: function (model) {
model.submitButtonState = "busy";
clearNotifications($scope.content);
//we need to return this promise so that the dialog can handle the result and wire up the validation response
return performSave({
saveMethod: contentResource.publish,
action: "publish",
showNotifications: false
}).then(function (data) {
//show all notifications manually here since we disabled showing them automatically in the save method
formHelper.showNotifications(data);
clearNotifications($scope.content);
overlayService.close();
return $q.when(data);
},
function (err) {
clearDirtyState($scope.content.variants);
model.submitButtonState = "error";
//re-map the dialog model since we've re-bound the properties
dialog.variants = $scope.content.variants;
return $q.reject(err);
//don't reject, we've handled the error
return $q.when(err);
});
},
close: function (oldModel) {
@@ -505,35 +413,40 @@
};
$scope.save = function () {
clearNotifications($scope.content);
// TODO: Add "..." to save button label if there are more than one variant to publish - currently it just adds the elipses if there's more than 1 variant
if (showSaveOrPublishDialog()) {
//before we launch the dialog we want to execute all client side validations first
if (formHelper.submitForm({ scope: $scope, action: "save" })) {
var dialog = {
parentScope: $scope,
view: "views/content/overlays/save.html",
variants: $scope.content.variants, //set a model property for the dialog
skipFormValidation: true, //when submitting the overlay form, skip any client side validation
submitButtonLabel: "Save",
submit: function (model) {
model.submitButtonState = "busy";
clearNotifications($scope.content);
//we need to return this promise so that the dialog can handle the result and wire up the validation response
return performSave({
saveMethod: $scope.saveMethod(),
action: "save",
showNotifications: false
}).then(function (data) {
//show all notifications manually here since we disabled showing them automatically in the save method
formHelper.showNotifications(data);
clearNotifications($scope.content);
overlayService.close();
return $q.when(data);
},
function (err) {
clearDirtyState($scope.content.variants);
model.submitButtonState = "error";
//re-map the dialog model since we've re-bound the properties
dialog.variants = $scope.content.variants;
return $q.reject(err);
//don't reject, we've handled the error
return $q.when(err);
});
},
close: function (oldModel) {
@@ -576,10 +489,6 @@
}
};
$scope.backToListView = function () {
$location.path($scope.page.listViewPath);
};
$scope.restore = function (content) {
$scope.page.buttonRestore = "busy";
@@ -685,12 +594,6 @@
}
};
$scope.$watch('culture', function (newVal, oldVal) {
if (newVal !== oldVal) {
setActiveCulture();
}
});
//ensure to unregister from all events!
$scope.$on('$destroy', function () {
for (var e in evts) {
@@ -13,7 +13,7 @@
scope.disableTemplates = Umbraco.Sys.ServerVariables.features.disabledFeatures.disableTemplates;
scope.allowChangeDocumentType = false;
scope.allowChangeTemplate = false;
function onInit() {
userService.getCurrentUser().then(function(user){
@@ -71,10 +71,11 @@
// make sure dates are formatted to the user's locale
formatDatesToLocal();
// Declare a fallback URL for the <umb-node-preview/> directive
scope.previewOpenUrl = '#/settings/documenttypes/edit/' + scope.documentType.id;
// Declare a fallback URL for the <umb-node-preview/> directive
if (scope.documentType !== null) {
scope.previewOpenUrl = '#/settings/documenttypes/edit/' + scope.documentType.id;
}
}
scope.auditTrailPageChange = function (pageNumber) {
@@ -142,7 +143,7 @@
item.timestampFormatted = dateHelper.getLocalDate(item.timestamp, currentUser.locale, 'LLL');
});
});
scope.auditTrail = data.items;
scope.auditTrailOptions.pageNumber = data.pageNumber;
scope.auditTrailOptions.pageSize = data.pageSize;
@@ -150,7 +151,7 @@
scope.auditTrailOptions.totalPages = data.totalPages;
setAuditTrailLogTypeColor(scope.auditTrail);
scope.loadingAuditTrail = false;
});
@@ -158,6 +159,7 @@
function setAuditTrailLogTypeColor(auditTrail) {
angular.forEach(auditTrail, function (item) {
switch (item.logType) {
case "Publish":
item.logTypeColor = "success";
@@ -286,7 +288,7 @@
eventsService.emit("editors.content.changeUnpublishDate", args);
}
function ucfirst(string) {
return string.charAt(0).toUpperCase() + string.slice(1);
}
@@ -295,13 +297,13 @@
// get current backoffice user and format dates
userService.getCurrentUser().then(function (currentUser) {
scope.node.createDateFormatted = dateHelper.getLocalDate(scope.node.createDate, currentUser.locale, 'LLL');
scope.node.releaseDateYear = scope.node.releaseDate ? ucfirst(dateHelper.getLocalDate(scope.node.releaseDate, currentUser.locale, 'YYYY')) : null;
scope.node.releaseDateMonth = scope.node.releaseDate ? ucfirst(dateHelper.getLocalDate(scope.node.releaseDate, currentUser.locale, 'MMMM')) : null;
scope.node.releaseDateDayNumber = scope.node.releaseDate ? ucfirst(dateHelper.getLocalDate(scope.node.releaseDate, currentUser.locale, 'DD')) : null;
scope.node.releaseDateDay = scope.node.releaseDate ? ucfirst(dateHelper.getLocalDate(scope.node.releaseDate, currentUser.locale, 'dddd')) : null;
scope.node.releaseDateTime = scope.node.releaseDate ? ucfirst(dateHelper.getLocalDate(scope.node.releaseDate, currentUser.locale, 'HH:mm')) : null;
scope.node.removeDateYear = scope.node.removeDate ? ucfirst(dateHelper.getLocalDate(scope.node.removeDate, currentUser.locale, 'YYYY')) : null;
scope.node.removeDateMonth = scope.node.removeDate ? ucfirst(dateHelper.getLocalDate(scope.node.removeDate, currentUser.locale, 'MMMM')) : null;
scope.node.removeDateDayNumber = scope.node.removeDate ? ucfirst(dateHelper.getLocalDate(scope.node.removeDate, currentUser.locale, 'DD')) : null;
@@ -326,8 +328,8 @@
scope.$watch('node.updateDate', function(newValue, oldValue){
if(!newValue) { return; }
if(newValue === oldValue) { return; }
if(newValue === oldValue) { return; }
if(isInfoTab) {
loadAuditTrail();
formatDatesToLocal();
@@ -2,133 +2,79 @@
'use strict';
/**
* A directive to encapsulate each variant editor which includes the name header and all content apps for a given variant
* @param {any} $timeout
* @param {any} $location
* A component to encapsulate each variant editor which includes the name header and all content apps for a given variant
*/
function variantContentDirective($timeout, $location) {
var umbVariantContent = {
templateUrl: 'views/components/content/umb-variant-content.html',
bindings: {
content: "<",
page: "<",
editor: "<",
editorIndex: "<",
editorCount: "<",
onCloseSplitView: "&",
onSelectVariant: "&",
onOpenSplitView: "&"
},
controllerAs: 'vm',
controller: umbVariantContentController
};
function umbVariantContentController($scope, $element, $location) {
var directive = {
restrict: 'E',
replace: true,
templateUrl: 'views/components/content/umb-variant-content.html',
link: function (scope) {
var unsubscribe = [];
/**
* Adds a new editor to the editors array to show content in a split view
* @param {any} selectedVariant
*/
scope.openInSplitView = function (selectedVariant) {
var vm = this;
var selectedCulture = selectedVariant.language.culture;
vm.$postLink = postLink;
vm.$onDestroy = onDestroy;
//only the content app can be selected since no other apps are shown, and because we copy all of these apps
//to the "editors" we need to update this across all editors
for (var e = 0; e < scope.editors.length; e++) {
var editor = scope.editors[e];
for (var i = 0; i < editor.content.apps.length; i++) {
var app = editor.content.apps[i];
if (app.alias === "content") {
app.active = true;
}
else {
app.active = false;
}
}
vm.selectVariant = selectVariant;
vm.openSplitView = openSplitView;
vm.backToListView = backToListView;
/** Called when the component has linked all elements, this is when the form controller is available */
function postLink() {
//set the content to dirty if the header changes
unsubscribe.push($scope.$watch("contentHeaderForm.$dirty",
function(newValue, oldValue) {
if (newValue === true) {
vm.editor.content.isDirty = true;
}
//Find the whole variant model based on the culture that was chosen
var variant = _.find(scope.content.variants, function (v) {
return v.language.culture === selectedCulture;
});
var editor = {
content: scope.initVariant({ variant: variant})
};
scope.editors.push(editor);
//TODO: hacking animation states - these should hopefully be easier to do when we upgrade angular
editor.collapsed = true;
editor.loading = true;
$timeout(function () {
editor.collapsed = false;
editor.loading = false;
scope.onSplitViewChanged();
}, 100);
};
/**
* Changes the currently selected variant
* @param {any} variantDropDownItem
*/
scope.selectVariant = function (variantDropDownItem) {
var editorIndex = _.findIndex(scope.editors, function (e) {
return e === scope.editor;
});
//if the editor index is zero, then update the query string to track the lang selection, otherwise if it's part
//of a 2nd split view editor then update the model directly.
if (editorIndex === 0) {
//if we've made it this far, then update the query string
$location.search("cculture", variantDropDownItem.language.culture);
}
else {
//set all variant drop down items as inactive for this editor and then set the selected on as active
for (var i = 0; i < scope.editor.content.variants.length; i++) {
scope.editor.content.variants[i].active = false;
}
variantDropDownItem.active = true;
//get the variant content model and initialize the editor with that
var variant = _.find(scope.content.variants, function (v) {
return v.language.culture === variantDropDownItem.language.culture;
});
scope.editor.content = scope.initVariant({ variant: variant });
}
};
/** Closes the split view */
scope.closeSplitView = function () {
//TODO: hacking animation states - these should hopefully be easier to do when we upgrade angular
scope.editor.loading = true;
scope.editor.collapsed = true;
$timeout(function () {
var index = _.findIndex(scope.editors, function(e) {
return e === scope.editor;
});
scope.editors.splice(index, 1);
scope.onSplitViewChanged();
}, 400);
};
//set the content to dirty if the header changes
scope.$watch("contentHeaderForm.$dirty",
function (newValue, oldValue) {
if (newValue === true) {
scope.editor.content.isDirty = true;
}
});
},
scope: {
//TODO: This should be turned into a proper component
page: "=",
content: "=",
editor: "=",
editors: "=",
//TODO: I don't like having this callback defined and would like to make this directive a bit less
// coupled but right now don't have time
initVariant: "&",
onSplitViewChanged: "&"
}));
}
function onDestroy() {
for (var i = 0; i < unsubscribe.length; i++) {
unsubscribe[i]();
}
}
function backToListView() {
$location.path(vm.page.listViewPath);
};
return directive;
/**
* Used to proxy a callback
* @param {any} variant
*/
function selectVariant(variant) {
if (vm.onSelectVariant) {
vm.onSelectVariant({ "variant": variant });
}
}
/**
* Used to proxy a callback
* @param {any} variant
*/
function openSplitView(variant) {
if (vm.onOpenSplitView) {
vm.onOpenSplitView({ "variant": variant });
}
}
}
angular.module('umbraco.directives').directive('umbVariantContent', variantContentDirective);
angular.module('umbraco.directives').component('umbVariantContent', umbVariantContent);
})();
@@ -0,0 +1,280 @@
(function () {
'use strict';
/**
* A component for split view content editing
*/
var umbVariantContentEditors = {
templateUrl: 'views/components/content/umb-variant-content-editors.html',
bindings: {
page: "<",
content: "<", //TODO: Not sure if this should be = since we are changing the 'active' property of a variant
culture: "<"
},
controllerAs: 'vm',
controller: umbVariantContentEditorsController
};
function umbVariantContentEditorsController($scope, $element, $location, $timeout) {
var prevContentDateUpdated = null;
var vm = this;
vm.$onInit = onInit;
vm.$onChanges = onChanges;
vm.$doCheck = doCheck;
vm.$postLink = postLink;
vm.openSplitView = openSplitView;
vm.closeSplitView = closeSplitView;
vm.selectVariant = selectVariant;
//Used to track how many content views there are (for split view there will be 2, it could support more in theory)
vm.editors = [];
/** Called when the component initializes */
function onInit() {
prevContentDateUpdated = angular.copy(vm.content.updateDate);
setActiveCulture();
}
/** Called when the component has linked all elements, this is when the form controller is available */
function postLink() {
}
/**
* Watch for model changes
* @param {any} changes
*/
function onChanges(changes) {
if (changes.culture && !changes.culture.isFirstChange() && changes.culture.currentValue !== changes.culture.previousValue) {
setActiveCulture();
}
}
/** Allows us to deep watch whatever we want - executes on every digest cycle */
function doCheck() {
if (!angular.equals(vm.content.updateDate, prevContentDateUpdated)) {
setActiveCulture();
prevContentDateUpdated = angular.copy(vm.content.updateDate);
}
}
/** This is called when the split view changes based on the umb-variant-content */
function splitViewChanged() {
//send an event downwards
$scope.$broadcast("editors.content.splitViewChanged", { editors: vm.editors });
}
/**
* Set the active variant based on the current culture (query string)
*/
function setActiveCulture() {
// set the active variant
var activeVariant = null;
_.each(vm.content.variants, function (v) {
if (v.language && v.language.culture === vm.culture) {
v.active = true;
activeVariant = v;
}
else {
v.active = false;
}
});
if (!activeVariant) {
// Set the first variant to active if we can't find it.
// If the content item is invariant, then only one item exists in the array.
vm.content.variants[0].active = true;
activeVariant = vm.content.variants[0];
}
insertVariantEditor(0, initVariant(activeVariant));
if (vm.editors.length > 1) {
//now re-sync any other editor content (i.e. if split view is open)
for (var s = 1; s < vm.editors.length; s++) {
//get the variant from the scope model
var variant = _.find(vm.content.variants, function (v) {
return v.language.culture === vm.editors[s].content.language.culture;
});
vm.editors[s].content = initVariant(variant);
}
}
}
/**
* Updates the editors collection for a given index for the specified variant
* @param {any} index
* @param {any} variant
*/
function insertVariantEditor(index, variant) {
var variantCulture = variant.language ? variant.language.culture : "invariant";
//check if the culture at the index is the same, if it's null an editor will be added
var currentCulture = vm.editors.length === 0 || vm.editors.length <= index ? null : vm.editors[index].culture;
if (currentCulture !== variantCulture) {
//Not the current culture which means we need to modify the array.
//NOTE: It is not good enough to just replace the `content` object at a given index in the array
// since that would mean that directives are not re-initialized.
vm.editors.splice(index, 1, {
content: variant,
//used for "track-by" ng-repeat
culture: variantCulture
});
}
else {
//replace the editor for the same culture
vm.editors[index].content = variant;
}
}
function initVariant(variant) {
//The model that is assigned to the editor contains the current content variant along
//with a copy of the contentApps. This is required because each editor renders it's own
//header and content apps section and the content apps contains the view for editing content itself
//and we need to assign a view model to the subView so that it is scoped to the current
//editor so that split views work.
//copy the apps from the main model if not assigned yet to the variant
if (!variant.apps) {
variant.apps = angular.copy(vm.content.apps);
}
//if this is a variant has a culture/language than we need to assign the language drop down info
if (variant.language) {
//if the variant list that defines the header drop down isn't assigned to the variant then assign it now
if (!variant.variants) {
variant.variants = _.map(vm.content.variants,
function (v) {
return _.pick(v, "active", "language", "state");
});
}
else {
//merge the scope variants on top of the header variants collection (handy when needing to refresh)
angular.extend(variant.variants,
_.map(vm.content.variants,
function (v) {
return _.pick(v, "active", "language", "state");
}));
}
//ensure the current culture is set as the active one
for (var i = 0; i < variant.variants.length; i++) {
if (variant.variants[i].language.culture === variant.language.culture) {
variant.variants[i].active = true;
}
else {
variant.variants[i].active = false;
}
}
}
//then assign the variant to a view model to the content app
var contentApp = _.find(variant.apps, function (a) {
return a.alias === "content";
});
contentApp.viewModel = variant;
return variant;
}
/**
* Adds a new editor to the editors array to show content in a split view
* @param {any} selectedVariant
*/
function openSplitView(selectedVariant) {
var selectedCulture = selectedVariant.language.culture;
//only the content app can be selected since no other apps are shown, and because we copy all of these apps
//to the "editors" we need to update this across all editors
for (var e = 0; e < vm.editors.length; e++) {
var editor = vm.editors[e];
for (var i = 0; i < editor.content.apps.length; i++) {
var app = editor.content.apps[i];
if (app.alias === "content") {
app.active = true;
}
else {
app.active = false;
}
}
}
//Find the whole variant model based on the culture that was chosen
var variant = _.find(vm.content.variants, function (v) {
return v.language.culture === selectedCulture;
});
insertVariantEditor(vm.editors.length, initVariant(variant));
//TODO: hacking animation states - these should hopefully be easier to do when we upgrade angular
editor.collapsed = true;
editor.loading = true;
$timeout(function () {
editor.collapsed = false;
editor.loading = false;
splitViewChanged();
}, 100);
}
/** Closes the split view */
function closeSplitView(editorIndex) {
//TODO: hacking animation states - these should hopefully be easier to do when we upgrade angular
var editor = vm.editors[editorIndex];
editor.loading = true;
editor.collapsed = true;
$timeout(function () {
vm.editors.splice(editorIndex, 1);
splitViewChanged();
}, 400);
}
/**
* Changes the currently selected variant
* @param {any} variant This is the model of the variant/language drop down item in the editor header
* @param {any} editorIndex The index of the editor being changed
*/
function selectVariant(variant, editorIndex) {
var variantCulture = variant.language ? variant.language.culture : "invariant";
//if the editor index is zero, then update the query string to track the lang selection, otherwise if it's part
//of a 2nd split view editor then update the model directly.
if (editorIndex === 0) {
//If we've made it this far, then update the query string.
//The editor will respond to this query string changing.
$location.search("cculture", variant.language.culture);
}
else {
//Update the 'active' variant for this editor
var editor = vm.editors[editorIndex];
//set all variant drop down items as inactive for this editor and then set the selected one as active
for (var i = 0; i < editor.content.variants.length; i++) {
editor.content.variants[i].active = false;
}
variant.active = true;
//get the variant content model and initialize the editor with that
var contentVariant = _.find(vm.content.variants,
function (v) {
return v.language.culture === variant.language.culture;
});
editor.content = initVariant(contentVariant);
//update the editors collection
insertVariantEditor(editorIndex, contentVariant);
}
}
}
angular.module('umbraco.directives').component('umbVariantContentEditors', umbVariantContentEditors);
})();
@@ -209,6 +209,13 @@ Use this directive to construct a header inside the main editor window.
function link(scope, el, attr, ctrl) {
if (!scope.serverValidationNameField) {
scope.serverValidationNameField = "Name";
}
if (!scope.serverValidationAliasField) {
scope.serverValidationAliasField = "Alias";
}
scope.vm = {};
scope.vm.dropdownOpen = false;
scope.vm.currentVariant = "";
@@ -324,7 +331,9 @@ Use this directive to construct a header inside the main editor window.
splitViewOpen: "=?",
onOpenInSplitView: "&?",
onCloseSplitView: "&?",
onSelectVariant: "&?"
onSelectVariant: "&?",
serverValidationNameField: "@?",
serverValidationAliasField: "@?"
},
link: link
};
@@ -22,8 +22,10 @@
// get document type details
scope.mediaType = scope.node.contentType;
// get node url
scope.nodeUrl = scope.node.mediaLink;
// set the media link initially
setMediaLink();
// make sure dates are formatted to the user's locale
formatDatesToLocal();
}
@@ -36,6 +38,10 @@
});
}
function setMediaLink(){
scope.nodeUrl = scope.node.mediaLink;
}
scope.openMediaType = function (mediaType) {
var editor = {
id: mediaType.id,
@@ -48,11 +54,16 @@
};
editorService.mediaTypeEditor(editor);
};
// watch for content updates - reload content when node is saved, published etc.
scope.$watch('node.updateDate', function(newValue, oldValue){
if(!newValue) { return; }
if(newValue === oldValue) { return; }
// Update the media link
setMediaLink();
// Update the create and update dates
formatDatesToLocal();
});
@@ -64,7 +75,6 @@
});
onInit();
}
var directive = {
@@ -412,7 +412,7 @@ Opens an overlay to show a custom YSOD. </br>
(function() {
'use strict';
function OverlayDirective($timeout, formHelper, overlayHelper, localizationService, $q) {
function OverlayDirective($timeout, formHelper, overlayHelper, localizationService, $q, $templateCache, $http, $compile) {
function link(scope, el, attr, ctrl) {
@@ -424,7 +424,8 @@ Opens an overlay to show a custom YSOD. </br>
var numberOfOverlays = 0;
var isRegistered = false;
var modelCopy = {};
var modelCopy = {};
var unsubscribe = [];
function activate() {
@@ -459,6 +460,21 @@ Opens an overlay to show a custom YSOD. </br>
scope.view = "views/common/overlays/" + viewAlias + "/" + viewAlias + ".html";
}
//if a custom parent scope is defined then we need to manually compile the view
if (scope.parentScope) {
var element = el.find(".scoped-view");
$http.get(scope.view, { cache: $templateCache })
.then(function (response) {
var templateScope = scope.parentScope.$new();
unsubscribe.push(function() {
templateScope.$destroy();
});
templateScope.model = scope.model;
element.html(response.data);
element.show();
$compile(element.contents())(templateScope);
});
}
}
}
@@ -553,7 +569,7 @@ Opens an overlay to show a custom YSOD. </br>
var newObject = {};
for (var key in object) {
if (key !== "event") {
if (key !== "event" && key !== "parentScope") {
newObject[key] = angular.copy(object[key]);
}
}
@@ -652,14 +668,14 @@ Opens an overlay to show a custom YSOD. </br>
$q.when(scope.model.submit(model, modelCopy, scope.directive.enableConfirmButton)).then(
function() {
formHelper.resetForm({ scope: scope });
}, angular.noop);
});
} else {
unregisterOverlay();
//wrap in a when since we don't know if this is a promise or not
$q.when(scope.model.submit(model, modelCopy, scope.directive.enableConfirmButton)).then(
function() {
formHelper.resetForm({ scope: scope });
}, angular.noop);
});
}
}
@@ -684,8 +700,11 @@ Opens an overlay to show a custom YSOD. </br>
};
scope.$on('$destroy', function(){
unregisterOverlay();
unsubscribe.push(unregisterOverlay);
scope.$on('$destroy', function () {
for (var i = 0; i < unsubscribe.length; i++) {
unsubscribe[i]();
}
});
activate();
@@ -701,7 +720,8 @@ Opens an overlay to show a custom YSOD. </br>
ngShow: "=",
model: "=",
view: "=",
position: "@"
position: "@",
parentScope: "=?"
},
link: link
};
@@ -58,9 +58,13 @@
entityResource.getPagedChildren(miniListView.node.id, scope.entityType, miniListView.pagination)
.then(function (data) {
// update children
miniListView.children = data.items;
_.each(miniListView.children, function(c) {
// child allowed by default
c.allowed = true;
// convert legacy icon for node
if(c.icon) {
c.icon = iconHelper.convertFromLegacyIcon(c.icon);
@@ -72,6 +76,17 @@
c.published = c.metaData.IsPublished;
}
}
// filter items if there is a filter and it's not advanced
// ** ignores advanced filter at the moment
if (scope.entityTypeFilter && !scope.entityTypeFilter.filterAdvanced) {
var a = scope.entityTypeFilter.filter.toLowerCase().replace(/\s/g, '').split(',');
var found = a.indexOf(c.metaData.ContentTypeAlias.toLowerCase()) >= 0;
if (!scope.entityTypeFilter.filterExclude && !found || scope.entityTypeFilter.filterExclude && found) {
c.allowed = false;
}
}
});
// update pagination
miniListView.pagination.totalItems = data.totalItems;
@@ -87,7 +102,7 @@
};
scope.selectNode = function(node) {
if(scope.onSelect) {
if (scope.onSelect && node.allowed) {
scope.onSelect({'node': node});
}
};
@@ -184,7 +199,8 @@
entityType: "@",
startNodeId: "=",
onSelect: "&",
onClose: "&"
onClose: "&",
entityTypeFilter: "="
},
link: link
};
@@ -50,6 +50,11 @@ Use this directive make an element sticky and follow the page when scrolling.
function activate() {
if (bar.parents(".umb-property").length > 1) {
bar.addClass("nested");
return;
}
if (attr.scrollableContainer) {
scrollableContainer = $(attr.scrollableContainer);
} else {
@@ -0,0 +1,10 @@
angular.module("umbraco.directives")
.directive('umbIsolateForm', function () {
return {
restrict: 'A',
require: ['form', '^form'],
link: function (scope, element, attrs, forms) {
forms[1].$removeControl(forms[0]);
}
}
});
@@ -3,16 +3,20 @@
function showValidationOnSubmit(serverValidationManager) {
return {
require: "ngMessages",
require: ["ngMessages", "^^?valFormManager"],
restrict: "A",
scope: {
form: "=?"
},
link: function (scope, element, attr, ctrl) {
//We can either get the form submitted status by the parent directive valFormManager (if we add a property to it)
//or we can just check upwards in the DOM for the css class (easier for now).
var formMgr = ctrl.length > 1 ? ctrl[1] : null;
//We can either get the form submitted status by the parent directive valFormManager
//or we can check upwards in the DOM for the css class... lets try both :)
//The initial hidden state can't always be hidden because when we switch variants in the content editor we cannot
//reset the status.
var submitted = element.closest(".show-validation").length > 0;
var submitted = element.closest(".show-validation").length > 0 || (formMgr && formMgr.showValidation);
if (!submitted) {
element.hide();
}
@@ -19,7 +19,7 @@ function valFormManager(serverValidationManager, $rootScope, $timeout, $location
var SAVED_EVENT_NAME = "formSubmitted";
return {
require: "form",
require: ["form", "^^?valFormManager"],
restrict: "A",
controller: function($scope) {
//This exposes an API for direct use with this directive
@@ -35,6 +35,8 @@ function valFormManager(serverValidationManager, $rootScope, $timeout, $location
}));
};
this.showValidation = $scope.showValidation === true;
//Ensure to remove the event handlers when this instance is destroyted
$scope.$on('$destroy', function () {
for (var u in unsubscribe) {
@@ -42,7 +44,10 @@ function valFormManager(serverValidationManager, $rootScope, $timeout, $location
}
});
},
link: function (scope, element, attr, formCtrl) {
link: function (scope, element, attr, ctrls) {
var formCtrl = ctrls[0];
var parentFormMgr = ctrls.length > 0 ? ctrls[1] : null;
var labels = {};
@@ -96,8 +101,9 @@ function valFormManager(serverValidationManager, $rootScope, $timeout, $location
var isSavingNewItem = false;
//we should show validation if there are any msgs in the server validation collection
if (serverValidationManager.items.length > 0) {
if (serverValidationManager.items.length > 0 || (parentFormMgr && parentFormMgr.showValidation)) {
element.addClass(SHOW_VALIDATION_CLASS_NAME);
scope.showValidation = true;
}
var unsubscribe = [];
@@ -105,7 +111,7 @@ function valFormManager(serverValidationManager, $rootScope, $timeout, $location
//listen for the forms saving event
unsubscribe.push(scope.$on(SAVING_EVENT_NAME, function(ev, args) {
element.addClass(SHOW_VALIDATION_CLASS_NAME);
scope.showValidation = true;
//set the flag so we can check to see if we should display the error.
isSavingNewItem = $routeParams.create;
}));
@@ -114,7 +120,7 @@ function valFormManager(serverValidationManager, $rootScope, $timeout, $location
unsubscribe.push(scope.$on(SAVED_EVENT_NAME, function(ev, args) {
//remove validation class
element.removeClass(SHOW_VALIDATION_CLASS_NAME);
scope.showValidation = false;
//clear form state as at this point we retrieve new data from the server
//and all validation will have cleared at this point
formCtrl.$setPristine();
@@ -26,12 +26,14 @@
function contentResource($q, $http, umbDataFormatter, umbRequestHelper) {
/** internal method process the saving of data and post processing the result */
function saveContentItem(content, action, files, restApiUrl) {
function saveContentItem(content, action, files, restApiUrl, showNotifications) {
return umbRequestHelper.postSaveContent({
restApiUrl: restApiUrl,
content: content,
action: action,
files: files,
showNotifications: showNotifications,
dataFormatter: function (c, a) {
return umbDataFormatter.formatContentPostData(c, a);
}
@@ -632,22 +634,23 @@ function contentResource($q, $http, umbDataFormatter, umbRequestHelper) {
*
* @param {Object} content The content item object with changes applied
* @param {Bool} isNew set to true to create a new item or to update an existing
* @param {Array} files collection of files for the document
* @param {Array} files collection of files for the document
* @param {Bool} showNotifications an option to disable/show notifications (default is true)
* @returns {Promise} resourcePromise object containing the saved content item.
*
*/
save: function (content, isNew, files) {
save: function (content, isNew, files, showNotifications) {
var endpoint = umbRequestHelper.getApiUrl(
"contentApiBaseUrl",
"PostSave");
return saveContentItem(content, "save" + (isNew ? "New" : ""), files, endpoint);
return saveContentItem(content, "save" + (isNew ? "New" : ""), files, endpoint, showNotifications);
},
saveBlueprint: function (content, isNew, files) {
saveBlueprint: function (content, isNew, files, showNotifications) {
var endpoint = umbRequestHelper.getApiUrl(
"contentApiBaseUrl",
"PostSaveBlueprint");
return saveContentItem(content, "save" + (isNew ? "New" : ""), files, endpoint);
return saveContentItem(content, "save" + (isNew ? "New" : ""), files, endpoint, showNotifications);
},
/**
@@ -674,15 +677,16 @@ function contentResource($q, $http, umbDataFormatter, umbRequestHelper) {
*
* @param {Object} content The content item object with changes applied
* @param {Bool} isNew set to true to create a new item or to update an existing
* @param {Array} files collection of files for the document
* @param {Array} files collection of files for the document
* @param {Bool} showNotifications an option to disable/show notifications (default is true)
* @returns {Promise} resourcePromise object containing the saved content item.
*
*/
publish: function (content, isNew, files) {
publish: function (content, isNew, files, showNotifications) {
var endpoint = umbRequestHelper.getApiUrl(
"contentApiBaseUrl",
"PostSave");
return saveContentItem(content, "publish" + (isNew ? "New" : ""), files, endpoint);
return saveContentItem(content, "publish" + (isNew ? "New" : ""), files, endpoint, showNotifications);
},
@@ -298,10 +298,10 @@ function contentTypeResource($q, $http, umbRequestHelper, umbDataFormatter, loca
},
createCollection: function (parentId, collectionName, collectionItemName, collectionIcon, collectionItemIcon) {
createCollection: function (parentId, collectionName, collectionCreateTemplate, collectionItemName, collectionItemCreateTemplate, collectionIcon, collectionItemIcon) {
return umbRequestHelper.resourcePromise(
$http.post(umbRequestHelper.getApiUrl("contentTypeApiBaseUrl", "PostCreateCollection", { parentId: parentId, collectionName: collectionName, collectionItemName: collectionItemName, collectionIcon: collectionIcon, collectionItemIcon: collectionItemIcon })),
$http.post(umbRequestHelper.getApiUrl("contentTypeApiBaseUrl", "PostCreateCollection", { parentId: parentId, collectionName: collectionName, collectionCreateTemplate: collectionCreateTemplate, collectionItemName: collectionItemName, collectionItemCreateTemplate: collectionItemCreateTemplate, collectionIcon: collectionIcon, collectionItemIcon: collectionItemIcon})),
'Failed to create collection under ' + parentId);
},
@@ -66,7 +66,7 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, notifica
args.scope.busy = true;
return args.saveMethod(args.content, $routeParams.create, fileManager.getFiles())
return args.saveMethod(args.content, $routeParams.create, fileManager.getFiles(), args.showNotifications)
.then(function (data) {
formHelper.resetForm({ scope: args.scope });
@@ -262,7 +262,7 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, notifica
// if save button is alread the default don't change it just update the label
if (buttons.defaultButton && buttons.defaultButton.letter === "A") {
buttons.defaultButton.labelKey = "buttons_saveAndSchedule";
return;
return buttons;
}
if (buttons.defaultButton && buttons.subButtons && buttons.subButtons.length > 0) {
@@ -439,8 +439,7 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, notifica
var shouldIgnore = function (propName) {
return _.some([
"variants",
"notifications",
"ModelState",
"tabs",
"properties",
"apps",
@@ -599,8 +598,8 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, notifica
//add model state errors to notifications
if (args.showNotifications) {
for (var e in modelState) {
notificationsService.error("Validation", modelState[e][0]);
for (var e in args.err.data.ModelState) {
notificationsService.error("Validation", args.err.data.ModelState[e][0]);
}
}
@@ -761,13 +761,13 @@ function tinyMceService($log, imageHelper, $http, $timeout, macroResource, macro
* @param {string} input the string to parse
*/
getAnchorNames: function (input) {
var anchors = [];
if (!input) {
return anchors;
}
var anchors = [];
if (!input) {
return anchors;
}
var anchorPattern = /<a id=\\"(.*?)\\">/gi;
var matches = input.match(anchorPattern);
var matches = input.match(anchorPattern);
if (matches) {
@@ -776,7 +776,9 @@ function tinyMceService($log, imageHelper, $http, $timeout, macroResource, macro
});
}
return anchors;
return anchors.filter(function(val, i, self) {
return self.indexOf(val) === i;
});
},
insertLinkInEditor: function (editor, target, anchorElm) {
@@ -136,8 +136,8 @@ function umbRequestHelper($http, $q, umbDataFormatter, angularHelper, dialogServ
//create the callbacs based on whats been passed in.
var callbacks = {
success: ((!opts || !opts.success) ? defaultSuccess : opts.success),
error: ((!opts || !opts.error) ? defaultError : opts.error)
success: (!opts || !opts.success) ? defaultSuccess : opts.success,
error: (!opts || !opts.error ? defaultError : opts.error)
};
return httpPromise.then(function (response) {
@@ -156,7 +156,7 @@ function umbRequestHelper($http, $q, umbDataFormatter, angularHelper, dialogServ
//this is a JS/angular error that we should deal with
return $q.reject({
errorMsg: response.message
})
});
}
//invoke the callback
@@ -188,12 +188,22 @@ function umbRequestHelper($http, $q, umbDataFormatter, angularHelper, dialogServ
errorMsg: result.errorMsg,
data: result.data,
status: result.status
})
});
});
},
/** Used for saving content/media/members specifically */
/**
* @ngdoc method
* @name umbraco.resources.contentResource#postSaveContent
* @methodOf umbraco.resources.contentResource
*
* @description
* Used for saving content/media/members specifically
*
* @param {Object} args arguments object
* @returns {Promise} http promise object.
*/
postSaveContent: function (args) {
if (!args.restApiUrl) {
@@ -211,6 +221,9 @@ function umbRequestHelper($http, $q, umbDataFormatter, angularHelper, dialogServ
if (!args.dataFormatter) {
throw "args.dataFormatter is a required argument";
}
if (args.showNotifications === null || args.showNotifications === undefined) {
args.showNotifications = true;
}
//save the active tab id so we can set it when the data is returned.
var activeTab = _.find(args.content.tabs, function (item) {
@@ -246,7 +259,9 @@ function umbRequestHelper($http, $q, umbDataFormatter, angularHelper, dialogServ
response.data.tabs[activeTabIndex].active = true;
}
formHelper.showNotifications(response.data);
if (args.showNotifications) {
formHelper.showNotifications(response.data);
}
//TODO: Do we need to pass the result through umbDataFormatter.formatContentGetData? Right now things work so not sure but we should check
@@ -278,7 +293,7 @@ function umbRequestHelper($http, $q, umbDataFormatter, angularHelper, dialogServ
}
}
else {
else if (args.showNotifications) {
formHelper.showNotifications(response.data);
}
@@ -8,7 +8,8 @@
{ "value": 0, "name": "Active", "key": "Active", "color": "success" },
{ "value": 1, "name": "Disabled", "key": "Disabled", "color": "danger" },
{ "value": 2, "name": "Locked out", "key": "LockedOut", "color": "danger" },
{ "value": 3, "name": "Invited", "key": "Invited", "color": "warning" }
{ "value": 3, "name": "Invited", "key": "Invited", "color": "warning" },
{ "value": 4, "name": "Inactive", "key": "Inactive", "color": "warning" }
];
angular.forEach(userStates, function (userState) {
@@ -13,23 +13,31 @@
list-style: none;
align-items: center;
margin: 0;
margin-right: 10px;
margin-right: -10px;
}
.umb-app-header__action a {
color: @white;
opacity: 0.6;
font-size: 22px;
padding-left: 10px;
padding-right: 10px;
text-decoration: none;
display: flex;
align-items: center;
height: @appHeaderHeight;
}
.umb-app-header__action a:hover,
.umb-app-header__action a:focus {
opacity: 1;
outline: none;
}
.umb-app-header__action-icon {
opacity: 0.6;
color: @white;
font-size: 22px;
}
.umb-app-header__action a:hover .umb-app-header__action-icon,
.umb-app-header__action a:focus .umb-app-header__action-icon {
opacity: 1;
}

Some files were not shown because too many files have changed in this diff Show More