/** * 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('theme_templates') . '&theme=' . $item['theme'] . '&report=deleted-template&var=' . urlencode($item['label'])); } else { $this->redirect(BackendModel::createURLForAction('theme_templates') . '&error=non-existing'); } } else { $this->redirect(BackendModel::createURLForAction('theme_templates') . '&error=non-existing'); } }
/** * 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 (!SpoonFile::exists(FRONTEND_PATH . '/themes/' . $this->currentTheme . '/info.xml')) { $this->redirect(BackendModel::createURLForAction('themes') . '&error=no-information-file&var=' . $this->currentTheme); } }
/** * Validate if the module can be installed. */ private function validateInstall() { // already installed if (BackendExtensionsModel::isModuleInstalled($this->currentModule)) { $this->redirect(BackendModel::createURLForAction('modules') . '&error=already-installed&var=' . $this->currentModule); } // no installer class present if (!SpoonFile::exists(BACKEND_MODULES_PATH . '/' . $this->currentModule . '/installer/installer.php')) { $this->redirect(BackendModel::createURLForAction('modules') . '&error=no-installer-file&var=' . $this->currentModule); } }
/** * 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), BackendModel::getModuleSetting('core', 'theme', 'core')); }
/** * Load the data for the 2 data grids. */ private function loadData() { // get all managable modules $modules = BackendExtensionsModel::getModules(); // split the modules in 2 seperate 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 (SPOON_DEBUG) { $warnings[] = array('message' => BL::err('DebugModeIsActive')); } // check if this action is allowed if (BackendAuthentication::isAllowedAction('index', 'settings')) { // check if the fork API keys are available if (self::getModuleSetting('core', 'fork_api_private_key') == '' || self::getModuleSetting('core', 'fork_api_public_key') == '') { $warnings[] = array('message' => sprintf(BL::err('ForkAPIKeys'), BackendModel::createURLForAction('index', 'settings'))); } } // check for extensions warnings $warnings = array_merge($warnings, BackendExtensionsModel::checkSettings()); return $warnings; }
/** * 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()); }
/** * 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; }
/** * 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('install_theme')); // data grids $this->tpl->assign('dataGridTemplates', isset($this->dataGridTemplates) && $this->dataGridTemplates->getNumResults() > 0 ? $this->dataGridTemplates->getContent() : false); }
/** * 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')); // 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 (substr_count($html, '"#position-' . $cell . '"') != 1) { $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['id'] = $this->id; $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')->getChecked() ? 'Y' : 'N'; $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_' . BackendLanguage::getWorkingLanguage()] = $this->extras; // serialize $item['data'] = serialize($item['data']); // if this is the default template make the template active if (BackendModel::getModuleSetting('pages', 'default_template') == $this->record['id']) { $item['active'] = 'Y'; } // if the template is in use we can't de-activate it if (BackendExtensionsModel::isTemplateInUse($item['id'])) { $item['active'] = 'Y'; } // insert the item BackendExtensionsModel::updateTemplate($item); // trigger event BackendModel::triggerEvent($this->getModule(), 'after_edit_template', array('item' => $item)); // set default template if ($this->frm->getField('default')->getChecked() && $item['theme'] == BackendModel::getModuleSetting('core', 'theme', 'core')) { BackendModel::setModuleSetting('pages', 'default_template', $item['id']); } // update all existing pages using this template to add the newly inserted block(s) if (BackendExtensionsModel::isTemplateInUse($item['id'])) { BackendPagesModel::updatePagesTemplates($item['id'], $item['id'], $this->frm->getField('overwrite')->getChecked()); } // everything is saved, so redirect to the overview $this->redirect(BackendModel::createURLForAction('theme_templates') . '&theme=' . $item['theme'] . '&report=edited-template&var=' . urlencode($item['label']) . '&highlight=row-' . $item['id']); } } }
/** * Install a theme. * * @param string $theme The name of the theme to be installed. */ public static function installTheme($theme) { // set path to info.xml $pathInfoXml = FRONTEND_PATH . '/themes/' . $theme . '/info.xml'; // load info.xml $infoXml = @new SimpleXMLElement($pathInfoXml, LIBXML_NOCDATA, true); // convert xml to useful array $information = BackendExtensionsModel::processThemeXml($infoXml); if (!$information) { throw new BackendException('Invalid info.xml'); } // loop templates foreach ($information['templates'] as $template) { // init var $item = array(); // build array $item['theme'] = $information['name']; $item['label'] = $template['label']; $item['path'] = $template['path']; $item['active'] = 'Y'; // set format $item['data']['format'] = $template['format']; // build positions $item['data']['names'] = array(); $item['data']['default_extras'] = array(); foreach ($template['positions'] as $position) { // init position $item['data']['names'][] = $position['name']; $item['data']['default_extras'][$position['name']] = array(); // add default widgets foreach ($position['widgets'] as $widget) { // fetch extra_id for this extra $extraId = (int) BackendModel::getDB()->getVar('SELECT i.id FROM modules_extras AS i WHERE type = ? AND module = ? AND action = ? AND data IS NULL AND hidden = ?', array('widget', $widget['module'], $widget['action'], 'N')); // add extra to defaults if ($extraId) { $item['data']['default_extras'][$position['name']][] = $extraId; } } // add default editors foreach ($position['editors'] as $editor) { $item['data']['default_extras'][$position['name']][] = 0; } } // serialize the data $item['data'] = serialize($item['data']); // insert the item $item['id'] = self::insertTemplate($item); } }
/** * Validate a submitted form and process it. */ private function validateForm() { // the form is submitted if ($this->frm->isSubmitted()) { // shorten field variables $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) { $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 { $fileFile->addError(BL::getError('FileIsEmpty')); } } else { $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); } } }
/** * 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[optional] $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::getDB()->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 = BackendPagesModel::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'] = BackendPagesModel::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 { // set new page revision id foreach ($blocksContent as &$block) { $block['revision_id'] = $page['revision_id']; } } // insert the blocks BackendPagesModel::insertBlocks($blocksContent); } }
/** * 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()); // get default template id $defaultTemplateId = BackendModel::getModuleSetting($this->getModule(), '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()); }
/** * Delete a template. * * @param int $id The id of the template to delete. * @return bool */ public static function deleteTemplate($id) { $id = (int) $id; // get all templates $templates = self::getTemplates(); // we can't delete a template that doesn't exist if (!isset($templates[$id])) { return false; } // we can't delete the last template if (count($templates) == 1) { return false; } // we can't delete the default template if ($id == BackendModel::getModuleSetting('pages', 'default_template')) { return false; } if (BackendExtensionsModel::isTemplateInUse($id)) { return false; } // get db $db = BackendModel::getDB(true); // delete $db->delete('themes_templates', 'id = ?', $id); // get all non-active pages that use this template $ids = (array) $db->getColumn('SELECT i.revision_id FROM pages AS i WHERE i.template_id = ? AND i.status != ?', array($id, 'active')); // any items if (!empty($ids)) { // delete those pages and the linked blocks $db->delete('pages', 'revision_id IN(' . implode(',', $ids) . ')'); $db->delete('pages_blocks', 'revision_id IN(' . implode(',', $ids) . ')'); } return true; }
/** * Parse. */ protected function parse() { parent::parse(); // assign module data $this->tpl->assign('name', $this->currentModule); $this->tpl->assign('warnings', $this->warnings); $this->tpl->assign('information', $this->information); $this->tpl->assign('showExtensionsInstallModule', !BackendExtensionsModel::isModuleInstalled($this->currentModule) && BackendAuthentication::isAllowedAction('install_module')); // data grids $this->tpl->assign('dataGridEvents', isset($this->dataGridEvents) && $this->dataGridEvents->getNumResults() > 0 ? $this->dataGridEvents->getContent() : false); $this->tpl->assign('dataGridCronjobs', isset($this->dataGridCronjobs) && $this->dataGridCronjobs->getNumResults() > 0 ? $this->dataGridCronjobs->getContent() : false); }