Initial commit

This commit is contained in:
Joey Kimsey
2024-08-04 21:15:59 -04:00
parent c9d1fb983f
commit 0d469501ee
695 changed files with 70184 additions and 71 deletions

View File

@ -0,0 +1,34 @@
<?php
/**
* app/classes/admin_controller.php
*
* This is the base admin controller. Every other admin controller should
* extend this class.
*
* @version 3.0
* @author Joey Kimsey <Joey@thetempusproject.com>
* @link https://TheTempusProject.com
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
*/
namespace TheTempusProject\Classes;
use TheTempusProject\Houdini\Classes\Template;
use TheTempusProject\Houdini\Classes\Filters;
use TheTempusProject\Houdini\Classes\Issues;
use TheTempusProject\TheTempusProject as App;
use TheTempusProject\Hermes\Functions\Redirect;
use TheTempusProject\Bedrock\Functions\Session;
class AdminController extends Controller {
public function __construct() {
parent::__construct();
if ( !App::$isAdmin ) {
Session::flash( 'error', 'You do not have permission to view this page.' );
return Redirect::home();
}
Template::noFollow();
Template::noIndex();
Template::setTemplate( 'admin' );
Filters::add( 'logMenu', '#<ul id="log-menu" class="collapse">#is', '<ul id="log-menu" class="">', true );
}
}

View File

@ -0,0 +1,32 @@
<?php
/**
* app/classes/admin_controller.php
*
* This is the base admin controller. Every other admin controller should
* extend this class.
*
* @version 3.0
* @author Joey Kimsey <Joey@thetempusproject.com>
* @link https://TheTempusProject.com
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
*/
namespace TheTempusProject\Classes;
use TheTempusProject\Houdini\Classes\Template;
use TheTempusProject\TheTempusProject as App;
use TheTempusProject\Hermes\Functions\Redirect;
use TheTempusProject\Bedrock\Functions\Session;
class ApiController extends Controller {
public function __construct() {
parent::__construct();
if ( ! App::verifyApiRequest() ) {
Session::flash( 'error', 'You do not have permission to view this page.' );
return Redirect::home();
}
Template::noFollow();
Template::noIndex();
Template::addHeader( 'Content-Type: application/json; charset=utf-8' );
Template::setTemplate( 'api' );
}
}

71
app/classes/config.php Normal file
View File

@ -0,0 +1,71 @@
<?php
/**
* classes/config.php
*
* This class handles all the hard-coded configurations.
*
* @version 3.0
* @author Joey Kimsey <Joey@thetempusproject.com>
* @link https://TheTempusProject.com/Core
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
*/
namespace TheTempusProject\Classes;
use TheTempusProject\Houdini\Classes\Forms;
use TheTempusProject\Canary\Canary as Debug;
use TheTempusProject\Bedrock\Functions\Check;
use TheTempusProject\Bedrock\Functions\Input;
use TheTempusProject\Bedrock\Classes\Config as BedrockConfig;
class Config extends BedrockConfig {
public static function getFieldEditHtml( $name, $includeProtected = false ) {
// @todo: includeProtected is unused here
$node = self::get( $name );
if ( empty( $node ) ) {
return;
}
if ( true === $node['protected'] ) {
return;
}
$fieldname = str_ireplace( '/', '-', $name );
$html = Forms::getFormFieldHtml(
$fieldname,
$node['pretty'],
$node['type'],
$node['value'],
);
return $html;
}
public static function getCategoryEditHtml( $category ) {
$html = '';
if ( self::$config === false ) {
Debug::warn( 'Config not loaded.' );
return;
}
if ( empty( self::$config[$category] ) ) {
Debug::warn( "Config category not found: $category" );
return;
}
$categoryHeader = '<div class="form-group"><label>' . ucfirst( $category ) . ':</label><hr></div>';
foreach ( self::$config[$category] as $field => $node ) {
$html .= self::getFieldEditHtml( $category . '/' . $field );
}
if ( !empty( $html ) ) {
$html = $categoryHeader . $html;
}
return $html;
}
public static function getEditHtml() {
if ( self::$config === false ) {
Debug::warn( 'Config not loaded.' );
return;
}
$html = '';
foreach ( self::$config as $category => $fields ) {
$html .= self::getCategoryEditHtml( $category );
}
return $html;
}
}

View File

@ -0,0 +1,41 @@
<?php
/**
* app/classes/controller.php
*
* This is the main controller class.
*
* @version 3.0
* @author Joey Kimsey <Joey@thetempusproject.com>
* @link https://TheTempusProject.com
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
*/
namespace TheTempusProject\Classes;
use TheTempusProject\Bedrock\Classes\Controller as BedrockController;
use TheTempusProject\Houdini\Classes\Template;
use TheTempusProject\Houdini\Classes\Pagination;
use TheTempusProject\TheTempusProject as App;
use TheTempusProject\Models\User;
use TheTempusProject\Models\Sessions;
class Controller extends BedrockController {
public static $user;
public static $session;
public static $pagination;
public function __construct() {
parent::__construct();
self::$session = new Sessions;
self::$user = new User;
self::$pagination = Pagination::generate();
if ( ! empty( App::$activePrefs ) ) {
self::$pagination::updatePrefs( App::$activePrefs['pageLimit'] );
}
new Template;
Template::setTemplate( 'default' );
}
public function __destruct() {
parent::__destruct();
}
}

View File

@ -0,0 +1,145 @@
<?php
/**
* app/classes/database_model.php
*
* This is the main TempusProject database model.
*
* @version 3.0
* @author Joey Kimsey <Joey@thetempusproject.com>
* @link https://TheTempusProject.com
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
*/
namespace TheTempusProject\Classes;
use TheTempusProject\Bedrock\Classes\DatabaseModel as BedrockDatabaseModel;
use TheTempusProject\Bedrock\Functions\Check;
use TheTempusProject\Canary\Canary as Debug;
use TheTempusProject\Models\Log;
class DatabaseModel extends BedrockDatabaseModel {
public $preferenceMatrix;
public $permissionMatrix;
public static $installFlags = MODEL_INSTALL_FLAGS;
protected static $user;
protected static $log;
protected static $group;
protected static $session;
protected static $message;
protected static $routes;
public function __construct() {
parent::__construct();
}
public function uninstall() {
Debug::log( 'Uninstalling Model: ' . get_class($this) );
parent::uninstall();
$this->uninstallPreferences();
$this->uninstallPermissions();
return true;
}
public function installPreferences() {
if ( empty( $this->preferenceMatrix ) ) {
Debug::log( 'preferenceMatrix is empty' );
return true;
}
$prefs = new Preferences();
foreach ( $this->preferenceMatrix as $name => $details ) {
$prefs->add( $name, $details );
}
return $prefs->save( true );
}
public function uninstallPreferences() {
if ( empty( $this->preferenceMatrix ) ) {
Debug::log( 'preferenceMatrix is empty' );
return true;
}
$prefs = new Preferences();
foreach ( $this->preferenceMatrix as $name => $details ) {
$prefs->remove( $name, true );
}
}
public function installPermissions() {
if ( empty( $this->permissionMatrix ) ) {
Debug::log( 'permissionMatrix is empty' );
return true;
}
$perms = new Permissions();
foreach ( $this->permissionMatrix as $name => $details ) {
$perms->add( $name, $details );
}
return $perms->save( true );
}
public function uninstallPermissions() {
$perms = new Permissions();
if ( empty( $this->permissionMatrix ) ) {
Debug::log( 'permissionMatrix is empty' );
return true;
}
foreach ( $this->permissionMatrix as $name => $details ) {
$perms->remove( $name, true );
}
}
public function delete( $idArray ) {
if ( empty( self::$log ) ) {
self::$log = new Log;
}
if ( !is_array( $idArray ) ) {
$idArray = [ $idArray ];
}
foreach ( $idArray as $id ) {
if ( !Check::id( $id ) ) {
Debug::info( "invalid ID: $id." );
$error = true;
continue;
}
$result = parent::delete( $id );
if ( true !== $result ) {
Debug::info( ucfirst( $this->tableName ) . " did not delete properly: $id" );
$error = true;
continue;
}
self::$log->admin( 'Deleted ' . ucfirst( $this->tableName ) . ": $id" );
Debug::info( ucfirst( $this->tableName ) . " successfully deleted: $id" );
}
if ( !empty( $error ) ) {
Debug::error( 'One or more rows were not deleted.' );
return false;
}
return true;
}
public function install( $options ) {
Debug::log( 'Installing Database Model');
$module_data = [];
$errors = [];
foreach ( self::$installFlags as $flag_name ) {
if ( empty( $options[$flag_name] ) ) {
$module_data[ $flag_name ] = INSTALL_STATUS_SKIPPED;
continue;
}
$result = $this->$flag_name();
if ( empty( $result ) ) {
$errors[] = ['errorInfo' => get_class($this) . " Failed to execute $flag_name properly."];
$module_data[ $flag_name ] = INSTALL_STATUS_FAIL;
continue;
}
if ( 'installResources' === $flag_name ) {
$module_data['installedResources'] = $result;
}
$module_data[ $flag_name ] = INSTALL_STATUS_SUCCESS;
continue;
}
return [ $module_data, $errors ];
}
}

