diff --git a/lib/Alchemy/Phrasea/Application/Helper/JsonBodyAware.php b/lib/Alchemy/Phrasea/Application/Helper/JsonBodyAware.php index 70dbeb78a9..1764bcd659 100644 --- a/lib/Alchemy/Phrasea/Application/Helper/JsonBodyAware.php +++ b/lib/Alchemy/Phrasea/Application/Helper/JsonBodyAware.php @@ -61,8 +61,8 @@ trait JsonBodyAware * @param null|string $schemaUri * @return stdClass */ - public function decodeJsonBody(Request $request, $schemaUri = null) + public function decodeJsonBody(Request $request, $schemaUri = null, $format = JsonBodyHelper::OBJECT) { - return $this->getJsonBodyHelper()->decodeJsonBody($request, $schemaUri); + return $this->getJsonBodyHelper()->decodeJsonBody($request, $schemaUri, $format); } } diff --git a/lib/Alchemy/Phrasea/Controller/Api/V3/V3SubdefsServiceController.php b/lib/Alchemy/Phrasea/Controller/Api/V3/V3SubdefsServiceController.php index 863cff851e..d7d604c9d9 100644 --- a/lib/Alchemy/Phrasea/Controller/Api/V3/V3SubdefsServiceController.php +++ b/lib/Alchemy/Phrasea/Controller/Api/V3/V3SubdefsServiceController.php @@ -9,11 +9,14 @@ use Alchemy\Phrasea\Border\Manager; use Alchemy\Phrasea\Controller\Api\Result; use Alchemy\Phrasea\Controller\Controller; use Alchemy\Phrasea\Filesystem\FilesystemService; +use Alchemy\Phrasea\Helper\JsonBodyHelper; use Alchemy\Phrasea\Media\SubdefGenerator; +use databox_subdef; use Exception; use Guzzle\Http\Client; use Neutron\TemporaryFilesystem\TemporaryFilesystemInterface; use Symfony\Component\HttpFoundation\File\UploadedFile; +use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Translation\TranslatorInterface; @@ -25,27 +28,43 @@ class V3SubdefsServiceController extends Controller use DispatcherAware; + /** + * the internal route "api/v3/subdefs_service_callback" can be used to explore the data sent to service callback + * it will save the received file in logs, and log infos into logs/subdefgenerator.txt + * + * @param Request $request + * @return JsonResponse|Response + */ public function callbackAction_POST(Request $request) { + $logto = realpath(dirname(__FILE__).'/../../../../../../logs') . '/'; + /** @var UploadedFile $file */ $file = $request->files->get('file'); - /** @var string $body json supplemental infos */ - $body = $request->get('body'); + $info = $request->get('file_info'); - file_put_contents(dirname(__FILE__).'/../../../../../../logs/subdefgenerator.txt', sprintf("\n%s [%s] : %s (%s); %s\n", (date('Y-m-d\TH:i:s')), getmypid(), __FILE__, __LINE__, + // save the received file + $src = $file->getRealPath(); + $dst = $logto . $info['filename']; + copy($src, $dst); + + // log + file_put_contents($logto. 'subdefgenerator.txt', sprintf("\n%s [%s] : %s (%s); %s\n", (date('Y-m-d\TH:i:s')), getmypid(), __FILE__, __LINE__, sprintf( - "into callbackAction_POST with\n - file: \"%s\"\n - filesize: %d\n - body: \"%s\"" , + "into callbackAction_POST with\n - file: \"%s\"\n - filesize: %d\n - saved to: \"%s\"\n - payload: %s" , $file->getRealPath(), $file->getSize(), - $body + $dst, + var_export($request->request->all(), true) ) ), FILE_APPEND | LOCK_EX); + // for now the subdef service does not expect any result from the callback + // so this "ret" is for debug only $ret = [ 'message' => "subdef service callback was called", 'file' => $file->getRealPath(), - 'filesize' => $file->getSize(), - 'body' => $body + 'filesize' => $file->getSize() ]; return Result::create($request, $ret)->createResponse(); @@ -62,7 +81,7 @@ class V3SubdefsServiceController extends Controller */ public function indexAction_POST(Request $request) { - $body = $this->decodeJsonBody($request); + $body = $this->decodeJsonBody($request, null, JsonBodyHelper::OBJECT); $dbox_id = $body->databoxId; $databox = $this->app->getApplicationBox()->get_databox($dbox_id); @@ -139,71 +158,96 @@ class V3SubdefsServiceController extends Controller $media = $this->app->getMediaFromUri($sourceFile); - $type = $media->getType(); // 'document', 'audio', 'video', 'image', 'flash', 'map' - $subdefs = $databox->get_subdef_structure()->getSubdefGroup($type); - // $subdef = new \databox_subdef($type, $sxSettings, $this->getTranslator()); + $phrSubdefs = []; // array of phr subdefs by name, will give the list of wanted subdefs (aliased by client) + $allWanted = []; // in case no wanted subdef was passed in body, prepare a full list + $type = $media->getType(); // 'document', 'audio', 'video', 'image', 'flash', 'map' + foreach($databox->get_subdef_structure()->getSubdefGroup($type) as $sd) { + $phrSubdefs[$sd->get_name()] = ['subdef' => $sd, 'destinations' => []]; + $allWanted[$sd->get_name()] = ['source' => $sd->get_name()]; + } + // list wanted subdefs + $wanted = (array)$body->destination->subdefs; + if(empty($wanted)) { + $wanted = $allWanted; // no list of wanted subdefs : send all + } + unset($allWanted); + + // map a list of phr sources to a list of alias (wanted) names + foreach ($wanted as $w => $a) { + $a = (array) $a; + if(!array_key_exists($a['source'], $phrSubdefs)) { + // the source (phr subdef name) is unknown : ignore + continue; + } + $k = $a['source']; + unset($a['source']); + $phrSubdefs[$k]['destinations'][$w] = (array) $a; + } + $guzzle = new Client(); $guzzle->setSslVerification(false); - $postFilenameRoot = $body->destination->filename ?: "subdef"; + $postFilenameRoot = $body->destination->filename ?: "subdef_"; $destPayload = $body->destination->payload ?: []; try { - foreach ($subdefs as $subdef) { - if (is_array($body->destination->subdefs) && !in_array($subdef->get_name(), $body->destination->subdefs)) { - continue; + foreach ($phrSubdefs as $sd) { + /** @var databox_subdef $subdef */ + $subdef = $sd['subdef']; + foreach ($sd['destinations'] as $destName => $destAttr) { + + $postFilename = $postFilenameRoot . $destName; + + $start = microtime(true); + $ext = $this->getFilesystemService()->getExtensionFromSpec($subdef->getSpecs()); + + /** @var string $destFile */ + $destFile = $this->getTmpFilesystem()->createTemporaryFile(null, '_' . $subdef->get_name(), $ext); + + $this->getSubdefGenerator()->generateSubdefFromFile($sourceFile, $subdef, $destFile); + + $duration = microtime(true) - $start; + + $postFilename .= '.' . $ext; + + $data = [ + 'filename' => $postFilename, + 'extension' => $ext, + 'name' => $subdef->get_name(), + 'class' => $subdef->get_class(), + 'filesize' => filesize($destFile), + 'build_duration' => $duration, + ]; + + $start = microtime(true); + + $postFields = array_merge((array)$destPayload, [ + 'file_info' => $data, + ]); + + try { + $guzzle->post($destination_url) + ->addPostFields($postFields) + ->addPostFile('file', $destFile, null, $postFilename) + ->send(); + } + catch (Exception $e) { + throw new Exception(sprintf( + 'Failed to post subdef "%s" file: %s', + $subdef->get_name(), + $e->getMessage() + ), 0, $e); + } + finally { + unlink($destFile); + } + + $data['post_duration'] = microtime(true) - $start; + + $ret['sent'][$subdef->get_name()] = $data; } - - $postFilename = $postFilenameRoot.'_'.$subdef->get_name(); - - $start = microtime(true); - $ext = $this->getFilesystemService()->getExtensionFromSpec($subdef->getSpecs()); - - /** @var string $destFile */ - $destFile = $this->getTmpFilesystem()->createTemporaryFile(null, '_'.$subdef->get_name(), $ext); - - $this->getSubdefGenerator()->generateSubdefFromFile($sourceFile, $subdef, $destFile); - - $duration = microtime(true) - $start; - - $postFilename .= '.'.$ext; - - $data = [ - 'filename' => $postFilename, - 'extension' => $ext, - 'name' => $subdef->get_name(), - 'class' => $subdef->get_class(), - 'filesize' => filesize($destFile), - 'build_duration' => $duration, - ]; - - $start = microtime(true); - - $postFields = array_merge((array)$destPayload, [ - 'file_info' => $data, - ]); - - try { - $guzzle->post($destination_url) - ->addPostFields($postFields) - ->addPostFile('file', $destFile, null, $postFilename) - ->send(); - } catch (Exception $e) { - throw new Exception(sprintf( - 'Failed to post subdef "%s" file: %s', - $subdef->get_name(), - $e->getMessage() - ), 0, $e); - } finally { - unlink($destFile); - } - - $data['post_duration'] = microtime(true) - $start; - - $ret['sent'][$subdef->get_name()] = $data; - } } finally { unlink($sourceFile); diff --git a/lib/Alchemy/Phrasea/Helper/JsonBodyHelper.php b/lib/Alchemy/Phrasea/Helper/JsonBodyHelper.php index 14e6704cf9..bba6d70d4b 100644 --- a/lib/Alchemy/Phrasea/Helper/JsonBodyHelper.php +++ b/lib/Alchemy/Phrasea/Helper/JsonBodyHelper.php @@ -21,6 +21,16 @@ use Webmozart\Json\ValidationFailedException; class JsonBodyHelper { + /** + * Decode a JSON value as PHP object. + */ + const OBJECT = 0; + + /** + * Decode a JSON value as associative array. + */ + const ASSOC_ARRAY = 1; + /** @var JsonValidator */ private $validator; /** @var JsonDecoder */ @@ -60,7 +70,7 @@ class JsonBodyHelper * @param null|string|object $schemaUri * @return mixed */ - public function decodeJsonBody(Request $request, $schemaUri = null) + public function decodeJsonBody(Request $request, $schemaUri = null, $format = self::OBJECT) { if(empty($content = $request->getContent())) { // in case of multipart/form-data (e.g. to upload a file), the only way to send @@ -72,6 +82,7 @@ class JsonBodyHelper $schema = $schemaUri ? $this->retrieveSchema($schemaUri) : null; try { + $this->decoder->setObjectDecoding($format===self::ASSOC_ARRAY ? $this->decoder::ASSOC_ARRAY : $this->decoder::OBJECT); return $this->decoder->decode($content, $schema); } catch (DecodingFailedException $exception) { throw new UnprocessableEntityHttpException('Json request cannot be decoded', $exception); diff --git a/lib/Alchemy/Phrasea/Media/SubdefGenerator.php b/lib/Alchemy/Phrasea/Media/SubdefGenerator.php index b0d93c74db..1828e17643 100644 --- a/lib/Alchemy/Phrasea/Media/SubdefGenerator.php +++ b/lib/Alchemy/Phrasea/Media/SubdefGenerator.php @@ -286,7 +286,7 @@ class SubdefGenerator $this->logger->error(sprintf('Subdef generation failed for record %d with message %s', $record->getRecordId(), $e->getMessage())); } - if($start){ + if($start) { // the subdef was done @@ -422,6 +422,21 @@ class SubdefGenerator $this->logger->error(sprintf('Subdef generation failed with message %s', $e->getMessage())); } + // watermark ? + if($subdef_class->getSpecs() instanceof Image) { + /** @var Subdef\Image $image */ + $image = $subdef_class->getSubdefType(); + /** @var Boolean $wm */ + $wm = $image->getOption(Subdef\Image::OPTION_WATERMARK); + if($wm->getValue()) { + + // we must watermark the file + /** @var Text $wmt */ + $wmt = $image->getOption(Subdef\Image::OPTION_WATERMARKTEXT); + $this->wartermarkImageFile($pathdest, $wmt->getValue()); + } + } + $duration = microtime(true) - $start; $originFileSize = $this->sizeHumanReadable(filesize($pathSrc));