mirror of
https://github.com/alchemy-fr/Phraseanet.git
synced 2025-10-18 07:23:13 +00:00
Merge branch 'master' into PHRAS-1378_es-max-result-window_MASTER
This commit is contained in:
@@ -5,6 +5,8 @@ namespace Alchemy\Phrasea\Application;
|
||||
use Alchemy\EmbedProvider\EmbedServiceProvider;
|
||||
use Alchemy\Phrasea\Application;
|
||||
use Alchemy\Phrasea\ControllerProvider as Providers;
|
||||
use Alchemy\Phrasea\PhraseanetService\Provider\PSAdminServiceProvider;
|
||||
use Alchemy\Phrasea\PhraseanetService\Provider\PSExposeServiceProvider;
|
||||
use Alchemy\Phrasea\Report\ControllerProvider\ProdReportControllerProvider;
|
||||
use Alchemy\Phrasea\WorkerManager\Provider\ControllerServiceProvider as WorkerManagerProvider;
|
||||
use Assert\Assertion;
|
||||
@@ -30,6 +32,7 @@ class RouteLoader
|
||||
'/admin/subdefs' => Providers\Admin\Subdefs::class,
|
||||
'/admin/task-manager' => Providers\Admin\TaskManager::class,
|
||||
'/admin/worker-manager' => WorkerManagerProvider::class,
|
||||
'/admin/phraseanet-service' => PSAdminServiceProvider::class,
|
||||
'/admin/users' => Providers\Admin\Users::class,
|
||||
'/client/' => Providers\Client\Root::class,
|
||||
'/datafiles' => Providers\Datafiles::class,
|
||||
@@ -45,6 +48,7 @@ class RouteLoader
|
||||
'/prod/bridge/' => Providers\Prod\Bridge::class,
|
||||
'/prod/download' => Providers\Prod\Download::class,
|
||||
'/prod/export/' => Providers\Prod\Export::class,
|
||||
'/prod/expose/' => PSExposeServiceProvider::class,
|
||||
'/prod/feeds' => Providers\Prod\Feed::class,
|
||||
'/prod/language' => Providers\Prod\Language::class,
|
||||
'/prod/lazaret/' => Providers\Prod\Lazaret::class,
|
||||
|
@@ -59,6 +59,8 @@ class LanguageController
|
||||
'feed_require_fields' => $translator->trans('Vous n\'avez pas rempli tous les champ requis'),
|
||||
'feed_require_feed' => $translator->trans('Vous n\'avez pas selectionne de fil de publication'),
|
||||
'removeTitle' => $translator->trans('panier::Supression d\'un element d\'un reportage'),
|
||||
'removeExposePublication' => $translator->trans('expose::Your are about to delete a publication from expose, please confirm your action !'),
|
||||
'removeAssetPublication' => $translator->trans('expose::Your are about to delete an asset from a publication, please confirm your action !'),
|
||||
'confirmRemoveReg' => $translator->trans('panier::Attention, vous etes sur le point de supprimer un element du reportage. Merci de confirmer votre action.'),
|
||||
'advsearch_title' => $translator->trans('phraseanet::recherche avancee'),
|
||||
'bask_rename' => $translator->trans('panier:: renommer le panier'),
|
||||
@@ -116,6 +118,7 @@ class LanguageController
|
||||
'attention' => $translator->trans('Attention !'),
|
||||
'mapMarkerEdit' => $translator->trans('Edit position'),
|
||||
'mapMarkerAdd' => $translator->trans('Add a position'),
|
||||
'Change position' => $translator->trans('prod:mapbox Change position'),
|
||||
'mapMarkerMoveLabel' => $translator->trans('Drag and drop the pin to move position'),
|
||||
'mapMarkerEditCancel' => $translator->trans('Cancel'),
|
||||
'mapMarkerEditSubmit' => $translator->trans('Submit'),
|
||||
@@ -156,8 +159,15 @@ class LanguageController
|
||||
'description notice' => $translator->trans('prod:mapboxgl: description notice'),
|
||||
'title-map-dialog' => $translator->trans('prod:mapboxgl: title map dialog'),
|
||||
'create new user' => $translator->trans('prod:push: create new user'),
|
||||
'prod:mapboxjs: title notice' => $translator->trans('prod:mapboxjs: title notice'),
|
||||
'prod:mapboxjs: description notice' => $translator->trans('prod:mapboxjs: description notice'),
|
||||
'prod:mapboxjs: title info' => $translator->trans('prod:mapboxjs: title info'),
|
||||
'prod:mapboxjs: description info : right click to add position' => $translator->trans('prod:mapboxjs: description info : right click to add position'),
|
||||
'prod:mapboxgl: title info' => $translator->trans('prod:mapboxgl: title info'),
|
||||
'prod:mapboxgl: description info : right click to add position' => $translator->trans('prod:mapboxgl: description info : right click to add position'),
|
||||
'prod:videoeditor:subtitletab:message:: error' => $translator->trans('prod:videoeditor:subtitletab:message:: error'),
|
||||
'prod:videoeditor:subtitletab:message:: success' => $translator->trans('prod:videoeditor:subtitletab:message:: success'),
|
||||
'Edit expose title' => $translator->trans('prod:workzone:expose:modal:: title'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
@@ -3,6 +3,8 @@
|
||||
namespace Alchemy\Phrasea\ControllerProvider;
|
||||
|
||||
use Alchemy\EmbedProvider\EmbedServiceProvider;
|
||||
use Alchemy\Phrasea\PhraseanetService\Provider\PSAdminServiceProvider;
|
||||
use Alchemy\Phrasea\PhraseanetService\Provider\PSExposeServiceProvider;
|
||||
use Silex\Application;
|
||||
use Silex\ServiceProviderInterface;
|
||||
|
||||
@@ -55,6 +57,8 @@ class ControllerProviderServiceProvider implements ServiceProviderInterface
|
||||
Admin\Subdefs::class => [],
|
||||
Admin\TaskManager::class => [],
|
||||
\Alchemy\Phrasea\WorkerManager\Provider\ControllerServiceProvider::class => [],
|
||||
PSAdminServiceProvider::class => [],
|
||||
PSExposeServiceProvider::class => [],
|
||||
Admin\Users::class => [],
|
||||
Client\Root::class => [],
|
||||
Datafiles::class => [],
|
||||
|
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace Alchemy\Phrasea\PhraseanetService\Controller;
|
||||
|
||||
use Alchemy\Phrasea\Application as PhraseaApplication;
|
||||
use Alchemy\Phrasea\Controller\Controller;
|
||||
use Alchemy\Phrasea\PhraseanetService\Form\PSExposeConfigurationType;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
class PSAdminController extends Controller
|
||||
{
|
||||
public function indexAction(PhraseaApplication $app)
|
||||
{
|
||||
return $this->render('admin/phraseanet-service/index.html.twig');
|
||||
}
|
||||
|
||||
public function authAction()
|
||||
{
|
||||
return $this->render('admin/phraseanet-service/auth.html.twig');
|
||||
}
|
||||
|
||||
public function exposeAction(PhraseaApplication $app, Request $request)
|
||||
{
|
||||
$exposeConfiguration = $app['conf']->get(['phraseanet-service', 'expose-service'], null);
|
||||
|
||||
$form = $app->form(new PSExposeConfigurationType(), $exposeConfiguration);
|
||||
|
||||
$form->handleRequest($request);
|
||||
|
||||
if ($form->isValid()) {
|
||||
$app['conf']->set(['phraseanet-service', 'expose-service'], $form->getData());
|
||||
|
||||
return $app->redirectPath('ps_admin');
|
||||
}
|
||||
|
||||
return $this->render('admin/phraseanet-service/expose.html.twig', [
|
||||
'form' => $form->createView()
|
||||
]);
|
||||
}
|
||||
|
||||
public function notifyAction()
|
||||
{
|
||||
return $this->render('admin/phraseanet-service/notify.html.twig');
|
||||
}
|
||||
|
||||
public function reportAction()
|
||||
{
|
||||
return $this->render('admin/phraseanet-service/report.html.twig');
|
||||
}
|
||||
|
||||
public function uploaderAction()
|
||||
{
|
||||
return $this->render('admin/phraseanet-service/uploader.html.twig');
|
||||
}
|
||||
}
|
@@ -0,0 +1,630 @@
|
||||
<?php
|
||||
|
||||
namespace Alchemy\Phrasea\PhraseanetService\Controller;
|
||||
|
||||
use Alchemy\Phrasea\Application as PhraseaApplication;
|
||||
use Alchemy\Phrasea\Controller\Controller;
|
||||
use Alchemy\Phrasea\WorkerManager\Event\ExposeUploadEvent;
|
||||
use Alchemy\Phrasea\WorkerManager\Event\WorkerEvents;
|
||||
use GuzzleHttp\Client;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Session\Session;
|
||||
|
||||
class PSExposeController extends Controller
|
||||
{
|
||||
/**
|
||||
* Set access token on session 'password_access_token'
|
||||
* @param PhraseaApplication $app
|
||||
* @param Request $request
|
||||
* @return \Symfony\Component\HttpFoundation\JsonResponse
|
||||
*/
|
||||
public function authenticateAction(PhraseaApplication $app, Request $request)
|
||||
{
|
||||
$exposeConfiguration = $app['conf']->get(['phraseanet-service', 'expose-service', 'exposes'], []);
|
||||
$exposeConfiguration = $exposeConfiguration[$request->request->get('exposeName')];
|
||||
|
||||
if ($exposeConfiguration == null) {
|
||||
return $this->app->json([
|
||||
'success' => false,
|
||||
'message' => 'Please, set configuration in admin!'
|
||||
]);
|
||||
}
|
||||
|
||||
$oauthClient = new Client(['base_uri' => $exposeConfiguration['auth_base_uri'], 'http_errors' => false]);
|
||||
|
||||
try {
|
||||
$response = $oauthClient->post('/oauth/v2/token', [
|
||||
'json' => [
|
||||
'client_id' => $exposeConfiguration['auth_client_id'],
|
||||
'client_secret' => $exposeConfiguration['auth_client_secret'],
|
||||
'grant_type' => 'password',
|
||||
'username' => $request->request->get('auth-username'),
|
||||
'password' => $request->request->get('auth-password') ]
|
||||
]);
|
||||
} catch(\Exception $e) {
|
||||
return $this->app->json([
|
||||
'success' => false,
|
||||
'message' => $e->getMessage()
|
||||
]);
|
||||
}
|
||||
|
||||
if ($response->getStatusCode() !== 200) {
|
||||
return $this->app->json([
|
||||
'success' => false,
|
||||
'message' => 'Status code: '. $response->getStatusCode()
|
||||
]);
|
||||
}
|
||||
|
||||
$tokenBody = $response->getBody()->getContents();
|
||||
|
||||
$tokenBody = json_decode($tokenBody,true);
|
||||
$session = $this->getSession();
|
||||
|
||||
$session->set('password_access_token', $tokenBody['access_token']);
|
||||
|
||||
return $this->app->json([
|
||||
'success' => true
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get list of publication
|
||||
* Use param "format=json" to retrieve a json
|
||||
*
|
||||
* @param PhraseaApplication $app
|
||||
* @param Request $request
|
||||
* @return string|\Symfony\Component\HttpFoundation\JsonResponse
|
||||
*/
|
||||
public function listPublicationAction(PhraseaApplication $app, Request $request)
|
||||
{
|
||||
if ($request->get('exposeName') == null) {
|
||||
return $this->render("prod/WorkZone/ExposeList.html.twig", [
|
||||
'publications' => [],
|
||||
]);
|
||||
}
|
||||
|
||||
$exposeConfiguration = $app['conf']->get(['phraseanet-service', 'expose-service', 'exposes'], []);
|
||||
$exposeConfiguration = $exposeConfiguration[$request->get('exposeName')];
|
||||
|
||||
$session = $this->getSession();
|
||||
|
||||
if (!$session->has('password_access_token') && $exposeConfiguration['connection_kind'] == 'password' && $request->get('format') != 'json') {
|
||||
return $this->render("prod/WorkZone/ExposeOauthLogin.html.twig", [
|
||||
'exposeName' => $request->get('exposeName')
|
||||
]);
|
||||
}
|
||||
|
||||
$accessToken = $this->getAndSaveToken($exposeConfiguration);
|
||||
|
||||
if ($exposeConfiguration == null ) {
|
||||
return $this->render("prod/WorkZone/ExposeList.html.twig", [
|
||||
'publications' => [],
|
||||
]);
|
||||
}
|
||||
|
||||
$exposeClient = new Client(['base_uri' => $exposeConfiguration['expose_base_uri'], 'http_errors' => false]);
|
||||
|
||||
$response = $exposeClient->get('/publications?flatten=true&order[createdAt]=desc', [
|
||||
'headers' => [
|
||||
'Authorization' => 'Bearer '. $accessToken,
|
||||
'Content-Type' => 'application/json'
|
||||
]
|
||||
]);
|
||||
|
||||
$exposeFrontBasePath = \p4string::addEndSlash($exposeConfiguration['expose_front_uri']);
|
||||
$publications = [];
|
||||
|
||||
if ($response->getStatusCode() == 200) {
|
||||
$body = json_decode($response->getBody()->getContents(),true);
|
||||
$publications = $body['hydra:member'];
|
||||
}
|
||||
|
||||
if ($request->get('format') == 'json') {
|
||||
return $app->json([
|
||||
'publications' => $publications
|
||||
]);
|
||||
}
|
||||
|
||||
return $this->render("prod/WorkZone/ExposeList.html.twig", [
|
||||
'publications' => $publications,
|
||||
'exposeFrontBasePath' => $exposeFrontBasePath
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Require params "exposeName" and "publicationId"
|
||||
* optional param "onlyAssets" equal to 1 to return only assets list
|
||||
*
|
||||
* @param PhraseaApplication $app
|
||||
* @param Request $request
|
||||
* @return string
|
||||
*/
|
||||
public function getPublicationAction(PhraseaApplication $app, Request $request)
|
||||
{
|
||||
$exposeConfiguration = $app['conf']->get(['phraseanet-service', 'expose-service', 'exposes'], []);
|
||||
$exposeConfiguration = $exposeConfiguration[$request->get('exposeName')];
|
||||
|
||||
$exposeClient = new Client(['base_uri' => $exposeConfiguration['expose_base_uri'], 'http_errors' => false]);
|
||||
|
||||
$accessToken = $this->getAndSaveToken($exposeConfiguration);
|
||||
|
||||
$publication = [];
|
||||
$resPublication = $exposeClient->get('/publications/' . $request->get('publicationId') , [
|
||||
'headers' => [
|
||||
'Authorization' => 'Bearer '. $accessToken,
|
||||
'Content-Type' => 'application/json'
|
||||
]
|
||||
]);
|
||||
|
||||
if ($resPublication->getStatusCode() != 200) {
|
||||
return $app->json([
|
||||
'success' => false,
|
||||
'message' => "An error occurred when getting publication: status-code " . $resPublication->getStatusCode()
|
||||
]);
|
||||
}
|
||||
|
||||
if ($resPublication->getStatusCode() == 200) {
|
||||
$publication = json_decode($resPublication->getBody()->getContents(),true);
|
||||
}
|
||||
|
||||
if ($request->get('onlyAssets')) {
|
||||
return $this->render("prod/WorkZone/ExposePublicationAssets.html.twig", [
|
||||
'assets' => $publication['assets'],
|
||||
'publicationId' => $publication['id']
|
||||
]);
|
||||
}
|
||||
|
||||
return $this->render("prod/WorkZone/ExposeEdit.html.twig", [
|
||||
'publication' => $publication,
|
||||
'exposeName' => $request->get('exposeName')
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Require params "exposeName" and "publicationId"
|
||||
* optionnal param "page"
|
||||
*
|
||||
* @param PhraseaApplication $app
|
||||
* @param Request $request
|
||||
* @return string|\Symfony\Component\HttpFoundation\JsonResponse
|
||||
*/
|
||||
public function getPublicationAssetsAction(PhraseaApplication $app, Request $request)
|
||||
{
|
||||
$page = $request->get('page')?:1;
|
||||
|
||||
$exposeConfiguration = $app['conf']->get(['phraseanet-service', 'expose-service', 'exposes'], []);
|
||||
$exposeConfiguration = $exposeConfiguration[$request->get('exposeName')];
|
||||
|
||||
$exposeClient = new Client(['base_uri' => $exposeConfiguration['expose_base_uri'], 'http_errors' => false]);
|
||||
|
||||
$accessToken = $this->getAndSaveToken($exposeConfiguration);
|
||||
|
||||
$resPublication = $exposeClient->get('/publications/' . $request->get('publicationId') . '/assets?page=' . $page , [
|
||||
'headers' => [
|
||||
'Authorization' => 'Bearer '. $accessToken,
|
||||
'Content-Type' => 'application/json'
|
||||
]
|
||||
]);
|
||||
|
||||
if ($resPublication->getStatusCode() != 200) {
|
||||
return $app->json([
|
||||
'success' => false,
|
||||
'message' => "An error occurred when getting publication assets: status-code " . $resPublication->getStatusCode()
|
||||
]);
|
||||
}
|
||||
|
||||
$pubAssets = [];
|
||||
$totalItems = 0;
|
||||
if ($resPublication->getStatusCode() == 200) {
|
||||
$body = json_decode($resPublication->getBody()->getContents(),true);
|
||||
$pubAssets = $body['hydra:member'];
|
||||
$totalItems = $body['hydra:totalItems'];
|
||||
}
|
||||
|
||||
return $this->render("prod/WorkZone/ExposePublicationAssets.html.twig", [
|
||||
'pubAssets' => $pubAssets,
|
||||
'publicationId' => $request->get('publicationId'),
|
||||
'totalItems' => $totalItems,
|
||||
'page' => $page
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Require params "exposeName"
|
||||
*
|
||||
* @param PhraseaApplication $app
|
||||
* @param Request $request
|
||||
* @return \Symfony\Component\HttpFoundation\JsonResponse
|
||||
*/
|
||||
public function listProfileAction(PhraseaApplication $app, Request $request)
|
||||
{
|
||||
if ( $request->get('exposeName') == null) {
|
||||
return $app->json([
|
||||
'profiles' => [],
|
||||
'basePath' => []
|
||||
]);
|
||||
}
|
||||
|
||||
$exposeConfiguration = $app['conf']->get(['phraseanet-service', 'expose-service', 'exposes'], []);
|
||||
$exposeConfiguration = $exposeConfiguration[$request->get('exposeName')];
|
||||
|
||||
$exposeClient = new Client(['base_uri' => $exposeConfiguration['expose_base_uri'], 'http_errors' => false]);
|
||||
|
||||
$accessToken = $this->getAndSaveToken($exposeConfiguration);
|
||||
|
||||
$profiles = [];
|
||||
$basePath = '';
|
||||
|
||||
$resProfile = $exposeClient->get('/publication-profiles' , [
|
||||
'headers' => [
|
||||
'Authorization' => 'Bearer '. $accessToken,
|
||||
'Content-Type' => 'application/json'
|
||||
]
|
||||
]);
|
||||
|
||||
if ($resProfile->getStatusCode() != 200) {
|
||||
return $app->json([
|
||||
'success' => false,
|
||||
'message' => "An error occurred when getting publication: status-code " . $resProfile->getStatusCode()
|
||||
]);
|
||||
}
|
||||
|
||||
if ($resProfile->getStatusCode() == 200) {
|
||||
$body = json_decode($resProfile->getBody()->getContents(),true);
|
||||
$profiles = $body['hydra:member'];
|
||||
$basePath = $body['@id'];
|
||||
}
|
||||
|
||||
return $app->json([
|
||||
'profiles' => $profiles,
|
||||
'basePath' => $basePath
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a publication
|
||||
* Require params "exposeName" and "publicationData"
|
||||
*
|
||||
* @param PhraseaApplication $app
|
||||
* @param Request $request
|
||||
* @return \Symfony\Component\HttpFoundation\JsonResponse
|
||||
*/
|
||||
public function createPublicationAction(PhraseaApplication $app, Request $request)
|
||||
{
|
||||
$exposeName = $request->get('exposeName');
|
||||
if ( $exposeName == null) {
|
||||
return $app->json([
|
||||
'success' => false,
|
||||
'message' => "ExposeName required, select one!"
|
||||
]);
|
||||
}
|
||||
|
||||
$exposeConfiguration = $app['conf']->get(['phraseanet-service', 'expose-service', 'exposes'], []);
|
||||
$exposeConfiguration = $exposeConfiguration[$exposeName];
|
||||
|
||||
$exposeClient = new Client(['base_uri' => $exposeConfiguration['expose_base_uri'], 'http_errors' => false]);
|
||||
|
||||
try {
|
||||
$accessToken = $this->getAndSaveToken($exposeConfiguration);
|
||||
|
||||
$response = $this->postPublication($exposeClient, $accessToken, json_decode($request->get('publicationData'), true));
|
||||
|
||||
if ($response->getStatusCode() == 401) {
|
||||
$accessToken = $this->getAndSaveToken($exposeConfiguration);
|
||||
|
||||
$response = $this->postPublication($exposeClient, $accessToken, json_decode($request->get('publicationData'), true));
|
||||
}
|
||||
|
||||
if ($response->getStatusCode() !== 201) {
|
||||
return $app->json([
|
||||
'success' => false,
|
||||
'message' => "An error occurred when creating publication: status-code " . $response->getStatusCode()
|
||||
]);
|
||||
}
|
||||
|
||||
$publicationsResponse = json_decode($response->getBody(),true);
|
||||
} catch (\Exception $e) {
|
||||
return $app->json([
|
||||
'success' => false,
|
||||
'message' => "An error occurred when creating publication!"
|
||||
]);
|
||||
}
|
||||
|
||||
$path = empty($publicationsResponse['slug']) ? $publicationsResponse['id'] : $publicationsResponse['slug'] ;
|
||||
$url = \p4string::addEndSlash($exposeConfiguration['expose_front_uri']) . $path;
|
||||
|
||||
$link = "<a style='color:blue;' target='_blank' href='" . $url . "'>" . $url . "</a>";
|
||||
|
||||
return $app->json([
|
||||
'success' => true,
|
||||
'message' => "Publication successfully created!",
|
||||
'link' => $link
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a publication
|
||||
* Require params "exposeName" and "publicationId"
|
||||
*
|
||||
* @param PhraseaApplication $app
|
||||
* @param Request $request
|
||||
* @return \Symfony\Component\HttpFoundation\JsonResponse
|
||||
*/
|
||||
public function updatePublicationAction(PhraseaApplication $app, Request $request)
|
||||
{
|
||||
$exposeName = $request->get('exposeName');
|
||||
|
||||
$exposeConfiguration = $app['conf']->get(['phraseanet-service', 'expose-service', 'exposes'], []);
|
||||
$exposeConfiguration = $exposeConfiguration[$exposeName];
|
||||
|
||||
$exposeClient = new Client(['base_uri' => $exposeConfiguration['expose_base_uri'], 'http_errors' => false]);
|
||||
|
||||
try {
|
||||
$accessToken = $this->getAndSaveToken($exposeConfiguration);
|
||||
|
||||
$response = $this->putPublication($exposeClient, $request->get('publicationId'), $accessToken, json_decode($request->get('publicationData'), true));
|
||||
|
||||
if ($response->getStatusCode() == 401) {
|
||||
$accessToken = $this->getAndSaveToken($exposeConfiguration);
|
||||
$response = $this->putPublication($exposeClient, $request->get('publicationId'), $accessToken, json_decode($request->get('publicationData'), true));
|
||||
}
|
||||
|
||||
if ($response->getStatusCode() !== 200) {
|
||||
return $app->json([
|
||||
'success' => false,
|
||||
'message' => "An error occurred when updating publication: status-code " . $response->getStatusCode()
|
||||
]);
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
return $app->json([
|
||||
'success' => false,
|
||||
'message' => "An error occurred when updating publication! ". $e->getMessage()
|
||||
]);
|
||||
}
|
||||
|
||||
return $app->json([
|
||||
'success' => true,
|
||||
'message' => "Publication successfully updated!"
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a Publication
|
||||
* require params "exposeName" and "publicationId"
|
||||
*
|
||||
* @param PhraseaApplication $app
|
||||
* @param Request $request
|
||||
* @return \Symfony\Component\HttpFoundation\JsonResponse
|
||||
*/
|
||||
public function deletePublicationAction(PhraseaApplication $app, Request $request)
|
||||
{
|
||||
$exposeName = $request->get('exposeName');
|
||||
|
||||
$exposeConfiguration = $app['conf']->get(['phraseanet-service', 'expose-service', 'exposes'], []);
|
||||
$exposeConfiguration = $exposeConfiguration[$exposeName];
|
||||
|
||||
$exposeClient = new Client(['base_uri' => $exposeConfiguration['expose_base_uri'], 'http_errors' => false]);
|
||||
|
||||
try {
|
||||
$accessToken = $this->getAndSaveToken($exposeConfiguration);
|
||||
|
||||
$response = $this->removePublication($exposeClient, $request->get('publicationId'), $accessToken);
|
||||
|
||||
if ($response->getStatusCode() == 401) {
|
||||
$accessToken = $this->getAndSaveToken($exposeConfiguration);
|
||||
$response = $this->removePublication($exposeClient, $request->get('publicationId'), $accessToken);
|
||||
}
|
||||
|
||||
if ($response->getStatusCode() !== 204) {
|
||||
return $app->json([
|
||||
'success' => false,
|
||||
'message' => "An error occurred when deleting publication: status-code " . $response->getStatusCode()
|
||||
]);
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
return $app->json([
|
||||
'success' => false,
|
||||
'message' => "An error occurred when deleting publication!"
|
||||
]);
|
||||
}
|
||||
|
||||
return $app->json([
|
||||
'success' => true,
|
||||
'message' => "Publication successfully deleted!"
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete asset from publication
|
||||
* require params "exposeName" ,"publicationId" and "assetId"
|
||||
*
|
||||
* @param PhraseaApplication $app
|
||||
* @param Request $request
|
||||
* @return \Symfony\Component\HttpFoundation\JsonResponse
|
||||
*/
|
||||
public function deletePublicationAssetAction(PhraseaApplication $app, Request $request)
|
||||
{
|
||||
$exposeName = $request->get('exposeName');
|
||||
|
||||
$exposeConfiguration = $app['conf']->get(['phraseanet-service', 'expose-service', 'exposes'], []);
|
||||
$exposeConfiguration = $exposeConfiguration[$exposeName];
|
||||
|
||||
$exposeClient = new Client(['base_uri' => $exposeConfiguration['expose_base_uri'], 'http_errors' => false]);
|
||||
|
||||
try {
|
||||
$accessToken = $this->getAndSaveToken($exposeConfiguration);
|
||||
|
||||
$response = $this->removeAssetPublication($exposeClient, $request->get('publicationId'), $request->get('assetId'), $accessToken);
|
||||
|
||||
if ($response->getStatusCode() == 401) {
|
||||
$accessToken = $this->getAndSaveToken($exposeConfiguration);
|
||||
$response = $this->removeAssetPublication($exposeClient, $request->get('publicationId'), $request->get('assetId'), $accessToken);
|
||||
}
|
||||
|
||||
if ($response->getStatusCode() !== 204) {
|
||||
return $app->json([
|
||||
'success' => false,
|
||||
'message' => "An error occurred when deleting asset: status-code " . $response->getStatusCode()
|
||||
]);
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
return $app->json([
|
||||
'success' => false,
|
||||
'message' => "An error occurred when deleting asset!"
|
||||
]);
|
||||
}
|
||||
|
||||
return $app->json([
|
||||
'success' => true,
|
||||
'message' => "Asset successfully removed from publication!"
|
||||
]);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Add assets in a publication
|
||||
* Require params "lst" , "exposeName" and "publicationId"
|
||||
* "lst" is a list of record as "baseId_recordId"
|
||||
*
|
||||
* @param PhraseaApplication $app
|
||||
* @param Request $request
|
||||
* @return \Symfony\Component\HttpFoundation\JsonResponse
|
||||
*/
|
||||
public function addPublicationAssetsAction(PhraseaApplication $app, Request $request)
|
||||
{
|
||||
$exposeName = $request->get('exposeName');
|
||||
$publicationId = $request->get('publicationId');
|
||||
$lst = $request->get('lst');
|
||||
|
||||
if ($publicationId == null) {
|
||||
return $app->json([
|
||||
'success' => false,
|
||||
'message' => 'Need to give publicationId to add asset in publication!'
|
||||
]);
|
||||
}
|
||||
|
||||
$exposeConfiguration = $app['conf']->get(['phraseanet-service', 'expose-service', 'exposes'], []);
|
||||
$exposeConfiguration = $exposeConfiguration[$exposeName];
|
||||
$accessToken = $this->getAndSaveToken($exposeConfiguration);
|
||||
|
||||
$this->getEventDispatcher()->dispatch(WorkerEvents::EXPOSE_UPLOAD_ASSETS, new ExposeUploadEvent($lst, $exposeName, $publicationId, $accessToken));
|
||||
|
||||
return $app->json([
|
||||
'success' => true,
|
||||
'message' => " Record (s) to be added to the publication!"
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Token and save in session
|
||||
* @param $config
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
private function getAndSaveToken($config)
|
||||
{
|
||||
$session = $this->getSession();
|
||||
|
||||
$accessToken = '';
|
||||
if ($config['connection_kind'] == 'password') {
|
||||
$accessToken = $session->get('password_access_token');
|
||||
} elseif ($config['connection_kind'] == 'client_credentials') {
|
||||
if ($session->has('credential_access_token')) {
|
||||
$accessToken = $session->get('credential_access_token');
|
||||
} else {
|
||||
$oauthClient = new Client();
|
||||
|
||||
try {
|
||||
$response = $oauthClient->post($config['expose_base_uri'] . '/oauth/v2/token', [
|
||||
'json' => [
|
||||
'client_id' => $config['expose_client_id'],
|
||||
'client_secret' => $config['expose_client_secret'],
|
||||
'grant_type' => 'client_credentials',
|
||||
'scope' => 'publish'
|
||||
]
|
||||
]);
|
||||
} catch(\Exception $e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($response->getStatusCode() !== 200) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$tokenBody = $response->getBody()->getContents();
|
||||
|
||||
$tokenBody = json_decode($tokenBody,true);
|
||||
|
||||
$session->set('credential_access_token', $tokenBody['access_token']);
|
||||
|
||||
$accessToken = $tokenBody['access_token'];
|
||||
}
|
||||
}
|
||||
|
||||
return $accessToken;
|
||||
}
|
||||
|
||||
private function postPublication(Client $exposeClient, $token, $publicationData)
|
||||
{
|
||||
return $exposeClient->post('/publications', [
|
||||
'headers' => [
|
||||
'Authorization' => 'Bearer '. $token,
|
||||
'Content-Type' => 'application/json'
|
||||
],
|
||||
'json' => $publicationData
|
||||
]);
|
||||
}
|
||||
|
||||
private function putPublication(Client $exposeClient, $publicationId, $token, $publicationData)
|
||||
{
|
||||
return $exposeClient->put('/publications/' . $publicationId, [
|
||||
'headers' => [
|
||||
'Authorization' => 'Bearer '. $token,
|
||||
'Content-Type' => 'application/json'
|
||||
],
|
||||
'json' => $publicationData
|
||||
]);
|
||||
}
|
||||
|
||||
private function removePublication(Client $exposeClient, $publicationId, $token)
|
||||
{
|
||||
return $exposeClient->delete('/publications/' . $publicationId, [
|
||||
'headers' => [
|
||||
'Authorization' => 'Bearer '. $token
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
private function removeAssetPublication(Client $exposeClient, $publicationId, $assetId, $token)
|
||||
{
|
||||
$exposeClient->delete('/publication-assets/'.$publicationId.'/'.$assetId, [
|
||||
'headers' => [
|
||||
'Authorization' => 'Bearer '. $token
|
||||
]
|
||||
]);
|
||||
|
||||
return $exposeClient->delete('/assets/'. $assetId, [
|
||||
'headers' => [
|
||||
'Authorization' => 'Bearer '. $token
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return EventDispatcherInterface
|
||||
*/
|
||||
private function getEventDispatcher()
|
||||
{
|
||||
return $this->app['dispatcher'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Session
|
||||
*/
|
||||
private function getSession()
|
||||
{
|
||||
return $this->app['session'];
|
||||
}
|
||||
}
|
@@ -0,0 +1,101 @@
|
||||
<?php
|
||||
|
||||
namespace Alchemy\Phrasea\PhraseanetService\Form;
|
||||
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\DataMapperInterface;
|
||||
use Symfony\Component\Form\Exception;
|
||||
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\Form\FormInterface;
|
||||
|
||||
class PSExposeConfigurationType extends AbstractType implements DataMapperInterface
|
||||
{
|
||||
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||
{
|
||||
parent::buildForm($builder, $options);
|
||||
|
||||
$builder
|
||||
->add('activated', CheckboxType::class, [
|
||||
'label' => 'admin:phrasea-service-setting:tab:expose:: activate Phraseanet-service expose',
|
||||
'required' => false,
|
||||
'attr' => [
|
||||
'class' => 'activate-expose',
|
||||
]
|
||||
])
|
||||
->add('exposes', CollectionType::class, [
|
||||
'label' => false,
|
||||
'entry_type' => PSExposeConnectionType::class,
|
||||
'prototype' => true,
|
||||
'allow_add' => true,
|
||||
'allow_delete' => true,
|
||||
])
|
||||
->setDataMapper($this)
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function mapDataToForms($data, $forms)
|
||||
{
|
||||
// there is no data yet, so nothing to prepopulate
|
||||
if ($data === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
/** @var FormInterface[] $forms */
|
||||
$forms = iterator_to_array($forms);
|
||||
|
||||
foreach ($data['exposes'] as $key => $config) {
|
||||
$data['exposes'][$key]['expose_name'] = $key;
|
||||
}
|
||||
|
||||
$forms['activated']->setData($data['activated']);
|
||||
$forms['exposes']->setData(array_values($data['exposes']));
|
||||
}
|
||||
|
||||
/**
|
||||
* Data structure like this
|
||||
*
|
||||
* expose-service:
|
||||
* activated: true
|
||||
* exposes:
|
||||
* expose_test:
|
||||
* activate_expose: true
|
||||
* connection_kind: account
|
||||
* expose_front_uri: 'localhost:8080'
|
||||
* expose_base_uri: 'localhost:8082'
|
||||
* client_secret: secret
|
||||
* client_id: id
|
||||
*
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function mapFormsToData($forms, &$data)
|
||||
{
|
||||
|
||||
/** @var FormInterface[] $forms */
|
||||
$forms = iterator_to_array($forms);
|
||||
|
||||
$data = null;
|
||||
|
||||
$data['activated'] = $forms['activated']->getData();
|
||||
|
||||
/** @var FormInterface[] $exposeConfigForms */
|
||||
$exposeConfigForms = iterator_to_array($forms['exposes']);
|
||||
|
||||
foreach ($exposeConfigForms as $exposeConfigForm) {
|
||||
$config = $exposeConfigForm->getData();
|
||||
$exposeName = $config['expose_name'];
|
||||
unset($config['expose_name']);
|
||||
|
||||
$data['exposes'][$exposeName] = $config;
|
||||
}
|
||||
}
|
||||
|
||||
public function getName()
|
||||
{
|
||||
return 'ps_expose_configuration';
|
||||
}
|
||||
}
|
@@ -0,0 +1,95 @@
|
||||
<?php
|
||||
|
||||
namespace Alchemy\Phrasea\PhraseanetService\Form;
|
||||
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\Form\FormEvent;
|
||||
use Symfony\Component\Form\FormEvents;
|
||||
|
||||
class PSExposeConnectionType extends AbstractType
|
||||
{
|
||||
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||
{
|
||||
parent::buildForm($builder, $options);
|
||||
|
||||
$builder
|
||||
->add('activate_expose', CheckboxType::class, [
|
||||
'label' => 'admin:phrasea-service-setting:tab:expose:: Activate this expose',
|
||||
'required' => false
|
||||
])
|
||||
->add('connection_kind', ChoiceType::class, [
|
||||
'label' => 'admin:phrasea-service-setting:tab:expose:: Connection Kind',
|
||||
'required' => true,
|
||||
'attr' => [
|
||||
'class' => 'auth-connection'
|
||||
],
|
||||
'choices' => [
|
||||
'client_credentials' => 'client_credentials',
|
||||
'password' => 'password'
|
||||
]
|
||||
])
|
||||
->add('expose_name', TextType::class, [
|
||||
'label' => 'admin:phrasea-service-setting:tab:expose:: Name',
|
||||
'attr' => [
|
||||
'class' => 'expose-name'
|
||||
]
|
||||
])
|
||||
->add('expose_front_uri', TextType::class, [
|
||||
'label' => 'admin:phrasea-service-setting:tab:expose:: Expose Front base uri',
|
||||
'attr' => [
|
||||
'class' => 'input-xxlarge'
|
||||
]
|
||||
])
|
||||
->add('expose_base_uri', TextType::class, [
|
||||
'label' => 'admin:phrasea-service-setting:tab:expose:: Expose Base Uri api',
|
||||
'attr' => [
|
||||
'class' => 'input-xxlarge'
|
||||
]
|
||||
])
|
||||
->add('expose_client_secret', TextType::class, [
|
||||
'label' => 'admin:phrasea-service-setting:tab:expose:: Expose Client secret',
|
||||
'required' => false,
|
||||
'attr' => [
|
||||
'class' => 'input-xxlarge'
|
||||
]
|
||||
])
|
||||
->add('expose_client_id', TextType::class, [
|
||||
'label' => 'admin:phrasea-service-setting:tab:expose:: Expose Client ID',
|
||||
'required' => false,
|
||||
'attr' => [
|
||||
'class' => 'input-xxlarge'
|
||||
]
|
||||
])
|
||||
->add('auth_base_uri', TextType::class, [
|
||||
'label' => 'admin:phrasea-service-setting:tab:expose:: Auth Base Uri ',
|
||||
'required' => false,
|
||||
'attr' => [
|
||||
'class' => 'input-xxlarge'
|
||||
]
|
||||
])
|
||||
->add('auth_client_secret', TextType::class, [
|
||||
'label' => 'admin:phrasea-service-setting:tab:expose:: Auth Client secret',
|
||||
'required' => false,
|
||||
'attr' => [
|
||||
'class' => 'input-xxlarge'
|
||||
]
|
||||
])
|
||||
->add('auth_client_id', TextType::class, [
|
||||
'label' => 'admin:phrasea-service-setting:tab:expose:: Auth Client ID',
|
||||
'required' => false,
|
||||
'attr' => [
|
||||
'class' => 'input-xxlarge'
|
||||
]
|
||||
])
|
||||
;
|
||||
}
|
||||
|
||||
public function getName()
|
||||
{
|
||||
return 'ps_expose_connection';
|
||||
}
|
||||
}
|
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
|
||||
namespace Alchemy\Phrasea\PhraseanetService\Provider;
|
||||
|
||||
use Alchemy\Phrasea\Application as PhraseaApplication;
|
||||
use Alchemy\Phrasea\ControllerProvider\ControllerProviderTrait;
|
||||
use Alchemy\Phrasea\PhraseanetService\Controller\PSAdminController;
|
||||
use Silex\Application;
|
||||
use Silex\ControllerCollection;
|
||||
use Silex\ControllerProviderInterface;
|
||||
use Silex\ServiceProviderInterface;
|
||||
|
||||
class PSAdminServiceProvider implements ControllerProviderInterface, ServiceProviderInterface
|
||||
{
|
||||
use ControllerProviderTrait;
|
||||
|
||||
/**
|
||||
* Registers services on the given app.
|
||||
*
|
||||
* This method should only be used to configure services and parameters.
|
||||
* It should not get services.
|
||||
*/
|
||||
public function register(Application $app)
|
||||
{
|
||||
$app['controller.ps.admin'] = $app->share(function (PhraseaApplication $app) {
|
||||
return new PSAdminController($app);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns routes to connect to the given application.
|
||||
*
|
||||
* @param Application $app An Application instance
|
||||
*
|
||||
* @return ControllerCollection A ControllerCollection instance
|
||||
*/
|
||||
public function connect(Application $app)
|
||||
{
|
||||
$controllers = $this->createAuthenticatedCollection($app);
|
||||
|
||||
$controllers->match('/', 'controller.ps.admin:indexAction')
|
||||
->method('GET')
|
||||
->bind('ps_admin');
|
||||
|
||||
$controllers->match('/auth', 'controller.ps.admin:authAction')
|
||||
->method('GET|POST')
|
||||
->bind('ps_admin_auth')
|
||||
;
|
||||
|
||||
$controllers->match('/expose', 'controller.ps.admin:exposeAction')
|
||||
->method('GET|POST')
|
||||
->bind('ps_admin_expose')
|
||||
;
|
||||
|
||||
$controllers->match('/uploader', 'controller.ps.admin:uploaderAction')
|
||||
->method('GET|POST')
|
||||
->bind('ps_admin_uploader')
|
||||
;
|
||||
|
||||
$controllers->match('/notify', 'controller.ps.admin:notifyAction')
|
||||
->method('GET|POST')
|
||||
->bind('ps_admin_notify')
|
||||
;
|
||||
|
||||
$controllers->match('/report', 'controller.ps.admin:reportAction')
|
||||
->method('GET|POST')
|
||||
->bind('ps_admin_report')
|
||||
;
|
||||
|
||||
return $controllers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bootstraps the application.
|
||||
*
|
||||
* This method is called after all services are registered
|
||||
* and should be used for "dynamic" configuration (whenever
|
||||
* a service must be requested).
|
||||
*/
|
||||
public function boot(Application $app)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
|
||||
namespace Alchemy\Phrasea\PhraseanetService\Provider;
|
||||
|
||||
use Alchemy\Phrasea\Application as PhraseaApplication;
|
||||
use Alchemy\Phrasea\ControllerProvider\ControllerProviderTrait;
|
||||
use Alchemy\Phrasea\PhraseanetService\Controller\PSExposeController;
|
||||
use Silex\Application;
|
||||
use Silex\ControllerProviderInterface;
|
||||
use Silex\ServiceProviderInterface;
|
||||
|
||||
class PSExposeServiceProvider implements ControllerProviderInterface, ServiceProviderInterface
|
||||
{
|
||||
use ControllerProviderTrait;
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function register(Application $app)
|
||||
{
|
||||
$app['controller.ps.expose'] = $app->share(function (PhraseaApplication $app) {
|
||||
return new PSExposeController($app);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function connect(Application $app)
|
||||
{
|
||||
$controllers = $this->createAuthenticatedCollection($app);
|
||||
|
||||
$controllers->match('/authenticate/', 'controller.ps.expose:authenticateAction')
|
||||
->method('POST')
|
||||
->bind('ps_expose_authenticate');
|
||||
|
||||
$controllers->match('/create-publication/', 'controller.ps.expose:createPublicationAction')
|
||||
->method('POST')
|
||||
->bind('ps_expose_create_publication');
|
||||
|
||||
$controllers->match('/update-publication/{publicationId}', 'controller.ps.expose:updatePublicationAction')
|
||||
->method('POST|PUT')
|
||||
->bind('ps_expose_update_publication');
|
||||
|
||||
$controllers->match('/list-publication/', 'controller.ps.expose:listPublicationAction')
|
||||
->method('GET')
|
||||
->bind('ps_expose_list_publication');
|
||||
|
||||
$controllers->match('/get-publication/{publicationId}/assets', 'controller.ps.expose:getPublicationAssetsAction')
|
||||
->method('GET')
|
||||
->bind('ps_expose_get_publication_assets');
|
||||
|
||||
$controllers->match('/get-publication/{publicationId}', 'controller.ps.expose:getPublicationAction')
|
||||
->method('GET')
|
||||
->bind('ps_expose_get_publication');
|
||||
|
||||
$controllers->match('/list-profile', 'controller.ps.expose:listProfileAction')
|
||||
->method('GET')
|
||||
->bind('ps_expose_get_publication_profile');
|
||||
|
||||
$controllers->match('/delete-publication/{publicationId}/', 'controller.ps.expose:deletePublicationAction')
|
||||
->method('POST|DELETE')
|
||||
->bind('ps_expose_delete_publication');
|
||||
|
||||
$controllers->match('/publication/delete-asset/{publicationId}/{assetId}/', 'controller.ps.expose:deletePublicationAssetAction')
|
||||
->method('POST|DELETE')
|
||||
->bind('ps_expose_publication_delete_asset');
|
||||
|
||||
$controllers->match('/publication/add-assets', 'controller.ps.expose:addPublicationAssetsAction')
|
||||
->method('POST')
|
||||
->bind('ps_expose_publication_add_assets');
|
||||
|
||||
return $controllers;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function boot(Application $app)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace Alchemy\Phrasea\WorkerManager\Event;
|
||||
|
||||
use Symfony\Component\EventDispatcher\Event as SfEvent;
|
||||
|
||||
class ExposeUploadEvent extends SfEvent
|
||||
{
|
||||
private $lst;
|
||||
private $exposeName;
|
||||
private $publicationId;
|
||||
private $accessToken;
|
||||
|
||||
public function __construct($lst, $exposeName, $publicationId, $accessToken)
|
||||
{
|
||||
$this->lst = $lst;
|
||||
$this->exposeName = $exposeName;
|
||||
$this->publicationId = $publicationId;
|
||||
$this->accessToken = $accessToken;
|
||||
}
|
||||
|
||||
public function getLst()
|
||||
{
|
||||
return $this->lst;
|
||||
}
|
||||
|
||||
public function getExposeName()
|
||||
{
|
||||
return $this->exposeName;
|
||||
}
|
||||
|
||||
public function getPublicationId()
|
||||
{
|
||||
return $this->publicationId;
|
||||
}
|
||||
|
||||
public function getAccessToken()
|
||||
{
|
||||
return $this->accessToken;
|
||||
}
|
||||
}
|
@@ -19,4 +19,6 @@ final class WorkerEvents
|
||||
const EXPORT_MAIL_FAILURE = 'export.worker_mail_failure';
|
||||
|
||||
const WEBHOOK_DELIVER_FAILURE = 'webhook.deliver_failure';
|
||||
|
||||
const EXPOSE_UPLOAD_ASSETS = 'expose.upload_assets';
|
||||
}
|
||||
|
@@ -10,6 +10,7 @@ use Alchemy\Phrasea\WorkerManager\Worker\AssetsIngestWorker;
|
||||
use Alchemy\Phrasea\WorkerManager\Worker\CreateRecordWorker;
|
||||
use Alchemy\Phrasea\WorkerManager\Worker\DeleteRecordWorker;
|
||||
use Alchemy\Phrasea\WorkerManager\Worker\ExportMailWorker;
|
||||
use Alchemy\Phrasea\WorkerManager\Worker\ExposeUploadWorker;
|
||||
use Alchemy\Phrasea\WorkerManager\Worker\Factory\CallableWorkerFactory;
|
||||
use Alchemy\Phrasea\WorkerManager\Worker\MainQueueWorker;
|
||||
use Alchemy\Phrasea\WorkerManager\Worker\PopulateIndexWorker;
|
||||
@@ -131,6 +132,11 @@ class AlchemyWorkerServiceProvider implements PluginProviderInterface
|
||||
->setApplicationBox($app['phraseanet.appbox']);
|
||||
}));
|
||||
|
||||
$app['alchemy_worker.type_based_worker_resolver']->addFactory(MessagePublisher::EXPOSE_UPLOAD_TYPE, new CallableWorkerFactory(function () use ($app) {
|
||||
return (new ExposeUploadWorker($app))
|
||||
->setApplicationBox($app['phraseanet.appbox']);
|
||||
}));
|
||||
|
||||
$app['alchemy_worker.type_based_worker_resolver']->addFactory(MessagePublisher::SUBTITLE_TYPE, new CallableWorkerFactory(function () use ($app) {
|
||||
return (new SubtitleWorker($app['repo.worker-job'], $app['conf'], new LazyLocator($app, 'phraseanet.appbox'), $app['alchemy_worker.logger']))
|
||||
->setFileSystemLocator(new LazyLocator($app, 'filesystem'))
|
||||
|
@@ -21,6 +21,7 @@ use Alchemy\Phrasea\WorkerManager\Queue\MessagePublisher;
|
||||
use Alchemy\Phrasea\WorkerManager\Queue\WebhookPublisher;
|
||||
use Alchemy\Phrasea\WorkerManager\Subscriber\AssetsIngestSubscriber;
|
||||
use Alchemy\Phrasea\WorkerManager\Subscriber\ExportSubscriber;
|
||||
use Alchemy\Phrasea\WorkerManager\Subscriber\ExposeSubscriber;
|
||||
use Alchemy\Phrasea\WorkerManager\Subscriber\RecordSubscriber;
|
||||
use Alchemy\Phrasea\WorkerManager\Subscriber\SearchengineSubscriber;
|
||||
use Alchemy\Phrasea\WorkerManager\Subscriber\SubtitleSubscriber;
|
||||
@@ -70,6 +71,7 @@ class QueueWorkerServiceProvider implements PluginProviderInterface
|
||||
$dispatcher->addSubscriber(new SearchengineSubscriber($app['alchemy_worker.message.publisher'], new LazyLocator($app, 'repo.worker-running-job')));
|
||||
$dispatcher->addSubscriber(new WebhookSubscriber($app['alchemy_worker.message.publisher']));
|
||||
$dispatcher->addSubscriber(new SubtitleSubscriber(new LazyLocator($app, 'repo.worker-job'), $app['alchemy_worker.message.publisher']));
|
||||
$dispatcher->addSubscriber(new ExposeSubscriber($app['alchemy_worker.message.publisher']));
|
||||
|
||||
return $dispatcher;
|
||||
})
|
||||
|
@@ -31,7 +31,8 @@ class AMQPConnection
|
||||
MessagePublisher::POPULATE_INDEX_TYPE => MessagePublisher::POPULATE_INDEX_QUEUE,
|
||||
MessagePublisher::DELETE_RECORD_TYPE => MessagePublisher::DELETE_RECORD_QUEUE,
|
||||
MessagePublisher::MAIN_QUEUE_TYPE => MessagePublisher::MAIN_QUEUE,
|
||||
MessagePublisher::SUBTITLE_TYPE => MessagePublisher::SUBTITLE_QUEUE
|
||||
MessagePublisher::SUBTITLE_TYPE => MessagePublisher::SUBTITLE_QUEUE,
|
||||
MessagePublisher::EXPOSE_UPLOAD_TYPE => MessagePublisher::EXPOSE_UPLOAD_QUEUE
|
||||
];
|
||||
|
||||
// the corresponding worker queues and retry queues, loop queue
|
||||
|
@@ -9,17 +9,18 @@ use Psr\Log\LoggerInterface;
|
||||
|
||||
class MessagePublisher
|
||||
{
|
||||
const EXPORT_MAIL_TYPE = 'exportMail';
|
||||
const SUBDEF_CREATION_TYPE = 'subdefCreation';
|
||||
const WRITE_METADATAS_TYPE = 'writeMetadatas';
|
||||
const ASSETS_INGEST_TYPE = 'assetsIngest';
|
||||
const CREATE_RECORD_TYPE = 'createRecord';
|
||||
const DELETE_RECORD_TYPE = 'deleteRecord';
|
||||
const WEBHOOK_TYPE = 'webhook';
|
||||
const POPULATE_INDEX_TYPE = 'populateIndex';
|
||||
const PULL_ASSETS_TYPE = 'pullAssets';
|
||||
const SUBTITLE_TYPE = 'subtitle';
|
||||
const MAIN_QUEUE_TYPE = 'mainQueue';
|
||||
const EXPORT_MAIL_TYPE = 'exportMail';
|
||||
const SUBDEF_CREATION_TYPE = 'subdefCreation';
|
||||
const WRITE_METADATAS_TYPE = 'writeMetadatas';
|
||||
const ASSETS_INGEST_TYPE = 'assetsIngest';
|
||||
const CREATE_RECORD_TYPE = 'createRecord';
|
||||
const DELETE_RECORD_TYPE = 'deleteRecord';
|
||||
const WEBHOOK_TYPE = 'webhook';
|
||||
const POPULATE_INDEX_TYPE = 'populateIndex';
|
||||
const PULL_ASSETS_TYPE = 'pullAssets';
|
||||
const SUBTITLE_TYPE = 'subtitle';
|
||||
const MAIN_QUEUE_TYPE = 'mainQueue';
|
||||
const EXPOSE_UPLOAD_TYPE = 'exposeUpload';
|
||||
|
||||
|
||||
const MAIN_QUEUE = 'main-queue';
|
||||
@@ -35,6 +36,7 @@ class MessagePublisher
|
||||
const DELETE_RECORD_QUEUE = 'deleterecord-queue';
|
||||
const POPULATE_INDEX_QUEUE = 'populateindex-queue';
|
||||
const PULL_QUEUE = 'pull-queue';
|
||||
const EXPOSE_UPLOAD_QUEUE = 'exposeupload-queue';
|
||||
|
||||
// retry queue
|
||||
// we can use these retry queue with TTL, so when message expires it is requeued to the corresponding worker queue
|
||||
|
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace Alchemy\Phrasea\WorkerManager\Subscriber;
|
||||
|
||||
use Alchemy\Phrasea\WorkerManager\Event\ExposeUploadEvent;
|
||||
use Alchemy\Phrasea\WorkerManager\Event\WorkerEvents;
|
||||
use Alchemy\Phrasea\WorkerManager\Queue\MessagePublisher;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
|
||||
class ExposeSubscriber implements EventSubscriberInterface
|
||||
{
|
||||
/** @var MessagePublisher $messagePublisher */
|
||||
private $messagePublisher;
|
||||
|
||||
public function __construct(MessagePublisher $messagePublisher)
|
||||
{
|
||||
$this->messagePublisher = $messagePublisher;
|
||||
}
|
||||
|
||||
public function onExposeUploadAssets(ExposeUploadEvent $event)
|
||||
{
|
||||
foreach (explode(";", $event->getLst()) as $bas_rec) {
|
||||
$basrec = explode('_', $bas_rec);
|
||||
if (count($basrec) != 2) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$payload = [
|
||||
'message_type' => MessagePublisher::EXPOSE_UPLOAD_TYPE,
|
||||
'payload' => [
|
||||
'recordId' => (int) $basrec[1],
|
||||
'databoxId' => (int) $basrec[0],
|
||||
'exposeName' => $event->getExposeName(),
|
||||
'publicationId' => $event->getPublicationId(),
|
||||
'accessToken' => $event->getAccessToken()
|
||||
]
|
||||
];
|
||||
|
||||
$this->messagePublisher->publishMessage($payload, MessagePublisher::EXPOSE_UPLOAD_QUEUE);
|
||||
}
|
||||
}
|
||||
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return [
|
||||
WorkerEvents::EXPOSE_UPLOAD_ASSETS => 'onExposeUploadAssets',
|
||||
];
|
||||
}
|
||||
}
|
226
lib/Alchemy/Phrasea/WorkerManager/Worker/ExposeUploadWorker.php
Normal file
226
lib/Alchemy/Phrasea/WorkerManager/Worker/ExposeUploadWorker.php
Normal file
@@ -0,0 +1,226 @@
|
||||
<?php
|
||||
|
||||
namespace Alchemy\Phrasea\WorkerManager\Worker;
|
||||
|
||||
use Alchemy\Phrasea\Application\Helper\ApplicationBoxAware;
|
||||
use Alchemy\Phrasea\Model\Entities\WorkerRunningJob;
|
||||
use Alchemy\Phrasea\Model\Repositories\WorkerRunningJobRepository;
|
||||
use Alchemy\Phrasea\Twig\PhraseanetExtension;
|
||||
use Alchemy\Phrasea\WorkerManager\Queue\MessagePublisher;
|
||||
use GuzzleHttp\Client;
|
||||
|
||||
class ExposeUploadWorker implements WorkerInterface
|
||||
{
|
||||
use ApplicationBoxAware;
|
||||
|
||||
/** @var WorkerRunningJobRepository $repoWorker*/
|
||||
private $repoWorker;
|
||||
/** @var MessagePublisher $messagePublisher */
|
||||
private $messagePublisher;
|
||||
|
||||
private $app;
|
||||
|
||||
public function __construct($app)
|
||||
{
|
||||
$this->app = $app;
|
||||
$this->repoWorker = $app['repo.worker-running-job'];
|
||||
$this->messagePublisher = $app['alchemy_worker.message.publisher'];
|
||||
}
|
||||
|
||||
public function process(array $payload)
|
||||
{
|
||||
$em = $this->repoWorker->getEntityManager();
|
||||
$em->beginTransaction();
|
||||
$date = new \DateTime();
|
||||
|
||||
$message = [
|
||||
'message_type' => MessagePublisher::EXPOSE_UPLOAD_TYPE,
|
||||
'payload' => $payload
|
||||
];
|
||||
$workerRunningJob = new WorkerRunningJob();
|
||||
try {
|
||||
$workerRunningJob
|
||||
->setWork(MessagePublisher::EXPOSE_UPLOAD_TYPE)
|
||||
->setDataboxId($payload['databoxId'])
|
||||
->setRecordId($payload['recordId'])
|
||||
->setWorkOn($payload['exposeName'])
|
||||
->setPayload($message)
|
||||
->setPublished($date->setTimestamp($payload['published']))
|
||||
->setStatus(WorkerRunningJob::RUNNING)
|
||||
;
|
||||
|
||||
$em->persist($workerRunningJob);
|
||||
|
||||
$em->flush();
|
||||
|
||||
$em->commit();
|
||||
} catch (\Exception $e) {
|
||||
$em->rollback();
|
||||
}
|
||||
|
||||
$exposeConfiguration = $this->app['conf']->get(['phraseanet-service', 'expose-service', 'exposes'], []);
|
||||
$exposeConfiguration = $exposeConfiguration[$payload['exposeName']];
|
||||
|
||||
$exposeClient = new Client(['base_uri' => $exposeConfiguration['expose_base_uri'], 'http_errors' => false]);
|
||||
|
||||
$record = $this->findDataboxById($payload['databoxId'])->get_record($payload['recordId']);
|
||||
|
||||
try {
|
||||
$helpers = new PhraseanetExtension($this->app);
|
||||
$canSeeBusiness = $helpers->isGrantedOnCollection($record->getBaseId(), [\ACL::CANMODIFRECORD]);
|
||||
|
||||
$captionsByfield = $record->getCaption($helpers->getCaptionFieldOrder($record, $canSeeBusiness));
|
||||
|
||||
$description = "<dl>";
|
||||
|
||||
foreach ($captionsByfield as $name => $value) {
|
||||
if ($helpers->getCaptionFieldGuiVisible($record, $name) == 1) {
|
||||
$description .= "<dt>" . $helpers->getCaptionFieldLabel($record, $name). "</dt>";
|
||||
$description .= "<dd>" . $helpers->getCaptionField($record, $name, $value). "</dd>";
|
||||
}
|
||||
}
|
||||
|
||||
$description .= "</dl>";
|
||||
|
||||
$databox = $record->getDatabox();
|
||||
$caption = $record->get_caption();
|
||||
$lat = $lng = null;
|
||||
|
||||
foreach ($databox->get_meta_structure() as $meta) {
|
||||
if (strpos(strtolower($meta->get_name()), 'longitude') !== FALSE && $caption->has_field($meta->get_name())) {
|
||||
// retrieve value for the corresponding field
|
||||
$fieldValues = $record->get_caption()->get_field($meta->get_name())->get_values();
|
||||
$fieldValue = array_pop($fieldValues);
|
||||
$lng = $fieldValue->getValue();
|
||||
|
||||
} elseif (strpos(strtolower($meta->get_name()), 'latitude') !== FALSE && $caption->has_field($meta->get_name())) {
|
||||
// retrieve value for the corresponding field
|
||||
$fieldValues = $record->get_caption()->get_field($meta->get_name())->get_values();
|
||||
$fieldValue = array_pop($fieldValues);
|
||||
$lat = $fieldValue->getValue();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
$multipartData = [
|
||||
[
|
||||
'name' => 'file',
|
||||
'contents' => fopen($record->get_subdef('document')->getRealPath(), 'r')
|
||||
],
|
||||
[
|
||||
'name' => 'publication_id',
|
||||
'contents' => $payload['publicationId'],
|
||||
|
||||
],
|
||||
[
|
||||
'name' => 'slug',
|
||||
'contents' => 'asset_'. $record->getId()
|
||||
],
|
||||
[
|
||||
'name' => 'description',
|
||||
'contents' => $description
|
||||
]
|
||||
];
|
||||
|
||||
if ($lat !== null) {
|
||||
array_push($multipartData, [
|
||||
'name' => 'lat',
|
||||
'contents' => $lat
|
||||
]);
|
||||
}
|
||||
|
||||
if ($lng !== null) {
|
||||
array_push($multipartData, [
|
||||
'name' => 'lng',
|
||||
'contents' => $lng
|
||||
]);
|
||||
}
|
||||
|
||||
$response = $exposeClient->post('/assets', [
|
||||
'headers' => [
|
||||
'Authorization' => 'Bearer ' . $payload['accessToken']
|
||||
],
|
||||
'multipart' => $multipartData
|
||||
]);
|
||||
|
||||
if ($response->getStatusCode() !==201) {
|
||||
$this->messagePublisher->pushLog("An error occurred when creating asset: status-code " . $response->getStatusCode());
|
||||
}
|
||||
|
||||
$assetsResponse = json_decode($response->getBody(),true);
|
||||
|
||||
// add preview sub-definition
|
||||
|
||||
$this->postSubDefinition(
|
||||
$exposeClient,
|
||||
$payload['accessToken'],
|
||||
$record->get_subdef('preview')->getRealPath(),
|
||||
$assetsResponse['id'],
|
||||
'preview',
|
||||
true
|
||||
);
|
||||
|
||||
// add thumbnail sub-definition
|
||||
|
||||
$this->postSubDefinition(
|
||||
$exposeClient,
|
||||
$payload['accessToken'],
|
||||
$record->get_subdef('thumbnail')->getRealPath(),
|
||||
$assetsResponse['id'],
|
||||
'thumbnail',
|
||||
false,
|
||||
true
|
||||
);
|
||||
|
||||
|
||||
} catch (\Exception $e) {
|
||||
$this->messagePublisher->pushLog("An error occurred when creating asset!");
|
||||
}
|
||||
|
||||
// tell that the upload is finished
|
||||
$this->repoWorker->reconnect();
|
||||
$em->getConnection()->beginTransaction();
|
||||
try {
|
||||
$workerRunningJob->setStatus(WorkerRunningJob::FINISHED);
|
||||
$workerRunningJob->setFinished(new \DateTime('now'));
|
||||
$em->persist($workerRunningJob);
|
||||
$em->flush();
|
||||
$em->commit();
|
||||
} catch (\Exception $e) {
|
||||
$this->messagePublisher->pushLog("Error when wanting to update database :" . $e->getMessage());
|
||||
$em->rollback();
|
||||
}
|
||||
}
|
||||
|
||||
private function postSubDefinition(Client $exposeClient, $token, $path, $assetId, $subdefName, $isPreview = false, $isThumbnail = false)
|
||||
{
|
||||
return $exposeClient->post('/sub-definitions', [
|
||||
'headers' => [
|
||||
'Authorization' => 'Bearer ' .$token
|
||||
],
|
||||
'multipart' => [
|
||||
[
|
||||
'name' => 'file',
|
||||
'contents' => fopen($path, 'r')
|
||||
],
|
||||
[
|
||||
'name' => 'asset_id',
|
||||
'contents' => $assetId,
|
||||
|
||||
],
|
||||
[
|
||||
'name' => 'name',
|
||||
'contents' => $subdefName
|
||||
],
|
||||
[
|
||||
'name' => 'use_as_preview',
|
||||
'contents' => $isPreview
|
||||
],
|
||||
[
|
||||
'name' => 'use_as_thumbnail',
|
||||
'contents' => $isThumbnail
|
||||
]
|
||||
]
|
||||
]);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user