212
app/classes/email.php Normal file
View File

@ -0,0 +1,212 @@
<?php
/**
* app/classes/email.php
*
* This is our class for constructing and sending various kinds of emails.
*
* @version 3.0
* @author Joey Kimsey <Joey@thetempusproject.com>
* @link https://TheTempusProject.com
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
*/
namespace TheTempusProject\Classes;
use TheTempusProject\Houdini\Classes\Template;
use TheTempusProject\Houdini\Classes\Views;
use TheTempusProject\Hermes\Functions\Route as Routes;
use TheTempusProject\Canary\Canary as Debug;
class Email {
private static $header = null;
private static $subject = null;
private static $title = null;
private static $message = null;
private static $unsub = false;
private static $useTemplate = false;
private static $footer = null;
private static $debug = false;
/**
* Sends pre-constructed email templates. Useful for modifying the
* entire theme or layout of the system generated emails.
*
* @param string $email - The email you are sending to.
* @param string $type - The template you wish to send.
* @param string|array $params - Any special parameters that may be required from your individual email template.
*
* @return bool
*/
public static function send( $email, $type, $params = null, $flags = null ) {
if ( !empty( $flags ) ) {
if ( is_array( $flags ) ) {
foreach ( $flags as $key => $value ) {
switch ( $key ) {
case 'template':
if ( $value == true ) {
self::$useTemplate = true;
}
break;
case 'unsubscribe':
if ( $value == true ) {
self::$unsub = true;
}
break;
case 'debug':
if ( $value == true ) {
self::$debug = false;
}
break;
}
}
}
}
self::build();
switch ( $type ) {
case 'debug':
self::$subject = 'Please Confirm your email at {SITENAME}';
self::$title = 'Almost Done';
self::$message = 'Please click or copy-paste this link to confirm your registration: <a href="{BASE}register/confirm/{PARAMS}">Confirm Your Email</a>';
break;
case 'confirmation':
self::$subject = 'Please Confirm your email at {SITENAME}';
self::$title = 'Almost Done';
self::$message = 'Please click or copy-paste this link to confirm your registration: <a href="{BASE}register/confirm/{PARAMS}">Confirm Your Email</a>';
break;
case 'install':
self::$subject = 'Notification from {SITENAME}';
self::$title = 'Installation Success';
self::$message = 'This is just a simple email to notify you that you have successfully installed The Tempus Project framework!';
break;
case 'passwordChange':
self::$subject = 'Security Notice from {SITENAME}';
self::$title = 'Password Successfully Changed';
self::$message = 'Recently your password on {SITENAME} was changed. If you are the one who changed the password, please ignore this email.';
break;
case 'emailChangeNotice':
self::$subject = 'Account Update from {SITENAME}';
self::$title = 'Email Updated';
self::$message = 'This is a simple notification to let you know your email has been changed at {SITENAME}.';
break;
case 'emailChange':
self::$subject = 'Account Update from {SITENAME}';
self::$title = 'Confirm your E-mail';
self::$message = 'Please click or copy-paste this link to confirm your new Email: <a href="{BASE}register/confirm/{PARAMS}">Confirm Your Email</a>';
break;
case 'emailNotify':
self::$subject = 'Account Update from {SITENAME}';
self::$title = 'Email Updated';
self::$message = 'You recently changed your email address on {SITENAME}.';
break;
case 'forgotPassword':
self::$subject = 'Reset Instructions for {SITENAME}';
self::$title = 'Reset your Password';
self::$message = 'You recently requested information to change your password at {SITENAME}.<br>Your password reset code is: {PARAMS}<br> Please click or copy-paste this link to reset your password: <a href="{BASE}register/reset/{PARAMS}">Password Reset</a>';
break;
case 'forgotUsername':
self::$subject = 'Account Update from {SITENAME}';
self::$title = 'Account Details';
self::$message = 'Your username for {SITENAME} is {PARAMS}.';
break;
case 'subscribe':
self::$subject = 'Thanks for Subscribing';
self::$title = 'Thanks for Subscribing!';
self::$message = 'Thank you for subscribing to updates from {SITENAME}. If you no longer wish to receive these emails, you can un-subscribe using the link below.';
self::$unsub = true;
break;
case 'unsubInstructions':
self::$subject = 'Unsubscribe Instructions';
self::$title = 'We are sad to see you go';
self::$message = 'If you would like to be un-subscribed from future emails from {SITENAME} simply click the link below.<br><br><a href="{BASE}home/unsubscribe/{EMAIL}/{PARAMS}">Click here to unsubscribe</a>';
self::$unsub = true;
break;
case 'unsubscribe':
self::$subject = 'Unsubscribed';
self::$title = 'We are sad to see you go';
self::$message = 'This is just a notification that you have successfully been unsubscribed from future emails from {SITENAME}.';
break;
case 'contact':
self::$subject = $params['subject'];
self::$title = $params['title'];
self::$message = $params['message'];
break;
default:
return false;
break;
}
if ( self::$useTemplate ) {
$data = new \stdClass();
if ( self::$unsub ) {
$data->UNSUB = Views::simpleView( 'email.unsubscribe' );
} else {
$data->UNSUB = '';
}
$data->LOGO = Config::getValue( 'main/logo' );
$data->SITENAME = Config::getValue( 'main/name' );
$data->EMAIL = $email;
if ( !is_array( $params ) ) {
$data->PARAMS = $params;
} else {
foreach ( $params as $key => $value ) {
$data->$key = $value;
}
}
$data->MAIL_FOOT = Views::simpleView( 'email.foot' );
$data->MAIL_TITLE = self::$title;
$data->MAIL_BODY = Template::parse( self::$message, $data );
$subject = Template::parse( self::$subject, $data );
$body = Views::simpleView( 'email.template', $data );
} else {
$subject = self::$subject;
$body = '<h1>' . self::$title . '</h1>' . self::$message;
}
if ( is_object( $email ) ) {
foreach ( $email as $data ) {
if ( !@mail( $data->email, $subject, $body, self::$header ) ) {
Debug::error( 'Failed to send email. Subject: ' . $subject . ' Email: ' . $data->email );
}
}
} else {
if ( !@mail( $email, $subject, $body, self::$header ) ) {
Debug::error( 'Failed to send email. Subject: ' . $subject . ' Email: ' . $email );
}
}
Debug::info( "Email sent: $type." );
return true;
}
/**
* Constructor for the header.
*/
public static function build() {
if ( !self::$header ) {
self::$header = 'From: ' . Config::getValue( 'main/name' ) . ' <noreply@' . $_SERVER['HTTP_HOST'] . ">\r\n";
self::$header .= "MIME-Version: 1.0\r\n";
self::$header .= "Content-Type: text/html; charset=ISO-8859-1\r\n";
$url = parse_url( Routes::getAddress(), PHP_URL_HOST );
$parts = explode( '.', $url );
$count = count( $parts );
if ( $count > 2 ) {
$host = $parts[ $count - 2 ] . '.' . $parts[ $count - 1 ];
} else {
$host = $url;
}
if ( self::$debug ) {
self::$header .= "CC: webmaster@localhost.com\r\n";
}
}
}
}

77
app/classes/forms.php Normal file
View File

