Compare commits

...

103 Commits

Author SHA1 Message Date
Sebastiaan Janssen bbe4a87784 U4-6171 Continuous Deployment from Visual Studio Online to Azure Websites not working as expected
#U4-6171 Fixed
2015-10-29 16:07:07 +01:00
Sebastiaan Janssen cbd5c295bd Merge pull request #728 from vnbaaij/dev-v7
Fix for #U4-6171 Continuous Deployment from Visual Studio Online to A…
2015-10-29 16:05:20 +01:00
Shannon 0d29e1438c strange/crazy peta poco fix for cultures 2015-10-29 15:24:06 +01:00
Sebastiaan Janssen 5a1ace9362 Revert "Fixes tests failing due to missing path"
This reverts commit 0c402310d9.
2015-10-29 13:00:51 +01:00
Stephan da85e4eb28 fixes list view ancestor check fix 2015-10-29 12:20:10 +01:00
Shannon fbc08d66f1 fixes list view ancestor check 2015-10-29 12:05:46 +01:00
Shannon 79f04bf939 Merge branch 'dev-v7' of https://github.com/umbraco/Umbraco-CMS into dev-v7 2015-10-29 11:57:07 +01:00
Shannon 9ab90595e2 Adds a filter to the interceptor to ignore errors for certain requests. 2015-10-29 11:56:23 +01:00
Sebastiaan Janssen 51b618826c Merge pull request #844 from ryanmcdonough/UKFest-U4-7151
Update database placeholder to backslash for instance name.
2015-10-29 11:16:56 +01:00
ryanmcdonough 04c28e5006 Update database placeholder to backslash for instance name. 2015-10-29 09:56:22 +00:00
Sebastiaan Janssen c160ce98c1 Merge pull request #794 from mstodd/dev-v7
Setting UMB_CONTEXT with Domain "FALSE"
2015-10-29 10:19:28 +01:00
Sebastiaan Janssen c3a60ea0e0 Merge pull request #838 from ryanmcdonough/U4-7302
Login overlay now higher than bootstrap datepicker
2015-10-29 09:19:42 +01:00
Stephan 3408efdee4 Merge pull request #842 from umbraco/temp-U4-7285
U4-7285 Fix DistributedCache.ClearXxxCacheOnCurrentServer
2015-10-28 19:38:04 +01:00
Shannon 1f0dc7e65d Merge branch 'dev-v7' of https://github.com/umbraco/Umbraco-CMS into dev-v7 2015-10-28 18:26:44 +01:00
Shannon f89083c772 bumped version 2015-10-28 18:26:34 +01:00
Sebastiaan Janssen 752065e540 Merge pull request #835 from umbraco/temp-U4-7032
U4-7032 7.3.0 Custom backoffice login provider requires simpler implementation extensibility
2015-10-28 18:25:10 +01:00
Sebastiaan Janssen 82e4e50584 Merge pull request #841 from umbraco/temp-U4-7231
U4-7231 TryConvertTo<T> of ObjectExtensions doesn't do null checks (c…
2015-10-28 17:09:30 +01:00
Sebastiaan Janssen 775e63148d Merge branch 'temp-U4-5963' into dev-v7 2015-10-28 17:02:51 +01:00
Sebastiaan Janssen 4259b02b8d Merge branch 'dev-v7' into temp-U4-5963
Conflicts:
	src/Umbraco.Web.UI.Client/src/controllers/main.controller.js
2015-10-28 16:56:40 +01:00
Sebastiaan Janssen 0c402310d9 Fixes tests failing due to missing path 2015-10-28 16:07:54 +01:00
Stephan 8d92330ad6 Fix broken comments 2015-10-28 15:01:23 +01:00
Sebastiaan Janssen 44e76f741f Merge pull request #840 from umbraco/temp-U4-7021
Fixes: U4-7021 "Actions" dropdown not available to children in listvi…
2015-10-28 14:52:48 +01:00
Shannon ecbced5c62 Massively simplifies the RenderActionInvoker which will support the native MVC caching and both async and non async support. U4-7270 Async Index actions for controllers implementing IRenderMvcController do not render view correctly 2015-10-28 14:31:40 +01:00
Shannon e6773dafc1 Updates PR to only display the prop alias in the title attribute when in debug mode. U4-4794 Display the property alias for content properties & provide a link to the content type from the generic properties tab 2015-10-28 12:45:15 +01:00
Shannon Deminick 7b8b7ed170 Merge pull request #837 from digbyswift/dev-v7
U4-7270 - Addition of allowance for async/await Index actions
2015-10-28 12:33:32 +01:00
Shannon Deminick c0997e1b9f Merge pull request #817 from tobbbe/hooverpropforalias
Hoover a property in backend to get its alias
2015-10-28 12:31:20 +01:00
Shannon d4f862a44f Merge branch 'dev-v7' of https://github.com/umbraco/Umbraco-CMS into dev-v7 2015-10-28 12:28:41 +01:00
Shannon 64c983eb07 Updates PR with fixes for code and implementation logic for the url list. 2015-10-28 12:28:29 +01:00
Shannon e25222162c Merge branch 'danieland-U4-7296-Link-to-each-items-doc-type-from-Properies-tab-in-Content-section' into dev-v7 2015-10-28 09:50:20 +01:00
Shannon e022687457 Merge branch 'U4-7296-Link-to-each-items-doc-type-from-Properies-tab-in-Content-section' of https://github.com/danieland/Umbraco-CMS into danieland-U4-7296-Link-to-each-items-doc-type-from-Properies-tab-in-Content-section 2015-10-28 09:49:55 +01:00
Shannon 84db2f4d85 U4-7285 Every server that reads a instruction from umbracoCacheInstruction will also write the same instruction to the database. Intentional ? 2015-10-27 19:24:56 +01:00
Shannon ef64409a9a U4-7231 TryConvertTo<T> of ObjectExtensions doesn't do null checks (causes handled errors on members after upgrade) 2015-10-27 18:29:46 +01:00
Shannon f0b68ac31e Fixes: U4-7021 "Actions" dropdown not available to children in listview nodes 2015-10-27 18:13:18 +01:00
Sebastiaan Janssen 6c80bd9eb9 U4-6385 Poor Handling of disallowedUploadFiles
#U4-6385 State: Review
2015-10-27 13:45:02 +01:00
Sebastiaan Janssen c7b7bf1510 Merge pull request #839 from umbraco/temp-U4-7214
U4-7214 Culture is not supported. Parameter name: name en_us is an in…
2015-10-27 11:27:53 +01:00
Shannon d1805b1448 U4-7214 Culture is not supported. Parameter name: name en_us is an invalid culture identifier error selecting user with different language after upgrade to 7.3.0 2015-10-27 11:22:28 +01:00
ryanmcdonough 780937dae9 Login overlay now higher than bootstrap datepicker 2015-10-26 15:49:55 +00:00
Shannon 9b054eaa47 Adds native ability to be able to fallback to default password checking if specifying a custom IBackOfficeUserPasswordChecker 2015-10-26 14:51:19 +01:00
Shannon Deminick badd9ae289 Merge pull request #833 from umbraco/temp-U4-7201
Fixes: U4-7201 Can only save once in some editors after upgrade to 7.3
2015-10-23 11:45:24 +02:00
Kieron McIntyre db6755a5bb Addition of allowance for async/await Index actions 2015-10-23 10:04:14 +01:00
Daniel 738815170c more nullchecks needed?
null check that we can access user
2015-10-23 00:21:42 +02:00
Daniel ef091e8c3a U4-7296
http://issues.umbraco.org/issue/U4-7296
2015-10-22 23:41:18 +02:00
Daniel 71b3810e9c Merge remote-tracking branch 'refs/remotes/umbraco/dev-v7' into dev-v7 2015-10-22 21:49:49 +02:00
Shannon Deminick a1e62dae5e Merge pull request #834 from Attackmonkey/Fix-U4-7257
Fixes issue where dictionary items are displayed in a random order
2015-10-22 18:43:23 +02:00
Shannon 96c087d00f adds a ctor to the BackOfficeUserManager to allow better inheritance so that all settings are initialized by default, changes init method to be protected so other devs can use it. Adds a new property for devs to use to more easily extend the logic to just validate the username/password. 2015-10-22 18:40:20 +02:00
Tim 0568bf51f0 Fixes issue where dictionary items are displayed in a random order (see issue U4-7257) 2015-10-22 17:17:29 +01:00
Shannon Deminick e3bade4d1a Merge pull request #816 from Jeavon/U4-7260
Fix for U4-7260
2015-10-22 18:08:23 +02:00
Shannon Deminick 633b0b0003 Merge pull request #830 from albinj/dev-v7
U4-7283 - Only Master/Single ServerRole should be removing old instru…
2015-10-22 18:06:53 +02:00
Shannon Deminick 82adf48699 Merge pull request #805 from umbraco/temp-7234
Fixes #7234
2015-10-22 18:06:14 +02:00
Shannon 63be12b9fe Merge branch 'dev-v7-U4-6967' of https://github.com/bjarnef/Umbraco-CMS into bjarnef-dev-v7-U4-6967
Conflicts:
	src/Umbraco.Web.UI.Client/src/controllers/main.controller.js
