How to get list of users who can read a page?

Permalink
Hello,

I am building a Dashboard page where I will list all pages with selected specific attribute. In that page I will display using a table format with few columns:

1. Page name (link to the page)
2. Total count of users with read access to the page
3. Few more columns
4. One button to view full list of users with name and email who can read the page.

I created the dashboard with the page and I have already all pages in array as objects, but I am in trouble how to retrieve all users that have read access to the specific page.

I know that I can get a list with all users in the application and run check for the specific page if the user has access to, but this sounds like not effective and slow method. Is there a way to get this information directly from the page object checking its permissions?

Note: A user could be part of multiple groups assigned to the page, so we should list this user only once.

I was checking the classes and methods, but didn't see a way to do it thru Page class and its methods.

Can you give me some ideas?

Regards,
Ali Nebi

 
anebi replied on at Permalink Reply
Any ideas are welcome :)
mnakalay replied on at Permalink Reply
mnakalay
Typically to restrict page viewing rights to specific users, the easiest way would be to put all those users in a user group and grant the group viewing permissions. From there it is easy to get a list of users belonging to that user group. To do that you'd use the function filterByGroup() in class Concrete\Core\User\UserList
anebi replied on at Permalink Reply
Hi.

Thank you for your reply. Yes, we do use multiple groups and have assigned multiple groups to each page permissions.

Yes, I was checking the API and codes, but still I don't know how to achieve this. There are few problems that I need to solve:

1. How to get all groups assigned to the page in 'view' section?
2. How should I do same in point 1. if page inherit permissions from parents?

Regards,
Ali
mnakalay replied on at Permalink Reply
mnakalay
Sorry I was taking a different approach based on the idea that there are things that you know. For instance, you know which groups you assigned to which permission type.

If you want something totally flexible where the code will check each page and for each page get users and filter them by permission, then you have to do it the hard and slow way as far as I know.

But if you organize your users into groups and your pages in a sensible way then you know to some extent what you're dealing with and can do it the easy way.

That page and all its children are accessible by that user group so I know what to do
That other page with all its children is accessible by that other group so, again, I know what to do

Like that it's easy.
anebi replied on at Permalink Reply
Yeah, It seems so. Problem is that I cannot know which groups to which type of page permissions will be assigned by editors. This is why I was looking for a way to get it thru pages to groups/users dynamically for each page. I got working with the code i posted, but as you said, this is a slow way. I need to go with multiple loops in order to achieve that :)

Maybe there is better way, but I will need to learn more about C5 before trying to optimize it.
anebi replied on at Permalink Reply
This works, but is slow. I will be happy if someone gives me a solution that is faster :)

// Here you can set variable for view $this->set('nameForView',$variable);
                $list = new PageList;
                $list->ignoreAliases();
                $list->filterByAttribute('require_read_and_sign', true);
                $list->sortByName();
                $pageList = $list->getResults();
                # Get all users
                $userList = new UserList();
                $userList->sortByUserName();
                $users = $userList->getResults();
                // Array with count of users with access to specific pages and total count of users signed the page
                $pages = array();
                // Create the final array with data
                foreach( $pageList as $page ) {
                        # get pageID
mnakalay replied on at Permalink Reply
mnakalay
you probably can simplify your code. Right now you are getting all users and looping through them, then for each user you are getting all groups and then checking permissions for each group. That means you are probably checking the same groups over and over again.

You could probably just loop through the users and check the permission. Even if the permission is attached to a user group, as long as the user is in the group (or not) you can check the user directly.

Or you could grab a list of all groups from the Group class and check them without having to grab the users first.

Last but not least, right now your variable $totalUsersCount is not giving you the number of users with viewing permission, it is giving you the number of groups with viewing permission
anebi replied on at Permalink Reply
Yeah. I will try to optimize it now to check users directly without groups. This will save one foreach for sure.

Thanks for your help and ideas! :)
mnakalay replied on at Permalink Reply
mnakalay
You can try this but keep in mind that it will not give you the groups that have viewing permission in theory, it will give you the ones that were effectively checked for each page permission.

SELECT ppa.cID, count(paeg.gID) FROM pagepermissionassignments ppa RIGHT JOIN permissionaccesslist pal on ppa.paID = pal.paID RIGHT JOIN permissionaccessentitygroups paeg on pal.peID = paeg.peID WHERE ppa.pkID = 1 GROUP BY ppa.cID

This will give you the number of groups that have viewing permission per page. Keep in mind it will also count groups like administrator and guests so you might want to filter to no include those.

Otherwise, this is as fast as it gets I think

If you want users instead of user groups you can do
SELECT ppa.cID, count(paeu.uID) FROM pagepermissionassignments ppa RIGHT JOIN permissionaccesslist pal on ppa.paID = pal.paID RIGHT JOIN permissionaccessentityusers paeu on pal.peID = paeu.peID WHERE ppa.pkID = 1 GROUP BY ppa.cID
anebi replied on at Permalink Reply
Thanks. I will give a try with those queries.

I just changed the code like this to check users directly instead of looping thru groups. I see that internally system gets all their groups too, but on my side code is simpler with less loops.

foreach( $pageList as $page ) {
                        # get pageID
                        $pageID = $page->getCollectionID();
                        // Users count with read access to the page
                        $totalUsersCount = 0;
                        // Check if users have read access to the page
                        $key = Key::getByHandle('view_page');
                        $key->setPermissionObject( $page );
                        $access = $key->getPermissionAccessObject();
                        if( $access ) {
                                foreach( $users as $user ) {
                                        $userObj = $user->getUserObject();
                                        $entity = \Concrete\Core\Permission\Access\Entity\Entity::getForUser( $userObj );
                                        if( $access->validateAccessEntities( $entity ) ) {
                                                $totalUsersCount++;