renderPushTemplate($request, 'Push'); } public function validateFormAction(Request $request) { return $this->renderPushTemplate($request, 'Feedback'); } /** ---------------------------------------------------------------------------------- * a simple push is made by the current user to many "receivers" (=participants) * * this is the same code as "validation" request, except here we don't create a validation session * * * @param Request $request * @return JsonResponse */ public function sendAction(Request $request) { $ret = [ 'success' => false, 'message' => $this->app->trans('Unable to send the documents') ]; try { $pusher = new RecordHelper\Push($this->app, $request); $push_name = $request->request->get( 'name', $this->app->trans('Push from %user%', [ '%user%' => $this->getAuthenticatedUser()->getDisplayName(), ]) ); $push_description = $request->request->get('push_description'); $receivers = $request->request->get('participants'); if (!is_array($receivers) || empty($receivers)) { throw new ControllerException($this->app->trans('No receivers specified')); } if (!is_array($pusher->get_elements()) || empty($pusher->get_elements())) { throw new ControllerException($this->app->trans('No elements to push')); } $manager = $this->getEntityManager(); foreach ($receivers as $receiver) { try { /** @var User $user_receiver */ $user_receiver = $this->getUserRepository()->find($receiver['usr_id']); } catch (Exception $e) { throw new ControllerException( $this->app->trans('Unknown user %user_id%', ['%user_id%' => $receiver['usr_id']]) ); } $Basket = new Basket(); $Basket->setName($push_name); $Basket->setDescription($push_description); $Basket->setUser($user_receiver); $Basket->setPusher($this->getAuthenticatedUser()); $Basket->markUnread(); $manager->persist($Basket); foreach ($pusher->get_elements() as $element) { $basketElement = new BasketElement(); $basketElement->setRecord($element); $basketElement->setBasket($Basket); $manager->persist($basketElement); $Basket->addElement($basketElement); if ($receiver['HD']) { $this->getAclForUser($user_receiver)->grant_hd_on( $basketElement->getRecord($this->app), $this->getAuthenticatedUser(), ACL::GRANT_ACTION_PUSH ); } else { $this->getAclForUser($user_receiver)->grant_preview_on( $basketElement->getRecord($this->app), $this->getAuthenticatedUser(), ACL::GRANT_ACTION_PUSH ); } $this->getDataboxLogger($element->getDatabox())->log( $element, Session_Logger::EVENT_PUSH, $user_receiver->getId(), '' ); } $manager->flush(); $arguments = [ 'basket' => $Basket->getId(), ]; // here we send an email to each participant // // if we don't request the user to auth (=type his login/pwd), // we generate a !!!! 'view' !!!! token to be included as 'LOG' parameter in url // // - the 'view' token is created to give access to lightbox in "compare" mode, NOT "validation" // - the 'view' token has no expiration // if (!$this->getConf()->get(['registry', 'actions', 'enable-push-authentication']) || !$request->get('force_authentication') ) { $arguments['LOG'] = $this->getTokenManipulator()->createBasketAccessToken($Basket, $user_receiver)->getValue(); } $url = $this->app->url('lightbox_compare', $arguments); $receipt = $request->get('recept') ? $this->getAuthenticatedUser()->getEmail() : ''; $this->dispatch( PhraseaEvents::BASKET_PUSH, new PushEvent($Basket, $request->request->get('message'), $url, $receipt) ); } $manager->flush(); $message = $this->app->trans( '%quantity_records% records have been sent to %quantity_users% users', [ '%quantity_records%' => count($pusher->get_elements()), '%quantity_users%' => count($receivers), ] ); $ret = [ 'success' => true, 'message' => $message ]; } catch (ControllerException $e) { $ret['message'] = $e->getMessage() . $e->getFile() . $e->getLine(); } return $this->app->json($ret); } /** ---------------------------------------------------------------------------------- * a validation request is made by the current user to many participants * * this is the same code as "send" request (=simple push), except here we create a validation session, * register participants and data... * * * @param Request $request * @return JsonResponse * @throws Exception */ public function validateAction(Request $request) { $ret = [ 'success' => false, 'message' => $this->app->trans('Unable to send the documents') ]; $manager = $this->getEntityManager(); $manager->beginTransaction(); try { $pusher = $this->getPushFromRequest($request); $validation_name = $request->request->get('name', $this->app->trans( 'Validation from %user%', [ '%user%' => $this->getAuthenticatedUser()->getDisplayName(), ])); $validation_description = $request->request->get('message'); $participants = $request->request->get('participants'); if (!is_array($participants) || empty($participants)) { throw new ControllerException($this->app->trans('No participants specified')); } if (!is_array($pusher->get_elements()) || empty($pusher->get_elements())) { throw new ControllerException($this->app->trans('No elements to validate')); } // a validation must apply to a basket... // if ($pusher->is_basket()) { $basket = $pusher->get_original_basket(); } else { // ...so if we got a list of elements (records), we create a basket for those $basket = new Basket(); $basket->setName($validation_name); $basket->setDescription($validation_description); $basket->setUser($this->getAuthenticatedUser()); $basket->markUnread(); $manager->persist($basket); foreach ($pusher->get_elements() as $element) { $basketElement = new BasketElement(); $basketElement->setRecord($element); $basketElement->setBasket($basket); $manager->persist($basketElement); $basket->addElement($basketElement); } $manager->flush(); } $manager->refresh($basket); // if the basket is already under validation, we work on it // else we create a validationSession // $expireDate = null; if (!$basket->getValidation()) { // create the validationSession $Validation = new ValidationSession(); $Validation->setInitiator($this->getAuthenticatedUser()); $Validation->setBasket($basket); // add an expiration date if a duration was specified $duration = (int)$request->request->get('duration'); if ($duration > 0) { $expireDate = new DateTime('+' . $duration . ' day' . ($duration > 1 ? 's' : '')); $Validation->setExpires($expireDate); } $basket->setValidation($Validation); $manager->persist($Validation); } else { // go on with existing validationSession $Validation = $basket->getValidation(); $expireDate = $Validation->getExpires(); } // we always add the author of the validation request (current user) to the participants // $found = false; foreach ($participants as $participant) { if ($participant['usr_id'] === $this->getAuthenticatedUser()->getId()) { $found = true; break; } } if (!$found) { $participants[] = [ 'see_others' => 1, 'usr_id' => $this->getAuthenticatedUser()->getId(), 'agree' => 0, 'HD' => 0, ]; } // used to check participant to be removed $action = $request->request->get('action'); $remainingParticipantsUserId = []; if ($action == 'adduser') { $remainingParticipantsUserId = $Validation->getListParticipantsUserId(); } // add participants to the validationSession // foreach ($participants as $key => $participant) { // sanity check foreach (['see_others', 'usr_id', 'agree', 'HD'] as $mandatoryParam) { if (!array_key_exists($mandatoryParam, $participant)) { throw new ControllerException( $this->app->trans('Missing mandatory parameter %parameter%', ['%parameter%' => $mandatoryParam]) ); } } try { /** @var User $participantUser */ $participantUser = $this->getUserRepository()->find($participant['usr_id']); if ($action == 'adduser') { $remainingParticipantsUserId = array_diff($remainingParticipantsUserId, [$participant['usr_id']]); } } catch (Exception $e) { throw new ControllerException( $this->app->trans('Unknown user %usr_id%', ['%usr_id%' => $participant['usr_id']]) ); } // end of sanity check // if participant already exists, skip insertion try { $Validation->getParticipant($participantUser); continue; } catch (NotFoundHttpException $e) { // participant not yet exists, create } $validationParticipant = new ValidationParticipant(); $validationParticipant->setUser($participantUser); $validationParticipant->setSession($Validation); $validationParticipant->setCanAgree($participant['agree']); $validationParticipant->setCanSeeOthers($participant['see_others']); $manager->persist($validationParticipant); foreach ($basket->getElements() as $basketElement) { $validationData = new ValidationData(); $validationData->setParticipant($validationParticipant); $validationData->setBasketElement($basketElement); $basketElement->addValidationData($validationData); if ($participant['HD']) { $this->getAclForUser($participantUser)->grant_hd_on( $basketElement->getRecord($this->app), $this->getAuthenticatedUser(), ACL::GRANT_ACTION_VALIDATE ); } else { $this->getAclForUser($participantUser)->grant_preview_on( $basketElement->getRecord($this->app), $this->getAuthenticatedUser(), ACL::GRANT_ACTION_VALIDATE ); } $manager->merge($basketElement); $manager->persist($validationData); $this->getDataboxLogger($basketElement->getRecord($this->app)->getDatabox())->log( $basketElement->getRecord($this->app), Session_Logger::EVENT_VALIDATE, $participantUser->getId(), '' ); $validationParticipant->addData($validationData); } /** @var ValidationParticipant $validationParticipant */ $validationParticipant = $manager->merge($validationParticipant); $manager->flush(); $arguments = [ 'basket' => $basket->getId(), ]; // here we send an email to each participant // // if we don't request the user to auth (=type his login/pwd), // we generate a !!!! 'validate' !!!! token to be included as 'LOG' parameter in url // // - the 'validate' token has same expiration as validation-session (except for initiator) // if (!$this->getConf()->get(['registry', 'actions', 'enable-push-authentication']) || !$request->get('force_authentication') ) { if($participantUser->getId() === $this->getAuthenticatedUser()->getId()) { // the initiator of the validation gets a no-expire token (so he can see result after validation expiration) $arguments['LOG'] = $this->getTokenManipulator()->createBasketValidationToken($basket, $participantUser, null)->getValue(); } else { // a "normal" participant/user gets a expiring token $arguments['LOG'] = $this->getTokenManipulator()->createBasketValidationToken($basket, $participantUser, $expireDate)->getValue(); } } $url = $this->app->url('lightbox_validation', $arguments); $receipt = $request->get('recept') ? $this->getAuthenticatedUser()->getEmail() : ''; $this->dispatch( PhraseaEvents::VALIDATION_CREATE, new ValidationEvent( $validationParticipant, $basket, $url, $request->request->get('message'), $receipt, (int)$request->request->get('duration') ) ); } if ($action == 'adduser') { foreach ($remainingParticipantsUserId as $userIdToRemove) { try { /** @var User $participantUser */ $participantUser = $this->getUserRepository()->find($userIdToRemove); } catch (Exception $e) { throw new ControllerException( $this->app->trans('Unknown user %usr_id%', ['%usr_id%' => $userIdToRemove]) ); } $validationParticipant = $Validation->getParticipant($participantUser); $Validation->removeParticipant($validationParticipant); $manager->remove($validationParticipant); } } $manager->merge($basket); $manager->merge($Validation); $manager->flush(); $message = $this->app->trans( '%quantity_records% records have been sent for validation to %quantity_users% users', [ '%quantity_records%' => count($pusher->get_elements()), '%quantity_users%' => count($request->request->get('participants')), ] ); $ret = [ 'success' => true, 'message' => $message, ]; $manager->commit(); } catch (ControllerException $e) { $ret['message'] = $e->getMessage(); $manager->rollback(); } return $this->app->json($ret); } /** * @param $usr_id * @return JsonResponse */ public function getUserAction($usr_id) { $data = null; $query = $this->createUserQuery(); $query->on_bases_where_i_am($this->getAclForUser($this->getAuthenticatedUser()), [ACL::CANPUSH]); $query->in([$usr_id]); $result = $query->include_phantoms() ->limit(0, 1) ->execute()->get_results(); if ($result) { foreach ($result as $user) { $data = $this->formatUser($user); } } return $this->app->json($data); } /** * @param $list_id * @return JsonResponse */ public function getListAction($list_id) { $data = null; $repository = $this->getUserListRepository(); $list = $repository->findUserListByUserAndId($this->getAuthenticatedUser(), $list_id); if ($list) { $data = $this->formatUserList($list); } return $this->app->json($data); } /** * @param Request $request * @return JsonResponse * @throws Exception */ public function addUserAction(Request $request) { $result = ['success' => false, 'message' => '', 'user' => null]; try { if (!$this->getAclForUser($this->getAuthenticatedUser())->has_right(ACL::CANADMIN)) throw new ControllerException($this->app->trans('You are not allowed to add users')); if (!$request->request->get('firstname')) throw new ControllerException($this->app->trans('First name is required')); if (!$request->request->get('lastname')) throw new ControllerException($this->app->trans('Last name is required')); if (!$request->request->get('email')) throw new ControllerException($this->app->trans('Email is required')); if (!Swift_Validate::email($request->request->get('email'))) throw new ControllerException($this->app->trans('Email is invalid')); } catch (ControllerException $e) { $result['message'] = $e->getMessage(); return $this->app->json($result); } $user = null; $email = $request->request->get('email'); if (null !== $user = $this->getUserRepository()->findByEmail($email)) { $result['message'] = $this->app->trans('User already exists'); $result['success'] = true; $result['user'] = $this->formatUser($user); return $this->app->json($result); } try { $manager = $this->getEntityManager(); $password = $this->getRandomGenerator()->generateString(128); $user = $this->getUserManipulator()->createUser($email, $password, $email); $user ->setFirstName($request->request->get('firstname')) ->setLastName($request->request->get('lastname')) ; if ($request->request->get('company')) { $user->setCompany($request->request->get('company')); } if ($request->request->get('job')) { $user->setJob($request->request->get('job')); } if ($request->request->get('city')) { $this->getUserManipulator()->setGeonameId($user, $request->request->get('city')); } $manager->persist($user); $manager->flush(); $result['message'] = $this->app->trans('User successfully created'); $result['success'] = true; $result['user'] = $this->formatUser($user); } catch (Exception $e) { $result['message'] = $this->app->trans('Error while creating user'); } return $this->app->json($result); } /** * @param Request $request * @return string */ public function getAddUserFormAction(Request $request) { $params = ['callback' => $request->query->get('callback')]; return $this->render('prod/User/Add.html.twig', $params); } /** * @param Request $request * @return JsonResponse */ public function searchUserAction(Request $request) { $query = $this->createUserQuery(); $query->on_bases_where_i_am($this->getAclForUser($this->getAuthenticatedUser()), [ACL::CANPUSH]); $query ->like(User_Query::LIKE_FIRSTNAME, $request->query->get('query')) ->like(User_Query::LIKE_LASTNAME, $request->query->get('query')) ->like(User_Query::LIKE_LOGIN, $request->query->get('query')) ->like(User_Query::LIKE_EMAIL, $request->query->get('query')) ->like(User_Query::LIKE_COMPANY, $request->query->get('query')) ->like_match(User_Query::LIKE_MATCH_OR); $result = $query ->include_phantoms() ->limit(0, 50) ->execute()->get_results(); $repository = $this->getUserListRepository(); $lists = $repository->findUserListLike($this->getAuthenticatedUser(), $request->query->get('query')); $data = []; if ($lists) { foreach ($lists as $list) { $data[] = $this->formatUserList($list); } } if ($result) { foreach ($result as $user) { $data[] = $this->formatUser($user); } } return $this->app->json($data); } /** * @param Request $request * @param $list_id * @return Response */ public function editListAction(Request $request, $list_id) { $repository = $this->getUserListRepository(); $list = $repository->findUserListByUserAndId($this->getAuthenticatedUser(), $list_id); $query = $this->createUserQuery(); $query->on_bases_where_i_am($this->getAclForUser($this->getAuthenticatedUser()), [ACL::CANPUSH]); if ($request->get('query')) { $query ->like($request->get('like_field'), $request->get('query')) ->like_match(User_Query::LIKE_MATCH_OR); } if (is_array($request->get('EmailDomain'))) { $query->haveEmailDomains($request->get('EmailDomain')); } if (is_array($request->get('Activity'))) { $query->haveActivities($request->get('Activity')); } if (is_array($request->get('Template'))) { $query->haveTemplate($request->get('Template')); } if (is_array($request->get('Company'))) { $query->inCompanies($request->get('Company')); } if (is_array($request->get('Country'))) { $query->inCountries($request->get('Country')); } if (is_array($request->get('Position'))) { $query->havePositions($request->get('Position')); } $sort = $request->get('srt', 'usr_creationdate'); $ord = $request->get('ord', 'desc'); $perPage = 10; $offset_start = Max(((int) $request->get('page') - 1) * $perPage, 0); $query->sort_by($sort, $ord); $results = $query ->include_phantoms() ->limit($offset_start, $perPage) ->execute()->get_results(); $params = [ 'query' => $query, 'results' => $results, 'list' => $list, 'sort' => $sort, 'ord' => $ord, ]; if ($request->get('type') === 'fragment') { return new Response( $this->render('prod/actions/Feedback/ResultTable.html.twig', $params) ); } return new Response( $this->render('prod/actions/Feedback/list.html.twig', $params) ); } /** * update the expiration date of a validation session * also update the expiration of the participants validation tokens * * @param Request $request * @return JsonResponse * @throws Exception */ public function updateExpirationAction(Request $request) { // sanity check if (is_null($request->request->get('date'))) { throw new Exception('The provided date is null!'); } $manager = $this->getEntityManager(); $manager->beginTransaction(); try { $basket = $this->getBasketRepository()->findUserBasket($request->request->get('basket_id'), $this->app->getAuthenticatedUser(), true); $expirationDate = new DateTime($request->request->get('date') . " 23:59:59"); $validation = $basket->getValidation(); if (is_null($validation)) { throw new Exception('Unable to find the validation session'); } // update validation tokens expiration // /** @var ValidationParticipant $participant */ foreach($validation->getParticipants() as $participant) { try { if(!is_null($token = $this->getTokenRepository()->findValidationToken($basket, $participant->getUser()))) { if($participant->getUser()->getId() === $validation->getInitiator()->getId()) { // the initiator keeps a no-expiration token $token->setExpiration(null); // shoud already be null, but who knows... } else { // the "normal" user token is fixed $token->setExpiration($expirationDate); } } } catch (Exception $e) { // not unique token ? should not happen. // no-op } } $validation->setExpires($expirationDate); $manager->persist($validation); $manager->flush(); $manager->commit(); $ret = [ 'success' => true, 'message' => $this->app->trans('Expiration date successfully updated!') ]; } catch (Exception $e) { $ret = [ 'success' => false, 'message' => $e->getMessage() ]; $manager->rollback(); } return $this->app->json($ret); } private function formatUser(User $user) { $subtitle = array_filter([$user->getJob(), $user->getCompany()]); return [ 'type' => 'USER', 'usr_id' => $user->getId(), 'firstname' => $user->getFirstName(), 'lastname' => $user->getLastName(), 'email' => $user->getEmail(), 'display_name' => $user->getDisplayName(), 'subtitle' => implode(', ', $subtitle), ]; } private function formatUserList(UsrList $list) { $entries = []; foreach ($list->getEntries() as $entry) { $entries[] = [ 'Id' => $entry->getId(), 'User' => $this->formatUser($entry->getUser()), ]; } return [ 'type' => 'LIST', 'list_id' => $list->getId(), 'name' => $list->getName(), 'length' => count($entries), 'entries' => $entries, ]; } /** * @param array|record_adapter[] $selection * @return ArrayCollection Users */ private function getUsersInSelectionExtractor($selection) { $users = new ArrayCollection(); foreach ($selection as $record) { foreach ($record->get_caption()->get_fields() as $caption_field) { foreach ($caption_field->get_values() as $value) { if (!$value->getVocabularyType()) continue; if ($value->getVocabularyType()->getType() !== 'User') continue; $user = $value->getResource(); $users->set($user->getId(), $user); } } } return $users; } /** * @return UsrListRepository */ private function getUserListRepository() { return $this->app['repo.usr-lists']; } /** * @param Request $request * @param $context * @return string */ public function renderPushTemplate(Request $request, $context) { $push = $this->getPushFromRequest($request); $action = $request->request->get('action'); $participants = []; if ($action === 'adduser' && $push->is_basket() && $push->get_original_basket()->getValidation()) { $participants = $push->get_original_basket()->getValidation()->getParticipants(); } $repository = $this->getUserListRepository(); $recommendedUsers = $this->getUsersInSelectionExtractor($push->get_elements()); return $this->render( 'prod/actions/Push.html.twig', [ 'push' => $push, 'message' => '', 'lists' => $repository->findUserLists($this->getAuthenticatedUser()), 'context' => $context, 'RecommendedUsers' => $recommendedUsers, 'participants' => $participants, 'action' => $action ] ); } /** * @return UserRepository */ private function getUserRepository() { return $this->app['repo.users']; } /** * @return TokenManipulator */ private function getTokenManipulator() { return $this->app['manipulator.token']; } /** * @param Request $request * @return RecordHelper\Push */ private function getPushFromRequest(Request $request) { return new RecordHelper\Push($this->app, $request); } /** * @return UserManipulator */ private function getUserManipulator() { return $this->app['manipulator.user']; } /** * @return Generator */ private function getRandomGenerator() { return $this->app['random.medium']; } /** * @return BasketRepository */ private function getBasketRepository() { return $this->app['repo.baskets']; } /** * @return TokenRepository */ private function getTokenRepository() { return $this->app['repo.tokens']; } }