@ -0,0 +1,77 @@
<?php
/**
* app/classes/forms.php
*
* This class is used in conjunction with TheTempusProject\Bedrock\Classes\Check
* to house complete form verification. You can utilize the
* error reporting to easily define exactly what feedback you
* would like to give.
*
* @version 3.0
* @author Joey Kimsey <Joey@thetempusproject.com>
* @link https://TheTempusProject.com
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
*/
namespace TheTempusProject\Classes;
use TheTempusProject\Bedrock\Functions\Check;
use TheTempusProject\Canary\Canary as Debug;
class Forms extends Check {
private static $formHandlers = [];
public static function check( $formName ) {
if ( empty( self::$formHandlers[ $formName ] ) ) {
Debug::error( "Form not found: $formName" );
return false;
}
$handler = self::$formHandlers[ $formName ];
return call_user_func_array( [ $handler['class'], $handler['method'] ], $handler['params'] );
}
public static function addHandler( $formName, $class, $method, $params = [] ) {
if ( !empty( self::$formHandlers[ $formName ] ) ) {
return false;
}
self::$formHandlers[$formName] = [
'class' => $class,
'method' => $method,
'params' => $params,
];
}
/**
* Checks username formatting.
*
* Requirements:
* - 4 - 16 characters long
* - must only contain numbers and letters: [A - Z] , [a - z], [0 - 9]
*
* @param string $data - The string being tested.
*
* @return boolean
*/
public static function checkUsername( $data ) {
if ( strlen( $data ) > 16 ) {
self::addError( 'Username must be be 4 to 16 numbers or letters.', $data );
return false;
}
if ( strlen( $data ) < 4 ) {
self::addError( 'Username must be be 4 to 16 numbers or letters.', $data );
return false;
}
if ( !ctype_alnum( $data ) ) {
self::addError( 'Username must be be 4 to 16 numbers or letters.', $data );
return false;
}
return true;
}
public static function date( $data ) {
if ( strtotime( $data ) == false ) {
self::addError( 'Username must be be 4 to 16 numbers or letters.', $data );
return false;
}
return true;
}
}

640
app/classes/installer.php Normal file
View File

