/** * Copy in all the assets for this theme into the assets location. * * Returns false if nothing changed, else will return an array of all the changes that occured. * * @param bool $install Set to false to uninstall the assets instead of installing. * @param int $verbosity 0 for standard output, 1 for real-time, 2 for real-time verbose output. * * @return false | array * @throws \InstallerException */ public function _parseAssets($install = true, $verbosity = 0) { $assetbase = \Core\Filestore\get_asset_path(); $coretheme = \ConfigHandler::Get('/theme/selected'); // WHY is core theme set to blank?!? // Damn installer... // this happens in the installer. if ($coretheme === null) { $coretheme = 'default'; } $theme = $this->getKeyName(); $changes = []; foreach ($this->_xmlloader->getElements('/assets/file') as $node) { // Cannot install assets if the directory is not setup! if (!$this->getAssetDir()) { continue; } $b = $this->getBaseDir(); // The base filename with the directory. $filename = $node->getAttribute('filename'); // The new theme asset will be installed into the same directory as its theme. // This differs from usual components because they just follow whatever theme is currently running. //$nf = Core::File($assetbase . $theme . '/' . $filename); $trimmedfilename = substr($b . $node->getAttribute('filename'), strlen($this->getAssetDir())); $themespecificfilename = $assetbase . $theme . '/' . $trimmedfilename; $newfilename = 'assets/' . $trimmedfilename; // Before anything, check and see if this file has a custom override file present. if (file_exists(ROOT_PDIR . 'themes/custom/' . $newfilename)) { // If so, then copy that asset to the custom directory too! $f = \Core\Filestore\Factory::File(ROOT_PDIR . 'themes/custom/' . $newfilename); $srcname = '!CUSTOM!'; } else { // Otherwise, the local file is guaranteed to be a local file. $f = new \Core\Filestore\Backends\FileLocal($b . $filename); $srcname = '-theme- '; } if ($verbosity == 2) { CLI::PrintActionStart('Installing ' . $srcname . ' asset ' . $f->getBasename()); } $nf = \Core\Filestore\Factory::File($newfilename); /* // The various replacement possibilities for this file. // The new destination must be in the theme-specific directory, this is a // bit of a hack from the usual behaviour of the filestore system. // Since that's designed to return the default if the theme-specific doesn't exist. $replacements = array( // The theme is not default, but the system translated the path to the default directory. // This is because the file doesn't exist in any theme. // This is actually expected behaviour, except unwanted here. 'default/' . $trimmedfilename => $theme . '/' . $trimmedfilename, // The theme is not the currently installed, but the system translated the path to the that directory. // This is because the filename is the same as the installed theme, so the system just translated there. // We don't want that. $coretheme . '/' . $trimmedfilename => $theme . '/' . $trimmedfilename, ); foreach($replacements as $k => $v){ if($k == $v) continue; if(strpos($nf->getFilename(), $k) !== false){ $nf->setFilename( str_replace($k, $v, $nf->getFilename()) ); } } */ // Check if this file even needs updated. (this is primarily used for reporting reasons) if ($nf->exists() && $nf->identicalTo($f)) { //echo "Skipping file, it's identical.<br/>"; if ($verbosity == 2) { CLI::PrintActionStatus('skip'); } continue; } elseif ($nf->exists()) { $action = 'Replaced'; } else { $action = 'Installed'; } if (!$f->isReadable()) { throw new \InstallerException('Source file [' . $f->getFilename() . '] is not readable.'); } try { $f->copyTo($nf, true); } catch (\Exception $e) { throw new \InstallerException('Unable to copy [' . $f->getFilename() . '] to [' . $nf->getFilename() . ']'); } $change = $action . ' ' . $nf->getFilename(); $changes[] = $change; if ($verbosity == 1) { CLI::PrintLine($change); } elseif ($verbosity == 2) { CLI::PrintActionStatus('ok'); } } // If there are custom assets not registered by any application, install them too! // This will allow an admin to upload additional css resources and images easily. $directory = \Core\Filestore\Factory::Directory('themes/custom/assets'); $ls = $directory->ls(null, true); $baseStrLen = strlen(ROOT_PDIR . '/themes/custom/assets'); foreach ($ls as $fileOrDir) { if ($fileOrDir instanceof File) { $newfilename = substr($fileOrDir->getFilename(), $baseStrLen); if ($verbosity == 2) { CLI::PrintActionStart('Installing CUSTOM asset ' . $newfilename); } $nf = \Core\Filestore\Factory::File('asset/' . $newfilename); if ($nf->exists() && $nf->identicalTo($fileOrDir)) { //echo "Skipping file, it's identical.<br/>"; if ($verbosity == 2) { CLI::PrintActionStatus('skip'); } continue; } elseif ($nf->exists()) { $action = 'Replaced'; } else { $action = 'Installed'; } try { $fileOrDir->copyTo($nf, true); } catch (\Exception $e) { throw new \InstallerException('Unable to copy [' . $fileOrDir->getFilename() . '] to [' . $nf->getFilename() . ']'); } $change = $action . ' ' . $nf->getFilename(); $changes[] = $change; if ($verbosity == 1) { CLI::PrintLine($change); } elseif ($verbosity == 2) { CLI::PrintActionStatus('ok'); } } } if (!sizeof($changes)) { if ($verbosity > 0) { CLI::PrintLine('No changes required'); } return false; } // Make sure the asset cache is purged! \Core\Cache::Delete('asset-resolveurl'); return $changes; }
public function actionStart($message){ if($this->realtime){ CLI::PrintActionStart($message); } if($this->_actionMessage){ $this->_profiler->record('[ABORTED]'); $this->log[] = $this->_actionMessage . ' [ABORTED]'; } $this->_profiler->record($message); $this->_actionMessage = $message; }
file_put_contents($destdir . '/' . $desttgz . '/packages.html', $changelog); CLI::PrintHeader('Finalizing Bundling for ' . $b['name'] . ' ' . $version); // create the tarballs! CLI::PrintActionStart("Creating tarball"); //exec('tar -czf "' . $destdir . '/' . $desttgz . '.tgz" -C "' . $destdir . '" --exclude-vcs --exclude=*~ --exclude=._* ' . $desttgz); exec('tar -czf "' . $destdir . '/' . $desttgz . '.tgz" -C "' . $destdir . '/' . $desttgz . '" --exclude-vcs --exclude=*~ --exclude=._* .'); CLI::PrintActionStatus('ok'); CLI::PrintActionStart("Creating zip"); //exec('cd "' . $destdir . '/"; zip -rq "' . $desttgz . '.zip" "' . $desttgz . '"; cd -'); exec('cd "' . $destdir . '/' . $desttgz . '/"; zip -rq "../' . $desttgz . '.zip" .; cd -'); CLI::PrintActionStatus('ok'); CLI::PrintActionStart("Creating hashes"); exec('md5sum "' . $destdir . '/' . $desttgz . '.tgz" > "' . $destdir . '/' . $desttgz . '.tgz.md5"'); exec('md5sum "' . $destdir . '/' . $desttgz . '.zip" > "' . $destdir . '/' . $desttgz . '.zip.md5"'); CLI::PrintActionStatus('ok'); CLI::PrintActionStart("Cleaning up"); exec('rm -fr "' . $destdir . '/' . $desttgz . '"'); CLI::PrintActionStatus('ok'); } // Give the option to automatically commit and tag all changes for the component. if(CLI::PromptUser('Bundles created, GIT tag the release for ' . $version . '?', 'boolean', true)){ exec('git tag -m "Release Version ' . $version . '" -f ' . 'v' . str_replace('~', '-', $version)); exec('git push --tags'); }
public function email_test(){ // Admin-only page. if(!\Core\user()->checkAccess('g:admin')){ return View::ERROR_ACCESSDENIED; } $request = $this->getPageRequest(); $view = $this->getView(); if(!$request->isPost()){ return View::ERROR_BADREQUEST; } if(!$request->getPost('email')){ return View::ERROR_BADREQUEST; } $view->mode = View::MODE_NOOUTPUT; $view->contenttype = View::CTYPE_HTML; $view->render(); $dest = $request->getPost('email'); $method = ConfigHandler::Get('/core/email/mailer'); $smtpHost = ConfigHandler::Get('/core/email/smtp_host'); $smtpUser = ConfigHandler::Get('/core/email/smtp_user'); $smtpPass = ConfigHandler::Get('/core/email/smtp_password'); $smtpPort = ConfigHandler::Get('/core/email/smtp_port'); $smtpSec = ConfigHandler::Get('/core/email/smtp_security'); $sendmailPath = ConfigHandler::Get('/core/email/sendmail_path'); $emailDebug = []; $emailDebug[] = 'Sending Method: ' . $method; switch($method){ case 'smtp': $emailDebug[] = 'SMTP Host: ' . $smtpHost . ($smtpPort ? ':' . $smtpPort : ''); $emailDebug[] = 'SMTP User/Pass: '******'//' . ($smtpPass ? '*** saved ***' : 'NO PASS') : 'Anonymous'); $emailDebug[] = 'SMTP Security: ' . $smtpSec; break; case 'sendmail': $emailDebug[] = 'Sendmail Path: ' . $sendmailPath; break; } CLI::PrintHeader('Sending test email to ' . $dest); CLI::PrintActionStart('Initializing Email System'); try{ $email = new Email(); $email->addAddress($dest); $email->setSubject('Test Email'); $email->templatename = 'emails/admin/test_email.tpl'; $email->assign('debugs', $emailDebug); $email->getMailer()->SMTPDebug = 2; CLI::PrintActionStatus(true); } catch(Exception $e){ CLI::PrintActionStatus(false); CLI::PrintError($e->getMessage()); CLI::PrintLine($e->getTrace()); return; } CLI::PrintActionStart('Sending Email via ' . $method); try{ $email->send(); CLI::PrintActionStatus(true); } catch(Exception $e){ CLI::PrintActionStatus(false); CLI::PrintError($e->getMessage()); CLI::PrintLine(explode("\n", $e->getTraceAsString())); } CLI::PrintHeader('Sent Headers:'); CLI::PrintLine(explode("\n", $email->getMailer()->CreateHeader())); CLI::PrintHeader('Sent Body:'); CLI::PrintLine(explode("\n", $email->getMailer()->CreateBody())); }
// If the class doesn't explicitly end with "Model", it's also not a model. continue; } if(strpos($class, '\\') !== false){ // If this "Model" class is namespaced, it's not a valid model! // All Models MUST reside in the global namespace in order to be valid. continue; } $ref = new ReflectionClass($class); if(!$ref->getProperty('HasSearch')->getValue()){ // This model doesn't have the searchable flag, skip it. continue; } CLI::PrintActionStart("Syncing searchable model $class"); $fac = new ModelFactory($class); foreach($fac->get() as $m){ /** @var Model $m */ $m->set('search_index_pri', '!'); $m->save(); } CLI::PrintActionStatus('ok'); $changes[] = "Synced searchable model " . $class; } } // Flush the system cache, just in case \Core\Cache::Flush(); \Core\Templates\Backends\Smarty::FlushCache();
else{ CLI::PrintLine('Added ' . $linesadded . ($linesadded != 1 ? ' lines' : ' line') . ' to the changelog successfully!'); print $thischange->fetchFormatted() . NL . NL; } // Cleanup unset($thischange, $versioncheck, $previouschange, $previousdate, $changes, $linecount, $linesadded, $line); } break; case 'viewchange': // Just print the current CHANGELOG section, easy now that everything is compartmentalized. CLI::PrintHeader('CHANGELOG for ' . $packager->getLabel() . ' ' . $packager->getVersion()); CLI::PrintLine($packager->getChangelogSection()->fetchFormatted()); break; case 'save': CLI::PrintActionStart('Saving ' . $packager->getLabel()); $packager->save(); CLI::PrintActionStatus('ok'); $saved = true; $saveopts = [ 'package-sign-commit' => 'Create signed package and GIT commit any changes', 'package-sign' => 'Create signed package', 'package' => 'Create unsigned package', 'commit' => 'GIT commit any changes', 'menu' => 'Do nothing else, back to menu', 'quit' => 'Do nothing else and exit script', ]; if(!sizeof($autostack)){ $saveans = CLI::PromptUser(ucfirst($packager->getLabel()) . ' saved, do you want to bundle the changes into a package?', $saveopts, 'menu');
/** * Internal function to parse and handle the dataset in the <upgrade> and <install> tasks. * This is used for installations and upgrades. * * Unlike the other parse functions, this handles a single node at a time. * * @param $node DOMElement * @param $verbose bool * * @throws InstallerException */ private function _parseDatasetNode(DOMElement $node, $verbose = false){ $action = $node->getAttribute('action'); $table = $node->getAttribute('table'); $haswhere = false; $sets = array(); $renames = array(); $ds = new Core\Datamodel\Dataset(); $ds->table($table); foreach($node->getElementsByTagName('datasetset') as $el){ $sets[$el->getAttribute('key')] = $el->nodeValue; } foreach($node->getElementsByTagName('datasetrenamecolumn') as $el){ // <datasetrenamecolumn oldname="ID" newname="id"/> $renames[$el->getAttribute('oldname')] = $el->getAttribute('newname'); } foreach($node->getElementsByTagName('datasetwhere') as $el){ $haswhere = true; $ds->where(trim($el->nodeValue)); } switch($action){ case 'alter': if(sizeof($sets)) throw new InstallerException('Invalid mix of arguments on ' . $action . ' dataset request, datasetset is not supported!'); if($haswhere) throw new InstallerException('Invalid mix of arguments on ' . $action . ' dataset request, datasetwhere is not supported!'); foreach($renames as $k => $v){ // ALTER TABLE `controllers` CHANGE `ID` `id` INT( 11 ) NOT NULL AUTO_INCREMENT $ds->renameColumn($k, $v); } break; case 'update': foreach($sets as $k => $v){ $ds->update($k, $v); } break; case 'insert': foreach($sets as $k => $v){ $ds->insert($k, $v); } break; case 'delete': if(sizeof($sets)) throw new InstallerException('Invalid mix of arguments on ' . $action . ' dataset request'); if(!$haswhere) throw new InstallerException('Cowardly refusing to delete with no where statement'); $ds->delete(); break; default: throw new InstallerException('Invalid action type, '. $action); } // and GO! if($verbose){ CLI::PrintActionStart('Executing dataset ' . $action . ' command on ' . $table); } $ds->execute(); if($ds->num_rows){ CLI::PrintActionStatus(true); return array($action . ' on table ' . $table . ' affected ' . $ds->num_rows . ' records.'); } else{ CLI::PrintActionStatus(false); return false; } }