Initial code for nested groups
This commit is contained in:
@@ -63,14 +63,43 @@ class Daemon
|
||||
|
||||
$accessChecker = new AccessChecker();
|
||||
|
||||
$slotRepo = $em->getRepository(Slot::class);
|
||||
$groupRepo = $em->getRepository(Group::class);
|
||||
|
||||
$routes = new RouteCollection();
|
||||
$routes->addController(new Http\Controller\SlotsController($em->getRepository(Slot::class), $this->messageBus, $accessChecker));
|
||||
$routes->addController(new Http\Controller\GroupsController($em->getRepository(Group::class), $em->getRepository(Slot::class)));
|
||||
$routes->addController(new Http\Controller\SlotsController($slotRepo, $this->messageBus, $accessChecker));
|
||||
$routes->addController(new Http\Controller\GroupsController($groupRepo, $slotRepo));
|
||||
$routes->addController(new Http\Controller\SchemassController($em->getRepository(Schema::class)));
|
||||
|
||||
$this->server = new HttpServer(
|
||||
new Http\Middleware\LoggingMiddleware($httpLogger ?? $logger),
|
||||
new SecurityMiddleware(...$securityOpts),
|
||||
function (ServerRequestInterface $request, ?callable $next) use ($slotRepo, $groupRepo) {
|
||||
$paths = explode("/", ltrim($request->getUri()->getPath(), "/"));
|
||||
$root = reset($paths);
|
||||
if ($root === 'api') {
|
||||
return $next($request);
|
||||
}
|
||||
$focus = null;
|
||||
while ($key = array_shift($paths)) {
|
||||
if (count($paths) > 0) {
|
||||
// match group name
|
||||
if (!$focus) {
|
||||
$focus = $groupRepo->findOneBy([ 'groupId' => $key ]);
|
||||
} else {
|
||||
$groups = $focus->getGroups();
|
||||
foreach ($groups as $g) {
|
||||
if ($g->getGroupId() == $key) {
|
||||
$focus = $g;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// match slot or group name
|
||||
}
|
||||
}
|
||||
},
|
||||
new RoutingMiddleware($routes),
|
||||
new RequestHandler(),
|
||||
function (ServerRequestInterface $request) {
|
||||
|
||||
@@ -21,6 +21,13 @@ class Group implements IteratorAggregate, JsonSerializable
|
||||
#[ORM\Column(type: 'integer')]
|
||||
private ?int $id = null;
|
||||
|
||||
#[ORM\ManyToOne(targetEntity: Group::class, inversedBy: 'groups')]
|
||||
private ?Group $parent = null;
|
||||
|
||||
#[ORM\OneToMany(targetEntity: Group::class, mappedBy: 'parent')]
|
||||
#[ORM\OrderBy([ 'groupId' => 'asc' ])]
|
||||
private Collection $groups;
|
||||
|
||||
#[ORM\Column(type: 'string', length: 96, unique: true)]
|
||||
private string $groupId;
|
||||
|
||||
@@ -39,6 +46,7 @@ class Group implements IteratorAggregate, JsonSerializable
|
||||
string $name,
|
||||
)
|
||||
{
|
||||
$this->groups = new ArrayCollection();
|
||||
$this->groupId = $groupId;
|
||||
$this->name = $name;
|
||||
$this->slots = new ArrayCollection();
|
||||
@@ -55,6 +63,11 @@ class Group implements IteratorAggregate, JsonSerializable
|
||||
return $this->groupId;
|
||||
}
|
||||
|
||||
public function getParent(): ?Group
|
||||
{
|
||||
return $this->parent;
|
||||
}
|
||||
|
||||
public function getIterator(): Traversable
|
||||
{
|
||||
return new ArrayIterator($this->props);
|
||||
@@ -81,6 +94,8 @@ class Group implements IteratorAggregate, JsonSerializable
|
||||
return [
|
||||
'_id' => $this->id,
|
||||
'_group' => $this->groupId,
|
||||
'_parent' => $this->parent ? $this->parent->getGroupId() : null,
|
||||
'_groups' => array_map(fn($g) => $g->getGroupId(), iterator_to_array($this->groups)),
|
||||
'_name' => $this->name,
|
||||
...$this->props,
|
||||
];
|
||||
|
||||
@@ -56,6 +56,7 @@ class GroupsController extends Controller
|
||||
|
||||
return Response::json([
|
||||
'_group' => $groupObj->getGroupId(),
|
||||
'_parent' => $groupObj->getParent()?->getGroupId(),
|
||||
'_name' => $groupObj->getName(),
|
||||
'_members' => array_map(
|
||||
fn(Slot $slot) => $slot->getSlotId(),
|
||||
|
||||
@@ -62,6 +62,7 @@ class SlotsController extends Controller
|
||||
#[Route(path:"/api/slotdb/v1/slots", methods:["POST"])]
|
||||
public function createSlots(ServerRequestInterface $request)
|
||||
{
|
||||
$acl = $request->getAttribute('acl');
|
||||
|
||||
$data = json_decode($request->getBody());
|
||||
$slots = [];
|
||||
@@ -71,6 +72,9 @@ class SlotsController extends Controller
|
||||
$props = $item->props ?? [];
|
||||
if (!$this->slots->hasSlot($slotId)) {
|
||||
$slot = new Slot($slotId, $slotName);
|
||||
// check access (for 'c'?)
|
||||
if (!$this->accessChecker->checkSlotAccess($slot, $acl, 'c')) continue;
|
||||
// TODO filter properties according to ACL
|
||||
$slot->setProperties($props);
|
||||
$slots[] = $slot;
|
||||
}
|
||||
|
||||
@@ -56,6 +56,26 @@ class AccessChecker
|
||||
return false;
|
||||
}
|
||||
|
||||
public function filterReadableProperties(Slot $slot, array $acl, array $props): array
|
||||
{
|
||||
$filtered = [];
|
||||
foreach ($props as $prop=>$value) {
|
||||
if ($this->checkPropertyAccess($slot, $prop, $acl, 'r'))
|
||||
$filtered[$prop] = $value;
|
||||
}
|
||||
return $filtered;
|
||||
}
|
||||
|
||||
public function filterWritableProperties(Slot $slot, array $acl, array $props): array
|
||||
{
|
||||
$filtered = [];
|
||||
foreach ($props as $prop=>$value) {
|
||||
if ($this->checkPropertyAccess($slot, $prop, $acl, 'w'))
|
||||
$filtered[$prop] = $value;
|
||||
}
|
||||
return $filtered;
|
||||
}
|
||||
|
||||
private function getCompiledMatcher(string $ace): AceMatcher
|
||||
{
|
||||
return $this->aclCache->get($ace, function (CacheItemInterface $item) use ($ace) {
|
||||
|
||||
@@ -34,10 +34,10 @@ class AceMatcher
|
||||
$this->prop = null;
|
||||
}
|
||||
}
|
||||
public function matches(string $slot, string $group, ?string $prop, string $access): bool
|
||||
public function matches(string $slot, ?string $group, ?string $prop, string $access): bool
|
||||
{
|
||||
// printf("match: slot=%s|%s group=%s|%s prop=%s|%s access=%s|%s\n", $slot, $this->slot, $group, $this->group, $prop, $this->prop, $access, $this->perms);
|
||||
if ($this->group && ($this->group != $group)) return false;
|
||||
if ($group && $this->group && ($this->group != $group)) return false;
|
||||
if ($this->slot && (!fnmatch($this->slot, $slot))) return false;
|
||||
if ($prop && $this->prop && (!fnmatch($this->prop, $prop))) return false;
|
||||
for ($n = 0; $n < strlen($access); $n++) {
|
||||
|
||||
Reference in New Issue
Block a user