The Frayed Ends of Sanity Posted March 16, 2018 Share Posted March 16, 2018 Hi everyone. I was wondering if the intelligent people on the forum could help me check over a piece of code related to access options. It's based on the template access options, but I need more access options than view/edit etc so I decided to create this so please don't laugh too hard. First of all, this will all be related to the front-end. I plan on restricting the PW admin area to the superuser only so normal users will be unable to change these settings. Basically I have Page Reference fields attached to certain templates. The Page Reference fields are defined as checkboxes and are linked to user roles. As an example, one of the fields could be called content_pinned. I could then create a new page using the template with that field attached and then my method would determine if a member is allowed to pin a topic for example via the front-end. Other Page Reference fields can be added to the templates at any time, for example content_delete, content_comment. My method would then check these permissions for the desired output. Examples of calling the method.... $deleteCheck = permissionCheck($page, "delete"); if($deleteCheck === false) { // The user can't delete this content, so maybe we could display a disabled delete button } else { // The user has a role that is allowed to delete this content so we can now add a delete button and some code to // allow them to delete it.... } OR $commentCheck = permissionCheck($page, "comment"); if($commentCheck === false) { // The user can't comment on this content, so display a message telling them how useless they are ;) } else { // The user has a role that is allowed to comment on this content so we can now add a shiny new editor for them // to use } Below is the method I came up with. It seems to work well, but I'm just a tad worried I have left in a loophole or something stupid. Also, it's worth noting that this method is designed to check parent pages etc for permissions as well. This will allow me to create categories. If the parent category doesn't allow the user to do something but the current page does, it should take this into account and still disallow the action. This allows me to disable certain permissions at a category level. function permissionCheck($content, $type) { $user = wire('user'); switch ($type) { case "view": $fieldName="content_view"; break; case "comment": $fieldName="content_comment"; break; case "post": $fieldName="content_post"; break; case "delete": $fieldName="content_delete"; break; case "pinned": $fieldName="content_pinned"; break; } // Check if the $content page has the $fieldName field. If it does, check that the user's role // is selected - if not, return false if($content->hasField($fieldName)) { if(!$content->$fieldName->has('id=' . $user->roles)) { return false; } } // Get all the parents for the $content page $contentParents = $content->parents(); foreach($contentParents as $contentParent) { // Find out how many parent pages have the $fieldName field if($contentParent->hasField($fieldName)) { // If the parent page has the field, check it has the user's role selected $rolesField = $contentParent->$fieldName; if(!$rolesField->has("id=" . $user->roles)) { return false; } } } return true; } Thanks for your time. Link to comment Share on other sites More sharing options...
Robin S Posted March 17, 2018 Share Posted March 17, 2018 21 hours ago, The Frayed Ends of Sanity said: Below is the method I came up with. It seems to work well, but I'm just a tad worried I have left in a loophole or something stupid. If it's working for your purposes then I think it's fine to do it the way you are. My suggestion is that you have the function return false by default rather than true, and reverse the logic in the conditionals. In general, when permissions are involved I'd say it's best practise that the default state be that the user can do nothing, and then you actively add permissions as needed. This post did get me thinking about if you could use the core permissions system for your needs. I found that when creating a new custom permission, if you prefix the permission name with "page-" then it gets some special features: namely that you can activate that permission for a role individually for each template. So that sounds promising for your needs, but I found that the downside is that the user must have the "page-edit" permission in order for the individual template activation to work. So that probably rules the option out because it's likely that you would want these permissions to be usable on roles that aren't allowed to edit pages. Maybe someone can shed some light on how "page-" prefixed permissions work. Are they mentioned anywhere in the docs or a blog post? Is there any other way to assign permissions on a per-template basis besides making them "page-" permissions? And do folks think it would be worth opening a request for per-template permissions that don't require the page-edit permission? 2 Link to comment Share on other sites More sharing options...
The Frayed Ends of Sanity Posted March 17, 2018 Author Share Posted March 17, 2018 Thanks a lot for the feedback @Robin S Of course you are totally right about returning false by default, that was bad practice on my part. Providing I haven't missed something silly then I guess my code is good? I'm not sure about how efficient it is, but I doubt it would cause too many issues? The other suggestion you made seems good, but for this project I need to limit all permission in the PW admin. Thanks again 1 Link to comment Share on other sites More sharing options...
The Frayed Ends of Sanity Posted March 31, 2018 Author Share Posted March 31, 2018 Just an update to my code. After looking through the forum for a few hours I changed it to the following which I hope is more efficient. function permissionCheck($content, $type) { $user = wire('user'); $fields = wire('fields'); switch ($type) { case "view": $fieldName="content_view"; break; case "comment": $fieldName="content_comment"; break; case "post": $fieldName="content_post"; break; case "delete": $fieldName="content_delete"; break; case "pinned": $fieldName="content_pinned"; break; } // Find only the parent pages that have the $fieldName attached to their template $templateWithField = $fields->get($fieldName)->getFieldgroups()->implode('|', 'name'); $pagesWithField = $content->parents("template=$templateWithField"); // Check the current $content page also, if it has the $fieldName, append it to the $pagesWithField array. if($content->hasField($fieldName)) $pagesWithField = $pagesWithField->append($content); // If the $pagesWithField array contains pages, check for the $user roles within the $fieldName if($pagesWithField->count > 0) { $i = 0; foreach ($pagesWithField as $item) { if($item->hasField($fieldName)) { if($item->$fieldName->has('id=' . $user->roles)) { $i++; } } } // Only return true if the $user has a role for all the pages within the $pagesWithField array if($pagesWithField->count == $i) return true; } return false; } 1 Link to comment Share on other sites More sharing options...
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now