@ -0,0 +1,640 @@
<?php
/**
* app/classes/installer.php
*
* This class is used for the installation, regulation, tracking, and updating of
* the application. It handles installing the application, installing and updating
* models as well as the database, and generating and checking the htaccess file.
*
* @version 3.0
* @author Joey Kimsey <Joey@thetempusproject.com>
* @link https://TheTempusProject.com
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
*/
namespace TheTempusProject\Classes;
use TheTempusProject\Bedrock\Functions\Check;
use TheTempusProject\Bedrock\Functions\Code;
use TheTempusProject\Bedrock\Functions\Cookie;
use TheTempusProject\Canary\Canary as Debug;
use TheTempusProject\Hermes\Functions\Redirect;
use TheTempusProject\Hermes\Functions\Route as Routes;
use TheTempusProject\Bedrock\Functions\Session;
use TheTempusProject\Classes\DatabaseModel;
use TheTempusProject\Classes\Plugin;
class Installer {
const MATRIX_MAP = [
'installPreferences' => 'preferenceMatrix',
'installPermissions' => 'permissionMatrix',
'installConfigs' => 'configMatrix',
'installTable' => 'databaseMatrix',
'installResources' => 'resourceMatrix',
];
private $override = false;
private $status = null;
private static $installJson = null;
private static $errors = [];
public function __construct() {
Debug::log( 'Installer initialized.' );
if ( self::$installJson === null ) {
self::$installJson = self::getJson();
}
}
public function getComposerJson() {
if ( !file_exists( COMPOSER_JSON_LOCATION ) ) {
Debug::error( 'No install json found.' );
return false;
}
return json_decode( file_get_contents( COMPOSER_JSON_LOCATION ), true );
}
public function getComposerLock() {
if ( !file_exists( COMPOSER_LOCK_LOCATION ) ) {
Debug::error( 'No install json found.' );
return false;
}
return json_decode( file_get_contents( COMPOSER_LOCK_LOCATION ), true );
}
public static function emptyModule( $type, $folder, $filename = '' ) {
switch ( $type ) {
case 'model':
if ( empty( $filename ) ) {
$class = '';
$class_name = '';
break;
}
$class = convertFileNameToModelClass( $filename );
$class_name = convertFileNameToClassName( $filename );
break;
case 'plugin':
if ( empty( $folder ) ) {
$class = '';
$class_name = '';
break;
}
$class = convertFileNameToPluginClass( $folder );
$class_name = convertFolderToClassName( $folder );
break;
}
if ( empty( $folder ) ) {
$folder = '';
}
$object = (object) [
'name' => $class_name,
'class' => $class,
'version' => '0.0',
'installedVersion' => '',
'folder' => $folder,
'type' => $type,
'installDate' => '',
'lastUpdate' => '',
'installStatus' => INSTALL_STATUS_NOT_INSTALLED,
'enabled' => false,
'enabled_txt' => 'no',
];
return $object;
}
/**
* This function automatically attempts to install all models in the
* specified directory.
* NOTE: The 'Models/ folder is used by default.
*
* @param string $directory - The directory you wish to install all
* models from.
* @return boolean
*/
public function getErrors( $array = true ) {
if ( $array ) {
$out = [];
foreach (self::$errors as $error) {
if ( ! is_array($error) ) {
exit(var_export($error,true));
}
$out[] = $error['errorInfo'];
}
} else {
$out = self::$errors;
}
return $out;
}
private static function getJson() {
if ( file_exists( INSTALL_JSON_LOCATION ) ) {
$content = file_get_contents( INSTALL_JSON_LOCATION );
$json = json_decode( $content, true );
} else {
touch( INSTALL_JSON_LOCATION );
$json = [];
}
return $json;
}
public static function saveJson() {
$encodedJson = json_encode( self::$installJson );
if ( !file_exists( INSTALL_JSON_LOCATION ) ) {
$content = file_get_contents( $location );
$json = json_decode( $content, true );
$fh = fopen( INSTALL_JSON_LOCATION, 'w' );
}
$writeSuccess = file_put_contents( INSTALL_JSON_LOCATION, $encodedJson );
if ( $writeSuccess ) {
return true;
}
return false;
}
public function getModule( $name ) {
$name = ucfirst( $name );
if ( isset( self::$installJson['modules'][$name] ) ) {
if ( isset( self::$installJson['modules'][$name]['enabled'] ) ) {
if ( self::$installJson['modules'][$name]['enabled'] == true ) {
self::$installJson['modules'][$name]['enabled_txt'] = '<span class="text-success">Yes</span>';
} else {
self::$installJson['modules'][$name]['enabled_txt'] = '<span class="text-danger">No</span>';
}
}
return self::$installJson['modules'][$name];
}
Debug::info( "install module not found: $name" );
return false;
}
public function getModules( $includeObjects ) {
if ( isset( self::$installJson['modules'] ) ) {
if ( empty( $includeObjects ) ) {
return self::$installJson['modules'];
} else {
$data = self::$installJson['modules'];
foreach ( $data as $name => $module) {
$class_object = new $module['class'];
$data[$name]['class_object'] = $class_object;
}
return $data;
}
}
Debug::error( "install modules not found" );
return false;
}
public function getNode( $name) {
if ( isset( self::$installJson[$name] ) ) {
return self::$installJson[$name];
}
}
public function setNode( $name, $value, $save = false ) {
self::$installJson[$name] = $value;
if ( $save !== false ) {
return self::saveJson();
}
return true;
}
public function setModule( $name, $value, $save = false ) {
if ( !isset( self::$installJson['modules'] ) ) {
self::$installJson['modules'] = [];
}
self::$installJson['modules'][$name] = $value;
if ( $save !== false ) {
return self::saveJson();
}
return true;
}
private function removeModule( $name, $save = false ) {
if ( !isset( self::$installJson['modules'] ) ) {
Debug::error( 'No modules installed' );
return false;
}
if ( !isset( self::$installJson['modules'][$name] ) ) {
Debug::error( 'Module not installed' );
return false;
}
self::$installJson['modules'][$name] = null;
if ( $save !== false ) {
return self::saveJson();
}
return true;
}
public function findModelFlags( $classObject ) {
$install_flags = [];
foreach ( self::MATRIX_MAP as $install_flag => $matrix_name ) {
if ( !empty( $classObject->$matrix_name ) ) {
$install_flags[$install_flag] = true;
} else {
$install_flags[$install_flag] = false;
}
}
return $install_flags;
}
public function getPluginInfo( $folder) {
$object = self::emptyModule( 'plugin', $folder );
$location = $folder . 'plugin.php';
if ( file_exists( $location ) ) {
include_once $location;
} else {
self::$errors[] = ['errorInfo' => "Could not find the requested plugin file: $location"];
return $object;
}
if ( ! class_exists( $object->class ) ) {
Debug::warn( 'Cannot get plugin version from class: ' . $object->class . ', class does NOT exist.');
return $object;
}
$class_object = new $object->class;
$object->version = $class_object->pluginVersion;
$module = $class_object->module;
if ( false !== $module ) {
$objectArray = (array) $object;
$object = (object) array_replace( $objectArray, $module );
}
$object->class_object = $class_object;
return $object;
}
public function getModelInfo( $filename, $folder = '' ) {
$object = self::emptyModule( 'model', $folder, $filename );
if ( ! class_exists( $object->class ) ) {
Debug::warn( 'Cannot get model version from class: ' . $object->class . ', class does NOT exist.');
return $object;
}
$class_object = new $object->class;
$object->version = $class_object->modelVersion;
$module = $this->getModule( $object->name );
if ( false !== $module ) {
$objectArray = (array) $object;
$object = (object) array_replace( $objectArray, $module );
}
$object->class_object = $class_object;
return $object;
}
public function getAvailablePlugins() {
$plugins = Plugin::getPluginDirectories();
$list = [];
foreach ( $plugins as $pluginName => $locations ) {
foreach ( $locations as $location ) {
foreach ( $location as $currentFolder => $file ) {
if ( 'plugin.php' == $file ) {
$list[ $pluginName ] = $this->getPluginInfo( str_ireplace( 'plugin.php', '', $currentFolder ) );
}
}
}
}
return $list;
}
public function getModelList( $folder ) {
$files = scandir( $folder );
$models = [];
array_shift( $files );
array_shift( $files );
foreach ( $files as $index => $filename ) {
if ( stripos( $filename, '.php' ) ) {
$list[] = $this->getModelInfo( $filename, $folder );
}
}
return $list;
}
public function installPlugin( $module_data, $flags = [], $defaultFlagValue = true ) {
Debug::log( 'Installing Plugin: ' . $module_data->name );
$errors = [];
if ( INSTALL_STATUS_INSTALLED === $module_data->installStatus ) {
Debug::warn( "$name has already been successfully installed" );
return true;
}
if ( empty( $module_data->class_object ) ) {
self::$errors[] = [ 'errorInfo' => 'Class not found: ' . $module_data->class ];
return false;
}
// normalize install flags
foreach ( PLUGIN_INSTALL_FLAGS as $flag_type ) {
// add any missing flags
if ( ! isset( $flags[ $flag_type ] ) ) {
$flags[ $flag_type ] = $defaultFlagValue;
}
// exclude any flags that have already been successfully installed
if ( !empty( $module_data->$flag_type ) && $module_data->$flag_type == INSTALL_STATUS_SUCCESS ) {
Debug::warn( "$flag_type has already been successfully executed" );
$flags[ $flag_type ] = false;
}
}
list( $install_data, $errors ) = $module_data->class_object->install( $flags );
$objectArray = (array) $module_data;
$module_data = array_replace( $objectArray, $install_data );
$module_data['installedVersion'] = $module_data['version'];
$module_data['lastUpdate'] = time();
if ( empty( $module_data['installDate'] ) ) {
$module_data['installDate'] = time();
}
unset($module_data['class_object']); // we don't want the class object though
$this->setModule( $module_data['name'], $module_data, true );
$this->updateInstallStatus( $module_data['name'] );
if ( !empty( $errors ) ) {
self::$errors = array_merge( self::$errors, $errors );
return false;
}
$errors[] = [ 'errorInfo' => $module_data['name'] . " has been installed." ];
self::$errors = array_merge( self::$errors, $errors );
return true;
}
public function uninstallPlugin( $module_data, $flags = [], $defaultFlagValue = true ) {
Debug::log( 'Uninstalling Plugin: ' . $module_data->name );
$errors = [];
if ( empty( $module_data->class_object ) ) {
self::$errors[] = [ 'errorInfo' => 'Class not found: ' . $module_data->class ];
return false;
}
// normalize install flags
foreach ( PLUGIN_INSTALL_FLAGS as $flag_type ) {
// add any missing flags
if ( ! isset( $flags[ $flag_type ] ) ) {
$flags[ $flag_type ] = $defaultFlagValue;
}
}
$errors = $module_data->class_object->uninstall( $flags );
if ( !empty( $errors ) ) {
self::$errors = array_merge( self::$errors, $errors );
return false;
}
$this->removeModule( $module_data->name, true );
$errors[] = [ 'errorInfo' => $module_data->name . " has been installed." ];
self::$errors = array_merge( self::$errors, $errors );
return true;
}
public function installModel( $module_data, $flags = [], $defaultFlagValue = true, $updateModule = true ) {
Debug::log( 'Installing Model: ' . $module_data->name );
$errors = [];
if ( INSTALL_STATUS_INSTALLED === $module_data->installStatus ) {
Debug::warn( "$module_data->name has already been successfully installed" );
return true;
}
if ( empty( $module_data->class_object ) ) {
self::$errors[] = [ 'errorInfo' => 'Class not found: ' . $module_data->class ];
return false;
}
// normalize install flags
$model_flags = $this->findModelFlags( $module_data->class_object );
foreach ( MODEL_INSTALL_FLAGS as $flag_type ) {
// add any missing flags
if ( ! isset( $flags[ $flag_type ] ) ) {
$flags[ $flag_type ] = $defaultFlagValue;
}
// exclude any flags that have already been successfully installed
if ( !empty( $module_data->$flag_type ) && $module_data->$flag_type == INSTALL_STATUS_SUCCESS ) {
Debug::warn( "$flag_type has already been successfully installed" );
$flags[ $flag_type ] = false;
}
if ( $flags[ $flag_type ] === true ) {
// exclude any flags we can't do anything with
if ( ! isset( $model_flags[ $flag_type ] ) ) {
Debug::warn( "$flag_type cannot be installed due to installFlags on the model." );
$flags[ $flag_type ] = false;
}
// check to make sure we have the proper mapping
$matrix = self::MATRIX_MAP[ $flag_type ];
// exclude any flags we don't have a matric map for
if ( empty( $module_data->class_object->$matrix ) ) {
Debug::warn( "$flag_type does not have a proper matrix map and cannot be installed." );
$module_data->$flag_type = INSTALL_STATUS_NOT_FOUND;
}
}
}
list( $install_data, $errors ) = $module_data->class_object->install( $flags );
$objectArray = (array) $module_data;
$module_data = array_replace( $objectArray, $install_data );
$module_data['installedVersion'] = $module_data['version'];
$module_data['lastUpdate'] = time();
if ( empty( $module_data['installDate'] ) ) {
$module_data['installDate'] = time();
}
if ($updateModule) {
unset($module_data['class_object']); // we don't want the class object though
$this->setModule( $module_data['name'], $module_data, true );
$this->updateInstallStatus( $module_data['name'] );
}
if ( !empty( $errors ) ) {
self::$errors = array_merge( self::$errors, $errors );
return false;
}
$errors[] = [ 'errorInfo' => $module_data['name'] . " has been installed." ];
self::$errors = array_merge( self::$errors, $errors );
return true;
}
public function uninstallModel( $module_data, $flags = [], $defaultFlagValue = true, $updateModule = true ) {
Debug::log( 'Uninstalling Model: ' . $module_data->name );
$errors = [];
if ( empty( $module_data->class_object ) ) {
self::$errors[] = [ 'errorInfo' => 'Class not found: ' . $module_data->class ];
return false;
}
// normalize install flags
$model_flags = $this->findModelFlags( $module_data->class_object );
foreach ( MODEL_INSTALL_FLAGS as $flag_type ) {
// add any missing flags
if ( ! isset( $flags[ $flag_type ] ) ) {
$flags[ $flag_type ] = $defaultFlagValue;
}
if ( $flags[ $flag_type ] === true ) {
// exclude any flags we can't do anything with
if ( ! isset( $model_flags[ $flag_type ] ) ) {
Debug::warn( "$flag_type cannot be installed due to installFlags on the model." );
$flags[ $flag_type ] = false;
}
// check to make sure we have the proper mapping
$matrix = self::MATRIX_MAP[ $flag_type ];
// exclude any flags we don't have a matric map for
if ( empty( $module_data->class_object->$matrix ) ) {
Debug::warn( "$flag_type does not have a proper matrix map and cannot be installed." );
$module_data->$flag_type = INSTALL_STATUS_NOT_FOUND;
}
}
}
list( $install_data, $errors ) = $module_data->class_object->uninstall( $flags );
if ( !empty( $errors ) ) {
self::$errors = array_merge( self::$errors, $errors );
return false;
}
$errors[] = [ 'errorInfo' => $module_data->name . " has been uninstalled." ];
self::$errors = array_merge( self::$errors, $errors );
return true;
}
private function updateInstallStatus( $name ) {
$modelInfo = $this->getModule( $name );
if ( $modelInfo === false ) {
return;
}
if ( $modelInfo['type'] == 'plugin' ) {
$flags = PLUGIN_INSTALL_FLAGS;
} else {
$flags = MODEL_INSTALL_FLAGS;
}
foreach ( $flags as $flag_type ) {
if ( ! in_array( $modelInfo[ $flag_type ], [ INSTALL_STATUS_SUCCESS, INSTALL_STATUS_NOT_REQUIRED ] ) ) {
$modelInfo['installStatus'] = INSTALL_STATUS_PARTIALLY_INSTALLED;
break;
}
$modelInfo['installStatus'] = INSTALL_STATUS_INSTALLED;
}
$this->setModule( $name, $modelInfo, true );
}
/**
* Checks the root directory for a .htaccess file and compares it with
* the .htaccess file the application generates by default.
*
* NOTE: The $override flag will cause this function to automatically generate a
* new htaccess file if the .htaccess found in the root directory does not match
* the default generated version.
*
* @param boolean $create - Optional flag to generate and save a new htaccess
* if none is found.
*
* @return boolean - Returns true if the htaccess file was found or
* created, false otherwise.
*/
public function saveHtaccess( $text = false ) {
if ( false === $text ) {
$text = $this->generateHtaccess();
}
if ( file_exists( HTACCESS_LOCATION ) ) {
Debug::error( "Can't overwrite existing htaccess file" );
return false;
}
return file_put_contents( HTACCESS_LOCATION, $text );
}
public function checkHtaccess( $create = false ) {
$check = 0;
$findRewrite1 = "RewriteEngine On\n";
$findRewrite2 = 'RewriteBase ' . Routes::getRoot() . "\n\n";
if ( file_exists( HTACCESS_LOCATION ) ) {
$htaccess = file_get_contents( HTACCESS_LOCATION );
if ( $htaccess === $this->generateHtaccess() ) {
return true;
}
if ( stripos( $htaccess, $findRewrite1 ) ) {
$check++;
}
if ( stripos( $htaccess, $findRewrite2 ) ) {
$check++;
}
if ( $check === 2 ) {
return true;
}
}
return false;
}
public function baseHtaccess() {
$out = "# Intercepts for images not found
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^images/(.*)$ index.php?error=image404&url=$1 [L,NC,QSA]
# Intercepts for uploads not found
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^uploads/(.*)$ index.php?error=upload404&url=$1 [L,NC,QSA]
# Intercepts other errors
RewriteRule ^errors/(.*)$ index.php?error=$1 [L,NC,QSA]
# Intercept all traffic not originating locally and not going to images or uploads
RewriteCond %{REMOTE_ADDR} !^127\.0\.0\.1
RewriteCond %{REMOTE_ADDR} !^\:\:1
RewriteCond %{REQUEST_URI} !^(.*)/images/(.*)$ [NC]
RewriteCond %{REQUEST_URI} !^(.*)/uploads/(.*)$ [NC]
RewriteCond %{REQUEST_URI} !^(.*).js$ [NC]
RewriteCond %{REQUEST_URI} !^(.*).css$ [NC]
RewriteCond %{REQUEST_URI} !^(.*).ico$ [NC]
RewriteRule ^(.+)$ index.php?url=$1 [QSA,L]
# Catchall for any non existent files or folders
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.+)$ index.php?url=$1 [QSA,L]";
return str_ireplace( ' ', '', $out );
}
/**
* Generates the default htaccess file for the application. This will funnel
* all traffic that comes into the application directory to index.php where we
* use that data to construct the desired page using the controller.
*
* @param string $docroot - A custom document root to use instead of the default.
*
* @return string - The generated contents of the htaccess file.
*/
protected function generateHtaccess( $docroot = null, $rewrite = true ) {
$out = '';
if ( empty( $docroot ) ) {
$docroot = Routes::getRoot();
}
if ( $rewrite === true ) {
$out .= "RewriteEngine On\n\n";
}
$out .= "RewriteBase $docroot\n\n";
$out .= $this->baseHtaccess();
return $out;
}
}

