Compare commits

...

171 Commits

Author SHA1 Message Date
Sebastiaan Janssen 4d3eef1124 Update version 2014-03-07 15:25:10 +01:00
Shannon 3e6e6faf03 Merge branch '6.2.0' of https://github.com/umbraco/Umbraco-CMS into 6.2.0 2014-03-07 20:08:22 +11:00
Shannon b3f18bc677 fixed an issue with setting password with legacy api 2014-03-07 20:08:10 +11:00
Sebastiaan Janssen a48fe40675 Also clean up v6 snippets 2014-03-07 09:46:45 +01:00
Shannon 1511ad58b2 oops, put back the defaults for umbracoSettings 2014-03-06 20:16:55 +11:00
Shannon 2e9b751174 Merge branch '6.2.0' of https://github.com/umbraco/Umbraco-CMS into 6.2.0 2014-03-06 20:12:21 +11:00
Shannon d61ab97be3 Fixes: U4-4217 Ensure that the cmsTask data is cleared for any entity that uses umbracoNode table 2014-03-06 20:12:05 +11:00
Stephan dd40d73b71 Merge remote-tracking branch 'origin/6.2.0' into 6.2.0 2014-03-06 10:06:50 +01:00
Shannon 068bca84b7 Fixes: U4-156 Drag / drop support 2014-03-06 20:05:13 +11:00
Shannon 0fda528b94 Fixes: U4-1550 Publish notifications on a load balanced environment 2014-03-06 19:47:23 +11:00
Shannon 3552f63d87 Merge branch '6.2.0' of https://github.com/umbraco/Umbraco-CMS into 6.2.0 2014-03-06 19:29:35 +11:00
Shannon 01d04fde37 Fixes: U4-4060 Rollback feature does not show differences 2014-03-06 19:29:09 +11:00
Stephan 7f8c526136 Fix TryConvertTo handling of number decimal separator 2014-03-06 09:14:05 +01:00
Stephan ea4be14f0c Fix 026d040 - keep Standalone stuff internal 2014-03-06 09:10:14 +01:00
Stephan 20df48e2f0 Merge remote-tracking branch 'origin/6.2.0' into 6.2.0 2014-03-06 08:49:38 +01:00
Stephan 2c0f6f975c Bugfix UmbracoEntity ctor test 2014-03-06 08:42:41 +01:00
Shannon fa7f91b39d Merge branch '6.2.0' of https://github.com/umbraco/Umbraco-CMS into 6.2.0 2014-03-06 18:26:10 +11:00
Shannon 72c5853fb1 Completes: U4-3937 Ensure media is indexed across all servers in LB environment with Distributed Cache calls
for members
2014-03-06 18:25:38 +11:00
Stephan f03b1a22f9 Merge remote-tracking branch 'origin/6.2.0' into 6.2.0 2014-03-06 08:12:51 +01:00
Shannon e7fb6e5beb Streamlines member and user services CreateMemberWithIdentity to be similar to media/content and not have a raise events flag. Also implements the CreateWithIdentity explicitly 2014-03-06 18:07:02 +11:00
Shannon d0cc93d6a2 Fixes: U4-3937 Ensure media is indexed across all servers in LB environment with Distributed Cache calls
This fix is for media indexes to be distributed properly and for unpublished content to be distributed properly, now to get members to do the same.
2014-03-06 17:50:08 +11:00
Shannon 4adc2562b1 Fixes issue with ugolive dashboard trying to load in knockout from a bundle which causes the examine mgr to fail 2014-03-06 17:49:09 +11:00
Shannon ba6878666c Fixes pretty ugly issue of the Saving/Saved events not being raised when using CreateWithIdentity 2014-03-06 17:35:47 +11:00
Stephan 792ab8d088 Introduce support for content fragments 2014-03-05 15:46:37 +01:00
Stephan 3d4409e52a Refactor CacheRefreshersResolver.CacheResolvers into .CacheRefreshers 2014-03-05 15:46:35 +01:00
Stephan acd377956f Improve how DomainHelper determines domain 2014-03-05 15:46:34 +01:00
Stephan 3b6dcc3421 Factor Dictionary.ReplaceKey method 2014-03-05 15:46:33 +01:00
Stephan cec4d41df7 Add comments to UmbracoViewPageOfTModel 2014-03-05 15:46:32 +01:00
Stephan ff0bcffefa Implement DefaultShortStringHelper.PostFilter to cut url segments at 240 chars 2014-03-05 15:46:31 +01:00
Stephan 5dbc72897a Add method to reset PublishedContentRequest template 2014-03-05 15:46:30 +01:00
Stephan 83736bec01 U4-4190 - enable retrieval of wildcard domains 2014-03-05 15:46:29 +01:00
Stephan 2f953c3819 Fix a38e0dc - use UInt64 instead of int 2014-03-05 15:46:28 +01:00
Stephan 026d040a62 Enable StandaloneApplication to work with Powershell 2014-03-05 15:39:16 +01:00
Stephan 7747b8f64f U4-3579 - support chars such as <, > or & in prevalues 2014-03-05 15:33:15 +01:00
Shannon feb9f40237 updates some ctors on umbraco context and routing context to have lazy overloads which allows us to more easily create/mock the umbraco context. 2014-03-03 04:16:09 +01:00
Shannon 651182f5de Fixes sql statement - to be like we have in v7 that supports all sql servers 2014-02-25 02:37:48 +11:00
Shannon 22b15a06f6 Fixes how member is approved is set by defaut and adds unit test for it. Also ensures that it returns true if the property value is invalid for whatever odd reason. 2014-02-25 02:10:25 +11:00
Shannon cb09795280 Removes new member service Creating event, as only Created makes sense. Deprecates the other 'Creating' events with a note to just use the Created event. 2014-02-25 01:45:41 +11:00
Sebastiaan Janssen a5637af2d8 Adding missing CreateMember method that also as a convenience allows you to pass in the member type alias instead of a whole membertype 2014-02-22 18:32:26 +01:00
Sebastiaan Janssen ac59c5deb0 Fixing some potential upgrade issues and two issues found with the legacy member API
- For legacy API we never had and "approved" checkbox, so the assumption is that members are always approved
- The RequiresUniqueEmail check was wrong, previously the assumption was: if there's no e-mail then don't check for uniqueness
2014-02-22 16:44:02 +01:00
Sebastiaan Janssen 683ddf6d34 Apparently we rely on <error404>1</error404> to be in umbracoSettings.config 2014-02-22 16:03:59 +01:00
Sebastiaan Janssen eda33b1ac4 Update incorrect summary 2014-02-22 14:47:59 +01:00
Sebastiaan Janssen ed0f884348 Been a while: properly syncing /config/*.config with /config/*.Release.config 2014-02-21 17:50:58 +01:00
Sebastiaan Janssen b561351340 Update UI.Release.xml with the correct Partial View references 2014-02-21 17:33:19 +01:00
Sebastiaan Janssen 690ab29863 Use the database "agnostic" query for this (see U4-3876) 2014-02-21 17:01:59 +01:00
Shannon 27cb1d5223 completes: U4-4275 Hide built-in member type properties from the insert umbraco field list 2014-02-21 16:20:07 +11:00
Shannon c677f36f08 Changes some of the naming conventions for the underlying membership provider services bits. 2014-02-21 16:03:32 +11:00
Shannon 750f7a6b33 Updates some method names to be less confusing regarding permissions 2014-02-21 15:55:56 +11:00
Shannon dea804b402 fixes some permission logic and a unit test 2014-02-21 15:46:39 +11:00
Shannon 3803d1d7da fixes reflected property on dynamicnode and unit test 2014-02-21 15:22:02 +11:00
Shannon 3e67b3034d Added the ability to specify explicit db type's for a property type using an overloaded ctor argument. This allows us to specify explicit db types for properties without having them get overwritten during the repository saving logic which will always reset it to be the db type of the underlying property editor. In the case of our built-in membership properties we do not want this to happen. Fixes some unit tests. Removes built-in props from being included in the property types on the profile model on the front-end. 2014-02-21 12:56:00 +11:00
Shannon 1ada5210ad updated to latest examine 2014-02-21 09:54:53 +11:00
Shannon 9a608674eb fixes another test 2014-02-20 23:11:27 +11:00
Shannon 7dae412a29 fixes most of the newly failing unit tests and adds better null checking 2014-02-20 23:00:04 +11:00
Shannon a1067e676f publicizes some repository factory methods and interfaces 2014-02-20 21:56:58 +11:00
Shannon ce649f54d7 Upgraded to latest examine, completes: U4-4240 Update with new examine version 0.1.53 2014-02-20 15:01:47 +11:00
Shannon d159792256 Updates last step of installer logic, we don't care about other providers as that would never have worked anyways 2014-02-20 14:38:00 +11:00
Shannon 606b5aa60a fixes logic in membershiphelper updatemember 2014-02-20 13:55:56 +11:00
Shannon a206652a0d updates login redirect logic to be more inline with v7, less greedy which is better. 2014-02-20 13:37:12 +11:00
Shannon 545040fdf0 Fixes installer upgrade 2014-02-20 13:09:54 +11:00
Shannon 40d1a09609 Updates the membership helper in how it updates the membership provider data, updates the editMember page to update the membership provider properties all via the membership provider 2014-02-19 23:49:53 +11:00
Shannon 2e25bc8fdb Moves all FindCOntrolRecursive calls to an extension method 2014-02-19 23:49:08 +11:00
Shannon 1618ac86b8 Adds implicit bool operator for Attempt, makes things nicer to check for success :) 2014-02-19 22:45:22 +11:00
Shannon a4adbca12c Removes the ability to edit the data type for a built-in membership property. Ensures that even if a data type is attempted to be changed with the API that the built-in properties are always persisted with the data type that we have defined by convention. 2014-02-19 21:56:33 +11:00
Shannon 8728e2f918 Fixes: U4-4260 When changing sort order on member type and saving, this doesn't get reflected on the member 2014-02-19 20:17:21 +11:00
Shannon cd53682ddb removes ability to configure custom fields for the new membership provider 2014-02-19 17:52:45 +11:00
Shannon e2d5fbf545 Fixes issue with ensuring properties on entities when a new property type has been created - but if the property type doesn't have an id, we should ignore it. 2014-02-19 17:27:08 +11:00
Shannon d339e7c814 updates the property type editability for built in member types 2014-02-19 16:57:33 +11:00
Shannon 078deb704b Completes: U4-4255 Add readonly membership provider properties to the profile model 2014-02-19 16:27:14 +11:00
Shannon 6858eb3330 Fixes: U4-4257 Fix member type editor to not have to re-call 'Save' so many times,
streamlines how the show property and editable property on member type's are dealt with (removes tuples)
2014-02-19 16:14:34 +11:00
Shannon e267b7700a Ensures that member properties are created when member type property type's are added (same as U4-1407), streamlines how this occurs on the base class. Streamlines how empty aliases are validated at the repo level for members, media, content. Makes built-in member property type's non-editable 2014-02-19 14:23:48 +11:00
Shannon 1e45abe71e oops, changes the failedpassattempts back to noedit 2014-02-18 17:58:57 +11:00
Shannon a556b4ed21 Logs warnings if accessing built-in properties on the member model but the underlying property type is missing. 2014-02-18 17:53:02 +11:00
Shannon 953c711ca4 Updates the default member type property types to use "Labels", then needed to update the member type repo and membertypereadonlyfactory to ensure that even though the underlying data type for the property exposes a different Db Type that we 'reset' that Db Type to what it always should be. This means that no matter what underlying data type a developer changes a property to, if it is a built-in membership property, the Db Type will always stay consistent and save in the correct column. Of course if someone enters some invalid data, then the data will not be saved. 2014-02-18 17:19:38 +11:00
Shannon f06c9e8235 Ensures the default member type properties are put on a custom tab 2014-02-18 15:39:00 +11:00
Shannon f1a439e851 removes version specific references to mysql in the proj files and web.config
ensures that escaping in the sql expression classes is done correctly without any double escaping. Also ensures that escaping is happening using the equals operator, not just the Equals() method and adds unit tests for them.
Fixes: U4-4232 Umbraco.Core.Persistence.Querying issue with backslashes
2014-02-18 14:57:03 +11:00
Shannon a0e496e589 Merge branch '6.2.0' of https://github.com/umbraco/Umbraco-CMS into 6.2.0 2014-02-17 21:38:38 +11:00
Shannon e0dcc3afbc Streamlines how strings are escaped with the sql expression helpers and syntax providers. Fixes: U4-4232 Umbraco.Core.Persistence.Querying issue with backslashes 2014-02-17 21:38:13 +11:00
Stephan 3634a77d61 U4-4241 - UrlAbsolute() returns relative urls 2014-02-17 10:47:51 +01:00
Shannon 846f4b5b6c Removes the various old hacks for the legacy user's membership provider, now that we have the AllowManuallyChangingPassword flag, these hacks are not required. 2014-02-17 19:32:04 +11:00
Shannon 2869f17eff ensures the default property aliases are set during ctor 2014-02-17 18:02:29 +11:00
Shannon feefb052fd Updates the BulkInsertRecords method to optionally close the trans - shouldn't by default. Updates how permissions are handled in the new services and exposes another method, ensures it's all wrapped in trans and ensures that cache is cleared properly. Fixes: U4-4213 "Replace child node permissions" does not work if all permissions cleared 2014-02-17 17:45:59 +11:00
Shannon 4d2d9156ba updates more plugin manager defs 2014-02-17 15:58:57 +11:00
Shannon 82ba1a24a3 Ensures we perform null checks in both GetAll and GetByQuery as we never want to include a null item in the resultant collection - which could happen depending on what the sub class repository is doing.
Fixes: U4-3145 Cache file periodically becomes corrupted: "Oops: this document is published but is not in the cache (internal error)"
2014-02-17 15:45:36 +11:00
Shannon 357db9d0b6 completes: U4-3282 Expose permission assignment methods at the service layer 2014-02-17 15:33:17 +11:00
Shannon 61766287bc Cleans up some more of the old 'object' User Id references. 2014-02-17 15:26:38 +11:00
Shannon ffbf8b2fd6 completes: U4-4103 Publicize PluginManager for devs to use to create their own plugins 2014-02-17 15:08:27 +11:00
Shannon f7a703195c Fixes: U4-4215 Tree.config registeres tree inconsistently 2014-02-17 14:56:12 +11:00
Shannon 509be9b431 Updates the underlying UmbracoServiceMembershipProvider to deal with 'object' for provider key, this then lets us deal with either guid or int for the new membership provider, just like the old one does. 2014-02-17 14:14:17 +11:00
Shannon 10ef5eb7bc adds new interface for members' membership providers to implement so we know what aliases to store data against. 2014-02-17 13:16:28 +11:00
Shannon 2849ecadb7 fix legacy member wrapping new api and mixing email/login name 2014-02-17 12:24:11 +11:00
Shannon 697f93c3ce removes null check for LoginName, since it gets set to the name passed in if it is empty 2014-02-17 12:09:27 +11:00
Shannon 18121e8726 Enxures user start node's are -1 by default when creating the model. 2014-02-17 11:48:32 +11:00
Shannon 81cdc71145 Ensures new user objects are approved by default. 2014-02-17 11:17:15 +11:00
Shannon 4069fc8d1f fixes issue with legacy user.Password property and fixes comparison of sections 2014-02-13 17:19:28 +11:00
Shannon 0a80c39962 Fixes merge 2014-02-13 15:25:57 +11:00
Florian Verdonck edee8134c2 Updated request after feedback 2014-02-13 15:21:40 +11:00
Shannon 30a73c0886 updated web.config template to use new role provider. 2014-02-13 14:45:24 +11:00
Shannon f5ee02a3e9 Updates the membership partial view templates to redirect to current page by default but allows this to be overridden. Creates a new RedirectToCurrentUmbracoUrl method which is slightly diff from RedirectToCurrentUmbracoPage since it doesn't care about the actual page item rendering, just the currently rendered URL which is useful if coming from a rewritten URL (which is what happens with public access rewrites) 2014-02-13 13:30:32 +11:00
Shannon 9827b40bea Fixes: U4-4223 MVC based forms with SurfaceControllers don't work when rendered in Webforms mode.
This slightly changes how the routing works in the module, now we always send the request to the RenderRouteHandler, this will first process the logic for route hijacking, then it will determine if the request was found to be a WebForms template, if so then we'll return the webforms handler. This also now allows us to have POSTed values to SurfaceController's from forms that have been rendered in Webforms whilst maintaining all viewdata, tempdata and model state on postback even when rendering in webforms!
2014-02-13 13:19:51 +11:00
Stephan f9323c85e4 Fix issue with 9d7b3b96 in .designer.cs file 2014-02-12 13:22:35 +01:00
Stephan 2677672e50 Merge remote-tracking branch 'origin/6.2.0' into 6.2.0 2014-02-12 13:22:30 +01:00
Morten Christensen a38e0dcf86 Adding integer overload for UmbracoEntity so it can be used with a dynamic object containing either a boolean or integer retrieved from the database to initialize the UmbracoEntity object. 2014-02-12 12:47:47 +01:00
Stephan fdd7227494 Fix DynamicPublishedContent to use CleanStringType.ConvertCase 2014-02-12 10:46:57 +01:00
Stephan 6b74e14cdd Backport DefaultShortStringHelper from 7.1 2014-02-12 10:40:00 +01:00
Shannon 9d7b3b965a fixes some issues with new bundles. 2014-02-12 18:19:20 +11:00
Shannon 806008a7e9 Fixes issue with @ symbols in login name and a member group query 2014-02-12 18:02:00 +11:00
Shannon 45fa192c95 Fixes some unit tests 2014-02-12 17:25:45 +11:00
Shannon 92235128f1 Got new MemberGroupService done, completed the MemberService for role based stuff, created a member group cache refresher since we are caching member groups by name (probably should cache others too). Public access stuff changes if a name of a member group is changed which is now done with an event instead of coded into the biz logic. 2014-02-12 17:14:16 +11:00
Shannon 7622937cfd implemented remaining methods for member groups/roles + unit tests 2014-02-11 20:38:48 +11:00
Shannon bf41694572 Fixed up some more of the member group + member stuff with more unit tests 2014-02-11 19:21:36 +11:00
Shannon 7b897ce64c Member group repo updated along with the member service to support roles, etc... got first of many unit tests passing. 2014-02-11 12:43:55 +11:00
Shannon 1ca950f721 Starts creating the IMemberGroupService and supporting classes. 2014-02-10 19:48:16 +11:00
Shannon ffba271fd0 Creates the MemberGroupRepository and supporting models. 2014-02-10 19:35:32 +11:00
Shannon ec08d3e910 Updates MembershipHelper to not change the email/name if the value has not changed. Updates the templates to show only validation summaries for their own values/prefixes. Fixes some underlying MVC methods that merge view state to ensure the prefixes work with validation summaries properly when not showing property level errors. Updates the Umb controllers to add model level validation msgs when failed. 2014-02-10 18:34:12 +11:00
Shannon 0bfd032fad Obsoletes the RedirectOnSucces on the RegisterModel as it is not needed. Adds RedirectUrl to the ProfileModel and updates the controller to redirect properly (ensures it doesn't just redirect to home!) 2014-02-10 16:46:45 +11:00
Shannon 2bb58b6fca Updates MembershipHelper to ensure that the membership provider is used when updating a profile, specifically to deal with unique emails. Updates the profile edit template to have correct validation procedures. 2014-02-10 16:22:15 +11:00
Shannon 4d2d656b3d Moved ChangePassword method to MembershipHelper and makes it public, adds an overload. 2014-02-10 14:29:29 +11:00
Shannon fa625d72f9 updates some comments 2014-02-10 14:12:44 +11:00
Shannon 1991380e02 Changes CDF version to be the hash code of UTC now 2014-02-10 13:53:12 +11:00
Shannon 3b8d6dc2c7 Merge remote-tracking branch 'origin/6.2.0' into 6.2.0 2014-02-10 13:50:43 +11:00
Shannon 1faeb76c27 Removes the need for duplicate templates for partial views. Of course we can have partial view only templates if necessary but currently we just borrow them from the partial view macros and update the header 2014-02-10 13:50:31 +11:00
Sebastiaan Janssen 3a513668fd U4-4185 Log fails to show unicode (cyrillic) characters 2014-02-05 15:52:20 +01:00
Stephan 3ef51d7357 U4-2317 - issue with domains & languages management 2014-01-30 16:18:06 +01:00
Stephan 8b553dd067 U4-4144 - work around media cache exceptions on invalid properties 2014-01-29 19:30:17 +01:00
Shannon ccaf82d797 Fixes object extensions for dates with a 'kind' specified. 2014-01-29 11:21:35 +11:00
Shannon f28ae52ae3 moved logic to update a profile to MembershipHelper. 2014-01-28 21:57:00 +11:00
Shannon cfd0973f00 Moves the registration logic to the MembershipHelper, fixes up the views to keep the indexes so props save. 2014-01-28 21:42:30 +11:00
Shannon 1bfdd83ba7 Cleans up more of the membership controllers and snippets to be using the membership helper and fixes up a few issues 2014-01-28 19:41:21 +11:00
Shannon 6fefcacc61 Adds more methods to the MembershipHelper, updates the RegisterModel and obsoletes the standard ctor so biz logic is not happening in the model, updates the snippets to use the correct way. Fixes an issue in the membership repo for persisting new members when the member type doesn't contain all the built-in props. 2014-01-28 18:59:27 +11:00
Shannon 3b639e61b2 Exposes MembershipHelper onthe UmbracoViewPage so people can use it directly in views. 2014-01-28 17:02:20 +11:00
Shannon 9959ff667e publicizes MembershipHelper and exposes it on the various base classes: SurfaceController, UmbracoApiController and UmbracoUserControl as the property "Members", will add more helper methods. 2014-01-28 16:58:55 +11:00
Shannon de1f86c7a1 adds logic to the membership helper to create a new LoginStatusModel with the values filled in, obsoletes the empty ctor on LoginStatusModel since that does some biz logic lookups, instead replaces it with a static method to create an empty one. 2014-01-28 16:30:58 +11:00
Shannon 28d8fd0531 Changes LoginStatusModel to use the correct api and updates the new membership provider stuff to ensure that the provideruserkey is the int id of the model for backwards compatibility. 2014-01-28 16:13:05 +11:00
Shannon e4e76eb0bf Backports commit: Prefixed built in controllers to better avoid conflicts with people's custom code
Conflicts:
	src/Umbraco.Web.UI/Umbraco/PartialViewMacros/Templates/EditProfile.cshtml
	src/Umbraco.Web.UI/Umbraco/PartialViewMacros/Templates/Login.cshtml
	src/Umbraco.Web/Controllers/UmbLoginController.cs
	src/Umbraco.Web/Controllers/UmbLoginStatusController.cs
	src/Umbraco.Web/Controllers/UmbProfileController.cs
	src/Umbraco.Web/Controllers/UmbRegisterController.cs
	src/Umbraco.Web/Umbraco.Web.csproj
2014-01-28 13:47:16 +11:00
Shannon 677cc8c8fd Fixes ProfileController to use normal .Net APIs and the new members service - also removes the Response.Redirect that was in there, why was it like that? 2014-01-28 13:35:43 +11:00
Shannon 3fa5c4e0b2 Updates RegisterController with the standard ASP.Net APIs to create and login a member. 2014-01-28 13:21:30 +11:00
Shannon 360393c464 Fixes LoginStatusController to use the standard ASP.Net APIs 2014-01-28 13:07:25 +11:00
Shannon d3daf88a8d Fixes the LoginController to use the correct APIs 2014-01-28 12:58:22 +11:00
Shannon 7a99ebd6d9 Starts the implementation of the new role provider. 2014-01-28 12:48:41 +11:00
Shannon a7298e2e5a Completes: U4-4148 Anytime RuntimeCacheProvider or InMemoryCacheProvider is used, a cache refresher will need to handle it's distribution! 2014-01-28 12:20:10 +11:00
Shannon 15d7443c61 Streamlines the content type cache refreshing, leaving some of the legacy cache clearing but that shouldn't really have an effect, with these new changes it should be guaranteed that the distributed cache is executed always for Doc, media and member types. 2014-01-28 12:13:27 +11:00
Shannon f2b7e27b34 Fixes: U4-2721 RuntimeCacheProvider is not cleared when data type changes and updates the repo factory to not use the InMemory cache provider since we should only ever use that for very very specific reasons since the memory can never auto-clear with that provider. 2014-01-28 11:30:02 +11:00
Shannon 690d08aa8c Completes wrapping the new IUserService from the legacy User object. Ensures User cache is handled correctly and distributed cache is updated for Users. 2014-01-28 10:46:59 +11:00
Shannon 6719d70cc0 Updates UserTypeCacheRefresher to clear the runtime cache accordingly. 2014-01-28 09:22:01 +11:00
Shannon 3cdcf513ec removes ancient test project 2014-01-28 09:00:17 +11:00
Shannon 43c426b46c Update booting.aspx
Throw the exception immediately if the parameter is not there or empty.

If the parameter is not there it's defaulted to the current url, and this will redirect to itself and create an endless loop here.
2014-01-24 12:36:02 +11:00
Shannon e2ac82abca Gets most of the User and UserType legacy objects wrapping the new services, yay! Now just need to sort out all the caching stuff which I have tasks for. 2014-01-23 18:44:41 +11:00
Shannon 64d1a484bd Fixes User Id issues with HasIdentity, wraps legacy UserType to the new service, fixes the uninstalling db schema to not throw exceptions and clog up the unit test log. 2014-01-23 17:11:58 +11:00
Shannon 585b42af48 More Save()'s missing and removes the extra calls to XmlGenerate - should save some processing time. 2014-01-23 16:13:29 +11:00
Shannon 7c4412fc4b Ensures that Save() is called wherever member data is saved 2014-01-23 16:09:59 +11:00
Shannon 0be8039c8f Changes how IProfile works which is now just exposed by the IUser instead of implemented, this cleans up the Id situation. 2014-01-23 15:31:49 +11:00
Shannon 668265f1ac Allows forcing pass change with new provider, updates conventions to not allow editing of question/answer - unfortunately cannot make the other ones readonly because noEdit data type is the wrong clr type. 2014-01-23 15:11:54 +11:00
Shannon 4735f27a66 Fixes more naming conventions with CreateMemberWithIdentity, fixes memberTasks to ensure the name is set, fixes new membership providers which had the name/email call reversed. Updates the cache refresher event handler to listen to MemberService events instead of the old legacy API events. 2014-01-23 14:55:41 +11:00
Shannon 6377b9aa50 Fixes some underlying type conversions, fixes more of the member type wrapping, updates contenttypecontrolnew to work with member types properly, ensures the property type cache is cleared when member types change. 2014-01-23 13:33:58 +11:00
Shannon 011be60205 Finishes wrapping the member service and fixes a few bugs - ensures the RepositoryBase doesn't keep enumerating when getting all 2014-01-23 12:30:28 +11:00
Shannon a272675ed8 Wraps the MemberService from the legacy Member object 2014-01-23 11:41:01 +11:00
Shannon 80697cf9ca MemberType fully wraps new MemberTypeService 2014-01-23 10:57:24 +11:00
Shannon f4534aa94c adds unit tests for member type can view/can edit properties 2014-01-23 10:55:22 +11:00
Shannon 56dec485a5 Starts wrapping MemberTypeService from the legacy MemberType object. Changes the User.Id to an int - no more casting. Changes CreateMember to CreateMemberWithIdentity for consistency. Adds raiseEvent params to the create/save methods. Updates the MemberTypeService to have consistent naming conventions. Starts wrapping more of the MemberService from the legacy Member object. 2014-01-23 10:41:57 +11:00
Shannon ffde0f48cf Starts wrapping MemberTypeService from the legacy MemberType object. Changes the User.Id to an int - no more casting. Changes CreateMember to CreateMemberWithIdentity for consistency. Adds raiseEvent params to the create/save methods. Updates the MemberTypeService to have consistent naming conventions. Starts wrapping more of the MemberService from the legacy Member object. 2014-01-23 10:35:30 +11:00
Shannon 2956aee4e3 Fixes: U4-4108 The backoffice should not be accessible when the app is not configured, it should redirect to the installer and U4-4106 Set the new membership providers to be shipped as default. 2014-01-22 15:26:45 +11:00
Shannon 9bd8d729fa publicizes user stuff, changes the IUser.Id to an int - no need for it to be an object and casted everywhere. Updates the login logic to perform the mapping logic for custom membership providers with an extension method. 2014-01-22 14:07:18 +11:00
Shannon fb9569d914 Fixes user membership providers to throw exceptions on duplicate emails when the provider is configured to not allow duplicates. 2014-01-22 13:20:00 +11:00
Shannon 47974d49fe obsoletes old providers, creates new membership role provider stub 2014-01-22 12:16:47 +11:00
Shannon 3f8b3031c2 completes: U4-3996 Fix EditUser to use the membership provider properly, U4-3997 Fix EditMember to use the membership provider properly 2014-01-22 11:57:33 +11:00
Shannon 7da41594fd re-publicizes member services, fixes: U4-4102 Un-obsolete ContentService.Publish 2014-01-22 11:27:44 +11:00
Shannon 9796b30bbb Fixes: U4-4104 Using strongly typed Html.Action<T> with a PluginController causes exception 2014-01-22 11:02:24 +11:00
Shannon c2c4763faa Ensures username is escaped in user service 2014-01-20 16:11:38 +11:00
Shannon c062d3b71b Merge branch '6.2.0' of https://github.com/umbraco/Umbraco-CMS into 6.2.0 2014-01-20 16:01:53 +11:00
Shannon ed83fb8216 updates user task creation for release 2014-01-20 16:00:19 +11:00
358 changed files with 9252 additions and 14230 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
@ECHO OFF
SET release=6.2.0
SET comment=
SET comment=beta
SET version=%release%
IF [%comment%] EQU [] (SET version=%release%) ELSE (SET version=%release%-%comment%)
+10
View File
@@ -160,5 +160,15 @@ namespace Umbraco.Core
{
return new Attempt<T>(condition, result, null);
}
/// <summary>
/// Implicity operator to check if the attempt was successful without having to access the 'success' property
/// </summary>
/// <param name="a"></param>
/// <returns></returns>
public static implicit operator bool(Attempt<T> a)
{
return a.Success;
}
}
}
+7 -1
View File
@@ -1,3 +1,5 @@
using System;
namespace Umbraco.Core.Cache
{
@@ -9,6 +11,7 @@ namespace Umbraco.Core.Cache
public const string ApplicationTreeCacheKey = "ApplicationTreeCache";
public const string ApplicationsCacheKey = "ApplicationCache";
[Obsolete("This is no longer used and will be removed from the codebase in the future")]
public const string UserTypeCacheKey = "UserTypeCache";
public const string ContentItemCacheKey = "contentItem";
@@ -24,13 +27,16 @@ namespace Umbraco.Core.Cache
public const string MemberLibraryCacheKey = "UL_GetMember";
public const string MemberBusinessLogicCacheKey = "MemberCacheItem_";
public const string TemplateFrontEndCacheKey = "template";
public const string TemplateBusinessLogicCacheKey = "UmbracoTemplateCache";
public const string UserContextCacheKey = "UmbracoUserContext";
public const string UserContextTimeoutCacheKey = "UmbracoUserContextTimeout";
[Obsolete("This is no longer used and will be removed from the codebase in the future")]
public const string UserCacheKey = "UmbracoUser";
public const string UserPermissionsCacheKey = "UmbracoUserPermissions";
public const string ContentTypeCacheKey = "UmbracoContentType";
+1 -1
View File
@@ -27,7 +27,7 @@ namespace Umbraco.Core
/// <summary>
/// Gets the <see cref="ICacheRefresher"/> implementations.
/// </summary>
public IEnumerable<ICacheRefresher> CacheResolvers
public IEnumerable<ICacheRefresher> CacheRefreshers
{
get
{
@@ -16,7 +16,7 @@ namespace Umbraco.Core.Configuration
}
/// <summary>
/// Increases the version number in ClientDependency.config by 1
/// Changes the version number in ClientDependency.config to a random value to avoid stale caches
/// </summary>
internal bool IncreaseVersionNumber()
{
@@ -28,9 +28,9 @@ namespace Umbraco.Core.Configuration
var versionAttribute = clientDependencyConfigXml.Root.Attribute("version");
int oldVersion;
int.TryParse(versionAttribute.Value, out oldVersion);
var newVersion = oldVersion + 1;
//Set the new version to the hashcode of now
var oldVersion = versionAttribute.Value;
var newVersion = Math.Abs(DateTime.UtcNow.GetHashCode());
versionAttribute.SetValue(newVersion);
clientDependencyConfigXml.Save(_fileName, SaveOptions.DisableFormatting);
@@ -7,6 +7,7 @@ using System.Web.Configuration;
using System.Web.Routing;
using System.Xml;
using System.Xml.Linq;
using System.Xml.XPath;
using Umbraco.Core.IO;
using Umbraco.Core.Logging;
@@ -255,7 +256,38 @@ namespace Umbraco.Core.Configuration
SaveSetting("umbracoConfigurationStatus", value);
}
}
/// <summary>
/// Gets or sets the Umbraco members membership providers' useLegacyEncoding state. This will return a boolean
/// </summary>
/// <value>The useLegacyEncoding status.</value>
public static bool UmbracoMembershipProviderLegacyEncoding
{
get
{
return ConfiguredMembershipProvidersLegacyEncoding(Constants.Conventions.Member.UmbracoMemberProviderName);
}
set
{
SetMembershipProvidersLegacyEncoding(Constants.Conventions.Member.UmbracoMemberProviderName, value);
}
}
/// <summary>
/// Gets or sets the Umbraco users membership providers' useLegacyEncoding state. This will return a boolean
/// </summary>
/// <value>The useLegacyEncoding status.</value>
public static bool UmbracoUsersMembershipProviderLegacyEncoding
{
get
{
return ConfiguredMembershipProvidersLegacyEncoding(Constants.Conventions.User.UmbracoUsersProviderName);
}
set
{
SetMembershipProvidersLegacyEncoding(Constants.Conventions.User.UmbracoUsersProviderName, value);
}
}
/// <summary>
/// Saves a setting into the configuration file.
@@ -315,6 +347,43 @@ namespace Umbraco.Core.Configuration
return fileName;
}
private static void SetMembershipProvidersLegacyEncoding(string providerName, bool useLegacyEncoding)
{
var webConfigFilename = GetFullWebConfigFileName();
var webConfigXml = XDocument.Load(webConfigFilename, LoadOptions.PreserveWhitespace);
var membershipConfigs = webConfigXml.XPathSelectElements("configuration/system.web/membership/providers/add").ToList();
if (membershipConfigs.Any() == false)
return;
var provider = membershipConfigs.SingleOrDefault(c => c.Attribute("name") != null && c.Attribute("name").Value == providerName);
if (provider == null)
return;
provider.SetAttributeValue("useLegacyEncoding", useLegacyEncoding);
webConfigXml.Save(webConfigFilename, SaveOptions.DisableFormatting);
}
private static bool ConfiguredMembershipProvidersLegacyEncoding(string providerName)
{
var webConfigFilename = GetFullWebConfigFileName();
var webConfigXml = XDocument.Load(webConfigFilename, LoadOptions.PreserveWhitespace);
var membershipConfigs = webConfigXml.XPathSelectElements("configuration/system.web/membership/providers/add").ToList();
var provider = membershipConfigs.SingleOrDefault(c => c.Attribute("name") != null && c.Attribute("name").Value == providerName);
var useLegacyEncodingAttribute = provider.Attribute("useLegacyEncoding");
bool useLegacyEncoding;
bool.TryParse(useLegacyEncodingAttribute.Value, out useLegacyEncoding);
return useLegacyEncoding;
}
/// <summary>
/// Gets the full path to root.
/// </summary>
@@ -658,7 +658,7 @@ namespace Umbraco.Core.Configuration
{
string defaultProvider = GetKey("/settings/providers/users/DefaultBackofficeProvider");
if (String.IsNullOrEmpty(defaultProvider))
defaultProvider = "UsersMembershipProvider";
defaultProvider = Constants.Conventions.User.UmbracoUsersProviderName;
return defaultProvider;
}
@@ -23,7 +23,7 @@ namespace Umbraco.Core.Configuration
/// Gets the version comment (like beta or RC).
/// </summary>
/// <value>The version comment.</value>
public static string CurrentComment { get { return ""; } }
public static string CurrentComment { get { return "beta"; } }
// Get the version of the umbraco.dll by looking at a class in that dll
// Had to do it like this due to medium trust issues, see: http://haacked.com/archive/2010/11/04/assembly-location-and-medium-trust.aspx
+25 -10
View File
@@ -85,7 +85,7 @@ namespace Umbraco.Core
/// <summary>
/// MediaType alias for a folder.
/// </summary>
/// </summary>
public const string Folder = "Folder";
/// <summary>
@@ -94,9 +94,19 @@ namespace Umbraco.Core
public const string Image = "Image";
}
/// <summary>
/// Constants for Umbraco user
/// </summary>
public static class User
{
public static readonly string UmbracoUsersProviderName = "UsersMembershipProvider";
}
/// <summary>
/// Constants for Umbraco Member property aliases.
/// </summary>
public static class Member
{
public static readonly string UmbracoMemberProviderName = "UmbracoMembershipProvider";
@@ -166,13 +176,18 @@ namespace Umbraco.Core
public const string FailedPasswordAttemptsLabel = "Failed Password Attempts";
/// <summary>
/// Group name to put the membership properties on
/// </summary>
internal const string StandardPropertiesGroupName = "Membership";
internal static Dictionary<string, PropertyType> GetStandardPropertyTypeStubs()
{
return new Dictionary<string, PropertyType>
{
{
Comments,
new PropertyType(new Guid(PropertyEditors.TextboxMultiple), DataTypeDatabaseType.Ntext)
new PropertyType(new Guid(PropertyEditors.TextboxMultiple), DataTypeDatabaseType.Ntext, true)
{
Alias = Comments,
Name = CommentsLabel
@@ -180,7 +195,7 @@ namespace Umbraco.Core
},
{
FailedPasswordAttempts,
new PropertyType(new Guid(PropertyEditors.Integer), DataTypeDatabaseType.Integer)
new PropertyType(new Guid(PropertyEditors.NoEdit), DataTypeDatabaseType.Integer, true)
{
Alias = FailedPasswordAttempts,
Name = FailedPasswordAttemptsLabel
@@ -188,7 +203,7 @@ namespace Umbraco.Core
},
{
IsApproved,
new PropertyType(new Guid(PropertyEditors.TrueFalse), DataTypeDatabaseType.Integer)
new PropertyType(new Guid(PropertyEditors.TrueFalse), DataTypeDatabaseType.Integer, true)
{
Alias = IsApproved,
Name = IsApprovedLabel
@@ -196,7 +211,7 @@ namespace Umbraco.Core
},
{
IsLockedOut,
new PropertyType(new Guid(PropertyEditors.TrueFalse), DataTypeDatabaseType.Integer)
new PropertyType(new Guid(PropertyEditors.TrueFalse), DataTypeDatabaseType.Integer, true)
{
Alias = IsLockedOut,
Name = IsLockedOutLabel
@@ -204,7 +219,7 @@ namespace Umbraco.Core
},
{
LastLockoutDate,
new PropertyType(new Guid(PropertyEditors.Date), DataTypeDatabaseType.Date)
new PropertyType(new Guid(PropertyEditors.NoEdit), DataTypeDatabaseType.Date, true)
{
Alias = LastLockoutDate,
Name = LastLockoutDateLabel
@@ -212,7 +227,7 @@ namespace Umbraco.Core
},
{
LastLoginDate,
new PropertyType(new Guid(PropertyEditors.Date), DataTypeDatabaseType.Date)
new PropertyType(new Guid(PropertyEditors.NoEdit), DataTypeDatabaseType.Date, true)
{
Alias = LastLoginDate,
Name = LastLoginDateLabel
@@ -220,7 +235,7 @@ namespace Umbraco.Core
},
{
LastPasswordChangeDate,
new PropertyType(new Guid(PropertyEditors.Date), DataTypeDatabaseType.Date)
new PropertyType(new Guid(PropertyEditors.NoEdit), DataTypeDatabaseType.Date, true)
{
Alias = LastPasswordChangeDate,
Name = LastPasswordChangeDateLabel
@@ -228,7 +243,7 @@ namespace Umbraco.Core
},
{
PasswordAnswer,
new PropertyType(new Guid(PropertyEditors.Textbox), DataTypeDatabaseType.Nvarchar)
new PropertyType(new Guid(PropertyEditors.NoEdit), DataTypeDatabaseType.Nvarchar, true)
{
Alias = PasswordAnswer,
Name = PasswordAnswerLabel
@@ -236,7 +251,7 @@ namespace Umbraco.Core
},
{
PasswordQuestion,
new PropertyType(new Guid(PropertyEditors.Textbox), DataTypeDatabaseType.Nvarchar)
new PropertyType(new Guid(PropertyEditors.NoEdit), DataTypeDatabaseType.Nvarchar, true)
{
Alias = PasswordQuestion,
Name = PasswordQuestionLabel
+46
View File
@@ -0,0 +1,46 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.UI;
namespace Umbraco.Core
{
internal static class ControlExtensions
{
/// <summary>
/// Recursively finds a control with the specified identifier.
/// </summary>
/// <typeparam name="T">
/// The type of control to be found.
/// </typeparam>
/// <param name="parent">
/// The parent control from which the search will start.
/// </param>
/// <param name="id">
/// The identifier of the control to be found.
/// </param>
/// <returns>
/// The control with the specified identifier, otherwise <see langword="null"/> if the control
/// is not found.
/// </returns>
public static T FindControlRecursive<T>(this Control parent, string id) where T : Control
{
if ((parent is T) && (parent.ID == id))
{
return (T)parent;
}
foreach (Control control in parent.Controls)
{
var foundControl = FindControlRecursive<T>(control, id);
if (foundControl != null)
{
return foundControl;
}
}
return default(T);
}
}
}
+1 -1
View File
@@ -250,7 +250,7 @@ namespace Umbraco.Core
() => PluginManager.Current.ResolveAssignedMapperTypes());
RepositoryResolver.Current = new RepositoryResolver(
new RepositoryFactory());
new RepositoryFactory(ApplicationCache));
SqlSyntaxProvidersResolver.Current = new SqlSyntaxProvidersResolver(
new[] { typeof(MySqlSyntaxProvider), typeof(SqlCeSyntaxProvider), typeof(SqlServerSyntaxProvider) })
+25
View File
@@ -18,5 +18,30 @@ namespace Umbraco.Core
return dt.ToString("yyyy-MM-dd HH:mm:ss");
}
public static DateTime TruncateTo(this DateTime dt, DateTruncate truncateTo)
{
if (truncateTo == DateTruncate.Year)
return new DateTime(dt.Year, 0, 0);
if (truncateTo == DateTruncate.Month)
return new DateTime(dt.Year, dt.Month, 0);
if (truncateTo == DateTruncate.Day)
return new DateTime(dt.Year, dt.Month, dt.Day);
if (truncateTo == DateTruncate.Hour)
return new DateTime(dt.Year, dt.Month, dt.Day, dt.Hour, 0, 0);
if (truncateTo == DateTruncate.Minute)
return new DateTime(dt.Year, dt.Month, dt.Day, dt.Hour, dt.Minute, 0);
return new DateTime(dt.Year, dt.Month, dt.Day, dt.Hour, dt.Minute, dt.Second);
}
public enum DateTruncate
{
Year,
Month,
Day,
Hour,
Minute,
Second
}
}
}
+2 -4
View File
@@ -306,10 +306,8 @@ namespace Umbraco.Core.Models
/// <returns><see cref="Property"/> Value as a <see cref="TPassType"/></returns>
public virtual TPassType GetValue<TPassType>(string propertyTypeAlias)
{
if (Properties[propertyTypeAlias].Value is TPassType)
return (TPassType)Properties[propertyTypeAlias].Value;
return (TPassType)Convert.ChangeType(Properties[propertyTypeAlias].Value, typeof(TPassType));
var convertAttempt = Properties[propertyTypeAlias].Value.TryConvertTo<TPassType>();
return convertAttempt.Success ? convertAttempt.Result : default(TPassType);
}
/// <summary>
@@ -25,6 +25,20 @@ namespace Umbraco.Core.Models
{
#region IContent
/// <summary>
/// Returns true if this entity was just published as part of a recent save operation (i.e. it wasn't previously published)
/// </summary>
/// <param name="entity"></param>
/// <returns></returns>
/// <remarks>
/// This is helpful for determining if the published event will execute during the saved event for a content item.
/// </remarks>
internal static bool JustPublished(this IContent entity)
{
var dirty = (IRememberBeingDirty)entity;
return dirty.WasPropertyDirty("Published") && entity.Published;
}
/// <summary>
/// Determines if a new version should be created
/// </summary>
@@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Umbraco.Core.Models.EntityBase;
namespace Umbraco.Core.Models
{
public static class EntityExtensions
{
/// <summary>
/// Returns true if this entity has just been created and persisted to the data store
/// </summary>
/// <param name="entity"></param>
/// <returns></returns>
/// <remarks>
/// This is useful when handling events to determine if an entity is a brand new entity or was
/// already existing.
/// </remarks>
public static bool IsNewEntity(this IEntity entity)
{
var dirty = (IRememberBeingDirty)entity;
return dirty.WasPropertyDirty("Id");
}
}
}
+26
View File
@@ -0,0 +1,26 @@
using System.Collections.Generic;
using Umbraco.Core.Models.EntityBase;
namespace Umbraco.Core.Models
{
/// <summary>
/// Represents a member type
/// </summary>
public interface IMemberGroup : IAggregateRoot
{
/// <summary>
/// The name of the member group
/// </summary>
string Name { get; set; }
/// <summary>
/// Profile of the user who created this Entity
/// </summary>
int CreatorId { get; set; }
/// <summary>
/// Some entities may expose additional data that other's might not, this custom data will be available in this collection
/// </summary>
IDictionary<string, object> AdditionalData { get; }
}
}
+6
View File
@@ -10,5 +10,11 @@
/// </summary>
/// <returns><see cref="RenderingEngine"/></returns>
RenderingEngine GetTypeOfRenderingEngine();
/// <summary>
/// Set the mastertemplate
/// </summary>
/// <param name="masterTemplate"></param>
void SetMasterTemplate(ITemplate masterTemplate);
}
}
+175 -41
View File
@@ -1,7 +1,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;
using Umbraco.Core.Logging;
namespace Umbraco.Core.Models
{
@@ -29,8 +31,10 @@ namespace Umbraco.Core.Models
: base(name, -1, contentType, new PropertyCollection())
{
_contentType = contentType;
IsApproved = true;
}
//TODO: Should we just get rid of this one? no reason to have a level set.
internal Member(string name, string email, string username, string password, int parentId, IMemberType contentType)
: base(name, parentId, contentType, new PropertyCollection())
{
@@ -40,6 +44,7 @@ namespace Umbraco.Core.Models
_email = email;
_username = username;
_password = password;
IsApproved = true;
}
public Member(string name, string email, string username, string password, IMemberType contentType)
@@ -51,6 +56,7 @@ namespace Umbraco.Core.Models
_email = email;
_username = username;
_password = password;
IsApproved = true;
}
//public Member(string name, string email, string username, string password, IContentBase parent, IMemberType contentType)
@@ -140,12 +146,19 @@ namespace Umbraco.Core.Models
{
get
{
var a = WarnIfPropertyTypeNotFoundOnGet(Constants.Conventions.Member.PasswordQuestion, "PasswordQuestion", default(string));
if (a.Success == false) return a.Result;
return Properties[Constants.Conventions.Member.PasswordQuestion].Value == null
? string.Empty
: Properties[Constants.Conventions.Member.PasswordQuestion].Value.ToString();
}
set
{
if (WarnIfPropertyTypeNotFoundOnSet(
Constants.Conventions.Member.PasswordQuestion,
"PasswordQuestion") == false) return;
Properties[Constants.Conventions.Member.PasswordQuestion].Value = value;
}
}
@@ -162,12 +175,19 @@ namespace Umbraco.Core.Models
{
get
{
var a = WarnIfPropertyTypeNotFoundOnGet(Constants.Conventions.Member.PasswordAnswer, "PasswordAnswer", default(string));
if (a.Success == false) return a.Result;
return Properties[Constants.Conventions.Member.PasswordAnswer].Value == null
? string.Empty
: Properties[Constants.Conventions.Member.PasswordAnswer].Value.ToString();
}
set
{
if (WarnIfPropertyTypeNotFoundOnSet(
Constants.Conventions.Member.PasswordAnswer,
"PasswordAnswer") == false) return;
Properties[Constants.Conventions.Member.PasswordAnswer].Value = value;
}
}
@@ -184,12 +204,19 @@ namespace Umbraco.Core.Models
{
get
{
var a = WarnIfPropertyTypeNotFoundOnGet(Constants.Conventions.Member.Comments, "Comments", default(string));
if (a.Success == false) return a.Result;
return Properties[Constants.Conventions.Member.Comments].Value == null
? string.Empty
: Properties[Constants.Conventions.Member.Comments].Value.ToString();
}
set
{
if (WarnIfPropertyTypeNotFoundOnSet(
Constants.Conventions.Member.Comments,
"Comments") == false) return;
Properties[Constants.Conventions.Member.Comments].Value = value;
}
}
@@ -206,16 +233,25 @@ namespace Umbraco.Core.Models
{
get
{
if (Properties[Constants.Conventions.Member.IsApproved].Value == null)
return default(bool);
var a = WarnIfPropertyTypeNotFoundOnGet(Constants.Conventions.Member.IsApproved, "IsApproved",
//This is the default value if the prop is not found
true);
if (a.Success == false) return a.Result;
if (Properties[Constants.Conventions.Member.IsApproved].Value is bool)
return (bool)Properties[Constants.Conventions.Member.IsApproved].Value;
return (bool)Convert.ChangeType(Properties[Constants.Conventions.Member.IsApproved].Value, typeof(bool));
var tryConvert = Properties[Constants.Conventions.Member.IsApproved].Value.TryConvertTo<bool>();
if (tryConvert.Success)
{
return tryConvert.Result;
}
//if the property exists but it cannot be converted, we will assume true
return true;
}
set
{
if (WarnIfPropertyTypeNotFoundOnSet(
Constants.Conventions.Member.IsApproved,
"IsApproved") == false) return;
Properties[Constants.Conventions.Member.IsApproved].Value = value;
}
}
@@ -232,16 +268,22 @@ namespace Umbraco.Core.Models
{
get
{
if (Properties[Constants.Conventions.Member.IsLockedOut].Value == null)
return default(bool);
if (Properties[Constants.Conventions.Member.IsLockedOut].Value is bool)
return (bool)Properties[Constants.Conventions.Member.IsLockedOut].Value;
return (bool)Convert.ChangeType(Properties[Constants.Conventions.Member.IsLockedOut].Value, typeof(bool));
var a = WarnIfPropertyTypeNotFoundOnGet(Constants.Conventions.Member.IsLockedOut, "IsLockedOut", false);
if (a.Success == false) return a.Result;
var tryConvert = Properties[Constants.Conventions.Member.IsLockedOut].Value.TryConvertTo<bool>();
if (tryConvert.Success)
{
return tryConvert.Result;
}
return false;
}
set
{
if (WarnIfPropertyTypeNotFoundOnSet(
Constants.Conventions.Member.IsLockedOut,
"IsLockedOut") == false) return;
Properties[Constants.Conventions.Member.IsLockedOut].Value = value;
}
}
@@ -258,16 +300,22 @@ namespace Umbraco.Core.Models
{
get
{
if (Properties[Constants.Conventions.Member.LastLoginDate].Value == null)
return default(DateTime);
if (Properties[Constants.Conventions.Member.LastLoginDate].Value is DateTime)
return (DateTime)Properties[Constants.Conventions.Member.LastLoginDate].Value;
return (DateTime)Convert.ChangeType(Properties[Constants.Conventions.Member.LastLoginDate].Value, typeof(DateTime));
var a = WarnIfPropertyTypeNotFoundOnGet(Constants.Conventions.Member.LastLoginDate, "LastLoginDate", default(DateTime));
if (a.Success == false) return a.Result;
var tryConvert = Properties[Constants.Conventions.Member.LastLoginDate].Value.TryConvertTo<DateTime>();
if (tryConvert.Success)
{
return tryConvert.Result;
}
return default(DateTime);
}
set
{
if (WarnIfPropertyTypeNotFoundOnSet(
Constants.Conventions.Member.LastLoginDate,
"LastLoginDate") == false) return;
Properties[Constants.Conventions.Member.LastLoginDate].Value = value;
}
}
@@ -284,16 +332,22 @@ namespace Umbraco.Core.Models
{
get
{
if (Properties[Constants.Conventions.Member.LastPasswordChangeDate].Value == null)
return default(DateTime);
var a = WarnIfPropertyTypeNotFoundOnGet(Constants.Conventions.Member.LastPasswordChangeDate, "LastPasswordChangeDate", default(DateTime));
if (a.Success == false) return a.Result;
if (Properties[Constants.Conventions.Member.LastPasswordChangeDate].Value is DateTime)
return (DateTime)Properties[Constants.Conventions.Member.LastPasswordChangeDate].Value;
return (DateTime)Convert.ChangeType(Properties[Constants.Conventions.Member.LastPasswordChangeDate].Value, typeof(DateTime));
var tryConvert = Properties[Constants.Conventions.Member.LastPasswordChangeDate].Value.TryConvertTo<DateTime>();
if (tryConvert.Success)
{
return tryConvert.Result;
}
return default(DateTime);
}
set
{
if (WarnIfPropertyTypeNotFoundOnSet(
Constants.Conventions.Member.LastPasswordChangeDate,
"LastPasswordChangeDate") == false) return;
Properties[Constants.Conventions.Member.LastPasswordChangeDate].Value = value;
}
}
@@ -310,16 +364,22 @@ namespace Umbraco.Core.Models
{
get
{
if (Properties[Constants.Conventions.Member.LastLockoutDate].Value == null)
return default(DateTime);
if (Properties[Constants.Conventions.Member.LastLockoutDate].Value is DateTime)
return (DateTime)Properties[Constants.Conventions.Member.LastLockoutDate].Value;
return (DateTime)Convert.ChangeType(Properties[Constants.Conventions.Member.LastLockoutDate].Value, typeof(DateTime));
var a = WarnIfPropertyTypeNotFoundOnGet(Constants.Conventions.Member.LastLockoutDate, "LastLockoutDate", default(DateTime));
if (a.Success == false) return a.Result;
var tryConvert = Properties[Constants.Conventions.Member.LastLockoutDate].Value.TryConvertTo<DateTime>();
if (tryConvert.Success)
{
return tryConvert.Result;
}
return default(DateTime);
}
set
{
if (WarnIfPropertyTypeNotFoundOnSet(
Constants.Conventions.Member.LastLockoutDate,
"LastLockoutDate") == false) return;
Properties[Constants.Conventions.Member.LastLockoutDate].Value = value;
}
}
@@ -337,17 +397,23 @@ namespace Umbraco.Core.Models
{
get
{
if (Properties[Constants.Conventions.Member.FailedPasswordAttempts].Value == null)
return default(int);
if (Properties[Constants.Conventions.Member.FailedPasswordAttempts].Value is int)
return (int)Properties[Constants.Conventions.Member.FailedPasswordAttempts].Value;
return (int)Convert.ChangeType(Properties[Constants.Conventions.Member.FailedPasswordAttempts].Value, typeof(int));
var a = WarnIfPropertyTypeNotFoundOnGet(Constants.Conventions.Member.FailedPasswordAttempts, "FailedPasswordAttempts", 0);
if (a.Success == false) return a.Result;
var tryConvert = Properties[Constants.Conventions.Member.FailedPasswordAttempts].Value.TryConvertTo<int>();
if (tryConvert.Success)
{
return tryConvert.Result;
}
return default(int);
}
set
{
Properties[Constants.Conventions.Member.LastLockoutDate].Value = value;
if (WarnIfPropertyTypeNotFoundOnSet(
Constants.Conventions.Member.FailedPasswordAttempts,
"FailedPasswordAttempts") == false) return;
Properties[Constants.Conventions.Member.FailedPasswordAttempts].Value = value;
}
}
@@ -461,5 +527,73 @@ namespace Umbraco.Core.Models
internal bool BoolPropertyValue { get; set; }
internal DateTime DateTimePropertyValue { get; set; }
internal string PropertyTypeAlias { get; set; }
private Attempt<T> WarnIfPropertyTypeNotFoundOnGet<T>(string propertyAlias, string propertyName, T defaultVal)
{
Action doLog = () => LogHelper.Warn<Member>(
"Trying to access the '"
+ propertyName
+ "' property on "
+ typeof(Member)
+ " but the "
+ propertyAlias
+ " property does not exist on the member type so a default value is returned. Ensure that you have a property type with alias: "
+ propertyAlias
+ " configured on your member type in order to use the '"
+ propertyName
+ "' property on the model correctly.");
//if the property doesn't exist, then do the logging and return a failure
if (Properties.Contains(propertyAlias) == false)
{
//we'll put a warn in the log if this entity has been persisted
if (HasIdentity)
{
doLog();
}
return Attempt<T>.Fail(defaultVal);
}
//if the property doesn't have an identity but we do, then do logging and return failure
var prop = Properties.Single(x => x.Alias == propertyAlias);
if (prop.HasIdentity == false && HasIdentity)
{
doLog();
return Attempt<T>.Fail(defaultVal);
}
return Attempt<T>.Succeed();
}
private bool WarnIfPropertyTypeNotFoundOnSet(string propertyAlias, string propertyname)
{
Action doLog = () => LogHelper.Warn<Member>("An attempt was made to set a value on the property '"
+ propertyname
+ "' on type "
+ typeof(Member)
+ " but the property type "
+ propertyAlias
+ " does not exist on the member type, ensure that this property type exists so that setting this property works correctly.");
//if the property doesn't exist, then do the logging and return a failure
if (Properties.Contains(propertyAlias) == false)
{
if (HasIdentity)
{
doLog();
}
return false;
}
//if the property doesn't have an identity but we do, then do logging and return failure
var prop = Properties.Single(x => x.Alias == propertyAlias);
if (prop.HasIdentity == false && HasIdentity)
{
doLog();
return false;
}
return true;
}
}
}
+76
View File
@@ -0,0 +1,76 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.Serialization;
using Umbraco.Core.Models.EntityBase;
namespace Umbraco.Core.Models
{
/// <summary>
/// Represents a member type
/// </summary>
[Serializable]
[DataContract(IsReference = true)]
public class MemberGroup : Entity, IMemberGroup
{
public MemberGroup()
{
AdditionalData = new Dictionary<string, object>();
}
private string _name;
private int _creatorId;
private static readonly PropertyInfo NameSelector = ExpressionHelper.GetPropertyInfo<MemberGroup, string>(x => x.Name);
private static readonly PropertyInfo CreatorIdSelector = ExpressionHelper.GetPropertyInfo<MemberGroup, int>(x => x.CreatorId);
[DataMember]
public string Name
{
get { return _name; }
set
{
SetPropertyValueAndDetectChanges(o =>
{
if (_name != value)
{
//if the name has changed, add the value to the additional data,
//this is required purely for event handlers to know the previous name of the group
//so we can keep the public access up to date.
AdditionalData["previousName"] = _name;
}
_name = value;
return _name;
}, _name, NameSelector);
}
}
public int CreatorId
{
get { return _creatorId; }
set
{
SetPropertyValueAndDetectChanges(o =>
{
_creatorId = value;
return _creatorId;
}, _creatorId, CreatorIdSelector);
}
}
public IDictionary<string, object> AdditionalData { get; private set; }
/// <summary>
/// Method to call when Entity is being saved
/// </summary>
/// <remarks>Created date is set and a Unique key is assigned</remarks>
internal override void AddingEntity()
{
base.AddingEntity();
if (Key == Guid.Empty)
Key = Guid.NewGuid();
}
}
}
+10 -27
View File
@@ -14,20 +14,18 @@ namespace Umbraco.Core.Models
public class MemberType : ContentTypeCompositionBase, IMemberType
{
//Dictionary is divided into string: PropertyTypeAlias, Tuple: MemberCanEdit, VisibleOnProfile, PropertyTypeId
private IDictionary<string, Tuple<bool, bool, int>> _memberTypePropertyTypes;
private string _alias;
public MemberType(int parentId) : base(parentId)
{
_memberTypePropertyTypes = new Dictionary<string, Tuple<bool, bool, int>>();
MemberTypePropertyTypes = new Dictionary<string, MemberTypePropertyProfileAccess>();
}
public MemberType(IContentTypeComposition parent) : base(parent)
{
_memberTypePropertyTypes = new Dictionary<string, Tuple<bool, bool, int>>();
MemberTypePropertyTypes = new Dictionary<string, MemberTypePropertyProfileAccess>();
}
private static readonly PropertyInfo MemberTypePropertyTypesSelector = ExpressionHelper.GetPropertyInfo<MemberType, IDictionary<string, Tuple<bool, bool, int>>>(x => x.MemberTypePropertyTypes);
private static readonly PropertyInfo AliasSelector = ExpressionHelper.GetPropertyInfo<MemberType, string>(x => x.Alias);
/// <summary>
@@ -53,21 +51,10 @@ namespace Umbraco.Core.Models
}
/// <summary>
/// Gets or Sets a Dictionary of Tuples (MemberCanEdit, VisibleOnProfile, PropertyTypeId) by the PropertyTypes' alias.
/// Gets or Sets a Dictionary of Tuples (MemberCanEdit, VisibleOnProfile) by the PropertyTypes' alias.
/// </summary>
[DataMember]
internal IDictionary<string, Tuple<bool, bool, int>> MemberTypePropertyTypes
{
get { return _memberTypePropertyTypes; }
set
{
SetPropertyValueAndDetectChanges(o =>
{
_memberTypePropertyTypes = value;
return _memberTypePropertyTypes;
}, _memberTypePropertyTypes, MemberTypePropertyTypesSelector);
}
}
internal IDictionary<string, MemberTypePropertyProfileAccess> MemberTypePropertyTypes { get; private set; }
/// <summary>
/// Gets a boolean indicating whether a Property is editable by the Member.
@@ -78,7 +65,7 @@ namespace Umbraco.Core.Models
{
if (MemberTypePropertyTypes.ContainsKey(propertyTypeAlias))
{
return MemberTypePropertyTypes[propertyTypeAlias].Item1;
return MemberTypePropertyTypes[propertyTypeAlias].IsEditable;
}
return false;
@@ -93,7 +80,7 @@ namespace Umbraco.Core.Models
{
if (MemberTypePropertyTypes.ContainsKey(propertyTypeAlias))
{
return MemberTypePropertyTypes[propertyTypeAlias].Item2;
return MemberTypePropertyTypes[propertyTypeAlias].IsVisible;
}
return false;
@@ -108,13 +95,11 @@ namespace Umbraco.Core.Models
{
if (MemberTypePropertyTypes.ContainsKey(propertyTypeAlias))
{
var tuple = MemberTypePropertyTypes[propertyTypeAlias];
MemberTypePropertyTypes[propertyTypeAlias] = new Tuple<bool, bool, int>(value, tuple.Item2, tuple.Item3);
MemberTypePropertyTypes[propertyTypeAlias].IsEditable = value;
}
else
{
var propertyType = PropertyTypes.First(x => x.Alias.Equals(propertyTypeAlias));
var tuple = new Tuple<bool, bool, int>(value, false, propertyType.Id);
var tuple = new MemberTypePropertyProfileAccess(false, value);
MemberTypePropertyTypes.Add(propertyTypeAlias, tuple);
}
}
@@ -128,13 +113,11 @@ namespace Umbraco.Core.Models
{
if (MemberTypePropertyTypes.ContainsKey(propertyTypeAlias))
{
var tuple = MemberTypePropertyTypes[propertyTypeAlias];
MemberTypePropertyTypes[propertyTypeAlias] = new Tuple<bool, bool, int>(tuple.Item1, value, tuple.Item3);
MemberTypePropertyTypes[propertyTypeAlias].IsVisible = value;
}
else
{
var propertyType = PropertyTypes.First(x => x.Alias.Equals(propertyTypeAlias));
var tuple = new Tuple<bool, bool, int>(false, value, propertyType.Id);
var tuple = new MemberTypePropertyProfileAccess(value, false);
MemberTypePropertyTypes.Add(propertyTypeAlias, tuple);
}
}
@@ -0,0 +1,17 @@
namespace Umbraco.Core.Models
{
/// <summary>
/// Used to track the property types that are visible/editable on member profiles
/// </summary>
internal class MemberTypePropertyProfileAccess
{
public MemberTypePropertyProfileAccess(bool isVisible, bool isEditable)
{
IsVisible = isVisible;
IsEditable = isEditable;
}
public bool IsVisible { get; set; }
public bool IsEditable { get; set; }
}
}
@@ -5,14 +5,14 @@
/// </summary>
public class EntityPermission
{
public EntityPermission(object userId, int entityId, string[] assignedPermissions)
public EntityPermission(int userId, int entityId, string[] assignedPermissions)
{
UserId = userId;
EntityId = entityId;
AssignedPermissions = assignedPermissions;
}
public object UserId { get; private set; }
public int UserId { get; private set; }
public int EntityId { get; private set; }
/// <summary>
@@ -3,6 +3,10 @@
/// <summary>
/// Defines the the Profile interface
/// </summary>
/// <remarks>
/// This interface is pretty useless but has been exposed publicly from 6.x so we're stuck with it. It would make more sense
/// if the Id was an int but since it's not people have to cast it to int all of the time!
/// </remarks>
public interface IProfile
{
object Id { get; set; }
+11 -7
View File
@@ -7,19 +7,18 @@ 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, IProfile
public interface IUser : IMembershipUser
{
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; }
//NOTE: I have removed this because it is obsolete in v7 and we are basically removing live editing for now
//bool DefaultToLiveEditing { get; set; }
IUserType UserType { get; }
/// <summary>
/// Gets/sets the user type for the user
/// </summary>
IUserType UserType { get; set; }
/// <summary>
/// The default permission set for the user
@@ -32,5 +31,10 @@ namespace Umbraco.Core.Models.Membership
IEnumerable<string> AllowedSections { get; }
void RemoveAllowedSection(string sectionAlias);
void AddAllowedSection(string sectionAlias);
/// <summary>
/// Exposes the basic profile data
/// </summary>
IProfile ProfileData { get; }
}
}
@@ -5,7 +5,7 @@ using Umbraco.Core.Persistence.Mappers;
namespace Umbraco.Core.Models.Membership
{
internal interface IUserType : IAggregateRoot
public interface IUserType : IAggregateRoot
{
/// <summary>
/// The user type alias
+89 -35
View File
@@ -5,6 +5,7 @@ using System.Collections.Specialized;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;
using Umbraco.Core.Configuration;
using Umbraco.Core.Models.EntityBase;
using Umbraco.Core.Persistence.Mappers;
@@ -19,7 +20,7 @@ namespace Umbraco.Core.Models.Membership
/// </remarks>
[Serializable]
[DataContract(IsReference = true)]
internal class User : TracksChangesEntityBase, IUser
public class User : TracksChangesEntityBase, IUser
{
public User(IUserType userType)
{
@@ -31,7 +32,12 @@ namespace Umbraco.Core.Models.Membership
_sectionCollection = new ObservableCollection<string>();
_addedSections = new List<string>();
_removedSections = new List<string>();
_language = GlobalSettings.DefaultUILanguage;
_sectionCollection.CollectionChanged += SectionCollectionChanged;
_isApproved = true;
_isLockedOut = false;
_startContentId = -1;
_startMediaId = -1;
}
public User(string name, string email, string username, string password, IUserType userType)
@@ -41,11 +47,15 @@ namespace Umbraco.Core.Models.Membership
_email = email;
_username = username;
_password = password;
_isApproved = true;
_isLockedOut = false;
_startContentId = -1;
_startMediaId = -1;
}
private readonly IUserType _userType;
private IUserType _userType;
private bool _hasIdentity;
private object _id;
private int _id;
private string _name;
private Type _userTypeKey;
private readonly List<string> _addedSections;
@@ -58,7 +68,6 @@ namespace Umbraco.Core.Models.Membership
private string _username;
private string _email;
private string _password;
private Guid _key;
private bool _isApproved;
private bool _isLockedOut;
private string _language;
@@ -81,23 +90,43 @@ namespace Umbraco.Core.Models.Membership
private static readonly PropertyInfo LanguageSelector = ExpressionHelper.GetPropertyInfo<User, string>(x => x.Language);
private static readonly PropertyInfo DefaultPermissionsSelector = ExpressionHelper.GetPropertyInfo<User, IEnumerable<string>>(x => x.DefaultPermissions);
private static readonly PropertyInfo DefaultToLiveEditingSelector = ExpressionHelper.GetPropertyInfo<User, bool>(x => x.DefaultToLiveEditing);
private static readonly PropertyInfo HasIdentitySelector = ExpressionHelper.GetPropertyInfo<User, bool>(x => x.HasIdentity);
private static readonly PropertyInfo UserTypeSelector = ExpressionHelper.GetPropertyInfo<User, IUserType>(x => x.UserType);
#region Implementation of IEntity
[IgnoreDataMember]
public bool HasIdentity { get { return Id != null || _hasIdentity; } }
[IgnoreDataMember]
int IEntity.Id
public bool HasIdentity
{
get
{
return int.Parse(Id.ToString());
return _hasIdentity;
}
protected set
{
SetPropertyValueAndDetectChanges(o =>
{
_hasIdentity = value;
return _hasIdentity;
}, _hasIdentity, HasIdentitySelector);
}
}
[DataMember]
public int Id
{
get
{
return _id;
}
set
{
Id = value;
_hasIdentity = true;
SetPropertyValueAndDetectChanges(o =>
{
_id = value;
HasIdentity = true; //set the has Identity
return _id;
}, _id, IdSelector);
}
}
@@ -239,8 +268,8 @@ namespace Umbraco.Core.Models.Membership
public int FailedPasswordAttempts { get; set; }
#endregion
#region Implementation of IProfile
#region Implementation of IUser
[DataMember]
public string Name
@@ -249,17 +278,13 @@ namespace Umbraco.Core.Models.Membership
set
{
SetPropertyValueAndDetectChanges(o =>
{
_name = value;
return _name;
}, _name, NameSelector);
{
_name = value;
return _name;
}, _name, NameSelector);
}
}
#endregion
#region Implementation of IUser
public IEnumerable<string> AllowedSections
{
get { return _sectionCollection; }
@@ -278,6 +303,11 @@ namespace Umbraco.Core.Models.Membership
}
}
public IProfile ProfileData
{
get { return new UserProfile(this); }
}
/// <summary>
/// Used internally to check if we need to add a section in the repository to the db
/// </summary>
@@ -354,20 +384,6 @@ namespace Umbraco.Core.Models.Membership
}
}
[DataMember]
public object Id
{
get { return _id; }
set
{
SetPropertyValueAndDetectChanges(o =>
{
_id = value;
return _id;
}, _id, IdSelector);
}
}
[DataMember]
public string Language
{
@@ -414,6 +430,19 @@ namespace Umbraco.Core.Models.Membership
public IUserType UserType
{
get { return _userType; }
set
{
if (value.HasIdentity == false)
{
throw new InvalidOperationException("Cannot assign a User Type that has not been persisted");
}
SetPropertyValueAndDetectChanges(o =>
{
_userType = value;
return _userType;
}, _userType, UserTypeSelector);
}
}
#endregion
@@ -459,5 +488,30 @@ namespace Umbraco.Core.Models.Membership
_removedSections.Add(e.OldItems.Cast<string>().First());
}
}
/// <summary>
/// Internal class used to wrap the user in a profile
/// </summary>
private class UserProfile : IProfile
{
private readonly IUser _user;
public UserProfile(IUser user)
{
_user = user;
}
public object Id
{
get { return _user.Id; }
set { _user.Id = (int)value; }
}
public string Name
{
get { return _user.Name; }
set { _user.Name = value; }
}
}
}
}
+8 -3
View File
@@ -43,7 +43,7 @@ namespace Umbraco.Core.Models
private static readonly PropertyInfo ValueSelector = ExpressionHelper.GetPropertyInfo<Property, object>(x => x.Value);
private static readonly PropertyInfo VersionSelector = ExpressionHelper.GetPropertyInfo<Property, Guid>(x => x.Version);
/// <summary>
/// Returns the Alias of the PropertyType, which this Property is based on
/// </summary>
@@ -59,9 +59,14 @@ namespace Umbraco.Core.Models
/// <summary>
/// Returns the DatabaseType that the underlaying DataType is using to store its values
/// </summary>
/// <remarks>Only used internally when saving the property value</remarks>
/// <remarks>
/// Only used internally when saving the property value.
/// </remarks>
[IgnoreDataMember]
internal DataTypeDatabaseType DataTypeDatabaseType { get { return _propertyType.DataTypeDatabaseType; } }
internal DataTypeDatabaseType DataTypeDatabaseType
{
get { return _propertyType.DataTypeDatabaseType; }
}
/// <summary>
/// Returns the PropertyType, which this Property is based on
+21 -5
View File
@@ -14,6 +14,7 @@ namespace Umbraco.Core.Models
[DataContract(IsReference = true)]
public class PropertyType : Entity, IEquatable<PropertyType>
{
private readonly bool _isExplicitDbType;
private string _name;
private string _alias;
private string _description;
@@ -29,16 +30,28 @@ namespace Umbraco.Core.Models
public PropertyType(IDataTypeDefinition dataTypeDefinition)
{
if(dataTypeDefinition.HasIdentity)
DataTypeDefinitionId = dataTypeDefinition.Id;
_dataTypeDefinitionId = dataTypeDefinition.Id;
DataTypeId = dataTypeDefinition.ControlId;
DataTypeDatabaseType = dataTypeDefinition.DatabaseType;
_dataTypeId = dataTypeDefinition.ControlId;
_dataTypeDatabaseType = dataTypeDefinition.DatabaseType;
}
internal PropertyType(Guid dataTypeControlId, DataTypeDatabaseType dataTypeDatabaseType)
: this(dataTypeControlId, dataTypeDatabaseType, false)
{
DataTypeId = dataTypeControlId;
DataTypeDatabaseType = dataTypeDatabaseType;
}
/// <summary>
/// Used internally to assign an explicity database type for this property type regardless of what the underlying data type/property editor is.
/// </summary>
/// <param name="dataTypeControlId"></param>
/// <param name="dataTypeDatabaseType"></param>
/// <param name="isExplicitDbType"></param>
internal PropertyType(Guid dataTypeControlId, DataTypeDatabaseType dataTypeDatabaseType, bool isExplicitDbType)
{
_isExplicitDbType = isExplicitDbType;
_dataTypeId = dataTypeControlId;
_dataTypeDatabaseType = dataTypeDatabaseType;
}
private static readonly PropertyInfo NameSelector = ExpressionHelper.GetPropertyInfo<PropertyType, string>(x => x.Name);
@@ -149,6 +162,9 @@ namespace Umbraco.Core.Models
get { return _dataTypeDatabaseType; }
set
{
//don't allow setting this if an explicit declaration has been made in the ctor
if (_isExplicitDbType) return;
SetPropertyValueAndDetectChanges(o =>
{
_dataTypeDatabaseType = value;
+7 -1
View File
@@ -191,5 +191,11 @@ namespace Umbraco.Core.Models
if (Key == Guid.Empty)
Key = Guid.NewGuid();
}
public void SetMasterTemplate(ITemplate masterTemplate)
{
MasterTemplateId = new Lazy<int>(() => masterTemplate.Id);
}
}
}
}
+8
View File
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Reflection;
using Umbraco.Core.Models.EntityBase;
@@ -53,6 +54,13 @@ namespace Umbraco.Core.Models
Trashed = trashed;
}
// for MySql
public UmbracoEntity(UInt64 trashed)
{
AdditionalData = new Dictionary<string, object>();
Trashed = trashed == 1;
}
public int CreatorId
{
get { return _creatorId; }
+29 -5
View File
@@ -237,12 +237,14 @@ namespace Umbraco.Core
else if (destinationType == typeof(Double))
{
Double value;
return Double.TryParse(input, out value) ? Attempt<object>.Succeed(value) : Attempt<object>.Fail();
var input2 = NormalizeNumberDecimalSeparator(input);
return Double.TryParse(input2, out value) ? Attempt<object>.Succeed(value) : Attempt<object>.Fail();
}
else if (destinationType == typeof(Single))
{
Single value;
return Single.TryParse(input, out value) ? Attempt<object>.Succeed(value) : Attempt<object>.Fail();
var input2 = NormalizeNumberDecimalSeparator(input);
return Single.TryParse(input2, out value) ? Attempt<object>.Succeed(value) : Attempt<object>.Fail();
}
else if (destinationType == typeof(Char))
{
@@ -283,7 +285,20 @@ namespace Umbraco.Core
else if (destinationType == typeof(DateTime))
{
DateTime value;
return DateTime.TryParse(input, out value) ? Attempt<object>.Succeed(value) : Attempt<object>.Fail();
if (DateTime.TryParse(input, out value))
{
switch (value.Kind)
{
case DateTimeKind.Unspecified:
case DateTimeKind.Utc:
return Attempt<object>.Succeed(value);
case DateTimeKind.Local:
return Attempt<object>.Succeed(value.ToUniversalTime());
default:
throw new ArgumentOutOfRangeException();
}
}
return Attempt<object>.Fail();
}
else if (destinationType == typeof(DateTimeOffset))
{
@@ -298,7 +313,8 @@ namespace Umbraco.Core
else if (destinationType == typeof(Decimal))
{
Decimal value;
return Decimal.TryParse(input, out value) ? Attempt<object>.Succeed(value) : Attempt<object>.Fail();
var input2 = NormalizeNumberDecimalSeparator(input);
return Decimal.TryParse(input2, out value) ? Attempt<object>.Succeed(value) : Attempt<object>.Fail();
}
else if (destinationType == typeof(Version))
{
@@ -310,6 +326,14 @@ namespace Umbraco.Core
return null; // we can't decide...
}
private readonly static char[] NumberDecimalSeparatorsToNormalize = new[] {'.', ','};
private static string NormalizeNumberDecimalSeparator(string s)
{
var normalized = System.Threading.Thread.CurrentThread.CurrentUICulture.NumberFormat.NumberDecimalSeparator[0];
return s.ReplaceMany(NumberDecimalSeparatorsToNormalize, normalized);
}
internal static void CheckThrowObjectDisposed(this IDisposable disposable, bool isDisposed, string objectname)
{
//TODO: Localise this exception
@@ -516,7 +540,7 @@ namespace Umbraco.Core
if (type == typeof(bool)) return XmlConvert.ToString((bool)value);
if (type == typeof(byte)) return XmlConvert.ToString((byte)value);
if (type == typeof(char)) return XmlConvert.ToString((char)value);
if (type == typeof(DateTime)) return XmlConvert.ToString((DateTime)value, XmlDateTimeSerializationMode.RoundtripKind);
if (type == typeof(DateTime)) return XmlConvert.ToString((DateTime)value, XmlDateTimeSerializationMode.Unspecified);
if (type == typeof(DateTimeOffset)) return XmlConvert.ToString((DateTimeOffset)value);
if (type == typeof(decimal)) return XmlConvert.ToString((decimal)value);
if (type == typeof(double)) return XmlConvert.ToString((double)value);
@@ -0,0 +1,64 @@
using System;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Rdbms;
namespace Umbraco.Core.Persistence.Factories
{
internal class MemberGroupFactory : IEntityFactory<IMemberGroup, NodeDto>
{
private readonly Guid _nodeObjectTypeId;
public MemberGroupFactory()
{
_nodeObjectTypeId = new Guid(Constants.ObjectTypes.MemberGroup);
}
#region Implementation of IEntityFactory<ITemplate,TemplateDto>
public IMemberGroup BuildEntity(NodeDto dto)
{
var template = new MemberGroup
{
CreateDate = dto.CreateDate,
Id = dto.NodeId,
Key = dto.UniqueId.Value,
Name = dto.Text
};
//on initial construction we don't want to have dirty properties tracked
// http://issues.umbraco.org/issue/U4-1946
template.ResetDirtyProperties(false);
return template;
}
public NodeDto BuildDto(IMemberGroup entity)
{
var dto = new NodeDto
{
CreateDate = entity.CreateDate,
NodeId = entity.Id,
Level = 0,
NodeObjectType = _nodeObjectTypeId,
ParentId = -1,
Path = "",
SortOrder = 0,
Text = entity.Name,
Trashed = false,
UniqueId = entity.Key,
UserId = entity.CreatorId
};
if (entity.HasIdentity)
{
dto.NodeId = entity.Id;
dto.Path = "-1," + entity.Id;
}
return dto;
}
#endregion
}
}
@@ -25,7 +25,7 @@ namespace Umbraco.Core.Persistence.Factories
CreateDate = dto.CreateDate,
UpdateDate = dto.UpdateDate,
Name = dto.Text,
ProviderUserKey = dto.UniqueId.Value,
ProviderUserKey = dto.NodeId,
Trashed = dto.Trashed,
Key = dto.UniqueId.Value,
CreatorId = dto.UserId.HasValue ? dto.UserId.Value : 0,
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Rdbms;
using Umbraco.Core.Persistence.Repositories;
namespace Umbraco.Core.Persistence.Factories
{
@@ -10,6 +11,8 @@ namespace Umbraco.Core.Persistence.Factories
{
public IMemberType BuildEntity(MemberTypeReadOnlyDto dto)
{
var standardPropertyTypes = Constants.Conventions.Member.GetStandardPropertyTypeStubs();
var memberType = new MemberType(dto.ParentId)
{
Alias = dto.Alias,
@@ -31,12 +34,12 @@ namespace Umbraco.Core.Persistence.Factories
AllowedContentTypes = Enumerable.Empty<ContentTypeSort>()
};
var propertyTypeGroupCollection = GetPropertyTypeGroupCollection(dto, memberType);
var propertyTypeGroupCollection = GetPropertyTypeGroupCollection(dto, memberType, standardPropertyTypes);
memberType.PropertyGroups = propertyTypeGroupCollection;
var propertyTypes = GetPropertyTypes(dto, memberType);
//By Convention we add 9 stnd PropertyTypes - This is only here to support loading of types that didn't have these conventions before.
var standardPropertyTypes = Constants.Conventions.Member.GetStandardPropertyTypeStubs();
var propertyTypes = GetPropertyTypes(dto, memberType, standardPropertyTypes);
//By Convention we add 9 stnd PropertyTypes - This is only here to support loading of types that didn't have these conventions before.
foreach (var standardPropertyType in standardPropertyTypes)
{
if(dto.PropertyTypes.Any(x => x.Alias.Equals(standardPropertyType.Key))) continue;
@@ -46,16 +49,17 @@ namespace Umbraco.Core.Persistence.Factories
//Internal dictionary for adding "MemberCanEdit" and "VisibleOnProfile" properties to each PropertyType
memberType.MemberTypePropertyTypes.Add(standardPropertyType.Key,
new Tuple<bool, bool, int>(false, false, default(int)));
new MemberTypePropertyProfileAccess(false, false));
}
memberType.PropertyTypes = propertyTypes;
return memberType;
}
private PropertyGroupCollection GetPropertyTypeGroupCollection(MemberTypeReadOnlyDto dto, MemberType memberType)
private PropertyGroupCollection GetPropertyTypeGroupCollection(MemberTypeReadOnlyDto dto, MemberType memberType, Dictionary<string, PropertyType> standardProps)
{
var propertyGroups = new PropertyGroupCollection();
var propertyGroups = new PropertyGroupCollection();
foreach (var groupDto in dto.PropertyTypeGroups.Where(x => x.Id.HasValue))
{
var group = new PropertyGroup();
@@ -84,11 +88,23 @@ namespace Umbraco.Core.Persistence.Factories
{
//Internal dictionary for adding "MemberCanEdit" and "VisibleOnProfile" properties to each PropertyType
memberType.MemberTypePropertyTypes.Add(typeDto.Alias,
new Tuple<bool, bool, int>(typeDto.CanEdit, typeDto.ViewOnProfile, typeDto.Id.Value));
new MemberTypePropertyProfileAccess(typeDto.ViewOnProfile, typeDto.CanEdit));
var tempGroupDto = groupDto;
var propertyType = new PropertyType(typeDto.ControlId,
typeDto.DbType.EnumParse<DataTypeDatabaseType>(true))
//ensures that any built-in membership properties have their correct dbtype assigned no matter
//what the underlying data type is
var propDbType = MemberTypeRepository.GetDbTypeForBuiltInProperty(
typeDto.Alias,
typeDto.DbType.EnumParse<DataTypeDatabaseType>(true),
standardProps);
var propertyType = new PropertyType(
typeDto.ControlId,
propDbType.Result,
//This flag tells the property type that it has an explicit dbtype and that it cannot be changed
// which is what we want for the built-in properties.
propDbType.Success)
{
Alias = typeDto.Alias,
DataTypeDefinitionId = typeDto.DataTypeId,
@@ -117,32 +133,47 @@ namespace Umbraco.Core.Persistence.Factories
return propertyGroups;
}
private List<PropertyType> GetPropertyTypes(MemberTypeReadOnlyDto dto, MemberType memberType)
private List<PropertyType> GetPropertyTypes(MemberTypeReadOnlyDto dto, MemberType memberType, Dictionary<string, PropertyType> standardProps)
{
//Find PropertyTypes that does not belong to a PropertyTypeGroup
var propertyTypes = new List<PropertyType>();
foreach (var propertyType in dto.PropertyTypes.Where(x => (x.PropertyTypeGroupId.HasValue == false || x.PropertyTypeGroupId.Value == 0) && x.Id.HasValue))
foreach (var typeDto in dto.PropertyTypes.Where(x => (x.PropertyTypeGroupId.HasValue == false || x.PropertyTypeGroupId.Value == 0) && x.Id.HasValue))
{
//Internal dictionary for adding "MemberCanEdit" and "VisibleOnProfile" properties to each PropertyType
memberType.MemberTypePropertyTypes.Add(propertyType.Alias,
new Tuple<bool, bool, int>(propertyType.CanEdit, propertyType.ViewOnProfile, propertyType.Id.Value));
//PropertyType Collection
propertyTypes.Add(new PropertyType(propertyType.ControlId,
propertyType.DbType.EnumParse<DataTypeDatabaseType>(true))
{
Alias = propertyType.Alias,
DataTypeDefinitionId = propertyType.DataTypeId,
Description = propertyType.Description,
HelpText = propertyType.HelpText,
Id = propertyType.Id.Value,
Mandatory = propertyType.Mandatory,
Name = propertyType.Name,
SortOrder = propertyType.SortOrder,
ValidationRegExp = propertyType.ValidationRegExp,
PropertyGroupId = new Lazy<int>(() => default(int)),
CreateDate = dto.CreateDate,
UpdateDate = dto.CreateDate
});
memberType.MemberTypePropertyTypes.Add(typeDto.Alias,
new MemberTypePropertyProfileAccess(typeDto.ViewOnProfile, typeDto.CanEdit));
//ensures that any built-in membership properties have their correct dbtype assigned no matter
//what the underlying data type is
var propDbType = MemberTypeRepository.GetDbTypeForBuiltInProperty(
typeDto.Alias,
typeDto.DbType.EnumParse<DataTypeDatabaseType>(true),
standardProps);
var propertyType = new PropertyType(
typeDto.ControlId,
propDbType.Result,
//This flag tells the property type that it has an explicit dbtype and that it cannot be changed
// which is what we want for the built-in properties.
propDbType.Success)
{
Alias = typeDto.Alias,
DataTypeDefinitionId = typeDto.DataTypeId,
Description = typeDto.Description,
HelpText = typeDto.HelpText,
Id = typeDto.Id.Value,
Mandatory = typeDto.Mandatory,
Name = typeDto.Name,
SortOrder = typeDto.SortOrder,
ValidationRegExp = typeDto.ValidationRegExp,
PropertyGroupId = new Lazy<int>(() => default(int)),
CreateDate = dto.CreateDate,
UpdateDate = dto.CreateDate
};
propertyTypes.Add(propertyType);
}
return propertyTypes;
}
@@ -11,17 +11,21 @@ namespace Umbraco.Core.Persistence.Factories
private readonly int _id;
private readonly DateTime _createDate;
private readonly DateTime _updateDate;
//a callback to create a property type which can be injected via a contructor
private readonly Func<Guid, DataTypeDatabaseType, string, PropertyType> _propertyTypeCtor;
public PropertyGroupFactory(int id)
{
_id = id;
_propertyTypeCtor = (guid, dbType, alias) => new PropertyType(guid, dbType);
}
public PropertyGroupFactory(int id, DateTime createDate, DateTime updateDate)
public PropertyGroupFactory(int id, DateTime createDate, DateTime updateDate, Func<Guid, DataTypeDatabaseType, string, PropertyType> propertyTypeCtor)
{
_id = id;
_createDate = createDate;
_updateDate = updateDate;
_propertyTypeCtor = propertyTypeCtor;
}
#region Implementation of IEntityFactory<IEnumerable<PropertyGroup>,IEnumerable<TabDto>>
@@ -55,22 +59,23 @@ namespace Umbraco.Core.Persistence.Factories
foreach (var typeDto in typeDtos)
{
var tempGroupDto = groupDto;
var propertyType = new PropertyType(typeDto.DataTypeDto.ControlId,
typeDto.DataTypeDto.DbType.EnumParse<DataTypeDatabaseType>(true))
{
Alias = typeDto.Alias,
DataTypeDefinitionId = typeDto.DataTypeId,
Description = typeDto.Description,
Id = typeDto.Id,
Name = typeDto.Name,
HelpText = typeDto.HelpText,
Mandatory = typeDto.Mandatory,
SortOrder = typeDto.SortOrder,
ValidationRegExp = typeDto.ValidationRegExp,
PropertyGroupId = new Lazy<int>(() => tempGroupDto.Id),
CreateDate = _createDate,
UpdateDate = _updateDate
};
var propertyType = _propertyTypeCtor(typeDto.DataTypeDto.ControlId,
typeDto.DataTypeDto.DbType.EnumParse<DataTypeDatabaseType>(true),
typeDto.Alias);
propertyType.Alias = typeDto.Alias;
propertyType.DataTypeDefinitionId = typeDto.DataTypeId;
propertyType.Description = typeDto.Description;
propertyType.Id = typeDto.Id;
propertyType.Name = typeDto.Name;
propertyType.HelpText = typeDto.HelpText;
propertyType.Mandatory = typeDto.Mandatory;
propertyType.SortOrder = typeDto.SortOrder;
propertyType.ValidationRegExp = typeDto.ValidationRegExp;
propertyType.PropertyGroupId = new Lazy<int>(() => tempGroupDto.Id);
propertyType.CreateDate = _createDate;
propertyType.UpdateDate = _updateDate;
//on initial construction we don't want to have dirty properties tracked
// http://issues.umbraco.org/issue/U4-1946
propertyType.ResetDirtyProperties(false);
@@ -0,0 +1,34 @@
using System.Collections.Concurrent;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Rdbms;
namespace Umbraco.Core.Persistence.Mappers
{
[MapperFor(typeof (IMemberGroup))]
[MapperFor(typeof (MemberGroup))]
public sealed class MemberGroupMapper : BaseMapper
{
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.
public MemberGroupMapper()
{
BuildMap();
}
internal override ConcurrentDictionary<string, DtoMapModel> PropertyInfoCache
{
get { return PropertyInfoCacheInstance; }
}
internal override void BuildMap()
{
CacheMap<MemberGroup, NodeDto>(src => src.Id, dto => dto.NodeId);
CacheMap<MemberGroup, NodeDto>(src => src.CreateDate, dto => dto.CreateDate);
CacheMap<MemberGroup, NodeDto>(src => src.CreatorId, dto => dto.UserId);
CacheMap<MemberGroup, NodeDto>(src => src.Name, dto => dto.Text);
CacheMap<MemberGroup, NodeDto>(src => src.Key, dto => dto.UniqueId);
}
}
}
@@ -80,7 +80,10 @@ namespace Umbraco.Core.Persistence.Migrations.Initial
try
{
_database.DropTable(tableName);
if (_database.TableExist(tableName))
{
_database.DropTable(tableName);
}
}
catch (Exception ex)
{
@@ -57,11 +57,20 @@ namespace Umbraco.Core.Persistence
using (var tr = db.GetTransaction())
{
db.BulkInsertRecords(collection, tr);
db.BulkInsertRecords(collection, tr, true);
}
}
public static void BulkInsertRecords<T>(this Database db, IEnumerable<T> collection, Transaction tr)
/// <summary>
/// Performs the bulk insertion in the context of a current transaction with an optional parameter to complete the transaction
/// when finished
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="db"></param>
/// <param name="collection"></param>
/// <param name="tr"></param>
/// <param name="commitTrans"></param>
public static void BulkInsertRecords<T>(this Database db, IEnumerable<T> collection, Transaction tr, bool commitTrans = false)
{
//don't do anything if there are no records.
if (collection.Any() == false)
@@ -95,11 +104,17 @@ namespace Umbraco.Core.Persistence
}
}
tr.Complete();
if (commitTrans)
{
tr.Complete();
}
}
catch
{
tr.Dispose();
if (commitTrans)
{
tr.Dispose();
}
throw;
}
}
@@ -1,5 +1,6 @@
using System;
using System.Globalization;
using Umbraco.Core.Persistence.SqlSyntax;
namespace Umbraco.Core.Persistence.Querying
{
@@ -25,7 +26,7 @@ namespace Umbraco.Core.Persistence.Querying
{
//if (TypeSerializer.CanCreateFromString(fieldType))
//{
// return "'" + EscapeParam(TypeSerializer.SerializeToString(value)) + "'";
// return "'" + escapeCallback(TypeSerializer.SerializeToString(value)) + "'";
//}
throw new NotSupportedException(
@@ -46,27 +47,24 @@ namespace Umbraco.Core.Persistence.Querying
if (fieldType == typeof(DateTime))
{
return "'" + EscapeParam(((DateTime)value).ToIsoString()) + "'";
return "'" + escapeCallback(((DateTime)value).ToIsoString()) + "'";
}
if (fieldType == typeof(bool))
return ((bool)value) ? Convert.ToString(1, CultureInfo.InvariantCulture) : Convert.ToString(0, CultureInfo.InvariantCulture);
return ShouldQuoteValue(fieldType)
? "'" + EscapeParam(value) + "'"
return shouldQuoteCallback(fieldType)
? "'" + escapeCallback(value) + "'"
: value.ToString();
}
public virtual string EscapeParam(object paramValue)
{
return paramValue.ToString().Replace("'", "''");
return paramValue == null
? string.Empty
: SqlSyntaxContext.SqlSyntaxProvider.EscapeString(paramValue.ToString());
}
public virtual string EscapeAtArgument(string exp)
{
return PetaPocoExtensions.EscapeAtSymbols(exp);
}
public virtual bool ShouldQuoteValue(Type fieldType)
{
return true;
@@ -205,13 +205,12 @@ namespace Umbraco.Core.Persistence.Querying
{
if (c.Value == null)
return "null";
else if (c.Value.GetType() == typeof(bool))
if (c.Value is bool)
{
object o = GetQuotedValue(c.Value, c.Value.GetType());
return string.Format("({0}={1})", GetQuotedTrueValue(), o);
}
else
return GetQuotedValue(c.Value, c.Value.GetType());
return GetQuotedValue(c.Value, c.Value.GetType());
}
protected virtual string VisitUnary(UnaryExpression u)
@@ -233,15 +232,15 @@ namespace Umbraco.Core.Persistence.Querying
switch (verb)
{
case "SqlWildcard":
return SqlSyntaxContext.SqlSyntaxProvider.GetStringColumnWildcardComparison(col, EscapeAtArgument(RemoveQuote(val)), columnType);
return SqlSyntaxContext.SqlSyntaxProvider.GetStringColumnWildcardComparison(col, RemoveQuote(val), columnType);
case "Equals":
return SqlSyntaxContext.SqlSyntaxProvider.GetStringColumnEqualComparison(col, EscapeAtArgument(RemoveQuote(val)), columnType);
return SqlSyntaxContext.SqlSyntaxProvider.GetStringColumnEqualComparison(col, RemoveQuote(val), columnType);
case "StartsWith":
return SqlSyntaxContext.SqlSyntaxProvider.GetStringColumnStartsWithComparison(col, EscapeAtArgument(RemoveQuote(val)), columnType);
return SqlSyntaxContext.SqlSyntaxProvider.GetStringColumnStartsWithComparison(col, RemoveQuote(val), columnType);
case "EndsWith":
return SqlSyntaxContext.SqlSyntaxProvider.GetStringColumnEndsWithComparison(col, EscapeAtArgument(RemoveQuote(val)), columnType);
return SqlSyntaxContext.SqlSyntaxProvider.GetStringColumnEndsWithComparison(col, RemoveQuote(val), columnType);
case "Contains":
return SqlSyntaxContext.SqlSyntaxProvider.GetStringColumnContainsComparison(col, EscapeAtArgument(RemoveQuote(val)), columnType);
return SqlSyntaxContext.SqlSyntaxProvider.GetStringColumnContainsComparison(col, RemoveQuote(val), columnType);
case "InvariantEquals":
case "SqlEquals":
//recurse
@@ -243,6 +243,10 @@ namespace Umbraco.Core.Persistence.Querying
args.RemoveAt(0);
}
//TODO: We should probably add the same logic we've done for ModelToSqlExpressionHelper with checking for:
// InvariantStartsWith, InvariantEndsWith, SqlWildcard, etc...
// since we should be able to easily handle that with the Poco objects too.
switch (m.Method.Name)
{
case "ToUpper":
@@ -250,11 +254,11 @@ namespace Umbraco.Core.Persistence.Querying
case "ToLower":
return string.Format("lower({0})", r);
case "StartsWith":
return string.Format("upper({0}) like '{1}%'", r, EscapeAtArgument(RemoveQuote(args[0].ToString().ToUpper())));
return string.Format("upper({0}) like '{1}%'", r, RemoveQuote(args[0].ToString().ToUpper()));
case "EndsWith":
return string.Format("upper({0}) like '%{1}'", r, EscapeAtArgument(RemoveQuote(args[0].ToString()).ToUpper()));
return string.Format("upper({0}) like '%{1}'", r, RemoveQuote(args[0].ToString()).ToUpper());
case "Contains":
return string.Format("upper({0}) like '%{1}%'", r, EscapeAtArgument(RemoveQuote(args[0].ToString()).ToUpper()));
return string.Format("upper({0}) like '%{1}%'", r, RemoveQuote(args[0].ToString()).ToUpper());
case "Substring":
var startIndex = Int32.Parse(args[0].ToString()) + 1;
if (args.Count == 2)
@@ -22,23 +22,26 @@ namespace Umbraco.Core.Persistence.Repositories
{
private readonly IContentTypeRepository _contentTypeRepository;
private readonly ITemplateRepository _templateRepository;
private readonly CacheHelper _cacheHelper;
public ContentRepository(IDatabaseUnitOfWork work, IContentTypeRepository contentTypeRepository, ITemplateRepository templateRepository)
public ContentRepository(IDatabaseUnitOfWork work, IContentTypeRepository contentTypeRepository, ITemplateRepository templateRepository, CacheHelper cacheHelper)
: base(work)
{
_contentTypeRepository = contentTypeRepository;
_templateRepository = templateRepository;
_cacheHelper = cacheHelper;
EnsureUniqueNaming = true;
}
public ContentRepository(IDatabaseUnitOfWork work, IRepositoryCacheProvider cache, IContentTypeRepository contentTypeRepository, ITemplateRepository templateRepository)
public ContentRepository(IDatabaseUnitOfWork work, IRepositoryCacheProvider cache, IContentTypeRepository contentTypeRepository, ITemplateRepository templateRepository, CacheHelper cacheHelper)
: base(work, cache)
{
_contentTypeRepository = contentTypeRepository;
_templateRepository = templateRepository;
_cacheHelper = cacheHelper;
EnsureUniqueNaming = true;
EnsureUniqueNaming = true;
}
public bool EnsureUniqueNaming { get; set; }
@@ -129,6 +132,7 @@ namespace Umbraco.Core.Persistence.Repositories
{
var list = new List<string>
{
"DELETE FROM cmsTask WHERE nodeId = @Id",
"DELETE FROM umbracoUser2NodeNotify WHERE nodeId = @Id",
"DELETE FROM umbracoUser2NodePermission WHERE nodeId = @Id",
"DELETE FROM umbracoRelation WHERE parentId = @Id",
@@ -264,7 +268,7 @@ namespace Umbraco.Core.Persistence.Repositories
//Assign the same permissions to it as the parent node
// http://issues.umbraco.org/issue/U4-2161
var permissionsRepo = new PermissionRepository<IContent>(UnitOfWork);
var permissionsRepo = new PermissionRepository<IContent>(UnitOfWork, _cacheHelper);
var parentPermissions = permissionsRepo.GetPermissionsForEntity(entity.ParentId).ToArray();
//if there are parent permissions then assign them, otherwise leave null and permissions will become the
// user's default permissions.
@@ -273,9 +277,9 @@ namespace Umbraco.Core.Persistence.Repositories
var userPermissions = (
from perm in parentPermissions
from p in perm.AssignedPermissions
select new Tuple<object, string>(perm.UserId, p)).ToList();
select new Tuple<int, string>(perm.UserId, p)).ToList();
permissionsRepo.AssignEntityPermissions(entity, userPermissions);
permissionsRepo.ReplaceEntityPermissions(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;
@@ -527,15 +531,21 @@ namespace Umbraco.Core.Persistence.Repositories
return GetByVersion(dto.ContentVersionDto.VersionId);
}
public void AssignEntityPermissions(IContent entity, char permission, IEnumerable<object> userIds)
/// <summary>
/// Assigns a single permission to the current content item for the specified user ids
/// </summary>
/// <param name="entity"></param>
/// <param name="permission"></param>
/// <param name="userIds"></param>
public void AssignEntityPermission(IContent entity, char permission, IEnumerable<int> userIds)
{
var repo = new PermissionRepository<IContent>(UnitOfWork);
repo.AssignEntityPermissions(entity, permission, userIds);
var repo = new PermissionRepository<IContent>(UnitOfWork, _cacheHelper);
repo.AssignEntityPermission(entity, permission, userIds);
}
public IEnumerable<EntityPermission> GetPermissionsForEntity(int entityId)
{
var repo = new PermissionRepository<IContent>(UnitOfWork);
var repo = new PermissionRepository<IContent>(UnitOfWork, _cacheHelper);
return repo.GetPermissionsForEntity(entityId);
}
@@ -568,33 +578,6 @@ namespace Umbraco.Core.Persistence.Repositories
return content;
}
private PropertyCollection GetPropertyCollection(int id, Guid versionId, IContentType contentType, DateTime createDate, DateTime updateDate)
{
var sql = new Sql();
sql.Select("*")
.From<PropertyDataDto>()
.InnerJoin<PropertyTypeDto>()
.On<PropertyDataDto, PropertyTypeDto>(left => left.PropertyTypeId, right => right.Id)
.Where<PropertyDataDto>(x => x.NodeId == id)
.Where<PropertyDataDto>(x => x.VersionId == versionId);
var propertyDataDtos = Database.Fetch<PropertyDataDto, PropertyTypeDto>(sql);
var propertyFactory = new PropertyFactory(contentType, versionId, id, createDate, updateDate);
var properties = propertyFactory.BuildEntity(propertyDataDtos);
var newProperties = properties.Where(x => x.HasIdentity == false);
foreach (var property in newProperties)
{
var propertyDataDto = new PropertyDataDto{ NodeId = id, PropertyTypeId = property.PropertyTypeId, VersionId = versionId };
int primaryKey = Convert.ToInt32(Database.Insert(propertyDataDto));
property.Version = versionId;
property.Id = primaryKey;
}
return new PropertyCollection(properties);
}
private string EnsureUniqueNodeName(int parentId, string nodeName, int id = 0)
{
if (EnsureUniqueNaming == false)
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Threading.Tasks;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Models.EntityBase;
using Umbraco.Core.Models.Rdbms;
@@ -54,19 +55,10 @@ namespace Umbraco.Core.Persistence.Repositories
yield return dto.ContentTypeNodeId;
}
}
/// <summary>
/// We need to override this method to ensure that any content cache is cleared
/// </summary>
/// <param name="entity"></param>
/// <remarks>
/// see: http://issues.umbraco.org/issue/U4-1963
/// </remarks>
public override void PersistUpdatedItem(IEntity entity)
protected virtual PropertyType CreatePropertyType(Guid dataTypeId, DataTypeDatabaseType dbType, string propertyTypeAlias)
{
InMemoryCacheProvider.Current.Clear(typeof(IContent));
RuntimeCacheProvider.Current.Clear(typeof(IContent));
base.PersistUpdatedItem(entity);
return new PropertyType(dataTypeId, dbType);
}
protected void PersistNewBaseContentType(ContentTypeDto dto, IContentTypeComposition entity)
@@ -158,8 +150,7 @@ namespace Umbraco.Core.Persistence.Repositories
//If the Id of the DataType is not set, we resolve it from the db by its ControlId
if (propertyType.DataTypeDefinitionId == 0 || propertyType.DataTypeDefinitionId == default(int))
{
var datatype = Database.FirstOrDefault<DataTypeDto>("WHERE controlId = @Id", new { Id = propertyType.DataTypeId });
propertyType.DataTypeDefinitionId = datatype.DataTypeId;
AssignDataTypeFromPropertyEditor(propertyType);
}
var propertyTypeDto = propertyFactory.BuildPropertyTypeDto(tabId, propertyType);
int typePrimaryKey = Convert.ToInt32(Database.Insert(propertyTypeDto));
@@ -312,12 +303,16 @@ namespace Umbraco.Core.Persistence.Repositories
foreach (var propertyType in entity.PropertyTypes)
{
var tabId = propertyType.PropertyGroupId != null ? propertyType.PropertyGroupId.Value : default(int);
//If the Id of the DataType is not set, we resolve it from the db by its ControlId
if (propertyType.DataTypeDefinitionId == 0 || propertyType.DataTypeDefinitionId == default(int))
{
var datatype = Database.FirstOrDefault<DataTypeDto>("WHERE controlId = @Id", new { Id = propertyType.DataTypeId });
propertyType.DataTypeDefinitionId = datatype.DataTypeId;
AssignDataTypeFromPropertyEditor(propertyType);
}
//validate the alias!
ValidateAlias(propertyType);
var propertyTypeDto = propertyGroupFactory.BuildPropertyTypeDto(tabId, propertyType);
int typePrimaryKey = propertyType.HasIdentity
? Database.Update(propertyTypeDto)
@@ -354,7 +349,7 @@ namespace Umbraco.Core.Persistence.Repositories
var dtos = Database.Fetch<PropertyTypeGroupDto, PropertyTypeDto, DataTypeDto, PropertyTypeGroupDto>(new GroupPropertyTypeRelator().Map, sql);
var propertyGroupFactory = new PropertyGroupFactory(id, createDate, updateDate);
var propertyGroupFactory = new PropertyGroupFactory(id, createDate, updateDate, CreatePropertyType);
var propertyGroups = propertyGroupFactory.BuildEntity(dtos);
return new PropertyGroupCollection(propertyGroups);
}
@@ -371,29 +366,88 @@ namespace Umbraco.Core.Persistence.Repositories
var dtos = Database.Fetch<PropertyTypeDto, DataTypeDto>(sql);
//TODO Move this to a PropertyTypeFactory
var list = (from dto in dtos
where (dto.PropertyTypeGroupId > 0) == false
select
new PropertyType(dto.DataTypeDto.ControlId,
dto.DataTypeDto.DbType.EnumParse<DataTypeDatabaseType>(true))
{
Alias = dto.Alias,
DataTypeDefinitionId = dto.DataTypeId,
Description = dto.Description,
Id = dto.Id,
Name = dto.Name,
HelpText = dto.HelpText,
Mandatory = dto.Mandatory,
SortOrder = dto.SortOrder,
ValidationRegExp = dto.ValidationRegExp,
CreateDate = createDate,
UpdateDate = updateDate
}).ToList();
var list = new List<PropertyType>();
foreach (var dto in dtos.Where(x => (x.PropertyTypeGroupId > 0) == false))
{
var propType = CreatePropertyType(dto.DataTypeDto.ControlId, dto.DataTypeDto.DbType.EnumParse<DataTypeDatabaseType>(true), dto.Alias);
propType.Alias = dto.Alias;
propType.DataTypeDefinitionId = dto.DataTypeId;
propType.Description = dto.Description;
propType.Id = dto.Id;
propType.Name = dto.Name;
propType.HelpText = dto.HelpText;
propType.Mandatory = dto.Mandatory;
propType.SortOrder = dto.SortOrder;
propType.ValidationRegExp = dto.ValidationRegExp;
propType.CreateDate = createDate;
propType.UpdateDate = updateDate;
list.Add(propType);
}
//Reset dirty properties
Parallel.ForEach(list, currentFile => currentFile.ResetDirtyProperties(false));
return new PropertyTypeCollection(list);
}
protected void ValidateAlias(PropertyType pt)
{
Mandate.That<InvalidOperationException>(string.IsNullOrEmpty(pt.Alias) == false,
() =>
{
var message =
string.Format(
"{0} '{1}' cannot have an empty Alias. This is most likely due to invalid characters stripped from the Alias.",
"Property Type",
pt.Name);
var exception = new InvalidOperationException(message);
LogHelper.Error<ContentTypeBaseRepository<TId, TEntity>>(message, exception);
throw exception;
});
}
protected void ValidateAlias(TEntity entity)
{
Mandate.That<InvalidOperationException>(string.IsNullOrEmpty(entity.Alias) == false,
() =>
{
var message =
string.Format(
"{0} '{1}' cannot have an empty Alias. This is most likely due to invalid characters stripped from the Alias.",
typeof(TEntity).Name,
entity.Name);
var exception = new InvalidOperationException(message);
LogHelper.Error<ContentTypeBaseRepository<TId, TEntity>>(message, exception);
throw exception;
});
}
/// <summary>
/// Try to set the data type id based on its ControlId
/// </summary>
/// <param name="propertyType"></param>
private void AssignDataTypeFromPropertyEditor(PropertyType propertyType)
{
//we cannot try to assign a data type of it's an empty guid
if (propertyType.DataTypeId != Guid.Empty)
{
var sql = new Sql()
.Select("*")
.From<DataTypeDto>()
.Where("controlId = @Id", new { Id = propertyType.DataTypeId })
.OrderBy<DataTypeDto>(typeDto => typeDto.DataTypeId);
var datatype = Database.FirstOrDefault<DataTypeDto>(sql);
//we cannot assign a data type if one was not found
if (datatype != null)
{
propertyType.DataTypeDefinitionId = datatype.DataTypeId;
}
else
{
LogHelper.Warn<ContentTypeBaseRepository<TId, TEntity>>("Could not assign a data type for the property type " + propertyType.Alias + " since no data type was found with a property editor " + propertyType.DataTypeId);
}
}
}
}
}
@@ -208,18 +208,7 @@ namespace Umbraco.Core.Persistence.Repositories
protected override void PersistUpdatedItem(IContentType entity)
{
Mandate.That<Exception>(string.IsNullOrEmpty(entity.Alias) == false,
() =>
{
var message =
string.Format(
"ContentType '{0}' cannot have an empty Alias. This is most likely due to invalid characters stripped from the Alias.",
entity.Name);
var exception = new Exception(message);
LogHelper.Error<ContentTypeRepository>(message, exception);
throw exception;
});
ValidateAlias(entity);
//Updates Modified date
((ContentType)entity).UpdatingEntity();
@@ -23,8 +23,19 @@ namespace Umbraco.Core.Persistence.Repositories
/// <returns>An enumerable list of <see cref="IContent"/></returns>
IEnumerable<IContent> GetByPublishedVersion(IQuery<IContent> query);
void AssignEntityPermissions(IContent entity, char permission, IEnumerable<object> userIds);
/// <summary>
/// Assigns a single permission to the current content item for the specified user ids
/// </summary>
/// <param name="entity"></param>
/// <param name="permission"></param>
/// <param name="userIds"></param>
void AssignEntityPermission(IContent entity, char permission, IEnumerable<int> userIds);
/// <summary>
/// Gets the list of permissions for the content item
/// </summary>
/// <param name="entityId"></param>
/// <returns></returns>
IEnumerable<EntityPermission> GetPermissionsForEntity(int entityId);
}
}
@@ -0,0 +1,43 @@
using System.Collections.Generic;
using Umbraco.Core.Models;
namespace Umbraco.Core.Persistence.Repositories
{
public interface IMemberGroupRepository : IRepositoryQueryable<int, IMemberGroup>
{
/// <summary>
/// Gets a member group by it's name
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
IMemberGroup GetByName(string name);
/// <summary>
/// Creates the new member group if it doesn't already exist
/// </summary>
/// <param name="roleName"></param>
IMemberGroup CreateIfNotExists(string roleName);
/// <summary>
/// Returns the member groups for a given member
/// </summary>
/// <param name="memberId"></param>
/// <returns></returns>
IEnumerable<IMemberGroup> GetMemberGroupsForMember(int memberId);
/// <summary>
/// Returns the member groups for a given member
/// </summary>
/// <param name="username"></param>
/// <returns></returns>
IEnumerable<IMemberGroup> GetMemberGroupsForMember(string username);
void AssignRoles(string[] usernames, string[] roleNames);
void DissociateRoles(string[] usernames, string[] roleNames);
void AssignRoles(int[] memberIds, string[] roleNames);
void DissociateRoles(int[] memberIds, string[] roleNames);
}
}
@@ -7,8 +7,17 @@ using Umbraco.Core.Persistence.Querying;
namespace Umbraco.Core.Persistence.Repositories
{
internal interface IMemberRepository : IRepositoryVersionable<int, IMember>
public interface IMemberRepository : IRepositoryVersionable<int, IMember>
{
/// <summary>
/// Finds members in a given role
/// </summary>
/// <param name="roleName"></param>
/// <param name="usernameToMatch"></param>
/// <param name="matchType"></param>
/// <returns></returns>
IEnumerable<IMember> FindMembersInRole(string roleName, string usernameToMatch, StringPropertyMatchType matchType = StringPropertyMatchType.StartsWith);
/// <summary>
/// Get all members in a specific group
/// </summary>
@@ -6,7 +6,7 @@ using Umbraco.Core.Persistence.Querying;
namespace Umbraco.Core.Persistence.Repositories
{
internal interface IUserRepository : IRepositoryQueryable<int, IUser>
public interface IUserRepository : IRepositoryQueryable<int, IUser>
{
/// <summary>
/// Gets the count of items based on a complex query
@@ -38,14 +38,21 @@ namespace Umbraco.Core.Persistence.Repositories
/// <param name="orderBy"></param>
/// <returns></returns>
IEnumerable<IUser> GetPagedResultsByQuery(IQuery<IUser> query, int pageIndex, int pageSize, out int totalRecords, Expression<Func<IUser, string>> orderBy);
/// <summary>
/// Gets the user permissions for the specified entities
/// </summary>
/// <param name="userId"></param>
/// <param name="entityIds"></param>
/// <returns></returns>
IEnumerable<EntityPermission> GetUserPermissionsForEntities(object userId, params int[] entityIds);
IEnumerable<EntityPermission> GetUserPermissionsForEntities(int userId, params int[] entityIds);
/// <summary>
/// Replaces the same permission set for a single user to any number of entities
/// </summary>
/// <param name="userId"></param>
/// <param name="permissions"></param>
/// <param name="entityIds"></param>
void ReplaceUserPermissions(int userId, IEnumerable<char> permissions, params int[] entityIds);
}
}
@@ -2,7 +2,7 @@
namespace Umbraco.Core.Persistence.Repositories
{
internal interface IUserTypeRepository : IRepositoryQueryable<int, IUserType>
public interface IUserTypeRepository : IRepositoryQueryable<int, IUserType>
{
}
@@ -124,6 +124,7 @@ namespace Umbraco.Core.Persistence.Repositories
{
var list = new List<string>
{
"DELETE FROM cmsTask WHERE nodeId = @Id",
"DELETE FROM umbracoUser2NodeNotify WHERE nodeId = @Id",
"DELETE FROM umbracoUser2NodePermission WHERE nodeId = @Id",
"DELETE FROM umbracoRelation WHERE parentId = @Id",
@@ -358,34 +359,7 @@ namespace Umbraco.Core.Persistence.Repositories
}
#endregion
private PropertyCollection GetPropertyCollection(int id, Guid versionId, IMediaType contentType, DateTime createDate, DateTime updateDate)
{
var sql = new Sql();
sql.Select("*")
.From<PropertyDataDto>()
.InnerJoin<PropertyTypeDto>()
.On<PropertyDataDto, PropertyTypeDto>(left => left.PropertyTypeId, right => right.Id)
.Where<PropertyDataDto>(x => x.NodeId == id)
.Where<PropertyDataDto>(x => x.VersionId == versionId);
var propertyDataDtos = Database.Fetch<PropertyDataDto, PropertyTypeDto>(sql);
var propertyFactory = new PropertyFactory(contentType, versionId, id, createDate, updateDate);
var properties = propertyFactory.BuildEntity(propertyDataDtos);
var newProperties = properties.Where(x => x.HasIdentity == false);
foreach (var property in newProperties)
{
var propertyDataDto = new PropertyDataDto { NodeId = id, PropertyTypeId = property.PropertyTypeId, VersionId = versionId };
int primaryKey = Convert.ToInt32(Database.Insert(propertyDataDto));
property.Version = versionId;
property.Id = primaryKey;
}
return new PropertyCollection(properties);
}
private string EnsureUniqueNodeName(int parentId, string nodeName, int id = 0)
{
if (EnsureUniqueNaming == false)
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Models.EntityBase;
using Umbraco.Core.Models.Rdbms;
@@ -162,6 +163,8 @@ namespace Umbraco.Core.Persistence.Repositories
protected override void PersistUpdatedItem(IMediaType entity)
{
ValidateAlias(entity);
//Updates Modified date
((MediaType)entity).UpdatingEntity();
@@ -1,7 +1,383 @@
namespace Umbraco.Core.Persistence.Repositories
using System;
using System.Collections.Generic;
using System.Linq;
using Umbraco.Core.Events;
using Umbraco.Core.Models;
using Umbraco.Core.Models.EntityBase;
using Umbraco.Core.Models.Rdbms;
using Umbraco.Core.Persistence.Caching;
using Umbraco.Core.Persistence.Factories;
using Umbraco.Core.Persistence.Querying;
using Umbraco.Core.Persistence.SqlSyntax;
using Umbraco.Core.Persistence.UnitOfWork;
using Umbraco.Core.Services;
using Umbraco.Core.Cache;
namespace Umbraco.Core.Persistence.Repositories
{
public class MemberGroupRepository
internal class MemberGroupRepository : PetaPocoRepositoryBase<int, IMemberGroup>, IMemberGroupRepository
{
private readonly CacheHelper _cacheHelper;
public MemberGroupRepository(IDatabaseUnitOfWork work, CacheHelper cacheHelper)
: base(work)
{
if (cacheHelper == null) throw new ArgumentNullException("cacheHelper");
_cacheHelper = cacheHelper;
}
public MemberGroupRepository(IDatabaseUnitOfWork work, IRepositoryCacheProvider cache, CacheHelper cacheHelper)
: base(work, cache)
{
if (cacheHelper == null) throw new ArgumentNullException("cacheHelper");
_cacheHelper = cacheHelper;
}
private readonly MemberGroupFactory _modelFactory = new MemberGroupFactory();
protected override IMemberGroup PerformGet(int id)
{
var sql = GetBaseQuery(false);
sql.Where(GetBaseWhereClause(), new { Id = id });
var dto = Database.Fetch<NodeDto>(sql).FirstOrDefault();
return dto == null ? null : _modelFactory.BuildEntity(dto);
}
protected override IEnumerable<IMemberGroup> PerformGetAll(params int[] ids)
{
if (ids.Any())
{
var sql = new Sql()
.Select("*")
.From<NodeDto>()
.Where<NodeDto>(dto => dto.NodeObjectType == NodeObjectTypeId)
.Where("umbracoNode.id in (@ids)", new { ids = ids });
return Database.Fetch<NodeDto>(sql)
.Select(x => _modelFactory.BuildEntity(x));
}
else
{
var sql = new Sql()
.From<NodeDto>()
.Where<NodeDto>(dto => dto.NodeObjectType == NodeObjectTypeId);
return Database.Fetch<NodeDto>(sql)
.Select(x => _modelFactory.BuildEntity(x));
}
}
protected override IEnumerable<IMemberGroup> PerformGetByQuery(IQuery<IMemberGroup> query)
{
var sqlClause = GetBaseQuery(false);
var translator = new SqlTranslator<IMemberGroup>(sqlClause, query);
var sql = translator.Translate();
return Database.Fetch<NodeDto>(sql)
.Select(x => _modelFactory.BuildEntity(x));
}
protected override Sql GetBaseQuery(bool isCount)
{
var sql = new Sql();
sql.Select(isCount ? "COUNT(*)" : "*")
.From<NodeDto>()
.Where<NodeDto>(x => x.NodeObjectType == NodeObjectTypeId);
return sql;
}
protected override string GetBaseWhereClause()
{
return "umbracoNode.id = @Id";
}
protected override IEnumerable<string> GetDeleteClauses()
{
var list = new[]
{
"DELETE FROM umbracoUser2NodeNotify WHERE nodeId = @Id",
"DELETE FROM umbracoUser2NodePermission WHERE nodeId = @Id",
"DELETE FROM umbracoRelation WHERE parentId = @Id",
"DELETE FROM umbracoRelation WHERE childId = @Id",
"DELETE FROM cmsTagRelationship WHERE nodeId = @Id",
"DELETE FROM cmsMember2MemberGroup WHERE MemberGroup = @Id",
"DELETE FROM umbracoNode WHERE id = @Id"
};
return list;
}
protected override Guid NodeObjectTypeId
{
get { return new Guid(Constants.ObjectTypes.MemberGroup); }
}
protected override void PersistNewItem(IMemberGroup entity)
{
//Save to db
var group = (MemberGroup)entity;
group.AddingEntity();
var dto = _modelFactory.BuildDto(group);
var o = Database.IsNew(dto) ? Convert.ToInt32(Database.Insert(dto)) : Database.Update(dto);
//Update with new correct path
dto.Path = string.Concat("-1,", dto.NodeId);
Database.Update(dto);
group.ResetDirtyProperties();
}
protected override void PersistUpdatedItem(IMemberGroup entity)
{
var dto = _modelFactory.BuildDto(entity);
Database.Update(dto);
((ICanBeDirty)entity).ResetDirtyProperties();
}
public IMemberGroup GetByName(string name)
{
return _cacheHelper.RuntimeCache.GetCacheItem<IMemberGroup>(
string.Format("{0}.{1}", typeof (IMemberGroup).FullName, name),
() =>
{
var qry = new Query<IMemberGroup>().Where(group => group.Name.Equals(name));
var result = GetByQuery(qry);
return result.FirstOrDefault();
},
//cache for 5 mins since that is the default in the RuntimeCacheProvider
TimeSpan.FromMinutes(5),
//sliding is true
true);
}
public IMemberGroup CreateIfNotExists(string roleName)
{
using (var transaction = Database.GetTransaction())
{
var qry = new Query<IMemberGroup>().Where(group => group.Name.Equals(roleName));
var result = GetByQuery(qry);
if (result.Any()) return null;
var grp = new MemberGroup
{
Name = roleName
};
PersistNewItem(grp);
if (SavingMemberGroup.IsRaisedEventCancelled(new SaveEventArgs<IMemberGroup>(grp), this))
{
return null;
}
transaction.Complete();
SavedMemberGroup.RaiseEvent(new SaveEventArgs<IMemberGroup>(grp), this);
return grp;
}
}
public IEnumerable<IMemberGroup> GetMemberGroupsForMember(int memberId)
{
var sql = new Sql();
sql.Select("umbracoNode.*")
.From<NodeDto>()
.InnerJoin<Member2MemberGroupDto>()
.On<NodeDto, Member2MemberGroupDto>(dto => dto.NodeId, dto => dto.MemberGroup)
.Where<NodeDto>(x => x.NodeObjectType == NodeObjectTypeId)
.Where<Member2MemberGroupDto>(x => x.Member == memberId);
return Database.Fetch<NodeDto>(sql)
.DistinctBy(dto => dto.NodeId)
.Select(x => _modelFactory.BuildEntity(x));
}
public IEnumerable<IMemberGroup> GetMemberGroupsForMember(string username)
{
//find the member by username
var memberSql = new Sql();
var memberObjectType = new Guid(Constants.ObjectTypes.Member);
var escapedUsername = PetaPocoExtensions.EscapeAtSymbols(username);
memberSql.Select("umbracoNode.id")
.From<NodeDto>()
.InnerJoin<MemberDto>()
.On<NodeDto, MemberDto>(dto => dto.NodeId, dto => dto.NodeId)
.Where<NodeDto>(x => x.NodeObjectType == memberObjectType)
.Where<MemberDto>(x => x.LoginName == escapedUsername);
var memberIdUsername = Database.Fetch<int?>(memberSql).FirstOrDefault();
if (memberIdUsername.HasValue == false)
{
return Enumerable.Empty<IMemberGroup>();
}
var sql = new Sql();
sql.Select("umbracoNode.*")
.From<NodeDto>()
.InnerJoin<Member2MemberGroupDto>()
.On<NodeDto, Member2MemberGroupDto>(dto => dto.NodeId, dto => dto.MemberGroup)
.Where<NodeDto>(x => x.NodeObjectType == NodeObjectTypeId)
.Where<Member2MemberGroupDto>(x => x.Member == memberIdUsername.Value);
return Database.Fetch<NodeDto>(sql)
.DistinctBy(dto => dto.NodeId)
.Select(x => _modelFactory.BuildEntity(x));
}
public void AssignRoles(string[] usernames, string[] roleNames)
{
using (var transaction = Database.GetTransaction())
{
//first get the member ids based on the usernames
var memberSql = new Sql();
var memberObjectType = new Guid(Constants.ObjectTypes.Member);
memberSql.Select("umbracoNode.id")
.From<NodeDto>()
.InnerJoin<MemberDto>()
.On<NodeDto, MemberDto>(dto => dto.NodeId, dto => dto.NodeId)
.Where<NodeDto>(x => x.NodeObjectType == memberObjectType)
.Where("cmsMember.LoginName in (@usernames)", new { usernames = usernames });
var memberIds = Database.Fetch<int>(memberSql).ToArray();
AssignRolesInternal(memberIds, roleNames);
transaction.Complete();
}
}
public void DissociateRoles(string[] usernames, string[] roleNames)
{
using (var transaction = Database.GetTransaction())
{
//first get the member ids based on the usernames
var memberSql = new Sql();
var memberObjectType = new Guid(Constants.ObjectTypes.Member);
memberSql.Select("umbracoNode.id")
.From<NodeDto>()
.InnerJoin<MemberDto>()
.On<NodeDto, MemberDto>(dto => dto.NodeId, dto => dto.NodeId)
.Where<NodeDto>(x => x.NodeObjectType == memberObjectType)
.Where("cmsMember.LoginName in (@usernames)", new { usernames = usernames });
var memberIds = Database.Fetch<int>(memberSql).ToArray();
DissociateRolesInternal(memberIds, roleNames);
transaction.Complete();
}
}
public void AssignRoles(int[] memberIds, string[] roleNames)
{
using (var transaction = Database.GetTransaction())
{
AssignRolesInternal(memberIds, roleNames);
transaction.Complete();
}
}
public void AssignRolesInternal(int[] memberIds, string[] roleNames)
{
//create the missing roles first
var existingSql = new Sql()
.Select("*")
.From<NodeDto>()
.Where<NodeDto>(dto => dto.NodeObjectType == NodeObjectTypeId)
.Where("umbracoNode." + SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName("text") + " in (@names)", new { names = roleNames });
var existingRoles = Database.Fetch<NodeDto>(existingSql).Select(x => x.Text);
var missingRoles = roleNames.Except(existingRoles);
var missingGroups = missingRoles.Select(x => new MemberGroup {Name = x}).ToArray();
if (SavingMemberGroup.IsRaisedEventCancelled(new SaveEventArgs<IMemberGroup>(missingGroups), this))
{
return;
}
foreach (var m in missingGroups)
{
PersistNewItem(m);
}
SavedMemberGroup.RaiseEvent(new SaveEventArgs<IMemberGroup>(missingGroups), this);
//now go get all the dto's for roles with these role names
var rolesForNames = Database.Fetch<NodeDto>(existingSql).ToArray();
//get the groups that are currently assigned to any of these members
var assignedSql = new Sql();
assignedSql.Select(string.Format(
"{0},{1},{2}",
SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName("text"),
SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName("Member"),
SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName("MemberGroup")))
.From<NodeDto>()
.InnerJoin<Member2MemberGroupDto>()
.On<NodeDto, Member2MemberGroupDto>(dto => dto.NodeId, dto => dto.MemberGroup)
.Where<NodeDto>(x => x.NodeObjectType == NodeObjectTypeId)
.Where("cmsMember2MemberGroup.Member in (@ids)", new { ids = memberIds });
var currentlyAssigned = Database.Fetch<AssignedRolesDto>(assignedSql).ToArray();
//assign the roles for each member id
foreach (var memberId in memberIds)
{
//find any roles for the current member that are currently assigned that
//exist in the roleNames list, then determine which ones are not currently assigned.
var mId = memberId;
var found = currentlyAssigned.Where(x => x.MemberId == mId).ToArray();
var assignedRoles = found.Where(x => roleNames.Contains(x.RoleName)).Select(x => x.RoleName);
var nonAssignedRoles = roleNames.Except(assignedRoles);
foreach (var toAssign in nonAssignedRoles)
{
var groupId = rolesForNames.First(x => x.Text == toAssign).NodeId;
Database.Insert(new Member2MemberGroupDto { Member = mId, MemberGroup = groupId });
}
}
}
public void DissociateRoles(int[] memberIds, string[] roleNames)
{
using (var transaction = Database.GetTransaction())
{
DissociateRolesInternal(memberIds, roleNames);
transaction.Complete();
}
}
private void DissociateRolesInternal(int[] memberIds, string[] roleNames)
{
var existingSql = new Sql()
.Select("*")
.From<NodeDto>()
.Where<NodeDto>(dto => dto.NodeObjectType == NodeObjectTypeId)
.Where("umbracoNode." + SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName("text") + " in (@names)", new { names = roleNames });
var existingRolesIds = Database.Fetch<NodeDto>(existingSql).Select(x => x.NodeId).ToArray();
Database.Execute("DELETE FROM cmsMember2MemberGroup WHERE Member IN (@memberIds) AND MemberGroup IN (@memberGroups)",
new { memberIds = memberIds, memberGroups = existingRolesIds });
}
private class AssignedRolesDto
{
[Column("text")]
public string RoleName { get; set; }
[Column("Member")]
public int MemberId { get; set; }
[Column("MemberGroup")]
public int MemberGroupId { get; set; }
}
/// <summary>
/// Occurs before Save
/// </summary>
internal static event TypedEventHandler<IMemberGroupRepository, SaveEventArgs<IMemberGroup>> SavingMemberGroup;
/// <summary>
/// Occurs after Save
/// </summary>
internal static event TypedEventHandler<IMemberGroupRepository, SaveEventArgs<IMemberGroup>> SavedMemberGroup;
}
}
@@ -23,19 +23,22 @@ namespace Umbraco.Core.Persistence.Repositories
internal class MemberRepository : VersionableRepositoryBase<int, IMember>, IMemberRepository
{
private readonly IMemberTypeRepository _memberTypeRepository;
private readonly IMemberGroupRepository _memberGroupRepository;
public MemberRepository(IDatabaseUnitOfWork work, IMemberTypeRepository memberTypeRepository)
public MemberRepository(IDatabaseUnitOfWork work, IMemberTypeRepository memberTypeRepository, IMemberGroupRepository memberGroupRepository)
: base(work)
{
if (memberTypeRepository == null) throw new ArgumentNullException("memberTypeRepository");
_memberTypeRepository = memberTypeRepository;
_memberGroupRepository = memberGroupRepository;
}
public MemberRepository(IDatabaseUnitOfWork work, IRepositoryCacheProvider cache, IMemberTypeRepository memberTypeRepository)
public MemberRepository(IDatabaseUnitOfWork work, IRepositoryCacheProvider cache, IMemberTypeRepository memberTypeRepository, IMemberGroupRepository memberGroupRepository)
: base(work, cache)
{
if (memberTypeRepository == null) throw new ArgumentNullException("memberTypeRepository");
_memberTypeRepository = memberTypeRepository;
_memberGroupRepository = memberGroupRepository;
}
#region Overrides of RepositoryBase<int, IMembershipUser>
@@ -164,6 +167,7 @@ namespace Umbraco.Core.Persistence.Repositories
{
var list = new List<string>
{
"DELETE FROM cmsTask WHERE nodeId = @Id",
"DELETE FROM umbracoUser2NodeNotify WHERE nodeId = @Id",
"DELETE FROM umbracoUser2NodePermission WHERE nodeId = @Id",
"DELETE FROM umbracoRelation WHERE parentId = @Id",
@@ -237,7 +241,12 @@ namespace Umbraco.Core.Persistence.Repositories
//Create the PropertyData for this version - cmsPropertyData
var propertyFactory = new PropertyFactory(entity.ContentType, entity.Version, entity.Id);
var propertyDataDtos = propertyFactory.BuildDto(((Member)entity).Properties);
//Add Properties
// - don't try to save the property if it doesn't exist (or doesn't have an ID) on the content type
// - this can occur if the member type doesn't contain the built-in properties that the
// - member object contains.
var propsToPersist = entity.Properties.Where(x => x.PropertyType.HasIdentity).ToArray();
var propertyDataDtos = propertyFactory.BuildDto(propsToPersist);
var keyDictionary = new Dictionary<int, int>();
//Add Properties
@@ -248,7 +257,7 @@ namespace Umbraco.Core.Persistence.Repositories
}
//Update Properties with its newly set Id
foreach (var property in ((Member)entity).Properties)
foreach (var property in propsToPersist)
{
property.Id = keyDictionary[property.PropertyTypeId];
}
@@ -331,12 +340,10 @@ namespace Umbraco.Core.Persistence.Repositories
//Add Properties
// - don't try to save the property if it doesn't exist (or doesn't have an ID) on the content type
// - this can occur if the member type doesn't contain the built-in properties that the
// - member object contains.
var existingProperties = entity.Properties
.Where(property => entity.ContentType.PropertyTypes.Any(x => x.Alias == property.Alias && x.HasIdentity))
.ToList();
// - member object contains.
var propsToPersist = entity.Properties.Where(x => x.PropertyType.HasIdentity).ToArray();
var propertyDataDtos = propertyFactory.BuildDto(existingProperties);
var propertyDataDtos = propertyFactory.BuildDto(propsToPersist);
foreach (var propertyDataDto in propertyDataDtos)
{
@@ -419,6 +426,57 @@ namespace Umbraco.Core.Persistence.Repositories
#endregion
public IEnumerable<IMember> FindMembersInRole(string roleName, string usernameToMatch, StringPropertyMatchType matchType = StringPropertyMatchType.StartsWith)
{
//get the group id
var grpQry = new Query<IMemberGroup>().Where(group => group.Name.Equals(roleName));
var memberGroup = _memberGroupRepository.GetByQuery(grpQry).FirstOrDefault();
if (memberGroup == null) return Enumerable.Empty<IMember>();
// get the members by username
var query = new Query<IMember>();
switch (matchType)
{
case StringPropertyMatchType.Exact:
query.Where(member => member.Username.Equals(usernameToMatch));
break;
case StringPropertyMatchType.Contains:
query.Where(member => member.Username.Contains(usernameToMatch));
break;
case StringPropertyMatchType.StartsWith:
query.Where(member => member.Username.StartsWith(usernameToMatch));
break;
case StringPropertyMatchType.EndsWith:
query.Where(member => member.Username.EndsWith(usernameToMatch));
break;
case StringPropertyMatchType.Wildcard:
query.Where(member => member.Username.SqlWildcard(usernameToMatch, TextColumnType.NVarchar));
break;
default:
throw new ArgumentOutOfRangeException("matchType");
}
var matchedMembers = GetByQuery(query).ToArray();
var membersInGroup = new List<IMember>();
//then we need to filter the matched members that are in the role
//since the max sql params are 2100 on sql server, we'll reduce that to be safe for potentially other servers and run the queries in batches
var inGroups = matchedMembers.InGroupsOf(1000);
foreach (var batch in inGroups)
{
var memberIdBatch = batch.Select(x => x.Id);
var sql = new Sql().Select("*").From<Member2MemberGroupDto>()
.Where<Member2MemberGroupDto>(dto => dto.MemberGroup == memberGroup.Id)
.Where("Member IN (@memberIds)", new { memberIds = memberIdBatch });
var memberIdsInGroup = Database.Fetch<Member2MemberGroupDto>(sql)
.Select(x => x.Member).ToArray();
membersInGroup.AddRange(matchedMembers.Where(x => memberIdsInGroup.Contains(x.Id)));
}
return membersInGroup;
}
/// <summary>
/// Get all members in a specific group
/// </summary>
@@ -426,9 +484,13 @@ namespace Umbraco.Core.Persistence.Repositories
/// <returns></returns>
public IEnumerable<IMember> GetByMemberGroup(string groupName)
{
var subquery = GetSubquery().Where<NodeDto>(x => x.Text == groupName);
var grpQry = new Query<IMemberGroup>().Where(group => group.Name.Equals(groupName));
var memberGroup = _memberGroupRepository.GetByQuery(grpQry).FirstOrDefault();
if (memberGroup == null) return Enumerable.Empty<IMember>();
var subQuery = new Sql().Select("Member").From<Member2MemberGroupDto>().Where<Member2MemberGroupDto>(dto => dto.MemberGroup == memberGroup.Id);
var sql = GetBaseQuery(false)
.Append(new Sql("WHERE umbracoNode.id IN (" + subquery.SQL + ")", subquery.Arguments))
.Append(new Sql("WHERE umbracoNode.id IN (" + subQuery.SQL + ")", subQuery.Arguments))
.OrderByDescending<ContentVersionDto>(x => x.VersionDate)
.OrderBy<NodeDto>(x => x.SortOrder);
@@ -539,6 +601,8 @@ namespace Umbraco.Core.Persistence.Repositories
var factory = new MemberReadOnlyFactory(memberTypes);
var member = factory.BuildEntity(dto);
member.Properties = GetPropertyCollection(dto.NodeId, dto.VersionId, member.ContentType, dto.CreateDate, dto.UpdateDate);
return member;
}
@@ -552,8 +616,15 @@ namespace Umbraco.Core.Persistence.Repositories
var memberTypeList = _memberTypeRepository.GetAll();
memberTypeList.ForEach(x => memberTypes.Add(x.Alias, x));
var entities = new List<IMember>();
var factory = new MemberReadOnlyFactory(memberTypes);
return dtos.Select(factory.BuildEntity);
foreach (var dto in dtos)
{
var entity = factory.BuildEntity(dto);
entity.Properties = GetPropertyCollection(dto.NodeId, dto.VersionId, entity.ContentType, dto.CreateDate, dto.UpdateDate);
entities.Add(entity);
}
return entities;
}
}
}
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Umbraco.Core.Logging;
using Umbraco.Core.Models.EntityBase;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Rdbms;
@@ -17,17 +18,17 @@ namespace Umbraco.Core.Persistence.Repositories
/// </summary>
internal class MemberTypeRepository : ContentTypeBaseRepository<int, IMemberType>, IMemberTypeRepository
{
public MemberTypeRepository(IDatabaseUnitOfWork work)
public MemberTypeRepository(IDatabaseUnitOfWork work)
: base(work)
{
}
public MemberTypeRepository(IDatabaseUnitOfWork work, IRepositoryCacheProvider cache)
public MemberTypeRepository(IDatabaseUnitOfWork work, IRepositoryCacheProvider cache)
: base(work, cache)
{
}
#region Overrides of RepositoryBase<int, IMemberType>
#region Overrides of RepositoryBase<int, IMemberType>
protected override IMemberType PerformGet(int id)
{
@@ -39,13 +40,13 @@ namespace Umbraco.Core.Persistence.Repositories
Database.Fetch<MemberTypeReadOnlyDto, PropertyTypeReadOnlyDto, PropertyTypeGroupReadOnlyDto, MemberTypeReadOnlyDto>(
new PropertyTypePropertyGroupRelator().Map, sql);
if (dtos == null || dtos.Any() == false)
return null;
if (dtos == null || dtos.Any() == false)
return null;
var factory = new MemberTypeReadOnlyFactory();
var member = factory.BuildEntity(dtos.First());
var factory = new MemberTypeReadOnlyFactory();
var member = factory.BuildEntity(dtos.First());
return member;
return member;
}
protected override IEnumerable<IMemberType> PerformGetAll(params int[] ids)
@@ -98,11 +99,11 @@ namespace Umbraco.Core.Persistence.Repositories
return sql;
}
sql.Select("umbracoNode.*", "cmsContentType.*", "cmsPropertyType.id AS PropertyTypeId", "cmsPropertyType.Alias",
sql.Select("umbracoNode.*", "cmsContentType.*", "cmsPropertyType.id AS PropertyTypeId", "cmsPropertyType.Alias",
"cmsPropertyType.Name", "cmsPropertyType.Description", "cmsPropertyType.helpText", "cmsPropertyType.mandatory",
"cmsPropertyType.validationRegExp", "cmsPropertyType.dataTypeId", "cmsPropertyType.sortOrder AS PropertyTypeSortOrder",
"cmsPropertyType.propertyTypeGroupId AS PropertyTypesGroupId", "cmsMemberType.memberCanEdit", "cmsMemberType.viewOnProfile",
"cmsDataType.controlId", "cmsDataType.dbType", "cmsPropertyTypeGroup.id AS PropertyTypeGroupId",
"cmsDataType.controlId", "cmsDataType.dbType", "cmsPropertyTypeGroup.id AS PropertyTypeGroupId",
"cmsPropertyTypeGroup.text AS PropertyGroupName", "cmsPropertyTypeGroup.parentGroupId",
"cmsPropertyTypeGroup.sortorder AS PropertyGroupSortOrder", "cmsPropertyTypeGroup.contenttypeNodeId")
.From<NodeDto>()
@@ -168,15 +169,18 @@ namespace Umbraco.Core.Persistence.Repositories
((MemberType)entity).AddingEntity();
//By Convention we add 9 stnd PropertyTypes to an Umbraco MemberType
entity.AddPropertyGroup(Constants.Conventions.Member.StandardPropertiesGroupName);
var standardPropertyTypes = Constants.Conventions.Member.GetStandardPropertyTypeStubs();
foreach (var standardPropertyType in standardPropertyTypes)
{
entity.AddPropertyType(standardPropertyType.Value);
entity.AddPropertyType(standardPropertyType.Value, Constants.Conventions.Member.StandardPropertiesGroupName);
}
var factory = new MemberTypeFactory(NodeObjectTypeId);
var dto = factory.BuildDto(entity);
EnsureExplicitDataTypeForBuiltInProperties(entity);
PersistNewBaseContentType(dto, entity);
//Handles the MemberTypeDto (cmsMemberType table)
@@ -191,6 +195,8 @@ namespace Umbraco.Core.Persistence.Repositories
protected override void PersistUpdatedItem(IMemberType entity)
{
ValidateAlias(entity);
//Updates Modified date
((MemberType)entity).UpdatingEntity();
@@ -210,10 +216,12 @@ namespace Umbraco.Core.Persistence.Repositories
var factory = new MemberTypeFactory(NodeObjectTypeId);
var dto = factory.BuildDto(entity);
EnsureExplicitDataTypeForBuiltInProperties(entity);
PersistUpdatedBaseContentType(dto, entity);
//Remove existing entries before inserting new ones
Database.Delete<MemberTypeDto>("WHERE NodeId = @Id", new {Id = entity.Id});
Database.Delete<MemberTypeDto>("WHERE NodeId = @Id", new { Id = entity.Id });
//Handles the MemberTypeDto (cmsMemberType table)
var memberTypeDtos = factory.BuildMemberTypeDtos(entity);
@@ -227,7 +235,50 @@ namespace Umbraco.Core.Persistence.Repositories
#endregion
private IEnumerable<IMemberType> BuildFromDtos(List<MemberTypeReadOnlyDto> dtos)
/// <summary>
/// Override so we can specify explicit db type's on any property types that are built-in.
/// </summary>
/// <param name="dataTypeId"></param>
/// <param name="dbType"></param>
/// <param name="propertyTypeAlias"></param>
/// <returns></returns>
protected override PropertyType CreatePropertyType(Guid dataTypeId, DataTypeDatabaseType dbType, string propertyTypeAlias)
{
//custom property type constructor logic to set explicit dbtype's for built in properties
var stdProps = Constants.Conventions.Member.GetStandardPropertyTypeStubs();
var propDbType = GetDbTypeForBuiltInProperty(propertyTypeAlias, dbType, stdProps);
return new PropertyType(dataTypeId, propDbType.Result,
//This flag tells the property type that it has an explicit dbtype and that it cannot be changed
// which is what we want for the built-in properties.
propDbType.Success);
}
/// <summary>
/// Ensure that all the built-in membership provider properties have their correct data type
/// and property editors assigned. This occurs prior to saving so that the correct values are persisted.
/// </summary>
/// <param name="memberType"></param>
private static void EnsureExplicitDataTypeForBuiltInProperties(IContentTypeBase memberType)
{
var stdProps = Constants.Conventions.Member.GetStandardPropertyTypeStubs();
foreach (var propertyType in memberType.PropertyTypes)
{
var dbTypeAttempt = GetDbTypeForBuiltInProperty(propertyType.Alias, propertyType.DataTypeDatabaseType, stdProps);
if (dbTypeAttempt)
{
//this reset's it's current data type reference which will be re-assigned based on the property editor assigned on the next line
propertyType.DataTypeDefinitionId = 0;
propertyType.DataTypeId = GetPropertyEditorForBuiltInProperty(propertyType.Alias, propertyType.DataTypeId, stdProps).Result;
}
}
}
/// <summary>
/// Builds a collection of entities from a collection of Dtos
/// </summary>
/// <param name="dtos"></param>
/// <returns></returns>
private static IEnumerable<IMemberType> BuildFromDtos(List<MemberTypeReadOnlyDto> dtos)
{
if (dtos == null || dtos.Any() == false)
return Enumerable.Empty<IMemberType>();
@@ -235,5 +286,58 @@ namespace Umbraco.Core.Persistence.Repositories
var factory = new MemberTypeReadOnlyFactory();
return dtos.Select(factory.BuildEntity);
}
/// <summary>
/// If this is one of our internal properties - we will manually assign the data type since they must
/// always correspond to the correct db type no matter what the backing data type is assigned.
/// </summary>
/// <param name="propAlias"></param>
/// <param name="dbType"></param>
/// <param name="standardProps"></param>
/// <returns>
/// Successful attempt if it was a built in property
/// </returns>
internal static Attempt<DataTypeDatabaseType> GetDbTypeForBuiltInProperty(
string propAlias,
DataTypeDatabaseType dbType,
Dictionary<string, PropertyType> standardProps)
{
var aliases = standardProps.Select(x => x.Key).ToArray();
//check if it is built in
if (aliases.Contains(propAlias))
{
//return the pre-determined db type for this property
return Attempt<DataTypeDatabaseType>.Succeed(standardProps.Single(x => x.Key == propAlias).Value.DataTypeDatabaseType);
}
return Attempt<DataTypeDatabaseType>.Fail(dbType);
}
/// <summary>
///
/// </summary>
/// <param name="propAlias"></param>
/// <param name="propertyEditor"></param>
/// <param name="standardProps"></param>
/// <returns>
/// Successful attempt if it was a built in property
/// </returns>
internal static Attempt<Guid> GetPropertyEditorForBuiltInProperty(
string propAlias,
Guid propertyEditor,
Dictionary<string, PropertyType> standardProps)
{
var aliases = standardProps.Select(x => x.Key).ToArray();
//check if it is built in
if (aliases.Contains(propAlias))
{
//return the pre-determined db type for this property
return Attempt<Guid>.Succeed(standardProps.Single(x => x.Key == propAlias).Value.DataTypeId);
}
return Attempt<Guid>.Fail(propertyEditor);
}
}
}
@@ -1,9 +1,12 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Dynamic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Web.Caching;
using Umbraco.Core.Events;
using Umbraco.Core.Models;
using Umbraco.Core.Models.EntityBase;
using Umbraco.Core.Models.Membership;
@@ -11,22 +14,26 @@ using Umbraco.Core.Models.Rdbms;
using Umbraco.Core.Persistence.Caching;
using Umbraco.Core.Persistence.SqlSyntax;
using Umbraco.Core.Persistence.UnitOfWork;
using Umbraco.Core.Services;
using CacheKeys = Umbraco.Core.Cache.CacheKeys;
using Umbraco.Core.Cache;
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 class PermissionRepository<TEntity>
where TEntity : class, IAggregateRoot
{
private readonly IDatabaseUnitOfWork _unitOfWork;
private readonly CacheHelper _cache;
internal PermissionRepository(IDatabaseUnitOfWork unitOfWork)
internal PermissionRepository(IDatabaseUnitOfWork unitOfWork, CacheHelper cache)
{
_unitOfWork = unitOfWork;
_cache = cache;
}
/// <summary>
@@ -35,39 +42,57 @@ namespace Umbraco.Core.Persistence.Repositories
/// <param name="userId"></param>
/// <param name="entityIds"></param>
/// <returns></returns>
internal IEnumerable<EntityPermission> GetUserPermissionsForEntities(object userId, params int[] entityIds)
public IEnumerable<EntityPermission> GetUserPermissionsForEntities(int userId, params int[] entityIds)
{
var whereBuilder = new StringBuilder();
//where userId = @userId AND
whereBuilder.Append(SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName("userId"));
whereBuilder.Append("=");
whereBuilder.Append(userId);
whereBuilder.Append(" AND ");
//where nodeId = @nodeId1 OR nodeId = @nodeId2, etc...
whereBuilder.Append("(");
for (var index = 0; index < entityIds.Length; index++)
{
var entityId = entityIds[index];
whereBuilder.Append(SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName("nodeId"));
whereBuilder.Append("=");
whereBuilder.Append(entityId);
if (index < entityIds.Length - 1)
var entityIdKey = string.Join(",", entityIds.Select(x => x.ToString(CultureInfo.InvariantCulture)));
return _cache.RuntimeCache.GetCacheItem<IEnumerable<EntityPermission>>(
string.Format("{0}{1}{2}", CacheKeys.UserPermissionsCacheKey, userId, entityIdKey),
() =>
{
whereBuilder.Append(" OR ");
}
}
whereBuilder.Append(")");
var sql = new Sql();
sql.Select("*")
.From<User2NodePermissionDto>()
.Where(whereBuilder.ToString());
var whereBuilder = new StringBuilder();
//where userId = @userId AND
whereBuilder.Append(SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName("userId"));
whereBuilder.Append("=");
whereBuilder.Append(userId);
if (entityIds.Any())
{
whereBuilder.Append(" AND ");
//where nodeId = @nodeId1 OR nodeId = @nodeId2, etc...
whereBuilder.Append("(");
for (var index = 0; index < entityIds.Length; index++)
{
var entityId = entityIds[index];
whereBuilder.Append(SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName("nodeId"));
whereBuilder.Append("=");
whereBuilder.Append(entityId);
if (index < entityIds.Length - 1)
{
whereBuilder.Append(" OR ");
}
}
whereBuilder.Append(")");
}
var sql = new Sql();
sql.Select("*")
.From<User2NodePermissionDto>()
.Where(whereBuilder.ToString());
//ToArray() to ensure it's all fetched from the db once.
var result = _unitOfWork.Database.Fetch<User2NodePermissionDto>(sql).ToArray();
return ConvertToPermissionList(result);
},
//Since this cache can be quite large (http://issues.umbraco.org/issue/U4-2161) we will only have this exist in cache for 20 minutes,
// then it will refresh from the database.
new TimeSpan(0, 20, 0),
//Since this cache can be quite large (http://issues.umbraco.org/issue/U4-2161) we will make this priority below average
priority: CacheItemPriority.BelowNormal);
//ToArray() to ensure it's all fetched from the db once.
var result = _unitOfWork.Database.Fetch<User2NodePermissionDto>(sql).ToArray();
return ConvertToPermissionList(result);
}
/// <summary>
@@ -75,7 +100,7 @@ namespace Umbraco.Core.Persistence.Repositories
/// </summary>
/// <param name="entityId"></param>
/// <returns></returns>
internal IEnumerable<EntityPermission> GetPermissionsForEntity(int entityId)
public IEnumerable<EntityPermission> GetPermissionsForEntity(int entityId)
{
var sql = new Sql();
sql.Select("*")
@@ -88,7 +113,118 @@ namespace Umbraco.Core.Persistence.Repositories
return ConvertToPermissionList(result);
}
private IEnumerable<EntityPermission> ConvertToPermissionList(IEnumerable<User2NodePermissionDto> result)
/// <summary>
/// Assigns the same permission set for a single user to any number of entities
/// </summary>
/// <param name="userId"></param>
/// <param name="permissions"></param>
/// <param name="entityIds"></param>
/// <remarks>
/// This will first clear the permissions for this user and entities and recreate them
/// </remarks>
public void ReplaceUserPermissions(int userId, IEnumerable<char> permissions, params int[] entityIds)
{
var db = _unitOfWork.Database;
using (var trans = db.GetTransaction())
{
db.Execute("DELETE FROM umbracoUser2NodePermission WHERE userId=@userId AND nodeId in (@nodeIds)",
new {userId = userId, nodeIds = entityIds});
var toInsert = new List<User2NodePermissionDto>();
foreach (var p in permissions)
{
foreach (var e in entityIds)
{
toInsert.Add(new User2NodePermissionDto
{
NodeId = e,
Permission = p.ToString(CultureInfo.InvariantCulture),
UserId = userId
});
}
}
_unitOfWork.Database.BulkInsertRecords(toInsert, trans);
trans.Complete();
//Raise the event
AssignedPermissions.RaiseEvent(
new SaveEventArgs<EntityPermission>(ConvertToPermissionList(toInsert), false), this);
}
}
/// <summary>
/// Assigns one permission to an entity for multiple users
/// </summary>
/// <param name="entity"></param>
/// <param name="permission"></param>
/// <param name="userIds"></param>
public void AssignEntityPermission(TEntity entity, char permission, IEnumerable<int> userIds)
{
var db = _unitOfWork.Database;
using (var trans = db.GetTransaction())
{
db.Execute("DELETE FROM umbracoUser2NodePermission WHERE nodeId=@nodeId AND permission=@permission AND userId in (@userIds)",
new
{
nodeId = entity.Id,
permission = permission.ToString(CultureInfo.InvariantCulture),
userIds = userIds
});
var actions = userIds.Select(id => new User2NodePermissionDto
{
NodeId = entity.Id,
Permission = permission.ToString(CultureInfo.InvariantCulture),
UserId = id
}).ToArray();
_unitOfWork.Database.BulkInsertRecords(actions, trans);
trans.Complete();
//Raise the event
AssignedPermissions.RaiseEvent(
new SaveEventArgs<EntityPermission>(ConvertToPermissionList(actions), false), this);
}
}
/// <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>
/// <remarks>
/// This will first clear the permissions for this entity then re-create them
/// </remarks>
public void ReplaceEntityPermissions(TEntity entity, IEnumerable<Tuple<int, string>> userPermissions)
{
var db = _unitOfWork.Database;
using (var trans = db.GetTransaction())
{
db.Execute("DELETE FROM umbracoUser2NodePermission WHERE nodeId=@nodeId", new { nodeId = entity.Id });
var actions = userPermissions.Select(p => new User2NodePermissionDto
{
NodeId = entity.Id,
Permission = p.Item2,
UserId = p.Item1
}).ToArray();
_unitOfWork.Database.BulkInsertRecords(actions, trans);
trans.Complete();
//Raise the event
AssignedPermissions.RaiseEvent(
new SaveEventArgs<EntityPermission>(ConvertToPermissionList(actions), false), this);
}
}
private static IEnumerable<EntityPermission> ConvertToPermissionList(IEnumerable<User2NodePermissionDto> result)
{
var permissions = new List<EntityPermission>();
var nodePermissions = result.GroupBy(x => x.NodeId);
@@ -104,116 +240,6 @@ namespace Umbraco.Core.Persistence.Repositories
return permissions;
}
/// <summary>
/// Assigns one permission to an entity for multiple users
/// </summary>
/// <param name="entity"></param>
/// <param name="permission"></param>
/// <param name="userIds"></param>
internal void AssignEntityPermissions(TEntity entity, char permission, IEnumerable<object> userIds)
{
var actions = userIds.Select(id => new User2NodePermissionDto
{
NodeId = entity.Id,
Permission = permission.ToString(CultureInfo.InvariantCulture),
UserId = (int)id
});
_unitOfWork.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>
internal void AssignEntityPermissions(TEntity entity, IEnumerable<Tuple<object, string>> userPermissions)
{
var actions = userPermissions.Select(p => new User2NodePermissionDto
{
NodeId = entity.Id,
Permission = p.Item2,
UserId = (int)p.Item1
});
_unitOfWork.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>
internal void ReplaceEntityPermissions(TEntity entity, string permissions, IEnumerable<object> userIds)
{
_unitOfWork.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>
internal void ReplaceEntityPermissions(TEntity entity, string permissions, Func<IEntity, IEnumerable<int>> getDescendantIds, IEnumerable<object> userIds)
{
_unitOfWork.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();
}
public static event TypedEventHandler<PermissionRepository<TEntity>, SaveEventArgs<EntityPermission>> AssignedPermissions;
}
}
@@ -55,7 +55,7 @@ namespace Umbraco.Core.Persistence.Repositories
/// <param name="entity"></param>
public void AddOrUpdate(TEntity entity)
{
if (!entity.HasIdentity)
if (entity.HasIdentity == false)
{
_work.RegisterAdded(entity, this);
}
@@ -101,7 +101,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
TracksChangesEntityBase asEntity = entity as TracksChangesEntityBase;
var asEntity = entity as TracksChangesEntityBase;
if (asEntity != null)
{
asEntity.ResetDirtyProperties(false);
@@ -132,13 +132,16 @@ namespace Umbraco.Core.Persistence.Repositories
{
if (ids.Any())
{
var entities = _cache.GetByIds(typeof(TEntity), ids.Select(id => id is int ? ConvertIdToGuid(id) : ConvertStringIdToGuid(id.ToString())).ToList());
var entities = _cache.GetByIds(
typeof (TEntity), ids.Select(id => id is int ? ConvertIdToGuid(id) : ConvertStringIdToGuid(id.ToString())).ToList())
.ToArray();
if (ids.Count().Equals(entities.Count()) && entities.Any(x => x == null) == false)
return entities.Select(x => (TEntity)x);
}
else
{
var allEntities = _cache.GetAllByType(typeof(TEntity));
var allEntities = _cache.GetAllByType(typeof (TEntity)).ToArray();
if (allEntities.Any())
{
@@ -151,7 +154,10 @@ namespace Umbraco.Core.Persistence.Repositories
}
}
var entityCollection = PerformGetAll(ids);
var entityCollection = PerformGetAll(ids)
//ensure we don't include any null refs in the returned collection!
.WhereNotNull()
.ToArray();
foreach (var entity in entityCollection)
{
@@ -172,7 +178,9 @@ namespace Umbraco.Core.Persistence.Repositories
/// <returns></returns>
public IEnumerable<TEntity> GetByQuery(IQuery<TEntity> query)
{
return PerformGetByQuery(query);
return PerformGetByQuery(query)
//ensure we don't include any null refs in the returned collection!
.WhereNotNull();
}
protected abstract bool PerformExists(TId id);
@@ -22,17 +22,20 @@ namespace Umbraco.Core.Persistence.Repositories
internal class UserRepository : PetaPocoRepositoryBase<int, IUser>, IUserRepository
{
private readonly IUserTypeRepository _userTypeRepository;
private readonly CacheHelper _cacheHelper;
public UserRepository(IDatabaseUnitOfWork work, IUserTypeRepository userTypeRepository)
public UserRepository(IDatabaseUnitOfWork work, IUserTypeRepository userTypeRepository, CacheHelper cacheHelper)
: base(work)
{
_userTypeRepository = userTypeRepository;
_cacheHelper = cacheHelper;
}
public UserRepository(IDatabaseUnitOfWork work, IRepositoryCacheProvider cache, IUserTypeRepository userTypeRepository)
public UserRepository(IDatabaseUnitOfWork work, IRepositoryCacheProvider cache, IUserTypeRepository userTypeRepository, CacheHelper cacheHelper)
: base(work, cache)
{
_userTypeRepository = userTypeRepository;
_cacheHelper = cacheHelper;
}
#region Overrides of RepositoryBase<int,IUser>
@@ -128,6 +131,8 @@ namespace Umbraco.Core.Persistence.Repositories
{
var list = new List<string>
{
"DELETE FROM cmsTask WHERE userId = @Id",
"DELETE FROM cmsTask WHERE parentUserId = @Id",
"DELETE FROM umbracoUser2NodePermission WHERE userId = @Id",
"DELETE FROM umbracoUser2NodeNotify WHERE userId = @Id",
"DELETE FROM umbracoUserLogins WHERE userId = @Id",
@@ -315,12 +320,24 @@ namespace Umbraco.Core.Persistence.Repositories
/// <param name="userId"></param>
/// <param name="entityIds"></param>
/// <returns></returns>
public IEnumerable<EntityPermission> GetUserPermissionsForEntities(object userId, params int[] entityIds)
public IEnumerable<EntityPermission> GetUserPermissionsForEntities(int userId, params int[] entityIds)
{
var repo = new PermissionRepository<IContent>(UnitOfWork);
var repo = new PermissionRepository<IContent>(UnitOfWork, _cacheHelper);
return repo.GetUserPermissionsForEntities(userId, entityIds);
}
/// <summary>
/// Replaces the same permission set for a single user to any number of entities
/// </summary>
/// <param name="userId"></param>
/// <param name="permissions"></param>
/// <param name="entityIds"></param>
public void ReplaceUserPermissions(int userId, IEnumerable<char> permissions, params int[] entityIds)
{
var repo = new PermissionRepository<IContent>(UnitOfWork, _cacheHelper);
repo.ReplaceUserPermissions(userId, permissions, entityIds);
}
#endregion
private IEnumerable<IUser> ConvertFromDtos(IEnumerable<UserDto> dtos)
@@ -1,9 +1,11 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Umbraco.Core.Models;
using Umbraco.Core.Models.EntityBase;
using Umbraco.Core.Models.Rdbms;
using Umbraco.Core.Persistence.Caching;
using Umbraco.Core.Persistence.Factories;
using Umbraco.Core.Persistence.UnitOfWork;
namespace Umbraco.Core.Persistence.Repositories
@@ -90,5 +92,42 @@ namespace Umbraco.Core.Persistence.Repositories
protected abstract void PerformDeleteVersion(int id, Guid versionId);
#endregion
/// <summary>
/// This is a fix for U4-1407 - when property types are added to a content type - the property of the entity are not actually created
/// and we get YSODs
/// </summary>
/// <param name="id"></param>
/// <param name="versionId"></param>
/// <param name="contentType"></param>
/// <param name="createDate"></param>
/// <param name="updateDate"></param>
/// <returns></returns>
protected PropertyCollection GetPropertyCollection(int id, Guid versionId, IContentTypeComposition contentType, DateTime createDate, DateTime updateDate)
{
var sql = new Sql();
sql.Select("*")
.From<PropertyDataDto>()
.InnerJoin<PropertyTypeDto>()
.On<PropertyDataDto, PropertyTypeDto>(left => left.PropertyTypeId, right => right.Id)
.Where<PropertyDataDto>(x => x.NodeId == id)
.Where<PropertyDataDto>(x => x.VersionId == versionId);
var propertyDataDtos = Database.Fetch<PropertyDataDto, PropertyTypeDto>(sql);
var propertyFactory = new PropertyFactory(contentType, versionId, id, createDate, updateDate);
var properties = propertyFactory.BuildEntity(propertyDataDtos).ToArray();
var newProperties = properties.Where(x => x.HasIdentity == false && x.PropertyType.HasIdentity);
foreach (var property in newProperties)
{
var propertyDataDto = new PropertyDataDto { NodeId = id, PropertyTypeId = property.PropertyTypeId, VersionId = versionId };
int primaryKey = Convert.ToInt32(Database.Insert(propertyDataDto));
property.Version = versionId;
property.Id = primaryKey;
}
return new PropertyCollection(properties);
}
}
}
@@ -1,3 +1,4 @@
using System;
using Umbraco.Core.Persistence.Caching;
using Umbraco.Core.Persistence.Repositories;
using Umbraco.Core.Persistence.UnitOfWork;
@@ -10,6 +11,7 @@ namespace Umbraco.Core.Persistence
public class RepositoryFactory
{
private readonly bool _disableAllCache;
private readonly CacheHelper _cacheHelper;
public RepositoryFactory()
: this(false)
@@ -17,9 +19,24 @@ namespace Umbraco.Core.Persistence
}
public RepositoryFactory(CacheHelper cacheHelper)
{
if (cacheHelper == null) throw new ArgumentNullException("cacheHelper");
_disableAllCache = false;
_cacheHelper = cacheHelper;
}
public RepositoryFactory(bool disableAllCache, CacheHelper cacheHelper)
{
if (cacheHelper == null) throw new ArgumentNullException("cacheHelper");
_disableAllCache = disableAllCache;
_cacheHelper = cacheHelper;
}
public RepositoryFactory(bool disableAllCache)
{
_disableAllCache = disableAllCache;
_cacheHelper = disableAllCache ? CacheHelper.CreateDisabledCacheHelper() : ApplicationContext.Current.ApplicationCache;
}
@@ -29,14 +46,15 @@ namespace Umbraco.Core.Persistence
uow,
_disableAllCache ? (IRepositoryCacheProvider)NullCacheProvider.Current : RuntimeCacheProvider.Current,
CreateContentTypeRepository(uow),
CreateTemplateRepository(uow)) { EnsureUniqueNaming = Umbraco.Core.Configuration.UmbracoSettings.EnsureUniqueNaming };
CreateTemplateRepository(uow),
_cacheHelper) { EnsureUniqueNaming = Configuration.UmbracoSettings.EnsureUniqueNaming };
}
public virtual IContentTypeRepository CreateContentTypeRepository(IDatabaseUnitOfWork uow)
{
return new ContentTypeRepository(
uow,
_disableAllCache ? (IRepositoryCacheProvider)NullCacheProvider.Current : InMemoryCacheProvider.Current,
_disableAllCache ? (IRepositoryCacheProvider)NullCacheProvider.Current : RuntimeCacheProvider.Current,
new TemplateRepository(uow, NullCacheProvider.Current));
}
@@ -51,7 +69,7 @@ namespace Umbraco.Core.Persistence
{
return new DictionaryRepository(
uow,
_disableAllCache ? (IRepositoryCacheProvider)NullCacheProvider.Current : InMemoryCacheProvider.Current,
_disableAllCache ? (IRepositoryCacheProvider)NullCacheProvider.Current : RuntimeCacheProvider.Current,
CreateLanguageRepository(uow));
}
@@ -59,7 +77,7 @@ namespace Umbraco.Core.Persistence
{
return new LanguageRepository(
uow,
_disableAllCache ? (IRepositoryCacheProvider)NullCacheProvider.Current : InMemoryCacheProvider.Current);
_disableAllCache ? (IRepositoryCacheProvider)NullCacheProvider.Current : RuntimeCacheProvider.Current);
}
public virtual IMediaRepository CreateMediaRepository(IDatabaseUnitOfWork uow)
@@ -67,14 +85,14 @@ namespace Umbraco.Core.Persistence
return new MediaRepository(
uow,
_disableAllCache ? (IRepositoryCacheProvider)NullCacheProvider.Current : RuntimeCacheProvider.Current,
CreateMediaTypeRepository(uow)) { EnsureUniqueNaming = Umbraco.Core.Configuration.UmbracoSettings.EnsureUniqueNaming };
CreateMediaTypeRepository(uow)) { EnsureUniqueNaming = Configuration.UmbracoSettings.EnsureUniqueNaming };
}
public virtual IMediaTypeRepository CreateMediaTypeRepository(IDatabaseUnitOfWork uow)
{
return new MediaTypeRepository(
uow,
_disableAllCache ? (IRepositoryCacheProvider)NullCacheProvider.Current : InMemoryCacheProvider.Current);
_disableAllCache ? (IRepositoryCacheProvider)NullCacheProvider.Current : RuntimeCacheProvider.Current);
}
public virtual IRelationRepository CreateRelationRepository(IDatabaseUnitOfWork uow)
@@ -114,33 +132,44 @@ namespace Umbraco.Core.Persistence
NullCacheProvider.Current);
}
internal virtual IUserTypeRepository CreateUserTypeRepository(IDatabaseUnitOfWork uow)
public virtual IUserTypeRepository CreateUserTypeRepository(IDatabaseUnitOfWork uow)
{
return new UserTypeRepository(
uow,
//There's not many user types but we query on users all the time so the result needs to be cached
RuntimeCacheProvider.Current);
_disableAllCache ? (IRepositoryCacheProvider)NullCacheProvider.Current : RuntimeCacheProvider.Current);
}
internal virtual IUserRepository CreateUserRepository(IDatabaseUnitOfWork uow)
{
public virtual IUserRepository CreateUserRepository(IDatabaseUnitOfWork uow)
{
return new UserRepository(
uow,
NullCacheProvider.Current,
CreateUserTypeRepository(uow));
//Need to cache users - we look up user information more than anything in the back office!
_disableAllCache ? (IRepositoryCacheProvider)NullCacheProvider.Current : RuntimeCacheProvider.Current,
CreateUserTypeRepository(uow),
_cacheHelper);
}
internal virtual IMemberRepository CreateMemberRepository(IDatabaseUnitOfWork uow)
public virtual IMemberRepository CreateMemberRepository(IDatabaseUnitOfWork uow)
{
return new MemberRepository(uow, _disableAllCache ? (IRepositoryCacheProvider)NullCacheProvider.Current : RuntimeCacheProvider.Current, CreateMemberTypeRepository(uow));
return new MemberRepository(
uow,
_disableAllCache ? (IRepositoryCacheProvider)NullCacheProvider.Current : RuntimeCacheProvider.Current,
CreateMemberTypeRepository(uow),
CreateMemberGroupRepository(uow));
}
internal virtual IMemberTypeRepository CreateMemberTypeRepository(IDatabaseUnitOfWork uow)
public virtual IMemberTypeRepository CreateMemberTypeRepository(IDatabaseUnitOfWork uow)
{
return new MemberTypeRepository(uow, _disableAllCache ? (IRepositoryCacheProvider)NullCacheProvider.Current : InMemoryCacheProvider.Current);
return new MemberTypeRepository(uow, _disableAllCache ? (IRepositoryCacheProvider)NullCacheProvider.Current : RuntimeCacheProvider.Current);
}
internal virtual IEntityRepository CreateEntityRepository(IDatabaseUnitOfWork uow)
public virtual IMemberGroupRepository CreateMemberGroupRepository(IDatabaseUnitOfWork uow)
{
return new MemberGroupRepository(uow, _disableAllCache ? (IRepositoryCacheProvider)NullCacheProvider.Current : RuntimeCacheProvider.Current, _cacheHelper);
}
public virtual IEntityRepository CreateEntityRepository(IDatabaseUnitOfWork uow)
{
return new EntityRepository(uow);
}
@@ -11,6 +11,8 @@ namespace Umbraco.Core.Persistence.SqlSyntax
/// </summary>
public interface ISqlSyntaxProvider
{
string EscapeString(string val);
string GetStringColumnEqualComparison(string column, string value, TextColumnType columnType);
string GetStringColumnStartsWithComparison(string column, string value, TextColumnType columnType);
string GetStringColumnEndsWithComparison(string column, string value, TextColumnType columnType);
@@ -327,5 +327,10 @@ namespace Umbraco.Core.Persistence.SqlSyntax
// add message to check with their hosting provider
return supportsCaseInsensitiveQueries;
}
public override string EscapeString(string val)
{
return PetaPocoExtensions.EscapeAtSymbols(MySql.Data.MySqlClient.MySqlHelper.EscapeString(val));
}
}
}
@@ -103,6 +103,11 @@ namespace Umbraco.Core.Persistence.SqlSyntax
DbTypeMap.Set<byte[]>(DbType.Binary, BlobColumnDefinition);
}
public virtual string EscapeString(string val)
{
return PetaPocoExtensions.EscapeAtSymbols(val.Replace("'", "''"));
}
public virtual string GetStringColumnEqualComparison(string column, string value, TextColumnType columnType)
{
//use the 'upper' method to always ensure strings are matched without case sensitivity no matter what the db setting.
+11 -9
View File
@@ -33,7 +33,7 @@ namespace Umbraco.Core
/// it will use the cached resolved plugins that it has already found which means that no assembly scanning is necessary. This leads
/// to much faster startup times.
/// </remarks>
internal class PluginManager
public class PluginManager
{
private readonly ApplicationContext _appContext;
private const string CacheKey = "umbraco-plugins.list";
@@ -106,7 +106,7 @@ namespace Umbraco.Core
/// <remarks>
/// The setter is generally only used for unit tests
/// </remarks>
internal static PluginManager Current
public static PluginManager Current
{
get
{
@@ -750,15 +750,16 @@ namespace Umbraco.Core
UpdateCachedPluginsFile<T>(typeList.GetTypes(), resolutionKind);
}
#region Public Methods
/// <summary>
/// Generic method to find the specified type and cache the result
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
internal IEnumerable<Type> ResolveTypes<T>(bool cacheResult = true)
public IEnumerable<Type> ResolveTypes<T>(bool cacheResult = true, IEnumerable<Assembly> specificAssemblies = null)
{
return ResolveTypes<T>(
() => TypeFinder.FindClassesOfType<T>(AssembliesToScan),
() => TypeFinder.FindClassesOfType<T>(specificAssemblies ?? AssembliesToScan),
TypeResolutionKind.FindAllTypes,
cacheResult);
}
@@ -769,11 +770,11 @@ namespace Umbraco.Core
/// <typeparam name="T"></typeparam>
/// <typeparam name="TAttribute"></typeparam>
/// <returns></returns>
internal IEnumerable<Type> ResolveTypesWithAttribute<T, TAttribute>(bool cacheResult = true)
public IEnumerable<Type> ResolveTypesWithAttribute<T, TAttribute>(bool cacheResult = true, IEnumerable<Assembly> specificAssemblies = null)
where TAttribute : Attribute
{
return ResolveTypes<T>(
() => TypeFinder.FindClassesOfTypeWithAttribute<T, TAttribute>(AssembliesToScan),
() => TypeFinder.FindClassesOfTypeWithAttribute<T, TAttribute>(specificAssemblies ?? AssembliesToScan),
TypeResolutionKind.FindTypesWithAttribute,
cacheResult);
}
@@ -783,14 +784,15 @@ namespace Umbraco.Core
/// </summary>
/// <typeparam name="TAttribute"></typeparam>
/// <returns></returns>
internal IEnumerable<Type> ResolveAttributedTypes<TAttribute>(bool cacheResult = true)
public IEnumerable<Type> ResolveAttributedTypes<TAttribute>(bool cacheResult = true, IEnumerable<Assembly> specificAssemblies = null)
where TAttribute : Attribute
{
return ResolveTypes<TAttribute>(
() => TypeFinder.FindClassesWithAttribute<TAttribute>(AssembliesToScan),
() => TypeFinder.FindClassesWithAttribute<TAttribute>(specificAssemblies ?? AssembliesToScan),
TypeResolutionKind.FindAttributedTypes,
cacheResult);
}
}
#endregion
/// <summary>
/// Used for unit tests
@@ -0,0 +1,10 @@
namespace Umbraco.Core.Security
{
/// <summary>
/// A marker interface used internally to identify Umbraco built-in Users membership providers
/// </summary>
internal interface IUsersMembershipProvider
{
}
}
@@ -10,6 +10,16 @@ namespace Umbraco.Core.Security
{
internal static class MembershipProviderExtensions
{
/// <summary>
/// Returns true if the provider specified is a built-in Umbraco users provider
/// </summary>
/// <param name="membershipProvider"></param>
/// <returns></returns>
public static bool IsUmbracoUsersProvider(this MembershipProvider membershipProvider)
{
return (membershipProvider is IUsersMembershipProvider);
}
/// <summary>
/// Returns true if the provider specified is a built-in Umbraco membership provider
/// </summary>
@@ -20,6 +30,8 @@ namespace Umbraco.Core.Security
return (membershipProvider is UmbracoMembershipProviderBase);
}
//TODO: Add role provider checks too
public static UmbracoMembershipProviderBase AsUmbracoMembershipProvider(this MembershipProvider membershipProvider)
{
return (UmbracoMembershipProviderBase)membershipProvider;
@@ -0,0 +1,23 @@
using System.Collections.Specialized;
namespace Umbraco.Core.Security
{
/// <summary>
/// An interface for exposing the content type properties for storing membership data in when
/// a membership provider's data is backed by an Umbraco content type.
/// </summary>
public interface IUmbracoMemberTypeMembershipProvider
{
string LockPropertyTypeAlias { get; }
string LastLockedOutPropertyTypeAlias { get; }
string FailedPasswordAttemptsPropertyTypeAlias { get; }
string ApprovedPropertyTypeAlias { get; }
string CommentPropertyTypeAlias { get; }
string LastLoginPropertyTypeAlias { get; }
string LastPasswordChangedPropertyTypeAlias { get; }
string PasswordRetrievalQuestionPropertyTypeAlias { get; }
string PasswordRetrievalAnswerPropertyTypeAlias { get; }
}
}
@@ -3,7 +3,6 @@ using System.Web.Security;
namespace Umbraco.Core.Security
{
/// <summary>
/// A base membership provider class for umbraco providers
/// </summary>
+48 -5
View File
@@ -9,6 +9,7 @@ using Umbraco.Core.Events;
using Umbraco.Core.IO;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Membership;
using Umbraco.Core.Models.Rdbms;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.Caching;
@@ -58,14 +59,32 @@ namespace Umbraco.Core.Services
_repositoryFactory = repositoryFactory;
}
//TODO: There are various ways to expose permission setting on this service, we just need to list out the different ways we'll need to
// be able to acheive this for the core, for now this is here so I can run a unit test.
internal void AssignContentPermissions(IContent entity, char permission, IEnumerable<object> userIds)
/// <summary>
/// Assigns a single permission to the current content item for the specified user ids
/// </summary>
/// <param name="entity"></param>
/// <param name="permission"></param>
/// <param name="userIds"></param>
public void AssignContentPermission(IContent entity, char permission, IEnumerable<int> userIds)
{
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateContentRepository(uow))
{
repository.AssignEntityPermissions(entity, permission, userIds);
repository.AssignEntityPermission(entity, permission, userIds);
}
}
/// <summary>
/// Gets the list of permissions for the content item
/// </summary>
/// <param name="content"></param>
/// <returns></returns>
public IEnumerable<EntityPermission> GetPermissionsForEntity(IContent content)
{
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateContentRepository(uow))
{
return repository.GetPermissionsForEntity(content.Id);
}
}
@@ -157,12 +176,20 @@ namespace Umbraco.Core.Services
var contentType = FindContentTypeByAlias(contentTypeAlias);
var content = new Content(name, parentId, contentType);
//NOTE: I really hate the notion of these Creating/Created events - they are so inconsistent, I've only just found
// out that in these 'WithIdentity' methods, the Saving/Saved events were not fired, wtf. Anyways, they're added now.
if (Creating.IsRaisedEventCancelled(new NewEventArgs<IContent>(content, contentTypeAlias, parentId), this))
{
content.WasCancelled = true;
return content;
}
if (Saving.IsRaisedEventCancelled(new SaveEventArgs<IContent>(content), this))
{
content.WasCancelled = true;
return content;
}
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateContentRepository(uow))
{
@@ -172,6 +199,8 @@ namespace Umbraco.Core.Services
uow.Commit();
}
Saved.RaiseEvent(new SaveEventArgs<IContent>(content, false), this);
Created.RaiseEvent(new NewEventArgs<IContent>(content, false, contentTypeAlias, parentId), this);
Audit.Add(AuditTypes.New, string.Format("Content '{0}' was created with Id {1}", name, content.Id), content.CreatorId, content.Id);
@@ -197,12 +226,20 @@ namespace Umbraco.Core.Services
var contentType = FindContentTypeByAlias(contentTypeAlias);
var content = new Content(name, parent, contentType);
//NOTE: I really hate the notion of these Creating/Created events - they are so inconsistent, I've only just found
// out that in these 'WithIdentity' methods, the Saving/Saved events were not fired, wtf. Anyways, they're added now.
if (Creating.IsRaisedEventCancelled(new NewEventArgs<IContent>(content, contentTypeAlias, parent), this))
{
content.WasCancelled = true;
return content;
}
if (Saving.IsRaisedEventCancelled(new SaveEventArgs<IContent>(content), this))
{
content.WasCancelled = true;
return content;
}
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateContentRepository(uow))
{
@@ -212,6 +249,8 @@ namespace Umbraco.Core.Services
uow.Commit();
}
Saved.RaiseEvent(new SaveEventArgs<IContent>(content, false), this);
Created.RaiseEvent(new NewEventArgs<IContent>(content, false, contentTypeAlias, parent), this);
Audit.Add(AuditTypes.New, string.Format("Content '{0}' was created with Id {1}", name, content.Id), content.CreatorId, content.Id);
@@ -622,10 +661,10 @@ namespace Umbraco.Core.Services
/// <param name="content">The <see cref="IContent"/> to publish</param>
/// <param name="userId">Optional Id of the User issueing the publishing</param>
/// <returns>True if publishing succeeded, otherwise False</returns>
[Obsolete("Use PublishWithStatus instead, that method will provide more detailed information on the outcome")]
public bool Publish(IContent content, int userId = 0)
{
var result = SaveAndPublishDo(content, userId);
LogHelper.Info<ContentService>("Call was made to ContentService.Publish, use PublishWithStatus instead since that method will provide more detailed information on the outcome");
return result.Success;
}
@@ -1217,6 +1256,7 @@ namespace Umbraco.Core.Services
}
}
/// <summary>
/// Sends an <see cref="IContent"/> to Publication, which executes handlers and events for the 'Send to Publication' action.
/// </summary>
@@ -1491,6 +1531,8 @@ namespace Umbraco.Core.Services
//bulk insert it into the database
uow.Database.BulkInsertRecords(xmlItems, tr);
tr.Complete();
}
Audit.Add(AuditTypes.Publish, "RebuildXmlStructures completed, the xml has been regenerated in the database", 0, -1);
@@ -1962,6 +2004,7 @@ namespace Umbraco.Core.Services
/// <summary>
/// Occurs before Create
/// </summary>
[Obsolete("Use the Created event instead, the Creating and Created events both offer the same functionality, Creating event has been deprecated.")]
public static event TypedEventHandler<IContentService, NewEventArgs<IContent>> Creating;
/// <summary>
+9 -9
View File
@@ -214,17 +214,17 @@ namespace Umbraco.Core.Services
{
using (var uow = _uowProvider.GetUnitOfWork())
{
var sortOrderObj =
uow.Database.ExecuteScalar<object>(
"SELECT max(sortorder) FROM cmsDataTypePreValues WHERE datatypeNodeId = @DataTypeId", new { DataTypeId = id });
int sortOrder;
if (sortOrderObj == null || int.TryParse(sortOrderObj.ToString(), out sortOrder) == false)
{
sortOrder = 1;
}
using (var transaction = uow.Database.GetTransaction())
{
var sortOrderObj =
uow.Database.ExecuteScalar<object>(
"SELECT max(sortorder) FROM cmsDataTypePreValues WHERE datatypeNodeId = @DataTypeId", new { DataTypeId = id });
int sortOrder;
if (sortOrderObj == null || int.TryParse(sortOrderObj.ToString(), out sortOrder) == false)
{
sortOrder = 1;
}
foreach (var value in values)
{
var dto = new DataTypePreValueDto { DataTypeNodeId = id, Value = value, SortOrder = sortOrder };
+14 -1
View File
@@ -11,6 +11,20 @@ namespace Umbraco.Core.Services
/// </summary>
public interface IContentService : IService
{
/// <summary>
/// Assigns a single permission to the current content item for the specified user ids
/// </summary>
/// <param name="entity"></param>
/// <param name="permission"></param>
/// <param name="userIds"></param>
void AssignContentPermission(IContent entity, char permission, IEnumerable<int> userIds);
/// <summary>
/// Gets the list of permissions for the content item
/// </summary>
/// <param name="content"></param>
/// <returns></returns>
IEnumerable<EntityPermission> GetPermissionsForEntity(IContent content);
bool SendToPublication(IContent content, int userId = 0);
@@ -249,7 +263,6 @@ namespace Umbraco.Core.Services
/// <param name="content">The <see cref="IContent"/> to publish</param>
/// <param name="userId">Optional Id of the User issueing the publishing</param>
/// <returns>True if publishing succeeded, otherwise False</returns>
[Obsolete("Use PublishWithStatus instead, that method will provide more detailed information on the outcome")]
bool Publish(IContent content, int userId = 0);
/// <summary>
@@ -0,0 +1,14 @@
using System.Collections.Generic;
using Umbraco.Core.Models;
namespace Umbraco.Core.Services
{
public interface IMemberGroupService : IService
{
IEnumerable<IMemberGroup> GetAll();
IMemberGroup GetById(int id);
IMemberGroup GetByName(string name);
void Save(IMemberGroup memberGroup, bool raiseEvents = true);
void Delete(IMemberGroup memberGroup);
}
}
+20 -9
View File
@@ -8,7 +8,7 @@ namespace Umbraco.Core.Services
/// <summary>
/// Defines the MemberService, which is an easy access to operations involving (umbraco) members.
/// </summary>
internal interface IMemberService : IMembershipMemberService
public interface IMemberService : IMembershipMemberService
{
/// <summary>
/// Checks if a member with the id exists
@@ -16,14 +16,7 @@ namespace Umbraco.Core.Services
/// <param name="id"></param>
/// <returns></returns>
bool Exists(int id);
/// <summary>
/// Get a member by its id
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
IMember GetById(int id);
/// <summary>
/// Get a member by the unique key
/// </summary>
@@ -31,6 +24,13 @@ namespace Umbraco.Core.Services
/// <returns></returns>
IMember GetByKey(Guid id);
/// <summary>
/// Gets a member by it's id
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
IMember GetById(int id);
/// <summary>
/// Get all members for the member type alias
/// </summary>
@@ -65,6 +65,17 @@ namespace Umbraco.Core.Services
/// <param name="memberTypeId"></param>
void DeleteMembersOfType(int memberTypeId);
/// <summary>
/// Find members based on their display name
/// </summary>
/// <param name="displayNameToMatch"></param>
/// <param name="pageIndex"></param>
/// <param name="pageSize"></param>
/// <param name="totalRecords"></param>
/// <param name="matchType"></param>
/// <returns></returns>
IEnumerable<IMember> FindMembersByDisplayName(string displayNameToMatch, int pageIndex, int pageSize, out int totalRecords, StringPropertyMatchType matchType = StringPropertyMatchType.StartsWith);
/// <summary>
/// Get members based on a property search
/// </summary>
@@ -3,28 +3,28 @@ using Umbraco.Core.Models;
namespace Umbraco.Core.Services
{
internal interface IMemberTypeService : IService
{
public interface IMemberTypeService : IService
{
/// <summary>
/// Gets a list of all available <see cref="IContentType"/> objects
/// </summary>
/// <param name="ids">Optional list of ids</param>
/// <returns>An Enumerable list of <see cref="IContentType"/> objects</returns>
IEnumerable<IMemberType> GetAllMemberTypes(params int[] ids);
IEnumerable<IMemberType> GetAll(params int[] ids);
/// <summary>
/// Gets an <see cref="IMemberType"/> object by its Id
/// </summary>
/// <param name="id">Id of the <see cref="IMediaType"/> to retrieve</param>
/// <returns><see cref="IMediaType"/></returns>
IMemberType GetMemberType(int id);
IMemberType Get(int id);
/// <summary>
/// Gets an <see cref="IMemberType"/> object by its Alias
/// </summary>
/// <param name="alias">Alias of the <see cref="IMediaType"/> to retrieve</param>
/// <returns><see cref="IMediaType"/></returns>
IMemberType GetMemberType(string alias);
IMemberType Get(string alias);
/// <summary>
/// Saves a single <see cref="IMemberType"/> object
@@ -6,16 +6,16 @@ using Umbraco.Core.Persistence.Querying;
namespace Umbraco.Core.Services
{
/// <summary>
/// Defines part of the MemberService, 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 IMembershipMemberService : IMembershipMemberService<IMember>
public interface IMembershipMemberService : IMembershipMemberService<IMember>, IMembershipRoleService<IMember>
{
IMember CreateMember(string email, string username, string password, IMemberType memberType);
IMember CreateMember(string username, string email, string password, string memberType);
IMember CreateMemberWithIdentity(string username, string email, string password, IMemberType memberType);
}
/// <summary>
@@ -24,7 +24,7 @@ namespace Umbraco.Core.Services
/// <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 IMembershipMemberService<T> : IService
public interface IMembershipMemberService<T> : IService
where T : class, IMembershipUser
{
/// <summary>
@@ -48,9 +48,14 @@ namespace Umbraco.Core.Services
/// <param name="password"></param>
/// <param name="memberTypeAlias"></param>
/// <returns></returns>
T CreateMember(string username, string email, string password, string memberTypeAlias);
T CreateWithIdentity(string username, string email, string password, string memberTypeAlias);
T GetById(object id);
/// <summary>
/// Gets the member by the provider key
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
T GetByProviderKey(object id);
/// <summary>
/// Get a member by email
@@ -62,20 +67,20 @@ namespace Umbraco.Core.Services
T GetByUsername(string login);
void Delete(T membershipUser);
void Save(T entity, bool raiseEvents = true);
void Save(T membershipUser, bool raiseEvents = true);
void Save(IEnumerable<T> entities, bool raiseEvents = true);
void Save(IEnumerable<T> members, bool raiseEvents = true);
IEnumerable<T> FindByEmail(string emailStringToMatch, int pageIndex, int pageSize, out int totalRecords, StringPropertyMatchType matchType = StringPropertyMatchType.StartsWith);
IEnumerable<T> FindMembersByEmail(string emailStringToMatch, int pageIndex, int pageSize, out int totalRecords, StringPropertyMatchType matchType = StringPropertyMatchType.StartsWith);
IEnumerable<T> FindMembersByUsername(string login, int pageIndex, int pageSize, out int totalRecords, StringPropertyMatchType matchType = StringPropertyMatchType.StartsWith);
IEnumerable<T> FindByUsername(string login, int pageIndex, int pageSize, out int totalRecords, StringPropertyMatchType matchType = StringPropertyMatchType.StartsWith);
/// <summary>
/// Gets the total number of members based on the count type
/// </summary>
/// <returns></returns>
int GetMemberCount(MemberCountType countType);
int GetCount(MemberCountType countType);
/// <summary>
/// Gets a list of paged member data
@@ -84,6 +89,6 @@ namespace Umbraco.Core.Services
/// <param name="pageSize"></param>
/// <param name="totalRecords"></param>
/// <returns></returns>
IEnumerable<T> GetAllMembers(int pageIndex, int pageSize, out int totalRecords);
IEnumerable<T> GetAll(int pageIndex, int pageSize, out int totalRecords);
}
}
@@ -0,0 +1,22 @@
using System.Collections.Generic;
using Umbraco.Core.Models.Membership;
using Umbraco.Core.Persistence.Querying;
namespace Umbraco.Core.Services
{
public interface IMembershipRoleService<out T>
where T : class, IMembershipUser
{
void AddRole(string roleName);
IEnumerable<string> GetAllRoles();
IEnumerable<string> GetAllRoles(int memberId);
IEnumerable<string> GetAllRoles(string username);
IEnumerable<T> GetMembersInRole(string roleName);
IEnumerable<T> FindMembersInRole(string roleName, string usernameToMatch, StringPropertyMatchType matchType = StringPropertyMatchType.StartsWith);
bool DeleteRole(string roleName, bool throwIfBeingUsed);
void AssignRoles(string[] usernames, string[] roleNames);
void DissociateRoles(string[] usernames, string[] roleNames);
void AssignRoles(int[] memberIds, string[] roleNames);
void DissociateRoles(int[] memberIds, string[] roleNames);
}
}
@@ -8,10 +8,10 @@ namespace Umbraco.Core.Services
/// <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 : IMembershipMemberService<IUser>
public interface IMembershipUserService : IMembershipMemberService<IUser>
{
IUser CreateMember(string username, string email, string password, IUserType userType);
IUser CreateUserWithIdentity(string username, string email, string password, IUserType userType);
}
}
+55 -14
View File
@@ -7,18 +7,64 @@ namespace Umbraco.Core.Services
/// <summary>
/// Defines the UserService, which is an easy access to operations involving <see cref="IProfile"/> and eventually Users.
/// </summary>
internal interface IUserService : IMembershipUserService
public interface IUserService : IMembershipUserService
{
/// <summary>
/// To permanently delete the user pass in true, otherwise they will just be disabled
/// </summary>
/// <param name="user"></param>
/// <param name="deletePermanently"></param>
void Delete(IUser user, bool deletePermanently);
/// <summary>
/// Gets an IProfile by User Id.
/// </summary>
/// <param name="id">Id of the User to retrieve</param>
/// <returns><see cref="IProfile"/></returns>
IProfile GetProfileById(int id);
/// <summary>
/// Get profile by username
/// </summary>
/// <param name="username"></param>
/// <returns></returns>
IProfile GetProfileByUserName(string username);
/// <summary>
/// Get user by Id
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
IUser GetUserById(int id);
/// <summary>
/// This is useful when an entire section is removed from config
/// </summary>
/// <param name="sectionAlias"></param>
void DeleteSectionFromAllUsers(string sectionAlias);
/// <summary>
/// Get permissions set for user and specified node ids
/// </summary>
/// <param name="user"></param>
/// <param name="nodeIds">
/// Specifiying nothing will return all user permissions for all nodes
/// </param>
/// <returns></returns>
IEnumerable<EntityPermission> GetPermissions(IUser user, params int[] nodeIds);
/// <summary>
/// Replaces the same permission set for a single user to any number of entities
/// </summary>
/// <param name="userId"></param>
/// <param name="permissions"></param>
/// <param name="entityIds"></param>
void ReplaceUserPermissions(int userId, IEnumerable<char> permissions, params int[] entityIds);
#region User types
IEnumerable<IUserType> GetAllUserTypes(params int[] ids);
/// <summary>
/// Gets an IUserType by its Alias
/// </summary>
@@ -26,6 +72,13 @@ namespace Umbraco.Core.Services
/// <returns><see cref="IUserType"/></returns>
IUserType GetUserTypeByAlias(string alias);
/// <summary>
/// Gets an IUserType by its Id
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
IUserType GetUserTypeById(int id);
/// <summary>
/// Gets an IUserType by its Name
/// </summary>
@@ -45,19 +98,7 @@ namespace Umbraco.Core.Services
/// </summary>
/// <param name="userType"></param>
void DeleteUserType(IUserType userType);
/// <summary>
/// This is useful when an entire section is removed from config
/// </summary>
/// <param name="sectionAlias"></param>
void DeleteSectionFromAllUsers(string sectionAlias);
/// <summary>
/// Returns a list of the sections that the user is allowed access to
/// </summary>
/// <returns></returns>
IEnumerable<string> GetUserSections(IUser user);
IEnumerable<EntityPermission> GetPermissions(IUser user, params int[] nodeIds);
#endregion
}
}
+27
View File
@@ -122,12 +122,23 @@ namespace Umbraco.Core.Services
{
var mediaType = FindMediaTypeByAlias(mediaTypeAlias);
var media = new Models.Media(name, parentId, mediaType);
//NOTE: I really hate the notion of these Creating/Created events - they are so inconsistent, I've only just found
// out that in these 'WithIdentity' methods, the Saving/Saved events were not fired, wtf. Anyways, they're added now.
if (Creating.IsRaisedEventCancelled(new NewEventArgs<IMedia>(media, mediaTypeAlias, parentId), this))
{
media.WasCancelled = true;
return media;
}
if (Saving.IsRaisedEventCancelled(new SaveEventArgs<IMedia>(media), this))
{
media.WasCancelled = true;
return media;
}
//TODO: Once we fix up the transaction logic, these write locks should be replaced with
// an outter transaction instead.
using (new WriteLock(Locker))
{
var uow = _uowProvider.GetUnitOfWork();
@@ -142,6 +153,8 @@ namespace Umbraco.Core.Services
}
}
Saved.RaiseEvent(new SaveEventArgs<IMedia>(media, false), this);
Created.RaiseEvent(new NewEventArgs<IMedia>(media, false, mediaTypeAlias, parentId), this);
Audit.Add(AuditTypes.New, string.Format("Media '{0}' was created with Id {1}", name, media.Id), media.CreatorId, media.Id);
@@ -166,12 +179,21 @@ namespace Umbraco.Core.Services
{
var mediaType = FindMediaTypeByAlias(mediaTypeAlias);
var media = new Models.Media(name, parent, mediaType);
//NOTE: I really hate the notion of these Creating/Created events - they are so inconsistent, I've only just found
// out that in these 'WithIdentity' methods, the Saving/Saved events were not fired, wtf. Anyways, they're added now.
if (Creating.IsRaisedEventCancelled(new NewEventArgs<IMedia>(media, mediaTypeAlias, parent), this))
{
media.WasCancelled = true;
return media;
}
if (Saving.IsRaisedEventCancelled(new SaveEventArgs<IMedia>(media), this))
{
media.WasCancelled = true;
return media;
}
using (new WriteLock(Locker))
{
var uow = _uowProvider.GetUnitOfWork();
@@ -186,6 +208,8 @@ namespace Umbraco.Core.Services
}
}
Saved.RaiseEvent(new SaveEventArgs<IMedia>(media, false), this);
Created.RaiseEvent(new NewEventArgs<IMedia>(media, false, mediaTypeAlias, parent), this);
Audit.Add(AuditTypes.New, string.Format("Media '{0}' was created with Id {1}", name, media.Id), media.CreatorId, media.Id);
@@ -938,6 +962,8 @@ namespace Umbraco.Core.Services
//bulk insert it into the database
uow.Database.BulkInsertRecords(xmlItems, tr);
tr.Complete();
}
Audit.Add(AuditTypes.Publish, "RebuildXmlStructures completed, the xml has been regenerated in the database", 0, -1);
@@ -1040,6 +1066,7 @@ namespace Umbraco.Core.Services
/// <summary>
/// Occurs before Create
/// </summary>
[Obsolete("Use the Created event instead, the Creating and Created events both offer the same functionality, Creating event has been deprecated.")]
public static event TypedEventHandler<IMediaService, NewEventArgs<IMedia>> Creating;
/// <summary>
@@ -0,0 +1,138 @@
using System.Collections.Generic;
using System.Linq;
using Umbraco.Core.Events;
using Umbraco.Core.Models;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.Querying;
using Umbraco.Core.Persistence.Repositories;
using Umbraco.Core.Persistence.UnitOfWork;
namespace Umbraco.Core.Services
{
public class MemberGroupService : IMemberGroupService
{
private readonly RepositoryFactory _repositoryFactory;
private readonly IDatabaseUnitOfWorkProvider _uowProvider;
public MemberGroupService(RepositoryFactory repositoryFactory)
: this(new PetaPocoUnitOfWorkProvider(), repositoryFactory)
{
}
public MemberGroupService(IDatabaseUnitOfWorkProvider provider)
: this(provider, new RepositoryFactory())
{
}
public MemberGroupService(IDatabaseUnitOfWorkProvider provider, RepositoryFactory repositoryFactory)
{
_repositoryFactory = repositoryFactory;
_uowProvider = provider;
//Proxy events!
MemberGroupRepository.SavedMemberGroup += MemberGroupRepository_SavedMemberGroup;
MemberGroupRepository.SavingMemberGroup += MemberGroupRepository_SavingMemberGroup;
}
#region Proxied event handlers
void MemberGroupRepository_SavingMemberGroup(IMemberGroupRepository sender, SaveEventArgs<IMemberGroup> e)
{
if (Saving.IsRaisedEventCancelled(new SaveEventArgs<IMemberGroup>(e.SavedEntities), this))
{
e.Cancel = true;
}
}
void MemberGroupRepository_SavedMemberGroup(IMemberGroupRepository sender, SaveEventArgs<IMemberGroup> e)
{
Saved.RaiseEvent(new SaveEventArgs<IMemberGroup>(e.SavedEntities, false), this);
}
#endregion
public IEnumerable<IMemberGroup> GetAll()
{
using (var repository = _repositoryFactory.CreateMemberGroupRepository(_uowProvider.GetUnitOfWork()))
{
return repository.GetAll();
}
}
public IMemberGroup GetById(int id)
{
using (var repository = _repositoryFactory.CreateMemberGroupRepository(_uowProvider.GetUnitOfWork()))
{
return repository.Get(id);
}
}
public IMemberGroup GetByName(string name)
{
using (var repository = _repositoryFactory.CreateMemberGroupRepository(_uowProvider.GetUnitOfWork()))
{
return repository.GetByName(name);
}
}
public void Save(IMemberGroup memberGroup, bool raiseEvents = true)
{
if (raiseEvents)
{
if (Saving.IsRaisedEventCancelled(new SaveEventArgs<IMemberGroup>(memberGroup), this))
{
return;
}
}
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateMemberGroupRepository(uow))
{
repository.AddOrUpdate(memberGroup);
uow.Commit();
}
if (raiseEvents)
Saved.RaiseEvent(new SaveEventArgs<IMemberGroup>(memberGroup, false), this);
}
public void Delete(IMemberGroup memberGroup)
{
if (Deleting.IsRaisedEventCancelled(new DeleteEventArgs<IMemberGroup>(memberGroup), this))
return;
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateMemberGroupRepository(uow))
{
repository.Delete(memberGroup);
uow.Commit();
}
Deleted.RaiseEvent(new DeleteEventArgs<IMemberGroup>(memberGroup, false), this);
}
/// <summary>
/// Occurs before Delete of a member group
/// </summary>
public static event TypedEventHandler<IMemberGroupService, DeleteEventArgs<IMemberGroup>> Deleting;
/// <summary>
/// Occurs after Delete of a member group
/// </summary>
public static event TypedEventHandler<IMemberGroupService, DeleteEventArgs<IMemberGroup>> Deleted;
/// <summary>
/// Occurs before Save of a member group
/// </summary>
/// <remarks>
/// We need to proxy these events because the events need to take place at the repo level
/// </remarks>
public static event TypedEventHandler<IMemberGroupService, SaveEventArgs<IMemberGroup>> Saving;
/// <summary>
/// Occurs after Save of a member group
/// </summary>
/// <remarks>
/// We need to proxy these events because the events need to take place at the repo level
/// </remarks>
public static event TypedEventHandler<IMemberGroupService, SaveEventArgs<IMemberGroup>> Saved;
}
}
+236 -37
View File
@@ -4,11 +4,13 @@ using System.Runtime.CompilerServices;
using System.Threading;
using System.Web.Security;
using System.Xml.Linq;
using Umbraco.Core.Auditing;
using Umbraco.Core.Events;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Rdbms;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.Querying;
using Umbraco.Core.Persistence.Repositories;
using Umbraco.Core.Persistence.SqlSyntax;
using Umbraco.Core.Persistence.UnitOfWork;
using System.Linq;
@@ -18,26 +20,31 @@ namespace Umbraco.Core.Services
/// <summary>
/// Represents the MemberService.
/// </summary>
internal class MemberService : IMemberService
public class MemberService : IMemberService
{
private readonly RepositoryFactory _repositoryFactory;
private readonly IMemberGroupService _memberGroupService;
private readonly IDatabaseUnitOfWorkProvider _uowProvider;
private static readonly ReaderWriterLockSlim Locker = new ReaderWriterLockSlim();
public MemberService(RepositoryFactory repositoryFactory)
: this(new PetaPocoUnitOfWorkProvider(), repositoryFactory)
public MemberService(RepositoryFactory repositoryFactory, IMemberGroupService memberGroupService)
: this(new PetaPocoUnitOfWorkProvider(), repositoryFactory, memberGroupService)
{
}
public MemberService(IDatabaseUnitOfWorkProvider provider)
: this(provider, new RepositoryFactory())
public MemberService(IDatabaseUnitOfWorkProvider provider, IMemberGroupService memberGroupService)
: this(provider, new RepositoryFactory(), memberGroupService)
{
}
public MemberService(IDatabaseUnitOfWorkProvider provider, RepositoryFactory repositoryFactory)
public MemberService(IDatabaseUnitOfWorkProvider provider, RepositoryFactory repositoryFactory, IMemberGroupService memberGroupService)
{
if (provider == null) throw new ArgumentNullException("provider");
if (repositoryFactory == null) throw new ArgumentNullException("repositoryFactory");
if (memberGroupService == null) throw new ArgumentNullException("memberGroupService");
_repositoryFactory = repositoryFactory;
_memberGroupService = memberGroupService;
_uowProvider = provider;
}
@@ -205,6 +212,38 @@ namespace Umbraco.Core.Services
}
}
public IEnumerable<IMember> FindMembersByDisplayName(string displayNameToMatch, int pageIndex, int pageSize, out int totalRecords, StringPropertyMatchType matchType = StringPropertyMatchType.StartsWith)
{
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateMemberRepository(uow))
{
var query = new Query<IMember>();
switch (matchType)
{
case StringPropertyMatchType.Exact:
query.Where(member => member.Name.Equals(displayNameToMatch));
break;
case StringPropertyMatchType.Contains:
query.Where(member => member.Name.Contains(displayNameToMatch));
break;
case StringPropertyMatchType.StartsWith:
query.Where(member => member.Name.StartsWith(displayNameToMatch));
break;
case StringPropertyMatchType.EndsWith:
query.Where(member => member.Name.EndsWith(displayNameToMatch));
break;
case StringPropertyMatchType.Wildcard:
query.Where(member => member.Name.SqlWildcard(displayNameToMatch, TextColumnType.NVarchar));
break;
default:
throw new ArgumentOutOfRangeException("matchType");
}
return repository.GetPagedResultsByQuery(query, pageIndex, pageSize, out totalRecords, dto => dto.Name);
}
}
/// <summary>
/// Does a search for members that contain the specified string in their email address
/// </summary>
@@ -214,7 +253,7 @@ namespace Umbraco.Core.Services
/// <param name="pageIndex"></param>
/// <param name="pageSize"></param>
/// <returns></returns>
public IEnumerable<IMember> FindMembersByEmail(string emailStringToMatch, int pageIndex, int pageSize, out int totalRecords, StringPropertyMatchType matchType = StringPropertyMatchType.StartsWith)
public IEnumerable<IMember> FindByEmail(string emailStringToMatch, int pageIndex, int pageSize, out int totalRecords, StringPropertyMatchType matchType = StringPropertyMatchType.StartsWith)
{
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateMemberRepository(uow))
@@ -246,7 +285,7 @@ namespace Umbraco.Core.Services
}
}
public IEnumerable<IMember> FindMembersByUsername(string login, int pageIndex, int pageSize, out int totalRecords, StringPropertyMatchType matchType = StringPropertyMatchType.StartsWith)
public IEnumerable<IMember> FindByUsername(string login, int pageIndex, int pageSize, out int totalRecords, StringPropertyMatchType matchType = StringPropertyMatchType.StartsWith)
{
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateMemberRepository(uow))
@@ -487,7 +526,7 @@ namespace Umbraco.Core.Services
/// that have their last active date within the Membership.UserIsOnlineTimeWindow (which is in minutes). It isn't exact science
/// but that is how MS have made theirs so we'll follow that principal.
/// </remarks>
public int GetMemberCount(MemberCountType countType)
public int GetCount(MemberCountType countType)
{
using (var repository = _repositoryFactory.CreateMemberRepository(_uowProvider.GetUnitOfWork()))
{
@@ -527,7 +566,7 @@ namespace Umbraco.Core.Services
}
public IEnumerable<IMember> GetAllMembers(int pageIndex, int pageSize, out int totalRecords)
public IEnumerable<IMember> GetAll(int pageIndex, int pageSize, out int totalRecords)
{
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateMemberRepository(uow))
@@ -536,11 +575,29 @@ namespace Umbraco.Core.Services
}
}
public IMember CreateMember(string email, string username, string password, IMemberType memberType)
public IMember CreateMember(string username, string email, string password, string memberTypeAlias)
{
var memberTypeService = ApplicationContext.Current.Services.MemberTypeService;
var memberType = memberTypeService.Get(memberTypeAlias);
var member = new Member(username, email.ToLower().Trim(), username, password, -1, memberType);
Created.RaiseEvent(new NewEventArgs<IMember>(member, false, memberTypeAlias, -1), this);
return member;
}
public IMember CreateMemberWithIdentity(string username, string email, string password, IMemberType memberType)
{
if (memberType == null) throw new ArgumentNullException("memberType");
var member = new Member(email, email, username, password, -1, memberType);
var member = new Member(username, email.ToLower().Trim(), username, password, -1, memberType);
if (Saving.IsRaisedEventCancelled(new SaveEventArgs<IMember>(member), this))
{
member.WasCancelled = true;
return member;
}
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateMemberRepository(uow))
@@ -553,9 +610,12 @@ namespace Umbraco.Core.Services
CreateAndSaveMemberXml(xml, member.Id, uow.Database);
}
Saved.RaiseEvent(new SaveEventArgs<IMember>(member, false), this);
Created.RaiseEvent(new NewEventArgs<IMember>(member, false, memberType.Alias, -1), this);
return member;
}
/// <summary>
/// Creates and persists a new Member
/// </summary>
@@ -564,7 +624,7 @@ namespace Umbraco.Core.Services
/// <param name="password"></param>
/// <param name="memberTypeAlias"></param>
/// <returns></returns>
public IMember CreateMember(string email, string username, string password, string memberTypeAlias)
IMember IMembershipMemberService<IMember>.CreateWithIdentity(string username, string email, string password, string memberTypeAlias)
{
var uow = _uowProvider.GetUnitOfWork();
IMemberType memberType;
@@ -580,7 +640,7 @@ namespace Umbraco.Core.Services
throw new ArgumentException(string.Format("No MemberType matching the passed in Alias: '{0}' was found", memberTypeAlias));
}
return CreateMember(email, username, password, memberTypeAlias);
return CreateMemberWithIdentity(username, email, password, memberType);
}
/// <summary>
@@ -591,17 +651,18 @@ namespace Umbraco.Core.Services
/// </remarks>
/// <param name="id"></param>
/// <returns></returns>
public IMember GetById(object id)
public IMember GetByProviderKey(object id)
{
if (id is int)
{
return GetById((int)id);
}
if (id is Guid)
var asGuid = id.TryConvertTo<Guid>();
if (asGuid.Success)
{
return GetByKey((Guid)id);
}
var asInt = id.TryConvertTo<int>();
if (asInt.Success)
{
return GetById((int)id);
}
return null;
}
@@ -631,7 +692,7 @@ namespace Umbraco.Core.Services
{
using (var repository = _repositoryFactory.CreateMemberRepository(_uowProvider.GetUnitOfWork()))
{
var query = Query<IMember>.Builder.Where(x => x.Username == userName);
var query = Query<IMember>.Builder.Where(x => x.Username.Equals(userName));
var member = repository.GetByQuery(query).FirstOrDefault();
return member;
@@ -656,39 +717,42 @@ namespace Umbraco.Core.Services
Deleted.RaiseEvent(new DeleteEventArgs<IMember>(member, false), this);
}
/// <summary>
/// Saves an updated Member
/// </summary>
/// <param name="member"></param>
/// <param name="entity"></param>
/// <param name="raiseEvents"></param>
public void Save(IMember member, bool raiseEvents = true)
public void Save(IMember entity, bool raiseEvents = true)
{
if (raiseEvents)
{
if (Saving.IsRaisedEventCancelled(new SaveEventArgs<IMember>(member), this))
if (Saving.IsRaisedEventCancelled(new SaveEventArgs<IMember>(entity), this))
{
return;
}
}
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateMemberRepository(uow))
{
repository.AddOrUpdate(member);
repository.AddOrUpdate(entity);
uow.Commit();
var xml = member.ToXml();
CreateAndSaveMemberXml(xml, member.Id, uow.Database);
var xml = entity.ToXml();
CreateAndSaveMemberXml(xml, entity.Id, uow.Database);
}
if (raiseEvents)
Saved.RaiseEvent(new SaveEventArgs<IMember>(member, false), this);
Saved.RaiseEvent(new SaveEventArgs<IMember>(entity, false), this);
}
public void Save(IEnumerable<IMember> members, bool raiseEvents = true)
public void Save(IEnumerable<IMember> entities, bool raiseEvents = true)
{
if (raiseEvents)
{
if (Saving.IsRaisedEventCancelled(new SaveEventArgs<IMember>(members), this))
if (Saving.IsRaisedEventCancelled(new SaveEventArgs<IMember>(entities), this))
return;
}
using (new WriteLock(Locker))
@@ -696,7 +760,7 @@ namespace Umbraco.Core.Services
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateMemberRepository(uow))
{
foreach (var member in members)
foreach (var member in entities)
{
repository.AddOrUpdate(member);
}
@@ -704,19 +768,143 @@ namespace Umbraco.Core.Services
//commit the whole lot in one go
uow.Commit();
foreach (var member in members)
foreach (var member in entities)
{
CreateAndSaveMemberXml(member.ToXml(), member.Id, uow.Database);
}
}
if (raiseEvents)
Saved.RaiseEvent(new SaveEventArgs<IMember>(members, false), this);
Saved.RaiseEvent(new SaveEventArgs<IMember>(entities, false), this);
}
}
#endregion
#region IMembershipRoleService Implementation
public void AddRole(string roleName)
{
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateMemberGroupRepository(uow))
{
repository.CreateIfNotExists(roleName);
}
}
public IEnumerable<string> GetAllRoles()
{
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateMemberGroupRepository(uow))
{
var result = repository.GetAll();
return result.Select(x => x.Name).Distinct();
}
}
public IEnumerable<string> GetAllRoles(int memberId)
{
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateMemberGroupRepository(uow))
{
var result = repository.GetMemberGroupsForMember(memberId);
return result.Select(x => x.Name).Distinct();
}
}
public IEnumerable<string> GetAllRoles(string username)
{
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateMemberGroupRepository(uow))
{
var result = repository.GetMemberGroupsForMember(username);
return result.Select(x => x.Name).Distinct();
}
}
public IEnumerable<IMember> GetMembersInRole(string roleName)
{
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateMemberRepository(uow))
{
return repository.GetByMemberGroup(roleName);
}
}
public IEnumerable<IMember> FindMembersInRole(string roleName, string usernameToMatch, StringPropertyMatchType matchType = StringPropertyMatchType.StartsWith)
{
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateMemberRepository(uow))
{
return repository.FindMembersInRole(roleName, usernameToMatch, matchType);
}
}
public bool DeleteRole(string roleName, bool throwIfBeingUsed)
{
using (new WriteLock(Locker))
{
if (throwIfBeingUsed)
{
var inRole = GetMembersInRole(roleName);
if (inRole.Any())
{
throw new InvalidOperationException("The role " + roleName + " is currently assigned to members");
}
}
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateMemberGroupRepository(uow))
{
var qry = new Query<IMemberGroup>().Where(g => g.Name == roleName);
var found = repository.GetByQuery(qry).ToArray();
foreach (var memberGroup in found)
{
_memberGroupService.Delete(memberGroup);
}
return found.Any();
}
}
}
public void AssignRoles(string[] usernames, string[] roleNames)
{
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateMemberGroupRepository(uow))
{
repository.AssignRoles(usernames, roleNames);
}
}
public void DissociateRoles(string[] usernames, string[] roleNames)
{
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateMemberGroupRepository(uow))
{
repository.DissociateRoles(usernames, roleNames);
}
}
public void AssignRoles(int[] memberIds, string[] roleNames)
{
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateMemberGroupRepository(uow))
{
repository.AssignRoles(memberIds, roleNames);
}
}
public void DissociateRoles(int[] memberIds, string[] roleNames)
{
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateMemberGroupRepository(uow))
{
repository.DissociateRoles(memberIds, roleNames);
}
}
#endregion
/// <summary>
/// Rebuilds all xml content in the cmsContentXml table for all media
/// </summary>
@@ -793,6 +981,8 @@ namespace Umbraco.Core.Services
//bulk insert it into the database
uow.Database.BulkInsertRecords(xmlItems, tr);
tr.Complete();
}
}
}
@@ -806,7 +996,6 @@ namespace Umbraco.Core.Services
#region Event Handlers
/// <summary>
/// Occurs before Delete
/// </summary>
@@ -821,6 +1010,15 @@ namespace Umbraco.Core.Services
/// Occurs before Save
/// </summary>
public static event TypedEventHandler<IMemberService, SaveEventArgs<IMember>> Saving;
/// <summary>
/// Occurs after Create
/// </summary>
/// <remarks>
/// Please note that the Member object has been created, but might not have been saved
/// so it does not have an identity yet (meaning no Id has been set).
/// </remarks>
public static event TypedEventHandler<IMemberService, NewEventArgs<IMember>> Created;
/// <summary>
/// Occurs after Save
@@ -890,5 +1088,6 @@ namespace Umbraco.Core.Services
// return new Member(name, email, username, password, -1, memType);
//}
}
}
+16 -16
View File
@@ -11,7 +11,7 @@ using Umbraco.Core.Persistence.UnitOfWork;
namespace Umbraco.Core.Services
{
internal class MemberTypeService : ContentTypeServiceBase, IMemberTypeService
public class MemberTypeService : ContentTypeServiceBase, IMemberTypeService
{
private readonly IDatabaseUnitOfWorkProvider _uowProvider;
private readonly RepositoryFactory _repositoryFactory;
@@ -36,7 +36,7 @@ namespace Umbraco.Core.Services
_memberService = memberService;
}
public IEnumerable<IMemberType> GetAllMemberTypes(params int[] ids)
public IEnumerable<IMemberType> GetAll(params int[] ids)
{
using (var repository = _repositoryFactory.CreateMemberTypeRepository(_uowProvider.GetUnitOfWork()))
{
@@ -49,7 +49,7 @@ namespace Umbraco.Core.Services
/// </summary>
/// <param name="id">Id of the <see cref="IMemberType"/> to retrieve</param>
/// <returns><see cref="IMemberType"/></returns>
public IMemberType GetMemberType(int id)
public IMemberType Get(int id)
{
using (var repository = _repositoryFactory.CreateMemberTypeRepository(_uowProvider.GetUnitOfWork()))
{
@@ -62,7 +62,7 @@ namespace Umbraco.Core.Services
/// </summary>
/// <param name="alias">Alias of the <see cref="IMemberType"/> to retrieve</param>
/// <returns><see cref="IMemberType"/></returns>
public IMemberType GetMemberType(string alias)
public IMemberType Get(string alias)
{
using (var repository = _repositoryFactory.CreateMemberTypeRepository(_uowProvider.GetUnitOfWork()))
{
@@ -75,7 +75,7 @@ namespace Umbraco.Core.Services
public void Save(IMemberType memberType, int userId = 0)
{
if (SavingMemberType.IsRaisedEventCancelled(new SaveEventArgs<IMemberType>(memberType), this))
if (Saving.IsRaisedEventCancelled(new SaveEventArgs<IMemberType>(memberType), this))
return;
using (new WriteLock(Locker))
@@ -91,14 +91,14 @@ namespace Umbraco.Core.Services
UpdateContentXmlStructure(memberType);
}
SavedMemberType.RaiseEvent(new SaveEventArgs<IMemberType>(memberType, false), this);
Saved.RaiseEvent(new SaveEventArgs<IMemberType>(memberType, false), this);
}
public void Save(IEnumerable<IMemberType> memberTypes, int userId = 0)
{
var asArray = memberTypes.ToArray();
if (SavingMemberType.IsRaisedEventCancelled(new SaveEventArgs<IMemberType>(asArray), this))
if (Saving.IsRaisedEventCancelled(new SaveEventArgs<IMemberType>(asArray), this))
return;
using (new WriteLock(Locker))
@@ -118,12 +118,12 @@ namespace Umbraco.Core.Services
UpdateContentXmlStructure(asArray.Cast<IContentTypeBase>().ToArray());
}
SavedMemberType.RaiseEvent(new SaveEventArgs<IMemberType>(asArray, false), this);
Saved.RaiseEvent(new SaveEventArgs<IMemberType>(asArray, false), this);
}
public void Delete(IMemberType memberType, int userId = 0)
{
if (DeletingMemberType.IsRaisedEventCancelled(new DeleteEventArgs<IMemberType>(memberType), this))
if (Deleting.IsRaisedEventCancelled(new DeleteEventArgs<IMemberType>(memberType), this))
return;
using (new WriteLock(Locker))
@@ -136,7 +136,7 @@ namespace Umbraco.Core.Services
repository.Delete(memberType);
uow.Commit();
DeletedMemberType.RaiseEvent(new DeleteEventArgs<IMemberType>(memberType, false), this);
Deleted.RaiseEvent(new DeleteEventArgs<IMemberType>(memberType, false), this);
}
}
}
@@ -145,7 +145,7 @@ namespace Umbraco.Core.Services
{
var asArray = memberTypes.ToArray();
if (DeletingMemberType.IsRaisedEventCancelled(new DeleteEventArgs<IMemberType>(asArray), this))
if (Deleting.IsRaisedEventCancelled(new DeleteEventArgs<IMemberType>(asArray), this))
return;
using (new WriteLock(Locker))
@@ -165,7 +165,7 @@ namespace Umbraco.Core.Services
uow.Commit();
DeletedMemberType.RaiseEvent(new DeleteEventArgs<IMemberType>(asArray, false), this);
Deleted.RaiseEvent(new DeleteEventArgs<IMemberType>(asArray, false), this);
}
}
}
@@ -195,21 +195,21 @@ namespace Umbraco.Core.Services
/// <summary>
/// Occurs before Save
/// </summary>
public static event TypedEventHandler<IMemberTypeService, SaveEventArgs<IMemberType>> SavingMemberType;
public static event TypedEventHandler<IMemberTypeService, SaveEventArgs<IMemberType>> Saving;
/// <summary>
/// Occurs after Save
/// </summary>
public static event TypedEventHandler<IMemberTypeService, SaveEventArgs<IMemberType>> SavedMemberType;
public static event TypedEventHandler<IMemberTypeService, SaveEventArgs<IMemberType>> Saved;
/// <summary>
/// Occurs before Delete
/// </summary>
public static event TypedEventHandler<IMemberTypeService, DeleteEventArgs<IMemberType>> DeletingMemberType;
public static event TypedEventHandler<IMemberTypeService, DeleteEventArgs<IMemberType>> Deleting;
/// <summary>
/// Occurs after Delete
/// </summary>
public static event TypedEventHandler<IMemberTypeService, DeleteEventArgs<IMemberType>> DeletedMemberType;
public static event TypedEventHandler<IMemberTypeService, DeleteEventArgs<IMemberType>> Deleted;
}
}
@@ -58,7 +58,7 @@ namespace Umbraco.Core.Services
IContent[] allVersions = null;
int totalUsers;
var allUsers = _userService.GetAllMembers(0, int.MaxValue, out totalUsers);
var allUsers = _userService.GetAll(0, int.MaxValue, out totalUsers);
foreach (var u in allUsers)
{
if (u.IsApproved == false) continue;
+20 -5
View File
@@ -28,6 +28,7 @@ namespace Umbraco.Core.Services
//private Lazy<ISectionService> _sectionService;
//private Lazy<IMacroService> _macroService;
private Lazy<IMemberTypeService> _memberTypeService;
private Lazy<IMemberGroupService> _memberGroupService;
private Lazy<INotificationService> _notificationService;
/// <summary>
@@ -45,6 +46,7 @@ namespace Umbraco.Core.Services
/// <param name="sectionService"></param>
/// <param name="treeService"></param>
/// <param name="tagService"></param>
/// <param name="memberGroupService"></param>
public ServiceContext(
IContentService contentService,
IMediaService mediaService,
@@ -54,7 +56,8 @@ namespace Umbraco.Core.Services
ILocalizationService localizationService,
PackagingService packagingService,
IEntityService entityService,
IRelationService relationService/*,
IRelationService relationService,
IMemberGroupService memberGroupService/*,
ISectionService sectionService,
IApplicationTreeService treeService*/)
{
@@ -67,6 +70,7 @@ namespace Umbraco.Core.Services
_packagingService = new Lazy<PackagingService>(() => packagingService);
_entityService = new Lazy<IEntityService>(() => entityService);
_relationService = new Lazy<IRelationService>(() => relationService);
_memberGroupService = new Lazy<IMemberGroupService>(() => memberGroupService);
//_sectionService = new Lazy<ISectionService>(() => sectionService);
//_treeService = new Lazy<IApplicationTreeService>(() => treeService);
}
@@ -109,7 +113,7 @@ namespace Umbraco.Core.Services
_userService = new Lazy<IUserService>(() => new UserService(provider, repositoryFactory.Value));
if (_memberService == null)
_memberService = new Lazy<IMemberService>(() => new MemberService(provider, repositoryFactory.Value));
_memberService = new Lazy<IMemberService>(() => new MemberService(provider, repositoryFactory.Value, _memberGroupService.Value));
if (_contentService == null)
_contentService = new Lazy<IContentService>(() => new ContentService(provider, repositoryFactory.Value, publishingStrategy));
@@ -149,6 +153,9 @@ namespace Umbraco.Core.Services
if (_memberTypeService == null)
_memberTypeService = new Lazy<IMemberTypeService>(() => new MemberTypeService(provider, repositoryFactory.Value, _memberService.Value));
if (_memberGroupService == null)
_memberGroupService = new Lazy<IMemberGroupService>(() => new MemberGroupService(provider, repositoryFactory.Value));
}
@@ -251,7 +258,7 @@ namespace Umbraco.Core.Services
/// <summary>
/// Gets the <see cref="UserService"/>
/// </summary>
internal IUserService UserService
public IUserService UserService
{
get { return _userService.Value; }
}
@@ -259,7 +266,7 @@ namespace Umbraco.Core.Services
/// <summary>
/// Gets the <see cref="MemberService"/>
/// </summary>
internal IMemberService MemberService
public IMemberService MemberService
{
get { return _memberService.Value; }
}
@@ -283,10 +290,18 @@ namespace Umbraco.Core.Services
/// <summary>
/// Gets the MemberTypeService
/// </summary>
internal IMemberTypeService MemberTypeService
public IMemberTypeService MemberTypeService
{
get { return _memberTypeService.Value; }
}
/// <summary>
/// Gets the MemberGroupService
/// </summary>
public IMemberGroupService MemberGroupService
{
get { return _memberGroupService.Value; }
}
}
}
+125 -65
View File
@@ -2,7 +2,6 @@ using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Web.Security;
using Umbraco.Core.Events;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Membership;
@@ -16,7 +15,7 @@ namespace Umbraco.Core.Services
/// <summary>
/// Represents the UserService, which is an easy access to operations involving <see cref="IProfile"/>, <see cref="IMembershipUser"/> and eventually Backoffice Users.
/// </summary>
internal class UserService : IUserService
public class UserService : IUserService
{
private readonly RepositoryFactory _repositoryFactory;
private readonly IDatabaseUnitOfWorkProvider _uowProvider;
@@ -76,10 +75,12 @@ namespace Umbraco.Core.Services
}
}
public IUser CreateMember(string username, string email, string password, IUserType userType)
public IUser CreateUserWithIdentity(string username, string email, string password, IUserType userType)
{
if (userType == null) throw new ArgumentNullException("userType");
//TODO: PUT lock here!!
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateUserRepository(uow))
{
@@ -102,14 +103,19 @@ namespace Umbraco.Core.Services
IsApproved = true
};
if (SavingUser.IsRaisedEventCancelled(new SaveEventArgs<IUser>(user), this))
return user;
repository.AddOrUpdate(user);
uow.Commit();
SavedUser.RaiseEvent(new SaveEventArgs<IUser>(user, false), this);
return user;
}
}
public IUser CreateMember(string username, string email, string password, string memberTypeAlias)
IUser IMembershipMemberService<IUser>.CreateWithIdentity(string username, string email, string password, string memberTypeAlias)
{
var userType = GetUserTypeByAlias(memberTypeAlias);
if (userType == null)
@@ -117,19 +123,25 @@ namespace Umbraco.Core.Services
throw new ArgumentException("The user type " + memberTypeAlias + " could not be resolved");
}
return CreateMember(username, email, password, userType);
return CreateUserWithIdentity(username, email, password, userType);
}
public IUser GetById(object id)
public IUser GetById(int id)
{
if (id is int)
using (var repository = _repositoryFactory.CreateUserRepository(_uowProvider.GetUnitOfWork()))
{
using (var repository = _repositoryFactory.CreateUserRepository(_uowProvider.GetUnitOfWork()))
{
var user = repository.Get((int) id);
var user = repository.Get((int)id);
return user;
}
return user;
}
}
public IUser GetByProviderKey(object id)
{
var asInt = id.TryConvertTo<int>();
if (asInt.Success)
{
return GetById((int)id);
}
return null;
@@ -150,57 +162,89 @@ namespace Umbraco.Core.Services
{
using (var repository = _repositoryFactory.CreateUserRepository(_uowProvider.GetUnitOfWork()))
{
var query = Query<IUser>.Builder.Where(x => x.Username == login);
var query = Query<IUser>.Builder.Where(x => x.Username.Equals(login));
return repository.GetByQuery(query).FirstOrDefault();
}
}
/// <summary>
/// This disables and renames the user, it does not delete them, use the overload to delete them
/// </summary>
/// <param name="membershipUser"></param>
public void Delete(IUser membershipUser)
{
if (UserDeleting.IsRaisedEventCancelled(new DeleteEventArgs<IUser>(membershipUser), this))
return;
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateUserRepository(uow))
{
//disable
membershipUser.IsApproved = false;
//can't rename if it's going to take up too many chars
if (membershipUser.Username.Length + 9 <= 125)
{
repository.Delete(membershipUser);
uow.Commit();
membershipUser.Username = DateTime.Now.ToString("yyyyMMdd") + "_" + membershipUser.Username;
}
Save(membershipUser);
UserDeleted.RaiseEvent(new DeleteEventArgs<IUser>(membershipUser, false), this);
//clear out the user logins!
var uow = _uowProvider.GetUnitOfWork();
uow.Database.Execute("delete from umbracoUserLogins where userID = @id", new {id = membershipUser.Id});
}
public void Save(IUser membershipUser, bool raiseEvents = true)
/// <summary>
/// To permanently delete the user pass in true, otherwise they will just be disabled
/// </summary>
/// <param name="user"></param>
/// <param name="deletePermanently"></param>
public void Delete(IUser user, bool deletePermanently)
{
if (deletePermanently == false)
{
Delete(user);
}
else
{
if (DeletingUser.IsRaisedEventCancelled(new DeleteEventArgs<IUser>(user), this))
return;
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateUserRepository(uow))
{
repository.Delete(user);
uow.Commit();
}
DeletedUser.RaiseEvent(new DeleteEventArgs<IUser>(user, false), this);
}
}
public void Save(IUser entity, bool raiseEvents = true)
{
if (raiseEvents)
{
if (UserSaving.IsRaisedEventCancelled(new SaveEventArgs<IUser>(membershipUser), this))
if (SavingUser.IsRaisedEventCancelled(new SaveEventArgs<IUser>(entity), this))
return;
}
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateUserRepository(uow))
{
repository.AddOrUpdate(membershipUser);
repository.AddOrUpdate(entity);
uow.Commit();
}
if (raiseEvents)
UserSaved.RaiseEvent(new SaveEventArgs<IUser>(membershipUser, false), this);
SavedUser.RaiseEvent(new SaveEventArgs<IUser>(entity, false), this);
}
public void Save(IEnumerable<IUser> members, bool raiseEvents = true)
public void Save(IEnumerable<IUser> entities, bool raiseEvents = true)
{
if (raiseEvents)
{
if (UserSaving.IsRaisedEventCancelled(new SaveEventArgs<IUser>(members), this))
if (SavingUser.IsRaisedEventCancelled(new SaveEventArgs<IUser>(entities), this))
return;
}
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateUserRepository(uow))
{
foreach (var member in members)
foreach (var member in entities)
{
repository.AddOrUpdate(member);
}
@@ -209,10 +253,10 @@ namespace Umbraco.Core.Services
}
if (raiseEvents)
UserSaved.RaiseEvent(new SaveEventArgs<IUser>(members, false), this);
SavedUser.RaiseEvent(new SaveEventArgs<IUser>(entities, false), this);
}
public IEnumerable<IUser> FindMembersByEmail(string emailStringToMatch, int pageIndex, int pageSize, out int totalRecords, StringPropertyMatchType matchType = StringPropertyMatchType.StartsWith)
public IEnumerable<IUser> FindByEmail(string emailStringToMatch, int pageIndex, int pageSize, out int totalRecords, StringPropertyMatchType matchType = StringPropertyMatchType.StartsWith)
{
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateUserRepository(uow))
@@ -244,7 +288,7 @@ namespace Umbraco.Core.Services
}
}
public IEnumerable<IUser> FindMembersByUsername(string login, int pageIndex, int pageSize, out int totalRecords, StringPropertyMatchType matchType = StringPropertyMatchType.StartsWith)
public IEnumerable<IUser> FindByUsername(string login, int pageIndex, int pageSize, out int totalRecords, StringPropertyMatchType matchType = StringPropertyMatchType.StartsWith)
{
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateUserRepository(uow))
@@ -276,7 +320,7 @@ namespace Umbraco.Core.Services
}
}
public int GetMemberCount(MemberCountType countType)
public int GetCount(MemberCountType countType)
{
using (var repository = _repositoryFactory.CreateUserRepository(_uowProvider.GetUnitOfWork()))
{
@@ -312,7 +356,7 @@ namespace Umbraco.Core.Services
}
}
public IEnumerable<IUser> GetAllMembers(int pageIndex, int pageSize, out int totalRecords)
public IEnumerable<IUser> GetAll(int pageIndex, int pageSize, out int totalRecords)
{
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateUserRepository(uow))
@@ -333,15 +377,15 @@ namespace Umbraco.Core.Services
public IProfile GetProfileById(int id)
{
var user = GetUserById(id);
return user;
return user.ProfileData;
}
public IProfile GetProfileByUserName(string login)
{
var user = GetByUsername(login);
return user;
return user.ProfileData;
}
public IUser GetUserById(int id)
{
using (var repository = _repositoryFactory.CreateUserRepository(_uowProvider.GetUnitOfWork()))
@@ -350,6 +394,30 @@ namespace Umbraco.Core.Services
}
}
/// <summary>
/// Replaces the same permission set for a single user to any number of entities
/// </summary>
/// <param name="userId"></param>
/// <param name="permissions"></param>
/// <param name="entityIds"></param>
public void ReplaceUserPermissions(int userId, IEnumerable<char> permissions, params int[] entityIds)
{
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateUserRepository(uow))
{
repository.ReplaceUserPermissions(userId, permissions, entityIds);
}
}
public IEnumerable<IUserType> GetAllUserTypes(params int[] ids)
{
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateUserTypeRepository(uow))
{
return repository.GetAll(ids);
}
}
/// <summary>
/// Gets an IUserType by its Alias
/// </summary>
@@ -365,6 +433,14 @@ namespace Umbraco.Core.Services
}
}
public IUserType GetUserTypeById(int id)
{
using (var repository = _repositoryFactory.CreateUserTypeRepository(_uowProvider.GetUnitOfWork()))
{
return repository.Get(id);
}
}
/// <summary>
/// Gets an IUserType by its Name
/// </summary>
@@ -384,7 +460,7 @@ namespace Umbraco.Core.Services
{
if (raiseEvents)
{
if (UserTypeSaving.IsRaisedEventCancelled(new SaveEventArgs<IUserType>(userType), this))
if (SavingUserType.IsRaisedEventCancelled(new SaveEventArgs<IUserType>(userType), this))
return;
}
@@ -396,12 +472,12 @@ namespace Umbraco.Core.Services
}
if (raiseEvents)
UserTypeSaved.RaiseEvent(new SaveEventArgs<IUserType>(userType, false), this);
SavedUserType.RaiseEvent(new SaveEventArgs<IUserType>(userType, false), this);
}
public void DeleteUserType(IUserType userType)
{
if (UserTypeDeleting.IsRaisedEventCancelled(new DeleteEventArgs<IUserType>(userType), this))
if (DeletingUserType.IsRaisedEventCancelled(new DeleteEventArgs<IUserType>(userType), this))
return;
var uow = _uowProvider.GetUnitOfWork();
@@ -411,7 +487,7 @@ namespace Umbraco.Core.Services
uow.Commit();
}
UserTypeDeleted.RaiseEvent(new DeleteEventArgs<IUserType>(userType, false), this);
DeletedUserType.RaiseEvent(new DeleteEventArgs<IUserType>(userType, false), this);
}
/// <summary>
@@ -434,22 +510,6 @@ namespace Umbraco.Core.Services
}
}
/// <summary>
/// Returns the user's applications that they are allowed to access
/// </summary>
/// <param name="user"></param>
/// <returns></returns>
public IEnumerable<string> GetUserSections(IUser user)
{
//TODO: We need to cache this result
var uow = _uowProvider.GetUnitOfWork();
var sql = new Sql();
sql.Select("app").From<User2AppDto>()
.Where<User2AppDto>(dto => dto.UserId == (int)user.Id);
return uow.Database.Fetch<string>(sql);
}
/// <summary>
/// Returns permissions for a given user for any number of nodes
/// </summary>
@@ -487,41 +547,41 @@ namespace Umbraco.Core.Services
/// <summary>
/// Occurs before Save
/// </summary>
public static event TypedEventHandler<IUserService, SaveEventArgs<IUser>> UserSaving;
public static event TypedEventHandler<IUserService, SaveEventArgs<IUser>> SavingUser;
/// <summary>
/// Occurs after Save
/// </summary>
public static event TypedEventHandler<IUserService, SaveEventArgs<IUser>> UserSaved;
public static event TypedEventHandler<IUserService, SaveEventArgs<IUser>> SavedUser;
/// <summary>
/// Occurs before Delete
/// </summary>
public static event TypedEventHandler<IUserService, DeleteEventArgs<IUser>> UserDeleting;
public static event TypedEventHandler<IUserService, DeleteEventArgs<IUser>> DeletingUser;
/// <summary>
/// Occurs after Delete
/// </summary>
public static event TypedEventHandler<IUserService, DeleteEventArgs<IUser>> UserDeleted;
public static event TypedEventHandler<IUserService, DeleteEventArgs<IUser>> DeletedUser;
/// <summary>
/// Occurs before Save
/// </summary>
public static event TypedEventHandler<IUserService, SaveEventArgs<IUserType>> UserTypeSaving;
public static event TypedEventHandler<IUserService, SaveEventArgs<IUserType>> SavingUserType;
/// <summary>
/// Occurs after Save
/// </summary>
public static event TypedEventHandler<IUserService, SaveEventArgs<IUserType>> UserTypeSaved;
public static event TypedEventHandler<IUserService, SaveEventArgs<IUserType>> SavedUserType;
/// <summary>
/// Occurs before Delete
/// </summary>
public static event TypedEventHandler<IUserService, DeleteEventArgs<IUserType>> UserTypeDeleting;
public static event TypedEventHandler<IUserService, DeleteEventArgs<IUserType>> DeletingUserType;
/// <summary>
/// Occurs after Delete
/// </summary>
public static event TypedEventHandler<IUserService, DeleteEventArgs<IUserType>> UserTypeDeleted;
public static event TypedEventHandler<IUserService, DeleteEventArgs<IUserType>> DeletedUserType;
}
}
@@ -0,0 +1,52 @@
using System;
using System.Web.Security;
using Umbraco.Core.Models.Membership;
namespace Umbraco.Core.Services
{
internal static class UserServiceExtensions
{
/// <summary>
/// Maps a custom provider's information to an umbraco user account
/// </summary>
/// <param name="userService"></param>
/// <param name="member"></param>
/// <remarks>
/// To maintain compatibility we have to check the login name if the provider key lookup fails but otherwise
/// we'll store the provider user key in the login column.
/// </remarks>
public static IUser CreateUserMappingForCustomProvider(this IUserService userService, MembershipUser member)
{
if (member == null) throw new ArgumentNullException("member");
var valToLookup = member.ProviderUserKey == null ? member.UserName : member.ProviderUserKey.ToString();
var found = userService.GetByUsername(valToLookup);
if (found == null && member.ProviderUserKey != null)
{
//try by username
found = userService.GetByUsername(member.UserName);
}
if (found == null)
{
var writer = userService.GetUserTypeByAlias("writer");
if (writer == null)
{
throw new InvalidOperationException("Could not map the custom user to an Umbraco user, no 'writer' user type could be found");
}
var user = new User(
member.UserName,
member.Email ?? Guid.NewGuid().ToString("N") + "@example.com", //email cannot be empty
member.ProviderUserKey == null ? member.UserName : member.ProviderUserKey.ToString(),
Guid.NewGuid().ToString("N"), //pass cannot be empty
writer);
user.AddAllowedSection(Constants.Applications.Content);
userService.Save(user);
return user;
}
return found;
}
}
}
+21 -20
View File
@@ -14,25 +14,6 @@ namespace Umbraco.Core.Strings
// note: you have 32 bits at your disposal
// 0xffffffff
// masks
/// <summary>
/// Flag mask for casing.
/// </summary>
CaseMask = 0x3f, // 0xff - 8 possible values
/// <summary>
/// Flag mask for encoding.
/// </summary>
CodeMask = 0x700, // 0xff00 - 8 possible values
/// <summary>
/// Flag mask for role.
/// </summary>
RoleMask = 0x070000, // 0xff0000 - 8 possible values
// no value
/// <summary>
@@ -43,6 +24,11 @@ namespace Umbraco.Core.Strings
// casing values
/// <summary>
/// Flag mask for casing.
/// </summary>
CaseMask = PascalCase | CamelCase | Unchanged | LowerCase | UpperCase | UmbracoCase,
/// <summary>
/// Pascal casing eg "PascalCase".
/// </summary>
@@ -78,6 +64,11 @@ namespace Umbraco.Core.Strings
// encoding values
/// <summary>
/// Flag mask for encoding.
/// </summary>
CodeMask = Unicode | Utf8 | Ascii,
/// <summary>
/// Unicode encoding.
/// </summary>
@@ -97,6 +88,11 @@ namespace Umbraco.Core.Strings
// role values
/// <summary>
/// Flag mask for role.
/// </summary>
RoleMask = UrlSegment | Alias | FileName | ConvertCase,
/// <summary>
/// Url role.
/// </summary>
@@ -110,6 +106,11 @@ namespace Umbraco.Core.Strings
/// <summary>
/// FileName role.
/// </summary>
FileName = 0x040000
FileName = 0x040000,
/// <summary>
/// ConvertCase role.
/// </summary>
ConvertCase = 0x080000
}
}
@@ -1,9 +1,20 @@
using System;
// debugging
// define WRTCONS to write cleaning details & steps to console
// leave it wrapped within #if DEBUG to make sure it does leak
// into RELEASE, see http://issues.umbraco.org/issue/U4-4199
#if DEBUG
#undef WRTCONS
#endif
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Globalization;
using System.Text;
using System.Text.RegularExpressions;
using Umbraco.Core.Configuration;
namespace Umbraco.Core.Strings
@@ -104,6 +115,11 @@ namespace Umbraco.Core.Strings
return InvalidFileNameChars.Contains(c) == false;
}
public static string CutMaxLength(string text, int length)
{
return text.Length <= length ? text : text.Substring(0, length);
}
#endregion
#region Configuration
@@ -157,6 +173,7 @@ namespace Umbraco.Core.Strings
return WithConfig(CleanStringType.UrlSegment, new Config
{
PreFilter = ApplyUrlReplaceCharacters,
PostFilter = x => CutMaxLength(x, 240),
IsTerm = (c, leading) => char.IsLetterOrDigit(c) || c == '_', // letter, digit or underscore
StringType = (UrlReplacingToAscii ? CleanStringType.Ascii : CleanStringType.Utf8) | CleanStringType.LowerCase,
BreakTermsOnUpper = false,
@@ -176,6 +193,12 @@ namespace Umbraco.Core.Strings
: (char.IsLetterOrDigit(c) || c == '_'), // letter, digit or underscore
StringType = CleanStringType.Ascii | CleanStringType.UmbracoCase,
BreakTermsOnUpper = false
}).WithConfig(CleanStringType.ConvertCase, new Config
{
PreFilter = null,
IsTerm = (c, leading) => char.IsLetterOrDigit(c) || c == '_', // letter, digit or underscore
StringType = CleanStringType.Ascii,
BreakTermsOnUpper = true
});
}
@@ -185,6 +208,7 @@ namespace Umbraco.Core.Strings
{
StringType = CleanStringType.Utf8 | CleanStringType.Unchanged;
PreFilter = null;
PostFilter = null;
IsTerm = (c, leading) => leading ? char.IsLetter(c) : char.IsLetterOrDigit(c);
BreakTermsOnUpper = false;
CutAcronymOnNonUpper = false;
@@ -197,6 +221,7 @@ namespace Umbraco.Core.Strings
return new Config
{
PreFilter = PreFilter,
PostFilter = PostFilter,
IsTerm = IsTerm,
StringType = StringType,
BreakTermsOnUpper = BreakTermsOnUpper,
@@ -207,6 +232,7 @@ namespace Umbraco.Core.Strings
}
public Func<string, string> PreFilter { get; set; }
public Func<string, string> PostFilter { get; set; }
public Func<char, bool, bool> IsTerm { get; set; }
public CleanStringType StringType { get; set; }
@@ -503,6 +529,10 @@ function validateSafeAlias(id, value, immediate, callback) {{
if (culture == null)
throw new ArgumentNullException("culture");
#if WRTCONS
Console.WriteLine("STRING TYPE {0}", stringType);
#endif
// get config
var config = GetConfig(stringType, culture);
stringType = config.StringTypeExtend(stringType);
@@ -533,6 +563,10 @@ function validateSafeAlias(id, value, immediate, callback) {{
// clean
text = CleanCodeString(text, stringType, separator.Value, culture, config);
// apply post-filter
if (config.PostFilter != null)
text = config.PostFilter(text);
return text;
}
@@ -570,6 +604,9 @@ function validateSafeAlias(id, value, immediate, callback) {{
var state = StateBreak;
caseType &= CleanStringType.CaseMask;
#if WRTCONS
Console.WriteLine("CASE {0}", caseType);
#endif
// if we apply global ToUpper or ToLower to text here
// then we cannot break words on uppercase chars
@@ -595,13 +632,13 @@ function validateSafeAlias(id, value, immediate, callback) {{
var isPair = char.IsSurrogate(c);
if (isPair)
throw new NotSupportedException("Surrogate pairs are not supported.");
//Console.WriteLine("CHAR '{0}' {1} {2} - {3} - {4}/{5} {6}",
// c,
// isTerm ? "term" : "!term", isUpper ? "upper" : "!upper",
// state,
// i, ipos, leading ? "leading" : "!leading");
#if WRTCONS
Console.WriteLine("CHAR '{0}' {1} {2} - {3} - {4}/{5} {6}",
c,
isTerm ? "term" : "!term", isUpper ? "upper" : "!upper",
state,
i, ipos, leading ? "leading" : "!leading");
#endif
switch (state)
{
// within a break
@@ -708,11 +745,12 @@ function validateSafeAlias(id, value, immediate, callback) {{
CleanStringType caseType, CultureInfo culture, bool isAcronym)
{
var term = input.Substring(ipos, len);
//Console.WriteLine("TERM \"{0}\" {1} {2}",
// term,
// isAcronym ? "acronym" : "word",
// caseType);
#if WRTCONS
Console.WriteLine("TERM \"{0}\" {1} {2}",
term,
isAcronym ? "acronym" : "word",
caseType);
#endif
if (isAcronym)
{
if ((caseType == CleanStringType.CamelCase && len <= 2 && opos > 0) ||
+18
View File
@@ -45,6 +45,10 @@
<Reference Include="MiniProfiler">
<HintPath>..\packages\MiniProfiler.2.1.0\lib\net40\MiniProfiler.dll</HintPath>
</Reference>
<Reference Include="MySql.Data">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\MySql.Data.6.6.5\lib\net40\MySql.Data.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json">
<HintPath>..\packages\Newtonsoft.Json.4.5.11\lib\net40\Newtonsoft.Json.dll</HintPath>
</Reference>
@@ -144,6 +148,7 @@
<Compile Include="Configuration\UmbracoConfigurationSection.cs" />
<Compile Include="Configuration\UmbracoVersion.cs" />
<Compile Include="Attempt.cs" />
<Compile Include="ControlExtensions.cs" />
<Compile Include="CoreBootManager.cs" />
<Compile Include="DatabaseContext.cs" />
<Compile Include="DataTableExtensions.cs" />
@@ -189,9 +194,13 @@
<Compile Include="Models\ContentTypeCompositionBase.cs" />
<Compile Include="Models\ContentTypeExtensions.cs" />
<Compile Include="Models\ContentTypeSort.cs" />
<Compile Include="Models\EntityExtensions.cs" />
<Compile Include="Models\IMemberGroup.cs" />
<Compile Include="Models\IRelation.cs" />
<Compile Include="Models\IRelationType.cs" />
<Compile Include="Models\MemberGroup.cs" />
<Compile Include="Models\Membership\EntityPermission.cs" />
<Compile Include="Models\MemberTypePropertyProfileAccess.cs" />
<Compile Include="Models\Notification.cs" />
<Compile Include="Models\PreValue.cs" />
<Compile Include="Models\PreValueCollection.cs" />
@@ -202,10 +211,13 @@
<Compile Include="Models\PublishedContent\PublishedContentModel.cs" />
<Compile Include="Models\PublishedContent\PublishedContentModelFactoryResolver.cs" />
<Compile Include="Models\TemplateNode.cs" />
<Compile Include="Persistence\Factories\MemberGroupFactory.cs" />
<Compile Include="Persistence\Mappers\MemberGroupMapper.cs" />
<Compile Include="Persistence\Querying\SqlStringExtensions.cs" />
<Compile Include="Persistence\Querying\StringPropertyMatchType.cs" />
<Compile Include="Persistence\Querying\TextColumnType.cs" />
<Compile Include="Persistence\Querying\ValuePropertyMatchType.cs" />
<Compile Include="Persistence\Repositories\Interfaces\IMemberGroupRepository.cs" />
<Compile Include="Persistence\Repositories\NotificationsRepository.cs" />
<Compile Include="Persistence\SqlSyntax\MySqlSyntax.cs" />
<Compile Include="Persistence\SqlSyntax\SqlCeSyntax.cs" />
@@ -740,10 +752,12 @@
<Compile Include="Publishing\PublishStatusType.cs" />
<Compile Include="RenderingEngine.cs" />
<Compile Include="Security\AuthenticationExtensions.cs" />
<Compile Include="Security\IUsersMembershipProvider.cs" />
<Compile Include="Security\MembershipProviderBase.cs" />
<Compile Include="Security\MembershipProviderExtensions.cs" />
<Compile Include="Security\UmbracoBackOfficeIdentity.cs" />
<Compile Include="Security\UmbracoMembershipProviderBase.cs" />
<Compile Include="Security\UmbracoMembersMembershipProviderBase.cs" />
<Compile Include="Security\UserData.cs" />
<Compile Include="Serialization\AbstractSerializationService.cs" />
<Compile Include="Serialization\Formatter.cs" />
@@ -767,8 +781,10 @@
<Compile Include="Services\IFileService.cs" />
<Compile Include="Services\ILocalizationService.cs" />
<Compile Include="Services\IMediaService.cs" />
<Compile Include="Services\IMemberGroupService.cs" />
<Compile Include="Services\IMemberService.cs" />
<Compile Include="Services\IMembershipMemberService.cs" />
<Compile Include="Services\IMembershipRoleService.cs" />
<Compile Include="Services\IMembershipUserService.cs" />
<Compile Include="Services\IMemberTypeService.cs" />
<Compile Include="Services\INotificationService.cs" />
@@ -778,6 +794,7 @@
<Compile Include="Services\LocalizationService.cs" />
<Compile Include="Services\MediaService.cs" />
<Compile Include="Services\MemberCountType.cs" />
<Compile Include="Services\MemberGroupService.cs" />
<Compile Include="Services\MemberService.cs" />
<Compile Include="Services\MemberTypeService.cs" />
<Compile Include="Services\NotificationService.cs" />
@@ -786,6 +803,7 @@
<Compile Include="Services\PackagingService.cs" />
<Compile Include="Services\ServiceContext.cs" />
<Compile Include="Services\UserService.cs" />
<Compile Include="Services\UserServiceExtensions.cs" />
<Compile Include="Standalone\ServiceContextManager.cs" />
<Compile Include="Standalone\StandaloneCoreApplication.cs" />
<Compile Include="Standalone\StandaloneCoreBootManager.cs" />
+17
View File
@@ -116,6 +116,23 @@ namespace Umbraco.Core
return afterAuthority.InvariantStartsWith(IOHelper.ResolveUrl("~/install").TrimStart("/"));
}
/// <summary>
/// Checks if the uri is a request for the default back office page
/// </summary>
/// <param name="url"></param>
/// <returns></returns>
internal static bool IsDefaultBackOfficeRequest(this Uri url)
{
if (url.AbsolutePath.InvariantEquals(GlobalSettings.Path.TrimEnd("/"))
|| url.AbsolutePath.InvariantEquals(GlobalSettings.Path.EnsureEndsWith('/'))
|| url.AbsolutePath.InvariantStartsWith(GlobalSettings.Path.EnsureEndsWith('/') + "Default.aspx")
|| url.AbsolutePath.InvariantStartsWith(GlobalSettings.Path.EnsureEndsWith('/') + "Umbraco.aspx"))
{
return true;
}
return false;
}
/// <summary>
/// This is a performance tweak to check if this is a .css, .js or .ico, .jpg, .jpeg, .png, .gif file request since
/// .Net will pass these requests through to the module when in integrated mode.
+1
View File
@@ -6,6 +6,7 @@
<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="MySql.Data" version="6.6.5" targetFramework="net40" />
<package id="Newtonsoft.Json" version="4.5.11" targetFramework="net40" />
<package id="SqlServerCE" version="4.0.0.0" targetFramework="net40" />
</packages>
+36 -5
View File
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8" ?>
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<section name="FileSystemProviders" type="Umbraco.Core.Configuration.FileSystemProvidersSection, Umbraco.Core" requirePermission="false"/>
<section name="FileSystemProviders" type="Umbraco.Core.Configuration.FileSystemProvidersSection, Umbraco.Core" requirePermission="false" />
</configSections>
<appSettings>
@@ -26,7 +26,7 @@
</appSettings>
<connectionStrings>
<add name="umbracoDbDSN" connectionString="Datasource=|DataDirectory|UmbracoPetaPocoTests.sdf;Flush Interval=1;" providerName="System.Data.SqlServerCe.4.0"/>
<add name="umbracoDbDSN" connectionString="Datasource=|DataDirectory|UmbracoPetaPocoTests.sdf;Flush Interval=1;" providerName="System.Data.SqlServerCe.4.0" />
</connectionStrings>
<FileSystemProviders>
@@ -74,9 +74,9 @@
<system.data>
<DbProviderFactories>
<remove invariant="System.Data.SqlServerCe.4.0"/>
<remove invariant="System.Data.SqlServerCe.4.0" />
<add name="Microsoft SQL Server Compact Data Provider 4.0" invariant="System.Data.SqlServerCe.4.0" description=".NET Framework Data Provider for Microsoft SQL Server Compact" type="System.Data.SqlServerCe.SqlCeProviderFactory, System.Data.SqlServerCe, Version=4.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91" />
<remove invariant="MySql.Data.MySqlClient"/>
<remove invariant="MySql.Data.MySqlClient" />
<add name="MySQL Data Provider" invariant="MySql.Data.MySqlClient" description=".Net Framework Data Provider for MySQL" type="MySql.Data.MySqlClient.MySqlClientFactory, MySql.Data, Version=6.6.4.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d" />
</DbProviderFactories>
</system.data>
@@ -93,4 +93,35 @@
</siteMap>
</system.web>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.0.0" newVersion="4.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.WebPages" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.0.0.0" newVersion="2.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.Helpers" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.0.0.0" newVersion="2.0.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
@@ -94,8 +94,8 @@ namespace Umbraco.Tests.Membership
mServiceMock.Setup(service => service.GetByEmail("test@test.com")).Returns(() => null);
mServiceMock.Setup(service => service.GetDefaultMemberType()).Returns("Member");
mServiceMock.Setup(
service => service.CreateMember(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>()))
.Callback((string u, string e, string p, string m) =>
service => service.CreateWithIdentity(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>()))
.Callback((string u, string e, string p, string m, bool b) =>
{
createdMember = new Member("test", e, u, p, memberType);
})
@@ -125,8 +125,8 @@ namespace Umbraco.Tests.Membership
mServiceMock.Setup(service => service.GetByEmail("test@test.com")).Returns(() => null);
mServiceMock.Setup(service => service.GetDefaultMemberType()).Returns("Member");
mServiceMock.Setup(
service => service.CreateMember(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>()))
.Callback((string u, string e, string p, string m) =>
service => service.CreateWithIdentity(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>()))
.Callback((string u, string e, string p, string m, bool b) =>
{
createdMember = new Member("test", e, u, p, memberType);
})
@@ -158,8 +158,8 @@ namespace Umbraco.Tests.Membership
mServiceMock.Setup(service => service.GetByEmail("test@test.com")).Returns(() => null);
mServiceMock.Setup(service => service.GetDefaultMemberType()).Returns("Member");
mServiceMock.Setup(
service => service.CreateMember(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>()))
.Callback((string u, string e, string p, string m) =>
service => service.CreateWithIdentity(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>()))
.Callback((string u, string e, string p, string m, bool b) =>
{
createdMember = new Member("test", e, u, p, memberType);
})
+18 -17
View File
@@ -47,7 +47,8 @@ namespace Umbraco.Tests
new RelationService(
new Mock<IDatabaseUnitOfWorkProvider>().Object,
new RepositoryFactory(true),
new Mock<IEntityService>().Object)/*,
new Mock<IEntityService>().Object),
new Mock<IMemberGroupService>().Object/*,
new Mock<ISectionService>().Object,
new Mock<IApplicationTreeService>().Object*/);
Assert.Pass();
@@ -66,26 +67,27 @@ namespace Umbraco.Tests
var appCtx = new ApplicationContext(
new DatabaseContext(new Mock<IDatabaseFactory>().Object),
new ServiceContext(
new Mock<IContentService>().Object,
new Mock<IMediaService>().Object,
new Mock<IContentTypeService>().Object,
new Mock<IDataTypeService>().Object,
new Mock<IFileService>().Object,
new Mock<ILocalizationService>().Object,
new PackagingService(
new Mock<IContentService>().Object,
new Mock<IContentTypeService>().Object,
new Mock<IMediaService>().Object,
new Mock<IContentTypeService>().Object,
new Mock<IDataTypeService>().Object,
new Mock<IFileService>().Object,
new Mock<ILocalizationService>().Object,
new RepositoryFactory(true),
new Mock<IDatabaseUnitOfWorkProvider>().Object),
new Mock<IEntityService>().Object,
new RelationService(
new Mock<IDatabaseUnitOfWorkProvider>().Object,
new RepositoryFactory(true),
new Mock<IEntityService>().Object)),
new PackagingService(
new Mock<IContentService>().Object,
new Mock<IContentTypeService>().Object,
new Mock<IMediaService>().Object,
new Mock<IDataTypeService>().Object,
new Mock<IFileService>().Object,
new Mock<ILocalizationService>().Object,
new RepositoryFactory(true),
new Mock<IDatabaseUnitOfWorkProvider>().Object),
new Mock<IEntityService>().Object,
new RelationService(
new Mock<IDatabaseUnitOfWorkProvider>().Object,
new RepositoryFactory(true),
new Mock<IEntityService>().Object),
new Mock<IMemberGroupService>().Object),
CacheHelper.CreateDisabledCacheHelper());
Assert.Pass();
}
@@ -107,7 +109,6 @@ namespace Umbraco.Tests
Assert.AreNotEqual(appCtx, result);
}
[NUnit.Framework.Ignore("Need to fix more stuff up, this is ignore because an exception occurs because it wants to ensure we have a resolver initialized - need to make that process better for testability")]
[Test]
public void Can_Get_Umbraco_Context()
{
@@ -0,0 +1,23 @@
using System;
using NUnit.Framework;
using Umbraco.Core.Models;
namespace Umbraco.Tests.Models
{
[TestFixture]
public class UmbracoEntityTests
{
[Test]
public void UmbracoEntity_Can_Be_Initialized_From_Dynamic()
{
var boolIsTrue = true;
ulong ulongIsTrue = 1; // because MySql might return ulong
var trashedWithBool = new UmbracoEntity((dynamic)boolIsTrue);
var trashedWithInt = new UmbracoEntity((dynamic)ulongIsTrue);
Assert.IsTrue(trashedWithBool.Trashed);
Assert.IsTrue(trashedWithInt.Trashed);
}
}
}
+14 -20
View File
@@ -105,30 +105,24 @@ namespace Umbraco.Tests
}
}
[Test]
public virtual void CanConvertStringToDateTime()
[TestCase("2012-11-10", true)]
[TestCase("2012/11/10", true)]
[TestCase("10/11/2012", true)]// assuming your culture uses DD/MM/YYYY
[TestCase("11/10/2012", false)]// assuming your culture uses DD/MM/YYYY
[TestCase("Sat 10, Nov 2012", true)]
[TestCase("Saturday 10, Nov 2012", true)]
[TestCase("Sat 10, November 2012", true)]
[TestCase("Saturday 10, November 2012", true)]
[TestCase("2012-11-10 13:14:15", true)]
[TestCase("2012-11-10T13:14:15Z", true)]
public virtual void CanConvertStringToDateTime(string date, bool outcome)
{
var dateTime = new DateTime(2012, 11, 10, 13, 14, 15);
var testCases = new Dictionary<string, bool>
{
{"2012-11-10", true},
{"2012/11/10", true},
{"10/11/2012", true}, // assuming your culture uses DD/MM/YYYY
{"11/10/2012", false}, // assuming your culture uses DD/MM/YYYY
{"Sat 10, Nov 2012", true},
{"Saturday 10, Nov 2012", true},
{"Sat 10, November 2012", true},
{"Saturday 10, November 2012", true},
{"2012-11-10 13:14:15", true}
};
foreach (var testCase in testCases)
{
var result = testCase.Key.TryConvertTo<DateTime>();
var result = date.TryConvertTo<DateTime>();
Assert.IsTrue(result.Success, testCase.Key);
Assert.AreEqual(DateTime.Equals(dateTime.Date, result.Result.Date), testCase.Value, testCase.Key);
}
Assert.IsTrue(result.Success, date);
Assert.AreEqual(DateTime.Equals(dateTime.Date, result.Result.Date), outcome, date);
}
[Test]
@@ -25,8 +25,7 @@ namespace Umbraco.Tests.Persistence
string path = TestHelper.CurrentAssemblyDirectory;
AppDomain.CurrentDomain.SetData("DataDirectory", path);
RepositoryResolver.Current = new RepositoryResolver(
new RepositoryFactory());
RepositoryResolver.Current = new RepositoryResolver(new RepositoryFactory(true));
//disable cache
var cacheHelper = CacheHelper.CreateDisabledCacheHelper();
@@ -2,7 +2,10 @@
using System.Linq.Expressions;
using NUnit.Framework;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Membership;
using Umbraco.Core.Models.Rdbms;
using Umbraco.Core.Persistence.Querying;
using Umbraco.Core.Persistence.SqlSyntax;
using Umbraco.Tests.TestHelpers;
namespace Umbraco.Tests.Persistence.Querying
@@ -35,5 +38,60 @@ namespace Umbraco.Tests.Persistence.Querying
Assert.AreEqual("[umbracoNode].[parentID] = -1", result);
}
[Test]
public void Equals_Operator_For_Value_Gets_Escaped()
{
Expression<Func<IUser, bool>> predicate = user => user.Username == "hello@world.com";
var modelToSqlExpressionHelper = new ModelToSqlExpressionHelper<IUser>();
var result = modelToSqlExpressionHelper.Visit(predicate);
Console.WriteLine("Model to Sql ExpressionHelper: \n" + result);
Assert.AreEqual("[umbracoUser].[userLogin] = 'hello@@world.com'", result);
}
[Test]
public void Equals_Method_For_Value_Gets_Escaped()
{
Expression<Func<IUser, bool>> predicate = user => user.Username.Equals("hello@world.com");
var modelToSqlExpressionHelper = new ModelToSqlExpressionHelper<IUser>();
var result = modelToSqlExpressionHelper.Visit(predicate);
Console.WriteLine("Model to Sql ExpressionHelper: \n" + result);
Assert.AreEqual("upper([umbracoUser].[userLogin]) = 'HELLO@@WORLD.COM'", result);
}
[Test]
public void Model_Expression_Value_Does_Not_Get_Double_Escaped()
{
//mysql escapes backslashes, so we'll test with that
SqlSyntaxContext.SqlSyntaxProvider = MySqlSyntax.Provider;
Expression<Func<IUser, bool>> predicate = user => user.Username.Equals("mydomain\\myuser");
var modelToSqlExpressionHelper = new ModelToSqlExpressionHelper<IUser>();
var result = modelToSqlExpressionHelper.Visit(predicate);
Console.WriteLine("Model to Sql ExpressionHelper: \n" + result);
Assert.AreEqual("upper(`umbracoUser`.`userLogin`) = 'MYDOMAIN\\\\MYUSER'", result);
}
[Test]
public void Poco_Expression_Value_Does_Not_Get_Double_Escaped()
{
//mysql escapes backslashes, so we'll test with that
SqlSyntaxContext.SqlSyntaxProvider = MySqlSyntax.Provider;
Expression<Func<UserDto, bool>> predicate = user => user.Login.StartsWith("mydomain\\myuser");
var modelToSqlExpressionHelper = new PocoToSqlExpressionHelper<UserDto>();
var result = modelToSqlExpressionHelper.Visit(predicate);
Console.WriteLine("Poco to Sql ExpressionHelper: \n" + result);
Assert.AreEqual("upper(`umbracoUser`.`userLogin`) like 'MYDOMAIN\\\\MYUSER%'", result);
}
}
}
@@ -12,25 +12,6 @@ namespace Umbraco.Tests.Persistence.Querying
[TestFixture]
public class PetaPocoSqlTests : BaseUsingSqlCeSyntax
{
[Test]
public void Generate_Replace_Entity_Permissions_Test()
{
// Act
var sql = PermissionRepository<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<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()
@@ -2,6 +2,7 @@
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;
@@ -38,7 +39,7 @@ namespace Umbraco.Tests.Persistence.Repositories
{
var templateRepository = new TemplateRepository(unitOfWork, NullCacheProvider.Current);
contentTypeRepository = new ContentTypeRepository(unitOfWork, NullCacheProvider.Current, templateRepository);
var repository = new ContentRepository(unitOfWork, NullCacheProvider.Current, contentTypeRepository, templateRepository);
var repository = new ContentRepository(unitOfWork, NullCacheProvider.Current, contentTypeRepository, templateRepository, CacheHelper.CreateDisabledCacheHelper());
return repository;
}
@@ -68,7 +69,7 @@ namespace Umbraco.Tests.Persistence.Repositories
unitOfWork.Commit();
// Act
repository.AssignEntityPermissions(parentPage, 'A', new object[] { 0 });
repository.AssignEntityPermission(parentPage, 'A', new int[] { 0 });
var childPage = MockedContent.CreateSimpleContent(contentType, "child", parentPage);
repository.AddOrUpdate(childPage);
unitOfWork.Commit();
@@ -36,7 +36,7 @@ namespace Umbraco.Tests.Persistence.Repositories
{
var templateRepository = new TemplateRepository(unitOfWork, NullCacheProvider.Current);
contentTypeRepository = new ContentTypeRepository(unitOfWork, NullCacheProvider.Current, templateRepository);
var repository = new ContentRepository(unitOfWork, NullCacheProvider.Current, contentTypeRepository, templateRepository);
var repository = new ContentRepository(unitOfWork, NullCacheProvider.Current, contentTypeRepository, templateRepository, CacheHelper.CreateDisabledCacheHelper());
return repository;
}

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