/** * Reset Email * * @param Application $app * @param Request $request * @return RedirectResponse */ public function resetEmail(PhraseaApplication $app, Request $request) { if (null === ($password = $request->request->get('form_password')) || null === ($email = $request->request->get('form_email')) || null === ($emailConfirm = $request->request->get('form_email_confirm'))) { $app->abort(400, $app->trans('Could not perform request, please contact an administrator.')); } $user = $app['authentication']->getUser(); if (!$app['auth.password-encoder']->isPasswordValid($user->getPassword(), $password, $user->getNonce())) { $app->addFlash('error', $app->trans('admin::compte-utilisateur:ftp: Le mot de passe est errone')); return $app->redirectPath('account_reset_email'); } if (!\Swift_Validate::email($email)) { $app->addFlash('error', $app->trans('forms::l\'email semble invalide')); return $app->redirectPath('account_reset_email'); } if ($email !== $emailConfirm) { $app->addFlash('error', $app->trans('forms::les emails ne correspondent pas')); return $app->redirectPath('account_reset_email'); } $date = new \DateTime('1 day'); $token = $app['tokens']->getUrlToken(\random::TYPE_EMAIL, $app['authentication']->getUser()->getId(), $date, $app['authentication']->getUser()->getEmail()); $url = $app->url('account_reset_email', ['token' => $token]); try { $receiver = Receiver::fromUser($app['authentication']->getUser()); } catch (InvalidArgumentException $e) { $app->addFlash('error', $app->trans('phraseanet::erreur: echec du serveur de mail')); return $app->redirectPath('account_reset_email'); } $mail = MailRequestEmailUpdate::create($app, $receiver, null); $mail->setButtonUrl($url); $mail->setExpiration($date); $app['notification.deliverer']->deliver($mail); $app->addFlash('info', $app->trans('admin::compte-utilisateur un email de confirmation vient de vous etre envoye. Veuillez suivre les instructions contenue pour continuer')); return $app->redirectPath('account'); }
public function list_notifications_available(User $user) { $personal_notifications = []; foreach ($this->notifications as $notification) { if (!$this->pool_classes[$notification]->is_available($user)) { continue; } $group = $this->pool_classes[$notification]->get_group(); $group = $group === null ? $this->app->trans('Notifications globales') : $group; $personal_notifications[$group][] = ['name' => $this->pool_classes[$notification]->get_name(), 'id' => $notification, 'description' => $this->pool_classes[$notification]->get_description(), 'subscribe_emails' => true]; } return $personal_notifications; }
public function doInstall(Application $app, Request $request) { set_time_limit(360); $servername = $request->getScheme() . '://' . $request->getHttpHost() . '/'; $abConn = $dbConn = null; $hostname = $request->request->get('ab_hostname'); $port = $request->request->get('ab_port'); $user_ab = $request->request->get('ab_user'); $ab_password = $request->request->get('ab_password'); $appbox_name = $request->request->get('ab_name'); $databox_name = $request->request->get('db_name'); try { $abConn = $app['dbal.provider']->get(['host' => $hostname, 'port' => $port, 'user' => $user_ab, 'password' => $ab_password, 'dbname' => $appbox_name]); $abConn->connect(); } catch (\Exception $e) { return $app->redirectPath('install_step2', ['error' => $app->trans('Appbox is unreachable')]); } try { if ($databox_name) { $dbConn = $app['dbal.provider']->get(['host' => $hostname, 'port' => $port, 'user' => $user_ab, 'password' => $ab_password, 'dbname' => $databox_name]); $dbConn->connect(); } } catch (\Exception $e) { return $app->redirectPath('install_step2', ['error' => $app->trans('Databox is unreachable')]); } $email = $request->request->get('email'); $password = $request->request->get('password'); $template = $request->request->get('db_template'); $dataPath = $request->request->get('datapath_noweb'); try { $installer = $app['phraseanet.installer']; $installer->setPhraseaIndexerPath($request->request->get('binary_phraseanet_indexer')); $binaryData = []; foreach (['php_binary' => $request->request->get('binary_php'), 'phraseanet_indexer' => $request->request->get('binary_phraseanet_indexer'), 'swf_extract_binary' => $request->request->get('binary_swfextract'), 'pdf2swf_binary' => $request->request->get('binary_pdf2swf'), 'swf_render_binary' => $request->request->get('binary_swfrender'), 'unoconv_binary' => $request->request->get('binary_unoconv'), 'ffmpeg_binary' => $request->request->get('binary_ffmpeg'), 'mp4box_binary' => $request->request->get('binary_MP4Box'), 'pdftotext_binary' => $request->request->get('binary_xpdf'), 'recess_binary' => $request->request->get('binary_recess')] as $key => $path) { $binaryData[$key] = $path; } $user = $installer->install($email, $password, $abConn, $servername, $dataPath, $dbConn, $template, $binaryData); $app['authentication']->openAccount($user); return $app->redirectPath('admin', ['section' => 'taskmanager', 'notice' => 'install_success']); } catch (\Exception $e) { return $app->redirectPath('install_step2', ['error' => $app->trans('an error occured : %message%', ['%message%' => $e->getMessage()])]); } }
/** * @param Request $request * @param PhraseaApplication $app * @return RedirectResponse|null */ public function redirectOnLogRequests(Request $request, PhraseaApplication $app) { if (!$request->query->has('LOG')) { return null; } if ($app->getAuthenticator()->isAuthenticated()) { $app->getAuthenticator()->closeAccount(); } if (null === ($token = $app['repo.tokens']->findValidToken($request->query->get('LOG')))) { $app->addFlash('error', $app->trans('The URL you used is out of date, please login')); return $app->redirectPath('homepage'); } /** @var Token $token */ $app->getAuthenticator()->openAccount($token->getUser()); switch ($token->getType()) { case TokenManipulator::TYPE_FEED_ENTRY: return $app->redirectPath('lightbox_feed_entry', ['entry_id' => $token->getData()]); case TokenManipulator::TYPE_VALIDATE: case TokenManipulator::TYPE_VIEW: return $app->redirectPath('lightbox_validation', ['basket' => $token->getData()]); } return null; }
/** * @param bool $highlight * @param SearchEngineInterface $searchEngine * @param null $removeExtension * @param SearchEngineOptions $options * @return string */ public function get_title($highlight = false, SearchEngineInterface $searchEngine = null, $removeExtension = null, SearchEngineOptions $options = null) { $cache = !$highlight && !$searchEngine && !$removeExtension; if ($cache) { try { return $this->get_data_from_cache(self::CACHE_TITLE); } catch (\Exception $e) { } } $title = ''; $fields = $this->get_databox()->get_meta_structure(); $fields_to_retrieve = []; foreach ($fields as $field) { if (in_array($field->get_thumbtitle(), ['1', $this->app['locale']])) { $fields_to_retrieve[] = $field->get_name(); } } if (count($fields_to_retrieve) > 0) { $retrieved_fields = $this->get_caption()->get_highlight_fields($highlight, $fields_to_retrieve, $searchEngine); $titles = []; foreach ($retrieved_fields as $value) { foreach ($value['values'] as $v) { $titles[] = $v['value']; } } $title = trim(implode(' - ', $titles)); } if (trim($title) === '') { $title = trim($this->get_original_name($removeExtension)); } $title = $title != "" ? $title : $this->app->trans('reponses::document sans titre'); if ($cache) { $this->set_data_to_cache(self::CACHE_TITLE, $title); } return $title; }
protected function apply_patches($from, $to, $post_process, Setup_Upgrade $upgrader, Application $app) { if (version::eq($from, $to)) { return true; } $list_patches = []; $upgrader->add_steps(1)->set_current_message($app->trans('Looking for patches')); $iterator = new DirectoryIterator($this->app['root.path'] . '/lib/classes/patch/'); foreach ($iterator as $fileinfo) { if (!$fileinfo->isDot()) { if (substr($fileinfo->getFilename(), 0, 1) == '.') { continue; } $versions = array_reverse(explode('.', $fileinfo->getFilename())); $classname = 'patch_' . array_pop($versions); $patch = new $classname(); if (!in_array($this->get_base_type(), $patch->concern())) { continue; } if (!!$post_process !== !!$patch->require_all_upgrades()) { continue; } // if patch is older than current install if (version::lte($patch->get_release(), $from)) { continue; } // if patch is new than current target if (version::gt($patch->get_release(), $to)) { continue; } $n = 0; do { $key = $patch->get_release() . '.' . $n; $n++; } while (isset($list_patches[$key])); $list_patches[$key] = $patch; } } $upgrader->add_steps_complete(1)->add_steps(count($list_patches))->set_current_message($app->trans('Applying patches on %databox_name%', ['%databox_name%' => $this->get_dbname()])); uasort($list_patches, function (\patchInterface $patch1, \patchInterface $patch2) { return version::lt($patch1->get_release(), $patch2->get_release()) ? -1 : 1; }); $success = true; foreach ($list_patches as $patch) { // Gets doctrine migrations required for current patch foreach ($patch->getDoctrineMigrations() as $doctrineVersion) { $version = $app['doctrine-migration.configuration']->getVersion($doctrineVersion); // Skip if already migrated if ($version->isMigrated()) { continue; } $migration = $version->getMigration(); // Inject entity manager $migration->setEntityManager($app['EM']); // Execute migration if not marked as migrated and not already applied by an older patch if (!$migration->isAlreadyApplied()) { $version->execute('up'); continue; } // Or mark it as migrated $version->markMigrated(); } if (false === $patch->apply($this, $app)) { $success = false; } $upgrader->add_steps_complete(1); } return $success; }
private function doAuthentication(PhraseaApplication $app, Request $request, FormInterface $form, $redirector) { if (!is_callable($redirector)) { throw new InvalidArgumentException('Redirector should be callable'); } $context = new Context(Context::CONTEXT_NATIVE); $app['dispatcher']->dispatch(PhraseaEvents::PRE_AUTHENTICATE, new PreAuthenticate($request, $context)); $form->bind($request); if (!$form->isValid()) { $app->addFlash('error', $app->trans('An unexpected error occured during authentication process, please contact an admin')); throw new AuthenticationException(call_user_func($redirector)); } $params = []; if (null !== ($redirect = $request->get('redirect'))) { $params['redirect'] = ltrim($redirect, '/'); } try { $usr_id = $app['auth.native']->getUsrId($request->request->get('login'), $request->request->get('password'), $request); } catch (RequireCaptchaException $e) { $app->requireCaptcha(); $app->addFlash('warning', $app->trans('Please fill the captcha')); throw new AuthenticationException(call_user_func($redirector, $params)); } catch (AccountLockedException $e) { $app->addFlash('warning', $app->trans('login::erreur: Vous n\'avez pas confirme votre email')); $app->addUnlockAccountData($e->getUsrId()); throw new AuthenticationException(call_user_func($redirector, $params)); } if (null === $usr_id) { $app['session']->getFlashBag()->set('error', $app->trans('login::erreur: Erreur d\'authentification')); throw new AuthenticationException(call_user_func($redirector, $params)); } $user = $app['manipulator.user']->getRepository()->find($usr_id); $session = $this->postAuthProcess($app, $user); $response = $this->generateAuthResponse($app, $app['browser'], $request->request->get('redirect')); $response->headers->clearCookie('invite-usr-id'); if ($request->cookies->has('postlog') && $request->cookies->get('postlog') == '1') { if (!$user->isGuest() && $request->cookies->has('invite-usr_id')) { if ($user->getId() != ($inviteUsrId = $request->cookies->get('invite-usr_id'))) { $repo = $app['EM']->getRepository('Phraseanet:Basket'); $baskets = $repo->findBy(['usr_id' => $inviteUsrId]); foreach ($baskets as $basket) { $basket->setUser($user); $app['EM']->persist($basket); } } } } if ($request->request->get('remember-me') == '1') { $nonce = \random::generatePassword(16); $string = $app['browser']->getBrowser() . '_' . $app['browser']->getPlatform(); $token = $app['auth.password-encoder']->encodePassword($string, $nonce); $session->setToken($token)->setNonce($nonce); $response->headers->setCookie(new Cookie('persistent', $token)); $app['EM']->persist($session); $app['EM']->flush(); } $event = new PostAuthenticate($request, $response, $user, $context); $app['dispatcher']->dispatch(PhraseaEvents::POST_AUTHENTICATE, $event); return $event->getResponse(); }
protected function buildResult(Application $app, $rs) { $i = 0; foreach ($rs as $row) { if ($i >= $this->nb_record) { break; } foreach ($this->champ as $key => $value) { if ($row[$value]) { if ($value == 'date') { $this->result[$i][$value] = $this->pretty_string ? $this->app['date-formatter']->getPrettyString(new DateTime($row[$value])) : $row[$value]; } elseif ($value == 'size') { $this->result[$i][$value] = p4string::format_octets($row[$value]); } else { $this->result[$i][$value] = $row[$value]; } } else { if ($value == 'comment') { $this->result[$i][$value] = ' '; } else { $this->result[$i][$value] = '<i>' . $app->trans('report:: non-renseigne') . '</i>'; } } } $i++; } }
protected function upgradeDb($apply_patches, Application $app) { $recommends = []; $allTables = []; $schema = $this->get_schema(); foreach ($schema->tables->table as $table) { $allTables[(string) $table['name']] = $table; } $sql = "SHOW TABLE STATUS"; $stmt = $this->get_connection()->prepare($sql); $stmt->execute(); $rs = $stmt->fetchAll(PDO::FETCH_ASSOC); $stmt->closeCursor(); $ORMTables = ['AuthFailures', 'ApiApplications', 'ApiAccounts', 'ApiLogs', 'ApiOauthCodes', 'ApiOauthRefreshTokens', 'ApiOauthTokens', 'AggregateTokens', 'BasketElements', 'Baskets', 'FeedEntries', 'FeedItems', 'FeedPublishers', 'FeedTokens', 'Feeds', 'FtpCredential', 'FtpExportElements', 'FtpExports', 'OrderElements', 'Orders', 'Registrations', 'StoryWZ', 'UsrListOwners', 'UsrLists', 'UsrListsContent', 'ValidationDatas', 'ValidationParticipants', 'ValidationSessions', 'LazaretAttributes', 'LazaretChecks', 'LazaretFiles', 'LazaretSessions', 'SessionModules', 'Sessions', 'Tasks', 'UsrAuthProviders', 'UserQueries', 'UserSettings', 'Users', 'UserNotificationSettings']; foreach ($rs as $row) { $tname = $row["Name"]; if (isset($allTables[$tname])) { $engine = strtolower(trim($allTables[$tname]->engine)); $ref_engine = strtolower($row['Engine']); if ($engine != $ref_engine && in_array($engine, ['innodb', 'myisam'])) { $sql = 'ALTER TABLE `' . $tname . '` ENGINE = ' . $engine; try { $stmt = $this->get_connection()->prepare($sql); $stmt->execute(); $stmt->closeCursor(); } catch (\Exception $e) { $recommends[] = ['message' => $app->trans('Erreur lors de la tentative ; errreur : %message%', ['%message%' => $e->getMessage()]), 'sql' => $sql]; } } $ret = self::upgradeTable($allTables[$tname]); $recommends = array_merge($recommends, $ret); unset($allTables[$tname]); } elseif (!in_array($tname, $ORMTables)) { $recommends[] = ['message' => 'Une table pourrait etre supprime', 'sql' => 'DROP TABLE ' . $this->dbname . '.`' . $tname . '`;']; } } foreach ($allTables as $tname => $table) { $this->createTable($table); } $current_version = $this->get_version(); if ($apply_patches) { $this->apply_patches($current_version, $app['phraseanet.version']->getNumber(), false, $app); } return $recommends; }
/** * etablis les correspondance entre gettext et le nom des mois du report * @return array */ private function setMonth() { return [$this->app->trans('janvier'), $this->app->trans('fevrier'), $this->app->trans('mars'), $this->app->trans('avril'), $this->app->trans('mai'), $this->app->trans('juin'), $this->app->trans('juillet'), $this->app->trans('aout'), $this->app->trans('septembre'), $this->app->trans('octobre'), $this->app->trans('novembre'), $this->app->trans('decembre')]; }
/** * * @param Application $app * @param string $lst * @param integer $sstid * @param integer $storyWZid * @return set_export */ public function __construct(Application $app, $lst, $sstid, $storyWZid = null) { $this->app = $app; $download_list = []; $remain_hd = []; if ($storyWZid) { $repository = $app['EM']->getRepository('\\Entities\\StoryWZ'); $storyWZ = $repository->findByUserAndId($this->app, $app['authentication']->getUser(), $storyWZid); $lst = $storyWZ->getRecord($this->app)->get_serialize_key(); } if ($sstid != "") { $repository = $app['EM']->getRepository('Phraseanet:Basket'); /* @var $repository Alchemy\Phrasea\Model\Repositories\BasketRepository */ $Basket = $repository->findUserBasket($sstid, $app['authentication']->getUser(), false); $this->exportName = str_replace([' ', '\\', '/'], '_', $Basket->getName()) . "_" . date("Y-n-d"); foreach ($Basket->getElements() as $basket_element) { $base_id = $basket_element->getRecord($this->app)->get_base_id(); $record_id = $basket_element->getRecord($this->app)->get_record_id(); if (!isset($remain_hd[$base_id])) { if ($app['acl']->get($app['authentication']->getUser())->is_restricted_download($base_id)) { $remain_hd[$base_id] = $app['acl']->get($app['authentication']->getUser())->remaining_download($base_id); } else { $remain_hd[$base_id] = false; } } $current_element = $download_list[] = new record_exportElement($app, $basket_element->getRecord($this->app)->get_sbas_id(), $record_id, $Basket->getName(), $remain_hd[$base_id]); $remain_hd[$base_id] = $current_element->get_remain_hd(); } } else { $this->exportName = "Export_" . date("Y-n-d") . '_' . mt_rand(100, 999); $tmp_lst = explode(';', $lst); $n = 1; foreach ($tmp_lst as $basrec) { $basrec = explode('_', $basrec); if (count($basrec) != 2) { continue; } try { $record = new record_adapter($this->app, $basrec[0], $basrec[1]); } catch (\Exception_Record_AdapterNotFound $e) { continue; } if ($record->is_grouping()) { foreach ($record->get_children() as $child_basrec) { $base_id = $child_basrec->get_base_id(); $record_id = $child_basrec->get_record_id(); if (!isset($remain_hd[$base_id])) { if ($app['acl']->get($app['authentication']->getUser())->is_restricted_download($base_id)) { $remain_hd[$base_id] = $app['acl']->get($app['authentication']->getUser())->remaining_download($base_id); } else { $remain_hd[$base_id] = false; } } $current_element = $download_list[] = new record_exportElement($app, $child_basrec->get_sbas_id(), $record_id, $record->get_title(null, null, true) . '_' . $n, $remain_hd[$base_id]); $remain_hd[$base_id] = $current_element->get_remain_hd(); } } else { $base_id = $record->get_base_id(); $record_id = $record->get_record_id(); if (!isset($remain_hd[$base_id])) { if ($app['acl']->get($app['authentication']->getUser())->is_restricted_download($base_id)) { $remain_hd[$base_id] = $app['acl']->get($app['authentication']->getUser())->remaining_download($base_id); } else { $remain_hd[$base_id] = false; } } $current_element = $download_list[$basrec[0] . '_' . $basrec[1]] = new record_exportElement($app, $record->get_sbas_id(), $record_id, '', $remain_hd[$base_id]); $remain_hd[$base_id] = $current_element->get_remain_hd(); } $n++; } } $this->elements = $download_list; $display_download = []; $display_orderable = []; $this->total_download = 0; $this->total_order = 0; $this->total_ftp = 0; $this->businessFieldsAccess = false; foreach ($this->elements as $download_element) { if ($app['acl']->get($app['authentication']->getUser())->has_right_on_base($download_element->get_base_id(), 'canmodifrecord')) { $this->businessFieldsAccess = true; } foreach ($download_element->get_downloadable() as $name => $properties) { if (!isset($display_download[$name])) { $display_download[$name] = ['size' => 0, 'total' => 0, 'available' => 0, 'refused' => []]; } $display_download[$name]['total']++; if ($properties !== false) { $display_download[$name]['available']++; $display_download[$name]['label'] = $properties['label']; $display_download[$name]['class'] = $properties['class']; $this->total_download++; $display_download[$name]['size'] += $download_element->get_size($name); } else { $display_download[$name]['refused'][] = $download_element->get_thumbnail(); } } foreach ($download_element->get_orderable() as $name => $properties) { if (!isset($display_orderable[$name])) { $display_orderable[$name] = ['total' => 0, 'available' => 0, 'refused' => []]; } $display_orderable[$name]['total']++; if ($properties !== false) { $display_orderable[$name]['available']++; $this->total_order++; } else { $display_orderable[$name]['refused'][] = $download_element->get_thumbnail(); } } } foreach ($display_download as $name => $values) { $display_download[$name]['size'] = (int) $values['size']; } $display_ftp = []; $hasadminright = $app['acl']->get($app['authentication']->getUser())->has_right('addrecord') || $app['acl']->get($app['authentication']->getUser())->has_right('deleterecord') || $app['acl']->get($app['authentication']->getUser())->has_right('modifyrecord') || $app['acl']->get($app['authentication']->getUser())->has_right('coll_manage') || $app['acl']->get($app['authentication']->getUser())->has_right('coll_modify_struct'); $this->ftp_datas = []; if ($this->app['conf']->get(['registry', 'ftp', 'ftp-enabled']) && ($hasadminright || $this->app['conf']->get(['registry', 'ftp', 'ftp-user-access']))) { $display_ftp = $display_download; $this->total_ftp = $this->total_download; $lst_base_id = array_keys($app['acl']->get($app['authentication']->getUser())->get_granted_base()); if ($hasadminright) { $sql = "SELECT Users.id AS usr_id ,Users.login AS usr_login ,Users.email AS usr_mail, FtpCredential.*\n FROM (\n FtpCredential INNER JOIN Users ON (\n FtpCredential.active = 1 AND FtpCredential.user_id = Users.id\n ) INNER JOIN basusr ON (\n Users.id=basusr.usr_id\n AND (basusr.base_id=\n '" . implode("' OR basusr.base_id='", $lst_base_id) . "'\n )\n )\n )\n GROUP BY Users.id "; $params = []; } elseif ($this->app['conf']->get(['registry', 'ftp', 'ftp-user-access'])) { $sql = "SELECT Users.id AS usr_id ,Users.login AS usr_login ,Users.email AS usr_mail, FtpCredential.*\n FROM (\n FtpCredential INNER JOIN Users ON (\n FtpCredential.active = 1 AND FtpCredential.id = Users.id\n ) INNER JOIN basusr ON (\n Users.id=basusr.usr_id\n AND Users.id = :usr_id\n AND (basusr.base_id=\n '" . implode("' OR basusr.base_id='", $lst_base_id) . "'\n )\n )\n )\n GROUP BY Users.id "; $params = [':usr_id' => $app['authentication']->getUser()->getId()]; } $datas[] = ['name' => $app->trans('export::ftp: reglages manuels'), 'usr_id' => '0', 'address' => '', 'login' => '', 'password' => '', 'ssl' => false, 'dest_folder' => '', 'prefix_folder' => 'Export_' . date("Y-m-d_H.i.s"), 'passive' => false, 'max_retry' => 5, 'sendermail' => $app['authentication']->getUser()->getEmail()]; $stmt = $app['phraseanet.appbox']->get_connection()->prepare($sql); $stmt->execute($params); $rs = $stmt->fetchAll(PDO::FETCH_ASSOC); $stmt->closeCursor(); foreach ($rs as $row) { $datas[] = ['name' => $row["usr_login"], 'usr_id' => $row['usr_id'], 'address' => $row['address'], 'login' => $row['login'], 'password' => $row['password'], 'ssl' => !!$row['tls'], 'dest_folder' => $row['reception_folder'], 'prefix_folder' => strlen(trim($row['repository_prefix_name'])) > 0 ? trim($row['repository_prefix_name']) : 'Export_' . date("Y-m-d_H.i.s"), 'passive' => !!$row['passive'], 'max_retry' => $row['max_retry'], 'usr_mail' => $row['usr_mail'], 'sender_mail' => $app['authentication']->getUser()->getEmail()]; } $this->ftp_datas = $datas; } $this->display_orderable = $display_orderable; $this->display_download = $display_download; $this->display_ftp = $display_ftp; return $this; }
public function getValidationString(Application $app, User $user) { if ($this->isInitiator($user)) { if ($this->isFinished()) { return $app->trans('Vous aviez envoye cette demande a %n% utilisateurs', ['%n%' => count($this->getParticipants()) - 1]); } return $app->trans('Vous avez envoye cette demande a %n% utilisateurs', ['%n%' => count($this->getParticipants()) - 1]); } else { if ($this->getParticipant($user)->getCanSeeOthers()) { return $app->trans('Processus de validation recu de %user% et concernant %n% utilisateurs', ['%user%' => $this->getInitiator($app)->getDisplayName(), '%n%' => count($this->getParticipants()) - 1]); } return $app->trans('Processus de validation recu de %user%', ['%user%' => $this->getInitiator($app)->getDisplayName()]); } }