/** * 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); } }
public function testMergesErrors() { $this->response->addError('foo', 'foo_message_one'); $errorStore = new ErrorStore(); $errorStore->addError('foo', 'foo_message_two'); $errorStore->addError('bar', 'bar_message'); $this->response->mergeErrors($errorStore); $this->assertEquals(['foo' => ['foo_message_one', 'foo_message_two'], 'bar' => ['bar_message']], $this->response->getErrors()); }
/** * {@inheritDoc} */ public function validateRequest(Request $request, ErrorStore $errorStore) { $data = $request->getContent(); if (array_key_exists('o:item_set', $data) && !is_array($data['o:item_set'])) { $errorStore->addError('o:item_set', 'Item sets must be an array'); } if (array_key_exists('o:media', $data) && !is_array($data['o:media'])) { $errorStore->addError('o:item_set', 'Media must be an array'); } }
/** * {@inheritDoc} */ public function validateEntity(EntityInterface $entity, ErrorStore $errorStore) { $label = $entity->getLabel(); if (false == trim($label)) { $errorStore->addError('o:label', 'The label cannot be empty.'); } if (!$this->isUnique($entity, ['label' => $label])) { $errorStore->addError('o:label', 'The label is already taken.'); } }
public function isValid(array $data, ErrorStore $errorStore) { if (!isset($data['label'])) { $errorStore->addError('o:navigation', 'Invalid navigation: URL link missing label'); return false; } if (!isset($data['url'])) { $errorStore->addError('o:navigation', 'Invalid navigation: URL link missing URL'); return false; } return true; }
/** * {@inheritDoc} */ public function validateEntity(EntityInterface $entity, ErrorStore $errorStore) { if (false == $entity->getName()) { $errorStore->addError('o:name', 'The name cannot be empty.'); } $email = $entity->getEmail(); $validator = new EmailAddress(); if (!$validator->isValid($email)) { $errorStore->addValidatorMessages('o:email', $validator->getMessages()); } if (!$this->isUnique($entity, ['email' => $email])) { $errorStore->addError('o:email', sprintf('The email "%s" is already taken.', $email)); } if (false == $entity->getRole()) { $errorStore->addError('o:role', 'Users must have a role.'); } }
/** * {@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']); } }
public function isValid(array $data, ErrorStore $errorStore) { if (!isset($data['label'])) { $errorStore->addError('o:navigation', 'Invalid navigation: page link missing label'); return false; } if (!isset($data['id'])) { $errorStore->addError('o:navigation', 'Invalid navigation: page link missing page ID'); return false; } if (!isset($data['pageSlug'])) { $errorStore->addError('o:navigation', 'Invalid navigation: page link missing page slug'); return false; } if (!isset($data['pageTitle'])) { $errorStore->addError('o:navigation', 'Invalid navigation: page link missing page title'); return false; } return true; }
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); } } }
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); } }
/** * Hydrate block data for the page. * * @param array $blockData * @param SitePage $page * @param bool $append */ private function hydrateBlocks(array $blockData, SitePage $page, ErrorStore $errorStore, $append = false) { $blocks = $page->getBlocks(); $existingBlocks = $blocks->toArray(); $newBlocks = []; $position = 1; $fallbackBlock = ['o:layout' => null, 'o:data' => []]; foreach ($blockData as $inputBlock) { if (!is_array($inputBlock)) { continue; } $inputBlock = array_merge($fallbackBlock, $inputBlock); $block = current($existingBlocks); if ($block === false || $append) { $block = new SitePageBlock(); $block->setPage($page); $newBlocks[] = $block; } else { // Null out values as we re-use them $existingBlocks[key($existingBlocks)] = null; next($existingBlocks); } if (!is_string($inputBlock['o:layout']) || $inputBlock['o:layout'] === '') { $errorStore->addError('o:block', 'All blocks must have a layout.'); return; } if (!is_array($inputBlock['o:data'])) { $errorStore->addError('o:block', 'Block data must not be a scalar value.'); return; } $block->setLayout($inputBlock['o:layout']); $block->setData($inputBlock['o:data']); // (Re-)order blocks by their order in the input $block->setPosition($position++); $attachmentData = isset($inputBlock['o:attachment']) ? $inputBlock['o:attachment'] : []; // Hydrate attachments, and abort block hydration if there's an error if (!$this->hydrateAttachments($attachmentData, $block, $errorStore)) { return; } $handler = $this->getServiceLocator()->get('Omeka\\BlockLayoutManager')->get($inputBlock['o:layout'])->onHydrate($block, $errorStore); } // Remove any blocks that weren't reused if (!$append) { foreach ($existingBlocks as $key => $existingBlock) { if ($existingBlock !== null) { $blocks->remove($key); } } } // Add any new blocks that had to be created foreach ($newBlocks as $newBlock) { $blocks->add($newBlock); } }
/** * Add errors derived from an ErrorStore. * * @param ErrorStore $errorStore */ public function addErrorStore(ErrorStore $errorStore) { foreach ($errorStore->getErrors() as $error) { foreach ($error as $message) { $this->addError($message); } } }
/** * {@inheritDoc} */ public function validateEntity(EntityInterface $entity, ErrorStore $errorStore) { // Validate local name if (false == $entity->getLocalName()) { $errorStore->addError('o:local_name', 'The local name cannot be empty.'); } // Validate label if (false == $entity->getLabel()) { $errorStore->addError('o:label', 'The label cannot be empty.'); } // Validate vocabulary if ($entity->getVocabulary() instanceof Vocabulary) { if ($entity->getVocabulary()->getId()) { // Vocabulary is persistent. Check for unique local name. $criteria = ['vocabulary' => $entity->getVocabulary(), 'localName' => $entity->getLocalName()]; if (!$this->isUnique($entity, $criteria)) { $errorStore->addError('o:local_name', sprintf('The local name "%s" is already taken.', $entity->getLocalName())); } } } else { $errorStore->addError('o:vocabulary', 'A vocabulary must be set.'); } }
/** * Make a request and handle any errors that might occur. * * @param string $url URL to request * @param string $type Type of URL (used to compose error messages) * @param ErrorStore $errorStore */ protected function makeRequest($url, $type, ErrorStore $errorStore) { $uri = new HttpUri($url); if (!($uri->isValid() && $uri->isAbsolute())) { $errorStore->addError('o:source', "Invalid {$type} 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; } return $response; }
/** * {@inheritDoc} */ public function validateEntity(EntityInterface $entity, ErrorStore $errorStore) { if (!$entity->getItem() instanceof Item) { $errorStore->addError('o:item', 'Media must belong to an item.'); } }
/** * Validate navigation. * * Prevent corrupt navigation data by validating prior to saving. * * @param EntityInterface $entity * @param ErrorStore $errorStore */ protected function validateNavigation(EntityInterface $entity, ErrorStore $errorStore) { $navigation = $entity->getNavigation(); if (!is_array($navigation)) { $errorStore->addError('o:navigation', 'Invalid navigation: navigation must be an array'); return; } $pagesInNavigation = []; $manager = $this->getServiceLocator()->get('Omeka\\Site\\NavigationLinkManager'); $validateLinks = function ($linksIn) use(&$validateLinks, $manager, $errorStore, $pagesInNavigation) { foreach ($linksIn as $key => $data) { if (!isset($data['type'])) { $errorStore->addError('o:navigation', 'Invalid navigation: link missing type'); return; } if (!isset($data['data'])) { $errorStore->addError('o:navigation', 'Invalid navigation: link missing data'); return; } if (!$manager->get($data['type'])->isValid($data['data'], $errorStore)) { $errorStore->addError('o:navigation', 'Invalid navigation: invalid link data'); return; } if ('page' === $data['type']) { if (in_array($data['data']['id'], $pagesInNavigation)) { $errorStore->addError('o:navigation', 'Invalid navigation: page links must be unique'); return; } $pagesInNavigation[] = $data['data']['id']; } if (isset($data['links'])) { if (!is_array($data['links'])) { $errorStore->addError('o:navigation', 'Invalid navigation: links must be an array'); return; } $validateLinks($data['links']); } } }; $validateLinks($navigation); }
/** * {@inheritDoc} */ public function validateEntity(EntityInterface $entity, ErrorStore $errorStore) { // Validate namespace URI $namespaceUri = $entity->getNamespaceUri(); if (false == $entity->getNamespaceUri()) { $errorStore->addError('o:namespace_uri', 'The namespace URI cannot be empty.'); } if (!$this->isUnique($entity, ['namespaceUri' => $namespaceUri])) { $errorStore->addError('o:namespace_uri', sprintf('The namespace URI "%s" is already taken.', $namespaceUri)); } // Validate prefix $prefix = $entity->getPrefix(); if (false == $entity->getPrefix()) { $errorStore->addError('o:prefix', 'The prefix cannot be empty.'); } if (!$this->isUnique($entity, ['prefix' => $prefix])) { $errorStore->addError('o:prefix', sprintf('The prefix "%s" is already taken.', $prefix)); } // Validate label if (false == $entity->getLabel()) { $errorStore->addError('o:label', 'The label cannot be empty.'); } // Check for uniqueness of resource class local names. $uniqueLocalNames = []; foreach ($entity->getResourceClasses() as $resourceClass) { if (in_array($resourceClass->getLocalName(), $uniqueLocalNames)) { $errorStore->addError('o:resource_class', sprintf('The local name "%s" is already taken.', $resourceClass->getLocalName())); } else { $uniqueLocalNames[] = $resourceClass->getLocalName(); } } // Check for uniqueness of property local names. $uniqueLocalNames = []; foreach ($entity->getProperties() as $property) { if (in_array($property->getLocalName(), $uniqueLocalNames)) { $errorStore->addError('o:resource_class', sprintf('The local name "%s" is already taken.', $property->getLocalName())); } else { $uniqueLocalNames[] = $property->getLocalName(); } } }