Building with XenForo 2 - Part 13 Working with permissions

Show video

i said when we started this series of  videos that i didn't really know where   the add-on was going to go and having looked  at what we still need to cover i am going to   fairly dramatically change the course of what  it's going to be doing because i want to show   various things that involve users interacting so  whereas the current code is essentially a single   user application and it just lets one user post  notes for them for their own purposes i'm going to   change that round so that multiple users can all  post to this one shared space and of course that's   sort of duplicative of the forum itself but  we're only making a demo here so who cares so the   first thing that we could look at doing would be  removing the requirement to be registered so let's   just comment that out for now h so maybe we could  say that guests can view notes that are posted by   anyone but we wouldn't want guests to be able  to post their own notes so we're going to need   to set up permissions the permission system  and the ability for user groups to apply   those permissions to different groups of users  represents a huge part of XenForo's functionality   the ability to control who can do what is at  the heart of an awful lot of the power that is   at your disposal so it's really important when  you're building an add-on to understand what the   permission system can do and how it works and  how to add your own permission system for your   own content so looking here at the user group for  the registered users you can see that we've got   some general permissions and then we've got some  general moderator permissions and some bookmark   permissions and the list goes on and on but we  want to create our own group of permissions for   the purposes of our note system so let's head down  into the development zone and go to permission   definitions and here we can see that we've got  that general permissions list we just looked at   and the general moderator permissions and these  are what we call permission interface groups and   they are a way to group permissions together in  a visual fashion for the purpose of management   so we're going to start off by creating our own  interface group now you'll see that this has a   little one next to it and that represents the  display order so that's going to be displayed   first on the page and then we've got two and then  five but what i want to do just for the purposes   of the demo is i'm going to give it a very small  display order so it appears at the top of the   page but when you're doing your own you should set  something that is a little more sensible so that   it doesn't interject itself right in the middle  of everything else so let's start off with adding   an interface group and i'm going to call this  notes permissions and i'll give it a title of   demo scratch pad note pad permissions because why  not and i'm going to try giving it a display order   of zero just so that it appears at the top it  doesn't contain moderator permissions so that's   fine for me and there it is right at the top which  is very convenient for the purpose of the demo   now let's go ahead and actually get some  permissions in there so we'll because as you   can see it says we don't have any permissions so  we'll add one now the permission group is not the   same as the interface group this is something that  is handled at the permissions level and the groups   are just defined by virtue of being referenced so  i'm just going to call it notes and the permission   id is going to be well let's talk about what  permission we're actually going to implement first   let's assume that all users can view notes  but only some people can view other people's   notes let's let's do that let's let's do both so  let's just have a view own and we'll call it view own notes it doesn't depend on a permission id and  we'll give it a display order of one that's fine   now that will create a permission that the system  behind the scenes there has also created a phrase   so we don't need to worry about language  independence with that and now let's add   another one to go along with that and we'll call  it view any and oh no that's not going that that   should be notes and then that should go in  there view any so this is going to refer to   the ability for a user to view notes that have  been posted by other people so let's call that   view others notes depending on permission id yes  it depends on view own because if you can't view   own then maybe you should only be able to view any  but maybe actually you want some sort of dropbox   system where you can only view other people's  but in this particular case you don't so we'll   say that view any depends on view own and then  the display order well let's associate it with   the next one and just have it a little higher up  so now we've got view own and view others notes now i'm going to carry on and add some more  of those and then we'll come back and actually   use some of these so you can see here i've gone  ahead and added three new permissions for post   new notes edit own notes and delete own notes  but i also want to add a set of permissions   that are essentially moderate permissions that  allow people to modify other people's content   but i'm going to put those into their own  interface group so i'm going to add a new   interface group here and i'm going to call  it notes permissions let's call it notes   moderator permissions and we'll just take that  and add the word moderator in there and i'm   going to add a zero in there to hopefully get  it up with the other group of notes permissions   and then i'm going to say that this group does  contain moderator permissions because it does   hit save and it's added it above but that's fine  for now so i'm going to add in a collection of   permissions for this to act as a sort of counter  to these edit own and delete own notes so let's   start off with edit others notes so it's  still going to be part of the notes group   the permission id is going to be edit others or  let's call it edit any edit others notes and it   depends on permission id no i don't think it  does and we'll give that a display order of 11   and then i'll go ahead and add a delete others as  well in the same way so with those new permissions   set up we need some other data in here so that  we can demonstrate the interaction of self-owned   data and data that's owned by other users so i've  logged a couple of other users into other browsers   so here's another copy of Chrome with Mr Spammer  logged in and two posts added for him and here   is what's that that's Firefox with Trolleta  logged in and two notes added there but we also   need to identify who belongs to each one of these  notes or which which note belongs to which person   so let's come in here and edit the demo_pad_note  template which has got the note macro in it   and then i think i'm just going to put a  username and maybe even an avatar into that   header section there so we can upload this a  bit later but let's just have an <xf:username>   and the username this again is obviously  a bit of XF template syntax magic   which is going to create me a linked  username with various other bits and pieces   the user it's expecting will be the user relation  for the current note because we're currently in   a for each outside of here and we're  passing in the note so it's going to be   $note.User (uppercase 'U') because that's the  name of the relation and then the link is going   to be a link to that user's member profile page  so that's just members and then we pass in the   $note.User as the parameter for that  and what we should expect to see now is   just a link to that user like that so that's  all good now obviously at this point if you   recall the logic the note controller is currently  limiting this to only show data that belongs to   the current visitor so we need to change that  round but before we do that we need to check that   we have permission to view notes at all so let's  do that first so it looks a bit like this if not   the \XF::visitor()->hasPermission and then we need  to say which permission we're checking and if we   go back to the control panel here the permission  we're checking is view own notes so it's notes   view own so the permission group is notes and the  promotion itself is view own and if you do not   have permission to view your own notes then we're  essentially going to say you can't go any further   so we'll return out of that with this and a  special kind of of error called noPermission()   and then normally you'd return a phrase as the  parameter here but we're not doing phrasing   yet we're just throwing a demo together so  we'll just say you can not view notes with a   particular test message there so if i were  to come back here and refresh that page   i'm going to expect to get that error message  and that is of course because we haven't actually   given those permissions to anyone  so let's come back to the groups and   permissions page and go and assign some  permissions to the registered user group   so the registered user group is going to need  to be able to view its own notes and we'll say   that they need to view other notes in a moment but  we'll just tick those three for now and save that   and we'll come back to that in a moment so now we  should get back to roughly where we were before   so the next step is going to be to limit  those who can't view everyone's notes to be   able to only view their own which is a slight  change around from what we've got here but   essentially we want this parameter or this this  where condition to be conditional upon whether   or not they have that permission so let's just  pop that into the clipboard and we'll check it   afterwards because obviously the $noteFinder is  being built up in a sort of chained fashion so   we can we don't have to do everything with it in  that one string we can do it afterwards so let's   check the permission if not \XF::visitor() and  this time it's notes and i believe it was view any   and i have faith that it was but it'll all blow up  if it wasn't if that's not the case then i don't   want to return a no permission error i just want  to constrain the note finder slightly so let's say   note finder and then hopefully my clipboard is  still available there we go so the logic now says   set up the note finder for demo_pad_note  and order it in ascending order   then let's i'm actually going to change that  back to descending order so that the newest stuff   appears on the front page and then if the visitor  doesn't have the view any permission on the notes   group then add an additional constraint to the  note finder to say only show me my own notes   let's take a look and see because right now if you  recall we haven't actually applied that permission   so we shouldn't see any differences at this  point except for the fact that the order will   be reversed so let's go and see the debug  info here and you can see under here   that i've got a query on the notes table here  it is so SELECT demo_pad _note LEFT JOIN xf_user   WHERE the demo_pad_note user_id is one so  that's this is the result of the finder query   so now let's go and apply that  permission to my user group hit save on that and now when i come back here i'll refresh  this rather than going and look at the actually   the azure interface and you can see that that  where clause has disappeared so now it's just   showing me everything from the demo pad note  table with no constraints although obviously   there is a constraint by virtue of it being  split into pages so show me the first eight posts   with no other constraints if i head  back into here and let that refresh   then i should now see the posts from Mr Spammer  and Trolletta which are more recent than   my own so that's the first permission up and  running correctly let's improve the visuals a   little by adding an avatar next to the username  here that's really very straightforward we just   come back to the template and right next to the  where we use the <xf:username> there we'll use   an <xf:avatar> and this time we'll pass the $note  .User again and we'll select a small avatar and   then i happen to know that the pad note header  class is display flex so we should be able to   just wrap the next bit into a single div and  then maybe wrap that one with a div as well and then we'll get something  that looks a little more pleasing   having implemented the view permissions we now  need to go and implement the edit permissions   because as you recall this code was built with  the anticipation that you would have one user   the visitor being able to view and edit their  own notes but with no access to anyone else's   so the code currently was not going to stop  me who's logged in as add this admin user from   editing and saving this notes here so  we need to control that with permissions   now instead of doing all of my permission checks  in the controller like i did for the view action   here i'm actually going to move my permission  checking into the entity and i may even fix that   up in a moment to change things around but why  would i do that well the entity contains all sorts   of information about itself so it makes sense that  it would be the final controlling structure to say   whether or not a particular user or user group  has the ability to do something to it so let's   start off with a quick can edit function so we'll  have a public function called can edit and then   i'm going to pass it by reference a parameter  called error so that i can not only return true   or false for can you edit or can't you but i can  also assign some sort of error code or string   to that variable i've passed by reference and then  the calling code would be able to reference that   so whose permissions are we going to be  checking well we're going to be checking   the visitor so let's assign him to a variable  and then let's do the actual checking so if   the visitor has not vista visit if the visitor  has permission and we're checking the notes   edit own permission this time if the visitor  does not have that permission then the error   string will be you may not edit this note that'll  do and we'll return false but recall this is not   quite correct because this is going to return  false if you can't edit your own note regardless   of who is the owner so we actually need to add  more conditions to this this if here so what   we're actually going to say is if the visit user  id is the same as the user id aside to the entity and you don't have that permission then you get  that error but that's still not the entire story   because we've got another permission for edit  we've got edit any so this time it's going to be   let's reorganize this slightly  we'll take that out and we'll say if you don't have the permission  then through the error and otherwise we'll just fall through and then  we'll have an else condition here and the else   being that the visitor user id is is not the  same as the entity user id and in that case   we'll say if not visitor has permission or notes  to edit any then the error is you may not edit   this note either i guess we'll just standardize  on that for now and we'll return false there and i guess if you've got past all of those  checks then you must be able to edit so   we'll return true so now we can head back to  the controller and just call on canedit and   then throw errors if not so back to the controller  and we'll look into action edit and so the first   thing we'll say is that we'll get the note but  then we'll insert our permission check so if   not note can edit and then we've  got our reference there then return this we're doing no no permissioner can't we  no permission and then we'll pass the error   that we got out of the entity as the option and  we're done now we're also going to need to put   this exact same thing into the action save in  the case that it's an update so that's here   so returning false if we can't  edit the note that we got there   and then i guess we need to do the same sort  of thing for deletion so we'll come back to the   entity note and we'll take the whole of action  oh sorry of can edit and we'll make can delete   and then we just need to say delete own you  may not delete this note notes delete any   you may not delete this note and then we can come  into here and just stick in the check like this so just checking the logic we're going to get the  same bit of code whether or not we're looking for   the confirmation or the actual action to do the  deletion so we're saying if you can delete it then   if you can't delete it then show no permission  either way and this will handle whether you're   trying to delete someone else's or your own  so that's all handled through the entity   i'm back in the entity here and having said  that i might move the permission checks   from the index view from here in the controller  into the entity that actually makes no sense   at all because the entity is concerned  with how to deal with one particular item   and this is all about which ones to fetch so  we don't deal with an entity at that point so   disregard that that was nonsense that said i have  implemented a can view action in the entity which   allows the controller to quickly check whether or  not you should be able to view one particular item   there's just one final permission to implement  from the selection that we built earlier   and that is the permission to create new notes  so we're just going to do this in the controller   because at this point we don't have the ability  to query a particular entity we're just creating   a skeleton here so we'll do a standard permission  check if not the \XF::visitor()->hasPermission   for notes i think we called it post but let's  just go and check notes post yeah that's the   one if you don't have the notes post permission  then return this no permission you may not post new notes and then we'll do the same in the first  part of the action save where we're looking to   actually do the savings so this is the  editing action and this is the creation   action so if you can't do that then oh what  happened there let's come back and have that let's have that let we could actually put  it before we even create the entity here   so let's do the same in the save action so if you don't have the post permission then  don't even get to that point so now that we've   actually made use of those permissions we need to  prepare for exporting our add-on and to make sure   that we don't run into that issue we found earlier  on where we've implemented the permissions but we   haven't actually awarded them to any user groups  and in order to do that we're going to have to   add some code to our setup script so these  are the permissions that we need to set up   and we need to make a note of all of those and  then go to the setup script and award them to   the appropriate user groups as part of the setup  process for this add-on so let's just move that   out of the way so that we can keep a reference  there and then bring up our setup.php and let's   add a new public function to be installStep2(),  no parameters required and then we're going to use   a function called applyGlobalPermission() it  looks like this this applyGlobalPermission   and you can see that it's suggested for  me there and what do we want to apply well   the first argument is the apply group id now   all of the permissions that we were working on  just now were set to the permission group of   notes and then let's go through them  one by one let's start off with view own and then let's have it depend upon the user group  that we're targeting having some other permission   i think a reasonable permission to base this  off would be the ability to view the forum   at all so let's scroll up to the top and we  can see that that is general view so let's   add that we are looking for just to remind  ourselves first of all the group we depend   on and then the permission id so it's going to be  general and view so what this will do is any group   that has permission to view the forum as defined  by the view permission in the general group   will be awarded the view owned permission in the  notes group so let's go ahead and do the rest for   these other permissions let's just close that  up so we've got some room here and we want   view others notes post new notes edit  notes and delete own so i'm just going to   duplicate that a bunch of times view any post edit  own and delete own so now just need to find out   which permissions to build those from so i  think view any is going to be something like   general permissions or forum permissions view of  threads by others so let's do forum view others   on that one and then post new let's post new  thread so that's forum and post thread edit own   edit own post a forum edit and post  and delete own we can have that as   forum delete and post then we can go through and  do the same for the moderator permissions here and   boast those off groups that also have those  moderator permissions and essentially that's   our work done once we export this plugin anytime  the install script is run then these permissions   will be applied to any group that matches the  criteria we've set up and you're good to go

2021-05-25

Show video