Compare commits

...

140 Commits

Author SHA1 Message Date
Sebastiaan Janssen a099af39c2 xmlrpcnet was missing from nuspecs 2013-07-25 11:50:56 +02:00
Shannon 118f9b02e2 Fixes: U4-1027 Media Sort Usability -> changed the sorting to use Web API instead of asmx web service. 2013-07-25 12:29:41 +10:00
Sebastiaan Janssen 38778cc7c7 Fixes U4-2488 Edit datatype: Media Picker appears incorrectly 2013-07-24 14:52:25 +02:00
Shannon ffff9efaa8 Fixes: U4-2535 The actions/publish.aspx page does not publish correctly and show the correct publish result 2013-07-24 13:06:25 +10:00
Shannon 7f4abb4893 Fixed editContent.aspx to let the business logic handle the property validation when trying to publish and show the correct status message result (if it was not publishable). Adds the invalid properties collection to the PublishStatus so those can be shown too. 2013-07-24 12:54:10 +10:00
Shannon 4d39ce1202 Fixes Allow At Root styling 2013-07-24 11:44:26 +10:00
Shannon 7164f23a98 Fixes up validation styling and the validation summary close button display. 2013-07-24 11:31:31 +10:00
Shannon 8b2d1b8eab Fixed Template model class to not have it's own NodePath property which was always null since it wasn't mapped (and there was no point in it). 2013-07-24 10:11:05 +10:00
Shannon 80394f08fb Fixed runtime cache provider issues & unit tests. 2013-07-24 09:36:01 +10:00
Sebastiaan Janssen ca1fe5ff2a Unit test for: U4-2514 Checkboxlist prevalues in packages broken 2013-07-23 16:13:20 +02:00
Sebastiaan Janssen a1037ce43c Fixes U4-2187 - Enable support for MySQL on Linux 2013-07-23 15:38:26 +02:00
Sebastiaan Janssen 2cd2f3741d Merge branch '6.1.2' of https://github.com/stevetemple/Umbraco-CMS into stevetemple-6.1.3 2013-07-23 15:20:28 +02:00
Sebastiaan Janssen e634dba4ea 2nd attempt: U4-2514 Checkboxlist prevalues in packages broken 2013-07-23 13:16:18 +02:00
Shannon d1eb8fd9eb Obsoletes UmbracoFile with new UmbracoMediaFile in the Core assembly and wraps the legacy class to use the new one. Improves performance of UmbracoMediaFile by ensuring any IO is lazy loaded and then saved to a local property so it doesn't need to re-read the file for things like length/size.
Conflicts:
	src/Umbraco.Core/Umbraco.Core.csproj
2013-07-23 17:59:44 +10:00
Shannon 2e91c89c02 Fixes null check for changes to RuntimeCacheProvider 2013-07-23 14:00:52 +10:00
Shannon 8be54ba0cc Fixes: U4-1970 v6 API - need to implement caching for templates since we're doing a db lookup on a front-end request. This is a temporary fix until we implement the ApplicationCache properly but it still works by utilizing the existing RuntimeCacheProvider singleton. I've tweaked this provider as well to ensure we use the HttpRuntime.Cache when it is available (during a web session). We don't want to have a seperate caching bucket so that IIS can manage cache memory properly. Have ensured that the template cache is cleared when templates are updated/removed. 2013-07-23 11:46:18 +10:00
Shannon 3da7682415 reverted change for U4-2514 as this change will cause other unwanted problems. Added logging for DefaultDataKeyValue instead of blindly swallowing an exception. 2013-07-23 10:50:48 +10:00
Sebastiaan Janssen 775892ff5a U4-2514 Checkboxlist prevalues in packages broken 2013-07-22 16:23:16 +02:00
Sebastiaan Janssen f30b4c8184 Slight refactor of UmbracoFile 2013-07-22 13:55:10 +02:00
Sebastiaan Janssen 319ba5c791 U4-2524 If tinyMCEImageHelper.DoResize fails, the src gets removed from the img tag 2013-07-22 13:51:13 +02:00
Sebastiaan Janssen 398bc6d767 Fix merge issue 2013-07-22 12:15:54 +02:00
Sebastiaan Janssen 5d3ef8d97f Merge branch '6.1.3' of https://github.com/Myster/Umbraco-CMS into Myster-6.1.3
Conflicts:
	src/Umbraco.Web.UI/umbraco/config/lang/de.xml
	src/Umbraco.Web.UI/umbraco/config/lang/no.xml
2013-07-22 12:09:41 +02:00
Sebastiaan Janssen 08a300fbe5 U4-2370 Style sheet property sorting broken 2013-07-22 10:47:01 +02:00
Sebastiaan Janssen 845770c4bb Merge pull request #69 from abryukhov/patch-2
tinyMCE internal language pack - RU
2013-07-22 00:05:22 -07:00
Sebastiaan Janssen 771dc10c85 Merge pull request #68 from abryukhov/patch-3
tinyMCE internal language pack - RU
2013-07-22 00:04:23 -07:00
Sebastiaan Janssen 2ac76202e5 Merge pull request #67 from abryukhov/patch-4
tinyMCE internal language pack - RU
2013-07-22 00:04:11 -07:00
Sebastiaan Janssen a5ecbe96e2 Merge pull request #66 from abryukhov/patch-5
tinyMCE internal language pack - RU
2013-07-22 00:04:03 -07:00
Sebastiaan Janssen 7240b22e48 Merge pull request #65 from abryukhov/patch-6
tinyMCE internal language pack - RU
2013-07-22 00:03:51 -07:00
Sebastiaan Janssen 1f00589cb4 Merge pull request #64 from abryukhov/patch-7
tinyMCE internal language pack - RU
2013-07-22 00:03:33 -07:00
Sebastiaan Janssen 60b14487a9 Merge pull request #63 from abryukhov/patch-8
tinyMCE internal language pack - RU
2013-07-22 00:03:24 -07:00
Sebastiaan Janssen 33bc85a843 Merge pull request #62 from abryukhov/patch-9
tinyMCE internal language pack - RU
2013-07-22 00:03:14 -07:00
Sebastiaan Janssen e6642674d4 Merge pull request #61 from abryukhov/patch-10
tinyMCE internal language pack - RU
2013-07-22 00:03:01 -07:00
Sebastiaan Janssen 8ad5fb3c44 Merge pull request #60 from abryukhov/patch-11
tinyMCE internal language pack - RU
2013-07-22 00:02:50 -07:00
Sebastiaan Janssen 1752d14c57 Merge pull request #59 from abryukhov/patch-12
tinyMCE internal language pack - RU
2013-07-22 00:02:40 -07:00
Sebastiaan Janssen ec4ccba1a7 Merge pull request #58 from abryukhov/patch-13
tinyMCE internal language pack - RU
2013-07-22 00:02:32 -07:00
Sebastiaan Janssen 0244492a89 Merge pull request #57 from abryukhov/patch-14
tinyMCE internal language pack - RU
2013-07-22 00:02:22 -07:00
Sebastiaan Janssen 546cf2c84d Merge pull request #56 from abryukhov/patch-15
tinyMCE internal language pack - RU
2013-07-22 00:02:14 -07:00
Sebastiaan Janssen d354dde774 Merge pull request #55 from abryukhov/patch-16
tinyMCE internal language pack - RU
2013-07-22 00:02:03 -07:00
Sebastiaan Janssen 22c9e9acd9 Merge pull request #54 from abryukhov/patch-17
tinyMCE internal language pack - RU
2013-07-22 00:01:47 -07:00
Alexander Bryukhov 5dd14723e9 tinyMCE internal language pack - RU 2013-07-22 10:29:12 +07:00
Alexander Bryukhov 7134e80c44 tinyMCE internal language pack - RU 2013-07-22 10:27:31 +07:00
Alexander Bryukhov f7196ee8f9 tinyMCE internal language pack - RU 2013-07-22 10:26:47 +07:00
Alexander Bryukhov fdecd697b7 tinyMCE internal language pack - RU 2013-07-22 10:26:04 +07:00
Alexander Bryukhov 6c03dac869 tinyMCE internal language pack - RU 2013-07-22 10:25:18 +07:00
Alexander Bryukhov 6cdb564a9f tinyMCE internal language pack - RU 2013-07-22 10:24:31 +07:00
Alexander Bryukhov 0da8a8db36 tinyMCE internal language pack - RU 2013-07-22 10:23:51 +07:00
Alexander Bryukhov a4a9620889 tinyMCE internal language pack - RU 2013-07-22 10:22:46 +07:00
Alexander Bryukhov 2307424fb6 tinyMCE internal language pack - RU 2013-07-22 10:22:01 +07:00
Alexander Bryukhov ca124fb662 tinyMCE internal language pack - RU 2013-07-22 10:21:16 +07:00
Alexander Bryukhov 6787252f9b tinyMCE internal language pack - RU 2013-07-22 10:20:36 +07:00
Alexander Bryukhov ef3094f8d9 tinyMCE internal language pack - RU 2013-07-22 10:19:51 +07:00
Alexander Bryukhov a2a20133aa tinyMCE internal language pack - RU 2013-07-22 10:18:38 +07:00
Alexander Bryukhov bb750d186a tinyMCE internal language pack - RU 2013-07-22 10:17:56 +07:00
Alexander Bryukhov f2a7dde5ce tinyMCE internal language pack - RU 2013-07-22 10:16:00 +07:00
Alexander Bryukhov 73e2559a13 tinyMCE internal language pack - RU 2013-07-22 10:14:48 +07:00
Shannon 80f8a9d01c Merge branch '6.1.3' of https://github.com/umbraco/Umbraco-CMS into 6.1.3 2013-07-22 12:44:06 +10:00
Shannon 6f9883d373 Fixes MNTP required validation (U4-1975) 2013-07-22 12:30:12 +10:00
Shannon 41c920a4ec Updated to latest CDF version which contains some fixes. 2013-07-22 11:29:32 +10:00
Sebastiaan Janssen 1f79b71738 Merge branch '6.1.3' of github.com:umbraco/Umbraco-CMS into 6.1.3 2013-07-19 15:59:09 +02:00
Sebastiaan Janssen 64fb588556 defaultDocumentTypeProperty is no longer case-sensitive. Added to the Release config as well so it makes it into the umbraco downloadable package. 2013-07-19 15:41:29 +02:00
Sebastiaan Janssen 90cfd004cb Merge branch 'wip-u4-1949' of https://github.com/AndyButland/Umbraco-CMS into AndyButland-wip-u4-1949 2013-07-19 15:41:15 +02:00
Sebastiaan Janssen ad927ec6c1 Merge pull request #53 from abryukhov/patch-1
Update of ru.xml with latest keys
2013-07-19 06:20:55 -07:00
Sebastiaan Janssen 8a19d28859 Merge pull request #52 from enkelmedia/patch-1
Update to readme to contain info about the support for MVC
2013-07-19 06:20:37 -07:00
Sebastiaan Janssen 7e24af9daf Merge branch '6.1.3' of github.com:umbraco/Umbraco-CMS into 6.1.3 2013-07-19 15:19:27 +02:00
Sebastiaan Janssen 7518b514a7 Merge pull request #51 from kipusoep/master
Updated the download link
2013-07-19 15:19:01 +02:00
Sebastiaan Janssen 96c38f50e4 Merge pull request #49 from lars-erik/6.1.3
Prettifying norwegian translation
2013-07-19 06:17:48 -07:00
Sebastiaan Janssen e723f1169f Merge pull request #48 from marc303/patch-1
Updated DE to 6.1.2
2013-07-19 06:16:48 -07:00
Sebastiaan Janssen 914005b2b6 Merge pull request #46 from michielvoo/u4-2417
U4-2417 Could the preview thumbnail link to the full image
Conflicts:
	src/Umbraco.Web/Umbraco.Web.csproj
	src/Umbraco.Web/umbraco.presentation/umbraco/controls/Images/ImageViewer.ascx.cs
	src/umbraco.editorControls/mediapicker/mediaChooser.cs
2013-07-19 15:09:07 +02:00
Sebastiaan Janssen 972b903f52 Merge pull request #32 from AndyButland/wip-u4-1285
Fix for U4-1285: Apostrophes in member groups cause exceptions
2013-07-19 14:40:28 +02:00
Sebastiaan Janssen 61d072c8d6 Fix merge issue 2013-07-19 13:32:24 +02:00
Sebastiaan Janssen 8740848aac Merge pull request #42 from michielvoo/u4-232
Enabled support for integrated security for SQL Server to the installer.
Conflicts:
	src/Umbraco.Web.UI/install/steps/database.ascx