244
app/classes/permissions.php Normal file
View File

@ -0,0 +1,244 @@
<?php
/**
* app/classes/permissions.php
*
* This class handles all the hard-coded permissions.
*
* @version 3.0
* @author Joey Kimsey <Joey@thetempusproject.com>
* @link https://TheTempusProject.com
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
*/
namespace TheTempusProject\Classes;
use TheTempusProject\Canary\Canary as Debug;
use TheTempusProject\Bedrock\Functions\Check;
use TheTempusProject\Houdini\Classes\Forms;
use TheTempusProject\Bedrock\Functions\Input;
class Permissions {
public static $permissions = false;
private static $location = false;
private static $initialized = false;
/**
* Default constructor which will attempt to load the permissions from the location specified.
*
* @param {string} [$location]
* @return {null|object}
*/
public function __construct( $location = '' ) {
if ( self::$initialized !== false ) {
Debug::log( 'Permissions already initialized.' );
return $this;
}
if ( empty( $location ) ) {
$location = PERMISSIONS_JSON;
}
self::$initialized = $this->load( $location );
if ( self::$initialized !== false ) {
Debug::log( 'Permissions initialization succeeded.' );
return $this;
}
Debug::warn( 'Permissions initialization failed.' );
}
/**
* Attempts to retrieve then set the configuration from a file.
* @note This function will reset the permissions every time it is used.
*
* @param {string} [$location]
* @return {bool}
*/
public function load( $location ) {
self::$permissions = $this->getPermsFile( $location );
self::$location = $location;
if ( self::$permissions === false || empty( self::$permissions ) ) {
Debug::warn( 'Permissions load failed.' );
return false;
}
Debug::log( 'Permissions load succeeded.' );
return true;
}
/**
* Opens and decodes the permissions json from the location provided.
*
* @param {string} [$location]
* @return {bool|array}
*/
public function getPermsFile( $location ) {
if ( file_exists( $location ) ) {
Debug::debug( "Permissions json found: $location" );
return json_decode( file_get_contents( $location ), true );
} else {
Debug::warn( "Permissions json not found: $location" );
return false;
}
}
/**
* Retrieves the permissions option for $name.
*
* @param {string} [$name]
* @return {WILD}
*/
public function get( $name ) {
if ( self::$permissions === false ) {
Debug::warn( 'Permissions not loaded.' );
return;
}
if ( isset( self::$permissions[$name] ) ) {
return self::$permissions[$name];
}
Debug::warn( "Permission not found: $name" );
return;
}
/**
* Saves the current permissions.
*
* @param {bool} [$default] - Whether or not to save a default copy.
* @return {bool}
*/
public function save( $save_backup = true ) {
if ( self::$permissions === false ) {
Debug::warn( 'Permissions not loaded.' );
return false;
}
if ( self::$location === false ) {
Debug::warn( 'Permissions location not set.' );
return false;
}
if ( $save_backup ) {
$locationArray = explode( '.', self::$location );
$locationArray[] = 'bak';
$backupLoction = implode( '.', $locationArray );
if ( !file_put_contents( $backupLoction, json_encode( self::$permissions ) ) ) {
return false;
}
}
if ( file_put_contents( self::$location, json_encode( self::$permissions ) ) ) {
return true;
}
return false;
}
/**
* Adds a new permission to the $permissions array.
*
* @param {string} [$name]
* @param {string} [$value]
* @return {bool}
*/
public function add( $permName, $details ) {
if ( !Check::simpleName( $permName ) ) {
Debug::error( "Permission name invalid: $permName" );
return false;
}
if ( isset( self::$permissions[$permName] ) ) {
Debug::warn( "Permission already exists: $permName" );
return false;
}
if ( self::$permissions === false ) {
self::$permissions = [];
}
self::$permissions[$permName] = $details;
return true;
}
/**
* Adds many new permissions to the $permissions array.
*
* @param {array} [$data]
* @return {bool}
*/
public function addMany( $data ) {
if ( !is_array( $data ) ) {
Debug::error( 'Permissions must be an array.' );
return false;
}
foreach ( $data as $name => $value ) {
$this->add( $name, $value );
}
return true;
}
/**
* Removes an existing permission from the $permissions array.
*
* @param {string} [$name]
* @param {string} [$save]
* @return {bool}
*/
public function remove( $name, $save = false ) {
if ( self::$permissions === false ) {
Debug::warn( 'Permissions not loaded.' );
return false;
}
if ( !isset( self::$permissions[$name] ) ) {
Debug::error( "Permission does not exist: $name" );
return false;
}
unset( self::$permissions[$name] );
if ( $save === true ) {
return $this->save();
}
return true;
}
public function getDefaultPermissionsArray() {
if ( self::$permissions === false ) {
Debug::warn( 'Permissions not loaded.' );
return false;
}
$permsArray = [];
foreach ( self::$permissions as $name => $details ) {
$permsArray[$name] = $details['default'];
}
return $permsArray;
}
public function convertFormToArray() {
$permsArray = [];
foreach ( self::$permissions as $name => $details ) {
if ( Input::exists( $name ) ) {
$permsArray[$name] = true;
} else {
$permsArray[$name] = false;
}
}
return $permsArray;
}
public function getDefault( $name ) {
$perm = $this->get( $name );
if ( empty( $perm ) || empty( $perm['default'] ) ) {
Debug::warn( "Permission Default not found: $name" );
return;
}
}
public function getPrettyName( $name ) {
$pref = $this->get( $name );
if ( empty( $pref ) || empty( $pref['pretty'] ) ) {
Debug::warn( "Permission Pretty Name not found: $name" );
return;
}
return $pref['pretty'];
}
public function getFormHtml( $populated = [] ) {
$form = '';
foreach ( self::$permissions as $name => $details ) {
if ( isset( $populated[$name] ) && $populated[$name] !== false ) {
$checked = true;
} else {
$checked = false;
}
$form .= Forms::getFormFieldHtml( $name, $details['pretty'], 'checkbox', $checked );
}
return $form;
}
}

