Jump to content

Check a page reference chain


pwFoo
 Share

Recommended Posts

Hi at all :)

What's the best way to check a page reference chain like this:

content (page) -> category/ group (page) <- user (page)

It should be a simple access check. Users added to groups via page reference field. the groups added to content pages also with a page reference field.

So far it's simple. 

How should a check the reference chain (also with a critical look at the performance...). In words:

Is the user referenced to the content via one (or maybe more) group(s)?

I think it should be possible with selectors, but don't know what's the best/ simplest way to do it.

Regards

pwFoo

Link to comment
Share on other sites

Interesting question, wanna know the answer too =)

Why do you need it? Breadcrumbs-like thing?

I doubt it's possible with one selector only (perhaps with the new nested selectors).

I would select all categories/groups with "your-user-page-field-name-here"-value of your desired user

and then select all pages with "your-category/group-page-field-name-here"-value of each previously selected groups/categories.

To wrap it all nicely I would first of all create a new hook called something like

$page->references('page-field-name');

which spits out a WireArray of all the referencing pages. You can go from there then ...

  • Like 1
Link to comment
Share on other sites

Maybe I build a access control based on references ;)

Could be used in backend and also frontend via page references. Instead of add users to content I try to group users. That's why I need to check the reference chain .

content -> group(s) -> user
Link to comment
Share on other sites

Getting a reference chain is one thing and might come in handy in other situations too, but for your case you might be satisfied what PW provides out of the box.

You have your User Roles, which are essentially your Groups. You also can define permissions on a template basis. if you want finer grained access per page you might wanna check out the "Page Edit Per User"-Module: http://modules.processwire.com/modules/page-edit-per-user/

There is also a Module by apeisa in the works for managing groups: https://processwire.com/talk/topic/5354-usergroups-module-in-development-groups-page-based-permissions/

You can even have permission per field: http://modules.processwire.com/modules/page-edit-field-permission/

Still, have you worked out a solution that works for you already?

I am sure one could patch together the pseudo code I wrote in my previous post in a couple of minutes.

Link to comment
Share on other sites

But I think also about  frontend user managed groups. For example to build a  G+ or FB like share feature.

reference based access should be more flexible and simpler to use by frontend users.

Link to comment
Share on other sites

Maybe I build a access control based on references ;)

Can one do that? Build custom access controls? That'd be awesome.

For now:

Let's say you have the following structure:

Pages 
	- Page 1
		- PageField 'userGroupSelect'
			- user-group-1
	- Page 2
		- PageField 'userGroupSelect'
			- user-group-2
	- Page 3
		- PageField 'userGroupSelect'
			- user-group-3

User Groups (which are pages)
	- User Group 1
		- PageField 'userSelect'
			- user1
			- user3
	- User Group 2
		- PageField 'userSelect'
			- user2
			- user3
	- User Group 3
		- PageField 'userSelect'
			- user2
			- user3

the following code would get you the references:

// the user you want to get references for
$targetUser = $users->get("user3");

// find pages that reference users
$userReferences = $pages->find("userSelect.count>0");

// create empty page array, which will contain the matching groups
$groupsWithUser = new PageArray();

foreach ($userReferences as $userReference) {
	if($userReference->userSelect->has("id={$targetUser->id}")) {
		$groupsWithUser->push($userReference);
	}
}

// find pages that reference user groups
$groupReferences = $pages->find("userGroupSelect.count>0");

// create empty page array, which will contain the matching pages
$pagesWithGroups = new PageArray();

foreach ($groupReferences as $groupReference) {
	if($groupReference->userGroupSelect->has("id={$groupReference->id}")) {
		$pagesWithGroups->push($groupReference);
	}
}

foreach ($groupsWithUser as $groupWithUser) {
	echo "{$targetUser->name} is referenced in User Group '{$groupWithUser->name}'<br>";
}

foreach ($pagesWithGroups as $pageWithGroups) {
	echo "{$targetUser->name} is referenced in Page '{$pageWithGroups->name}'<br>";
}

Perhaps there is a more elegant way, dunno.

But as I said, you would want to wrap that logic into a custom hook for users, like $user->isInGroup('user-group-1') or $user->isReferencedOnPage('some-page-name') or something similar.

  • Like 2
Link to comment
Share on other sites

My first idea was something like that (pseudo code).