2013-07-19 13:29:07 +02:00
Sebastiaan Janssen 6766aa9732 Merge pull request #41 from michielvoo/u4-667
U4-667
2013-07-19 13:19:30 +02:00
Sebastiaan Janssen a57334d1f7 Merge pull request #40 from michielvoo/u4-663
U4-663
2013-07-19 12:55:16 +02:00
Sebastiaan Janssen 3dea16fad1 U4-2309 BackOffice / ExamineMngr : "Optimize index" don't ends correctly when website has not members. 2013-07-19 12:39:50 +02:00
Shannon 1bf4121796 Fixes a null check in UmbracoTemplatePage 2013-07-19 12:36:02 +10:00
Shannon 93bebdd50b Merge branch '6.1.3' of https://github.com/umbraco/Umbraco-CMS into 6.1.3 2013-07-19 12:27:59 +10:00
Shannon 6a9532f10a Fixes: U4-1599 [MVC] ChangeContentType doesn't work in macros rendered from a View -> We need to manually reset the ContentType after we execute a webforms based macro because Server.Execute resets the ContentType back to the default. 2013-07-19 12:27:37 +10:00
Sebastiaan Janssen d88494e90e U4-638 Bug (and fix/solution): Saving inline base64 image (or any attribute value with equal sign at the end) 2013-07-18 17:09:26 +02:00
Sebastiaan Janssen e48f08b657 When using Public Access > Single User Protection the email of the member is empty, this caused errors because the result of GetMembersFromEmail is null 2013-07-18 16:07:39 +02:00
Sebastiaan Janssen a79e349f3d U4-2467 v4.11.1: Membership search does not search on email address anymore 2013-07-18 11:00:56 +02:00
Shannon 1c70570078 Fixes : U4-2055 Unpublish Date Bug in Umbraco 6.0.3 -> with unit test to ensure that all dates are formatted as ISO date standards when used in SQL 2013-07-17 14:16:38 +10:00
Alexander Bryukhov 197dacfae7 Update of ru.xml with latest keys 2013-07-17 09:56:50 +07:00
Shannon d8aad718d5 Fixed broken unit test 2013-07-17 11:28:46 +10:00
Sebastiaan Janssen 1d7bfc2781 U4-2465 "Login Name already exists" when creating a new member that existed before 2013-07-16 13:33:52 +02:00
Sebastiaan Janssen 8063717e4c U4-2511 Locallink:NODEID not working 2013-07-16 13:21:27 +02:00
Lars-Erik Aabech 3900b7ebc8 Remove WebForms from nuspec file
Not just WebForms anymore. :)
2013-07-16 13:09:53 +02:00
Shannon 0296c646cb Fixes up a small code issue for U4-2505 2013-07-16 11:45:28 +10:00
enkelmedia 275dbc83dd Update to readme to contain info about the support for MVC 2013-07-15 19:38:10 +02:00
Sebastiaan Janssen 1cd2dc8a42 Fixes U4-2436 Editing an existing property changes its alias 2013-07-15 16:52:23 +02:00
Sebastiaan Janssen 60867af1a7 Fixes U4-2444 Missing image - /umbraco/images/pinnedIcons/umb.ico
Also fixes casing of folder names
2013-07-15 16:31:19 +02:00
Sebastiaan Janssen 1e129bcc4d Fixes U4-2505 umbraco 6.1.2 throws System.NullReferenceException on the first publish after site compilation 2013-07-15 16:16:39 +02:00
Sebastiaan Janssen e5c758bbc1 Fixes U4-1838 uGoLive Success/Failure Images not showing 2013-07-15 16:07:42 +02:00
Shannon 25780663a6 Fixes: U4-1304 Umbraco.Field not replacing localLink when recursive:true . 2013-07-15 15:26:18 +10:00
Sebastiaan Janssen aa327696fe Fixes U4-2354 MiniProfiler - Show SQL parameter values and more stacktrace info
Refactored duplicate code
2013-07-10 12:35:21 +02:00
Lars-Erik Aabech 1272a7c74b Prettifying norwegian translation
Removed obsolete, translated new, removed incorrect spacing and
hyphenation, misc. improvements in term usage. Ref.
http://i18n.skulelinux.no/nb/Fellesordl.eng-no.html.
2013-07-09 12:56:13 +02:00
esn303 dcbe6726b0 Updated DE to 6.1.2
Markup encoded instead of CDATA blocks
2013-07-09 10:30:20 +02:00
Shannon ba68da5736 Makes Domain.GetDomains public (#U4-2483) 2013-07-09 11:55:29 +10:00
Shannon fdabd945dc Merge branch '6.1.3' of https://github.com/umbraco/Umbraco-CMS into 6.1.3 2013-07-09 11:48:03 +10:00
Shannon 868edee5e6 Fixes: #U4-2161 - permissions inheritance. Fixes up how user permissions cache is invalidated and looked up (it is now lazy and not forced). User permissions are also cached as a low priority for now and only for 20 mins based on #U4-2474. 2013-07-09 11:47:46 +10:00
Shannon b91d0bb117 Updates ContentRepository to bulk insert all parent permissions at once (overload to the AssignEntityPermissions method) 2013-07-09 10:08:31 +10:00
Murray Roke cc91977e94 Fix notification-email link to unpublished page
http://issues.umbraco.org/issue/U4-2482
I've added links to language files which did not contain it.
I used the %5% syntax in the sv.xml file which seems to otherwise use
{5} syntax
2013-07-09 11:19:51 +12:00
Shannon 90b94f6ffb Fixes: #U4-2476 2013-07-08 18:58:38 +10:00
Shannon 3c4cf56309 Fixes: #U4-2475 2013-07-08 18:47:53 +10:00
Shannon b7f6195791 Started adding base PermissionsRepository for sub classes to use for assigning permissions, created a BulkImport extension methods for PetaPoco with tests since we'll be needing that for assigning permissions in a nice way. Wrote unit tests for all sql gen for permissions and assigning permissions. This all starts fixing #U4-2161 but there's still a bit more work to do. 2013-07-08 17:29:26 +10:00
Morten Christensen 42eb82e6ca Merge branch '6.1.3' of https://github.com/umbraco/Umbraco-CMS into 6.1.3 2013-07-05 10:55:12 +02:00
Morten Christensen 93def731ef Fixes #U4-2466 2013-07-05 10:51:19 +02:00
Shannon 60805f91d6 bit of code cleaning. 2013-07-05 16:58:51 +10:00
Shannon 048480d5be Fixes: #U4-2460 - UmbracoHelper.RenderTemplate will now execute the complete MVC cycle when rendering MVC templates whereas before it would only execute the view which means any actionfilters, etc... applied would never have fired (as well as other things) 2013-07-05 14:12:31 +10:00
Morten Christensen 173d388c12 Fixes #U4-2450 2013-07-04 12:31:31 +02:00
Morten Christensen b1285fa7e3 Add missing id to unique naming overload 2013-07-04 12:31:10 +02:00
Morten Christensen e34c857f6c A bit of refactoring around unique naming, and implementing it for media as well 2013-07-04 11:22:59 +02:00
Morten Christensen 7ff0e6cd4b Fixes #U4-2458 2013-07-04 10:50:02 +02:00
Shannon 0683094f84 oops, overwrote previous changes to CmsNode, now merged them back in properly. 2013-07-04 12:20:25 +10:00
Shannon 983b7a85e1 Merge branch '6.1.3' of https://github.com/umbraco/Umbraco-CMS into 6.1.3 2013-07-04 12:13:24 +10:00
Shannon d015780b9f Fixes: #U4-2447 - non thread safe icon lookup 2013-07-04 12:13:02 +10:00
Morten Christensen aeece499bb Fixing unit test for PublishedMedia cache, which had expected result set incorrect 2013-07-03 14:00:44 +02:00
Morten Christensen 8465b4e556 Merge branch '6.1.3' of https://github.com/umbraco/Umbraco-CMS into 6.1.3 2013-07-03 12:34:52 +02:00
Morten Christensen e280785f48 Adding Msdeploy PropertyGroup to build prop file, so both FileSystem and MsDeploy package will include the umbraco and umbraco_client folders 2013-07-03 12:30:34 +02:00
Shannon 5e0a59e4b3 Merge branch '6.1.3' of https://github.com/umbraco/Umbraco-CMS into 6.1.3 2013-07-03 19:47:25 +10:00
Morten Christensen 30835797ff Merge branch '6.1.3' of https://github.com/umbraco/Umbraco-CMS into 6.1.3 2013-07-03 11:47:09 +02:00
Shannon 4077a01a6b Fixes: #U4-2344 - fixes examine re-indexing for media and a null check for DataType.Data 2013-07-03 19:47:06 +10:00
Morten Christensen aed70ae40c Updating dependencies in our own nuspec file 2013-07-03 11:46:53 +02:00
Morten Christensen 6d44628352 Merge pull request #45 from jhauge/PublishUmbracoFiles
Add Umbraco files during publish
2013-07-03 02:39:12 -07:00
Jesper Hauge 7a398d34b1 Added file-reg to .nuspec 2013-07-03 11:33:05 +02:00
Morten Christensen 69c5aeb1b3 Updating nuget dependencies for test project 2013-07-03 11:29:58 +02:00
Shannon da545b890b Updated UserRepository to not contain the general query methods, we do those in the service. 2013-07-03 19:26:28 +10:00
Morten Christensen 6609bc09f2 Updating nuget dependency for HtmlAgilityPack 2013-07-03 11:26:17 +02:00
Morten Christensen f06a6f42da Updating nuget dependency for ClientDependency 2013-07-03 11:20:42 +02:00
Jesper Hauge c9065d96a9 These files will add MSBuild target that copies /umbraco /umbraco_client and /App_Browsers files to .csproj files, during install of NuGet package UmbracoCms
Functionality has been tested by creating af copy of the current Nuget package and add these files to the package, then using this package on a new Web application project. Building and doing a VS Publish to the filesystem.
2013-07-03 11:17:47 +02:00
Morten Christensen 9d4e1362c4 Updating nuget references for ASP.NET MVC, Razor, WebPages and WebApi to latest patch release 2013-07-03 11:11:37 +02:00
Shannon d3b69e04e1 Updated IUserService and added more unit tests for new methods. Fixed unit tests that were failing due to incorrectly set settings... not sure how this is working on the server but oh well. 2013-07-03 19:01:37 +10:00
Morten Christensen 0d54e8df89 Updating MySql package dependency 2013-07-03 11:00:26 +02:00
Morten Christensen 8f949d0a2f Merge branch '6.1.3' of https://github.com/umbraco/Umbraco-CMS into 6.1.3 2013-07-03 09:40:17 +02:00
Shannon d67480e98b Updated UserService, didn't need one of the methods on there, updated the unit tests to test all the other methods. 2013-07-03 17:09:14 +10:00
Shannon 5d76ead469 backported changes to IUserRepository from v7 2013-07-03 16:52:00 +10:00
Shannon 2796100067 added another unit test. 2013-07-03 16:45:56 +10:00
Shannon a132f609d7 backports changes for -> Finished upgrading the UserRepository and entities to properly support Users' Allowed Sections & streamlines Persistence/Mappers with less code duplication. 2013-07-03 16:40:22 +10:00
Morten Christensen 7f7456701d Adding license 2013-07-02 15:32:53 +02:00
Sebastiaan Janssen ffce1a3e6b Open new branch for 6.1.3 2013-06-28 14:44:56 +02:00
Steve Temple b12f60e443 Allow for absolute URLs as well as virtual in ResolveUrl to allow for FileSystemProviders that use CDNs 2013-06-27 00:04:37 +01:00
251 changed files with 9800 additions and 6778 deletions
+9
View File
@@ -0,0 +1,9 @@
# The MIT License (MIT) #
Copyright (c) 2013 Umbraco
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+2 -2
View File
@@ -8,7 +8,7 @@ Umbraco CMS
**More than 177,000 sites trust Umbraco**
For the first time on the Microsoft platform a free user and developer friendly CMS that makes it quick and easy to create websites - or a breeze to build complex web applications. Umbraco has award-winning integration capabilities and supports your ASP.NET User and Custom Controls out of the box. It's a developers dream and your users will love it too.
For the first time on the Microsoft platform a free user and developer friendly CMS that makes it quick and easy to create websites - or a breeze to build complex web applications. Umbraco has award-winning integration capabilities and supports ASP.NET MVC or Web Forms, including User and Custom Controls, out of the box. It's a developers dream and your users will love it too.
Used by more than 177,000 active websites including [http://daviscup.com](http://daviscup.com), [http://heinz.com](http://heinz.com), [http://peugeot.com](http://peugeot.com), [http://www.hersheys.com/](http://www.hersheys.com/) and **The Official ASP.NET and IIS.NET website from Microsoft** ([http://asp.net](http://asp.net) / [http://iis.net](http://iis.net)) you can be sure that the technology is proven, stable and scales.
@@ -16,7 +16,7 @@ To view more examples please visit [http://umbraco.com/why-umbraco/#caseStudies]
## Downloading ##
The downloadable Umbraco releases live at [http://our.umbraco.org/contribute/releases](http://our.umbraco.org/contribute/releases).
The downloadable Umbraco releases live at [http://our.umbraco.org/download](http://our.umbraco.org/download).
## Forums ##
+1 -1
View File
@@ -1,5 +1,5 @@
@ECHO OFF
SET release=6.1.2
SET release=6.1.3
SET comment=
SET version=%release%
+5 -5
View File
@@ -19,22 +19,22 @@
<dependency id="Microsoft.AspNet.WebApi" version="4.0" />
<dependency id="Microsoft.AspNet.Mvc.FixedDisplayModes" version="1.0.0" />
<dependency id="MiniProfiler" version="2.1.0" />
<dependency id="HtmlAgilityPack" version="1.4.5" />
<dependency id="HtmlAgilityPack" version="1.4.6" />
<dependency id="Lucene.Net" version="[2.9.4.1]" />
<dependency id="SharpZipLib" version="0.86.0" />
<dependency id="MySql.Data" version="[6.6,6.7)" />
<dependency id="MySql.Data" version="[6.6.5]" />
<dependency id="xmlrpcnet" version="2.5.0" />
<dependency id="ClientDependency" version="[1.7.0,1.7.1)" />
<dependency id="ClientDependency-Mvc" version="[1.7.0,1.7.1)" />
</dependencies>
</metadata>
<files>
<file src="..\_BuildOutput\WebApp\bin\businesslogic.dll" target="lib\businesslogic.dll" />
<file src="..\_BuildOutput\WebApp\bin\businesslogic.xml" target="lib\businesslogic.xml" />
<file src="..\_BuildOutput\WebApp\bin\ClientDependency.Core.dll" target="lib\ClientDependency.Core.dll" />
<file src="..\_BuildOutput\WebApp\bin\ClientDependency.Core.Mvc.dll" target="lib\ClientDependency.Core.Mvc.dll" />
<file src="..\_BuildOutput\WebApp\bin\cms.dll" target="lib\cms.dll" />
<file src="..\_BuildOutput\WebApp\bin\cms.xml" target="lib\cms.xml" />
<file src="..\_BuildOutput\WebApp\bin\controls.dll" target="lib\controls.dll" />
<file src="..\_BuildOutput\WebApp\bin\controls.xml" target="lib\controls.xml" />
<file src="..\_BuildOutput\WebApp\bin\CookComputing.XmlRpcV2.dll" target="lib\CookComputing.XmlRpcV2.dll" />
<file src="..\_BuildOutput\WebApp\bin\Examine.dll" target="lib\Examine.dll" />
<file src="..\_BuildOutput\WebApp\bin\interfaces.dll" target="lib\interfaces.dll" />
<file src="..\_BuildOutput\WebApp\bin\interfaces.xml" target="lib\interfaces.xml" />
+3 -2
View File
@@ -10,8 +10,8 @@
<projectUrl>http://umbraco.com/</projectUrl>
<iconUrl>http://umbraco.com/media/357769/100px_transparent.png</iconUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>Installs Umbraco Cms in your Visual Studio ASP.NET Webforms project</description>
<summary>Installs Umbraco Cms in your Visual Studio ASP.NET Webforms project</summary>
<description>Installs Umbraco Cms in your Visual Studio ASP.NET project</description>
<summary>Installs Umbraco Cms in your Visual Studio ASP.NET project</summary>
<language>en-US</language>
<tags>umbraco</tags>
<dependencies>
@@ -44,5 +44,6 @@
<file src="..\_BuildOutput\WebApp\Web.config" target="UmbracoFiles\Web.config" />
<file src="tools\install.ps1" target="tools\install.ps1" />
<file src="tools\Readme.txt" target="tools\Readme.txt" />
<file src="build\**" target="build" />
</files>
</package>
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<CopyAllFilesToSingleFolderForPackageDependsOn>
AddUmbracoFilesToOutput;
$(CopyAllFilesToSingleFolderForPackageDependsOn);
</CopyAllFilesToSingleFolderForPackageDependsOn>
<CopyAllFilesToSingleFolderForMsdeployDependsOn>
AddUmbracoFilesToOutput;
$(CopyAllFilesToSingleFolderForPackageDependsOn);
</CopyAllFilesToSingleFolderForMsdeployDependsOn>
</PropertyGroup>
</Project>
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="AddUmbracoFilesToOutput">
<ItemGroup>
<UmbracoFiles Include=".\umbraco\**\*;" />
<UmbracoClientFiles Include=".\umbraco_client\**\*;" />
<AppBrowsersFiles Include=".\App_Browsers\**\*" />
<FilesForPackagingFromProject Include="%(UmbracoFiles.Identity)">
<DestinationRelativePath>umbraco\%(RecursiveDir)%(Filename)%(Extension)</DestinationRelativePath>
</FilesForPackagingFromProject>
<FilesForPackagingFromProject Include="%(UmbracoClientFiles.Identity)">
<DestinationRelativePath>umbraco_client\%(RecursiveDir)%(Filename)%(Extension)</DestinationRelativePath>
</FilesForPackagingFromProject>
<FilesForPackagingFromProject Include="%(AppBrowsersFiles.Identity)">
<DestinationRelativePath>App_Browsers\%(RecursiveDir)%(Filename)%(Extension)</DestinationRelativePath>
</FilesForPackagingFromProject>
</ItemGroup>
</Target>
</Project>
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<CopyAllFilesToSingleFolderForPackageDependsOn>
AddUmbracoFilesToOutput;
$(CopyAllFilesToSingleFolderForPackageDependsOn);
</CopyAllFilesToSingleFolderForPackageDependsOn>
<CopyAllFilesToSingleFolderForMsdeployDependsOn>
AddUmbracoFilesToOutput;
$(CopyAllFilesToSingleFolderForPackageDependsOn);
</CopyAllFilesToSingleFolderForMsdeployDependsOn>
</PropertyGroup>
</Project>
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="AddUmbracoFilesToOutput">
<ItemGroup>
<UmbracoFiles Include=".\umbraco\**\*;" />
<UmbracoClientFiles Include=".\umbraco_client\**\*;" />
<AppBrowsersFiles Include=".\App_Browsers\**\*" />
<FilesForPackagingFromProject Include="%(UmbracoFiles.Identity)">
<DestinationRelativePath>umbraco\%(RecursiveDir)%(Filename)%(Extension)</DestinationRelativePath>
</FilesForPackagingFromProject>
<FilesForPackagingFromProject Include="%(UmbracoClientFiles.Identity)">
<DestinationRelativePath>umbraco_client\%(RecursiveDir)%(Filename)%(Extension)</DestinationRelativePath>
</FilesForPackagingFromProject>
<FilesForPackagingFromProject Include="%(AppBrowsersFiles.Identity)">
<DestinationRelativePath>App_Browsers\%(RecursiveDir)%(Filename)%(Extension)</DestinationRelativePath>
</FilesForPackagingFromProject>
</ItemGroup>
</Target>
</Project>
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<CopyAllFilesToSingleFolderForPackageDependsOn>
AddUmbracoFilesToOutput;
$(CopyAllFilesToSingleFolderForPackageDependsOn);
</CopyAllFilesToSingleFolderForPackageDependsOn>
<CopyAllFilesToSingleFolderForMsdeployDependsOn>
AddUmbracoFilesToOutput;
$(CopyAllFilesToSingleFolderForPackageDependsOn);
</CopyAllFilesToSingleFolderForMsdeployDependsOn>
</PropertyGroup>
</Project>
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="AddUmbracoFilesToOutput">
<ItemGroup>
<UmbracoFiles Include=".\umbraco\**\*;" />
<UmbracoClientFiles Include=".\umbraco_client\**\*;" />
<AppBrowsersFiles Include=".\App_Browsers\**\*" />
<FilesForPackagingFromProject Include="%(UmbracoFiles.Identity)">
<DestinationRelativePath>umbraco\%(RecursiveDir)%(Filename)%(Extension)</DestinationRelativePath>
</FilesForPackagingFromProject>
<FilesForPackagingFromProject Include="%(UmbracoClientFiles.Identity)">
<DestinationRelativePath>umbraco_client\%(RecursiveDir)%(Filename)%(Extension)</DestinationRelativePath>
</FilesForPackagingFromProject>
<FilesForPackagingFromProject Include="%(AppBrowsersFiles.Identity)">
<DestinationRelativePath>App_Browsers\%(RecursiveDir)%(Filename)%(Extension)</DestinationRelativePath>
</FilesForPackagingFromProject>
</ItemGroup>
</Target>
</Project>
+1
View File
@@ -31,6 +31,7 @@ namespace Umbraco.Core.Cache
public const string UserContextCacheKey = "UmbracoUserContext";
public const string UserContextTimeoutCacheKey = "UmbracoUserContextTimeout";
public const string UserCacheKey = "UmbracoUser";
public const string UserPermissionsCacheKey = "UmbracoUserPermissions";
public const string ContentTypeCacheKey = "UmbracoContentType";
@@ -8,7 +8,7 @@ namespace Umbraco.Core.Cache
/// An abstract class for implementing a runtime cache provider
/// </summary>
/// <remarks>
/// THIS MUST REMAIN INTERNAL UNTIL WE STREAMLINE HOW ALL CACHE IS HANDLED, WE NEED TO SUPPORT HTTP RUNTIME CACHE, IN MEMORY CACHE, ETC...
/// THIS MUST REMAIN INTERNAL UNTIL WE STREAMLINE HOW ALL CACHE IS HANDLED, WE NEED TO SUPPORT HTTP RUNTIME CACHE, IN MEMORY CACHE, REQUEST CACHE, ETC...
/// </remarks>
internal abstract class RuntimeCacheProviderBase : CacheProviderBase
{
@@ -1305,6 +1305,25 @@ namespace Umbraco.Core.Configuration
}
}
/// <summary>
/// Gets the default document type property used when adding new properties through the back-office
/// </summary>
/// <value>Configured text for the default document type property</value>
/// <remarks>If undefined, 'Textstring' is the default</remarks>
public static string DefaultDocumentTypeProperty
{
get
{
var defaultDocumentTypeProperty = GetKey("/settings/content/defaultDocumentTypeProperty");
if (string.IsNullOrEmpty(defaultDocumentTypeProperty))
{
defaultDocumentTypeProperty = "Textstring";
}
return defaultDocumentTypeProperty;
}
}
/// <summary>
/// Configuration regarding webservices
/// </summary>
@@ -5,7 +5,7 @@ namespace Umbraco.Core.Configuration
{
public class UmbracoVersion
{
private static readonly Version Version = new Version("6.1.2");
private static readonly Version Version = new Version("6.1.3");
/// <summary>
/// Gets the current version of Umbraco.
+20 -6
View File
@@ -169,6 +169,20 @@ namespace Umbraco.Core
Initialize(providerName);
}
/// <summary>
/// Configures a ConnectionString for the Umbraco database that uses Microsoft SQL Server integrated security.
/// </summary>
/// <param name="server">Name or address of the database server</param>
/// <param name="databaseName">Name of the database</param>
public void ConfigureIntegratedSecurityDatabaseConnection(string server, string databaseName)
{
const string providerName = "System.Data.SqlClient";
string connectionString = String.Format("Server={0};Database={1};Integrated Security=true", server, databaseName);
SaveConnectionString(connectionString, providerName);
Initialize(providerName);
}
internal string BuildAzureConnectionString(string server, string databaseName, string user, string password)
{
if (server.Contains(".") && ServerStartsWithTcp(server) == false)
@@ -393,8 +407,8 @@ namespace Umbraco.Core
if (supportsCaseInsensitiveQueries == false)
{
message = "<p>&nbsp;</p><p>The database you're trying to use does not support case insensitive queries. <br />We currently do not support these types of databases.</p>" +
"<p>You can fix this by changing the following two settings in your my.ini file in your MySQL installation directory:</p>" +
"<pre>lower_case_table_names=1\nlower_case_file_system=1</pre><br />" +
"<p>You can fix this by changing the following setting in your my.ini file in your MySQL installation directory:</p>" +
"<pre>lower_case_table_names=1</pre><br />" +
"<p>Note: Make sure to check with your hosting provider if they support case insensitive queries as well.</p>" +
"<p>For more technical information on case sensitivity in MySQL, have a look at " +
"<a href='http://dev.mysql.com/doc/refman/5.0/en/identifier-case-sensitivity.html'>the documentation on the subject</a></p>";
@@ -404,8 +418,8 @@ namespace Umbraco.Core
else if (supportsCaseInsensitiveQueries == null)
{
message = "<p>&nbsp;</p><p>Warning! Could not check if your database type supports case insensitive queries. <br />We currently do not support these databases that do not support case insensitive queries.</p>" +
"<p>You can check this by looking for the following two settings in your my.ini file in your MySQL installation directory:</p>" +
"<pre>lower_case_table_names=1\nlower_case_file_system=1</pre><br />" +
"<p>You can check this by looking for the following setting in your my.ini file in your MySQL installation directory:</p>" +
"<pre>lower_case_table_names=1</pre><br />" +
"<p>Note: Make sure to check with your hosting provider if they support case insensitive queries as well.</p>" +
"<p>For more technical information on case sensitivity in MySQL, have a look at " +
"<a href='http://dev.mysql.com/doc/refman/5.0/en/identifier-case-sensitivity.html'>the documentation on the subject</a></p>";
@@ -418,8 +432,8 @@ namespace Umbraco.Core
"<p>Note: You're using MySQL and the database instance you're connecting to seems to support case insensitive queries.</p>" +
"<p>However, your hosting provider may not support this option. Umbraco does not currently support MySQL installs that do not support case insensitive queries</p>" +
"<p>Make sure to check with your hosting provider if they support case insensitive queries as well.</p>" +
"<p>They can check this by looking for the following two settings in the my.ini file in their MySQL installation directory:</p>" +
"<pre>lower_case_table_names=1\nlower_case_file_system=1</pre><br />" +
"<p>They can check this by looking for the following setting in the my.ini file in their MySQL installation directory:</p>" +
"<pre>lower_case_table_names=1</pre><br />" +
"<p>For more technical information on case sensitivity in MySQL, have a look at " +
"<a href='http://dev.mysql.com/doc/refman/5.0/en/identifier-case-sensitivity.html'>the documentation on the subject</a></p>";
}
+22
View File
@@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Umbraco.Core
{
public static class DateTimeExtensions
{
/// <summary>
/// Returns the DateTime as an ISO formatted string that is globally expectable
/// </summary>
/// <param name="dt"></param>
/// <returns></returns>
public static string ToIsoString(this DateTime dt)
{
return dt.ToString("yyyy-MM-dd HH:mm:ss");
}
}
}
+2
View File
@@ -45,6 +45,8 @@ namespace Umbraco.Core.IO
{
if (virtualPath.StartsWith("~"))
return virtualPath.Replace("~", SystemDirectories.Root).Replace("//", "/");
else if (Uri.IsWellFormedUriString(virtualPath, UriKind.Absolute))
return virtualPath;
else
return VirtualPathUtility.ToAbsolute(virtualPath, SystemDirectories.Root);
}
+20
View File
@@ -0,0 +1,20 @@
namespace Umbraco.Core.IO
{
internal class ResizedImage
{
public ResizedImage()
{
}
public ResizedImage(int width, int height, string fileName)
{
Width = width;
Height = height;
FileName = fileName;
}
public int Width { get; set; }
public int Height { get; set; }
public string FileName { get; set; }
}
}
+253
View File
@@ -0,0 +1,253 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Web;
using Umbraco.Core.Configuration;
namespace Umbraco.Core.IO
{
public class UmbracoMediaFile
{
private readonly MediaFileSystem _fs;
#region Constructors
public UmbracoMediaFile()
{
_fs = FileSystemProviderManager.Current.GetFileSystemProvider<MediaFileSystem>();
}
public UmbracoMediaFile(string path)
{
_fs = FileSystemProviderManager.Current.GetFileSystemProvider<MediaFileSystem>();
Path = path;
Initialize();
}
#endregion
#region Static Methods
//MB: Do we really need all these overloads? looking through the code, only one of them is actually used
public static UmbracoMediaFile Save(HttpPostedFile file, string path)
{
return Save(file.InputStream, path);
}
public static UmbracoMediaFile Save(HttpPostedFileBase file, string path)
{
return Save(file.InputStream, path);
}
public static UmbracoMediaFile Save(Stream inputStream, string path)
{
var fs = FileSystemProviderManager.Current.GetFileSystemProvider<MediaFileSystem>();
fs.AddFile(path, inputStream);
return new UmbracoMediaFile(path);
}
public static UmbracoMediaFile Save(byte[] file, string relativePath)
{
return Save(new MemoryStream(file), relativePath);
}
public static UmbracoMediaFile Save(HttpPostedFile file)
{
var tempDir = System.IO.Path.Combine("uploads", Guid.NewGuid().ToString());
return Save(file, tempDir);
}
//filebase overload...
public static UmbracoMediaFile Save(HttpPostedFileBase file)
{
var tempDir = System.IO.Path.Combine("uploads", Guid.NewGuid().ToString());
return Save(file, tempDir);
}
#endregion
private long? _length;
private Size? _size;
/// <summary>
/// Initialized values that don't require opening the file.
/// </summary>
private void Initialize()
{
Filename = _fs.GetFileName(Path);
Extension = _fs.GetExtension(Path) != null
? _fs.GetExtension(Path).Substring(1).ToLowerInvariant()
: "";
Url = _fs.GetUrl(Path);
}
public string Filename { get; private set; }
public string Extension { get; private set; }
public string Path { get; private set; }
public string Url { get; private set; }
/// <summary>
/// Get the length of the file in bytes
/// </summary>
/// <remarks>
/// We are lazy loading this, don't go opening the file on ctor like we were doing.
/// </remarks>
public long Length
{
get
{
if (_length == null)
{
_length = _fs.GetSize(Path);
}
return _length.Value;
}
}
public bool SupportsResizing
{
get
{
return ("," + UmbracoSettings.ImageFileTypes + ",").Contains(string.Format(",{0},", Extension));
}
}
public string GetFriendlyName()
{
return Filename.SplitPascalCasing().ToFirstUpperInvariant();
}
public Size GetDimensions()
{
if (_size == null)
{
EnsureFileSupportsResizing();
var fs = _fs.OpenFile(Path);
var image = Image.FromStream(fs);
var fileWidth = image.Width;
var fileHeight = image.Height;
fs.Close();
image.Dispose();
_size = new Size(fileWidth, fileHeight);
}
return _size.Value;
}
public string Resize(int width, int height)
{
EnsureFileSupportsResizing();
var fileNameThumb = DoResize(width, height, 0, string.Empty);
return _fs.GetUrl(fileNameThumb);
}
public string Resize(int maxWidthHeight, string fileNameAddition)
{
EnsureFileSupportsResizing();
var fileNameThumb = DoResize(GetDimensions().Width, GetDimensions().Height, maxWidthHeight, fileNameAddition);
return _fs.GetUrl(fileNameThumb);
}
private string DoResize(int width, int height, int maxWidthHeight, string fileNameAddition)
{
using (var fs = _fs.OpenFile(Path))
{
using (var image = Image.FromStream(fs))
{
var fileNameThumb = string.IsNullOrWhiteSpace(fileNameAddition)
? string.Format("{0}_UMBRACOSYSTHUMBNAIL.jpg", Path.Substring(0, Path.LastIndexOf(".", StringComparison.Ordinal)))
: string.Format("{0}_{1}.jpg", Path.Substring(0, Path.LastIndexOf(".", StringComparison.Ordinal)), fileNameAddition);
var thumbnail = GenerateThumbnail(image, maxWidthHeight, width, height, fileNameThumb, maxWidthHeight == 0);
return thumbnail.FileName;
}
}
}
private void EnsureFileSupportsResizing()
{
if (SupportsResizing == false)
throw new InvalidOperationException(string.Format("The file {0} is not an image, so can't get dimensions", Filename));
}
private ResizedImage GenerateThumbnail(Image image, int maxWidthHeight, int fileWidth, int fileHeight, string thumbnailFileName, bool useFixedDimensions)
{
// Generate thumbnail
float f = 1;
if (useFixedDimensions == false)
{
var fx = (float)image.Size.Width / (float)maxWidthHeight;
var fy = (float)image.Size.Height / (float)maxWidthHeight;
// must fit in thumbnail size
f = Math.Max(fx, fy);
}
var widthTh = (int)Math.Round((float)fileWidth / f);
var heightTh = (int)Math.Round((float)fileHeight / f);
// fixes for empty width or height
if (widthTh == 0)
widthTh = 1;
if (heightTh == 0)
heightTh = 1;
// Create new image with best quality settings
using (var bp = new Bitmap(widthTh, heightTh))
{
using (var g = Graphics.FromImage(bp))
{
g.SmoothingMode = SmoothingMode.HighQuality;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.PixelOffsetMode = PixelOffsetMode.HighQuality;
g.CompositingQuality = CompositingQuality.HighQuality;
// Copy the old image to the new and resized
var rect = new Rectangle(0, 0, widthTh, heightTh);
g.DrawImage(image, rect, 0, 0, image.Width, image.Height, GraphicsUnit.Pixel);
// Copy metadata
var imageEncoders = ImageCodecInfo.GetImageEncoders();
var codec = Extension.ToLower() == "png" || Extension.ToLower() == "gif"
? imageEncoders.Single(t => t.MimeType.Equals("image/png"))
: imageEncoders.Single(t => t.MimeType.Equals("image/jpeg"));
// Set compresion ratio to 90%
var ep = new EncoderParameters();
ep.Param[0] = new EncoderParameter(Encoder.Quality, 90L);
// Save the new image using the dimensions of the image
var newFileName = thumbnailFileName.Replace("UMBRACOSYSTHUMBNAIL", string.Format("{0}x{1}", widthTh, heightTh));
using (var ms = new MemoryStream())
{
bp.Save(ms, codec, ep);
ms.Seek(0, 0);
_fs.AddFile(newFileName, ms);
}
return new ResizedImage(widthTh, heightTh, newFileName);
}
}
}
}
}
+18 -1
View File
@@ -22,7 +22,7 @@ namespace Umbraco.Core.Models
private DateTime? _expireDate;
private int _writer;
private string _nodeName;//NOTE Once localization is introduced this will be the non-localized Node Name.
private bool _permissionsChanged;
/// <summary>
/// Constructor for creating a Content object
/// </summary>
@@ -82,6 +82,7 @@ namespace Umbraco.Core.Models
private static readonly PropertyInfo ExpireDateSelector = ExpressionHelper.GetPropertyInfo<Content, DateTime?>(x => x.ExpireDate);
private static readonly PropertyInfo WriterSelector = ExpressionHelper.GetPropertyInfo<Content, int>(x => x.WriterId);
private static readonly PropertyInfo NodeNameSelector = ExpressionHelper.GetPropertyInfo<Content, string>(x => x.NodeName);
private static readonly PropertyInfo PermissionsChangedSelector = ExpressionHelper.GetPropertyInfo<Content, bool>(x => x.PermissionsChanged);
/// <summary>
/// Gets or sets the template used by the Content.
@@ -243,6 +244,22 @@ namespace Umbraco.Core.Models
}
}
/// <summary>
/// Used internally to track if permissions have been changed during the saving process for this entity
/// </summary>
internal bool PermissionsChanged
{
get { return _permissionsChanged; }
set
{
SetPropertyValueAndDetectChanges(o =>
{
_permissionsChanged = value;
return _permissionsChanged;
}, _permissionsChanged, PermissionsChangedSelector);
}
}
/// <summary>
/// Gets the ContentType used by this content object
/// </summary>
+12 -1
View File
@@ -27,6 +27,7 @@ namespace Umbraco.Core.Models
private bool _trashed;
private int _contentTypeId;
private PropertyCollection _properties;
private readonly List<Property> _lastInvalidProperties = new List<Property>();
/// <summary>
/// Protected constructor for ContentBase (Base for Content and Media)
@@ -421,7 +422,17 @@ namespace Umbraco.Core.Models
/// <returns>True if content is valid otherwise false</returns>
public virtual bool IsValid()
{
return Properties.Any(property => !property.IsValid()) == false;
_lastInvalidProperties.Clear();
_lastInvalidProperties.AddRange(Properties.Where(property => property.IsValid() == false));
return _lastInvalidProperties.Any() == false;
}
/// <summary>
/// Returns a collection of the result of the last validation process, this collection contains all invalid properties.
/// </summary>
internal IEnumerable<Property> LastInvalidProperties
{
get { return _lastInvalidProperties; }
}
public abstract void ChangeTrashedState(bool isTrashed, int parentId = -20);
@@ -535,6 +535,11 @@ namespace Umbraco.Core.Models
return ApplicationContext.Current.Services.PackagingService.Export(media);
}
internal static XElement ToDeepXml(this IMedia media)
{
return ApplicationContext.Current.Services.PackagingService.Export(media, true);
}
/// <summary>
/// Creates the xml representation for the <see cref="IContent"/> object
/// </summary>
@@ -108,7 +108,7 @@ namespace Umbraco.Core.Models.EntityBase
/// Please note that resetting the dirty properties could potentially
/// obstruct the saving of a new or updated entity.
/// </remarks>
internal void ResetDirtyProperties(bool rememberPreviouslyChangedProperties)
internal virtual void ResetDirtyProperties(bool rememberPreviouslyChangedProperties)
{
if (rememberPreviouslyChangedProperties)
{
+12 -4
View File
@@ -7,17 +7,25 @@ namespace Umbraco.Core.Models.Membership
/// Defines the interface for a <see cref="User"/>
/// </summary>
/// <remarks>Will be left internal until a proper Membership implementation is part of the roadmap</remarks>
internal interface IUser : IMembershipUser
internal interface IUser : IMembershipUser, IUserProfile
{
string Name { get; set; }
new object Id { get; set; }
//string Name { get; set; }
int SessionTimeout { get; set; }
int StartContentId { get; set; }
int StartMediaId { get; set; }
string Language { get; set; }
bool DefaultToLiveEditing { get; set; }
IEnumerable<string> Applications { get; set; }
bool NoConsole { get; set; }
IUserType UserType { get; }
string Permissions { get; set; }
string DefaultPermissions { get; set; }
}
internal interface IUserProfile : IProfile
{
IEnumerable<string> AllowedSections { get; }
void RemoveAllowedSection(string sectionAlias);
void AddAllowedSection(string sectionAlias);
}
}
+57 -5
View File
@@ -1,5 +1,7 @@
using System;
using System.Reflection;
using System.Runtime.Serialization;
using Umbraco.Core.Models.EntityBase;
namespace Umbraco.Core.Models.Membership
{
@@ -8,7 +10,7 @@ namespace Umbraco.Core.Models.Membership
/// </summary>
[Serializable]
[DataContract(IsReference = true)]
internal class Profile : IProfile
internal class Profile : TracksChangesEntityBase, IProfile, IRememberBeingDirty
{
/// <summary>
/// Initializes a new instance of the <see cref="Profile"/> class.
@@ -25,11 +27,47 @@ namespace Umbraco.Core.Models.Membership
Name = name;
}
[DataMember]
public object Id { get; set; }
private object _id;
private string _name;
private Type _userTypeKey;
private static readonly PropertyInfo IdSelector = ExpressionHelper.GetPropertyInfo<Profile, object>(x => x.Id);
private static readonly PropertyInfo NameSelector = ExpressionHelper.GetPropertyInfo<Profile, string>(x => x.Name);
private static readonly PropertyInfo UserTypeKeySelector = ExpressionHelper.GetPropertyInfo<Profile, Type>(x => x.ProviderUserKeyType);
[DataMember]
public string Name { get; set; }
public object Id
{
get
{
return _id;
}
set
{
SetPropertyValueAndDetectChanges(o =>
{
_id = value;
return _id;
}, _id, IdSelector);
}
}
[DataMember]
public string Name
{
get
{
return _name;
}
set
{
SetPropertyValueAndDetectChanges(o =>
{
_name = value;
return _name;
}, _name, NameSelector);
}
}
[IgnoreDataMember]
public virtual object ProviderUserKey
@@ -45,7 +83,21 @@ namespace Umbraco.Core.Models.Membership
/// The type of the provider user key.
/// </value>
[IgnoreDataMember]
internal Type ProviderUserKeyType { get; private set; }
internal Type ProviderUserKeyType
{
get
{
return _userTypeKey;
}
private set
{
SetPropertyValueAndDetectChanges(o =>
{
_userTypeKey = value;
return _userTypeKey;
}, _userTypeKey, UserTypeKeySelector);
}
}
/// <summary>
/// Sets the type of the provider user key.
+5 -4
View File
@@ -22,7 +22,7 @@ namespace Umbraco.Core.Models.Membership
public User(IUserType userType)
{
Groups = new List<object> {userType};
Groups = new List<object> { userType };
}
#region Implementation of IEntity
@@ -91,7 +91,8 @@ namespace Umbraco.Core.Models.Membership
[DataMember]
public string Language { get; set; }
[DataMember]
public string Permissions { get; set; }
public string DefaultPermissions { get; set; }
[DataMember]
public bool DefaultToLiveEditing { get; set; }
[DataMember]
@@ -100,8 +101,8 @@ namespace Umbraco.Core.Models.Membership
[IgnoreDataMember]
public IUserType UserType
{
get
{
get
{
var type = Groups.FirstOrDefault();
return type as IUserType;
}
+138 -11
View File
@@ -1,6 +1,9 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;
namespace Umbraco.Core.Models.Membership
@@ -14,14 +17,29 @@ namespace Umbraco.Core.Models.Membership
/// </remarks>
[Serializable]
[DataContract(IsReference = true)]
internal class UserProfile : Profile
internal class UserProfile : Profile, IUserProfile
{
public UserProfile()
{
SessionTimeout = 60;
Applications = Enumerable.Empty<string>();
_sectionCollection = new ObservableCollection<string>();
_addedSections = new List<string>();
_removedSections = new List<string>();
_sectionCollection.CollectionChanged += SectionCollectionChanged;
}
private readonly List<string> _addedSections;
private readonly List<string> _removedSections;
private readonly ObservableCollection<string> _sectionCollection;
private int _sessionTimeout;
private int _startContentId;
private int _startMediaId;
private static readonly PropertyInfo SessionTimeoutSelector = ExpressionHelper.GetPropertyInfo<UserProfile, int>(x => x.SessionTimeout);
private static readonly PropertyInfo StartContentIdSelector = ExpressionHelper.GetPropertyInfo<UserProfile, int>(x => x.StartContentId);
private static readonly PropertyInfo StartMediaIdSelector = ExpressionHelper.GetPropertyInfo<UserProfile, int>(x => x.StartMediaId);
private static readonly PropertyInfo AllowedSectionsSelector = ExpressionHelper.GetPropertyInfo<UserProfile, IEnumerable<string>>(x => x.AllowedSections);
/// <summary>
/// Gets or sets the session timeout.
/// </summary>
@@ -29,7 +47,21 @@ namespace Umbraco.Core.Models.Membership
/// The session timeout.
/// </value>
[DataMember]
public int SessionTimeout { get; set; }
public int SessionTimeout
{
get
{
return _sessionTimeout;
}
set
{
SetPropertyValueAndDetectChanges(o =>
{
_sessionTimeout = value;
return _sessionTimeout;
}, _sessionTimeout, SessionTimeoutSelector);
}
}
/// <summary>
/// Gets or sets the start content id.
@@ -38,7 +70,21 @@ namespace Umbraco.Core.Models.Membership
/// The start content id.
/// </value>
[DataMember]
public int StartContentId { get; set; }
public int StartContentId
{
get
{
return _startContentId;
}
set
{
SetPropertyValueAndDetectChanges(o =>
{
_startContentId = value;
return _startContentId;
}, _startContentId, StartContentIdSelector);
}
}
/// <summary>
/// Gets or sets the start media id.
@@ -47,15 +93,96 @@ namespace Umbraco.Core.Models.Membership
/// The start media id.
/// </value>
[DataMember]
public int StartMediaId { get; set; }
public int StartMediaId
{
get
{
return _startMediaId;
}
set
{
SetPropertyValueAndDetectChanges(o =>
{
_startMediaId = value;
return _startMediaId;
}, _startMediaId, StartMediaIdSelector);
}
}
public IEnumerable<string> AllowedSections
{
get { return _sectionCollection; }
}
public void RemoveAllowedSection(string sectionAlias)
{
_sectionCollection.Remove(sectionAlias);
}
public void AddAllowedSection(string sectionAlias)
{
if (!_sectionCollection.Contains(sectionAlias))
{
_sectionCollection.Add(sectionAlias);
}
}
/// <summary>
/// Gets or sets the applications.
/// Whenever resetting occurs, clear the remembered add/removed collections, even if
/// rememberPreviouslyChangedProperties is true, the AllowedSections property will still
/// be flagged as dirty.
/// </summary>
/// <value>
/// The applications.
/// </value>
[DataMember]
public IEnumerable<string> Applications { get; set; }
/// <param name="rememberPreviouslyChangedProperties"></param>
internal override void ResetDirtyProperties(bool rememberPreviouslyChangedProperties)
{
_addedSections.Clear();
_removedSections.Clear();
base.ResetDirtyProperties(rememberPreviouslyChangedProperties);
}
/// <summary>
/// Used internally to check if we need to add a section in the repository to the db
/// </summary>
internal IEnumerable<string> AddedSections
{
get { return _addedSections; }
}
/// <summary>
/// Used internally to check if we need to remove a section in the repository to the db
/// </summary>
internal IEnumerable<string> RemovedSections
{
get { return _removedSections; }
}
/// <summary>
/// Handles the collection changed event in order for us to flag the AllowedSections property as changed
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void SectionCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
OnPropertyChanged(AllowedSectionsSelector);
if (e.Action == NotifyCollectionChangedAction.Add)
{
//remove from the removed/added sections (since people could add/remove all they want in one request)
_removedSections.RemoveAll(s => s == e.NewItems.Cast<string>().First());
_addedSections.RemoveAll(s => s == e.NewItems.Cast<string>().First());
//add to the added sections
_addedSections.Add(e.NewItems.Cast<string>().First());
}
else if (e.Action == NotifyCollectionChangedAction.Remove)
{
//remove from the removed/added sections (since people could add/remove all they want in one request)
_removedSections.RemoveAll(s => s == e.OldItems.Cast<string>().First());
_addedSections.RemoveAll(s => s == e.OldItems.Cast<string>().First());
//add to the added sections
_removedSections.Add(e.OldItems.Cast<string>().First());
}
}
}
}
+15 -2
View File
@@ -1,7 +1,15 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Xml;
using System.Xml.Linq;
using System.Xml.XPath;
using Umbraco.Core.Configuration;
using Umbraco.Core.Models.Rdbms;
using Umbraco.Core.Services;
using umbraco.interfaces;
namespace Umbraco.Core.Models
{
@@ -28,8 +36,13 @@ namespace Umbraco.Core.Models
}
//This seems to fail during testing
xmlNode.AppendChild(property.PropertyType.DataType(property.Id).Data.ToXMl(xd));
//SD: With the new null checks below, this shouldn't fail anymore.
var dt = property.PropertyType.DataType(property.Id);
if (dt != null && dt.Data != null)
{
xmlNode.AppendChild(dt.Data.ToXMl(xd));
}
var element = xmlNode.GetXElement();
return element;
}
@@ -20,6 +20,10 @@ namespace Umbraco.Core.Models
{
Mandate.ParameterNotNull(propertyType, "propertyType");
var dataType = ApplicationContext.Current.Services.DataTypeService.GetDataTypeById(propertyType.DataTypeId);
if (dataType == null)
{
return null;
}
dataType.DataTypeDefinitionId = propertyType.DataTypeDefinitionId;
dataType.Data.PropertyId = propertyId;
return dataType;
+5 -1
View File
@@ -1,4 +1,5 @@
using Umbraco.Core.Persistence;
using System.Collections.Generic;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.DatabaseAnnotations;
namespace Umbraco.Core.Models.Rdbms
@@ -59,5 +60,8 @@ namespace Umbraco.Core.Models.Rdbms
[Column("defaultToLiveEditing")]
[Constraint(Default = "0")]
public bool DefaultToLiveEditing { get; set; }
[ResultColumn]
public List<User2AppDto> User2AppDtos { get; set; }
}
}
+1 -17
View File
@@ -20,7 +20,6 @@ namespace Umbraco.Core.Models
private int _level;
private int _sortOrder;
private int _parentId;
private string _nodePath;
private int _masterTemplateId;
private string _masterTemplateAlias;
@@ -28,7 +27,6 @@ namespace Umbraco.Core.Models
private static readonly PropertyInfo LevelSelector = ExpressionHelper.GetPropertyInfo<Template, int>(x => x.Level);
private static readonly PropertyInfo SortOrderSelector = ExpressionHelper.GetPropertyInfo<Template, int>(x => x.SortOrder);
private static readonly PropertyInfo ParentIdSelector = ExpressionHelper.GetPropertyInfo<Template, int>(x => x.ParentId);
private static readonly PropertyInfo NodePathSelector = ExpressionHelper.GetPropertyInfo<Template, string>(x => x.NodePath);
//private static readonly PropertyInfo MasterTemplateIdSelector = ExpressionHelper.GetPropertyInfo<Template, int>(x => x.MasterTemplateId);
private static readonly PropertyInfo MasterTemplateAliasSelector = ExpressionHelper.GetPropertyInfo<Template, string>(x => x.MasterTemplateAlias);
@@ -104,21 +102,7 @@ namespace Umbraco.Core.Models
}, _parentId, ParentIdSelector);
}
}
[DataMember]
internal string NodePath
{
get { return _nodePath; }
set
{
SetPropertyValueAndDetectChanges(o =>
{
_nodePath = value;
return _nodePath;
}, _nodePath, NodePathSelector);
}
}
[DataMember]
internal Lazy<int> MasterTemplateId { get; set; }
@@ -1,9 +1,11 @@
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Caching;
using System.Threading;
using System.Web;
using Umbraco.Core.Models.EntityBase;
namespace Umbraco.Core.Persistence.Caching
@@ -11,6 +13,23 @@ namespace Umbraco.Core.Persistence.Caching
/// <summary>
/// The Runtime Cache provider looks up objects in the Runtime cache for fast retrival
/// </summary>
/// <remarks>
///
/// If a web session is detected then the HttpRuntime.Cache will be used for the runtime cache, otherwise a custom
/// MemoryCache instance will be used. It is important to use the HttpRuntime.Cache when a web session is detected so
/// that the memory management of cache in IIS can be handled appopriately.
///
/// When a web sessions is detected we will pre-fix all HttpRuntime.Cache entries so that when we clear it we are only
/// clearing items that have been inserted by this provider.
///
/// NOTE: These changes are all temporary until we finalize the ApplicationCache implementation which will support static cache, runtime cache
/// and request based cache which will all live in one central location so it is easily managed.
///
/// Also note that we don't always keep checking if HttpContext.Current == null and instead check for _memoryCache != null. This is because
/// when there are async requests being made even in the context of a web request, the HttpContext.Current will be null but the HttpRuntime.Cache will
/// always be available.
///
/// </remarks>
internal sealed class RuntimeCacheProvider : IRepositoryCacheProvider
{
#region Singleton
@@ -21,19 +40,25 @@ namespace Umbraco.Core.Persistence.Caching
private RuntimeCacheProvider()
{
if (HttpContext.Current == null)
{
_memoryCache = new MemoryCache("in-memory");
}
}
#endregion
//TODO Save this in cache as well, so its not limited to a single server usage
private readonly ConcurrentHashSet<string> _keyTracker = new ConcurrentHashSet<string>();
private ObjectCache _memoryCache = new MemoryCache("in-memory");
private ObjectCache _memoryCache;
private static readonly ReaderWriterLockSlim ClearLock = new ReaderWriterLockSlim();
public IEntity GetById(Type type, Guid id)
{
var key = GetCompositeId(type, id);
var item = _memoryCache.Get(key);
var item = _memoryCache != null
? _memoryCache.Get(key)
: HttpRuntime.Cache.Get(key);
return item as IEntity;
}
@@ -41,7 +66,11 @@ namespace Umbraco.Core.Persistence.Caching
{
foreach (var guid in ids)
{
yield return _memoryCache.Get(GetCompositeId(type, guid)) as IEntity;
var item = _memoryCache != null
? _memoryCache.Get(GetCompositeId(type, guid))
: HttpRuntime.Cache.Get(GetCompositeId(type, guid));
yield return item as IEntity;
}
}
@@ -49,9 +78,13 @@ namespace Umbraco.Core.Persistence.Caching
{
foreach (var key in _keyTracker)
{
if (key.StartsWith(type.Name))
if (key.StartsWith(string.Format("{0}{1}-", CacheItemPrefix, type.Name)))
{
yield return _memoryCache.Get(key) as IEntity;
var item = _memoryCache != null
? _memoryCache.Get(key)
: HttpRuntime.Cache.Get(key);
yield return item as IEntity;
}
}
}
@@ -59,21 +92,34 @@ namespace Umbraco.Core.Persistence.Caching
public void Save(Type type, IEntity entity)
{
var key = GetCompositeId(type, entity.Id);
var exists = _memoryCache.GetCacheItem(key) != null;
_keyTracker.TryAdd(key);
if (exists)
//NOTE: Before we were checking if it already exists but the MemoryCache.Set handles this implicitly and does
// an add or update, same goes for HttpRuntime.Cache.Insert.
if (_memoryCache != null)
{
_memoryCache.Set(key, entity, new CacheItemPolicy { SlidingExpiration = TimeSpan.FromMinutes(5) });
return;
}
_memoryCache.Add(key, entity, new CacheItemPolicy { SlidingExpiration = TimeSpan.FromMinutes(5) });
else
{
HttpRuntime.Cache.Insert(key, entity, null, System.Web.Caching.Cache.NoAbsoluteExpiration, TimeSpan.FromMinutes(5));
}
}
public void Delete(Type type, IEntity entity)
{
var key = GetCompositeId(type, entity.Id);
_memoryCache.Remove(key);
if (_memoryCache != null)
{
_memoryCache.Remove(key);
}
else
{
HttpRuntime.Cache.Remove(key);
}
_keyTracker.Remove(key);
}
@@ -88,14 +134,21 @@ namespace Umbraco.Core.Persistence.Caching
var keys = new string[_keyTracker.Count];
_keyTracker.CopyTo(keys, 0);
var keysToRemove = new List<string>();
foreach (var key in keys.Where(x => x.StartsWith(string.Format("{0}-", type.Name))))
foreach (var key in keys.Where(x => x.StartsWith(string.Format("{0}{1}-", CacheItemPrefix, type.Name))))
{
_keyTracker.Remove(key);
keysToRemove.Add(key);
}
foreach (var key in keysToRemove)
{
_memoryCache.Remove(key);
if (_memoryCache != null)
{
_memoryCache.Remove(key);
}
else
{
HttpRuntime.Cache.Remove(key);
}
}
}
}
@@ -105,19 +158,40 @@ namespace Umbraco.Core.Persistence.Caching
using (new WriteLock(ClearLock))
{
_keyTracker.Clear();
_memoryCache.DisposeIfDisposable();
_memoryCache = new MemoryCache("in-memory");
if (_memoryCache != null)
{
_memoryCache.DisposeIfDisposable();
_memoryCache = new MemoryCache("in-memory");
}
else
{
foreach (DictionaryEntry c in HttpRuntime.Cache)
{
if (c.Key is string && ((string)c.Key).InvariantStartsWith(CacheItemPrefix))
{
if (HttpRuntime.Cache[(string)c.Key] == null) return;
HttpRuntime.Cache.Remove((string)c.Key);
}
}
}
}
}
/// <summary>
/// We prefix all cache keys with this so that we know which ones this class has created when
/// using the HttpRuntime cache so that when we clear it we don't clear other entries we didn't create.
/// </summary>
private const string CacheItemPrefix = "umbrtmche_";
private string GetCompositeId(Type type, Guid id)
{
return string.Format("{0}-{1}", type.Name, id.ToString());
return string.Format("{0}{1}-{2}", CacheItemPrefix, type.Name, id.ToString());
}
private string GetCompositeId(Type type, int id)
{
return string.Format("{0}-{1}", type.Name, id.ToGuid());
return string.Format("{0}{1}-{2}", CacheItemPrefix, type.Name, id.ToGuid());
}
}
}
@@ -37,7 +37,7 @@ namespace Umbraco.Core.Persistence.Factories
Level = dto.NodeDto.Level,
ParentId = dto.NodeDto.ParentId,
SortOrder = dto.NodeDto.SortOrder,
NodePath = dto.NodeDto.Path
Path = dto.NodeDto.Path
};
if(dto.Master.HasValue)
@@ -83,7 +83,7 @@ namespace Umbraco.Core.Persistence.Factories
Level = short.Parse(entity.Level.ToString(CultureInfo.InvariantCulture)),
NodeObjectType = _nodeObjectTypeId,
ParentId = entity.ParentId,
Path = entity.NodePath,
Path = entity.Path,
SortOrder = entity.SortOrder,
Text = entity.Name,
Trashed = false,
@@ -1,4 +1,5 @@
using Umbraco.Core.Models.Membership;
using System.Collections.Generic;
using Umbraco.Core.Models.Membership;
using Umbraco.Core.Models.Rdbms;
namespace Umbraco.Core.Persistence.Factories
@@ -16,8 +17,7 @@ namespace Umbraco.Core.Persistence.Factories
public IUser BuildEntity(UserDto dto)
{
//TODO Add list of applications for user
return new User(_userType)
var user = new User(_userType)
{
Id = dto.Id,
ProfileId = dto.Id,
@@ -32,8 +32,19 @@ namespace Umbraco.Core.Persistence.Factories
Language = dto.UserLanguage,
DefaultToLiveEditing = dto.DefaultToLiveEditing,
NoConsole = dto.NoConsole,
Permissions = dto.DefaultPermissions
DefaultPermissions = dto.DefaultPermissions
};
foreach (var app in dto.User2AppDtos)
{
user.AddAllowedSection(app.AppAlias);
}
//on initial construction we don't want to have dirty properties tracked
// http://issues.umbraco.org/issue/U4-1946
user.ResetDirtyProperties(false);
return user;
}
public UserDto BuildDto(IUser entity)
@@ -51,9 +62,24 @@ namespace Umbraco.Core.Persistence.Factories
UserLanguage = entity.Language,
UserName = entity.Name,
Type = short.Parse(entity.UserType.Id.ToString()),
DefaultPermissions = entity.Permissions
DefaultPermissions = entity.DefaultPermissions,
User2AppDtos = new List<User2AppDto>()
};
foreach (var app in entity.AllowedSections)
{
var appDto = new User2AppDto
{
AppAlias = app
};
if (entity.Id != null)
{
appDto.UserId = (int) entity.Id;
}
dto.User2AppDtos.Add(appDto);
}
if (entity.HasIdentity)
dto.Id = entity.Id.SafeCast<int>();
@@ -1,4 +1,5 @@
using System;
using System.Collections.Concurrent;
using System.Linq.Expressions;
using System.Reflection;
using Umbraco.Core.Persistence.SqlSyntax;
@@ -7,11 +8,24 @@ namespace Umbraco.Core.Persistence.Mappers
{
public abstract class BaseMapper
{
internal abstract ConcurrentDictionary<string, DtoMapModel> PropertyInfoCache { get; }
internal abstract void BuildMap();
internal abstract string Map(string propertyName);
internal string Map(string propertyName)
{
DtoMapModel dtoTypeProperty;
return PropertyInfoCache.TryGetValue(propertyName, out dtoTypeProperty)
? GetColumnName(dtoTypeProperty.Type, dtoTypeProperty.PropertyInfo)
: string.Empty;
}
internal abstract void CacheMap<TSource, TDestination>(Expression<Func<TSource, object>> sourceMember, Expression<Func<TDestination, object>> destinationMember);
internal void CacheMap<TSource, TDestination>(Expression<Func<TSource, object>> sourceMember, Expression<Func<TDestination, object>> destinationMember)
{
var property = ResolveMapping(sourceMember, destinationMember);
PropertyInfoCache.AddOrUpdate(property.SourcePropertyName, property, (x, y) => property);
}
internal DtoMapModel ResolveMapping<TSource, TDestination>(Expression<Func<TSource, object>> sourceMember, Expression<Func<TDestination, object>> destinationMember)
{
@@ -14,7 +14,7 @@ namespace Umbraco.Core.Persistence.Mappers
[MapperFor(typeof(IContent))]
public sealed class ContentMapper : BaseMapper
{
private static readonly ConcurrentDictionary<string, DtoMapModel> PropertyInfoCache = new ConcurrentDictionary<string, DtoMapModel>();
private static readonly ConcurrentDictionary<string, DtoMapModel> PropertyInfoCacheInstance = new ConcurrentDictionary<string, DtoMapModel>();
//NOTE: its an internal class but the ctor must be public since we're using Activator.CreateInstance to create it
// otherwise that would fail because there is no public constructor.
@@ -25,6 +25,11 @@ namespace Umbraco.Core.Persistence.Mappers
#region Overrides of BaseMapper
internal override ConcurrentDictionary<string, DtoMapModel> PropertyInfoCache
{
get { return PropertyInfoCacheInstance; }
}
internal override void BuildMap()
{
if(PropertyInfoCache.IsEmpty)
@@ -52,23 +57,7 @@ namespace Umbraco.Core.Persistence.Mappers
//CacheMap<Content, DocumentDto>(src => src.Template, dto => dto.TemplateId);
}
}
internal override string Map(string propertyName)
{
if (!PropertyInfoCache.ContainsKey(propertyName))
return string.Empty;
var dtoTypeProperty = PropertyInfoCache[propertyName];
return base.GetColumnName(dtoTypeProperty.Type, dtoTypeProperty.PropertyInfo);
}
internal override void CacheMap<TSource, TDestination>(Expression<Func<TSource, object>> sourceMember, Expression<Func<TDestination, object>> destinationMember)
{
var property = base.ResolveMapping(sourceMember, destinationMember);
PropertyInfoCache.AddOrUpdate(property.SourcePropertyName, property, (x, y) => property);
}
#endregion
}
}
@@ -14,7 +14,7 @@ namespace Umbraco.Core.Persistence.Mappers
[MapperFor(typeof(IContentType))]
public sealed class ContentTypeMapper : BaseMapper
{
private static readonly ConcurrentDictionary<string, DtoMapModel> PropertyInfoCache = new ConcurrentDictionary<string, DtoMapModel>();
private static readonly ConcurrentDictionary<string, DtoMapModel> PropertyInfoCacheInstance = new ConcurrentDictionary<string, DtoMapModel>();
//NOTE: its an internal class but the ctor must be public since we're using Activator.CreateInstance to create it
// otherwise that would fail because there is no public constructor.
@@ -25,6 +25,11 @@ namespace Umbraco.Core.Persistence.Mappers
#region Overrides of BaseMapper
internal override ConcurrentDictionary<string, DtoMapModel> PropertyInfoCache
{
get { return PropertyInfoCacheInstance; }
}
internal override void BuildMap()
{
if (PropertyInfoCache.IsEmpty)
@@ -48,22 +53,6 @@ namespace Umbraco.Core.Persistence.Mappers
}
}
internal override string Map(string propertyName)
{
if (!PropertyInfoCache.ContainsKey(propertyName))
return string.Empty;
var dtoTypeProperty = PropertyInfoCache[propertyName];
return base.GetColumnName(dtoTypeProperty.Type, dtoTypeProperty.PropertyInfo);
}
internal override void CacheMap<TSource, TDestination>(Expression<Func<TSource, object>> sourceMember, Expression<Func<TDestination, object>> destinationMember)
{
var property = base.ResolveMapping(sourceMember, destinationMember);
PropertyInfoCache.AddOrUpdate(property.SourcePropertyName, property, (x, y) => property);
}
#endregion
}
}
@@ -14,7 +14,7 @@ namespace Umbraco.Core.Persistence.Mappers
[MapperFor(typeof(IDataTypeDefinition))]
public sealed class DataTypeDefinitionMapper : BaseMapper
{
private static readonly ConcurrentDictionary<string, DtoMapModel> PropertyInfoCache = new ConcurrentDictionary<string, DtoMapModel>();
private static readonly ConcurrentDictionary<string, DtoMapModel> PropertyInfoCacheInstance = new ConcurrentDictionary<string, DtoMapModel>();
//NOTE: its an internal class but the ctor must be public since we're using Activator.CreateInstance to create it
// otherwise that would fail because there is no public constructor.
@@ -25,6 +25,11 @@ namespace Umbraco.Core.Persistence.Mappers
#region Overrides of BaseMapper
internal override ConcurrentDictionary<string, DtoMapModel> PropertyInfoCache
{
get { return PropertyInfoCacheInstance; }
}
internal override void BuildMap()
{
CacheMap<DataTypeDefinition, NodeDto>(src => src.Id, dto => dto.NodeId);
@@ -42,22 +47,6 @@ namespace Umbraco.Core.Persistence.Mappers
}
internal override string Map(string propertyName)
{
if (!PropertyInfoCache.ContainsKey(propertyName))
return string.Empty;
var dtoTypeProperty = PropertyInfoCache[propertyName];
return base.GetColumnName(dtoTypeProperty.Type, dtoTypeProperty.PropertyInfo);
}
internal override void CacheMap<TSource, TDestination>(Expression<Func<TSource, object>> sourceMember, Expression<Func<TDestination, object>> destinationMember)
{
var property = base.ResolveMapping(sourceMember, destinationMember);
PropertyInfoCache.AddOrUpdate(property.SourcePropertyName, property, (x, y) => property);
}
#endregion
}
}
@@ -14,7 +14,7 @@ namespace Umbraco.Core.Persistence.Mappers
[MapperFor(typeof(IDictionaryItem))]
public sealed class DictionaryMapper : BaseMapper
{
private static readonly ConcurrentDictionary<string, DtoMapModel> PropertyInfoCache = new ConcurrentDictionary<string, DtoMapModel>();
private static readonly ConcurrentDictionary<string, DtoMapModel> PropertyInfoCacheInstance = new ConcurrentDictionary<string, DtoMapModel>();
//NOTE: its an internal class but the ctor must be public since we're using Activator.CreateInstance to create it
// otherwise that would fail because there is no public constructor.
@@ -25,6 +25,11 @@ namespace Umbraco.Core.Persistence.Mappers
#region Overrides of BaseMapper
internal override ConcurrentDictionary<string, DtoMapModel> PropertyInfoCache
{
get { return PropertyInfoCacheInstance; }
}
internal override void BuildMap()
{
CacheMap<DictionaryItem, DictionaryDto>(src => src.Id, dto => dto.PrimaryKey);
@@ -32,23 +37,7 @@ namespace Umbraco.Core.Persistence.Mappers
CacheMap<DictionaryItem, DictionaryDto>(src => src.ItemKey, dto => dto.Key);
CacheMap<DictionaryItem, DictionaryDto>(src => src.ParentId, dto => dto.Parent);
}
internal override string Map(string propertyName)
{
if (!PropertyInfoCache.ContainsKey(propertyName))
return string.Empty;
var dtoTypeProperty = PropertyInfoCache[propertyName];
return base.GetColumnName(dtoTypeProperty.Type, dtoTypeProperty.PropertyInfo);
}
internal override void CacheMap<TSource, TDestination>(Expression<Func<TSource, object>> sourceMember, Expression<Func<TDestination, object>> destinationMember)
{
var property = base.ResolveMapping(sourceMember, destinationMember);
PropertyInfoCache.AddOrUpdate(property.SourcePropertyName, property, (x, y) => property);
}
#endregion
}
}
@@ -14,7 +14,7 @@ namespace Umbraco.Core.Persistence.Mappers
[MapperFor(typeof(IDictionaryTranslation))]
public class DictionaryTranslationMapper : BaseMapper
{
private static readonly ConcurrentDictionary<string, DtoMapModel> PropertyInfoCache = new ConcurrentDictionary<string, DtoMapModel>();
private static readonly ConcurrentDictionary<string, DtoMapModel> PropertyInfoCacheInstance = new ConcurrentDictionary<string, DtoMapModel>();
//NOTE: its an internal class but the ctor must be public since we're using Activator.CreateInstance to create it
// otherwise that would fail because there is no public constructor.
@@ -25,6 +25,11 @@ namespace Umbraco.Core.Persistence.Mappers
#region Overrides of BaseMapper
internal override ConcurrentDictionary<string, DtoMapModel> PropertyInfoCache
{
get { return PropertyInfoCacheInstance; }
}
internal override void BuildMap()
{
CacheMap<DictionaryTranslation, LanguageTextDto>(src => src.Id, dto => dto.PrimaryKey);
@@ -33,22 +38,6 @@ namespace Umbraco.Core.Persistence.Mappers
CacheMap<DictionaryTranslation, LanguageTextDto>(src => src.Value, dto => dto.Value);
}
internal override string Map(string propertyName)
{
if (!PropertyInfoCache.ContainsKey(propertyName))
return string.Empty;
var dtoTypeProperty = PropertyInfoCache[propertyName];
return base.GetColumnName(dtoTypeProperty.Type, dtoTypeProperty.PropertyInfo);
}
internal override void CacheMap<TSource, TDestination>(Expression<Func<TSource, object>> sourceMember, Expression<Func<TDestination, object>> destinationMember)
{
var property = base.ResolveMapping(sourceMember, destinationMember);
PropertyInfoCache.AddOrUpdate(property.SourcePropertyName, property, (x, y) => property);
}
#endregion
}
}
@@ -14,7 +14,7 @@ namespace Umbraco.Core.Persistence.Mappers
[MapperFor(typeof(Language))]
public sealed class LanguageMapper : BaseMapper
{
private static readonly ConcurrentDictionary<string, DtoMapModel> PropertyInfoCache = new ConcurrentDictionary<string, DtoMapModel>();
private static readonly ConcurrentDictionary<string, DtoMapModel> PropertyInfoCacheInstance = new ConcurrentDictionary<string, DtoMapModel>();
//NOTE: its an internal class but the ctor must be public since we're using Activator.CreateInstance to create it
// otherwise that would fail because there is no public constructor.
@@ -25,6 +25,11 @@ namespace Umbraco.Core.Persistence.Mappers
#region Overrides of BaseMapper
internal override ConcurrentDictionary<string, DtoMapModel> PropertyInfoCache
{
get { return PropertyInfoCacheInstance; }
}
internal override void BuildMap()
{
CacheMap<Language, LanguageDto>(src => src.Id, dto => dto.Id);
@@ -32,22 +37,6 @@ namespace Umbraco.Core.Persistence.Mappers
CacheMap<Language, LanguageDto>(src => src.CultureName, dto => dto.CultureName);
}
internal override string Map(string propertyName)
{
if (!PropertyInfoCache.ContainsKey(propertyName))
return string.Empty;
var dtoTypeProperty = PropertyInfoCache[propertyName];
return base.GetColumnName(dtoTypeProperty.Type, dtoTypeProperty.PropertyInfo);
}
internal override void CacheMap<TSource, TDestination>(Expression<Func<TSource, object>> sourceMember, Expression<Func<TDestination, object>> destinationMember)
{
var property = base.ResolveMapping(sourceMember, destinationMember);
PropertyInfoCache.AddOrUpdate(property.SourcePropertyName, property, (x, y) => property);
}
#endregion
}
}
@@ -14,7 +14,7 @@ namespace Umbraco.Core.Persistence.Mappers
[MapperFor(typeof(Umbraco.Core.Models.Media))]
public sealed class MediaMapper : BaseMapper
{
private static readonly ConcurrentDictionary<string, DtoMapModel> PropertyInfoCache = new ConcurrentDictionary<string, DtoMapModel>();
private static readonly ConcurrentDictionary<string, DtoMapModel> PropertyInfoCacheInstance = new ConcurrentDictionary<string, DtoMapModel>();
//NOTE: its an internal class but the ctor must be public since we're using Activator.CreateInstance to create it
// otherwise that would fail because there is no public constructor.
@@ -25,6 +25,11 @@ namespace Umbraco.Core.Persistence.Mappers
#region Overrides of BaseMapper
internal override ConcurrentDictionary<string, DtoMapModel> PropertyInfoCache
{
get { return PropertyInfoCacheInstance; }
}
internal override void BuildMap()
{
if (PropertyInfoCache.IsEmpty)
@@ -45,22 +50,6 @@ namespace Umbraco.Core.Persistence.Mappers
}
}
internal override string Map(string propertyName)
{
if (!PropertyInfoCache.ContainsKey(propertyName))
return string.Empty;
var dtoTypeProperty = PropertyInfoCache[propertyName];
return base.GetColumnName(dtoTypeProperty.Type, dtoTypeProperty.PropertyInfo);
}
internal override void CacheMap<TSource, TDestination>(Expression<Func<TSource, object>> sourceMember, Expression<Func<TDestination, object>> destinationMember)
{
var property = base.ResolveMapping(sourceMember, destinationMember);
PropertyInfoCache.AddOrUpdate(property.SourcePropertyName, property, (x, y) => property);
}
#endregion
}
}
@@ -14,7 +14,7 @@ namespace Umbraco.Core.Persistence.Mappers
[MapperFor(typeof(MediaType))]
public sealed class MediaTypeMapper : BaseMapper
{
private static readonly ConcurrentDictionary<string, DtoMapModel> PropertyInfoCache = new ConcurrentDictionary<string, DtoMapModel>();
private static readonly ConcurrentDictionary<string, DtoMapModel> PropertyInfoCacheInstance = new ConcurrentDictionary<string, DtoMapModel>();
//NOTE: its an internal class but the ctor must be public since we're using Activator.CreateInstance to create it
// otherwise that would fail because there is no public constructor.
@@ -25,6 +25,11 @@ namespace Umbraco.Core.Persistence.Mappers
#region Overrides of BaseMapper
internal override ConcurrentDictionary<string, DtoMapModel> PropertyInfoCache
{
get { return PropertyInfoCacheInstance; }
}
internal override void BuildMap()
{
if (PropertyInfoCache.IsEmpty)
@@ -48,22 +53,6 @@ namespace Umbraco.Core.Persistence.Mappers
}
}
internal override string Map(string propertyName)
{
if (!PropertyInfoCache.ContainsKey(propertyName))
return string.Empty;
var dtoTypeProperty = PropertyInfoCache[propertyName];
return base.GetColumnName(dtoTypeProperty.Type, dtoTypeProperty.PropertyInfo);
}
internal override void CacheMap<TSource, TDestination>(Expression<Func<TSource, object>> sourceMember, Expression<Func<TDestination, object>> destinationMember)
{
var property = base.ResolveMapping(sourceMember, destinationMember);
PropertyInfoCache.AddOrUpdate(property.SourcePropertyName, property, (x, y) => property);
}
#endregion
}
}
@@ -13,7 +13,7 @@ namespace Umbraco.Core.Persistence.Mappers
[MapperFor(typeof(PropertyGroup))]
public sealed class PropertyGroupMapper : BaseMapper
{
private static readonly ConcurrentDictionary<string, DtoMapModel> PropertyInfoCache = new ConcurrentDictionary<string, DtoMapModel>();
private static readonly ConcurrentDictionary<string, DtoMapModel> PropertyInfoCacheInstance = new ConcurrentDictionary<string, DtoMapModel>();
//NOTE: its an internal class but the ctor must be public since we're using Activator.CreateInstance to create it
// otherwise that would fail because there is no public constructor.
@@ -24,6 +24,11 @@ namespace Umbraco.Core.Persistence.Mappers
#region Overrides of BaseMapper
internal override ConcurrentDictionary<string, DtoMapModel> PropertyInfoCache
{
get { return PropertyInfoCacheInstance; }
}
internal override void BuildMap()
{
CacheMap<PropertyGroup, PropertyTypeGroupDto>(src => src.Id, dto => dto.Id);
@@ -32,22 +37,6 @@ namespace Umbraco.Core.Persistence.Mappers
CacheMap<PropertyGroup, PropertyTypeGroupDto>(src => src.Name, dto => dto.Text);
}
internal override string Map(string propertyName)
{
if (!PropertyInfoCache.ContainsKey(propertyName))
return string.Empty;
var dtoTypeProperty = PropertyInfoCache[propertyName];
return base.GetColumnName(dtoTypeProperty.Type, dtoTypeProperty.PropertyInfo);
}
internal override void CacheMap<TSource, TDestination>(Expression<Func<TSource, object>> sourceMember, Expression<Func<TDestination, object>> destinationMember)
{
var property = base.ResolveMapping(sourceMember, destinationMember);
PropertyInfoCache.AddOrUpdate(property.SourcePropertyName, property, (x, y) => property);
}
#endregion
}
}
@@ -9,7 +9,7 @@ namespace Umbraco.Core.Persistence.Mappers
[MapperFor(typeof(Property))]
public sealed class PropertyMapper : BaseMapper
{
private static readonly ConcurrentDictionary<string, DtoMapModel> PropertyInfoCache = new ConcurrentDictionary<string, DtoMapModel>();
private static readonly ConcurrentDictionary<string, DtoMapModel> PropertyInfoCacheInstance = new ConcurrentDictionary<string, DtoMapModel>();
//NOTE: its an internal class but the ctor must be public since we're using Activator.CreateInstance to create it
// otherwise that would fail because there is no public constructor.
@@ -20,6 +20,11 @@ namespace Umbraco.Core.Persistence.Mappers
#region Overrides of BaseMapper
internal override ConcurrentDictionary<string, DtoMapModel> PropertyInfoCache
{
get { return PropertyInfoCacheInstance; }
}
internal override void BuildMap()
{
CacheMap<Property, PropertyDataDto>(src => src.Id, dto => dto.Id);
@@ -27,22 +32,6 @@ namespace Umbraco.Core.Persistence.Mappers
CacheMap<Property, PropertyDataDto>(src => src.PropertyTypeId, dto => dto.PropertyTypeId);
}
internal override string Map(string propertyName)
{
if (!PropertyInfoCache.ContainsKey(propertyName))
return string.Empty;
var dtoTypeProperty = PropertyInfoCache[propertyName];
return base.GetColumnName(dtoTypeProperty.Type, dtoTypeProperty.PropertyInfo);
}
internal override void CacheMap<TSource, TDestination>(Expression<Func<TSource, object>> sourceMember, Expression<Func<TDestination, object>> destinationMember)
{
var property = base.ResolveMapping(sourceMember, destinationMember);
PropertyInfoCache.AddOrUpdate(property.SourcePropertyName, property, (x, y) => property);
}
#endregion
}
}
@@ -13,7 +13,7 @@ namespace Umbraco.Core.Persistence.Mappers
[MapperFor(typeof(PropertyType))]
public sealed class PropertyTypeMapper : BaseMapper
{
private static readonly ConcurrentDictionary<string, DtoMapModel> PropertyInfoCache = new ConcurrentDictionary<string, DtoMapModel>();
private static readonly ConcurrentDictionary<string, DtoMapModel> PropertyInfoCacheInstance = new ConcurrentDictionary<string, DtoMapModel>();
//NOTE: its an internal class but the ctor must be public since we're using Activator.CreateInstance to create it
// otherwise that would fail because there is no public constructor.
@@ -24,6 +24,11 @@ namespace Umbraco.Core.Persistence.Mappers
#region Overrides of BaseMapper
internal override ConcurrentDictionary<string, DtoMapModel> PropertyInfoCache
{
get { return PropertyInfoCacheInstance; }
}
internal override void BuildMap()
{
if(PropertyInfoCache.IsEmpty)
@@ -42,22 +47,6 @@ namespace Umbraco.Core.Persistence.Mappers
}
}
internal override string Map(string propertyName)
{
if (!PropertyInfoCache.ContainsKey(propertyName))
return string.Empty;
var dtoTypeProperty = PropertyInfoCache[propertyName];
return base.GetColumnName(dtoTypeProperty.Type, dtoTypeProperty.PropertyInfo);
}
internal override void CacheMap<TSource, TDestination>(Expression<Func<TSource, object>> sourceMember, Expression<Func<TDestination, object>> destinationMember)
{
var property = base.ResolveMapping(sourceMember, destinationMember);
PropertyInfoCache.AddOrUpdate(property.SourcePropertyName, property, (x, y) => property);
}
#endregion
}
}
@@ -13,7 +13,7 @@ namespace Umbraco.Core.Persistence.Mappers
[MapperFor(typeof(Relation))]
public sealed class RelationMapper : BaseMapper
{
private static readonly ConcurrentDictionary<string, DtoMapModel> PropertyInfoCache = new ConcurrentDictionary<string, DtoMapModel>();
private static readonly ConcurrentDictionary<string, DtoMapModel> PropertyInfoCacheInstance = new ConcurrentDictionary<string, DtoMapModel>();
//NOTE: its an internal class but the ctor must be public since we're using Activator.CreateInstance to create it
// otherwise that would fail because there is no public constructor.
@@ -24,6 +24,11 @@ namespace Umbraco.Core.Persistence.Mappers
#region Overrides of BaseMapper
internal override ConcurrentDictionary<string, DtoMapModel> PropertyInfoCache
{
get { return PropertyInfoCacheInstance; }
}
internal override void BuildMap()
{
CacheMap<Relation, RelationDto>(src => src.Id, dto => dto.Id);
@@ -33,23 +38,7 @@ namespace Umbraco.Core.Persistence.Mappers
CacheMap<Relation, RelationDto>(src => src.ParentId, dto => dto.ParentId);
CacheMap<Relation, RelationDto>(src => src.RelationTypeId, dto => dto.RelationType);
}
internal override string Map(string propertyName)
{
if (!PropertyInfoCache.ContainsKey(propertyName))
return string.Empty;
var dtoTypeProperty = PropertyInfoCache[propertyName];
return base.GetColumnName(dtoTypeProperty.Type, dtoTypeProperty.PropertyInfo);
}
internal override void CacheMap<TSource, TDestination>(Expression<Func<TSource, object>> sourceMember, Expression<Func<TDestination, object>> destinationMember)
{
var property = base.ResolveMapping(sourceMember, destinationMember);
PropertyInfoCache.AddOrUpdate(property.SourcePropertyName, property, (x, y) => property);
}
#endregion
}
}
@@ -13,7 +13,7 @@ namespace Umbraco.Core.Persistence.Mappers
[MapperFor(typeof(RelationType))]
public sealed class RelationTypeMapper : BaseMapper
{
private static readonly ConcurrentDictionary<string, DtoMapModel> PropertyInfoCache = new ConcurrentDictionary<string, DtoMapModel>();
private static readonly ConcurrentDictionary<string, DtoMapModel> PropertyInfoCacheInstance = new ConcurrentDictionary<string, DtoMapModel>();
//NOTE: its an internal class but the ctor must be public since we're using Activator.CreateInstance to create it
// otherwise that would fail because there is no public constructor.
@@ -24,6 +24,11 @@ namespace Umbraco.Core.Persistence.Mappers
#region Overrides of BaseMapper
internal override ConcurrentDictionary<string, DtoMapModel> PropertyInfoCache
{
get { return PropertyInfoCacheInstance; }
}
internal override void BuildMap()
{
CacheMap<RelationType, RelationTypeDto>(src => src.Id, dto => dto.Id);
@@ -33,23 +38,7 @@ namespace Umbraco.Core.Persistence.Mappers
CacheMap<RelationType, RelationTypeDto>(src => src.Name, dto => dto.Name);
CacheMap<RelationType, RelationTypeDto>(src => src.ParentObjectType, dto => dto.ParentObjectType);
}
internal override string Map(string propertyName)
{
if (!PropertyInfoCache.ContainsKey(propertyName))
return string.Empty;
var dtoTypeProperty = PropertyInfoCache[propertyName];
return base.GetColumnName(dtoTypeProperty.Type, dtoTypeProperty.PropertyInfo);
}
internal override void CacheMap<TSource, TDestination>(Expression<Func<TSource, object>> sourceMember, Expression<Func<TDestination, object>> destinationMember)
{
var property = base.ResolveMapping(sourceMember, destinationMember);
PropertyInfoCache.AddOrUpdate(property.SourcePropertyName, property, (x, y) => property);
}
#endregion
}
}
@@ -9,7 +9,7 @@ namespace Umbraco.Core.Persistence.Mappers
[MapperFor(typeof(ServerRegistration))]
public sealed class ServerRegistrationMapper : BaseMapper
{
private static readonly ConcurrentDictionary<string, DtoMapModel> PropertyInfoCache = new ConcurrentDictionary<string, DtoMapModel>();
private static readonly ConcurrentDictionary<string, DtoMapModel> PropertyInfoCacheInstance = new ConcurrentDictionary<string, DtoMapModel>();
//NOTE: its an internal class but the ctor must be public since we're using Activator.CreateInstance to create it
// otherwise that would fail because there is no public constructor.
@@ -20,6 +20,11 @@ namespace Umbraco.Core.Persistence.Mappers
#region Overrides of BaseMapper
internal override ConcurrentDictionary<string, DtoMapModel> PropertyInfoCache
{
get { return PropertyInfoCacheInstance; }
}
internal override void BuildMap()
{
CacheMap<ServerRegistration, ServerRegistrationDto>(src => src.Id, dto => dto.Id);
@@ -30,22 +35,6 @@ namespace Umbraco.Core.Persistence.Mappers
CacheMap<ServerRegistration, ServerRegistrationDto>(src => src.ComputerName, dto => dto.ComputerName);
}
internal override string Map(string propertyName)
{
if (!PropertyInfoCache.ContainsKey(propertyName))
return string.Empty;
var dtoTypeProperty = PropertyInfoCache[propertyName];
return base.GetColumnName(dtoTypeProperty.Type, dtoTypeProperty.PropertyInfo);
}
internal override void CacheMap<TSource, TDestination>(Expression<Func<TSource, object>> sourceMember, Expression<Func<TDestination, object>> destinationMember)
{
var property = base.ResolveMapping(sourceMember, destinationMember);
PropertyInfoCache.AddOrUpdate(property.SourcePropertyName, property, (x, y) => property);
}
#endregion
}
}
@@ -9,8 +9,7 @@ namespace Umbraco.Core.Persistence.Mappers
[MapperFor(typeof (IUmbracoEntity))]
public sealed class UmbracoEntityMapper : BaseMapper
{
private static readonly ConcurrentDictionary<string, DtoMapModel> PropertyInfoCache =
new ConcurrentDictionary<string, DtoMapModel>();
private static readonly ConcurrentDictionary<string, DtoMapModel> PropertyInfoCacheInstance = new ConcurrentDictionary<string, DtoMapModel>();
//NOTE: its an internal class but the ctor must be public since we're using Activator.CreateInstance to create it
// otherwise that would fail because there is no public constructor.
@@ -21,6 +20,11 @@ namespace Umbraco.Core.Persistence.Mappers
#region Overrides of BaseMapper
internal override ConcurrentDictionary<string, DtoMapModel> PropertyInfoCache
{
get { return PropertyInfoCacheInstance; }
}
internal override void BuildMap()
{
CacheMap<IUmbracoEntity, NodeDto>(src => src.Id, dto => dto.NodeId);
@@ -34,24 +38,7 @@ namespace Umbraco.Core.Persistence.Mappers
CacheMap<IUmbracoEntity, NodeDto>(src => src.Key, dto => dto.UniqueId);
CacheMap<IUmbracoEntity, NodeDto>(src => src.CreatorId, dto => dto.UserId);
}
internal override string Map(string propertyName)
{
if (!PropertyInfoCache.ContainsKey(propertyName))
return string.Empty;
var dtoTypeProperty = PropertyInfoCache[propertyName];
return base.GetColumnName(dtoTypeProperty.Type, dtoTypeProperty.PropertyInfo);
}
internal override void CacheMap<TSource, TDestination>(Expression<Func<TSource, object>> sourceMember,
Expression<Func<TDestination, object>> destinationMember)
{
var property = base.ResolveMapping(sourceMember, destinationMember);
PropertyInfoCache.AddOrUpdate(property.SourcePropertyName, property, (x, y) => property);
}
#endregion
}
}
@@ -10,7 +10,7 @@ namespace Umbraco.Core.Persistence.Mappers
[MapperFor(typeof(User))]
public sealed class UserMapper : BaseMapper
{
private static readonly ConcurrentDictionary<string, DtoMapModel> PropertyInfoCache = new ConcurrentDictionary<string, DtoMapModel>();
private static readonly ConcurrentDictionary<string, DtoMapModel> PropertyInfoCacheInstance = new ConcurrentDictionary<string, DtoMapModel>();
//NOTE: its an internal class but the ctor must be public since we're using Activator.CreateInstance to create it
// otherwise that would fail because there is no public constructor.
@@ -21,6 +21,11 @@ namespace Umbraco.Core.Persistence.Mappers
#region Overrides of BaseMapper
internal override ConcurrentDictionary<string, DtoMapModel> PropertyInfoCache
{
get { return PropertyInfoCacheInstance; }
}
internal override void BuildMap()
{
CacheMap<User, UserDto>(src => src.Id, dto => dto.Id);
@@ -28,7 +33,7 @@ namespace Umbraco.Core.Persistence.Mappers
CacheMap<User, UserDto>(src => src.Username, dto => dto.Login);
CacheMap<User, UserDto>(src => src.Password, dto => dto.Password);
CacheMap<User, UserDto>(src => src.Name, dto => dto.UserName);
CacheMap<User, UserDto>(src => src.Permissions, dto => dto.DefaultPermissions);
CacheMap<User, UserDto>(src => src.DefaultPermissions, dto => dto.DefaultPermissions);
CacheMap<User, UserDto>(src => src.StartMediaId, dto => dto.MediaStartId);
CacheMap<User, UserDto>(src => src.StartContentId, dto => dto.ContentStartId);
CacheMap<User, UserDto>(src => src.DefaultToLiveEditing, dto => dto.DefaultToLiveEditing);
@@ -38,22 +43,6 @@ namespace Umbraco.Core.Persistence.Mappers
CacheMap<User, UserDto>(src => src.Language, dto => dto.UserLanguage);
}
internal override string Map(string propertyName)
{
if (!PropertyInfoCache.ContainsKey(propertyName))
return string.Empty;
var dtoTypeProperty = PropertyInfoCache[propertyName];
return base.GetColumnName(dtoTypeProperty.Type, dtoTypeProperty.PropertyInfo);
}
internal override void CacheMap<TSource, TDestination>(Expression<Func<TSource, object>> sourceMember, Expression<Func<TDestination, object>> destinationMember)
{
var property = base.ResolveMapping(sourceMember, destinationMember);
PropertyInfoCache.AddOrUpdate(property.SourcePropertyName, property, (x, y) => property);
}
#endregion
}
}
@@ -14,7 +14,7 @@ namespace Umbraco.Core.Persistence.Mappers
[MapperFor(typeof(UserType))]
public sealed class UserTypeMapper : BaseMapper
{
private static readonly ConcurrentDictionary<string, DtoMapModel> PropertyInfoCache = new ConcurrentDictionary<string, DtoMapModel>();
private static readonly ConcurrentDictionary<string, DtoMapModel> PropertyInfoCacheInstance = new ConcurrentDictionary<string, DtoMapModel>();
//NOTE: its an internal class but the ctor must be public since we're using Activator.CreateInstance to create it
// otherwise that would fail because there is no public constructor.
@@ -25,6 +25,11 @@ namespace Umbraco.Core.Persistence.Mappers
#region Overrides of BaseMapper
internal override ConcurrentDictionary<string, DtoMapModel> PropertyInfoCache
{
get { return PropertyInfoCacheInstance; }
}
internal override void BuildMap()
{
CacheMap<UserType, UserTypeDto>(src => src.Id, dto => dto.Id);
@@ -33,21 +38,6 @@ namespace Umbraco.Core.Persistence.Mappers
CacheMap<UserType, UserTypeDto>(src => src.Permissions, dto => dto.DefaultPermissions);
}
internal override string Map(string propertyName)
{
if (!PropertyInfoCache.ContainsKey(propertyName))
return string.Empty;
var dtoTypeProperty = PropertyInfoCache[propertyName];
return base.GetColumnName(dtoTypeProperty.Type, dtoTypeProperty.PropertyInfo);
}
internal override void CacheMap<TSource, TDestination>(Expression<Func<TSource, object>> sourceMember, Expression<Func<TDestination, object>> destinationMember)
{
var property = base.ResolveMapping(sourceMember, destinationMember);
PropertyInfoCache.AddOrUpdate(property.SourcePropertyName, property, (x, y) => property);
}
#endregion
}
+1 -1
View File
@@ -384,7 +384,7 @@ namespace Umbraco.Core.Persistence
}
// Add a parameter to a DB command
void AddParam(IDbCommand cmd, object item, string ParameterPrefix)
internal void AddParam(IDbCommand cmd, object item, string ParameterPrefix)
{
// Convert value to from poco type to db type
if (Database.Mapper != null && item!=null)
@@ -1,4 +1,6 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using Umbraco.Core.Logging;
using Umbraco.Core.Models.Rdbms;
@@ -28,6 +30,80 @@ namespace Umbraco.Core.Persistence
CreateTable(db, overwrite, tableType);
}
public static void BulkInsertRecords<T>(this Database db, IEnumerable<T> collection)
{
using (var tr = db.GetTransaction())
{
try
{
if (SqlSyntaxContext.SqlSyntaxProvider is SqlCeSyntaxProvider)
{
//SqlCe doesn't support bulk insert statements!
foreach (var poco in collection)
{
db.Insert(poco);
}
}
else
{
string sql;
using (var cmd = db.GenerateBulkInsertCommand(collection, db.Connection, out sql))
{
cmd.CommandText = sql;
cmd.ExecuteNonQuery();
}
}
tr.Complete();
}
catch
{
tr.Dispose();
throw;
}
}
}
internal static IDbCommand GenerateBulkInsertCommand<T>(this Database db, IEnumerable<T> collection, IDbConnection connection, out string sql)
{
var pd = Database.PocoData.ForType(typeof(T));
var tableName = db.EscapeTableName(pd.TableInfo.TableName);
//get all columns but not the primary key if it is auto-incremental
var cols = string.Join(", ", (
from c in pd.Columns
where
//don't return ResultColumns
!c.Value.ResultColumn
//if the table is auto-incremental, don't return the primary key
&& (pd.TableInfo.AutoIncrement && c.Key != pd.TableInfo.PrimaryKey)
select tableName + "." + db.EscapeSqlIdentifier(c.Key))
.ToArray());
var cmd = db.CreateCommand(connection, "");
var pocoValues = new List<string>();
var index = 0;
foreach (var poco in collection)
{
var values = new List<string>();
foreach (var i in pd.Columns)
{
if (pd.TableInfo.AutoIncrement && i.Key == pd.TableInfo.PrimaryKey)
{
continue;
}
values.Add(string.Format("{0}{1}", "@", index++));
db.AddParam(cmd, i.Value.GetValue(poco), "@");
}
pocoValues.Add("(" + string.Join(",", values.ToArray()) + ")");
}
sql = string.Format("INSERT INTO {0} ({1}) VALUES {2}", tableName, cols, string.Join(", ", pocoValues));
return cmd;
}
public static void CreateTable(this Database db, bool overwrite, Type modelType)
{
var tableDefinition = DefinitionFactory.GetTableDefinition(modelType);
@@ -67,7 +143,7 @@ namespace Umbraco.Core.Persistence
//Turn on identity insert if db provider is not mysql
if (SqlSyntaxContext.SqlSyntaxProvider.SupportsIdentityInsert() && tableDefinition.Columns.Any(x => x.IsIdentity))
db.Execute(new Sql(string.Format("SET IDENTITY_INSERT {0} ON ", SqlSyntaxContext.SqlSyntaxProvider.GetQuotedTableName(tableName))));
//Call the NewTable-event to trigger the insert of base/default data
NewTable(tableName, db, e);
@@ -106,7 +182,7 @@ namespace Umbraco.Core.Persistence
public static void DropTable<T>(this Database db)
where T : new()
{
Type type = typeof (T);
Type type = typeof(T);
var tableNameAttribute = type.FirstAttribute<TableNameAttribute>();
if (tableNameAttribute == null)
throw new Exception(
@@ -184,5 +260,5 @@ namespace Umbraco.Core.Persistence
}
}
internal class TableCreationEventArgs : System.ComponentModel.CancelEventArgs{}
internal class TableCreationEventArgs : System.ComponentModel.CancelEventArgs { }
}
@@ -455,8 +455,11 @@ namespace Umbraco.Core.Persistence.Querying
if (fieldType == typeof(decimal))
return ((decimal)value).ToString(CultureInfo.InvariantCulture);
if (fieldType == typeof(DateTime))
return "'" + EscapeParam(((DateTime)value).ToString(CultureInfo.InvariantCulture)) + "'";
if (fieldType == typeof (DateTime))
{
return "'" + EscapeParam(((DateTime)value).ToIsoString()) + "'";
}
if (fieldType == typeof(bool))
return ((bool)value) ? Convert.ToString(1, CultureInfo.InvariantCulture) : Convert.ToString(0, CultureInfo.InvariantCulture);
@@ -465,8 +465,11 @@ namespace Umbraco.Core.Persistence.Querying
if (fieldType == typeof(decimal))
return ((decimal)value).ToString(CultureInfo.InvariantCulture);
if(fieldType == typeof(DateTime))
return "'" + EscapeParam(((DateTime)value).ToString(CultureInfo.InvariantCulture)) + "'";
if (fieldType == typeof (DateTime))
{
return "'" + EscapeParam(((DateTime)value).ToIsoString()) + "'";
}
if (fieldType == typeof(bool))
return ((bool)value) ? Convert.ToString(1, CultureInfo.InvariantCulture) : Convert.ToString(0, CultureInfo.InvariantCulture);
@@ -0,0 +1,47 @@
using System.Collections.Generic;
using Umbraco.Core.Models.Rdbms;
namespace Umbraco.Core.Persistence.Relators
{
internal class UserSectionRelator
{
internal UserDto Current;
internal UserDto Map(UserDto a, User2AppDto p)
{
// Terminating call. Since we can return null from this function
// we need to be ready for PetaPoco to callback later with null
// parameters
if (a == null)
return Current;
// Is this the same DictionaryItem as the current one we're processing
if (Current != null && Current.Id == a.Id)
{
// Yes, just add this User2AppDto to the current item's collection
Current.User2AppDtos.Add(p);
// Return null to indicate we're not done with this User yet
return null;
}
// This is a different User to the current one, or this is the
// first time through and we don't have one yet
// Save the current User
var prev = Current;
// Setup the new current User
Current = a;
Current.User2AppDtos = new List<User2AppDto>();
//this can be null since we are doing a left join
if (p.AppAlias != null)
{
Current.User2AppDtos.Add(p);
}
// Return the now populated previous User (or null if first time through)
return prev;
}
}
}
@@ -206,7 +206,7 @@ namespace Umbraco.Core.Persistence.Repositories
nodeDto.Level = short.Parse(level.ToString(CultureInfo.InvariantCulture));
nodeDto.SortOrder = sortOrder;
var o = Database.IsNew(nodeDto) ? Convert.ToInt32(Database.Insert(nodeDto)) : Database.Update(nodeDto);
//Update with new correct path
nodeDto.Path = string.Concat(parent.Path, ",", nodeDto.NodeId);
Database.Update(nodeDto);
@@ -217,6 +217,24 @@ namespace Umbraco.Core.Persistence.Repositories
entity.SortOrder = sortOrder;
entity.Level = level;
//Assign the same permissions to it as the parent node
// http://issues.umbraco.org/issue/U4-2161
var parentPermissions = GetPermissionsForEntity(entity.ParentId).ToArray();
//if there are parent permissions then assign them, otherwise leave null and permissions will become the
// user's default permissions.
if (parentPermissions.Any())
{
var userPermissions = parentPermissions.Select(
permissionDto => new KeyValuePair<object, string>(
permissionDto.UserId,
permissionDto.Permission));
AssignEntityPermissions(entity, userPermissions);
//flag the entity's permissions changed flag so we can track those changes.
//Currently only used for the cache refreshers to detect if we should refresh all user permissions cache.
((Content) entity).PermissionsChanged = true;
}
//Create the Content specific data - cmsContent
var contentDto = dto.ContentVersionDto.ContentDto;
contentDto.NodeId = nodeDto.NodeId;
@@ -283,6 +301,10 @@ namespace Umbraco.Core.Persistence.Repositories
"SELECT coalesce(max(sortOrder),0) FROM umbracoNode WHERE parentid = @ParentId AND nodeObjectType = @NodeObjectType",
new {ParentId = entity.ParentId, NodeObjectType = NodeObjectTypeId});
entity.SortOrder = maxSortOrder + 1;
//Question: If we move a node, should we update permissions to inherit from the new parent if the parent has permissions assigned?
// if we do that, then we'd need to propogate permissions all the way downward which might not be ideal for many people.
// Gonna just leave it as is for now, and not re-propogate permissions.
}
var factory = new ContentFactory(NodeObjectTypeId, entity.Id);
@@ -510,7 +532,7 @@ namespace Umbraco.Core.Persistence.Repositories
var sql = new Sql();
sql.Select("*")
.From<NodeDto>()
.Where<NodeDto>(x => x.ParentId == parentId && x.Text.StartsWith(nodeName));
.Where<NodeDto>(x => x.NodeObjectType == NodeObjectTypeId && x.ParentId == parentId && x.Text.StartsWith(nodeName));
int uniqueNumber = 1;
var currentName = nodeName;
@@ -533,45 +555,5 @@ namespace Umbraco.Core.Persistence.Repositories
return currentName;
}
/// <summary>
/// Comparer that takes into account the duplicate index of a node name
/// This is needed as a normal alphabetic sort would go Page (1), Page (10), Page (2) etc.
/// </summary>
private class SimilarNodeNameComparer : IComparer<string>
{
public int Compare(string x, string y)
{
if (x.LastIndexOf(')') == x.Length - 1 && y.LastIndexOf(')') == y.Length - 1)
{
if (x.ToLower().Substring(0, x.LastIndexOf('(')) == y.ToLower().Substring(0, y.LastIndexOf('(')))
{
int xDuplicateIndex = ExtractDuplicateIndex(x);
int yDuplicateIndex = ExtractDuplicateIndex(y);
if (xDuplicateIndex != 0 && yDuplicateIndex != 0)
{
return xDuplicateIndex.CompareTo(yDuplicateIndex);
}
}
}
return String.Compare(x.ToLower(), y.ToLower(), StringComparison.Ordinal);
}
private int ExtractDuplicateIndex(string text)
{
int index = 0;
if (text.LastIndexOf('(') != -1 && text.LastIndexOf('(') < text.Length - 2)
{
int startPos = text.LastIndexOf('(') + 1;
int length = text.Length - 1 - startPos;
int.TryParse(text.Substring(startPos, length), out index);
}
return index;
}
}
}
}
@@ -9,8 +9,7 @@ namespace Umbraco.Core.Persistence.Repositories
/// </summary>
/// <typeparam name="TEntity">Type of <see cref="IAggregateRoot"/> entity for which the repository is used</typeparam>
/// <typeparam name="TId">Type of the Id used for this entity</typeparam>
public interface IRepositoryQueryable<TId, TEntity> : IRepository<TId, TEntity>
where TEntity : IAggregateRoot
public interface IRepositoryQueryable<in TId, TEntity> : IRepository<TId, TEntity>
{
/// <summary>
/// Gets all entities of the specified type and query
@@ -1,9 +1,18 @@
using Umbraco.Core.Models.Membership;
using System.Collections.Generic;
using Umbraco.Core.Models.Membership;
namespace Umbraco.Core.Persistence.Repositories
{
internal interface IUserRepository : IRepositoryQueryable<int, IUser>
{
IProfile GetProfileById(int id);
//IProfile GetProfileById(int id);
//IProfile GetProfileByUserName(string username);
//IUser GetUserByUserName(string username);
/// <summary>
/// This is useful when an entire section is removed from config
/// </summary>
/// <param name="sectionAlias"></param>
IEnumerable<IUser> GetUsersAssignedToSection(string sectionAlias);
}
}
@@ -25,14 +25,20 @@ namespace Umbraco.Core.Persistence.Repositories
: base(work)
{
_mediaTypeRepository = mediaTypeRepository;
EnsureUniqueNaming = true;
}
public MediaRepository(IDatabaseUnitOfWork work, IRepositoryCacheProvider cache, IMediaTypeRepository mediaTypeRepository)
: base(work, cache)
{
_mediaTypeRepository = mediaTypeRepository;
EnsureUniqueNaming = true;
}
public bool EnsureUniqueNaming { get; set; }
#region Overrides of RepositoryBase<int,IMedia>
protected override IMedia PerformGet(int id)
@@ -182,6 +188,9 @@ namespace Umbraco.Core.Persistence.Repositories
{
((Models.Media)entity).AddingEntity();
//Ensure unique name on the same level
entity.Name = EnsureUniqueNodeName(entity.ParentId, entity.Name);
var factory = new MediaFactory(NodeObjectTypeId, entity.Id);
var dto = factory.BuildDto(entity);
@@ -246,6 +255,9 @@ namespace Umbraco.Core.Persistence.Repositories
//Updates Modified date
((Models.Media)entity).UpdatingEntity();
//Ensure unique name on the same level
entity.Name = EnsureUniqueNodeName(entity.ParentId, entity.Name, entity.Id);
//Look up parent to get and set the correct Path and update SortOrder if ParentId has changed
if (((ICanBeDirty)entity).IsPropertyDirty("ParentId"))
{
@@ -370,5 +382,37 @@ namespace Umbraco.Core.Persistence.Repositories
return new PropertyCollection(properties);
}
private string EnsureUniqueNodeName(int parentId, string nodeName, int id = 0)
{
if (EnsureUniqueNaming == false)
return nodeName;
var sql = new Sql();
sql.Select("*")
.From<NodeDto>()
.Where<NodeDto>(x => x.NodeObjectType == NodeObjectTypeId && x.ParentId == parentId && x.Text.StartsWith(nodeName));
int uniqueNumber = 1;
var currentName = nodeName;
var dtos = Database.Fetch<NodeDto>(sql);
if (dtos.Any())
{
var results = dtos.OrderBy(x => x.Text, new SimilarNodeNameComparer());
foreach (var dto in results)
{
if (id != 0 && id == dto.NodeId) continue;
if (dto.Text.ToLowerInvariant().Equals(currentName.ToLowerInvariant()))
{
currentName = nodeName + string.Format(" ({0})", uniqueNumber);
uniqueNumber++;
}
}
}
return currentName;
}
}
}
@@ -0,0 +1,154 @@
using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
using System.Text;
using Umbraco.Core.Models;
using Umbraco.Core.Models.EntityBase;
using Umbraco.Core.Models.Membership;
using Umbraco.Core.Models.Rdbms;
using Umbraco.Core.Persistence.Caching;
using Umbraco.Core.Persistence.SqlSyntax;
using Umbraco.Core.Persistence.UnitOfWork;
namespace Umbraco.Core.Persistence.Repositories
{
/// <summary>
/// A repository that exposes functionality to modify assigned permissions to a node
/// </summary>
/// <typeparam name="TId"></typeparam>
/// <typeparam name="TEntity"></typeparam>
internal abstract class PermissionRepository<TId, TEntity> : PetaPocoRepositoryBase<TId, TEntity>
where TEntity : class, IAggregateRoot
{
protected PermissionRepository(IDatabaseUnitOfWork work)
: base(work)
{
}
protected PermissionRepository(IDatabaseUnitOfWork work, IRepositoryCacheProvider cache)
: base(work, cache)
{
}
protected internal IEnumerable<User2NodePermissionDto> GetPermissionsForEntity(int entityId)
{
var sql = new Sql();
sql.Select("*")
.From<User2NodePermissionDto>()
.Where<User2NodePermissionDto>(dto => dto.NodeId == entityId);
return Database.Fetch<User2NodePermissionDto>(sql);
}
/// <summary>
/// Assigns permissions to an entity for multiple users
/// </summary>
/// <param name="entity"></param>
/// <param name="permissions"></param>
/// <param name="userIds"></param>
protected internal void AssignEntityPermissions(TEntity entity, string permissions, IEnumerable<object> userIds)
{
var actions = userIds.Select(id => new User2NodePermissionDto
{
NodeId = entity.Id,
Permission = permissions,
UserId = (int)id
});
Database.BulkInsertRecords(actions);
}
/// <summary>
/// Assigns permissions to an entity for multiple users/permission entries
/// </summary>
/// <param name="entity"></param>
/// <param name="userPermissions">
/// A key/value pair list containing a userId and a permission to assign
/// </param>
protected internal void AssignEntityPermissions(TEntity entity, IEnumerable<KeyValuePair<object, string>> userPermissions)
{
var actions = userPermissions.Select(p => new User2NodePermissionDto
{
NodeId = entity.Id,
Permission = p.Value,
UserId = (int)p.Key
});
Database.BulkInsertRecords(actions);
}
/// <summary>
/// Replace permissions for an entity for multiple users
/// </summary>
/// <param name="entity"></param>
/// <param name="permissions"></param>
/// <param name="userIds"></param>
protected internal void ReplaceEntityPermissions(TEntity entity, string permissions, IEnumerable<object> userIds)
{
Database.Update<User2NodePermissionDto>(
GenerateReplaceEntityPermissionsSql(entity.Id, permissions, userIds.ToArray()));
}
/// <summary>
/// An overload to replace entity permissions and all replace all descendant permissions
/// </summary>
/// <param name="entity"></param>
/// <param name="permissions"></param>
/// <param name="getDescendantIds">
/// A callback to get the descendant Ids of the current entity
/// </param>
/// <param name="userIds"></param>
protected internal void ReplaceEntityPermissions(TEntity entity, string permissions, Func<IEntity, IEnumerable<int>> getDescendantIds, IEnumerable<object> userIds)
{
Database.Update<User2NodePermissionDto>(
GenerateReplaceEntityPermissionsSql(
new[] {entity.Id}.Concat(getDescendantIds(entity)).ToArray(),
permissions,
userIds.ToArray()));
}
internal static string GenerateReplaceEntityPermissionsSql(int entityId, string permissions, object[] userIds)
{
return GenerateReplaceEntityPermissionsSql(new[] {entityId}, permissions, userIds);
}
internal static string GenerateReplaceEntityPermissionsSql(int[] entityIds, string permissions, object[] userIds)
{
//create the "SET" clause of the update statement
var sqlSet = string.Format("SET {0}={1}",
SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName("permission"),
SqlSyntaxContext.SqlSyntaxProvider.GetQuotedValue(permissions));
//build the nodeIds part of the where clause
var sqlNodeWhere = BuildOrClause(entityIds, "nodeId");
//build up the userIds part of the where clause
var userWhereBuilder = BuildOrClause(userIds, "userId");
var sqlWhere = new Sql();
sqlWhere.Where(string.Format("{0} AND {1}", sqlNodeWhere, userWhereBuilder));
return string.Format("{0} {1}", sqlSet, sqlWhere.SQL);
}
private static string BuildOrClause<T>(IEnumerable<T> ids, string colName)
{
var asArray = ids.ToArray();
var userWhereBuilder = new StringBuilder();
userWhereBuilder.Append("(");
for (var index = 0; index < asArray.Length; index++)
{
var userId = asArray[index];
userWhereBuilder.Append(SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName(colName));
userWhereBuilder.Append("=");
userWhereBuilder.Append(userId);
if (index < asArray.Length - 1)
{
userWhereBuilder.Append(" OR ");
}
}
userWhereBuilder.Append(")");
return userWhereBuilder.ToString();
}
}
}
@@ -102,7 +102,7 @@ namespace Umbraco.Core.Persistence.Repositories
{
//on initial construction we don't want to have dirty properties tracked
// http://issues.umbraco.org/issue/U4-1946
Entity asEntity = entity as Entity;
TracksChangesEntityBase asEntity = entity as TracksChangesEntityBase;
if (asEntity != null)
{
asEntity.ResetDirtyProperties(false);
@@ -0,0 +1,45 @@
using System;
using System.Collections.Generic;
namespace Umbraco.Core.Persistence.Repositories
{
/// <summary>
/// Comparer that takes into account the duplicate index of a node name
/// This is needed as a normal alphabetic sort would go Page (1), Page (10), Page (2) etc.
/// </summary>
internal class SimilarNodeNameComparer : IComparer<string>
{
public int Compare(string x, string y)
{
if (x.LastIndexOf(')') == x.Length - 1 && y.LastIndexOf(')') == y.Length - 1)
{
if (x.ToLower().Substring(0, x.LastIndexOf('(')) == y.ToLower().Substring(0, y.LastIndexOf('(')))
{
int xDuplicateIndex = ExtractDuplicateIndex(x);
int yDuplicateIndex = ExtractDuplicateIndex(y);
if (xDuplicateIndex != 0 && yDuplicateIndex != 0)
{
return xDuplicateIndex.CompareTo(yDuplicateIndex);
}
}
}
return String.Compare(x.ToLower(), y.ToLower(), StringComparison.Ordinal);
}
private int ExtractDuplicateIndex(string text)
{
int index = 0;
if (text.LastIndexOf('(') != -1 && text.LastIndexOf('(') < text.Length - 2)
{
int startPos = text.LastIndexOf('(') + 1;
int length = text.Length - 1 - startPos;
int.TryParse(text.Substring(startPos, length), out index);
}
return index;
}
}
}
@@ -1,11 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Umbraco.Core.Models;
using Umbraco.Core.Models.EntityBase;
using Umbraco.Core.Models.Membership;
using Umbraco.Core.Models.Rdbms;
using Umbraco.Core.Persistence.Caching;
using Umbraco.Core.Persistence.Factories;
using Umbraco.Core.Persistence.Querying;
using Umbraco.Core.Persistence.Relators;
using Umbraco.Core.Persistence.SqlSyntax;
using Umbraco.Core.Persistence.UnitOfWork;
namespace Umbraco.Core.Persistence.Repositories
@@ -13,17 +17,17 @@ namespace Umbraco.Core.Persistence.Repositories
/// <summary>
/// Represents the UserRepository for doing CRUD operations for <see cref="IUser"/>
/// </summary>
internal class UserRepository : PetaPocoRepositoryBase<int, IUser>, IUserRepository
internal class UserRepository : PermissionRepository<int, IUser>, IUserRepository
{
private readonly IUserTypeRepository _userTypeRepository;
public UserRepository(IDatabaseUnitOfWork work, IUserTypeRepository userTypeRepository)
public UserRepository(IDatabaseUnitOfWork work, IUserTypeRepository userTypeRepository)
: base(work)
{
_userTypeRepository = userTypeRepository;
}
public UserRepository(IDatabaseUnitOfWork work, IRepositoryCacheProvider cache, IUserTypeRepository userTypeRepository)
public UserRepository(IDatabaseUnitOfWork work, IRepositoryCacheProvider cache, IUserTypeRepository userTypeRepository)
: base(work, cache)
{
_userTypeRepository = userTypeRepository;
@@ -36,7 +40,7 @@ namespace Umbraco.Core.Persistence.Repositories
var sql = GetBaseQuery(false);
sql.Where(GetBaseWhereClause(), new { Id = id });
var dto = Database.FirstOrDefault<UserDto>(sql);
var dto = Database.Fetch<UserDto, User2AppDto, UserDto>(new UserSectionRelator().Map, sql).FirstOrDefault();
if (dto == null)
return null;
@@ -52,18 +56,20 @@ namespace Umbraco.Core.Persistence.Repositories
{
if (ids.Any())
{
foreach (var id in ids)
{
yield return Get(id);
}
return PerformGetAllOnIds(ids);
}
else
var sql = GetBaseQuery(false);
return ConvertFromDtos(Database.Fetch<UserDto, User2AppDto, UserDto>(new UserSectionRelator().Map, sql));
}
private IEnumerable<IUser> PerformGetAllOnIds(params int[] ids)
{
if (ids.Any() == false) yield break;
foreach (var id in ids)
{
var userDtos = Database.Fetch<UserDto>("WHERE id >= 0");
foreach (var userDto in userDtos)
{
yield return Get(userDto.Id);
}
yield return Get(id);
}
}
@@ -73,7 +79,7 @@ namespace Umbraco.Core.Persistence.Repositories
var translator = new SqlTranslator<IUser>(sqlClause, query);
var sql = translator.Translate();
var dtos = Database.Fetch<UserDto>(sql);
var dtos = Database.Fetch<UserDto, User2AppDto, UserDto>(new UserSectionRelator().Map, sql);
foreach (var dto in dtos.DistinctBy(x => x.Id))
{
@@ -88,20 +94,41 @@ namespace Umbraco.Core.Persistence.Repositories
protected override Sql GetBaseQuery(bool isCount)
{
var sql = new Sql();
sql.Select(isCount ? "COUNT(*)" : "*")
.From<UserDto>();
if (isCount)
{
sql.Select("COUNT(*)").From<UserDto>();
}
else
{
return GetBaseQuery("*");
}
return sql;
}
private static Sql GetBaseQuery(string columns)
{
var sql = new Sql();
sql.Select(columns)
.From<UserDto>()
.LeftJoin<User2AppDto>()
.On<UserDto, User2AppDto>(left => left.Id, right => right.UserId);
return sql;
}
protected override string GetBaseWhereClause()
{
return "umbracoUser.id = @Id";
}
protected override IEnumerable<string> GetDeleteClauses()
{
{
var list = new List<string>
{
"DELETE FROM umbracoUser2NodePermission WHERE userId = @Id",
"DELETE FROM umbracoUser2NodeNotify WHERE userId = @Id",
"DELETE FROM umbracoUserLogins WHERE userId = @Id",
"DELETE FROM umbracoUser2app WHERE " + SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName("user") + "=@Id",
"DELETE FROM umbracoUser WHERE id = @Id"
};
return list;
@@ -120,6 +147,14 @@ namespace Umbraco.Core.Persistence.Repositories
var id = Convert.ToInt32(Database.Insert(userDto));
entity.Id = id;
foreach (var sectionDto in userDto.User2AppDtos)
{
//need to set the id explicitly here
sectionDto.UserId = id;
Database.Insert(sectionDto);
}
((ICanBeDirty)entity).ResetDirtyProperties();
}
protected override void PersistUpdatedItem(IUser entity)
@@ -128,25 +163,89 @@ namespace Umbraco.Core.Persistence.Repositories
var userDto = userFactory.BuildDto(entity);
Database.Update(userDto);
//update the sections if they've changed
var user = (User)entity;
if (user.IsPropertyDirty("AllowedSections"))
{
//for any that exist on the object, we need to determine if we need to update or insert
foreach (var sectionDto in userDto.User2AppDtos)
{
if (user.AddedSections.Contains(sectionDto.AppAlias))
{
//we need to insert since this was added
Database.Insert(sectionDto);
}
else
{
//we need to manually update this record because it has a composite key
Database.Update<User2AppDto>("SET app=@Section WHERE app=@Section AND " + SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName("user") + "=@UserId",
new { Section = sectionDto.AppAlias, UserId = sectionDto.UserId });
}
}
//now we need to delete any applications that have been removed
foreach (var section in user.RemovedSections)
{
//we need to manually delete thsi record because it has a composite key
Database.Delete<User2AppDto>("WHERE app=@Section AND " + SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName("user") + "=@UserId",
new { Section = section, UserId = (int)user.Id });
}
}
((ICanBeDirty)entity).ResetDirtyProperties();
}
#endregion
#region Implementation of IUserRepository
public IProfile GetProfileById(int id)
public IEnumerable<IUser> GetUsersAssignedToSection(string sectionAlias)
{
//Here we're building up a query that looks like this, a sub query is required because the resulting structure
// needs to still contain all of the section rows per user.
//SELECT *
//FROM [umbracoUser]
//LEFT JOIN [umbracoUser2app]
//ON [umbracoUser].[id] = [umbracoUser2app].[user]
//WHERE umbracoUser.id IN (SELECT umbracoUser.id
// FROM [umbracoUser]
// LEFT JOIN [umbracoUser2app]
// ON [umbracoUser].[id] = [umbracoUser2app].[user]
// WHERE umbracoUser2app.app = 'content')
var sql = GetBaseQuery(false);
sql.Where(GetBaseWhereClause(), new { Id = id });
var innerSql = GetBaseQuery("umbracoUser.id");
innerSql.Where("umbracoUser2app.app = " + SqlSyntaxContext.SqlSyntaxProvider.GetQuotedValue(sectionAlias));
sql.Where(string.Format("umbracoUser.id IN ({0})", innerSql.SQL));
var dto = Database.FirstOrDefault<UserDto>(sql);
if (dto == null)
return null;
return new Profile(dto.Id, dto.UserName);
return ConvertFromDtos(Database.Fetch<UserDto, User2AppDto, UserDto>(new UserSectionRelator().Map, sql));
}
#endregion
private IEnumerable<IUser> ConvertFromDtos(IEnumerable<UserDto> dtos)
{
var foundUserTypes = new Dictionary<short, IUserType>();
return dtos.Select(dto =>
{
//first we need to get the user type
IUserType userType;
if (foundUserTypes.ContainsKey(dto.Type))
{
userType = foundUserTypes[dto.Type];
}
else
{
userType = _userTypeRepository.Get(dto.Type);
//put it in the local cache
foundUserTypes.Add(dto.Type, userType);
}
var userFactory = new UserFactory(userType);
return userFactory.BuildEntity(dto);
});
}
}
}
@@ -32,7 +32,7 @@ namespace Umbraco.Core.Persistence.Repositories
var sql = GetBaseQuery(false);
sql.Where(GetBaseWhereClause(), new { Id = id });
var dto = Database.Query<UserTypeDto>(sql).FirstOrDefault();
var dto = Database.FirstOrDefault<UserTypeDto>(sql);
if (dto == null)
return null;
@@ -8,7 +8,7 @@ using Umbraco.Core.Persistence.UnitOfWork;
namespace Umbraco.Core.Persistence.Repositories
{
internal abstract class VersionableRepositoryBase<TId, TEntity> : PetaPocoRepositoryBase<TId, TEntity>
internal abstract class VersionableRepositoryBase<TId, TEntity> : PermissionRepository<TId, TEntity>
where TEntity : class, IAggregateRoot
{
protected VersionableRepositoryBase(IDatabaseUnitOfWork work) : base(work)
@@ -81,7 +81,7 @@ namespace Umbraco.Core.Persistence
return new MediaRepository(
uow,
RuntimeCacheProvider.Current,
CreateMediaTypeRepository(uow));
CreateMediaTypeRepository(uow)) { EnsureUniqueNaming = Umbraco.Core.Configuration.UmbracoSettings.EnsureUniqueNaming };
}
public virtual IMediaTypeRepository CreateMediaTypeRepository(IDatabaseUnitOfWork uow)
@@ -118,7 +118,7 @@ namespace Umbraco.Core.Persistence
public virtual ITemplateRepository CreateTemplateRepository(IDatabaseUnitOfWork uow)
{
return new TemplateRepository(uow, NullCacheProvider.Current);
return new TemplateRepository(uow, RuntimeCacheProvider.Current);
}
}
}
@@ -317,11 +317,10 @@ namespace Umbraco.Core.Persistence.SqlSyntax
{
db.OpenSharedConnection();
// Need 4 @ signs as it is regarded as a parameter, @@ escapes it once, @@@@ escapes it twice
var lowerCaseFileSystem = db.Fetch<int>("SELECT @@@@Global.lower_case_file_system");
var lowerCaseTableNames = db.Fetch<int>("SELECT @@@@Global.lower_case_table_names");
if(lowerCaseFileSystem.Any() && lowerCaseTableNames.Any())
supportsCaseInsensitiveQueries = lowerCaseFileSystem.First() == 1 && lowerCaseTableNames.First() == 1;
if(lowerCaseTableNames.Any())
supportsCaseInsensitiveQueries = lowerCaseTableNames.First() == 1;
}
catch(Exception ex)
{
@@ -1,6 +1,8 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Linq;
using StackExchange.Profiling;
using Umbraco.Core.Logging;
@@ -46,8 +48,7 @@ namespace Umbraco.Core.Persistence
// wrap the connection with a profiling connection that tracks timings
return new StackExchange.Profiling.Data.ProfiledDbConnection(connection as DbConnection, MiniProfiler.Current);
}
public override void OnException(Exception x)
{
LogHelper.Info<UmbracoDatabase>(x.StackTrace);
+22 -24
View File
@@ -1,6 +1,7 @@
using System;
using System.Web;
using StackExchange.Profiling;
using StackExchange.Profiling.SqlFormatters;
using Umbraco.Core.Configuration;
using Umbraco.Core.Logging;
@@ -52,13 +53,8 @@ namespace Umbraco.Core.Profiling
/// <param name="e"></param>
void UmbracoApplicationEndRequest(object sender, EventArgs e)
{
if (GlobalSettings.DebugMode == false) return;
var request = TryGetRequest(sender);
if (request.Success == false) return;
if (request.Result.Url.IsClientSideRequest()) return;
if (string.IsNullOrEmpty(request.Result["umbDebug"]) == false)
if (CanPerformProfilingAction(sender))
{
//stop the profiler
Stop();
}
}
@@ -70,17 +66,28 @@ namespace Umbraco.Core.Profiling
/// <param name="e"></param>
void UmbracoApplicationBeginRequest(object sender, EventArgs e)
{
if (GlobalSettings.DebugMode == false) return;
var request = TryGetRequest(sender);
if (request.Success == false) return;
if (request.Result.Url.IsClientSideRequest()) return;
if (string.IsNullOrEmpty(request.Result["umbDebug"]) == false)
if (CanPerformProfilingAction(sender))
{
//start the profiler
Start();
}
}
private bool CanPerformProfilingAction(object sender)
{
if (GlobalSettings.DebugMode == false)
return false;
//will not run in medium trust
if (SystemUtilities.GetCurrentTrustLevel() < AspNetHostingPermissionLevel.High)
return false;
var request = TryGetRequest(sender);
if (request.Success == false || request.Result.Url.IsClientSideRequest() || string.IsNullOrEmpty(request.Result["umbDebug"]))
return false;
return true;
}
/// <summary>
/// Render the UI to display the profiler
/// </summary>
@@ -103,9 +110,7 @@ namespace Umbraco.Core.Profiling
/// </remarks>
public IDisposable Step(string name)
{
if (GlobalSettings.DebugMode == false) return null;
return MiniProfiler.Current.Step(name);
return GlobalSettings.DebugMode == false ? null : MiniProfiler.Current.Step(name);
}
/// <summary>
@@ -113,10 +118,8 @@ namespace Umbraco.Core.Profiling
/// </summary>
public void Start()
{
if (GlobalSettings.DebugMode == false) return;
//will not run in medium trust
if (SystemUtilities.GetCurrentTrustLevel() < AspNetHostingPermissionLevel.High) return;
MiniProfiler.Settings.SqlFormatter = new SqlServerFormatter();
MiniProfiler.Settings.StackMaxLength = 5000;
MiniProfiler.Start();
}
@@ -129,10 +132,6 @@ namespace Umbraco.Core.Profiling
/// </remarks>
public void Stop(bool discardResults = false)
{
if (GlobalSettings.DebugMode == false) return;
//will not run in medium trust
if (SystemUtilities.GetCurrentTrustLevel() < AspNetHostingPermissionLevel.High) return;
MiniProfiler.Stop(discardResults);
}
@@ -156,6 +155,5 @@ namespace Umbraco.Core.Profiling
return new Attempt<HttpRequestBase>(ex);
}
}
}
}
+6 -1
View File
@@ -1,3 +1,4 @@
using System.Collections.Generic;
using Umbraco.Core.Models;
namespace Umbraco.Core.Publishing
@@ -10,6 +11,11 @@ namespace Umbraco.Core.Publishing
public IContent ContentItem { get; private set; }
public PublishStatusType StatusType { get; internal set; }
/// <summary>
/// Gets sets the invalid properties if the status failed due to validation.
/// </summary>
public IEnumerable<Property> InvalidProperties { get; set; }
public PublishStatus(IContent content, PublishStatusType statusType)
{
ContentItem = content;
@@ -24,6 +30,5 @@ namespace Umbraco.Core.Publishing
{
}
}
}
+9 -6
View File
@@ -3,14 +3,12 @@ using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Threading;
using System.Web;
using System.Xml.Linq;
using Umbraco.Core.Auditing;
using Umbraco.Core.Events;
using Umbraco.Core.IO;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Models.EntityBase;
using Umbraco.Core.Models.Rdbms;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.Caching;
@@ -88,7 +86,7 @@ namespace Umbraco.Core.Services
Created.RaiseEvent(new NewEventArgs<IContent>(content, false, contentTypeAlias, parentId), this);
Audit.Add(AuditTypes.New, "", content.CreatorId, content.Id);
Audit.Add(AuditTypes.New, string.Format("Content '{0}' was created", name), content.CreatorId, content.Id);
return content;
}
@@ -123,7 +121,7 @@ namespace Umbraco.Core.Services
Created.RaiseEvent(new NewEventArgs<IContent>(content, false, contentTypeAlias, parent), this);
Audit.Add(AuditTypes.New, "", content.CreatorId, content.Id);
Audit.Add(AuditTypes.New, string.Format("Content '{0}' was created", name), content.CreatorId, content.Id);
return content;
}
@@ -163,7 +161,7 @@ namespace Umbraco.Core.Services
Created.RaiseEvent(new NewEventArgs<IContent>(content, false, contentTypeAlias, parentId), this);
Audit.Add(AuditTypes.New, "", content.CreatorId, content.Id);
Audit.Add(AuditTypes.New, string.Format("Content '{0}' was created with Id {1}", name, content.Id), content.CreatorId, content.Id);
return content;
}
@@ -203,7 +201,7 @@ namespace Umbraco.Core.Services
Created.RaiseEvent(new NewEventArgs<IContent>(content, false, contentTypeAlias, parent), this);
Audit.Add(AuditTypes.New, "", content.CreatorId, content.Id);
Audit.Add(AuditTypes.New, string.Format("Content '{0}' was created with Id {1}", name, content.Id), content.CreatorId, content.Id);
return content;
}
@@ -1124,6 +1122,9 @@ namespace Umbraco.Core.Services
Audit.Add(AuditTypes.Copy, "Copy Content performed by user", content.WriterId, content.Id);
//TODO: Don't think we need this here because cache should be cleared by the event listeners
// and the correct ICacheRefreshers!?
RuntimeCacheProvider.Current.Clear();
return copy;
@@ -1551,6 +1552,8 @@ namespace Umbraco.Core.Services
publishStatus.StatusType = CheckAndLogIsPublishable(content);
//Content contains invalid property values and can therefore not be published - fire event?
publishStatus.StatusType = CheckAndLogIsValid(content);
//set the invalid properties (if there are any)
publishStatus.InvalidProperties = ((ContentBase) content).LastInvalidProperties;
//if we're still successful, then publish using the strategy
if (publishStatus.StatusType == PublishStatusType.Success)
@@ -0,0 +1,15 @@
using Umbraco.Core.Models.Membership;
namespace Umbraco.Core.Services
{
/// <summary>
/// Defines part of the UserService, which is specific to methods used by the membership provider.
/// </summary>
/// <remarks>
/// Idea is to have this is an isolated interface so that it can be easily 'replaced' in the membership provider impl.
/// </remarks>
internal interface IMembershipUserService : IService
{
IMembershipUser CreateMembershipUser(string name, string login, string password, IUserType userType, string email = "");
}
}
+15 -10
View File
@@ -15,6 +15,10 @@ namespace Umbraco.Core.Services
/// <returns><see cref="IProfile"/></returns>
IProfile GetProfileById(int id);
IProfile GetProfileByUserName(string username);
IUser GetUserByUserName(string username);
IUser GetUserById(int id);
/// <summary>
/// Gets an IUserType by its Alias
/// </summary>
@@ -28,16 +32,17 @@ namespace Umbraco.Core.Services
/// <param name="name">Name of the UserType to retrieve</param>
/// <returns><see cref="IUserType"/></returns>
IUserType GetUserTypeByName(string name);
}
/// <summary>
/// Defines part of the UserService, which is specific to methods used by the membership provider.
/// </summary>
/// <remarks>
/// Idea is to have this is an isolated interface so that it can be easily 'replaced' in the membership provider impl.
/// </remarks>
internal interface IMembershipUserService : IService
{
IMembershipUser CreateUser(string name, string login, string password, IUserType userType, string email = "");
/// <summary>
/// Saves changes to the user object
/// </summary>
/// <param name="user"></param>
void SaveUser(IUser user);
/// <summary>
/// This is useful when an entire section is removed from config
/// </summary>
/// <param name="sectionAlias"></param>
void DeleteSectionFromAllUsers(string sectionAlias);
}
}
+5 -5
View File
@@ -63,9 +63,9 @@ namespace Umbraco.Core.Services
media.CreatorId = userId;
Created.RaiseEvent(new NewEventArgs<IMedia>(media, false, mediaTypeAlias, parentId), this);
Created.RaiseEvent(new NewEventArgs<IMedia>(media, false, mediaTypeAlias, parentId), this);
Audit.Add(AuditTypes.New, "", media.CreatorId, media.Id);
Audit.Add(AuditTypes.New, string.Format("Media '{0}' was created", name), media.CreatorId, media.Id);
return media;
}
@@ -98,7 +98,7 @@ namespace Umbraco.Core.Services
Created.RaiseEvent(new NewEventArgs<IMedia>(media, false, mediaTypeAlias, parent), this);
Audit.Add(AuditTypes.New, "", media.CreatorId, media.Id);
Audit.Add(AuditTypes.New, string.Format("Media '{0}' was created", name), media.CreatorId, media.Id);
return media;
}
@@ -142,7 +142,7 @@ namespace Umbraco.Core.Services
Created.RaiseEvent(new NewEventArgs<IMedia>(media, false, mediaTypeAlias, parentId), this);
Audit.Add(AuditTypes.New, "", media.CreatorId, media.Id);
Audit.Add(AuditTypes.New, string.Format("Media '{0}' was created with Id {1}", name, media.Id), media.CreatorId, media.Id);
return media;
}
@@ -186,7 +186,7 @@ namespace Umbraco.Core.Services
Created.RaiseEvent(new NewEventArgs<IMedia>(media, false, mediaTypeAlias, parent), this);
Audit.Add(AuditTypes.New, "", media.CreatorId, media.Id);
Audit.Add(AuditTypes.New, string.Format("Media '{0}' was created with Id {1}", name, media.Id), media.CreatorId, media.Id);
return media;
}
+24 -2
View File
@@ -9,6 +9,7 @@ using Umbraco.Core.Configuration;
using Umbraco.Core.IO;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Rdbms;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.Querying;
using Umbraco.Core.Persistence.UnitOfWork;
@@ -286,7 +287,7 @@ namespace Umbraco.Core.Services
var properties = from property in element.Elements()
where property.Attribute("isDoc") == null
select property;
IContent content = parent == null
? new Content(nodeName, parentId, contentType)
{
@@ -303,12 +304,33 @@ namespace Umbraco.Core.Services
{
string propertyTypeAlias = isLegacySchema ? property.Attribute("alias").Value : property.Name.LocalName;
if (content.HasProperty(propertyTypeAlias))
content.SetValue(propertyTypeAlias, property.Value);
{
var propertyValue = property.Value;
var propertyType = contentType.PropertyTypes.FirstOrDefault(pt => pt.Alias == propertyTypeAlias);
if (propertyType != null && propertyType.DataTypeId == new Guid(Constants.PropertyEditors.CheckBoxList))
{
var database = ApplicationContext.Current.DatabaseContext.Database;
var dtos = database.Fetch<DataTypePreValueDto>("WHERE datatypeNo" + "deId = @Id", new { Id = propertyType.DataTypeDefinitionId });
var propertyValueList = new List<string>();
foreach (var preValue in propertyValue.Split(','))
{
propertyValueList.Add(dtos.Single(x => x.Value == preValue).Id.ToString(CultureInfo.InvariantCulture));
}
propertyValue = string.Join(",", propertyValueList.ToArray());
}
content.SetValue(propertyTypeAlias, propertyValue);
}
}
return content;
}
#endregion
#region ContentTypes
+97 -22
View File
@@ -1,6 +1,8 @@
using System;
using System.Globalization;
using System.Linq;
using Umbraco.Core.Events;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Membership;
using Umbraco.Core.Models.Rdbms;
using Umbraco.Core.Persistence;
@@ -14,19 +16,21 @@ namespace Umbraco.Core.Services
/// </summary>
internal class UserService : IUserService
{
private readonly RepositoryFactory _repositoryFactory;
private readonly RepositoryFactory _repositoryFactory;
private readonly IDatabaseUnitOfWorkProvider _uowProvider;
public UserService(RepositoryFactory repositoryFactory) : this(new PetaPocoUnitOfWorkProvider(), repositoryFactory)
{}
public UserService(RepositoryFactory repositoryFactory)
: this(new PetaPocoUnitOfWorkProvider(), repositoryFactory)
{ }
public UserService(IDatabaseUnitOfWorkProvider provider) : this(provider, new RepositoryFactory())
{}
public UserService(IDatabaseUnitOfWorkProvider provider)
: this(provider, new RepositoryFactory())
{ }
public UserService(IDatabaseUnitOfWorkProvider provider, RepositoryFactory repositoryFactory)
{
_repositoryFactory = repositoryFactory;
_uowProvider = provider;
_repositoryFactory = repositoryFactory;
_uowProvider = provider;
}
#region Implementation of IUserService
@@ -37,13 +41,35 @@ namespace Umbraco.Core.Services
/// <param name="id">Id of the User to retrieve</param>
/// <returns><see cref="IProfile"/></returns>
public IProfile GetProfileById(int id)
{
var user = GetUserById(id);
return new Profile(user.Id, user.Username);
}
public IProfile GetProfileByUserName(string username)
{
var user = GetUserByUserName(username);
return new Profile(user.Id, user.Username);
}
public IUser GetUserByUserName(string username)
{
using (var repository = _repositoryFactory.CreateUserRepository(_uowProvider.GetUnitOfWork()))
{
return repository.GetProfileById(id);
var query = Query<IUser>.Builder.Where(x => x.Username == username);
return repository.GetByQuery(query).FirstOrDefault();
}
}
public IUser GetUserById(int id)
{
using (var repository = _repositoryFactory.CreateUserRepository(_uowProvider.GetUnitOfWork()))
{
return repository.Get(id);
}
}
/// <summary>
/// Gets an IUserType by its Alias
/// </summary>
@@ -74,6 +100,45 @@ namespace Umbraco.Core.Services
}
}
/// <summary>
/// Savers changes to a user to the database
/// </summary>
/// <param name="user"></param>
public void SaveUser(IUser user)
{
if (UserSaving.IsRaisedEventCancelled(new SaveEventArgs<IUser>(user), this))
return;
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateUserRepository(uow))
{
repository.AddOrUpdate(user);
uow.Commit();
}
UserSaved.RaiseEvent(new SaveEventArgs<IUser>(user, false), this);
}
/// <summary>
/// This is useful for when a section is removed from config
/// </summary>
/// <param name="sectionAlias"></param>
public void DeleteSectionFromAllUsers(string sectionAlias)
{
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateUserRepository(uow))
{
var assignedUsers = repository.GetUsersAssignedToSection(sectionAlias);
foreach (var user in assignedUsers)
{
//now remove the section for each user and commit
user.RemoveAllowedSection(sectionAlias);
repository.AddOrUpdate(user);
}
uow.Commit();
}
}
/// <summary>
/// Creates a new user for logging into the umbraco backoffice
/// </summary>
@@ -83,7 +148,7 @@ namespace Umbraco.Core.Services
/// <param name="userType"></param>
/// <param name="email"></param>
/// <returns></returns>
public IMembershipUser CreateUser(string name, string login, string password, IUserType userType, string email = "")
public IMembershipUser CreateMembershipUser(string name, string login, string password, IUserType userType, string email = "")
{
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateUserRepository(uow))
@@ -93,19 +158,19 @@ namespace Umbraco.Core.Services
throw new ArgumentException("Login already exists");
var user = new User(userType)
{
DefaultToLiveEditing = false,
Email = email,
Language = Umbraco.Core.Configuration.GlobalSettings.DefaultUILanguage,
Name = name,
Password = password,
Permissions = userType.Permissions,
Username = login,
StartContentId = -1,
StartMediaId = -1,
NoConsole = false,
IsApproved = true
};
{
DefaultToLiveEditing = false,
Email = email,
Language = Umbraco.Core.Configuration.GlobalSettings.DefaultUILanguage,
Name = name,
Password = password,
DefaultPermissions = userType.Permissions,
Username = login,
StartContentId = -1,
StartMediaId = -1,
NoConsole = false,
IsApproved = true
};
repository.AddOrUpdate(user);
uow.Commit();
@@ -115,5 +180,15 @@ namespace Umbraco.Core.Services
}
#endregion
/// <summary>
/// Occurs before Save
/// </summary>
public static event TypedEventHandler<IUserService, SaveEventArgs<IUser>> UserSaving;
/// <summary>
/// Occurs after Save
/// </summary>
public static event TypedEventHandler<IUserService, SaveEventArgs<IUser>> UserSaved;
}
}
+13 -5
View File
@@ -35,12 +35,20 @@ namespace Umbraco.Core.Sync
if (_addresses == null)
{
_addresses = new List<IServerAddress>();
var nodes = _xmlServers.SelectNodes("./server");
foreach (XmlNode n in nodes)
{
_addresses.Add(new ConfigServerAddress(n));
}
if (_xmlServers != null)
{
var nodes = _xmlServers.SelectNodes("./server");
if (nodes != null)
{
foreach (XmlNode n in nodes)
{
_addresses.Add(new ConfigServerAddress(n));
}
}
}
}
return _addresses;
}
}
+13 -6
View File
@@ -68,28 +68,28 @@
<Reference Include="System.Web.Extensions" />
<Reference Include="System.Web.Helpers, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<Private>True</Private>
<HintPath>..\packages\Microsoft.AspNet.WebPages.2.0.20710.0\lib\net40\System.Web.Helpers.dll</HintPath>
<HintPath>..\packages\Microsoft.AspNet.WebPages.2.0.30506.0\lib\net40\System.Web.Helpers.dll</HintPath>
</Reference>
<Reference Include="System.Web.Mvc, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<Private>True</Private>
<HintPath>..\packages\Microsoft.AspNet.Mvc.4.0.20710.0\lib\net40\System.Web.Mvc.dll</HintPath>
<HintPath>..\packages\Microsoft.AspNet.Mvc.4.0.30506.0\lib\net40\System.Web.Mvc.dll</HintPath>
</Reference>
<Reference Include="System.Web.Razor, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<Private>True</Private>
<HintPath>..\packages\Microsoft.AspNet.Razor.2.0.20715.0\lib\net40\System.Web.Razor.dll</HintPath>
<HintPath>..\packages\Microsoft.AspNet.Razor.2.0.30506.0\lib\net40\System.Web.Razor.dll</HintPath>
</Reference>
<Reference Include="System.Web.Services" />
<Reference Include="System.Web.WebPages, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<Private>True</Private>
<HintPath>..\packages\Microsoft.AspNet.WebPages.2.0.20710.0\lib\net40\System.Web.WebPages.dll</HintPath>
<HintPath>..\packages\Microsoft.AspNet.WebPages.2.0.30506.0\lib\net40\System.Web.WebPages.dll</HintPath>
</Reference>
<Reference Include="System.Web.WebPages.Deployment, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<Private>True</Private>
<HintPath>..\packages\Microsoft.AspNet.WebPages.2.0.20710.0\lib\net40\System.Web.WebPages.Deployment.dll</HintPath>
<HintPath>..\packages\Microsoft.AspNet.WebPages.2.0.30506.0\lib\net40\System.Web.WebPages.Deployment.dll</HintPath>
</Reference>
<Reference Include="System.Web.WebPages.Razor, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<Private>True</Private>
<HintPath>..\packages\Microsoft.AspNet.WebPages.2.0.20710.0\lib\net40\System.Web.WebPages.Razor.dll</HintPath>
<HintPath>..\packages\Microsoft.AspNet.WebPages.2.0.30506.0\lib\net40\System.Web.WebPages.Razor.dll</HintPath>
</Reference>
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
@@ -140,6 +140,7 @@
<Compile Include="CoreBootManager.cs" />
<Compile Include="DatabaseContext.cs" />
<Compile Include="DataTableExtensions.cs" />
<Compile Include="DateTimeExtensions.cs" />
<Compile Include="DictionaryExtensions.cs" />
<Compile Include="Dictionary\CultureDictionaryFactoryResolver.cs" />
<Compile Include="Dictionary\ICultureDictionaryFactory.cs" />
@@ -163,6 +164,8 @@
<Compile Include="Events\SaveEventArgs.cs" />
<Compile Include="Events\SendToPublishEventArgs.cs" />
<Compile Include="IApplicationEventHandler.cs" />
<Compile Include="IO\ResizedImage.cs" />
<Compile Include="IO\UmbracoMediaFile.cs" />
<Compile Include="Media\MediaSubfolderCounter.cs" />
<Compile Include="Models\ContentBase.cs" />
<Compile Include="Models\ContentExtensions.cs" />
@@ -461,6 +464,7 @@
<Compile Include="Persistence\Querying\Query.cs" />
<Compile Include="Persistence\Querying\SqlTranslator.cs" />
<Compile Include="Persistence\Relators\DictionaryLanguageTextRelator.cs" />
<Compile Include="Persistence\Relators\UserSectionRelator.cs" />
<Compile Include="Persistence\Repositories\ContentRepository.cs" />
<Compile Include="Persistence\Repositories\ContentTypeBaseRepository.cs" />
<Compile Include="Persistence\Repositories\ContentTypeRepository.cs" />
@@ -490,12 +494,14 @@
<Compile Include="Persistence\Repositories\LanguageRepository.cs" />
<Compile Include="Persistence\Repositories\MediaRepository.cs" />
<Compile Include="Persistence\Repositories\MediaTypeRepository.cs" />
<Compile Include="Persistence\Repositories\PermissionRepository.cs" />
<Compile Include="Persistence\Repositories\PetaPocoRepositoryBase.cs" />
<Compile Include="Persistence\Repositories\RelationRepository.cs" />
<Compile Include="Persistence\Repositories\RelationTypeRepository.cs" />
<Compile Include="Persistence\Repositories\RepositoryBase.cs" />
<Compile Include="Persistence\Repositories\ScriptRepository.cs" />
<Compile Include="Persistence\Repositories\ServerRegistrationRepository.cs" />
<Compile Include="Persistence\Repositories\SimilarNodeNameComparer.cs" />
<Compile Include="Persistence\Repositories\StylesheetRepository.cs" />
<Compile Include="Persistence\Repositories\TemplateRepository.cs" />
<Compile Include="Persistence\Repositories\UserRepository.cs" />
@@ -680,6 +686,7 @@
<Compile Include="Services\ILocalizationService.cs" />
<Compile Include="Services\IMediaService.cs" />
<Compile Include="Services\IMemberService.cs" />
<Compile Include="Services\IMembershipUserService.cs" />
<Compile Include="Services\IService.cs" />
<Compile Include="Services\IUserService.cs" />
<Compile Include="Services\LocalizationService.cs" />
+3 -3
View File
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="log4net-mediumtrust" version="2.0.0" targetFramework="net40" />
<package id="Microsoft.AspNet.Mvc" version="4.0.20710.0" targetFramework="net40" />
<package id="Microsoft.AspNet.Razor" version="2.0.20715.0" targetFramework="net40" />
<package id="Microsoft.AspNet.WebPages" version="2.0.20710.0" targetFramework="net40" />
<package id="Microsoft.AspNet.Mvc" version="4.0.30506.0" targetFramework="net40" />
<package id="Microsoft.AspNet.Razor" version="2.0.30506.0" targetFramework="net40" />
<package id="Microsoft.AspNet.WebPages" version="2.0.30506.0" targetFramework="net40" />
<package id="Microsoft.Web.Infrastructure" version="1.0.0.0" targetFramework="net40" />
<package id="MiniProfiler" version="2.1.0" targetFramework="net40" />
<package id="Newtonsoft.Json" version="4.5.11" targetFramework="net40" />
@@ -0,0 +1,85 @@
using System;
using System.Collections.Generic;
using NUnit.Framework;
using Umbraco.Core;
using Umbraco.Core.Models.Rdbms;
using Umbraco.Core.Persistence;
using Umbraco.Tests.TestHelpers;
namespace Umbraco.Tests.Persistence
{
[TestFixture]
public class PetaPocoExtensionsTest : BaseDatabaseFactoryTest
{
[SetUp]
public override void Initialize()
{
base.Initialize();
}
[TearDown]
public override void TearDown()
{
base.TearDown();
}
[Test]
public void Can_Bulk_Insert()
{
// Arrange
var db = DatabaseContext.Database;
var servers = new List<ServerRegistrationDto>();
for (var i = 0; i < 1000; i++)
{
servers.Add(new ServerRegistrationDto
{
Address = "address" + i,
ComputerName = "computer" + i,
DateRegistered = DateTime.Now,
IsActive = true,
LastNotified = DateTime.Now
});
}
// Act
using (DisposableTimer.TraceDuration<PetaPocoExtensionsTest>("starting insert", "finished insert"))
{
db.BulkInsertRecords(servers);
}
// Assert
Assert.That(db.ExecuteScalar<int>("SELECT COUNT(*) FROM umbracoServer"), Is.EqualTo(1000));
}
[Test]
public void Generate_Bulk_Import_Sql()
{
// Arrange
var db = DatabaseContext.Database;
var servers = new List<ServerRegistrationDto>();
for (var i = 0; i < 2; i++)
{
servers.Add(new ServerRegistrationDto
{
Address = "address" + i,
ComputerName = "computer" + i,
DateRegistered = DateTime.Now,
IsActive = true,
LastNotified = DateTime.Now
});
}
db.OpenSharedConnection();
// Act
string sql;
db.GenerateBulkInsertCommand(servers, db.Connection, out sql);
db.CloseSharedConnection();
// Assert
Assert.That(sql,
Is.EqualTo("INSERT INTO [umbracoServer] ([umbracoServer].[address], [umbracoServer].[computerName], [umbracoServer].[registeredDate], [umbracoServer].[lastNotifiedDate], [umbracoServer].[isActive]) VALUES (@0,@1,@2,@3,@4), (@5,@6,@7,@8,@9)"));
}
}
}
@@ -1,7 +1,10 @@
using System;
using NUnit.Framework;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Membership;
using Umbraco.Core.Models.Rdbms;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.Repositories;
using Umbraco.Tests.TestHelpers;
namespace Umbraco.Tests.Persistence.Querying
@@ -9,6 +12,26 @@ namespace Umbraco.Tests.Persistence.Querying
[TestFixture]
public class PetaPocoSqlTests : BaseUsingSqlCeSyntax
{
[Test]
public void Generate_Replace_Entity_Permissions_Test()
{
// Act
var sql = PermissionRepository<int, IContent>.GenerateReplaceEntityPermissionsSql(123, "A", new object[] {10, 11, 12});
// Assert
Assert.AreEqual(@"SET [permission]='A' WHERE (([nodeId]=123) AND ([userId]=10 OR [userId]=11 OR [userId]=12))", sql);
}
[Test]
public void Generate_Replace_Entity_Permissions_With_Descendants_Test()
{
// Act
var sql = PermissionRepository<int, IContent>.GenerateReplaceEntityPermissionsSql(new[] {123, 456}, "A", new object[] {10, 11, 12});
// Assert
Assert.AreEqual(@"SET [permission]='A' WHERE (([nodeId]=123 OR [nodeId]=456) AND ([userId]=10 OR [userId]=11 OR [userId]=12))", sql);
}
[Test]
public void Can_Select_From_With_Type()
{
@@ -12,6 +12,22 @@ namespace Umbraco.Tests.Persistence.Querying
[TestFixture]
public class QueryBuilderTests : BaseUsingSqlCeSyntax
{
[Test]
public void Dates_Formatted_Properly()
{
var sql = new Sql();
sql.Select("*").From<DocumentDto>();
var dt = new DateTime(2013, 11, 21, 13, 25, 55);
var query = Query<IContent>.Builder.Where(x => x.ExpireDate <= dt);
var translator = new SqlTranslator<IContent>(sql, query);
var result = translator.Translate();
Assert.IsTrue(result.SQL.Contains("[expireDate] <= '2013-11-21 13:25:55'"));
}
[Test]
public void Can_Build_StartsWith_Query_For_IContent()
{
@@ -1,8 +1,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using Umbraco.Core;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Rdbms;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.Mappers;
using Umbraco.Core.Persistence.Querying;
@@ -15,7 +17,7 @@ using umbraco.interfaces;
namespace Umbraco.Tests.Persistence.Repositories
{
[TestFixture]
[TestFixture]
public class ContentRepositoryTest : BaseDatabaseFactoryTest
{
[SetUp]
@@ -32,6 +34,42 @@ namespace Umbraco.Tests.Persistence.Repositories
base.TearDown();
}
[Test]
public void Ensures_Permissions_Are_Set_If_Parent_Entity_Permissions_Exist()
{
// Arrange
var provider = new PetaPocoUnitOfWorkProvider();
var unitOfWork = provider.GetUnitOfWork();
var contentTypeRepository = RepositoryResolver.Current.ResolveByType<IContentTypeRepository>(unitOfWork);
var repository = (ContentRepository)RepositoryResolver.Current.ResolveByType<IContentRepository>(unitOfWork);
var contentType = MockedContentTypes.CreateSimpleContentType("umbTextpage", "Textpage");
contentType.AllowedContentTypes = new List<ContentTypeSort>
{
new ContentTypeSort
{
Alias = contentType.Alias,
Id = new Lazy<int>(() => contentType.Id),
SortOrder = 0
}
};
var parentPage = MockedContent.CreateSimpleContent(contentType);
contentTypeRepository.AddOrUpdate(contentType);
repository.AddOrUpdate(parentPage);
unitOfWork.Commit();
// Act
repository.AssignEntityPermissions(parentPage, "A", new object[] {0});
var childPage = MockedContent.CreateSimpleContent(contentType, "child", parentPage);
repository.AddOrUpdate(childPage);
unitOfWork.Commit();
// Assert
var permissions = repository.GetPermissionsForEntity(childPage.Id);
Assert.AreEqual(1, permissions.Count());
Assert.AreEqual("A", permissions.Single().Permission);
}
[Test]
public void Can_Instantiate_Repository()
{
@@ -0,0 +1,472 @@
using System;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using Umbraco.Core.Models.Membership;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.Querying;
using Umbraco.Core.Persistence.Repositories;
using Umbraco.Core.Persistence.UnitOfWork;
using Umbraco.Tests.TestHelpers;
using Umbraco.Tests.TestHelpers.Entities;
namespace Umbraco.Tests.Persistence.Repositories
{
[TestFixture]
public class UserRepositoryTest : BaseDatabaseFactoryTest
{
[SetUp]
public override void Initialize()
{
base.Initialize();
}
[TearDown]
public override void TearDown()
{
base.TearDown();
}
[Test]
public void Can_Instantiate_Repository()
{
// Arrange
var provider = new PetaPocoUnitOfWorkProvider();
var unitOfWork = provider.GetUnitOfWork();
// Act
var repository = RepositoryResolver.Current.ResolveByType<IUserRepository>(unitOfWork);
// Assert
Assert.That(repository, Is.Not.Null);
}
[Test]
public void Can_Perform_Add_On_UserRepository()
{
// Arrange
var provider = new PetaPocoUnitOfWorkProvider();
var unitOfWork = provider.GetUnitOfWork();
var repository = RepositoryResolver.Current.ResolveByType<IUserRepository>(unitOfWork);
var user = MockedUser.CreateUser(CreateAndCommitUserType());
// Act
repository.AddOrUpdate(user);
unitOfWork.Commit();
// Assert
Assert.That(user.HasIdentity, Is.True);
}
[Test]
public void Can_Perform_Multiple_Adds_On_UserRepository()
{
// Arrange
var provider = new PetaPocoUnitOfWorkProvider();
var unitOfWork = provider.GetUnitOfWork();
var repository = RepositoryResolver.Current.ResolveByType<IUserRepository>(unitOfWork);
var user1 = MockedUser.CreateUser(CreateAndCommitUserType(), "1");
var use2 = MockedUser.CreateUser(CreateAndCommitUserType(), "2");
// Act
repository.AddOrUpdate(user1);
unitOfWork.Commit();
repository.AddOrUpdate(use2);
unitOfWork.Commit();
// Assert
Assert.That(user1.HasIdentity, Is.True);
Assert.That(use2.HasIdentity, Is.True);
}
[Test]
public void Can_Verify_Fresh_Entity_Is_Not_Dirty()
{
// Arrange
var provider = new PetaPocoUnitOfWorkProvider();
var unitOfWork = provider.GetUnitOfWork();
var repository = RepositoryResolver.Current.ResolveByType<IUserRepository>(unitOfWork);
var user = MockedUser.CreateUser(CreateAndCommitUserType());
repository.AddOrUpdate(user);
unitOfWork.Commit();
// Act
var resolved = repository.Get((int)user.Id);
bool dirty = ((User)resolved).IsDirty();
// Assert
Assert.That(dirty, Is.False);
}
[Test]
public void Can_Perform_Update_On_UserRepository()
{
// Arrange
var provider = new PetaPocoUnitOfWorkProvider();
var unitOfWork = provider.GetUnitOfWork();
var repository = RepositoryResolver.Current.ResolveByType<IUserRepository>(unitOfWork);
var user = MockedUser.CreateUser(CreateAndCommitUserType());
repository.AddOrUpdate(user);
unitOfWork.Commit();
// Act
var resolved = repository.Get((int)user.Id);
resolved.Name = "New Name";
resolved.DefaultPermissions = "ZYX";
resolved.Language = "fr";
resolved.IsApproved = false;
resolved.Password = "new";
resolved.NoConsole = true;
resolved.StartContentId = 10;
resolved.StartMediaId = 11;
resolved.DefaultToLiveEditing = true;
resolved.Email = "new@new.com";
resolved.Username = "newName";
resolved.RemoveAllowedSection("content");
repository.AddOrUpdate(resolved);
unitOfWork.Commit();
var updatedItem = repository.Get((int)user.Id);
// Assert
Assert.That(updatedItem.Id, Is.EqualTo(resolved.Id));
Assert.That(updatedItem.Name, Is.EqualTo(resolved.Name));
Assert.That(updatedItem.DefaultPermissions, Is.EqualTo(resolved.DefaultPermissions));
Assert.That(updatedItem.Language, Is.EqualTo(resolved.Language));
Assert.That(updatedItem.IsApproved, Is.EqualTo(resolved.IsApproved));
Assert.That(updatedItem.Password, Is.EqualTo(resolved.Password));
Assert.That(updatedItem.NoConsole, Is.EqualTo(resolved.NoConsole));
Assert.That(updatedItem.StartContentId, Is.EqualTo(resolved.StartContentId));
Assert.That(updatedItem.StartMediaId, Is.EqualTo(resolved.StartMediaId));
Assert.That(updatedItem.DefaultToLiveEditing, Is.EqualTo(resolved.DefaultToLiveEditing));
Assert.That(updatedItem.Email, Is.EqualTo(resolved.Email));
Assert.That(updatedItem.Username, Is.EqualTo(resolved.Username));
Assert.That(updatedItem.AllowedSections.Count(), Is.EqualTo(1));
Assert.IsTrue(updatedItem.AllowedSections.Contains("media"));
}
[Test]
public void Can_Perform_Delete_On_UserRepository()
{
// Arrange
var provider = new PetaPocoUnitOfWorkProvider();
var unitOfWork = provider.GetUnitOfWork();
var repository = RepositoryResolver.Current.ResolveByType<IUserRepository>(unitOfWork);
var user = MockedUser.CreateUser(CreateAndCommitUserType());
// Act
repository.AddOrUpdate(user);
unitOfWork.Commit();
var id = user.Id;
var repository2 = RepositoryResolver.Current.ResolveByType<IUserRepository>(unitOfWork);
repository2.Delete(user);
unitOfWork.Commit();
var resolved = repository2.Get((int)id);
// Assert
Assert.That(resolved, Is.Null);
}
//[Test]
//public void Can_Perform_Delete_On_UserRepository_With_Permissions_Assigned()
//{
// // Arrange
// var provider = new PetaPocoUnitOfWorkProvider();
// var unitOfWork = provider.GetUnitOfWork();
// var repository = RepositoryResolver.Current.ResolveByType<IUserRepository>(unitOfWork);
// var user = MockedUser.CreateUser(CreateAndCommitUserType());
// //repository.AssignPermissions()
// // Act
// repository.AddOrUpdate(user);
// unitOfWork.Commit();
// var id = user.Id;
// var repository2 = RepositoryResolver.Current.ResolveByType<IUserRepository>(unitOfWork);
// repository2.Delete(user);
// unitOfWork.Commit();
// var resolved = repository2.Get((int)id);
// // Assert
// Assert.That(resolved, Is.Null);
//}
[Test]
public void Can_Perform_Get_On_UserRepository()
{
// Arrange
var provider = new PetaPocoUnitOfWorkProvider();
var unitOfWork = provider.GetUnitOfWork();
var repository = RepositoryResolver.Current.ResolveByType<IUserRepository>(unitOfWork);
var user = MockedUser.CreateUser(CreateAndCommitUserType());
repository.AddOrUpdate(user);
unitOfWork.Commit();
// Act
var updatedItem = repository.Get((int)user.Id);
// Assert
AssertPropertyValues(updatedItem, user);
}
[Test]
public void Can_Perform_GetByQuery_On_UserRepository()
{
// Arrange
var provider = new PetaPocoUnitOfWorkProvider();
var unitOfWork = provider.GetUnitOfWork();
var repository = RepositoryResolver.Current.ResolveByType<IUserRepository>(unitOfWork);
CreateAndCommitMultipleUsers(repository, unitOfWork);
// Act
var query = Query<IUser>.Builder.Where(x => x.Username == "TestUser1");
var result = repository.GetByQuery(query);
// Assert
Assert.That(result.Count(), Is.GreaterThanOrEqualTo(1));
}
[Test]
public void Can_Perform_GetAll_By_Param_Ids_On_UserRepository()
{
// Arrange
var provider = new PetaPocoUnitOfWorkProvider();
var unitOfWork = provider.GetUnitOfWork();
var repository = RepositoryResolver.Current.ResolveByType<IUserRepository>(unitOfWork);
var users = CreateAndCommitMultipleUsers(repository, unitOfWork);
// Act
var result = repository.GetAll((int)users[0].Id, (int)users[1].Id);
// Assert
Assert.That(result, Is.Not.Null);
Assert.That(result.Any(), Is.True);
Assert.That(result.Count(), Is.EqualTo(2));
}
[Test]
public void Can_Perform_GetAll_On_UserRepository()
{
// Arrange
var provider = new PetaPocoUnitOfWorkProvider();
var unitOfWork = provider.GetUnitOfWork();
var repository = RepositoryResolver.Current.ResolveByType<IUserRepository>(unitOfWork);
CreateAndCommitMultipleUsers(repository, unitOfWork);
// Act
var result = repository.GetAll();
// Assert
Assert.That(result, Is.Not.Null);
Assert.That(result.Any(), Is.True);
Assert.That(result.Count(), Is.GreaterThanOrEqualTo(3));
}
[Test]
public void Can_Perform_Exists_On_UserRepository()
{
// Arrange
var provider = new PetaPocoUnitOfWorkProvider();
var unitOfWork = provider.GetUnitOfWork();
var repository = RepositoryResolver.Current.ResolveByType<IUserRepository>(unitOfWork);
var users = CreateAndCommitMultipleUsers(repository, unitOfWork);
// Act
var exists = repository.Exists((int)users[0].Id);
// Assert
Assert.That(exists, Is.True);
}
[Test]
public void Can_Perform_Count_On_UserRepository()
{
// Arrange
var provider = new PetaPocoUnitOfWorkProvider();
var unitOfWork = provider.GetUnitOfWork();
var repository = RepositoryResolver.Current.ResolveByType<IUserRepository>(unitOfWork);
var users = CreateAndCommitMultipleUsers(repository, unitOfWork);
// Act
var query = Query<IUser>.Builder.Where(x => x.Username == "TestUser1" || x.Username == "TestUser2");
var result = repository.Count(query);
// Assert
Assert.That(result, Is.GreaterThanOrEqualTo(2));
}
[Test]
public void Can_Remove_Section_For_User()
{
// Arrange
var provider = new PetaPocoUnitOfWorkProvider();
var unitOfWork = provider.GetUnitOfWork();
var repository = RepositoryResolver.Current.ResolveByType<IUserRepository>(unitOfWork);
var users = CreateAndCommitMultipleUsers(repository, unitOfWork);
// Act
//add and remove a few times, this tests the internal collection
users[0].RemoveAllowedSection("content");
users[0].RemoveAllowedSection("content");
users[0].AddAllowedSection("content");
users[0].RemoveAllowedSection("content");
users[1].RemoveAllowedSection("media");
users[1].RemoveAllowedSection("media");
repository.AddOrUpdate(users[0]);
repository.AddOrUpdate(users[1]);
unitOfWork.Commit();
// Assert
var result = repository.GetAll((int) users[0].Id, (int) users[1].Id).ToArray();
Assert.AreEqual(1, result[0].AllowedSections.Count());
Assert.AreEqual("media", result[0].AllowedSections.First());
Assert.AreEqual(1, result[1].AllowedSections.Count());
Assert.AreEqual("content", result[1].AllowedSections.First());
}
[Test]
public void Can_Add_Section_For_User()
{
// Arrange
var provider = new PetaPocoUnitOfWorkProvider();
var unitOfWork = provider.GetUnitOfWork();
var repository = RepositoryResolver.Current.ResolveByType<IUserRepository>(unitOfWork);
var users = CreateAndCommitMultipleUsers(repository, unitOfWork);
// Act
//add and remove a few times, this tests the internal collection
users[0].AddAllowedSection("settings");
users[0].AddAllowedSection("settings");
users[0].RemoveAllowedSection("settings");
users[0].AddAllowedSection("settings");
users[1].AddAllowedSection("developer");
//add the same even though it's already there
users[2].AddAllowedSection("content");
repository.AddOrUpdate(users[0]);
repository.AddOrUpdate(users[1]);
unitOfWork.Commit();
// Assert
var result = repository.GetAll((int)users[0].Id, (int)users[1].Id, (int)users[2].Id).ToArray();
Assert.AreEqual(3, result[0].AllowedSections.Count());
Assert.IsTrue(result[0].AllowedSections.Contains("content"));
Assert.IsTrue(result[0].AllowedSections.Contains("media"));
Assert.IsTrue(result[0].AllowedSections.Contains("settings"));
Assert.AreEqual(3, result[1].AllowedSections.Count());
Assert.IsTrue(result[1].AllowedSections.Contains("content"));
Assert.IsTrue(result[1].AllowedSections.Contains("media"));
Assert.IsTrue(result[1].AllowedSections.Contains("developer"));
Assert.AreEqual(2, result[2].AllowedSections.Count());
Assert.IsTrue(result[1].AllowedSections.Contains("content"));
Assert.IsTrue(result[1].AllowedSections.Contains("media"));
}
[Test]
public void Can_Update_Section_For_User()
{
// Arrange
var provider = new PetaPocoUnitOfWorkProvider();
var unitOfWork = provider.GetUnitOfWork();
var repository = RepositoryResolver.Current.ResolveByType<IUserRepository>(unitOfWork);
var users = CreateAndCommitMultipleUsers(repository, unitOfWork);
// Act
users[0].RemoveAllowedSection("content");
users[0].AddAllowedSection("settings");
repository.AddOrUpdate(users[0]);
unitOfWork.Commit();
// Assert
var result = repository.Get((int)users[0].Id);
Assert.AreEqual(2, result.AllowedSections.Count());
Assert.IsTrue(result.AllowedSections.Contains("settings"));
Assert.IsTrue(result.AllowedSections.Contains("media"));
}
[Test]
public void Get_Users_Assigned_To_Section()
{
// Arrange
var provider = new PetaPocoUnitOfWorkProvider();
var unitOfWork = provider.GetUnitOfWork();
var repository = RepositoryResolver.Current.ResolveByType<IUserRepository>(unitOfWork);
var user1 = MockedUser.CreateUser(CreateAndCommitUserType(), "1", "test", "media");
var user2 = MockedUser.CreateUser(CreateAndCommitUserType(), "2", "media", "settings");
var user3 = MockedUser.CreateUser(CreateAndCommitUserType(), "3", "test", "settings");
repository.AddOrUpdate(user1);
repository.AddOrUpdate(user2);
repository.AddOrUpdate(user3);
unitOfWork.Commit();
// Act
var users = repository.GetUsersAssignedToSection("test");
// Assert
Assert.AreEqual(2, users.Count());
var names = users.Select(x => x.Username).ToArray();
Assert.IsTrue(names.Contains("TestUser1"));
Assert.IsTrue(names.Contains("TestUser3"));
}
private void AssertPropertyValues(IUser updatedItem, IUser originalUser)
{
Assert.That(updatedItem.Id, Is.EqualTo(originalUser.Id));
Assert.That(updatedItem.Name, Is.EqualTo(originalUser.Name));
Assert.That(updatedItem.DefaultPermissions, Is.EqualTo(originalUser.DefaultPermissions));
Assert.That(updatedItem.Language, Is.EqualTo(originalUser.Language));
Assert.That(updatedItem.IsApproved, Is.EqualTo(originalUser.IsApproved));
Assert.That(updatedItem.Password, Is.EqualTo(originalUser.Password));
Assert.That(updatedItem.NoConsole, Is.EqualTo(originalUser.NoConsole));
Assert.That(updatedItem.StartContentId, Is.EqualTo(originalUser.StartContentId));
Assert.That(updatedItem.StartMediaId, Is.EqualTo(originalUser.StartMediaId));
Assert.That(updatedItem.DefaultToLiveEditing, Is.EqualTo(originalUser.DefaultToLiveEditing));
Assert.That(updatedItem.Email, Is.EqualTo(originalUser.Email));
Assert.That(updatedItem.Username, Is.EqualTo(originalUser.Username));
Assert.That(updatedItem.AllowedSections.Count(), Is.EqualTo(2));
Assert.IsTrue(updatedItem.AllowedSections.Contains("media"));
Assert.IsTrue(updatedItem.AllowedSections.Contains("content"));
}
private IUser[] CreateAndCommitMultipleUsers(IUserRepository repository, IUnitOfWork unitOfWork)
{
var user1 = MockedUser.CreateUser(CreateAndCommitUserType(), "1");
var user2 = MockedUser.CreateUser(CreateAndCommitUserType(), "2");
var user3 = MockedUser.CreateUser(CreateAndCommitUserType(), "3");
repository.AddOrUpdate(user1);
repository.AddOrUpdate(user2);
repository.AddOrUpdate(user3);
unitOfWork.Commit();
return new IUser[] {user1, user2, user3};
}
private IUserType CreateAndCommitUserType()
{
var provider = new PetaPocoUnitOfWorkProvider();
var unitOfWork = provider.GetUnitOfWork();
var repository = RepositoryResolver.Current.ResolveByType<IUserTypeRepository>(unitOfWork);
var userType = MockedUserType.CreateUserType();
repository.AddOrUpdate(userType);
unitOfWork.Commit();
return userType;
}
}
}
@@ -0,0 +1,272 @@
using System.Linq;
using NUnit.Framework;
using Umbraco.Core.Models.Membership;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.Querying;
using Umbraco.Core.Persistence.Repositories;
using Umbraco.Core.Persistence.UnitOfWork;
using Umbraco.Tests.TestHelpers;
using Umbraco.Tests.TestHelpers.Entities;
namespace Umbraco.Tests.Persistence.Repositories
{
[TestFixture]
public class UserTypeRepositoryTest : BaseDatabaseFactoryTest
{
[SetUp]
public override void Initialize()
{
base.Initialize();
}
[TearDown]
public override void TearDown()
{
base.TearDown();
}
[Test]
public void Can_Instantiate_Repository()
{
// Arrange
var provider = new PetaPocoUnitOfWorkProvider();
var unitOfWork = provider.GetUnitOfWork();
// Act
var repository = RepositoryResolver.Current.ResolveByType<IUserTypeRepository>(unitOfWork);
// Assert
Assert.That(repository, Is.Not.Null);
}
[Test]
public void Can_Perform_Add_On_UserTypeRepository()
{
// Arrange
var provider = new PetaPocoUnitOfWorkProvider();
var unitOfWork = provider.GetUnitOfWork();
var repository = RepositoryResolver.Current.ResolveByType<IUserTypeRepository>(unitOfWork);
var userType = MockedUserType.CreateUserType();
// Act
repository.AddOrUpdate(userType);
unitOfWork.Commit();
// Assert
Assert.That(userType.HasIdentity, Is.True);
}
[Test]
public void Can_Perform_Multiple_Adds_On_UserTypeRepository()
{
// Arrange
var provider = new PetaPocoUnitOfWorkProvider();
var unitOfWork = provider.GetUnitOfWork();
var repository = RepositoryResolver.Current.ResolveByType<IUserTypeRepository>(unitOfWork);
var userType1 = MockedUserType.CreateUserType("1");
var userType2 = MockedUserType.CreateUserType("2");
// Act
repository.AddOrUpdate(userType1);
unitOfWork.Commit();
repository.AddOrUpdate(userType2);
unitOfWork.Commit();
// Assert
Assert.That(userType1.HasIdentity, Is.True);
Assert.That(userType2.HasIdentity, Is.True);
}
[Test]
public void Can_Verify_Fresh_Entity_Is_Not_Dirty()
{
// Arrange
var provider = new PetaPocoUnitOfWorkProvider();
var unitOfWork = provider.GetUnitOfWork();
var repository = RepositoryResolver.Current.ResolveByType<IUserTypeRepository>(unitOfWork);
var userType = MockedUserType.CreateUserType();
repository.AddOrUpdate(userType);
unitOfWork.Commit();
// Act
var resolved = repository.Get(userType.Id);
bool dirty = ((UserType)resolved).IsDirty();
// Assert
Assert.That(dirty, Is.False);
}
[Test]
public void Can_Perform_Update_On_UserTypeRepository()
{
// Arrange
var provider = new PetaPocoUnitOfWorkProvider();
var unitOfWork = provider.GetUnitOfWork();
var repository = RepositoryResolver.Current.ResolveByType<IUserTypeRepository>(unitOfWork);
var userType = MockedUserType.CreateUserType();
repository.AddOrUpdate(userType);
unitOfWork.Commit();
// Act
var resolved = repository.Get(userType.Id);
resolved.Name = "New Name";
resolved.Permissions = "ZYX";
repository.AddOrUpdate(resolved);
unitOfWork.Commit();
var updatedItem = repository.Get(userType.Id);
// Assert
Assert.That(updatedItem.Id, Is.EqualTo(resolved.Id));
Assert.That(updatedItem.Name, Is.EqualTo(resolved.Name));
Assert.That(updatedItem.Permissions, Is.EqualTo(resolved.Permissions));
}
[Test]
public void Can_Perform_Delete_On_UserTypeRepository()
{
// Arrange
var provider = new PetaPocoUnitOfWorkProvider();
var unitOfWork = provider.GetUnitOfWork();
var repository = RepositoryResolver.Current.ResolveByType<IUserTypeRepository>(unitOfWork);
var userType = MockedUserType.CreateUserType();
// Act
repository.AddOrUpdate(userType);
unitOfWork.Commit();
var id = userType.Id;
var repository2 = RepositoryResolver.Current.ResolveByType<IUserTypeRepository>(unitOfWork);
repository2.Delete(userType);
unitOfWork.Commit();
var resolved = repository2.Get(id);
// Assert
Assert.That(resolved, Is.Null);
}
[Test]
public void Can_Perform_Get_On_UserTypeRepository()
{
// Arrange
var provider = new PetaPocoUnitOfWorkProvider();
var unitOfWork = provider.GetUnitOfWork();
var repository = RepositoryResolver.Current.ResolveByType<IUserTypeRepository>(unitOfWork);
var userType = MockedUserType.CreateUserType();
repository.AddOrUpdate(userType);
unitOfWork.Commit();
// Act
var resolved = repository.Get(userType.Id);
// Assert
Assert.That(resolved.Id, Is.EqualTo(userType.Id));
//Assert.That(resolved.CreateDate, Is.GreaterThan(DateTime.MinValue));
//Assert.That(resolved.UpdateDate, Is.GreaterThan(DateTime.MinValue));
Assert.That(resolved.Name, Is.EqualTo(userType.Name));
Assert.That(resolved.Alias, Is.EqualTo(userType.Alias));
Assert.That(resolved.Permissions, Is.EqualTo(userType.Permissions));
}
[Test]
public void Can_Perform_GetByQuery_On_UserTypeRepository()
{
// Arrange
var provider = new PetaPocoUnitOfWorkProvider();
var unitOfWork = provider.GetUnitOfWork();
var repository = RepositoryResolver.Current.ResolveByType<IUserTypeRepository>(unitOfWork);
CreateAndCommitMultipleUserTypes(repository, unitOfWork);
// Act
var query = Query<IUserType>.Builder.Where(x => x.Alias == "testUserType1");
var result = repository.GetByQuery(query);
// Assert
Assert.That(result.Count(), Is.GreaterThanOrEqualTo(1));
}
[Test]
public void Can_Perform_GetAll_By_Param_Ids_On_UserTypeRepository()
{
// Arrange
var provider = new PetaPocoUnitOfWorkProvider();
var unitOfWork = provider.GetUnitOfWork();
var repository = RepositoryResolver.Current.ResolveByType<IUserTypeRepository>(unitOfWork);
var userTypes = CreateAndCommitMultipleUserTypes(repository, unitOfWork);
// Act
var result = repository.GetAll(userTypes[0].Id, userTypes[1].Id);
// Assert
Assert.That(result, Is.Not.Null);
Assert.That(result.Any(), Is.True);
Assert.That(result.Count(), Is.EqualTo(2));
}
[Test]
public void Can_Perform_GetAll_On_UserTypeRepository()
{
// Arrange
var provider = new PetaPocoUnitOfWorkProvider();
var unitOfWork = provider.GetUnitOfWork();
var repository = RepositoryResolver.Current.ResolveByType<IUserTypeRepository>(unitOfWork);
CreateAndCommitMultipleUserTypes(repository, unitOfWork);
// Act
var result = repository.GetAll();
// Assert
Assert.That(result, Is.Not.Null);
Assert.That(result.Any(), Is.True);
Assert.That(result.Count(), Is.GreaterThanOrEqualTo(3));
}
[Test]
public void Can_Perform_Exists_On_UserTypeRepository()
{
// Arrange
var provider = new PetaPocoUnitOfWorkProvider();
var unitOfWork = provider.GetUnitOfWork();
var repository = RepositoryResolver.Current.ResolveByType<IUserTypeRepository>(unitOfWork);
var userTypes = CreateAndCommitMultipleUserTypes(repository, unitOfWork);
// Act
var exists = repository.Exists(userTypes[0].Id);
// Assert
Assert.That(exists, Is.True);
}
[Test]
public void Can_Perform_Count_On_UserTypeRepository()
{
// Arrange
var provider = new PetaPocoUnitOfWorkProvider();
var unitOfWork = provider.GetUnitOfWork();
var repository = RepositoryResolver.Current.ResolveByType<IUserTypeRepository>(unitOfWork);
var userTypes = CreateAndCommitMultipleUserTypes(repository, unitOfWork);
// Act
var query = Query<IUserType>.Builder.Where(x => x.Alias == "testUserType1" || x.Alias == "testUserType2");
var result = repository.Count(query);
// Assert
Assert.That(result, Is.GreaterThanOrEqualTo(2));
}
private IUserType[] CreateAndCommitMultipleUserTypes(IUserTypeRepository repository, IUnitOfWork unitOfWork)
{
var userType1 = MockedUserType.CreateUserType("1");
var userType2 = MockedUserType.CreateUserType("2");
var userType3 = MockedUserType.CreateUserType("3");
repository.AddOrUpdate(userType1);
repository.AddOrUpdate(userType2);
repository.AddOrUpdate(userType3);
unitOfWork.Commit();
return new IUserType[] {userType1, userType2, userType3};
}
}
}
@@ -61,7 +61,7 @@ namespace Umbraco.Tests.PublishedCache
Assert.AreEqual(mRoot.Id, publishedMedia.Id);
Assert.AreEqual(mRoot.CreateDateTime.ToString("dd/MM/yyyy HH:mm:ss"), publishedMedia.CreateDate.ToString("dd/MM/yyyy HH:mm:ss"));
Assert.AreEqual(mRoot.User.Id, publishedMedia.CreatorId);
Assert.AreEqual(mRoot.User.Name, publishedMedia.CreatorName);
Assert.AreEqual(mRoot.User.LoginName, publishedMedia.CreatorName);
Assert.AreEqual(mRoot.ContentType.Alias, publishedMedia.DocumentTypeAlias);
Assert.AreEqual(mRoot.ContentType.Id, publishedMedia.DocumentTypeId);
Assert.AreEqual(mRoot.Level, publishedMedia.Level);
@@ -5,6 +5,7 @@ using Lucene.Net.Documents;
using Lucene.Net.Store;
using NUnit.Framework;
using Umbraco.Core.Configuration;
using Umbraco.Tests.TestHelpers;
using Umbraco.Tests.UmbracoExamine;
using umbraco.MacroEngines;
@@ -15,13 +16,13 @@ namespace Umbraco.Tests.PublishedContent
public override void TestSetup()
{
base.TestSetup();
UmbracoSettings.ForceSafeAliases = true;
UmbracoSettings.UmbracoLibraryCacheDuration = 1800;
UmbracoSettings.ForceSafeAliases = true;
SettingsForTests.ForceSafeAliases = true;
SettingsForTests.UmbracoLibraryCacheDuration = 1800;
}
public override void TestTearDown()
{
SettingsForTests.Reset();
base.TestTearDown();
}
@@ -38,10 +38,7 @@ namespace Umbraco.Tests.PublishedContent
{
base.Initialize();
UmbracoExamineSearcher.DisableInitializationCheck = true;
BaseUmbracoIndexer.DisableInitializationCheck = true;
UmbracoSettings.ForceSafeAliases = true;
UmbracoSettings.UmbracoLibraryCacheDuration = 1800;
UmbracoSettings.ForceSafeAliases = true;
BaseUmbracoIndexer.DisableInitializationCheck = true;
}
public override void TearDown()
@@ -0,0 +1,76 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<umbPackage>
<files />
<info>
<package>
<name>CheckboxListTest</name>
<version>1</version>
<license url="http://www.opensource.org/licenses/mit-license.php">MIT license</license>
<url>1</url>
<requirements>
<major>3</major>
<minor>0</minor>
<patch>0</patch>
</requirements>
</package>
<author>
<name>1</name>
<website>1</website>
</author>
<readme><![CDATA[]]></readme>
</info>
<Documents>
<DocumentSet importMode="root">
<NewType id="1148" parentID="-1" level="1" creatorID="0" sortOrder="9" createDate="2013-07-23T12:06:07" updateDate="2013-07-23T15:56:37" nodeName="DoIt" urlName="doit" path="-1,1148" isDoc="" nodeType="1134" creatorName="admin" writerName="admin" writerID="0" template="1133" nodeTypeAlias="NewType">
<testList><![CDATA[test3]]></testList>
</NewType>
</DocumentSet>
</Documents>
<DocumentTypes>
<DocumentType>
<Info>
<Name>NewType</Name>
<Alias>NewType</Alias>
<Icon>.sprTreeFolder</Icon>
<Thumbnail>folder.png</Thumbnail>
<Description>
</Description>
<AllowAtRoot>True</AllowAtRoot>
<AllowedTemplates>
<Template>NewType</Template>
</AllowedTemplates>
<DefaultTemplate>NewType</DefaultTemplate>
</Info>
<Structure />
<GenericProperties>
<GenericProperty>
<Name>testList</Name>
<Alias>testList</Alias>
<Type>b4471851-82b6-4c75-afa4-39fa9c6a75e9</Type>
<Definition>8dacee1a-1bbd-46c0-b07f-8ffd49fcca7c</Definition>
<Tab>
</Tab>
<Mandatory>False</Mandatory>
<Validation>
</Validation>
<Description><![CDATA[]]></Description>
</GenericProperty>
</GenericProperties>
<Tabs />
</DocumentType>
</DocumentTypes>
<Templates />
<Stylesheets />
<Macros />
<DictionaryItems />
<Languages />
<DataTypes>
<DataType Name="NewCheckBox" Id="b4471851-82b6-4c75-afa4-39fa9c6a75e9" Definition="8dacee1a-1bbd-46c0-b07f-8ffd49fcca7c" DatabaseType="Nvarchar">
<PreValues>
<PreValue Id="59" Value="test" />
<PreValue Id="60" Value="test3" />
<PreValue Id="61" Value="test2" />
</PreValues>
</DataType>
</DataTypes>
</umbPackage>
@@ -1,7 +1,7 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.18033
// Runtime Version:4.0.30319.18213
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
@@ -60,6 +60,34 @@ namespace Umbraco.Tests.Services.Importing {
}
}
/// <summary>
/// Looks up a localized string similar to &lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;
///&lt;umbPackage&gt;
/// &lt;files /&gt;
/// &lt;info&gt;
/// &lt;package&gt;
/// &lt;name&gt;CheckboxListTest&lt;/name&gt;
/// &lt;version&gt;1&lt;/version&gt;
/// &lt;license url=&quot;http://www.opensource.org/licenses/mit-license.php&quot;&gt;MIT license&lt;/license&gt;
/// &lt;url&gt;1&lt;/url&gt;
/// &lt;requirements&gt;
/// &lt;major&gt;3&lt;/major&gt;
/// &lt;minor&gt;0&lt;/minor&gt;
/// &lt;patch&gt;0&lt;/patch&gt;
/// &lt;/requirements&gt;
/// &lt;/package&gt;
/// &lt;author&gt;
/// &lt;name&gt;1&lt;/name&gt;
/// &lt;website&gt;1&lt;/website&gt;
/// &lt;/author&gt;
/// &lt;r [rest of string was truncated]&quot;;.
/// </summary>
internal static string CheckboxList_Content_Package {
get {
return ResourceManager.GetString("CheckboxList_Content_Package", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to &lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;
///&lt;umbPackage&gt;
@@ -139,4 +139,7 @@
<data name="TemplateOnly_Updated_Package" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>templateonly-updated-package.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data>
<data name="CheckboxList_Content_Package" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>checkboxlist-content-package.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data>
</root>
@@ -1,6 +1,9 @@
using System.Linq;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using NUnit.Framework;
using Umbraco.Core.Models.Rdbms;
using umbraco.editorControls.MultiNodeTreePicker;
namespace Umbraco.Tests.Services.Importing
{
@@ -213,6 +216,42 @@ namespace Umbraco.Tests.Services.Importing
Assert.That(contents.Count(), Is.EqualTo(numberOfDocs));
}
[Test]
public void PackagingService_Can_Import_CheckboxList_Content_Package_Xml()
{
// Arrange
string strXml = ImportResources.CheckboxList_Content_Package;
var xml = XElement.Parse(strXml);
var dataTypeElement = xml.Descendants("DataTypes").First();
var docTypesElement = xml.Descendants("DocumentTypes").First();
var element = xml.Descendants("DocumentSet").First();
var packagingService = ServiceContext.PackagingService;
// Act
var dataTypeDefinitions = packagingService.ImportDataTypeDefinitions(dataTypeElement);
var contentTypes = packagingService.ImportContentTypes(docTypesElement);
var contents = packagingService.ImportContent(element);
var numberOfDocs = (from doc in element.Descendants()
where (string) doc.Attribute("isDoc") == ""
select doc).Count();
var database = ApplicationContext.DatabaseContext.Database;
var dtos = database.Fetch<DataTypePreValueDto>("WHERE datatypeNodeId = @Id", new { dataTypeDefinitions.First().Id });
int preValueId;
int.TryParse(contents.First().GetValue<string>("testList"), out preValueId);
var preValueKey = dtos.SingleOrDefault(x => x.Id == preValueId);
// Assert
Assert.That(dataTypeDefinitions, Is.Not.Null);
Assert.That(dataTypeDefinitions.Any(), Is.True);
Assert.That(contents, Is.Not.Null);
Assert.That(contentTypes.Any(), Is.True);
Assert.That(contents.Any(), Is.True);
Assert.That(contents.Count(), Is.EqualTo(numberOfDocs));
Assert.That(preValueKey, Is.Not.Null);
Assert.That(preValueKey.Value, Is.EqualTo("test3"));
}
[Test]
public void PackagingService_Can_Import_Templates_Package_Xml_With_Invalid_Master()
{
+92 -4
View File
@@ -1,4 +1,5 @@
using System;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using NUnit.Framework;
@@ -32,13 +33,13 @@ namespace Umbraco.Tests.Services
var userType = userService.GetUserTypeByAlias("admin");
// Act
var membershipUser = userService.CreateUser("John Doe", "john@umbraco.io", "12345", userType, "john@umbraco.io");
var membershipUser = userService.CreateMembershipUser("John Doe", "john@umbraco.io", "12345", userType, "john@umbraco.io");
// Assert
Assert.That(membershipUser.HasIdentity, Is.True);
IUser user = membershipUser as User;
Assert.That(user, Is.Not.Null);
Assert.That(user.Permissions, Is.EqualTo(userType.Permissions));
Assert.That(user.DefaultPermissions, Is.EqualTo(userType.Permissions));
}
[Test]
@@ -54,7 +55,7 @@ namespace Umbraco.Tests.Services
var hash = new HMACSHA1();
hash.Key = Encoding.Unicode.GetBytes(password);
var encodedPassword = Convert.ToBase64String(hash.ComputeHash(Encoding.Unicode.GetBytes(password)));
var membershipUser = userService.CreateUser("John Doe", "john@umbraco.io", encodedPassword, userType, "john@umbraco.io");
var membershipUser = userService.CreateMembershipUser("John Doe", "john@umbraco.io", encodedPassword, userType, "john@umbraco.io");
// Assert
Assert.That(membershipUser.HasIdentity, Is.True);
@@ -62,7 +63,94 @@ namespace Umbraco.Tests.Services
Assert.That(membershipUser.Password, Is.EqualTo(encodedPassword));
IUser user = membershipUser as User;
Assert.That(user, Is.Not.Null);
Assert.That(user.Permissions, Is.EqualTo(userType.Permissions));
Assert.That(user.DefaultPermissions, Is.EqualTo(userType.Permissions));
}
[Test]
public void Can_Remove_Section_From_All_Assigned_Users()
{
var userType = ServiceContext.UserService.GetUserTypeByAlias("admin");
//we know this actually is an IUser so we'll just cast
var user1 = (IUser)ServiceContext.UserService.CreateMembershipUser("test1", "test1", "test1", userType, "test1@test.com");
var user2 = (IUser)ServiceContext.UserService.CreateMembershipUser("test2", "test2", "test2", userType, "test2@test.com");
//adds some allowed sections
user1.AddAllowedSection("test");
user2.AddAllowedSection("test");
ServiceContext.UserService.SaveUser(user1);
ServiceContext.UserService.SaveUser(user2);
//now clear the section from all users
ServiceContext.UserService.DeleteSectionFromAllUsers("test");
//assert
var result1 = ServiceContext.UserService.GetUserById((int)user1.Id);
var result2 = ServiceContext.UserService.GetUserById((int)user2.Id);
Assert.IsFalse(result1.AllowedSections.Contains("test"));
Assert.IsFalse(result2.AllowedSections.Contains("test"));
}
[Test]
public void Get_By_Profile_Username()
{
// Arrange
var userType = ServiceContext.UserService.GetUserTypeByAlias("admin");
var user = (IUser)ServiceContext.UserService.CreateMembershipUser("test1", "test1", "test1", userType, "test1@test.com");
// Act
var profile = ServiceContext.UserService.GetProfileByUserName(user.Username);
// Assert
Assert.IsNotNull(profile);
Assert.AreEqual(user.Username, profile.Name);
Assert.AreEqual(user.Id, profile.Id);
}
[Test]
public void Get_By_Profile_Id()
{
// Arrange
var userType = ServiceContext.UserService.GetUserTypeByAlias("admin");
var user = (IUser)ServiceContext.UserService.CreateMembershipUser("test1", "test1", "test1", userType, "test1@test.com");
// Act
var profile = ServiceContext.UserService.GetProfileById((int)user.Id);
// Assert
Assert.IsNotNull(profile);
Assert.AreEqual(user.Username, profile.Name);
Assert.AreEqual(user.Id, profile.Id);
}
[Test]
public void Get_User_By_Username()
{
// Arrange
var userType = ServiceContext.UserService.GetUserTypeByAlias("admin");
var originalUser = (IUser)ServiceContext.UserService.CreateMembershipUser("test1", "test1", "test1", userType, "test1@test.com");
// Act
var updatedItem = ServiceContext.UserService.GetUserByUserName(originalUser.Username);
// Assert
Assert.IsNotNull(updatedItem);
Assert.That(updatedItem.Id, Is.EqualTo(originalUser.Id));
Assert.That(updatedItem.Name, Is.EqualTo(originalUser.Name));
Assert.That(updatedItem.DefaultPermissions, Is.EqualTo(originalUser.DefaultPermissions));
Assert.That(updatedItem.Language, Is.EqualTo(originalUser.Language));
Assert.That(updatedItem.IsApproved, Is.EqualTo(originalUser.IsApproved));
Assert.That(updatedItem.Password, Is.EqualTo(originalUser.Password));
Assert.That(updatedItem.NoConsole, Is.EqualTo(originalUser.NoConsole));
Assert.That(updatedItem.StartContentId, Is.EqualTo(originalUser.StartContentId));
Assert.That(updatedItem.StartMediaId, Is.EqualTo(originalUser.StartMediaId));
Assert.That(updatedItem.DefaultToLiveEditing, Is.EqualTo(originalUser.DefaultToLiveEditing));
Assert.That(updatedItem.Email, Is.EqualTo(originalUser.Email));
Assert.That(updatedItem.Username, Is.EqualTo(originalUser.Username));
Assert.That(updatedItem.AllowedSections.Count(), Is.EqualTo(0));
}
}
}
@@ -18,6 +18,11 @@ namespace Umbraco.Tests.TestHelpers
{
TestHelper.SetupLog4NetForTests();
TestHelper.InitializeContentDirectories();
SettingsForTests.UseLegacyXmlSchema = false;
SettingsForTests.ForceSafeAliases = true;
SettingsForTests.UmbracoLibraryCacheDuration = 1800;
SetupPluginManager();
FreezeResolution();
@@ -0,0 +1,46 @@
using System.Linq;
using Umbraco.Core.Models.Membership;
namespace Umbraco.Tests.TestHelpers.Entities
{
public class MockedUser
{
internal static User CreateUser(IUserType userType = null, string suffix = "", params string[] allowedSections)
{
if (userType == null)
{
userType = MockedUserType.CreateUserType();
}
var user = new User(userType)
{
Language = "en",
IsApproved = true,
Name = "TestUser" + suffix,
Password = "testing",
NoConsole = false,
DefaultPermissions = "ABC",
StartContentId = -1,
StartMediaId = -1,
DefaultToLiveEditing = false,
Email = "test" + suffix + "@test.com",
Username = "TestUser" + suffix
};
if (allowedSections.Any())
{
foreach (var s in allowedSections)
{
user.AddAllowedSection(s);
}
}
else
{
user.AddAllowedSection("content");
user.AddAllowedSection("media");
}
return user;
}
}
}
@@ -0,0 +1,17 @@
using Umbraco.Core.Models.Membership;
namespace Umbraco.Tests.TestHelpers.Entities
{
public class MockedUserType
{
internal static UserType CreateUserType(string suffix = "")
{
return new UserType()
{
Alias = "testUserType" + suffix,
Name = "TestUserType" + suffix,
Permissions = "ABC"
};
}
}
}
@@ -11,6 +11,12 @@ namespace Umbraco.Tests.TestHelpers
{
// umbracoSettings
public static int UmbracoLibraryCacheDuration
{
get { return UmbracoSettings.UmbracoLibraryCacheDuration; }
set { UmbracoSettings.UmbracoLibraryCacheDuration = value; }
}
public static bool UseLegacyXmlSchema
{
get { return UmbracoSettings.UseLegacyXmlSchema; }
@@ -35,6 +41,12 @@ namespace Umbraco.Tests.TestHelpers
set { UmbracoSettings.SettingsFilePath = value; }
}
public static bool ForceSafeAliases
{
get { return UmbracoSettings.ForceSafeAliases; }
set { UmbracoSettings.ForceSafeAliases = value; }
}
// from appSettings
private static readonly IDictionary<string, string> SavedAppSettings = new Dictionary<string, string>();

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