493
app/classes/plugin.php Normal file
View File

@ -0,0 +1,493 @@
<?php
/**
* app/classes/plugin.php
*
* This class is used as a foundation for all plugins to build from.
*
* @version 3.0
* @author Joey Kimsey <Joey@thetempusproject.com>
* @link https://TheTempusProject.com
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
*/
namespace TheTempusProject\Classes;
use TheTempusProject\Houdini\Classes\Navigation;
use TheTempusProject\Houdini\Classes\Filters;
use TheTempusProject\TheTempusProject as App;
use TheTempusProject\Canary\Canary as Debug;
use TheTempusProject\Bedrock\Classes\Database;
class Plugin {
public $required_models = [];
public $models = [];
public $errors = [];
// Global Properties
public $module;
public $initialized = false;
public static $installer;
public static $db;
public static $installFlags = PLUGIN_INSTALL_FLAGS;
public static $pluginFolders = [];
public static $pluginsAvailable = [];
public static $pluginsActive = [];
// Basic Required Info
public $pluginName = 'Default Plugin Name';
public $pluginAuthor = 'TheTempusProject';
public $pluginWebsite = 'https://TheTempusProject.com';
public $pluginVersion = 0.0;
public $pluginDescription = 'The Default Plugin Description';
// Front-end Properties
public $admin_links = [];
public $main_links = [];
public $footer_links = [];
public $filters = [];
// Install Related
public $configName = '';
public $configMatrix = [];
public $resourceMatrix = [];
public $preferenceMatrix = [];
public $permissionMatrix = [];
const PLUGIN_FLAG_MAP = [
'preferences_installed' => 'installPreferences',
'permissions_installed' => 'installPermissions',
'configs_installed' => 'installConfigs',
'models_installed' => 'installModels',
'resources_installed' => 'installResources',
];
public function __construct( $load = false ) {
if ( true === $this->initialized && false == $load ) {
return;
}
self::$db = Database::getInstance();
if ( ! isset( self::$installer ) ) {
self::$installer = new Installer();
}
if ( ! isset( $this->module ) ) {
$this->module = self::$installer->getModule( getClassName( $this ) );
}
if ( true == $load ) {
if ( $this->checkEnabled() ) {
$this->loadAdminNav();
$this->loadMainNav();
$this->loadFooterNav();
$this->loadFilters();
}
$this->initialized = true;
}
}
public function install( $options ) {
Debug::log( 'Installing Plugin: ' . $this->pluginName );
$module_data = [];
$errors = [];
foreach ( self::PLUGIN_FLAG_MAP as $flag_name => $function_name ) {
if ( empty( $options[$flag_name] ) ) {
$module_data[ $flag_name ] = INSTALL_STATUS_SKIPPED;
continue;
}
if ( 'installModels' != $function_name ) {
$result = $this->$function_name( $options );
} else {
$model_options = $this->convertPluginOptionsToModelOptions( $options );
$result = $this->$function_name( $model_options );
}
if ( empty( $result ) ) {
$errors[] = ['errorInfo' => get_class($this) . " Failed to execute $flag_name properly."];
$module_data[ $flag_name ] = INSTALL_STATUS_FAIL;
continue;
}
if ( 'installResources' === $function_name ) {
$module_data[ $flag_name ] = $result;
continue;
}
$module_data[ $flag_name ] = INSTALL_STATUS_SUCCESS;
continue;
}
return [ $module_data, $errors ];
}
public function uninstall( $options ) {
Debug::log( 'Uninstalling Plugin: ' . $this->pluginName );
$module_data = [];
$errors = [];
foreach ( self::PLUGIN_FLAG_MAP as $flag_name => $function_name ) {
$function_name = 'un' . $function_name;
if ( empty( $options[$flag_name] ) ) {
$module_data[ $flag_name ] = INSTALL_STATUS_SKIPPED;
continue;
}
if ( 'installModels' != $function_name ) {
$result = $this->$function_name( $options );
} else {
$model_options = $this->convertPluginOptionsToModelOptions( $options );
$result = $this->$function_name( $model_options );
}
if ( empty( $result ) ) {
$errors[] = ['errorInfo' => get_class($this) . " Failed to execute $flag_name properly."];
$module_data[ $flag_name ] = INSTALL_STATUS_FAIL;
continue;
}
if ( 'uninstallResources' === $function_name ) {
$module_data[ $flag_name ] = $result;
continue;
}
$module_data[ $flag_name ] = INSTALL_STATUS_UNINSTALLED;
continue;
}
return $errors;
}
public function installModels( $options ) {
$class = get_class($this);
$nameArray = explode( '\\', $class );
$name = array_pop( $nameArray );
$directory = PLUGIN_DIRECTORY . lcfirst($name) . DIRECTORY_SEPARATOR . 'models' . DIRECTORY_SEPARATOR;
if ( ! file_exists( $directory ) ) {
Debug::log( 'models directory is empty' );
return true;
}
$models = self::$installer->getModelList( $directory );
$error = false;
foreach ( $models as $model ) {
$result = self::$installer->installModel( $model, $options, true, false );
if ( $result === false ) {
$error = true;
continue;
}
}
if ( $error ) {
return false;
} else {
return true;
}
}
public function uninstallModels( $options ) {
$class = get_class($this);
$nameArray = explode( '\\', $class );
$name = array_pop( $nameArray );
$directory = PLUGIN_DIRECTORY . lcfirst($name) . DIRECTORY_SEPARATOR . 'models' . DIRECTORY_SEPARATOR;
if ( ! file_exists( $directory ) ) {
Debug::log( 'models directory is empty' );
return true;
}
$models = self::$installer->getModelList( $directory );
$error = false;
foreach ( $models as $model ) {
$result = self::$installer->uninstallModel( $model, $options, true, false );
if ( $result === false ) {
$error = true;
continue;
}
}
if ( $error ) {
return false;
} else {
return true;
}
}
public function installPermissions( $options = '' ) {
if ( empty( $this->permissionMatrix ) ) {
Debug::log( 'permissionMatrix is empty' );
return true;
}
$perms = new Permissions();
foreach ( $this->permissionMatrix as $name => $details ) {
$perms->add( $name, $details );
}
return $perms->save( true );
}
public function uninstallPermissions( $options = '' ) {
if ( empty( $this->permissionMatrix ) ) {
Debug::log( 'permissionMatrix is empty' );
return true;
}
$perms = new Permissions();
foreach ( $this->permissionMatrix as $name => $details ) {
$perms->remove( $name, true );
}
return true;
}
public function installConfigs( $options = '' ) {
if ( empty( $this->configMatrix ) || empty( $this->configName )) {
Debug::log( 'configMatrix is empty' );
return true;
}
$config = new Config( CONFIG_JSON );
// should have some sort of DELTA functionality and safeguards
$config->addCategory( $this->configName );
foreach ( $this->configMatrix as $name => $details ) {
$config->add( $this->configName, $name, $details );
}
return $config->save();
}
public function uninstallConfigs( $options = '' ) {
if ( empty( $this->configName ) ) {
return true;
}
$config = new Config( CONFIG_JSON );
return $config->removeCategory( $this->configName, true, true );
}
public function installPreferences( $options = '' ) {
$prefs = new Preferences();
if ( empty( $this->preferenceMatrix ) ) {
Debug::log( 'preferenceMatrix is empty' );
return true;
}
foreach ( $this->preferenceMatrix as $name => $details ) {
$prefs->add( $name, $details );
}
return $prefs->save( true );
}
public function uninstallPreferences( $options = '' ) {
if ( empty( $this->preferenceMatrix ) ) {
Debug::log( 'preferenceMatrix is empty' );
return true;
}
$prefs = new Preferences();
foreach ( $this->preferenceMatrix as $name => $details ) {
$prefs->remove( $name, true );
}
return $prefs->save( true );
}
public function installResources( $options = '' ) {
if ( empty( $this->resourceMatrix ) ) {
Debug::log( 'resourceMatrix is empty' );
return true;
}
$ids = [];
foreach( $this->resourceMatrix as $tableName => $entries ) {
foreach ( $entries as $entry ) {
foreach ( $entry as $key => $value ) {
if ( '{time}' == $value ) {
$entry[$key] = time();
}
}
self::$db->insert( $tableName, $entry );
$id = self::$db->lastId();
if ( $id ) {
$ids[] = $id;
}
}
}
return $ids;
}
public function uninstallResources( $options = '' ) {
if ( empty( $this->resourceMatrix ) ) {
Debug::log( 'resourceMatrix is empty' );
return true;
}
$ids = $this->module['resources_installed'];
$data = [];
foreach( $this->resourceMatrix as $tableName => $entries ) {
foreach ($ids as $id) {
$data[] = self::$db->delete( $tableName, $id );
}
}
return $data;
}
/**
* Loaders
*/
public function loadAdminNav() {
if ( !empty( $this->admin_links ) ) {
foreach( $this->admin_links as $key => $link ) {
Navigation::addLink( App::ADMIN_MENU_NAME, $link );
}
}
}
public function loadMainNav() {
if ( !empty( $this->main_links ) ) {
foreach( $this->main_links as $key => $link ) {
Navigation::addLink( App::MAIN_MENU_NAME, $link );
}
}
}
public function loadFooterNav() {
if ( !empty( $this->footer_links ) ) {
foreach( $this->footer_links as $key => $link ) {
Navigation::addLink( App::FOOTER_MENU_NAME, $link );
}
}
}
public function loadFilters() {
if ( ! empty( $this->filters ) ) {
foreach( $this->filters as $filter ) {
Filters::add( $filter['name'], $filter['find'], $filter['replace'], $filter['enabled'] );
}
}
}
public function convertPluginOptionsToModelOptions( $options ) {
$data = [];
foreach (self::PLUGIN_FLAG_MAP as $pluginValue => $modelValue) {
if ( isset( $options[$pluginValue] ) ) {
$data[$modelValue] = $options[$pluginValue];
}
}
return $data;
}
public static function getPluginDirectories( $forceRefresh = false ) {
if ( !empty( self::$pluginFolders ) && true !== $forceRefresh ) {
return self::$pluginFolders;
}
$pluginFolders = [];
if ( ! PLUGINS_ENABLED && true !== $forceRefresh ) {
Debug::warn('Plugins disabled');
return $pluginFolders;
}
if ( ! file_exists( PLUGIN_DIRECTORY ) ) {
Debug::warn("Plugins folder is missing: $dir");
return $pluginFolders;
}
// get a list of all plugins in the plugin directory
$pluginDirectories = scandir( PLUGIN_DIRECTORY );
array_shift( $pluginDirectories ); // remove the .
array_shift( $pluginDirectories ); // remove the ..
foreach ( $pluginDirectories as $key => $pluginName ) {
$pluginDirectory = PLUGIN_DIRECTORY . $pluginName;
if ( is_file( $pluginDirectory ) ) {
continue; // skip any files in the main plugin directory if they exist
}
// get a list of all directories in this plugin directory
$pluginFolders[ $pluginName ] = [];
$pluginDirectory .= DIRECTORY_SEPARATOR;
$pluginDirectoryArray = scandir( $pluginDirectory );
array_shift( $pluginDirectoryArray ); // remove the .
array_shift( $pluginDirectoryArray ); // remove the ..
// loop over each sub-directory insider plugin directory
foreach ( $pluginDirectoryArray as $key => $file ) {
$currentFolder = $pluginDirectory . $file . DIRECTORY_SEPARATOR;
switch ( $file ) {
case 'controllers':
case 'config':
case 'models':
case 'views':
case 'templates':
break;
case 'forms.php':
$currentFolder = rtrim( $currentFolder, DIRECTORY_SEPARATOR );
break;
case 'plugin.php':
$currentFolder = rtrim( $currentFolder, DIRECTORY_SEPARATOR );
break;
default:
continue 2; // break if we aren't looking for whatever we found
}
$pluginFolders[ $pluginName ][] = [ $currentFolder => $file ];
}
}
self::$pluginFolders = $pluginFolders;
return self::$pluginFolders;
}
public static function getActivePlugins( $forceRefresh = false ) {
if ( ! empty( self::$pluginsActive ) && true !== $forceRefresh ) {
return self::$pluginsActive;
}
if ( ! isset( self::$installer ) ) {
self::$installer = new Installer();
}
$out = [];
$plugins = self::$installer->getAvailablePlugins( $forceRefresh );
if ( ! empty( $plugins ) ) {
foreach ( $plugins as $plugin ) {
if ( !isset( $plugin->class_object )) {
continue;
}
$installedPlugin = $plugin->class_object->module;
if ( !isset( $installedPlugin['enabled'] ) || !$installedPlugin['enabled'] ) {
continue;
}
$out[] = [
$plugin->name => $installedPlugin['class'],
];
}
}
self::$pluginsActive = $out;
return self::$pluginsActive;
}
public static function enable( $name, $save = true ) {
if ( ! isset( self::$installer ) ) {
self::$installer = new Installer();
}
$module = self::$installer->getModule( $name );
if ( empty( $module ) ) {
Debug::warn( "plugin not found: $name" );
return false;
}
if ( ! isset( $module['enabled'] ) ) {
Debug::error( "plugin enabled not set: $name" );
return false;
}
$module['enabled'] = true;
return self::$installer->setModule( $name, $module, $save );
}
public static function disable( $name, $save = true ) {
if ( ! isset( self::$installer ) ) {
self::$installer = new Installer();
}
$module = self::$installer->getModule( $name );
if ( empty($module) ) {
Debug::warn( "plugin not found: $name" );
return false;
}
if ( ! isset( $module['enabled'] ) ) {
Debug::error( "plugin not enabled: $name" );
return false;
}
$module['enabled'] = false;
return self::$installer->setModule( $name, $module, $save );
}
public function checkEnabled() {
$name = ucfirst( strtolower( $this->pluginName ) );
if ( isset( $this->module['enabled'] ) ) {
return $this->module['enabled'];
}
Debug::warn( "install not found: {$this->pluginName}" );
return false;
}
}

