/** * Ingest from a URL. * * Accepts the following non-prefixed keys: * * + ingest_url: (required) The URL to ingest. The idea is that some URLs * contain sensitive data that should not be saved to the database, such * as private keys. To preserve the URL, remove sensitive data from the * URL and set it to o:source. * + store_original: (optional, default true) Whether to store an original * file. This is helpful when you want the media to have thumbnails but do * not need the original file. * * {@inheritDoc} */ public function ingest(Media $media, Request $request, ErrorStore $errorStore) { $data = $request->getContent(); if (!isset($data['ingest_url'])) { $errorStore->addError('error', 'No ingest URL specified'); return; } $uri = new HttpUri($data['ingest_url']); if (!($uri->isValid() && $uri->isAbsolute())) { $errorStore->addError('ingest_url', 'Invalid ingest URL'); return; } $file = $this->getServiceLocator()->get('Omeka\\File'); $file->setSourceName($uri->getPath()); $this->downloadFile($uri, $file->getTempPath()); $fileManager = $this->getServiceLocator()->get('Omeka\\File\\Manager'); $hasThumbnails = $fileManager->storeThumbnails($file); $media->setHasThumbnails($hasThumbnails); if (!isset($data['store_original']) || $data['store_original']) { $fileManager->storeOriginal($file); $media->setHasOriginal(true); } $media->setFilename($file->getStorageName()); $media->setMediaType($file->getMediaType()); if (!array_key_exists('o:source', $data)) { $media->setSource($uri); } }
/** * {@inheritDoc} */ public function read(Request $request) { $manager = $this->getServiceLocator()->get('Omeka\\ModuleManager'); $response = new Response(); $representation = $this->getRepresentation($manager->getModule($request->getId())); $response->setContent($representation); return $response; }
public function update(Media $media, Request $request, ErrorStore $errorStore) { $data = $request->getContent(); $html = $data['o:media']['__index__']['html']; $serviceLocator = $this->getServiceLocator(); $purifier = $serviceLocator->get('Omeka\\HtmlPurifier'); $html = $purifier->purify($html); $media->setData(['html' => $html]); }
public function ingest(Media $media, Request $request, ErrorStore $errorStore) { $data = $request->getContent(); if (!isset($data['o:source'])) { $errorStore->addError('o:source', 'No OEmbed URL specified'); return; } $config = $this->getServiceLocator()->get('Config'); $whitelist = $config['oembed']['whitelist']; $whitelisted = false; foreach ($whitelist as $regex) { if (preg_match($regex, $data['o:source']) === 1) { $whitelisted = true; break; } } if (!$whitelisted) { $errorStore->addError('o:source', 'Invalid OEmbed URL'); return; } $source = $data['o:source']; $response = $this->makeRequest($source, 'OEmbed URL', $errorStore); if (!$response) { return; } $document = $response->getBody(); $dom = new Query($document); $oEmbedLinks = $dom->queryXpath('//link[@rel="alternate" or @rel="alternative"][@type="application/json+oembed"]'); if (!count($oEmbedLinks)) { $errorStore->addError('o:source', 'No OEmbed links were found at the given URI'); return; } $oEmbedLink = $oEmbedLinks[0]; $linkResponse = $this->makeRequest($oEmbedLink->getAttribute('href'), 'OEmbed link URL', $errorStore); if (!$linkResponse) { return; } $mediaData = json_decode($linkResponse->getBody(), true); if (!$mediaData) { $errorStore->addError('o:source', 'Error decoding OEmbed JSON'); return; } if (isset($mediaData['thumbnail_url'])) { $fileManager = $this->getServiceLocator()->get('Omeka\\File\\Manager'); $file = $this->getServiceLocator()->get('Omeka\\File'); $this->downloadFile($mediaData['thumbnail_url'], $file->getTempPath()); $hasThumbnails = $fileManager->storeThumbnails($file); if ($hasThumbnails) { $media->setFilename($file->getStorageName()); $media->setHasThumbnails(true); } } $media->setData($mediaData); $media->setSource($source); }
public function ingest(Media $media, Request $request, ErrorStore $errorStore) { $data = $request->getContent(); if (!isset($data['o:source'])) { $errorStore->addError('o:source', 'No IIIF Image URL specified'); return; } $source = $data['o:source']; //Make a request and handle any errors that might occur. $uri = new HttpUri($source); if (!($uri->isValid() && $uri->isAbsolute())) { $errorStore->addError('o:source', "Invalid url specified"); return false; } $client = $this->getServiceLocator()->get('Omeka\\HttpClient'); $client->setUri($uri); $response = $client->send(); if (!$response->isOk()) { $errorStore->addError('o:source', sprintf("Error reading %s: %s (%s)", $type, $response->getReasonPhrase(), $response->getStatusCode())); return false; } $IIIFData = json_decode($response->getBody(), true); if (!$IIIFData) { $errorStore->addError('o:source', 'Error decoding IIIF JSON'); return; } //Check if valid IIIF data if ($this->validate($IIIFData)) { $media->setData($IIIFData); // Not IIIF } else { $errorStore->addError('o:source', 'URL does not link to IIIF JSON'); return; } //Check API version and generate a thumbnail //Version 2.0 if (isset($IIIFData['@context']) && $IIIFData['@context'] == 'http://iiif.io/api/image/2/context.json') { $URLString = '/full/full/0/default.jpg'; // Earlier versions } else { $URLString = '/full/full/0/native.jpg'; } if (isset($IIIFData['@id'])) { $fileManager = $this->getServiceLocator()->get('Omeka\\File\\Manager'); $file = $this->getServiceLocator()->get('Omeka\\File'); $this->downloadFile($IIIFData['@id'] . $URLString, $file->getTempPath()); $hasThumbnails = $fileManager->storeThumbnails($file); if ($hasThumbnails) { $media->setFilename($file->getStorageName()); $media->setHasThumbnails(true); } } }
/** * {@inheritDoc} */ public function hydrate(Request $request, EntityInterface $entity, ErrorStore $errorStore) { $data = $request->getContent(); $this->hydrateOwner($request, $entity); if ($this->shouldHydrate($request, 'o:local_name')) { $entity->setLocalName($request->getValue('o:local_name')); } if ($this->shouldHydrate($request, 'o:label')) { $entity->setLabel($request->getValue('o:label')); } if ($this->shouldHydrate($request, 'o:comment')) { $entity->setComment($request->getValue('o:comment')); } }
/** * {@inheritDoc} */ public function hydrate(Request $request, EntityInterface $entity, ErrorStore $errorStore) { $data = $request->getContent(); if (Request::CREATE === $request->getOperation() && isset($data['o:site']['o:id'])) { $site = $this->getAdapter('sites')->findEntity($data['o:site']['o:id']); $this->authorize($site, 'add-page'); $entity->setSite($site); } if ($this->shouldHydrate($request, 'o:slug')) { $entity->setSlug($request->getValue('o:slug')); } if ($this->shouldHydrate($request, 'o:title')) { $entity->setTitle($request->getValue('o:title')); } $appendBlocks = $request->getOperation() === Request::UPDATE && $request->isPartial(); $this->hydrateBlocks($request->getValue('o:block', []), $entity, $errorStore, $appendBlocks); }
/** * {@inheritDoc} */ public function hydrate(Request $request, EntityInterface $entity, ErrorStore $errorStore) { $data = $request->getContent(); if ($this->shouldHydrate($request, 'o:is_public')) { $entity->setIsPublic($request->getValue('o:is_public', true)); } // Hydrate this resource's values. $append = $request->getOperation() === Request::UPDATE && $request->isPartial(); $valueHydrator = new ValueHydrator($this); $valueHydrator->hydrate($data, $entity, $append); // o:owner $this->hydrateOwner($request, $entity); // o:resource_class $this->hydrateResourceClass($request, $entity); // o:resource_template $this->hydrateResourceTemplate($request, $entity); }
public function ingest(Media $media, Request $request, ErrorStore $errorStore) { $data = $request->getContent(); if (!isset($data['o:source'])) { $errorStore->addError('o:source', 'No YouTube URL specified'); return; } $uri = new HttpUri($data['o:source']); if (!($uri->isValid() && $uri->isAbsolute())) { $errorStore->addError('o:source', 'Invalid YouTube URL specified'); return; } switch ($uri->getHost()) { case 'www.youtube.com': if ('/watch' !== $uri->getPath()) { $errorStore->addError('o:source', 'Invalid YouTube URL specified, missing "/watch" path'); return; } $query = $uri->getQueryAsArray(); if (!isset($query['v'])) { $errorStore->addError('o:source', 'Invalid YouTube URL specified, missing "v" parameter'); return; } $youtubeId = $query['v']; break; case 'youtu.be': $youtubeId = substr($uri->getPath(), 1); break; default: $errorStore->addError('o:source', 'Invalid YouTube URL specified, not a YouTube URL'); return; } $fileManager = $this->getServiceLocator()->get('Omeka\\File\\Manager'); $file = $this->getServiceLocator()->get('Omeka\\File'); $url = sprintf('http://img.youtube.com/vi/%s/0.jpg', $youtubeId); $this->downloadFile($url, $file->getTempPath()); $hasThumbnails = $fileManager->storeThumbnails($file); $media->setData(['id' => $youtubeId, 'start' => $request->getValue('start'), 'end' => $request->getValue('end')]); if ($hasThumbnails) { $media->setFilename($file->getStorageName()); $media->setHasThumbnails(true); } }
/** * {@inheritDoc} */ public function ingest(Media $media, Request $request, ErrorStore $errorStore) { $data = $request->getContent(); $fileData = $request->getFileData(); if (!isset($fileData['file'])) { $errorStore->addError('error', 'No files were uploaded'); return; } if (!isset($data['file_index'])) { $errorStore->addError('error', 'No file index was specified'); return; } $index = $data['file_index']; if (!isset($fileData['file'][$index])) { $errorStore->addError('error', 'No file uploaded for the specified index'); return; } $fileManager = $this->getServiceLocator()->get('Omeka\\File\\Manager'); $file = $this->getServiceLocator()->get('Omeka\\File'); $fileInput = new FileInput('file'); $fileInput->getFilterChain()->attach(new RenameUpload(['target' => $file->getTempPath(), 'overwrite' => true])); $fileData = $fileData['file'][$index]; $fileInput->setValue($fileData); if (!$fileInput->isValid()) { foreach ($fileInput->getMessages() as $message) { $errorStore->addError('upload', $message); } return; } // Actually process and move the upload $fileInput->getValue(); $file->setSourceName($fileData['name']); $hasThumbnails = $fileManager->storeThumbnails($file); $fileManager->storeOriginal($file); $media->setFilename($file->getStorageName()); $media->setMediaType($file->getMediaType()); $media->setHasThumbnails($hasThumbnails); $media->setHasOriginal(true); if (!array_key_exists('o:source', $data)) { $media->setSource($fileData['name']); } }
/** * {@inheritDoc} */ public function hydrate(Request $request, EntityInterface $entity, ErrorStore $errorStore) { $data = $request->getContent(); if (Request::CREATE === $request->getOperation()) { // Accept the passed ingester only on CREATE to prevent overwriting // on subsequent UPDATE requests. $ingesterName = $request->getValue('o:ingester'); } else { $ingesterName = $entity->getIngester(); } $ingester = $this->getServiceLocator()->get('Omeka\\MediaIngesterManager')->get($ingesterName); if (Request::CREATE === $request->getOperation()) { if ($ingester instanceof Fallback) { $errorStore->addError('o:ingester', 'Media must set a valid ingester.'); return; } $entity->setIngester($ingesterName); $entity->setRenderer($ingester->getRenderer()); if (isset($data['o:item']['o:id'])) { $item = $this->getAdapter('items')->findEntity($data['o:item']['o:id']); $entity->setItem($item); } if (isset($data['data'])) { $entity->setData($data['data']); } if (isset($data['o:source'])) { $entity->setSource($data['o:source']); } } parent::hydrate($request, $entity, $errorStore); if ($this->shouldHydrate($request, 'o:lang')) { $entity->setLang($request->getValue('o:lang', null)); } if (Request::CREATE === $request->getOperation()) { $ingester->ingest($entity, $request, $errorStore); } elseif ($ingester instanceof MutableIngesterInterface) { $ingester->update($entity, $request, $errorStore); } }
public function testConstructorSetsProperties() { $request = new Request('search', 'foo'); $this->assertEquals('search', $request->getOperation()); $this->assertEquals('foo', $request->getResource()); }
/** * {@inheritDoc} */ public function hydrate(Request $request, EntityInterface $entity, ErrorStore $errorStore) { parent::hydrate($request, $entity, $errorStore); if ($this->shouldHydrate($request, 'o:item_set')) { $itemSetsData = $request->getValue('o:item_set', []); $itemSetAdapter = $this->getAdapter('item_sets'); $itemSets = $entity->getItemSets(); $itemSetsToRetain = []; foreach ($itemSetsData as $itemSetData) { if (is_array($itemSetData) && array_key_exists('o:id', $itemSetData) && is_numeric($itemSetData['o:id'])) { $itemSetId = $itemSetData['o:id']; } elseif (is_numeric($itemSetData)) { $itemSetId = $itemSetData; } else { continue; } if (!($itemSet = $itemSets->get($itemSetId))) { // Item set not already assigned. Assign it. $itemSet = $itemSetAdapter->findEntity($itemSetId); $itemSets->add($itemSet); } $itemSetsToRetain[] = $itemSet; } // Unassign item sets that were not included in the passed data. foreach ($itemSets as $itemSet) { if (!in_array($itemSet, $itemSetsToRetain)) { $itemSets->removeElement($itemSet); } } } if ($this->shouldHydrate($request, 'o:media')) { $mediasData = $request->getValue('o:media', []); $adapter = $this->getAdapter('media'); $class = $adapter->getEntityClass(); $retainMedia = []; $position = 1; foreach ($mediasData as $mediaData) { $subErrorStore = new ErrorStore(); if (isset($mediaData['o:id'])) { $media = $adapter->findEntity($mediaData['o:id']); $media->setPosition($position); if (isset($mediaData['o:is_public'])) { $media->setIsPublic($mediaData['o:is_public']); } $retainMedia[] = $media; } else { // Create a new media. $media = new $class(); $media->setItem($entity); $media->setPosition($position); $subrequest = new Request(Request::CREATE, 'media'); $subrequest->setContent($mediaData); $subrequest->setFileData($request->getFileData()); try { $adapter->hydrateEntity($subrequest, $media, $subErrorStore); } catch (Exception\ValidationException $e) { $errorStore->mergeErrors($e->getErrorStore(), 'o:media'); } $entity->getMedia()->add($media); $retainMedia[] = $media; } $position++; } // Remove media not included in request. foreach ($entity->getMedia() as $media) { if (!in_array($media, $retainMedia, true)) { $entity->getMedia()->removeElement($media); } } } }
/** * Hydrate the entity's resource template. * * Assumes the resource template can be set to NULL. * * @param Request $request * @param EntityInterface $entity */ public function hydrateResourceTemplate(Request $request, EntityInterface $entity) { $data = $request->getContent(); $resourceTemplate = $entity->getResourceTemplate(); if ($this->shouldHydrate($request, 'o:resource_template')) { if (isset($data['o:resource_template']['o:id']) && is_numeric($data['o:resource_template']['o:id'])) { $resourceTemplate = $this->getAdapter('resource_templates')->findEntity($data['o:resource_template']['o:id']); } else { $resourceTemplate = null; } } $entity->setResourceTemplate($resourceTemplate); }
/** * Execute a batch create operation. * * @param Request $request * @param null|AdapterInterface $adapter Custom adapter * @return Response */ protected function executeBatchCreate(Request $request, AdapterInterface $adapter) { $t = $this->getTranslator(); if (!is_array($request->getContent())) { throw new Exception\BadRequestException($t->translate('Invalid batch operation request data.')); } // Create a simulated request for individual create events. $createRequest = new Request(Request::CREATE, $request->getResource()); // Trigger the create.pre event for every resource. foreach ($request->getContent() as $content) { $createRequest->setContent($content); $createEvent = new Event(Event::API_CREATE_PRE, $adapter, ['request' => $createRequest]); $adapter->getEventManager()->trigger($createEvent); } $response = $adapter->batchCreate($request); // Do not trigger create.post events if an error has occured or if the // response does not return valid content. if ($response->isError() || !is_array($response->getContent())) { return $response; } // Trigger the create.post event for every created resource. foreach ($response->getContent() as $resource) { $createRequest->setContent($resource); $createEvent = new Event(Event::API_CREATE_POST, $adapter, ['request' => $createRequest, 'response' => new Response($resource)]); $adapter->getEventManager()->trigger($createEvent); } return $response; }
/** * {@inheritDoc} */ public function hydrate(Request $request, EntityInterface $entity, ErrorStore $errorStore) { $data = $request->getContent(); $this->hydrateOwner($request, $entity); $this->hydrateResourceClass($request, $entity); if ($this->shouldHydrate($request, 'o:label')) { $entity->setLabel($request->getValue('o:label')); } if ($this->shouldHydrate($request, 'o:resource_template_property') && isset($data['o:resource_template_property']) && is_array($data['o:resource_template_property'])) { // Get a resource template property by property ID. $getResTemProp = function ($propertyId, $resTemProps) { foreach ($resTemProps as $resTemProp) { if ($propertyId == $resTemProp->getProperty()->getId()) { return $resTemProp; } } return null; }; $propertyAdapter = $this->getAdapter('properties'); $resTemProps = $entity->getResourceTemplateProperties(); $resTemPropsToRetain = []; $position = 1; foreach ($data['o:resource_template_property'] as $resTemPropData) { if (!isset($resTemPropData['o:property']['o:id'])) { continue; // skip when no property ID } $propertyId = $resTemPropData['o:property']['o:id']; $altLabel = null; if (isset($resTemPropData['o:alternate_label']) && '' !== trim($resTemPropData['o:alternate_label'])) { $altLabel = $resTemPropData['o:alternate_label']; } $altComment = null; if (isset($resTemPropData['o:alternate_comment']) && '' !== trim($resTemPropData['o:alternate_comment'])) { $altComment = $resTemPropData['o:alternate_comment']; } // Check whether a passed property is already assigned to this // resource template. $resTemProp = $getResTemProp($propertyId, $resTemProps); if ($resTemProp) { // It is already assigned. Modify the existing entity. $resTemProp->setAlternateLabel($altLabel); $resTemProp->setAlternateComment($altComment); } else { // It is not assigned. Add a new resource template property. // No need to explicitly add it to the collection since it // is added implicitly when setting the resource template. $property = $propertyAdapter->findEntity($propertyId); $resTemProp = new ResourceTemplateProperty(); $resTemProp->setResourceTemplate($entity); $resTemProp->setProperty($property); $resTemProp->setAlternateLabel($altLabel); $resTemProp->setAlternateComment($altComment); $entity->getResourceTemplateProperties()->add($resTemProp); } // Set the position of the property to its intrinsic order // within the passed array. $resTemProp->setPosition($position++); $resTemPropsToRetain[] = $resTemProp; } // Remove resource template properties that were not included in the // passed data. foreach ($resTemProps as $resTemPropId => $resTemProp) { if (!in_array($resTemProp, $resTemPropsToRetain)) { $resTemProps->remove($resTemPropId); } } } }
/** * {@inheritDoc} */ public function hydrate(Request $request, EntityInterface $entity, ErrorStore $errorStore) { $this->hydrateOwner($request, $entity); if ($this->shouldHydrate($request, 'o:namespace_uri')) { $entity->setNamespaceUri($request->getValue('o:namespace_uri')); } if ($this->shouldHydrate($request, 'o:prefix')) { $entity->setPrefix($request->getValue('o:prefix')); } if ($this->shouldHydrate($request, 'o:label')) { $entity->setLabel($request->getValue('o:label')); } if ($this->shouldHydrate($request, 'o:comment')) { $entity->setComment($request->getValue('o:comment')); } if ($this->shouldHydrate($request, 'o:class')) { $classesData = $request->getValue('o:class', []); $adapter = $this->getAdapter('resource_classes'); $class = $adapter->getEntityClass(); $retainResourceClasses = []; $retainResourceClassIds = []; foreach ($classesData as $classData) { if (isset($classData['o:id'])) { // Do not update existing resource classes. $retainResourceClassIds[] = $classData['o:id']; } else { // Create a new resource class. $resourceClass = new $class(); $resourceClass->setVocabulary($entity); $subrequest = new Request(Request::CREATE, 'resource_classes'); $subrequest->setContent($classData); $adapter->hydrateEntity($subrequest, $resourceClass, $errorStore); $entity->getResourceClasses()->add($resourceClass); $retainResourceClasses[] = $resourceClass; } } // Remove resource classes not included in request. foreach ($entity->getResourceClasses() as $resourceClass) { if (!in_array($resourceClass, $retainResourceClasses, true) && !in_array($resourceClass->getId(), $retainResourceClassIds)) { $entity->getResourceClasses()->removeElement($resourceClass); } } } if ($this->shouldHydrate($request, 'o:property')) { $propertiesData = $request->getValue('o:property', []); $adapter = $this->getAdapter('properties'); $class = $adapter->getEntityClass(); $retainProperties = []; $retainPropertyIds = []; foreach ($propertiesData as $propertyData) { if (isset($propertyData['o:id'])) { // Do not update existing properties. $retainPropertyIds[] = $propertyData['o:id']; } else { // Create a new property. $property = new $class(); $property->setVocabulary($entity); $subrequest = new Request(Request::CREATE, 'properties'); $subrequest->setContent($propertyData); $adapter->hydrateEntity($subrequest, $property, $errorStore); $entity->getProperties()->add($property); $retainProperties[] = $property; } } // Remove resource classes not included in request. foreach ($entity->getProperties() as $property) { if (!in_array($property, $retainProperties, true) && !in_array($property->getId(), $retainPropertyIds)) { $entity->getProperties()->removeElement($property); } } } }