10

I have implemented an event handler for the following use case:

  1. Validate some custom permissions
  2. If the user doesn't have these permissions then undo checkout of the item and then throw an exception.

    EventSystem.Subscribe(HandlerForInitiated, EventPhases.Initiated);

And this is the pseudo code for the "HandlerForInitiated" method:

private void HandlerForInitiated(RepositoryLocalObject subject, CheckInEventArgs args, EventPhases phase)
        {
            Log.InfoFormat("Trying to check-in [{0}] {1} of type: {2} ", subject.Id,subject.Title,subject.Id.ItemType);
            bool allowed = true;
            var type = subject.Id.ItemType;
            try
            {
                var user = subject.Session.User;
                allowed = IsActionAllowed(subject, user);
                Log.DebugFormat("Is Allowed: {0}", allowed);
                if (!allowed)
                {
                    Log.InfoFormat("User {0} [{1}] is not allowed to check-in items of type {2}.", user.Title, user.Id, type);    
                }

            }
            catch (Exception ex)
            {
                Log.Error(ex.Message);
            }
            if (!allowed)
            {
                TryUndoCheckOut(subject);
                throw new Exception("You are not allowed to perform this action. Contact the Tridion CoE for support");
            }
        }

This is the TryUndoCheckOut method:

private void TryUndoCheckOut(RepositoryLocalObject subject)
        {
            if (subject is VersionedItem && subject.IsLocked)
            {
                var vi = (VersionedItem)subject;
                if (vi.LockType.HasFlag(LockType.CheckedOut))
                {
                    Log.DebugFormat("Item {0} is checked out!", subject.Id);
                    try
                    {
                        Log.Debug("Undoing check-out...");
                        vi.UndoCheckOut();
                        Log.Debug("Undo-checkout successful!");
                    }
                    catch (Exception ex)
                    {
                        Log.ErrorFormat("Error while trying to undo check out for item: {0}", subject.Id);
                    }
                }
            }
        }

When I check the component in the CME it remains checked-out although I don't get any errors.

2 Answers 2

11

Unless you're trying to implement really granular permissions (more on that in a minute) it makes more sense to handle this on the check-out event instead. The rudimentary issue that I see - and this also applies to implementing granular permissions (e.g., treating check-in and check-out as two separate permissions) - is that by the time the check-in event fires the changes have already been made to whatever they've been editing. This happens in the Save event, which fires prior to the item actually being checked in. Thus, it'd be possible to wind up in a position where the user has taken the time to make changes (and potentially wasted time doing so) that will never be used if they can't be checked in for some reason.

If you're looking to implement some sort of approval process for content or item changes then implementing a Workflow solution is the better option; in fact, that's exactly what it was intended for.

If you're looking to just prevent unauthorized checkouts, this code should do what you want (pseudo code; I haven't tested it):

private void CheckoutPermissionsInitiated(RepositoryLocalObject subject, CheckOutEventArgs args, EventPhases phase) {

    var type = subject.Id.ItemType;
    try {
        var user = subject.Session.User;
        if (!IsActionAllowed(subject, user)) {
            throw new Exception("Sorry, chief. No soup for you.");
        }
    } catch (Exception e) {
        // SOMETHING BAD HAPPENED HERE.
    }
}

If you take a look at the !IsActionAllowed conditional, I'm intentionally throwing an exception if the user failed the condition. Throwing an exception will cause that event to fail, and stop event processing where it sits.

1
  • Hi Rob, thanks for the answer, I was planning to add the same check on the Save event too, for the reasons you very clearly explain in your answer. I was considering using the CheckOut event instead, but I am not sure whether that allow the user to open the item in read-only mode... Because the system should allow the user to "see/read" the item, simply not modify it. I know I could use regular Tridion Permissions... but let's say that it is not an option for now... Commented Jul 23, 2015 at 14:35
0

My guess is that when you throw an exception it rolls back the entire transaction (including your UndoCheckout). Have you tried with not throwing an exception?

2
  • No, I haven't, but I need to throw the exception, otherwise my Event Handler would be useless :) Commented Jul 23, 2015 at 14:27
  • If you do an undo checkout and not throw an exception does the new code still get checked in? Commented Jul 23, 2015 at 14:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.