Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions application/Module.php
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,8 @@ public function addTermDefinitionsToContext(LaminasEvent $event)
}
$context['o-cnt'] = 'http://www.w3.org/2011/content#';
$context['o-time'] = 'http://www.w3.org/2006/time#';
$context['oa'] = 'http://www.w3.org/ns/oa#';
$context['rdf'] = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
$event->setParam('context', $context);
}

Expand Down
71 changes: 68 additions & 3 deletions application/src/Api/Adapter/ValueAnnotationAdapter.php
Original file line number Diff line number Diff line change
@@ -1,12 +1,21 @@
<?php
namespace Omeka\Api\Adapter;

use Doctrine\ORM\QueryBuilder;
use Omeka\Api\Exception;
use Omeka\Api\Representation\ValueAnnotationRepresentation;
use Omeka\Api\Request;
use Omeka\Entity\ValueAnnotation;

class ValueAnnotationAdapter extends AbstractResourceEntityAdapter
{
protected $sortFields = [
'id' => 'id',
'is_public' => 'isPublic',
'created' => 'created',
'modified' => 'modified',
];

public function getResourceName()
{
return 'value_annotations';
Expand All @@ -22,14 +31,70 @@ public function getEntityClass()
return ValueAnnotation::class;
}

public function search(Request $request)
public function buildQuery(QueryBuilder $qb, array $query)
{
return AbstractAdapter::search($request);
parent::buildQuery($qb, $query);

// The visibility filter only checks the annotation's own public flag, not
// the parent resource's. Join through Value to check both.
$services = $this->getServiceLocator();
$acl = $services->get('Omeka\Acl');
if ($acl->userIsAllowed('Omeka\Entity\Resource', 'view-all')) {
return;
}

$identity = $services->get('Omeka\AuthenticationService')->getIdentity();
$valueAlias = $qb->createAlias();
$parentResourceAlias = $qb->createAlias();

$qb->join(
'Omeka\Entity\Value',
$valueAlias,
'WITH',
$qb->expr()->eq("$valueAlias.valueAnnotation", 'omeka_root')
);
$qb->join("$valueAlias.resource", $parentResourceAlias);

$parentVisibilityExpr = $qb->expr()->eq(
"$parentResourceAlias.isPublic",
$qb->createNamedParameter(true)
);
if ($identity) {
$parentVisibilityExpr = $qb->expr()->orX(
$parentVisibilityExpr,
$qb->expr()->eq(
"$parentResourceAlias.owner",
$qb->createNamedParameter($identity)
)
);
}
$qb->andWhere($parentVisibilityExpr);
}

public function read(Request $request)
{
return AbstractAdapter::read($request);
// The visibility filter doesn't catch a public annotation on a private
// resource, so verify the parent explicitly. Return 404 rather than 403
// to avoid revealing that the resource exists.
$response = parent::read($request);

$acl = $this->getServiceLocator()->get('Omeka\Acl');
if ($acl->userIsAllowed('Omeka\Entity\Resource', 'view-all')) {
return $response;
}

// The ResourceVisibilityFilter applies to lazy-loaded associations, so
// if the parent resource is not visible to this user, getResource() returns null.
$entity = $response->getContent();
if (!$entity->getValue()->getResource()) {
throw new Exception\NotFoundException(sprintf(
$this->getTranslator()->translate('%1$s entity with criteria %2$s not found'),
$this->getEntityClass(),
json_encode(['id' => $entity->getId()])
));
}

return $response;
}

public function create(Request $request)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,33 @@ class ValueAnnotationRepresentation extends AbstractResourceEntityRepresentation
{
public function getResourceJsonLdType()
{
return 'o:ValueAnnotation';
return ['o:ValueAnnotation', 'oa:Annotation'];
}

public function getResourceJsonLd()
{
return [];
$value = $this->annotatedValue();
$valueJson = $value->jsonSerialize();
// Unset @annotation to avoid a circular reference back to this object.
unset($valueJson['@annotation']);
return [
'oa:hasTarget' => [
'@type' => 'rdf:Statement',
'rdf:subject' => $this->resource()->getReference(),
'rdf:predicate' => ['@id' => $value->property()->uri()],
'rdf:object' => $valueJson,
],
];
}

public function annotatedValue()
{
return new ValueRepresentation($this->resource->getValue(), $this->getServiceLocator());
}

public function resource()
{
return $this->getAdapter('resources')->getRepresentation($this->resource->getValue()->getResource());
}

public function displayValues(array $options = [])
Expand Down
10 changes: 10 additions & 0 deletions application/src/Entity/ValueAnnotation.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ class ValueAnnotation extends Resource
*/
protected $id;

/**
* @OneToOne(targetEntity="Value", mappedBy="valueAnnotation")
*/
protected $value;

public function getResourceName()
{
return 'value_annotations';
Expand All @@ -21,4 +26,9 @@ public function getId()
{
return $this->id;
}

public function getValue()
{
return $this->value;
}
}
2 changes: 2 additions & 0 deletions application/src/Service/AclFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,7 @@ protected function addRulesForAllRoles(Acl $acl)
'Omeka\Api\Adapter\AssetAdapter',
'Omeka\Api\Adapter\ApiResourceAdapter',
'Omeka\Api\Adapter\DataTypeAdapter',
'Omeka\Api\Adapter\ValueAnnotationAdapter',
],
[
'search',
Expand All @@ -299,6 +300,7 @@ protected function addRulesForAllRoles(Acl $acl)
'Omeka\Entity\Property',
'Omeka\Entity\ResourceTemplate',
'Omeka\Entity\Asset',
'Omeka\Entity\ValueAnnotation',
],
[
'read',
Expand Down
Loading