297
app/classes/preferences.php Normal file
View File

@ -0,0 +1,297 @@
<?php
/**
* app/classes/preferences.php
*
* This class handles all the hard-coded preferences.
*
* @version 3.0
* @author Joey Kimsey <Joey@thetempusproject.com>
* @link https://TheTempusProject.com
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
*/
namespace TheTempusProject\Classes;
use TheTempusProject\Houdini\Classes\Issues;
use TheTempusProject\Houdini\Classes\Forms;
use TheTempusProject\Canary\Canary as Debug;
use TheTempusProject\Bedrock\Functions\Check;
use TheTempusProject\Bedrock\Functions\Upload;
use TheTempusProject\Bedrock\Functions\Input;
use TheTempusProject\TheTempusProject as App;
class Preferences {
public static $preferences = false;
private static $location = false;
private static $initialized = false;
/**
* Default constructor which will attempt to load the preferences from the location specified.
*
* @param {string} [$location]
* @return {null|object}
*/
public function __construct( $location = '' ) {
if ( self::$initialized !== false ) {
Debug::log( 'Preferences already initialized.' );
return $this;
}
if ( empty( $location ) ) {
$location = PREFERENCES_JSON;
}
self::$initialized = $this->load( $location );
if ( self::$initialized !== false ) {
Debug::log( 'Preferences initialization succeeded.' );
return $this;
}
Debug::warn( 'Preferences initialization failed.' );
}
/**
* Attempts to retrieve then set the preferences from a file.
* @note This function will reset the preferences every time it is used.
*
* @param {string} [$location]
* @return {bool}
*/
public function load( $location ) {
self::$preferences = $this->getPrefsFile( $location );
self::$location = $location;
if ( self::$preferences === false || empty( self::$preferences ) ) {
Debug::warn( 'Preferences load failed.' );
return false;
}
Debug::log( 'Preferences load succeeded.' );
return true;
}
/**
* Opens and decodes the preferences json from the location provided.
*
* @param {string} [$location]
* @return {bool|array}
*/
public function getPrefsFile( $location ) {
if ( file_exists( $location ) ) {
Debug::debug( "Preferences json found: $location" );
return json_decode( file_get_contents( $location ), true );
} else {
Debug::warn( "Preferences json not found: $location" );
return false;
}
}
/**
* Retrieves the preference option for $name.
*
* @param {string} [$name]
* @return {WILD}
*/
public static function get( $name ) {
if ( self::$preferences === false ) {
return Debug::warn( 'Preferences not loaded.' );
}
if ( isset( self::$preferences[$name] ) ) {
return self::$preferences[$name];
}
return Debug::warn( "Preference not found: $name" );
}
public function getType( $name ) {
$pref = $this->get( $name );
if ( empty( $pref ) || empty( $pref['type'] ) ) {
return Debug::warn( "Preference Type not found: $name" );
}
return $pref['type'];
}
public function getDefault( $name ) {
$pref = $this->get( $name );
if ( empty( $pref ) || empty( $pref['default'] ) ) {
return Debug::warn( "Preference Default not found: $name" );
}
return $pref['default'];
}
public function getOptions( $name ) {
$pref = $this->get( $name );
if ( empty( $pref ) || empty( $pref['options'] ) ) {
return Debug::warn( "Preference Options not found: $name" );
}
return $pref['options'];
}
public function getPrettyName( $name ) {
$pref = $this->get( $name );
if ( empty( $pref ) || empty( $pref['pretty'] ) ) {
return Debug::warn( "Preference Pretty Name not found: $name" );
}
return $pref['pretty'];
}
/**
* Saves the current preferences.
*
* @param {bool} [$default] - Whether or not to save a default copy.
* @return {bool}
*/
public function save( $backup = true ) {
if ( self::$preferences === false ) {
Debug::warn( 'Preferences not loaded.' );
return false;
}
if ( self::$location === false ) {
Debug::warn( 'Preferences location not set.' );
return false;
}
if ( $backup ) {
$locationArray = explode( '.', self::$location );
$locationArray[] = 'bak';
$backupLoction = implode( '.', $locationArray );
if ( !file_put_contents( $backupLoction, json_encode( self::$preferences ) ) ) {
return false;
}
}
if ( file_put_contents( self::$location, json_encode( self::$preferences ) ) ) {
return true;
}
return false;
}
/**
* Adds a new preference to the $preferences array.
*
* @param {string} [$name]
* @param {string} [$value]
* @return {bool}
*/
public function add( $name, $details ) {
if ( !Check::simpleName( $name ) ) {
Debug::error( "Preference name invalid: $name" );
return false;
}
if ( isset( self::$preferences[$name] ) ) {
Debug::warn( "Preference already exists: $name" );
return false;
}
if ( self::$preferences === false ) {
self::$preferences = [];
}
$prefsArray = $this->normalizePreferenceArray( $name, $details );
if ( false === $prefsArray ) {
Debug::warn( 'Preference array failed to load properly.' );
return false;
}
self::$preferences[$name] = $prefsArray;
return true;
}
public function getFormHtml( $populated = [] ) {
$form = '';
foreach ( self::$preferences as $name => $details ) {
$tempPrefsArray = $this->normalizePreferenceArray( $name, $details );
if ( isset( $populated[ $name ] ) ) {
$tempPrefsArray['default'] = $populated[$name];
}
$form .= Forms::getFormFieldHtml( $name, $tempPrefsArray['pretty'], $tempPrefsArray['type'], $tempPrefsArray['default'], $tempPrefsArray['options'] );
}
return $form;
}
public function convertFormToArray( $fillMissing = true, $defaultsOnly = true ) {
$prefsArray = [];
foreach ( self::$preferences as $name => $details ) {
if ( true === $fillMissing ) {
if ( true !== $defaultsOnly && !empty( App::$activePrefs[$name] ) ) {
$prefsArray[$name] = App::$activePrefs[$name];
} else {
$prefsArray[$name] = $details['default'];
}
}
if ( Input::exists( $name ) ) {
$prefsArray[$name] = Input::post( $name );
}
if ( 'file' == $details['type'] ) {
if ( Input::exists( $name ) ) {
$folder = IMAGE_UPLOAD_DIRECTORY . App::$activeUser->username . DIRECTORY_SEPARATOR;
if ( !Upload::image( $name, $folder ) ) {
Issues::add( 'error', [ 'There was an error with your upload.' => Check::systemErrors() ] );
} else {
$route = str_replace( APP_ROOT_DIRECTORY, '', $folder );
$prefsArray[$name] = $route . Upload::last();
}
}
}
if ( 'checkbox' == $details['type'] ) {
if ( Input::exists( $name ) ) {
$prefsArray[$name] = true;
} else {
$prefsArray[$name] = false;
}
}
}
return $prefsArray;
}
public function getDefaultPreferencesArray() {
if ( self::$preferences === false ) {
Debug::warn( 'Preferences not loaded.' );
return false;
}
$prefsArray = [];
foreach ( self::$preferences as $name => $details ) {
$tempPrefsArray = $this->normalizePreferenceArray( $name, $details );
$prefsArray[$name] = $tempPrefsArray['default'];
}
return $prefsArray;
}
public function normalizePreferenceArray( $name, $prefsArray ) {
if ( !is_array( $prefsArray ) ) {
Debug::warn( 'Preference array was not an array.' );
return false;
}
if ( !isset( $prefsArray['type'] ) ) {
if ( isset( $prefsArray['options'] ) ) {
$prefsArray['type'] = 'select';
} else {
$prefsArray['type'] = 'text';
}
}
if ( !isset( $prefsArray['pretty'] ) ) {
$prefsArray['pretty'] = ucfirst( $name );
}
if ( !isset( $prefsArray['default'] ) ) {
$prefsArray['default'] = '';
}
if ( ( empty( $prefsArray['avatar'] ) ) || ( $prefsArray['avatar'] == 'defaultAvatar.png' ) ) {
$prefsArray['avatar'] = IMAGE_DIRECTORY . 'defaultAvatar.png';
}
if ( !isset( $prefsArray['options'] ) ) {
$prefsArray['options'] = null;
}
return $prefsArray;
}
/**
* Removes an existing preference from the $preferences array.
*
* @param {string} [$name]
* @param {bool} [$save]
* @return {bool}
*/
public function remove( $name, $save = false ) {
if ( self::$preferences === false ) {
Debug::warn( 'Preferences not loaded.' );
return false;
}
if ( !isset( self::$preferences[$name] ) ) {
Debug::error( "Preference does not exist: $name" );
return false;
}
unset( self::$preferences[$name] );
if ( $save === true ) {
return $this->save( true );
}
return true;
}
}