Specifying the content owner when overriding IMembershipService

Topics: Customizing Orchard, Writing modules
Apr 10, 2012 at 11:30 PM
Edited Apr 10, 2012 at 11:41 PM

In my custom module, I've overridden the IMembershipService, IAuthorizationService, and IAuthenticationService to use a pre-existing user database (see http://orchard.codeplex.com/discussions/262962). Apart from some transaction scoping issues (see http://orchard.codeplex.com/discussions/350250), this seems to have worked pretty well.

In fact, the only thing that it seems to have broken is the Owner field in the Content editor. The issue there is this: when I'm editing the page, I have to re-specify the Owner every time, and of course, it doesn't get saved to the database (or rather, it gets saved as a "0" to the [Common_CommonPartRecord].[OwnerId] column). So the next time I pull up the page, the Owner is blank again. Even specifying an existing UserId (e.g., "admin") doesn't seem to work.

This isn't the end of the world, because it's not too difficult to type it back in every time, but it is a bit annoying (especially for non-techie folks who want to administer their own pages - which is sorta the point), and I worry that eventually we'll actually want to identify the owner of page A or projection B.

So does anyone have any suggestions for the best way to handle this? None of the options I can think of sound too palatable, but for the record they include:

- Synchronize the external user database with Orchard somehow.

- Give up on the idea of using the Orchard security infrastructure with my custom module (and figure out a way to handle it in a way that's completely internal to my module).

- Figure out how to get the UserPartRecord to talk to my external user database. (Not sure if this is at all possible, of if so, how to get it to happen.)

- Override the OwnerEditorDriver to set the owner to "admin" if it's not already set.

- Hack (or override?) the OwnerEditorViewModel and remove the [Required] attribute.

Other suggestions? Like I said, none of these sound terribly palatable, but perhaps some will be easier or have fewer side-effects than I think.

Apr 11, 2012 at 1:12 AM

For what it's worth, I ended up overriding the OwnerEditorDriver to set the part.Owner to the currently authenticated user, like so:

using Orchard;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Drivers;
using Orchard.Core.Common.Models;
using Orchard.Environment.Extensions;
using Orchard.Security;

namespace Alanta.Web.Corp.Drivers
	public class OwnerEditorDriver : Orchard.Core.Common.OwnerEditor.OwnerEditorDriver
		public OwnerEditorDriver(
					IOrchardServices services,
					IAuthenticationService authenticationService,
					IAuthorizationService authorizationService,
					IMembershipService membershipService)
			: base(services, authenticationService, authorizationService, membershipService)
			_authenticationService = authenticationService;

		private readonly IAuthenticationService _authenticationService;

		/// <remarks>
		/// Without this, you always have to type back in the Owner.
		/// </remarks>
		protected override DriverResult Editor(CommonPart part, IUpdateModel updater, dynamic shapeHelper)
			if (part.Owner == null)
				part.Owner = _authenticationService.GetAuthenticatedUser();
			return base.Editor(part, updater, (object)shapeHelper);
That seems to be working, though there may be side-effects I haven't discovered yet.

Apr 11, 2012 at 9:07 AM

You could also use handler events (On* methods) to hook into a part's lifetime, it's not necessary to use a driver for this.

I guess the problem is that the Owner is an IContent object, that means, if there is no content item of an owner, it also can't be set as owner.