Compare commits
218 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 87716c7ed8 | |||
| afa3e9b5eb | |||
| 3aece09e09 | |||
| fd1a9bb365 | |||
| 4d1b361f8f | |||
| ee4a252b07 | |||
| d1b1a1cf6d | |||
| 7e16cf360a | |||
| 9986c10cec | |||
| 9b4f879b6d | |||
| 62d65f0e3a | |||
| 8d35dac9b6 | |||
| b8890aee25 | |||
| bb23e8e200 | |||
| cbc3ca0768 | |||
| e76d7cf060 | |||
| 471e47e11b | |||
| 747edaa6ce | |||
| 08818c6358 | |||
| 94922ccbd2 | |||
| 3977d24eb2 | |||
| 2e135d2006 | |||
| b820baf643 | |||
| a3cf1d7d58 | |||
| 4d7a36e017 | |||
| a9756e065c | |||
| 59962c7afe | |||
| 0f3da1ae14 | |||
| 774f1d706c | |||
| 6b55c11321 | |||
| 2737085161 | |||
| e7d7de6273 | |||
| b6c3297884 | |||
| 9d36ee6bd8 | |||
| 7355ba4b23 | |||
| deca5d7bdb | |||
| bc081db9e6 | |||
| b6966055b4 | |||
| 2389901ba9 | |||
| 9579b97dde | |||
| c27b9d76db | |||
| a8df8f484f | |||
| 0a245dda43 | |||
| 125bbdd5bd | |||
| 321460c395 | |||
| 6bd31636f0 | |||
| e80c450e42 | |||
| 262f7aff7c | |||
| 62a82c17c2 | |||
| 833137772d | |||
| 69528704ca | |||
| be140bd06c | |||
| 2bda1a211d | |||
| f42bb663ff | |||
| ff0b95b337 | |||
| 7c28e8979a | |||
| 93ae55c919 | |||
| 985e1cc1b7 | |||
| c90e7735f9 | |||
| 3dffb59f72 | |||
| 38bd53978b | |||
| 9c04abc5ad | |||
| 66221364ca | |||
| eda6e084a7 | |||
| 328b4b1556 | |||
| fabab44342 | |||
| 2c9256c672 | |||
| 63a2a155d1 | |||
| 8fad718347 | |||
| 3879b81ed3 | |||
| c5de33dcae | |||
| f36139619a | |||
| 093182c56d | |||
| 5f1fb144e0 | |||
| 6b398a2d16 | |||
| 3c73f6a764 | |||
| 865cdc09c6 | |||
| 7f107a8559 | |||
| 0dbbb585ad | |||
| a7573ce31f | |||
| c6e2ced971 | |||
| 45f574ed3a | |||
| 12a9466cd7 | |||
| fce0dd98f9 | |||
| 25aa74b4cd | |||
| 976d329292 | |||
| b079593efd | |||
| 883da4eaf1 | |||
| c021cc50ce | |||
| 85291b562e | |||
| ca8c6248c1 | |||
| 6843fa72aa | |||
| 258baad127 | |||
| 0e6376f4e5 | |||
| b0374695b1 | |||
| 471bc7f116 | |||
| 9c0aa5e099 | |||
| 3940176f23 | |||
| 5832387484 | |||
| a1224da5e1 | |||
| 540e4f17d6 | |||
| 2e92172ed4 | |||
| f0fbc808f2 | |||
| c44a22d205 | |||
| 0f6ce1eeba | |||
| cbeb0de748 | |||
| e06fef2b6d | |||
| 524f53d03f | |||
| d2d77d2732 | |||
| 31bdc9d9a6 | |||
| 8c8e23f981 | |||
| 35ec07f970 | |||
| 917269a260 | |||
| 00fc1b7c26 | |||
| 53c218428f | |||
| b9f5ddab06 | |||
| f9973f602c | |||
| 3d0d8d7430 | |||
| 70a851dbf9 | |||
| 3f79067e26 | |||
| 1050e9d0a1 | |||
| 8bf8e0a741 | |||
| fd0e2f5a9c | |||
| 6ee235b640 | |||
| 2921413476 | |||
| 7f4280c67f | |||
| e9f8fb8d1f | |||
| 28ae25c166 | |||
| 1acc61ede8 | |||
| 31ed4e0574 | |||
| a0ae39a147 | |||
| 9e3cf00cc0 | |||
| fbbc89b477 | |||
| 2f74720c38 | |||
| 91ebc649d4 | |||
| b2133aace1 | |||
| 32591eec36 | |||
| e05a55c532 | |||
| f3d96ad45e | |||
| 010a2e012e | |||
| da88cc2d04 | |||
| 8ff671a7c6 | |||
| 5986899b5e | |||
| c8664a886a | |||
| 5dd04d9a3e | |||
| 6ff2f1eabb | |||
| cbdfb6f25f | |||
| 1437af62b3 | |||
| ac9c6305e7 | |||
| b2b9b53af1 | |||
| 2dd5010d2c | |||
| c6a31b30f1 | |||
| ef3abea005 | |||
| c95cc14703 | |||
| bfd12b3a7b | |||
| 396b499e81 | |||
| 61ce1bcdca | |||
| ec1d2a6433 | |||
| 9ea9c5d6b7 | |||
| fee9bce110 | |||
| 222720aea4 | |||
| 9e3213147f | |||
| c29357b845 | |||
| cc680f2cfb | |||
| 58dab23d04 | |||
| 90a47cd042 | |||
| fb6079d4e2 | |||
| f359648215 | |||
| 74ca315197 | |||
| 541e546f7b | |||
| 26a8d680d4 | |||
| 412069414b | |||
| ec1a3f0fe8 | |||
| 8ce200bd16 | |||
| 26e2bc6afa | |||
| 546458bcfd | |||
| f2090e9fc7 | |||
| 46b0063921 | |||
| 7fd1617759 | |||
| 5e7c9f2341 | |||
| bec8aabede | |||
| c07780caff | |||
| 0c3d3ca545 | |||
| 35a0d4451f | |||
| 03fdba6a3b | |||
| 550c383598 | |||
| 9d3d718e16 | |||
| b09bf518c6 | |||
| 8666b222ac | |||
| 9e564d70ef | |||
| 276810be6c | |||
| 49df6e7c9d | |||
| 06e55c8c4e | |||
| efbcce5261 | |||
| 07e5161988 | |||
| 03e642fced | |||
| 051b595f82 | |||
| 0cd3bb38ed | |||
| 92273f263b | |||
| f5b017ed67 | |||
| 08bf48b8b7 | |||
| 8ddda5868e | |||
| 477761a81a | |||
| 4512cf0145 | |||
| 38e9a3d2ee | |||
| 13f42773d7 | |||
| 71d3c1112e | |||
| 5bfac6c5b4 | |||
| ebae69d00c | |||
| a8ea535bb2 | |||
| 3b231f5138 | |||
| 1ece576825 | |||
| a2611ce35f | |||
| 7a89580db2 | |||
| a031551fb2 | |||
| 69728fb5c4 | |||
| afd91f8adb | |||
| d99d5a0b36 |
@@ -17,7 +17,7 @@ Assume positive intent and try to understand before being understood.
|
||||
|
||||
Treat others as you would like to be treated.
|
||||
|
||||
This also goes for treating the HQ with respect. For example: don’t promote products on [our.umbraco.org](https://our.umbraco.org) that directly compete with our commercial offerings which enables us to work for a sustainable Umbraco.
|
||||
This also goes for treating the HQ with respect. For example: don’t promote products on [our.umbraco.com](https://our.umbraco.com) that directly compete with our commercial offerings which enables us to work for a sustainable Umbraco.
|
||||
|
||||
## Open
|
||||
|
||||
@@ -82,7 +82,7 @@ These wonderful volunteers will provide you with a first reply to your PR, revie
|
||||
You can get in touch with [the PR team](#the-pr-team) in multiple ways, we love open conversations and we are a friendly bunch. No question you have is stupid. Any questions you have usually helps out multiple people with the same question. Ask away:
|
||||
|
||||
- If there's an existing issue on the issue tracker then that's a good place to leave questions and discuss how to start or move forward
|
||||
- Unsure where to start? Did something not work as expected? Try leaving a note in the ["Contributing to Umbraco"](https://our.umbraco.org/forum/contributing-to-umbraco-cms/) forum, the team monitors that one closely
|
||||
- Unsure where to start? Did something not work as expected? Try leaving a note in the ["Contributing to Umbraco"](https://our.umbraco.com/forum/contributing-to-umbraco-cms/) forum, the team monitors that one closely
|
||||
- We're also [active in the Gitter chatroom](https://gitter.im/umbraco/Umbraco-CMS)
|
||||
|
||||
## Code of Conduct
|
||||
@@ -31,7 +31,7 @@ Before creating bug reports, please check [this list](#before-submitting-a-bug-r
|
||||
|
||||
##### Before Submitting A Bug Report
|
||||
|
||||
* Most importantly, check **if you can reproduce the problem** in the [latest version of Umbraco](https://our.umbraco.org/download/). We might have already fixed your particular problem.
|
||||
* Most importantly, check **if you can reproduce the problem** in the [latest version of Umbraco](https://our.umbraco.com/download/). We might have already fixed your particular problem.
|
||||
* It also helps tremendously to check if the issue you're experiencing is present in **a clean install** of the Umbraco version you're currently using. Custom code can have side-effects that don't occur in a clean install.
|
||||
* **Use the Google**. Whatever you're experiencing, Google it plus "Umbraco" - usually you can get some pretty good hints from the search results, including open issues and further troubleshooting hints.
|
||||
* If you do find and existing issue has **and the issue is still open**, add a comment to the existing issue if you have additional information. If you have the same problem and no new info to add, just "star" the issue.
|
||||
@@ -65,7 +65,7 @@ Most of the suggestions in the [reporting bugs](#reporting-bugs) section also co
|
||||
Some additional hints that may be helpful:
|
||||
|
||||
* **Include screenshots and animated GIFs** which help you demonstrate the steps or point out the part of Umbraco which the suggestion is related to.
|
||||
* **Explain why this enhancement would be useful to most Umbraco users** and isn't something that can or should be implemented as a [community package](https://our.umbraco.org/projects/).
|
||||
* **Explain why this enhancement would be useful to most Umbraco users** and isn't something that can or should be implemented as a [community package](https://our.umbraco.com/projects/).
|
||||
|
||||
### Your First Code Contribution
|
||||
|
||||
@@ -80,7 +80,7 @@ The most successful pull requests usually look a like this:
|
||||
* Fill in the required template
|
||||
* Include screenshots and animated GIFs in your pull request whenever possible.
|
||||
* Unit tests, while optional are awesome, thank you!
|
||||
* New code is commented with documentation from which [the reference documentation](https://our.umbraco.org/documentation/Reference/) is generated
|
||||
* New code is commented with documentation from which [the reference documentation](https://our.umbraco.com/documentation/Reference/) is generated
|
||||
|
||||
Again, these are guidelines, not strict requirements.
|
||||
|
||||
@@ -116,8 +116,8 @@ There's two big areas that you should know about:
|
||||
|
||||
To find the general areas of something you're looking to fix or improve, have a look at the following two parts of the API documentation.
|
||||
|
||||
* [The AngularJS based backoffice files](https://our.umbraco.org/apidocs/ui/#/api) (to be found in `src\Umbraco.Web.UI.Client\src`)
|
||||
* [The rest](https://our.umbraco.org/apidocs/csharp/)
|
||||
* [The AngularJS based backoffice files](https://our.umbraco.com/apidocs/ui/#/api) (to be found in `src\Umbraco.Web.UI.Client\src`)
|
||||
* [The rest](https://our.umbraco.com/apidocs/csharp/)
|
||||
|
||||
### What branch should I target for my contributions?
|
||||
|
||||
@@ -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.
|
||||
|
||||

|
||||
|
||||
@@ -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))
|
||||
@@ -12,7 +12,7 @@ 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/docs/CONTRIBUTING.md
|
||||
See: https://github.com/umbraco/Umbraco-CMS/blob/dev-v7/.github/CONTRIBUTING.md
|
||||
|
||||
-->
|
||||
|
||||
@@ -44,6 +44,7 @@ Umbraco is contribution focused and community driven. If you want to contribute
|
||||
|
||||
## Found a bug?
|
||||
|
||||
Another way you can contribute to Umbraco is by providing issue reports. For information on how to submit an issue report refer to our [online guide for reporting issues](https://github.com/umbraco/Umbraco-CMS/blob/dev-v7/docs/CONTRIBUTING.md).
|
||||
Another way you can contribute to Umbraco is by providing issue reports. For information on how to submit an issue report refer to our [online guide for reporting issues](https://github.com/umbraco/Umbraco-CMS/blob/dev-v7/.github/CONTRIBUTING.md).
|
||||
|
||||
To view existing issues, please visit [http://issues.umbraco.org](http://issues.umbraco.org).
|
||||
You can comment and report issues on the [github issue tracker](https://github.com/umbraco/Umbraco-CMS/issues).
|
||||
Since [September 2018](https://umbraco.com/blog/a-second-take-on-umbraco-issue-tracker-hello-github-issues/) the old issue tracker is in read only mode, but can still be found at [http://issues.umbraco.org](http://issues.umbraco.org).
|
||||
|
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 |
@@ -1,6 +1,6 @@
|
||||
# The MIT License (MIT) #
|
||||
|
||||
Copyright (c) 2013 Umbraco
|
||||
Copyright (c) 2013-present Umbraco
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<meta name="title" content="{{#title}}{{title}}{{/title}}{{^title}}{{>partials/title}}{{/title}} {{#_appTitle}}| {{_appTitle}} {{/_appTitle}}">
|
||||
<meta name="generator" content="docfx {{_docfxVersion}}">
|
||||
{{#_description}}<meta name="description" content="{{_description}}">{{/_description}}
|
||||
<link rel="icon" type="image/png" href="https://our.umbraco.org/assets/images/app-icons/favicon.png">
|
||||
<link rel="icon" type="image/png" href="https://our.umbraco.com/assets/images/app-icons/favicon.png">
|
||||
<link rel="stylesheet" href="{{_rel}}styles/docfx.vendor.css">
|
||||
<link rel="stylesheet" href="{{_rel}}styles/docfx.css">
|
||||
<link rel="stylesheet" href="{{_rel}}styles/main.css">
|
||||
|
||||
@@ -63,7 +63,7 @@ a:focus {
|
||||
}
|
||||
|
||||
.navbar-header .navbar-brand {
|
||||
background: url(https://our.umbraco.org/assets/images/logo.svg) left center no-repeat;
|
||||
background: url(https://our.umbraco.com/assets/images/logo.svg) left center no-repeat;
|
||||
background-size: 40px auto;
|
||||
width:50px;
|
||||
}
|
||||
|
||||
@@ -94,14 +94,14 @@ function Get-UmbracoBuildEnv
|
||||
}
|
||||
|
||||
# ensure we have node
|
||||
$node = "$path\node-v6.9.1-win-x86"
|
||||
$source = "http://nodejs.org/dist/v6.9.1/node-v6.9.1-win-x86.7z"
|
||||
$node = "$path\node-v8.12.0-win-x86"
|
||||
$source = "http://nodejs.org/dist/v8.12.0/node-v8.12.0-win-x86.7z "
|
||||
if (-not (test-path $node))
|
||||
{
|
||||
Write-Host "Download Node..."
|
||||
Invoke-WebRequest $source -OutFile "$path\node-v6.9.1-win-x86.7z"
|
||||
&$sevenZip x "$path\node-v6.9.1-win-x86.7z" -o"$path" -aos > $nul
|
||||
Remove-File "$path\node-v6.9.1-win-x86.7z"
|
||||
Invoke-WebRequest $source -OutFile "$path\node-v8.12.0-win-x86.7z"
|
||||
&$sevenZip x "$path\node-v8.12.0-win-x86.7z" -o"$path" -aos > $nul
|
||||
Remove-File "$path\node-v8.12.0-win-x86.7z"
|
||||
}
|
||||
|
||||
# note: why? node already brings everything we need!
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
<dependency id="HtmlAgilityPack" version="[1.4.9.5, 2.0.0)" />
|
||||
<dependency id="Lucene.Net" version="[2.9.4.1, 3.0.0.0)" />
|
||||
<dependency id="MySql.Data" version="[6.9.9, 7.0.0)" />
|
||||
<dependency id="ClientDependency" version="[1.9.6, 2.0.0)" />
|
||||
<dependency id="ClientDependency" version="[1.9.7, 2.0.0)" />
|
||||
<dependency id="ClientDependency-Mvc5" version="[1.8.0.0, 2.0.0)" />
|
||||
<dependency id="AutoMapper" version="[3.3.1, 4.0.0)" />
|
||||
<dependency id="Newtonsoft.Json" version="[10.0.2, 11.0.0)" />
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
<dependency id="Umbraco.ModelsBuilder" version="[3.0.10, 4.0.0)" />
|
||||
<dependency id="Microsoft.AspNet.SignalR.Core" version="[2.2.1, 3.0.0)" />
|
||||
<dependency id="ImageProcessor.Web.Config" version="[2.3.1, 3.0.0)" />
|
||||
<dependency id="Microsoft.CodeDom.Providers.DotNetCompilerPlatform" version="[2.0.0, 3.0.0)" />
|
||||
</dependencies>
|
||||
</metadata>
|
||||
<files>
|
||||
|
||||
@@ -21,6 +21,6 @@ The following items will now be automatically included when creating a deploy pa
|
||||
system: umbraco, umbraco_client, config\splashes and global.asax.
|
||||
|
||||
Please read the release notes on our.umbraco.com:
|
||||
http://our.umbraco.com/contribute/releases
|
||||
https://our.umbraco.com/download/releases
|
||||
|
||||
- Umbraco
|
||||
- Umbraco
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
using System.Resources;
|
||||
|
||||
[assembly: AssemblyCompany("Umbraco")]
|
||||
[assembly: AssemblyCopyright("Copyright © Umbraco 2017")]
|
||||
[assembly: AssemblyCopyright("Copyright © Umbraco 2018")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
@@ -11,5 +11,5 @@ using System.Resources;
|
||||
|
||||
[assembly: AssemblyVersion("1.0.*")]
|
||||
|
||||
[assembly: AssemblyFileVersion("7.12.2")]
|
||||
[assembly: AssemblyInformationalVersion("7.12.2")]
|
||||
[assembly: AssemblyFileVersion("7.13.0")]
|
||||
[assembly: AssemblyInformationalVersion("7.13.0")]
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
|
||||
IEnumerable<string> ImageTagAllowedAttributes { get; }
|
||||
|
||||
IEnumerable<IImagingAutoFillUploadField> ImageAutoFillProperties { get; }
|
||||
|
||||
|
||||
string ScriptFolderPath { get; }
|
||||
|
||||
IEnumerable<string> ScriptFileTypes { get; }
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
|
||||
bool DisableAlternativeTemplates { get; }
|
||||
|
||||
bool ValidateAlternativeTemplates { get; }
|
||||
|
||||
bool DisableFindContentByIdPath { get; }
|
||||
|
||||
bool DisableRedirectUrlTracking { get; }
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Configuration;
|
||||
using System;
|
||||
using System.Configuration;
|
||||
|
||||
namespace Umbraco.Core.Configuration.UmbracoSettings
|
||||
{
|
||||
@@ -21,6 +22,13 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
|
||||
{
|
||||
get { return (bool) base["disableAlternativeTemplates"]; }
|
||||
}
|
||||
|
||||
[ConfigurationProperty("validateAlternativeTemplates", DefaultValue = "false")]
|
||||
public bool ValidateAlternativeTemplates
|
||||
{
|
||||
get { return (bool)base["validateAlternativeTemplates"]; }
|
||||
}
|
||||
|
||||
[ConfigurationProperty("disableFindContentByIdPath", DefaultValue = "false")]
|
||||
public bool DisableFindContentByIdPath
|
||||
{
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace Umbraco.Core.Configuration
|
||||
{
|
||||
public class UmbracoVersion
|
||||
{
|
||||
private static readonly Version Version = new Version("7.12.2");
|
||||
private static readonly Version Version = new Version("7.13.0");
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current version of Umbraco.
|
||||
|
||||
@@ -110,6 +110,11 @@ namespace Umbraco.Core
|
||||
/// Property alias for the Media's file extension.
|
||||
/// </summary>
|
||||
public const string Extension = "umbracoExtension";
|
||||
|
||||
/// <summary>
|
||||
/// The default height/width of an image file if the size can't be determined from the metadata
|
||||
/// </summary>
|
||||
public const int DefaultSize = 200;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -354,4 +359,4 @@ namespace Umbraco.Core
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,6 +61,7 @@
|
||||
public const int DefaultContentListViewDataTypeId = -95;
|
||||
public const int DefaultMediaListViewDataTypeId = -96;
|
||||
public const int DefaultMembersListViewDataTypeId = -97;
|
||||
public const int DefaultLabelDataTypeId = -92;
|
||||
|
||||
public const string UmbracoConnectionName = "umbracoDbDSN";
|
||||
public const string UmbracoMigrationName = "Umbraco";
|
||||
|
||||
@@ -17,15 +17,15 @@ using Umbraco.Core.Models;
|
||||
|
||||
namespace Umbraco.Core.IO
|
||||
{
|
||||
/// <summary>
|
||||
/// A custom file system provider for media
|
||||
/// </summary>
|
||||
[FileSystemProvider("media")]
|
||||
public class MediaFileSystem : FileSystemWrapper
|
||||
{
|
||||
private readonly IContentSection _contentConfig;
|
||||
/// <summary>
|
||||
/// A custom file system provider for media
|
||||
/// </summary>
|
||||
[FileSystemProvider("media")]
|
||||
public class MediaFileSystem : FileSystemWrapper
|
||||
{
|
||||
private readonly IContentSection _contentConfig;
|
||||
private readonly UploadAutoFillProperties _uploadAutoFillProperties;
|
||||
private readonly ILogger _logger;
|
||||
private readonly ILogger _logger;
|
||||
|
||||
private readonly object _folderCounterLock = new object();
|
||||
private long _folderCounter;
|
||||
@@ -39,8 +39,8 @@ namespace Umbraco.Core.IO
|
||||
};
|
||||
|
||||
public MediaFileSystem(IFileSystem wrapped)
|
||||
: this(wrapped, UmbracoConfig.For.UmbracoSettings().Content, ApplicationContext.Current.ProfilingLogger.Logger)
|
||||
{ }
|
||||
: this(wrapped, UmbracoConfig.For.UmbracoSettings().Content, ApplicationContext.Current.ProfilingLogger.Logger)
|
||||
{ }
|
||||
|
||||
public MediaFileSystem(IFileSystem wrapped, IContentSection contentConfig, ILogger logger)
|
||||
: base(wrapped)
|
||||
@@ -60,13 +60,13 @@ namespace Umbraco.Core.IO
|
||||
|
||||
[Obsolete("This low-level method should NOT exist.")]
|
||||
public string GetRelativePath(int propertyId, string fileName)
|
||||
{
|
||||
{
|
||||
var sep = _contentConfig.UploadAllowDirectories
|
||||
? Path.DirectorySeparatorChar
|
||||
: '-';
|
||||
? Path.DirectorySeparatorChar
|
||||
: '-';
|
||||
|
||||
return propertyId.ToString(CultureInfo.InvariantCulture) + sep + fileName;
|
||||
}
|
||||
return propertyId.ToString(CultureInfo.InvariantCulture) + sep + fileName;
|
||||
}
|
||||
|
||||
[Obsolete("This low-level method should NOT exist.", false)]
|
||||
public string GetRelativePath(string subfolder, string fileName)
|
||||
@@ -264,7 +264,7 @@ namespace Umbraco.Core.IO
|
||||
var filename = Path.GetFileName(sourcepath);
|
||||
var filepath = GetMediaPath(filename, content.Key, propertyType.Key);
|
||||
this.CopyFile(sourcepath, filepath);
|
||||
|
||||
|
||||
return filepath;
|
||||
}
|
||||
|
||||
@@ -321,7 +321,7 @@ namespace Umbraco.Core.IO
|
||||
/// <param name="filepath"></param>
|
||||
/// <param name="filestream"></param>
|
||||
private void SetUploadFile(IContentBase content, Property property, string filepath, Stream filestream)
|
||||
{
|
||||
{
|
||||
// will use filepath for extension, and filestream for length
|
||||
_uploadAutoFillProperties.Populate(content, property.Alias, filepath, filestream);
|
||||
}
|
||||
@@ -368,19 +368,20 @@ namespace Umbraco.Core.IO
|
||||
return new Size(width, height);
|
||||
}
|
||||
}
|
||||
|
||||
//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);
|
||||
}
|
||||
}
|
||||
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);
|
||||
return new Size(Constants.Conventions.Media.DefaultSize, Constants.Conventions.Media.DefaultSize);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -430,8 +431,8 @@ namespace Umbraco.Core.IO
|
||||
}
|
||||
}
|
||||
|
||||
public void DeleteMediaFiles(IEnumerable<string> files)
|
||||
{
|
||||
public void DeleteMediaFiles(IEnumerable<string> files)
|
||||
{
|
||||
files = files.Distinct();
|
||||
|
||||
Parallel.ForEach(files, file =>
|
||||
|
||||
@@ -37,6 +37,7 @@ namespace Umbraco.Core.IO
|
||||
}
|
||||
}
|
||||
|
||||
[Obsolete("This file is no longer used and should not be accessed!")]
|
||||
public static string MetablogConfig
|
||||
{
|
||||
get
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using Umbraco.Core.Media.TypeDetector;
|
||||
|
||||
namespace Umbraco.Core.Media.Exif
|
||||
{
|
||||
@@ -118,22 +119,25 @@ namespace Umbraco.Core.Media.Exif
|
||||
/// <returns>The <see cref="ImageFile"/> created from the file.</returns>
|
||||
public static ImageFile FromStream(Stream stream, Encoding encoding)
|
||||
{
|
||||
stream.Seek (0, SeekOrigin.Begin);
|
||||
byte[] header = new byte[8];
|
||||
stream.Seek (0, SeekOrigin.Begin);
|
||||
if (stream.Read (header, 0, header.Length) != header.Length)
|
||||
throw new NotValidImageFileException ();
|
||||
|
||||
// JPEG
|
||||
if (header[0] == 0xFF && header[1] == 0xD8)
|
||||
return new JPEGFile (stream, encoding);
|
||||
|
||||
// TIFF
|
||||
string tiffHeader = Encoding.ASCII.GetString (header, 0, 4);
|
||||
if (tiffHeader == "MM\x00\x2a" || tiffHeader == "II\x2a\x00")
|
||||
return new TIFFFile (stream, encoding);
|
||||
|
||||
throw new NotValidImageFileException ();
|
||||
// JPEG
|
||||
if(JPEGDetector.IsOfType(stream))
|
||||
{
|
||||
return new JPEGFile(stream, encoding);
|
||||
}
|
||||
|
||||
// TIFF
|
||||
if (TIFFDetector.IsOfType(stream))
|
||||
{
|
||||
return new TIFFFile(stream, encoding);
|
||||
}
|
||||
|
||||
// SVG
|
||||
if (SVGDetector.IsOfType(stream))
|
||||
{
|
||||
return new SVGFile(stream);
|
||||
}
|
||||
|
||||
throw new NotValidImageFileException ();
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
@@ -17,5 +17,9 @@
|
||||
/// The file is a TIFF File.
|
||||
/// </summary>
|
||||
TIFF,
|
||||
/// <summary>
|
||||
/// The file is a SVG File.
|
||||
/// </summary>
|
||||
SVG,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Umbraco.Core.Media.Exif
|
||||
{
|
||||
internal class SVGFile : ImageFile
|
||||
{
|
||||
public SVGFile(Stream fileStream)
|
||||
{
|
||||
fileStream.Position = 0;
|
||||
|
||||
var document = XDocument.Load(fileStream); //if it throws an exception the ugly try catch in MediaFileSystem will catch it
|
||||
|
||||
var width = document.Root?.Attributes().Where(x => x.Name == "width").Select(x => x.Value).FirstOrDefault();
|
||||
var height = document.Root?.Attributes().Where(x => x.Name == "height").Select(x => x.Value).FirstOrDefault();
|
||||
|
||||
Properties.Add(new ExifSInt(ExifTag.PixelYDimension,
|
||||
height == null ? Constants.Conventions.Media.DefaultSize : int.Parse(height)));
|
||||
Properties.Add(new ExifSInt(ExifTag.PixelXDimension,
|
||||
width == null ? Constants.Conventions.Media.DefaultSize : int.Parse(width)));
|
||||
|
||||
Format = ImageFileFormat.SVG;
|
||||
}
|
||||
|
||||
public override void Save(Stream stream)
|
||||
{
|
||||
}
|
||||
|
||||
public override Image ToImage()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Umbraco.Core.Media.TypeDetector
|
||||
{
|
||||
public class JPEGDetector : RasterizedTypeDetector
|
||||
{
|
||||
public static bool IsOfType(Stream fileStream)
|
||||
{
|
||||
var header = GetFileHeader(fileStream);
|
||||
|
||||
return header[0] == 0xff && header[1] == 0xD8;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Umbraco.Core.Media.TypeDetector
|
||||
{
|
||||
public abstract class RasterizedTypeDetector
|
||||
{
|
||||
public static byte[] GetFileHeader(Stream fileStream)
|
||||
{
|
||||
fileStream.Seek(0, SeekOrigin.Begin);
|
||||
byte[] header = new byte[8];
|
||||
fileStream.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
return header;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using System.IO;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Umbraco.Core.Media.TypeDetector
|
||||
{
|
||||
public class SVGDetector
|
||||
{
|
||||
public static bool IsOfType(Stream fileStream)
|
||||
{
|
||||
var document = new XDocument();
|
||||
|
||||
try
|
||||
{
|
||||
document = XDocument.Load(fileStream);
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return document.Root?.Name.LocalName == "svg";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace Umbraco.Core.Media.TypeDetector
|
||||
{
|
||||
public class TIFFDetector
|
||||
{
|
||||
public static bool IsOfType(Stream fileStream)
|
||||
{
|
||||
string tiffHeader = GetFileHeader(fileStream);
|
||||
|
||||
return tiffHeader == "MM\x00\x2a" || tiffHeader == "II\x2a\x00";
|
||||
}
|
||||
|
||||
public static string GetFileHeader(Stream fileStream)
|
||||
{
|
||||
var header = RasterizedTypeDetector.GetFileHeader(fileStream);
|
||||
|
||||
string tiffHeader = Encoding.ASCII.GetString(header, 0, 4);
|
||||
|
||||
return tiffHeader;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -102,6 +102,28 @@ 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)
|
||||
{
|
||||
var allowedTemplates = AllowedTemplates ?? new ITemplate[0];
|
||||
return 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)
|
||||
{
|
||||
var allowedTemplates = AllowedTemplates ?? new ITemplate[0];
|
||||
return allowedTemplates.Any(t => t.Alias.Equals(templateAlias, StringComparison.InvariantCultureIgnoreCase));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the default template for the ContentType
|
||||
/// </summary>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -83,7 +83,7 @@ namespace Umbraco.Core.Models
|
||||
/// <summary>
|
||||
/// Returns the instance of the tag support, by default tags are not enabled
|
||||
/// </summary>
|
||||
internal PropertyTags TagSupport
|
||||
public PropertyTags TagSupport
|
||||
{
|
||||
get { return _tagSupport; }
|
||||
}
|
||||
@@ -242,4 +242,4 @@ namespace Umbraco.Core.Models
|
||||
return clone;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
internal enum PropertyTagBehavior
|
||||
public enum PropertyTagBehavior
|
||||
{
|
||||
Replace,
|
||||
Remove,
|
||||
Merge
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace Umbraco.Core.Models
|
||||
/// <summary>
|
||||
/// A property extension class that allows us to enable tags for any given property
|
||||
/// </summary>
|
||||
internal class PropertyTags
|
||||
public class PropertyTags
|
||||
{
|
||||
public PropertyTags()
|
||||
{
|
||||
@@ -33,4 +33,4 @@ namespace Umbraco.Core.Models
|
||||
public IEnumerable<Tuple<string, string>> Tags { get; set; }
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models.Rdbms;
|
||||
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
|
||||
@@ -11,6 +10,9 @@ using Umbraco.Core.Services;
|
||||
namespace Umbraco.Core.Persistence
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Helper class for working with databases and schemas.
|
||||
/// </summary>
|
||||
public class DatabaseSchemaHelper
|
||||
{
|
||||
private readonly Database _db;
|
||||
@@ -18,6 +20,22 @@ namespace Umbraco.Core.Persistence
|
||||
private readonly ISqlSyntaxProvider _syntaxProvider;
|
||||
private readonly BaseDataCreation _baseDataCreation;
|
||||
|
||||
/// <summary>
|
||||
/// Intializes a new helper instance.
|
||||
/// </summary>
|
||||
/// <param name="db">The database to be used.</param>
|
||||
/// <param name="logger">The logger.</param>
|
||||
/// <param name="syntaxProvider">The syntax provider.</param>
|
||||
/// <example>
|
||||
/// A new instance could be initialized like:
|
||||
/// <code>
|
||||
/// var schemaHelper = new DatabaseSchemaHelper(
|
||||
/// ApplicationContext.Current.DatabaseContext.Database,
|
||||
/// ApplicationContext.Current.ProfilingLogger.Logger,
|
||||
/// ApplicationContext.Current.DatabaseContext.SqlSyntax
|
||||
/// );
|
||||
/// </code>
|
||||
/// </example>
|
||||
public DatabaseSchemaHelper(Database db, ILogger logger, ISqlSyntaxProvider syntaxProvider)
|
||||
{
|
||||
_db = db;
|
||||
@@ -26,11 +44,41 @@ namespace Umbraco.Core.Persistence
|
||||
_baseDataCreation = new BaseDataCreation(db, logger);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns whether a table with the specified <paramref name="tableName"/> exists in the database.
|
||||
/// </summary>
|
||||
/// <param name="tableName">The name of the table.</param>
|
||||
/// <returns><c>true</c> if the table exists; otherwise <c>false</c>.</returns>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// if (schemaHelper.TableExist("MyTable"))
|
||||
/// {
|
||||
/// // do something when the table exists
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
public bool TableExist(string tableName)
|
||||
{
|
||||
return _syntaxProvider.DoesTableExist(_db, tableName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns whether the table for the specified <typeparamref name="T"/> exists in the database.
|
||||
///
|
||||
/// If <typeparamref name="T"/> has been decorated with an <see cref="TableNameAttribute"/>, the name from that
|
||||
/// attribute will be used for the table name. If the attribute is not present, the name
|
||||
/// <typeparamref name="T"/> will be used instead.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type representing the DTO/table.</typeparam>
|
||||
/// <returns><c>true</c> if the table exists; otherwise <c>false</c>.</returns>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// if (schemaHelper.TableExist<MyDto>)
|
||||
/// {
|
||||
/// // do something when the table exists
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
public bool TableExist<T>()
|
||||
{
|
||||
var poco = Database.PocoData.ForType(typeof(T));
|
||||
@@ -90,6 +138,17 @@ namespace Umbraco.Core.Persistence
|
||||
_logger.Info<Database>("Finalized database schema creation");
|
||||
}
|
||||
|
||||
/// Creates a new table in the database based on the type of <typeparamref name="T"/>.
|
||||
///
|
||||
/// If <typeparamref name="T"/> has been decorated with an <see cref="TableNameAttribute"/>, the name from that
|
||||
/// attribute will be used for the table name. If the attribute is not present, the name
|
||||
/// <typeparamref name="T"/> will be used instead.
|
||||
///
|
||||
/// If a table with the same name already exists, the <paramref name="overwrite"/> parameter will determine
|
||||
/// whether the table is overwritten. If <c>true</c>, the table will be overwritten, whereas this method will
|
||||
/// not do anything if the parameter is <c>false</c>.
|
||||
/// <typeparam name="T">The type representing the DTO/table.</typeparam>
|
||||
/// <param name="overwrite">Whether the table should be overwritten if it already exists.</param>
|
||||
public void CreateTable<T>(bool overwrite)
|
||||
where T : new()
|
||||
{
|
||||
@@ -97,6 +156,16 @@ namespace Umbraco.Core.Persistence
|
||||
CreateTable(overwrite, tableType);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new table in the database based on the type of <typeparamref name="T"/>.
|
||||
///
|
||||
/// If <typeparamref name="T"/> has been decorated with an <see cref="TableNameAttribute"/>, the name from that
|
||||
/// attribute will be used for the table name. If the attribute is not present, the name
|
||||
/// <typeparamref name="T"/> will be used instead.
|
||||
///
|
||||
/// If a table with the same name already exists, this method will not do anything.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type representing the DTO/table.</typeparam>
|
||||
public void CreateTable<T>()
|
||||
where T : new()
|
||||
{
|
||||
@@ -104,6 +173,19 @@ namespace Umbraco.Core.Persistence
|
||||
CreateTable(false, tableType);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new table in the database for the specified <paramref name="modelType"/>.
|
||||
///
|
||||
/// If <paramref name="modelType"/> has been decorated with an <see cref="TableNameAttribute"/>, the name from
|
||||
/// that attribute will be used for the table name. If the attribute is not present, the name
|
||||
/// <paramref name="modelType"/> will be used instead.
|
||||
///
|
||||
/// If a table with the same name already exists, the <paramref name="overwrite"/> parameter will determine
|
||||
/// whether the table is overwritten. If <c>true</c>, the table will be overwritten, whereas this method will
|
||||
/// not do anything if the parameter is <c>false</c>.
|
||||
/// </summary>
|
||||
/// <param name="overwrite">Whether the table should be overwritten if it already exists.</param>
|
||||
/// <param name="modelType">The the representing the table.</param>
|
||||
public void CreateTable(bool overwrite, Type modelType)
|
||||
{
|
||||
var tableDefinition = DefinitionFactory.GetTableDefinition(_syntaxProvider, modelType);
|
||||
@@ -117,6 +199,8 @@ namespace Umbraco.Core.Persistence
|
||||
var tableExist = TableExist(tableName);
|
||||
if (overwrite && tableExist)
|
||||
{
|
||||
_logger.Info<Database>(string.Format("Table '{0}' already exists, but will be recreated", tableName));
|
||||
|
||||
DropTable(tableName);
|
||||
tableExist = false;
|
||||
}
|
||||
@@ -169,15 +253,37 @@ namespace Umbraco.Core.Persistence
|
||||
_logger.Info<Database>(string.Format("Create Foreign Key sql {0}:\n {1}", createdFk, sql));
|
||||
}
|
||||
|
||||
|
||||
|
||||
transaction.Complete();
|
||||
if (overwrite)
|
||||
{
|
||||
_logger.Info<Database>(string.Format("Table '{0}' was recreated", tableName));
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Info<Database>(string.Format("New table '{0}' was created", tableName));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_logger.Info<Database>(string.Format("New table '{0}' was created", tableName));
|
||||
else
|
||||
{
|
||||
// The table exists and was not recreated/overwritten.
|
||||
_logger.Info<Database>(string.Format("Table '{0}' already exists - no changes were made", tableName));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Drops the table for the specified <typeparamref name="T"/>.
|
||||
///
|
||||
/// If <typeparamref name="T"/> has been decorated with an <see cref="TableNameAttribute"/>, the name from that
|
||||
/// attribute will be used for the table name. If the attribute is not present, the name
|
||||
/// <typeparamref name="T"/> will be used instead.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type representing the DTO/table.</typeparam>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// schemaHelper.DropTable<MyDto>);
|
||||
/// </code>
|
||||
/// </example>
|
||||
public void DropTable<T>()
|
||||
where T : new()
|
||||
{
|
||||
@@ -193,6 +299,15 @@ namespace Umbraco.Core.Persistence
|
||||
DropTable(tableName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Drops the table with the specified <paramref name="tableName"/>.
|
||||
/// </summary>
|
||||
/// <param name="tableName">The name of the table.</param>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// schemaHelper.DropTable("MyTable");
|
||||
/// </code>
|
||||
/// </example>
|
||||
public void DropTable(string tableName)
|
||||
{
|
||||
var sql = new Sql(string.Format(
|
||||
|
||||
@@ -30,7 +30,7 @@ namespace Umbraco.Core.Persistence.Migrations.Initial
|
||||
|
||||
if(tableName.Equals("umbracoNode"))
|
||||
{
|
||||
CreateUmbracNodeData();
|
||||
CreateUmbracoNodeData();
|
||||
}
|
||||
|
||||
if (tableName.Equals("umbracoLock"))
|
||||
@@ -111,7 +111,7 @@ namespace Umbraco.Core.Persistence.Migrations.Initial
|
||||
_logger.Info<BaseDataCreation>(string.Format("Done creating data in table {0}", tableName));
|
||||
}
|
||||
|
||||
private void CreateUmbracNodeData()
|
||||
private void CreateUmbracoNodeData()
|
||||
{
|
||||
_database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = -1, Trashed = false, ParentId = -1, UserId = 0, Level = 0, Path = "-1", SortOrder = 0, UniqueId = new Guid("916724a5-173d-4619-b97e-b9de133dd6f5"), Text = "SYSTEM DATA: umbraco master root", NodeObjectType = new Guid(Constants.ObjectTypes.SystemRoot), CreateDate = DateTime.Now });
|
||||
_database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = -20, Trashed = false, ParentId = -1, UserId = 0, Level = 0, Path = "-1,-20", SortOrder = 0, UniqueId = new Guid("0F582A79-1E41-4CF0-BFA0-76340651891A"), Text = "Recycle Bin", NodeObjectType = new Guid(Constants.ObjectTypes.ContentRecycleBin), CreateDate = DateTime.Now });
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenTwelveZ
|
||||
// We need to get all datatypes with an alias of "umbraco.tags" so we can loop over them and set the missing values if needed
|
||||
var datatypes = Context.Database.Fetch<DataTypeDto>("SELECT * FROM cmsDataType");
|
||||
var tagsDataTypes = datatypes.Where(x => string.Equals(x.PropertyEditorAlias, Constants.PropertyEditors.TagsAlias, StringComparison.InvariantCultureIgnoreCase));
|
||||
var dataTypePreValues = Context.Database.Fetch<DataTypePreValueDto>("SELECT * FROM cmsDataTypePrevalues");
|
||||
var dataTypePreValues = Context.Database.Fetch<DataTypePreValueDto>("SELECT * FROM cmsDataTypePreValues");
|
||||
|
||||
foreach (var datatype in tagsDataTypes)
|
||||
{
|
||||
@@ -36,7 +36,7 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenTwelveZ
|
||||
// if the "storageType" has not been set we do so by adding a new row in the table for the nodid and set it
|
||||
if (result == null)
|
||||
{
|
||||
Insert.IntoTable("CmsDataTypePrevalues").Row(new
|
||||
Insert.IntoTable("cmsDataTypePreValues").Row(new
|
||||
{
|
||||
datatypeNodeId = datatype.DataTypeId,
|
||||
value = "Csv",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.Membership;
|
||||
@@ -47,43 +48,33 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
var sql = GetBaseQuery(false);
|
||||
|
||||
if (query == null) query = new Query<IAuditItem>();
|
||||
|
||||
var queryHasWhereClause = query.GetWhereClauses().Any();
|
||||
var translatorIds = new SqlTranslator<IAuditItem>(sql, query);
|
||||
var translatedQuery = translatorIds.Translate();
|
||||
|
||||
var customFilterWheres = customFilter != null ? customFilter.GetWhereClauses().ToArray() : null;
|
||||
var customFilterWheres = customFilter?.GetWhereClauses().ToArray();
|
||||
var hasCustomFilter = customFilterWheres != null && customFilterWheres.Length > 0;
|
||||
if (hasCustomFilter)
|
||||
{
|
||||
var filterSql = new Sql();
|
||||
var first = true;
|
||||
foreach (var filterClaus in customFilterWheres)
|
||||
{
|
||||
if (first == false)
|
||||
{
|
||||
filterSql.Append(" AND ");
|
||||
}
|
||||
filterSql.Append(string.Format("({0})", filterClaus.Item1), filterClaus.Item2);
|
||||
first = false;
|
||||
foreach (var filterClause in customFilterWheres)
|
||||
{
|
||||
filterSql.Append($"AND ({filterClause.Item1})", filterClause.Item2);
|
||||
}
|
||||
|
||||
translatedQuery = GetFilteredSqlForPagedResults(translatedQuery, filterSql);
|
||||
translatedQuery = GetFilteredSqlForPagedResults(translatedQuery, filterSql, queryHasWhereClause);
|
||||
}
|
||||
|
||||
if (auditTypeFilter.Length > 0)
|
||||
{
|
||||
var filterSql = new Sql();
|
||||
var first = true;
|
||||
foreach (var filterClaus in auditTypeFilter)
|
||||
{
|
||||
if (first == false || hasCustomFilter)
|
||||
{
|
||||
filterSql.Append(" AND ");
|
||||
}
|
||||
filterSql.Append("(logHeader = @logHeader)", new {logHeader = filterClaus.ToString() });
|
||||
first = false;
|
||||
foreach (var filterClause in auditTypeFilter)
|
||||
{
|
||||
filterSql.Append("AND (logHeader = @logHeader)", new { logHeader = filterClause.ToString() });
|
||||
}
|
||||
|
||||
translatedQuery = GetFilteredSqlForPagedResults(translatedQuery, filterSql);
|
||||
translatedQuery = GetFilteredSqlForPagedResults(translatedQuery, filterSql, queryHasWhereClause || hasCustomFilter);
|
||||
}
|
||||
|
||||
if (orderDirection == Direction.Descending)
|
||||
@@ -99,7 +90,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
dto => new AuditItem(dto.Id, dto.Comment, Enum<AuditType>.ParseOrNull(dto.Header) ?? AuditType.Custom, dto.UserId)).ToArray();
|
||||
|
||||
//Mapping the DateStamp
|
||||
for (int i = 0; i < pages.Length; i++)
|
||||
for (var i = 0; i < pages.Length; i++)
|
||||
{
|
||||
pages[i].CreateDate = pagedResult.Items[i].Datestamp;
|
||||
}
|
||||
@@ -169,14 +160,17 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
}
|
||||
#endregion
|
||||
|
||||
private Sql GetFilteredSqlForPagedResults(Sql sql, Sql filterSql)
|
||||
private Sql GetFilteredSqlForPagedResults(Sql sql, Sql filterSql, bool hasWhereClause)
|
||||
{
|
||||
Sql filteredSql;
|
||||
|
||||
// Apply filter
|
||||
if (filterSql != null)
|
||||
{
|
||||
var sqlFilter = " WHERE " + filterSql.SQL.TrimStart("AND ");
|
||||
//ensure we don't append a WHERE if there is already one
|
||||
var sqlFilter = hasWhereClause
|
||||
? filterSql.SQL
|
||||
: " WHERE " + filterSql.SQL.TrimStart("AND ");
|
||||
|
||||
//NOTE: this is certainly strange - NPoco handles this much better but we need to re-create the sql
|
||||
// instance a couple of times to get the parameter order correct, for some reason the first
|
||||
|
||||
@@ -134,7 +134,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
.InnerJoin<ContentDto>(SqlSyntax)
|
||||
.On<ContentVersionDto, ContentDto>(SqlSyntax, left => left.NodeId, right => right.NodeId)
|
||||
.InnerJoin<NodeDto>(SqlSyntax)
|
||||
.On<ContentDto, NodeDto>(SqlSyntax, left => left.NodeId, right => right.NodeId)
|
||||
.On<ContentDto, NodeDto>(SqlSyntax, left => left.NodeId, right => right.NodeId)
|
||||
.InnerJoin<ContentTypeDto>()
|
||||
.On<ContentTypeDto, ContentDto>(left => left.NodeId, right => right.ContentTypeId);
|
||||
//TODO: IF we want to enable querying on content type information this will need to be joined
|
||||
@@ -836,19 +836,19 @@ order by umbracoNode.{2}, umbracoNode.parentID, umbracoNode.sortOrder",
|
||||
}
|
||||
|
||||
public int CountPublished(string contentTypeAlias = null)
|
||||
{
|
||||
if (contentTypeAlias.IsNullOrWhiteSpace())
|
||||
{
|
||||
{
|
||||
if (contentTypeAlias.IsNullOrWhiteSpace())
|
||||
{
|
||||
var sql = GetBaseQuery(true).Where<NodeDto>(x => x.Trashed == false)
|
||||
.Where<DocumentDto>(x => x.Published == true);
|
||||
return Database.ExecuteScalar<int>(sql);
|
||||
.Where<DocumentDto>(x => x.Published == true);
|
||||
return Database.ExecuteScalar<int>(sql);
|
||||
}
|
||||
else
|
||||
{
|
||||
else
|
||||
{
|
||||
var sql = GetBaseQuery(true).Where<NodeDto>(x => x.Trashed == false)
|
||||
.Where<DocumentDto>(x => x.Published == true)
|
||||
.Where<ContentTypeDto>(x => x.Alias == contentTypeAlias);
|
||||
return Database.ExecuteScalar<int>(sql);
|
||||
.Where<DocumentDto>(x => x.Published == true)
|
||||
.Where<ContentTypeDto>(x => x.Alias == contentTypeAlias);
|
||||
return Database.ExecuteScalar<int>(sql);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1220,7 +1220,14 @@ ORDER BY cmsContentVersion.id DESC
|
||||
if (def.DocumentDto.TemplateId.HasValue)
|
||||
templates.TryGetValue(def.DocumentDto.TemplateId.Value, out template); // else null
|
||||
cc.Template = template;
|
||||
cc.Properties = propertyData[cc.Version];
|
||||
if (propertyData.ContainsKey(cc.Version))
|
||||
{
|
||||
cc.Properties = propertyData[cc.Version];
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException($"No property data found for version: '{cc.Version}'.");
|
||||
}
|
||||
|
||||
//on initial construction we don't want to have dirty properties tracked
|
||||
// http://issues.umbraco.org/issue/U4-1946
|
||||
@@ -1307,4 +1314,4 @@ ORDER BY cmsContentVersion.id DESC
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -284,7 +284,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
var nonAssignedRoles = roleNames.Except(assignedRoles, StringComparer.CurrentCultureIgnoreCase);
|
||||
foreach (var toAssign in nonAssignedRoles)
|
||||
{
|
||||
var groupId = rolesForNames.First(x => x.Text == toAssign).NodeId;
|
||||
var groupId = rolesForNames.First(x => x.Text.InvariantEquals(toAssign)).NodeId;
|
||||
Database.Insert(new Member2MemberGroupDto { Member = mId, MemberGroup = groupId });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Web.Security;
|
||||
using Newtonsoft.Json;
|
||||
using Umbraco.Core.Configuration;
|
||||
@@ -710,10 +711,10 @@ ORDER BY colName";
|
||||
|
||||
|
||||
|
||||
private IEnumerable<IUser> GetPagedResultsByQuery(IQuery<IUser> query, long pageIndex, int pageSize, out long totalRecords, string orderBy, Direction orderDirection,
|
||||
string[] includeUserGroups = null,
|
||||
string[] excludeUserGroups = null,
|
||||
UserState[] userState = null,
|
||||
private IEnumerable<IUser> GetPagedResultsByQuery(IQuery<IUser> query, long pageIndex, int pageSize, out long totalRecords, string orderBy, Direction orderDirection,
|
||||
string[] includeUserGroups = null,
|
||||
string[] excludeUserGroups = null,
|
||||
UserState[] userState = null,
|
||||
IQuery<IUser> customFilter = null)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(orderBy)) throw new ArgumentException("Value cannot be null or whitespace.", "orderBy");
|
||||
@@ -721,23 +722,23 @@ ORDER BY colName";
|
||||
|
||||
Sql filterSql = null;
|
||||
var customFilterWheres = customFilter != null ? customFilter.GetWhereClauses().ToArray() : null;
|
||||
var hasCustomFilter = customFilterWheres != null && customFilterWheres.Length > 0;
|
||||
var hasCustomFilter = customFilterWheres != null && customFilterWheres.Length > 0;
|
||||
if (hasCustomFilter
|
||||
|| (includeUserGroups != null && includeUserGroups.Length > 0) || (excludeUserGroups != null && excludeUserGroups.Length > 0)
|
||||
|| (userState != null && userState.Length > 0 && userState.Contains(UserState.All) == false))
|
||||
filterSql = new Sql();
|
||||
|| (includeUserGroups != null && includeUserGroups.Length > 0) || (excludeUserGroups != null && excludeUserGroups.Length > 0)
|
||||
|| (userState != null && userState.Length > 0 && userState.Contains(UserState.All) == false))
|
||||
filterSql = new Sql();
|
||||
|
||||
if (hasCustomFilter)
|
||||
{
|
||||
foreach (var filterClause in customFilterWheres)
|
||||
{
|
||||
filterSql.Append(string.Format("AND ({0})", filterClause.Item1), filterClause.Item2);
|
||||
filterSql.Append($"AND ({filterClause.Item1})", filterClause.Item2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (includeUserGroups != null && includeUserGroups.Length > 0)
|
||||
{
|
||||
var subQuery = @"AND (umbracoUser.id IN (SELECT DISTINCT umbracoUser.id
|
||||
const string subQuery = @"AND (umbracoUser.id IN (SELECT DISTINCT umbracoUser.id
|
||||
FROM umbracoUser
|
||||
INNER JOIN umbracoUser2UserGroup ON umbracoUser2UserGroup.userId = umbracoUser.id
|
||||
INNER JOIN umbracoUserGroup ON umbracoUserGroup.id = umbracoUser2UserGroup.userGroupId
|
||||
@@ -747,21 +748,21 @@ ORDER BY colName";
|
||||
|
||||
if (excludeUserGroups != null && excludeUserGroups.Length > 0)
|
||||
{
|
||||
var subQuery = @"AND (umbracoUser.id NOT IN (SELECT DISTINCT umbracoUser.id
|
||||
const string subQuery = @"AND (umbracoUser.id NOT IN (SELECT DISTINCT umbracoUser.id
|
||||
FROM umbracoUser
|
||||
INNER JOIN umbracoUser2UserGroup ON umbracoUser2UserGroup.userId = umbracoUser.id
|
||||
INNER JOIN umbracoUserGroup ON umbracoUserGroup.id = umbracoUser2UserGroup.userGroupId
|
||||
WHERE umbracoUserGroup.userGroupAlias IN (@userGroups)))";
|
||||
filterSql.Append(subQuery, new { userGroups = excludeUserGroups });
|
||||
}
|
||||
}
|
||||
|
||||
if (userState != null && userState.Length > 0)
|
||||
{
|
||||
{
|
||||
//the "ALL" state doesn't require any filtering so we ignore that, if it exists in the list we don't do any filtering
|
||||
if (userState.Contains(UserState.All) == false)
|
||||
{
|
||||
var sb = new StringBuilder("(");
|
||||
var appended = false;
|
||||
var appended = false;
|
||||
|
||||
if (userState.Contains(UserState.Active))
|
||||
{
|
||||
@@ -797,67 +798,81 @@ ORDER BY colName";
|
||||
|
||||
filterSql.Append("AND " + sb);
|
||||
}
|
||||
}
|
||||
|
||||
// Get base query for returning IDs
|
||||
var sqlBaseIds = GetBaseQuery("id");
|
||||
|
||||
}
|
||||
|
||||
// Get base query for returning IDs
|
||||
var sqlBaseIds = GetBaseQuery("id");
|
||||
|
||||
if (query == null) query = new Query<IUser>();
|
||||
var queryHasWhereClause = query.GetWhereClauses().Any();
|
||||
var translatorIds = new SqlTranslator<IUser>(sqlBaseIds, query);
|
||||
var sqlQueryIds = translatorIds.Translate();
|
||||
|
||||
//get sorted and filtered sql
|
||||
var sqlQueryIds = translatorIds.Translate();
|
||||
var sqlBaseFull = GetBaseQuery("umbracoUser.*, umbracoUserGroup.*, umbracoUserGroup2App.*, umbracoUserStartNode.*");
|
||||
var translatorFull = new SqlTranslator<IUser>(sqlBaseFull, query);
|
||||
|
||||
//get sorted and filtered sql
|
||||
var sqlNodeIdsWithSort = GetSortedSqlForPagedResults(
|
||||
GetFilteredSqlForPagedResults(sqlQueryIds, filterSql),
|
||||
GetFilteredSqlForPagedResults(sqlQueryIds, filterSql, queryHasWhereClause),
|
||||
orderDirection, orderBy);
|
||||
|
||||
// Get page of results and total count
|
||||
var pagedResult = Database.Page<UserDto>(pageIndex + 1, pageSize, sqlNodeIdsWithSort);
|
||||
totalRecords = Convert.ToInt32(pagedResult.TotalItems);
|
||||
|
||||
//NOTE: We need to check the actual items returned, not the 'totalRecords', that is because if you request a page number
|
||||
// that doesn't actually have any data on it, the totalRecords will still indicate there are records but there are none in
|
||||
// the pageResult.
|
||||
totalRecords = Convert.ToInt32(pagedResult.TotalItems);
|
||||
|
||||
//NOTE: We need to check the actual items returned, not the 'totalRecords', that is because if you request a page number
|
||||
// that doesn't actually have any data on it, the totalRecords will still indicate there are records but there are none in
|
||||
// the pageResult.
|
||||
if (pagedResult.Items.Any())
|
||||
{
|
||||
//Create the inner paged query that was used above to get the paged result, we'll use that as the inner sub query
|
||||
var args = sqlNodeIdsWithSort.Arguments;
|
||||
string sqlStringCount, sqlStringPage;
|
||||
Database.BuildPageQueries<UserDto>(pageIndex * pageSize, pageSize, sqlNodeIdsWithSort.SQL, ref args, out sqlStringCount, out sqlStringPage);
|
||||
|
||||
var sqlQueryFull = translatorFull.Translate();
|
||||
|
||||
var sqlQueryFull = GetBaseQuery("umbracoUser.*, umbracoUserGroup.*, umbracoUserGroup2App.*, umbracoUserStartNode.*");
|
||||
|
||||
var fullQueryWithPagedInnerJoin = sqlQueryFull
|
||||
.Append("INNER JOIN (")
|
||||
//join the paged query with the paged query arguments
|
||||
//We need to make this FULL query an inner join on the paged ID query
|
||||
var splitQuery = sqlQueryFull.SQL.Split(new[] { "WHERE " }, StringSplitOptions.None);
|
||||
var fullQueryWithPagedInnerJoin = new Sql(splitQuery[0])
|
||||
.Append("INNER JOIN (")
|
||||
//join the paged query with the paged query arguments
|
||||
.Append(sqlStringPage, args)
|
||||
.Append(") temp ")
|
||||
.Append("ON umbracoUser.id = temp.id");
|
||||
|
||||
AddGroupLeftJoin(fullQueryWithPagedInnerJoin);
|
||||
|
||||
if (splitQuery.Length > 1)
|
||||
{
|
||||
//add the original where clause back with the original arguments
|
||||
fullQueryWithPagedInnerJoin.Where(splitQuery[1], sqlQueryIds.Arguments);
|
||||
}
|
||||
|
||||
//get sorted and filtered sql
|
||||
var fullQuery = GetSortedSqlForPagedResults(
|
||||
GetFilteredSqlForPagedResults(fullQueryWithPagedInnerJoin, filterSql),
|
||||
GetFilteredSqlForPagedResults(fullQueryWithPagedInnerJoin, filterSql, queryHasWhereClause),
|
||||
orderDirection, orderBy);
|
||||
|
||||
var users = ConvertFromDtos(Database.Fetch<UserDto, UserGroupDto, UserGroup2AppDto, UserStartNodeDto, UserDto>(new UserGroupRelator().Map, fullQuery))
|
||||
.ToArray(); // important so we don't iterate twice, if we don't do this we can end up with null values in cache if we were caching.
|
||||
|
||||
return users;
|
||||
}
|
||||
}
|
||||
|
||||
return Enumerable.Empty<IUser>();
|
||||
}
|
||||
|
||||
private Sql GetFilteredSqlForPagedResults(Sql sql, Sql filterSql)
|
||||
private Sql GetFilteredSqlForPagedResults(Sql sql, Sql filterSql, bool hasWhereClause)
|
||||
{
|
||||
Sql filteredSql;
|
||||
|
||||
// Apply filter
|
||||
if (filterSql != null)
|
||||
{
|
||||
var sqlFilter = " WHERE " + filterSql.SQL.TrimStart("AND ");
|
||||
//ensure we don't append a WHERE if there is already one
|
||||
var sqlFilter = hasWhereClause
|
||||
? filterSql.SQL
|
||||
: " WHERE " + filterSql.SQL.TrimStart("AND ");
|
||||
|
||||
//NOTE: this is certainly strange - NPoco handles this much better but we need to re-create the sql
|
||||
// instance a couple of times to get the parameter order correct, for some reason the first
|
||||
|
||||
@@ -290,6 +290,9 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
// Apply filter
|
||||
if (defaultFilter != null)
|
||||
{
|
||||
//NOTE: It is assumed here that the `sql` already contains a WHERE clause, see UserRepository.GetFilteredSqlForPagedResults
|
||||
// for an example of when it's not assumed there's already a WHERE clause
|
||||
|
||||
var filterResult = defaultFilter();
|
||||
|
||||
//NOTE: this is certainly strange - NPoco handles this much better but we need to re-create the sql
|
||||
@@ -993,4 +996,4 @@ ORDER BY contentNodeId, versionId, propertytypeid
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,189 +1,188 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
|
||||
|
||||
namespace Umbraco.Core.Persistence.SqlSyntax
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents an SqlSyntaxProvider for Sql Server.
|
||||
/// </summary>
|
||||
[SqlSyntaxProvider(Constants.DatabaseProviders.SqlServer)]
|
||||
public class SqlServerSyntaxProvider : MicrosoftSqlSyntaxProviderBase<SqlServerSyntaxProvider>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets/sets the version of the current SQL server instance
|
||||
/// </summary>
|
||||
internal SqlServerVersionName GetVersionName(Database database)
|
||||
{
|
||||
if (_versionName.HasValue)
|
||||
return _versionName.Value;
|
||||
|
||||
try
|
||||
{
|
||||
var version = database.ExecuteScalar<string>("SELECT SERVERPROPERTY('productversion')");
|
||||
var firstPart = version.Split('.')[0];
|
||||
switch (firstPart)
|
||||
{
|
||||
case "13":
|
||||
_versionName = SqlServerVersionName.V2016;
|
||||
break;
|
||||
case "12":
|
||||
_versionName = SqlServerVersionName.V2014;
|
||||
break;
|
||||
case "11":
|
||||
_versionName = SqlServerVersionName.V2012;
|
||||
break;
|
||||
case "10":
|
||||
_versionName = SqlServerVersionName.V2008;
|
||||
break;
|
||||
case "9":
|
||||
_versionName = SqlServerVersionName.V2005;
|
||||
break;
|
||||
case "8":
|
||||
_versionName = SqlServerVersionName.V2000;
|
||||
break;
|
||||
case "7":
|
||||
_versionName = SqlServerVersionName.V7;
|
||||
break;
|
||||
default:
|
||||
_versionName = SqlServerVersionName.Other;
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
_versionName = SqlServerVersionName.Invalid;
|
||||
}
|
||||
|
||||
return _versionName.Value;
|
||||
}
|
||||
|
||||
private SqlServerVersionName? _versionName;
|
||||
|
||||
/// <summary>
|
||||
/// SQL Server stores default values assigned to columns as constraints, it also stores them with named values, this is the only
|
||||
/// server type that does this, therefore this method doesn't exist on any other syntax provider
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public IEnumerable<Tuple<string, string, string, string>> GetDefaultConstraintsPerColumn(Database 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");
|
||||
return items.Select(x => new Tuple<string, string, string, string>(x.TableName, x.ColumnName, x.Name, x.Definition));
|
||||
}
|
||||
|
||||
public override IEnumerable<string> GetTablesInSchema(Database db)
|
||||
{
|
||||
var items = db.Fetch<dynamic>("SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES");
|
||||
return items.Select(x => x.TABLE_NAME).Cast<string>().ToList();
|
||||
}
|
||||
|
||||
public override IEnumerable<ColumnInfo> GetColumnsInSchema(Database db)
|
||||
{
|
||||
var items = db.Fetch<dynamic>("SELECT TABLE_NAME, COLUMN_NAME, ORDINAL_POSITION, COLUMN_DEFAULT, IS_NULLABLE, DATA_TYPE FROM INFORMATION_SCHEMA.COLUMNS");
|
||||
return
|
||||
items.Select(
|
||||
item =>
|
||||
new ColumnInfo(item.TABLE_NAME, item.COLUMN_NAME, item.ORDINAL_POSITION, item.COLUMN_DEFAULT,
|
||||
item.IS_NULLABLE, item.DATA_TYPE)).ToList();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override IEnumerable<Tuple<string, string>> GetConstraintsPerTable(Database db)
|
||||
{
|
||||
var items =
|
||||
db.Fetch<dynamic>(
|
||||
"SELECT TABLE_NAME, CONSTRAINT_NAME FROM INFORMATION_SCHEMA.CONSTRAINT_TABLE_USAGE");
|
||||
return items.Select(item => new Tuple<string, string>(item.TABLE_NAME, item.CONSTRAINT_NAME)).ToList();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override IEnumerable<Tuple<string, string, string>> GetConstraintsPerColumn(Database db)
|
||||
{
|
||||
var items =
|
||||
db.Fetch<dynamic>(
|
||||
"SELECT TABLE_NAME, COLUMN_NAME, CONSTRAINT_NAME FROM INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE");
|
||||
return items.Select(item => new Tuple<string, string, string>(item.TABLE_NAME, item.COLUMN_NAME, item.CONSTRAINT_NAME)).ToList();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override IEnumerable<Tuple<string, string, string, bool>> GetDefinedIndexes(Database db)
|
||||
{
|
||||
var items =
|
||||
db.Fetch<dynamic>(
|
||||
@"select T.name as TABLE_NAME, I.name as INDEX_NAME, AC.Name as COLUMN_NAME,
|
||||
CASE WHEN I.is_unique_constraint = 1 OR I.is_unique = 1 THEN 1 ELSE 0 END AS [UNIQUE]
|
||||
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
|
||||
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();
|
||||
|
||||
}
|
||||
|
||||
public override bool DoesTableExist(Database db, string tableName)
|
||||
{
|
||||
var result =
|
||||
db.ExecuteScalar<long>("SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = @TableName",
|
||||
new { TableName = tableName });
|
||||
|
||||
return result > 0;
|
||||
}
|
||||
|
||||
public override string FormatColumnRename(string tableName, string oldName, string newName)
|
||||
{
|
||||
return string.Format(RenameColumn, tableName, oldName, newName);
|
||||
}
|
||||
|
||||
public override string FormatTableRename(string oldName, string newName)
|
||||
{
|
||||
return string.Format(RenameTable, oldName, newName);
|
||||
}
|
||||
|
||||
protected override string FormatIdentity(ColumnDefinition column)
|
||||
{
|
||||
return column.IsIdentity ? GetIdentityString(column) : string.Empty;
|
||||
}
|
||||
|
||||
public override Sql SelectTop(Sql sql, int top)
|
||||
{
|
||||
return new Sql(sql.SQL.Insert(sql.SQL.IndexOf(' '), " TOP " + top), sql.Arguments);
|
||||
}
|
||||
|
||||
private static string GetIdentityString(ColumnDefinition column)
|
||||
{
|
||||
return "IDENTITY(1,1)";
|
||||
}
|
||||
|
||||
protected override string FormatSystemMethods(SystemMethods systemMethod)
|
||||
{
|
||||
switch (systemMethod)
|
||||
{
|
||||
case SystemMethods.NewGuid:
|
||||
return "NEWID()";
|
||||
case SystemMethods.CurrentDateTime:
|
||||
return "GETDATE()";
|
||||
//case SystemMethods.NewSequentialId:
|
||||
// return "NEWSEQUENTIALID()";
|
||||
//case SystemMethods.CurrentUTCDateTime:
|
||||
// return "GETUTCDATE()";
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public override string DeleteDefaultConstraint
|
||||
{
|
||||
get { return "ALTER TABLE [{0}] DROP CONSTRAINT [DF_{0}_{1}]"; }
|
||||
}
|
||||
|
||||
|
||||
public override string DropIndex { get { return "DROP INDEX {0} ON {1}"; } }
|
||||
|
||||
public override string RenameColumn { get { return "sp_rename '{0}.{1}', '{2}', 'COLUMN'"; } }
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
|
||||
|
||||
namespace Umbraco.Core.Persistence.SqlSyntax
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents an SqlSyntaxProvider for Sql Server.
|
||||
/// </summary>
|
||||
[SqlSyntaxProvider(Constants.DatabaseProviders.SqlServer)]
|
||||
public class SqlServerSyntaxProvider : MicrosoftSqlSyntaxProviderBase<SqlServerSyntaxProvider>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets/sets the version of the current SQL server instance
|
||||
/// </summary>
|
||||
internal SqlServerVersionName GetVersionName(Database database)
|
||||
{
|
||||
if (_versionName.HasValue)
|
||||
return _versionName.Value;
|
||||
|
||||
try
|
||||
{
|
||||
var version = database.ExecuteScalar<string>("SELECT SERVERPROPERTY('productversion')");
|
||||
var firstPart = version.Split('.')[0];
|
||||
switch (firstPart)
|
||||
{
|
||||
case "13":
|
||||
_versionName = SqlServerVersionName.V2016;
|
||||
break;
|
||||
case "12":
|
||||
_versionName = SqlServerVersionName.V2014;
|
||||
break;
|
||||
case "11":
|
||||
_versionName = SqlServerVersionName.V2012;
|
||||
break;
|
||||
case "10":
|
||||
_versionName = SqlServerVersionName.V2008;
|
||||
break;
|
||||
case "9":
|
||||
_versionName = SqlServerVersionName.V2005;
|
||||
break;
|
||||
case "8":
|
||||
_versionName = SqlServerVersionName.V2000;
|
||||
break;
|
||||
case "7":
|
||||
_versionName = SqlServerVersionName.V7;
|
||||
break;
|
||||
default:
|
||||
_versionName = SqlServerVersionName.Other;
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
_versionName = SqlServerVersionName.Invalid;
|
||||
}
|
||||
|
||||
return _versionName.Value;
|
||||
}
|
||||
|
||||
private SqlServerVersionName? _versionName;
|
||||
|
||||
/// <summary>
|
||||
/// SQL Server stores default values assigned to columns as constraints, it also stores them with named values, this is the only
|
||||
/// server type that does this, therefore this method doesn't exist on any other syntax provider
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public IEnumerable<Tuple<string, string, string, string>> GetDefaultConstraintsPerColumn(Database 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 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(Database db)
|
||||
{
|
||||
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(Database db)
|
||||
{
|
||||
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 =>
|
||||
new ColumnInfo(item.TABLE_NAME, item.COLUMN_NAME, item.ORDINAL_POSITION, item.COLUMN_DEFAULT,
|
||||
item.IS_NULLABLE, item.DATA_TYPE)).ToList();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override IEnumerable<Tuple<string, string>> GetConstraintsPerTable(Database db)
|
||||
{
|
||||
var items =
|
||||
db.Fetch<dynamic>(
|
||||
"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();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override IEnumerable<Tuple<string, string, string>> GetConstraintsPerColumn(Database db)
|
||||
{
|
||||
var items =
|
||||
db.Fetch<dynamic>(
|
||||
"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();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override IEnumerable<Tuple<string, string, string, bool>> GetDefinedIndexes(Database db)
|
||||
{
|
||||
var items =
|
||||
db.Fetch<dynamic>(
|
||||
@"select T.name as TABLE_NAME, I.name as INDEX_NAME, AC.Name as COLUMN_NAME,
|
||||
CASE WHEN I.is_unique_constraint = 1 OR I.is_unique = 1 THEN 1 ELSE 0 END AS [UNIQUE]
|
||||
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]
|
||||
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();
|
||||
|
||||
}
|
||||
|
||||
public override bool DoesTableExist(Database db, string tableName)
|
||||
{
|
||||
var result =
|
||||
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;
|
||||
}
|
||||
|
||||
public override string FormatColumnRename(string tableName, string oldName, string newName)
|
||||
{
|
||||
return string.Format(RenameColumn, tableName, oldName, newName);
|
||||
}
|
||||
|
||||
public override string FormatTableRename(string oldName, string newName)
|
||||
{
|
||||
return string.Format(RenameTable, oldName, newName);
|
||||
}
|
||||
|
||||
protected override string FormatIdentity(ColumnDefinition column)
|
||||
{
|
||||
return column.IsIdentity ? GetIdentityString(column) : string.Empty;
|
||||
}
|
||||
|
||||
public override Sql SelectTop(Sql sql, int top)
|
||||
{
|
||||
return new Sql(sql.SQL.Insert(sql.SQL.IndexOf(' '), " TOP " + top), sql.Arguments);
|
||||
}
|
||||
|
||||
private static string GetIdentityString(ColumnDefinition column)
|
||||
{
|
||||
return "IDENTITY(1,1)";
|
||||
}
|
||||
|
||||
protected override string FormatSystemMethods(SystemMethods systemMethod)
|
||||
{
|
||||
switch (systemMethod)
|
||||
{
|
||||
case SystemMethods.NewGuid:
|
||||
return "NEWID()";
|
||||
case SystemMethods.CurrentDateTime:
|
||||
return "GETDATE()";
|
||||
//case SystemMethods.NewSequentialId:
|
||||
// return "NEWSEQUENTIALID()";
|
||||
//case SystemMethods.CurrentUTCDateTime:
|
||||
// return "GETUTCDATE()";
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public override string DeleteDefaultConstraint
|
||||
{
|
||||
get { return "ALTER TABLE [{0}] DROP CONSTRAINT [DF_{0}_{1}]"; }
|
||||
}
|
||||
|
||||
|
||||
public override string DropIndex { get { return "DROP INDEX {0} ON {1}"; } }
|
||||
|
||||
public override string RenameColumn { get { return "sp_rename '{0}.{1}', '{2}', 'COLUMN'"; } }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.ComponentModel;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
@@ -458,5 +460,23 @@ namespace Umbraco.Core.Security
|
||||
|
||||
return ticket;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensures that the thread culture is set based on the back office user's culture
|
||||
/// </summary>
|
||||
/// <param name="identity"></param>
|
||||
internal static void EnsureCulture(this IIdentity identity)
|
||||
{
|
||||
if (identity is UmbracoBackOfficeIdentity umbIdentity && umbIdentity.IsAuthenticated)
|
||||
{
|
||||
Thread.CurrentThread.CurrentUICulture =
|
||||
Thread.CurrentThread.CurrentCulture =
|
||||
UserCultures.GetOrAdd(umbIdentity.Culture, s => new CultureInfo(s));
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Used so that we aren't creating a new CultureInfo object for every single request
|
||||
/// </summary>
|
||||
private static readonly ConcurrentDictionary<string, CultureInfo> UserCultures = new ConcurrentDictionary<string, CultureInfo>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,7 +102,8 @@ namespace Umbraco.Core.Security
|
||||
/// <returns/>
|
||||
public override async Task ValidateIdentity(CookieValidateIdentityContext context)
|
||||
{
|
||||
EnsureCulture(context);
|
||||
//ensure the thread culture is set
|
||||
context?.Identity?.EnsureCulture();
|
||||
|
||||
await EnsureValidSessionId(context);
|
||||
|
||||
@@ -120,21 +121,5 @@ namespace Umbraco.Core.Security
|
||||
if (_appCtx.IsConfigured && _appCtx.IsUpgrading == false)
|
||||
await SessionIdValidator.ValidateSessionAsync(TimeSpan.FromMinutes(1), context);
|
||||
}
|
||||
|
||||
private void EnsureCulture(CookieValidateIdentityContext context)
|
||||
{
|
||||
var umbIdentity = context.Identity as UmbracoBackOfficeIdentity;
|
||||
if (umbIdentity != null && umbIdentity.IsAuthenticated)
|
||||
{
|
||||
Thread.CurrentThread.CurrentCulture =
|
||||
Thread.CurrentThread.CurrentUICulture =
|
||||
UserCultures.GetOrAdd(umbIdentity.Culture, s => new CultureInfo(s));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used so that we aren't creating a new CultureInfo object for every single request
|
||||
/// </summary>
|
||||
private static readonly ConcurrentDictionary<string, CultureInfo> UserCultures = new ConcurrentDictionary<string, CultureInfo>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -236,7 +236,10 @@ namespace Umbraco.Core.Security
|
||||
|
||||
if (dataProtectionProvider != null)
|
||||
{
|
||||
manager.UserTokenProvider = new DataProtectorTokenProvider<T, int>(dataProtectionProvider.Create("ASP.NET Identity"));
|
||||
manager.UserTokenProvider = new DataProtectorTokenProvider<T, int>(dataProtectionProvider.Create("ASP.NET Identity"))
|
||||
{
|
||||
TokenLifespan = TimeSpan.FromDays(3)
|
||||
};
|
||||
}
|
||||
|
||||
manager.UserLockoutEnabledByDefault = true;
|
||||
@@ -748,6 +751,7 @@ namespace Umbraco.Core.Security
|
||||
var httpContext = HttpContext.Current == null ? (HttpContextBase)null : new HttpContextWrapper(HttpContext.Current);
|
||||
return httpContext.GetCurrentRequestIpAddress();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -630,7 +630,9 @@ namespace Umbraco.Core.Security
|
||||
|| identityUser.LastLoginDateUtc.HasValue && user.LastLoginDate.ToUniversalTime() != identityUser.LastLoginDateUtc.Value)
|
||||
{
|
||||
anythingChanged = true;
|
||||
user.LastLoginDate = identityUser.LastLoginDateUtc.Value.ToLocalTime();
|
||||
//if the LastLoginDate is being set to MinValue, don't convert it ToLocalTime
|
||||
var dt = identityUser.LastLoginDateUtc == DateTime.MinValue ? DateTime.MinValue : identityUser.LastLoginDateUtc.Value.ToLocalTime();
|
||||
user.LastLoginDate = dt;
|
||||
}
|
||||
if (identityUser.IsPropertyDirty("LastPasswordChangeDateUtc")
|
||||
|| (user.LastPasswordChangeDate != default(DateTime) && identityUser.LastPasswordChangeDateUtc.HasValue == false)
|
||||
|
||||
@@ -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)
|
||||
@@ -963,4 +963,4 @@ namespace Umbraco.Core.Security
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2060,12 +2060,15 @@ namespace Umbraco.Core.Services
|
||||
using (new WriteLock(Locker))
|
||||
{
|
||||
var allContent = GetByIds(ids).ToDictionary(x => x.Id, x => x);
|
||||
var items = ids.Select(x => allContent[x]);
|
||||
if (allContent.Any() == false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
var items = ids.Select(x => allContent[x]).ToArray();
|
||||
|
||||
using (var uow = UowProvider.GetUnitOfWork())
|
||||
{
|
||||
var asArray = items.ToArray();
|
||||
var saveEventArgs = new SaveEventArgs<IContent>(asArray);
|
||||
var saveEventArgs = new SaveEventArgs<IContent>(items);
|
||||
if (raiseEvents && uow.Events.DispatchCancelable(Saving, this, saveEventArgs, "Saving"))
|
||||
{
|
||||
uow.Commit();
|
||||
@@ -2075,7 +2078,7 @@ namespace Umbraco.Core.Services
|
||||
var repository = RepositoryFactory.CreateContentRepository(uow);
|
||||
|
||||
var i = 0;
|
||||
foreach (var content in asArray)
|
||||
foreach (var content in items)
|
||||
{
|
||||
//If the current sort order equals that of the content
|
||||
//we don't need to update it, so just increment the sort order
|
||||
@@ -2122,7 +2125,7 @@ namespace Umbraco.Core.Services
|
||||
_publishingStrategy.PublishingFinalized(uow, shouldBePublished, false);
|
||||
}
|
||||
|
||||
Audit(uow, AuditType.Sort, "Sorting content performed by user", userId, 0);
|
||||
Audit(uow, AuditType.Sort, "Sort child items performed by user", userId, items.First().ParentId);
|
||||
uow.Commit();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ namespace Umbraco.Core.Services
|
||||
private Dictionary<string, IContentType> _importedContentTypes;
|
||||
private IPackageInstallation _packageInstallation;
|
||||
private readonly IUserService _userService;
|
||||
|
||||
private static HttpClient _httpClient;
|
||||
|
||||
public PackagingService(
|
||||
ILogger logger,
|
||||
@@ -89,7 +89,6 @@ namespace Umbraco.Core.Services
|
||||
/// <returns></returns>
|
||||
public string FetchPackageFile(Guid packageId, Version umbracoVersion, int userId)
|
||||
{
|
||||
using (var httpClient = new HttpClient())
|
||||
using (var uow = _uowProvider.GetUnitOfWork())
|
||||
{
|
||||
//includeHidden = true because we don't care if it's hidden we want to get the file regardless
|
||||
@@ -97,7 +96,11 @@ namespace Umbraco.Core.Services
|
||||
byte[] bytes;
|
||||
try
|
||||
{
|
||||
bytes = httpClient.GetByteArrayAsync(url).GetAwaiter().GetResult();
|
||||
if (_httpClient == null)
|
||||
{
|
||||
_httpClient = new HttpClient();
|
||||
}
|
||||
bytes = _httpClient.GetByteArrayAsync(url).GetAwaiter().GetResult();
|
||||
}
|
||||
catch (HttpRequestException ex)
|
||||
{
|
||||
@@ -1746,7 +1749,7 @@ namespace Umbraco.Core.Services
|
||||
|
||||
internal InstallationSummary InstallPackage(string packageFilePath, int userId = 0, bool raiseEvents = false)
|
||||
{
|
||||
var metaData = GetPackageMetaData(packageFilePath);
|
||||
var metaData = GetPackageMetaData(packageFilePath);
|
||||
|
||||
if (raiseEvents)
|
||||
{
|
||||
|
||||
@@ -77,7 +77,7 @@ namespace Umbraco.Core.Services
|
||||
regs = xr.Repository.GetAll().ToArray();
|
||||
|
||||
// default role is single server, but if registrations contain more
|
||||
// than one active server, then role is master or slave
|
||||
// than one active server, then role is master or replica
|
||||
_currentServerRole = regs.Count(x => x.IsActive) > 1
|
||||
? (server.IsMaster ? ServerRole.Master : ServerRole.Slave)
|
||||
: ServerRole.Single;
|
||||
@@ -175,4 +175,4 @@ namespace Umbraco.Core.Services
|
||||
return _currentServerRole;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1574,5 +1574,29 @@ namespace Umbraco.Core
|
||||
guid[left] = guid[right];
|
||||
guid[right] = temp;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a file name to a friendly name for a content item
|
||||
/// </summary>
|
||||
/// <param name="fileName"></param>
|
||||
/// <returns></returns>
|
||||
public static string ToFriendlyName(this string fileName)
|
||||
{
|
||||
// strip the file extension
|
||||
fileName = fileName.StripFileExtension();
|
||||
|
||||
// underscores and dashes to spaces
|
||||
fileName = fileName.ReplaceMany(new[] { '_', '-' }, ' ');
|
||||
|
||||
// any other conversions ?
|
||||
|
||||
// Pascalcase (to be done last)
|
||||
fileName = System.Threading.Thread.CurrentThread.CurrentCulture.TextInfo.ToTitleCase(fileName);
|
||||
|
||||
// Replace multiple consecutive spaces with a single space
|
||||
fileName = string.Join(" ", fileName.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries));
|
||||
|
||||
return fileName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace Umbraco.Core.Sync
|
||||
Single = 1,
|
||||
|
||||
/// <summary>
|
||||
/// In a multi-servers environment, the server is a slave server.
|
||||
/// In a multi-servers environment, the server is a replica server.
|
||||
/// </summary>
|
||||
Slave = 2,
|
||||
|
||||
@@ -25,4 +25,4 @@ namespace Umbraco.Core.Sync
|
||||
/// </summary>
|
||||
Master = 3
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
@@ -45,8 +45,8 @@
|
||||
<Reference Include="AutoMapper.Net4, Version=3.3.1.0, Culture=neutral, PublicKeyToken=be96cd2c38ef1005, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\AutoMapper.3.3.1\lib\net40\AutoMapper.Net4.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="ClientDependency.Core, Version=1.9.6.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\ClientDependency.1.9.6\lib\net45\ClientDependency.Core.dll</HintPath>
|
||||
<Reference Include="ClientDependency.Core, Version=1.9.7.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\ClientDependency.1.9.7\lib\net45\ClientDependency.Core.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="HtmlAgilityPack, Version=1.4.9.5, Culture=neutral, PublicKeyToken=bd319b19eaf3b43a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\HtmlAgilityPack.1.4.9.5\lib\Net45\HtmlAgilityPack.dll</HintPath>
|
||||
@@ -365,6 +365,11 @@
|
||||
<Compile Include="IEmailSender.cs" />
|
||||
<Compile Include="IHttpContextAccessor.cs" />
|
||||
<Compile Include="Logging\RollingFileCleanupAppender.cs" />
|
||||
<Compile Include="Media\Exif\SVGFile.cs" />
|
||||
<Compile Include="Media\TypeDetector\JPEGDetector.cs" />
|
||||
<Compile Include="Media\TypeDetector\RasterizedTypeDetector.cs" />
|
||||
<Compile Include="Media\TypeDetector\SVGDetector.cs" />
|
||||
<Compile Include="Media\TypeDetector\TIFFDetector.cs" />
|
||||
<Compile Include="Models\AuditEntry.cs" />
|
||||
<Compile Include="Models\Consent.cs" />
|
||||
<Compile Include="Models\ConsentExtensions.cs" />
|
||||
@@ -567,8 +572,8 @@
|
||||
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenEightZero\AddInstructionCountColumn.cs" />
|
||||
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenEightZero\AddCmsMediaTable.cs" />
|
||||
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenEightZero\AddUserLoginTable.cs" />
|
||||
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenTwelveZero\RenameTrueFalseField.cs" />
|
||||
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenTwelveZero\SetDefaultTagsStorageType.cs" />
|
||||
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenTwelveZero\RenameTrueFalseField.cs" />
|
||||
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenTwelveZero\SetDefaultTagsStorageType.cs" />
|
||||
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenNineZero\AddUmbracoAuditTable.cs" />
|
||||
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenNineZero\AddUmbracoConsentTable.cs" />
|
||||
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenNineZero\AddIsSensitiveMemberTypeColumn.cs" />
|
||||
@@ -638,7 +643,7 @@
|
||||
<Compile Include="Media\Exif\TIFFStrip.cs" />
|
||||
<Compile Include="Media\Exif\Utility.cs" />
|
||||
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenThreeOne\UpdateUserLanguagesToIsoCode.cs" />
|
||||
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenTwelveZero\IncreaseLanguageIsoCodeColumnLength.cs" />
|
||||
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenTwelveZero\IncreaseLanguageIsoCodeColumnLength.cs" />
|
||||
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenTwelveZero\UpdateUmbracoConsent.cs" />
|
||||
<Compile Include="Persistence\PocoDataDataReader.cs" />
|
||||
<Compile Include="Persistence\Querying\CachedExpression.cs" />
|
||||
@@ -1688,4 +1693,4 @@
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
||||
</Project>
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="AutoMapper" version="3.3.1" targetFramework="net45" />
|
||||
<package id="ClientDependency" version="1.9.6" targetFramework="net45" />
|
||||
<package id="ClientDependency" version="1.9.7" targetFramework="net45" />
|
||||
<package id="HtmlAgilityPack" version="1.4.9.5" targetFramework="net45" />
|
||||
<package id="ImageProcessor" version="2.5.6" targetFramework="net45" />
|
||||
<package id="log4net" version="2.0.8" targetFramework="net45" />
|
||||
|
||||
@@ -129,7 +129,7 @@ namespace Umbraco.Tests
|
||||
public void SetApplicationUrlFromDcSettingsSsl2()
|
||||
{
|
||||
// set from distributed call settings
|
||||
// other servers are slave servers
|
||||
// other servers are replica servers
|
||||
|
||||
var settings = Mock.Of<IUmbracoSettingsSection>(section =>
|
||||
section.DistributedCall == Mock.Of<IDistributedCallSection>(callSection => callSection.Enabled == true && callSection.Servers == new IServer[]
|
||||
@@ -224,7 +224,7 @@ namespace Umbraco.Tests
|
||||
[Test]
|
||||
public void ServerRoleUnknown2()
|
||||
{
|
||||
// distributed call enabled, cannot find server, assume it's an undeclared slave
|
||||
// distributed call enabled, cannot find server, assume it's an undeclared replica
|
||||
|
||||
var settings = Mock.Of<IUmbracoSettingsSection>(section =>
|
||||
section.DistributedCall == Mock.Of<IDistributedCallSection>(callSection => callSection.Enabled == true && callSection.Servers == new IServer[]
|
||||
@@ -301,4 +301,4 @@ namespace Umbraco.Tests
|
||||
Assert.AreEqual("httpx://whatever.com/umbraco", appCtx._umbracoApplicationUrl);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
{
|
||||
|
||||
@@ -66,6 +66,46 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Get_Paged_Items_By_User_Id_With_Query_And_Filter()
|
||||
{
|
||||
var provider = new PetaPocoUnitOfWorkProvider(Logger);
|
||||
var unitOfWork = provider.GetUnitOfWork();
|
||||
using (var repo = new AuditRepository(unitOfWork, CacheHelper, Logger, SqlSyntax))
|
||||
{
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
repo.AddOrUpdate(new AuditItem(i, string.Format("Content {0} created", i), AuditType.New, 0));
|
||||
repo.AddOrUpdate(new AuditItem(i, string.Format("Content {0} published", i), AuditType.Publish, 0));
|
||||
}
|
||||
unitOfWork.Commit();
|
||||
}
|
||||
|
||||
using (var repo = new AuditRepository(unitOfWork, CacheHelper, Logger, SqlSyntax))
|
||||
{
|
||||
var query = Query<IAuditItem>.Builder.Where(x => x.UserId == 0);
|
||||
|
||||
try
|
||||
{
|
||||
DatabaseContext.Database.EnableSqlTrace = true;
|
||||
DatabaseContext.Database.EnableSqlCount();
|
||||
|
||||
var page = repo.GetPagedResultsByQuery(query, 0, 10, out var total, Direction.Descending,
|
||||
new[] { AuditType.Publish },
|
||||
Query<IAuditItem>.Builder.Where(x => x.UserId > -1));
|
||||
|
||||
Assert.AreEqual(10, page.Count());
|
||||
Assert.AreEqual(100, total);
|
||||
}
|
||||
finally
|
||||
{
|
||||
DatabaseContext.Database.EnableSqlTrace = false;
|
||||
DatabaseContext.Database.DisableSqlCount();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void Get_Paged_Items_With_AuditType_Filter()
|
||||
{
|
||||
@@ -83,14 +123,24 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
|
||||
using (var repo = new AuditRepository(unitOfWork, CacheHelper, Logger, SqlSyntax))
|
||||
{
|
||||
long total;
|
||||
var page = repo.GetPagedResultsByQuery(Query<IAuditItem>.Builder, 0, 9, out total, Direction.Descending,
|
||||
new[] {AuditType.Publish}, null)
|
||||
.ToArray();
|
||||
try
|
||||
{
|
||||
DatabaseContext.Database.EnableSqlTrace = true;
|
||||
DatabaseContext.Database.EnableSqlCount();
|
||||
|
||||
Assert.AreEqual(9, page.Length);
|
||||
Assert.IsTrue(page.All(x => x.AuditType == AuditType.Publish));
|
||||
Assert.AreEqual(100, total);
|
||||
var page = repo.GetPagedResultsByQuery(Query<IAuditItem>.Builder, 0, 9, out var total, Direction.Descending,
|
||||
new[] { AuditType.Publish }, null)
|
||||
.ToArray();
|
||||
|
||||
Assert.AreEqual(9, page.Length);
|
||||
Assert.IsTrue(page.All(x => x.AuditType == AuditType.Publish));
|
||||
Assert.AreEqual(100, total);
|
||||
}
|
||||
finally
|
||||
{
|
||||
DatabaseContext.Database.EnableSqlTrace = false;
|
||||
DatabaseContext.Database.DisableSqlCount();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,15 +161,25 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
|
||||
using (var repo = new AuditRepository(unitOfWork, CacheHelper, Logger, SqlSyntax))
|
||||
{
|
||||
long total;
|
||||
var page = repo.GetPagedResultsByQuery(Query<IAuditItem>.Builder, 0, 8, out total, Direction.Descending,
|
||||
null, Query<IAuditItem>.Builder.Where(item => item.Comment == "Content created"))
|
||||
.ToArray();
|
||||
try
|
||||
{
|
||||
DatabaseContext.Database.EnableSqlTrace = true;
|
||||
DatabaseContext.Database.EnableSqlCount();
|
||||
|
||||
Assert.AreEqual(8, page.Length);
|
||||
Assert.IsTrue(page.All(x => x.Comment == "Content created"));
|
||||
Assert.AreEqual(100, total);
|
||||
var page = repo.GetPagedResultsByQuery(Query<IAuditItem>.Builder, 0, 8, out var total, Direction.Descending,
|
||||
null, Query<IAuditItem>.Builder.Where(item => item.Comment == "Content created"))
|
||||
.ToArray();
|
||||
|
||||
Assert.AreEqual(8, page.Length);
|
||||
Assert.IsTrue(page.All(x => x.Comment == "Content created"));
|
||||
Assert.AreEqual(100, total);
|
||||
}
|
||||
finally
|
||||
{
|
||||
DatabaseContext.Database.EnableSqlTrace = false;
|
||||
DatabaseContext.Database.DisableSqlCount();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ using Umbraco.Core.Configuration.UmbracoSettings;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models.Membership;
|
||||
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
using Umbraco.Core.Persistence.Repositories;
|
||||
using Umbraco.Core.Persistence.UnitOfWork;
|
||||
@@ -392,7 +393,71 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
var result = repository.Count(query);
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Is.GreaterThanOrEqualTo(2));
|
||||
Assert.AreEqual(2, result);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Can_Get_Paged_Results_By_Query_And_Filter_And_Groups()
|
||||
{
|
||||
// Arrange
|
||||
var provider = new PetaPocoUnitOfWorkProvider(Logger);
|
||||
var unitOfWork = provider.GetUnitOfWork();
|
||||
using (var repository = CreateRepository(unitOfWork))
|
||||
{
|
||||
var users = CreateAndCommitMultipleUsers(repository, unitOfWork);
|
||||
var query = Query<IUser>.Builder.Where(x => x.Username == "TestUser1" || x.Username == "TestUser2");
|
||||
|
||||
try
|
||||
{
|
||||
DatabaseContext.Database.EnableSqlTrace = true;
|
||||
DatabaseContext.Database.EnableSqlCount();
|
||||
|
||||
// Act
|
||||
var result = repository.GetPagedResultsByQuery(query, 0, 10, out var totalRecs, user => user.Id, Direction.Ascending,
|
||||
excludeUserGroups: new[] { Constants.Security.TranslatorGroupAlias },
|
||||
filter: Query<IUser>.Builder.Where(x => x.Id > -1));
|
||||
|
||||
// Assert
|
||||
Assert.AreEqual(2, totalRecs);
|
||||
}
|
||||
finally
|
||||
{
|
||||
DatabaseContext.Database.EnableSqlTrace = false;
|
||||
DatabaseContext.Database.DisableSqlCount();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Can_Get_Paged_Results_With_Filter_And_Groups()
|
||||
{
|
||||
// Arrange
|
||||
var provider = new PetaPocoUnitOfWorkProvider(Logger);
|
||||
var unitOfWork = provider.GetUnitOfWork();
|
||||
using (var repository = CreateRepository(unitOfWork))
|
||||
{
|
||||
var users = CreateAndCommitMultipleUsers(repository, unitOfWork);
|
||||
|
||||
try
|
||||
{
|
||||
DatabaseContext.Database.EnableSqlTrace = true;
|
||||
DatabaseContext.Database.EnableSqlCount();
|
||||
|
||||
// Act
|
||||
var result = repository.GetPagedResultsByQuery(null, 0, 10, out var totalRecs, user => user.Id, Direction.Ascending,
|
||||
includeUserGroups: new[] { Constants.Security.AdminGroupAlias, Constants.Security.SensitiveDataGroupAlias },
|
||||
excludeUserGroups: new[] { Constants.Security.TranslatorGroupAlias },
|
||||
filter: Query<IUser>.Builder.Where(x => x.Id == 0));
|
||||
|
||||
// Assert
|
||||
Assert.AreEqual(1, totalRecs);
|
||||
}
|
||||
finally
|
||||
{
|
||||
DatabaseContext.Database.EnableSqlTrace = false;
|
||||
DatabaseContext.Database.DisableSqlCount();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -439,4 +504,4 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
return new IUser[] { user1, user2, user3 };
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -288,6 +288,29 @@ namespace Umbraco.Tests.Services
|
||||
Assert.AreEqual(2, membersInRole.Count());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Associate_Members_To_Roles_With_Member_Id_Casing()
|
||||
{
|
||||
ServiceContext.MemberService.AddRole("MyTestRole1");
|
||||
|
||||
IMemberType memberType = MockedContentTypes.CreateSimpleMemberType();
|
||||
ServiceContext.MemberTypeService.Save(memberType);
|
||||
var member1 = MockedMember.CreateSimpleMember(memberType, "test1", "test1@test.com", "pass", "test1");
|
||||
ServiceContext.MemberService.Save(member1);
|
||||
var member2 = MockedMember.CreateSimpleMember(memberType, "test2", "test2@test.com", "pass", "test2");
|
||||
ServiceContext.MemberService.Save(member2);
|
||||
|
||||
// temp make sure they exist
|
||||
Assert.IsNotNull(ServiceContext.MemberService.GetById(member1.Id));
|
||||
Assert.IsNotNull(ServiceContext.MemberService.GetById(member2.Id));
|
||||
|
||||
ServiceContext.MemberService.AssignRoles(new[] { member1.Id, member2.Id }, new[] { "mytestrole1" });
|
||||
|
||||
var membersInRole = ServiceContext.MemberService.GetMembersInRole("MyTestRole1");
|
||||
|
||||
Assert.AreEqual(2, membersInRole.Count());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Associate_Members_To_Roles_With_Member_Username()
|
||||
{
|
||||
@@ -1179,4 +1202,4 @@ namespace Umbraco.Tests.Services
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,19 +1,4 @@
|
||||
{
|
||||
"author": "Umbraco HQ",
|
||||
"name": "umbraco",
|
||||
"homepage": "https://github.com/umbraco/umbraco-cms/",
|
||||
"version": "7.1.2",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/umbraco/Umbraco-CMS.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://issues.umbraco.org"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8.4"
|
||||
},
|
||||
"scripts": {
|
||||
"install": "bower-installer",
|
||||
"test": "karma start test/config/karma.conf.js --singlerun",
|
||||
|
||||
@@ -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>
|
||||
@@ -1,4 +1,17 @@
|
||||
(function() {
|
||||
/**
|
||||
@ngdoc directive
|
||||
@name umbraco.directives.directive:umbTourStep
|
||||
@restrict E
|
||||
@scope
|
||||
|
||||
@description
|
||||
<b>Added in Umbraco 7.8</b>. The tour step component is a component that can be used in custom views for tour steps.
|
||||
|
||||
@param {callback} onClose The callback which should be performened when the close button of the tour step is clicked
|
||||
@param {boolean=} hideClose A boolean indicating if the close button needs to be shown
|
||||
|
||||
**/
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
function TourStepDirective() {
|
||||
|
||||
@@ -1,4 +1,17 @@
|
||||
(function() {
|
||||
/**
|
||||
@ngdoc directive
|
||||
@name umbraco.directives.directive:umbTourStepContent
|
||||
@restrict E
|
||||
@scope
|
||||
|
||||
@description
|
||||
<b>Added in Umbraco 7.8</b>. The tour step content component is a component that can be used in custom views for tour steps.
|
||||
It's meant to be used in the umb-tour-step directive.
|
||||
All markup in the body of the directive will be shown after the content attribute
|
||||
|
||||
@param {string} content The content that needs to be shown
|
||||
**/
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
function TourStepContentDirective() {
|
||||
|
||||
@@ -1,4 +1,18 @@
|
||||
(function() {
|
||||
/**
|
||||
@ngdoc directive
|
||||
@name umbraco.directives.directive:umbTourStepCounter
|
||||
@restrict E
|
||||
@scope
|
||||
|
||||
@description
|
||||
<b>Added in Umbraco 7.8</b>. The tour step counter component is a component that can be used in custom views for tour steps.
|
||||
It's meant to be used in the umb-tour-step-footer directive. It will show the progress you have made in a tour eg. step 2/12
|
||||
|
||||
|
||||
@param {int} currentStep The current step the tour is on
|
||||
@param {int} totalSteps The current step the tour is on
|
||||
**/
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
function TourStepCounterDirective() {
|
||||
|
||||
@@ -1,4 +1,16 @@
|
||||
(function() {
|
||||
/**
|
||||
@ngdoc directive
|
||||
@name umbraco.directives.directive:umbTourStepFooter
|
||||
@restrict E
|
||||
@scope
|
||||
|
||||
@description
|
||||
<b>Added in Umbraco 7.8</b>. The tour step footer component is a component that can be used in custom views for tour steps. It's meant to be used in the umb-tour-step directive.
|
||||
All markup in the body of the directive will be shown as the footer of the tour step
|
||||
|
||||
|
||||
**/
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
function TourStepFooterDirective() {
|
||||
|
||||
@@ -1,4 +1,16 @@
|
||||
(function() {
|
||||
/**
|
||||
@ngdoc directive
|
||||
@name umbraco.directives.directive:umbTourStepHeader
|
||||
@restrict E
|
||||
@scope
|
||||
|
||||
@description
|
||||
<b>Added in Umbraco 7.8</b>. The tour step header component is a component that can be used in custom views for tour steps. It's meant to be used in the umb-tour-step directive.
|
||||
|
||||
|
||||
@param {string} title The title that needs to be shown
|
||||
**/
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
function TourStepHeaderDirective() {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
function ContentNodeInfoDirective($timeout, $location, logResource, eventsService, userService, localizationService, dateHelper) {
|
||||
function ContentNodeInfoDirective($timeout, $location, logResource, eventsService, userService, localizationService, dateHelper, redirectUrlsResource) {
|
||||
|
||||
function link(scope, element, attrs, ctrl) {
|
||||
|
||||
@@ -46,6 +46,9 @@
|
||||
// Make sure to set the node status
|
||||
setNodePublishStatus(scope.node);
|
||||
|
||||
//default setting for redirect url management
|
||||
scope.urlTrackerDisabled = false;
|
||||
|
||||
// Declare a fallback URL for the <umb-node-preview/> directive
|
||||
if (scope.documentType !== null) {
|
||||
scope.previewOpenUrl = '#/settings/documenttypes/edit/' + scope.documentType.id;
|
||||
@@ -99,7 +102,7 @@
|
||||
|
||||
// get current backoffice user and format dates
|
||||
userService.getCurrentUser().then(function (currentUser) {
|
||||
angular.forEach(data.items, function(item) {
|
||||
angular.forEach(data.items, function (item) {
|
||||
item.timestampFormatted = dateHelper.getLocalDate(item.timestamp, currentUser.locale, 'LLL');
|
||||
});
|
||||
});
|
||||
@@ -116,6 +119,25 @@
|
||||
});
|
||||
|
||||
}
|
||||
function loadRedirectUrls() {
|
||||
scope.loadingRedirectUrls = true;
|
||||
//check if Redirect Url Management is enabled
|
||||
redirectUrlsResource.getEnableState().then(function (response) {
|
||||
scope.urlTrackerDisabled = response.enabled !== true;
|
||||
if (scope.urlTrackerDisabled === false) {
|
||||
|
||||
redirectUrlsResource.getRedirectsForContentItem(scope.node.udi)
|
||||
.then(function (data) {
|
||||
scope.redirectUrls = data.searchResults;
|
||||
scope.hasRedirects = (typeof data.searchResults !== 'undefined' && data.searchResults.length > 0);
|
||||
scope.loadingRedirectUrls = false;
|
||||
});
|
||||
}
|
||||
else {
|
||||
scope.loadingRedirectUrls = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function setAuditTrailLogTypeColor(auditTrail) {
|
||||
angular.forEach(auditTrail, function (item) {
|
||||
@@ -136,27 +158,27 @@
|
||||
|
||||
function setNodePublishStatus(node) {
|
||||
// deleted node
|
||||
if(node.trashed === true) {
|
||||
if (node.trashed === true) {
|
||||
scope.publishStatus.label = localizationService.localize("general_deleted");
|
||||
scope.publishStatus.color = "danger";
|
||||
}
|
||||
|
||||
// unpublished node
|
||||
if(node.published === false && node.trashed === false) {
|
||||
if (node.published === false && node.trashed === false) {
|
||||
scope.publishStatus.label = localizationService.localize("content_unpublished");
|
||||
scope.publishStatus.color = "gray";
|
||||
}
|
||||
|
||||
// published node
|
||||
if(node.hasPublishedVersion === true && node.publishDate && node.published === true) {
|
||||
if (node.hasPublishedVersion === true && node.publishDate && node.published === true) {
|
||||
scope.publishStatus.label = localizationService.localize("content_published");
|
||||
scope.publishStatus.color = "success";
|
||||
}
|
||||
|
||||
// published node with pending changes
|
||||
if(node.hasPublishedVersion === true && node.publishDate && node.published === false) {
|
||||
if (node.hasPublishedVersion === true && node.publishDate && node.published === false) {
|
||||
scope.publishStatus.label = localizationService.localize("content_publishedPendingChanges");
|
||||
scope.publishStatus.color = "success"
|
||||
scope.publishStatus.color = "success";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -252,12 +274,13 @@
|
||||
});
|
||||
}
|
||||
|
||||
// load audit trail when on the info tab
|
||||
// load audit trail and redirects when on the info tab
|
||||
evts.push(eventsService.on("app.tabChange", function (event, args) {
|
||||
$timeout(function(){
|
||||
$timeout(function () {
|
||||
if (args.id === -1) {
|
||||
isInfoTab = true;
|
||||
loadAuditTrail();
|
||||
loadRedirectUrls();
|
||||
} else {
|
||||
isInfoTab = false;
|
||||
}
|
||||
@@ -265,13 +288,14 @@
|
||||
}));
|
||||
|
||||
// watch for content updates - reload content when node is saved, published etc.
|
||||
scope.$watch('node.updateDate', function(newValue, oldValue){
|
||||
scope.$watch('node.updateDate', function (newValue, oldValue) {
|
||||
|
||||
if(!newValue) { return; }
|
||||
if(newValue === oldValue) { return; }
|
||||
if (!newValue) { return; }
|
||||
if (newValue === oldValue) { return; }
|
||||
|
||||
if(isInfoTab) {
|
||||
loadAuditTrail();
|
||||
loadRedirectUrls();
|
||||
formatDatesToLocal();
|
||||
setNodePublishStatus(scope.node);
|
||||
}
|
||||
|
||||
@@ -11,32 +11,36 @@ function hexBgColor() {
|
||||
restrict: "A",
|
||||
link: function (scope, element, attr, formCtrl) {
|
||||
|
||||
var origColor = null;
|
||||
if (attr.hexBgOrig) {
|
||||
//set the orig based on the attribute if there is one
|
||||
origColor = attr.hexBgOrig;
|
||||
}
|
||||
|
||||
attr.$observe("hexBgColor", function (newVal) {
|
||||
if (newVal) {
|
||||
if (!origColor) {
|
||||
//get the orig color before changing it
|
||||
origColor = element.css("border-color");
|
||||
}
|
||||
//validate it - test with and without the leading hash.
|
||||
if (/^([0-9a-f]{3}|[0-9a-f]{6})$/i.test(newVal)) {
|
||||
element.css("background-color", "#" + newVal);
|
||||
return;
|
||||
}
|
||||
if (/^#([0-9a-f]{3}|[0-9a-f]{6})$/i.test(newVal)) {
|
||||
element.css("background-color", newVal);
|
||||
return;
|
||||
}
|
||||
}
|
||||
element.css("background-color", origColor);
|
||||
});
|
||||
// Only add inline hex background color if defined and not "true".
|
||||
if (attr.hexBgInline === undefined || (attr.hexBgInline !== undefined && attr.hexBgInline === "true")) {
|
||||
|
||||
var origColor = null;
|
||||
if (attr.hexBgOrig) {
|
||||
// Set the orig based on the attribute if there is one.
|
||||
origColor = attr.hexBgOrig;
|
||||
}
|
||||
|
||||
attr.$observe("hexBgColor", function (newVal) {
|
||||
if (newVal) {
|
||||
if (!origColor) {
|
||||
// Get the orig color before changing it.
|
||||
origColor = element.css("border-color");
|
||||
}
|
||||
// Validate it - test with and without the leading hash.
|
||||
if (/^([0-9a-f]{3}|[0-9a-f]{6})$/i.test(newVal)) {
|
||||
element.css("background-color", "#" + newVal);
|
||||
return;
|
||||
}
|
||||
if (/^#([0-9a-f]{3}|[0-9a-f]{6})$/i.test(newVal)) {
|
||||
element.css("background-color", newVal);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
element.css("background-color", origColor);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
angular.module('umbraco.directives').directive("hexBgColor", hexBgColor);
|
||||
angular.module('umbraco.directives').directive("hexBgColor", hexBgColor);
|
||||
|
||||
@@ -14,7 +14,7 @@ angular.module("umbraco.directives")
|
||||
scope: {
|
||||
src: '=',
|
||||
center: "=",
|
||||
onImageLoaded: "="
|
||||
onImageLoaded: "&"
|
||||
},
|
||||
link: function(scope, element, attrs) {
|
||||
|
||||
@@ -31,10 +31,10 @@ angular.module("umbraco.directives")
|
||||
//elements
|
||||
var $viewport = element.find(".viewport");
|
||||
var $image = element.find("img");
|
||||
var $overlay = element.find(".overlay");
|
||||
var $overlay = element.find(".overlay");
|
||||
|
||||
scope.style = function () {
|
||||
if(scope.dimensions.width <= 0){
|
||||
scope.style = function () {
|
||||
if (scope.dimensions.width <= 0) {
|
||||
setDimensions();
|
||||
}
|
||||
|
||||
@@ -45,28 +45,28 @@ angular.module("umbraco.directives")
|
||||
};
|
||||
|
||||
scope.setFocalPoint = function(event) {
|
||||
scope.$emit("imageFocalPointStart");
|
||||
|
||||
scope.$emit("imageFocalPointStart");
|
||||
var offsetX = event.offsetX - 10;
|
||||
var offsetY = event.offsetY - 10;
|
||||
|
||||
var offsetX = event.offsetX - 10;
|
||||
var offsetY = event.offsetY - 10;
|
||||
|
||||
calculateGravity(offsetX, offsetY);
|
||||
|
||||
lazyEndEvent();
|
||||
calculateGravity(offsetX, offsetY);
|
||||
|
||||
lazyEndEvent();
|
||||
};
|
||||
|
||||
var setDimensions = function(){
|
||||
scope.dimensions.width = $image.width();
|
||||
scope.dimensions.height = $image.height();
|
||||
|
||||
if(scope.center){
|
||||
scope.dimensions.left = scope.center.left * scope.dimensions.width -10;
|
||||
scope.dimensions.top = scope.center.top * scope.dimensions.height -10;
|
||||
}else{
|
||||
scope.center = { left: 0.5, top: 0.5 };
|
||||
}
|
||||
var setDimensions = function () {
|
||||
if (scope.isCroppable) {
|
||||
scope.dimensions.width = $image.width();
|
||||
scope.dimensions.height = $image.height();
|
||||
|
||||
if(scope.center){
|
||||
scope.dimensions.left = scope.center.left * scope.dimensions.width -10;
|
||||
scope.dimensions.top = scope.center.top * scope.dimensions.height -10;
|
||||
}else{
|
||||
scope.center = { left: 0.5, top: 0.5 };
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var calculateGravity = function(offsetX, offsetY){
|
||||
@@ -107,10 +107,32 @@ angular.module("umbraco.directives")
|
||||
//// INIT /////
|
||||
$image.load(function() {
|
||||
$timeout(function() {
|
||||
scope.isCroppable = true;
|
||||
scope.hasDimensions = true;
|
||||
|
||||
if (scope.src !== "undefined") {
|
||||
if (scope.src.endsWith(".svg")) {
|
||||
scope.isCroppable = false;
|
||||
scope.hasDimensions = false;
|
||||
} else {
|
||||
// From: https://stackoverflow.com/a/51789597/5018
|
||||
var type = scope.src.substring(scope.src.indexOf("/") + 1, scope.src.indexOf(";base64"));
|
||||
if (type.startsWith("svg")) {
|
||||
scope.isCroppable = false;
|
||||
scope.hasDimensions = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setDimensions();
|
||||
scope.loaded = true;
|
||||
if (angular.isFunction(scope.onImageLoaded)) {
|
||||
scope.onImageLoaded();
|
||||
scope.onImageLoaded(
|
||||
{
|
||||
"isCroppable": scope.isCroppable,
|
||||
"hasDimensions": scope.hasDimensions
|
||||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
</example>
|
||||
*/
|
||||
angular.module("umbraco.directives")
|
||||
.directive('umbTreeItem', function ($compile, $http, $templateCache, $interpolate, $log, $location, $rootScope, $window, treeService, $timeout, localizationService) {
|
||||
.directive('umbTreeItem', function ($compile, $http, $templateCache, $interpolate, $log, $location, $rootScope, $window, treeService, $timeout, localizationService, appState) {
|
||||
return {
|
||||
restrict: 'E',
|
||||
replace: true,
|
||||
@@ -132,7 +132,15 @@ angular.module("umbraco.directives")
|
||||
}
|
||||
if (node.selected) {
|
||||
css.push("umb-tree-node-checked");
|
||||
}
|
||||
}
|
||||
|
||||
//is this the current action node (this is not the same as the current selected node!)
|
||||
var actionNode = appState.getMenuState("currentNode");
|
||||
if(actionNode) {
|
||||
if(actionNode.id === node.id) {
|
||||
css.push("active");
|
||||
}
|
||||
}
|
||||
|
||||
return css.join(" ");
|
||||
};
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
|
||||
/**
|
||||
/**
|
||||
@ngdoc directive
|
||||
@name umbraco.directives.directive:umbColorSwatches
|
||||
@restrict E
|
||||
@@ -15,9 +14,10 @@ Use this directive to generate color swatches to pick from.
|
||||
</umb-color-swatches>
|
||||
</pre>
|
||||
@param {array} colors (<code>attribute</code>): The array of colors.
|
||||
@param {string} colors (<code>attribute</code>): The array of colors.
|
||||
@param {string} selectedColor (<code>attribute</code>): The selected color.
|
||||
@param {string} size (<code>attribute</code>): The size (s, m).
|
||||
@param {string} useLabel (<code>attribute</code>): Specify if labels should be used.
|
||||
@param {string} useColorClass (<code>attribute</code>): Specify if color values are css classes.
|
||||
@param {function} onSelect (<code>expression</code>): Callback function when the item is selected.
|
||||
**/
|
||||
|
||||
@@ -28,6 +28,11 @@ Use this directive to generate color swatches to pick from.
|
||||
|
||||
function link(scope, el, attr, ctrl) {
|
||||
|
||||
// Set default to true if not defined
|
||||
if (angular.isUndefined(scope.useColorClass)) {
|
||||
scope.useColorClass = false;
|
||||
}
|
||||
|
||||
scope.setColor = function (color) {
|
||||
//scope.selectedColor({color: color });
|
||||
scope.selectedColor = color;
|
||||
@@ -47,7 +52,9 @@ Use this directive to generate color swatches to pick from.
|
||||
colors: '=?',
|
||||
size: '@',
|
||||
selectedColor: '=',
|
||||
onSelect: '&'
|
||||
onSelect: '&',
|
||||
useLabel: '=',
|
||||
useColorClass: '=?'
|
||||
},
|
||||
link: link
|
||||
};
|
||||
|
||||
@@ -125,6 +125,20 @@ Use this directive to generate a thumbnail grid of media items.
|
||||
i--;
|
||||
}
|
||||
|
||||
|
||||
// If subfolder search is not enabled remove the media items that's not needed
|
||||
// Make sure that includeSubFolder is not undefined since the directive is used
|
||||
// in contexts where it should not be used. Currently only used when we trigger
|
||||
// a media picker
|
||||
if(scope.includeSubFolders !== undefined){
|
||||
if (scope.includeSubFolders !== 'true') {
|
||||
if (item.parentId !== parseInt(scope.currentFolderId)) {
|
||||
scope.items.splice(i, 1);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (scope.items.length > 0) {
|
||||
@@ -144,7 +158,7 @@ Use this directive to generate a thumbnail grid of media items.
|
||||
}
|
||||
|
||||
if (!item.isFolder) {
|
||||
|
||||
|
||||
// handle entity
|
||||
if(item.image) {
|
||||
item.thumbnail = mediaHelper.resolveFileFromEntity(item, true);
|
||||
@@ -153,7 +167,7 @@ Use this directive to generate a thumbnail grid of media items.
|
||||
} else {
|
||||
item.thumbnail = mediaHelper.resolveFile(item, true);
|
||||
item.image = mediaHelper.resolveFile(item, false);
|
||||
|
||||
|
||||
var fileProp = _.find(item.properties, function (v) {
|
||||
return (v.alias === "umbracoFile");
|
||||
});
|
||||
@@ -307,7 +321,9 @@ Use this directive to generate a thumbnail grid of media items.
|
||||
itemMaxHeight: "@",
|
||||
itemMinWidth: "@",
|
||||
itemMinHeight: "@",
|
||||
onlyImages: "@"
|
||||
onlyImages: "@",
|
||||
includeSubFolders: "@",
|
||||
currentFolderId: "@"
|
||||
},
|
||||
link: link
|
||||
};
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
scope.search = "";
|
||||
scope.miniListViews = [];
|
||||
scope.breadcrumb = [];
|
||||
|
||||
|
||||
var miniListViewsHistory = [];
|
||||
var goingForward = true;
|
||||
var skipAnimation = true;
|
||||
@@ -60,9 +60,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);
|
||||
@@ -74,6 +78,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;
|
||||
@@ -89,7 +104,7 @@
|
||||
};
|
||||
|
||||
scope.selectNode = function(node) {
|
||||
if(scope.onSelect) {
|
||||
if (scope.onSelect && node.allowed) {
|
||||
scope.onSelect({'node': node});
|
||||
}
|
||||
};
|
||||
@@ -202,7 +217,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 {
|
||||
|
||||
@@ -298,10 +298,10 @@ function contentTypeResource($q, $http, umbRequestHelper, umbDataFormatter) {
|
||||
|
||||
},
|
||||
|
||||
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);
|
||||
|
||||
},
|
||||
|
||||
@@ -7,10 +7,60 @@
|
||||
**/
|
||||
function logResource($q, $http, umbRequestHelper) {
|
||||
|
||||
function isValidDate(input) {
|
||||
if (input) {
|
||||
if (Object.prototype.toString.call(input) === "[object Date]" && !isNaN(input.getTime())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
function dateToValidIsoString(input) {
|
||||
if (isValidDate(input)) {
|
||||
return input.toISOString();
|
||||
}
|
||||
|
||||
return '';
|
||||
};
|
||||
|
||||
//the factory object returned
|
||||
return {
|
||||
|
||||
getPagedEntityLog: function (options) {
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.resources.logResource#getPagedEntityLog
|
||||
* @methodOf umbraco.resources.logResource
|
||||
*
|
||||
* @description
|
||||
* Gets a paginated log history for a entity
|
||||
*
|
||||
* ##usage
|
||||
* <pre>
|
||||
* var options = {
|
||||
* id : 1234
|
||||
* pageSize : 10,
|
||||
* pageNumber : 1,
|
||||
* orderDirection : "Descending",
|
||||
* sinceDate : new Date(2018,0,1)
|
||||
* };
|
||||
* logResource.getPagedEntityLog(options)
|
||||
* .then(function(log) {
|
||||
* alert('its here!');
|
||||
* });
|
||||
* </pre>
|
||||
*
|
||||
* @param {Object} options options object
|
||||
* @param {Int} options.id the id of the entity
|
||||
* @param {Int} options.pageSize if paging data, number of nodes per page, default = 10, set to 0 to disable paging
|
||||
* @param {Int} options.pageNumber if paging data, current page index, default = 1
|
||||
* @param {String} options.orderDirection can be `Ascending` or `Descending` - Default: `Descending`
|
||||
* @param {Date} options.sinceDate if provided this will only get log entries going back to this date
|
||||
* @returns {Promise} resourcePromise object containing the log.
|
||||
*
|
||||
*/
|
||||
getPagedEntityLog: function(options) {
|
||||
|
||||
var defaults = {
|
||||
pageSize: 10,
|
||||
@@ -24,17 +74,21 @@ function logResource($q, $http, umbRequestHelper) {
|
||||
angular.extend(defaults, options);
|
||||
//now copy back to the options we will use
|
||||
options = defaults;
|
||||
|
||||
if (options.hasOwnProperty('sinceDate')) {
|
||||
options.sinceDate = dateToValidIsoString(options.sinceDate);
|
||||
}
|
||||
|
||||
//change asc/desct
|
||||
if (options.orderDirection === "asc") {
|
||||
options.orderDirection = "Ascending";
|
||||
}
|
||||
else if (options.orderDirection === "desc") {
|
||||
} else if (options.orderDirection === "desc") {
|
||||
options.orderDirection = "Descending";
|
||||
}
|
||||
|
||||
|
||||
if (options.id === undefined || options.id === null) {
|
||||
throw "options.id is required";
|
||||
}
|
||||
}
|
||||
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.get(
|
||||
@@ -45,7 +99,37 @@ function logResource($q, $http, umbRequestHelper) {
|
||||
'Failed to retrieve log data for id');
|
||||
},
|
||||
|
||||
getPagedUserLog: function (options) {
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.resources.logResource#getPagedUserLog
|
||||
* @methodOf umbraco.resources.logResource
|
||||
*
|
||||
* @description
|
||||
* Gets a paginated log history for the current user
|
||||
*
|
||||
* ##usage
|
||||
* <pre>
|
||||
* var options = {
|
||||
* pageSize : 10,
|
||||
* pageNumber : 1,
|
||||
* orderDirection : "Descending",
|
||||
* sinceDate : new Date(2018,0,1)
|
||||
* };
|
||||
* logResource.getPagedUserLog(options)
|
||||
* .then(function(log) {
|
||||
* alert('its here!');
|
||||
* });
|
||||
* </pre>
|
||||
*
|
||||
* @param {Object} options options object
|
||||
* @param {Int} options.pageSize if paging data, number of nodes per page, default = 10, set to 0 to disable paging
|
||||
* @param {Int} options.pageNumber if paging data, current page index, default = 1
|
||||
* @param {String} options.orderDirection can be `Ascending` or `Descending` - Default: `Descending`
|
||||
* @param {Date} options.sinceDate if provided this will only get log entries going back to this date
|
||||
* @returns {Promise} resourcePromise object containing the log.
|
||||
*
|
||||
*/
|
||||
getPagedUserLog: function(options) {
|
||||
|
||||
var defaults = {
|
||||
pageSize: 10,
|
||||
@@ -59,11 +143,15 @@ function logResource($q, $http, umbRequestHelper) {
|
||||
angular.extend(defaults, options);
|
||||
//now copy back to the options we will use
|
||||
options = defaults;
|
||||
|
||||
if (options.hasOwnProperty('sinceDate')) {
|
||||
options.sinceDate = dateToValidIsoString(options.sinceDate);
|
||||
}
|
||||
|
||||
//change asc/desct
|
||||
if (options.orderDirection === "asc") {
|
||||
options.orderDirection = "Ascending";
|
||||
}
|
||||
else if (options.orderDirection === "desc") {
|
||||
} else if (options.orderDirection === "desc") {
|
||||
options.orderDirection = "Descending";
|
||||
}
|
||||
|
||||
@@ -71,10 +159,10 @@ function logResource($q, $http, umbRequestHelper) {
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"logApiBaseUrl",
|
||||
"GetPagedEntityLog",
|
||||
"GetPagedCurrentUserLog",
|
||||
options)),
|
||||
'Failed to retrieve log data for id');
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
@@ -82,6 +170,7 @@ function logResource($q, $http, umbRequestHelper) {
|
||||
* @methodOf umbraco.resources.logResource
|
||||
*
|
||||
* @description
|
||||
* <strong>[OBSOLETE] use getPagedEntityLog instead</strong><br />
|
||||
* Gets the log history for a give entity id
|
||||
*
|
||||
* ##usage
|
||||
@@ -96,23 +185,24 @@ function logResource($q, $http, umbRequestHelper) {
|
||||
* @returns {Promise} resourcePromise object containing the log.
|
||||
*
|
||||
*/
|
||||
getEntityLog: function (id) {
|
||||
getEntityLog: function(id) {
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"logApiBaseUrl",
|
||||
"GetEntityLog",
|
||||
[{ id: id }])),
|
||||
'Failed to retrieve user data for id ' + id);
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"logApiBaseUrl",
|
||||
"GetEntityLog",
|
||||
[{ id: id }])),
|
||||
'Failed to retrieve user data for id ' + id);
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.resources.logResource#getUserLog
|
||||
* @methodOf umbraco.resources.logResource
|
||||
*
|
||||
* @description
|
||||
* Gets the current users' log history for a given type of log entry
|
||||
* <strong>[OBSOLETE] use getPagedUserLog instead</strong><br />
|
||||
* Gets the current user's log history for a given type of log entry
|
||||
*
|
||||
* ##usage
|
||||
* <pre>
|
||||
@@ -127,14 +217,14 @@ function logResource($q, $http, umbRequestHelper) {
|
||||
* @returns {Promise} resourcePromise object containing the log.
|
||||
*
|
||||
*/
|
||||
getUserLog: function (type, since) {
|
||||
getUserLog: function(type, since) {
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"logApiBaseUrl",
|
||||
"GetCurrentUserLog",
|
||||
[{ logtype: type}, {sinceDate: since }])),
|
||||
'Failed to retrieve log data for current user of type ' + type + ' since ' + since);
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"logApiBaseUrl",
|
||||
"GetCurrentUserLog",
|
||||
[{ logtype: type }, { sinceDate: dateToValidIsoString(since) }])),
|
||||
'Failed to retrieve log data for current user of type ' + type + ' since ' + since);
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -158,16 +248,16 @@ function logResource($q, $http, umbRequestHelper) {
|
||||
* @returns {Promise} resourcePromise object containing the log.
|
||||
*
|
||||
*/
|
||||
getLog: function (type, since) {
|
||||
getLog: function(type, since) {
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"logApiBaseUrl",
|
||||
"GetLog",
|
||||
[{ logtype: type}, {sinceDate: since }])),
|
||||
'Failed to retrieve log data of type ' + type + ' since ' + since);
|
||||
}
|
||||
};
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"logApiBaseUrl",
|
||||
"GetLog",
|
||||
[{ logtype: type }, { sinceDate: dateToValidIsoString(since) }])),
|
||||
'Failed to retrieve log data of type ' + type + ' since ' + since);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
angular.module('umbraco.resources').factory('logResource', logResource);
|
||||
|
||||
@@ -46,7 +46,7 @@ function mediaResource($q, $http, umbDataFormatter, umbRequestHelper) {
|
||||
* .then(function() {
|
||||
* $scope.complete = true;
|
||||
* });
|
||||
* </pre>
|
||||
* </pre>
|
||||
* @param {Object} args arguments object
|
||||
* @param {Int} args.parentId the ID of the parent node
|
||||
* @param {Array} options.sortedIds array of node IDs as they should be sorted
|
||||
@@ -87,9 +87,9 @@ function mediaResource($q, $http, umbDataFormatter, umbRequestHelper) {
|
||||
* .then(function() {
|
||||
* alert("node was moved");
|
||||
* }, function(err){
|
||||
* alert("node didnt move:" + err.data.Message);
|
||||
* alert("node didnt move:" + err.data.Message);
|
||||
* });
|
||||
* </pre>
|
||||
* </pre>
|
||||
* @param {Object} args arguments object
|
||||
* @param {Int} args.idd the ID of the node to move
|
||||
* @param {Int} args.parentId the ID of the parent node to move to
|
||||
@@ -109,11 +109,23 @@ function mediaResource($q, $http, umbDataFormatter, umbRequestHelper) {
|
||||
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.post(umbRequestHelper.getApiUrl("mediaApiBaseUrl", "PostMove"),
|
||||
{
|
||||
parentId: args.parentId,
|
||||
id: args.id
|
||||
}),
|
||||
'Failed to move media');
|
||||
{
|
||||
parentId: args.parentId,
|
||||
id: args.id
|
||||
}),
|
||||
{
|
||||
error: function(data){
|
||||
var errorMsg = 'Failed to move media';
|
||||
|
||||
if(data.parentId === data.id){
|
||||
errorMsg = 'Media can\'t be moved into itself';
|
||||
}
|
||||
|
||||
return {
|
||||
errorMsg: errorMsg
|
||||
};
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
@@ -129,12 +141,12 @@ function mediaResource($q, $http, umbDataFormatter, umbRequestHelper) {
|
||||
* <pre>
|
||||
* mediaResource.getById(1234)
|
||||
* .then(function(media) {
|
||||
* var myMedia = media;
|
||||
* var myMedia = media;
|
||||
* alert('its here!');
|
||||
* });
|
||||
* </pre>
|
||||
*
|
||||
* @param {Int} id id of media item to return
|
||||
* </pre>
|
||||
*
|
||||
* @param {Int} id id of media item to return
|
||||
* @returns {Promise} resourcePromise object containing the media item.
|
||||
*
|
||||
*/
|
||||
@@ -163,9 +175,9 @@ function mediaResource($q, $http, umbDataFormatter, umbRequestHelper) {
|
||||
* .then(function() {
|
||||
* alert('its gone!');
|
||||
* });
|
||||
* </pre>
|
||||
*
|
||||
* @param {Int} id id of media item to delete
|
||||
* </pre>
|
||||
*
|
||||
* @param {Int} id id of media item to delete
|
||||
* @returns {Promise} resourcePromise object.
|
||||
*
|
||||
*/
|
||||
@@ -191,12 +203,12 @@ function mediaResource($q, $http, umbDataFormatter, umbRequestHelper) {
|
||||
* <pre>
|
||||
* mediaResource.getByIds( [1234,2526,28262])
|
||||
* .then(function(mediaArray) {
|
||||
* var myDoc = contentArray;
|
||||
* var myDoc = contentArray;
|
||||
* alert('they are here!');
|
||||
* });
|
||||
* </pre>
|
||||
*
|
||||
* @param {Array} ids ids of media items to return as an array
|
||||
* </pre>
|
||||
*
|
||||
* @param {Array} ids ids of media items to return as an array
|
||||
* @returns {Promise} resourcePromise object containing the media items array.
|
||||
*
|
||||
*/
|
||||
@@ -223,28 +235,28 @@ function mediaResource($q, $http, umbDataFormatter, umbRequestHelper) {
|
||||
*
|
||||
* @description
|
||||
* Returns a scaffold of an empty media item, given the id of the media item to place it underneath and the media type alias.
|
||||
*
|
||||
*
|
||||
* - Parent Id must be provided so umbraco knows where to store the media
|
||||
* - Media Type alias must be provided so umbraco knows which properties to put on the media scaffold
|
||||
*
|
||||
* - Media Type alias must be provided so umbraco knows which properties to put on the media scaffold
|
||||
*
|
||||
* The scaffold is used to build editors for media that has not yet been populated with data.
|
||||
*
|
||||
*
|
||||
* ##usage
|
||||
* <pre>
|
||||
* mediaResource.getScaffold(1234, 'folder')
|
||||
* .then(function(scaffold) {
|
||||
* var myDoc = scaffold;
|
||||
* myDoc.name = "My new media item";
|
||||
* myDoc.name = "My new media item";
|
||||
*
|
||||
* mediaResource.save(myDoc, true)
|
||||
* .then(function(media){
|
||||
* alert("Retrieved, updated and saved again");
|
||||
* });
|
||||
* });
|
||||
* </pre>
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @param {Int} parentId id of media item to return
|
||||
* @param {String} alias mediatype alias to base the scaffold on
|
||||
* @param {String} alias mediatype alias to base the scaffold on
|
||||
* @returns {Promise} resourcePromise object containing the media scaffold.
|
||||
*
|
||||
*/
|
||||
@@ -283,11 +295,11 @@ function mediaResource($q, $http, umbDataFormatter, umbRequestHelper) {
|
||||
* <pre>
|
||||
* mediaResource.getChildren(1234, {pageSize: 10, pageNumber: 2})
|
||||
* .then(function(contentArray) {
|
||||
* var children = contentArray;
|
||||
* var children = contentArray;
|
||||
* alert('they are here!');
|
||||
* });
|
||||
* </pre>
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @param {Int} parentid id of content item to return children of
|
||||
* @param {Object} options optional options object
|
||||
* @param {Int} options.pageSize if paging data, number of nodes per page, default = 0
|
||||
@@ -361,9 +373,9 @@ function mediaResource($q, $http, umbDataFormatter, umbRequestHelper) {
|
||||
*
|
||||
* @description
|
||||
* Saves changes made to a media item, if the media item is new, the isNew paramater must be passed to force creation
|
||||
* if the media item needs to have files attached, they must be provided as the files param and passed separately
|
||||
*
|
||||
*
|
||||
* if the media item needs to have files attached, they must be provided as the files param and passed separately
|
||||
*
|
||||
*
|
||||
* ##usage
|
||||
* <pre>
|
||||
* mediaResource.getById(1234)
|
||||
@@ -374,11 +386,11 @@ function mediaResource($q, $http, umbDataFormatter, umbRequestHelper) {
|
||||
* alert("Retrieved, updated and saved again");
|
||||
* });
|
||||
* });
|
||||
* </pre>
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @param {Object} media The media item object with changes applied
|
||||
* @param {Bool} isNew set to true to create a new item or to update an existing
|
||||
* @param {Array} files collection of files for the media item
|
||||
* @param {Bool} isNew set to true to create a new item or to update an existing
|
||||
* @param {Array} files collection of files for the media item
|
||||
* @returns {Promise} resourcePromise object containing the saved media item.
|
||||
*
|
||||
*/
|
||||
@@ -400,10 +412,10 @@ function mediaResource($q, $http, umbDataFormatter, umbRequestHelper) {
|
||||
* .then(function(folder) {
|
||||
* alert('New folder');
|
||||
* });
|
||||
* </pre>
|
||||
* </pre>
|
||||
*
|
||||
* @param {string} name Name of the folder to create
|
||||
* @param {int} parentId Id of the media item to create the folder underneath
|
||||
* @param {int} parentId Id of the media item to create the folder underneath
|
||||
* @returns {Promise} resourcePromise object.
|
||||
*
|
||||
*/
|
||||
@@ -427,18 +439,18 @@ function mediaResource($q, $http, umbDataFormatter, umbRequestHelper) {
|
||||
* Retrieves all media children with types used as folders.
|
||||
* Uses the convention of looking for media items with mediaTypes ending in
|
||||
* *Folder so will match "Folder", "bannerFolder", "secureFolder" etc,
|
||||
*
|
||||
*
|
||||
* NOTE: This will return a max of 500 folders, if more is required it needs to be paged
|
||||
*
|
||||
*
|
||||
* ##usage
|
||||
* <pre>
|
||||
* mediaResource.getChildFolders(1234)
|
||||
* .then(function(data) {
|
||||
* alert('folders');
|
||||
* });
|
||||
* </pre>
|
||||
* </pre>
|
||||
*
|
||||
* @param {int} parentId Id of the media item to query for child folders
|
||||
* @param {int} parentId Id of the media item to query for child folders
|
||||
* @returns {Promise} resourcePromise object.
|
||||
*
|
||||
*/
|
||||
@@ -473,8 +485,8 @@ function mediaResource($q, $http, umbDataFormatter, umbRequestHelper) {
|
||||
* .then(function() {
|
||||
* alert('its empty!');
|
||||
* });
|
||||
* </pre>
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @returns {Promise} resourcePromise object.
|
||||
*
|
||||
*/
|
||||
@@ -501,8 +513,8 @@ function mediaResource($q, $http, umbDataFormatter, umbRequestHelper) {
|
||||
* .then(function(searchResult) {
|
||||
* alert('it's here!');
|
||||
* });
|
||||
* </pre>
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @param {string} query The search query
|
||||
* @param {int} pageNumber The page number
|
||||
* @param {int} pageSize The number of media items on a page
|
||||
@@ -513,7 +525,7 @@ function mediaResource($q, $http, umbDataFormatter, umbRequestHelper) {
|
||||
search: function (query, pageNumber, pageSize, searchFrom) {
|
||||
|
||||
var args = [
|
||||
{ "query": query },
|
||||
{ "query": query },
|
||||
{ "pageNumber": pageNumber },
|
||||
{ "pageSize": pageSize },
|
||||
{ "searchFrom": searchFrom }
|
||||
|
||||
@@ -40,6 +40,32 @@
|
||||
{ searchTerm: searchTerm, page: pageIndex, pageSize: pageSize })),
|
||||
'Failed to retrieve data for searching redirect urls');
|
||||
}
|
||||
/**
|
||||
* @ngdoc function
|
||||
* @name umbraco.resources.redirectUrlResource#getRedirectsForContentItem
|
||||
* @methodOf umbraco.resources.redirectUrlResource
|
||||
* @function
|
||||
*
|
||||
* @description
|
||||
* Used to retrieve RedirectUrls for a specific item of content for Information tab
|
||||
* ##usage
|
||||
* <pre>
|
||||
* redirectUrlsResource.getRedirectsForContentItem("udi:123456")
|
||||
* .then(function(response) {
|
||||
*
|
||||
* });
|
||||
* </pre>
|
||||
* @param {String} contentUdi identifier for the content item to retrieve redirects for
|
||||
*/
|
||||
function getRedirectsForContentItem(contentUdi) {
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"redirectUrlManagementApiBaseUrl",
|
||||
"RedirectUrlsForContentItem",
|
||||
{ contentUdi: contentUdi })),
|
||||
'Failed to retrieve redirects for content: ' + contentUdi);
|
||||
}
|
||||
|
||||
function getEnableState() {
|
||||
|
||||
@@ -50,7 +76,7 @@
|
||||
"GetEnableState")),
|
||||
'Failed to retrieve data to check if the 301 redirect is enabled');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @ngdoc function
|
||||
* @name umbraco.resources.redirectUrlResource#deleteRedirectUrl
|
||||
@@ -107,7 +133,8 @@
|
||||
searchRedirectUrls: searchRedirectUrls,
|
||||
deleteRedirectUrl: deleteRedirectUrl,
|
||||
toggleUrlTracker: toggleUrlTracker,
|
||||
getEnableState: getEnableState
|
||||
getEnableState: getEnableState,
|
||||
getRedirectsForContentItem: getRedirectsForContentItem
|
||||
};
|
||||
|
||||
return resource;
|
||||
|
||||
@@ -73,6 +73,7 @@ function navigationService($rootScope, $routeParams, $log, $location, $q, $timeo
|
||||
appState.setSectionState("showSearchResults", false);
|
||||
appState.setGlobalState("stickyNavigation", false);
|
||||
appState.setGlobalState("showTray", false);
|
||||
appState.setMenuState("currentNode", null);
|
||||
|
||||
if (appState.getGlobalState("isTablet") === true) {
|
||||
appState.setGlobalState("showNavigation", false);
|
||||
@@ -347,7 +348,8 @@ function navigationService($rootScope, $routeParams, $log, $location, $q, $timeo
|
||||
|
||||
if (appState.getGlobalState("isTablet") === true && !appState.getGlobalState("stickyNavigation")) {
|
||||
//reset it to whatever is in the url
|
||||
appState.setSectionState("currentSection", $routeParams.section);
|
||||
appState.setSectionState("currentSection", $routeParams.section);
|
||||
|
||||
setMode("default-hidesectiontree");
|
||||
}
|
||||
|
||||
@@ -659,10 +661,10 @@ function navigationService($rootScope, $routeParams, $log, $location, $q, $timeo
|
||||
*/
|
||||
hideDialog: function (showMenu) {
|
||||
|
||||
setMode("default");
|
||||
|
||||
if(showMenu){
|
||||
if (showMenu) {
|
||||
this.showMenu(undefined, { skipDefault: true, node: appState.getMenuState("currentNode") });
|
||||
} else {
|
||||
setMode("default");
|
||||
}
|
||||
},
|
||||
/**
|
||||
|
||||
@@ -143,7 +143,6 @@ angular.module('umbraco.services')
|
||||
/** Called to update the current user's timeout */
|
||||
function setUserTimeoutInternal(newTimeout) {
|
||||
|
||||
|
||||
var asNumber = parseFloat(newTimeout);
|
||||
if (!isNaN(asNumber) && currentUser && angular.isNumber(asNumber)) {
|
||||
currentUser.remainingAuthSeconds = newTimeout;
|
||||
@@ -151,6 +150,29 @@ angular.module('umbraco.services')
|
||||
}
|
||||
}
|
||||
|
||||
function getMomentLocales(locales, supportedLocales) {
|
||||
|
||||
var localeUrls = [];
|
||||
var locales = locales.split(',');
|
||||
for (var i = 0; i < locales.length; i++) {
|
||||
var locale = locales[i].toString().toLowerCase();
|
||||
if (locale !== 'en-us') {
|
||||
|
||||
if (supportedLocales.indexOf(locale + '.js') > -1) {
|
||||
localeUrls.push('lib/moment/' + locale + '.js');
|
||||
}
|
||||
if (locale.indexOf('-') > -1) {
|
||||
var majorLocale = locale.split('-')[0] + '.js';
|
||||
if (supportedLocales.indexOf(majorLocale) > -1) {
|
||||
localeUrls.push('lib/moment/' + majorLocale);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return localeUrls;
|
||||
}
|
||||
|
||||
/** resets all user data, broadcasts the notAuthenticated event and shows the login dialog */
|
||||
function userAuthExpired(isLogout) {
|
||||
//store the last user id and clear the user
|
||||
@@ -178,7 +200,7 @@ angular.module('umbraco.services')
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
var services = {
|
||||
|
||||
/** Internal method to display the login dialog */
|
||||
_showLoginDialog: function () {
|
||||
@@ -279,47 +301,39 @@ angular.module('umbraco.services')
|
||||
/** Loads the Moment.js Locale for the current user. */
|
||||
loadMomentLocaleForCurrentUser: function () {
|
||||
|
||||
function loadLocales(currentUser, supportedLocales) {
|
||||
var locale = currentUser.locale.toLowerCase();
|
||||
if (locale !== 'en-us') {
|
||||
var localeUrls = [];
|
||||
if (supportedLocales.indexOf(locale + '.js') > -1) {
|
||||
localeUrls.push('lib/moment/' + locale + '.js');
|
||||
}
|
||||
if (locale.indexOf('-') > -1) {
|
||||
var majorLocale = locale.split('-')[0] + '.js';
|
||||
if (supportedLocales.indexOf(majorLocale) > -1) {
|
||||
localeUrls.push('lib/moment/' + majorLocale);
|
||||
}
|
||||
}
|
||||
return assetsService.load(localeUrls, $rootScope);
|
||||
}
|
||||
else {
|
||||
//return a noop promise
|
||||
var deferred = $q.defer();
|
||||
var promise = deferred.promise;
|
||||
deferred.resolve(true);
|
||||
return promise;
|
||||
}
|
||||
}
|
||||
|
||||
var promises = {
|
||||
currentUser: this.getCurrentUser(),
|
||||
supportedLocales: javascriptLibraryService.getSupportedLocalesForMoment()
|
||||
}
|
||||
|
||||
return $q.all(promises).then(function (values) {
|
||||
return loadLocales(values.currentUser, values.supportedLocales);
|
||||
return services.loadLocales(values.currentUser.locale, values.supportedLocales);
|
||||
});
|
||||
|
||||
|
||||
|
||||
},
|
||||
|
||||
/** Loads specific Moment.js Locales. */
|
||||
loadLocales: function (locales, supportedLocales) {
|
||||
|
||||
var localeUrls = getMomentLocales(locales, supportedLocales);
|
||||
|
||||
if (localeUrls.length >= 1) {
|
||||
return assetsService.load(localeUrls, $rootScope);
|
||||
}
|
||||
else {
|
||||
//return a noop promise
|
||||
var deferred = $q.defer();
|
||||
var promise = deferred.promise;
|
||||
deferred.resolve(true);
|
||||
return promise;
|
||||
}
|
||||
},
|
||||
|
||||
/** Called whenever a server request is made that contains a x-umb-user-seconds response header for which we can update the user's remaining timeout seconds */
|
||||
setUserTimeout: function (newTimeout) {
|
||||
setUserTimeoutInternal(newTimeout);
|
||||
}
|
||||
};
|
||||
|
||||
return services;
|
||||
});
|
||||
|
||||
@@ -126,6 +126,7 @@
|
||||
@import "components/umb-querybuilder.less";
|
||||
@import "components/umb-pagination.less";
|
||||
@import "components/umb-mini-list-view.less";
|
||||
@import "components/umb-multiple-textbox.less";
|
||||
@import "components/umb-badge.less";
|
||||
@import "components/umb-nested-content.less";
|
||||
@import "components/umb-checkmark.less";
|
||||
@@ -145,6 +146,7 @@
|
||||
@import "components/umb-mini-editor.less";
|
||||
|
||||
@import "components/users/umb-user-cards.less";
|
||||
@import "components/users/umb-user-details.less";
|
||||
@import "components/users/umb-user-group-picker-list.less";
|
||||
@import "components/users/umb-user-group-preview.less";
|
||||
@import "components/users/umb-user-preview.less";
|
||||
|
||||
@@ -63,9 +63,6 @@
|
||||
.btn-group>.btn+.dropdown-toggle {
|
||||
box-shadow: none;
|
||||
-webkit-box-shadow:none;
|
||||
}
|
||||
|
||||
.btn-group .btn.dropdown-toggle {
|
||||
border-left-width: 1px;
|
||||
border-left-style: solid;
|
||||
}
|
||||
|
||||
@@ -81,9 +81,9 @@ a, a:hover{
|
||||
|
||||
.wait {
|
||||
display: block;
|
||||
height: 280px;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
background: center center url(../img/loader.gif) no-repeat;
|
||||
background:#fff center center url(../img/loader.gif) no-repeat;
|
||||
}
|
||||
|
||||
/****************************/
|
||||
@@ -790,13 +790,13 @@ h4.panel-title {
|
||||
}
|
||||
|
||||
.smartphone-portrait {
|
||||
width: 320px;
|
||||
height: 504px;
|
||||
width: 360px;
|
||||
height: 640px;
|
||||
}
|
||||
|
||||
.smartphone-landscape {
|
||||
width: 480px;
|
||||
height: 256px;
|
||||
width: 640px;
|
||||
height: 360px;
|
||||
}
|
||||
|
||||
.border {
|
||||
|
||||
@@ -156,6 +156,7 @@
|
||||
margin-bottom: 1px;
|
||||
border-radius: 0;
|
||||
border-bottom: 1px solid @gray-9;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.umb-help-list-item__group-title i {
|
||||
@@ -186,6 +187,7 @@
|
||||
.umb-help-list-item__title {
|
||||
font-size: 14px;
|
||||
display: block;
|
||||
margin-left: 26px;
|
||||
}
|
||||
|
||||
.umb-help-list-item__description {
|
||||
@@ -198,6 +200,7 @@
|
||||
margin-right: 8px;
|
||||
color: @gray-4;
|
||||
font-size: 18px;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.umb-help-list-item__open-icon {
|
||||
@@ -212,4 +215,4 @@
|
||||
|
||||
[data-element*="tour-"].umb-help-list-item:hover .umb-help-list-item__title {
|
||||
text-decoration:none;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,10 @@
|
||||
}
|
||||
}
|
||||
|
||||
.umb-toggle:focus .umb-toggle__toggle{
|
||||
box-shadow: 0 1px 3px fade(@black, 12%), 0 1px 2px fade(@black, 24%);
|
||||
}
|
||||
|
||||
.umb-toggle__handler {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
@@ -30,6 +34,7 @@
|
||||
background: @gray-8;
|
||||
border-radius: 90px;
|
||||
position: relative;
|
||||
transition: box-shadow .3s;
|
||||
}
|
||||
|
||||
.umb-toggle--checked .umb-toggle__toggle {
|
||||
@@ -43,7 +48,6 @@
|
||||
/* Labels */
|
||||
|
||||
.umb-toggle__label {
|
||||
font-size: 12px;
|
||||
color: @gray-2;
|
||||
}
|
||||
|
||||
|
||||