$pages->get("$currentPage.groupRef, template = group")->find("$group.userRef = $currentUser", limit = 1)

Get current page group references. Chained find() to select only groups with current user referenced. If true = access allowed.

Good night ;)

Link to comment
Share on other sites

Here my tested code which seems to work so far...

$pages->find("id={$page->GroupRef}, template=Group")->find("UserRef={$user->id}")->count();

GroupRef = page field reference groups to the current page 

UserRef = page field reference pw users to groups (sadly PageAutocomple not supported for pw users?!)

page tree

page
- content (GroupRef field)
- group
-- group1 (UserRef field)
-- group2 (UserRef field)
- admin
-- access
--- users
---- testUser

Result:

0 = no reference chain 

1+ one or more references

If it works as expected it could be used to check access for current user to the current page (0 = denied, 1+ = allowed).

Link to comment
Share on other sites

  • 3 weeks later...

Optimized code to check reference chain

$a = $pages->find("id={$page->GroupRef}, template=Group, created_users_id={$page->created_users_id}")->find("UserRef={$user->id}")->count();

With words...

1) Find all groups created by the current page creator and referenced to the current page

2) where the current logged in user is referenced

3) if count > 0 the current user is referenced via group to the content (and should be allowed to view it) 

Could be used in the backend (pages and groups created by admin) or also as frontend / user access controll (groups created by frontend users like G+ circles).

I try to build a refAccess module around that check in the future.

Update

First commit, dev, not ready to use!

https://bitbucket.org/pwFoo/refaccess

Link to comment
Share on other sites

  • 7 months later...

After long time haven't take a look at this try...

In the above example I use two find() to get the chain reference 

current page -> assigned groups -> current user assigned?

If the current user is referenced to the current loading page via a group membership, access will be allowed.

It seems possible to do this check with one count() with Processwire?!

$pages->count("id={$refPage}, refGroups.refUser={$user->id}");

$refPage = "current page" the user asking for access

refGroups = the groups referenced with $refPage (page reference field)

refUser = page reference field to manage "group memberships", field is added to group pages

$curUser = current user / user to check access for

Don't know if the reference is to complex for good performance? Two find() vs. one complex(?) count 

Link to comment
Share on other sites

A simple module to exend view / edit permissions via reference

current page -> group -> user
current Page -> user

It works with 4 additional fields

refAccessGroup_view
refAccessGroup_edit
refAccessUser_view
refAccessUser_edit

Selector to check permissions is generated because fields optional. Field exists at current template is checked by a has() call and permissions verified by count() calls.

Here is the combined view / edit permission check function

    public function checkRefAccess($refPage, $userId, $permission = 'view') {
        // Has page group based reference access field?
        if ($fieldGroupExists = $refPage->has("{$this->fieldGroupRef}_{$permission}")) {
            $selector[] = "{$this->fieldGroupRef}_{$permission}.{$this->fieldUserRef}_{$permission}";
            $selectorCount[] = "{$this->fieldGroupRef}_{$permission}.count<1";
        }
        // Has page user based reference access field?
        if ($fieldUserExists = $refPage->has("{$this->fieldUserRef}_{$permission}")) {
            $selector[] = "{$this->fieldUserRef}_{$permission}";
            $selectorCount[] = "{$this->fieldUserRef}_{$permission}.count<1";
        }
        
        if (!$fieldGroupExists && !$fieldUserExists) return false;
        
        // Build selector with existing field(s)
        $selectorCount = implode(',', $selectorCount);
        $selector = implode('|', $selector);

        // view access to public and unrestricted content?
        if ($permission == 'view' && $this->publicAccess && $this->pages->count("id={$refPage->id}, {$selectorCount}")) {
            return true;
        }
        // view | edit access allowed by group | user reference?
        elseif ($this->pages->count("id={$refPage->id}, {$selector}={$userId}")) {
            return true;
        }
        else {
            return false;
        }
    }

Maybe looks confusing, but seems to work *g*

1) check viewable && default public && group / user count < 1 (NO users or groups set!)

-> public page without restrictions

2) user get permission to view | edit by a group or user reference

-> user is member of a allowed group or directly referenced as user

Link to bitbucket branch

https://bitbucket.org/pwFoo/accessbyreference/src/c806dc3c7cec154f84b7f31fb81767603a4009b7/AccessByReference/AccessByReference.module?at=pwFoo

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...