Compare commits

...

114 Commits

Author SHA1 Message Date
Sebastiaan Janssen f1a8da2876 Bumps version to 7.9.6 2018-04-20 11:02:29 +02:00
Sebastiaan Janssen 27f6560a00 U4-11253 New Chrome 66 trimStart function is overriding the Umbraco Core trimStart polyfill 2018-04-20 11:00:49 +02:00
Sebastiaan Janssen c61fd65463 Bumps version to 7.9.5 2018-04-12 16:38:22 +02:00
Sebastiaan Janssen b5415844b8 Cherry picked - Fix scope leaks caused by database messenger [U4-11207] #2580 2018-04-12 16:30:55 +02:00
Sebastiaan Janssen 98b7467306 Merge branch 'dev-v7' into master-v7 2018-03-22 10:53:24 +01:00
Sebastiaan Janssen 4bb75d73dd Bump version to 7.9.3 2018-03-22 10:50:12 +01:00
Shannon Deminick dd8e43d80a Fixes U4-10472 Cannot upgrade to 7.7+ when using MySql (#2493)
* Fixes U4-10472 Cannot upgrade to 7.7+ when using MySql

* Fixes dropping the FK for the AddUserGroupTables migration
2018-03-22 10:35:41 +01:00
Sebastiaan Janssen b4a0dadee9 Re-apply the nice C# syntax James provided 2018-03-21 19:53:20 +01:00
Lee Kelleher 014ac98d0b U4-11052 - Enabled IntegerValueConverter to handle Int64 source values (#2500)
* Enabled IntegerValueConverter to handle `Int64` source values
2018-03-21 19:08:24 +01:00
Robert 35a79a8598 Merge pull request #2525 from umbraco/temp-U4-11020
U4-11020 Deleting a member group that is part of a Public Access feat…
2018-03-21 13:47:02 +01:00
Robert 3c4f052a27 Moved some code around based on feedback 2018-03-21 13:45:44 +01:00
Robert 97d7e3db84 Forgot add the new namespace 2018-03-21 10:46:42 +01:00
Robert 0d2df4de81 Some cleanup 2018-03-21 10:22:08 +01:00
Shannon e2e0dd0c73 Merge branch 'dev-v7' of https://github.com/umbraco/Umbraco-CMS into dev-v7 2018-03-21 12:34:15 +11:00
Shannon 1a590664e7 Revert "Merge pull request #2502 from umbraco/temp-U4-11032"
This reverts commit 2aa0dfb2c5, reversing
changes made to 2c6e7e46c2.
2018-03-21 12:32:27 +11:00
Shannon Deminick 64fd6ee7c5 Merge pull request #2477 from Shazwazza/U4-10992
U4-10992 (UDUF) TourController Object reference not set to an instance of an…
2018-03-21 12:24:50 +11:00
Shannon Deminick 2ed5b6c1ee Merge pull request #2436 from umbraco/temp-U4-10957_2
U4-10957 If RequiredSection is not defined in a tour - backoffice wil…
2018-03-21 12:24:10 +11:00
Sebastiaan Janssen edf7038848 U4-11020 Deleting a member group that is part of a Public Access feature, from the system, does not also remove the corresponding rows from the umbracoAccessRule table. 2018-03-20 15:00:09 +01:00
Niels Hartvig bcac02861d Merge pull request #2524 from davidwandar/patch-2
Fixed typo in Readme.
2018-03-20 11:18:57 +01:00
Sebastiaan Janssen 79ecaecc9e Merge pull request #2503 from umbraco/temp-U4-11070
Adds support for *not* closing an overlay on enter
2018-03-20 11:14:57 +01:00
Sebastiaan Janssen f604117c6d Merge pull request #2504 from umbraco/temp-U4-11071
U4-11071 Prevalue editor for multiple values TLC
2018-03-20 11:14:42 +01:00
David Wandar dcf7f35078 Fixed typo.
Xloud -> Cloud 

Xloud sounds awsome though :)
2018-03-20 10:00:53 +01:00
Robert 2aa0dfb2c5 Merge pull request #2502 from umbraco/temp-U4-11032
U4-11032 Consolidate the number of dropdown property editors into one
2018-03-19 14:37:47 +01:00
Robert e4b77416a6 Fixed typo 2018-03-19 14:28:24 +01:00
Robert 3aed889e2a Merge branch 'dev-v7' into temp-U4-11032 2018-03-19 14:14:51 +01:00
Robert 2c6e7e46c2 Merge pull request #2517 from dawoe/patch-1
Fixed documentation of umb-overlay directive
2018-03-19 08:58:23 +01:00
Mikulas Tomanka 0a71a09d21 Merge pull request #2518 from dawoe/patch-2
Remove console.log from slider property editor
2018-03-19 08:32:40 +01:00
Dave Woestenborghs 0c868fb72d Remove console.log from slider property editor
removed console.log statement from slider property editor controller
2018-03-16 18:43:54 +01:00
Dave Woestenborghs a96cbce9b1 Fixed documentation of umb-overlay directive
- Removed lorem ipsum text 
- Fixed casing of subtitle
2018-03-16 18:12:46 +01:00
Sebastiaan Janssen 5f3090c81e grunt was discontinued in 7.7 and shouldn't exist here any more to avoid confusion 2018-03-15 10:40:40 +01:00
Sebastiaan Janssen 054a8b48fa Revert PR #2507 - needs to go in 7.10 2018-03-15 09:59:04 +01:00
Sebastiaan Janssen dfbc3c477a Merge branch 'dev-v7' of https://github.com/umbraco/Umbraco-CMS into pr/2507 2018-03-15 09:38:44 +01:00
Niels Hartvig 57426ae895 Feedback from review. Makes the moment service more generic and changes promises chaining 2018-03-14 11:10:01 +01:00
Shannon b4aad19573 Revert "Merge pull request #2508 from umbraco/temp-U4-11076"
This reverts commit 4161d244c1, reversing
changes made to eea87e411f.
2018-03-14 13:23:33 +11:00
Sebastiaan Janssen 03012cf54d Merge pull request #1435 from neilgaietto/U4-8822
U4-8822- Fixes Unpublish error with empty RTE
2018-03-14 00:10:49 +01:00
Sebastiaan Janssen 7ff339e18a Merge pull request #1306 from shiroganee/Fix-8533
removes a overflow: hidden which decrease update-tree-layer performance
2018-03-13 23:34:59 +01:00
Sebastiaan Janssen 0048b9c4c8 Merge pull request #2516 from bjarnef/dev-v7-U4-11093
U4-11093 - Update Danish translations
2018-03-13 23:03:48 +01:00
Bjarne Fyrstenborg 47f5e6bf17 Remove duplicate key in user area 2018-03-13 22:23:38 +01:00
Bjarne Fyrstenborg a8908c90bc Add better translations to Danish 2018-03-13 22:21:44 +01:00
Sebastiaan Janssen 9e5e8b539a Merge branch 'bjarnef-dev-v7-U4-6616' into dev-v7 2018-03-13 22:19:15 +01:00
Sebastiaan Janssen 45d292e196 Merge branch 'dev-v7-U4-6616' of https://github.com/bjarnef/Umbraco-CMS into bjarnef-dev-v7-U4-6616
# Conflicts:
#	src/Umbraco.Web.UI.Client/src/less/variables.less
#	src/Umbraco.Web.UI.Client/src/views/common/dialogs/iconpicker.controller.js
#	src/Umbraco.Web.UI.Client/src/views/common/dialogs/iconpicker.html
2018-03-13 22:18:28 +01:00
Niels Hartvig 6bafd3a254 Removes ugly non-existing comment :) 2018-03-13 16:39:01 +01:00
Niels Hartvig 564074a2bd Adds check for existing moment locales before attempting to download them 2018-03-13 16:19:51 +01:00
Shannon Deminick 4161d244c1 Merge pull request #2508 from umbraco/temp-U4-11076
Fix - U4-11076 Remove all references to templates from the backoffice
2018-03-12 20:32:29 -07:00
Shannon 171e0d87db Updates some of the variable names, removes the EnabledFeatures since we don't really need that 2018-03-13 14:31:30 +11:00
Shannon Deminick eea87e411f Merge pull request #2514 from umbraco/temp-U4-11065
Fix - U4-11065 Sensitive data is shown in listviews
2018-03-12 17:25:49 -07:00
Shannon 89edfe5782 refactors a bit - merges the 2 new resolvers into one and renames with code comments. Updates the ContentPropertyBasic to include a new IsSensitive property for mapping, updates the UI to check for this, updats the mapping to map with UmbracoContext, 2018-03-13 11:23:44 +11:00
Shannon Deminick cbd5071eed Merge pull request #2510 from umbraco/temp-UAASSCRUM-1441
fixes UAASSCRUM-1441: fix token identity breaking RestAPI and others
2018-03-12 06:27:50 -07:00
Robert 3dbc2944aa Translations 2018-03-12 12:06:57 +01:00
Robert 709dab6afd Hooked sensitive data checks on member list view 2018-03-12 12:06:23 +01:00
Robert 8749b030cf Added custom resolver to deal with sensitive values on member list view, some cleanup 2018-03-12 12:04:54 +01:00
Sebastiaan Janssen 62fd15d54b Update CONTRIBUTING.md 2018-03-10 12:24:13 +01:00
Sebastiaan Janssen 66e71db85c Update CONTRIBUTING.md 2018-03-10 12:20:56 +01:00
Sebastiaan Janssen 469527da0a Update CONTRIBUTING.md 2018-03-10 12:20:24 +01:00
Robert 304e574bbc Merge pull request #2509 from umbraco/temp-U4-11058
fixes: U4-11058 Add guidance to the multinode treepicker UI for min. …
2018-03-08 14:01:14 +01:00
Robert 723644ace5 Merge pull request #2475 from barryokane/U4-7484-markdown
(uDuf) Prevent "unsaved" warning when no changes on MarkDown Editor
2018-03-08 13:23:46 +01:00
Stephan 2b936a6d31 UAASSCRUM-1441 - fix token identity 2018-03-08 13:18:53 +01:00
Sebastiaan Jansssen 3121635e07 Clarify upgrade readme 2018-03-08 13:15:04 +01:00
Mads Rasmussen f2a3a269ba fixes: U4-11058 Add guidance to the multinode treepicker UI for min. and max. allowed items 2018-03-08 11:22:31 +01:00
Robert 557fc1bcdd Removed hardcoded value for disabletemplate 2018-03-07 21:43:19 +01:00
Kyle Weems 617bdb2bd1 Merge branch 'dev-v7' of git://github.com/umbraco/Umbraco-CMS into dev-v7 2018-03-07 10:21:11 -08:00
Kyle Weems 2c91f9bf14 Reduce the first load impact of Moment by moving from using moment-with-locales.js to moment.min.js and loading in the specific locale files when the app authorizes. http://issues.umbraco.org/issue/U4-11044 2018-03-07 10:19:11 -08:00
Robert 1a5fe63638 Switching to ng-if to hide the template dropdown in the info tab 2018-03-07 14:51:24 +01:00
Robert dfb0efbc98 Removed option to assign templates from the info tab 2018-03-07 14:43:30 +01:00
Robert d399ad6e51 Removed option to assign templates from the document type 2018-03-07 14:13:53 +01:00
Robert eb06e62937 Removing the option to create document type with a template 2018-03-07 14:10:25 +01:00
Robert 728bf8b52d Adding disableFeatures server variable and new DisableTemplate property in DisabledFeatures.cs 2018-03-07 14:03:35 +01:00
Niels Hartvig ca74100e12 TLC for multiple pre values editor 2018-03-06 16:11:44 +01:00
Niels Hartvig 3061dc4e6f Adds support for *not* closing an overlay on enter 2018-03-06 15:37:52 +01:00
Niels Hartvig 5166dc08d6 Missing null check 2018-03-06 12:44:39 +01:00
Niels Hartvig 05a9c44e9e Needs to check if single value is an array and then pick first value 2018-03-06 11:51:32 +01:00
Niels Hartvig 8e0565e030 Fixes spacing in description :) 2018-03-06 11:16:51 +01:00
Niels Hartvig ceb3ae361a Adds flexible dropdown editor to replace the four current ones 2018-03-06 11:07:08 +01:00
Niels Hartvig 4cee7b831a Merge branch 'dev-v7' into temp-U4-11032 2018-03-06 10:08:04 +01:00
Robert f146262031 Merge pull request #2476 from barryokane/U4-9996
(uDuf) Prevent unsaved dialogue appearing when no changes made on FileUpload
2018-03-06 09:17:17 +01:00
Robert ddae0d01e3 Merge pull request #2460 from mwanchap/U4-10821
Fix for U4-10821, render alt text attribute from grid image editor (uduf hackathon)
2018-03-05 14:35:23 +01:00
Robert b9ee85dabc String ->string 2018-03-05 14:34:36 +01:00
Sebastiaan Janssen 29fa6061a9 Merge pull request #2496 from soreng/temp-U4-9992
U4-9992: Added nuget config to restore command
2018-03-02 11:56:39 +01:00
Søren Gregersen 8ee61312b6 Added nuget config to restore command 2018-03-02 11:47:57 +01:00
Sebastiaan Janssen cfd4b8c7bf Merge pull request #2495 from soreng/temp-U4-9992
U4-9992: Added usage of nuget config in environment setup
2018-03-02 11:45:42 +01:00
Sebastiaan Janssen 7ce3b6046c Merge pull request #2494 from Mivaweb/patch-1
Update NL.xml rectify and permissionDenied
2018-03-02 11:43:20 +01:00
Søren Gregersen 43d98c9682 Added usage of nuget config in environment setup 2018-03-02 11:42:41 +01:00
Michaël Vanbrabandt 62e4825a5e Update NL.xml rectify and permissionDenied 2018-03-02 10:47:15 +01:00
Sebastiaan Janssen 81d35c6079 Merge pull request #2491 from mortenbock/temp-U4-5614
U4-5614 - Handle invalid urls in extension check
2018-03-01 20:49:09 +01:00
Morten Bock 7e15077f96 Handle invalid urls in extension check 2018-03-01 20:18:18 +01:00
Sebastiaan Janssen 6543e3c058 Merge pull request #2489 from mortenbock/temp-U4-288
U4-288 - Allow relative urls in sheduled tasks
2018-03-01 19:47:31 +01:00
Morten Bock 7c73c379cf Use the UmbracoApplicationUrl as the base for sheduled task urls, in case they are relative. 2018-03-01 19:11:37 +01:00
Sebastiaan Janssen 4bc9d96bce Merge pull request #2488 from hemraker/temp-U4-10993
Fixed open doc type button
2018-03-01 18:09:48 +01:00
Rune Hem Strand 45fd54d046 Fixed open doc type button 2018-03-01 18:06:46 +01:00
Sebastiaan Jansssen 4f062306a6 U4-10891 Color Picker Cannot read property 'hasOwnProperty' of null
(cherry picked from commit 4a8730b925)
2018-03-01 16:47:28 +01:00
Sebastiaan Jansssen 4a8730b925 U4-10891 Color Picker Cannot read property 'hasOwnProperty' of null 2018-03-01 16:45:38 +01:00
Sebastiaan Janssen 0beda4b790 Update CONTRIBUTING.md 2018-03-01 16:43:02 +01:00
Sebastiaan Jansssen d94e7cd906 Merge branch 'dev-v7' into master-v7 2018-03-01 15:09:45 +01:00
Sebastiaan Jansssen 213ea6470f Bump version to 7.9.2 2018-03-01 15:09:04 +01:00
Sebastiaan Jansssen dde8ba5617 Merge branch 'dev-v7' into master-v7 2018-03-01 14:57:11 +01:00
Sebastiaan Janssen e783308cf0 Merge pull request #2487 from umbraco/temp-hartvig-ocd
Aligns installer/login background photo
2018-03-01 14:54:56 +01:00
Sebastiaan Jansssen 01f49bb07e Revert "Merge pull request #2426 from JeffreyPerplex/U4-9991-KeyboardShortcuts"
This reverts commit 325cefa349, reversing
changes made to d4cf4cd700.
2018-03-01 14:52:17 +01:00
Niels Hartvig d06b7edd84 Change default value label to "true" 2018-03-01 14:46:36 +01:00
Niels Hartvig 466de5ee0b Adds a label to the boolean pre value editor 2018-03-01 14:41:44 +01:00
Niels Hartvig 976e1e8a35 Mark existing dropdown property editors as obsolete 2018-03-01 14:25:07 +01:00
Niels Hartvig a3d08c19c5 Aligns photo 2018-03-01 14:05:34 +01:00
Mads Rasmussen 761804baf8 Merge pull request #2486 from umbraco/temp-U4-10876
Fixes "Content Picker 2 can search outside of it's selected start node"
2018-03-01 10:46:50 +01:00
Robert 88e6e44f4e Fixes Content Picker 2 can search outside of it's selected start node 2018-02-28 15:54:13 +01:00
Matt Wanchap da0a1c808a Added fallback to caption if no altText, as suggested 2018-02-28 11:06:59 +10:00
Barry 08965982fd Prevent unsaved dialogue appearing when no changes made on FileUpload property editor
Addresses this issue in media section (U4-9996) and content (U4-7484)
2018-02-25 05:50:10 +00:00
Barry 732d3ef326 Prevent "unsaved" warning when no changes on MarkDown Editor
http://issues.umbraco.org/issue/U4-7484#
2018-02-25 03:18:00 +00:00
Shannon 7019c9433b U4-10991 TourController Object reference not set to an instance of an object - when loading an invalid tour 2018-02-23 16:40:29 +10:00
Matt Wanchap b37197f66a Fix for U4-10821, render alt text attribute from grid image editor, or empty string if null (for screen readers) 2018-02-22 11:46:23 +10:00
Claus b2004057a5 U4-10957 If RequiredSection is not defined in a tour - backoffice will throw errors 2018-02-09 11:55:34 +01:00
Neil Gaietto 3f1f67e323 U4-8822- Fixes Unpublish error with empty RTE by passing an empty value instead of null 2016-08-16 09:30:05 -04:00
Kamil Jakubczak f1d37a5072 removes a overflow: hidden which decrease update-tree-layer performance
removes a overflow: hidden which decrease update-tree-layer performance.
If it is required it should be solved differently due to the possibility
of having plenty items in div that has this class.
2016-06-09 15:01:26 +02:00
bjarnef 2dc6e395a8 Add more colors to icon-picker dialog 2015-11-16 01:15:51 +01:00
bjarnef eedeb90673 Merge remote-tracking branch 'refs/remotes/umbraco/dev-v7' into dev-v7-U4-6616 2015-11-16 01:12:49 +01:00
bjarnef 977c390a95 Merge remote-tracking branch 'refs/remotes/umbraco/dev-v7' into dev-v7-U4-6616 2015-11-09 23:52:00 +01:00
65 changed files with 755 additions and 1003 deletions
+34 -1
View File
@@ -24,6 +24,7 @@ Remember, we're a friendly bunch and are happy with whatever contribution you mi
* [Working with the source code](#working-with-the-source-code)
* [What branch should I target for my contributions?](#what-branch-should-i-target-for-my-contributions)
* [Building Umbraco from source code](#building-umbraco-from-source-code)
* [Keeping your Umbraco fork in sync with the main repository](#keeping-your-umbraco-fork-in-sync-with-the-main-repository)
[How do I even begin?](#how-do-i-even-begin)
@@ -114,6 +115,15 @@ Some parts of our source code is over 10 years old now. And when we say "old", w
There's two big areas that you should know about:
1. The Umbraco backoffice is a extensible AngularJS app and requires you to run a `gulp dev` command while you're working with it, so changes are copied over to the appropriate directories and you can refresh your browser to view the results of your changes.
You may need to run the following commands to set up gulp properly:
```
npm cache clean
npm install -g bower
npm install -g gulp
npm install -g gulp-cli
npm install
gulp build
```
2. "The rest" is a C# based codebase, with some traces of our WebForms past but mostly ASP.NET MVC based these days. You can make changes, build them in Visual Studio, and hit `F5` to see the result.
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.
@@ -137,6 +147,29 @@ Alternatively, you can open `src\umbraco.sln` in Visual Studio 2017 ([the commun
After this build completes, you should be able to hit `F5` in Visual Studio to build and run the project. A IISExpress webserver will start and the Umbraco installer will pop up in your browser, follow the directions there to get a working Umbraco install up and running.
### Keeping your Umbraco fork in sync with the main repository
We recommend you sync with our repository before you submit your pull request. That way, you can fix any potential merge conflicts and make our lives a little bit easier.
Also, if you've submitted a pull request three weeks ago and want to work on something new, you'll want to get the latest code to build against of course.
To sync your fork with this original one, you'll have to add the upstream url, you only have to do this once:
```
git remote add upstream https://github.com/umbraco/Umbraco-CMS.git
```
Then when you want to get the changes from the main repository:
```
git fetch upstream
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))
## How do I even begin?
Great question! The short version goes like this:
@@ -171,4 +204,4 @@ Did something not work as expected? Try leaving a note in the ["Contributing to
## Credits
This contribution guide borrows heavily from the excellent work on [the Atom contribution guide](https://github.com/atom/atom/blob/master/CONTRIBUTING.md). A big [#h5yr](http://h5yr.com/) to them!
This contribution guide borrows heavily from the excellent work on [the Atom contribution guide](https://github.com/atom/atom/blob/master/CONTRIBUTING.md). A big [#h5yr](http://h5yr.com/) to them!
+1 -1
View File
@@ -30,7 +30,7 @@ As an Open Source platform, Umbraco is more than just a CMS. We are transparent
[Umbraco Cloud](https://umbraco.com) is the easiest and fastest way to use Umbraco yet with full support for all your custom .NET code and intergrations. You're up and running in less than a minute and your life will be made easier with automated upgrades and a built-in deployment engine. We offer a free 14 day trial, no credit card needed.
If you want to DIY you can [download Umbraco](https://our.umbraco.org/download) either as a ZIP file or via NuGet. It's the same version of Umbraco CMS that powers Umbraco Xloud, but you'll need to find a place to host yourself and handling deployments and upgrades is all down to you.
If you want to DIY you can [download Umbraco](https://our.umbraco.org/download) either as a ZIP file or via NuGet. It's the same version of Umbraco CMS that powers Umbraco Cloud, but you'll need to find a place to host yourself and handling deployments and upgrades is all down to you.
## Community
@@ -8,6 +8,7 @@ function Get-UmbracoBuildEnv
# store tools in the module's directory
# and cache them for two days
$path = "$PSScriptRoot\temp"
$src = "$PSScriptRoot\..\..\..\src"
$cache = 2
if (-not (test-path $path))
@@ -37,7 +38,7 @@ function Get-UmbracoBuildEnv
if (-not (test-path $sevenZip))
{
Write-Host "Download 7-Zip..."
&$nuget install 7-Zip.CommandLine -OutputDirectory $path -Verbosity quiet
&$nuget install 7-Zip.CommandLine -configFile "$src\NuGet.config" -OutputDirectory $path -Verbosity quiet
$dir = ls "$path\7-Zip.CommandLine.*" | sort -property Name -descending | select -first 1
$file = ls -path "$dir" -name 7za.exe -recurse
$file = ls -path "$dir" -name 7za.exe -recurse | select -first 1 #A select is because there is tools\7za.exe & tools\x64\7za.exe
@@ -54,7 +55,7 @@ function Get-UmbracoBuildEnv
if (-not (test-path $vswhere))
{
Write-Host "Download VsWhere..."
&$nuget install vswhere -OutputDirectory $path -Verbosity quiet
&$nuget install vswhere -configFile "$src\NuGet.config" -OutputDirectory $path -Verbosity quiet
$dir = ls "$path\vswhere.*" | sort -property Name -descending | select -first 1
$file = ls -path "$dir" -name vswhere.exe -recurse
mv "$dir\$file" $vswhere
@@ -70,7 +71,7 @@ function Get-UmbracoBuildEnv
if (-not (test-path $semver))
{
Write-Host "Download Semver..."
&$nuget install semver -OutputDirectory $path -Verbosity quiet
&$nuget install semver -configFile "$src\NuGet.config" -OutputDirectory $path -Verbosity quiet
$dir = ls "$path\semver.*" | sort -property Name -descending | select -first 1
$file = "$dir\lib\net452\Semver.dll"
if (-not (test-path $file))
@@ -445,7 +445,7 @@ function Restore-NuGet
Write-Host ">> Restore NuGet"
Write-Host "Logging to $tmp\nuget.restore.log"
&$uenv.NuGet restore "$src\Umbraco.sln" > "$tmp\nuget.restore.log"
&$uenv.NuGet restore "$src\Umbraco.sln" -configfile "$src\NuGet.config" > "$tmp\nuget.restore.log"
}
#
+1 -1
View File
@@ -8,7 +8,7 @@
----------------------------------------------------
*** IMPORTANT NOTICE FOR 7.7 UPGRADES ***
*** IMPORTANT NOTICE FOR UPGRADES FROM VERSIONS BELOW 7.7.0 ***
Be sure to read the version specific upgrade information before proceeding:
https://our.umbraco.org/documentation/Getting-Started/Setup/Upgrading/version-specific#version-7-7-0
+2 -2
View File
@@ -11,5 +11,5 @@ using System.Resources;
[assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyFileVersion("7.9.1")]
[assembly: AssemblyInformationalVersion("7.9.1")]
[assembly: AssemblyFileVersion("7.9.6")]
[assembly: AssemblyInformationalVersion("7.9.6")]
@@ -6,7 +6,7 @@ namespace Umbraco.Core.Configuration
{
public class UmbracoVersion
{
private static readonly Version Version = new Version("7.9.1");
private static readonly Version Version = new Version("7.9.6");
/// <summary>
/// Gets the current version of Umbraco.
+28 -56
View File
@@ -140,8 +140,7 @@ namespace Umbraco.Core
if (underlying != null)
{
// Special case for empty strings for bools/dates which should return null if an empty string.
var inputString = input as string;
if (inputString != null)
if (input is string inputString)
{
//TODO: Why the check against only bool/date when a string is null/empty? In what scenario can we convert to another type when the string is null or empty other than just being null?
if (string.IsNullOrEmpty(inputString) && (underlying == typeof(DateTime) || underlying == typeof(bool)))
@@ -168,8 +167,7 @@ namespace Umbraco.Core
{
// target is not a generic type
var inputString = input as string;
if (inputString != null)
if (input is string inputString)
{
// Try convert from string, returns an Attempt if the string could be
// processed (either succeeded or failed), else null if we need to try
@@ -218,8 +216,7 @@ namespace Umbraco.Core
}
// Re-check convertables since we altered the input through recursion
var convertible2 = input as IConvertible;
if (convertible2 != null)
if (input is IConvertible convertible2)
{
return Attempt.Succeed(Convert.ChangeType(convertible2, target));
}
@@ -277,8 +274,7 @@ namespace Umbraco.Core
{
if (target == typeof(int))
{
int value;
if (int.TryParse(input, out value))
if (int.TryParse(input, out var value))
{
return Attempt<object>.Succeed(value);
}
@@ -286,30 +282,26 @@ namespace Umbraco.Core
// Because decimal 100.01m will happily convert to integer 100, it
// makes sense that string "100.01" *also* converts to integer 100.
var input2 = NormalizeNumberDecimalSeparator(input);
decimal value2;
return Attempt<object>.SucceedIf(decimal.TryParse(input2, out value2), Convert.ToInt32(value2));
return Attempt<object>.SucceedIf(decimal.TryParse(input2, out var value2), Convert.ToInt32(value2));
}
if (target == typeof(long))
{
long value;
if (long.TryParse(input, out value))
if (long.TryParse(input, out var value))
{
return Attempt<object>.Succeed(value);
}
// Same as int
var input2 = NormalizeNumberDecimalSeparator(input);
decimal value2;
return Attempt<object>.SucceedIf(decimal.TryParse(input2, out value2), Convert.ToInt64(value2));
return Attempt<object>.SucceedIf(decimal.TryParse(input2, out var value2), Convert.ToInt64(value2));
}
// TODO: Should we do the decimal trick for short, byte, unsigned?
if (target == typeof(bool))
{
bool value;
if (bool.TryParse(input, out value))
if (bool.TryParse(input, out var value))
{
return Attempt<object>.Succeed(value);
}
@@ -322,53 +314,42 @@ namespace Umbraco.Core
switch (Type.GetTypeCode(target))
{
case TypeCode.Int16:
short value;
return Attempt<object>.SucceedIf(short.TryParse(input, out value), value);
return Attempt<object>.SucceedIf(short.TryParse(input, out var value), value);
case TypeCode.Double:
var input2 = NormalizeNumberDecimalSeparator(input);
double valueD;
return Attempt<object>.SucceedIf(double.TryParse(input2, out valueD), valueD);
return Attempt<object>.SucceedIf(double.TryParse(input2, out var valueD), valueD);
case TypeCode.Single:
var input3 = NormalizeNumberDecimalSeparator(input);
float valueF;
return Attempt<object>.SucceedIf(float.TryParse(input3, out valueF), valueF);
return Attempt<object>.SucceedIf(float.TryParse(input3, out var valueF), valueF);
case TypeCode.Char:
char valueC;
return Attempt<object>.SucceedIf(char.TryParse(input, out valueC), valueC);
return Attempt<object>.SucceedIf(char.TryParse(input, out var valueC), valueC);
case TypeCode.Byte:
byte valueB;
return Attempt<object>.SucceedIf(byte.TryParse(input, out valueB), valueB);
return Attempt<object>.SucceedIf(byte.TryParse(input, out var valueB), valueB);
case TypeCode.SByte:
sbyte valueSb;
return Attempt<object>.SucceedIf(sbyte.TryParse(input, out valueSb), valueSb);
return Attempt<object>.SucceedIf(sbyte.TryParse(input, out var valueSb), valueSb);
case TypeCode.UInt32:
uint valueU;
return Attempt<object>.SucceedIf(uint.TryParse(input, out valueU), valueU);
return Attempt<object>.SucceedIf(uint.TryParse(input, out var valueU), valueU);
case TypeCode.UInt16:
ushort valueUs;
return Attempt<object>.SucceedIf(ushort.TryParse(input, out valueUs), valueUs);
return Attempt<object>.SucceedIf(ushort.TryParse(input, out var valueUs), valueUs);
case TypeCode.UInt64:
ulong valueUl;
return Attempt<object>.SucceedIf(ulong.TryParse(input, out valueUl), valueUl);
return Attempt<object>.SucceedIf(ulong.TryParse(input, out var valueUl), valueUl);
}
}
else if (target == typeof(Guid))
{
Guid value;
return Attempt<object>.SucceedIf(Guid.TryParse(input, out value), value);
return Attempt<object>.SucceedIf(Guid.TryParse(input, out var value), value);
}
else if (target == typeof(DateTime))
{
DateTime value;
if (DateTime.TryParse(input, out value))
if (DateTime.TryParse(input, out var value))
{
switch (value.Kind)
{
@@ -388,24 +369,20 @@ namespace Umbraco.Core
}
else if (target == typeof(DateTimeOffset))
{
DateTimeOffset value;
return Attempt<object>.SucceedIf(DateTimeOffset.TryParse(input, out value), value);
return Attempt<object>.SucceedIf(DateTimeOffset.TryParse(input, out var value), value);
}
else if (target == typeof(TimeSpan))
{
TimeSpan value;
return Attempt<object>.SucceedIf(TimeSpan.TryParse(input, out value), value);
return Attempt<object>.SucceedIf(TimeSpan.TryParse(input, out var value), value);
}
else if (target == typeof(decimal))
{
var input2 = NormalizeNumberDecimalSeparator(input);
decimal value;
return Attempt<object>.SucceedIf(decimal.TryParse(input2, out value), value);
return Attempt<object>.SucceedIf(decimal.TryParse(input2, out var value), value);
}
else if (input != null && target == typeof(Version))
{
Version value;
return Attempt<object>.SucceedIf(Version.TryParse(input, out value), value);
return Attempt<object>.SucceedIf(Version.TryParse(input, out var value), value);
}
// E_NOTIMPL IPAddress, BigInteger
@@ -690,8 +667,7 @@ namespace Umbraco.Core
{
var key = new CompositeTypeTypeKey(source, target);
TypeConverter typeConverter;
if (InputTypeConverterCache.TryGetValue(key, out typeConverter))
if (InputTypeConverterCache.TryGetValue(key, out TypeConverter typeConverter))
{
return typeConverter;
}
@@ -711,8 +687,7 @@ namespace Umbraco.Core
{
var key = new CompositeTypeTypeKey(source, target);
TypeConverter typeConverter;
if (DestinationTypeConverterCache.TryGetValue(key, out typeConverter))
if (DestinationTypeConverterCache.TryGetValue(key, out TypeConverter typeConverter))
{
return typeConverter;
}
@@ -730,8 +705,7 @@ namespace Umbraco.Core
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static Type GetCachedGenericNullableType(Type type)
{
Type underlyingType;
if (NullableGenericCache.TryGetValue(type, out underlyingType))
if (NullableGenericCache.TryGetValue(type, out Type underlyingType))
{
return underlyingType;
}
@@ -750,8 +724,7 @@ namespace Umbraco.Core
private static bool GetCachedCanAssign(object input, Type source, Type target)
{
var key = new CompositeTypeTypeKey(source, target);
bool canConvert;
if (AssignableTypeCache.TryGetValue(key, out canConvert))
if (AssignableTypeCache.TryGetValue(key, out bool canConvert))
{
return canConvert;
}
@@ -770,8 +743,7 @@ namespace Umbraco.Core
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static bool GetCachedCanConvertToBoolean(Type type)
{
bool result;
if (BoolConvertCache.TryGetValue(type, out result))
if (BoolConvertCache.TryGetValue(type, out bool result))
{
return result;
}
@@ -6,6 +6,7 @@ using Umbraco.Core.Configuration;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Rdbms;
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
using Umbraco.Core.Persistence.SqlSyntax;
namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenSevenZero
@@ -343,15 +344,24 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenSevenZe
if (tables.InvariantContains("umbracoUserType") && tables.InvariantContains("umbracoUser"))
{
if (constraints.Any(x => x.Item1.InvariantEquals("umbracoUser") && x.Item3.InvariantEquals("FK_umbracoUser_umbracoUserType_id")))
if (Context.CurrentDatabaseProvider == DatabaseProviders.MySql)
{
Delete.ForeignKey("FK_umbracoUser_umbracoUserType_id").OnTable("umbracoUser");
//In MySql, this will drop the FK according to it's special naming rules
Delete.ForeignKey().FromTable("umbracoUser").ForeignColumn("userType").ToTable("umbracoUserType").PrimaryColumn("id");
}
//This is the super old constraint name of the FK for user type so check this one too
if (constraints.Any(x => x.Item1.InvariantEquals("umbracoUser") && x.Item3.InvariantEquals("FK_user_userType")))
else
{
Delete.ForeignKey("FK_user_userType").OnTable("umbracoUser");
}
//Delete the FK if it exists before dropping the column
if (constraints.Any(x => x.Item1.InvariantEquals("umbracoUser") && x.Item3.InvariantEquals("FK_umbracoUser_umbracoUserType_id")))
{
Delete.ForeignKey("FK_umbracoUser_umbracoUserType_id").OnTable("umbracoUser");
}
//This is the super old constraint name of the FK for user type so check this one too
if (constraints.Any(x => x.Item1.InvariantEquals("umbracoUser") && x.Item3.InvariantEquals("FK_user_userType")))
{
Delete.ForeignKey("FK_user_userType").OnTable("umbracoUser");
}
}
Delete.Column("userType").FromTable("umbracoUser");
Delete.Table("umbracoUserType");
@@ -361,4 +371,4 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenSevenZe
public override void Down()
{ }
}
}
}
+7 -8
View File
@@ -402,7 +402,7 @@ namespace Umbraco.Core.Persistence
}
// Helper to handle named parameters from object properties
static Regex rxParams = new Regex(@"(?<!@)@\w+", RegexOptions.Compiled);
static readonly Regex rxParams = new Regex(@"(?<!@)@\w+", RegexOptions.Compiled);
public static string ProcessParams(string _sql, object[] args_src, List<object> args_dest)
{
return rxParams.Replace(_sql, m =>
@@ -545,7 +545,7 @@ namespace Umbraco.Core.Persistence
}
// Create a command
static Regex rxParamsPrefix = new Regex(@"(?<!@)@\w+", RegexOptions.Compiled);
static readonly Regex rxParamsPrefix = new Regex(@"(?<!@)@\w+", RegexOptions.Compiled);
public IDbCommand CreateCommand(IDbConnection connection, string sql, params object[] args)
{
// Perform named argument replacements
@@ -666,8 +666,8 @@ namespace Umbraco.Core.Persistence
return ExecuteScalar<T>(sql.SQL, sql.Arguments);
}
Regex rxSelect = new Regex(@"\A\s*(SELECT|EXECUTE|CALL)\s", RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.IgnoreCase | RegexOptions.Multiline);
Regex rxFrom = new Regex(@"\A\s*FROM\s", RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.IgnoreCase | RegexOptions.Multiline);
static readonly Regex rxSelect = new Regex(@"\A\s*(SELECT|EXECUTE|CALL)\s", RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.IgnoreCase | RegexOptions.Multiline);
static readonly Regex rxFrom = new Regex(@"\A\s*FROM\s", RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.IgnoreCase | RegexOptions.Multiline);
string AddSelectClause<T>(string sql)
{
if (sql.StartsWith(";"))
@@ -701,9 +701,9 @@ namespace Umbraco.Core.Persistence
return Fetch<T>(sql.SQL, sql.Arguments);
}
static Regex rxColumns = new Regex(@"\A\s*SELECT\s+((?:\((?>\((?<depth>)|\)(?<-depth>)|.?)*(?(depth)(?!))\)|.)*?)(?<!,\s+)\bFROM\b", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.Compiled);
static Regex rxOrderBy = new Regex(@"\bORDER\s+BY\s+(?:\((?>\((?<depth>)|\)(?<-depth>)|.?)*(?(depth)(?!))\)|[\w\(\)\.])+(?:\s+(?:ASC|DESC))?(?:\s*,\s*(?:\((?>\((?<depth>)|\)(?<-depth>)|.?)*(?(depth)(?!))\)|[\w\(\)\.])+(?:\s+(?:ASC|DESC))?)*", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.Compiled);
static Regex rxDistinct = new Regex(@"\ADISTINCT\s", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.Compiled);
static readonly Regex rxColumns = new Regex(@"\A\s*SELECT\s+((?:\((?>\((?<depth>)|\)(?<-depth>)|.?)*(?(depth)(?!))\)|.)*?)(?<!,\s+)\bFROM\b", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.Compiled);
static readonly Regex rxOrderBy = new Regex(@"\bORDER\s+BY\s+(?:\((?>\((?<depth>)|\)(?<-depth>)|.?)*(?(depth)(?!))\)|[\w\(\)\.])+(?:\s+(?:ASC|DESC))?(?:\s*,\s*(?:\((?>\((?<depth>)|\)(?<-depth>)|.?)*(?(depth)(?!))\)|[\w\(\)\.])+(?:\s+(?:ASC|DESC))?)*", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.Compiled);
static readonly Regex rxDistinct = new Regex(@"\ADISTINCT\s", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.Compiled);
public static bool SplitSqlForPaging(string sql, out string sqlCount, out string sqlSelectRemoved, out string sqlOrderBy)
{
sqlSelectRemoved = null;
@@ -2546,5 +2546,4 @@ namespace Umbraco.Core.Persistence
}
}
}
}
@@ -1,4 +1,5 @@
using Umbraco.Core.Models.PublishedContent;
using System;
using Umbraco.Core.Models.PublishedContent;
namespace Umbraco.Core.PropertyEditors.ValueConverters
{
@@ -14,19 +15,7 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
public override object ConvertDataToSource(PublishedPropertyType propertyType, object source, bool preview)
{
if (source == null) return 0;
// in XML an integer is a string
var sourceString = source as string;
if (sourceString != null)
{
int i;
return (int.TryParse(sourceString, out i)) ? i : 0;
}
// in the database an integer is an integer
// default value is zero
return (source is int) ? source : 0;
return source.TryConvertTo<int>().Result;
}
}
}
+3
View File
@@ -20,6 +20,7 @@ namespace Umbraco.Core.Scoping
public NoScope(ScopeProvider scopeProvider)
{
_scopeProvider = scopeProvider;
Timestamp = DateTime.Now;
#if DEBUG_SCOPES
_scopeProvider.RegisterScope(this);
#endif
@@ -28,6 +29,8 @@ namespace Umbraco.Core.Scoping
private readonly Guid _instanceId = Guid.NewGuid();
public Guid InstanceId { get { return _instanceId; } }
public DateTime Timestamp { get; }
/// <inheritdoc />
public bool CallContext { get { return false; } }
+1 -1
View File
@@ -374,7 +374,7 @@ namespace Umbraco.Core.Scoping
}
var parent = ParentScope;
_scopeProvider.AmbientScope = parent;
_scopeProvider.AmbientScope = parent; // might be null = this is how scopes are removed from context objects
#if DEBUG_SCOPES
_scopeProvider.Disposed(this);
+51 -6
View File
@@ -2,10 +2,12 @@
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Runtime.Remoting.Messaging;
using System.Text;
using System.Web;
using Umbraco.Core.Events;
using Umbraco.Core.Logging;
using Umbraco.Core.Persistence;
#if DEBUG_SCOPES
using System.Linq;
@@ -66,22 +68,38 @@ namespace Umbraco.Core.Scoping
// tests, any other things (see https://msdn.microsoft.com/en-us/library/dn458353(v=vs.110).aspx),
// but we don't want to make all of our objects serializable since they are *not* meant to be
// used in cross-AppDomain scenario anyways.
//
// in addition, whatever goes into the logical call context is serialized back and forth any
// time cross-AppDomain code executes, so if we put an "object" there, we'll can *another*
// "object" instance - and so we cannot use a random object as a key.
// time cross-AppDomain code executes, so if we put an "object" there, we'll get *another*
// "object" instance back - and so we cannot use a random object as a key.
//
// so what we do is: we register a guid in the call context, and we keep a table mapping those
// guids to the actual objects. the guid serializes back and forth without causing any issue,
// and we can retrieve the actual objects from the table.
// only issue: how are we supposed to clear the table? we can't, really. objects should take
// care of de-registering themselves from context.
// everything we use does, except the NoScope scope, which just stays there
//
// during tests, NoScope can to into call context... nothing much we can do about it
// so far, the only objects that go into this table are scopes (using ScopeItemKey) and
// scope contexts (using ContextItemKey).
private static readonly object StaticCallContextObjectsLock = new object();
private static readonly Dictionary<Guid, object> StaticCallContextObjects
= new Dictionary<Guid, object>();
// normal scopes and scope contexts take greate care removing themselves when disposed, so it
// is all safe. OTOH the NoScope *CANNOT* remove itself, this is by design, it *WILL* leak and
// there is little (nothing) we can do about it - NoScope exists for backward compatibility
// reasons and relying on it is greatly discouraged.
//
// however... we can *try* at protecting the app against memory leaks, by collecting NoScope
// instances that are too old. if anything actually *need* to retain a NoScope instance for
// a long time, it will break. but that's probably ok. so: the constants below define how
// long a NoScope instance can stay in the table before being removed, and how often we should
// collect the table - and collecting happens anytime SetCallContextObject is invoked
private static readonly TimeSpan StaticCallContextNoScopeLifeSpan = TimeSpan.FromMinutes(30);
private static readonly TimeSpan StaticCallContextCollectPeriod = TimeSpan.FromMinutes(4);
private static DateTime _staticCallContextLastCollect = DateTime.MinValue;
#if DEBUG_SCOPES
public Dictionary<Guid, object> CallContextObjects
{
@@ -156,6 +174,7 @@ namespace Umbraco.Core.Scoping
//Logging.LogHelper.Debug<ScopeProvider>("At:\r\n" + Head(Environment.StackTrace, 24));
#endif
StaticCallContextObjects.Remove(objectKey);
CollectStaticCallContextObjectsLocked();
}
}
else
@@ -171,11 +190,37 @@ namespace Umbraco.Core.Scoping
//Logging.LogHelper.Debug<ScopeProvider>("At:\r\n" + Head(Environment.StackTrace, 24));
#endif
StaticCallContextObjects.Add(objectKey, value);
CollectStaticCallContextObjectsLocked();
}
CallContext.LogicalSetData(key, objectKey);
}
}
private static void CollectStaticCallContextObjectsLocked()
{
// is it time to collect?
var now = DateTime.Now;
if (now - _staticCallContextLastCollect <= StaticCallContextCollectPeriod)
return;
// disable warning: this method is invoked from within a lock
// ReSharper disable InconsistentlySynchronizedField
var threshold = now.Add(-StaticCallContextNoScopeLifeSpan);
var guids = StaticCallContextObjects
.Where(x => x.Value is NoScope noScope && noScope.Timestamp < threshold)
.Select(x => x.Key)
.ToList();
if (guids.Count > 0)
{
LogHelper.Warn<ScopeProvider>($"Collected {guids.Count} NoScope instances from StaticCallContextObjects.");
foreach (var guid in guids)
StaticCallContextObjects.Remove(guid);
}
// ReSharper restore InconsistentlySynchronizedField
_staticCallContextLastCollect = now;
}
// this is for tests exclusively until we have a proper accessor in v8
internal static Func<IDictionary> HttpContextItemsGetter { get; set; }
@@ -37,15 +37,15 @@ namespace Umbraco.Core.Security
var username = identity.GetUserName();
var session = identity.FindFirstValue(Constants.Security.SessionIdClaimType);
var securityStamp = identity.FindFirstValue(Microsoft.AspNet.Identity.Constants.DefaultSecurityStampClaimType);
var startContentId = identity.FindFirstValue(Constants.Security.StartContentNodeIdClaimType);
var startContentId = identity.FindFirstValue(Constants.Security.StartContentNodeIdClaimType);
var startMediaId = identity.FindFirstValue(Constants.Security.StartMediaNodeIdClaimType);
var culture = identity.FindFirstValue(ClaimTypes.Locality);
var id = identity.FindFirstValue(ClaimTypes.NameIdentifier);
var id = identity.FindFirstValue(ClaimTypes.NameIdentifier);
var realName = identity.FindFirstValue(ClaimTypes.GivenName);
if (username == null || startContentId == null || startMediaId == null
|| culture == null || id == null
if (username == null || startContentId == null || startMediaId == null
|| culture == null || id == null
|| realName == null || session == null)
throw new InvalidOperationException("Cannot create a " + typeof(UmbracoBackOfficeIdentity) + " from " + typeof(ClaimsIdentity) + " since there are missing required claims");
@@ -62,7 +62,7 @@ namespace Umbraco.Core.Security
catch (Exception e)
{
throw new InvalidOperationException("Cannot create a " + typeof(UmbracoBackOfficeIdentity) + " from " + typeof(ClaimsIdentity) + " since the data is not formatted correctly - either content or media start Ids could not be parsed as JSON", e);
}
}
var roles = identity.FindAll(x => x.Type == DefaultRoleClaimType).Select(role => role.Value).ToList();
var allowedApps = identity.FindAll(x => x.Type == Constants.Security.AllowedApplicationsClaimType).Select(app => app.Value).ToList();
@@ -165,7 +165,7 @@ namespace Umbraco.Core.Security
{
foreach (var claim in claimsIdentity.Claims)
{
//In one special case we will replace a claim if it exists already and that is the
//In one special case we will replace a claim if it exists already and that is the
// Forms auth claim for name which automatically gets added
TryRemoveClaim(FindFirst(x => x.Type == claim.Type && x.Issuer == "Forms"));
@@ -187,15 +187,15 @@ namespace Umbraco.Core.Security
{
ClaimTypes.NameIdentifier, //id
ClaimTypes.Name, //username
ClaimTypes.GivenName,
ClaimTypes.GivenName,
Constants.Security.StartContentNodeIdClaimType,
Constants.Security.StartMediaNodeIdClaimType,
ClaimTypes.Locality,
Constants.Security.StartMediaNodeIdClaimType,
ClaimTypes.Locality,
Constants.Security.SessionIdClaimType,
Microsoft.AspNet.Identity.Constants.DefaultSecurityStampClaimType
};
}
}
}
/// <summary>
/// Adds claims based on the UserData data
@@ -222,23 +222,19 @@ namespace Umbraco.Core.Security
AddClaim(new Claim(ClaimTypes.Locality, Culture, ClaimValueTypes.String, Issuer, Issuer, this));
if (HasClaim(x => x.Type == Constants.Security.SessionIdClaimType) == false && SessionId.IsNullOrWhiteSpace() == false)
{
AddClaim(new Claim(Constants.Security.SessionIdClaimType, SessionId, ClaimValueTypes.String, Issuer, Issuer, this));
//The security stamp claim is also required... this is because this claim type is hard coded
// by the SecurityStampValidator, see: https://katanaproject.codeplex.com/workitem/444
if (HasClaim(x => x.Type == Microsoft.AspNet.Identity.Constants.DefaultSecurityStampClaimType) == false)
{
AddClaim(new Claim(Microsoft.AspNet.Identity.Constants.DefaultSecurityStampClaimType, SecurityStamp, ClaimValueTypes.String, Issuer, Issuer, this));
}
}
//The security stamp claim is also required... this is because this claim type is hard coded
// by the SecurityStampValidator, see: https://katanaproject.codeplex.com/workitem/444
if (HasClaim(x => x.Type == Microsoft.AspNet.Identity.Constants.DefaultSecurityStampClaimType) == false)
AddClaim(new Claim(Microsoft.AspNet.Identity.Constants.DefaultSecurityStampClaimType, SecurityStamp, ClaimValueTypes.String, Issuer, Issuer, this));
//Add each app as a separate claim
if (HasClaim(x => x.Type == Constants.Security.AllowedApplicationsClaimType) == false)
{
foreach (var application in AllowedApplications)
{
AddClaim(new Claim(Constants.Security.AllowedApplicationsClaimType, application, ClaimValueTypes.String, Issuer, Issuer, this));
AddClaim(new Claim(Constants.Security.AllowedApplicationsClaimType, application, ClaimValueTypes.String, Issuer, Issuer, this));
}
}
@@ -253,8 +249,8 @@ namespace Umbraco.Core.Security
}
}
}
protected internal UserData UserData { get; private set; }
@@ -332,4 +328,4 @@ namespace Umbraco.Core.Security
}
}
}
}
+18 -24
View File
@@ -207,20 +207,17 @@ namespace Umbraco.Core.Services
{
return repository.GetByUsername(username, includeSecurityData: true);
}
catch (Exception ex)
catch (DbException ex)
{
if (ex is SqlException || ex is SqlCeException)
//we need to handle this one specific case which is when we are upgrading to 7.7 since the user group
//tables don't exist yet. This is the 'easiest' way to deal with this without having to create special
//version checks in the BackOfficeSignInManager and calling into other special overloads that we'd need
//like "GetUserById(int id, bool includeSecurityData)" which may cause confusion because the result of
//that method would not be cached.
if (ApplicationContext.Current.IsUpgrading)
{
//we need to handle this one specific case which is when we are upgrading to 7.7 since the user group
//tables don't exist yet. This is the 'easiest' way to deal with this without having to create special
//version checks in the BackOfficeSignInManager and calling into other special overloads that we'd need
//like "GetUserById(int id, bool includeSecurityData)" which may cause confusion because the result of
//that method would not be cached.
if (ApplicationContext.Current.IsUpgrading)
{
//NOTE: this will not be cached
return repository.GetByUsername(username, includeSecurityData: false);
}
//NOTE: this will not be cached
return repository.GetByUsername(username, includeSecurityData: false);
}
throw;
}
@@ -789,20 +786,17 @@ namespace Umbraco.Core.Services
var result = repository.Get(id);
return result;
}
catch (Exception ex)
catch (DbException ex)
{
if (ex is SqlException || ex is SqlCeException)
//we need to handle this one specific case which is when we are upgrading to 7.7 since the user group
//tables don't exist yet. This is the 'easiest' way to deal with this without having to create special
//version checks in the BackOfficeSignInManager and calling into other special overloads that we'd need
//like "GetUserById(int id, bool includeSecurityData)" which may cause confusion because the result of
//that method would not be cached.
if (ApplicationContext.Current.IsUpgrading)
{
//we need to handle this one specific case which is when we are upgrading to 7.7 since the user group
//tables don't exist yet. This is the 'easiest' way to deal with this without having to create special
//version checks in the BackOfficeSignInManager and calling into other special overloads that we'd need
//like "GetUserById(int id, bool includeSecurityData)" which may cause confusion because the result of
//that method would not be cached.
if (ApplicationContext.Current.IsUpgrading)
{
//NOTE: this will not be cached
return repository.Get(id, includeSecurityData: false);
}
//NOTE: this will not be cached
return repository.Get(id, includeSecurityData: false);
}
throw;
}
+14 -5
View File
@@ -3,6 +3,7 @@ using System.IO;
using System.Linq;
using Umbraco.Core.Configuration;
using Umbraco.Core.IO;
using Umbraco.Core.Logging;
namespace Umbraco.Core
{
@@ -142,10 +143,18 @@ namespace Umbraco.Core
/// <returns></returns>
internal static bool IsClientSideRequest(this Uri url)
{
var ext = Path.GetExtension(url.LocalPath);
if (ext.IsNullOrWhiteSpace()) return false;
var toInclude = new[] { ".aspx", ".ashx", ".asmx", ".axd", ".svc" };
return toInclude.Any(ext.InvariantEquals) == false;
try
{
var ext = Path.GetExtension(url.LocalPath);
if (ext.IsNullOrWhiteSpace()) return false;
var toInclude = new[] {".aspx", ".ashx", ".asmx", ".axd", ".svc"};
return toInclude.Any(ext.InvariantEquals) == false;
}
catch (ArgumentException ex)
{
LogHelper.Error(typeof(UriExtensions), "Failed to determine if request was client side", ex);
return false;
}
}
/// <summary>
@@ -311,4 +320,4 @@ namespace Umbraco.Core
return new Uri(uri.GetComponents(UriComponents.AbsoluteUri & ~UriComponents.Port, UriFormat.UriEscaped));
}
}
}
}
+46 -40
View File
@@ -93,53 +93,59 @@ namespace Umbraco.Tests.Routing
var result = uri.IsClientSideRequest();
Assert.AreEqual(assert, result);
}
[Test]
public void Is_Client_Side_Request_InvalidPath_ReturnFalse()
{
//This url is invalid. Default to false when the extension cannot be determined
var uri = new Uri("http://test.com/installing-modules+foobar+\"yipee\"");
var result = uri.IsClientSideRequest();
Assert.AreEqual(false, result);
}
//NOTE: This test shows how we can test most of the HttpModule, it however is testing a method that no longer exists and is testing too much,
// we need to write unit tests for each of the components: NiceUrlProvider, all of the Lookup classes, etc...
// to ensure that each one is individually tested.
//[TestCase("/", 1046)]
//[TestCase("/home.aspx", 1046)]
//[TestCase("/home/sub1.aspx", 1173)]
//[TestCase("/home.aspx?altTemplate=blah", 1046)]
//public void Process_Front_End_Document_Request_Match_Node(string url, int nodeId)
//{
// var httpContextFactory = new FakeHttpContextFactory(url);
// var httpContext = httpContextFactory.HttpContext;
// var umbracoContext = new UmbracoContext(httpContext, ApplicationContext.Current, new NullRoutesCache());
// var contentStore = new ContentStore(umbracoContext);
// var niceUrls = new NiceUrlProvider(contentStore, umbracoContext);
// umbracoContext.RoutingContext = new RoutingContext(
// new IPublishedContentLookup[] {new LookupByNiceUrl()},
// new DefaultLastChanceLookup(),
// contentStore,
// niceUrls);
// StateHelper.HttpContext = httpContext;
//NOTE: This test shows how we can test most of the HttpModule, it however is testing a method that no longer exists and is testing too much,
// we need to write unit tests for each of the components: NiceUrlProvider, all of the Lookup classes, etc...
// to ensure that each one is individually tested.
// //because of so much dependency on the db, we need to create som stuff here, i originally abstracted out stuff but
// //was turning out to be quite a deep hole because ultimately we'd have to abstract the old 'Domain' and 'Language' classes
// Domain.MakeNew("Test.com", 1000, Language.GetByCultureCode("en-US").id);
//[TestCase("/", 1046)]
//[TestCase("/home.aspx", 1046)]
//[TestCase("/home/sub1.aspx", 1173)]
//[TestCase("/home.aspx?altTemplate=blah", 1046)]
//public void Process_Front_End_Document_Request_Match_Node(string url, int nodeId)
//{
// var httpContextFactory = new FakeHttpContextFactory(url);
// var httpContext = httpContextFactory.HttpContext;
// var umbracoContext = new UmbracoContext(httpContext, ApplicationContext.Current, new NullRoutesCache());
// var contentStore = new ContentStore(umbracoContext);
// var niceUrls = new NiceUrlProvider(contentStore, umbracoContext);
// umbracoContext.RoutingContext = new RoutingContext(
// new IPublishedContentLookup[] {new LookupByNiceUrl()},
// new DefaultLastChanceLookup(),
// contentStore,
// niceUrls);
// //need to create a template with id 1045
// var template = Template.MakeNew("test", new User(0));
// StateHelper.HttpContext = httpContext;
// SetupUmbracoContextForTest(umbracoContext, template);
// //because of so much dependency on the db, we need to create som stuff here, i originally abstracted out stuff but
// //was turning out to be quite a deep hole because ultimately we'd have to abstract the old 'Domain' and 'Language' classes
// Domain.MakeNew("Test.com", 1000, Language.GetByCultureCode("en-US").id);
// _module.AssignDocumentRequest(httpContext, umbracoContext, httpContext.Request.Url);
// //need to create a template with id 1045
// var template = Template.MakeNew("test", new User(0));
// Assert.IsNotNull(umbracoContext.PublishedContentRequest);
// Assert.IsNotNull(umbracoContext.PublishedContentRequest.XmlNode);
// Assert.IsFalse(umbracoContext.PublishedContentRequest.IsRedirect);
// Assert.IsFalse(umbracoContext.PublishedContentRequest.Is404);
// Assert.AreEqual(umbracoContext.PublishedContentRequest.Culture, Thread.CurrentThread.CurrentCulture);
// Assert.AreEqual(umbracoContext.PublishedContentRequest.Culture, Thread.CurrentThread.CurrentUICulture);
// Assert.AreEqual(nodeId, umbracoContext.PublishedContentRequest.NodeId);
// SetupUmbracoContextForTest(umbracoContext, template);
//}
// _module.AssignDocumentRequest(httpContext, umbracoContext, httpContext.Request.Url);
// Assert.IsNotNull(umbracoContext.PublishedContentRequest);
// Assert.IsNotNull(umbracoContext.PublishedContentRequest.XmlNode);
// Assert.IsFalse(umbracoContext.PublishedContentRequest.IsRedirect);
// Assert.IsFalse(umbracoContext.PublishedContentRequest.Is404);
// Assert.AreEqual(umbracoContext.PublishedContentRequest.Culture, Thread.CurrentThread.CurrentCulture);
// Assert.AreEqual(umbracoContext.PublishedContentRequest.Culture, Thread.CurrentThread.CurrentUICulture);
// Assert.AreEqual(nodeId, umbracoContext.PublishedContentRequest.NodeId);
//}
}
}
}
}
+1 -3
View File
@@ -1,13 +1,11 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
using Umbraco.Core;
using Umbraco.Web.UI;
using umbraco;
using umbraco.BusinessLogic;
using umbraco.interfaces;
using Umbraco.Web.umbraco.presentation.umbraco.create;
namespace Umbraco.Tests.UI
{
-605
View File
@@ -1,605 +0,0 @@
module.exports = function (grunt) {
// Default task.
grunt.registerTask('default', ['jshint:dev', 'build', 'karma:unit']);
grunt.registerTask('dev', ['jshint:dev', 'build-dev', 'webserver', 'open:dev', 'watch']);
grunt.registerTask('docserve', ['docs:api', 'connect:docserver', 'open:docs', 'watch:docs']);
grunt.registerTask('vs', ['jshint:dev', 'build-dev', 'watch']);
//TODO: Too much watching, this brings windows to it's knees when in dev mode
//run by the watch task
grunt.registerTask('watch-js', ['jshint:dev', 'concat', 'copy:app', 'copy:mocks', 'copy:canvasdesigner', 'copy:vs', 'karma:unit']);
grunt.registerTask('watch-less', ['recess:build', 'recess:installer', 'recess:nonodes', 'recess:canvasdesigner', 'postcss', 'copy:canvasdesigner', 'copy:assets', 'copy:vs']);
grunt.registerTask('watch-html', ['copy:views', 'copy:vs']);
grunt.registerTask('watch-installer', ['concat:install', 'concat:installJs', 'copy:installer', 'copy:vs']);
grunt.registerTask('watch-canvasdesigner', ['copy:canvasdesigner', 'concat:canvasdesignerJs', 'copy:vs']);
grunt.registerTask('watch-test', ['jshint:dev', 'karma:unit']);
//triggered from grunt
grunt.registerTask('build', ['concat', 'recess:build', 'recess:installer', 'recess:nonodes', 'recess:canvasdesigner', 'postcss', 'bower-install-simple', 'bower', 'copy', 'clean:post']);
//triggered from grunt dev vs or grunt vs
grunt.registerTask('build-dev', ['clean:pre', 'concat', 'recess:build', 'recess:installer', 'recess:nonodes', 'postcss', 'bower-install-simple', 'bower', 'copy']);
//utillity tasks
grunt.registerTask('docs', ['ngdocs']);
grunt.registerTask('webserver', ['connect:devserver']);
// Print a timestamp (useful for when watching)
grunt.registerTask('timestamp', function () {
grunt.log.subhead(Date());
});
// Project configuration.
grunt.initConfig({
buildVersion: grunt.option('buildversion') || '7',
connect: {
devserver: {
options: {
port: 9990,
hostname: '0.0.0.0',
base: './build',
middleware: function(connect, options) {
return [
//uncomment to enable CSP
// util.csp(),
//util.rewrite(),
connect.favicon('images/favicon.ico'),
connect.static(options.base),
connect.directory(options.base)
];
}
}
},
testserver: {},
docserver: {
options: {
port: 8880,
hostname: '0.0.0.0',
base: './docs/api',
middleware: function(connect, options) {
return [
//uncomment to enable CSP
// util.csp(),
//util.rewrite(),
connect.static(options.base),
connect.directory(options.base)
];
}
}
},
},
open: {
dev: {
path: 'http://localhost:9990/belle/'
},
docs: {
path: 'http://localhost:8880/index.html'
}
},
distdir: 'build/belle',
vsdir: '../Umbraco.Web.UI/umbraco',
pkg: grunt.file.readJSON('package.json'),
banner:
'/*! <%= pkg.title || pkg.name %>\n' +
'<%= pkg.homepage ? " * " + pkg.homepage + "\\n" : "" %>' +
' * Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author %>;\n' +
' * Licensed <%= _.pluck(pkg.licenses, "type").join(", ") %>\n */\n',
src: {
js: ['src/**/*.js', 'src/*.js'],
common: ['src/common/**/*.js'],
controllers: ['src/**/*.controller.js'],
specs: ['test/**/*.spec.js'],
scenarios: ['test/**/*.scenario.js'],
samples: ['sample files/*.js'],
html: ['src/index.html', 'src/install.html'],
everything: ['src/**/*.*', 'test/**/*.*', 'docs/**/*.*'],
tpl: {
app: ['src/views/**/*.html'],
common: ['src/common/**/*.tpl.html']
},
less: ['src/less/belle.less'], // recess:build doesn't accept ** in its file patterns
prod: ['<%= distdir %>/js/*.js']
},
clean: {
pre: ['<%= distdir %>/*'],
post: ['<%= distdir %>/js/*.dev.js']
},
copy: {
assets: {
files: [{ dest: '<%= distdir %>/assets', src: '**', expand: true, cwd: 'src/assets/' }]
},
config: {
files: [{ dest: '<%= distdir %>/../config', src: '**', expand: true, cwd: 'src/config/' }]
},
installer: {
files: [{ dest: '<%= distdir %>/views/install', src: '**/*.html', expand: true, cwd: 'src/installer/steps' }]
},
canvasdesigner: {
files: [
{ dest: '<%= distdir %>/preview', src: '**/*.html', expand: true, cwd: 'src/canvasdesigner' },
{ dest: '<%= distdir %>/preview/editors', src: '**/*.html', expand: true, cwd: 'src/canvasdesigner/editors' },
{ dest: '<%= distdir %>/assets/less', src: '**/*.less', expand: true, cwd: 'src/canvasdesigner/editors' },
{ dest: '<%= distdir %>/js', src: 'canvasdesigner.config.js', expand: true, cwd: 'src/canvasdesigner/config' },
{ dest: '<%= distdir %>/js', src: 'canvasdesigner.palettes.js', expand: true, cwd: 'src/canvasdesigner/config' },
{ dest: '<%= distdir %>/js', src: 'canvasdesigner.front.js', expand: true, cwd: 'src/canvasdesigner' }
]
},
vendor: {
files: [{ dest: '<%= distdir %>/lib', src: '**', expand: true, cwd: 'lib/' }]
},
views: {
files: [{ dest: '<%= distdir %>/views', src: ['**/*.*', '!**/*.controller.js'], expand: true, cwd: 'src/views' }]
},
app: {
files: [
{ dest: '<%= distdir %>/js', src: '*.js', expand: true, cwd: 'src/' }
]
},
mocks: {
files: [{ dest: '<%= distdir %>/js', src: '*.js', expand: true, cwd: 'src/common/mocks/' }]
},
vs: {
files: [
//everything except the index.html root file!
//then we need to figure out how to not copy all the test stuff either!?
{ dest: '<%= vsdir %>/assets', src: '**', expand: true, cwd: '<%= distdir %>/assets' },
{ dest: '<%= vsdir %>/js', src: '**', expand: true, cwd: '<%= distdir %>/js' },
{ dest: '<%= vsdir %>/views', src: '**', expand: true, cwd: '<%= distdir %>/views' },
{ dest: '<%= vsdir %>/preview', src: '**', expand: true, cwd: '<%= distdir %>/preview' },
{ dest: '<%= vsdir %>/lib', src: '**', expand: true, cwd: '<%= distdir %>/lib' }
]
}
},
karma: {
unit: { configFile: 'test/config/karma.conf.js', keepalive: true },
e2e: { configFile: 'test/config/e2e.js', keepalive: true },
watch: { configFile: 'test/config/unit.js', singleRun: false, autoWatch: true, keepalive: true }
},
concat: {
index: {
src: ['src/index.html'],
dest: '<%= distdir %>/index.html',
options: {
process: true
}
},
install: {
src: ['src/installer/installer.html'],
dest: '<%= distdir %>/installer.html',
options: {
process: true
}
},
installJs: {
src: ['src/installer/**/*.js'],
dest: '<%= distdir %>/js/umbraco.installer.js',
options: {
banner: "<%= banner %>\n(function() { \n\n",
footer: "\n\n})();"
}
},
canvasdesignerJs: {
src: ['src/canvasdesigner/canvasdesigner.global.js', 'src/canvasdesigner/canvasdesigner.controller.js', 'src/canvasdesigner/editors/*.js', 'src/canvasdesigner/lib/*.js'],
dest: '<%= distdir %>/js/canvasdesigner.panel.js'
},
controllers: {
src: ['src/controllers/**/*.controller.js', 'src/views/**/*.controller.js'],
dest: '<%= distdir %>/js/umbraco.controllers.js',
options: {
banner: "<%= banner %>\n(function() { \n\n",
footer: "\n\n})();"
}
},
services: {
src: ['src/common/services/*.js'],
dest: '<%= distdir %>/js/umbraco.services.js',
options: {
banner: "<%= banner %>\n(function() { \n\n",
footer: "\n\n})();"
}
},
security: {
src: ['src/common/security/*.js'],
dest: '<%= distdir %>/js/umbraco.security.js',
options: {
banner: "<%= banner %>\n(function() { \n\n",
footer: "\n\n})();"
}
},
resources: {
src: ['src/common/resources/*.js'],
dest: '<%= distdir %>/js/umbraco.resources.js',
options: {
banner: "<%= banner %>\n(function() { \n\n",
footer: "\n\n})();"
}
},
testing: {
src: ['src/common/mocks/*/*.js'],
dest: '<%= distdir %>/js/umbraco.testing.js',
options: {
banner: "<%= banner %>\n(function() { \n\n",
footer: "\n\n})();"
}
},
directives: {
src: ['src/common/directives/**/*.js'],
dest: '<%= distdir %>/js/umbraco.directives.js',
options: {
banner: "<%= banner %>\n(function() { \n\n",
footer: "\n\n})();"
}
},
filters: {
src: ['src/common/filters/*.js'],
dest: '<%= distdir %>/js/umbraco.filters.js',
options: {
banner: "<%= banner %>\n(function() { \n\n",
footer: "\n\n})();"
}
}
},
uglify: {
options: {
mangle: true
},
combine: {
files: {
'<%= distdir %>/js/umbraco.min.js': ['<%= distdir %>/js/umbraco.*.js']
}
}
},
recess: {
build: {
files: {
'<%= distdir %>/assets/css/<%= pkg.name %>.css':
['<%= src.less %>']
},
options: {
compile: true,
compress: true
}
},
nonodes: {
files: {
'<%= distdir %>/assets/css/nonodes.style.min.css':
['src/less/pages/nonodes.less']
},
options: {
compile: true,
compress: true
}
},
installer: {
files: {
'<%= distdir %>/assets/css/installer.css':
['src/less/installer.less']
},
options: {
compile: true,
compress: true
}
},
canvasdesigner: {
files: {
'<%= distdir %>/assets/css/canvasdesigner.css':
['src/less/canvas-designer.less', 'src/less/helveticons.less']
},
options: {
compile: true,
compress: true
}
}
},
postcss: {
options: {
processors: [
// add vendor prefixes
require('autoprefixer-core')({
browsers: 'last 2 versions'
})
]
},
dist: {
src: '<%= distdir %>/assets/css/<%= pkg.name %>.css'
}
},
ngTemplateCache: {
views: {
files: {
'<%= distdir %>/js/umbraco.views.js': 'src/views/**/*.html'
},
options: {
trim: 'src/',
module: 'umbraco.views'
}
}
},
watch: {
docs: {
files: ['docs/src/**/*.md'],
tasks: ['watch-docs', 'timestamp']
},
css: {
files: 'src/**/*.less',
tasks: ['watch-less', 'timestamp'],
options: {
livereload: true,
},
},
js: {
files: ['src/**/*.js', 'src/*.js'],
tasks: ['watch-js', 'timestamp'],
},
test: {
files: ['test/**/*.js'],
tasks: ['watch-test', 'timestamp'],
},
installer: {
files: ['src/installer/**/*.*'],
tasks: ['watch-installer', 'timestamp'],
},
canvasdesigner: {
files: ['src/canvasdesigner/**/*.*'],
tasks: ['watch-canvasdesigner', 'timestamp'],
},
html: {
files: ['src/views/**/*.html', 'src/*.html'],
tasks: ['watch-html', 'timestamp']
},
options: {
interval: 500
}
},
ngdocs: {
options: {
dest: 'docs/api',
startPage: '/api',
title: "Umbraco Backoffice UI API Documentation",
html5Mode: false,
styles: [
'docs/umb-docs.css'
],
image: "https://our.umbraco.org/assets/images/logo.svg"
},
api: {
src: ['src/common/**/*.js', 'docs/src/api/**/*.ngdoc'],
title: 'API Documentation'
},
tutorials: {
src: [],
title: ''
}
},
eslint:{
src: ['<%= src.common %>','<%= src.controllers %>'],
options: {quiet: true}
},
jshint: {
dev: {
files: {
src: ['<%= src.common %>']
},
options: {
curly: true,
eqeqeq: true,
immed: true,
latedef: "nofunc",
newcap: true,
noarg: true,
sub: true,
boss: true,
//NOTE: This is required so it doesn't barf on reserved words like delete when doing $http.delete
es5: true,
eqnull: true,
//NOTE: we need to use eval sometimes so ignore it
evil: true,
//NOTE: we need to check for strings such as "javascript:" so don't throw errors regarding those
scripturl: true,
//NOTE: we ignore tabs vs spaces because enforcing that causes lots of errors depending on the text editor being used
smarttabs: true,
globals: {}
}
},
build: {
files: {
src: ['<%= src.prod %>']
},
options: {
curly: true,
eqeqeq: true,
immed: true,
latedef: "nofunc",
newcap: true,
noarg: true,
sub: true,
boss: true,
//NOTE: This is required so it doesn't barf on reserved words like delete when doing $http.delete
es5: true,
eqnull: true,
//NOTE: we need to use eval sometimes so ignore it
evil: true,
//NOTE: we need to check for strings such as "javascript:" so don't throw errors regarding those
scripturl: true,
//NOTE: we ignore tabs vs spaces because enforcing that causes lots of errors depending on the text editor being used
smarttabs: true,
globalstrict: true,
globals: { $: false, jQuery: false, define: false, require: false, window: false }
}
}
},
bower: {
dev: {
dest: '<%= distdir %>/lib',
options: {
expand: true,
ignorePackages: ['bootstrap'],
packageSpecific: {
'moment': {
keepExpandedHierarchy: false,
files: ['min/moment-with-locales.js']
},
'typeahead.js': {
keepExpandedHierarchy: false,
files: ['dist/typeahead.bundle.min.js']
},
'underscore': {
files: ['underscore-min.js', 'underscore-min.map']
},
'rgrove-lazyload': {
files: ['lazyload.js']
},
'bootstrap-social': {
files: ['bootstrap-social.css']
},
'font-awesome': {
files: ['css/font-awesome.min.css', 'fonts/*']
},
"jquery": {
keepExpandedHierarchy: false,
files: ['dist/jquery.min.js', 'dist/jquery.min.map']
},
'jquery-ui': {
keepExpandedHierarchy: false,
files: ['jquery-ui.min.js']
},
'jquery-migrate': {
keepExpandedHierarchy: false,
files: ['jquery-migrate.min.js']
},
'tinymce': {
files: ['plugins/**', 'themes/**', 'tinymce.min.js']
},
'angular-dynamic-locale': {
files: ['tmhDynamicLocale.min.js', 'tmhDynamicLocale.min.js.map']
},
'ng-file-upload': {
keepExpandedHierarchy: false,
files: ['ng-file-upload.min.js']
},
'angular-local-storage': {
keepExpandedHierarchy: false,
files: ['dist/angular-local-storage.min.js']
},
'codemirror': {
files: [
'lib/codemirror.js',
'lib/codemirror.css',
'mode/css/*',
'mode/javascript/*',
'mode/xml/*',
'mode/htmlmixed/*',
'addon/search/*',
'addon/edit/*',
'addon/selection/*',
'addon/dialog/*'
]
},
'ace-builds': {
files: [
'src-min-noconflict/ace.js',
'src-min-noconflict/ext-language_tools.js',
'src-min-noconflict/ext-searchbox.js',
'src-min-noconflict/ext-settings_menu.js',
'src-min-noconflict/snippets/text.js',
'src-min-noconflict/snippets/javascript.js',
'src-min-noconflict/theme-chrome.js',
'src-min-noconflict/mode-razor.js',
'src-min-noconflict/mode-javascript.js',
'src-min-noconflict/worker-javascript.js',
]
},
'clipboard': {
keepExpandedHierarchy: false,
files: ['dist/clipboard.min.js']
},
'angular-moment': {
keepExpandedHierarchy: false,
files: ['angular-moment.min.js']
}
}
}
},
options: {
expand: true
}
},
"bower-install-simple": {
options: {
color: true
},
"dev": {}
}
});
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-clean');
grunt.loadNpmTasks('grunt-contrib-copy');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-recess');
grunt.loadNpmTasks('grunt-postcss');
grunt.loadNpmTasks('grunt-karma');
grunt.loadNpmTasks('grunt-open');
grunt.loadNpmTasks('grunt-contrib-connect');
grunt.loadNpmTasks("grunt-bower-install-simple");
grunt.loadNpmTasks('grunt-bower');
grunt.loadNpmTasks('grunt-ngdocs');
grunt.loadNpmTasks('grunt-eslint');
grunt.loadNpmTasks('grunt-hustler');
};
@@ -84,27 +84,21 @@
};
}
if (!String.prototype.trimStart) {
/** trims the start of the string*/
String.prototype.trimStart = function (str) {
if (this.startsWith(str)) {
return this.substring(str.length);
}
return this;
};
}
if (!String.prototype.trimEnd) {
/** trims the start of the string*/
String.prototype.trimStart = function (str) {
if (this.startsWith(str)) {
return this.substring(str.length);
}
return this;
};
/** trims the end of the string*/
String.prototype.trimEnd = function (str) {
if (this.endsWith(str)) {
return this.substring(0, this.length - str.length);
}
return this;
};
}
/** trims the end of the string*/
String.prototype.trimEnd = function (str) {
if (this.endsWith(str)) {
return this.substring(0, this.length - str.length);
}
return this;
};
if (!String.prototype.utf8Encode) {
@@ -332,4 +326,4 @@
}
})();
})();
Binary file not shown.

Before

Width:  |  Height:  |  Size: 386 KiB

After

Width:  |  Height:  |  Size: 180 KiB

@@ -50,7 +50,7 @@
scope.openDocumentType = function (documentType) {
var url = "/settings/documenttypes/edit/" + documentType.id;
$location.path(url);
$location.url(url);
};
scope.updateTemplate = function (templateAlias) {
@@ -59,7 +59,6 @@
</pre>
<h1>General Options</h1>
Lorem ipsum dolor sit amet..
<table>
<thead>
<tr>
@@ -74,7 +73,7 @@ Lorem ipsum dolor sit amet..
<td>Set the title of the overlay.</td>
</tr>
<tr>
<td>model.subTitle</td>
<td>model.subtitle</td>
<td>String</td>
<td>Set the subtitle of the overlay.</td>
</tr>
@@ -496,6 +495,7 @@ Opens an overlay to show a custom YSOD. </br>
var activeElementType = document.activeElement.tagName;
var clickableElements = ["A", "BUTTON"];
var submitOnEnter = document.activeElement.hasAttribute("overlay-submit-on-enter");
var submitOnEnterValue = submitOnEnter ? document.activeElement.getAttribute("overlay-submit-on-enter") : "";
if(clickableElements.indexOf(activeElementType) === 0) {
document.activeElement.click();
@@ -503,7 +503,9 @@ Opens an overlay to show a custom YSOD. </br>
} else if(activeElementType === "TEXTAREA" && !submitOnEnter) {
} else {
} else if (submitOnEnter && submitOnEnterValue === "false") {
// don't do anything
}else {
scope.$apply(function () {
scope.submitForm(scope.model);
});
@@ -10,12 +10,12 @@ function noDirtyCheck() {
require: 'ngModel',
link: function (scope, elm, attrs, ctrl) {
elm.focus(function () {
scope.$watch(function() {
ctrl.$pristine = false;
});
});
var alwaysFalse = {
get: function () { return false; },
set: function () { }
};
Object.defineProperty(ctrl, '$pristine', alwaysFalse);
Object.defineProperty(ctrl, '$dirty', alwaysFalse);
}
};
@@ -168,6 +168,9 @@
//used for property editors
@import "property-editors.less";
//used for prevalue editors
@import "components/prevalues/multivalues.less";
@import "typeahead.less";
@import "hacks.less";
@@ -175,4 +178,4 @@
@import "healthcheck.less";
// cleanup properties.less when it is done
@import "properties.less";
@import "properties.less";
@@ -0,0 +1,53 @@
.umb-prevalues-multivalues {
width: 400px;
}
.umb-prevalues-multivalues__left {
display: flex;
flex: 1 1 auto;
}
.umb-prevalues-multivalues__right {
display: flex;
flex: 0 0 auto;
align-items: center;
}
.umb-prevalues-multivalues__add {
display: flex;
}
.umb-prevalues-multivalues__add input {
width: 320px;
}
.umb-prevalues-multivalues__add input {
display: flex;
}
.umb-prevalues-multivalues__add button {
margin: 0 6px 0 0;
float: right
}
.umb-prevalues-multivalues__listitem {
display: flex;
padding: 6px;
margin: 10px 0px !important;
background: #F3F3F5;
cursor: move;
}
.umb-prevalues-multivalues__listitem i {
display: flex;
align-items: center;
margin-right: 5px
}
.umb-prevalues-multivalues__listitem a {
cursor: pointer;
}
.umb-prevalues-multivalues__listitem input {
width: 295px;
}
@@ -280,7 +280,6 @@
.umb-grid .umb-control {
position: relative;
display: block;
overflow: hidden;
margin-left: 10px;
margin-right: 10px;
margin-bottom: 10px;
@@ -40,6 +40,16 @@
padding: 10px;
}
.umb-contentpicker__min-max-help {
font-size: 13px;
margin-top: 5px;
color: @gray-4;
}
.show-validation .umb-contentpicker__min-max-help {
display: none;
}
.umb-contentpicker small {
&:not(:last-child) {
@@ -109,22 +119,22 @@ ul.color-picker li a {
}
/* pre-value editor */
/*.control-group.color-picker-preval:before {
content: "";
display: inline-block;
vertical-align: middle;
height: 100%;
}*/
/*.control-group.color-picker-preval div.thumbnail {
display: inline-block;
/*.control-group.color-picker-preval:before {
content: "";
display: inline-block;
vertical-align: middle;
}*/
.control-group.color-picker-preval div.color-picker-prediv {
display: inline-block;
height: 100%;
}*/
/*.control-group.color-picker-preval div.thumbnail {
display: inline-block;
vertical-align: middle;
}*/
.control-group.color-picker-preval div.color-picker-prediv {
display: inline-block;
width: 60%;
}
}
.control-group.color-picker-preval pre {
display: inline;
margin-right: 20px;
@@ -136,18 +146,18 @@ ul.color-picker li a {
vertical-align: middle;
}
.control-group.color-picker-preval btn {
.control-group.color-picker-preval btn {
//vertical-align: middle;
}
}
.control-group.color-picker-preval input[type="text"] {
min-width: 40%;
width: 40%;
display: inline-block;
margin-right: 20px;
.control-group.color-picker-preval input[type="text"] {
min-width: 40%;
width: 40%;
display: inline-block;
margin-right: 20px;
margin-top: 1px;
}
}
.control-group.color-picker-preval label {
border: solid @white 1px;
padding: 6px;
@@ -203,10 +213,22 @@ ul.color-picker li a {
.umb-thumbnails{
position: relative;
.umb-thumbnails {
position: relative;
display: flex;
-ms-flex-direction: row;
-webkit-flex-direction: row;
flex-direction: row;
-ms-flex-wrap: wrap;
-webkit-flex-wrap: wrap;
flex-wrap: wrap;
justify-content: flex-start;
}
.umb-thumbnails > li.icon {
width: 14%;
text-align: center;
}
.umb-thumbnails i{margin: auto;}
.umb-thumbnails a{
@@ -100,6 +100,27 @@
.color-green, .color-green i{color: @green-d1 !important;}
.color-yellow, .color-yellow i{color: @yellow-d1 !important;}
/* Colors based on http://zavoloklom.github.io/material-design-color-palette/colors.html */
.color-black, .color-black i { color: #000 !important; }
.color-blue-grey, .color-blue-grey i { color: #607d8b !important; }
.color-grey, .color-grey i { color: #9e9e9e !important; }
.color-brown, .color-brown i { color: #795548 !important; }
.color-blue, .color-blue i { color: #2196f3 !important; }
.color-light-blue, .color-light-blue i {color: #03a9f4 !important; }
.color-cyan, .color-cyan i { color: #00bcd4 !important; }
.color-green, .color-green i { color: #4caf50 !important; }
.color-light-green, .color-light-green i {color: #8bc34a !important; }
.color-lime, .color-lime i { color: #cddc39 !important; }
.color-yellow, .color-yellow i { color: #ffeb3b !important; }
.color-amber, .color-amber i { color: #ffc107 !important; }
.color-orange, .color-orange i { color: #ff9800 !important; }
.color-deep-orange, .color-deep-orange i { color: #ff5722 !important; }
.color-red, .color-red i { color: #f44336 !important; }
.color-pink, .color-pink i { color: #e91e63 !important; }
.color-purple,.color-purple i { color: #9c27b0 !important; }
.color-deep-purple, .color-deep-purple i { color: #673ab7 !important; }
.color-indigo, .color-indigo i { color: #3f51b5 !important; }
// Scaffolding
// -------------------------
@@ -7,14 +7,13 @@ angular.module("umbraco")
$scope.icons = icons;
});
$scope.submitClass = function (icon) {
$scope.submitClass = function(icon){
if($scope.color) {
$scope.submit(icon + " " + $scope.color);
}
else {
$scope.submit(icon);
else {
$scope.submit(icon);
}
};
}
);
@@ -16,24 +16,25 @@
<div class="umb-control-group">
<select ng-model="color" class="input-block-level">
<option value="">
<localize key="colors_black">Black</localize>
</option>
<option value="color-green">
<localize key="colors_green">Green</localize>
</option>
<option value="color-yellow">
<localize key="colors_yellow">Yellow</localize>
</option>
<option value="color-orange">
<localize key="colors_orange">Orange</localize>
</option>
<option value="color-blue">
<localize key="colors_blue">Blue</localize>
</option>
<option value="color-red">
<localize key="colors_red">Red</localize>
</option>
<option value=""><localize key="colors_black">Black</localize></option>
<option value="color-blue-grey"><localize key="colors_bluegrey">Blue Grey</localize></option>
<option value="color-grey"><localize key="colors_grey">Grey</localize></option>
<option value="color-brown"><localize key="colors_brown">Brown</localize></option>
<option value="color-blue"><localize key="colors_blue">Blue</localize></option>
<option value="color-light-blue"><localize key="colors_lightblue">Light Blue</localize></option>
<option value="color-cyan"><localize key="colors_cyan">Cyan</localize></option>
<option value="color-green"><localize key="colors_green">Green</localize></option>
<option value="color-light-green"><localize key="colors_lightgreen">Light Green</localize></option>
<option value="color-yellow"><localize key="colors_yellow">Yellow</localize></option>
<option value="color-lime"><localize key="colors_lime">Lime</localize></option>
<option value="color-amber"><localize key="colors_amber">Amber</localize></option>
<option value="color-orange"><localize key="colors_orange">Orange</localize></option>
<option value="color-deep-orange"><localize key="colors_deeporange">Deep Orange</localize></option>
<option value="color-red"><localize key="colors_red">Red</localize></option>
<option value="color-pink"><localize key="colors_pink">Pink</localize></option>
<option value="color-purple"><localize key="colors_purple">Purple</localize></option>
<option value="color-deep-purple"><localize key="colors_deeppurple">Deep Purple</localize></option>
<option value="color-indigo"><localize key="colors_indigo">Indigo</localize></option>
</select>
</div>
@@ -14,7 +14,6 @@
</li>
<li data-element="section-{{section.alias}}" ng-repeat="section in sections | limitTo: maxSections" ng-class="{current: section.alias == currentSection}">
<a href="#/{{section.alias}}"
hotkey="ctrl+alt+{{$index+1}}"
ng-dblclick="sectionDblClick(section)"
ng-click="sectionClick($event, section)"
prevent-default>
@@ -42,8 +41,6 @@
<ul class="sections sections-tray">
<li ng-repeat="section in sections | limitTo: overflowingSections" ng-class="{current: section.alias == currentSection}">
<a href="#/{{section.alias}}"
hotkey="ctrl+alt+{{$index+1+maxSections}}"
hotkey-when-hidden="true"
ng-dblclick="sectionDblClick(section)"
ng-click="sectionClick($event, section)"
prevent-default>
@@ -30,7 +30,6 @@
ng-model="name"
ng-class="{'name-is-empty': $parent.name===null || $parent.name===''}"
umb-auto-focus
hotkey="ctrl+,"
val-server-field="Name"
required />
</ng-form>
@@ -4,7 +4,7 @@
class="alert alert-block alert-{{notification.type}} umb-notifications__notification animated -half-second fadeIn"
ng-class="{'-no-border -extra-padding': notification.type === 'form'}">
<a class='close -align-right' hotkey="esc" ng-click="removeNotification($index)" prevent-default href>&times;</a>
<a class='close -align-right' ng-click="removeNotification($index)" prevent-default href>&times;</a>
<div ng-if="notification.view">
<div ng-include="notification.view"></div>
@@ -1,5 +1,4 @@
<div data-element="overlay" class="umb-overlay umb-overlay-{{position}}" hotkey="esc" on-outside-click="closeOverLay()">
<div data-element="overlay" class="umb-overlay umb-overlay-{{position}}" on-outside-click="closeOverLay()">
<ng-form class="umb-overlay__form" name="overlayForm" novalidate val-form-manager>
<div data-element="overlay-header" class="umb-overlay-header">
@@ -1,5 +1,5 @@
<ul class="nav nav-tabs umb-nav-tabs">
<li data-element="tab-{{tab.alias}}" ng-class="{'tab-error': tabHasError}" ng-repeat="tab in model" val-tab>
<a data-toggle="tab" hotkey="ctrl+{{$index+1}}" href="#tab{{tab.id}}{{idSuffix}}">{{ tab.label }}</a>
<a data-toggle="tab" href="#tab{{tab.id}}{{idSuffix}}">{{ tab.label }}</a>
</li>
</ul>
@@ -47,7 +47,17 @@
</a>
</div>
<div class="umb-table-cell" ng-repeat="column in itemProperties">
<span title="{{column.header}}: {{item[column.alias]}}">{{item[column.alias]}}</span>
<span title="{{column.header}}: {{item[column.alias]}}">
<div ng-if="!column.isSensitive">
{{item[column.alias]}}
</div>
<em ng-show="column.isSensitive" class="muted">
<localize key="content_isSensitiveValue_short"></localize>
</em>
</span>
</div>
</div>
</div>
@@ -5,6 +5,7 @@ angular.module("umbraco").controller("Umbraco.PrevalueEditors.MultiValuesControl
$scope.newItem = "";
$scope.hasError = false;
$scope.focusOnNew = false;
if (!angular.isArray($scope.model.value)) {
@@ -43,6 +44,7 @@ angular.module("umbraco").controller("Umbraco.PrevalueEditors.MultiValuesControl
$scope.model.value.push({ value: $scope.newItem });
$scope.newItem = "";
$scope.hasError = false;
$scope.focusOnNew = true;
return;
}
}
@@ -73,6 +75,12 @@ angular.module("umbraco").controller("Umbraco.PrevalueEditors.MultiValuesControl
}
};
$scope.createNew = function (event) {
if (event.keyCode == 13) {
$scope.add(event);
}
}
function getElementIndexByPrevalueText(value) {
for (var i = 0; i < $scope.model.value.length; i++) {
if ($scope.model.value[i].value === value) {
@@ -1,13 +1,21 @@
<div class="umb-editor" ng-controller="Umbraco.PrevalueEditors.MultiValuesController">
<div class="control-group">
<input name="newItem" type="text" ng-model="newItem" val-highlight="{{hasError}}" />
<button class="btn" ng-click="add($event)">Add</button>
<div class="umb-editor umb-prevalues-multivalues" ng-controller="Umbraco.PrevalueEditors.MultiValuesController">
<div class="control-group umb-prevalues-multivalues__add">
<div class="umb-prevalues-multivalues__left">
<input overlay-submit-on-enter="false" name="newItem" focus-when="{{focusOnNew}}" ng-keydown="createNew($event)" type="text" ng-model="newItem" val-highlight="{{hasError}}" />
</div>
<div class="umb-prevalues-multivalues__right">
<button class="btn btn-info" ng-click="add($event)">Add</button>
</div>
</div>
<div ui-sortable="sortableOptions">
<div class="control-group" ng-repeat="item in model.value">
<div class="control-group umb-prevalues-multivalues__listitem" ng-repeat="item in model.value">
<i class="icon icon-navigation handle"></i>
<input type="text" ng-model="item.value" val-server="item_{{$index}}" required />
<button class="btn btn-danger" ng-click="remove(item, $event)">Remove</button>
<div class="umb-prevalues-multivalues__left">
<input type="text" ng-model="item.value" val-server="item_{{$index}}" required />
</div>
<div class="umb-prevalues-multivalues__right">
<a class="umb-node-preview__action" ng-click="remove(item, $event)">Remove</a>
</div>
</div>
</div>
</div>
@@ -15,7 +15,7 @@ function ColorPickerController($scope) {
$scope.toggleItem = function (color) {
var currentColor = $scope.model.value.hasOwnProperty("value")
var currentColor = ($scope.model.value && $scope.model.value.hasOwnProperty("value"))
? $scope.model.value.value
: $scope.model.value;
@@ -20,7 +20,7 @@
</umb-node-preview>
</div>
<a ng-show="model.config.multiPicker === true || renderModel.length === 0"
<a ng-show="model.config.multiPicker === true && renderModel.length < model.config.maxNumber || renderModel.length === 0 || !model.config.maxNumber"
class="umb-node-preview-add"
href=""
ng-click="openContentPicker()"
@@ -28,6 +28,39 @@
<localize key="general_add">Add</localize>
</a>
<div class="umb-contentpicker__min-max-help">
<!-- Both min and max items -->
<span ng-if="model.config.minNumber && model.config.maxNumber && model.config.minNumber !== model.config.maxNumber">
<span ng-if="renderModel.length < model.config.maxNumber">Add between {{model.config.minNumber}} and {{model.config.maxNumber}} items</span>
<span ng-if="renderModel.length > model.config.maxNumber">
<localize key="validation_maxCount">You can only have</localize> {{model.config.maxNumber}} <localize key="validation_itemsSelected"> items selected</localize>
</span>
</span>
<!-- Equal min and max -->
<span ng-if="model.config.minNumber && model.config.maxNumber && model.config.minNumber === model.config.maxNumber">
<span ng-if="renderModel.length < model.config.maxNumber">Add {{model.config.minNumber - renderModel.length}} item(s)</span>
<span ng-if="renderModel.length > model.config.maxNumber">
<localize key="validation_maxCount">You can only have</localize> {{model.config.maxNumber}} <localize key="validation_itemsSelected"> items selected</localize>
</span>
</span>
<!-- Only max -->
<span ng-if="!model.config.minNumber && model.config.maxNumber">
<span ng-if="renderModel.length < model.config.maxNumber">Add up to {{model.config.maxNumber}} items</span>
<span ng-if="renderModel.length > model.config.maxNumber">
<localize key="validation_maxCount">You can only have</localize> {{model.config.maxNumber}} <localize key="validation_itemsSelected">items selected</localize>
</span>
</span>
<!-- Only min -->
<span ng-if="model.config.minNumber && !model.config.maxNumber && renderModel.length < model.config.minNumber">
Add at least {{model.config.minNumber}} item(s)
</span>
</div>
<!--These are here because we need ng-form fields to validate against-->
<input type="hidden" name="minCount" ng-model="renderModel" />
<input type="hidden" name="maxCount" ng-model="renderModel" />
@@ -130,6 +130,9 @@ function fileUploadController($scope, $element, $compile, imageHelper, fileManag
// in the description of this controller, it states that this value isn't actually used for persistence,
// but we need to set it so that the editor and the server can detect that it's been changed, and it is used for validation.
$scope.model.value = { selectedFiles: newVal.trimEnd(",") };
//need to explicity setDirty here as file upload field can't track dirty & we can't use the fileCount (hidden field/model)
$scope.propertyForm.$setDirty();
});
});
@@ -31,6 +31,6 @@
</ul>
</div>
<input type="hidden" name="fileCount" ng-model="files.length" val-property-validator="validateMandatory"/>
<input type="hidden" name="fileCount" ng-model="files.length" val-property-validator="validateMandatory" no-dirty-check />
</div>
@@ -30,15 +30,14 @@
vm.dragLeave = dragLeave;
vm.onFilesQueue = onFilesQueue;
vm.onUploadComplete = onUploadComplete;
markAsSensitive();
function activate() {
if ($scope.entityType === 'media') {
mediaTypeHelper.getAllowedImagetypes(vm.nodeId).then(function (types) {
vm.acceptedMediatypes = types;
});
}
}
function selectAll($event) {
@@ -87,6 +86,27 @@
$scope.getContent($scope.contentId);
}
function markAsSensitive() {
angular.forEach($scope.options.includeProperties, function (option) {
option.isSensitive = false;
angular.forEach($scope.items,
function (item) {
angular.forEach(item.properties,
function (property) {
if (option.alias === property.alias) {
option.isSensitive = property.isSensitive;
}
});
});
});
}
activate();
}
@@ -46,6 +46,7 @@ function MarkdownEditorController($scope, $element, assetsService, dialogService
// init the md editor after this digest because the DOM needs to be ready first
// so run the init on a timeout
$timeout(function () {
$scope.markdownEditorInitComplete = false;
var converter2 = new Markdown.Converter();
var editor2 = new Markdown.Editor(converter2, "-" + $scope.model.alias);
editor2.run();
@@ -59,7 +60,12 @@ function MarkdownEditorController($scope, $element, assetsService, dialogService
editor2.hooks.set("onPreviewRefresh", function () {
// We must manually update the model as there is no way to hook into the markdown editor events without exstensive edits to the library.
if ($scope.model.value !== $("textarea", $element).val()) {
angularHelper.getCurrentForm($scope).$setDirty();
if ($scope.markdownEditorInitComplete) {
//only set dirty after init load to avoid "unsaved" dialogue when we don't want it
angularHelper.getCurrentForm($scope).$setDirty();
} else {
$scope.markdownEditorInitComplete = true;
}
$scope.model.value = $("textarea", $element).val();
}
});
@@ -359,7 +359,8 @@ angular.module("umbraco")
//this is instead of doing a watch on the model.value = faster
$scope.model.onValueChanged = function (newVal, oldVal) {
//update the display val again if it has changed from the server;
tinyMceEditor.setContent(newVal, { format: 'raw' });
//uses an empty string in the editor when the value is null
tinyMceEditor.setContent(newVal || "", { format: 'raw' });
//we need to manually fire this event since it is only ever fired based on loading from the DOM, this
// is required for our plugins listening to this event to execute
tinyMceEditor.fire('LoadContent', null);
@@ -92,7 +92,6 @@
$scope.model.config.ticksPositions = _.map($scope.model.config.ticksPositions.split(','), function (item) {
return parseInt(item.trim());
});
console.log($scope.model.config.ticksPositions);
}
if (!$scope.model.config.ticksLabels) {
@@ -215,4 +214,4 @@
assetsService.loadCss("lib/slider/bootstrap-slider.css");
assetsService.loadCss("lib/slider/bootstrap-slider-custom.css");
}
angular.module("umbraco").controller("Umbraco.PropertyEditors.SliderController", sliderController);
angular.module("umbraco").controller("Umbraco.PropertyEditors.SliderController", sliderController);
+2 -2
View File
@@ -1023,9 +1023,9 @@ xcopy "$(ProjectDir)"..\packages\SqlServerCE.4.0.0.1\x86\*.* "$(TargetDir)x86\"
<WebProjectProperties>
<UseIIS>True</UseIIS>
<AutoAssignPort>True</AutoAssignPort>
<DevelopmentServerPort>7910</DevelopmentServerPort>
<DevelopmentServerPort>7960</DevelopmentServerPort>
<DevelopmentServerVPath>/</DevelopmentServerVPath>
<IISUrl>http://localhost:7910</IISUrl>
<IISUrl>http://localhost:7960</IISUrl>
<NTLMAuthentication>False</NTLMAuthentication>
<UseCustomServer>False</UseCustomServer>
<CustomServerUrl>
@@ -13,8 +13,10 @@
url += "&mode=crop";
}
}
var altText = Model.value.altText ?? Model.value.caption ?? string.Empty;
<img src="@url" alt="@Model.value.caption">
<img src="@url" alt="@altText">
if (Model.value.caption != null)
{
@@ -661,7 +661,7 @@
<area alias="graphicheadline">
<key alias="backgroundcolor">Baggrundsfarve</key>
<key alias="bold">Fed</key>
<key alias="color">Tekst farve</key>
<key alias="color">Tekstfarve</key>
<key alias="font">Skrifttype</key>
<key alias="text">Tekst</key>
</area>
@@ -1259,9 +1259,9 @@ Mange hilsner fra Umbraco robotten
<key alias="styles">Typografi</key>
<key alias="stylesDetails">Vælg, hvilke typografiværdier, en redaktør kan ændre</key>
<key alias="stylesDetails">Vælg hvilke typografiværdier en redaktør kan ændre</key>
<key alias="settingDialogDetails">Indstillinger gemmes kun, hvis den indtaste json-konfiguration er gyldig</key>
<key alias="settingDialogDetails">Indstillinger gemmes kun, hvis den indtastede json-konfiguration er gyldig</key>
<key alias="allowAllEditors">Tillad alle editorer</key>
<key alias="allowAllRowConfigurations">Tillad alle rækkekonfigurationer</key>
@@ -1272,7 +1272,7 @@ Mange hilsner fra Umbraco robotten
<key alias="areAdded">er tilføjet</key>
<key alias="maxItems">Maksimalt emner</key>
<key alias="maxItemsDescription">Efterlad blank eller sat til 0 ubegrænset for</key>
<key alias="maxItemsDescription">Efterlad blank eller sæt til 0 for ubegrænset</key>
</area>
<area alias="contentTypeEditor">
@@ -1282,7 +1282,7 @@ Mange hilsner fra Umbraco robotten
<key alias="addNewTab">Tilføj ny fane</key>
<key alias="addAnotherTab">Tilføj endnu en fane</key>
<key alias="inheritedFrom">Nedarvet fra</key>
<key alias="addProperty">Tilføj property</key>
<key alias="addProperty">Tilføj egenskab</key>
<key alias="requiredLabel">Påkrævet label</key>
<key alias="enableListViewHeading">Aktiver listevisning</key>
@@ -1473,7 +1473,6 @@ Mange hilsner fra Umbraco robotten
<key alias="noLogin">har endnu ikke logget ind</key>
<key alias="oldPassword">Gammelt kodeord</key>
<key alias="password">Adgangskode</key>
<key alias="removePhoto">Fjern billede</key>
<key alias="resetPassword">Nulstil kodeord</key>
<key alias="passwordChanged">Dit kodeord er blevet ændret!</key>
<key alias="passwordConfirm">Bekræft venligst dit nye kodeord</key>
@@ -229,6 +229,7 @@
<key alias="removeTextBox">Remove this text box</key>
<key alias="contentRoot">Content root</key>
<key alias="isSensitiveValue">This value is hidden. If you need access to view this value please contact your website administrator.</key>
<key alias="isSensitiveValue_short">This value is hidden.</key>
</area>
<area alias="blueprints">
<key alias="createBlueprintFrom">Create a new Content Template from '%0%'</key>
@@ -662,7 +663,20 @@
<key alias="yellow">Yellow</key>
<key alias="orange">Orange</key>
<key alias="blue">Blue</key>
<key alias="bluegrey">Blue Grey</key>
<key alias="grey">Grey</key>
<key alias="brown">Brown</key>
<key alias="lightblue">Light Blue</key>
<key alias="cyan">Cyan</key>
<key alias="lightgreen">Light Green</key>
<key alias="lime">Lime</key>
<key alias="amber">Amber</key>
<key alias="deeporange">Deep Orange</key>
<key alias="red">Red</key>
<key alias="pink">Pink</key>
<key alias="purple">Purple</key>
<key alias="deeppurple">Deep Purple</key>
<key alias="indigo">Indigo</key>
</area>
<area alias="shortcuts">
@@ -229,6 +229,7 @@
<key alias="removeTextBox">Remove this text box</key>
<key alias="contentRoot">Content root</key>
<key alias="isSensitiveValue">This value is hidden. If you need access to view this value please contact your website administrator.</key>
<key alias="isSensitiveValue_short">This value is hidden.</key>
</area>
<area alias="blueprints">
<key alias="createBlueprintFrom">Create a new Content Template from '%0%'</key>
@@ -660,7 +661,20 @@
<key alias="yellow">Yellow</key>
<key alias="orange">Orange</key>
<key alias="blue">Blue</key>
<key alias="bluegrey">Blue Grey</key>
<key alias="grey">Grey</key>
<key alias="brown">Brown</key>
<key alias="lightblue">Light Blue</key>
<key alias="cyan">Cyan</key>
<key alias="lightgreen">Light Green</key>
<key alias="lime">Lime</key>
<key alias="amber">Amber</key>
<key alias="deeporange">Deep Orange</key>
<key alias="red">Red</key>
<key alias="pink">Pink</key>
<key alias="purple">Purple</key>
<key alias="deeppurple">Deep Purple</key>
<key alias="indigo">Indigo</key>
</area>
<area alias="shortcuts">
<key alias="addTab">Add tab</key>
@@ -38,7 +38,7 @@
<key alias="update">Bijwerken</key>
</area>
<area alias="assignDomain">
<key alias="permissionDenied">Permission denied.</key>
<key alias="permissionDenied">Toegang geweigerd.</key>
<key alias="addNew">Nieuw domein toevoegen</key>
<key alias="remove">verwijderen</key>
<key alias="invalidNode">Ongeldige node.</key>
@@ -1379,10 +1379,10 @@ Om een vertalingstaak te sluiten, ga aub naar het detailoverzicht en klik op de
<key alias="httpsCheckEnableHttpsDescription">Zet in de appSettings van de web.config de umbracoSSL instelling op 'true'.</key>
<key alias="httpsCheckEnableHttpsSuccess">De appSetting 'umbracoUseSSL' is nu ingesteld op 'true', cookies zullen als 'secure' worden aangemerkt.</key>
<key alias="rectifyButton">Fix</key>
<key alias="cannotRectifyShouldNotEqual">Cannot fix a check with a value comparison type of 'ShouldNotEqual'.</key>
<key alias="cannotRectifyShouldEqualWithValue">Cannot fix a check with a value comparison type of 'ShouldEqual' with a provided value.</key>
<key alias="valueToRectifyNotProvided">Value to fix check not provided.</key>
<key alias="rectifyButton">Herstellen</key>
<key alias="cannotRectifyShouldNotEqual">Kan een controle met vergelijkingstype 'ShouldNotEqual' niet herstellen.</key>
<key alias="cannotRectifyShouldEqualWithValue">Kan een controle met vergelijkingstype 'ShouldNotEqual' en gedefinieerde waarde niet herstellen.</key>
<key alias="valueToRectifyNotProvided">Waarde om te herstellen niet gedefinieerd.</key>
<key alias="compilationDebugCheckSuccessMessage">Debug compiliate mode staat uit.</key>
<key alias="compilationDebugCheckErrorMessage">Debug compiliate mode staat momenteel aan. Wij raden aan deze instelling uit te zetten voor livegang.</key>
@@ -9,6 +9,7 @@ using Umbraco.Core.Models.Rdbms;
using Umbraco.Core.Sync;
using Umbraco.Web.Routing;
using Umbraco.Core.Logging;
using Umbraco.Core.Scoping;
using Umbraco.Web.Scheduling;
namespace Umbraco.Web
@@ -21,9 +22,12 @@ namespace Umbraco.Web
/// </remarks>
public class BatchedDatabaseServerMessenger : DatabaseServerMessenger
{
private readonly ApplicationContext _appContext;
public BatchedDatabaseServerMessenger(ApplicationContext appContext, bool enableDistCalls, DatabaseServerMessengerOptions options)
: base(appContext, enableDistCalls, options)
{
_appContext = appContext;
Scheduler.Initializing += Scheduler_Initializing;
}
@@ -42,7 +46,7 @@ namespace Umbraco.Web
//start the background task runner for processing instructions
const int delayMilliseconds = 60000;
var instructionProcessingRunner = new BackgroundTaskRunner<IBackgroundTask>("InstructionProcessing", ApplicationContext.ProfilingLogger.Logger);
var instructionProcessingTask = new InstructionProcessing(instructionProcessingRunner, this, delayMilliseconds, Options.ThrottleSeconds * 1000);
var instructionProcessingTask = new InstructionProcessing(instructionProcessingRunner, this, _appContext.ScopeProvider, delayMilliseconds, Options.ThrottleSeconds * 1000);
instructionProcessingRunner.TryAdd(instructionProcessingTask);
e.Add(instructionProcessingTask);
}
@@ -73,18 +77,31 @@ namespace Umbraco.Web
private class InstructionProcessing : RecurringTaskBase
{
private readonly DatabaseServerMessenger _messenger;
private readonly IScopeProvider _scopeProvider;
public InstructionProcessing(IBackgroundTaskRunner<RecurringTaskBase> runner,
DatabaseServerMessenger messenger,
IScopeProvider scopeProvider,
int delayMilliseconds, int periodMilliseconds)
: base(runner, delayMilliseconds, periodMilliseconds)
{
_messenger = messenger;
_scopeProvider = scopeProvider;
}
public override bool PerformRun()
{
_messenger.Sync();
// beware!
// DatabaseServerMessenger uses _appContext.DatabaseContext.Database without creating
// scopes, and since we are running in a background task, there will be no ambient
// scope (as would be the case within a web request), and so we would end up creating
// (and leaking) a NoScope instance, which is bad - better make sure we have a true
// scope here! - see U4-11207
using (var scope = _scopeProvider.CreateScope())
{
_messenger.Sync();
scope.Complete();
}
//return true to repeat
return true;
}
@@ -121,14 +138,17 @@ namespace Umbraco.Web
batch.Clear();
//Write the instructions but only create JSON blobs with a max instruction count equal to MaxProcessingInstructionCount
foreach (var instructionsBatch in instructions.InGroupsOf(Options.MaxProcessingInstructionCount))
using (var scope = _appContext.ScopeProvider.CreateScope())
{
WriteInstructions(instructionsBatch);
foreach (var instructionsBatch in instructions.InGroupsOf(Options.MaxProcessingInstructionCount))
{
WriteInstructions(scope, instructionsBatch);
}
scope.Complete();
}
}
private void WriteInstructions(IEnumerable<RefreshInstruction> instructions)
private void WriteInstructions(IScope scope, IEnumerable<RefreshInstruction> instructions)
{
var dto = new CacheInstructionDto
{
@@ -137,8 +157,7 @@ namespace Umbraco.Web
OriginIdentity = LocalIdentity,
InstructionCount = instructions.Sum(x => x.JsonIdCount)
};
ApplicationContext.DatabaseContext.Database.Insert(dto);
scope.Database.Insert(dto);
}
protected ICollection<RefreshInstructionEnvelope> GetBatch(bool create)
@@ -179,16 +198,19 @@ namespace Umbraco.Web
if (batch == null)
{
//only write the json blob with a maximum count of the MaxProcessingInstructionCount
foreach (var maxBatch in instructions.InGroupsOf(Options.MaxProcessingInstructionCount))
using (var scope = _appContext.ScopeProvider.CreateScope())
{
WriteInstructions(maxBatch);
foreach (var maxBatch in instructions.InGroupsOf(Options.MaxProcessingInstructionCount))
{
WriteInstructions(scope, maxBatch);
}
scope.Complete();
}
}
else
{
batch.Add(new RefreshInstructionEnvelope(servers, refresher, instructions));
}
}
}
}
}
}
+21 -30
View File
@@ -1,29 +1,18 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Formatting;
using System.Net.Http.Headers;
using System.Reflection;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using System.Web.Http;
using System.Web.Http.ModelBinding;
using System.Web.Security;
using AutoMapper;
using Examine.LuceneEngine.SearchCriteria;
using Examine.SearchCriteria;
using Umbraco.Core;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Models.EntityBase;
using Umbraco.Core.Models.Membership;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
using Umbraco.Core.Security;
using Umbraco.Core.Services;
@@ -33,10 +22,7 @@ using Umbraco.Web.Models.ContentEditing;
using Umbraco.Web.Mvc;
using Umbraco.Web.WebApi.Binders;
using Umbraco.Web.WebApi.Filters;
using umbraco;
using Constants = Umbraco.Core.Constants;
using Examine;
using Newtonsoft.Json;
namespace Umbraco.Web.Editors
{
@@ -96,16 +82,18 @@ namespace Umbraco.Web.Editors
if (MembershipScenario == MembershipScenario.NativeUmbraco)
{
long totalRecords;
var members = Services.MemberService
.GetAll((pageNumber - 1), pageSize, out totalRecords, orderBy, orderDirection, orderBySystemField, memberTypeAlias, filter).ToArray();
.GetAll((pageNumber - 1), pageSize, out var totalRecords, orderBy, orderDirection, orderBySystemField, memberTypeAlias, filter).ToArray();
if (totalRecords == 0)
{
return new PagedResult<MemberBasic>(0, 0, 0);
}
var pagedResult = new PagedResult<MemberBasic>(totalRecords, pageNumber, pageSize);
pagedResult.Items = members
.Select(Mapper.Map<IMember, MemberBasic>);
var pagedResult = new PagedResult<MemberBasic>(totalRecords, pageNumber, pageSize)
{
Items = members
.Select(x => AutoMapperExtensions.MapWithUmbracoContext<IMember, MemberBasic>(x, UmbracoContext))
};
return pagedResult;
}
else
@@ -133,10 +121,13 @@ namespace Umbraco.Web.Editors
{
return new PagedResult<MemberBasic>(0, 0, 0);
}
var pagedResult = new PagedResult<MemberBasic>(totalRecords, pageNumber, pageSize);
pagedResult.Items = members
.Cast<MembershipUser>()
.Select(Mapper.Map<MembershipUser, MemberBasic>);
var pagedResult = new PagedResult<MemberBasic>(totalRecords, pageNumber, pageSize)
{
Items = members
.Cast<MembershipUser>()
.Select(Mapper.Map<MembershipUser, MemberBasic>)
};
return pagedResult;
}
@@ -437,7 +428,7 @@ namespace Umbraco.Web.Editors
var sensitiveProperties = contentItem.PersistedContent.ContentType
.PropertyTypes.Where(x => contentItem.PersistedContent.ContentType.IsSensitiveProperty(x.Alias))
.ToList();
foreach (var sensitiveProperty in sensitiveProperties)
{
//if found, change the value of the contentItem model to the persisted value so it remains unchanged
@@ -665,7 +656,7 @@ namespace Umbraco.Web.Editors
contentItem.Email,
"TEMP", //some membership provider's require something here even if q/a is disabled!
"TEMP", //some membership provider's require something here even if q/a is disabled!
contentItem.IsApproved,
contentItem.IsApproved,
contentItem.PersistedContent.Key, //custom membership provider, we'll link that based on the IMember unique id (GUID)
out status);
@@ -682,7 +673,7 @@ namespace Umbraco.Web.Editors
contentItem.Email,
"TEMP", //some membership provider's require something here even if q/a is disabled!
"TEMP", //some membership provider's require something here even if q/a is disabled!
contentItem.IsApproved,
contentItem.IsApproved,
newKey,
out status);
@@ -828,17 +819,17 @@ namespace Umbraco.Web.Editors
var member = ((MemberService)Services.MemberService).ExportMember(key);
var fileName = $"{member.Name}_{member.Email}.txt";
httpResponseMessage.Content = new ObjectContent<MemberExportModel>(member, new JsonMediaTypeFormatter {Indent = true});
httpResponseMessage.Content = new ObjectContent<MemberExportModel>(member, new JsonMediaTypeFormatter { Indent = true });
httpResponseMessage.Content.Headers.Add("x-filename", fileName);
httpResponseMessage.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
httpResponseMessage.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
httpResponseMessage.Content.Headers.ContentDisposition.FileName = fileName;
httpResponseMessage.StatusCode = HttpStatusCode.OK;
return httpResponseMessage;
}
}
}
+11 -5
View File
@@ -70,14 +70,20 @@ namespace Umbraco.Web.Editors
//Checking to see if the user has access to the required tour sections, else we remove the tour
foreach (var backOfficeTourFile in result)
{
foreach (var tour in backOfficeTourFile.Tours)
if (backOfficeTourFile.Tours != null)
{
foreach (var toursRequiredSection in tour.RequiredSections)
foreach (var tour in backOfficeTourFile.Tours)
{
if (allowedSections.Contains(toursRequiredSection) == false)
if (tour.RequiredSections != null)
{
toursToBeRemoved.Add(backOfficeTourFile);
break;
foreach (var toursRequiredSection in tour.RequiredSections)
{
if (allowedSections.Contains(toursRequiredSection) == false)
{
toursToBeRemoved.Add(backOfficeTourFile);
break;
}
}
}
}
}
+5
View File
@@ -9,6 +9,11 @@ namespace Umbraco.Web.Models
[DataContract(Name = "tour", Namespace = "")]
public class BackOfficeTour
{
public BackOfficeTour()
{
RequiredSections = new List<string>();
}
[DataMember(Name = "name")]
public string Name { get; set; }
[DataMember(Name = "alias")]
+6 -1
View File
@@ -9,6 +9,11 @@ namespace Umbraco.Web.Models
[DataContract(Name = "tourFile", Namespace = "")]
public class BackOfficeTourFile
{
public BackOfficeTourFile()
{
Tours = new List<BackOfficeTour>();
}
/// <summary>
/// The file name for the tour
/// </summary>
@@ -27,4 +32,4 @@ namespace Umbraco.Web.Models
[DataMember(Name = "tours")]
public IEnumerable<BackOfficeTour> Tours { get; set; }
}
}
}
@@ -30,6 +30,11 @@ namespace Umbraco.Web.Models.ContentEditing
[DataMember(Name = "editor", IsRequired = false)]
public string Editor { get; set; }
/// <summary>
/// Flags the property to denote that it can contain sensitive data
/// </summary>
[DataMember(Name = "isSensitive", IsRequired = false)]
public bool IsSensitive { get; set; }
/// <summary>
/// Used internally during model mapping
@@ -38,4 +43,4 @@ namespace Umbraco.Web.Models.ContentEditing
internal PropertyEditor PropertyEditor { get; set; }
}
}
}
@@ -80,17 +80,21 @@ namespace Umbraco.Web.Models.Mapping
//FROM IMember TO MemberBasic
config.CreateMap<IMember, MemberBasic>()
.ForMember(display => display.Udi, expression => expression.MapFrom(content => Udi.Create(Constants.UdiEntityType.Member, content.Key)))
.ForMember(display => display.Udi,
expression =>
expression.MapFrom(content => Udi.Create(Constants.UdiEntityType.Member, content.Key)))
.ForMember(dto => dto.Owner, expression => expression.ResolveUsing(new OwnerResolver<IMember>()))
.ForMember(dto => dto.Icon, expression => expression.MapFrom(content => content.ContentType.Icon))
.ForMember(dto => dto.ContentTypeAlias, expression => expression.MapFrom(content => content.ContentType.Alias))
.ForMember(dto => dto.ContentTypeAlias,
expression => expression.MapFrom(content => content.ContentType.Alias))
.ForMember(dto => dto.Email, expression => expression.MapFrom(content => content.Email))
.ForMember(dto => dto.Username, expression => expression.MapFrom(content => content.Username))
.ForMember(dto => dto.Trashed, expression => expression.Ignore())
.ForMember(dto => dto.Published, expression => expression.Ignore())
.ForMember(dto => dto.Updater, expression => expression.Ignore())
.ForMember(dto => dto.Alias, expression => expression.Ignore())
.ForMember(dto => dto.HasPublishedVersion, expression => expression.Ignore());
.ForMember(dto => dto.HasPublishedVersion, expression => expression.Ignore())
.ForMember(dto => dto.Properties, expression => expression.ResolveUsing(new MemberBasicPropertiesResolver()));
//FROM MembershipUser TO MemberBasic
config.CreateMap<MembershipUser, MemberBasic>()
@@ -395,6 +399,8 @@ namespace Umbraco.Web.Models.Mapping
//check permissions for viewing sensitive data
if (isSensitiveProperty && umbracoContext.Security.CurrentUser.HasAccessToSensitiveData() == false)
{
//mark this property as sensitive
prop.IsSensitive = true;
//mark this property as readonly so that it does not post any data
prop.Readonly = true;
//replace this editor with a sensitivevalue
@@ -477,8 +483,51 @@ namespace Umbraco.Web.Models.Mapping
return AutoMapperExtensions.MapWithUmbracoContext<IMember, MemberDisplay>(member, context.GetUmbracoContext());
}
}
/// <summary>
/// A resolver to map <see cref="IMember"/> properties to a collection of <see cref="ContentPropertyBasic"/>
/// </summary>
internal class MemberBasicPropertiesResolver : IValueResolver
{
public ResolutionResult Resolve(ResolutionResult source)
{
if (source.Value != null && (source.Value is IMember) == false)
throw new AutoMapperMappingException(string.Format("Value supplied is of type {0} but expected {1}.\nChange the value resolver source type, or redirect the source value supplied to the value resolver using FromMember.", new object[]
{
source.Value.GetType(),
typeof (IMember)
}));
return source.New(
//perform the mapping with the current umbraco context
ResolveCore(source.Context.GetUmbracoContext(), (IMember)source.Value), typeof(IEnumerable<ContentPropertyDisplay>));
}
private IEnumerable<ContentPropertyBasic> ResolveCore(UmbracoContext umbracoContext, IMember content)
{
var result = Mapper.Map<IEnumerable<Property>, IEnumerable<ContentPropertyBasic>>(
// Sort properties so items from different compositions appear in correct order (see U4-9298). Map sorted properties.
content.Properties.OrderBy(prop => prop.PropertyType.SortOrder))
.ToList();
var member = (IMember)content;
var memberType = member.ContentType;
//now update the IsSensitive value
foreach (var prop in result)
{
//check if this property is flagged as sensitive
var isSensitiveProperty = memberType.IsSensitiveProperty(prop.Alias);
//check permissions for viewing sensitive data
if (isSensitiveProperty && umbracoContext.Security.CurrentUser.HasAccessToSensitiveData() == false)
{
//mark this property as sensitive
prop.IsSensitive = true;
//clear the value
prop.Value = null;
}
}
return result;
}
}
}
}
@@ -1,7 +1,5 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Globalization;
using System.Linq;
using AutoMapper;
using Umbraco.Core;
@@ -9,7 +7,6 @@ using Umbraco.Core.Models;
using Umbraco.Core.PropertyEditors;
using Umbraco.Core.Services;
using Umbraco.Web.Models.ContentEditing;
using umbraco;
namespace Umbraco.Web.Models.Mapping
{
@@ -53,7 +50,7 @@ namespace Umbraco.Web.Models.Mapping
//perform the mapping with the current umbraco context
ResolveCore(source.Context.GetUmbracoContext(), (TSource)source.Value), typeof(List<Tab<ContentPropertyDisplay>>));
}
/// <summary>
/// Adds the container (listview) tab to the document
/// </summary>
@@ -275,7 +272,7 @@ namespace Umbraco.Web.Models.Mapping
//now add the user props
contentProps.AddRange(currProps);
//re-assign
genericProps.Properties = contentProps;
@@ -308,6 +305,6 @@ namespace Umbraco.Web.Models.Mapping
return result;
}
}
}
+5 -1
View File
@@ -63,6 +63,10 @@ namespace Umbraco.Web.Scheduling
{
using (var wc = new HttpClient())
{
if (Uri.TryCreate(_appContext.UmbracoApplicationUrl, UriKind.Absolute, out var baseUri))
{
wc.BaseAddress = baseUri;
}
var request = new HttpRequestMessage(HttpMethod.Get, url);
//TODO: pass custom the authorization header, currently these aren't really secured!
@@ -122,4 +126,4 @@ namespace Umbraco.Web.Scheduling
get { return true; }
}
}
}
}
@@ -208,6 +208,10 @@ namespace Umbraco.Web.Search
if (sb == null) throw new ArgumentNullException("sb");
if (entityService == null) throw new ArgumentNullException("entityService");
Udi udi;
Udi.TryParse(searchFrom, true, out udi);
searchFrom = udi == null ? searchFrom : entityService.GetIdForUdi(udi).Result.ToString();
int searchFromId;
var entityPath = int.TryParse(searchFrom, out searchFromId) && searchFromId > 0
? entityService.GetAllPaths(objectType, searchFromId).FirstOrDefault()
@@ -332,4 +336,4 @@ namespace Umbraco.Web.Search
}
}
}
}
@@ -1,45 +1,53 @@
using System;
using System.Data;
using System.Linq;
using System.Web.Security;
using Umbraco.Web.UI;
using umbraco.BusinessLogic;
using umbraco.DataLayer;
using umbraco.BasePages;
using Umbraco.Core.IO;
using umbraco.cms.businesslogic.member;
using Umbraco.Web.UI;
namespace umbraco
namespace Umbraco.Web.umbraco.presentation.umbraco.create
{
public class MemberGroupTasks : LegacyDialogTask
{
public override bool PerformSave()
{
Roles.CreateRole(Alias);
_returnUrl = string.Format("members/EditMemberGroup.aspx?id={0}", System.Web.HttpContext.Current.Server.UrlEncode(Alias));
_returnUrl = $"members/EditMemberGroup.aspx?id={System.Web.HttpContext.Current.Server.UrlEncode(Alias)}";
return true;
}
public override bool PerformDelete()
{
var roleDeleted = false;
// only built-in roles can be deleted
if (Member.IsUsingUmbracoRoles())
{
MemberGroup.GetByName(Alias).delete();
return true;
roleDeleted = Roles.DeleteRole(Alias);
}
return false;
// Need to delete the member group from any content item that has it assigned in public access settings
var publicAccessService = UmbracoContext.Current.Application.Services.PublicAccessService;
var allPublicAccessRules = publicAccessService.GetAll();
// Find only rules which have the current role name (alias) assigned to them
var rulesWithDeletedRoles = allPublicAccessRules.Where(x => x.Rules.Any(r => r.RuleValue == Alias));
var contentService = UmbracoContext.Current.Application.Services.ContentService;
foreach (var publicAccessEntry in rulesWithDeletedRoles)
{
var contentItem = contentService.GetById(publicAccessEntry.ProtectedNodeId);
var rulesToDelete = publicAccessEntry.Rules.ToList();
foreach (var rule in rulesToDelete)
publicAccessService.RemoveRule(contentItem, rule.RuleType, rule.RuleValue);
}
return roleDeleted;
}
private string _returnUrl = "";
public override string ReturnUrl
{
get { return _returnUrl; }
}
public override string ReturnUrl => _returnUrl;
public override string AssignedApp
{
get { return DefaultApps.member.ToString(); }
}
public override string AssignedApp => DefaultApps.member.ToString();
}
}