Macro to hide pages in pages application tree

Andrew Malone asked on May 29, 2018 12:42

Hi,

I am trying to create a macro in the CMS scopes under a particular starting path achieve the following function: I have a custom field "OfficeID" on a user. I need to be able to restrict visibility in the the pages application Tree to only show pages to that user of type "custom.office" that have the same OfficeID as the OfficeID assigned to the user.

So something like:

DocumentHelper.GetDocuments().Where(ClassName = "custom.Office").Where(Document.GetValue("OfficeID") = CurrentUser.OfficeID)

Could anybody help?

Correct Answer

Andrew Malone answered on June 1, 2018 10:45

I took advice from both of you and created a global event handler to intercept the action of a user being updated. I captured the office id that the user was associated with, then got the document with that ID. I then set the users starting alias path value equal to that of the office node alias path.

    /// <summary>
/// Every time a user in the role "officer" is updated, updated the user "starting alias path" value to node alias path of the office they are associated with
/// </summary>
/// <param name="sender"></param>
/// <param name="user"></param>
private void UserGroup_UpdateUserStartingAliasPathHandler(object sender, ObjectEventArgs user)
{
    // Gets the user
    UserInfo currentUser = UserInfoProvider.GetUserInfo((int)user.Object.GetValue("UserID"));
    //user is a privilege level of admin or higher 
    var userIsAdminPrivilegeOrHigher = currentUser.CheckPrivilegeLevel(CMS.Base.UserPrivilegeLevelEnum.Admin, SiteContext.CurrentSiteName);
    bool checkGlobalRoles = true;
    bool checkMembership = true;
    bool userIsOfficer = currentUser.IsInRole("SecurityOfficer", SiteContext.CurrentSiteName, checkGlobalRoles, checkMembership);
    if (userIsOfficer && userIsAdminPrivilegeOrHigher == false)
    {
        try
        {
            //Get Officer credit union node alias path
            //NOTE: officehelper is a helper class to get documents from treenode based on where conditions used kentico api.
            var nodeAliasPath = officeHelper.GetSingleOfficeNodeAliasPath((int)currentUser.GetValue("OfficeID"));
            //Assign the user node alias path value
            user.Object.SetValue("UserStartingAliasPath", nodeAliasPath);
        }
        catch (Exception ex)
        {
            EventLogProvider.LogEvent(EventType.ERROR, "Global Event Handler: User enabled email", "GEVUserOfficeAliasPath", "Unabled to set user alias path value to document alias path - Error Message: " + ex);
            return;
        }
    }
}
1 votesVote for this answer Unmark Correct answer

Recent Answers


Rui Wang answered on May 29, 2018 15:34

Here is a suggestion in a different way.

In user properties, there is a property called "Starting alias path". You can use that to specify which sub branch that user can see as starting point in Pages application. E.g. /office/Boston, then when the user go to Pages app, the content tree will only show Boston and all the sub pages.

You can utilize the authentication event, get the OfficeID during the user login, and find the alias path for the page that matches the ID. (Add condition checks for other users who don't have the office ID restriction).

1 votesVote for this answer Mark as a Correct answer

Trevor Fayas answered on May 29, 2018 16:15

I would look into handling the global events under CMS.Membership.SecurityEvents

There's an AuthorizeUIElement.Execute that you probably can use that passes the Element Name, Class Name, and User (and some other things), if you can debug this and see if it contains enough info that you can determine which page it is (may need to look to the UIContext or the URL Parameters to get the Node ID) you can set the "IsAuthorized" bool on the AuthorizeEventArgs to dynamically allow or deny.

using CMS;
using CMS.DataEngine;
using CMS.DocumentEngine;
using CMS.FormEngine.Web.UI;
using CMS.Membership;

// Registers the custom module into the system
[assembly: RegisterModule(typeof(CustomInitializationModule))]

public class CustomInitializationModule : Module
{
    // Module class constructor, the system registers the module under the name "CustomInit"
    public CustomInitializationModule()
        : base("CustomInit")
    {
    }

    // Contains initialization code that is executed when the application starts
    protected override void OnInit()
    {
        base.OnInit();

        // Assigns custom handlers to events
        CMS.Membership.SecurityEvents.AuthorizeClass.Execute += AuthorizeClass_Execute;
    }


    private void AuthorizeClass_Execute(object sender, CMS.Membership.AuthorizationEventArgs e)
    {
        if(e.ClassName == "custom.Office")
        {
            int NodeID = UIContext.Current.ObjectID; // may need to get from URL
            int CurrentUsersOfficeID = UserSettingsInfoProvider.GetUserSettingsInfoByUser(e.User.UserID).GetIntegerValue("UsersOffice", -1);
            e.Authorized = (DocumentHelper.GetDocuments("custom.Office").WhereEquals("NodeID", NodeID).WhereEquals("OfficeID", CurrentUsersOfficeID).FirstObject != null);
        }
    }
}
2 votesVote for this answer Mark as a Correct answer

Juraj Ondrus answered on May 30, 2018 11:36

And I would add another idea - split the user to a user roles based on the offices and then use ACL permissions and hide the pages of other offices they do not have access to.

0 votesVote for this answer Mark as a Correct answer

   Please, sign in to be able to submit a new answer.