The final piece of the puzzle. The only thing remaining was displaying the list of papers and volumes that a user had access to, instead of all the papers/volumes.
<?php // papers_controller.php function su_index() { $papers = array(); $user_id = $this->Auth->user('id'); $nodes = $this->Acl->Aro->findByForeignKeyAndModel($user_id, 'User'); foreach ($nodes['Aco'] as $node) { if ($node['model'] === 'Paper') { $papers[] = $node['foreign_key']; } // Get children from volumes if ($node['model'] === 'Volume') { $children = $this->Acl->Aco->children($node['id']); foreach ($children as $child) { $papers[] = $child['Aco']['foreign_key']; } } } $conditions = array('Paper.id' => $papers); if ($this->Auth->user('group_id') == 4) { $conditions = null; } $this->set('papers', $this->paginate($conditions)); } ?> The same applies to the volumes controller, but a little simpler as you don't need the hierarchy. There must be an easier way to retrieve a set of Model records given an ARO and a parent ACO, but I couldn't find it. If anyone has any tips/suggestions, let me know. HTH, Aidan On Mar 2, 12:13 am, Aidan Lister <aidanlis...@gmail.com> wrote: > For the archives, this is a step-by-step on how I solved the problem: > > Rather than controllers/Papers/view/n which becomes unwieldy given you > have to create an ACO for each action, I instead created an ACO for > each row in my two models. Thanks to markstory for the suggestion. > > I created the following ACO heirachy: > Papers/<volume id>/<paper id> > > This allowed me to give editors access to a volume, which > automatically gives access to the papers inside. This is the beauty of > ACLs. > > I created the ACO tree like so (using acltool, a custom cake shell > component): > > <?php > // $ cake acltool aco_models > function aco_models() > { > $this->out('Starting models sync'); > $Paper = ClassRegistry::init('Paper'); > $Volume = ClassRegistry::init('Volume'); > > // Create the root node > $root_alias = 'papers'; > $this->Aco->create(); > $this->Aco->save(array('parent_id' => null, 'model' => null, > 'alias' => $root_alias)); > $aco_root = $this->Aco->id; > > // Iterate all the volumes > $volumes = $Volume->findAll(); > foreach ($volumes as $volume) { > // Create a node for the volume > $this->out(sprintf('Created Aco node: %s/%s', $root_alias, > $volume['Volume']['number'])); > $this->Aco->create(); > $row = array('parent_id' => $aco_root, 'foreign_key' => > $volume['Volume']['id'], 'model' => 'Volume', 'alias' => $volume > ['Volume']['number']); > $this->Aco->save($row); > $parent_id = $this->Aco->id; > > // Iterate all the papers > $papers = $Paper->find('all', array('conditions' => array > ('volume_id' => $volume['Volume']['id']), 'recursive' => -1)); > foreach ($papers as $paper) { > // Create a node for the paper > $this->out(sprintf('Created Aco node: %s/%s/%s', > $root_alias, $volume['Volume']['number'], $paper['Paper']['slug'])); > $this->Acl->Aco->create(); > $row = array('parent_id' => $parent_id, 'foreign_key' > => $paper['Paper']['id'], 'model' => 'Paper', 'alias' => $paper > ['Paper']['slug']); > $this->Acl->Aco->save($row); > } > } > } > ?> > > Once all the ACOs are created, I gave access to my editors and authors > like so: > > <?php > // $ cake acltool vol_perms > function vol_perms() > { > // Row level access for volumes > $this->out('Creating row-level permissions for volumes'); > $Volume = ClassRegistry::init('Volume'); > $volumes = $Volume->findAll(); > foreach ($volumes as $vol) { > $this->out(sprintf('- Entering volume number %s', $vol > ['Volume']['number'])); > $Volume->id = $vol['Volume']['id']; > foreach ($vol['User'] as $user) { > $this->out(sprintf('-- Granting access to %s', $user > ['name'])); > $User->id = $user['id']; > $this->Acl->allow($User, $Volume); > } > }} > > ?> > > Next we need to inform our models about our chosen ACO structure: > > <?php > // volume.php > function parentNode() > { > return null; > } > > // paper.php > function parentNode() > { > if (!$this->id && empty($this->data)) { > return null; > } > $data = $this->data; > if (empty($this->data)) { > $data = $this->read(); > } > if (empty($data['Paper']['volume_id'])) { > return null; > } else { > return array('Volume' => array('id' => $data['Paper'] > ['volume_id'])); > } > } > ?> > > Next, in our controllers that we wish to handle the row-level access > we do the following: > > In beforeFilter, we check that they're not an admin, then we apply our > Acl check. This relies on the fact that a) access is blocked to users > by the 'controllers' Aco tree and b) access is granted to editors/ > volumes to this controller by the 'controllers' Aco tree. Both of > these constraints are enforced by Auth (with $this->Auth->authorize = > 'actions'). > > <?php > // Check row-level access > if (isset($this->params['pass'][0]) && $this->Auth->user > ('group_id') < 4) { > $aco = $this->Acl->Aco->findByModelAndForeignKey('Paper', > $this->params['pass'][0]); > $aro = $this->Acl->Aro->findByModelAndForeignKey('User', > $this->Auth->user('id')); > if (!$this->Acl->check($aro['Aro'], $aco['Aco'])) { > $this->Session->setFlash($this->Auth->authError); > $this->redirect(array('su' => true, 'controller' => > 'papers', 'action' => 'index')); > } > } > ?> > > And that's it. If anyone has any improvements or suggestions I'd love > to here them. > > Cheers, > Aidan Lister > > On Mar 1, 4:36 pm, Aidan Lister <aidanlis...@gmail.com> wrote: > > > Hello, > > > I need to do some additional row level ACL access control for two of > > my models. > > > My system has the following groups: admins, editors, authors and > > users. > > > I'm restricting access to my controller actions using the Auth > > component, via $this->Auth->authorize = 'actions'. > > > At the moment, my authors have access to "controllers/Papers/view", I > > need to be able to limit their access to "controllers/Papers/view/n". > > Whether I use a custom query to check access to "n" or an ACL, I don't > > mind, both are feasible so whichever is easier. > > > Similarly, I need to control access to "controllers/Volumes/view/n" > > for editors. > > > Does anyone have any suggestions for achieving this? > > > Thanks, > > Aidan --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "CakePHP" group. To post to this group, send email to cake-php@googlegroups.com To unsubscribe from this group, send email to cake-php+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/cake-php?hl=en -~----------~----~----~----~------~----~------~--~---