2015-10-22 18:03:03 +02:00
Shannon 33f7ed5129 Fixes: U4-7223 GetCropUrl outputs html entities in url when used in css
Adding in HtmlHelper extensions for GetCropUrl.
2015-10-22 17:52:58 +02:00
Shannon 79583c571c Fixes: U4-7201 Can only save once in some editors after upgrade to 7.3 2015-10-22 15:40:12 +02:00
Shannon Deminick a7e2c0b4dc Merge pull request #804 from rasmusjp/feature/copy-content-dialog
Added recursive option to copy dialog
2015-10-22 10:38:07 +02:00
Shannon da48e1b392 Fixes: U4-6962 Public access in multiple levels is broken in 7.3
Ensured the backoffice UI will look at protection for the specific node only (no inheritance) when specifying public access.
Added non-recursive method to Access class.
Fixed bug causing the tree (child nodes) not to update correctly after changing public access on nodes.
2015-10-21 18:43:30 +02:00
albinj f535ece685 U4-7283 - Only Master/Single ServerRole should be removing old instructions from the database 2015-10-21 14:29:18 +01:00
Claus Jensen 04e46c7cd1 Merge pull request #815 from umbraco/temp-U4-7198
Fixes: U4-7198 Change default log4net config to include machine name …
2015-10-21 12:20:45 +02:00
Claus Jensen 1089aef00a Merge pull request #825 from umbraco/temp-U4-7217
Fixes: U4-7217 umbracoReservedUrls do not always resolve correctly.
2015-10-21 11:52:39 +02:00
Shannon 8950d94b25 adds unit test showing deleting a property group does not delete the property types. 2015-10-20 14:51:08 +02:00
Shannon bb6299cc01 Fixes: U4-7217 umbracoReservedUrls do not always resolve correctly.
Verified that all tests in GlobalSettingsTests run correctly.
Removes the strange old legacy compare thing and replaces it with a more readable Linq solution that ensures that the strings compared are always consistent.
2015-10-20 09:48:58 +02:00
Shannon Deminick 2176f2a1c9 Merge pull request #802 from tmoxon/dev-v7
Null check to prevent object reference error with public properties on custom indexers
2015-10-19 18:05:33 +02:00
Shannon Deminick 6a351bede1 Merge pull request #823 from umbraco/tmp-6797
U4-6797 - clear domains cache when deleting content
2015-10-19 15:52:37 +02:00
Shannon Deminick efc1aae0ae Merge pull request #822 from umbraco/tmp-3642
U4-3642 - proper validation msg in hostnames dialog
2015-10-19 15:49:09 +02:00
Stephan df39e027fd U4-3642 - proper validation msg in hostnames dialog 2015-10-16 17:23:12 +02:00
Stephan 64f05e4c97 U4-6797 - clear domains cache when deleting content 2015-10-16 17:21:44 +02:00
Shannon 30bc89ba93 U4-7092 can't show avatar because in China all users can't access to some sites. - Fixes where and how the avatar gets loaded, we first check if it exist or that we can connect to the internet and then load it, removes the avatar loading from the user service.. not sure why it was even there. 2015-10-16 14:45:49 +02:00
Shannon 841c8d69fc removes unused avatar directive 2015-10-16 14:30:23 +02:00
Shannon aa780d2b8a updates the googlefontpicker to lazy load the required google font lib. 2015-10-16 14:09:54 +02:00
Shannon 59f15f1618 updates the canvas loader, ensures that there are no external dependencies and that paths are relative. 2015-10-16 14:09:27 +02:00
TOXIC\Tobbe b2f0a9f23d Hoover a property in backend to get its alias 2015-10-16 14:07:19 +02:00
Shannon 40cd07f3f4 removes wide setting from canvas designer since it does not exist. 2015-10-16 13:36:30 +02:00
Shannon 99e7f84f79 Moves EnableCanvasDesigner to HtmlHelperRenderExtensions because it's for rendering html, obsoletes the old ones and fixes up the canvasdesigner to use
the correct umbraco paths instead of hard coded absolute paths.
2015-10-16 13:36:10 +02:00
Stephan 3a5a32c65f U4-7255 - fix RefreshInstruction serialization 2015-10-16 12:28:14 +02:00
Shannon c2627f3a2a removes strange parse feed method, what the heck is this? it isn't used so its removed 2015-10-15 19:17:47 +02:00
Shannon 22b8d41aee U4-5963 There should be no external request dependencies - updates nonodes, removes the font references that is never used, replaces the open sans font-reference with the one that we already have locally and uses it. 2015-10-15 19:08:53 +02:00
Jeavon ee47ea2026 Fix for U4-7260 - Multi node tree picker with no selection can cause a error to display in the backoffice 2015-10-15 16:29:40 +01:00
Shannon 57622cef9a Fixes: U4-7198 Change default log4net config to include machine name in file name 2015-10-15 17:14:24 +02:00
Shannon 30ad3f5aa6 bumps version 2015-10-15 17:12:13 +02:00
Shannon 2c11f0be0f updates method to use the available request instance instead of using HttpContext.Current! no idea why it was using that. 2015-10-15 17:07:46 +02:00
Shannon c514ce8da3 Fixes: U4-7248 Can't update roles on public access, obsolete AddOrUpdateRule 2015-10-15 17:06:00 +02:00
Sebastiaan Janssen 65d421b619 Can_Update_Rule was wrong, it's not possible to "update" a rule, can only add or remove - added a test for removing 2015-10-14 11:32:55 +02:00
Sebastiaan Janssen 62897f7064 Test was wrong, 2 rules were added and was expecting 1 to be returned, now that the code is fixed, this test needs to be corrected 2015-10-14 11:13:23 +02:00
Sebastiaan Janssen e0619edabb U4-6962 Public access in multiple levels is broken in 7.3
#U4-6962 Fixed
2015-10-14 10:19:39 +02:00
Sebastiaan Janssen 4142f47861 U4-6125 Installing MySQL Web Provider Breaks Page Publishing
#U4-6125 Fixed Due in version 7.3.1
2015-10-13 13:48:58 +02:00
Sebastiaan Janssen 7135f9a268 Removes message that is no longer correct 2015-10-13 13:12:28 +02:00
Niels Hartvig a75a58b719 Fixes #7234 2015-10-12 18:45:01 +02:00
Claus Jensen 7b969fc167 Merge pull request #790 from umbraco/U4-7075
Fixes: U4-7075 Enable Content and Media section by default for new ba…
2015-10-12 14:46:28 +02:00
Rasmus John Pedersen 78475b0686 Added recursive option to copy dialog 2015-10-09 20:25:51 +02:00
Shannon 4925d55e8f Fixes: U4-7197 open redirect vulnerability with ClientRedirect 2015-10-06 11:46:38 +02:00
Shannon 52d2306e17 Fixes: U4-7196 XSS vulnerability in BrowseRepository 2015-10-06 11:36:54 +02:00
Shannon 5e5207d4f3 Fixes: U4-7194 XSS issue with regexws page, U4-7195 XSS issue with editview.aspx 2015-10-06 10:56:16 +02:00
Sebastiaan Janssen 96d46c82fe U4-7193 NuGet install doesn't add all bindingRedirects
#U4-7193 Fixed Due in version 7.3.1
2015-10-06 08:58:19 +02:00
Per Ploug 86bf50db12 Merge pull request #803 from Tazer/dev-v7
Updated readme with working intro video , that is for umbraco v7
2015-10-05 14:28:08 +02:00
Patrik 14778422e6 Updated readme with working intro video , that is for umbraco v7 2015-10-05 14:22:57 +02:00
tmoxon 6a931273a6 The indexing api would break if an indexer was created with a public property defaulting to a null value. This would result in an object reference error in the admin system. Added null check and warning to the log. 2015-10-01 14:42:32 +01:00
Sebastiaan Janssen 5fab1ea436 U4-7164 Nuget Update-Package UmbracoCms fails if I have removed dashboard section
#U4-7164 Fixed Due in version 7.3.1
2015-10-01 08:52:40 +02:00
Daniel Andreasen 5310ce38fd Merge pull request #1 from umbraco/dev-v7
update original fork
2015-09-27 23:30:26 +02:00
m_stodd 7abbfbcfcc Setting UMB_CONTEXT with Domain "FALSE"
Running Umbraco on localhost, Chrome does not handle received 'Set Cookie's with no domain.  "FALSE" works as noted here:  http://stackoverflow.com/questions/1134290/cookies-on-localhost-with-explicit-domain
2015-09-18 02:13:12 -05:00
Vincent Baaij a22b97643a Merge remote-tracking branch 'umbraco/dev-v7' into dev-v7 2015-09-14 21:53:33 +02:00
Claus 80be614731 Fixes: U4-7075 Enable Content and Media section by default for new backoffice users 2015-09-14 11:06:03 +02:00
Vincent Baaij e25886180a Merge remote-tracking branch 'upstream/dev-v7' into dev-v7 2015-09-09 13:57:35 +02:00
Vincent Baaij d5a41d41e9 Merge remote-tracking branch 'upstream/dev-v7' into dev-v7 2015-08-18 09:14:11 +02:00
Vincent Baaij 2e43a34812 Merge remote-tracking branch 'upstream/dev-v7' into dev-v7 2015-06-25 17:37:36 +02:00
Vincent Baaij 1b9afc961b Fix for #U4-6171 Continuous Deployment from Visual Studio Online to Azure Websites not working as expected 2015-06-25 17:35:15 +02:00
92 changed files with 1123 additions and 571 deletions
+2 -2
View File
@@ -7,9 +7,9 @@ The easiest way to get started is to run `build/build.bat` which will build both
If you're interested in making changes to Belle make sure to read the [Belle ReadMe file](src/Umbraco.Web.UI.Client/README.md). Note that you can always [download a nightly build](http://nightly.umbraco.org/umbraco%207.0.0/) so you don't have to build the code yourself.
## Watch a five minute introduction video ##
## Watch a introduction video ##
[![ScreenShot](http://umbraco.com/images/whatisumbraco.png)](http://umbraco.org/help-and-support/video-tutorials/getting-started/what-is-umbraco)
[![ScreenShot](http://umbraco.com/images/whatisumbraco.png)](https://umbraco.tv/videos/umbraco-v7/content-editor/basics/introduction/cms-explanation/)
## Umbraco - the simple, flexible and friendly ASP.NET CMS ##
+12 -1
View File
@@ -1,6 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="CopyUmbracoFilesToWebRootForDeploy" AfterTargets="CopyAllFilesToSingleFolderForMsdeploy">
<PropertyGroup>
<UmbracoFilesFolder>$(MSBuildThisFileDirectory)..\UmbracoFiles\</UmbracoFilesFolder>
</PropertyGroup>
<ItemGroup>
<UmbracoFiles Include="$(UmbracoFilesFolder)**\*" />
</ItemGroup>
<Copy SourceFiles="%(UmbracoFiles.FullPath)" DestinationFiles="$(_PackageTempDir)\%(RecursiveDir)%(Filename)%(Extension)" Condition="!Exists('%(RecursiveDir)%(Filename)%(Extension)')" />
</Target>
<Target Name="CopyUmbracoFilesToWebRoot" BeforeTargets="AfterBuild">
<!-- This copies the files listed in `AddUmbracoFilesToOutput` to the webroot during NuGet install and should -->
<!-- not be altered to support automated builds, use `CopyUmbracoFilesToWebRootForDeploy` for that instead -->
<PropertyGroup>
<UmbracoFilesFolder>$(MSBuildThisFileDirectory)..\UmbracoFiles\</UmbracoFilesFolder>
</PropertyGroup>
@@ -47,4 +58,4 @@
</FilesForPackagingFromProject>
</ItemGroup>
</Target>
</Project>
</Project>
@@ -1,6 +1,6 @@
<?xml version="1.0"?>
<dashBoard xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<section alias="StartupSettingsDashboardSection" xdt:Locator="Match(alias)">
<section alias="StartupSettingsDashboardSection" xdt:Locator="Match(alias)" xdt:Transform="InsertIfMissing">
<tab caption="Get Started" xdt:Locator="Match(caption)" xdt:Transform="Remove" />
<tab caption="Welcome" xdt:Locator="Match(caption)" xdt:Transform="InsertIfMissing">
<control showOnce="true" addPanel="true" panelCaption="" xdt:Transform="InsertIfMissing">
@@ -20,7 +20,7 @@
</tab>
</section>
<section alias="StartupDeveloperDashboardSection" xdt:Locator="Match(alias)">
<section alias="StartupDeveloperDashboardSection" xdt:Locator="Match(alias)" xdt:Transform="InsertIfMissing">
<tab caption="Get Started" xdt:Locator="Match(caption)" xdt:Transform="Replace">
<control showOnce="true" addPanel="true" panelCaption="">
views/dashboard/developer/developerdashboardvideos.html
@@ -29,7 +29,7 @@
<tab caption="Examine Management" xdt:Locator="Match(caption)" xdt:Transform="Remove" />
</section>
<section alias="StartupDeveloperDashboardSection" xdt:Locator="Match(alias)">
<section alias="StartupDeveloperDashboardSection" xdt:Locator="Match(alias)" xdt:Transform="InsertIfMissing">
<tab caption="Examine Management" xdt:Locator="Match(caption)" xdt:Transform="InsertIfMissing">
<control>
views/dashboard/developer/examinemanagement.html
@@ -39,10 +39,10 @@
<control>
views/dashboard/developer/xmldataintegrityreport.html
</control>
</tab>
</tab>
</section>
<section alias="StartupMediaDashboardSection" xdt:Locator="Match(alias)">
<section alias="StartupMediaDashboardSection" xdt:Locator="Match(alias)" xdt:Transform="InsertIfMissing">
<tab caption="Get Started" xdt:Locator="Match(caption)" xdt:Transform="Remove" />
<tab caption="Content" xdt:Locator="Match(caption)" xdt:Transform="InsertIfMissing" />
<tab caption="Content" xdt:Locator="Match(caption)" xdt:Transform="Replace">
@@ -52,7 +52,7 @@
</tab>
</section>
<section alias="StartupDashboardSection" xdt:Locator="Match(alias)">
<section alias="StartupDashboardSection" xdt:Locator="Match(alias)" xdt:Transform="InsertIfMissing">
<tab caption="Get Started" xdt:Locator="Match(caption)" xdt:Transform="Remove" />
<tab caption="Get Started" xdt:Transform="Insert">
<access>
@@ -72,7 +72,7 @@
<tab caption="Last Edits" xdt:Locator="Match(caption)" xdt:Transform="Remove" />
</section>
<section alias="StartupMemberDashboardSection" xdt:Locator="Match(alias)">
<section alias="StartupMemberDashboardSection" xdt:Locator="Match(alias)" xdt:Transform="InsertIfMissing">
<tab caption="Get Started" xdt:Locator="Match(caption)" xdt:Transform="Remove" />
<tab caption="Get Started" xdt:Transform="Insert">
<control showOnce="true" addPanel="true" panelCaption="">
-3
View File
@@ -10,9 +10,6 @@
Don't forget to build!
When upgrading your website using NuGet you should answer "No" to the questions to overwrite the Web.config
file (and config files in the config folder).
We've done our best to transform your configuration files but in case something is not quite right: remember we
backed up your files in App_Data\NuGetBackup so you can find the original files before they were transformed.
+10 -5
View File
@@ -48,6 +48,11 @@
<system.web xdt:Transform="InsertIfMissing" />
<system.web>
<siteMap xdt:Transform="Remove" />
<siteMap xdt:Transform="Insert">
<providers xdt:Transform="Insert">
<remove name="MySqlSiteMapProvider" xdt:Transform="Insert" />
</providers>
</siteMap>
<httpRuntime xdt:Transform="InsertIfMissing" />
<httpRuntime targetFramework="4.5" xdt:Transform="SetAttributes(targetFramework)" />
<membership defaultProvider="DefaultMembershipProvider" xdt:Locator="Match(defaultProvider)" xdt:Transform="Remove" />
@@ -172,23 +177,23 @@
<assemblyIdentity name="System.Web.Http" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-5.2.3.0" newVersion="5.2.3.0" />
</dependentAssembly>
<dependentAssembly>
<dependentAssembly xdt:Transform="Insert">
<assemblyIdentity name="Microsoft.Owin" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
</dependentAssembly>
<dependentAssembly>
<dependentAssembly xdt:Transform="Insert">
<assemblyIdentity name="Microsoft.Owin.Security.OAuth" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
</dependentAssembly>
<dependentAssembly>
<dependentAssembly xdt:Transform="Insert">
<assemblyIdentity name="Microsoft.Owin.Security" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
</dependentAssembly>
<dependentAssembly>
<dependentAssembly xdt:Transform="Insert">
<assemblyIdentity name="Microsoft.Owin.Security.Cookies" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
</dependentAssembly>
<dependentAssembly>
<dependentAssembly xdt:Transform="Insert">
<assemblyIdentity name="System.Net.Http.Formatting" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-5.2.3.0" newVersion="5.2.3.0" />
</dependentAssembly>
+1 -1
View File
@@ -1,2 +1,2 @@
# Usage: on line 2 put the release version, on line 3 put the version comment (example: beta)
7.3.0
7.3.1
+2 -2
View File
@@ -11,5 +11,5 @@ using System.Resources;
[assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyFileVersion("7.3.0")]
[assembly: AssemblyInformationalVersion("7.3.0")]
[assembly: AssemblyFileVersion("7.3.1")]
[assembly: AssemblyInformationalVersion("7.3.1")]
+23 -120
View File
@@ -36,7 +36,7 @@ namespace Umbraco.Core.Configuration
//make this volatile so that we can ensure thread safety with a double check lock
private static volatile string _reservedUrlsCache;
private static string _reservedPathsCache;
private static StartsWithContainer _reservedList = new StartsWithContainer();
private static HashSet<string> _reservedList = new HashSet<string>();
private static string _reservedPaths;
private static string _reservedUrls;
//ensure the built on (non-changeable) reserved paths are there at all times
@@ -767,38 +767,31 @@ namespace Umbraco.Core.Configuration
// store references to strings to determine changes
_reservedPathsCache = GlobalSettings.ReservedPaths;
_reservedUrlsCache = GlobalSettings.ReservedUrls;
string _root = SystemDirectories.Root.Trim().ToLower();
// add URLs and paths to a new list
StartsWithContainer _newReservedList = new StartsWithContainer();
foreach (string reservedUrl in _reservedUrlsCache.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries))
var newReservedList = new HashSet<string>();
foreach (var reservedUrlTrimmed in _reservedUrlsCache
.Split(new[] {","}, StringSplitOptions.RemoveEmptyEntries)
.Select(x => x.Trim().ToLowerInvariant())
.Where(x => x.IsNullOrWhiteSpace() == false)
.Select(reservedUrl => IOHelper.ResolveUrl(reservedUrl).Trim().EnsureStartsWith("/"))
.Where(reservedUrlTrimmed => reservedUrlTrimmed.IsNullOrWhiteSpace() == false))
{
if (string.IsNullOrWhiteSpace(reservedUrl))
continue;
//resolves the url to support tilde chars
string reservedUrlTrimmed = IOHelper.ResolveUrl(reservedUrl.Trim()).Trim().ToLower();
if (reservedUrlTrimmed.Length > 0)
_newReservedList.Add(reservedUrlTrimmed);
newReservedList.Add(reservedUrlTrimmed);
}
foreach (string reservedPath in _reservedPathsCache.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries))
foreach (var reservedPathTrimmed in _reservedPathsCache
.Split(new[] {","}, StringSplitOptions.RemoveEmptyEntries)
.Select(x => x.Trim().ToLowerInvariant())
.Where(x => x.IsNullOrWhiteSpace() == false)
.Select(reservedPath => IOHelper.ResolveUrl(reservedPath).Trim().EnsureStartsWith("/").EnsureEndsWith("/"))
.Where(reservedPathTrimmed => reservedPathTrimmed.IsNullOrWhiteSpace() == false))
{
bool trimEnd = !reservedPath.EndsWith("/");
if (string.IsNullOrWhiteSpace(reservedPath))
continue;
//resolves the url to support tilde chars
string reservedPathTrimmed = IOHelper.ResolveUrl(reservedPath.Trim()).Trim().ToLower();
if (reservedPathTrimmed.Length > 0)
_newReservedList.Add(reservedPathTrimmed + (reservedPathTrimmed.EndsWith("/") ? "" : "/"));
newReservedList.Add(reservedPathTrimmed);
}
// use the new list from now on
_reservedList = _newReservedList;
_reservedList = newReservedList;
}
}
}
@@ -806,107 +799,17 @@ namespace Umbraco.Core.Configuration
//The url should be cleaned up before checking:
// * If it doesn't contain an '.' in the path then we assume it is a path based URL, if that is the case we should add an trailing '/' because all of our reservedPaths use a trailing '/'
// * We shouldn't be comparing the query at all
var pathPart = url.Split('?')[0];
if (!pathPart.Contains(".") && !pathPart.EndsWith("/"))
var pathPart = url.Split(new[] {'?'}, StringSplitOptions.RemoveEmptyEntries)[0].ToLowerInvariant();
if (pathPart.Contains(".") == false)
{
pathPart += "/";
pathPart = pathPart.EnsureEndsWith('/');
}
// return true if url starts with an element of the reserved list
return _reservedList.StartsWith(pathPart.ToLowerInvariant());
return _reservedList.Any(x => pathPart.InvariantStartsWith(x));
}
/// <summary>
/// Structure that checks in logarithmic time
/// if a given string starts with one of the added keys.
/// </summary>
private class StartsWithContainer
{
/// <summary>Internal sorted list of keys.</summary>
public SortedList<string, string> _list
= new SortedList<string, string>(StartsWithComparator.Instance);
/// <summary>
/// Adds the specified new key.
/// </summary>
/// <param name="newKey">The new key.</param>
public void Add(string newKey)
{
// if the list already contains an element that begins with newKey, return
if (String.IsNullOrEmpty(newKey) || StartsWith(newKey))
return;
// create a new collection, so the old one can still be accessed
SortedList<string, string> newList
= new SortedList<string, string>(_list.Count + 1, StartsWithComparator.Instance);
// add only keys that don't already start with newKey, others are unnecessary
foreach (string key in _list.Keys)
if (!key.StartsWith(newKey))
newList.Add(key, null);
// add the new key
newList.Add(newKey, null);
// update the list (thread safe, _list was never in incomplete state)
_list = newList;
}
/// <summary>
/// Checks if the given string starts with any of the added keys.
/// </summary>
/// <param name="target">The target.</param>
/// <returns>true if a key is found that matches the start of target</returns>
/// <remarks>
/// Runs in O(s*log(n)), with n the number of keys and s the length of target.
/// </remarks>
public bool StartsWith(string target)
{
return _list.ContainsKey(target);
}
/// <summary>Comparator that tests if a string starts with another.</summary>
/// <remarks>Not a real comparator, since it is not reflexive. (x==y does not imply y==x)</remarks>
private sealed class StartsWithComparator : IComparer<string>
{
/// <summary>Default string comparer.</summary>
private readonly static Comparer<string> _stringComparer = Comparer<string>.Default;
/// <summary>Gets an instance of the StartsWithComparator.</summary>
public static readonly StartsWithComparator Instance = new StartsWithComparator();
/// <summary>
/// Tests if whole begins with all characters of part.
/// </summary>
/// <param name="part">The part.</param>
/// <param name="whole">The whole.</param>
/// <returns>
/// Returns 0 if whole starts with part, otherwise performs standard string comparison.
/// </returns>
public int Compare(string part, string whole)
{
// let the default string comparer deal with null or when part is not smaller then whole
if (part == null || whole == null || part.Length >= whole.Length)
return _stringComparer.Compare(part, whole);
////ensure both have a / on the end
//part = part.EndsWith("/") ? part : part + "/";
//whole = whole.EndsWith("/") ? whole : whole + "/";
//if (part.Length >= whole.Length)
// return _stringComparer.Compare(part, whole);
// loop through all characters that part and whole have in common
int pos = 0;
bool match;
do
{
match = (part[pos] == whole[pos]);
} while (match && ++pos < part.Length);
// return result of last comparison
return match ? 0 : (part[pos] < whole[pos] ? -1 : 1);
}
}
}
}
@@ -6,7 +6,7 @@ namespace Umbraco.Core.Configuration
{
public class UmbracoVersion
{
private static readonly Version Version = new Version("7.3.0");
private static readonly Version Version = new Version("7.3.1");
/// <summary>
/// Gets the current version of Umbraco.
+6 -6
View File
@@ -280,7 +280,7 @@ namespace Umbraco.Core.Models
//This is the default value if the prop is not found
true);
if (a.Success == false) return a.Result;
if (Properties[Constants.Conventions.Member.IsApproved].Value == null) return true;
var tryConvert = Properties[Constants.Conventions.Member.IsApproved].Value.TryConvertTo<bool>();
if (tryConvert.Success)
{
@@ -313,7 +313,7 @@ namespace Umbraco.Core.Models
{
var a = WarnIfPropertyTypeNotFoundOnGet(Constants.Conventions.Member.IsLockedOut, "IsLockedOut", false);
if (a.Success == false) return a.Result;
if (Properties[Constants.Conventions.Member.IsLockedOut].Value == null) return false;
var tryConvert = Properties[Constants.Conventions.Member.IsLockedOut].Value.TryConvertTo<bool>();
if (tryConvert.Success)
{
@@ -346,7 +346,7 @@ namespace Umbraco.Core.Models
{
var a = WarnIfPropertyTypeNotFoundOnGet(Constants.Conventions.Member.LastLoginDate, "LastLoginDate", default(DateTime));
if (a.Success == false) return a.Result;
if (Properties[Constants.Conventions.Member.LastLoginDate].Value == null) return default(DateTime);
var tryConvert = Properties[Constants.Conventions.Member.LastLoginDate].Value.TryConvertTo<DateTime>();
if (tryConvert.Success)
{
@@ -379,7 +379,7 @@ namespace Umbraco.Core.Models
{
var a = WarnIfPropertyTypeNotFoundOnGet(Constants.Conventions.Member.LastPasswordChangeDate, "LastPasswordChangeDate", default(DateTime));
if (a.Success == false) return a.Result;
if (Properties[Constants.Conventions.Member.LastPasswordChangeDate].Value == null) return default(DateTime);
var tryConvert = Properties[Constants.Conventions.Member.LastPasswordChangeDate].Value.TryConvertTo<DateTime>();
if (tryConvert.Success)
{
@@ -412,7 +412,7 @@ namespace Umbraco.Core.Models
{
var a = WarnIfPropertyTypeNotFoundOnGet(Constants.Conventions.Member.LastLockoutDate, "LastLockoutDate", default(DateTime));
if (a.Success == false) return a.Result;
if (Properties[Constants.Conventions.Member.LastLockoutDate].Value == null) return default(DateTime);
var tryConvert = Properties[Constants.Conventions.Member.LastLockoutDate].Value.TryConvertTo<DateTime>();
if (tryConvert.Success)
{
@@ -446,7 +446,7 @@ namespace Umbraco.Core.Models
{
var a = WarnIfPropertyTypeNotFoundOnGet(Constants.Conventions.Member.FailedPasswordAttempts, "FailedPasswordAttempts", 0);
if (a.Success == false) return a.Result;
if (Properties[Constants.Conventions.Member.FailedPasswordAttempts].Value == null) return default(int);
var tryConvert = Properties[Constants.Conventions.Member.FailedPasswordAttempts].Value.TryConvertTo<int>();
if (tryConvert.Success)
{
@@ -0,0 +1,38 @@
using System.Linq;
using Umbraco.Core.Configuration;
using Umbraco.Core.Logging;
using Umbraco.Core.Models.Rdbms;
using Umbraco.Core.Persistence.SqlSyntax;
namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenThreeOne
{
/// <summary>
/// This fixes the storage of user languages from the old format like en_us to en-US
/// </summary>
[Migration("7.3.1", 0, GlobalSettings.UmbracoMigrationName)]
public class UpdateUserLanguagesToIsoCode : MigrationBase
{
public UpdateUserLanguagesToIsoCode(ISqlSyntaxProvider sqlSyntax, ILogger logger) : base(sqlSyntax, logger)
{
}
public override void Up()
{
var userData = Context.Database.Fetch<UserDto>(new Sql().Select("*").From<UserDto>(SqlSyntax));
foreach (var user in userData.Where(x => x.UserLanguage.Contains("_")))
{
var languageParts = user.UserLanguage.Split('_');
if (languageParts.Length == 2)
{
Update.Table("umbracoUser")
.Set(new {userLanguage = languageParts[0] + "-" + languageParts[1].ToUpperInvariant()})
.Where(new {id = user.Id});
}
}
}
public override void Down()
{
}
}
}
+49 -2
View File
@@ -20,10 +20,12 @@ using System.Text;
using System.Configuration;
using System.Data.Common;
using System.Data;
using System.Globalization;
using System.Text.RegularExpressions;
using System.Reflection;
using System.Reflection.Emit;
using System.Linq.Expressions;
using System.Threading;
namespace Umbraco.Core.Persistence
{
@@ -1802,8 +1804,53 @@ namespace Umbraco.Core.Persistence
return ObjectCache;
}
static readonly ObjectCache ObjectCache = new MemoryCache("NPoco");
//static readonly ObjectCache ObjectCache = new MemoryCache("NPoco");
private static readonly ObjectCache ObjectCache;
// this should probably happen somewhere else...f
private static void FixCurrentCulture()
{
// get the current culture
var currentCulture = CultureInfo.CurrentCulture;
// at the top of any culture should be the invariant culture - find it
var invariantCulture = currentCulture;
while (invariantCulture.Equals(CultureInfo.InvariantCulture) == false)
invariantCulture = invariantCulture.Parent;
// now that invariant culture should be the same object as CultureInfo.InvariantCulture
// yet for some weird reason, sometimes it is not - and this breaks eg MemoryCache,
// because it ends up in PerformanceCounterLib.IsCustomCategory which does:
//
// CultureInfo culture = CultureInfo.CurrentCulture;
// while (culture != CultureInfo.InvariantCulture)
// {
// library = GetPerformanceCounterLib(machine, culture);
// if (library.IsCustomCategory(category))
// return true;
// culture = culture.Parent;
// }
//
// ie a reference comparisons = enters an endless loop and hangs everything.
if (ReferenceEquals(invariantCulture, CultureInfo.InvariantCulture))
return;
// so if it is not the same object, replace the culture by the "fixed" version of
// itself - this prevents MemoryCache from dying - but it is an ugly workaround and
// does not explain why we would have different CultureInfo objects
var fixedCulture = CultureInfo.GetCultureInfo(currentCulture.Name);
Thread.CurrentThread.CurrentCulture = Thread.CurrentThread.CurrentUICulture = fixedCulture;
}
static ManagedCache()
{
FixCurrentCulture();
ObjectCache = new MemoryCache("NPoco");
}
}
public class PocoData
@@ -2,6 +2,7 @@ using System;
namespace Umbraco.Core.PropertyEditors
{
/// <summary>
/// Maps a property source value to a data object.
/// </summary>
// todo: drop IPropertyEditorValueConverter support (when?).
@@ -1,6 +1,7 @@
using System;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web.Security;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.Owin;
@@ -9,8 +10,6 @@ using Umbraco.Core.Services;
namespace Umbraco.Core.Security
{
/// <summary>
/// Default back office user manager
/// </summary>
@@ -21,6 +20,18 @@ namespace Umbraco.Core.Security
{
}
public BackOfficeUserManager(
IUserStore<BackOfficeIdentityUser, int> store,
IdentityFactoryOptions<BackOfficeUserManager> options,
MembershipProviderBase membershipProvider)
: base(store)
{
if (options == null) throw new ArgumentNullException("options");
var manager = new BackOfficeUserManager(store);
InitUserManager(manager, membershipProvider, options);
}
#region Static Create methods
/// <summary>
/// Creates a BackOfficeUserManager instance with all default options and the default BackOfficeUserManager
/// </summary>
@@ -40,8 +51,8 @@ namespace Umbraco.Core.Security
if (externalLoginService == null) throw new ArgumentNullException("externalLoginService");
var manager = new BackOfficeUserManager(new BackOfficeUserStore(userService, externalLoginService, membershipProvider));
return InitUserManager(manager, membershipProvider, options);
manager.InitUserManager(manager, membershipProvider, options);
return manager;
}
/// <summary>
@@ -56,13 +67,10 @@ namespace Umbraco.Core.Security
BackOfficeUserStore customUserStore,
MembershipProviderBase membershipProvider)
{
if (options == null) throw new ArgumentNullException("options");
if (customUserStore == null) throw new ArgumentNullException("customUserStore");
var manager = new BackOfficeUserManager(customUserStore);
return InitUserManager(manager, membershipProvider, options);
}
var manager = new BackOfficeUserManager(customUserStore, options, membershipProvider);
return manager;
}
#endregion
/// <summary>
/// Initializes the user manager with the correct options
@@ -71,7 +79,7 @@ namespace Umbraco.Core.Security
/// <param name="membershipProvider"></param>
/// <param name="options"></param>
/// <returns></returns>
private static BackOfficeUserManager InitUserManager(BackOfficeUserManager manager, MembershipProviderBase membershipProvider, IdentityFactoryOptions<BackOfficeUserManager> options)
protected void InitUserManager(BackOfficeUserManager manager, MembershipProviderBase membershipProvider, IdentityFactoryOptions<BackOfficeUserManager> options)
{
// Configure validation logic for usernames
manager.UserValidator = new UserValidator<BackOfficeIdentityUser, int>(manager)
@@ -125,10 +133,10 @@ namespace Umbraco.Core.Security
//});
//manager.EmailService = new EmailService();
//manager.SmsService = new SmsService();
return manager;
//manager.SmsService = new SmsService();
}
}
/// <summary>
@@ -171,5 +179,44 @@ namespace Umbraco.Core.Security
}
#endregion
/// <summary>
/// Logic used to validate a username and password
/// </summary>
/// <param name="user"></param>
/// <param name="password"></param>
/// <returns></returns>
/// <remarks>
/// By default this uses the standard ASP.Net Identity approach which is:
/// * Get password store
/// * Call VerifyPasswordAsync with the password store + user + password
/// * Uses the PasswordHasher.VerifyHashedPassword to compare the stored password
///
/// In some cases people want simple custom control over the username/password check, for simplicity
/// sake, developers would like the users to simply validate against an LDAP directory but the user
/// data remains stored inside of Umbraco.
/// See: http://issues.umbraco.org/issue/U4-7032 for the use cases.
///
/// We've allowed this check to be overridden with a simple callback so that developers don't actually
/// have to implement/override this class.
/// </remarks>
public async override Task<bool> CheckPasswordAsync(T user, string password)
{
if (BackOfficeUserPasswordChecker != null)
{
var result = await BackOfficeUserPasswordChecker.CheckPasswordAsync(user, password);
//if the result indicates to not fallback to the default, then return true if the credentials are valid
if (result != BackOfficeUserPasswordCheckerResult.FallbackToDefaultChecker)
{
return result == BackOfficeUserPasswordCheckerResult.ValidCredentials;
}
}
//use the default behavior
return await base.CheckPasswordAsync(user, password);
}
/// <summary>
/// Gets/sets the default back office user password checker
/// </summary>
public IBackOfficeUserPasswordChecker BackOfficeUserPasswordChecker { get; set; }
}
}
@@ -0,0 +1,12 @@
namespace Umbraco.Core.Security
{
/// <summary>
/// The result returned from the IBackOfficeUserPasswordChecker
/// </summary>
public enum BackOfficeUserPasswordCheckerResult
{
ValidCredentials,
InvalidCredentials,
FallbackToDefaultChecker
}
}
@@ -0,0 +1,14 @@
using System.Threading.Tasks;
using Umbraco.Core.Models.Identity;
namespace Umbraco.Core.Security
{
/// <summary>
/// Used by the BackOfficeUserManager to check the username/password which allows for developers to more easily
/// set the logic for this procedure.
/// </summary>
public interface IBackOfficeUserPasswordChecker
{
Task<BackOfficeUserPasswordCheckerResult> CheckPasswordAsync(BackOfficeIdentityUser user, string password);
}
}
@@ -445,6 +445,9 @@ namespace Umbraco.Core.Services
/// <returns>An Enumerable list of <see cref="IContent"/> objects</returns>
public IEnumerable<IContent> GetAncestors(IContent content)
{
//null check otherwise we get exceptions
if (content.Path.IsNullOrWhiteSpace()) return Enumerable.Empty<IContent>();
var ids = content.Path.Split(',').Where(x => x != Constants.System.Root.ToInvariantString() && x != content.Id.ToString(CultureInfo.InvariantCulture)).Select(int.Parse).ToArray();
if (ids.Any() == false)
return new List<IContent>();
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using Umbraco.Core.Models;
using Umbraco.Core.Security;
@@ -42,14 +43,18 @@ namespace Umbraco.Core.Services
/// <returns></returns>
Attempt<PublicAccessEntry> IsProtected(string contentPath);
[EditorBrowsable(EditorBrowsableState.Never)]
[Obsolete("Use AddRule instead, this method will be removed in future versions")]
Attempt<OperationStatus<PublicAccessEntry, OperationStatusType>> AddOrUpdateRule(IContent content, string ruleType, string ruleValue);
/// <summary>
/// Adds/updates a rule, if an entry doesn't exist one will be created with the new rule
/// Adds a rule if the entry doesn't already exist
/// </summary>
/// <param name="content"></param>
/// <param name="ruleType"></param>
/// <param name="newRuleValue"></param>
/// <param name="ruleValue"></param>
/// <returns></returns>
Attempt<OperationStatus<PublicAccessEntry, OperationStatusType>> AddOrUpdateRule(IContent content, string ruleType, string newRuleValue);
Attempt<OperationStatus<PublicAccessEntry, OperationStatusType>> AddRule(IContent content, string ruleType, string ruleValue);
/// <summary>
/// Removes a rule
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using Umbraco.Core.Events;
using Umbraco.Core.Logging;
@@ -104,14 +105,21 @@ namespace Umbraco.Core.Services
return Attempt.If(result != null, result);
}
[EditorBrowsable(EditorBrowsableState.Never)]
[Obsolete("Use AddRule instead, this method will be removed in future versions")]
public Attempt<OperationStatus<PublicAccessEntry, OperationStatusType>> AddOrUpdateRule(IContent content, string ruleType, string ruleValue)
{
return AddRule(content, ruleType, ruleValue);
}
/// <summary>
/// Adds/updates a rule
/// Adds a rule
/// </summary>
/// <param name="content"></param>
/// <param name="ruleType"></param>
/// <param name="newRuleValue"></param>
/// <param name="ruleValue"></param>
/// <returns></returns>
public Attempt<OperationStatus<PublicAccessEntry, OperationStatusType>> AddOrUpdateRule(IContent content, string ruleType, string newRuleValue)
public Attempt<OperationStatus<PublicAccessEntry, OperationStatusType>> AddRule(IContent content, string ruleType, string ruleValue)
{
var evtMsgs = EventMessagesFactory.Get();
var uow = UowProvider.GetUnitOfWork();
@@ -121,15 +129,16 @@ namespace Umbraco.Core.Services
if (entry == null)
return Attempt<OperationStatus<PublicAccessEntry, OperationStatusType>>.Fail();
var existingRule = entry.Rules.FirstOrDefault(x => x.RuleType == ruleType);
var existingRule = entry.Rules.FirstOrDefault(x => x.RuleType == ruleType && x.RuleValue == ruleValue);
if (existingRule == null)
{
entry.AddRule(newRuleValue, ruleType);
entry.AddRule(ruleValue, ruleType);
}
else
{
existingRule.RuleType = ruleType;
existingRule.RuleValue = newRuleValue;
//If they are both the same already then there's nothing to update, exit
return Attempt<OperationStatus<PublicAccessEntry, OperationStatusType>>.Succeed(
new OperationStatus<PublicAccessEntry, OperationStatusType>(entry, OperationStatusType.Success, evtMsgs));
}
if (Saving.IsRaisedEventCancelled(
+3
View File
@@ -146,6 +146,9 @@ namespace Umbraco.Core.Services
IsLockedOut = false,
IsApproved = true
};
//adding default sections content and media
user.AddAllowedSection("content");
user.AddAllowedSection("media");
if (SavingUser.IsRaisedEventCancelled(new SaveEventArgs<IUser>(user), this))
return user;
@@ -187,7 +187,13 @@ namespace Umbraco.Core.Sync
using (_profilingLogger.DebugDuration<DatabaseServerMessenger>("Syncing from database..."))
{
ProcessDatabaseInstructions();
PruneOldInstructions();
switch (_appContext.GetCurrentServerRole())
{
case ServerRole.Single:
case ServerRole.Master:
PruneOldInstructions();
break;
}
}
}
finally
@@ -214,9 +220,9 @@ namespace Umbraco.Core.Sync
// FIXME not true if we're running on a background thread, assuming we can?
var sql = new Sql().Select("*")
.From<CacheInstructionDto>()
.From<CacheInstructionDto>(_appContext.DatabaseContext.SqlSyntax)
.Where<CacheInstructionDto>(dto => dto.Id > _lastId)
.OrderBy<CacheInstructionDto>(dto => dto.Id);
.OrderBy<CacheInstructionDto>(dto => dto.Id, _appContext.DatabaseContext.SqlSyntax);
var dtos = _appContext.DatabaseContext.Database.Fetch<CacheInstructionDto>(sql);
if (dtos.Count <= 0) return;
@@ -288,7 +294,7 @@ namespace Umbraco.Core.Sync
private void EnsureInstructions()
{
var sql = new Sql().Select("*")
.From<CacheInstructionDto>()
.From<CacheInstructionDto>(_appContext.DatabaseContext.SqlSyntax)
.Where<CacheInstructionDto>(dto => dto.Id == _lastId);
var dtos = _appContext.DatabaseContext.Database.Fetch<CacheInstructionDto>(sql);
+6 -1
View File
@@ -15,7 +15,12 @@ namespace Umbraco.Core.Sync
// but at the moment it is exposed in CacheRefresher webservice
// so for the time being we keep it as-is for backward compatibility reasons
// need the public one so it can be de-serialized
// need this public, parameter-less constructor so the web service messenger
// can de-serialize the instructions it receives
public RefreshInstruction()
{ }
// need this public one so it can be de-serialized - used by the Json thing
// otherwise, should use GetInstructions(...)
public RefreshInstruction(Guid refresherId, RefreshMethodType refreshType, Guid guidId, int intId, string jsonIds, string jsonPayload)
{
+3
View File
@@ -435,6 +435,7 @@
<Compile Include="Media\Exif\TIFFHeader.cs" />
<Compile Include="Media\Exif\TIFFStrip.cs" />
<Compile Include="Media\Exif\Utility.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenThreeOne\UpdateUserLanguagesToIsoCode.cs" />
<Compile Include="Persistence\RecordPersistenceType.cs" />
<Compile Include="Persistence\Relators\AccessRulesRelator.cs" />
<Compile Include="Persistence\Repositories\AuditRepository.cs" />
@@ -462,7 +463,9 @@
<Compile Include="Security\BackOfficeCookieAuthenticationProvider.cs" />
<Compile Include="Security\BackOfficeSignInManager.cs" />
<Compile Include="Security\BackOfficeUserManager.cs" />
<Compile Include="Security\BackOfficeUserPasswordCheckerResult.cs" />
<Compile Include="Security\BackOfficeUserStore.cs" />
<Compile Include="Security\IBackOfficeUserPasswordChecker.cs" />
<Compile Include="Security\MembershipPasswordHasher.cs" />
<Compile Include="SemVersionExtensions.cs" />
<Compile Include="ServiceProviderExtensions.cs" />
@@ -1163,6 +1163,36 @@ namespace Umbraco.Tests.Services
Assert.That(propertyGroup.ParentId.HasValue, Is.False);
}
[Test]
public void Can_Remove_PropertyGroup_Without_Removing_Property_Types()
{
var service = ServiceContext.ContentTypeService;
var basePage = (IContentType)MockedContentTypes.CreateBasicContentType();
service.Save(basePage);
var authorPropertyType = new PropertyType(Constants.PropertyEditors.TextboxAlias, DataTypeDatabaseType.Ntext, "author")
{
Name = "Author",
Description = "",
Mandatory = false,
SortOrder = 1,
DataTypeDefinitionId = -88
};
var authorAdded = basePage.AddPropertyType(authorPropertyType, "Content");
service.Save(basePage);
basePage = service.GetContentType(basePage.Id);
var totalPt = basePage.PropertyTypes.Count();
basePage.RemovePropertyGroup("Content");
service.Save(basePage);
basePage = service.GetContentType(basePage.Id);
Assert.AreEqual(totalPt, basePage.PropertyTypes.Count());
}
[Test]
public void Can_Add_PropertyGroup_With_Same_Name_On_Parent_and_Child()
{
@@ -80,7 +80,7 @@ namespace Umbraco.Tests.Services
publicAccessService.Save(entry);
// Act
var updated = publicAccessService.AddOrUpdateRule(c, "TestType2", "AnotherVal");
var updated = publicAccessService.AddRule(c, "TestType2", "AnotherVal");
//re-get
entry = publicAccessService.GetEntryForContent(c);
@@ -91,7 +91,7 @@ namespace Umbraco.Tests.Services
}
[Test]
public void Can_Update_Rule()
public void Can_Add_Multiple_Value_For_Same_Rule_Type()
{
// Arrange
var contentService = ServiceContext.ContentService;
@@ -106,21 +106,63 @@ namespace Umbraco.Tests.Services
new PublicAccessRule()
{
RuleType = "TestType",
RuleValue = "TestValue"
RuleValue = "TestVal"
},
});
publicAccessService.Save(entry);
// Act
var updated = publicAccessService.AddOrUpdateRule(c, "TestType", "AnotherVal");
var updated1 = publicAccessService.AddRule(c, "TestType", "AnotherVal1");
var updated2 = publicAccessService.AddRule(c, "TestType", "AnotherVal2");
//re-get
entry = publicAccessService.GetEntryForContent(c);
// Assert
Assert.IsTrue(updated.Success);
Assert.AreEqual(OperationStatusType.Success, updated.Result.StatusType);
Assert.AreEqual(1, entry.Rules.Count());
Assert.AreEqual("AnotherVal", entry.Rules.ElementAt(0).RuleValue);
Assert.IsTrue(updated1.Success);
Assert.IsTrue(updated2.Success);
Assert.AreEqual(OperationStatusType.Success, updated1.Result.StatusType);
Assert.AreEqual(OperationStatusType.Success, updated2.Result.StatusType);
Assert.AreEqual(3, entry.Rules.Count());
}
[Test]
public void Can_Remove_Rule()
{
// Arrange
var contentService = ServiceContext.ContentService;
var contentTypeService = ServiceContext.ContentTypeService;
var ct = MockedContentTypes.CreateSimpleContentType("blah", "Blah");
contentTypeService.Save(ct);
var c = MockedContent.CreateSimpleContent(ct, "Test", -1);
contentService.Save(c);
var publicAccessService = ServiceContext.PublicAccessService;
var entry = new PublicAccessEntry(c, c, c, new[]
{
new PublicAccessRule()
{
RuleType = "TestType",
RuleValue = "TestValue1"
},
new PublicAccessRule()
{
RuleType = "TestType",
RuleValue = "TestValue2"
},
});
publicAccessService.Save(entry);
// Act
var removed = publicAccessService.RemoveRule(c, "TestType", "TestValue1");
//re-get
entry = publicAccessService.GetEntryForContent(c);
// Assert
Assert.IsTrue(removed.Success);
Assert.AreEqual(OperationStatusType.Success, removed.Result.StatusType);
Assert.AreEqual(1, entry.Rules.Count());
Assert.AreEqual("TestValue2", entry.Rules.ElementAt(0).RuleValue);
}
}
}
@@ -398,6 +398,10 @@ namespace Umbraco.Tests.Services
var user1 = ServiceContext.UserService.CreateUserWithIdentity("test1", "test1@test.com", userType);
var result1 = ServiceContext.UserService.GetUserById((int)user1.Id);
//expect 2 sections by default
Assert.AreEqual(2, result1.AllowedSections.Count());
//adds some allowed sections
user1.AddAllowedSection("test1");
user1.AddAllowedSection("test2");
@@ -405,8 +409,9 @@ namespace Umbraco.Tests.Services
user1.AddAllowedSection("test4");
ServiceContext.UserService.Save(user1);
var result1 = ServiceContext.UserService.GetUserById((int)user1.Id);
Assert.AreEqual(4, result1.AllowedSections.Count());
result1 = ServiceContext.UserService.GetUserById((int)user1.Id);
//expect 6 sections including the two default sections
Assert.AreEqual(6, result1.AllowedSections.Count());
//simulate clearing the sections
foreach (var s in user1.AllowedSections)
@@ -419,11 +424,9 @@ namespace Umbraco.Tests.Services
ServiceContext.UserService.Save(result1);
//assert
//re-get
result1 = ServiceContext.UserService.GetUserById((int)user1.Id);
Assert.AreEqual(2, result1.AllowedSections.Count());
}
[Test]
@@ -448,7 +451,6 @@ namespace Umbraco.Tests.Services
var result2 = ServiceContext.UserService.GetUserById((int)user2.Id);
Assert.IsFalse(result1.AllowedSections.Contains("test"));
Assert.IsFalse(result2.AllowedSections.Contains("test"));
}
[Test]
@@ -546,7 +548,7 @@ namespace Umbraco.Tests.Services
Assert.That(updatedItem.StartMediaId, Is.EqualTo(originalUser.StartMediaId));
Assert.That(updatedItem.Email, Is.EqualTo(originalUser.Email));
Assert.That(updatedItem.Username, Is.EqualTo(originalUser.Username));
Assert.That(updatedItem.AllowedSections.Count(), Is.EqualTo(0));
Assert.That(updatedItem.AllowedSections.Count(), Is.EqualTo(2));
}
}
}
@@ -1 +1,17 @@
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 400;
src: url('../fonts/opensans/OpenSans-Regular-webfont.eot');
src: local('Open Sans'), local('OpenSans'), url('../fonts/opensans/OpenSans-Regular-webfont.eot?#iefix') format('embedded-opentype'), url('../fonts/opensans/OpenSans-Regular-webfont.ttf') format('truetype'), url('../fonts/opensans/OpenSans-Regular-webfont.svg#open_sansregular') format('svg');
}
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 600;
src: url('../fonts/opensans/OpenSans-Semibold-webfont.eot');
src: local('Open Sans Semibold'), local('OpenSans-Semibold'), url('../fonts/opensans/OpenSans-Semibold-webfont.eot?#iefix') format('embedded-opentype'), url('../fonts/opensans/OpenSans-Semibold-webfont.ttf') format('truetype'), url('../fonts/opensans/OpenSans-Semibold-webfont.svg#open_sanssemibold') format('svg');
}
abbr,address,article,aside,audio,b,blockquote,body,canvas,caption,cite,code,dd,del,details,dfn,div,dl,dt,em,fieldset,figcaption,figure,footer,form,h1,h2,h3,h4,h5,h6,header,hgroup,html,i,iframe,img,ins,kbd,label,legend,li,mark,menu,nav,object,ol,p,pre,q,samp,section,small,span,strong,sub,summary,sup,table,tbody,td,tfoot,th,thead,time,tr,ul,var,video{margin:0;padding:0;outline:0;border:0;background:0 0;vertical-align:baseline;font-size:100%}article,aside,details,figcaption,figure,footer,header,hgroup,menu,nav,section{display:block}nav ul{list-style:none}blockquote,q{quotes:none}blockquote:after,blockquote:before,q:after,q:before{content:'';content:none}a{margin:0;padding:0;background:0 0;vertical-align:baseline;font-size:100%}ins{background-color:#ff9;color:#000;text-decoration:none}mark{background-color:#ff9;color:#000;font-weight:700;font-style:italic}del{text-decoration:line-through}abbr[title],dfn[title]{border-bottom:1px dotted;cursor:help}table{border-spacing:0;border-collapse:collapse}hr{display:block;margin:1em 0;padding:0;height:1px;border:0;border-top:1px solid #ccc}input,select{vertical-align:middle}html{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}*,:after,:before{box-sizing:border-box}body,html{height:100%;width:100%;color:#fff;font-family:'Open Sans',sans-serif;font-weight:400;font-size:.9375em;line-height:1.5}h1{font-size:1.7em;margin:40px auto 10px;font-weight:700}h2{font-size:1.35em;margin:0 auto .4em;font-weight:700}h3{font-size:1em;font-weight:400;font-style:italic}p{font-size:1em;line-height:1.6}p+a{margin-top:1rem;display:inline-block}a,a:active,a:visited{text-decoration:none}.cta{margin:4.5em auto 1.5em;padding-bottom:4.5em}.button,.button:visited{padding:.9375em 1.875em;border-radius:.1em;font-weight:600;font-size:1.2em;background:#2e99f4;color:#fff;display:inline-block;border:none;transition:all 200ms ease-in-out}.button:hover,.button:visited:hover{border-bottom:none;background:#0c80e3}section{background:url(../img/nonodesbg.jpg) center center/cover;height:100%;width:100%;display:table;padding:3em 1.75em}section a,section a:focus,section a:visited{color:#46a5f5;font-size:1.1625em;border-bottom:1px solid transparent;transition:border-bottom 100ms ease-in-out}section a:focus:hover,section a:hover,section a:visited:hover{border-bottom:1px solid}section:after{content:"";position:absolute;top:0;right:0;bottom:0;left:0;background:rgba(0,0,0,.17);background:linear-gradient(45deg,rgba(85,98,112,.1) 10%,rgba(255,107,107,.1) 95%);z-index:0}section article{display:table-cell;vertical-align:middle;margin:0 auto;text-align:center;position:relative;z-index:100}section article>div{max-width:60em;margin:0 auto}section .logo{background:url(../img/logo.png) no-repeat;width:91px;height:91px;margin:0 auto}section .row{overflow:hidden}section .row .col{text-align:left;width:100%}section .row .col:nth-child(2){margin-top:3em}@media screen and (min-width:48em){body,html{font-size:1em}h1{font-size:2.5em;margin:70px auto 0;letter-spacing:.5px}h2{font-size:1.4375em;margin:0 auto 1em}h3{font-size:1.2em}a{font-size:1.1rem;font-weight:600}p+a{margin-top:3rem}.cta{margin:7.5em auto 2.5em;border-bottom:1px solid rgba(255,255,255,.5);padding-bottom:7.5em}section{padding:0 15px}section .row .col{float:left;width:50%;padding-right:5%;display:inline-block}section .row .col:nth-child(2){padding-right:0;padding-left:5%;margin-top:0}.button{font-size:1.1625em}}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 367 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

@@ -1,16 +1,17 @@
LazyLoad.js([
'/Umbraco/lib/jquery/jquery.min.js',
'/Umbraco/lib/jquery-ui/jquery-ui.min.js',
'/Umbraco/lib/angular/1.1.5/angular.min.js',
'/Umbraco/lib/underscore/underscore-min.js',
'/Umbraco/js/app.js',
'/Umbraco/js/umbraco.resources.js',
'/Umbraco/js/umbraco.services.js',
'/Umbraco/js/umbraco.security.js',
'/Umbraco/ServerVariables',
'/Umbraco/lib/spectrum/spectrum.js',
'https://ajax.googleapis.com/ajax/libs/webfont/1/webfont.js',
'/umbraco/js/canvasdesigner.panel.js',
'../lib/jquery/jquery.min.js',
'../lib/jquery-ui/jquery-ui.min.js',
'../lib/angular/1.1.5/angular.min.js',
'../lib/underscore/underscore-min.js',
'../lib/umbraco/Extensions.js',
'../js/app.js',
'../js/umbraco.resources.js',
'../js/umbraco.services.js',
'../js/umbraco.security.js',
'../ServerVariables',
'../lib/spectrum/spectrum.js',
'../js/canvasdesigner.panel.js',
], function () {
jQuery(document).ready(function () {
angular.bootstrap(document, ['Umbraco.canvasdesigner']);
@@ -9,11 +9,6 @@ var canvasdesignerConfig = {
schema: "body",
selector: "body",
editors: [
{
type: "wide",
category: "Dimension",
name: "Layout"
},
{
type: "background",
category: "Color",
@@ -104,6 +104,30 @@ angular.module("Umbraco.canvasdesigner")
}
};
function loadFont(font, variant) {
WebFont.load({
google: {
families: [font.fontFamily + ":" + variant]
},
loading: function () {
console.log('loading');
},
active: function () {
$scope.selectedFont = font;
$scope.selectedFont.fontWeight = googleGetWeight(variant);
$scope.selectedFont.fontStyle = googleGetStyle(variant);
// If $apply isn't called, the new font family isn't applied until the next user click.
$scope.change({
fontFamily: $scope.selectedFont.fontFamily,
fontType: $scope.selectedFont.fontType,
fontWeight: $scope.selectedFont.fontWeight,
fontStyle: $scope.selectedFont.fontStyle,
});
}
});
}
var webFontScriptLoaded = false;
$scope.showFontPreview = function (font, variant) {
if (!variant)
@@ -114,27 +138,19 @@ angular.module("Umbraco.canvasdesigner")
// Font needs to be independently loaded in the iframe for live preview to work.
document.getElementById("resultFrame").contentWindow.getFont(font.fontFamily + ":" + variant);
WebFont.load({
google: {
families: [font.fontFamily + ":" + variant]
},
loading: function () {
console.log('loading');
},
active: function () {
$scope.selectedFont = font;
$scope.selectedFont.fontWeight = googleGetWeight(variant);
$scope.selectedFont.fontStyle = googleGetStyle(variant);
// If $apply isn't called, the new font family isn't applied until the next user click.
$scope.change({
fontFamily: $scope.selectedFont.fontFamily,
fontType: $scope.selectedFont.fontType,
fontWeight: $scope.selectedFont.fontWeight,
fontStyle: $scope.selectedFont.fontStyle,
if (!webFontScriptLoaded) {
$.getScript('https://ajax.googleapis.com/ajax/libs/webfont/1/webfont.js')
.done(function() {
webFontScriptLoaded = true;
loadFont(font, variant);
})
.fail(function() {
console.log('error loading webfont');
});
}
});
}
else {
loadFont(font, variant);
}
}
else {
@@ -1,27 +0,0 @@
/**
* @ngdoc directive
* @name umbraco.directives.directive:umbAvatar
* @restrict E
**/
function avatarDirective() {
return {
restrict: "E", // restrict to an element
replace: true, // replace the html element with the template
templateUrl: 'views/directives/umb-avatar.html',
scope: {
name: '@',
email: '@',
hash: '@'
},
link: function(scope, element, attr, ctrl) {
scope.$watch("hash", function (val) {
//set the gravatar url
scope.gravatar = "https://www.gravatar.com/avatar/" + val + "?s=40";
});
}
};
}
angular.module('umbraco.directives').directive("umbAvatar", avatarDirective);
@@ -13,14 +13,16 @@ angular.module("umbraco.directives")
restrict: 'E',
replace: true,
templateUrl: 'views/directives/umb-property.html',
link: function(scope) {
scope.propertyAlias = Umbraco.Sys.ServerVariables.isDebuggingEnabled === true ? scope.property.alias : null;
},
//Define a controller for this directive to expose APIs to other directives
controller: function ($scope, $timeout) {
var self = this;
//set the API properties/methods
self.property = $scope.property;
self.setPropertyError = function(errorMsg) {
$scope.property.propertyErrorMessage = errorMsg;
@@ -139,6 +139,12 @@ function entityResource($q, $http, umbRequestHelper) {
_.each(ids, function(item) {
query += "ids=" + item + "&";
});
// if ids array is empty we need a empty variable in the querystring otherwise the service returns a error
if (ids.length === 0) {
query += "ids=&";
}
query += "type=" + type;
return umbRequestHelper.resourcePromise(
@@ -1,6 +1,6 @@
angular.module('umbraco.security.interceptor', ['umbraco.security.retryQueue'])
// This http interceptor listens for authentication successes and failures
.factory('securityInterceptor', ['$injector', 'securityRetryQueue', 'notificationsService', function ($injector, queue, notifications) {
.factory('securityInterceptor', ['$injector', 'securityRetryQueue', 'notificationsService', 'requestInterceptorFilter', function ($injector, queue, notifications, requestInterceptorFilter) {
return function(promise) {
return promise.then(
@@ -19,6 +19,19 @@ angular.module('umbraco.security.interceptor', ['umbraco.security.retryQueue'])
return promise;
}, function(originalResponse) {
// Intercept failed requests
//Here we'll check if we should ignore the error, this will be based on an original header set
var headers = originalResponse.config ? originalResponse.config.headers : {};
if (headers["x-umb-ignore-error"] === "ignore") {
//exit/ignore
return promise;
}
var filtered = _.find(requestInterceptorFilter(), function(val) {
return originalResponse.config.url.indexOf(val) > 0;
});
if (filtered) {
return promise;
}
//A 401 means that the user is not logged in
if (originalResponse.status === 401) {
@@ -72,6 +85,10 @@ angular.module('umbraco.security.interceptor', ['umbraco.security.retryQueue'])
};
}])
.value('requestInterceptorFilter', function() {
return ["www.gravatar.com"];
})
// We have to add the interceptor to the queue as a string because the interceptor depends upon service instances that are not available in the config block.
.config(['$httpProvider', function ($httpProvider) {
$httpProvider.responseInterceptors.push('securityInterceptor');
@@ -1,5 +1,5 @@
angular.module('umbraco.services')
.factory('userService', function ($rootScope, eventsService, $q, $location, $log, securityRetryQueue, authResource, dialogService, $timeout, angularHelper) {
.factory('userService', function ($rootScope, eventsService, $q, $location, $log, securityRetryQueue, authResource, dialogService, $timeout, angularHelper, $http) {
var currentUser = null;
var lastUserId = null;
@@ -250,7 +250,7 @@ angular.module('umbraco.services')
}
setCurrentUser(data);
currentUser.avatar = 'https://www.gravatar.com/avatar/' + data.emailHash + '?s=40&d=404';
deferred.resolve(currentUser);
});
@@ -372,9 +372,6 @@ function xmlhelper($http) {
fromJson: function (json) {
var xml = x2js.json2xml_str(json);
return xml;
},
parseFeed: function (url) {
return $http.jsonp('//ajax.googleapis.com/ajax/services/feed/load?v=1.0&num=50&callback=JSON_CALLBACK&q=' + encodeURIComponent(url));
}
};
}
@@ -13,7 +13,11 @@ function MainController($scope, $rootScope, $location, $routeParams, $timeout, $
//the null is important because we do an explicit bool check on this in the view
//the avatar is by default the umbraco logo
$scope.authenticated = null;
$scope.avatar = "assets/img/application/logo.png";
$scope.avatar = [
{ value: "assets/img/application/logo.png" },
{ value: "assets/img/application/logo@2x.png" },
{ value: "assets/img/application/logo@3x.png" }
];
$scope.touchDevice = appState.getGlobalState("touchDevice");
@@ -84,20 +88,32 @@ function MainController($scope, $rootScope, $location, $routeParams, $timeout, $
tmhDynamicLocale.set($scope.user.locale);
}
if($scope.user.emailHash){
$timeout(function () {
//yes this is wrong..
$("#avatar-img").fadeTo(1000, 0, function () {
$timeout(function () {
//this can be null if they time out
if ($scope.user && $scope.user.emailHash) {
$scope.avatar = "https://www.gravatar.com/avatar/" + $scope.user.emailHash + ".jpg?s=64&d=mm";
}
if ($scope.user.emailHash) {
//let's attempt to load the avatar, it might not exist or we might not have
// internet access so we'll detect it first
$http.get("https://www.gravatar.com/avatar/" + $scope.user.emailHash + ".jpg?s=64&d=404")
.then(
function successCallback(response) {
$("#avatar-img").fadeTo(1000, 0, function () {
$scope.$apply(function () {
//this can be null if they time out
if ($scope.user && $scope.user.emailHash) {
var avatarBaseUrl = "https://www.gravatar.com/avatar/",
hash = $scope.user.emailHash;
$scope.avatar = [
{ value: avatarBaseUrl + hash + ".jpg?s=30&d=mm" },
{ value: avatarBaseUrl + hash + ".jpg?s=60&d=mm" },
{ value: avatarBaseUrl + hash + ".jpg?s=90&d=mm" }
];
}
});
$("#avatar-img").fadeTo(1000, 1);
});
}, function errorCallback(response) {
//cannot load it from the server so we cannot do anything
});
$("#avatar-img").fadeTo(1000, 1);
});
}, 3000);
}
}));
@@ -42,7 +42,7 @@
<div class="control-group">
<label class="control-label" for="server">Server</label>
<div class="controls">
<input type="text" name="server" placeholder="127.0.0.1/SQLEXPRESS" required ng-model="installer.current.model.server" />
<input type="text" name="server" placeholder="127.0.0.1\SQLEXPRESS" required ng-model="installer.current.model.server" />
<small class="inline-help">Enter server domain or IP</small>
</div>
</div>
@@ -8,7 +8,7 @@
background-size: 30px 30px !important;
color: @white;
position: absolute;
z-index: 2000;
z-index: 10000;
top: 0px;
left: 0px;
margin: 0 !Important;
@@ -81,8 +81,8 @@ ul.sections li.avatar a {
}
ul.sections li.avatar a img {
border-radius: 16px;
width: 30px
border-radius: 50%;
width: 30px;
}
.faded ul.sections li {
@@ -7,6 +7,7 @@ angular.module("umbraco").controller("Umbraco.Editors.Content.CopyController",
searchText = value + "...";
});
$scope.recursive = true;
$scope.relateToOriginal = false;
$scope.dialogTreeEventHandler = $({});
$scope.busy = false;
@@ -95,7 +96,7 @@ angular.module("umbraco").controller("Umbraco.Editors.Content.CopyController",
$scope.busy = true;
$scope.error = false;
contentResource.copy({ parentId: $scope.target.id, id: node.id, relateToOriginal: $scope.relateToOriginal })
contentResource.copy({ parentId: $scope.target.id, id: node.id, relateToOriginal: $scope.relateToOriginal, recursive: $scope.recursive })
.then(function (path) {
$scope.error = false;
$scope.success = true;
@@ -56,6 +56,12 @@
</umb-control-group>
</umb-pane>
<umb-pane>
<umb-control-group label="Include descendants">
<input type="checkbox" ng-model="$parent.$parent.recursive" />
</umb-control-group>
</umb-pane>
</div>
</div>
</div>
@@ -1,3 +0,0 @@
<a href="#" title="{{name}}">
<img ng-src="{{gravatar}}" />
</a>
@@ -5,7 +5,7 @@
<val-property-msg property="property"></val-property-msg>
<div class="umb-el-wrap">
<label class="control-label" ng-hide="property.hideLabel" for="{{property.alias}}">
<label class="control-label" ng-hide="property.hideLabel" for="{{property.alias}}" ng-attr-title="{{propertyAlias}}">
{{property.label}}
<small ng-bind-html="property.description"></small>
</label>
@@ -3,7 +3,7 @@
<ul class="sections">
<li class="avatar">
<a href="#" ng-click="avatarClick()" hotkey="ctrl+shift+u" title="{{user.name}}" prevent-default>
<img id="avatar-img" ng-src="{{avatar}}" />
<img id="avatar-img" ng-src="{{avatar[0].value}}" ng-srcset="{{avatar[1].value}} 2x, {{avatar[2].value}} 3x" />
</a>
</li>
<li ng-repeat="section in sections | limitTo: maxSections" ng-class="{current: section.alias == currentSection}">
@@ -1,13 +1,29 @@
angular.module('umbraco').controller("Umbraco.PropertyEditors.UrlListController",
function($rootScope, $scope, $filter) {
function formatDisplayValue() {
$scope.renderModel = _.map($scope.model.value.split(","), function (item) {
return {
url: item,
urlTarget: ($scope.config && $scope.config.target) ? $scope.config.target : "_blank"
};
});
function formatDisplayValue() {
if (angular.isArray($scope.model.value)) {
//it's the json value
$scope.renderModel = _.map($scope.model.value, function (item) {
return {
url: item.url,
linkText: item.linkText,
urlTarget: (item.target) ? item.target : "_blank",
icon: (item.icon) ? item.icon : "icon-out"
};
});
}
else {
//it's the default csv value
$scope.renderModel = _.map($scope.model.value.split(","), function (item) {
return {
url: item,
linkText: "",
urlTarget: ($scope.config && $scope.config.target) ? $scope.config.target : "_blank",
icon: ($scope.config && $scope.config.icon) ? $scope.config.icon : "icon-out"
};
});
}
}
$scope.getUrl = function(valueUrl) {
@@ -1,7 +1,11 @@
<div ng-controller="Umbraco.PropertyEditors.UrlListController">
<ul class="nav nav-stacked">
<li ng-repeat="value in renderModel">
<a href="{{getUrl(value.url)}}" prevent-default="{{value.url.indexOf('/') == -1}}" target="{{value.urlTarget}}"><i class="icon-out"></i> {{value.url}}</a>
<a href="{{getUrl(value.url)}}" prevent-default="{{value.url.indexOf('/') == -1}}" target="{{value.urlTarget}}">
<i ng-class="value.icon"></i>
<span ng-if="value.linkText">{{value.linkText}}</span>
<span ng-if="!value.linkText">{{value.url}}</span>
</a>
</li>
</ul>
</div>
+2 -2
View File
@@ -2411,9 +2411,9 @@ xcopy "$(ProjectDir)"..\packages\SqlServerCE.4.0.0.0\x86\*.* "$(TargetDir)x86\"
<WebProjectProperties>
<UseIIS>True</UseIIS>
<AutoAssignPort>True</AutoAssignPort>
<DevelopmentServerPort>7300</DevelopmentServerPort>
<DevelopmentServerPort>7310</DevelopmentServerPort>
<DevelopmentServerVPath>/</DevelopmentServerVPath>
<IISUrl>http://localhost:7300</IISUrl>
<IISUrl>http://localhost:7310</IISUrl>
<NTLMAuthentication>False</NTLMAuthentication>
<UseCustomServer>False</UseCustomServer>
<CustomServerUrl>
@@ -7,7 +7,7 @@
</root>
<appender name="rollingFile" type="log4net.Appender.RollingFileAppender">
<file value="App_Data\Logs\UmbracoTraceLog.txt" />
<file type="log4net.Util.PatternString" value="App_Data\Logs\UmbracoTraceLog.%property{log4net:HostName}.txt" />
<lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
<appendToFile value="true" />
<rollingStyle value="Date" />
+1 -1
View File
@@ -7,7 +7,7 @@
</root>
<appender name="rollingFile" type="log4net.Appender.RollingFileAppender">
<file value="App_Data\Logs\UmbracoTraceLog.txt" />
<file type="log4net.Util.PatternString" value="App_Data\Logs\UmbracoTraceLog.%property{log4net:HostName}.txt" />
<lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
<appendToFile value="true" />
<rollingStyle value="Date" />
@@ -16,15 +16,8 @@
<meta name="description" content="">
<meta name="author" content="">
<link href='https://fonts.googleapis.com/css?family=Open+Sans:300,400,700,600' rel='stylesheet' type='text/css'>
<link href='https://fonts.googleapis.com/css?family=Asap:400,700,400italic,700italic' rel='stylesheet' type='text/css'>
<link rel="stylesheet" href="../../Umbraco/assets/css/nonodes.style.min.css" />
<!--[if lt IE 9]>
<script src="https://cdnjs.cloudflare.com/ajax/libs/modernizr/2.7.1/modernizr.min.js"></script>
<![endif]-->
</head>
<body>
@@ -10,7 +10,7 @@
<script type="text/javascript">
var parts = window.location.href.split("?redirectUrl=");
if (parts.length != 2) {
if (parts.length !== 2) {
window.location.href = "/";
}
else {
@@ -23,12 +23,12 @@
parser.href = parts[1];
// => "http:"
if (!parser.protocol || (parser.protocol.toLowerCase() != "http:" && parser.protocol.toLowerCase() != "https:")) {
if (!parser.protocol || (parser.protocol.toLowerCase() !== "http:" && parser.protocol.toLowerCase() !== "https:")) {
throw "invalid protocol";
};
// => "example.com"
if (!parser.hostname || parser.hostname == "") {
if (!parser.hostname || parser.hostname === "") {
throw "invalid hostname";
}
@@ -37,13 +37,15 @@
//parser.search => "?search=test"
// => "#hash"
if (parser.hash && parser.hash.indexOf("#/developer/framed/") != 0) {
if (parser.hash && parser.hash.indexOf("#/developer/framed/") !== 0) {
throw "invalid hash";
}
//parser.host; // => "example.com:3000"
window.location.href = parts[1];
if (parser.host === window.location.host) {
window.location.href = parts[1];
}
} catch (e) {
alert(e);
@@ -53,7 +53,7 @@
<key alias="domainUpdated">Domain '%0%' has been updated</key>
<key alias="orEdit">Edit Current Domains</key>
<key alias="domainHelp"><![CDATA[Valid domain names are: "example.com", "www.example.com", "example.com:8080" or
"https://www.example.com/".<br /><br />One-level paths in domains are supported, eg. "example.com/en". However, they
"https://www.example.com/". One-level paths in domains are supported, eg. "example.com/en". However, they
should be avoided. Better use the culture setting above.]]></key>
<key alias="inherit">Inherit</key>
<key alias="setLanguage">Culture</key>
@@ -53,7 +53,7 @@
<key alias="domainUpdated">Domain '%0%' has been updated</key>
<key alias="orEdit">Edit Current Domains</key>
<key alias="domainHelp"><![CDATA[Valid domain names are: "example.com", "www.example.com", "example.com:8080" or
"https://www.example.com/".<br /><br />One-level paths in domains are supported, eg. "example.com/en". However, they
"https://www.example.com/". One-level paths in domains are supported, eg. "example.com/en". However, they
should be avoided. Better use the culture setting above.]]></key>
<key alias="inherit">Inherit</key>
<key alias="setLanguage">Culture</key>
@@ -40,6 +40,7 @@
<cc1:Pane runat="server" ID="pane_domains">
<small class="help-inline"><%=umbraco.ui.Text("assignDomain", "domainHelp") %></small>
<cc1:PropertyPanel runat="server">
<table class="table domains" data-bind="visible: domains().length > 0">
<thead>
@@ -51,7 +52,7 @@
</thead>
<tbody data-bind="foreach: domains">
<tr>
<td valign="top"><input class="domain" data-bind="value: Name, uniqueName: true" /><input type="hidden" value="0" data-bind="uniqueName: true"/></td>
<td valign="top"><input class="domain duplicate" data-bind="value: Name, uniqueName: true" /><input type="hidden" value="" data-bind="uniqueName: true"/></td>
<td valign="top"><select class="language" data-bind="options: $parent.languages, optionsText: 'Code', optionsValue: 'Id', value: Lang, uniqueName: true"></select></td>
<td valign="top"><a href="#" class="btn btn-danger" data-bind="click: $parent.removeDomain"><i class="icon icon-trash"></i></a></td>
</tr>
@@ -60,7 +61,6 @@
</cc1:PropertyPanel>
<cc1:PropertyPanel runat="server">
<small data-bind="visible: domains().length == 0" class="help-inline"><%=umbraco.ui.Text("assignDomain", "domainHelp") %></small>
<button class="btn" data-bind="click: addDomain"><%=umbraco.ui.Text("assignDomain", "addNew") %></button>
</cc1:PropertyPanel>
@@ -1,4 +1,5 @@
<%@ Page Language="C#" AutoEventWireup="true" MasterPageFile="../masterpages/umbracoDialog.Master" CodeBehind="RegexWs.aspx.cs" Inherits="umbraco.presentation.dialogs.RegexWs" %>
<%@ Import Namespace="Umbraco.Web" %>
<%@ Register TagPrefix="cc1" Namespace="umbraco.uicontrols" Assembly="controls" %>
<%@ Register TagPrefix="umb" Namespace="ClientDependency.Core.Controls" Assembly="ClientDependency.Core" %>
@@ -40,7 +41,7 @@
<asp:Content ContentPlaceHolderID="head" runat="server">
<script type="text/javascript">
function chooseRegex(regex) {
var target = top.right.document.getElementById('<%= Request.QueryString["target"] %>');
var target = top.right.document.getElementById('<%= Request.CleanForXss("target") %>');
target.value = regex;
UmbClientMgr.closeModalWindow();
}
@@ -6,6 +6,7 @@
<%@ Import Namespace="Umbraco.Core" %>
<%@ Import Namespace="Umbraco.Core.IO" %>
<%@ Import Namespace="Umbraco.Web" %>
<%@ Register TagPrefix="cc1" Namespace="umbraco.uicontrols" Assembly="controls" %>
<%@ Register TagPrefix="umb" Namespace="ClientDependency.Core.Controls" Assembly="ClientDependency.Core" %>
@@ -35,7 +36,7 @@
nameTxtBox: $("#<%= NameTxt.ClientID %>"),
aliasTxtBox: $("#<%= AliasTxt.ClientID %>"),
saveButton: $("#<%= ((Control)SaveButton).ClientID %>"),
templateId: '<%= Request.QueryString["templateID"] %>',
templateId: '<%= Request.CleanForXss("templateID") %>',
codeEditorElementId: '<%= editorSource.ClientID %>',
modalUrl: "<%= IOHelper.ResolveUrl(SystemDirectories.Umbraco) %>/dialogs/editMacro.aspx"
});
@@ -66,7 +66,7 @@ namespace Umbraco.Web.UI.Umbraco.Settings.Views
{
return TreeDefinitionCollection.Instance.FindTree<PartialViewsTree>().Tree.Alias;
}
return Request.QueryString["treeType"];
return Request.CleanForXss("treeType");
}
}
@@ -63,9 +63,17 @@
return ret;
}, self._opts.invalidDomain);
function getDuplicateMessage(val, el) {
var other = $(el).nextAll('input').val();
var msg = self._opts.duplicateDomain
if (other != "" && other != "!!!")
msg = msg + ' (' + other + ')';
return msg;
}
$.validator.addMethod("duplicate", function (value, element, param) {
return $(element).nextAll('input').val() == 0 && !self._isRepeated($(element));
}, self._opts.duplicateDomain);
return $(element).nextAll('input').val() == "" && !self._isRepeated($(element));
}, getDuplicateMessage);
$.validator.addClassRules({
domain: { domain: true },
@@ -80,7 +88,7 @@
$('form input.domain').live('focus', function(event) {
if (event.type != 'focusin') return;
$(this).nextAll('input').val(0);
$(this).nextAll('input').val("");
});
// force validation *now*
@@ -105,14 +113,14 @@
}
else {
var inputs = $('form input.domain');
inputs.each(function() { $(this).nextAll('input').val(0); });
inputs.each(function() { $(this).nextAll('input').val(""); });
for (var i = 0; i < json.Domains.length; i++) {
var d = json.Domains[i];
if (d.Duplicate == 1)
if (d.Duplicate)
inputs.each(function() {
var input = $(this);
if (input.val() == d.Name)
input.nextAll('input').val(1);
input.nextAll('input').val(d.Other ? d.Other : "!!!");
});
}
$('form').valid();
@@ -189,8 +189,12 @@
top.UmbSpeechBubble.ShowMessage('save', header, msg);
this._opts.originalFileName = args.name;
this._opts.treeSyncPath = args.path;
if (args && args.name) {
this._opts.originalFileName = args.name;
}
if (args && args.path) {
this._opts.treeSyncPath = args.path;
}
UmbClientMgr.mainTree().syncTree(path, true, null, newFilePath.split("/")[1]);
}
+5
View File
@@ -150,6 +150,11 @@
<add name="UmbracoRoleProvider" type="Umbraco.Web.Security.Providers.MembersRoleProvider" />
</providers>
</roleManager>
<siteMap>
<providers>
<remove name="MySqlSiteMapProvider" />
</providers>
</siteMap>
</system.web>
<system.webServer>
+17 -13
View File
@@ -1,4 +1,5 @@
using System;
using System.ComponentModel;
using System.Linq;
using Umbraco.Core;
using Umbraco.Core.Sync;
@@ -192,24 +193,27 @@ namespace Umbraco.Web.Cache
public void RefreshAll(Guid factoryGuid)
{
if (factoryGuid == Guid.Empty) return;
RefreshAll(factoryGuid, true);
ServerMessengerResolver.Current.Messenger.PerformRefreshAll(
ServerRegistrarResolver.Current.Registrar.Registrations,
GetRefresherById(factoryGuid));
}
/// <summary>
/// Notifies the distributed cache of a global invalidation for a specified <see cref="ICacheRefresher"/>.
/// </summary>
/// <param name="factoryGuid">The unique identifier of the ICacheRefresher.</param>
/// <param name="allServers">If true, all servers in the load balancing environment are notified; otherwise,
/// only the local server is notified.</param>
[EditorBrowsable(EditorBrowsableState.Never)]
[Obsolete("This method is no longer in use and does not work as advertised, the allServers parameter doesnt have any affect for database server messengers, do not use!")]
public void RefreshAll(Guid factoryGuid, bool allServers)
{
if (factoryGuid == Guid.Empty) return;
ServerMessengerResolver.Current.Messenger.PerformRefreshAll(
allServers
? ServerRegistrarResolver.Current.Registrar.Registrations
: Enumerable.Empty<IServerAddress>(), //this ensures it will only execute against the current server
GetRefresherById(factoryGuid));
if (allServers)
{
RefreshAll(factoryGuid);
}
else
{
ServerMessengerResolver.Current.Messenger.PerformRefreshAll(
Enumerable.Empty<IServerAddress>(),
GetRefresherById(factoryGuid));
}
}
/// <summary>
@@ -5,6 +5,7 @@ using Umbraco.Core.Events;
using Umbraco.Core.Models;
using umbraco;
using umbraco.cms.businesslogic.web;
using Umbraco.Core.Persistence.Repositories;
namespace Umbraco.Web.Cache
{
@@ -262,8 +263,8 @@ namespace Umbraco.Web.Cache
public static void ClearAllMacroCacheOnCurrentServer(this DistributedCache dc)
{
// NOTE: The 'false' ensure that it will only refresh on the current server, not post to all servers
dc.RefreshAll(DistributedCache.MacroCacheRefresherGuid, false);
var macroRefresher = CacheRefreshersResolver.Current.GetById(DistributedCache.MacroCacheRefresherGuid);
macroRefresher.RefreshAll();
}
public static void RefreshMacroCache(this DistributedCache dc, IMacro macro)
@@ -400,6 +401,12 @@ namespace Umbraco.Web.Cache
dc.Remove(DistributedCache.DomainCacheRefresherGuid, domain.Id);
}
public static void ClearDomainCacheOnCurrentServer(this DistributedCache dc)
{
var domainRefresher = CacheRefreshersResolver.Current.GetById(DistributedCache.DomainCacheRefresherGuid);
domainRefresher.RefreshAll();
}
#endregion
#region Language Cache
@@ -79,6 +79,7 @@ namespace Umbraco.Web.Cache
{
ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes<IContent>();
ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes<PublicAccessEntry>();
DistributedCache.Instance.ClearDomainCacheOnCurrentServer();
base.RefreshAll();
}
@@ -87,6 +88,7 @@ namespace Umbraco.Web.Cache
ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheItem(RepositoryBase.GetCacheIdKey<IContent>(id));
ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes<PublicAccessEntry>();
content.Instance.UpdateSortOrder(id);
DistributedCache.Instance.ClearDomainCacheOnCurrentServer();
base.Refresh(id);
}
@@ -94,6 +96,7 @@ namespace Umbraco.Web.Cache
{
ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheItem(RepositoryBase.GetCacheIdKey<IContent>(id));
ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes<PublicAccessEntry>();
DistributedCache.Instance.ClearDomainCacheOnCurrentServer();
base.Remove(id);
}
@@ -103,6 +106,7 @@ namespace Umbraco.Web.Cache
ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheItem(RepositoryBase.GetCacheIdKey<IContent>(instance.Id));
ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes<PublicAccessEntry>();
content.Instance.UpdateSortOrder(instance);
DistributedCache.Instance.ClearDomainCacheOnCurrentServer();
base.Refresh(instance);
}
@@ -110,6 +114,7 @@ namespace Umbraco.Web.Cache
{
ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheItem(RepositoryBase.GetCacheIdKey<IContent>(instance.Id));
ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes<PublicAccessEntry>();
DistributedCache.Instance.ClearDomainCacheOnCurrentServer();
base.Remove(instance);
}
@@ -127,6 +132,8 @@ namespace Umbraco.Web.Cache
content.Instance.UpdateSortOrder(payload.Id);
}
DistributedCache.Instance.ClearDomainCacheOnCurrentServer();
OnCacheUpdated(Instance, new CacheRefresherEventArgs(jsonPayload, MessageType.RefreshByJson));
}
@@ -349,7 +349,9 @@ namespace Umbraco.Web.Editors
{"trees", GetTreePluginsMetaData()}
}
},
{"isDebuggingEnabled", HttpContext.IsDebuggingEnabled},
{
"isDebuggingEnabled", HttpContext.IsDebuggingEnabled
},
{
"application", GetApplicationState()
},
+1 -1
View File
@@ -491,7 +491,7 @@ namespace Umbraco.Web.Editors
{
var toCopy = ValidateMoveOrCopy(copy);
var c = Services.ContentService.Copy(toCopy, copy.ParentId, copy.RelateToOriginal);
var c = Services.ContentService.Copy(toCopy, copy.ParentId, copy.RelateToOriginal, copy.Recursive);
var response = Request.CreateResponse(HttpStatusCode.OK);
response.Content = new StringContent(c.Path, Encoding.UTF8, "application/json");
+1 -1
View File
@@ -471,7 +471,7 @@ namespace Umbraco.Web.Editors
{
tempFiles.Notifications.Add(new Notification(
Services.TextService.Localize("speechBubbles/operationFailedHeader"),
"Cannot upload file " + file + ", it is not an approved file type",
"Cannot upload file " + file.Headers.ContentDisposition.FileName + ", it is not an approved file type",
SpeechBubbleIcon.Warning));
}
}
+5 -5
View File
@@ -87,7 +87,7 @@ namespace Umbraco.Web
}
//[Obsolete("This should not be used, GetGridHtml methods accepting HtmlHelper as a parameter or GetGridHtml extensions on HtmlHelper should be used instead")]
[Obsolete("This should not be used, GetGridHtml methods accepting HtmlHelper as a parameter or GetGridHtml extensions on HtmlHelper should be used instead")]
public static MvcHtmlString GetGridHtml(this IPublishedProperty property, string framework = "bootstrap3")
{
var asString = property.Value as string;
@@ -97,13 +97,13 @@ namespace Umbraco.Web
return htmlHelper.GetGridHtml(property, framework);
}
//[Obsolete("This should not be used, GetGridHtml methods accepting HtmlHelper as a parameter or GetGridHtml extensions on HtmlHelper should be used instead")]
[Obsolete("This should not be used, GetGridHtml methods accepting HtmlHelper as a parameter or GetGridHtml extensions on HtmlHelper should be used instead")]
public static MvcHtmlString GetGridHtml(this IPublishedContent contentItem)
{
return GetGridHtml(contentItem, "bodyText", "bootstrap3");
}
//[Obsolete("This should not be used, GetGridHtml methods accepting HtmlHelper as a parameter or GetGridHtml extensions on HtmlHelper should be used instead")]
[Obsolete("This should not be used, GetGridHtml methods accepting HtmlHelper as a parameter or GetGridHtml extensions on HtmlHelper should be used instead")]
public static MvcHtmlString GetGridHtml(this IPublishedContent contentItem, string propertyAlias)
{
Mandate.ParameterNotNullOrEmpty(propertyAlias, "propertyAlias");
@@ -111,7 +111,7 @@ namespace Umbraco.Web
return GetGridHtml(contentItem, propertyAlias, "bootstrap3");
}
//[Obsolete("This should not be used, GetGridHtml methods accepting HtmlHelper as a parameter or GetGridHtml extensions on HtmlHelper should be used instead")]
[Obsolete("This should not be used, GetGridHtml methods accepting HtmlHelper as a parameter or GetGridHtml extensions on HtmlHelper should be used instead")]
public static MvcHtmlString GetGridHtml(this IPublishedContent contentItem, string propertyAlias, string framework)
{
Mandate.ParameterNotNullOrEmpty(propertyAlias, "propertyAlias");
@@ -127,7 +127,7 @@ namespace Umbraco.Web
return htmlHelper.GetGridHtml(contentItem, propertyAlias, framework);
}
//[Obsolete("This shouldn't need to be used but because the obsolete extension methods above don't have access to the current HtmlHelper, we need to create a fake one, unfortunately however this will not pertain the current views viewdata, tempdata or model state so should not be used")]
[Obsolete("This shouldn't need to be used but because the obsolete extension methods above don't have access to the current HtmlHelper, we need to create a fake one, unfortunately however this will not pertain the current views viewdata, tempdata or model state so should not be used")]
private static HtmlHelper CreateHtmlHelper(object model)
{
var cc = new ControllerContext
+187 -12
View File
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Web;
@@ -11,10 +10,12 @@ using Umbraco.Core;
using Umbraco.Core.Configuration;
using Umbraco.Core.Dynamics;
using Umbraco.Core.IO;
using Umbraco.Core.Models;
using Umbraco.Core.Profiling;
using Umbraco.Web.Models;
using Umbraco.Web.Mvc;
using umbraco;
using umbraco.cms.businesslogic.member;
using Constants = Umbraco.Core.Constants;
using Member = umbraco.cms.businesslogic.member.Member;
namespace Umbraco.Web
{
@@ -194,12 +195,123 @@ namespace Umbraco.Web
return htmlHelper.Action(actionName, metaData.ControllerName, routeVals);
}
#region BeginUmbracoForm
#region GetCropUrl
/// <summary>
/// Used for rendering out the Form for BeginUmbracoForm
/// </summary>
internal class UmbracoForm : MvcForm
/// <summary>
/// Gets the ImageProcessor Url of a media item by the crop alias (using default media item property alias of "umbracoFile")
/// </summary>
/// <param name="htmlHelper"></param>
/// <param name="mediaItem"></param>
/// <param name="cropAlias"></param>
/// <returns></returns>
public static IHtmlString GetCropUrl(this HtmlHelper htmlHelper, IPublishedContent mediaItem, string cropAlias)
{
return new HtmlString(mediaItem.GetCropUrl(cropAlias: cropAlias, useCropDimensions: true));
}
/// <summary>
/// Gets the ImageProcessor Url of a media item by the property alias and crop alias.
/// </summary>
/// <param name="htmlHelper"></param>
/// <param name="mediaItem"></param>
/// <param name="propertyAlias"></param>
/// <param name="cropAlias"></param>
/// <returns></returns>
public static IHtmlString GetCropUrl(this HtmlHelper htmlHelper, IPublishedContent mediaItem, string propertyAlias, string cropAlias)
{
return new HtmlString(mediaItem.GetCropUrl(propertyAlias: propertyAlias, cropAlias: cropAlias, useCropDimensions: true));
}
/// <summary>
/// Gets the ImageProcessor Url of a media item
/// </summary>
/// <param name="htmlHelper"></param>
/// <param name="mediaItem"></param>
/// <param name="width"></param>
/// <param name="height"></param>
/// <param name="propertyAlias"></param>
/// <param name="cropAlias"></param>
/// <param name="quality"></param>
/// <param name="imageCropMode"></param>
/// <param name="imageCropAnchor"></param>
/// <param name="preferFocalPoint"></param>
/// <param name="useCropDimensions"></param>
/// <param name="cacheBuster"></param>
/// <param name="furtherOptions"></param>
/// <param name="ratioMode"></param>
/// <param name="upScale"></param>
/// <returns></returns>
public static IHtmlString GetCropUrl(this HtmlHelper htmlHelper,
IPublishedContent mediaItem,
int? width = null,
int? height = null,
string propertyAlias = Constants.Conventions.Media.File,
string cropAlias = null,
int? quality = null,
ImageCropMode? imageCropMode = null,
ImageCropAnchor? imageCropAnchor = null,
bool preferFocalPoint = false,
bool useCropDimensions = false,
bool cacheBuster = true,
string furtherOptions = null,
ImageCropRatioMode? ratioMode = null,
bool upScale = true)
{
return
new HtmlString(mediaItem.GetCropUrl(width, height, propertyAlias, cropAlias, quality, imageCropMode,
imageCropAnchor, preferFocalPoint, useCropDimensions, cacheBuster, furtherOptions, ratioMode,
upScale));
}
/// <summary>
/// Gets the ImageProcessor Url from the media path
/// </summary>
/// <param name="htmlHelper"></param>
/// <param name="imageUrl"></param>
/// <param name="width"></param>
/// <param name="height"></param>
/// <param name="imageCropperValue"></param>
/// <param name="cropAlias"></param>
/// <param name="quality"></param>
/// <param name="imageCropMode"></param>
/// <param name="imageCropAnchor"></param>
/// <param name="preferFocalPoint"></param>
/// <param name="useCropDimensions"></param>
/// <param name="cacheBusterValue"></param>
/// <param name="furtherOptions"></param>
/// <param name="ratioMode"></param>
/// <param name="upScale"></param>
/// <returns></returns>
public static IHtmlString GetCropUrl(this HtmlHelper htmlHelper,
string imageUrl,
int? width = null,
int? height = null,
string imageCropperValue = null,
string cropAlias = null,
int? quality = null,
ImageCropMode? imageCropMode = null,
ImageCropAnchor? imageCropAnchor = null,
bool preferFocalPoint = false,
bool useCropDimensions = false,
string cacheBusterValue = null,
string furtherOptions = null,
ImageCropRatioMode? ratioMode = null,
bool upScale = true)
{
return
new HtmlString(imageUrl.GetCropUrl(width, height, imageCropperValue, cropAlias, quality, imageCropMode,
imageCropAnchor, preferFocalPoint, useCropDimensions, cacheBusterValue, furtherOptions, ratioMode,
upScale));
}
#endregion
#region BeginUmbracoForm
/// <summary>
/// Used for rendering out the Form for BeginUmbracoForm
/// </summary>
internal class UmbracoForm : MvcForm
{
/// <summary>
/// Creates an UmbracoForm
@@ -756,8 +868,7 @@ namespace Umbraco.Web
}
#endregion
#region Wrap
public static HtmlTagWrapper Wrap(this HtmlHelper html, string tag, string innerText, params IHtmlTagWrapper[] children)
@@ -823,7 +934,71 @@ namespace Umbraco.Web
return item;
}
#endregion
#endregion
}
#region canvasdesigner
public static IHtmlString EnableCanvasDesigner(this HtmlHelper html,
UrlHelper url,
UmbracoContext umbCtx)
{
return html.EnableCanvasDesigner(url, umbCtx, string.Empty, string.Empty);
}
public static IHtmlString EnableCanvasDesigner(this HtmlHelper html,
UrlHelper url,
UmbracoContext umbCtx, string canvasdesignerConfigPath)
{
return html.EnableCanvasDesigner(url, umbCtx, canvasdesignerConfigPath, string.Empty);
}
public static IHtmlString EnableCanvasDesigner(this HtmlHelper html,
UrlHelper url,
UmbracoContext umbCtx, string canvasdesignerConfigPath, string canvasdesignerPalettesPath)
{
var umbracoPath = url.Content(SystemDirectories.Umbraco);
string previewLink = @"<script src=""{0}/lib/jquery/jquery.min.js"" type=""text/javascript""></script>" +
@"<script src=""{1}"" type=""text/javascript""></script>" +
@"<script src=""{2}"" type=""text/javascript""></script>" +
@"<script type=""text/javascript"">var pageId = '{3}'</script>" +
@"<script src=""{0}/js/canvasdesigner.front.js"" type=""text/javascript""></script>";
string noPreviewLinks = @"<link href=""{1}"" type=""text/css"" rel=""stylesheet"" data-title=""canvasdesignerCss"" />";
// Get page value
int pageId = umbCtx.PublishedContentRequest.UmbracoPage.PageID;
string[] path = umbCtx.PublishedContentRequest.UmbracoPage.SplitPath;
string result = string.Empty;
string cssPath = CanvasDesignerUtility.GetStylesheetPath(path, false);
if (umbCtx.InPreviewMode)
{
canvasdesignerConfigPath = string.IsNullOrEmpty(canvasdesignerConfigPath) == false
? canvasdesignerConfigPath
: string.Format("{0}/js/canvasdesigner.config.js", umbracoPath);
canvasdesignerPalettesPath = string.IsNullOrEmpty(canvasdesignerPalettesPath) == false
? canvasdesignerPalettesPath
: string.Format("{0}/js/canvasdesigner.palettes.js", umbracoPath);
if (string.IsNullOrEmpty(cssPath) == false)
result = string.Format(noPreviewLinks, cssPath) + Environment.NewLine;
result = result + string.Format(previewLink, umbracoPath, canvasdesignerConfigPath, canvasdesignerPalettesPath, pageId);
}
else
{
// Get css path for current page
if (string.IsNullOrEmpty(cssPath) == false)
result = string.Format(noPreviewLinks, cssPath);
}
return new HtmlString(result);
}
#endregion
}
}
+3 -3
View File
@@ -32,7 +32,7 @@ namespace Umbraco.Web
/// <returns></returns>
public static string GetItemAsString(this HttpRequest request, string key, string valueIfNotFound = "")
{
return new HttpRequestWrapper(request).GetItemAsString(key);
return new HttpRequestWrapper(request).GetItemAsString(key, valueIfNotFound);
}
/// <summary>
@@ -44,7 +44,7 @@ namespace Umbraco.Web
/// <returns></returns>
public static string GetItemAsString(this HttpRequestBase request, string key, string valueIfNotFound = "")
{
var val = HttpContext.Current.Request[key];
var val = request[key];
return !val.IsNullOrWhiteSpace() ? val : valueIfNotFound;
}
@@ -57,7 +57,7 @@ namespace Umbraco.Web
/// <returns></returns>
public static T GetItemAs<T>(this HttpRequestBase request, string key)
{
var val = HttpContext.Current.Request[key];
var val = request[key];
var whitespaceCheck = !val.IsNullOrWhiteSpace() ? val : string.Empty;
if (whitespaceCheck.IsNullOrWhiteSpace())
return (T) typeof (T).GetDefaultValue();
@@ -34,6 +34,6 @@ namespace Umbraco.Web.Models.ContentEditing
public bool HideLabel { get; set; }
[DataMember(Name = "validation")]
public PropertyTypeValidation Validation { get; set; }
public PropertyTypeValidation Validation { get; set; }
}
}
@@ -33,6 +33,13 @@ namespace Umbraco.Web.Models.ContentEditing
[DataMember(Name = "relateToOriginal", IsRequired = true)]
[Required]
public bool RelateToOriginal { get; set; }
/// <summary>
/// Boolean indicating whether copying the object should be recursive
/// </summary>
[DataMember(Name = "recursive", IsRequired = true)]
[Required]
public bool Recursive { get; set; }
}
}
@@ -2,22 +2,16 @@
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Linq.Expressions;
using System.Runtime.Serialization;
using System.Threading;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using AutoMapper;
using Newtonsoft.Json;
using Umbraco.Core;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Mapping;
using Umbraco.Core.PropertyEditors;
using Umbraco.Core.Services;
using Umbraco.Web.Models.ContentEditing;
using Umbraco.Web.Trees;
using umbraco;
using Umbraco.Web.Routing;
using umbraco.BusinessLogic.Actions;
@@ -51,11 +45,7 @@ namespace Umbraco.Web.Models.Mapping
.ForMember(
dto => dto.IsContainer,
expression => expression.MapFrom(content => content.ContentType.IsContainer))
.ForMember(
dto => dto.IsChildOfListView,
//TODO: Fix this shorthand .Parent() lookup, at least have an overload to use the current
// application context so it's testable!
expression => expression.MapFrom(content => content.Parent().ContentType.IsContainer))
.ForMember(display => display.IsChildOfListView, expression => expression.Ignore())
.ForMember(
dto => dto.Trashed,
expression => expression.MapFrom(content => content.Trashed))
@@ -78,7 +68,8 @@ namespace Umbraco.Web.Models.Mapping
.ForMember(display => display.Tabs, expression => expression.ResolveUsing<TabsAndPropertiesResolver>())
.ForMember(display => display.AllowedActions, expression => expression.ResolveUsing(
new ActionButtonsResolver(new Lazy<IUserService>(() => applicationContext.Services.UserService))))
.AfterMap((media, display) => AfterMap(media, display, applicationContext.Services.DataTypeService, applicationContext.Services.TextService));
.AfterMap((media, display) => AfterMap(media, display, applicationContext.Services.DataTypeService, applicationContext.Services.TextService,
applicationContext.Services.ContentTypeService));
//FROM IContent TO ContentItemBasic<ContentPropertyBasic, IContent>
config.CreateMap<IContent, ContentItemBasic<ContentPropertyBasic, IContent>>()
@@ -119,8 +110,37 @@ namespace Umbraco.Web.Models.Mapping
/// <param name="display"></param>
/// <param name="dataTypeService"></param>
/// <param name="localizedText"></param>
private static void AfterMap(IContent content, ContentItemDisplay display, IDataTypeService dataTypeService, ILocalizedTextService localizedText)
/// <param name="contentTypeService"></param>
private static void AfterMap(IContent content, ContentItemDisplay display, IDataTypeService dataTypeService,
ILocalizedTextService localizedText, IContentTypeService contentTypeService)
{
//map the IsChildOfListView (this is actually if it is a descendant of a list view!)
//TODO: Fix this shorthand .Ancestors() lookup, at least have an overload to use the current
if (content.HasIdentity)
{
var ancesctorListView = content.Ancestors().FirstOrDefault(x => x.ContentType.IsContainer);
display.IsChildOfListView = ancesctorListView != null;
}
else
{
//it's new so it doesn't have a path, so we need to look this up by it's parent + ancestors
var parent = content.Parent();
if (parent == null)
{
display.IsChildOfListView = false;
}
else if (parent.ContentType.IsContainer)
{
display.IsChildOfListView = true;
}
else
{
var ancesctorListView = parent.Ancestors().FirstOrDefault(x => x.ContentType.IsContainer);
display.IsChildOfListView = ancesctorListView != null;
}
}
//map the tree node url
if (HttpContext.Current != null)
{
@@ -142,44 +162,77 @@ namespace Umbraco.Web.Models.Mapping
TabsAndPropertiesResolver.AddListView(display, "content", dataTypeService);
}
TabsAndPropertiesResolver.MapGenericProperties(
content, display,
var properties = new List<ContentPropertyDisplay>
{
new ContentPropertyDisplay
{
Alias = string.Format("{0}releasedate", Constants.PropertyEditors.InternalGenericPropertiesPrefix),
Label = localizedText.Localize("content/releaseDate"),
Value = display.ReleaseDate.HasValue ? display.ReleaseDate.Value.ToIsoString() : null,
View = "datepicker" //TODO: Hard coding this because the templatepicker doesn't necessarily need to be a resolvable (real) property editor
},
{
Alias = string.Format("{0}releasedate", Constants.PropertyEditors.InternalGenericPropertiesPrefix),
Label = localizedText.Localize("content/releaseDate"),
Value = display.ReleaseDate.HasValue ? display.ReleaseDate.Value.ToIsoString() : null,
View = "datepicker" //TODO: Hard coding this because the templatepicker doesn't necessarily need to be a resolvable (real) property editor
},
new ContentPropertyDisplay
{
Alias = string.Format("{0}expiredate", Constants.PropertyEditors.InternalGenericPropertiesPrefix),
Label = localizedText.Localize("content/unpublishDate"),
Value = display.ExpireDate.HasValue ? display.ExpireDate.Value.ToIsoString() : null,
View = "datepicker" //TODO: Hard coding this because the templatepicker doesn't necessarily need to be a resolvable (real) property editor
},
{
Alias = string.Format("{0}expiredate", Constants.PropertyEditors.InternalGenericPropertiesPrefix),
Label = localizedText.Localize("content/unpublishDate"),
Value = display.ExpireDate.HasValue ? display.ExpireDate.Value.ToIsoString() : null,
View = "datepicker" //TODO: Hard coding this because the templatepicker doesn't necessarily need to be a resolvable (real) property editor
},
new ContentPropertyDisplay
{
Alias = string.Format("{0}template", Constants.PropertyEditors.InternalGenericPropertiesPrefix),
Label = "Template", //TODO: localize this?
Value = display.TemplateAlias,
View = "dropdown", //TODO: Hard coding until we make a real dropdown property editor to lookup
Config = new Dictionary<string, object>
{
Alias = string.Format("{0}template", Constants.PropertyEditors.InternalGenericPropertiesPrefix),
Label = "Template", //TODO: localize this?
Value = display.TemplateAlias,
View = "dropdown", //TODO: Hard coding until we make a real dropdown property editor to lookup
Config = new Dictionary<string, object>
{"items", templateItemConfig}
}
},
new ContentPropertyDisplay
{
Alias = string.Format("{0}urls", Constants.PropertyEditors.InternalGenericPropertiesPrefix),
Label = localizedText.Localize("content/urls"),
Value = string.Join(",", display.Urls),
View = "urllist" //TODO: Hard coding this because the templatepicker doesn't necessarily need to be a resolvable (real) property editor
}
};
TabsAndPropertiesResolver.MapGenericProperties(content, display, properties.ToArray(),
genericProperties =>
{
//TODO: This would be much nicer with the IUmbracoContextAccessor so we don't use singletons
//If this is a web request and debugging is enabled and there's a user signed in and the
// user has access tot he settings section, we will
if (HttpContext.Current != null && HttpContext.Current.IsDebuggingEnabled
&& UmbracoContext.Current != null && UmbracoContext.Current.Security.CurrentUser != null
&& UmbracoContext.Current.Security.CurrentUser.AllowedSections.Any(x => x.Equals(Constants.Applications.Settings)))
{
var currentDocumentType = contentTypeService.GetContentType(display.ContentTypeAlias);
var currentDocumentTypeName = currentDocumentType == null ? string.Empty : currentDocumentType.Name;
var currentDocumentTypeId = currentDocumentType == null ? string.Empty : currentDocumentType.Id.ToString(CultureInfo.InvariantCulture);
//TODO: Hard coding this is not good
var docTypeLink = string.Format("#/settings/framed/%252Fumbraco%252Fsettings%252FeditNodeTypeNew.aspx%253Fid%253D{0}", currentDocumentTypeId);
//Replace the doc type property
var docTypeProp = genericProperties.First(x => x.Alias == string.Format("{0}doctype", Constants.PropertyEditors.InternalGenericPropertiesPrefix));
docTypeProp.Value = new List<object>
{
new
{
{"items", templateItemConfig}
linkText = currentDocumentTypeName,
url = docTypeLink,
target = "_self", icon = "icon-item-arrangement"
}
},
new ContentPropertyDisplay
{
Alias = string.Format("{0}urls", Constants.PropertyEditors.InternalGenericPropertiesPrefix),
Label = localizedText.Localize("content/urls"),
Value = string.Join(",", display.Urls),
View = "urllist" //TODO: Hard coding this because the templatepicker doesn't necessarily need to be a resolvable (real) property editor
});
};
//TODO: Hard coding this because the templatepicker doesn't necessarily need to be a resolvable (real) property editor
docTypeProp.View = "urllist";
}
});
}
/// <summary>
/// Gets the published date value for the IContent object
/// </summary>
@@ -35,11 +35,7 @@ namespace Umbraco.Web.Models.Mapping
.ForMember(
dto => dto.ContentTypeAlias,
expression => expression.MapFrom(content => content.ContentType.Alias))
.ForMember(
dto => dto.IsChildOfListView,
//TODO: Fix this shorthand .Parent() lookup, at least have an overload to use the current
// application context so it's testable!
expression => expression.MapFrom(content => content.Parent().ContentType.IsContainer))
.ForMember(display => display.IsChildOfListView, expression => expression.Ignore())
.ForMember(
dto => dto.Trashed,
expression => expression.MapFrom(content => content.Trashed))
@@ -178,45 +178,48 @@ namespace Umbraco.Web.Models.Mapping
display.TreeNodeUrl = url;
}
TabsAndPropertiesResolver.MapGenericProperties(
member, display,
var genericProperties = new List<ContentPropertyDisplay>
{
GetLoginProperty(memberService, member, display),
new ContentPropertyDisplay
{
Alias = string.Format("{0}email", Constants.PropertyEditors.InternalGenericPropertiesPrefix),
Label = ui.Text("general", "email"),
Value = display.Email,
View = "email",
Validation = { Mandatory = true }
},
{
Alias = string.Format("{0}email", Constants.PropertyEditors.InternalGenericPropertiesPrefix),
Label = ui.Text("general", "email"),
Value = display.Email,
View = "email",
Validation = {Mandatory = true}
},
new ContentPropertyDisplay
{
Alias = string.Format("{0}password", Constants.PropertyEditors.InternalGenericPropertiesPrefix),
Label = ui.Text("password"),
//NOTE: The value here is a json value - but the only property we care about is the generatedPassword one if it exists, the newPassword exists
// only when creating a new member and we want to have a generated password pre-filled.
Value = new Dictionary<string, object>
{
Alias = string.Format("{0}password", Constants.PropertyEditors.InternalGenericPropertiesPrefix),
Label = ui.Text("password"),
//NOTE: The value here is a json value - but the only property we care about is the generatedPassword one if it exists, the newPassword exists
// only when creating a new member and we want to have a generated password pre-filled.
Value = new Dictionary<string, object>
{
{"generatedPassword", member.GetAdditionalDataValueIgnoreCase("GeneratedPassword", null) },
{"newPassword", member.GetAdditionalDataValueIgnoreCase("NewPassword", null) },
},
//TODO: Hard coding this because the changepassword doesn't necessarily need to be a resolvable (real) property editor
View = "changepassword",
//initialize the dictionary with the configuration from the default membership provider
Config = new Dictionary<string, object>(membersProvider.GetConfiguration())
{
//the password change toggle will only be displayed if there is already a password assigned.
{"hasPassword", member.RawPasswordValue.IsNullOrWhiteSpace() == false}
}
{"generatedPassword", member.GetAdditionalDataValueIgnoreCase("GeneratedPassword", null)},
{"newPassword", member.GetAdditionalDataValueIgnoreCase("NewPassword", null)},
},
new ContentPropertyDisplay
//TODO: Hard coding this because the changepassword doesn't necessarily need to be a resolvable (real) property editor
View = "changepassword",
//initialize the dictionary with the configuration from the default membership provider
Config = new Dictionary<string, object>(membersProvider.GetConfiguration())
{
Alias = string.Format("{0}membergroup", Constants.PropertyEditors.InternalGenericPropertiesPrefix),
Label = ui.Text("content", "membergroup"),
Value = GetMemberGroupValue(display.Username),
View = "membergroups",
Config = new Dictionary<string, object> { { "IsRequired", true } }
});
//the password change toggle will only be displayed if there is already a password assigned.
{"hasPassword", member.RawPasswordValue.IsNullOrWhiteSpace() == false}
}
},
new ContentPropertyDisplay
{
Alias = string.Format("{0}membergroup", Constants.PropertyEditors.InternalGenericPropertiesPrefix),
Label = ui.Text("content", "membergroup"),
Value = GetMemberGroupValue(display.Username),
View = "membergroups",
Config = new Dictionary<string, object> {{"IsRequired", true}}
}
};
TabsAndPropertiesResolver.MapGenericProperties(member, display, genericProperties);
//check if there's an approval field
var provider = membersProvider as global::umbraco.providers.members.UmbracoMembershipProvider;
@@ -1,10 +1,11 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Web;
using AutoMapper;
using Umbraco.Core;
using Umbraco.Core.Dictionary;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.PropertyEditors;
using Umbraco.Core.Services;
@@ -17,7 +18,7 @@ namespace Umbraco.Web.Models.Mapping
/// Creates the tabs collection with properties assigned for display models
/// </summary>
internal class TabsAndPropertiesResolver : ValueResolver<IContentBase, IEnumerable<Tab<ContentPropertyDisplay>>>
{
{
private ICultureDictionary _cultureDictionary;
protected IEnumerable<string> IgnoreProperties { get; set; }
@@ -27,7 +28,7 @@ namespace Umbraco.Web.Models.Mapping
}
public TabsAndPropertiesResolver(IEnumerable<string> ignoreProperties)
{
{
if (ignoreProperties == null) throw new ArgumentNullException("ignoreProperties");
IgnoreProperties = ignoreProperties;
}
@@ -40,6 +41,7 @@ namespace Umbraco.Web.Models.Mapping
/// <param name="customProperties">
/// Any additional custom properties to assign to the generic properties tab.
/// </param>
/// <param name="onGenericPropertiesMapped"></param>
/// <remarks>
/// The generic properties tab is mapped during AfterMap and is responsible for
/// setting up the properties such as Created date, updated date, template selected, etc...
@@ -47,11 +49,10 @@ namespace Umbraco.Web.Models.Mapping
public static void MapGenericProperties<TPersisted>(
TPersisted content,
ContentItemDisplayBase<ContentPropertyDisplay, TPersisted> display,
params ContentPropertyDisplay[] customProperties)
IEnumerable<ContentPropertyDisplay> customProperties = null,
Action<List<ContentPropertyDisplay>> onGenericPropertiesMapped = null)
where TPersisted : IContentBase
{
var genericProps = display.Tabs.Single(x => x.Id == 0);
//store the current props to append to the newly inserted ones
@@ -60,56 +61,67 @@ namespace Umbraco.Web.Models.Mapping
var labelEditor = PropertyEditorResolver.Current.GetByAlias(Constants.PropertyEditors.NoEditAlias).ValueEditor.View;
var contentProps = new List<ContentPropertyDisplay>
{
new ContentPropertyDisplay
{
new ContentPropertyDisplay
{
Alias = string.Format("{0}id", Constants.PropertyEditors.InternalGenericPropertiesPrefix),
Label = "Id",
Value = Convert.ToInt32(display.Id).ToInvariantString() + "<br/><small class='muted'>" + display.Key + "</small>",
View = labelEditor
},
new ContentPropertyDisplay
{
Alias = string.Format("{0}creator", Constants.PropertyEditors.InternalGenericPropertiesPrefix),
Label = ui.Text("content", "createBy"),
Description = ui.Text("content", "createByDesc"), //TODO: Localize this
Value = display.Owner.Name,
View = labelEditor
},
new ContentPropertyDisplay
{
Alias = string.Format("{0}createdate", Constants.PropertyEditors.InternalGenericPropertiesPrefix),
Label = ui.Text("content", "createDate"),
Description = ui.Text("content", "createDateDesc"),
Value = display.CreateDate.ToIsoString(),
View = labelEditor
},
new ContentPropertyDisplay
{
Alias = string.Format("{0}updatedate", Constants.PropertyEditors.InternalGenericPropertiesPrefix),
Label = ui.Text("content", "updateDate"),
Description = ui.Text("content", "updateDateDesc"),
Value = display.UpdateDate.ToIsoString(),
View = labelEditor
},
new ContentPropertyDisplay
{
Alias = string.Format("{0}doctype", Constants.PropertyEditors.InternalGenericPropertiesPrefix),
Label = ui.Text("content", "documentType"),
Value = TranslateItem(display.ContentTypeName, CreateDictionary()),
View = labelEditor
}
};
Alias = string.Format("{0}id", Constants.PropertyEditors.InternalGenericPropertiesPrefix),
Label = "Id",
Value = Convert.ToInt32(display.Id).ToInvariantString() + "<br/><small class='muted'>" + display.Key + "</small>",
View = labelEditor
},
new ContentPropertyDisplay
{
Alias = string.Format("{0}creator", Constants.PropertyEditors.InternalGenericPropertiesPrefix),
Label = ui.Text("content", "createBy"),
Description = ui.Text("content", "createByDesc"), //TODO: Localize this
Value = display.Owner.Name,
View = labelEditor
},
new ContentPropertyDisplay
{
Alias = string.Format("{0}createdate", Constants.PropertyEditors.InternalGenericPropertiesPrefix),
Label = ui.Text("content", "createDate"),
Description = ui.Text("content", "createDateDesc"),
Value = display.CreateDate.ToIsoString(),
View = labelEditor
},
new ContentPropertyDisplay
{
Alias = string.Format("{0}updatedate", Constants.PropertyEditors.InternalGenericPropertiesPrefix),
Label = ui.Text("content", "updateDate"),
Description = ui.Text("content", "updateDateDesc"),
Value = display.UpdateDate.ToIsoString(),
View = labelEditor
},
new ContentPropertyDisplay
{
Alias = string.Format("{0}doctype", Constants.PropertyEditors.InternalGenericPropertiesPrefix),
Label = ui.Text("content", "documentType"),
Value = TranslateItem(display.ContentTypeName, CreateDictionary()),
View = labelEditor
}
};
//add the custom ones
contentProps.AddRange(customProperties);
if (customProperties != null)
{
//add the custom ones
contentProps.AddRange(customProperties);
}
//now add the user props
contentProps.AddRange(currProps);
//callback
if (onGenericPropertiesMapped != null)
{
onGenericPropertiesMapped(contentProps);
}
//re-assign
genericProps.Properties = contentProps;
}
/// <summary>
+4 -15
View File
@@ -1,6 +1,7 @@
using System;
using System.Collections.Concurrent;
using System.Linq;
using System.Threading.Tasks;
using System.Web.Mvc;
using System.Web.Mvc.Async;
@@ -10,10 +11,7 @@ namespace Umbraco.Web.Mvc
/// Ensures that if an action for the Template name is not explicitly defined by a user, that the 'Index' action will execute
/// </summary>
public class RenderActionInvoker : AsyncControllerActionInvoker
{
private static readonly ConcurrentDictionary<Type, ReflectedActionDescriptor> IndexDescriptors = new ConcurrentDictionary<Type, ReflectedActionDescriptor>();
{
/// <summary>
/// Ensures that if an action for the Template name is not explicitly defined by a user, that the 'Index' action will execute
/// </summary>
@@ -31,17 +29,8 @@ namespace Umbraco.Web.Mvc
//check if the controller is an instance of IRenderMvcController
if (controllerContext.Controller is IRenderMvcController)
{
return IndexDescriptors.GetOrAdd(controllerContext.Controller.GetType(),
type => new ReflectedActionDescriptor(
controllerContext.Controller.GetType().GetMethods()
.First(x => x.Name == "Index" &&
x.GetCustomAttributes(typeof (NonActionAttribute), false).Any() == false),
"Index",
controllerDescriptor));
}
return controllerDescriptor.FindAction(controllerContext, "Index");
}
}
return ad;
}
@@ -83,7 +83,7 @@ namespace Umbraco.Web.Security.Identity
var cookieOptions = new CookieOptions
{
Path = "/",
Domain = _authOptions.CookieDomain,
Domain = _authOptions.CookieDomain ?? "FALSE",
Expires = DateTime.Now.AddMinutes(_authOptions.LoginTimeoutMinutes),
HttpOnly = true,
Secure = _authOptions.CookieSecure == CookieSecureOption.Always
+27 -32
View File
@@ -14,6 +14,9 @@ using Umbraco.Core.Xml;
using Umbraco.Web.Routing;
using Umbraco.Web.Security;
using System.Collections.Generic;
using System.IO;
using System.Web.Mvc;
using System.Web.Routing;
using Umbraco.Core.Cache;
namespace Umbraco.Web
@@ -1170,52 +1173,44 @@ namespace Umbraco.Web
#region canvasdesigner
public HtmlString EnableCanvasDesigner()
[Obsolete("Use EnableCanvasDesigner on the HtmlHelper extensions instead")]
public IHtmlString EnableCanvasDesigner()
{
return EnableCanvasDesigner(string.Empty, string.Empty);
}
public HtmlString EnableCanvasDesigner(string canvasdesignerConfigPath)
[Obsolete("Use EnableCanvasDesigner on the HtmlHelper extensions instead")]
public IHtmlString EnableCanvasDesigner(string canvasdesignerConfigPath)
{
return EnableCanvasDesigner(canvasdesignerConfigPath, string.Empty);
}
public HtmlString EnableCanvasDesigner(string canvasdesignerConfigPath, string canvasdesignerPalettesPath)
[Obsolete("Use EnableCanvasDesigner on the HtmlHelper extensions instead")]
public IHtmlString EnableCanvasDesigner(string canvasdesignerConfigPath, string canvasdesignerPalettesPath)
{
var html = CreateHtmlHelper("");
var urlHelper = new UrlHelper(UmbracoContext.HttpContext.Request.RequestContext);
return html.EnableCanvasDesigner(urlHelper, UmbracoContext, canvasdesignerConfigPath, canvasdesignerPalettesPath);
}
string previewLink = @"<script src=""/Umbraco/lib/jquery/jquery.min.js"" type=""text/javascript""></script>" +
@"<script src=""{0}"" type=""text/javascript""></script>" +
@"<script src=""{1}"" type=""text/javascript""></script>" +
@"<script type=""text/javascript"">var pageId = '{2}'</script>" +
@"<script src=""/umbraco/js/canvasdesigner.front.js"" type=""text/javascript""></script>";
string noPreviewLinks = @"<link href=""{0}"" type=""text/css"" rel=""stylesheet"" data-title=""canvasdesignerCss"" />";
// Get page value
int pageId = UmbracoContext.PublishedContentRequest.UmbracoPage.PageID;
string[] path = UmbracoContext.PublishedContentRequest.UmbracoPage.SplitPath;
string result = string.Empty;
string cssPath = CanvasDesignerUtility.GetStylesheetPath(path, false);
if (UmbracoContext.Current.InPreviewMode)
[Obsolete("This shouldn't need to be used but because the obsolete extension methods above don't have access to the current HtmlHelper, we need to create a fake one, unfortunately however this will not pertain the current views viewdata, tempdata or model state so should not be used")]
private HtmlHelper CreateHtmlHelper(object model)
{
var cc = new ControllerContext
{
canvasdesignerConfigPath = !string.IsNullOrEmpty(canvasdesignerConfigPath) ? canvasdesignerConfigPath : "/umbraco/js/canvasdesigner.config.js";
canvasdesignerPalettesPath = !string.IsNullOrEmpty(canvasdesignerPalettesPath) ? canvasdesignerPalettesPath : "/umbraco/js/canvasdesigner.palettes.js";
if (!string.IsNullOrEmpty(cssPath))
result = string.Format(noPreviewLinks, cssPath) + Environment.NewLine;
RequestContext = UmbracoContext.HttpContext.Request.RequestContext
};
var viewContext = new ViewContext(cc, new FakeView(), new ViewDataDictionary(model), new TempDataDictionary(), new StringWriter());
var htmlHelper = new HtmlHelper(viewContext, new ViewPage());
return htmlHelper;
}
result = result + string.Format(previewLink, canvasdesignerConfigPath, canvasdesignerPalettesPath, pageId);
}
else
[Obsolete("This shouldn't need to be used but because the obsolete extension methods above don't have access to the current HtmlHelper, we need to create a fake one, unfortunately however this will not pertain the current views viewdata, tempdata or model state so should not be used")]
private class FakeView : IView
{
public void Render(ViewContext viewContext, TextWriter writer)
{
// Get css path for current page
if (!string.IsNullOrEmpty(cssPath))
result = string.Format(noPreviewLinks, cssPath);
}
return new HtmlString(result);
}
#endregion
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Web.Http;
using System.Web.Services.Description;
using Umbraco.Core;
@@ -113,7 +114,25 @@ namespace Umbraco.Web.WebServices
if (domain != null)
domain.LanguageId = language.Id;
else if (Services.DomainService.Exists(domainModel.Name))
{
domainModel.Duplicate = true;
var xdomain = Services.DomainService.GetByName(domainModel.Name);
var xrcid = xdomain.RootContentId;
if (xrcid.HasValue)
{
var xcontent = Services.ContentService.GetById(xrcid.Value);
var xnames = new List<string>();
while (xcontent != null)
{
xnames.Add(xcontent.Name);
if (xcontent.ParentId < -1)
xnames.Add("Recycle Bin");
xcontent = xcontent.Parent();
}
xnames.Reverse();
domainModel.Other = "/" + string.Join("/", xnames);
}
}
else
{
// yet there is a race condition here...
@@ -159,6 +178,7 @@ namespace Umbraco.Web.WebServices
public string Name { get; private set; }
public int Lang { get; private set; }
public bool Duplicate { get; set; }
public string Other { get; set; }
}
#endregion
@@ -258,9 +258,16 @@ namespace Umbraco.Web.WebServices
//ignore these properties
.Where(x => new[] {"IndexerData", "Description", "WorkingFolder"}.InvariantContains(x.Name) == false)
.OrderBy(x => x.Name);
foreach (var p in props)
{
indexerModel.ProviderProperties.Add(p.Name, p.GetValue(indexer, null).ToString());
var val = p.GetValue(indexer, null);
if (val == null)
{
LogHelper.Warn<ExamineManagementApiController>("Property value was null when setting up property on indexer: " + indexer.Name + " property: " + p.Name);
val = string.Empty;
}
indexerModel.ProviderProperties.Add(p.Name, val.ToString());
}
var luceneIndexer = indexer as LuceneIndexer;
@@ -97,22 +97,25 @@ namespace Umbraco.Web.WebServices
oldname = oldname.TrimStart(pathPrefix);
}
var view = get(svce, oldname);
if (view == null)
view = new PartialView(filename);
var currentView = oldname.IsNullOrWhiteSpace()
? get(svce, filename)
: get(svce, oldname);
if (currentView == null)
currentView = new PartialView(filename);
else
view.Path = filename;
view.Content = contents;
currentView.Path = filename;
currentView.Content = contents;
Attempt<IPartialView> attempt;
try
{
var partialView = view as PartialView;
var partialView = currentView as PartialView;
if (partialView != null && validate != null && validate(svce, partialView) == false)
return Failed(ui.Text("speechBubbles", "partialViewErrorText"), ui.Text("speechBubbles", "partialViewErrorHeader"),
new FileSecurityException("File '" + view.Path + "' is not a valid partial view file."));
new FileSecurityException("File '" + currentView.Path + "' is not a valid partial view file."));
attempt = save(svce, view);
attempt = save(svce, currentView);
}
catch (Exception e)
{
@@ -602,7 +602,7 @@ namespace umbraco
XmlDocument mXml = new XmlDocument();
mXml.LoadXml(m.ToXml(mXml, false).OuterXml);
XPathNavigator xp = mXml.CreateNavigator();
return xp.Select("/node");
return xp.Select("/node()");
}
XmlDocument xd = new XmlDocument();
@@ -2,6 +2,7 @@
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.IO;
using System.Text;
using System.Web;
@@ -71,7 +72,7 @@ namespace umbraco
else
tmp = new Dictionary.DictionaryItem(this.id).Children;
foreach (Dictionary.DictionaryItem di in tmp)
foreach (Dictionary.DictionaryItem di in tmp.OrderBy(a => a.key))
{
XmlTreeNode xNode = XmlTreeNode.Create(this);
xNode.NodeID = di.id.ToString(); //dictionary_ + id..
@@ -12,6 +12,7 @@ using System.Xml;
using System.Xml.XPath;
using Umbraco.Core.Configuration;
using Umbraco.Core.IO;
using Umbraco.Web;
namespace umbraco.presentation.developer.packages {
public partial class BrowseRepository : BasePages.UmbracoEnsuredPage {
@@ -31,8 +32,8 @@ namespace umbraco.presentation.developer.packages {
fb.Text = "<strong>" + ui.Text("errors", "filePermissionsError") + ":</strong><br/>" + ex.Message;
}
string category = Request.QueryString["category"];
string repoGuid = Request.QueryString["repoGuid"];
string category = Request.CleanForXss("category");
string repoGuid = Request.CleanForXss("repoGuid");
var repo = cms.businesslogic.packager.repositories.Repository.getByGuid(repoGuid);
if (repo == null)
@@ -79,7 +79,7 @@ namespace umbraco.presentation.umbraco.dialogs
if (IsPostBack == false)
{
if (Access.IsProtected(documentId, documentObject.Path) && Access.GetProtectionType(documentId) != ProtectionType.NotProtected)
if (Access.IsProtected(documentId) && Access.GetProtectionType(documentId) != ProtectionType.NotProtected)
{
bt_buttonRemoveProtection.Visible = true;
bt_buttonRemoveProtection.Attributes.Add("onClick", "return confirm('" + ui.Text("areyousure") + "')");
@@ -263,10 +263,11 @@ namespace umbraco.presentation.umbraco.dialogs
p_buttons.Visible = false;
pane_advanced.Visible = false;
pane_simple.Visible = false;
var content = ApplicationContext.Current.Services.ContentService.GetById(pageId);
//reloads the current node in the tree
ClientTools.SyncTree(content.Path, true);
//reloads the current node's children in the tree
ClientTools.ReloadActionNode(false, true);
feedback.type = global::umbraco.uicontrols.Feedback.feedbacktype.success;
}
}
@@ -284,8 +285,10 @@ namespace umbraco.presentation.umbraco.dialogs
feedback.Text = ui.Text("publicAccess", "paIsRemoved", new cms.businesslogic.CMSNode(pageId).Text) + "</p><p><a href='#' onclick='" + ClientTools.Scripts.CloseModalWindow() + "'>" + ui.Text("closeThisWindow") + "</a>";
var content = ApplicationContext.Current.Services.ContentService.GetById(pageId);
//reloads the current node in the tree
ClientTools.SyncTree(content.Path, true);
//reloads the current node's children in the tree
ClientTools.ReloadActionNode(false, true);
feedback.type = global::umbraco.uicontrols.Feedback.feedbacktype.success;
}
@@ -19,7 +19,6 @@ using umbraco.BasePages;
using umbraco.BusinessLogic;
using umbraco.businesslogic.Exceptions;
using umbraco.cms.businesslogic.media;
using umbraco.cms.businesslogic.propertytype;
using umbraco.cms.businesslogic.web;
using umbraco.controls;
using umbraco.presentation.channels.businesslogic;
@@ -28,7 +27,9 @@ using umbraco.providers;
using umbraco.cms.presentation.Trees;
using Umbraco.Core.IO;
using Umbraco.Core;
using Umbraco.Core.Models;
using Umbraco.Core.Services;
using PropertyType = umbraco.cms.businesslogic.propertytype.PropertyType;
namespace umbraco.cms.presentation.user
{
@@ -106,8 +107,8 @@ namespace umbraco.cms.presentation.user
userType.Items.Add(li);
}
}
var userCulture = Services.TextService.ConvertToSupportedCultureWithRegionCode(new CultureInfo(u.Language));
var userCulture = UserExtensions.GetUserCulture(u.Language, Services.TextService);
// Populate ui language lsit
foreach (var lang in Services.TextService.GetSupportedCultures())
@@ -161,7 +161,7 @@ namespace umbraco.presentation.umbraco.webservices
var ext = uploadFile.FileName.Substring(uploadFile.FileName.LastIndexOf('.') + 1).ToLower();
if (UmbracoConfig.For.UmbracoSettings().Content.DisallowedUploadFiles.Contains(ext))
{
LogHelper.Warn<MediaUploader>("Cannot upload file " + uploadFile + ", it is not an approved file type");
LogHelper.Warn<MediaUploader>("Cannot upload file " + uploadFile.FileName + ", it is not approved in `disallowedUploadFiles` in ~/config/UmbracoSettings.config");
continue;
}
+12 -6
View File
@@ -71,7 +71,7 @@ namespace umbraco.cms.businesslogic.web
if (e.Cancel) return;
var entry = ApplicationContext.Current.Services.PublicAccessService.AddOrUpdateRule(
var entry = ApplicationContext.Current.Services.PublicAccessService.AddRule(
doc.ContentEntity,
Constants.Conventions.PublicAccess.MemberRoleRuleType,
role);
@@ -95,7 +95,7 @@ namespace umbraco.cms.businesslogic.web
if (content == null)
throw new Exception("No content found with document id " + DocumentId);
if (ApplicationContext.Current.Services.PublicAccessService.AddOrUpdateRule(
if (ApplicationContext.Current.Services.PublicAccessService.AddRule(
content,
Constants.Conventions.PublicAccess.MemberGroupIdRuleType,
MemberGroupId.ToString(CultureInfo.InvariantCulture)))
@@ -113,7 +113,7 @@ namespace umbraco.cms.businesslogic.web
if (content == null)
throw new Exception("No content found with document id " + DocumentId);
if (ApplicationContext.Current.Services.PublicAccessService.AddOrUpdateRule(
if (ApplicationContext.Current.Services.PublicAccessService.AddRule(
content,
Constants.Conventions.PublicAccess.MemberIdRuleType,
MemberId.ToString(CultureInfo.InvariantCulture)))
@@ -132,7 +132,7 @@ namespace umbraco.cms.businesslogic.web
if (e.Cancel) return;
var entry = ApplicationContext.Current.Services.PublicAccessService.AddOrUpdateRule(
var entry = ApplicationContext.Current.Services.PublicAccessService.AddRule(
doc.ContentEntity,
Constants.Conventions.PublicAccess.MemberUsernameRuleType,
membershipUserName);
@@ -155,7 +155,7 @@ namespace umbraco.cms.businesslogic.web
{
var doc = new Document(DocumentId);
var entry = ApplicationContext.Current.Services.PublicAccessService.AddOrUpdateRule(
var entry = ApplicationContext.Current.Services.PublicAccessService.AddRule(
doc.ContentEntity,
Constants.Conventions.PublicAccess.MemberGroupIdRuleType,
MemberGroupId.ToString(CultureInfo.InvariantCulture));
@@ -213,7 +213,7 @@ namespace umbraco.cms.businesslogic.web
var noAccessContent = ApplicationContext.Current.Services.ContentService.GetById(ErrorDocumentId);
if (noAccessContent == null) throw new NullReferenceException("No content item found with id " + ErrorDocumentId);
var entry = ApplicationContext.Current.Services.PublicAccessService.GetEntryForContent(doc.ContentEntity);
var entry = ApplicationContext.Current.Services.PublicAccessService.GetEntryForContent(doc.ContentEntity.Id.ToString());
if (entry != null)
{
if (Simple)
@@ -420,6 +420,12 @@ namespace umbraco.cms.businesslogic.web
return ApplicationContext.Current.Services.PublicAccessService.IsProtected(Path.EnsureEndsWith("," + DocumentId));
}
//return the protection status of this exact document - not based on inheritance
public static bool IsProtected(int DocumentId)
{
return ApplicationContext.Current.Services.PublicAccessService.IsProtected(DocumentId.ToString());
}
public static int GetErrorPage(string Path)
{
var entry = ApplicationContext.Current.Services.PublicAccessService.GetEntryForContent(Path);