/** * Execute the action */ public function execute() { // get parameters $this->id = $this->getParameter('id', 'int'); // does the item exist if ($this->id !== null && BackendExtensionsModel::existsTemplate($this->id)) { // call parent, this will probably add some general CSS/JS or other required files parent::execute(); // init var $success = false; // get template (we need the title) $item = BackendExtensionsModel::getTemplate($this->id); // valid template? if (!empty($item)) { // delete the page $success = BackendExtensionsModel::deleteTemplate($this->id); // trigger event BackendModel::triggerEvent($this->getModule(), 'after_delete_template', array('id' => $this->id)); } // page is deleted, so redirect to the overview if ($success) { $this->redirect(BackendModel::createURLForAction('ThemeTemplates') . '&theme=' . $item['theme'] . '&report=deleted-template&var=' . urlencode($item['label'])); } else { $this->redirect(BackendModel::createURLForAction('ThemeTemplates') . '&error=non-existing'); } } else { // something went wrong $this->redirect(BackendModel::createURLForAction('ThemeTemplates') . '&error=non-existing'); } }
/** * Validate the form */ protected function validateForm() { if ($this->frm->isSubmitted()) { $this->frm->cleanupFields(); // validation $fields = $this->frm->getFields(); $fields['title']->isFilled(Language::err('TitleIsRequired')); $fields['description']->isFilled(Language::err('FieldIsRequired')); $fields['author_name']->isFilled(Language::err('FieldIsRequired')); $fields['author_url']->isFilled(Language::err('FieldIsRequired')); $fields['author_email']->isFilled(Language::err('FieldIsRequired')); // cleanup the modulename $title = preg_replace('/[^A-Za-z ]/', '', $fields['title']->getValue()); // check if there is already a module with this name if (BackendExtensionsModel::existsModule($title)) { $fields['title']->addError(Language::err('DuplicateModuleName')); } if ($this->frm->isCorrect()) { $this->record['title'] = $title; $this->record['description'] = trim($fields['description']->getValue()); $this->record['author_name'] = $fields['author_name']->getValue(); $this->record['author_url'] = $fields['author_url']->getValue(); $this->record['author_email'] = $fields['author_email']->getValue(); $this->record['camel_case_name'] = BackendModuleMakerHelper::buildCamelCasedName($title); $this->record['underscored_name'] = BackendModuleMakerHelper::buildUnderscoredName($title); \SpoonSession::set('module', $this->record); $this->redirect(Model::createURLForAction('AddStep2')); } } }
/** * Export the templates as XML. */ protected function parse() { $xml = Model::createTemplateXmlForExport($this->selectedTheme); $filename = 'templates_' . BackendModel::getUTCDate('d-m-Y') . '.xml'; header('Content-type: text/xml'); header('Content-disposition: attachment; filename="' . $filename . '"'); echo $xml; exit; }
/** * Load the data. * This will also set some warnings if needed. */ private function loadData() { // inform that the module is not installed yet if (!BackendModel::isModuleInstalled($this->currentModule)) { $this->warnings[] = array('message' => BL::getMessage('InformationModuleIsNotInstalled')); } // fetch the module information $moduleInformation = BackendExtensionsModel::getModuleInformation($this->currentModule); $this->information = $moduleInformation['data']; $this->warnings = $this->warnings + $moduleInformation['warnings']; }
/** * Load the record */ private function loadData() { // get data $this->selectedTheme = $this->getParameter('theme', 'string'); // build available themes foreach (BackendExtensionsModel::getThemes() as $theme) { $this->availableThemes[$theme['value']] = $theme['label']; } // determine selected theme, based upon submitted form or default theme $this->selectedTheme = \SpoonFilter::getValue($this->selectedTheme, array_keys($this->availableThemes), $this->get('fork.settings')->get('Core', 'theme', 'core')); }
/** * Validate if the theme can be installed. */ private function validateInstall() { // already installed if (BackendExtensionsModel::isThemeInstalled($this->currentTheme)) { $this->redirect(BackendModel::createURLForAction('Themes') . '&error=already-installed&var=' . $this->currentTheme); } // no information file present if (!is_file(FRONTEND_PATH . '/Themes/' . $this->currentTheme . '/info.xml')) { $this->redirect(BackendModel::createURLForAction('Themes') . '&error=no-information-file&var=' . $this->currentTheme); } }
/** * Load the data for the 2 data grids. */ private function loadData() { // get all manageable modules $modules = BackendExtensionsModel::getModules(); // split the modules in 2 separate data grid sources foreach ($modules as $module) { if ($module['installed']) { $this->installedModules[] = $module; } else { $this->installableModules[] = $module; } } }
/** * Execute the action */ public function execute() { parent::execute(); // get some data $modulesThatRequireAkismet = BackendExtensionsModel::getModulesThatRequireAkismet(); $modulesThatRequireGoogleMaps = BackendExtensionsModel::getModulesThatRequireGoogleMaps(); // set properties $this->needsAkismet = !empty($modulesThatRequireAkismet); $this->needsGoogleMaps = !empty($modulesThatRequireGoogleMaps); $this->loadForm(); $this->validateForm(); $this->parse(); $this->display(); }
/** * Checks the settings and optionally returns an array with warnings * * @return array */ public static function checkSettings() { $warnings = array(); // check if debug-mode is active if (BackendModel::getContainer()->getParameter('kernel.debug')) { $warnings[] = array('message' => Language::err('DebugModeIsActive')); } // check if this action is allowed if (Authentication::isAllowedAction('Index', 'Settings')) { // check if the fork API keys are available if (self::get('fork.settings')->get('Core', 'fork_api_private_key') == '' || self::get('fork.settings')->get('Core', 'fork_api_public_key') == '') { $warnings[] = array('message' => sprintf(Language::err('ForkAPIKeys'), self::createURLForAction('Index', 'Settings'))); } } // check for extensions warnings $warnings = array_merge($warnings, BackendExtensionsModel::checkSettings()); return $warnings; }
/** * Execute the action. */ public function execute() { // get parameters $this->currentModule = $this->getParameter('module', 'string'); // does the item exist if ($this->currentModule !== null && BackendExtensionsModel::existsModule($this->currentModule)) { // call parent, this will probably add some general CSS/JS or other required files parent::execute(); // make sure this module can be installed $this->validateInstall(); // do the actual install BackendExtensionsModel::installModule($this->currentModule); // remove our container cache after this request $filesystem = new Filesystem(); $filesystem->remove($this->getContainer()->getParameter('kernel.cache_dir')); // redirect to index with a success message $this->redirect(BackendModel::createURLForAction('Modules') . '&report=module-installed&var=' . $this->currentModule . '&highlight=row-module_' . $this->currentModule); } else { // no item found, redirect to index, because somebody is f*****g with our url $this->redirect(BackendModel::createURLForAction('Modules') . '&error=non-existing'); } }
/** * @return Response */ public function getContent() { $filename = 'templates_' . BackendModel::getUTCDate('d-m-Y') . '.xml'; return new Response(Model::createTemplateXmlForExport($this->selectedTheme), Response::HTTP_OK, ['Content-type' => 'text/xml', 'Content-disposition' => 'attachment; filename="' . $filename . '"']); }
/** * Validate a submitted form and process it. */ private function validateForm() { // The form is submitted if (!$this->frm->isSubmitted()) { return; } /** @var $fileFile \SpoonFormFile */ $fileFile = $this->frm->getField('file'); $zip = null; $zipFiles = null; // Validate the file. Check if the file field is filled and if it's a zip. if ($fileFile->isFilled(BL::err('FieldIsRequired')) && $fileFile->isAllowedExtension(array('zip'), sprintf(BL::getError('ExtensionNotAllowed'), 'zip'))) { // Create ziparchive instance $zip = new ZipArchive(); // Try and open it if ($zip->open($fileFile->getTempFileName()) === true) { // zip file needs to contain some files if ($zip->numFiles > 0) { $infoXml = $this->findInfoFileInZip($zip); // Throw error if info.xml is not found if ($infoXml === null) { return $fileFile->addError(sprintf(BL::getError('NoInformationFile'), $fileFile->getFileName())); } // Parse xml try { // Load info.xml $infoXml = @new \SimpleXMLElement($infoXml, LIBXML_NOCDATA, false); // Convert xml to useful array $this->info = BackendExtensionsModel::processThemeXml($infoXml); // Empty data (nothing useful) if (empty($this->info)) { return $fileFile->addError(BL::getMessage('InformationFileIsEmpty')); } // Define the theme name, based on the info.xml file. $this->themeName = $this->info['name']; } catch (Exception $e) { // Warning that the information file is corrupt return $fileFile->addError(BL::getMessage('InformationFileCouldNotBeLoaded')); } // Wow wow, you are trying to upload an already existing theme if (BackendExtensionsModel::existsTheme($this->themeName)) { return $fileFile->addError(sprintf(BL::getError('ThemeAlreadyExists'), $this->themeName)); } $zipFiles = $this->getValidatedFilesList($zip); } else { // Empty zip file $fileFile->addError(BL::getError('FileIsEmpty')); } } else { // Something went very wrong, probably corrupted return $fileFile->addError(BL::getError('CorruptedFile')); } } // Passed all validation if ($this->frm->isCorrect() && $zip !== null) { // Unpack the zip. If the files were not found inside a parent directory, we create the theme directory. $themePath = FRONTEND_PATH . '/Themes'; if ($this->parentFolderName === null) { $themePath .= "/{$this->themeName}"; } $zip->extractTo($themePath, $zipFiles); // Rename the original name of the parent folder from the zip to the correct theme foldername. $fs = new Filesystem(); $parentZipFolderPath = $themePath . '/' . $this->parentFolderName; if ($this->parentFolderName !== $this->themeName && $this->parentFolderName !== null && $fs->exists($parentZipFolderPath)) { $fs->rename($parentZipFolderPath, "{$themePath}/{$this->themeName}"); } // Run installer BackendExtensionsModel::installTheme($this->themeName); // Redirect with fireworks $this->redirect(BackendModel::createURLForAction('Themes') . '&report=theme-installed&var=' . $this->themeName); } }
/** * Do we have write rights to the modules folders? * * @return bool */ private function isWritable() { // check if writable if (!BackendExtensionsModel::isWritable(FRONTEND_MODULES_PATH)) { return false; } if (!BackendExtensionsModel::isWritable(BACKEND_MODULES_PATH)) { return false; } // everything is writeable return true; }
/** * Validate the form */ private function validateForm() { // is the form submitted? if ($this->frm->isSubmitted()) { // cleanup the submitted fields, ignore fields that were added by hackers $this->frm->cleanupFields(); // required fields $this->frm->getField('file')->isFilled(BL::err('FieldIsRequired')); $this->frm->getField('label')->isFilled(BL::err('FieldIsRequired')); $this->frm->getField('format')->isFilled(BL::err('FieldIsRequired')); // check if the template file exists if ($this->frm->getField('theme')->getValue() == 'Core') { $templateFile = PATH_WWW . '/src/Frontend/Core/Layout/Templates/' . $this->frm->getField('file')->getValue(); } else { $templateFile = PATH_WWW . '/src/Frontend/Themes/' . $this->frm->getField('theme')->getValue() . '/Core/Layout/Templates/' . $this->frm->getField('file')->getValue(); } if (!is_file($templateFile)) { $this->frm->getField('file')->addError(BL::err('TemplateFileNotFound')); } // validate syntax $syntax = trim(str_replace(array("\n", "\r", ' '), '', $this->frm->getField('format')->getValue())); // init var $table = BackendExtensionsModel::templateSyntaxToArray($syntax); // validate the syntax if ($table === false) { $this->frm->getField('format')->addError(BL::err('InvalidTemplateSyntax')); } else { $html = BackendExtensionsModel::buildTemplateHTML($syntax); $cellCount = 0; $first = true; $errors = array(); // loop rows foreach ($table as $row) { // first row defines the cellcount if ($first) { $cellCount = count($row); } // not same number of cells if (count($row) != $cellCount) { // add error $errors[] = BL::err('InvalidTemplateSyntax'); // stop break; } // doublecheck position names foreach ($row as $cell) { // ignore unavailable space if ($cell != '/') { // not alphanumeric -> error if (!in_array($cell, $this->names)) { $errors[] = sprintf(BL::getError('NonExistingPositionName'), $cell); } elseif (mb_substr_count($html, '"#position-' . $cell . '"') != 1) { // can't build proper html -> error $errors[] = BL::err('InvalidTemplateSyntax'); } } } // reset $first = false; } // add errors if ($errors) { $this->frm->getField('format')->addError(implode('<br />', array_unique($errors))); } } // no errors? if ($this->frm->isCorrect()) { // build array $item['theme'] = $this->frm->getField('theme')->getValue(); $item['label'] = $this->frm->getField('label')->getValue(); $item['path'] = 'Core/Layout/Templates/' . $this->frm->getField('file')->getValue(); $item['active'] = $this->frm->getField('active')->getActualValue(); $item['data']['format'] = trim(str_replace(array("\n", "\r", ' '), '', $this->frm->getField('format')->getValue())); $item['data']['names'] = $this->names; $item['data']['default_extras'] = $this->extras; $item['data']['default_extras_' . BL::getWorkingLanguage()] = $this->extras; $item['data']['image'] = $this->frm->getField('image')->isChecked(); // serialize the data $item['data'] = serialize($item['data']); // insert the item $item['id'] = BackendExtensionsModel::insertTemplate($item); // trigger event BackendModel::triggerEvent($this->getModule(), 'after_add_template', array('item' => $item)); // set default template if ($this->frm->getField('default')->getChecked() && $item['theme'] == $this->get('fork.settings')->get('Core', 'theme', 'core')) { $this->get('fork.settings')->set($this->getModule(), 'default_template', $item['id']); } // everything is saved, so redirect to the overview $this->redirect(BackendModel::createURLForAction('ThemeTemplates') . '&theme=' . $item['theme'] . '&report=added-template&var=' . rawurlencode($item['label']) . '&highlight=row-' . $item['id']); } } }
/** * Parse. */ protected function parse() { parent::parse(); // assign theme data $this->tpl->assign('name', $this->currentTheme); $this->tpl->assign('warnings', $this->warnings); $this->tpl->assign('information', $this->information); $this->tpl->assign('showExtensionsInstallTheme', !BackendExtensionsModel::isThemeInstalled($this->currentTheme) && BackendAuthentication::isAllowedAction('InstallTheme')); // data grids $this->tpl->assign('dataGridTemplates', isset($this->dataGridTemplates) && $this->dataGridTemplates->getNumResults() > 0 ? $this->dataGridTemplates->getContent() : false); }
/** * Parse */ protected function parse() { parent::parse(); // set $this->record['url'] = $this->meta->getURL(); if ($this->id == 1) { $this->record['url'] = ''; } // parse some variables $this->tpl->assign('item', $this->record); $this->tpl->assign('isGod', $this->isGod); $this->tpl->assign('templates', $this->templates); $this->tpl->assign('positions', $this->positions); $this->tpl->assign('extrasData', json_encode(BackendExtensionsModel::getExtrasData())); $this->tpl->assign('extrasById', json_encode(BackendExtensionsModel::getExtras())); $this->tpl->assign('prefixURL', rtrim(BackendPagesModel::getFullURL($this->record['parent_id']), '/')); $this->tpl->assign('formErrors', (string) $this->frm->getErrors()); // init var $showDelete = true; // has children? if (BackendPagesModel::getFirstChildId($this->record['id']) !== false) { $showDelete = false; } if (!$this->record['delete_allowed']) { $showDelete = false; } // allowed? if (!BackendAuthentication::isAllowedAction('Delete', $this->getModule())) { $showDelete = false; } // show delete button $this->tpl->assign('showPagesDelete', $showDelete); // assign template $this->tpl->assignArray($this->templates[$this->record['template_id']], 'template'); // parse datagrids $this->tpl->assign('revisions', $this->dgRevisions->getNumResults() != 0 ? $this->dgRevisions->getContent() : false); $this->tpl->assign('drafts', $this->dgDrafts->getNumResults() != 0 ? $this->dgDrafts->getContent() : false); // parse the tree $this->tpl->assign('tree', BackendPagesModel::getTreeHTML()); }
/** * Parse */ protected function parse() { parent::parse(); // parse some variables $this->tpl->assign('templates', $this->templates); $this->tpl->assign('isGod', $this->isGod); $this->tpl->assign('positions', $this->positions); $this->tpl->assign('extrasData', json_encode(BackendExtensionsModel::getExtrasData())); $this->tpl->assign('extrasById', json_encode(BackendExtensionsModel::getExtras())); $this->tpl->assign('prefixURL', rtrim(BackendPagesModel::getFullURL(1), '/')); $this->tpl->assign('formErrors', (string) $this->frm->getErrors()); $this->tpl->assign('showTags', $this->showTags()); // get default template id $defaultTemplateId = $this->get('fork.settings')->get('Pages', 'default_template', 1); // assign template $this->tpl->assignArray($this->templates[$defaultTemplateId], 'template'); // parse the form $this->frm->parse($this->tpl); // parse the tree $this->tpl->assign('tree', BackendPagesModel::getTreeHTML()); }
/** * Do we have write rights to the modules folders? * * @return bool */ private function isWritable() { if (!BackendExtensionsModel::isWritable(FRONTEND_MODULES_PATH)) { return false; } return BackendExtensionsModel::isWritable(BACKEND_MODULES_PATH); }
/** * Validates the form. */ private function validateForm() { // is the form submitted? if ($this->frm->isSubmitted()) { // no errors? if ($this->frm->isCorrect()) { // determine themes $newTheme = $this->frm->getField('installedThemes')->getValue(); $oldTheme = $this->get('fork.settings')->get('Core', 'theme', 'core'); // check if we actually switched themes if ($newTheme != $oldTheme) { // fetch templates $oldTemplates = BackendExtensionsModel::getTemplates($oldTheme); $newTemplates = BackendExtensionsModel::getTemplates($newTheme); // check if templates already exist if (empty($newTemplates)) { // templates do not yet exist; don't switch $this->redirect(BackendModel::createURLForAction('Themes') . '&error=no-templates-available'); exit; } // fetch current default template $oldDefaultTemplatePath = $oldTemplates[$this->get('fork.settings')->get('Pages', 'default_template')]['path']; // loop new templates foreach ($newTemplates as $newTemplateId => $newTemplate) { // check if a a similar default template exists if ($newTemplate['path'] == $oldDefaultTemplatePath) { // set new default id $newDefaultTemplateId = (int) $newTemplateId; break; } } // no default template was found, set first template as default if (!isset($newDefaultTemplateId)) { $newDefaultTemplateId = array_keys($newTemplates); $newDefaultTemplateId = $newDefaultTemplateId[0]; } // update theme $this->get('fork.settings')->set('Core', 'theme', $newTheme); // save new default template $this->get('fork.settings')->set('Pages', 'default_template', $newDefaultTemplateId); // loop old templates foreach ($oldTemplates as $oldTemplateId => $oldTemplate) { // loop new templates foreach ($newTemplates as $newTemplateId => $newTemplate) { // if the templates don't match we can skip this one if ($oldTemplate['path'] != $newTemplate['path']) { continue; } // switch template BackendPagesModel::updatePagesTemplates($oldTemplateId, $newTemplateId); // break loop continue 2; } // getting here meant we found no matching template for the new theme; pick first theme's template as default BackendPagesModel::updatePagesTemplates($oldTemplateId, $newDefaultTemplateId); } // trigger event BackendModel::triggerEvent($this->getModule(), 'after_changed_theme'); } // assign report $this->tpl->assign('report', true); $this->tpl->assign('reportMessage', BL::msg('Saved')); } } }
/** * Switch templates for all existing pages * * @param int $oldTemplateId The id of the new template to replace. * @param int $newTemplateId The id of the new template to use. * @param bool $overwrite Overwrite all pages with default blocks. */ public static function updatePagesTemplates($oldTemplateId, $newTemplateId, $overwrite = false) { $newTemplateId = (int) $newTemplateId; $oldTemplateId = (int) $oldTemplateId; $overwrite = (bool) $overwrite; // fetch new template data $newTemplate = BackendExtensionsModel::getTemplate($newTemplateId); $newTemplate['data'] = @unserialize($newTemplate['data']); // fetch all pages $pages = (array) BackendModel::getContainer()->get('database')->getRecords('SELECT * FROM pages WHERE template_id = ? AND status IN (?, ?)', array($oldTemplateId, 'active', 'draft')); // there is no active/draft page with the old template id if (empty($pages)) { return; } // loop pages foreach ($pages as $page) { // fetch blocks $blocksContent = self::getBlocks($page['id'], $page['revision_id'], $page['language']); // unset revision id unset($page['revision_id']); // change template $page['template_id'] = $newTemplateId; // save new page revision $page['revision_id'] = self::update($page); // overwrite all blocks with current defaults if ($overwrite) { // init var $blocksContent = array(); // fetch default blocks for this page $defaultBlocks = array(); if (isset($newTemplate['data']['default_extras_' . $page['language']])) { $defaultBlocks = $newTemplate['data']['default_extras_' . $page['language']]; } elseif (isset($newTemplate['data']['default_extras'])) { $defaultBlocks = $newTemplate['data']['default_extras']; } // loop positions foreach ($defaultBlocks as $position => $blocks) { // loop blocks foreach ($blocks as $extraId) { // build block $block = array(); $block['revision_id'] = $page['revision_id']; $block['position'] = $position; $block['extra_id'] = $extraId; $block['html'] = ''; $block['created_on'] = BackendModel::getUTCDate(); $block['edited_on'] = $block['created_on']; $block['visible'] = 'Y'; $block['sequence'] = count($defaultBlocks[$position]) - 1; // add to the list $blocksContent[] = $block; } } } else { // don't overwrite blocks, just re-use existing // set new page revision id foreach ($blocksContent as &$block) { $block['revision_id'] = $page['revision_id']; $block['created_on'] = BackendModel::getUTCDate(null, $block['created_on']); $block['edited_on'] = BackendModel::getUTCDate(null, $block['edited_on']); } } // insert the blocks self::insertBlocks($blocksContent); } }
/** * Validate a submitted form and process it. */ private function validateForm() { // the form is submitted if ($this->frm->isSubmitted()) { // shorten field variables /** @var $fileFile \SpoonFormFile */ $fileFile = $this->frm->getField('file'); // validate the file if ($fileFile->isFilled(BL::err('FieldIsRequired'))) { // only zip files allowed if ($fileFile->isAllowedExtension(array('zip'), sprintf(BL::getError('ExtensionNotAllowed'), 'zip'))) { // create ziparchive instance $zip = new \ZipArchive(); // try and open it if ($zip->open($fileFile->getTempFileName()) === true) { // zip file needs to contain some files if ($zip->numFiles > 0) { // get first entry (= the theme folder) $file = $zip->statIndex(0); // name of the module we are trying to upload $themeName = trim($file['name'], '/'); // find info.xml $infoXml = $zip->getFromName($themeName . '/info.xml'); // add error if info.xml is not found if ($infoXml === false) { $fileFile->addError(sprintf(BL::getError('NoInformationFile'), $themeName)); } else { // parse xml try { // load info.xml $infoXml = @new \SimpleXMLElement($infoXml, LIBXML_NOCDATA, false); // convert xml to useful array $this->information = BackendExtensionsModel::processThemeXml($infoXml); // empty data (nothing useful) if (empty($this->information)) { $fileFile->addError(BL::getMessage('InformationFileIsEmpty')); } // check if theme name in info.xml matches folder name if ($this->information['name'] != $themeName) { $fileFile->addError(BL::err('ThemeNameDoesntMatch')); } } catch (\Exception $e) { // warning that the information file is corrupt $fileFile->addError(BL::getMessage('InformationFileCouldNotBeLoaded')); } } // wow wow, you are trying to upload an already existing theme if (BackendExtensionsModel::existsTheme($themeName)) { $fileFile->addError(sprintf(BL::getError('ThemeAlreadyExists'), $themeName)); } // list of validated files (these files will actually be unpacked) $files = array(); // check every file in the zip for ($i = 0; $i < $zip->numFiles; $i++) { // get the file name $file = $zip->statIndex($i); $fileName = $file['name']; // yay, in a valid directory if (stripos($fileName, $themeName . '/') === 0) { // valid file, add to extraction-list $files[] = $fileName; } } } else { // empty zip file $fileFile->addError(BL::getError('FileIsEmpty')); } } else { // something went very wrong, probably corrupted $fileFile->addError(BL::getError('CorruptedFile')); } } } // passed all validation if ($this->frm->isCorrect()) { // unpack module files $zip->extractTo(FRONTEND_PATH . '/Themes', $files); // run installer BackendExtensionsModel::installTheme($themeName); // redirect with fireworks $this->redirect(BackendModel::createURLForAction('Themes') . '&report=theme-installed&var=' . $themeName); } } }