From cde9ce18ae59894ef3f29f7edfb80acc38ce586b Mon Sep 17 00:00:00 2001 From: Nicolas Le Goff Date: Tue, 9 Oct 2012 19:50:10 +0200 Subject: [PATCH] Add prod refactor Fix issue Conflicts: lib/Alchemy/Phrasea/Controller/Prod/Share.php lib/Alchemy/Phrasea/Controller/User/Notifications.php lib/Alchemy/Phrasea/Controller/User/Preferences.php templates/web/common/dialog_export.html.twig --- lib/Alchemy/Phrasea/Application/Root.php | 10 +- .../Phrasea/Controller/Prod/Export.php | 296 ++++++++++++++ .../Phrasea/Controller/Prod/Language.php | 1 + lib/Alchemy/Phrasea/Controller/Prod/Query.php | 326 +++++++++------ .../Controller/Prod/Record/Property.php | 186 ++++++--- lib/Alchemy/Phrasea/Controller/Prod/Root.php | 13 - lib/Alchemy/Phrasea/Controller/Prod/Share.php | 95 +++++ .../Controller/Prod/UserPreferences.php | 68 ---- .../Phrasea/Controller/User/Notifications.php | 123 ++++++ .../Phrasea/Controller/User/Preferences.php | 133 ++++++ lib/classes/eventsmanager/broker.class.php | 2 +- templates/web/common/dialog_export.html.twig | 380 ++++++++++-------- .../web/prod/actions/Property/index.html.twig | 76 +++- 13 files changed, 1282 insertions(+), 427 deletions(-) create mode 100644 lib/Alchemy/Phrasea/Controller/Prod/Export.php create mode 100644 lib/Alchemy/Phrasea/Controller/Prod/Share.php delete mode 100644 lib/Alchemy/Phrasea/Controller/Prod/UserPreferences.php create mode 100644 lib/Alchemy/Phrasea/Controller/User/Notifications.php create mode 100644 lib/Alchemy/Phrasea/Controller/User/Preferences.php diff --git a/lib/Alchemy/Phrasea/Application/Root.php b/lib/Alchemy/Phrasea/Application/Root.php index 88e3e5bad4..41a5daad95 100644 --- a/lib/Alchemy/Phrasea/Application/Root.php +++ b/lib/Alchemy/Phrasea/Application/Root.php @@ -35,6 +35,7 @@ use Alchemy\Phrasea\Controller\Admin\Users; use Alchemy\Phrasea\Controller\Prod\Basket; use Alchemy\Phrasea\Controller\Prod\Bridge; use Alchemy\Phrasea\Controller\Prod\Edit; +use Alchemy\Phrasea\Controller\Prod\Export; use Alchemy\Phrasea\Controller\Prod\Feed; use Alchemy\Phrasea\Controller\Prod\Language; use Alchemy\Phrasea\Controller\Prod\Lazaret; @@ -51,11 +52,12 @@ use Alchemy\Phrasea\Controller\Prod\Tools; use Alchemy\Phrasea\Controller\Prod\Tooltip; use Alchemy\Phrasea\Controller\Prod\TOU; use Alchemy\Phrasea\Controller\Prod\Upload; -use Alchemy\Phrasea\Controller\Prod\UserPreferences; use Alchemy\Phrasea\Controller\Prod\UsrLists; use Alchemy\Phrasea\Controller\Prod\WorkZone; use Alchemy\Phrasea\Controller\Utils\ConnectionTest; use Alchemy\Phrasea\Controller\Utils\PathFileTest; +use Alchemy\Phrasea\Controller\User\Notifications; +use Alchemy\Phrasea\Controller\User\Preferences; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\RedirectResponse; @@ -127,7 +129,6 @@ return call_user_func(function($environment = null) { $app->mount('/admin/tests/connection', new ConnectionTest()); $app->mount('/admin/tests/pathurl', new PathFileTest()); - $app->mount('/prod/UserPreferences/', new UserPreferences()); $app->mount('/prod/query/', new Query()); $app->mount('/prod/order/', new Order()); $app->mount('/prod/baskets', new Basket()); @@ -141,6 +142,8 @@ return call_user_func(function($environment = null) { $app->mount('/prod/bridge/', new Bridge()); $app->mount('/prod/push/', new Push()); $app->mount('/prod/printer/', new Printer()); + $app->mount('/prod/share/', new Share()); + $app->mount('/prod/export/', new Export()); $app->mount('/prod/TOU/', new TOU()); $app->mount('/prod/feeds', new Feed()); $app->mount('/prod/tooltip', new Tooltip()); @@ -150,6 +153,9 @@ return call_user_func(function($environment = null) { $app->mount('/prod/upload/', new Upload()); $app->mount('/prod/', new Prod()); + $app->mount('/user/preferences/', new Preferences()); + $app->mount('/user/notifications/', new Notifications()); + $app->error(function(\Exception $e) use ($app) { $request = $app['request']; diff --git a/lib/Alchemy/Phrasea/Controller/Prod/Export.php b/lib/Alchemy/Phrasea/Controller/Prod/Export.php new file mode 100644 index 0000000000..730e9a3ee3 --- /dev/null +++ b/lib/Alchemy/Phrasea/Controller/Prod/Export.php @@ -0,0 +1,296 @@ +before(function(Request $request) use ($app) { + $app['firewall']->requireNotGuest(); + }); + + /** + * Display multi export + * + * name : export_multi_export + * + * description : Display multi export + * + * method : POST + * + * parameters : none + * + * return : HTML Response + */ + $controllers->post('/multi-export/', $this->call('displayMultiExport')) + ->bind('export_multi_export'); + + /** + * Export by mail + * + * name : export_mail + * + * description : Export by mail + * + * method : POST + * + * parameters : none + * + * return : JSON Response + */ + $controllers->post('/mail/', $this->call('exportMail')) + ->bind('export_mail'); + + /** + * Export by FTP + * + * name : export_ftp + * + * description : Export by FTP + * + * method : POST + * + * parameters : none + * + * return : JSON Response + */ + $controllers->post('/ftp/', $this->call('exportFtp')) + ->bind('export_ftp'); + + /** + * Test FTP connexion + * + * name : export_ftp_test + * + * description : Test a FTP connexion + * + * method : POST + * + * parameters : none + * + * return : JSON Response + */ + $controllers->post('/ftp/test/', $this->call('testFtpConnexion')) + ->bind('export_ftp_test'); + + return $controllers; + } + + /** + * Display form to export documents + * + * @param Application $app + * @param Request $request + * @return Response + */ + public function displayMultiExport(Application $app, Request $request) + { + $download = new \set_export($app, $request->request->get('lst', ''), (int) $request->request->get('ssel'), $request->request->get('story')); + + return new Response($app['twig']->render('common/dialog_export.html.twig', array( + 'download' => $download, + 'ssttid' => $request->request->get('ssel'), + 'lst' => $download->serialize_list(), + 'default_export_title' => $app['phraseanet.registry']->get('GV_default_export_title'), + 'choose_export_title' => $app['phraseanet.registry']->get('GV_choose_export_title') + ))); + } + + /** + * Test a FTP connexion + * + * @param Application $app + * @param Request $request + * @return JsonResponse + */ + public function testFtpConnexion(Application $app, Request $request) + { + if (!$request->isXmlHttpRequest()) { + $app->abort(400); + } + + $success = false; + try { + $ftpClient = $app['phraseanet.ftp.client']($request->request->get('addr', ''), 21, 90, !!$request->request->get('ssl')); + $ftpClient->login($request->request->get('login', ''), $request->request->get('pwd', '')); + $ftpClient->close(); + $msg = _('Connection to FTP succeed'); + $success = true; + } catch (Exception $e) { + $msg = sprintf(_('Error while connecting to FTP')); + } + + return $app->json(array( + 'success' => $success, + 'message' => $msg + )); + } + + /** + * + * @param Application $app + * @param Request $request + * @return JsonResponse + */ + public function exportFtp(Application $app, Request $request) + { + $download = new \set_exportftp($app, $request->request->get('lst'), $request->request->get('ssttid')); + + if (null === $address = $request->request->get('addr')) { + $app->abort(400, _('Missing ftp adress')); + } + + if (null === $login = $request->request->get('login')) { + $app->abort(400, _('Missing ftp lofin')); + } + + if (null === $destFolder = $request->request->get('destfolder')) { + $app->abort(400, _('Missing destination folder')); + } + + if (null === $folderTocreate = $request->request->get('NAMMKDFOLD')) { + $app->abort(400, _('Missing folder to create')); + } + + if (null === $subdefs = $request->request->get('obj')) { + $app->abort(400, _('Missing subdefs to export')); + } + + if (count($download->get_display_ftp()) == 0) { + + return $app->json(array('success' => false, 'message' => _('Documents can be sent by FTP'))); + } else { + try { + $download->prepare_export($app['phraseanet.user'], $app['filesystem'], $request->request->get('obj'), false, $request->request->get('businessfields')); + $download->export_ftp($request->request->get('user_dest'), $address, $login, $request->request->get('pwd', ''), $request->request->get('ssl'), $request->request->get('nbretry'), $request->request->get('passif'), $destFolder, $folderTocreate, $request->request->get('logfile')); + + return $app->json(array( + 'success' => true, + 'message' => _('Export saved in the waiting queue') + )); + } catch (Exception $e) { + + return $app->json(array( + 'success' => false, + 'message' => _('Something gone wrong') + )); + } + } + } + + public function exportMail(Application $app, Request $request) + { + set_time_limit(0); + session_write_close(); + ignore_user_abort(true); + + //prepare export + $download = new \set_export($app, $request->get('lst', ''), $request->get('ssttid', '')); + $list = $download->prepare_export($app['phraseanet.user'], $app['filesystem'], $request->get('obj'), $request->get("type") == "title" ? : false, $request->get('businessfields')); + $list['export_name'] = sprintf("%s.zip", $download->getExportName()); + $list['email'] = $request->get("destmail", ""); + + $destMails = array(); + //get destination mails + foreach (explode(";", $list['email']) as $mail) { + if (filter_var($mail, FILTER_VALIDATE_EMAIL)) { + $destMails[] = $mail; + } else { + $app['events-manager']->trigger('__EXPORT_MAIL_FAIL__', array( + 'usr_id' => $app['phraseanet.user']->get_id(), + 'lst' => $request->get('lst', ''), + 'ssttid' => $request->get('ssttid', ''), + 'dest' => $mail, + 'reason' => \eventsmanager_notify_downloadmailfail::MAIL_NO_VALID + )); + } + } + + //generate validation token + $endDateObject = new \DateTime('+1 day'); + $token = \random::getUrlToken($app, \random::TYPE_EMAIL, false, $endDateObject, serialize($list)); + + if (count($destMails) > 0 && $token) { + //zip documents + \set_export::build_zip(new Filesystem(), $token, $list, $app['phraseanet.registry']->get('GV_RootPath') . 'tmp/download/' . $token . '.zip'); + + $remaingEmails = $destMails; + + $url = $app['phraseanet.registry']->get('GV_ServerName') . 'mail-export/' . $token . '/'; + + $from = array( + 'name' => $app['phraseanet.user']->get_display_name(), + 'email' => $app['phraseanet.user']->get_email() + ); + + //send mails + foreach ($destMails as $key => $mail) { + if (\mail::send_documents($app, trim($mail), $url, $from, $endDateObject, $request->get('textmail'), $request->get('reading_confirm') == '1' ? : false)) { + unset($remaingEmails[$key]); + } + } + + //some mails failed + if (count($remaingEmails) > 0) { + foreach ($remaingEmails as $mail) { + $app['events-manager']->trigger('__EXPORT_MAIL_FAIL__', array( + 'usr_id' => $app['phraseanet.user']->get_id(), + 'lst' => $request->get('lst', ''), + 'ssttid' => $request->get('ssttid', ''), + 'dest' => $mail, + 'reason' => \eventsmanager_notify_downloadmailfail::MAIL_FAIL + )); + } + } + } elseif (!$token && count($destMails) > 0) { //couldn't generate token + foreach ($destMails as $mail) { + $app['events-manager']->trigger('__EXPORT_MAIL_FAIL__', array( + 'usr_id' => $app['phraseanet.user']->get_id(), + 'lst' => $request->get('lst', ''), + 'ssttid' => $request->get('ssttid', ''), + 'dest' => $mail, + 'reason' => 0 + )); + } + } + } + + /** + * Prefix the method to call with the controller class name + * + * @param string $method The method to call + * @return string + */ + private function call($method) + { + return sprintf('%s::%s', __CLASS__, $method); + } +} diff --git a/lib/Alchemy/Phrasea/Controller/Prod/Language.php b/lib/Alchemy/Phrasea/Controller/Prod/Language.php index 0266f05e61..941f952ba6 100644 --- a/lib/Alchemy/Phrasea/Controller/Prod/Language.php +++ b/lib/Alchemy/Phrasea/Controller/Prod/Language.php @@ -101,6 +101,7 @@ class Language implements ControllerProviderInterface $out['feedbackCanContribute'] = _('User contribute to the feedback'); $out['feedbackCanSeeOthers'] = _('User can see others choices'); $out['forceSendDocument'] = _('Force sending of the document ?'); + $out['export'] = _('Export'); return $app->json($out); }); diff --git a/lib/Alchemy/Phrasea/Controller/Prod/Query.php b/lib/Alchemy/Phrasea/Controller/Prod/Query.php index 9975c4b7c3..65e17a9a73 100644 --- a/lib/Alchemy/Phrasea/Controller/Prod/Query.php +++ b/lib/Alchemy/Phrasea/Controller/Prod/Query.php @@ -13,7 +13,9 @@ namespace Alchemy\Phrasea\Controller\Prod; use Silex\Application; use Silex\ControllerProviderInterface; +use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; /** * @@ -28,180 +30,252 @@ class Query implements ControllerProviderInterface $controllers = $app['controllers_factory']; $controllers->before(function(Request $request) use ($app) { - $app['firewall']->requireAuthentication(); - }); + $app['firewall']->requireAuthentication(); + }); - $controllers->post('/', function(Application $app, Request $request) { - $query = (string) $request->request->get('qry'); + $controllers->post('/', $this->call('query')) + ->bind('prod_query'); + + $controllers->post('/answer-train/', $this->call('queryAnswerTrain')) + ->bind('preview_answer_train'); - $mod = $app['phraseanet.user']->getPrefs('view'); + $controllers->post('/reg-train/', $this->call('queryRegTrain')) + ->bind('preview_reg_train'); - $json = array(); + return $controllers; + } - $options = new \searchEngine_options(); + /** + * Query Phraseanet to fetch records + * + * @param Application $app + * @param Request $request + * @return JsonResponse + */ + public function query(Application $app, Request $request) + { + $query = (string) $request->request->get('qry'); - $bas = is_array($request->request->get('bas')) ? $request->request->get('bas') : array_keys($user->ACL()->get_granted_base()); + $mod = $app['phraseanet.user']->getPrefs('view'); - if ($app['phraseanet.user']->ACL()->has_right('modifyrecord')) { - $options->set_business_fields(array()); + $json = array(); - $BF = array(); + $options = new \searchEngine_options(); - foreach ($app['phraseanet.user']->ACL()->get_granted_base(array('canmodifrecord')) as $collection) { - if (count($bas) === 0 || in_array($collection->get_base_id(), $bas)) { - $BF[] = $collection->get_base_id(); - } + $bas = is_array($request->request->get('bas')) ? $request->request->get('bas') : array_keys($user->ACL()->get_granted_base()); + + if ($app['phraseanet.user']->ACL()->has_right('modifyrecord')) { + $options->set_business_fields(array()); + + $BF = array(); + + foreach ($app['phraseanet.user']->ACL()->get_granted_base(array('canmodifrecord')) as $collection) { + if (count($bas) === 0 || in_array($collection->get_base_id(), $bas)) { + $BF[] = $collection->get_base_id(); } - $options->set_business_fields($BF); - } else { - $options->set_business_fields(array()); } + $options->set_business_fields($BF); + } else { + $options->set_business_fields(array()); + } - $status = is_array($request->request->get('status')) ? $request->request->get('status') : array(); - $fields = is_array($request->request->get('fields')) ? $request->request->get('fields') : array(); + $status = is_array($request->request->get('status')) ? $request->request->get('status') : array(); + $fields = is_array($request->request->get('fields')) ? $request->request->get('fields') : array(); - $options->set_fields($fields); - $options->set_status($status); - $options->set_bases($bas, $app['phraseanet.user']->ACL()); + $options->set_fields($fields); + $options->set_status($status); + $options->set_bases($bas, $app['phraseanet.user']->ACL()); - $options->set_search_type($request->request->get('search_type')); - $options->set_record_type($request->request->get('recordtype')); - $options->set_min_date($request->request->get('datemin')); - $options->set_max_date($request->request->get('datemax')); - $options->set_date_fields(explode('|', $request->request->get('datefield'))); - $options->set_sort($request->request->get('sort'), $request->request->get('ord', PHRASEA_ORDER_DESC)); - $options->set_use_stemming($request->request->get('stemme')); + $options->set_search_type($request->request->get('search_type')); + $options->set_record_type($request->request->get('recordtype')); + $options->set_min_date($request->request->get('datemin')); + $options->set_max_date($request->request->get('datemax')); + $options->set_date_fields(explode('|', $request->request->get('datefield'))); + $options->set_sort($request->request->get('sort'), $request->request->get('ord', PHRASEA_ORDER_DESC)); + $options->set_use_stemming($request->request->get('stemme')); - $form = serialize($options); + $form = serialize($options); - $perPage = (int) $app['phraseanet.user']->getPrefs('images_per_page'); + $perPage = (int) $app['phraseanet.user']->getPrefs('images_per_page'); - $search_engine = new \searchEngine_adapter($app); - $search_engine->set_options($options); + $search_engine = new \searchEngine_adapter($app); + $search_engine->set_options($options); - $page = (int) $request->request->get('pag'); + $page = (int) $request->request->get('pag'); - if ($page < 1) { - $search_engine->set_is_first_page(true); - $search_engine->reset_cache(); - $page = 1; - } + if ($page < 1) { + $search_engine->set_is_first_page(true); + $search_engine->reset_cache(); + $page = 1; + } - $result = $search_engine->query_per_page($query, $page, $perPage); + $result = $search_engine->query_per_page($query, $page, $perPage); - $proposals = $search_engine->is_first_page() ? $result->get_propositions() : false; + $proposals = $search_engine->is_first_page() ? $result->get_propositions() : false; - $npages = $result->get_total_pages(); + $npages = $result->get_total_pages(); - $page = $result->get_current_page(); + $page = $result->get_current_page(); - $string = ''; + $string = ''; - if ($npages > 1) { + if ($npages > 1) { - $d2top = ($npages - $page); - $d2bottom = $page; + $d2top = ($npages - $page); + $d2bottom = $page; - if (min($d2top, $d2bottom) < 4) { - if ($d2bottom < 4) { - for ($i = 1; ($i <= 4 && (($i <= $npages) === true)); $i++) { - if ($i == $page) - $string .= ''; - else - $string .= "" . $i . ""; - } - if ($npages > 4) - $string .= ">>"; - } else { - $start = $npages - 4; - if (($start) > 0) - $string .= "<<"; - else - $start = 1; - for ($i = ($start); $i <= $npages; $i++) { - if ($i == $page) - $string .= ''; - else - $string .= "" . $i . ""; - } - } - } else { - $string .= "<<"; - - for ($i = ($page - 2); $i <= ($page + 2); $i++) { + if (min($d2top, $d2bottom) < 4) { + if ($d2bottom < 4) { + for ($i = 1; ($i <= 4 && (($i <= $npages) === true)); $i++) { + if ($i == $page) + $string .= ''; + else + $string .= "" . $i . ""; + } + if ($npages > 4) + $string .= ">>"; + } else { + $start = $npages - 4; + if (($start) > 0) + $string .= "<<"; + else + $start = 1; + for ($i = ($start); $i <= $npages; $i++) { if ($i == $page) $string .= ''; else $string .= "" . $i . ""; } - - $string .= ">>"; } - } - $string .= '
'; - - $explain = "
"; - - $explain .= ""; - - if ($result->get_count_total_results() != $result->get_count_available_results()) { - $explain .= sprintf(_('reponses:: %d Resultats rappatries sur un total de %d trouves'), $result->get_count_available_results(), $result->get_count_total_results()); } else { - $explain .= sprintf(_('reponses:: %d Resultats'), $result->get_count_total_results()); + $string .= "<<"; + + for ($i = ($page - 2); $i <= ($page + 2); $i++) { + if ($i == $page) + $string .= ''; + else + $string .= "" . $i . ""; + } + + $string .= ">>"; } + } + $string .= '
'; - $explain .= "
"; - $explain .= '
' . $result->get_query_time() . ' s
dans index ' . $result->get_search_indexes(); - $explain .= "
"; + $explain = "
"; - $infoResult = '' . sprintf(_('reponses:: %d reponses'), $result->get_count_total_results()) . ' | ' . sprintf(_('reponses:: %s documents selectionnes'), ''); + $explain .= ""; - $json['infos'] = $infoResult; - $json['navigation'] = $string; + if ($result->get_count_total_results() != $result->get_count_available_results()) { + $explain .= sprintf(_('reponses:: %d Resultats rappatries sur un total de %d trouves'), $result->get_count_available_results(), $result->get_count_total_results()); + } else { + $explain .= sprintf(_('reponses:: %d Resultats'), $result->get_count_total_results()); + } - $prop = null; + $explain .= " "; + $explain .= '
' . $result->get_query_time() . ' s
dans index ' . $result->get_search_indexes(); + $explain .= "
"; - if ($search_engine->is_first_page()) { - $propals = $result->get_suggestions($app['locale.I18n']); - if (count($propals) > 0) { - foreach ($propals as $prop_array) { - if ($prop_array['value'] !== $query && $prop_array['hits'] > $result->get_count_total_results()) { - $prop = $prop_array['value']; - break; - } + $infoResult = '' . sprintf(_('reponses:: %d reponses'), $result->get_count_total_results()) . ' | ' . sprintf(_('reponses:: %s documents selectionnes'), ''); + + $json['infos'] = $infoResult; + $json['navigation'] = $string; + + $prop = null; + + if ($search_engine->is_first_page()) { + $propals = $result->get_suggestions($app['locale.I18n']); + if (count($propals) > 0) { + foreach ($propals as $prop_array) { + if ($prop_array['value'] !== $query && $prop_array['hits'] > $result->get_count_total_results()) { + $prop = $prop_array['value']; + break; } } } + } - if ($result->get_count_total_results() === 0) { - $template = 'prod/results/help.html.twig'; + if ($result->get_count_total_results() === 0) { + $template = 'prod/results/help.html.twig'; + } else { + if ($mod == 'thumbs') { + $template = 'prod/results/answergrid.html.twig'; } else { - if ($mod == 'thumbs') { - $template = 'prod/results/answergrid.html.twig'; - } else { - $template = 'prod/results/answerlist.html.twig'; - } + $template = 'prod/results/answerlist.html.twig'; } + } - $json['results'] = $app['twig']->render($template, array( - 'results' => $result, - 'GV_social_tools' => $app['phraseanet.registry']->get('GV_social_tools'), - 'highlight' => $search_engine->get_query(), - 'searchEngine' => $search_engine, - 'suggestions' => $prop - ) - ); + $json['results'] = $app['twig']->render($template, array( + 'results' => $result, + 'GV_social_tools' => $app['phraseanet.registry']->get('GV_social_tools'), + 'highlight' => $search_engine->get_query(), + 'searchEngine' => $search_engine, + 'suggestions' => $prop + ) + ); - $json['query'] = $query; - $json['phrasea_props'] = $proposals; - $json['total_answers'] = (int) $result->get_count_available_results(); - $json['next_page'] = ($page < $npages && $result->get_count_available_results() > 0) ? ($page + 1) : false; - $json['prev_page'] = ($page > 1 && $result->get_count_available_results() > 0) ? ($page - 1) : false; - $json['form'] = $form; + $json['query'] = $query; + $json['phrasea_props'] = $proposals; + $json['total_answers'] = (int) $result->get_count_available_results(); + $json['next_page'] = ($page < $npages && $result->get_count_available_results() > 0) ? ($page + 1) : false; + $json['prev_page'] = ($page > 1 && $result->get_count_available_results() > 0) ? ($page - 1) : false; + $json['form'] = $form; - return $app->json($json); - }); + return $app->json($json); + } - return $controllers; + /** + * + * @param Application $app + * @param Request $request + * @return JsonResponse + */ + public function queryAnswerTrain(Application $app, Request $request) + { + $searchEngine = null; + + if (($options = unserialize($request->request->get('options_serial'))) !== false) { + $searchEngine = new \searchEngine_adapter($app); + $searchEngine->set_options($options); + } + + $pos = $request->request->get('pos'); + $query = $request->request->get('query'); + + $record = new \record_preview($app, 'RESULT', $pos, '', '', $searchEngine, $query); + + return $app->json(array( + 'current' => $app['twig']->render('prod/preview/result_train.html.twig', array( + 'records' => $record->get_train($pos, $query, $searchEngine), + 'selected' => $pos + )) + )); + } + + /** + * + * @param Application $app + * @param Request $request + * @return Response + */ + public function queryRegTrain(Application $app, Request $request) + { + $record = new \record_preview($app, 'REG', $request->request->get('pos'), $request->request->get('cont')); + + return $app['twig']->render('prod/preview/reg_train.html.twig', array( + 'container_records' => $record->get_container()->get_children(), + 'record' => $record + )); + } + + /** + * Prefix the method to call with the controller class name + * + * @param string $method The method to call + * @return string + */ + private function call($method) + { + return sprintf('%s::%s', __CLASS__, $method); } } diff --git a/lib/Alchemy/Phrasea/Controller/Prod/Record/Property.php b/lib/Alchemy/Phrasea/Controller/Prod/Record/Property.php index 0e82a42461..654cae990a 100644 --- a/lib/Alchemy/Phrasea/Controller/Prod/Record/Property.php +++ b/lib/Alchemy/Phrasea/Controller/Prod/Record/Property.php @@ -14,6 +14,7 @@ namespace Alchemy\Phrasea\Controller\Prod\Record; use Alchemy\Phrasea\Controller\RecordsRequest; use Silex\Application; use Silex\ControllerProviderInterface; +use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; @@ -39,12 +40,54 @@ class Property implements ControllerProviderInterface } }); + /** + * Display records property + * + * name : display_property + * + * description : Display records property + * + * method : GET + * + * parameters : none + * + * return : HTML Response + */ $controllers->get('/', $this->call('displayProperty')) ->bind('display_property'); + /** + * Change records status + * + * name : change_status + * + * description : Change records status + * + * method : POST + * + * parameters : none + * + * return : JSON Response + */ $controllers->post('/status/', $this->call('changeStatus')) ->bind('change_status'); + /** + * Change records type + * + * name : change_type + * + * description : Change records type + * + * method : POST + * + * parameters : none + * + * return : JSON Response + */ + $controllers->post('/type/', $this->call('changeType')) + ->bind('change_type'); + return $controllers; } @@ -69,20 +112,54 @@ class Property implements ControllerProviderInterface if (!$app['phraseanet.user']->ACL()->has_hd_grant($record) || !$app['phraseanet.user']->ACL()->has_preview_grant($record)) { try { - $conn = $record->get_databox()->get_connection(); - - $sql = sprintf('SELECT record_id FROM record WHERE ((status ^ %s) & %s) = 0 AND record_id = :record_id', $app['phraseanet.user']->ACL()->get_mask_xor($record->get_base_id()), $app['phraseanet.user']->ACL()->get_mask_and($record->get_base_id())); - - $stmt = $conn->prepare($sql); + $stmt = $record->get_databox()->get_connection()->prepare(sprintf('SELECT record_id FROM record WHERE ((status ^ %s) & %s) = 0 AND record_id = :record_id', $app['phraseanet.user']->ACL()->get_mask_xor($record->get_base_id()), $app['phraseanet.user']->ACL()->get_mask_and($record->get_base_id()))); $stmt->execute(array(':record_id' => $record->get_record_id())); if (0 === $stmt->rowCount()) { $toRemove[] = $key; + } else { + //perform logic + $sbasId = $record->get_databox()->get_sbas_id(); + + if (!isset($nRec[$sbasId])) { + $nRec[$sbasId] = array('stories' => 0, 'records' => 0); + } + + $nRec[$sbasId]['records']++; + + if ($record->is_grouping()) { + $nRec[$sbasId]['stories']++; + } + + if (!isset($recordsType[$sbasId])) { + $recordsType[$sbasId] = array(); + } + + if (!isset($recordsType[$sbasId][$record->get_type()])) { + $recordsType[$sbasId][$record->get_type()] = array(); + } + + $recordsType[$sbasId][$record->get_type()][] = $record; + + if (!isset($statusBit[$sbasId])) { + + $statusBit[$sbasId] = isset($databoxStatus[$sbasId]) ? $databoxStatus[$sbasId] : array(); + + foreach (array_keys($statusBit[$sbasId]) as $bit) { + $statusBit[$sbasId][$bit]['nset'] = 0; + } + } + + $status = strrev($record->get_status()); + + foreach (array_keys($statusBit[$sbasId]) as $bit) { + $statusBit[$sbasId][$bit]["nset"] += substr($status, $bit, 1) !== "0" ? 1 : 0; + } } $stmt->closeCursor(); unset($stmt); - } catch (Exception $e) { + } catch (\Exception $e) { $toRemove[] = $key; } } @@ -92,45 +169,6 @@ class Property implements ControllerProviderInterface $records->remove($key); } - foreach ($records as $record) { - $sbasId = $record->get_databox()->get_sbas_id(); - - if (!isset($nRec[$sbasId])) { - $nRec[$sbasId] = array('stories' => 0, 'records' => 0); - } - - $nRec[$sbasId]['records']++; - - if ($record->is_grouping()) { - $nRec[$sbasId]['stories']++; - } - - if (!isset($recordsType[$sbasId])) { - $recordsType[$sbasId] = array(); - } - - if (!isset($recordsType[$sbasId][$record->get_type()])) { - $recordsType[$sbasId][$record->get_type()] = array(); - } - - $recordsType[$sbasId][$record->get_type()] = $record; - - if (!isset($statusBit[$sbasId])) { - - $statusBit[$sbasId] = isset($databoxStatus[$sbasId]) ? $databoxStatus[$sbasId] : array(); - - foreach (array_keys($statusBit[$sbasId]) as $bit) { - $statusBit[$sbasId][$bit]['nset'] = 0; - } - } - - $status = strrev($record->get_status()); - - foreach (array_keys($statusBit[$sbasId]) as $bit) { - $statusBit[$sbasId][$bit]["nset"] += substr($status, $bit, 1) !== "0" ? 1 : 0; - } - } - foreach ($records->databoxes() as $databox) { $sbasId = $databox->get_sbas_id(); foreach ($statusBit[$sbasId] as $bit => $values) { @@ -138,14 +176,21 @@ class Property implements ControllerProviderInterface } } - return $app['twig']->render('prod/actions/Property/index.html.twig', array( + return new Response($app['twig']->render('prod/actions/Property/index.html.twig', array( 'records' => $records, 'statusBit' => $statusBit, 'recordsType' => $recordsType, 'nRec' => $nRec - )); + ))); } + /** + * Change record status + * + * @param Application $app + * @param Request $request + * @return JsonResponse + */ public function changeStatus(Application $app, Request $request) { $applyStatusToChildren = $request->request->get('apply_to_children', array()); @@ -157,12 +202,16 @@ class Property implements ControllerProviderInterface $sbasId = $record->get_databox()->get_sbas_id(); //update record - $updated[$record->get_serialize_key()] = $this->updateRecordStatus($record, $postStatus); + if (null !== $updatedStatus = $this->updateRecordStatus($record, $postStatus)) { + $updated[$record->get_serialize_key()] = $updatedStatus; + } //update children if current record is a story if (isset($applyStatusToChildren[$sbasId]) && $record->is_grouping()) { foreach ($record->get_children() as $child) { - $updated[$record->get_serialize_key()] = $this->updateRecordStatus($child, $postStatus); + if (null !== $updatedStatus = $this->updateRecordStatus($child, $postStatus)) { + $updated[$record->get_serialize_key()] = $updatedStatus; + } } } } @@ -170,6 +219,43 @@ class Property implements ControllerProviderInterface return $app->json(array('success' => true, 'updated' => $updated), 201); } + /** + * Change record type + * + * @param Application $app + * @param Request $request + * @return type + */ + public function changeType(Application $app, Request $request) + { + $typeLst = $request->request('types', array()); + $records = RecordsRequest::fromRequest($app, $request, false, array('modifyrecord')); + $forceType = $request->request('force_types', ''); + $updated = array(); + + foreach ($records as $record) { + try { + $recordType = !empty($forceType) ? $forceType : (isset($typeLst[$record->get_serialize_key()]) ? $typeLst[$record->get_serialize_key()] : null); + + if ($recordType) { + $record->setType($recordType); + $updated[$record->get_serialize_key()] = $recordType; + } + } catch (\Exception $e) { + + } + } + + return $app->json(array('success' => true, 'updated' => $updated), 201); + } + + /** + * Set new status to selected record + * + * @param \record_adapter $record + * @param array $postStatus + * @return array|null + */ private function updateRecordStatus(\record_adapter $record, Array $postStatus) { $sbasId = $record->get_databox()->get_sbas_id(); @@ -190,6 +276,8 @@ class Property implements ControllerProviderInterface 'new_status' => $newStatus ); } + + return null; } /** diff --git a/lib/Alchemy/Phrasea/Controller/Prod/Root.php b/lib/Alchemy/Phrasea/Controller/Prod/Root.php index fb4aa66293..4cea156ef5 100644 --- a/lib/Alchemy/Phrasea/Controller/Prod/Root.php +++ b/lib/Alchemy/Phrasea/Controller/Prod/Root.php @@ -126,19 +126,6 @@ class Root implements ControllerProviderInterface )); }); - $controllers->post('/multi-export/', function(Application $app, Request $request) { - - $download = new \set_export($app, $request->request->get('lst', ''), (int) $request->request->get('ssel'), $request->request->get('story')); - - return $app['twig']->render('common/dialog_export.html.twig', array( - 'download' => $download, - 'ssttid' => (int) $request->request->get('ssel'), - 'lst' => $download->serialize_list(), - 'default_export_title' => $app['phraseanet.registry']->get('GV_default_export_title'), - 'choose_export_title' => $app['phraseanet.registry']->get('GV_choose_export_title') - )); - }); - return $controllers; } } diff --git a/lib/Alchemy/Phrasea/Controller/Prod/Share.php b/lib/Alchemy/Phrasea/Controller/Prod/Share.php new file mode 100644 index 0000000000..cd2dfa50c6 --- /dev/null +++ b/lib/Alchemy/Phrasea/Controller/Prod/Share.php @@ -0,0 +1,95 @@ +before(function(Request $request) use ($app) { + $response = $app['firewall']->requireNotGuest(); + if ($response instanceof Response) { + return $response; + } + }); + + /** + * Share a record + * + * name : share_record + * + * description : Share a record + * + * method : GET + * + * parameters : none + * + * return : HTML Response + */ + $controllers->get('/record/{base_id}/{record_id}/', $this->call('shareRecord')) + ->before(function(Request $request) use ($app) { + $app['firewall']->requireRightOnBase(\phrasea::sbasFromBas($app, $request->attributes->get('base_id')), 'bas_chupub'); + }) + ->bind('share_record'); + + return $controllers; + } + + /** + * Share a record + * + * @param Application $app + * @param Request $request + * @param integer $base_id + * @param integer $record_id + * @return Response + */ + public function shareRecord(Application $app, Request $request, $base_id, $record_id) + { + $record = new \record_adapter($app, \phrasea::sbasFromBas($app, $base_id), $record_id); + + if ( ! $app['phraseanet.user']->ACL()->has_access_to_subdef($record, 'preview')){ + $app->abort(403); + } + + return new Response($app['twig']->render('prod/Share/record.html.twig', array( + 'record' => $record, + ))); + } + + /** + * Prefix the method to call with the controller class name + * + * @param string $method The method to call + * @return string + */ + private function call($method) + { + return sprintf('%s::%s', __CLASS__, $method); + } +} diff --git a/lib/Alchemy/Phrasea/Controller/Prod/UserPreferences.php b/lib/Alchemy/Phrasea/Controller/Prod/UserPreferences.php deleted file mode 100644 index 196a304166..0000000000 --- a/lib/Alchemy/Phrasea/Controller/Prod/UserPreferences.php +++ /dev/null @@ -1,68 +0,0 @@ -before(function(Request $request) use ($app) { - $app['firewall']->requireAuthentication(); - }); - - $controllers->post('/save/', $this->call('savePreference')); - - return $controllers; - } - - public function savePreference(Application $app, Request $request) - { - $ret = array('success' => false, 'message' => _('Error while saving preference')); - - try { - $ret = $app['phraseanet.user']->setPrefs($request->request->get('prop'), $request->request->get('value')); - - if ($ret == $request->request->get('value')) - $output = "1"; else - $output = "0"; - - $ret = array('success' => true, 'message' => _('Preference saved !')); - } catch (\Exception $e) { - - } - - return $app->json($ret); - } - - /** - * Prefix the method to call with the controller class name - * - * @param string $method The method to call - * @return string - */ - private function call($method) - { - return sprintf('%s::%s', __CLASS__, $method); - } -} diff --git a/lib/Alchemy/Phrasea/Controller/User/Notifications.php b/lib/Alchemy/Phrasea/Controller/User/Notifications.php new file mode 100644 index 0000000000..2d9221d2ec --- /dev/null +++ b/lib/Alchemy/Phrasea/Controller/User/Notifications.php @@ -0,0 +1,123 @@ +before(function(Request $request) use ($app) { + $app['firewall']->requireNotGuest(); + }); + + + /** + * Read all notifications + * + * name : read_notifications_full + * + * description : Read full notification + * + * method : GET + * + * parameters : none + * + * return : JSON Response + */ + $controllers->get('/', $this->call('listNotifications')) + ->bind('get_notifications'); + + /** + * Read notifications + * + * name : read_notifications + * + * description : Read notification + * + * method : GET + * + * parameters : none + * + * return : JSON Response + */ + $controllers->post('/read/', $this->call('setNotificationsReaded')) + ->bind(''); + + return $controllers; + } + + /** + * Get the new notifications + * + * @param Application $app + * @param Request $request + * @return JsonResponse + */ + public function setNotificationsReaded(Application $app, Request $request) + { + if(!$request->isXmlHttpRequest()) { + $app->abort(400); + } + + try { + $app['events-manager']->read(explode('_', (string) $request->query->get('notifications')), $app['phraseanet.user']->get_id()); + + return $app->json(array('success' => true, 'message' => '')); + } catch (Exception $e) { + + return $app->json(array('success' => false, 'message' => $e->getMessage())); + } + } + + /** + * Get all notifications + * + * @param Application $app + * @param Request $request + * @return JsonResponse + */ + public function listNotifications(Application $app, Request $request) + { + if(!$request->isXmlHttpRequest()) { + $app->abort(400); + } + + $page = (int) $request->query->get('page', 1); + return $app->json($app['events-manager']->get_json_notifications(($page < 1 ? 1 : $page))); + } + + /** + * Prefix the method to call with the controller class name + * + * @param string $method The method to call + * @return string + */ + private function call($method) + { + return sprintf('%s::%s', __CLASS__, $method); + } +} diff --git a/lib/Alchemy/Phrasea/Controller/User/Preferences.php b/lib/Alchemy/Phrasea/Controller/User/Preferences.php new file mode 100644 index 0000000000..7d8d4e5c8e --- /dev/null +++ b/lib/Alchemy/Phrasea/Controller/User/Preferences.php @@ -0,0 +1,133 @@ +before(function(Request $request) use ($app) { + $app['firewall']->requireAuthentication(); + }); + + /** + * Save preferences + * + * name : save_pref + * + * description : Save User preferences + * + * method : POST + * + * parameters : none + * + * return : JSON Response + */ + $controllers->post('/', $this->call('saveUserPref')) + ->bind('save_pref'); + + /** + * Save CSS preferences + * + * name : save_css_pref + * + * description : Save CSS preferences + * + * method : POST + * + * parameters : none + * + * return : JSON Response + */ + $controllers->post('/temporary/', $this->call('saveTemporaryPref')) + ->bind('save_css_pref'); + + return $controllers; + } + + /** + * Save user production preferenes + * + * @param Application $app + * @param Request $request + * @return JsonResponse + */ + public function saveTemporaryPref(Application $app, Request $request) + { + if(!$request->isXmlHttpRequest()) { + $app->abort(400); + } + + $prop = $request->request->get('prop'); + $value = $request->request->get('value'); + $success = false; + + if($prop && $value) { + $app['session']->set('pref.' . $prop, $value); + $success = true; + } + + return new JsonResponse(array('success' => $success)); + } + + /** + * Save css production preferenes + * + * @param Application $app + * @param Request $request + * @return JsonResponse + */ + public function saveUserPref(Application $app, Request $request) + { + if(!$request->isXmlHttpRequest()) { + $app->abort(400); + } + + $msg = _('Error while saving preference'); + $prop = $request->request->get('prop'); + $value = $request->request->get('value'); + + $success = false; + if($prop && $value) { + $success = ! ! $app['phraseanet.user']->setPrefs($prop, $value); + $msg = _('Preference saved !'); + } + + return new JsonResponse(array('success' => $success, 'message' => $msg)); + } + + /** + * Prefix the method to call with the controller class name + * + * @param string $method The method to call + * @return string + */ + private function call($method) + { + return sprintf('%s::%s', __CLASS__, $method); + } +} diff --git a/lib/classes/eventsmanager/broker.class.php b/lib/classes/eventsmanager/broker.class.php index 1a2ce98e5e..1adbe2dad0 100644 --- a/lib/classes/eventsmanager/broker.class.php +++ b/lib/classes/eventsmanager/broker.class.php @@ -203,7 +203,7 @@ class eventsmanager_broker $data['next'] = '' . _('charger d\'avantages de notifications') . ''; } - return p4string::jsonencode($datas); + return p4string::jsonencode($data); } public function get_unread_notifications_number() diff --git a/templates/web/common/dialog_export.html.twig b/templates/web/common/dialog_export.html.twig index 525cb71dec..a0e39659bb 100644 --- a/templates/web/common/dialog_export.html.twig +++ b/templates/web/common/dialog_export.html.twig @@ -76,24 +76,18 @@ {% endmacro %} -{% if download.get_total_download() <= 0 and download.get_total_order() <= 0 and download.get_total_ftp() <= 0%} -
-

{% trans 'Les documents ne peuvent pas etre exportes' %}

- -
-{% endif %} +{% if app['phraseanet.registry'].get('GV_needAuth2DL') and app['phraseanet.user'].is_guest() %} + +{% else %} -
- {% if download.get_total_download() > 0 %} @@ -233,14 +227,8 @@ {% endtrans %}
- {% endif %} -
- - - -
- - + + {% endif %} @@ -270,108 +258,123 @@ {% endfor %} {% endif %} - - {% endif %} - {% endfor %} -
-
- - - -
- -
- -
+
+ + + +
+ +
+ + {% endif %} + {% if download.get_total_order() > 0 %} +
+ {% for name, values in download.get_display_orderable() %} + {% if values.available > 0 %} +
+ {% set docs_orderable = values.available %} + {% trans %}{{docs_orderable}} documents commandes{% endtrans %} + {% set docs_not_orderable = values.total - values.available %} + {% if docs_not_orderable > 0%} + {% trans %}{{docs_not_orderable}} documents ne peuvent pas etre commandes{% endtrans %} + {% endif %} + {% set title%} + {% trans 'Documents indisponibles' %} + {% endset %} + {% if values.refused|length > 0 %} + {% set title%} + {% trans 'Documents indisponibles' %} + {% endset %} + + + + {% endif %} +
+ {% endif %} + {% endfor %} +
+
+ + -
- -
- +
+ +
+ +
-
-
- -
- +
+ +
+ +
-
-
- -
- +
+ +
+ +
-
-
- -
- +
+ +
+ +
-
-
- -
- +
+ +
+ +
-
-
- -
- +
+ +
+ +
-
-
- -
- +
+ +
+ +
-
-
- -
- +
+ +
+ +
-
-
- -
- +
+ +
+ +
-
-
- -
- +
+ +
+ +
-
- -
- -
- -
-
- -
- -
- -
-
{% if app['phraseanet.registry'].get('GV_requireTOUValidationForExport') == true %}
@@ -384,40 +387,18 @@ {% endtrans %}
- {% endif %} -
- - - -
- -
- {% endif %} - {% if download.get_total_ftp() > 0 %} -
-
-

{% trans 'export:: FTP' %}

-
- -
- +
- +
-
-
- {% for datas in download.get_ftp_datas() %} - {{ _self.print_ftp_form(datas) }} - {% endfor %} + +
+ +
+
@@ -468,32 +449,115 @@
{% endif %} -
- - - - + +
+ +
- -
- {% endif %} -
+ {% endif %} + {% if download.get_total_ftp() > 0 %} +
+
+

{% trans 'export:: FTP' %}

+
+ + +
+ +
+ +
+
+
+
+ {% for datas in download.get_ftp_datas() %} + {{ _self.print_ftp_form(datas) }} + {% endfor %} +
+
+
+

{% trans 'export::mail: fichiers joint' %}

+ {% for name, values in download.get_display_ftp() %} + {% if values.available > 0 %} +
+ + {% if values.refused|length > 0 %} + + {% endif %} +
+ {% endif %} + {% endfor %} +
+ {% if download.has_business_fields_access() %} + + {% endif %} + + {% if app['phraseanet.registry'].get('GV_requireTOUValidationForExport') == true %} +
+ +
+ {% endif %} +
+ + + + + +
+
+
+ +
+ {% endif %} +
-
+{% endif %} diff --git a/templates/web/prod/actions/Property/index.html.twig b/templates/web/prod/actions/Property/index.html.twig index fe697a053a..9650e05ddd 100644 --- a/templates/web/prod/actions/Property/index.html.twig +++ b/templates/web/prod/actions/Property/index.html.twig @@ -1,3 +1,5 @@ +{% import 'common/thumbnail.html.twig' as thumbnail %} + {% set nbReceivedDocuments = records.received().count() %} {% set nbEditableDocuments = records.count() %} @@ -8,8 +10,8 @@
-

-

+

+

{% trans %} You have selected one document. {% plural nbReceivedDocuments %} @@ -42,8 +44,8 @@ - - + + {% if nbRecords == 0 and nbStories > 0 %} ({% trans %}Status edition of stories{% endtrans %}) {% elseif nbRecords > 0 and nbStories == 0 %} @@ -61,7 +63,7 @@ {% set inverse = 1 %} {% endif %} - +

{{ values['name']|title }}
@@ -74,7 +76,7 @@ {% endif %} -
-
TODO
+ +
+ {% set typesEnum = [ + constant('\\Alchemy\\Phrasea\\Media\\Type\\Type::TYPE_AUDIO'), + constant('\\Alchemy\\Phrasea\\Media\\Type\\Type::TYPE_VIDEO'), + constant('\\Alchemy\\Phrasea\\Media\\Type\\Type::TYPE_DOCUMENT'), + constant('\\Alchemy\\Phrasea\\Media\\Type\\Type::TYPE_FLASH'), + constant('\\Alchemy\\Phrasea\\Media\\Type\\Type::TYPE_IMAGE') + ] + %} + +
+
+ +
+ + {% for sbasId,databoxTypes in recordsType %} +

{{ sbasId|sbas_names(app) }}

+ {% for currentType, recordsByType in databoxTypes %} +
    + {% for record in recordsByType %} +
  • +
    + {{ thumbnail.format(record.get_thumbnail(), 160, 120, '', false, false) }} +
    +
    {{ record.get_title() }}
    +

    + +

    +
    +
    +
  • + {% endfor %} +
+ {% endfor %} + {% endfor %} + +
+ + +
+
+