/** * @dataProvider runProvider */ public function testRun($input, $expected) { $parser = new PermissionParser(); $actual = $parser->run($input); $this->assertEquals($expected, $actual); }
/** * Runs a permission check. Permissions are encoded as strings, where * the ':' character acts as a separator for dynamic parts and * sub-permissions. * Apart from the route-based rules defined in permissions.yml, the * following special cases are available:. * * "overview:$contenttype" - view the overview for the content type. Alias * for "contenttype:$contenttype:view". * "contenttype:$contenttype", * "contenttype:$contenttype:view", * "contenttype:$contenttype:view:$id" - View any item or a particular item * of the specified content type. * "contenttype:$contenttype:edit", * "contenttype:$contenttype:edit:$id" - Edit any item or a particular item * of the specified content type. * "contenttype:$contenttype:create" - Create a new item of the specified * content type. (It doesn't make sense * to provide this permission on a * per-item basis, for obvious reasons) * "contenttype:$contenttype:change-ownership", * "contenttype:$contenttype:change-ownership:$id" - Change the ownership * of the specified content type or item. * Further, permissions can be combined with the special keywords 'and' and * 'or' (case-insensitive), or their symbolic aliases '&' (or '&&') and '|' * (or '||'). To override the default precedence (with 'or' binding tighter * than 'and'), or to make precedence explicit, use parentheses. Ex.: * * "contenttype:$contenttype:edit or contenttype:$contenttype:view" * * @param string $what The desired permission, as elaborated upon above. * @param mixed $user The user to check permissions against. * @param string|array|Content $content Optional: Content object/array or ContentType slug. * If specified, $what is taken to be a relative permission (e.g. 'edit') * rather than an absolute one (e.g. 'contenttype:pages:edit'). * @param integer $contentId Only used if $content is given, to further specifiy the content item. * * @return boolean TRUE if the permission is granted, FALSE if denied. */ public function isAllowed($what, $user, $content = null, $contentId = null) { if (is_array($content)) { $contenttypeSlug = $content['slug']; } elseif ($content instanceof \Bolt\Content) { $contenttypeSlug = $content->contenttype['slug']; } else { $contenttypeSlug = $content; } $this->audit("Checking permission query '{$what}' for user '{$user['username']}' with contenttype '{$contenttypeSlug}' and contentid '{$contentId}'"); // First, let's see if we have the check in the per-request cache. $rqCacheKey = $user['id'] . '//' . $what . '//' . $contenttypeSlug . '//' . $contentId; if (isset($this->rqcache[$rqCacheKey])) { return $this->rqcache[$rqCacheKey]; } $cacheKey = "_permission_rule:{$what}"; if ($this->app['cache']->contains($cacheKey)) { $rule = json_decode($this->app['cache']->fetch($cacheKey), true); } else { $parser = new PermissionParser(); $rule = $parser->run($what); $this->app['cache']->save($cacheKey, json_encode($rule)); } $userRoles = $this->getEffectiveRolesForUser($user); $isAllowed = $this->isAllowedRule($rule, $user, $userRoles, $content, $contenttypeSlug, $contentId); // Cache for the current request $this->rqcache[$rqCacheKey] = $isAllowed; return $isAllowed; }