/** * @param Request $request * @return \Symfony\Component\HttpFoundation\JsonResponse */ protected function saveApiKeyAction(Request $request) { $apiKey = InputHelper::clean($request->request->get('apiKey')); $dataArray = ['success' => 0]; /** @var \Mautic\InstallBundle\Configurator\Configurator $configurator */ $configurator = $this->get('mautic.configurator'); if ($configurator->isFileWritable()) { try { $cronfigConfig = array('api_key' => $apiKey); // Ensure the config has a secret key $params = $configurator->getParameters(); if (!isset($params['cronfig']) || empty($params['cronfig']['secret_key'])) { $cronfigConfig['secret_key'] = EncryptionHelper::generateKey(); $dataArray['secret_key'] = $cronfigConfig['secret_key']; } // Save the API key only if it doesn't exist or has changed if (!isset($params['cronfig']['api_key']) || !isset($params['cronfig']['secret_key']) || isset($params['cronfig']['api_key']) && $params['cronfig']['api_key'] == $apiKey || isset($params['cronfig']['secret_key']) && $params['cronfig']['secret_key'] == $apiKey) { $configurator->mergeParameters(array('cronfig' => $cronfigConfig)); $configurator->write(); $dataArray['success'] = 1; // We must clear the application cache for the updated values to take effect /** @var \Mautic\CoreBundle\Helper\CacheHelper $cacheHelper */ $cacheHelper = $this->factory->getHelper('cache'); $cacheHelper->clearContainerFile(); } } catch (\RuntimeException $exception) { $this->addFlash('mautic.config.config.error.not.updated', ['%exception%' => $exception->getMessage()], 'error'); } } else { $form->addError(new FormError($this->factory->getTranslator()->trans('mautic.config.notwritable'))); } return $this->sendJsonResponse($dataArray); }
/** * Controller action for install steps * * @param integer $index The step number to process * * @return \Symfony\Component\HttpFoundation\JsonResponse|\Symfony\Component\HttpFoundation\Response */ public function stepAction($index = 0) { // We're going to assume a bit here; if the config file exists already and DB info is provided, assume the app is installed and redirect if ($this->checkIfInstalled()) { return $this->redirect($this->generateUrl('mautic_dashboard_index')); } /** @var \Mautic\InstallBundle\Configurator\Configurator $configurator */ $configurator = $this->container->get('mautic.configurator'); $params = $configurator->getParameters(); $step = $configurator->getStep($index); $action = $this->generateUrl('mautic_installer_step', array('index' => $index)); /** @var \Symfony\Component\Form\Form $form */ $form = $this->container->get('form.factory')->create($step->getFormType(), $step, array('action' => $action)); $tmpl = $this->request->isXmlHttpRequest() ? $this->request->get('tmpl', 'index') : 'index'; // Always pass the requirements into the templates $majors = $configurator->getRequirements(); $minors = $configurator->getOptionalSettings(); $session = $this->factory->getSession(); $completedSteps = $session->get('mautic.installer.completedsteps', array()); // Check to ensure the installer is in the right place if ((empty($params) || empty($params['db_driver'])) && $index > 1) { $session->set('mautic.installer.completedsteps', array(0)); return $this->redirect($this->generateUrl('mautic_installer_step', array('index' => 1))); } if ('POST' === $this->request->getMethod()) { $form->handleRequest($this->request); if ($form->isValid()) { $configurator->mergeParameters($step->update($form->getData())); try { $configurator->write(); } catch (RuntimeException $exception) { return $this->postActionRedirect(array('viewParameters' => array('form' => $form->createView(), 'index' => $index, 'count' => $configurator->getStepCount(), 'version' => $this->factory->getVersion(), 'tmpl' => $tmpl, 'majors' => $majors, 'minors' => $minors, 'appRoot' => $this->container->getParameter('kernel.root_dir'), 'configFile' => $this->factory->getLocalConfigFile()), 'returnUrl' => $this->generateUrl('mautic_installer_step', array('index' => $index)), 'contentTemplate' => $step->getTemplate(), 'passthroughVars' => array('activeLink' => '#mautic_installer_index', 'mauticContent' => 'installer'), 'flashes' => array(array('type' => 'error', 'msg' => 'mautic.installer.error.writing.configuration')), 'forwardController' => false)); } // Post-step processing $flashes = array(); $originalData = $form->getData(); $success = true; switch ($index) { case 1: //let's create a dynamic details $dbParams = (array) $originalData; //validate settings $dbValid = false; $translator = $this->factory->getTranslator(); if ($dbParams['driver'] == 'pdo_sqlite') { if (empty($dbParams['path'])) { $form['path']->addError(new FormError($translator->trans('mautic.core.value.required', array(), 'validators'))); } elseif (!is_writable(dirname($dbParams['path'])) || substr($dbParams['path'], -4) != '.db3') { $form['path']->addError(new FormError($translator->trans('mautic.install.database.path.invalid', array(), 'validators'))); } else { $root = $this->factory->getSystemPath('root'); if (strpos(dirname($dbParams['path']), $root) !== false) { $flashes[] = array('msg' => 'mautic.install.database.path.warning', 'msgVars' => array('%root%' => $root), 'domain' => 'validators'); } $dbValid = true; } if (!file_exists($dbParams['path'])) { //create the file file_put_contents($dbParams['path'], ''); } } else { $required = array('host', 'name', 'user'); foreach ($required as $r) { if (empty($dbParams[$r])) { $form[$r]->addError(new FormError($translator->trans('mautic.core.value.required', array(), 'validators'))); } } if ((int) $dbParams['port'] <= 0) { $form['port']->addError(new FormError($translator->trans('mautic.install.database.port.invalid', array(), 'validators'))); } else { $dbValid = true; } } if (!$dbValid) { $success = false; } else { $dbParams['dbname'] = $dbParams['name']; unset($dbParams['name']); // Support for env variables foreach ($dbParams as $k => &$v) { if (!empty($v) && is_string($v) && preg_match('/getenv\\((.*?)\\)/', $v, $match)) { $v = (string) getenv($match[1]); } } $result = $this->performDatabaseInstallation($dbParams); if (is_array($result)) { $flashes[] = $result; $success = false; } else { //write the working database details to the configuration file $configurator->mergeParameters($step->update($originalData)); $configurator->write(); $result = $this->performFixtureInstall($dbParams); if (is_array($result)) { $flashes[] = $result; $success = false; } } } break; case 2: $entityManager = $this->getEntityManager(); //ensure the username and email are unique try { $existing = $entityManager->getRepository('MauticUserBundle:User')->find(1); } catch (\Exception $e) { $existing = null; } if (!empty($existing)) { $result = $this->performUserAddition($form, $existing); } else { $result = $this->performUserAddition($form); } if (is_array($result)) { $flashes[] = $result; $success = false; } //store the data unset($originalData->password); $session->set('mautic.installer.user', $originalData); break; default: $success = true; } if ($success) { $completedSteps[] = $index; $session->set('mautic.installer.completedsteps', $completedSteps); $index++; if ($index < $configurator->getStepCount()) { $nextStep = $configurator->getStep($index); $action = $this->generateUrl('mautic_installer_step', array('index' => $index)); $form = $this->container->get('form.factory')->create($nextStep->getFormType(), $nextStep, array('action' => $action)); return $this->postActionRedirect(array('viewParameters' => array('form' => $form->createView(), 'index' => $index, 'count' => $configurator->getStepCount(), 'version' => $this->factory->getVersion(), 'tmpl' => $tmpl, 'majors' => $majors, 'minors' => $minors, 'appRoot' => $this->container->getParameter('kernel.root_dir'), 'configFile' => $this->factory->getLocalConfigFile()), 'flashes' => $flashes, 'returnUrl' => $action, 'contentTemplate' => $nextStep->getTemplate(), 'forwardController' => false)); } /* * Post-processing once installation is complete */ // Need to generate a secret value and merge it into the config $configurator->mergeParameters(array('secret_key' => EncryptionHelper::generateKey())); // Write the updated config file try { $configurator->write(); } catch (RuntimeException $exception) { $flashes[] = array('type' => 'error', 'msg' => 'mautic.installer.error.writing.configuration'); } // Clear the cache one final time with the updated config /** @var \Mautic\CoreBundle\Helper\CacheHelper $cacheHelper */ $cacheHelper = $this->factory->getHelper('cache'); $cacheHelper->clearContainerFile(); return $this->postActionRedirect(array('viewParameters' => array('welcome_url' => $this->generateUrl('mautic_dashboard_index'), 'parameters' => $configurator->render(), 'config_path' => $this->factory->getLocalConfigFile(), 'is_writable' => $configurator->isFileWritable(), 'version' => $this->factory->getVersion(), 'tmpl' => $tmpl), 'returnUrl' => $this->generateUrl('mautic_installer_final'), 'contentTemplate' => 'MauticInstallBundle:Install:final.html.php', 'flashes' => $flashes, 'forwardController' => false)); } elseif (!empty($flashes)) { return $this->postActionRedirect(array('viewParameters' => array('form' => $form->createView(), 'index' => $index, 'count' => $configurator->getStepCount(), 'version' => $this->factory->getVersion(), 'tmpl' => $tmpl, 'majors' => $majors, 'minors' => $minors, 'appRoot' => $this->container->getParameter('kernel.root_dir'), 'configFile' => $this->factory->getLocalConfigFile()), 'returnUrl' => $this->generateUrl('mautic_installer_step', array('index' => $index)), 'contentTemplate' => $step->getTemplate(), 'flashes' => $flashes, 'forwardController' => false)); } } } else { //redirect back to last step if the user advanced ahead via the URL $last = (int) end($completedSteps) + 1; if ($index > $last) { return $this->redirect($this->generateUrl('mautic_installer_step', array('index' => (int) $last))); } } return $this->delegateView(array('viewParameters' => array('form' => $form->createView(), 'index' => $index, 'count' => $configurator->getStepCount(), 'version' => $this->factory->getVersion(), 'tmpl' => $tmpl, 'majors' => $majors, 'minors' => $minors, 'appRoot' => $this->container->getParameter('kernel.root_dir'), 'configFile' => $this->factory->getLocalConfigFile(), 'completedSteps' => $completedSteps), 'contentTemplate' => $step->getTemplate(), 'passthroughVars' => array('route' => $this->generateUrl('mautic_installer_step', array('index' => $index))))); }
/** * Controller action for editing the application configuration * * @return \Symfony\Component\HttpFoundation\JsonResponse|\Symfony\Component\HttpFoundation\Response */ public function editAction() { //admin only allowed if (!$this->factory->getUser()->isAdmin()) { return $this->accessDenied(); } $event = new ConfigBuilderEvent($this->factory); $dispatcher = $this->get('event_dispatcher'); $dispatcher->dispatch(ConfigEvents::CONFIG_ON_GENERATE, $event); $formConfigs = $event->getForms(); $formThemes = $event->getFormThemes(); $doNotChange = $this->factory->getParameter('security.restrictedConfigFields'); $doNotChangeDisplayMode = $this->factory->getParameter('security.restrictedConfigFields.displayMode', 'remove'); $this->mergeParamsWithLocal($formConfigs, $doNotChange); /* @type \Mautic\ConfigBundle\Model\ConfigModel $model */ $model = $this->factory->getModel('config'); // Create the form $action = $this->generateUrl('mautic_config_action', array('objectAction' => 'edit')); $form = $model->createForm($formConfigs, $this->get('form.factory'), array('action' => $action, 'doNotChange' => $doNotChange, 'doNotChangeDisplayMode' => $doNotChangeDisplayMode)); /** @var \Mautic\InstallBundle\Configurator\Configurator $configurator */ $configurator = $this->get('mautic.configurator'); $isWritabale = $configurator->isFileWritable(); // Check for a submitted form and process it if ($this->request->getMethod() == 'POST') { if (!($cancelled = $this->isFormCancelled($form))) { $isValid = false; if ($isWritabale && ($isValid = $this->isFormValid($form))) { // Bind request to the form $post = $this->request->request; $formData = $form->getData(); // Dispatch pre-save event. Bundles may need to modify some field values like passwords before save $configEvent = new ConfigEvent($formData, $post); $dispatcher->dispatch(ConfigEvents::CONFIG_PRE_SAVE, $configEvent); $formValues = $configEvent->getConfig(); // Prevent these from getting overwritten with empty values $unsetIfEmpty = $configEvent->getPreservedFields(); // Merge each bundle's updated configuration into the local configuration foreach ($formValues as $object) { $checkThese = array_intersect(array_keys($object), $unsetIfEmpty); foreach ($checkThese as $checkMe) { if (empty($object[$checkMe])) { unset($object[$checkMe]); } } $configurator->mergeParameters($object); } try { // Ensure the config has a secret key $params = $configurator->getParameters(); if (empty($params['secret_key'])) { $configurator->mergeParameters(array('secret_key' => EncryptionHelper::generateKey())); } $configurator->write(); $this->addFlash('mautic.config.config.notice.updated'); // We must clear the application cache for the updated values to take effect /** @var \Mautic\CoreBundle\Helper\CacheHelper $cacheHelper */ $cacheHelper = $this->factory->getHelper('cache'); $cacheHelper->clearCache(false, true); } catch (RuntimeException $exception) { $this->addFlash('mautic.config.config.error.not.updated', array('%exception%' => $exception->getMessage()), 'error'); } } elseif (!$isWritabale) { $form->addError(new FormError($this->factory->getTranslator()->trans('mautic.config.notwritable'))); } } // If the form is saved or cancelled, redirect back to the dashboard if ($cancelled || $isValid) { if (!$cancelled && $this->isFormApplied($form)) { return $this->delegateRedirect($this->generateUrl('mautic_config_action', array('objectAction' => 'edit'))); } else { return $this->delegateRedirect($this->generateUrl('mautic_dashboard_index')); } } } $tmpl = $this->request->isXmlHttpRequest() ? $this->request->get('tmpl', 'index') : 'index'; return $this->delegateView(array('viewParameters' => array('tmpl' => $tmpl, 'security' => $this->factory->getSecurity(), 'form' => $this->setFormTheme($form, 'MauticConfigBundle:Config:form.html.php', $formThemes), 'formConfigs' => $formConfigs, 'isWritable' => $isWritabale), 'contentTemplate' => 'MauticConfigBundle:Config:form.html.php', 'passthroughVars' => array('activeLink' => '#mautic_config_index', 'mauticContent' => 'config', 'route' => $this->generateUrl('mautic_config_action', array('objectAction' => 'edit'))))); }
/** * Controller action for install steps * * @param integer $index The step number to process * * @return \Symfony\Component\HttpFoundation\JsonResponse|\Symfony\Component\HttpFoundation\Response */ public function stepAction($index = 0) { // We're going to assume a bit here; if the config file exists already and DB info is provided, assume the app // is installed and redirect if ($this->checkIfInstalled()) { return $this->redirect($this->generateUrl('mautic_dashboard_index')); } if (strpos($index, '.') !== false) { list($index, $subIndex) = explode('.', $index); } $params = $this->configurator->getParameters(); $step = $this->configurator->getStep($index)[0]; $action = $this->generateUrl('mautic_installer_step', ['index' => $index]); $form = $this->createForm($step->getFormType(), $step, ['action' => $action]); $tmpl = $this->request->isXmlHttpRequest() ? $this->request->get('tmpl', 'index') : 'index'; $session = $this->get('session'); $completedSteps = $session->get('mautic.installer.completedsteps', []); // Check to ensure the installer is in the right place if ((empty($params) || empty($params['db_driver'])) && $index > 1) { $session->set('mautic.installer.completedsteps', [0]); return $this->redirect($this->generateUrl('mautic_installer_step', ['index' => 1])); } // Note if this step is complete $complete = false; if ('POST' === $this->request->getMethod()) { $form->handleRequest($this->request); if ($form->isValid()) { // Post-step processing $formData = $form->getData(); switch ($index) { case self::CHECK_STEP: $complete = true; break; case self::DOCTRINE_STEP: $dbParams = (array) $formData; $this->validateDatabaseParams($form, $dbParams); if (!$form->getErrors(true)->count()) { // Check if connection works and/or create database if applicable $schemaHelper = new SchemaHelper($dbParams); try { $schemaHelper->testConnection(); if ($schemaHelper->createDatabase()) { $formData->server_version = $schemaHelper->getServerVersion(); if ($this->saveConfiguration($formData, $step, true)) { // Refresh to install schema with new connection information in the container return $this->redirect($this->generateUrl('mautic_installer_step', ['index' => 1.1])); } $this->addFlash('mautic.installer.error.writing.configuration', [], 'error'); } else { $this->addFlash('mautic.installer.error.creating.database', ['%name%' => $dbParams['name']], 'error'); } } catch (\Exception $exception) { $this->addFlash('mautic.installer.error.connecting.database', ['%exception%' => $exception->getMessage()], 'error'); } } break; case self::USER_STEP: try { $this->createAdminUserStep($formData); // Store the data to repopulate the form unset($formData->password); $session->set('mautic.installer.user', $formData); $complete = true; } catch (\Exception $exception) { $this->addFlash('mautic.installer.error.creating.user', ['%exception%' => $exception->getMessage()], 'error'); } break; case self::EMAIL_STEP: if (!$this->saveConfiguration($formData, $step)) { $this->addFlash('mautic.installer.error.writing.configuration', [], 'error'); } else { $complete = true; } break; } } } elseif (!empty($subIndex)) { switch ($index) { case self::DOCTRINE_STEP: $dbParams = (array) $step; $schemaHelper = new SchemaHelper($dbParams); $schemaHelper->setEntityManager($this->get('doctrine.orm.entity_manager')); switch ((int) $subIndex) { case 1: try { if (!$schemaHelper->installSchema()) { $this->addFlash('mautic.installer.error.no.metadata', [], 'error'); } else { return $this->redirect($this->generateUrl('mautic_installer_step', ['index' => 1.2])); } } catch (\Exception $exception) { $this->addFlash('mautic.installer.error.installing.data', ['%exception%' => $exception->getMessage(), 'error']); } return $this->redirect($this->generateUrl('mautic_installer_step', ['index' => 1])); case 2: try { $this->installDatabaseFixtures(); $complete = true; } catch (\Exception $exception) { $this->addFlash('mautic.installer.error.adding.fixtures', ['%exception%' => $exception->getMessage()], 'error'); return $this->redirect($this->generateUrl('mautic_installer_step', ['index' => 1])); } break; } break; } } if ($complete) { $completedSteps[] = $index; $session->set('mautic.installer.completedsteps', $completedSteps); $index++; if ($index < $this->configurator->getStepCount()) { // On to the next step return $this->redirect($this->generateUrl('mautic_installer_step', ['index' => (int) $index])); } else { // Merge final things into the config, wipe the container, and we're done! $finalConfigVars = ['secret_key' => EncryptionHelper::generateKey(), 'site_url' => $this->request->getSchemeAndHttpHost() . $this->request->getBaseUrl()]; if (!$this->saveConfiguration($finalConfigVars, null, true)) { $this->addFlash('mautic.installer.error.writing.configuration', [], 'error'); } return $this->postActionRedirect(['viewParameters' => ['welcome_url' => $this->generateUrl('mautic_dashboard_index'), 'parameters' => $this->configurator->render(), 'version' => MAUTIC_VERSION, 'tmpl' => $tmpl], 'returnUrl' => $this->generateUrl('mautic_installer_final'), 'contentTemplate' => 'MauticInstallBundle:Install:final.html.php', 'forwardController' => false]); } } else { // Redirect back to last step if the user advanced ahead via the URL $last = (int) end($completedSteps) + 1; if ($index && $index > $last) { return $this->redirect($this->generateUrl('mautic_installer_step', ['index' => (int) $last])); } } return $this->delegateView(['viewParameters' => ['form' => $form->createView(), 'index' => $index, 'count' => $this->configurator->getStepCount(), 'version' => MAUTIC_VERSION, 'tmpl' => $tmpl, 'majors' => $this->configurator->getRequirements(), 'minors' => $this->configurator->getOptionalSettings(), 'appRoot' => $this->container->getParameter('kernel.root_dir'), 'configFile' => $this->get('mautic.helper.paths')->getSystemPath('local_config'), 'completedSteps' => $completedSteps], 'contentTemplate' => $step->getTemplate(), 'passthroughVars' => ['route' => $this->generateUrl('mautic_installer_step', ['index' => $index])]]); }
/** * Create/update user from authentication plugins. * * @param User $user * @param bool|true $createIfNotExists * * @return User */ public function saveUser(User $user, $createIfNotExists = true) { $isNew = !$user->getId(); if ($isNew) { // Check if user exists and create one if applicable try { $user = $this->loadUserByUsername($user->getUsername(), $user->getEmail()); } catch (UsernameNotFoundException $exception) { if (!$createIfNotExists) { throw new BadCredentialsException(); } } } // Validation for User objects returned by a plugin if (!$user->getRole()) { throw new AuthenticationException('mautic.integration.sso.error.no_role'); } if (!$user->getUsername()) { throw new AuthenticationException('mautic.integration.sso.error.no_username'); } if (!$user->getEmail()) { throw new AuthenticationException('mautic.integration.sso.error.no_email'); } if (!$user->getFirstName() || !$user->getLastName()) { throw new AuthenticationException('mautic.integration.sso.error.no_name'); } // Check for plain password $plainPassword = $user->getPlainPassword(); if ($plainPassword) { // Encode plain text $user->setPassword($this->encoder->getEncoder($user)->encodePassword($plainPassword, $user->getSalt())); } elseif (!($password = $user->getPassword())) { // Generate and encode a random password $user->setPassword($this->encoder->getEncoder($user)->encodePassword(EncryptionHelper::generateKey(), $user->getSalt())); } $event = new UserEvent($user, $isNew); if ($this->dispatcher->hasListeners(UserEvents::USER_PRE_SAVE)) { $event = $this->dispatcher->dispatch(UserEvents::USER_PRE_SAVE, $event); } $this->userRepository->saveEntity($user); if ($this->dispatcher->hasListeners(UserEvents::USER_POST_SAVE)) { $this->dispatcher->dispatch(UserEvents::USER_POST_SAVE, $event); } return $user; }