Compare commits
47 Commits
Author | SHA1 | Date | |
---|---|---|---|
5590592ebe | |||
b65dda1328 | |||
f928e87141 | |||
a6b241c7f0 | |||
a38d132e61 | |||
d7e8b586d7 | |||
ea120e09bc | |||
2aed4ec2ed | |||
bd939cc078 | |||
1fb4d2eb57 | |||
e52ae78ed0 | |||
5e621883ff | |||
b5996dc7db | |||
bc33b4cac4 | |||
ca850bb46b | |||
35b7be92a6 | |||
d4751696f3 | |||
fa12dd20ba | |||
41a6aed209 | |||
509a10bc36 | |||
5e99213601 | |||
ebfeead788 | |||
32a9711ade | |||
87e4f90bab | |||
1c5b020a87 | |||
5fe1c3aafe | |||
a859fb7ace | |||
2220c6cda3 | |||
de6d608857 | |||
41426fda4e | |||
7bef832417 | |||
aaefd66350 | |||
a0726e6578 | |||
f3f323d30f | |||
b3018de907 | |||
4ab9d33b01 | |||
485d85cb0a | |||
b93d0259e4 | |||
bf7b7ba1c9 | |||
113499254b | |||
3b6d7f3a2c | |||
09f96c369a | |||
afb9624971 | |||
8d3dee2ac2 | |||
355e509e68 | |||
c3f46cf6c3 | |||
4a521afa88 |
4
.gitignore
vendored
4
.gitignore
vendored
@ -62,3 +62,7 @@ logs/*
|
|||||||
mail.log
|
mail.log
|
||||||
vendor/canary/logs/*
|
vendor/canary/logs/*
|
||||||
.env
|
.env
|
||||||
|
components/*
|
||||||
|
mailhog.log
|
||||||
|
uploads/*
|
||||||
|
images/qr-codes/
|
||||||
|
@ -35,7 +35,7 @@ New classes must be prefaced with a doc-block following this style:
|
|||||||
*
|
*
|
||||||
* This is the admin controller.
|
* This is the admin controller.
|
||||||
*
|
*
|
||||||
* @version 3.0
|
* @version 5.0.1
|
||||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||||
* @link https://TheTempusProject.com
|
* @link https://TheTempusProject.com
|
||||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||||
|
@ -18,7 +18,7 @@ I am working very hard to ensure the system is safe and reliable enough for me t
|
|||||||
## Find Us
|
## Find Us
|
||||||
|
|
||||||
* [DockerHub](https://hub.docker.com/repositories/thetempusproject)
|
* [DockerHub](https://hub.docker.com/repositories/thetempusproject)
|
||||||
* [Packagist](https://packagist.org/users/joeyk4816/packages/)
|
* [Packagist](https://packagist.org/packages/thetempusproject/)
|
||||||
* [GitLab](https://git.thetempusproject.com/the-tempus-project/thetempusproject)
|
* [GitLab](https://git.thetempusproject.com/the-tempus-project/thetempusproject)
|
||||||
|
|
||||||
## Summary
|
## Summary
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
* This is the base admin controller. Every other admin controller should
|
* This is the base admin controller. Every other admin controller should
|
||||||
* extend this class.
|
* extend this class.
|
||||||
*
|
*
|
||||||
* @version 3.0
|
* @version 5.0.1
|
||||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||||
* @link https://TheTempusProject.com
|
* @link https://TheTempusProject.com
|
||||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* app/classes/admin_controller.php
|
* app/classes/api_controller.php
|
||||||
*
|
*
|
||||||
* This is the base admin controller. Every other admin controller should
|
* This is the base api controller. Every other api controller should
|
||||||
* extend this class.
|
* extend this class.
|
||||||
*
|
*
|
||||||
* @version 3.0
|
* @version 5.0.1
|
||||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||||
* @link https://TheTempusProject.com
|
* @link https://TheTempusProject.com
|
||||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||||
@ -16,17 +16,122 @@ use TheTempusProject\Houdini\Classes\Template;
|
|||||||
use TheTempusProject\TheTempusProject as App;
|
use TheTempusProject\TheTempusProject as App;
|
||||||
use TheTempusProject\Hermes\Functions\Redirect;
|
use TheTempusProject\Hermes\Functions\Redirect;
|
||||||
use TheTempusProject\Bedrock\Functions\Session;
|
use TheTempusProject\Bedrock\Functions\Session;
|
||||||
|
use TheTempusProject\Bedrock\Classes\Config;
|
||||||
|
use TheTempusProject\Models\Token;
|
||||||
|
use TheTempusProject\Canary\Bin\Canary as Debug;
|
||||||
|
use TheTempusProject\Houdini\Classes\Views;
|
||||||
|
|
||||||
class ApiController extends Controller {
|
class ApiController extends Controller {
|
||||||
public function __construct() {
|
protected static $canAccessApplicationApi = false;
|
||||||
|
protected static $canAccessUserApi = false;
|
||||||
|
protected static $canAccessAuthenticationApi = false;
|
||||||
|
protected static $authToken;
|
||||||
|
|
||||||
|
public function __construct( $secure = true ) {
|
||||||
|
header('Content-Type: application/json; charset=utf-8');
|
||||||
parent::__construct();
|
parent::__construct();
|
||||||
if ( ! App::verifyApiRequest() ) {
|
Template::setTemplate( 'api' );
|
||||||
Session::flash( 'error', 'You do not have permission to view this page.' );
|
|
||||||
return Redirect::home();
|
|
||||||
}
|
|
||||||
Template::noFollow();
|
Template::noFollow();
|
||||||
Template::noIndex();
|
Template::noIndex();
|
||||||
Template::addHeader( 'Content-Type: application/json; charset=utf-8' );
|
$res = $this->verifyApiRequest();
|
||||||
Template::setTemplate( 'api' );
|
if ( $secure && ! $this->canUseApi() ) {
|
||||||
|
exit( $res );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function canUseApi() {
|
||||||
|
return ( $this->canUseUserApi() || $this->canUseAppApi() || $this->canUseAuthApi() );
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function canUseUserApi() {
|
||||||
|
$apiEnabled = Config::getValue( 'api/apiAccessApp' );
|
||||||
|
if ( empty( $apiEnabled ) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return self::$canAccessUserApi;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function canUseAppApi() {
|
||||||
|
$apiEnabled = Config::getValue( 'api/apiAccessPersonal' );
|
||||||
|
if ( empty( $apiEnabled ) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return self::$canAccessApplicationApi;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function canUseAuthApi() {
|
||||||
|
return self::$canAccessAuthenticationApi;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function verifyApiRequest() {
|
||||||
|
$tokens = new Token;
|
||||||
|
$secret = null;
|
||||||
|
|
||||||
|
$bearer_token = $this->getBearerToken();
|
||||||
|
if ( ! empty( $bearer_token ) ) {
|
||||||
|
$token = $tokens->findByToken( $bearer_token );
|
||||||
|
} else {
|
||||||
|
$secret = $this->getSecretToken();
|
||||||
|
if ( empty( $secret ) ) {
|
||||||
|
return Views::simpleView( 'api.response', ['response' => json_encode( [ 'error' => 'invalid secret' ], true )]);
|
||||||
|
}
|
||||||
|
$token = $tokens->findBySecret( $secret );
|
||||||
|
}
|
||||||
|
if ( empty( $token ) ) {
|
||||||
|
return Views::simpleView( 'api.response', ['response' => json_encode( [ 'error' => 'invalid token' ], true )]);
|
||||||
|
}
|
||||||
|
self::$authToken = $token;
|
||||||
|
if ( $token->expiresAt <= time() && empty( $secret ) ) {
|
||||||
|
return Views::simpleView( 'api.response', ['response' => json_encode( [ 'error' => 'token expired' ], true )]);
|
||||||
|
}
|
||||||
|
if ( $token->expiresAt <= time() ) {
|
||||||
|
self::$canAccessAuthenticationApi = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ( $token->token_type == 'app' ) {
|
||||||
|
self::$canAccessApplicationApi = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ( $token->token_type == 'user' ) {
|
||||||
|
self::$canAccessUserApi = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSecretToken() {
|
||||||
|
$headers = $this->getAuthorizationHeader();
|
||||||
|
if ( ! empty( $headers ) ) {
|
||||||
|
if ( preg_match( '/Secret\s(\S+)/', $headers, $matches ) ) {
|
||||||
|
return $matches[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getBearerToken() {
|
||||||
|
$headers = $this->getAuthorizationHeader();
|
||||||
|
if ( ! empty( $headers ) ) {
|
||||||
|
if ( preg_match( '/Bearer\s(\S+)/', $headers, $matches ) ) {
|
||||||
|
return $matches[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAuthorizationHeader(){
|
||||||
|
$headers = null;
|
||||||
|
if ( isset( $_SERVER['Authorization'] ) ) {
|
||||||
|
$headers = trim( $_SERVER["Authorization"] );
|
||||||
|
} elseif ( isset( $_SERVER['HTTP_AUTHORIZATION'] ) ) {
|
||||||
|
$headers = trim( $_SERVER["HTTP_AUTHORIZATION"] );
|
||||||
|
} elseif ( function_exists( 'apache_request_headers' ) ) {
|
||||||
|
$requestHeaders = apache_request_headers();
|
||||||
|
$requestHeaders = array_combine(array_map('ucwords', array_keys($requestHeaders)), array_values($requestHeaders));
|
||||||
|
if ( isset( $requestHeaders['Authorization'] ) ) {
|
||||||
|
$headers = trim( $requestHeaders['Authorization'] );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $headers;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,18 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* classes/config.php
|
* app/classes/config.php
|
||||||
*
|
*
|
||||||
* This class handles all the hard-coded configurations.
|
* This class handles all the hard-coded configurations.
|
||||||
*
|
*
|
||||||
* @version 3.0
|
* @version 5.0.1
|
||||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||||
* @link https://TheTempusProject.com/Core
|
* @link https://TheTempusProject.com
|
||||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||||
*/
|
*/
|
||||||
namespace TheTempusProject\Classes;
|
namespace TheTempusProject\Classes;
|
||||||
|
|
||||||
use TheTempusProject\Houdini\Classes\Forms;
|
use TheTempusProject\Houdini\Classes\Forms;
|
||||||
|
use TheTempusProject\Houdini\Classes\Template;
|
||||||
use TheTempusProject\Canary\Bin\Canary as Debug;
|
use TheTempusProject\Canary\Bin\Canary as Debug;
|
||||||
use TheTempusProject\Bedrock\Functions\Check;
|
use TheTempusProject\Bedrock\Functions\Check;
|
||||||
use TheTempusProject\Bedrock\Functions\Input;
|
use TheTempusProject\Bedrock\Functions\Input;
|
||||||
@ -19,7 +20,6 @@ use TheTempusProject\Bedrock\Classes\Config as BedrockConfig;
|
|||||||
|
|
||||||
class Config extends BedrockConfig {
|
class Config extends BedrockConfig {
|
||||||
public static function getFieldEditHtml( $name, $includeProtected = false ) {
|
public static function getFieldEditHtml( $name, $includeProtected = false ) {
|
||||||
// @todo: includeProtected is unused here
|
|
||||||
$node = self::get( $name );
|
$node = self::get( $name );
|
||||||
if ( empty( $node ) ) {
|
if ( empty( $node ) ) {
|
||||||
return;
|
return;
|
||||||
@ -28,13 +28,64 @@ class Config extends BedrockConfig {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$fieldname = str_ireplace( '/', '-', $name );
|
$fieldname = str_ireplace( '/', '-', $name );
|
||||||
$html = Forms::getFormFieldHtml(
|
|
||||||
$fieldname,
|
$html = '';
|
||||||
$node['pretty'],
|
$fieldHtml = '';
|
||||||
$node['type'],
|
switch ( $node['type'] ) {
|
||||||
$node['value'],
|
case 'radio':
|
||||||
);
|
case 'bool':
|
||||||
return $html;
|
case 'boolean':
|
||||||
|
$fieldHtml = Forms::getSwitchHtml( $fieldname, $node['value'] );
|
||||||
|
break;
|
||||||
|
case 'select':
|
||||||
|
$fieldHtml = Forms::getSelectHtml( $fieldname, $options, $node['value'] );
|
||||||
|
break;
|
||||||
|
case 'block':
|
||||||
|
$fieldHtml = Forms::getTextBlockHtml( $fieldname, $node['value'] );
|
||||||
|
break;
|
||||||
|
case 'text':
|
||||||
|
case 'url':
|
||||||
|
$fieldHtml = Forms::getTextHtml( $fieldname, $node['value'] );
|
||||||
|
break;
|
||||||
|
case 'checkbox':
|
||||||
|
$fieldHtml = Forms::getCheckboxHtml( $fieldname, $node['value'] );
|
||||||
|
break;
|
||||||
|
case 'timezone':
|
||||||
|
$fieldHtml = Forms::getTimezoneHtml( $node['value'] );
|
||||||
|
break;
|
||||||
|
case 'file':
|
||||||
|
$fieldHtml = Forms::getFileHtml( $fieldname );
|
||||||
|
break;
|
||||||
|
case 'customSelect':
|
||||||
|
if ( empty( $options ) ) {
|
||||||
|
$options = '{' . $fieldname . '-options}';
|
||||||
|
}
|
||||||
|
$fieldHtml = Forms::getSelectHtml( $fieldname, $options, $node['value'] );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$html .= '<div class="mb-3 row">';
|
||||||
|
$html .= '<label for="' . $fieldname . '" class="col-lg-3 col-form-label text-end">' . $node['pretty'] . '</label>';
|
||||||
|
$html .= '<div class="col-lg-6">';
|
||||||
|
$html .= $fieldHtml;
|
||||||
|
$html .= '</div>';
|
||||||
|
$html .= '</div>';
|
||||||
|
if ( 'file' === $node['type'] ) {
|
||||||
|
$html .= '<div class="mb-3 row">';
|
||||||
|
$html .= '<h4 class="col-lg-3 col-form-label text-end">Current Value</h4>';
|
||||||
|
$html .= '<div class="col-lg-6">';
|
||||||
|
$html .= '<input type="text" class="form-control" name="'.$name.'Text" value="'.$node['value'] . '">';
|
||||||
|
$html .= '</div>';
|
||||||
|
$html .= '</div>';
|
||||||
|
$html .= '<div class="mb-3 row">';
|
||||||
|
$html .= '<h4 class="col-lg-3 col-form-label text-end">Current Image</h4>';
|
||||||
|
$html .= '<div class="col-lg-6 d-flex justify-content-center">';
|
||||||
|
$html .= '<img alt="configured image" src="{ROOT_URL}' . $node['value'] . '" class="img-circle img-fluid p-2 avatar-125">';
|
||||||
|
$html .= '</div>';
|
||||||
|
$html .= '</div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
return Template::parse( $html );
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getCategoryEditHtml( $category ) {
|
public static function getCategoryEditHtml( $category ) {
|
||||||
@ -47,12 +98,12 @@ class Config extends BedrockConfig {
|
|||||||
Debug::warn( "Config category not found: $category" );
|
Debug::warn( "Config category not found: $category" );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$categoryHeader = '<div class="form-group"><label>' . ucfirst( $category ) . ':</label><hr></div>';
|
$categoryHeader = '<div class=""><h3 class="text-center">' . ucfirst( $category ) . ':</h3><hr>';
|
||||||
foreach ( self::$config[$category] as $field => $node ) {
|
foreach ( self::$config[$category] as $field => $node ) {
|
||||||
$html .= self::getFieldEditHtml( $category . '/' . $field );
|
$html .= self::getFieldEditHtml( $category . '/' . $field );
|
||||||
}
|
}
|
||||||
if ( !empty( $html ) ) {
|
if ( !empty( $html ) ) {
|
||||||
$html = $categoryHeader . $html;
|
$html = $categoryHeader . $html . '</div>';
|
||||||
}
|
}
|
||||||
return $html;
|
return $html;
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
*
|
*
|
||||||
* This is the main controller class.
|
* This is the main controller class.
|
||||||
*
|
*
|
||||||
* @version 3.0
|
* @version 5.0.1
|
||||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||||
* @link https://TheTempusProject.com
|
* @link https://TheTempusProject.com
|
||||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||||
@ -35,7 +35,6 @@ class Controller extends BedrockController {
|
|||||||
}
|
}
|
||||||
new Template;
|
new Template;
|
||||||
Template::setTemplate( 'default' );
|
Template::setTemplate( 'default' );
|
||||||
Components::set( 'TOKEN', Token::generate() );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function __destruct() {
|
public function __destruct() {
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
*
|
*
|
||||||
* This is the main TempusProject database model.
|
* This is the main TempusProject database model.
|
||||||
*
|
*
|
||||||
* @version 3.0
|
* @version 5.0.1
|
||||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||||
* @link https://TheTempusProject.com
|
* @link https://TheTempusProject.com
|
||||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||||
@ -121,7 +121,6 @@ class DatabaseModel extends BedrockDatabaseModel {
|
|||||||
$errors = [];
|
$errors = [];
|
||||||
foreach ( self::$installFlags as $flag_name ) {
|
foreach ( self::$installFlags as $flag_name ) {
|
||||||
if ( empty( $options[$flag_name] ) ) {
|
if ( empty( $options[$flag_name] ) ) {
|
||||||
$module_data[ $flag_name ] = INSTALL_STATUS_SKIPPED;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
*
|
*
|
||||||
* This is our class for constructing and sending various kinds of emails.
|
* This is our class for constructing and sending various kinds of emails.
|
||||||
*
|
*
|
||||||
* @version 3.0
|
* @version 5.0.1
|
||||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||||
* @link https://TheTempusProject.com
|
* @link https://TheTempusProject.com
|
||||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* error reporting to easily define exactly what feedback you
|
* error reporting to easily define exactly what feedback you
|
||||||
* would like to give.
|
* would like to give.
|
||||||
*
|
*
|
||||||
* @version 3.0
|
* @version 5.0.1
|
||||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||||
* @link https://TheTempusProject.com
|
* @link https://TheTempusProject.com
|
||||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||||
@ -112,6 +112,11 @@ class Forms extends Check {
|
|||||||
self::addHandler( 'newGroup', __CLASS__, 'newGroup' );
|
self::addHandler( 'newGroup', __CLASS__, 'newGroup' );
|
||||||
self::addHandler( 'editGroup', __CLASS__, 'editGroup' );
|
self::addHandler( 'editGroup', __CLASS__, 'editGroup' );
|
||||||
self::addHandler( 'install', __CLASS__, 'install' );
|
self::addHandler( 'install', __CLASS__, 'install' );
|
||||||
|
self::addHandler( 'adminCreateToken', __CLASS__, 'adminCreateToken' );
|
||||||
|
self::addHandler( 'apiLogin', __CLASS__, 'apiLogin' );
|
||||||
|
self::addHandler( 'updatePreference', __CLASS__, 'updatePreference' );
|
||||||
|
self::addHandler( 'renameIImage', __CLASS__, 'renameIImage' );
|
||||||
|
self::addHandler( 'addImage', __CLASS__, 'addImage' );
|
||||||
self::addHandler( 'installStart', __CLASS__, 'install', [ 'start' ] );
|
self::addHandler( 'installStart', __CLASS__, 'install', [ 'start' ] );
|
||||||
self::addHandler( 'installAgreement', __CLASS__, 'install', [ 'agreement' ] );
|
self::addHandler( 'installAgreement', __CLASS__, 'install', [ 'agreement' ] );
|
||||||
self::addHandler( 'installCheck', __CLASS__, 'install', [ 'check' ] );
|
self::addHandler( 'installCheck', __CLASS__, 'install', [ 'check' ] );
|
||||||
@ -212,6 +217,10 @@ class Forms extends Check {
|
|||||||
* @return {bool}
|
* @return {bool}
|
||||||
*/
|
*/
|
||||||
public static function passwordResetCode() {
|
public static function passwordResetCode() {
|
||||||
|
if ( !Input::exists( 'resetCode' ) ) {
|
||||||
|
self::addUserError( 'Invalid resetCode.' );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if ( !self::token() ) {
|
if ( !self::token() ) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -608,4 +617,76 @@ class Forms extends Check {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function adminCreateToken() {
|
||||||
|
if ( !Input::exists( 'name' ) ) {
|
||||||
|
self::addUserError( 'You must specify a name' );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ( !Input::exists( 'token_type' ) ) {
|
||||||
|
self::addUserError( 'You must specify a token_type' );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function adminEditToken() {
|
||||||
|
if ( !Input::exists( 'name' ) ) {
|
||||||
|
self::addUserError( 'You must specify a name' );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ( !Input::exists( 'token_type' ) ) {
|
||||||
|
self::addUserError( 'You must specify a token_type' );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function apiLogin() {
|
||||||
|
if ( !self::checkUsername( Input::post( 'username' ) ) ) {
|
||||||
|
self::addUserError( 'Invalid username.' );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ( !self::password( Input::post( 'password' ) ) ) {
|
||||||
|
self::addUserError( 'Invalid password.' );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function updatePreference() {
|
||||||
|
if ( !Input::exists( 'prefName' ) ) {
|
||||||
|
self::addUserError( 'You must specify a name' );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ( !Input::exists( 'prefValue' ) ) {
|
||||||
|
self::addUserError( 'You must specify a value' );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function renameIImage() {
|
||||||
|
if ( !Input::exists( 'filelocation' ) ) {
|
||||||
|
self::addUserError( 'You must specify a location' );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ( !Input::exists( 'newname' ) ) {
|
||||||
|
self::addUserError( 'You must specify a new name' );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function addImage() {
|
||||||
|
if ( !Input::exists( 'folderSelect' ) ) {
|
||||||
|
self::addUserError( 'You must specify a location' );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ( !Input::exists( 'uploadImage' ) ) {
|
||||||
|
self::addUserError( 'You must include a file.' );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
* the application. It handles installing the application, installing and updating
|
* the application. It handles installing the application, installing and updating
|
||||||
* models as well as the database, and generating and checking the htaccess file.
|
* models as well as the database, and generating and checking the htaccess file.
|
||||||
*
|
*
|
||||||
* @version 3.0
|
* @version 5.0.1
|
||||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||||
* @link https://TheTempusProject.com
|
* @link https://TheTempusProject.com
|
||||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||||
@ -158,6 +158,10 @@ class Installer {
|
|||||||
} else {
|
} else {
|
||||||
self::$installJson['modules'][$name]['enabled_txt'] = '<span class="text-danger">No</span>';
|
self::$installJson['modules'][$name]['enabled_txt'] = '<span class="text-danger">No</span>';
|
||||||
}
|
}
|
||||||
|
// in this case only, we save an array to remove the objects later, so an array stored is a success.
|
||||||
|
if ( ! empty( self::$installJson['modules'][$name]['resources_installed'] ) && is_array( self::$installJson['modules'][$name]['resources_installed'] ) ) {
|
||||||
|
self::$installJson['modules'][$name]['resources_installed'] = INSTALL_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return self::$installJson['modules'][$name];
|
return self::$installJson['modules'][$name];
|
||||||
}
|
}
|
||||||
@ -422,7 +426,7 @@ class Installer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// exclude any flags that have already been successfully installed
|
// exclude any flags that have already been successfully installed
|
||||||
if ( !empty( $module_data->$flag_type ) && $module_data->$flag_type == INSTALL_STATUS_SUCCESS ) {
|
if ( ! empty( $module_data->$flag_type ) && $module_data->$flag_type == INSTALL_STATUS_SUCCESS ) {
|
||||||
Debug::warn( "$flag_type has already been successfully installed" );
|
Debug::warn( "$flag_type has already been successfully installed" );
|
||||||
$flags[ $flag_type ] = false;
|
$flags[ $flag_type ] = false;
|
||||||
}
|
}
|
||||||
@ -530,7 +534,7 @@ class Installer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
foreach ( $flags as $flag_type ) {
|
foreach ( $flags as $flag_type ) {
|
||||||
if ( ! in_array( $modelInfo[ $flag_type ], [ INSTALL_STATUS_SUCCESS, INSTALL_STATUS_NOT_REQUIRED ] ) ) {
|
if ( empty( $modelInfo[ $flag_type ] ) || ! in_array( $modelInfo[ $flag_type ], [ INSTALL_STATUS_SUCCESS, INSTALL_STATUS_NOT_REQUIRED ] ) ) {
|
||||||
$modelInfo['installStatus'] = INSTALL_STATUS_PARTIALLY_INSTALLED;
|
$modelInfo['installStatus'] = INSTALL_STATUS_PARTIALLY_INSTALLED;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
*
|
*
|
||||||
* This class handles all the hard-coded permissions.
|
* This class handles all the hard-coded permissions.
|
||||||
*
|
*
|
||||||
* @version 3.0
|
* @version 5.0.1
|
||||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||||
* @link https://TheTempusProject.com
|
* @link https://TheTempusProject.com
|
||||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||||
@ -15,6 +15,7 @@ use TheTempusProject\Canary\Bin\Canary as Debug;
|
|||||||
use TheTempusProject\Bedrock\Functions\Check;
|
use TheTempusProject\Bedrock\Functions\Check;
|
||||||
use TheTempusProject\Houdini\Classes\Forms;
|
use TheTempusProject\Houdini\Classes\Forms;
|
||||||
use TheTempusProject\Bedrock\Functions\Input;
|
use TheTempusProject\Bedrock\Functions\Input;
|
||||||
|
use TheTempusProject\Houdini\Classes\Template;
|
||||||
|
|
||||||
class Permissions {
|
class Permissions {
|
||||||
public static $permissions = false;
|
public static $permissions = false;
|
||||||
@ -237,8 +238,21 @@ class Permissions {
|
|||||||
} else {
|
} else {
|
||||||
$checked = false;
|
$checked = false;
|
||||||
}
|
}
|
||||||
$form .= Forms::getFormFieldHtml( $name, $details['pretty'], 'checkbox', $checked );
|
$form .= self::getFieldEditHtml( $name, $checked, $details['pretty'] );
|
||||||
}
|
}
|
||||||
return $form;
|
return $form;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function getFieldEditHtml( $name, $default, $pretty ) {
|
||||||
|
$fieldname = str_ireplace( '/', '-', $name );
|
||||||
|
$fieldHtml = Forms::getSwitchHtml( $fieldname, $default );
|
||||||
|
$html = '';
|
||||||
|
$html .= '<div class="mb-3 row">';
|
||||||
|
$html .= '<label for="' . $fieldname . '" class="col-lg-6 col-form-label text-end">' . $pretty . '</label>';
|
||||||
|
$html .= '<div class="col-lg-6">';
|
||||||
|
$html .= $fieldHtml;
|
||||||
|
$html .= '</div>';
|
||||||
|
$html .= '</div>';
|
||||||
|
return Template::parse( $html );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
*
|
*
|
||||||
* This class is used as a foundation for all plugins to build from.
|
* This class is used as a foundation for all plugins to build from.
|
||||||
*
|
*
|
||||||
* @version 3.0
|
* @version 5.0.1
|
||||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||||
* @link https://TheTempusProject.com
|
* @link https://TheTempusProject.com
|
||||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||||
@ -89,7 +89,7 @@ class Plugin {
|
|||||||
|
|
||||||
foreach ( self::PLUGIN_FLAG_MAP as $flag_name => $function_name ) {
|
foreach ( self::PLUGIN_FLAG_MAP as $flag_name => $function_name ) {
|
||||||
if ( empty( $options[$flag_name] ) ) {
|
if ( empty( $options[$flag_name] ) ) {
|
||||||
$module_data[ $flag_name ] = INSTALL_STATUS_SKIPPED;
|
// $module_data[ $flag_name ] = INSTALL_STATUS_SKIPPED;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -280,7 +280,7 @@ class Plugin {
|
|||||||
public function installResources( $options = '' ) {
|
public function installResources( $options = '' ) {
|
||||||
if ( empty( $this->resourceMatrix ) ) {
|
if ( empty( $this->resourceMatrix ) ) {
|
||||||
Debug::log( 'resourceMatrix is empty' );
|
Debug::log( 'resourceMatrix is empty' );
|
||||||
return true;
|
return INSTALL_STATUS_NOT_REQUIRED;
|
||||||
}
|
}
|
||||||
$ids = [];
|
$ids = [];
|
||||||
foreach( $this->resourceMatrix as $tableName => $entries ) {
|
foreach( $this->resourceMatrix as $tableName => $entries ) {
|
||||||
@ -309,7 +309,7 @@ class Plugin {
|
|||||||
$data = [];
|
$data = [];
|
||||||
foreach( $this->resourceMatrix as $tableName => $entries ) {
|
foreach( $this->resourceMatrix as $tableName => $entries ) {
|
||||||
foreach ($ids as $id) {
|
foreach ($ids as $id) {
|
||||||
$data[] = self::$db->delete( $tableName, $id );
|
$data[] = self::$db->delete( $tableName, [ 'ID', '=', $id ] );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return $data;
|
return $data;
|
||||||
@ -335,9 +335,14 @@ class Plugin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function loadFooterNav() {
|
public function loadFooterNav() {
|
||||||
if ( !empty( $this->footer_links ) ) {
|
if ( !empty( $this->contact_footer_links ) ) {
|
||||||
foreach( $this->footer_links as $key => $link ) {
|
foreach( $this->contact_footer_links as $key => $link ) {
|
||||||
Navigation::addLink( App::FOOTER_MENU_NAME, $link );
|
Navigation::addLink( App::CONTACT_FOOTER_MENU_NAME, $link );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( !empty( $this->info_footer_links ) ) {
|
||||||
|
foreach( $this->info_footer_links as $key => $link ) {
|
||||||
|
Navigation::addLink( App::INFO_FOOTER_MENU_NAME, $link );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
*
|
*
|
||||||
* This class handles all the hard-coded preferences.
|
* This class handles all the hard-coded preferences.
|
||||||
*
|
*
|
||||||
* @version 3.0
|
* @version 5.0.1
|
||||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||||
* @link https://TheTempusProject.com
|
* @link https://TheTempusProject.com
|
||||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||||
@ -13,11 +13,13 @@ namespace TheTempusProject\Classes;
|
|||||||
|
|
||||||
use TheTempusProject\Houdini\Classes\Issues;
|
use TheTempusProject\Houdini\Classes\Issues;
|
||||||
use TheTempusProject\Houdini\Classes\Forms;
|
use TheTempusProject\Houdini\Classes\Forms;
|
||||||
|
use TheTempusProject\Houdini\Classes\Template;
|
||||||
use TheTempusProject\Canary\Bin\Canary as Debug;
|
use TheTempusProject\Canary\Bin\Canary as Debug;
|
||||||
use TheTempusProject\Bedrock\Functions\Check;
|
use TheTempusProject\Bedrock\Functions\Check;
|
||||||
use TheTempusProject\Bedrock\Functions\Upload;
|
use TheTempusProject\Bedrock\Functions\Upload;
|
||||||
use TheTempusProject\Bedrock\Functions\Input;
|
use TheTempusProject\Bedrock\Functions\Input;
|
||||||
use TheTempusProject\TheTempusProject as App;
|
use TheTempusProject\TheTempusProject as App;
|
||||||
|
use TheTempusProject\Bedrock\Classes\Config;
|
||||||
|
|
||||||
class Preferences {
|
class Preferences {
|
||||||
public static $preferences = false;
|
public static $preferences = false;
|
||||||
@ -186,17 +188,101 @@ class Preferences {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function getFormHtml( $populated = [] ) {
|
public function getFormHtml( $populated = [] ) {
|
||||||
|
// dv( self::$preferences );
|
||||||
$form = '';
|
$form = '';
|
||||||
|
// Added so i can force some sort of ordering
|
||||||
|
$inputTypes = [
|
||||||
|
'file' => [],
|
||||||
|
'select' => [],
|
||||||
|
'timezone' => [],
|
||||||
|
'checkbox' => [],
|
||||||
|
'switch' => [],
|
||||||
|
];
|
||||||
foreach ( self::$preferences as $name => $details ) {
|
foreach ( self::$preferences as $name => $details ) {
|
||||||
$tempPrefsArray = $this->normalizePreferenceArray( $name, $details );
|
$tempPrefsArray = $this->normalizePreferenceArray( $name, $details );
|
||||||
if ( isset( $populated[ $name ] ) ) {
|
if ( isset( $populated[ $name ] ) ) {
|
||||||
$tempPrefsArray['default'] = $populated[$name];
|
$tempPrefsArray['value'] = $populated[$name];
|
||||||
|
} else {
|
||||||
|
$tempPrefsArray['value'] = $tempPrefsArray['default'];
|
||||||
}
|
}
|
||||||
$form .= Forms::getFormFieldHtml( $name, $tempPrefsArray['pretty'], $tempPrefsArray['type'], $tempPrefsArray['default'], $tempPrefsArray['options'] );
|
// $form .= Forms::getFormFieldHtml( $name, $tempPrefsArray['pretty'], $tempPrefsArray['type'], $tempPrefsArray['default'], $tempPrefsArray['options'] );
|
||||||
|
if ( $tempPrefsArray['type'] == 'checkbox' ) {
|
||||||
|
$tempPrefsArray['type'] = 'switch';
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( 'file' === $tempPrefsArray['type'] ) {
|
||||||
|
// dv( Config::getValue( 'uploads/images' ) );
|
||||||
|
if ( ! Config::getValue( 'uploads/images' ) ) {
|
||||||
|
Debug::info( 'Preference hidden because uploads are disabled.' );
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$inputTypes[ $tempPrefsArray['type'] ][] = self::getFormFieldHtml( $name, $tempPrefsArray['pretty'], $tempPrefsArray['type'], $tempPrefsArray['value'], $tempPrefsArray['options'] );
|
||||||
|
}
|
||||||
|
foreach ( $inputTypes as $skip => $items ) {
|
||||||
|
$form .= implode( ' ', $items );
|
||||||
}
|
}
|
||||||
return $form;
|
return $form;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function getFormFieldHtml( $fieldname, $fieldTitle, $type, $defaultValue = '', $options = null ) {
|
||||||
|
$html = '';
|
||||||
|
switch ( $type ) {
|
||||||
|
case 'radio':
|
||||||
|
case 'bool':
|
||||||
|
case 'boolean':
|
||||||
|
$fieldHtml = Forms::getRadioHtml( $fieldname, [ 'true', 'false' ], $defaultValue );
|
||||||
|
break;
|
||||||
|
case 'select':
|
||||||
|
$fieldHtml = Forms::getSelectHtml( $fieldname, $options, $defaultValue );
|
||||||
|
break;
|
||||||
|
case 'customSelect':
|
||||||
|
if ( empty( $options ) ) {
|
||||||
|
$options = '{' . $fieldname . '-options}';
|
||||||
|
}
|
||||||
|
$fieldHtml = Forms::getSelectHtml( $fieldname, $options, $defaultValue );
|
||||||
|
break;
|
||||||
|
case 'block':
|
||||||
|
$fieldHtml = Forms::getTextBlockHtml( $fieldname, $defaultValue );
|
||||||
|
break;
|
||||||
|
case 'text':
|
||||||
|
case 'url':
|
||||||
|
$fieldHtml = Forms::getTextHtml( $fieldname, $defaultValue );
|
||||||
|
break;
|
||||||
|
case 'checkbox':
|
||||||
|
$fieldHtml = Forms::getCheckboxHtml( $fieldname, $defaultValue );
|
||||||
|
break;
|
||||||
|
case 'switch':
|
||||||
|
$fieldHtml = Forms::getSwitchHtml( $fieldname, $defaultValue );
|
||||||
|
break;
|
||||||
|
case 'timezone':
|
||||||
|
$fieldHtml = Forms::getTimezoneHtml( $defaultValue );
|
||||||
|
break;
|
||||||
|
case 'file':
|
||||||
|
$fieldHtml = Forms::getFileHtml( $fieldname );
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Debug::error( "unknown field type: $type" );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$html .= '<div class="mb-3 row">';
|
||||||
|
$html .= '<label for="' . $fieldname . '" class="col-lg-6 col-form-label text-start text-lg-end">' . $fieldTitle . '</label>';
|
||||||
|
$html .= '<div class="col-lg-6">';
|
||||||
|
$html .= $fieldHtml;
|
||||||
|
$html .= '</div>';
|
||||||
|
if ( 'file' === $type ) {
|
||||||
|
$html .= '<div class="mb-3 row">';
|
||||||
|
$html .= '<h4 class="col-lg-6 col-form-label text-start text-lg-end">Current Image</h4>';
|
||||||
|
$html .= '<div class="col-lg-6">';
|
||||||
|
$html .= '<img alt="preferred image" src="{ROOT_URL}' . $defaultValue . '" class="img-circle img-fluid p-2">';
|
||||||
|
$html .= '</div>';
|
||||||
|
}
|
||||||
|
$html .= '</div>';
|
||||||
|
return Template::parse( $html );
|
||||||
|
}
|
||||||
|
|
||||||
public function convertFormToArray( $fillMissing = true, $defaultsOnly = true ) {
|
public function convertFormToArray( $fillMissing = true, $defaultsOnly = true ) {
|
||||||
$prefsArray = [];
|
$prefsArray = [];
|
||||||
foreach ( self::$preferences as $name => $details ) {
|
foreach ( self::$preferences as $name => $details ) {
|
||||||
@ -212,12 +298,14 @@ class Preferences {
|
|||||||
}
|
}
|
||||||
if ( 'file' == $details['type'] ) {
|
if ( 'file' == $details['type'] ) {
|
||||||
if ( Input::exists( $name ) ) {
|
if ( Input::exists( $name ) ) {
|
||||||
$folder = IMAGE_UPLOAD_DIRECTORY . App::$activeUser->username . DIRECTORY_SEPARATOR;
|
$folder = UPLOAD_DIRECTORY . App::$activeUser->username . DIRECTORY_SEPARATOR . 'images' . DIRECTORY_SEPARATOR;
|
||||||
if ( !Upload::image( $name, $folder ) ) {
|
$upload = Upload::image( $name, $folder );
|
||||||
Issues::add( 'error', [ 'There was an error with your upload.' => Check::systemErrors() ] );
|
if ( $upload ) {
|
||||||
} else {
|
|
||||||
$route = str_replace( APP_ROOT_DIRECTORY, '', $folder );
|
$route = str_replace( APP_ROOT_DIRECTORY, '', $folder );
|
||||||
$prefsArray[$name] = $route . Upload::last();
|
$prefsArray[$name] = $route . Upload::last();
|
||||||
|
} else {
|
||||||
|
Issues::add( 'error', [ 'There was an error with your upload.' => Check::userErrors() ] );
|
||||||
|
unset( $prefsArray[$name] );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -38,6 +38,8 @@ if ( ! defined( 'CONFIG_DIRECTORY' ) ) {
|
|||||||
# Tempus Debugger
|
# Tempus Debugger
|
||||||
define( 'CANARY_SECURE_HASH', 'd73ed7591a30f0ca7d686a0e780f0d05' );
|
define( 'CANARY_SECURE_HASH', 'd73ed7591a30f0ca7d686a0e780f0d05' );
|
||||||
# Tempus Project Core
|
# Tempus Project Core
|
||||||
|
define( 'APP_NAME', 'The Tempus Project');
|
||||||
|
define( 'TP_DEFAULT_LOGO', 'images/logoWhite.png');
|
||||||
// Check
|
// Check
|
||||||
define( 'MINIMUM_PHP_VERSION', 8.1);
|
define( 'MINIMUM_PHP_VERSION', 8.1);
|
||||||
// Cookies
|
// Cookies
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
*
|
*
|
||||||
* This is the admin log controller.
|
* This is the admin log controller.
|
||||||
*
|
*
|
||||||
* @version 3.0
|
* @version 5.0.1
|
||||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||||
* @link https://TheTempusProject.com
|
* @link https://TheTempusProject.com
|
||||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||||
@ -39,7 +39,7 @@ class Admin extends AdminController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function index() {
|
public function index() {
|
||||||
return Views::view( 'admin.logs.admin_list', self::$log->listPaginated( 'admin' ) );
|
return Views::view( 'admin.logs.admin_list', self::$log->list( 'admin' ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
public function view( $id = null ) {
|
public function view( $id = null ) {
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
*
|
*
|
||||||
* This is the composer controller. Its only very effective when using composer for autoloading.
|
* This is the composer controller. Its only very effective when using composer for autoloading.
|
||||||
*
|
*
|
||||||
* @version 3.0
|
* @version 5.0.1
|
||||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||||
* @link https://TheTempusProject.com
|
* @link https://TheTempusProject.com
|
||||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||||
@ -59,6 +59,6 @@ class Composer extends AdminController {
|
|||||||
$out[] = (object) $versionsInstalled[ $name ];
|
$out[] = (object) $versionsInstalled[ $name ];
|
||||||
}
|
}
|
||||||
|
|
||||||
Views::view( 'admin.modules.composer.dependencies', $out );
|
Views::view( 'admin.modules.dependencies', $out );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
*
|
*
|
||||||
* This is the error logs controller.
|
* This is the error logs controller.
|
||||||
*
|
*
|
||||||
* @version 3.0
|
* @version 5.0.1
|
||||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||||
* @link https://TheTempusProject.com
|
* @link https://TheTempusProject.com
|
||||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||||
@ -39,7 +39,7 @@ class Errors extends AdminController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function index() {
|
public function index() {
|
||||||
return Views::view( 'admin.logs.error_list', self::$log->listPaginated( 'error' ) );
|
return Views::view( 'admin.logs.error_list', self::$log->list( 'error' ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
public function view( $id = null ) {
|
public function view( $id = null ) {
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
*
|
*
|
||||||
* This is the groups admin controller.
|
* This is the groups admin controller.
|
||||||
*
|
*
|
||||||
* @version 3.0
|
* @version 5.0.1
|
||||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||||
* @link https://TheTempusProject.com
|
* @link https://TheTempusProject.com
|
||||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||||
@ -32,8 +32,6 @@ class Groups extends AdminController {
|
|||||||
self::$title = 'Admin - Groups';
|
self::$title = 'Admin - Groups';
|
||||||
self::$group = new Group;
|
self::$group = new Group;
|
||||||
self::$permissions = new Permissions;
|
self::$permissions = new Permissions;
|
||||||
$view = Navigation::activePageSelect( 'nav.admin', '/admin/groups' );
|
|
||||||
Components::set( 'ADMINNAV', $view );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function create( $data = null ) {
|
public function create( $data = null ) {
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
*
|
*
|
||||||
* This is the admin dashboard controller.
|
* This is the admin dashboard controller.
|
||||||
*
|
*
|
||||||
* @version 3.0
|
* @version 5.0.1
|
||||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||||
* @link https://TheTempusProject.com
|
* @link https://TheTempusProject.com
|
||||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||||
@ -15,8 +15,14 @@ use TheTempusProject\Houdini\Classes\Views;
|
|||||||
use TheTempusProject\Houdini\Classes\Components;
|
use TheTempusProject\Houdini\Classes\Components;
|
||||||
use TheTempusProject\Classes\AdminController;
|
use TheTempusProject\Classes\AdminController;
|
||||||
use TheTempusProject\Models\User;
|
use TheTempusProject\Models\User;
|
||||||
use TheTempusProject\Plugins\Comments;
|
use TheTempusProject\Models\Comments;
|
||||||
use TheTempusProject\Plugins\Blog;
|
use TheTempusProject\Models\Posts;
|
||||||
|
use TheTempusProject\Models\Contact;
|
||||||
|
use TheTempusProject\Plugins\Comments as CommentPlugin;
|
||||||
|
use TheTempusProject\Plugins\Blog as BlogPlugin;
|
||||||
|
use TheTempusProject\Plugins\Contact as ContactPlugin;
|
||||||
|
use TheTempusProject\Canary\Bin\Canary as Debug;
|
||||||
|
use TheTempusProject\Bedrock\Functions\Input;
|
||||||
|
|
||||||
class Home extends AdminController {
|
class Home extends AdminController {
|
||||||
public static $user;
|
public static $user;
|
||||||
@ -29,18 +35,43 @@ class Home extends AdminController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function index() {
|
public function index() {
|
||||||
|
Components::set( 'commentDash', '' );
|
||||||
if ( class_exists( 'TheTempusProject\Plugins\Comments' ) ) {
|
if ( class_exists( 'TheTempusProject\Plugins\Comments' ) ) {
|
||||||
|
$plugin = new CommentPlugin;
|
||||||
|
|
||||||
|
if ( ! $plugin->checkEnabled() ) {
|
||||||
|
Debug::info( 'Comments Plugin is disabled in the control panel.' );
|
||||||
|
} else {
|
||||||
$comments = new Comments;
|
$comments = new Comments;
|
||||||
self::$comments = $comments->getModel();
|
$commentList = Views::simpleView( 'comments.admin.dashboard', $comments->recent( 'all', 5 ) );
|
||||||
$comments = Views::simpleView( 'comments.admin.dashboard', self::$comments->recent( 'all', 5 ) );
|
Components::set( 'commentDash', $commentList );
|
||||||
Components::set( 'commentDash', $comments );
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( class_exists( 'TheTempusProject\Plugins\Blog' ) ) {
|
if ( class_exists( 'TheTempusProject\Plugins\Blog' ) ) {
|
||||||
$blog = new Blog;
|
$plugin = new BlogPlugin;
|
||||||
self::$posts = $blog->posts;
|
|
||||||
$posts = Views::simpleView( 'blog.admin.dashboard', self::$posts->recent( 5 ) );
|
if ( ! $plugin->checkEnabled() ) {
|
||||||
Components::set( 'blogDash', $posts );
|
Debug::info( 'Blog Plugin is disabled in the control panel.' );
|
||||||
|
Components::set( 'blogDash', '' );
|
||||||
|
} else {
|
||||||
|
$posts = new Posts;
|
||||||
|
$postsList = Views::simpleView( 'blog.admin.dashboard', $posts->recent( 5 ) );
|
||||||
|
Components::set( 'blogDash', $postsList );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( class_exists( 'TheTempusProject\Plugins\Contact' ) ) {
|
||||||
|
$plugin = new ContactPlugin;
|
||||||
|
|
||||||
|
if ( ! $plugin->checkEnabled() ) {
|
||||||
|
Debug::info( 'Contact Plugin is disabled in the control panel.' );
|
||||||
|
Components::set( 'contactDash', '' );
|
||||||
|
} else {
|
||||||
|
$posts = new Contact;
|
||||||
|
$postsList = Views::simpleView( 'contact.admin.dashboard', $posts->listPaginated( 5 ) );
|
||||||
|
Components::set( 'contactDash', $postsList );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self::$user = new User;
|
self::$user = new User;
|
||||||
|
337
app/controllers/admin/images.php
Normal file
337
app/controllers/admin/images.php
Normal file
@ -0,0 +1,337 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* app/controllers/admin/tokens.php
|
||||||
|
*
|
||||||
|
* This is the admin app/user tokens controller.
|
||||||
|
*
|
||||||
|
* @version 5.0.1
|
||||||
|
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||||
|
* @link https://TheTempusProject.com
|
||||||
|
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||||
|
*/
|
||||||
|
namespace TheTempusProject\Controllers\Admin;
|
||||||
|
|
||||||
|
use TheTempusProject\Classes\Forms as TTPForms;
|
||||||
|
use TheTempusProject\Houdini\Classes\Views;
|
||||||
|
use TheTempusProject\Houdini\Classes\Issues;
|
||||||
|
use TheTempusProject\Houdini\Classes\Navigation;
|
||||||
|
use TheTempusProject\Houdini\Classes\Components;
|
||||||
|
use TheTempusProject\Houdini\Classes\Forms;
|
||||||
|
use TheTempusProject\Classes\AdminController;
|
||||||
|
use TheTempusProject\Models\Token;
|
||||||
|
use TheTempusProject\Bedrock\Functions\Input;
|
||||||
|
use TheTempusProject\Bedrock\Functions\Check;
|
||||||
|
use TheTempusProject\Hermes\Functions\Redirect;
|
||||||
|
use TheTempusProject\Bedrock\Functions\Session;
|
||||||
|
use TheTempusProject\Hermes\Functions\Route as Routes;
|
||||||
|
use TheTempusProject\Bedrock\Functions\Upload;
|
||||||
|
use RecursiveIteratorIterator;
|
||||||
|
use RecursiveDirectoryIterator;
|
||||||
|
use FilesystemIterator;
|
||||||
|
|
||||||
|
class Images extends AdminController {
|
||||||
|
private $directories = [
|
||||||
|
APP_ROOT_DIRECTORY . 'images',
|
||||||
|
APP_ROOT_DIRECTORY . 'app/images',
|
||||||
|
APP_ROOT_DIRECTORY . 'app/plugins'
|
||||||
|
];
|
||||||
|
|
||||||
|
private $spacer = [];
|
||||||
|
|
||||||
|
private $excludedDirectories = [
|
||||||
|
'.',
|
||||||
|
'..',
|
||||||
|
'vendor',
|
||||||
|
'docker',
|
||||||
|
'logs',
|
||||||
|
'gitlab',
|
||||||
|
'uploads',
|
||||||
|
'config',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function upload() {
|
||||||
|
if ( Input::exists( 'submit' ) ) {
|
||||||
|
$route = '';
|
||||||
|
$destination = '';
|
||||||
|
if ( !TTPForms::check( 'addImage' ) ) {
|
||||||
|
Issues::add( 'error', [ 'There was an error with your image upload.' => Check::userErrors() ] );
|
||||||
|
} else {
|
||||||
|
$folder = Input::post( 'folderSelect' ) . DIRECTORY_SEPARATOR;
|
||||||
|
// dv( $folder );
|
||||||
|
$upload = Upload::image( 'uploadImage', $folder );
|
||||||
|
if ( $upload ) {
|
||||||
|
$route = str_replace( APP_ROOT_DIRECTORY, '', $folder );
|
||||||
|
$destination = $route . Upload::last();
|
||||||
|
Issues::add( 'success', 'Image uploaded.' );
|
||||||
|
} else {
|
||||||
|
Issues::add( 'error', [ 'There was an error with your image upload.' => Check::userErrors() ] );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$folders = $this->getDirectoriesRecursive( APP_ROOT_DIRECTORY );
|
||||||
|
$folderHtml = $this->generateFolderHtml( $folders );
|
||||||
|
Components::set( 'FOLDER_SELECT_ROOT', APP_ROOT_DIRECTORY );
|
||||||
|
Components::set( 'FOLDER_SELECT', Views::simpleView( 'forms.folderSelect', $folderHtml ) );
|
||||||
|
Views::view( 'admin.images.upload' );
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getFolderObject( $folder, $subdirs = '' ) {
|
||||||
|
$names = explode( DIRECTORY_SEPARATOR, $folder );
|
||||||
|
$folderName = array_pop( $names );
|
||||||
|
$out = [
|
||||||
|
'spacer' => implode( '', $this->spacer ),
|
||||||
|
'folderName' => $folderName,
|
||||||
|
'location' => $folder,
|
||||||
|
'subdirs' => $subdirs,
|
||||||
|
];
|
||||||
|
if ( ! empty( $subdirs ) ) {
|
||||||
|
$out['folderexpand'] = '<i class="fa fa-caret-down"></i>';
|
||||||
|
} else {
|
||||||
|
$out['folderexpand'] = '';
|
||||||
|
}
|
||||||
|
return (object) $out;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function generateFolderHtml( $folders ) {
|
||||||
|
$rows = [];
|
||||||
|
foreach ( $folders as $top => $sub ) {
|
||||||
|
$object = $this->getFolderObject( $top );
|
||||||
|
if ( $top == $sub ) {
|
||||||
|
$html = '';
|
||||||
|
} else {
|
||||||
|
$this->spacer[] = '-> ';
|
||||||
|
$children = $this->generateFolderHtml( $sub );
|
||||||
|
array_pop( $this->spacer );
|
||||||
|
Components::set( 'parentfolderName', $object->folderName );
|
||||||
|
$html = Views::simpleView( 'forms.folderSelectParent', $children );
|
||||||
|
Components::set( 'parentfolderName', '' );
|
||||||
|
}
|
||||||
|
$rows[] = $this->getFolderObject( $top, $html );
|
||||||
|
}
|
||||||
|
return $rows;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getDirectoriesRecursive( $directory ) {
|
||||||
|
$dirs = [];
|
||||||
|
|
||||||
|
$directory = rtrim( $directory, DIRECTORY_SEPARATOR );
|
||||||
|
$directory = $directory. DIRECTORY_SEPARATOR;
|
||||||
|
|
||||||
|
$files = scandir( $directory );
|
||||||
|
$filteredFiles = array_values( array_diff( $files, $this->excludedDirectories ) );
|
||||||
|
|
||||||
|
foreach ( $filteredFiles as $key => $filename ) {
|
||||||
|
$long_name = $directory . $filename;
|
||||||
|
$is_dir = ( ( strpos( $filename, '.' ) === false ) && ( is_dir( $long_name ) === true ) );
|
||||||
|
if ( $is_dir ) {
|
||||||
|
$recursive_dirs = $this->getDirectoriesRecursive( $long_name );
|
||||||
|
if ( empty( $recursive_dirs ) ) {
|
||||||
|
$recursive_dirs = $long_name;
|
||||||
|
}
|
||||||
|
$dirs[$long_name] = $recursive_dirs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $dirs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __construct() {
|
||||||
|
parent::__construct();
|
||||||
|
self::$title = 'Admin - Images';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function create() {
|
||||||
|
if ( Input::exists( 'submit' ) ) {
|
||||||
|
if ( !TTPForms::check( 'addImage' ) ) {
|
||||||
|
Issues::add( 'error', [ 'There was an error with your image.' => Check::userErrors() ] );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( Input::exists( 'folder' ) ) {
|
||||||
|
$folder = Input::post('folder');
|
||||||
|
} else {
|
||||||
|
// IMAGE_DIRECTORY
|
||||||
|
$folder = UPLOAD_DIRECTORY . App::$activeUser->username . DIRECTORY_SEPARATOR . 'images' . DIRECTORY_SEPARATOR;
|
||||||
|
}
|
||||||
|
|
||||||
|
$upload = Upload::image( 'upload', $folder );
|
||||||
|
|
||||||
|
if ( $upload ) {
|
||||||
|
$route = str_replace( APP_ROOT_DIRECTORY, '', $folder );
|
||||||
|
$out = $route . Upload::last();
|
||||||
|
} else {
|
||||||
|
Debug::error( 'There was an error with your upload.');
|
||||||
|
Issues::add( 'error', [ 'There was an error with your upload.' => Check::userErrors() ] );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Views::view( 'admin.images.create' );
|
||||||
|
}
|
||||||
|
|
||||||
|
public function delete() {
|
||||||
|
if ( ! Input::exists( 'fileLocation' ) ) {
|
||||||
|
Session::flash( 'warning', 'Unknown image.' );
|
||||||
|
Redirect::to( 'admin/images' );
|
||||||
|
}
|
||||||
|
|
||||||
|
$fileLocation = Input::get('fileLocation');
|
||||||
|
|
||||||
|
// Ensure the file exists
|
||||||
|
if ( ! file_exists( $fileLocation ) ) {
|
||||||
|
Session::flash('error', 'File does not exist.');
|
||||||
|
Redirect::to('admin/images');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the file is an image
|
||||||
|
$validMimeTypes = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'];
|
||||||
|
$fileMimeType = mime_content_type( $fileLocation );
|
||||||
|
|
||||||
|
if ( ! in_array( $fileMimeType, $validMimeTypes ) ) {
|
||||||
|
Session::flash('error', 'Invalid file type. Only images can be deleted.');
|
||||||
|
Redirect::to('admin/images');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attempt to delete the file
|
||||||
|
if (@unlink($fileLocation)) {
|
||||||
|
Session::flash('success', 'Image deleted.');
|
||||||
|
} else {
|
||||||
|
Session::flash('error', 'Failed to delete the image.');
|
||||||
|
}
|
||||||
|
|
||||||
|
Redirect::to('admin/images');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function rename() {
|
||||||
|
if ( ! Input::exists( 'fileLocation' ) ) {
|
||||||
|
Session::flash( 'warning', 'Unknown image.' );
|
||||||
|
Redirect::to( 'admin/images' );
|
||||||
|
}
|
||||||
|
|
||||||
|
Components::set( 'filelocation', Input::get( 'fileLocation' ) );
|
||||||
|
|
||||||
|
if ( Input::exists( 'submit' ) ) {
|
||||||
|
if ( !TTPForms::check( 'renameIImage' ) ) {
|
||||||
|
Issues::add( 'error', [ 'There was an error renaming the image.' => Check::userErrors() ] );
|
||||||
|
} else {
|
||||||
|
$result = $this->renameFile( Input::post( 'filelocation' ), Input::post( 'newname' ) );
|
||||||
|
if ( ! empty( $result ) ) {
|
||||||
|
Session::flash( 'success', 'Image has been renamed.' );
|
||||||
|
Redirect::to( 'admin/images' );
|
||||||
|
} else {
|
||||||
|
Issues::add( 'error', [ 'There was an error with the install.' => $this->installer->getErrors() ] );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Views::view( 'admin.images.rename' );
|
||||||
|
}
|
||||||
|
|
||||||
|
public function index() {
|
||||||
|
return Views::view( 'admin.images.list.combined', $this->getAllImageDetails() );
|
||||||
|
}
|
||||||
|
|
||||||
|
public function view() {
|
||||||
|
if ( Input::exists( 'fileLocation' ) ) {
|
||||||
|
return Views::view( 'admin.images.view', $this->getImageByLocation( Input::get( 'fileLocation' ) ) );
|
||||||
|
}
|
||||||
|
return $this->index();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getAllImages() {
|
||||||
|
$files = [];
|
||||||
|
foreach ($this->directories as $dir) {
|
||||||
|
if ($dir === 'app/plugins') {
|
||||||
|
$pluginDirs = glob($dir . '/*', GLOB_ONLYDIR);
|
||||||
|
foreach ($pluginDirs as $pluginDir) {
|
||||||
|
$imageDir = $pluginDir . '/images';
|
||||||
|
if (is_dir($imageDir)) {
|
||||||
|
$files = array_merge($files, $this->scanDirectoryRecursively($imageDir));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$files = array_merge($files, $this->scanDirectory($dir));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $files;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function scanDirectory($path) {
|
||||||
|
return glob($path . '/*.{jpg,jpeg,png,gif,webp}', GLOB_BRACE) ?: [];
|
||||||
|
}
|
||||||
|
|
||||||
|
private function scanDirectoryRecursively($path) {
|
||||||
|
$files = [];
|
||||||
|
$iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path, FilesystemIterator::SKIP_DOTS));
|
||||||
|
|
||||||
|
foreach ($iterator as $file) {
|
||||||
|
if (preg_match('/\.(jpg|jpeg|png|gif|webp)$/i', $file->getFilename())) {
|
||||||
|
$files[] = $file->getPathname();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $files;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getAllImageDetails() {
|
||||||
|
$images = [];
|
||||||
|
$files = $this->getAllImages();
|
||||||
|
foreach ( $files as $file ) {
|
||||||
|
$images[] = $this->getImageByLocation( $file );
|
||||||
|
}
|
||||||
|
return $images;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getImageByLocation( $location ) {
|
||||||
|
$realPath = realpath( $location );
|
||||||
|
|
||||||
|
return (object) [
|
||||||
|
'filename' => basename( $location ),
|
||||||
|
'extension' => pathinfo( $location , PATHINFO_EXTENSION),
|
||||||
|
'fileSize' => $this->formatFileSize(filesize( $location )),
|
||||||
|
'location' => $realPath,
|
||||||
|
'locationSafe' => urlencode( $realPath ),
|
||||||
|
'url' => Routes::getAddress() . str_replace( APP_ROOT_DIRECTORY, '', $realPath ),
|
||||||
|
'folder' => dirname( $location )
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
private function formatFileSize($size) {
|
||||||
|
$units = ['B', 'KB', 'MB', 'GB', 'TB'];
|
||||||
|
$i = 0;
|
||||||
|
while ($size >= 1024 && $i < count($units) - 1) {
|
||||||
|
$size /= 1024;
|
||||||
|
$i++;
|
||||||
|
}
|
||||||
|
return round($size, 2) . ' ' . $units[$i];
|
||||||
|
}
|
||||||
|
|
||||||
|
private function renameFile( $currentLocation, $newFilename ) {
|
||||||
|
// Ensure the file exists
|
||||||
|
if (!file_exists($currentLocation)) {
|
||||||
|
throw new \Exception("File does not exist: $currentLocation");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract directory and current extension
|
||||||
|
$directory = dirname($currentLocation);
|
||||||
|
$currentExtension = pathinfo($currentLocation, PATHINFO_EXTENSION);
|
||||||
|
$newExtension = pathinfo($newFilename, PATHINFO_EXTENSION);
|
||||||
|
|
||||||
|
// Ensure the file extension has not changed
|
||||||
|
if (strcasecmp($currentExtension, $newExtension) !== 0) {
|
||||||
|
throw new \Exception("File extension cannot be changed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Construct the new file path
|
||||||
|
$newLocation = $directory . DIRECTORY_SEPARATOR . $newFilename;
|
||||||
|
|
||||||
|
// Ensure the new file name does not already exist
|
||||||
|
if (file_exists($newLocation)) {
|
||||||
|
throw new \Exception("A file with the new name already exists: $newFilename");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attempt to rename the file
|
||||||
|
if (!rename($currentLocation, $newLocation)) {
|
||||||
|
throw new \Exception("Failed to rename file.");
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
@ -4,7 +4,7 @@
|
|||||||
*
|
*
|
||||||
* This is the login logs controller.
|
* This is the login logs controller.
|
||||||
*
|
*
|
||||||
* @version 3.0
|
* @version 5.0.1
|
||||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||||
* @link https://TheTempusProject.com
|
* @link https://TheTempusProject.com
|
||||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||||
@ -39,7 +39,7 @@ class Logins extends AdminController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function index() {
|
public function index() {
|
||||||
return Views::view( 'admin.logs.login_list', self::$log->listPaginated( 'login' ) );
|
return Views::view( 'admin.logs.login_list', self::$log->list( 'login' ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
public function view( $id = null ) {
|
public function view( $id = null ) {
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
*
|
*
|
||||||
* This is the generic logs controller.
|
* This is the generic logs controller.
|
||||||
*
|
*
|
||||||
* @version 3.0
|
* @version 5.0.1
|
||||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||||
* @link https://TheTempusProject.com
|
* @link https://TheTempusProject.com
|
||||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||||
@ -26,8 +26,8 @@ class Logs extends AdminController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function index( $data = null ) {
|
public function index( $data = null ) {
|
||||||
Views::view( 'admin.logs.error_list', self::$log->listPaginated( 'error' ) );
|
Views::view( 'admin.logs.error_list', self::$log->list( 'error' ) );
|
||||||
Views::view( 'admin.logs.admin_list', self::$log->listPaginated( 'admin' ) );
|
Views::view( 'admin.logs.admin_list', self::$log->list( 'admin' ) );
|
||||||
Views::view( 'admin.logs.login_list', self::$log->listPaginated( 'login' ) );
|
Views::view( 'admin.logs.login_list', self::$log->list( 'login' ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
*
|
*
|
||||||
* This is the installed plugins controller.
|
* This is the installed plugins controller.
|
||||||
*
|
*
|
||||||
* @version 3.0
|
* @version 5.0.1
|
||||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||||
* @link https://TheTempusProject.com
|
* @link https://TheTempusProject.com
|
||||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||||
@ -30,8 +30,6 @@ class Plugins extends AdminController {
|
|||||||
self::$title = 'Admin - Installed Plugins';
|
self::$title = 'Admin - Installed Plugins';
|
||||||
$this->installer = new Installer;
|
$this->installer = new Installer;
|
||||||
$this->plugins = $this->installer->getAvailablePlugins();
|
$this->plugins = $this->installer->getAvailablePlugins();
|
||||||
$view = Navigation::activePageSelect( 'nav.admin', '/admin/plugins' );
|
|
||||||
Components::set( 'ADMINNAV', $view );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function index() {
|
public function index() {
|
||||||
@ -39,7 +37,12 @@ class Plugins extends AdminController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function disable( $name = null ) {
|
public function disable( $name = null ) {
|
||||||
|
if ( empty( $name ) ) {
|
||||||
|
Session::flash( 'error', 'Unknown Plugin.' );
|
||||||
|
Redirect::to( 'admin/plugins' );
|
||||||
|
}
|
||||||
Components::set( 'PLUGIN', $name );
|
Components::set( 'PLUGIN', $name );
|
||||||
|
self::$title = 'Admin - Disable ' . $name;
|
||||||
if ( !Input::exists( 'installHash' ) ) {
|
if ( !Input::exists( 'installHash' ) ) {
|
||||||
return Views::view( 'admin.modules.plugins.disable' );
|
return Views::view( 'admin.modules.plugins.disable' );
|
||||||
}
|
}
|
||||||
@ -52,7 +55,12 @@ class Plugins extends AdminController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function enable( $name = null ) {
|
public function enable( $name = null ) {
|
||||||
|
if ( empty( $name ) ) {
|
||||||
|
Session::flash( 'error', 'Unknown Plugin.' );
|
||||||
|
Redirect::to( 'admin/plugins' );
|
||||||
|
}
|
||||||
Components::set( 'PLUGIN', $name );
|
Components::set( 'PLUGIN', $name );
|
||||||
|
self::$title = 'Admin - Enable ' . $name;
|
||||||
if ( !Input::exists( 'installHash' ) ) {
|
if ( !Input::exists( 'installHash' ) ) {
|
||||||
return Views::view( 'admin.modules.plugins.enable' );
|
return Views::view( 'admin.modules.plugins.enable' );
|
||||||
}
|
}
|
||||||
@ -71,6 +79,7 @@ class Plugins extends AdminController {
|
|||||||
}
|
}
|
||||||
$name = strtolower( $name );
|
$name = strtolower( $name );
|
||||||
Components::set( 'PLUGIN', $name );
|
Components::set( 'PLUGIN', $name );
|
||||||
|
self::$title = 'Admin - Install ' . $name;
|
||||||
if ( ! Input::exists( 'installHash' ) ) {
|
if ( ! Input::exists( 'installHash' ) ) {
|
||||||
return Views::view( 'admin.modules.plugins.install' );
|
return Views::view( 'admin.modules.plugins.install' );
|
||||||
}
|
}
|
||||||
@ -95,6 +104,7 @@ class Plugins extends AdminController {
|
|||||||
}
|
}
|
||||||
$name = strtolower($name);
|
$name = strtolower($name);
|
||||||
Components::set( 'PLUGIN', $name );
|
Components::set( 'PLUGIN', $name );
|
||||||
|
self::$title = 'Admin - Uninstall ' . $name;
|
||||||
|
|
||||||
if ( !Input::exists( 'uninstallHash' ) ) {
|
if ( !Input::exists( 'uninstallHash' ) ) {
|
||||||
return Views::view( 'admin.modules.plugins.uninstall' );
|
return Views::view( 'admin.modules.plugins.uninstall' );
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
*
|
*
|
||||||
* This is the admin routes/redirects controller.
|
* This is the admin routes/redirects controller.
|
||||||
*
|
*
|
||||||
* @version 3.0
|
* @version 5.0.1
|
||||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||||
* @link https://TheTempusProject.com
|
* @link https://TheTempusProject.com
|
||||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||||
@ -31,15 +31,18 @@ class Routes extends AdminController {
|
|||||||
parent::__construct();
|
parent::__construct();
|
||||||
self::$title = 'Admin - Redirects';
|
self::$title = 'Admin - Redirects';
|
||||||
self::$routes = new RoutesClass;
|
self::$routes = new RoutesClass;
|
||||||
$view = Navigation::activePageSelect( 'nav.admin', '/admin/routes' );
|
|
||||||
Components::set( 'ADMINNAV', $view );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function create() {
|
public function create() {
|
||||||
if ( Input::exists( 'redirect_type' ) ) {
|
if ( ! Input::exists( 'redirect_type' ) ) {
|
||||||
|
return Views::view( 'admin.routes.create' );
|
||||||
|
}
|
||||||
|
|
||||||
if ( !TTPForms::check( 'createRoute' ) ) {
|
if ( !TTPForms::check( 'createRoute' ) ) {
|
||||||
Issues::add( 'error', [ 'There was an error with your route.' => Check::userErrors() ] );
|
Issues::add( 'error', [ 'There was an error with your route.' => Check::userErrors() ] );
|
||||||
|
return Views::view( 'admin.routes.create' );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( self::$routes->create(
|
if ( self::$routes->create(
|
||||||
Input::post( 'original_url' ),
|
Input::post( 'original_url' ),
|
||||||
Input::post( 'forwarded_url' ),
|
Input::post( 'forwarded_url' ),
|
||||||
@ -49,7 +52,8 @@ class Routes extends AdminController {
|
|||||||
Session::flash( 'success', 'Route Created' );
|
Session::flash( 'success', 'Route Created' );
|
||||||
Redirect::to( 'admin/routes' );
|
Redirect::to( 'admin/routes' );
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
Issues::add( 'error', 'There was an unknown error saving your redirect.' );
|
||||||
Views::view( 'admin.routes.create' );
|
Views::view( 'admin.routes.create' );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* app/controllers/admin/contact.php
|
* app/controllers/admin/send_mail.php
|
||||||
*
|
*
|
||||||
* This is the admin contact controller. The only real use is to send out emails to the various lists.
|
* This is the admin email controller. The only real use is to send out emails to the various lists.
|
||||||
*
|
*
|
||||||
* @version 3.0
|
* @version 5.0.1
|
||||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||||
* @link https://TheTempusProject.com
|
* @link https://TheTempusProject.com
|
||||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||||
@ -18,19 +18,34 @@ use TheTempusProject\Houdini\Classes\Issues;
|
|||||||
use TheTempusProject\Houdini\Classes\Views;
|
use TheTempusProject\Houdini\Classes\Views;
|
||||||
use TheTempusProject\Models\User;
|
use TheTempusProject\Models\User;
|
||||||
use TheTempusProject\Models\Subscribe;
|
use TheTempusProject\Models\Subscribe;
|
||||||
|
use TheTempusProject\Plugins\Subscribe as Plugin;
|
||||||
|
|
||||||
class Contact extends AdminController {
|
class SendMail extends AdminController {
|
||||||
public static $user;
|
public static $user;
|
||||||
public static $subscribe;
|
public static $subscribe;
|
||||||
|
|
||||||
public function __construct() {
|
public function __construct() {
|
||||||
parent::__construct();
|
parent::__construct();
|
||||||
self::$title = 'Admin - Contact';
|
self::$title = 'Admin - Send Mail';
|
||||||
self::$user = new User;
|
self::$user = new User;
|
||||||
|
|
||||||
|
if ( class_exists( 'TheTempusProject\Plugins\Subscribe' ) ) {
|
||||||
|
$plugin = new Plugin;
|
||||||
|
if ( ! $plugin->checkEnabled() ) {
|
||||||
|
Issues::add( 'notice', 'Subscriptions are disabled so those feature will be unavailable.' );
|
||||||
|
} else {
|
||||||
self::$subscribe = new Subscribe;
|
self::$subscribe = new Subscribe;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
Issues::add( 'notice', 'Subscriptions plugin is not installed so those feature will be unavailable.' );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private function emailSubscribers( $params ) {
|
private function emailSubscribers( $params ) {
|
||||||
|
if ( empty( self::$subscribe ) ) {
|
||||||
|
Issues::add( 'error', 'Subscriptions plugin is unavailable' );
|
||||||
|
return;
|
||||||
|
}
|
||||||
$list = self::$subscribe->list();
|
$list = self::$subscribe->list();
|
||||||
if ( empty( $list ) ) {
|
if ( empty( $list ) ) {
|
||||||
Issues::add( 'error', 'No subscribers found' );
|
Issues::add( 'error', 'No subscribers found' );
|
@ -4,7 +4,7 @@
|
|||||||
*
|
*
|
||||||
* This is the configuration and settings controller.
|
* This is the configuration and settings controller.
|
||||||
*
|
*
|
||||||
* @version 3.0
|
* @version 5.0.1
|
||||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||||
* @link https://TheTempusProject.com
|
* @link https://TheTempusProject.com
|
||||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||||
|
88
app/controllers/admin/tokens.php
Normal file
88
app/controllers/admin/tokens.php
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* app/controllers/admin/tokens.php
|
||||||
|
*
|
||||||
|
* This is the admin app/user tokens controller.
|
||||||
|
*
|
||||||
|
* @version 5.0.1
|
||||||
|
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||||
|
* @link https://TheTempusProject.com
|
||||||
|
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||||
|
*/
|
||||||
|
namespace TheTempusProject\Controllers\Admin;
|
||||||
|
|
||||||
|
use TheTempusProject\Classes\Forms as TTPForms;
|
||||||
|
use TheTempusProject\Houdini\Classes\Views;
|
||||||
|
use TheTempusProject\Houdini\Classes\Issues;
|
||||||
|
use TheTempusProject\Houdini\Classes\Navigation;
|
||||||
|
use TheTempusProject\Houdini\Classes\Components;
|
||||||
|
use TheTempusProject\Houdini\Classes\Forms;
|
||||||
|
use TheTempusProject\Classes\AdminController;
|
||||||
|
use TheTempusProject\Models\Token;
|
||||||
|
use TheTempusProject\Bedrock\Functions\Input;
|
||||||
|
use TheTempusProject\Bedrock\Functions\Check;
|
||||||
|
use TheTempusProject\Hermes\Functions\Redirect;
|
||||||
|
use TheTempusProject\Bedrock\Functions\Session;
|
||||||
|
|
||||||
|
class Tokens extends AdminController {
|
||||||
|
public static $token;
|
||||||
|
|
||||||
|
public function __construct() {
|
||||||
|
parent::__construct();
|
||||||
|
self::$title = 'Admin - Tokens';
|
||||||
|
self::$token = new Token;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function create() {
|
||||||
|
if ( Input::exists( 'submit' ) ) {
|
||||||
|
if ( !TTPForms::check( 'adminCreateToken' ) ) {
|
||||||
|
Issues::add( 'error', [ 'There was an error with your token.' => Check::userErrors() ] );
|
||||||
|
}
|
||||||
|
if ( self::$token->create(
|
||||||
|
Input::post( 'name' ),
|
||||||
|
Input::post( 'notes' ),
|
||||||
|
Input::post( 'token_type' )
|
||||||
|
) ) {
|
||||||
|
Session::flash( 'success', 'Token Created' );
|
||||||
|
Redirect::to( 'admin/tokens' );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Views::view( 'admin.tokens.create' );
|
||||||
|
}
|
||||||
|
|
||||||
|
public function delete( $id = null ) {
|
||||||
|
if ( self::$token->delete( [ $id ] ) ) {
|
||||||
|
Session::flash( 'success', 'Token deleted.' );
|
||||||
|
}
|
||||||
|
Redirect::to( 'admin/tokens' );
|
||||||
|
}
|
||||||
|
|
||||||
|
public function edit( $id = null ) {
|
||||||
|
$token = self::$token->findById( $id );
|
||||||
|
if ( Input::exists( 'submit' ) ) {
|
||||||
|
if ( !TTPForms::check( 'adminEditToken' ) ) {
|
||||||
|
Issues::add( 'error', [ 'There was an error with your token.' => Check::userErrors() ] );
|
||||||
|
} else {
|
||||||
|
if ( self::$token->update(
|
||||||
|
$id,
|
||||||
|
Input::post( 'name' ),
|
||||||
|
Input::post( 'notes' ),
|
||||||
|
Input::post( 'token_type' )
|
||||||
|
) ) {
|
||||||
|
Session::flash( 'success', 'Token Updated' );
|
||||||
|
Redirect::to( 'admin/tokens' );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Forms::selectOption( $token->token_type );
|
||||||
|
return Views::view( 'admin.tokens.edit', $token );
|
||||||
|
}
|
||||||
|
|
||||||
|
public function index() {
|
||||||
|
return Views::view( 'admin.tokens.list', self::$token->listPaginated() );
|
||||||
|
}
|
||||||
|
|
||||||
|
public function view( $id = null ) {
|
||||||
|
return Views::view( 'admin.tokens.view', self::$token->findById( $id ) );
|
||||||
|
}
|
||||||
|
}
|
@ -4,7 +4,7 @@
|
|||||||
*
|
*
|
||||||
* This is the users admin controller.
|
* This is the users admin controller.
|
||||||
*
|
*
|
||||||
* @version 3.0
|
* @version 5.0.1
|
||||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||||
* @link https://TheTempusProject.com
|
* @link https://TheTempusProject.com
|
||||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||||
@ -26,6 +26,8 @@ use TheTempusProject\Classes\AdminController;
|
|||||||
use TheTempusProject\Models\User;
|
use TheTempusProject\Models\User;
|
||||||
use TheTempusProject\Models\Group;
|
use TheTempusProject\Models\Group;
|
||||||
use TheTempusProject\TheTempusProject as App;
|
use TheTempusProject\TheTempusProject as App;
|
||||||
|
use TheTempusProject\Houdini\Classes\Template;
|
||||||
|
use TheTempusProject\Bedrock\Functions\Upload;
|
||||||
|
|
||||||
class Users extends AdminController {
|
class Users extends AdminController {
|
||||||
public static $user;
|
public static $user;
|
||||||
@ -36,8 +38,6 @@ class Users extends AdminController {
|
|||||||
self::$title = 'Admin - Users';
|
self::$title = 'Admin - Users';
|
||||||
self::$user = new User;
|
self::$user = new User;
|
||||||
self::$group = new Group;
|
self::$group = new Group;
|
||||||
$view = Navigation::activePageSelect( 'nav.admin', '/admin/users' );
|
|
||||||
Components::set( 'ADMINNAV', $view );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function create() {
|
public function create() {
|
||||||
@ -63,8 +63,11 @@ class Users extends AdminController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
$select = Forms::getSelectHtml(
|
||||||
$select = Forms::getFormFieldHtml( 'groupSelect', 'User Group', 'select', Config::getValue( 'group/defaultGroup' ), self::$group->listGroupsSimple() );
|
'groupSelect',
|
||||||
|
self::$group->listGroupsSimple(),
|
||||||
|
Config::getValue( 'group/defaultGroup' ),
|
||||||
|
);
|
||||||
Components::set( 'groupSelect', $select );
|
Components::set( 'groupSelect', $select );
|
||||||
Views::view( 'admin.users.create' );
|
Views::view( 'admin.users.create' );
|
||||||
}
|
}
|
||||||
@ -102,7 +105,7 @@ class Users extends AdminController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ( Input::exists( 'submit' ) ) {
|
if ( Input::exists( 'submit' ) ) {
|
||||||
if ( !FormChecker::check( 'editUser' ) ) {
|
if ( ! FormChecker::check( 'editUser' ) ) {
|
||||||
Issues::add( 'error', [ 'There was an error with your request.' => Check::userErrors() ] );
|
Issues::add( 'error', [ 'There was an error with your request.' => Check::userErrors() ] );
|
||||||
} else {
|
} else {
|
||||||
$fields = [
|
$fields = [
|
||||||
@ -110,6 +113,25 @@ class Users extends AdminController {
|
|||||||
'email' => Input::post( 'email' ),
|
'email' => Input::post( 'email' ),
|
||||||
'userGroup' => Input::post( 'groupSelect' ),
|
'userGroup' => Input::post( 'groupSelect' ),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
if ( Input::exists( 'avatar' ) ) {
|
||||||
|
$folder = UPLOAD_DIRECTORY . $userData->username . DIRECTORY_SEPARATOR . 'images' . DIRECTORY_SEPARATOR;
|
||||||
|
$upload = Upload::image( 'avatar', $folder );
|
||||||
|
if ( $upload ) {
|
||||||
|
$route = str_replace( APP_ROOT_DIRECTORY, '', $folder );
|
||||||
|
$prefs = [];
|
||||||
|
$prefs['avatar'] = $route . Upload::last();
|
||||||
|
|
||||||
|
self::$user->updatePrefs( $prefs, $userData->ID );
|
||||||
|
} else {
|
||||||
|
Issues::add( 'error', [ 'There was an error with your avatar.' => Check::userErrors() ] );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( Input::exists( 'password' ) ) {
|
||||||
|
$fields['password'] = Hash::make( Input::post( 'password' ) );
|
||||||
|
}
|
||||||
|
|
||||||
if ( Input::exists( 'confirmed' ) ) {
|
if ( Input::exists( 'confirmed' ) ) {
|
||||||
$fields['confirmed'] = 1;
|
$fields['confirmed'] = 1;
|
||||||
} else {
|
} else {
|
||||||
@ -117,6 +139,7 @@ class Users extends AdminController {
|
|||||||
$fields['confirmationCode'] = Code::genConfirmation();
|
$fields['confirmationCode'] = Code::genConfirmation();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( self::$user->update( $userData->ID, $fields ) ) {
|
if ( self::$user->update( $userData->ID, $fields ) ) {
|
||||||
Issues::add( 'success', 'User Updated.' );
|
Issues::add( 'success', 'User Updated.' );
|
||||||
return $this->index();
|
return $this->index();
|
||||||
@ -132,9 +155,15 @@ class Users extends AdminController {
|
|||||||
$userGroup = $userData->userGroup;
|
$userGroup = $userData->userGroup;
|
||||||
}
|
}
|
||||||
Forms::selectRadio( 'confirmed', $userData->confirmed );
|
Forms::selectRadio( 'confirmed', $userData->confirmed );
|
||||||
$avatar = Forms::getFormFieldHtml( 'avatar', 'User Avatar', 'file', $avatarLocation );
|
|
||||||
$select = Forms::getFormFieldHtml( 'groupSelect', 'User Group', 'select', $userGroup, self::$group->listGroupsSimple() );
|
$avatar = $this->getAvatar( 'avatar', $avatarLocation );
|
||||||
Components::set( 'AvatarSettings', $avatar );
|
Components::set( 'AvatarSettings', $avatar );
|
||||||
|
|
||||||
|
$select = Forms::getSelectHtml(
|
||||||
|
'groupSelect',
|
||||||
|
self::$group->listGroupsSimple(),
|
||||||
|
$userGroup,
|
||||||
|
);
|
||||||
Components::set( 'groupSelect', $select );
|
Components::set( 'groupSelect', $select );
|
||||||
Views::view( 'admin.users.edit', $userData );
|
Views::view( 'admin.users.edit', $userData );
|
||||||
}
|
}
|
||||||
@ -153,4 +182,28 @@ class Users extends AdminController {
|
|||||||
}
|
}
|
||||||
$this->index();
|
$this->index();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function getAvatar( $name, $value ) {
|
||||||
|
$fieldname = str_ireplace( '/', '-', $name );
|
||||||
|
|
||||||
|
$html = '';
|
||||||
|
$fieldHtml = '';
|
||||||
|
$fieldHtml = Forms::getFileHtml( $fieldname );
|
||||||
|
|
||||||
|
$html .= '<div class="mb-3 row">';
|
||||||
|
$html .= ' <label for="' . $fieldname . '" class="col-lg-6 col-form-label text-end">' . ucfirst( $fieldname ) . '</label>';
|
||||||
|
$html .= ' <div class="col-lg-2">';
|
||||||
|
$html .= ' ' . $fieldHtml;
|
||||||
|
$html .= ' </div>';
|
||||||
|
$html .= '</div>';
|
||||||
|
|
||||||
|
$html .= '<div class="mb-3 row">';
|
||||||
|
$html .= ' <h4 class="col-lg-6 col-form-label text-end">Current Image</h4>';
|
||||||
|
$html .= ' <div class="col-lg-2">';
|
||||||
|
$html .= ' <img alt="User Avatar" src="{ROOT_URL}' . $value . '" class="img-circle img-fluid p-2 avatar-125">';
|
||||||
|
$html .= ' </div>';
|
||||||
|
$html .= '</div>';
|
||||||
|
|
||||||
|
return Template::parse( $html );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,35 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* app/controllers/alpha.php
|
|
||||||
*
|
|
||||||
* This is the friends and family alpha controller.
|
|
||||||
*
|
|
||||||
* @version 3.0
|
|
||||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
|
||||||
* @link https://TheTempusProject.com
|
|
||||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
|
||||||
*/
|
|
||||||
namespace TheTempusProject\Controllers;
|
|
||||||
|
|
||||||
use TheTempusProject\Classes\Controller;
|
|
||||||
use TheTempusProject\Houdini\Classes\Views;
|
|
||||||
|
|
||||||
class Alpha extends Controller {
|
|
||||||
public function index() {
|
|
||||||
self::$title = 'Friends and Family Alpha';
|
|
||||||
self::$pageDescription = 'The Tempus Project friends and family alpha has begun. Please join me and take part in bringing a dream to reality.';
|
|
||||||
Views::view( 'alpha.index' );
|
|
||||||
}
|
|
||||||
|
|
||||||
public function crashcourse() {
|
|
||||||
self::$title = 'Friends and Family Crash-Course';
|
|
||||||
self::$pageDescription = 'The Tempus Project runs not only this site, but it can be used and deployed for any number of sites. This crash course is intended to give you all the knowledge you will need to start building your own applications powered by The Tempus Project.';
|
|
||||||
Views::view( 'alpha.crashcourse' );
|
|
||||||
}
|
|
||||||
|
|
||||||
public function certification() {
|
|
||||||
self::$title = 'Friends and Family Certification';
|
|
||||||
self::$pageDescription = 'The Tempus Project runs not only this site, but it can be used and deployed for any number of sites. This certification course is intended to give experienced users all the information they will need to start building your own applications powered by The Tempus Project.';
|
|
||||||
Views::view( 'alpha.certification' );
|
|
||||||
}
|
|
||||||
}
|
|
38
app/controllers/api/auth.php
Normal file
38
app/controllers/api/auth.php
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* app/controllers/api/auth.php
|
||||||
|
*
|
||||||
|
* This is the api authentication controller.
|
||||||
|
*
|
||||||
|
* @version 5.0.1
|
||||||
|
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||||
|
* @link https://TheTempusProject.com
|
||||||
|
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||||
|
*/
|
||||||
|
namespace TheTempusProject\Controllers\Api;
|
||||||
|
|
||||||
|
use TheTempusProject\Models\User;
|
||||||
|
use TheTempusProject\Classes\ApiController;
|
||||||
|
use TheTempusProject\Houdini\Classes\Views;
|
||||||
|
use TheTempusProject\Models\Token;
|
||||||
|
|
||||||
|
class Auth extends ApiController {
|
||||||
|
public static $tokens;
|
||||||
|
|
||||||
|
public function __construct() {
|
||||||
|
parent::__construct();
|
||||||
|
self::$tokens = new Token;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function refresh() {
|
||||||
|
$token = self::$tokens->refresh( self::$authToken->ID );
|
||||||
|
if ( empty( $token ) ) {
|
||||||
|
$responseType = 'error';
|
||||||
|
$response = 'IRDK';
|
||||||
|
} else {
|
||||||
|
$responseType = 'token';
|
||||||
|
$response = $token;
|
||||||
|
}
|
||||||
|
Views::view( 'api.response', ['response' => json_encode( [ $responseType => $response ], true )]);
|
||||||
|
}
|
||||||
|
}
|
50
app/controllers/api/login.php
Normal file
50
app/controllers/api/login.php
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* app/controllers/api/auth.php
|
||||||
|
*
|
||||||
|
* This is the api authentication controller.
|
||||||
|
*
|
||||||
|
* @version 5.0.1
|
||||||
|
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||||
|
* @link https://TheTempusProject.com
|
||||||
|
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||||
|
*/
|
||||||
|
namespace TheTempusProject\Controllers\Api;
|
||||||
|
|
||||||
|
use TheTempusProject\Classes\ApiController;
|
||||||
|
use TheTempusProject\Houdini\Classes\Views;
|
||||||
|
use TheTempusProject\Models\Token;
|
||||||
|
use TheTempusProject\Models\User;
|
||||||
|
use TheTempusProject\Houdini\Classes\Template;
|
||||||
|
use TheTempusProject\Classes\Forms;
|
||||||
|
use TheTempusProject\Bedrock\Functions\Input;
|
||||||
|
|
||||||
|
class Login extends ApiController {
|
||||||
|
public static $tokens;
|
||||||
|
public static $user;
|
||||||
|
|
||||||
|
public function __construct() {
|
||||||
|
parent::__construct( false );
|
||||||
|
self::$tokens = new Token;
|
||||||
|
self::$user = new User;
|
||||||
|
Template::addHeader( 'Access-Control-Allow-Origin: *' );
|
||||||
|
Template::addHeader( 'Content-Type: application/json; charset=utf-8' );
|
||||||
|
}
|
||||||
|
|
||||||
|
public function index() {
|
||||||
|
if ( ! Forms::check( 'apiLogin' ) ) {
|
||||||
|
$responseType = 'error';
|
||||||
|
$response = 'malformed input';
|
||||||
|
return Views::view( 'api.response', ['response' => json_encode( [ $responseType => $response ], true )]);
|
||||||
|
}
|
||||||
|
$user = self::$user->authorize( Input::post( 'username' ), Input::post( 'password' ) );
|
||||||
|
if ( ! $user ) {
|
||||||
|
$responseType = 'error';
|
||||||
|
$response = 'bad credentials';
|
||||||
|
return Views::view( 'api.response', ['response' => json_encode( [ $responseType => $response ], true )]);
|
||||||
|
}
|
||||||
|
$responseType = 'token';
|
||||||
|
$token = self::$tokens->findOrCreateUserToken( $user->ID, true );
|
||||||
|
return Views::view( 'api.response', ['response' => json_encode( [ $responseType => $token ], true )]);
|
||||||
|
}
|
||||||
|
}
|
@ -4,7 +4,7 @@
|
|||||||
*
|
*
|
||||||
* This is the users' api controller.
|
* This is the users' api controller.
|
||||||
*
|
*
|
||||||
* @version 3.0
|
* @version 5.0.1
|
||||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||||
* @link https://TheTempusProject.com
|
* @link https://TheTempusProject.com
|
||||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||||
@ -30,7 +30,7 @@ class Users extends ApiController {
|
|||||||
$response = 'No user found.';
|
$response = 'No user found.';
|
||||||
} else {
|
} else {
|
||||||
$responseType = 'data';
|
$responseType = 'data';
|
||||||
$response = $user;
|
$response = $user->ID;
|
||||||
}
|
}
|
||||||
Views::view( 'api.response', ['response' => json_encode( [ $responseType => $response ], true )]);
|
Views::view( 'api.response', ['response' => json_encode( [ $responseType => $response ], true )]);
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
*
|
*
|
||||||
* This is the error controller.
|
* This is the error controller.
|
||||||
*
|
*
|
||||||
* @version 3.0
|
* @version 5.0.1
|
||||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||||
* @link https://TheTempusProject.com
|
* @link https://TheTempusProject.com
|
||||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
*
|
*
|
||||||
* This is the home or 'index' controller.
|
* This is the home or 'index' controller.
|
||||||
*
|
*
|
||||||
* @version 3.0
|
* @version 5.0.1
|
||||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||||
* @link https://TheTempusProject.com
|
* @link https://TheTempusProject.com
|
||||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||||
@ -27,26 +27,26 @@ use TheTempusProject\TheTempusProject as App;
|
|||||||
class Home extends Controller {
|
class Home extends Controller {
|
||||||
public function index() {
|
public function index() {
|
||||||
self::$title = '{SITENAME}';
|
self::$title = '{SITENAME}';
|
||||||
self::$pageDescription = 'This is the homepage of your new Tempus Project Installation. Thank you for installing. find more info at https://thetempusproject.com';
|
self::$pageDescription = '{SITENAME} is here to provide you a better, faster, and easier - way to create and manage your own web applications.';
|
||||||
Views::view( 'index' );
|
Views::view( 'index' );
|
||||||
}
|
}
|
||||||
|
|
||||||
public function login() {
|
public function login() {
|
||||||
self::$title = 'Portal - {SITENAME}';
|
self::$title = 'Portal - {SITENAME}';
|
||||||
self::$pageDescription = 'Please log in to use {SITENAME} member features.';
|
self::$pageDescription = 'Please log in to access all of the great features {SITENAME} has to offer.';
|
||||||
if ( App::$isLoggedIn ) {
|
if ( App::$isLoggedIn ) {
|
||||||
return Issues::add( 'notice', 'You are already logged in. Please <a href="' . Routes::getAddress() . 'home/logout">click here</a> to log out.' );
|
return Issues::add( 'notice', 'You are already logged in. Please <a href="' . Routes::getAddress() . 'home/logout">click here</a> to log out.' );
|
||||||
}
|
}
|
||||||
if ( !Input::exists() ) {
|
if ( !Input::exists() ) {
|
||||||
return Views::view( 'login' );
|
return Views::view( 'auth.login' );
|
||||||
}
|
}
|
||||||
if ( !Forms::check( 'login' ) ) {
|
if ( !Forms::check( 'login' ) ) {
|
||||||
Issues::add( 'error', [ 'There was an error with your login.' => Check::userErrors() ] );
|
Issues::add( 'error', [ 'There was an error with your login.' => Check::userErrors() ] );
|
||||||
return Views::view( 'login' );
|
return Views::view( 'auth.login' );
|
||||||
}
|
}
|
||||||
if ( !self::$user->logIn( Input::post( 'username' ), Input::post( 'password' ), Input::post( 'remember' ) ) ) {
|
if ( !self::$user->logIn( Input::post( 'username' ), Input::post( 'password' ), Input::post( 'remember' ) ) ) {
|
||||||
Issues::add( 'error', 'Username or password was incorrect.' );
|
Issues::add( 'error', 'Username or password was incorrect.' );
|
||||||
return Views::view( 'login' );
|
return Views::view( 'auth.login' );
|
||||||
}
|
}
|
||||||
Session::flash( 'success', 'You have been logged in.' );
|
Session::flash( 'success', 'You have been logged in.' );
|
||||||
if ( Input::exists( 'rurl' ) ) {
|
if ( Input::exists( 'rurl' ) ) {
|
||||||
@ -69,7 +69,7 @@ class Home extends Controller {
|
|||||||
|
|
||||||
public function profile( $id = null ) {
|
public function profile( $id = null ) {
|
||||||
self::$title = 'User Profile - {SITENAME}';
|
self::$title = 'User Profile - {SITENAME}';
|
||||||
self::$pageDescription = 'User Profiles for {SITENAME}';
|
self::$pageDescription = 'User Profile - {SITENAME}';
|
||||||
if ( !App::$isLoggedIn ) {
|
if ( !App::$isLoggedIn ) {
|
||||||
return Issues::add( 'notice', 'You must be logged in to view this page.' );
|
return Issues::add( 'notice', 'You must be logged in to view this page.' );
|
||||||
}
|
}
|
||||||
@ -79,23 +79,31 @@ class Home extends Controller {
|
|||||||
}
|
}
|
||||||
self::$title = $user->username . '\'s Profile - {SITENAME}';
|
self::$title = $user->username . '\'s Profile - {SITENAME}';
|
||||||
self::$pageDescription = 'User Profile for ' . $user->username . ' - {SITENAME}';
|
self::$pageDescription = 'User Profile for ' . $user->username . ' - {SITENAME}';
|
||||||
Views::view( 'profile', $user );
|
Views::view( 'profilePage', $user );
|
||||||
}
|
}
|
||||||
|
|
||||||
public function terms() {
|
public function terms() {
|
||||||
self::$title = 'Terms and Conditions - {SITENAME}';
|
self::$title = 'Terms and Conditions - {SITENAME}';
|
||||||
self::$pageDescription = '{SITENAME} Terms and Conditions of use. Please use {SITENAME} safely.';
|
self::$pageDescription = '{SITENAME} Terms and Conditions of use. Please use {SITENAME} safely.';
|
||||||
Components::set( 'TERMS', Views::simpleView( 'terms' ) );
|
Components::set( 'TERMS', Views::simpleView( 'auth.terms' ) );
|
||||||
Views::raw( '<div class="terms-page">{TERMS}</div>' );
|
Views::view( 'termsPage' );
|
||||||
}
|
}
|
||||||
|
|
||||||
public function hashtag( $id = null ) {
|
public function about() {
|
||||||
self::$title = 'HashTag - {SITENAME}';
|
self::$title = 'About - {SITENAME}';
|
||||||
self::$pageDescription = 'HashTags for {SITENAME}';
|
self::$pageDescription = '{SITENAME} was started by a developer with years of industry experience which has lead to a refined no-nonsense tool for everyone. Find out more about us here.';
|
||||||
if ( !App::$isLoggedIn ) {
|
Views::view( 'about' );
|
||||||
return Issues::add( 'notice', 'You must be logged in to view this page.' );
|
|
||||||
}
|
}
|
||||||
// this should look up comments and blog posts with the hashtag in them
|
|
||||||
Views::view( 'hashtags' );
|
public function privacy() {
|
||||||
|
self::$title = 'Privacy Policy - {SITENAME}';
|
||||||
|
self::$pageDescription = 'At {SITENAME} you privacy is very important to us. On this page you can find a detailed outline of all the information we collect and how its used.';
|
||||||
|
Views::view( 'privacy' );
|
||||||
|
}
|
||||||
|
|
||||||
|
public function faq() {
|
||||||
|
self::$title = 'Frequently Asked Questions - {SITENAME}';
|
||||||
|
self::$pageDescription = 'Many times, we aren\'t the first to ask why or how something works. Here you will find a list of {SITENAME} commonly asked questions and our best answers.' ;
|
||||||
|
Views::view( 'faq' );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,3 +0,0 @@
|
|||||||
<?php
|
|
||||||
// the idea is that this will be info pages for the plugin various/info
|
|
||||||
?>
|
|
@ -4,7 +4,7 @@
|
|||||||
*
|
*
|
||||||
* This is the user registration controller.
|
* This is the user registration controller.
|
||||||
*
|
*
|
||||||
* @version 3.0
|
* @version 5.0.1
|
||||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||||
* @link https://TheTempusProject.com
|
* @link https://TheTempusProject.com
|
||||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||||
@ -24,37 +24,44 @@ use TheTempusProject\Houdini\Classes\Views;
|
|||||||
use TheTempusProject\TheTempusProject as App;
|
use TheTempusProject\TheTempusProject as App;
|
||||||
use TheTempusProject\Classes\Controller;
|
use TheTempusProject\Classes\Controller;
|
||||||
use TheTempusProject\Classes\Forms;
|
use TheTempusProject\Classes\Forms;
|
||||||
|
use TheTempusProject\Bedrock\Classes\Config;
|
||||||
|
|
||||||
class Register extends Controller {
|
class Register extends Controller {
|
||||||
public function confirm( $code = null ) {
|
public function confirm( $code = null ) {
|
||||||
|
Template::noIndex();
|
||||||
self::$title = 'Confirm Email';
|
self::$title = 'Confirm Email';
|
||||||
if ( !isset( $code ) && !Input::exists( 'confirmationCode' ) ) {
|
if ( !isset( $code ) && !Input::exists( 'confirmationCode' ) ) {
|
||||||
return Views::view( 'email.confirmation' );
|
return Views::view( 'auth.confirmation' );
|
||||||
}
|
}
|
||||||
if ( Forms::check( 'emailConfirmation' ) ) {
|
if ( Forms::check( 'emailConfirmation' ) ) {
|
||||||
$code = Input::post( 'confirmationCode' );
|
$code = Input::post( 'confirmationCode' );
|
||||||
}
|
}
|
||||||
if ( !self::$user->confirm( $code ) ) {
|
if ( !self::$user->confirm( $code ) ) {
|
||||||
Issues::add( 'error', 'There was an error confirming your account, please try again.' );
|
Issues::add( 'error', 'There was an error confirming your account, please try again.' );
|
||||||
return Views::view( 'email.confirmation' );
|
return Views::view( 'auth.confirmation' );
|
||||||
}
|
}
|
||||||
Session::flash( 'success', 'You have successfully confirmed your email address.' );
|
Session::flash( 'success', 'You have successfully confirmed your email address.' );
|
||||||
Redirect::to( 'home/index' );
|
Redirect::to( 'home/index' );
|
||||||
}
|
}
|
||||||
|
|
||||||
public function index() {
|
public function index() {
|
||||||
self::$title = 'Register';
|
self::$title = '{SITENAME} Sign Up';
|
||||||
self::$pageDescription = 'Many features of the site are disabled or even hidden from unregistered users. On this page you can sign up for an account to access all the app has to offer.';
|
self::$pageDescription = 'Many features of {SITENAME} are disabled or hidden from unregistered users. On this page you can sign up for an account to access all the app has to offer.';
|
||||||
Components::set( 'TERMS', Views::simpleView( 'terms' ) );
|
|
||||||
|
if ( ! Config::getValue( 'main/registrationEnabled' ) ) {
|
||||||
|
return Issues::add( 'notice', 'The site administrator has disable the ability to register a new account.' );
|
||||||
|
}
|
||||||
|
|
||||||
|
Components::set( 'TERMS', Views::simpleView( 'auth.terms' ) );
|
||||||
if ( App::$isLoggedIn ) {
|
if ( App::$isLoggedIn ) {
|
||||||
return Issues::add( 'notice', 'You are currently logged in.' );
|
return Issues::add( 'notice', 'You are currently logged in.' );
|
||||||
}
|
}
|
||||||
if ( !Input::exists() ) {
|
if ( !Input::exists() ) {
|
||||||
return Views::view( 'register' );
|
return Views::view( 'auth.register' );
|
||||||
}
|
}
|
||||||
if ( !Forms::check( 'register' ) ) {
|
if ( !Forms::check( 'register' ) ) {
|
||||||
Issues::add( 'error', [ 'There was an error with your registration.' => Check::userErrors() ] );
|
Issues::add( 'error', [ 'There was an error with your registration.' => Check::userErrors() ] );
|
||||||
return Views::view( 'register' );
|
return Views::view( 'auth.register' );
|
||||||
}
|
}
|
||||||
self::$user->create( [
|
self::$user->create( [
|
||||||
'username' => Input::post( 'username' ),
|
'username' => Input::post( 'username' ),
|
||||||
@ -73,7 +80,7 @@ class Register extends Controller {
|
|||||||
self::$title = 'Recover Account - {SITENAME}';
|
self::$title = 'Recover Account - {SITENAME}';
|
||||||
Template::noIndex();
|
Template::noIndex();
|
||||||
if ( !Input::exists() ) {
|
if ( !Input::exists() ) {
|
||||||
return Views::view( 'forgot' );
|
return Views::view( 'auth.forgot' );
|
||||||
}
|
}
|
||||||
if ( Check::email( Input::post( 'entry' ) ) && self::$user->findByEmail( Input::post( 'entry' ) ) ) {
|
if ( Check::email( Input::post( 'entry' ) ) && self::$user->findByEmail( Input::post( 'entry' ) ) ) {
|
||||||
$userData = self::$user->data();
|
$userData = self::$user->data();
|
||||||
@ -89,48 +96,50 @@ class Register extends Controller {
|
|||||||
Redirect::to( 'home/login' );
|
Redirect::to( 'home/login' );
|
||||||
}
|
}
|
||||||
Issues::add( 'error', 'User not found.' );
|
Issues::add( 'error', 'User not found.' );
|
||||||
Views::view( 'forgot' );
|
Views::view( 'auth.forgot' );
|
||||||
}
|
}
|
||||||
|
|
||||||
public function resend() {
|
public function resend() {
|
||||||
self::$title = 'Resend Confirmation';
|
self::$title = 'Resend Confirmation';
|
||||||
|
Template::noIndex();
|
||||||
if ( !App::$isLoggedIn ) {
|
if ( !App::$isLoggedIn ) {
|
||||||
return Issues::add( 'notice', 'Please log in to resend your confirmation email.' );
|
return Issues::add( 'notice', 'Please log in to resend your confirmation email.' );
|
||||||
}
|
}
|
||||||
if ( App::$activeUser->data()->confirmed == '1' ) {
|
if ( App::$activeUser->confirmed == '1' ) {
|
||||||
return Issues::add( 'notice', 'Your account has already been confirmed.' );
|
return Issues::add( 'notice', 'Your account has already been confirmed.' );
|
||||||
}
|
}
|
||||||
if ( !Forms::check( 'confirmationResend' ) ) {
|
if ( !Forms::check( 'confirmationResend' ) ) {
|
||||||
return Views::view( 'email.confirmation_resend' );
|
return Views::view( 'auth.confirmation_resend' );
|
||||||
}
|
}
|
||||||
Email::send( App::$activeUser->data()->email, 'confirmation', App::$activeUser->data()->confirmationCode, [ 'template' => true ] );
|
Email::send( App::$activeUser->email, 'confirmation', App::$activeUser->confirmationCode, [ 'template' => true ] );
|
||||||
Session::flash( 'success', 'Your confirmation email has been sent to the email for your account.' );
|
Session::flash( 'success', 'Your confirmation email has been sent to the email for your account.' );
|
||||||
Redirect::to( 'home/index' );
|
Redirect::to( 'home/index' );
|
||||||
}
|
}
|
||||||
|
|
||||||
public function reset( $code = null ) {
|
public function reset( $code = null ) {
|
||||||
self::$title = 'Password Reset';
|
self::$title = 'Password Reset';
|
||||||
|
Template::noIndex();
|
||||||
if ( !isset( $code ) && !Input::exists( 'resetCode' ) ) {
|
if ( !isset( $code ) && !Input::exists( 'resetCode' ) ) {
|
||||||
Issues::add( 'error', 'No reset code provided.' );
|
Issues::add( 'info', 'Please provide a reset code.' );
|
||||||
return Views::view( 'password_reset_code' );
|
return Views::view( 'auth.password_reset_code' );
|
||||||
}
|
}
|
||||||
if ( Input::exists( 'resetCode' ) ) {
|
if ( Input::exists( 'resetCode' ) ) {
|
||||||
if ( Forms::check( 'password_reset_code' ) ) {
|
if ( Forms::check( 'passwordResetCode' ) ) {
|
||||||
$code = Input::post( 'resetCode' );
|
$code = Input::post( 'resetCode' );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ( !self::$user->checkCode( $code ) ) {
|
if ( ! self::$user->checkCode( $code ) ) {
|
||||||
Issues::add( 'error', 'There was an error with your reset code. Please try again.' );
|
Issues::add( 'error', 'There was an error with your reset code. Please try again.' );
|
||||||
return Views::view( 'password_reset_code' );
|
return Views::view( 'auth.password_reset_code' );
|
||||||
}
|
|
||||||
if ( !Input::exists() ) {
|
|
||||||
return Views::view( 'password_reset' );
|
|
||||||
}
|
|
||||||
if ( !Forms::check( 'passwordReset' ) ) {
|
|
||||||
Issues::add( 'error', [ 'There was an error with your request.' => Check::userErrors() ] );
|
|
||||||
return Views::view( 'password_reset' );
|
|
||||||
}
|
}
|
||||||
Components::set( 'resetCode', $code );
|
Components::set( 'resetCode', $code );
|
||||||
|
if ( ! Input::exists('password') ) {
|
||||||
|
return Views::view( 'auth.password_reset' );
|
||||||
|
}
|
||||||
|
if ( ! Forms::check( 'passwordReset' ) ) {
|
||||||
|
Issues::add( 'error', [ 'There was an error with your request.' => Check::userErrors() ] );
|
||||||
|
return Views::view( 'auth.password_reset' );
|
||||||
|
}
|
||||||
self::$user->changePassword( $code, Input::post( 'password' ) );
|
self::$user->changePassword( $code, Input::post( 'password' ) );
|
||||||
Email::send( self::$user->data()->email, 'passwordChange', null, [ 'template' => true ] );
|
Email::send( self::$user->data()->email, 'passwordChange', null, [ 'template' => true ] );
|
||||||
Session::flash( 'success', 'Your Password has been changed, please use your new password to log in.' );
|
Session::flash( 'success', 'Your Password has been changed, please use your new password to log in.' );
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
*
|
*
|
||||||
* This is the user control panel controller.
|
* This is the user control panel controller.
|
||||||
*
|
*
|
||||||
* @version 3.0
|
* @version 5.0.1
|
||||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||||
* @link https://TheTempusProject.com
|
* @link https://TheTempusProject.com
|
||||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||||
@ -31,18 +31,19 @@ use TheTempusProject\Bedrock\Functions\Session;
|
|||||||
class Usercp extends Controller {
|
class Usercp extends Controller {
|
||||||
public function __construct() {
|
public function __construct() {
|
||||||
parent::__construct();
|
parent::__construct();
|
||||||
if ( !App::$isLoggedIn ) {
|
if ( ! App::$isLoggedIn ) {
|
||||||
Session::flash( 'notice', 'You must be logged in to view this page!' );
|
Session::flash( 'notice', 'You must be logged in to view this page!' );
|
||||||
Redirect::home();
|
Redirect::home();
|
||||||
}
|
}
|
||||||
Template::noIndex();
|
Template::noIndex();
|
||||||
Navigation::activePageSelect( 'nav.usercp', null, true );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function email() {
|
public function email() {
|
||||||
self::$title = 'Email Settings';
|
self::$title = 'Email Settings';
|
||||||
|
$menu = Views::simpleView( 'nav.usercp', App::$userCPlinks );
|
||||||
|
Navigation::activePageSelect( $menu, null, true, true );
|
||||||
if ( App::$activeUser->confirmed != '1' ) {
|
if ( App::$activeUser->confirmed != '1' ) {
|
||||||
return Issues::add( 'notice', 'You need to confirm your email address before you can make modifications. If you would like to resend that confirmation link, please <a href="{BASE}register/resend">click here</a>', true );
|
return Issues::add( 'notice', 'You need to confirm your email address before you can make modifications. If you would like to resend that confirmation link, please <a href="/register/resend">click here</a>', true );
|
||||||
}
|
}
|
||||||
if ( !Input::exists() ) {
|
if ( !Input::exists() ) {
|
||||||
return Views::view( 'user_cp.email_change' );
|
return Views::view( 'user_cp.email_change' );
|
||||||
@ -67,11 +68,15 @@ class Usercp extends Controller {
|
|||||||
|
|
||||||
public function index() {
|
public function index() {
|
||||||
self::$title = 'User Control Panel';
|
self::$title = 'User Control Panel';
|
||||||
Views::view( 'profile', App::$activeUser );
|
$menu = Views::simpleView( 'nav.usercp', App::$userCPlinks );
|
||||||
|
Navigation::activePageSelect( $menu, null, true, true );
|
||||||
|
Views::view( 'user_cp.profile', App::$activeUser );
|
||||||
}
|
}
|
||||||
|
|
||||||
public function password() {
|
public function password() {
|
||||||
self::$title = 'Password Settings';
|
self::$title = 'Password Settings';
|
||||||
|
$menu = Views::simpleView( 'nav.usercp', App::$userCPlinks );
|
||||||
|
Navigation::activePageSelect( $menu, null, true, true );
|
||||||
if ( !Input::exists() ) {
|
if ( !Input::exists() ) {
|
||||||
return Views::view( 'user_cp.password_change' );
|
return Views::view( 'user_cp.password_change' );
|
||||||
}
|
}
|
||||||
@ -93,8 +98,10 @@ class Usercp extends Controller {
|
|||||||
|
|
||||||
public function settings() {
|
public function settings() {
|
||||||
self::$title = 'Preferences';
|
self::$title = 'Preferences';
|
||||||
|
$menu = Views::simpleView( 'nav.usercp', App::$userCPlinks );
|
||||||
|
Navigation::activePageSelect( $menu, null, true, true );
|
||||||
$prefs = new Preferences;
|
$prefs = new Preferences;
|
||||||
$fields = App::$activePrefs;
|
$userPrefs = App::$activePrefs;
|
||||||
if ( Input::exists( 'submit' ) ) {
|
if ( Input::exists( 'submit' ) ) {
|
||||||
$fields = $prefs->convertFormToArray( true, false );
|
$fields = $prefs->convertFormToArray( true, false );
|
||||||
// @TODO now i may need to rework the form checker to work with this....
|
// @TODO now i may need to rework the form checker to work with this....
|
||||||
@ -103,9 +110,48 @@ class Usercp extends Controller {
|
|||||||
// }
|
// }
|
||||||
self::$user->updatePrefs( $fields, App::$activeUser->ID );
|
self::$user->updatePrefs( $fields, App::$activeUser->ID );
|
||||||
Issues::add( 'success', 'Your preferences have been updated.' );
|
Issues::add( 'success', 'Your preferences have been updated.' );
|
||||||
|
// if the image upload fails, need to fall back on original
|
||||||
|
if ( empty( $fields['avatar'] ) ) {
|
||||||
|
$fields['avatar'] = $userPrefs['avatar'];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$fields = $userPrefs;
|
||||||
}
|
}
|
||||||
Components::set( 'AVATAR_SETTINGS', $fields['avatar'] );
|
Components::set( 'AVATAR_SETTINGS', $fields['avatar'] );
|
||||||
Components::set( 'PREFERENCES_FORM', $prefs->getFormHtml( $fields ) );
|
Components::set( 'PREFERENCES_FORM', $prefs->getFormHtml( $fields ) );
|
||||||
Views::view( 'user_cp.settings', App::$activeUser );
|
Views::view( 'user_cp.settings', App::$activeUser );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function updatePref() {
|
||||||
|
Template::setTemplate( 'api' );
|
||||||
|
if ( ! App::$isLoggedIn ) {
|
||||||
|
return Views::view( 'api.response', ['response' => json_encode( [ 'error' => 'Not Logged In' ], true )]);
|
||||||
|
}
|
||||||
|
if ( ! Forms::check( 'updatePreference' ) ) {
|
||||||
|
return Views::view( 'api.response', ['response' => json_encode( [ 'error' => Check::userErrors() ], true )]);
|
||||||
|
}
|
||||||
|
$name = Input::post( 'prefName' );
|
||||||
|
$value = Input::post('prefValue' );
|
||||||
|
|
||||||
|
if ( 'false' === $value ) {
|
||||||
|
$value = false;
|
||||||
|
} elseif ( 'true' === $value ) {
|
||||||
|
$value = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( empty( Preferences::get( $name ) ) ) {
|
||||||
|
return Views::view( 'api.response', ['response' => json_encode( [ 'error' => 'Unknown Preference' ], true )]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$prefs = new Preferences;
|
||||||
|
$fields1 = $prefs->convertFormToArray( true, false );
|
||||||
|
$fields3 = $fields1;
|
||||||
|
|
||||||
|
if ( isset( $fields1[ $name ] ) ) {
|
||||||
|
$fields3[ $name ] = $value;
|
||||||
|
}
|
||||||
|
$result = self::$user->updatePrefs( $fields3, App::$activeUser->ID );
|
||||||
|
|
||||||
|
return Views::view( 'api.response', ['response' => json_encode( $result, true )]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
*
|
*
|
||||||
* This is css used in the debuging console.
|
* This is css used in the debuging console.
|
||||||
*
|
*
|
||||||
* @version 3.0
|
* @version 5.0.1
|
||||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||||
* @link https://TheTempusProject.com
|
* @link https://TheTempusProject.com
|
||||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||||
|
161
app/css/main-dark.css
Normal file
161
app/css/main-dark.css
Normal file
@ -0,0 +1,161 @@
|
|||||||
|
/**
|
||||||
|
* app/css/main-dark.css
|
||||||
|
*
|
||||||
|
* This file provides dark mode styles to override existing Bootstrap 5 base styles.
|
||||||
|
*
|
||||||
|
* @version 5.0.1
|
||||||
|
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||||
|
* @link https://TheTempusProject.com
|
||||||
|
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||||
|
*/
|
||||||
|
|
||||||
|
.context-main-border {
|
||||||
|
border-color: #f5f5f5!important;
|
||||||
|
}
|
||||||
|
.context-main-border-other {
|
||||||
|
border-color: #1e1e1e!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.context-main-bg {
|
||||||
|
background-color: #2c2c2c;
|
||||||
|
}
|
||||||
|
.context-second-bg {
|
||||||
|
background-color: #383838;
|
||||||
|
}
|
||||||
|
.context-third-bg {
|
||||||
|
background-color: #3a3a3a;
|
||||||
|
}
|
||||||
|
.context-other-bg {
|
||||||
|
background-color: #1e1e1e;
|
||||||
|
}
|
||||||
|
|
||||||
|
.context-main {
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.bg-default {
|
||||||
|
background-color: #2c2c2c;
|
||||||
|
}
|
||||||
|
hr {
|
||||||
|
color: #f5f5f5;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.bg-none,.bg-warning {
|
||||||
|
color: #000 !important;
|
||||||
|
}
|
||||||
|
.accordion-button:not(.collapsed) {
|
||||||
|
color: #f5f5f5;
|
||||||
|
background-color: var(--bs-accordion-dark-active-bg);
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
background-image: linear-gradient(180deg, #2c2c2c, #1e1e1e 100px, #1e1e1e);
|
||||||
|
color: #f5f5f5;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Install Terms
|
||||||
|
*/
|
||||||
|
.install-terms {
|
||||||
|
border: 1px solid #555;
|
||||||
|
background: #3a3a3a;
|
||||||
|
}
|
||||||
|
.install-terms p,
|
||||||
|
.install-terms li {
|
||||||
|
color: #dcdcdc;
|
||||||
|
}
|
||||||
|
.install-terms h3 {
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
.install-terms h4 {
|
||||||
|
color: #eaeaea;
|
||||||
|
}
|
||||||
|
.install-terms strong {
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Terms Page
|
||||||
|
*/
|
||||||
|
.terms-page {
|
||||||
|
border: 1px solid #555;
|
||||||
|
background: #3a3a3a;
|
||||||
|
}
|
||||||
|
.terms-page p,
|
||||||
|
.terms-page li {
|
||||||
|
color: #dcdcdc;
|
||||||
|
}
|
||||||
|
.terms-page h3 {
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
.terms-page h4 {
|
||||||
|
color: #eaeaea;
|
||||||
|
}
|
||||||
|
.terms-page strong {
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Terms
|
||||||
|
*/
|
||||||
|
.terms {
|
||||||
|
border: 1px solid #555;
|
||||||
|
background: #3a3a3a;
|
||||||
|
}
|
||||||
|
.terms p,
|
||||||
|
.terms li {
|
||||||
|
color: #dcdcdc;
|
||||||
|
}
|
||||||
|
.terms h3 {
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
.terms h4 {
|
||||||
|
color: #eaeaea;
|
||||||
|
}
|
||||||
|
.terms strong {
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Form Control
|
||||||
|
*/
|
||||||
|
.form-control-dark:focus {
|
||||||
|
border-color: #1e90ff;
|
||||||
|
box-shadow: 0 0 0 .25rem rgba(30, 144, 255, .5);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Example Divider
|
||||||
|
*/
|
||||||
|
.b-example-divider {
|
||||||
|
background-color: rgba(255, 255, 255, .1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Text Shadows
|
||||||
|
*/
|
||||||
|
.text-shadow-1 {
|
||||||
|
text-shadow: 0 .125rem .25rem rgba(255, 255, 255, .25);
|
||||||
|
}
|
||||||
|
.text-shadow-2 {
|
||||||
|
text-shadow: 0 .25rem .5rem rgba(255, 255, 255, .25);
|
||||||
|
}
|
||||||
|
.text-shadow-3 {
|
||||||
|
text-shadow: 0 .5rem 1.5rem rgba(255, 255, 255, .25);
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-control {
|
||||||
|
background-color: #1f1f1f;
|
||||||
|
color: #e0e0e0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-control:focus {
|
||||||
|
color: #e0e0e0;
|
||||||
|
border-color: #1e90ff;
|
||||||
|
background-color: #1f1f1f;
|
||||||
|
box-shadow: 0 0 0 .25rem rgba(30, 144, 255, .5);
|
||||||
|
}
|
760
app/css/main.css
760
app/css/main.css
@ -3,26 +3,111 @@
|
|||||||
*
|
*
|
||||||
* This file is for any css that should be applied site wide.
|
* This file is for any css that should be applied site wide.
|
||||||
*
|
*
|
||||||
* @version 3.0
|
* @version 5.0.1
|
||||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||||
* @link https://TheTempusProject.com
|
* @link https://TheTempusProject.com
|
||||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
.context-main-border {
|
||||||
|
border-color: #1e1e1e!important;
|
||||||
|
}
|
||||||
|
.context-main-border-other {
|
||||||
|
border-color: #f5f5f5!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.context-main-bg {
|
||||||
|
background-color: #f7f7f7;
|
||||||
|
/* background-color: #b1b; */
|
||||||
|
}
|
||||||
|
.context-second-bg {
|
||||||
|
background-color: #eaeaea;
|
||||||
|
/* background-color: #b1b; */
|
||||||
|
}
|
||||||
|
.context-third-bg {
|
||||||
|
background-color: #ccc;
|
||||||
|
/* background-color: #b1b; */
|
||||||
|
}
|
||||||
|
|
||||||
|
.context-main {
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.nav-link.active {
|
||||||
|
font-weight: bold; /* Make the text bold */
|
||||||
|
}
|
||||||
|
|
||||||
|
hr {
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Base styles for the switch container */
|
||||||
|
.material-switch {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
width: 50px;
|
||||||
|
height: 25px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hide the default checkbox */
|
||||||
|
.material-switch input {
|
||||||
|
opacity: 0;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Style the label as the switch */
|
||||||
|
.material-switch .label-default {
|
||||||
|
position: absolute;
|
||||||
|
cursor: pointer;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background-color: var(--switch-off-bg, #ccc);
|
||||||
|
border-radius: 25px;
|
||||||
|
transition: background-color 0.3s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Style the toggle circle (slider) */
|
||||||
|
.material-switch .label-default::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
height: 20px;
|
||||||
|
width: 20px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background-color: var(--switch-slider-bg, #fff);
|
||||||
|
bottom: 2.5px;
|
||||||
|
left: 5px;
|
||||||
|
transition: transform 0.3s ease-in-out;
|
||||||
|
box-shadow: 0 2px 4px #00000033;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Change background color when checked */
|
||||||
|
.material-switch input:checked + .label-default {
|
||||||
|
background-color: var(--switch-on-bg, #555); /* Bootstrap primary color */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Move the slider when checked */
|
||||||
|
.material-switch input:checked + .label-default::before {
|
||||||
|
transform: translateX(25px); /* Adjust based on switch width */
|
||||||
|
}
|
||||||
|
|
||||||
html {
|
html {
|
||||||
font-family: 'Open Sans', sans-serif;
|
font-family: 'Open Sans', sans-serif;
|
||||||
position: relative;
|
position: relative;
|
||||||
min-height: 100%;
|
min-height: 100%;
|
||||||
}
|
}
|
||||||
body {
|
|
||||||
margin-top: 100px;
|
|
||||||
}
|
|
||||||
pre {
|
pre {
|
||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
background-color: #e4e4e4;
|
||||||
|
/* background-image: linear-gradient(180deg, #eee, #fff 100px, #fff); */
|
||||||
|
}
|
||||||
@media ( min-width: 768px ) {
|
@media ( min-width: 768px ) {
|
||||||
body {
|
|
||||||
margin-top: 75px;
|
|
||||||
}
|
|
||||||
.main {
|
.main {
|
||||||
padding-right: 40px;
|
padding-right: 40px;
|
||||||
padding-left: 40px;
|
padding-left: 40px;
|
||||||
@ -31,546 +116,9 @@ pre {
|
|||||||
padding-right: 225px;
|
padding-right: 225px;
|
||||||
padding-left: 0;
|
padding-left: 0;
|
||||||
}
|
}
|
||||||
.side-nav {
|
.bd-placeholder-img-lg {
|
||||||
right: 0;
|
font-size: 3.5rem;
|
||||||
left: auto;
|
|
||||||
}
|
}
|
||||||
.side-nav {
|
|
||||||
position: fixed;
|
|
||||||
top: 51px;
|
|
||||||
left: 225px;
|
|
||||||
width: 225px;
|
|
||||||
margin-left: -225px;
|
|
||||||
border: none;
|
|
||||||
border-radius: 0;
|
|
||||||
overflow-y: auto;
|
|
||||||
background-color: #222;
|
|
||||||
bottom: 53px;
|
|
||||||
overflow-x: hidden;
|
|
||||||
padding-bottom: 10px;
|
|
||||||
}
|
|
||||||
.side-nav>li>a {
|
|
||||||
width: 225px;
|
|
||||||
}
|
|
||||||
.side-nav li a:hover,
|
|
||||||
.side-nav li a:focus {
|
|
||||||
outline: none;
|
|
||||||
background-color: #000 !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Other
|
|
||||||
*/
|
|
||||||
.custom-nav {
|
|
||||||
display: relative;
|
|
||||||
float: right;
|
|
||||||
}
|
|
||||||
.navbar-form-alt {
|
|
||||||
margin-top: 10px;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
.bars {
|
|
||||||
display: block;
|
|
||||||
width: 60px;
|
|
||||||
height: 3px;
|
|
||||||
background-color: #333;
|
|
||||||
box-shadow: 0 5px 0 #333, 0 10px 0 #333;
|
|
||||||
}
|
|
||||||
.slide-text-bg {
|
|
||||||
opacity: 0.6;
|
|
||||||
}
|
|
||||||
.avatar-125 {
|
|
||||||
height: 125px;
|
|
||||||
width: 125px;
|
|
||||||
}
|
|
||||||
.full {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
.gap {
|
|
||||||
height: 30px;
|
|
||||||
width: 100%;
|
|
||||||
clear: both;
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
.supportLi h4 {
|
|
||||||
font-size: 20px;
|
|
||||||
font-weight: lighter;
|
|
||||||
line-height: normal;
|
|
||||||
margin-bottom: 0 !important;
|
|
||||||
padding-bottom: 0;
|
|
||||||
}
|
|
||||||
.bg-gray {
|
|
||||||
background-image: -moz-linear-gradient( center bottom, #BBBBBB 0%, #F0F0F0 100% );
|
|
||||||
box-shadow: 0 1px 0 #B4B3B3;
|
|
||||||
}
|
|
||||||
.payments {
|
|
||||||
font-size: 1.5em;
|
|
||||||
}
|
|
||||||
.UI-buffer {
|
|
||||||
padding-top: 35px;
|
|
||||||
height: auto;
|
|
||||||
border-bottom: 1px solid #CCCCCC;
|
|
||||||
}
|
|
||||||
.avatar {
|
|
||||||
max-width: 33px;
|
|
||||||
}
|
|
||||||
.UI-page-buffer {
|
|
||||||
padding-top: 30px;
|
|
||||||
position: relative;
|
|
||||||
height: auto;
|
|
||||||
border-bottom: 1px solid #CCCCCC;
|
|
||||||
}
|
|
||||||
.main {
|
|
||||||
padding: 20px;
|
|
||||||
padding-bottom: 75px;
|
|
||||||
}
|
|
||||||
.user-row {
|
|
||||||
margin-bottom: 14px;
|
|
||||||
}
|
|
||||||
.user-row:last-child {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
.dropdown-user {
|
|
||||||
margin: 13px 0;
|
|
||||||
padding: 5px;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
.dropdown-user:hover {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
.table-user-information>tbody>tr {
|
|
||||||
border-top: 1px solid rgb( 221, 221, 221 );
|
|
||||||
}
|
|
||||||
.table-user-information>tbody>tr:first-child {
|
|
||||||
border-top: 0;
|
|
||||||
}
|
|
||||||
.table-user-information>tbody>tr>td {
|
|
||||||
border-top: 0;
|
|
||||||
}
|
|
||||||
.top-pad {
|
|
||||||
margin-top: 70px;
|
|
||||||
}
|
|
||||||
.foot-pad {
|
|
||||||
padding-bottom: 0;
|
|
||||||
/* padding-bottom: 261px; */
|
|
||||||
}
|
|
||||||
.dynamic-footer-padding {
|
|
||||||
padding-bottom: var(--footer-height);
|
|
||||||
}
|
|
||||||
.footer-head .navbar-toggle {
|
|
||||||
display: inline-block;
|
|
||||||
float: none;
|
|
||||||
}
|
|
||||||
.avatar-round-40 {
|
|
||||||
height: 40px;
|
|
||||||
width: 40px;
|
|
||||||
}
|
|
||||||
.sticky-foot-head {
|
|
||||||
z-index: 10;
|
|
||||||
position: fixed;
|
|
||||||
bottom: 51px;
|
|
||||||
width: 100%;
|
|
||||||
background: #EDEFF1;
|
|
||||||
border-bottom: 1px solid #CCCCCC;
|
|
||||||
border-top: 1px solid #DDDDDD;
|
|
||||||
}
|
|
||||||
.sticky-foot {
|
|
||||||
background-color: #000;
|
|
||||||
position: fixed;
|
|
||||||
bottom: 0;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
.sticky-copy {
|
|
||||||
z-index: 10;
|
|
||||||
padding-top: 10px;
|
|
||||||
padding-bottom: 10px;
|
|
||||||
height: 50px;
|
|
||||||
background: #E3E3E3;
|
|
||||||
border-bottom: 1px solid #CCCCCC;
|
|
||||||
border-top: 1px solid #DDDDDD;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Main Carousel
|
|
||||||
*/
|
|
||||||
.main-text {
|
|
||||||
padding-bottom: 0px;
|
|
||||||
padding-top: 0px;
|
|
||||||
top: 10px;
|
|
||||||
bottom: auto;
|
|
||||||
z-index: 10;
|
|
||||||
width: auto;
|
|
||||||
color: #FFF;
|
|
||||||
}
|
|
||||||
.btn-min-block {
|
|
||||||
min-width: 170px;
|
|
||||||
line-height: 26px;
|
|
||||||
}
|
|
||||||
.btn-clear {
|
|
||||||
color: #FFF;
|
|
||||||
background-color: transparent;
|
|
||||||
border-color: #FFF;
|
|
||||||
margin-right: 15px;
|
|
||||||
}
|
|
||||||
.btn-clear:hover {
|
|
||||||
color: #000;
|
|
||||||
background-color: #FFF;
|
|
||||||
}
|
|
||||||
#carousel-example-generic {
|
|
||||||
margin-bottom: 30px;
|
|
||||||
}
|
|
||||||
.col-centered {
|
|
||||||
float: none;
|
|
||||||
margin: 0 auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Top Navigation
|
|
||||||
*/
|
|
||||||
.top-nav {
|
|
||||||
padding: 0 15px;
|
|
||||||
}
|
|
||||||
.top-nav>li {
|
|
||||||
display: inline-block;
|
|
||||||
float: left;
|
|
||||||
}
|
|
||||||
.top-nav>li>a {
|
|
||||||
padding-top: 15px;
|
|
||||||
padding-bottom: 15px;
|
|
||||||
line-height: 20px;
|
|
||||||
color: #999;
|
|
||||||
}
|
|
||||||
.top-nav>li>a:hover,
|
|
||||||
.top-nav>li>a:focus,
|
|
||||||
.top-nav>.open>a,
|
|
||||||
.top-nav>.open>a:hover,
|
|
||||||
.top-nav>.open>a:focus {
|
|
||||||
color: #fff;
|
|
||||||
background-color: #000;
|
|
||||||
}
|
|
||||||
.top-nav>.open>.dropdown-menu {
|
|
||||||
float: left;
|
|
||||||
position: absolute;
|
|
||||||
margin-top: 0;
|
|
||||||
border: 1px solid rgba( 0, 0, 0, .15 );
|
|
||||||
border-top-left-radius: 0;
|
|
||||||
border-top-right-radius: 0;
|
|
||||||
background-color: #fff;
|
|
||||||
-webkit-box-shadow: 0 6px 12px rgba( 0, 0, 0, .175 );
|
|
||||||
box-shadow: 0 6px 12px rgba( 0, 0, 0, .175 );
|
|
||||||
}
|
|
||||||
.top-nav>.open>.dropdown-menu>li>a {
|
|
||||||
white-space: normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Messages Dropdown
|
|
||||||
*/
|
|
||||||
ul.message-dropdown {
|
|
||||||
padding: 0;
|
|
||||||
max-height: 250px;
|
|
||||||
overflow-x: hidden;
|
|
||||||
overflow-y: auto;
|
|
||||||
}
|
|
||||||
li.message-header {
|
|
||||||
margin: 5px 0;
|
|
||||||
border-bottom: 1px solid rgba( 0, 0, 0, .15 );
|
|
||||||
}
|
|
||||||
li.message-preview {
|
|
||||||
width: 275px;
|
|
||||||
border-bottom: 1px solid rgba( 0, 0, 0, .15 );
|
|
||||||
}
|
|
||||||
li.message-preview>a {
|
|
||||||
padding-top: 15px;
|
|
||||||
padding-bottom: 15px;
|
|
||||||
}
|
|
||||||
li.message-footer {
|
|
||||||
margin: 5px 0;
|
|
||||||
}
|
|
||||||
ul.alert-dropdown {
|
|
||||||
width: 200px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Widget
|
|
||||||
*/
|
|
||||||
.widget .list-group {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
.widget .panel-title {
|
|
||||||
display: inline
|
|
||||||
}
|
|
||||||
.widget .label {
|
|
||||||
float: right;
|
|
||||||
}
|
|
||||||
.widget li.list-group-item {
|
|
||||||
border-radius: 0;
|
|
||||||
border: 0;
|
|
||||||
border-top: 1px solid #ddd;
|
|
||||||
}
|
|
||||||
.widget li.list-group-item:hover {
|
|
||||||
background-color: rgba( 86, 61, 124, .1 );
|
|
||||||
}
|
|
||||||
.widget .mic-info {
|
|
||||||
color: #666666;
|
|
||||||
font-size: 11px;
|
|
||||||
}
|
|
||||||
.widget .action {
|
|
||||||
margin-top: 5px;
|
|
||||||
}
|
|
||||||
.widget .comment-text {
|
|
||||||
font-size: 12px;
|
|
||||||
}
|
|
||||||
.widget .btn-block {
|
|
||||||
border-top-left-radius: 0px;
|
|
||||||
border-top-right-radius: 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Signin Form
|
|
||||||
*/
|
|
||||||
.form-signin {
|
|
||||||
max-width: 330px;
|
|
||||||
padding: 15px;
|
|
||||||
margin: 0 auto;
|
|
||||||
}
|
|
||||||
.form-signin .form-signin-heading,
|
|
||||||
.form-signin .checkbox {
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
.form-signin .checkbox {
|
|
||||||
font-weight: normal;
|
|
||||||
}
|
|
||||||
.form-signin .form-control {
|
|
||||||
position: relative;
|
|
||||||
height: auto;
|
|
||||||
-webkit-box-sizing: border-box;
|
|
||||||
-moz-box-sizing: border-box;
|
|
||||||
box-sizing: border-box;
|
|
||||||
padding: 10px;
|
|
||||||
font-size: 16px;
|
|
||||||
}
|
|
||||||
.form-signin .form-control:focus {
|
|
||||||
z-index: 2;
|
|
||||||
}
|
|
||||||
.form-signin input[type="text"] {
|
|
||||||
margin-bottom: -1px;
|
|
||||||
border-bottom-right-radius: 0;
|
|
||||||
border-bottom-left-radius: 0;
|
|
||||||
}
|
|
||||||
.form-signin input[type="password"] {
|
|
||||||
margin-bottom: 10px;
|
|
||||||
border-top-left-radius: 0;
|
|
||||||
border-top-right-radius: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Footer and Copyright
|
|
||||||
*/
|
|
||||||
.copy {
|
|
||||||
z-index: 10;
|
|
||||||
padding-top: 10px;
|
|
||||||
padding-bottom: 10px;
|
|
||||||
position: absolute;
|
|
||||||
bottom: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: 50px;
|
|
||||||
background: #E3E3E3;
|
|
||||||
border-bottom: 1px solid #CCCCCC;
|
|
||||||
border-top: 1px solid #DDDDDD;
|
|
||||||
}
|
|
||||||
.footer-head {
|
|
||||||
z-index: 10;
|
|
||||||
position: absolute;
|
|
||||||
bottom: 51px;
|
|
||||||
width: 100%;
|
|
||||||
background: #EDEFF1;
|
|
||||||
border-bottom: 1px solid #CCCCCC;
|
|
||||||
border-top: 1px solid #DDDDDD;
|
|
||||||
}
|
|
||||||
.footer-head p {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
.footer-head img {
|
|
||||||
max-width: 100%;
|
|
||||||
}
|
|
||||||
.footer-head h3 {
|
|
||||||
border-bottom: 1px solid #BAC1C8;
|
|
||||||
color: #54697E;
|
|
||||||
font-size: 18px;
|
|
||||||
font-weight: 600;
|
|
||||||
line-height: 27px;
|
|
||||||
padding: 5px 0 10px;
|
|
||||||
text-transform: uppercase;
|
|
||||||
}
|
|
||||||
.footer-head ul {
|
|
||||||
font-size: 13px;
|
|
||||||
list-style-type: none;
|
|
||||||
margin-left: 0;
|
|
||||||
padding-left: 0;
|
|
||||||
margin-top: 15px;
|
|
||||||
color: #7F8C8D;
|
|
||||||
}
|
|
||||||
.footer-head ul li a {
|
|
||||||
padding: 0 0 5px 0;
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
.footer-head a {
|
|
||||||
color: #78828D
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Side Navigation
|
|
||||||
*/
|
|
||||||
.side-nav>li>ul {
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
.side-nav>li>ul>li>a {
|
|
||||||
display: block;
|
|
||||||
padding: 10px 15px 10px 38px;
|
|
||||||
text-decoration: none;
|
|
||||||
color: #999;
|
|
||||||
}
|
|
||||||
.side-nav>li>ul>li>a:hover {
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
.side-nav .active > a {
|
|
||||||
color: #fff;
|
|
||||||
background-color: #080808;
|
|
||||||
}
|
|
||||||
.side-nav .active > a:hover {
|
|
||||||
color: #fff;
|
|
||||||
background-color: #080808;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Social
|
|
||||||
*/
|
|
||||||
.social {
|
|
||||||
margin-top: 75px;
|
|
||||||
bottom: 0;
|
|
||||||
}
|
|
||||||
.content {
|
|
||||||
position: absolute;
|
|
||||||
}
|
|
||||||
.social span {
|
|
||||||
background: none repeat scroll 0 0 #B5B5B5;
|
|
||||||
border: 2px solid #B5B5B5;
|
|
||||||
-webkit-border-radius: 50%;
|
|
||||||
-moz-border-radius: 50%;
|
|
||||||
-o-border-radius: 50%;
|
|
||||||
-ms-border-radius: 50%;
|
|
||||||
border-radius: 50%;
|
|
||||||
float: center;
|
|
||||||
height: 36px;
|
|
||||||
line-height: 36px;
|
|
||||||
margin: 0 8px 0 0;
|
|
||||||
padding: 0;
|
|
||||||
text-align: center;
|
|
||||||
width: 41px;
|
|
||||||
transition: all 0.5s ease 0s;
|
|
||||||
-moz-transition: all 0.5s ease 0s;
|
|
||||||
-webkit-transition: all 0.5s ease 0s;
|
|
||||||
-ms-transition: all 0.5s ease 0s;
|
|
||||||
-o-transition: all 0.5s ease 0s;
|
|
||||||
}
|
|
||||||
.social span:hover {
|
|
||||||
transform: scale( 1.15 ) rotate( 360deg) ;
|
|
||||||
-webkit-transform: scale( 1.1 ) rotate( 360deg) ;
|
|
||||||
-moz-transform: scale( 1.1 ) rotate( 360deg) ;
|
|
||||||
-ms-transform: scale( 1.1 ) rotate( 360deg) ;
|
|
||||||
-o-transform: scale( 1.1 ) rotate( 360deg) ;
|
|
||||||
}
|
|
||||||
.social span a {
|
|
||||||
color: #EDEFF1;
|
|
||||||
}
|
|
||||||
.social span:hover {
|
|
||||||
border: 2px solid #2c3e50;
|
|
||||||
background: #2c3e50;
|
|
||||||
}
|
|
||||||
.social span a i {
|
|
||||||
font-size: 16px;
|
|
||||||
margin: 0 0 0 5px;
|
|
||||||
color: #EDEFF1 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Newsletter Box
|
|
||||||
*/
|
|
||||||
.newsletter-box input#appendedInputButton {
|
|
||||||
background: #FFFFFF;
|
|
||||||
display: inline-block;
|
|
||||||
float: center;
|
|
||||||
height: 30px;
|
|
||||||
clear: both;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
.newsletter-box .btn {
|
|
||||||
border: medium none;
|
|
||||||
-webkit-border-radius: 3px;
|
|
||||||
-moz-border-radius: 3px;
|
|
||||||
-o-border-radius: 3px;
|
|
||||||
-ms-border-radius: 3px;
|
|
||||||
border-radius: 3px;
|
|
||||||
display: inline-block;
|
|
||||||
height: 40px;
|
|
||||||
padding: 0;
|
|
||||||
width: 100%;
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
.newsletter-box {
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Colored Badges
|
|
||||||
*/
|
|
||||||
.badge {
|
|
||||||
padding: 1px 9px 2px;
|
|
||||||
font-size: 12.025px;
|
|
||||||
font-weight: bold;
|
|
||||||
white-space: nowrap;
|
|
||||||
color: #ffffff;
|
|
||||||
background-color: #999999;
|
|
||||||
-webkit-border-radius: 9px;
|
|
||||||
-moz-border-radius: 9px;
|
|
||||||
border-radius: 9px;
|
|
||||||
}
|
|
||||||
.badge:hover {
|
|
||||||
color: #ffffff;
|
|
||||||
text-decoration: none;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
.badge-error {
|
|
||||||
background-color: #b94a48;
|
|
||||||
}
|
|
||||||
.badge-error:hover {
|
|
||||||
background-color: #953b39;
|
|
||||||
}
|
|
||||||
.badge-warning {
|
|
||||||
background-color: #f89406;
|
|
||||||
}
|
|
||||||
.badge-warning:hover {
|
|
||||||
background-color: #c67605;
|
|
||||||
}
|
|
||||||
.badge-success {
|
|
||||||
background-color: #468847;
|
|
||||||
}
|
|
||||||
.badge-success:hover {
|
|
||||||
background-color: #356635;
|
|
||||||
}
|
|
||||||
.badge-info {
|
|
||||||
background-color: #3a87ad;
|
|
||||||
}
|
|
||||||
.badge-info:hover {
|
|
||||||
background-color: #2d6987;
|
|
||||||
}
|
|
||||||
.badge-inverse {
|
|
||||||
background-color: #333333;
|
|
||||||
}
|
|
||||||
.badge-inverse:hover {
|
|
||||||
background-color: #1a1a1a;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -658,12 +206,120 @@ ul.alert-dropdown {
|
|||||||
.terms strong {
|
.terms strong {
|
||||||
color: #000;
|
color: #000;
|
||||||
}
|
}
|
||||||
|
.pricing-header {
|
||||||
|
max-width: 700px;
|
||||||
.navbar-header {
|
}
|
||||||
margin-right: 75px;
|
.pricing-container {
|
||||||
|
max-width: 960px;
|
||||||
|
}
|
||||||
|
.bd-placeholder-img {
|
||||||
|
font-size: 1.125rem;
|
||||||
|
text-anchor: middle;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
-moz-user-select: none;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
.b-example-vr {
|
||||||
|
flex-shrink: 0;
|
||||||
|
width: 1.5rem;
|
||||||
|
height: 100vh;
|
||||||
|
}
|
||||||
|
.bi {
|
||||||
|
vertical-align: -.125em;
|
||||||
|
fill: currentColor;
|
||||||
|
}
|
||||||
|
.form-control-dark {
|
||||||
|
border-color: var(--bs-gray);
|
||||||
|
}
|
||||||
|
.form-control-dark:focus {
|
||||||
|
border-color: #fff;
|
||||||
|
box-shadow: 0 0 0 .25rem rgba(255, 255, 255, .25);
|
||||||
|
}
|
||||||
|
.text-small {
|
||||||
|
font-size: 85%;
|
||||||
|
}
|
||||||
|
.dropdown-toggle {
|
||||||
|
outline: 0;
|
||||||
|
}
|
||||||
|
.b-example-divider {
|
||||||
|
height: 3rem;
|
||||||
|
background-color: rgba(0, 0, 0, .1);
|
||||||
|
border: solid rgba(0, 0, 0, .15);
|
||||||
|
border-width: 1px 0;
|
||||||
|
box-shadow: inset 0 .5em 1.5em rgba(0, 0, 0, .1), inset 0 .125em .5em rgba(0, 0, 0, .15);
|
||||||
|
}
|
||||||
|
.b-example-vr {
|
||||||
|
flex-shrink: 0;
|
||||||
|
width: 1.5rem;
|
||||||
|
height: 100vh;
|
||||||
|
}
|
||||||
|
.nav-scroller {
|
||||||
|
position: relative;
|
||||||
|
z-index: 2;
|
||||||
|
height: 2.75rem;
|
||||||
|
overflow-y: hidden;
|
||||||
|
}
|
||||||
|
.nav-scroller .nav {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
padding-bottom: 1rem;
|
||||||
|
margin-top: -1px;
|
||||||
|
overflow-x: auto;
|
||||||
|
text-align: center;
|
||||||
|
white-space: nowrap;
|
||||||
|
-webkit-overflow-scrolling: touch;
|
||||||
|
}
|
||||||
|
.b-example-vr {
|
||||||
|
flex-shrink: 0;
|
||||||
|
width: 1.5rem;
|
||||||
|
height: 100vh;
|
||||||
|
}
|
||||||
|
.feature-icon {
|
||||||
|
width: 4rem;
|
||||||
|
height: 4rem;
|
||||||
|
border-radius: .75rem;
|
||||||
|
}
|
||||||
|
.icon-link > .bi {
|
||||||
|
margin-top: .125rem;
|
||||||
|
margin-left: .125rem;
|
||||||
|
fill: currentcolor;
|
||||||
|
transition: transform .25s ease-in-out;
|
||||||
|
}
|
||||||
|
.icon-link:hover > .bi {
|
||||||
|
transform: translate(.25rem);
|
||||||
|
}
|
||||||
|
.icon-square {
|
||||||
|
width: 3rem;
|
||||||
|
height: 3rem;
|
||||||
|
border-radius: .75rem;
|
||||||
|
}
|
||||||
|
.text-shadow-1 {
|
||||||
|
text-shadow: 0 .125rem .25rem rgba(0, 0, 0, .25);
|
||||||
|
}
|
||||||
|
.text-shadow-2 {
|
||||||
|
text-shadow: 0 .25rem .5rem rgba(0, 0, 0, .25);
|
||||||
|
}
|
||||||
|
.text-shadow-3 {
|
||||||
|
text-shadow: 0 .5rem 1.5rem rgba(0, 0, 0, .25);
|
||||||
|
}
|
||||||
|
.card-cover {
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: center center;
|
||||||
|
background-size: cover;
|
||||||
|
}
|
||||||
|
.feature-icon-small {
|
||||||
|
width: 3rem;
|
||||||
|
height: 3rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.pagination {
|
.gradient-custom-2 {
|
||||||
padding-left: 75px;
|
/* fallback for old browsers */
|
||||||
|
background: #fccb90;
|
||||||
|
|
||||||
|
/* Chrome 10-25, Safari 5.1-6 */
|
||||||
|
background: -webkit-linear-gradient(to right, #2c2c2c, #1e1e1e, #1e1e1e);
|
||||||
|
|
||||||
|
/* W3C, IE 10+/ Edge, Firefox 16+, Chrome 26+, Opera 12+, Safari 7+ */
|
||||||
|
background: linear-gradient(to right, #2c2c2c, #1e1e1e, #1e1e1e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,218 +0,0 @@
|
|||||||
/**
|
|
||||||
* app/css/wysiwyg.css
|
|
||||||
*
|
|
||||||
* This file is for the wysiwyg editor's css.
|
|
||||||
*
|
|
||||||
* @version 3.0
|
|
||||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
|
||||||
* @link https://TheTempusProject.com
|
|
||||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
|
||||||
*/
|
|
||||||
body {
|
|
||||||
margin: 0;
|
|
||||||
height: 100vh;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
font-family: 'Helvetica Neue', 'Helvetica', arial, sans-serif;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* WYSIWYG Editor */
|
|
||||||
.wp-webdeasy-comment-editor {
|
|
||||||
width: 40rem;
|
|
||||||
min-height: 18rem;
|
|
||||||
box-shadow: 0 0 4px 1px rgba(0, 0, 0, 0.3);
|
|
||||||
border-top: 6px solid #4a4a4a;
|
|
||||||
border-radius: 3px;
|
|
||||||
margin: 2rem 0;
|
|
||||||
|
|
||||||
.toolbar {
|
|
||||||
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.2);
|
|
||||||
|
|
||||||
.line {
|
|
||||||
display: flex;
|
|
||||||
border-bottom: 1px solid #e2e2e2;
|
|
||||||
|
|
||||||
&:last-child {
|
|
||||||
border-bottom: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.box {
|
|
||||||
display: flex;
|
|
||||||
border-left: 1px solid #e2e2e2;
|
|
||||||
|
|
||||||
.editor-btn {
|
|
||||||
display: block;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
position: relative;
|
|
||||||
transition: .2s ease all;
|
|
||||||
|
|
||||||
&:hover, &.active {
|
|
||||||
background-color: #e1e1e1;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.icon img {
|
|
||||||
width: 15px;
|
|
||||||
padding: 9px;
|
|
||||||
box-sizing: content-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.icon.smaller img {
|
|
||||||
width: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.has-submenu {
|
|
||||||
width: 20px;
|
|
||||||
padding: 0 10px;
|
|
||||||
|
|
||||||
&::after {
|
|
||||||
content: '';
|
|
||||||
width: 6px;
|
|
||||||
height: 6px;
|
|
||||||
position: absolute;
|
|
||||||
background-image: url(https://img.icons8.com/ios-glyphs/30/000000/chevron-down.png);
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
background-size: cover;
|
|
||||||
background-position: center;
|
|
||||||
right: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.submenu {
|
|
||||||
display: none;
|
|
||||||
position: absolute;
|
|
||||||
top: 34px;
|
|
||||||
left: -1px;
|
|
||||||
z-index: 10;
|
|
||||||
background-color: #FFF;
|
|
||||||
border: 1px solid #b5b5b5;
|
|
||||||
border-top: none;
|
|
||||||
|
|
||||||
.btn {
|
|
||||||
width: 39px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover .submenu {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.content-area {
|
|
||||||
padding: 15px 12px;
|
|
||||||
line-height: 1.5;
|
|
||||||
|
|
||||||
.visuell-view {
|
|
||||||
outline: none;
|
|
||||||
min-height: 12rem;
|
|
||||||
|
|
||||||
p {
|
|
||||||
margin: 12px 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.html-view {
|
|
||||||
outline: none;
|
|
||||||
display: none;
|
|
||||||
width: 100%;
|
|
||||||
height: 200px;
|
|
||||||
border: none;
|
|
||||||
resize: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Modal */
|
|
||||||
.modal {
|
|
||||||
z-index: 40;
|
|
||||||
display: none;
|
|
||||||
|
|
||||||
.modal-wrapper {
|
|
||||||
background-color: #FFF;
|
|
||||||
padding: 1rem;
|
|
||||||
position: fixed;
|
|
||||||
top: 50%;
|
|
||||||
left: 50%;
|
|
||||||
transform: translate(-50%, -50%);
|
|
||||||
width: 20rem;
|
|
||||||
min-height: 10rem;
|
|
||||||
z-index: 41;
|
|
||||||
|
|
||||||
.close {
|
|
||||||
position: absolute;
|
|
||||||
top: 1rem;
|
|
||||||
right: 1rem;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-content {
|
|
||||||
flex-direction: column;
|
|
||||||
|
|
||||||
h3 {
|
|
||||||
margin-top: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
input {
|
|
||||||
margin: 1rem 0;
|
|
||||||
padding: .5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
input[type="text"] {
|
|
||||||
width: calc(100% - 1rem);
|
|
||||||
}
|
|
||||||
|
|
||||||
.row {
|
|
||||||
|
|
||||||
label {
|
|
||||||
margin-left: .5rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
button {
|
|
||||||
background-color: #D2434F;
|
|
||||||
border: 0;
|
|
||||||
color: #FFF;
|
|
||||||
padding: .5rem 1.2rem;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-bg {
|
|
||||||
position: fixed;
|
|
||||||
background-color: rgba(0, 0, 0, .3);
|
|
||||||
width: 100vw;
|
|
||||||
height: 100vh;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Codepen Footer */
|
|
||||||
footer {
|
|
||||||
position: fixed;
|
|
||||||
bottom: 0;
|
|
||||||
display: flex;
|
|
||||||
|
|
||||||
p {
|
|
||||||
margin: 0.5rem 1rem;
|
|
||||||
font-size: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
text-decoration: none;
|
|
||||||
font-weight: bold;
|
|
||||||
color: #000;
|
|
||||||
}
|
|
||||||
}
|
|
@ -2,7 +2,7 @@
|
|||||||
/**
|
/**
|
||||||
* app/functions/common.php
|
* app/functions/common.php
|
||||||
*
|
*
|
||||||
* @version 3.0
|
* @version 5.0.1
|
||||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||||
* @link https://TheTempusProject.com
|
* @link https://TheTempusProject.com
|
||||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||||
@ -89,3 +89,31 @@ function iv( $variable ) {
|
|||||||
echo var_export( $variable, true );
|
echo var_export( $variable, true );
|
||||||
echo '</pre>';
|
echo '</pre>';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function generateToken(): string {
|
||||||
|
return bin2hex(random_bytes(32)); // Generates a 64-character hexadecimal token
|
||||||
|
}
|
||||||
|
|
||||||
|
function generateRandomString( $length = 10 ) {
|
||||||
|
$characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
||||||
|
$charactersLength = strlen( $characters );
|
||||||
|
$randomString = '';
|
||||||
|
for ($i = 0; $i < $length; $i++) {
|
||||||
|
$randomString .= $characters[random_int(0, $charactersLength - 1)];
|
||||||
|
}
|
||||||
|
return $randomString;
|
||||||
|
}
|
||||||
|
|
||||||
|
function generateUuidV4(): string {
|
||||||
|
// Generate 16 random bytes
|
||||||
|
$data = random_bytes(16);
|
||||||
|
|
||||||
|
// Set the version to 4 -> random (bits 12-15 of time_hi_and_version)
|
||||||
|
$data[6] = chr((ord($data[6]) & 0x0f) | 0x40);
|
||||||
|
|
||||||
|
// Set the variant to RFC 4122 -> (bits 6-7 of clock_seq_hi_and_reserved)
|
||||||
|
$data[8] = chr((ord($data[8]) & 0x3f) | 0x80);
|
||||||
|
|
||||||
|
// Convert to hexadecimal and format as a UUID
|
||||||
|
return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($data), 4));
|
||||||
|
}
|
Binary file not shown.
Before Width: | Height: | Size: 56 KiB |
BIN
app/images/ttp-gitlab.png
Normal file
BIN
app/images/ttp-gitlab.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 117 KiB |
Binary file not shown.
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 26 KiB |
Binary file not shown.
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 47 KiB |
244
app/js/main.js
244
app/js/main.js
@ -3,11 +3,68 @@
|
|||||||
*
|
*
|
||||||
* This file is for 'access anywhere' javascript.
|
* This file is for 'access anywhere' javascript.
|
||||||
*
|
*
|
||||||
* @version 3.0
|
* @version 5.0.1
|
||||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||||
* @link https://TheTempusProject.com
|
* @link https://TheTempusProject.com
|
||||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||||
*/
|
*/
|
||||||
|
let deferredPrompt;
|
||||||
|
const installPrompt = document.getElementById("install-prompt");
|
||||||
|
const installButton = document.getElementById("install-button");
|
||||||
|
const dismissButton = document.querySelector("#install-prompt .btn-close");
|
||||||
|
|
||||||
|
// Check if the user previously dismissed the prompt
|
||||||
|
if (!localStorage.getItem("pwaInstallDismissed")) {
|
||||||
|
window.addEventListener("beforeinstallprompt", (event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
deferredPrompt = event;
|
||||||
|
installPrompt.classList.remove("d-none");
|
||||||
|
installPrompt.classList.add("d-block"); // Show the prompt
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle Install Button Click
|
||||||
|
if ( installButton ) {
|
||||||
|
installButton.addEventListener("click", async () => {
|
||||||
|
if (deferredPrompt) {
|
||||||
|
deferredPrompt.prompt();
|
||||||
|
const { outcome } = await deferredPrompt.userChoice;
|
||||||
|
|
||||||
|
if (outcome === "dismissed") {
|
||||||
|
setInstallDismissed(); // Store that the user dismissed the prompt
|
||||||
|
}
|
||||||
|
|
||||||
|
deferredPrompt = null; // Reset prompt
|
||||||
|
installPrompt.classList.remove("d-block");
|
||||||
|
installPrompt.classList.add("d-none");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle Close Button Click
|
||||||
|
if ( dismissButton ) {
|
||||||
|
dismissButton.addEventListener("click", () => {
|
||||||
|
setInstallDismissed(); // Store that the user dismissed the prompt
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to remember user choice for 7 days
|
||||||
|
function setInstallDismissed() {
|
||||||
|
localStorage.setItem("pwaInstallDismissed", Date.now() + 7 * 24 * 60 * 60 * 1000);
|
||||||
|
installPrompt.classList.remove("d-block"); // Hide the prompt
|
||||||
|
installPrompt.classList.add("d-none");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the 7-day period has passed
|
||||||
|
if (localStorage.getItem("pwaInstallDismissed")) {
|
||||||
|
const dismissUntil = parseInt(localStorage.getItem("pwaInstallDismissed"), 10);
|
||||||
|
if (Date.now() < dismissUntil) {
|
||||||
|
//
|
||||||
|
} else {
|
||||||
|
localStorage.removeItem("pwaInstallDismissed"); // Reset after 7 days
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Automatically selects/de-selects all check boxes associated with that field
|
* Automatically selects/de-selects all check boxes associated with that field
|
||||||
**/
|
**/
|
||||||
@ -27,15 +84,6 @@ function checkAll(ele) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function copyAll( ele ) {
|
|
||||||
var eleName = '#' + ele;
|
|
||||||
var text = $( eleName ).text();
|
|
||||||
text = text.replaceAll( "''", "\n" ).trim();
|
|
||||||
text = text.substring( 1, text.length - 1 );
|
|
||||||
navigator.clipboard.writeText( text );
|
|
||||||
console.log( '#' + ele );
|
|
||||||
}
|
|
||||||
|
|
||||||
function insertTag( box, tag ) {
|
function insertTag( box, tag ) {
|
||||||
var Field = document.getElementById( box );
|
var Field = document.getElementById( box );
|
||||||
var currentPos = cursorPos( Field );
|
var currentPos = cursorPos( Field );
|
||||||
@ -69,43 +117,161 @@ function getRandomInt(min, max) {
|
|||||||
return Math.floor(Math.random() * (maxFloored - minCeiled) + minCeiled);
|
return Math.floor(Math.random() * (maxFloored - minCeiled) + minCeiled);
|
||||||
}
|
}
|
||||||
|
|
||||||
$(document).ready(function() {
|
function copyElementText( id ) {
|
||||||
$('select').each(function() {
|
const inputElement = document.getElementById( id );
|
||||||
var selectedValue = $(this).attr('value');
|
const textToCopy = inputElement.value;
|
||||||
|
|
||||||
|
if (navigator.clipboard && navigator.clipboard.writeText) {
|
||||||
|
navigator.clipboard.writeText(textToCopy)
|
||||||
|
.then(() => alert('Copied to clipboard!'))
|
||||||
|
.catch((err) => console.error('Failed to copy: ', err));
|
||||||
|
} else {
|
||||||
|
// Fallback for older browsers
|
||||||
|
inputElement.select();
|
||||||
|
try {
|
||||||
|
document.execCommand('copy');
|
||||||
|
alert('Copied to clipboard!');
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Failed to copy: ', err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener("DOMContentLoaded", function () {
|
||||||
|
document.querySelectorAll("select").forEach(function (select) {
|
||||||
|
var selectedValue = select.getAttribute("value");
|
||||||
if (selectedValue) {
|
if (selectedValue) {
|
||||||
$(this).removeAttr('value');
|
select.removeAttribute("value");
|
||||||
$(this).find('option').each(function() {
|
select.querySelectorAll("option").forEach(function (option) {
|
||||||
if ($(this).attr('value') === selectedValue) {
|
if (option.getAttribute("value") === selectedValue) {
|
||||||
$(this).prop('selected', true);
|
option.selected = true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// with the dynamic footer, you need to adjust the content padding to make sure the footer doesn't overlap the content
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
window.onload = function () {
|
const ttpDarkmode = document.getElementById('dark-mode-pref');
|
||||||
function updateFooterPadding() {
|
const toggleButton = document.getElementById('dark-mode-toggle');
|
||||||
var footer = document.querySelector('footer');
|
const enableButton = document.getElementById('dark-mode-toggle-button');
|
||||||
var container = document.querySelector('.container-fluid.top-pad');
|
const darkModeStylesheet = document.getElementById('dark-mode-stylesheet');
|
||||||
if ( ! container ) {
|
let currentState = '';
|
||||||
return;
|
|
||||||
|
// Check if dark mode is set by ttp
|
||||||
|
if ( ttpDarkmode ) {
|
||||||
|
if ( 'true' == ttpDarkmode.value ) {
|
||||||
|
currentState = 'enabled';
|
||||||
|
}
|
||||||
|
if ( 'false' == ttpDarkmode.value ) {
|
||||||
|
currentState = 'disabled';
|
||||||
}
|
}
|
||||||
// footer has no height but its children do!
|
|
||||||
var footerHeight = Array.from(footer.children).reduce((totalHeight, child) => {
|
|
||||||
return totalHeight + child.offsetHeight;
|
|
||||||
}, 0);
|
|
||||||
|
|
||||||
footerHeight += 20; // Add 20px for padding
|
|
||||||
|
|
||||||
// console.error(footerHeight);
|
|
||||||
|
|
||||||
container.style.setProperty('--footer-height', footerHeight + 'px');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update padding on initial load
|
// Check if dark mode is set in localStorage
|
||||||
updateFooterPadding();
|
if ( '' == currentState ) {
|
||||||
|
if ( localStorage.getItem('darkMode') === 'enabled' ) {
|
||||||
|
currentState = 'enabled';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Update padding on window resize
|
// Update current button states
|
||||||
window.addEventListener('resize', updateFooterPadding);
|
if ( 'enabled' == currentState ) {
|
||||||
};
|
darkModeStylesheet.disabled = false;
|
||||||
|
|
||||||
|
if ( toggleButton ) {
|
||||||
|
toggleButton.checked = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( enableButton ) {
|
||||||
|
enableButton.innerText = 'Disable Now';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Style striped table elements
|
||||||
|
document.querySelectorAll('.table-striped').forEach((table) => {
|
||||||
|
if ( 'enabled' == currentState ) {
|
||||||
|
table.classList.add('table-dark');
|
||||||
|
} else {
|
||||||
|
table.classList.add('table-light')
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if ( enableButton ) {
|
||||||
|
enableButton.addEventListener('click', function () {
|
||||||
|
if ( darkModeStylesheet.disabled ) {
|
||||||
|
darkModeStylesheet.disabled = false;
|
||||||
|
localStorage.setItem('darkMode', 'enabled');
|
||||||
|
enableButton.innerText = 'Disable Now';
|
||||||
|
} else {
|
||||||
|
darkModeStylesheet.disabled = true;
|
||||||
|
localStorage.setItem('darkMode', 'disabled');
|
||||||
|
enableButton.innerText = 'Enable Now';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( toggleButton ) {
|
||||||
|
toggleButton.addEventListener('click', function () {
|
||||||
|
if (darkModeStylesheet.disabled) {
|
||||||
|
toggleDarkModePref( true );
|
||||||
|
darkModeStylesheet.disabled = false;
|
||||||
|
localStorage.setItem('darkMode', 'enabled');
|
||||||
|
} else {
|
||||||
|
toggleDarkModePref( false );
|
||||||
|
darkModeStylesheet.disabled = true;
|
||||||
|
localStorage.setItem('darkMode', 'disabled');
|
||||||
|
}
|
||||||
|
|
||||||
|
document.querySelectorAll('.table-striped').forEach((table) => {
|
||||||
|
if (localStorage.getItem('darkMode') === 'enabled') {
|
||||||
|
table.classList.add('table-dark');
|
||||||
|
table.classList.remove('table-light');
|
||||||
|
} else {
|
||||||
|
table.classList.add('table-light');
|
||||||
|
table.classList.remove('table-dark');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleDarkModePref(value) {
|
||||||
|
var fields = new URLSearchParams();
|
||||||
|
fields.append("prefName", "darkMode");
|
||||||
|
fields.append("prefValue", value);
|
||||||
|
|
||||||
|
fetch("/usercp/updatePref", {
|
||||||
|
method: "POST",
|
||||||
|
body: fields,
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/x-www-form-urlencoded",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
// .then(response => response.text()) // Handle response if needed
|
||||||
|
.catch(error => console.error("Error:", error));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// this reverses the carets for the folderSelect
|
||||||
|
document.querySelectorAll('[data-bs-toggle="collapse"]').forEach(button => {
|
||||||
|
button.addEventListener('click', () => {
|
||||||
|
setTimeout(() => {
|
||||||
|
const icon = button.querySelector('i');
|
||||||
|
|
||||||
|
// Only proceed if the icon already has one of the relevant classes
|
||||||
|
if (icon && (icon.classList.contains('fa-caret-down') || icon.classList.contains('fa-caret-up'))) {
|
||||||
|
icon.classList.toggle('fa-caret-down', button.classList.contains('collapsed'));
|
||||||
|
icon.classList.toggle('fa-caret-up', !button.classList.contains('collapsed'));
|
||||||
|
}
|
||||||
|
}, 150);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// this should load all popovers
|
||||||
|
document.addEventListener("DOMContentLoaded", function () {
|
||||||
|
var popoverTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]'));
|
||||||
|
var popoverList = popoverTriggerList.map(function (popoverTriggerEl) {
|
||||||
|
return new bootstrap.Popover(popoverTriggerEl);
|
||||||
|
});
|
||||||
|
});
|
@ -1,233 +0,0 @@
|
|||||||
/**
|
|
||||||
* app/js/wysiwyg.js
|
|
||||||
*
|
|
||||||
* This is css used in the debuging console.
|
|
||||||
*
|
|
||||||
* @version 3.0
|
|
||||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
|
||||||
* @link https://TheTempusProject.com
|
|
||||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
|
||||||
*/
|
|
||||||
// define vars
|
|
||||||
const editor = document.getElementsByClassName('wp-webdeasy-comment-editor')[0];
|
|
||||||
const toolbar = editor.getElementsByClassName('toolbar')[0];
|
|
||||||
const buttons = toolbar.querySelectorAll('.editor-btn:not(.has-submenu)');
|
|
||||||
const contentArea = editor.getElementsByClassName('content-area')[0];
|
|
||||||
const visuellView = contentArea.getElementsByClassName('visuell-view')[0];
|
|
||||||
const htmlView = contentArea.getElementsByClassName('html-view')[0];
|
|
||||||
const modal = document.getElementsByClassName('modal')[0];
|
|
||||||
|
|
||||||
// add active tag event
|
|
||||||
document.addEventListener('selectionchange', selectionChange);
|
|
||||||
|
|
||||||
// add paste event
|
|
||||||
visuellView.addEventListener('paste', pasteEvent);
|
|
||||||
|
|
||||||
// add paragraph tag on new line
|
|
||||||
contentArea.addEventListener('keypress', addParagraphTag);
|
|
||||||
|
|
||||||
// add toolbar button actions
|
|
||||||
for(let i = 0; i < buttons.length; i++) {
|
|
||||||
let button = buttons[i];
|
|
||||||
|
|
||||||
button.addEventListener('click', function(e) {
|
|
||||||
let action = this.dataset.action;
|
|
||||||
|
|
||||||
switch(action) {
|
|
||||||
case 'toggle-view':
|
|
||||||
execCodeAction(this, editor);
|
|
||||||
break;
|
|
||||||
case 'createLink':
|
|
||||||
execLinkAction();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
execDefaultAction(action);
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This function toggles between visual and html view
|
|
||||||
*/
|
|
||||||
function execCodeAction(button, editor) {
|
|
||||||
|
|
||||||
if(button.classList.contains('active')) { // show visuell view
|
|
||||||
visuellView.innerHTML = htmlView.value;
|
|
||||||
htmlView.style.display = 'none';
|
|
||||||
visuellView.style.display = 'block';
|
|
||||||
|
|
||||||
button.classList.remove('active');
|
|
||||||
} else { // show html view
|
|
||||||
htmlView.innerText = visuellView.innerHTML;
|
|
||||||
visuellView.style.display = 'none';
|
|
||||||
htmlView.style.display = 'block';
|
|
||||||
|
|
||||||
button.classList.add('active');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This function adds a link to the current selection
|
|
||||||
*/
|
|
||||||
function execLinkAction() {
|
|
||||||
modal.style.display = 'block';
|
|
||||||
let selection = saveSelection();
|
|
||||||
|
|
||||||
let submit = modal.querySelectorAll('button.done')[0];
|
|
||||||
let close = modal.querySelectorAll('.close')[0];
|
|
||||||
|
|
||||||
// done button active => add link
|
|
||||||
submit.addEventListener('click', function(e) {
|
|
||||||
e.preventDefault();
|
|
||||||
let newTabCheckbox = modal.querySelectorAll('#new-tab')[0];
|
|
||||||
let linkInput = modal.querySelectorAll('#linkValue')[0];
|
|
||||||
let linkValue = linkInput.value;
|
|
||||||
let newTab = newTabCheckbox.checked;
|
|
||||||
|
|
||||||
restoreSelection(selection);
|
|
||||||
|
|
||||||
if(window.getSelection().toString()) {
|
|
||||||
let a = document.createElement('a');
|
|
||||||
a.href = linkValue;
|
|
||||||
if(newTab) a.target = '_blank';
|
|
||||||
window.getSelection().getRangeAt(0).surroundContents(a);
|
|
||||||
}
|
|
||||||
|
|
||||||
modal.style.display = 'none';
|
|
||||||
linkInput.value = '';
|
|
||||||
|
|
||||||
// deregister modal events
|
|
||||||
submit.removeEventListener('click', arguments.callee);
|
|
||||||
close.removeEventListener('click', arguments.callee);
|
|
||||||
});
|
|
||||||
|
|
||||||
// close modal on X click
|
|
||||||
close.addEventListener('click', function(e) {
|
|
||||||
e.preventDefault();
|
|
||||||
let linkInput = modal.querySelectorAll('#linkValue')[0];
|
|
||||||
|
|
||||||
modal.style.display = 'none';
|
|
||||||
linkInput.value = '';
|
|
||||||
|
|
||||||
// deregister modal events
|
|
||||||
submit.removeEventListener('click', arguments.callee);
|
|
||||||
close.removeEventListener('click', arguments.callee);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This function executes all 'normal' actions
|
|
||||||
*/
|
|
||||||
function execDefaultAction(action) {
|
|
||||||
document.execCommand(action, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Saves the current selection
|
|
||||||
*/
|
|
||||||
function saveSelection() {
|
|
||||||
if(window.getSelection) {
|
|
||||||
sel = window.getSelection();
|
|
||||||
if(sel.getRangeAt && sel.rangeCount) {
|
|
||||||
let ranges = [];
|
|
||||||
for(var i = 0, len = sel.rangeCount; i < len; ++i) {
|
|
||||||
ranges.push(sel.getRangeAt(i));
|
|
||||||
}
|
|
||||||
return ranges;
|
|
||||||
}
|
|
||||||
} else if (document.selection && document.selection.createRange) {
|
|
||||||
return document.selection.createRange();
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads a saved selection
|
|
||||||
*/
|
|
||||||
function restoreSelection(savedSel) {
|
|
||||||
if(savedSel) {
|
|
||||||
if(window.getSelection) {
|
|
||||||
sel = window.getSelection();
|
|
||||||
sel.removeAllRanges();
|
|
||||||
for(var i = 0, len = savedSel.length; i < len; ++i) {
|
|
||||||
sel.addRange(savedSel[i]);
|
|
||||||
}
|
|
||||||
} else if(document.selection && savedSel.select) {
|
|
||||||
savedSel.select();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the current selected format buttons active/inactive
|
|
||||||
*/
|
|
||||||
function selectionChange(e) {
|
|
||||||
|
|
||||||
for(let i = 0; i < buttons.length; i++) {
|
|
||||||
let button = buttons[i];
|
|
||||||
|
|
||||||
// don't remove active class on code toggle button
|
|
||||||
if(button.dataset.action === 'toggle-view') continue;
|
|
||||||
|
|
||||||
button.classList.remove('active');
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!childOf(window.getSelection().anchorNode.parentNode, editor)) return false;
|
|
||||||
|
|
||||||
parentTagActive(window.getSelection().anchorNode.parentNode);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the passed child has the passed parent
|
|
||||||
*/
|
|
||||||
function childOf(child, parent) {
|
|
||||||
return parent.contains(child);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the tag active that is responsible for the current element
|
|
||||||
*/
|
|
||||||
function parentTagActive(elem) {
|
|
||||||
if(!elem ||!elem.classList || elem.classList.contains('visuell-view')) return false;
|
|
||||||
|
|
||||||
let toolbarButton;
|
|
||||||
|
|
||||||
// active by tag names
|
|
||||||
let tagName = elem.tagName.toLowerCase();
|
|
||||||
toolbarButton = document.querySelectorAll(`.toolbar .editor-btn[data-tag-name="${tagName}"]`)[0];
|
|
||||||
if(toolbarButton) {
|
|
||||||
toolbarButton.classList.add('active');
|
|
||||||
}
|
|
||||||
|
|
||||||
// active by text-align
|
|
||||||
let textAlign = elem.style.textAlign;
|
|
||||||
toolbarButton = document.querySelectorAll(`.toolbar .editor-btn[data-style="textAlign:${textAlign}"]`)[0];
|
|
||||||
if(toolbarButton) {
|
|
||||||
toolbarButton.classList.add('active');
|
|
||||||
}
|
|
||||||
|
|
||||||
return parentTagActive(elem.parentNode);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles the paste event and removes all HTML tags
|
|
||||||
*/
|
|
||||||
function pasteEvent(e) {
|
|
||||||
e.preventDefault();
|
|
||||||
|
|
||||||
let text = (e.originalEvent || e).clipboardData.getData('text/plain');
|
|
||||||
document.execCommand('insertHTML', false, text);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This functions adds a paragraph tag when the enter key is pressed
|
|
||||||
*/
|
|
||||||
function addParagraphTag(evt) {
|
|
||||||
if (evt.keyCode == '13') {
|
|
||||||
|
|
||||||
// don't add a p tag on list item
|
|
||||||
if(window.getSelection().anchorNode.parentNode.tagName === 'LI') return;
|
|
||||||
document.execCommand('formatBlock', false, 'p');
|
|
||||||
}
|
|
||||||
}
|
|
@ -4,7 +4,7 @@
|
|||||||
*
|
*
|
||||||
* This class is used for the manipulation of the groups database table.
|
* This class is used for the manipulation of the groups database table.
|
||||||
*
|
*
|
||||||
* @version 3.0
|
* @version 5.0.1
|
||||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||||
* @link https://TheTempusProject.com
|
* @link https://TheTempusProject.com
|
||||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||||
@ -31,18 +31,29 @@ class Group extends DatabaseModel {
|
|||||||
'defaultGroup' => [
|
'defaultGroup' => [
|
||||||
'type' => 'customSelect',
|
'type' => 'customSelect',
|
||||||
'pretty' => 'The Default Group for new registrations.',
|
'pretty' => 'The Default Group for new registrations.',
|
||||||
'default' => 5,
|
'default' => 4,
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
public $databaseMatrix = [
|
public $databaseMatrix = [
|
||||||
[ 'name', 'varchar', '32' ],
|
[ 'name', 'varchar', '32' ],
|
||||||
[ 'permissions', 'text', '' ],
|
[ 'permissions', 'text', '' ],
|
||||||
];
|
];
|
||||||
|
public $searchFields = [
|
||||||
|
'name',
|
||||||
|
];
|
||||||
public $permissionMatrix = [
|
public $permissionMatrix = [
|
||||||
'adminAccess' => [
|
'adminAccess' => [
|
||||||
'pretty' => 'Access Administrator Areas',
|
'pretty' => 'Access Administrator Areas',
|
||||||
'default' => false,
|
'default' => false,
|
||||||
],
|
],
|
||||||
|
'uploadImages' => [
|
||||||
|
'pretty' => 'Upload images (such as avatars)',
|
||||||
|
'default' => false,
|
||||||
|
],
|
||||||
|
'maintenanceAccess' => [
|
||||||
|
'pretty' => 'Upload images (such as avatars)',
|
||||||
|
'default' => false,
|
||||||
|
],
|
||||||
];
|
];
|
||||||
public $resourceMatrix = [
|
public $resourceMatrix = [
|
||||||
[
|
[
|
||||||
@ -257,7 +268,7 @@ class Group extends DatabaseModel {
|
|||||||
if ( $group === false ) {
|
if ( $group === false ) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$members = self::$db->getPaginated( 'users', [ 'userGroup', '=', $id ] );
|
$members = self::$db->get( 'users', [ 'userGroup', '=', $id ] );
|
||||||
if ( !$members->count() ) {
|
if ( !$members->count() ) {
|
||||||
Debug::info( "list members: Could not find anyone in group: $id" );
|
Debug::info( "list members: Could not find anyone in group: $id" );
|
||||||
return false;
|
return false;
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
*
|
*
|
||||||
* Model for handling all logging.
|
* Model for handling all logging.
|
||||||
*
|
*
|
||||||
* @version 3.0
|
* @version 5.0.1
|
||||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||||
* @link https://TheTempusProject.com
|
* @link https://TheTempusProject.com
|
||||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||||
@ -46,6 +46,9 @@ class Log extends DatabaseModel {
|
|||||||
[ 'source', 'varchar', '64' ],
|
[ 'source', 'varchar', '64' ],
|
||||||
[ 'action', 'text', '' ],
|
[ 'action', 'text', '' ],
|
||||||
];
|
];
|
||||||
|
public $searchFields = [
|
||||||
|
'source',
|
||||||
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The model constructor.
|
* The model constructor.
|
||||||
@ -87,7 +90,7 @@ class Log extends DatabaseModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function list( $filter = null ) {
|
public function list( $filter = null ) {
|
||||||
$logData = self::$db->getPaginated( $this->tableName, [ 'source', '=', $filter ] );
|
$logData = self::$db->get( $this->tableName, [ 'source', '=', $filter ] );
|
||||||
if ( !$logData->count() ) {
|
if ( !$logData->count() ) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
*
|
*
|
||||||
* This class is used for the manipulation of the routes database table.
|
* This class is used for the manipulation of the routes database table.
|
||||||
*
|
*
|
||||||
* @version 3.0
|
* @version 5.0.1
|
||||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||||
* @link https://TheTempusProject.com
|
* @link https://TheTempusProject.com
|
||||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||||
@ -24,6 +24,9 @@ class Routes extends DatabaseModel {
|
|||||||
[ 'original_url', 'varchar', '32' ],
|
[ 'original_url', 'varchar', '32' ],
|
||||||
[ 'forwarded_url', 'text', '' ],
|
[ 'forwarded_url', 'text', '' ],
|
||||||
];
|
];
|
||||||
|
public $searchFields = [
|
||||||
|
'nickname',
|
||||||
|
];
|
||||||
public $resourceMatrix = [
|
public $resourceMatrix = [
|
||||||
[
|
[
|
||||||
'original_url' => 'fb',
|
'original_url' => 'fb',
|
||||||
@ -72,7 +75,7 @@ class Routes extends DatabaseModel {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if ( !Check::simpleName( $nickname ) ) {
|
if ( !Check::simpleName( $nickname ) ) {
|
||||||
Debug::warn( 'Invalid route nickname: ' . $name );
|
Debug::warn( 'Invalid route nickname: ' . $nickname );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if ( 'external' == $type && !Check::url( $forwarded_url ) ) {
|
if ( 'external' == $type && !Check::url( $forwarded_url ) ) {
|
||||||
@ -128,7 +131,7 @@ class Routes extends DatabaseModel {
|
|||||||
}
|
}
|
||||||
$routeData = self::$db->get( $this->tableName, [ 'nickname', '=', $name ] );
|
$routeData = self::$db->get( $this->tableName, [ 'nickname', '=', $name ] );
|
||||||
if ( !$routeData->count() ) {
|
if ( !$routeData->count() ) {
|
||||||
Debug::warn( "Could not find a group named: $name" );
|
Debug::info( "Routes:findByName: Could not find a route named: $name" );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return $this->filter( $routeData->first() );
|
return $this->filter( $routeData->first() );
|
||||||
@ -137,7 +140,7 @@ class Routes extends DatabaseModel {
|
|||||||
public function findByOriginalUrl( $url ) {
|
public function findByOriginalUrl( $url ) {
|
||||||
$routeData = self::$db->get( $this->tableName, [ 'original_url', '=', $url ] );
|
$routeData = self::$db->get( $this->tableName, [ 'original_url', '=', $url ] );
|
||||||
if ( !$routeData->count() ) {
|
if ( !$routeData->count() ) {
|
||||||
Debug::warn( "Could not find route by original url: $url" );
|
Debug::info( "Routes:findByOriginalUrl: Could not find route by original url: $url" );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return $this->filter( $routeData->first() );
|
return $this->filter( $routeData->first() );
|
||||||
@ -145,12 +148,12 @@ class Routes extends DatabaseModel {
|
|||||||
|
|
||||||
public function findByforwardedUrl( $url ) {
|
public function findByforwardedUrl( $url ) {
|
||||||
if ( !Check::url( $url ) ) {
|
if ( !Check::url( $url ) ) {
|
||||||
Debug::warn( "Invalid forwarded_url: $url" );
|
Debug::warn( "Routes:findByforwardedUrl: Invalid forwarded_url: $url" );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$routeData = self::$db->get( $this->tableName, [ 'forwarded_url', '=', $url ] );
|
$routeData = self::$db->get( $this->tableName, [ 'forwarded_url', '=', $url ] );
|
||||||
if ( !$routeData->count() ) {
|
if ( !$routeData->count() ) {
|
||||||
Debug::warn( "Could not find route by forwarded url: $url" );
|
Debug::info( "Routes:findByforwardedUrl: Could not find route by forwarded url: $url" );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return $this->filter( $routeData->first() );
|
return $this->filter( $routeData->first() );
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Notes: After refactor, the sessions will use ID's for short term, and Cookies
|
* Notes: After refactor, the sessions will use ID's for short term, and Cookies
|
||||||
* will use the token for long term storage
|
* will use the token for long term storage
|
||||||
*
|
*
|
||||||
* @version 3.0
|
* @version 5.0.1
|
||||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||||
* @link https://TheTempusProject.com
|
* @link https://TheTempusProject.com
|
||||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||||
@ -20,6 +20,7 @@ use TheTempusProject\Canary\Bin\Canary as Debug;
|
|||||||
use TheTempusProject\Bedrock\Functions\Session;
|
use TheTempusProject\Bedrock\Functions\Session;
|
||||||
use TheTempusProject\Bedrock\Functions\Cookie;
|
use TheTempusProject\Bedrock\Functions\Cookie;
|
||||||
use TheTempusProject\Classes\DatabaseModel;
|
use TheTempusProject\Classes\DatabaseModel;
|
||||||
|
use TheTempusProject\Classes\Config;
|
||||||
use TheTempusProject\TheTempusProject as App;
|
use TheTempusProject\TheTempusProject as App;
|
||||||
|
|
||||||
class Sessions extends DatabaseModel {
|
class Sessions extends DatabaseModel {
|
||||||
@ -35,6 +36,9 @@ class Sessions extends DatabaseModel {
|
|||||||
[ 'username', 'varchar', '20' ],
|
[ 'username', 'varchar', '20' ],
|
||||||
[ 'token', 'varchar', '120' ],
|
[ 'token', 'varchar', '120' ],
|
||||||
];
|
];
|
||||||
|
public $searchFields = [
|
||||||
|
'username',
|
||||||
|
];
|
||||||
public static $activeSession = false;
|
public static $activeSession = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -56,9 +60,11 @@ class Sessions extends DatabaseModel {
|
|||||||
$user = new User;
|
$user = new User;
|
||||||
// @todo lets put this on some sort of realistic checking regime other than check everything every time
|
// @todo lets put this on some sort of realistic checking regime other than check everything every time
|
||||||
if ( $sessionID == false ) {
|
if ( $sessionID == false ) {
|
||||||
|
Debug::log( 'sessionID false' );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if ( !Check::id( $sessionID ) ) {
|
if ( !Check::id( $sessionID ) ) {
|
||||||
|
Debug::log( 'sessionID not id' );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$data = self::$db->get( $this->tableName, [ 'ID', '=', $sessionID ] );
|
$data = self::$db->get( $this->tableName, [ 'ID', '=', $sessionID ] );
|
||||||
@ -115,12 +121,12 @@ class Sessions extends DatabaseModel {
|
|||||||
public function checkCookie( $cookieToken, $create = false ) {
|
public function checkCookie( $cookieToken, $create = false ) {
|
||||||
$user = new User;
|
$user = new User;
|
||||||
if ( $cookieToken === false ) {
|
if ( $cookieToken === false ) {
|
||||||
|
Debug::info( 'cookieToken false' );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$data = self::$db->get( $this->tableName, [ 'token', '=', $cookieToken ] );
|
$data = self::$db->get( $this->tableName, [ 'token', '=', $cookieToken ] );
|
||||||
if ( !$data->count() ) {
|
if ( !$data->count() ) {
|
||||||
Debug::info( 'sessions->checkCookie - Session token not found.' );
|
Debug::info( 'sessions->checkCookie - Session token not found.' );
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$session = $data->first();
|
$session = $data->first();
|
||||||
@ -145,22 +151,6 @@ class Sessions extends DatabaseModel {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function checkToken( $apiToken, $create = false ) {
|
|
||||||
$user = new User;
|
|
||||||
if ( $apiToken === false ) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
$result = $user->findByToken( $apiToken );
|
|
||||||
if ( $result === false ) {
|
|
||||||
Debug::info( 'sessions->checkToken - could not find user by token.' );
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if ( $create ) {
|
|
||||||
return $this->newSession( null, false, false, $result->ID );
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new session from the data provided. The
|
* Creates a new session from the data provided. The
|
||||||
* expiration time is optional and will be set to the
|
* expiration time is optional and will be set to the
|
||||||
@ -171,9 +161,10 @@ class Sessions extends DatabaseModel {
|
|||||||
* @return {bool}
|
* @return {bool}
|
||||||
*/
|
*/
|
||||||
public function newSession( $expire = null, $override = false, $remember = false, $userID = null ) {
|
public function newSession( $expire = null, $override = false, $remember = false, $userID = null ) {
|
||||||
if ( ! isset( $expire ) ) {
|
if ( empty( $expire ) ) {
|
||||||
// default Session Expiration is 24 hours
|
// default Session Expiration is 24 hours
|
||||||
$expire = ( time() + ( 3600 * 24 ) );
|
$expireLimit = Config::getValue( 'main/loginTimer' );
|
||||||
|
$expire = ( time() + $expireLimit );
|
||||||
Debug::log( 'Using default expiration time' );
|
Debug::log( 'Using default expiration time' );
|
||||||
}
|
}
|
||||||
$lastPage = App::getUrl();
|
$lastPage = App::getUrl();
|
||||||
|
207
app/models/token.php
Normal file
207
app/models/token.php
Normal file
@ -0,0 +1,207 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* app/models/token.php
|
||||||
|
*
|
||||||
|
* This class is used for the manipulation of the tokens database table.
|
||||||
|
*
|
||||||
|
* @version 5.0.1
|
||||||
|
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||||
|
* @link https://TheTempusProject.com
|
||||||
|
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||||
|
*/
|
||||||
|
namespace TheTempusProject\Models;
|
||||||
|
|
||||||
|
use TheTempusProject\Bedrock\Functions\Check;
|
||||||
|
use TheTempusProject\Canary\Bin\Canary as Debug;
|
||||||
|
use TheTempusProject\Classes\DatabaseModel;
|
||||||
|
use TheTempusProject\Bedrock\Classes\Config;
|
||||||
|
use TheTempusProject\TheTempusProject as App;
|
||||||
|
|
||||||
|
class Token extends DatabaseModel {
|
||||||
|
public $tableName = 'tokens';
|
||||||
|
public $modelVersion = '1.0';
|
||||||
|
public $configName = 'api';
|
||||||
|
public $databaseMatrix = [
|
||||||
|
[ 'name', 'varchar', '128' ],
|
||||||
|
[ 'token_type', 'varchar', '8' ],
|
||||||
|
[ 'notes', 'text', '' ],
|
||||||
|
[ 'token', 'varchar', '64' ],
|
||||||
|
[ 'secret', 'varchar', '256' ],
|
||||||
|
[ 'createdAt', 'int', '10' ],
|
||||||
|
[ 'createdBy', 'int', '10' ],
|
||||||
|
[ 'expiresAt', 'int', '10' ],
|
||||||
|
];
|
||||||
|
public $searchFields = [
|
||||||
|
'name',
|
||||||
|
'token',
|
||||||
|
];
|
||||||
|
public $permissionMatrix = [
|
||||||
|
'addAppToken' => [
|
||||||
|
'pretty' => 'Add Application Tokens',
|
||||||
|
'default' => false,
|
||||||
|
],
|
||||||
|
'addAppToken' => [
|
||||||
|
'pretty' => 'Add Personal Tokens',
|
||||||
|
'default' => false,
|
||||||
|
],
|
||||||
|
];
|
||||||
|
public $configMatrix = [
|
||||||
|
'apiAccessApp' => [
|
||||||
|
'type' => 'radio',
|
||||||
|
'pretty' => 'Enable Api Access for Personal Tokens.',
|
||||||
|
'default' => true,
|
||||||
|
],
|
||||||
|
'apiAccessPersonal' => [
|
||||||
|
'type' => 'radio',
|
||||||
|
'pretty' => 'Enable Api Access for Personal Tokens.',
|
||||||
|
'default' => true,
|
||||||
|
],
|
||||||
|
'AppAccessTokenExpiration' => [
|
||||||
|
'type' => 'text',
|
||||||
|
'pretty' => 'How long before app tokens expire (in seconds)',
|
||||||
|
'default' => 2592000,
|
||||||
|
],
|
||||||
|
'UserAccessTokenExpiration' => [
|
||||||
|
'type' => 'text',
|
||||||
|
'pretty' => 'How long before user tokens expire (in seconds)',
|
||||||
|
'default' => 604800,
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
public function create( $name, $note, $token_type = 'app' ) {
|
||||||
|
if ( 'app' == $token_type ) {
|
||||||
|
$expiration = Config::getValue( 'api/AppAccessTokenExpiration' );
|
||||||
|
if ( empty( $expiration ) ) {
|
||||||
|
$expiration = $this->configMatrix['AppAccessTokenExpiration']['default'];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$expiration = Config::getValue( 'api/UserAccessTokenExpiration' );
|
||||||
|
if ( empty( $expiration ) ) {
|
||||||
|
$expiration = $this->configMatrix['UserAccessTokenExpiration']['default'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$expireTime = time() + $expiration;
|
||||||
|
|
||||||
|
$fields = [
|
||||||
|
'name' => $name,
|
||||||
|
'notes' => $note,
|
||||||
|
'token_type' => $token_type,
|
||||||
|
'createdBy' => App::$activeUser->ID,
|
||||||
|
'createdAt' => time(),
|
||||||
|
'expiresAt' => $expireTime,
|
||||||
|
'token' => generateToken(),
|
||||||
|
'secret' => generateRandomString(256),
|
||||||
|
];
|
||||||
|
if ( self::$db->insert( $this->tableName, $fields ) ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function findOrCreateUserToken( $user_id, $refresh = false ) {
|
||||||
|
$test = $this->findUserToken( $user_id );
|
||||||
|
if ( ! empty( $test ) ) {
|
||||||
|
if ( ! empty( $refresh ) ) {
|
||||||
|
$token = $this->refresh( $test->ID, 'user' );
|
||||||
|
} else {
|
||||||
|
$token = $test->token;
|
||||||
|
}
|
||||||
|
return $token;
|
||||||
|
}
|
||||||
|
|
||||||
|
$expiration = Config::getValue( 'api/UserAccessTokenExpiration' );
|
||||||
|
if ( empty( $expiration ) ) {
|
||||||
|
$expiration = $this->configMatrix['UserAccessTokenExpiration']['default'];
|
||||||
|
}
|
||||||
|
$expireTime = time() + $expiration;
|
||||||
|
$token = generateToken();
|
||||||
|
$fields = [
|
||||||
|
'name' => 'Browser Token',
|
||||||
|
'notes' => 'findOrCreateUserToken',
|
||||||
|
'token_type' => 'user',
|
||||||
|
'createdBy' => $user_id,
|
||||||
|
'createdAt' => time(),
|
||||||
|
'expiresAt' => $expireTime,
|
||||||
|
'token' => $token,
|
||||||
|
'secret' => generateRandomString(256),
|
||||||
|
];
|
||||||
|
if ( self::$db->insert( $this->tableName, $fields ) ) {
|
||||||
|
return $token;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function update( $id, $name, $note, $token_type = 'app' ) {
|
||||||
|
$fields = [
|
||||||
|
'name' => $name,
|
||||||
|
'notes' => $note,
|
||||||
|
'token_type' => $token_type,
|
||||||
|
];
|
||||||
|
if ( self::$db->update( $this->tableName, $id, $fields ) ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function refresh( $id, $token_type = 'app' ) {
|
||||||
|
if ( 'app' == $token_type ) {
|
||||||
|
$expiration = Config::getValue( 'api/AppAccessTokenExpiration' );
|
||||||
|
if ( empty( $expiration ) ) {
|
||||||
|
$expiration = $this->configMatrix['AppAccessTokenExpiration']['default'];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$expiration = Config::getValue( 'api/UserAccessTokenExpiration' );
|
||||||
|
if ( empty( $expiration ) ) {
|
||||||
|
$expiration = $this->configMatrix['UserAccessTokenExpiration']['default'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$expireTime = time() + $expiration;
|
||||||
|
$token = generateToken();
|
||||||
|
|
||||||
|
$fields = [
|
||||||
|
'expiresAt' => $expireTime,
|
||||||
|
'token' => $token,
|
||||||
|
];
|
||||||
|
if ( self::$db->update( $this->tableName, $id, $fields ) ) {
|
||||||
|
return $token;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function findByforwardedUrl( $url ) {
|
||||||
|
if ( !Check::url( $url ) ) {
|
||||||
|
Debug::warn( "Invalid forwarded_url: $url" );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$routeData = self::$db->get( $this->tableName, [ 'forwarded_url', '=', $url ] );
|
||||||
|
if ( !$routeData->count() ) {
|
||||||
|
Debug::warn( "Could not find route by forwarded url: $url" );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return $this->filter( $routeData->first() );
|
||||||
|
}
|
||||||
|
|
||||||
|
public function findByToken( $token ) {
|
||||||
|
$data = self::$db->get( $this->tableName, [ 'token', '=', $token ] );
|
||||||
|
if ( ! $data->count() ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return $data->first();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function findBySecret( $secret ) {
|
||||||
|
$data = self::$db->get( $this->tableName, [ 'secret', '=', $secret ] );
|
||||||
|
if ( ! $data->count() ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return $data->first();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function findUserToken( $user_id ) {
|
||||||
|
$data = self::$db->get( $this->tableName, [ 'createdBy', '=', $user_id, 'AND', 'token_type', '=', 'user' ] );
|
||||||
|
if ( ! $data->count() ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return $data->first();
|
||||||
|
}
|
||||||
|
}
|
@ -8,7 +8,7 @@
|
|||||||
* @todo finish fixing the check functions that were migrated here
|
* @todo finish fixing the check functions that were migrated here
|
||||||
* These could go in the Forms class?
|
* These could go in the Forms class?
|
||||||
*
|
*
|
||||||
* @version 3.0
|
* @version 5.0.1
|
||||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||||
* @link https://TheTempusProject.com
|
* @link https://TheTempusProject.com
|
||||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||||
@ -43,13 +43,9 @@ class User extends DatabaseModel {
|
|||||||
[ 'name', 'varchar', '20' ],
|
[ 'name', 'varchar', '20' ],
|
||||||
[ 'confirmationCode', 'varchar', '80' ],
|
[ 'confirmationCode', 'varchar', '80' ],
|
||||||
[ 'prefs', 'text', '' ],
|
[ 'prefs', 'text', '' ],
|
||||||
[ 'auth_token', 'text', '' ],
|
|
||||||
];
|
];
|
||||||
public $permissionMatrix = [
|
public $searchFields = [
|
||||||
'uploadImages' => [
|
'username',
|
||||||
'pretty' => 'Upload images (such as avatars)',
|
|
||||||
'default' => false,
|
|
||||||
],
|
|
||||||
];
|
];
|
||||||
public $preferenceMatrix = [
|
public $preferenceMatrix = [
|
||||||
'gender' => [
|
'gender' => [
|
||||||
@ -122,6 +118,11 @@ class User extends DatabaseModel {
|
|||||||
'50',
|
'50',
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
'darkMode' => [
|
||||||
|
'pretty' => 'Enable Dark-Mode viewing',
|
||||||
|
'type' => 'checkbox',
|
||||||
|
'default' => 'false',
|
||||||
|
],
|
||||||
];
|
];
|
||||||
protected static $avatars;
|
protected static $avatars;
|
||||||
protected static $preferences;
|
protected static $preferences;
|
||||||
@ -424,7 +425,7 @@ class User extends DatabaseModel {
|
|||||||
if ( ! empty( $filter ) ) {
|
if ( ! empty( $filter ) ) {
|
||||||
switch ( $filter ) {
|
switch ( $filter ) {
|
||||||
case 'newsletter':
|
case 'newsletter':
|
||||||
$data = self::$db->search( $this->tableName, 'prefs', 'newsletter":"true' );
|
$data = self::$db->searchColumn( $this->tableName, 'prefs', 'newsletter":"true' );
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
$data = self::$db->get( $this->tableName, '*' );
|
$data = self::$db->get( $this->tableName, '*' );
|
||||||
@ -447,7 +448,7 @@ class User extends DatabaseModel {
|
|||||||
*/
|
*/
|
||||||
public function recent( $limit = null ) {
|
public function recent( $limit = null ) {
|
||||||
if ( empty( $limit ) ) {
|
if ( empty( $limit ) ) {
|
||||||
$data = self::$db->getpaginated( $this->tableName, '*' );
|
$data = self::$db->get( $this->tableName, '*' );
|
||||||
} else {
|
} else {
|
||||||
$data = self::$db->get( $this->tableName, [ 'ID', '>', '0' ], 'ID', 'DESC', [ 0, $limit ] );
|
$data = self::$db->get( $this->tableName, [ 'ID', '>', '0' ], 'ID', 'DESC', [ 0, $limit ] );
|
||||||
}
|
}
|
||||||
@ -542,6 +543,7 @@ class User extends DatabaseModel {
|
|||||||
$instance->prefs = json_decode( $instance->prefs, true );
|
$instance->prefs = json_decode( $instance->prefs, true );
|
||||||
$instance->gender = $instance->prefs['gender'];
|
$instance->gender = $instance->prefs['gender'];
|
||||||
$instance->avatar = $instance->prefs['avatar'];
|
$instance->avatar = $instance->prefs['avatar'];
|
||||||
|
$instance->usernamePretty = \ucfirst( $instance->username );
|
||||||
$out[] = $instance;
|
$out[] = $instance;
|
||||||
if ( !empty( $end ) ) {
|
if ( !empty( $end ) ) {
|
||||||
$out = $out[0];
|
$out = $out[0];
|
||||||
@ -655,7 +657,7 @@ class User extends DatabaseModel {
|
|||||||
}
|
}
|
||||||
if ( !self::$db->update( $this->tableName, $id, $fields ) ) {
|
if ( !self::$db->update( $this->tableName, $id, $fields ) ) {
|
||||||
new CustomException( 'userUpdate' );
|
new CustomException( 'userUpdate' );
|
||||||
Debug::error( "User: $id not updated: $fields" );
|
Debug::error( "User: $id not updated: " . var_export( $fields, true ) );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -682,6 +684,10 @@ class User extends DatabaseModel {
|
|||||||
Debug::error( "User: $id not updated." );
|
Debug::error( "User: $id not updated." );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if ( $id === App::$activeUser->ID ) {
|
||||||
|
$userData = $this->get( $id );
|
||||||
|
App::$activeUser = $userData;
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -694,33 +700,45 @@ class User extends DatabaseModel {
|
|||||||
return $this->data;
|
return $this->data;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function findByToken( $token ) {
|
public function authorize( $username, $password ) {
|
||||||
$data = self::$db->get( $this->tableName, [ 'auth_token', '=', $token ] );
|
if ( !isset( self::$log ) ) {
|
||||||
if ( ! $data->count() ) {
|
self::$log = new Log;
|
||||||
|
}
|
||||||
|
if ( !$this->get( $username ) ) {
|
||||||
|
self::$log->login( 0, "API: User not found: $username" );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return $data->first();
|
// login attempts protection.
|
||||||
}
|
$timeLimit = ( time() - 3600 );
|
||||||
|
$limit = Config::getValue( 'main/loginLimit' );
|
||||||
public function addAccessToken( $id, $length = 64 ) {
|
$user = $this->data();
|
||||||
if ( ! Check::id( $id ) ) {
|
if ( $limit > 0 ) {
|
||||||
|
$limitCheck = self::$db->get(
|
||||||
|
'logs',
|
||||||
|
[
|
||||||
|
'source', '=', 'login',
|
||||||
|
'AND',
|
||||||
|
'userID', '=', $user->ID,
|
||||||
|
'AND',
|
||||||
|
'time', '>=', $timeLimit,
|
||||||
|
'AND',
|
||||||
|
'action', '!=', 'pass',
|
||||||
|
]
|
||||||
|
);
|
||||||
|
if ( $limitCheck->count() >= $limit ) {
|
||||||
|
self::$log->login( $user->ID, 'API: Too many failed attempts.' );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$fields = [ 'auth_token' => $this->generateRandomString( $length ) ];
|
}
|
||||||
if ( !self::$db->update( $this->tableName, $id, $fields ) ) {
|
if ( !Check::password( $password ) ) {
|
||||||
Debug::error( "User: $id not updated." );
|
self::$log->login( $user->ID, 'API: Invalid Password.' );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
if ( !Hash::check( $password, $user->password ) ) {
|
||||||
|
self::$log->login( $user->ID, 'API: Wrong Password.' );
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
self::$log->login( $this->data()->ID, 'API: pass' );
|
||||||
private function generateRandomString( $length = 10 ) {
|
return $user;
|
||||||
$characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
|
||||||
$charactersLength = strlen( $characters );
|
|
||||||
$randomString = '';
|
|
||||||
for ($i = 0; $i < $length; $i++) {
|
|
||||||
$randomString .= $characters[random_int(0, $charactersLength - 1)];
|
|
||||||
}
|
|
||||||
return $randomString;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
* This is the Blog admin controller.
|
* This is the Blog admin controller.
|
||||||
*
|
*
|
||||||
* @package TP Blog
|
* @package TP Blog
|
||||||
* @version 3.0
|
* @version 5.0.1
|
||||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||||
* @link https://TheTempusProject.com
|
* @link https://TheTempusProject.com
|
||||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||||
@ -20,18 +20,15 @@ use TheTempusProject\Houdini\Classes\Navigation;
|
|||||||
use TheTempusProject\Houdini\Classes\Components;
|
use TheTempusProject\Houdini\Classes\Components;
|
||||||
use TheTempusProject\Classes\AdminController;
|
use TheTempusProject\Classes\AdminController;
|
||||||
use TheTempusProject\Classes\Forms;
|
use TheTempusProject\Classes\Forms;
|
||||||
use TheTempusProject\Plugins\Blog as BlogPlugin;
|
use TheTempusProject\Models\Posts;
|
||||||
|
|
||||||
class Blog extends AdminController {
|
class Blog extends AdminController {
|
||||||
public static $posts;
|
public static $posts;
|
||||||
|
|
||||||
public function __construct() {
|
public function __construct() {
|
||||||
parent::__construct();
|
parent::__construct();
|
||||||
$blog = new BlogPlugin;
|
self::$posts = new Posts;
|
||||||
self::$posts = $blog->posts;
|
|
||||||
self::$title = 'Admin - Blog';
|
self::$title = 'Admin - Blog';
|
||||||
$view = Navigation::activePageSelect( 'nav.admin', '/admin/blog' );
|
|
||||||
Components::set( 'ADMINNAV', $view );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function index( $data = null ) {
|
public function index( $data = null ) {
|
||||||
@ -47,7 +44,7 @@ class Blog extends AdminController {
|
|||||||
return $this->index();
|
return $this->index();
|
||||||
}
|
}
|
||||||
|
|
||||||
$result = self::$posts->newPost( Input::post( 'title' ), Input::post( 'blogPost' ), Input::post( 'submit' ) );
|
$result = self::$posts->newPost( Input::post( 'title' ), Input::post( 'blogPost' ), Input::post( 'slug' ), Input::post( 'submit' ) );
|
||||||
if ( $result ) {
|
if ( $result ) {
|
||||||
Issues::add( 'success', 'Your post has been created.' );
|
Issues::add( 'success', 'Your post has been created.' );
|
||||||
return $this->index();
|
return $this->index();
|
||||||
@ -68,7 +65,7 @@ class Blog extends AdminController {
|
|||||||
Issues::add( 'error', [ 'There was an error with your form.' => Check::userErrors() ] );
|
Issues::add( 'error', [ 'There was an error with your form.' => Check::userErrors() ] );
|
||||||
return $this->index();
|
return $this->index();
|
||||||
}
|
}
|
||||||
if ( self::$posts->updatePost( $data, Input::post( 'title' ), Input::post( 'blogPost' ), Input::post( 'submit' ) ) === true ) {
|
if ( self::$posts->updatePost( $data, Input::post( 'title' ), Input::post( 'blogPost' ), Input::post( 'slug' ), Input::post( 'submit' ) ) === true ) {
|
||||||
Issues::add( 'success', 'Post Updated.' );
|
Issues::add( 'success', 'Post Updated.' );
|
||||||
return $this->index();
|
return $this->index();
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
* This is the blog controller.
|
* This is the blog controller.
|
||||||
*
|
*
|
||||||
* @package TP Blog
|
* @package TP Blog
|
||||||
* @version 3.0
|
* @version 5.0.1
|
||||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||||
* @link https://TheTempusProject.com
|
* @link https://TheTempusProject.com
|
||||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||||
@ -27,17 +27,16 @@ use TheTempusProject\Plugins\Blog as BlogPlugin;
|
|||||||
use TheTempusProject\TheTempusProject as App;
|
use TheTempusProject\TheTempusProject as App;
|
||||||
use TheTempusProject\Plugins\Comments;
|
use TheTempusProject\Plugins\Comments;
|
||||||
use TheTempusProject\Models\Comments as CommentsModel;
|
use TheTempusProject\Models\Comments as CommentsModel;
|
||||||
|
use TheTempusProject\Models\Posts as PostsModel;
|
||||||
|
|
||||||
class Blog extends Controller {
|
class Blog extends Controller {
|
||||||
protected static $blog;
|
protected static $blog;
|
||||||
protected static $comments;
|
|
||||||
protected static $posts;
|
protected static $posts;
|
||||||
|
|
||||||
public function __construct() {
|
public function __construct() {
|
||||||
parent::__construct();
|
parent::__construct();
|
||||||
Template::setTemplate( 'blog' );
|
Template::setTemplate( 'blog' );
|
||||||
$blog = new BlogPlugin;
|
self::$posts = new PostsModel;
|
||||||
self::$posts = $blog->posts;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function index() {
|
public function index() {
|
||||||
@ -57,39 +56,46 @@ class Blog extends Controller {
|
|||||||
|
|
||||||
public function comments( $sub = null, $data = null ) {
|
public function comments( $sub = null, $data = null ) {
|
||||||
Debug::log( 'Controller initiated: ' . __METHOD__ . '.' );
|
Debug::log( 'Controller initiated: ' . __METHOD__ . '.' );
|
||||||
if ( empty( self::$comments ) ) {
|
|
||||||
self::$comments = new CommentsModel;
|
|
||||||
}
|
|
||||||
$plugin = new Comments;
|
|
||||||
if ( empty( $sub ) || empty( $data ) ) {
|
if ( empty( $sub ) || empty( $data ) ) {
|
||||||
Session::flash( 'error', 'Whoops, try again.' );
|
Issues::add( 'error', 'There was an issue with your request. Please check the url and try again.' );
|
||||||
Redirect::to( 'blog' );
|
return $this->index();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( class_exists( 'TheTempusProject\Plugins\Comments' ) ) {
|
||||||
|
$plugin = new Comments;
|
||||||
|
if ( ! $plugin->checkEnabled() ) {
|
||||||
|
Issues::add( 'error', 'Comments are disabled.' );
|
||||||
|
return $this->index();
|
||||||
|
}
|
||||||
|
$comments = new CommentsModel;
|
||||||
|
} else {
|
||||||
|
Debug::info( 'error', 'Comments plugin missing.' );
|
||||||
|
return $this->index();
|
||||||
|
}
|
||||||
|
|
||||||
switch ( $sub ) {
|
switch ( $sub ) {
|
||||||
case 'post':
|
case 'post':
|
||||||
$content = self::$posts->findById( (int) $data );
|
$content = self::$posts->findById( (int) $data );
|
||||||
if ( empty( $content ) ) {
|
if ( empty( $content ) ) {
|
||||||
Session::flash( 'error', 'Unknown Post.' );
|
Issues::add( 'error', 'Unknown Content.' );
|
||||||
Redirect::to( 'blog' );
|
return $this->index();
|
||||||
}
|
}
|
||||||
return $plugin->formPost( self::$posts->tableName, $content, 'blog/post/' );
|
return $plugin->formPost( self::$posts->tableName, $content, 'blog/post/' );
|
||||||
return self::$comments->formPost( 'blog', $content, 'blog/post/' );
|
|
||||||
case 'edit':
|
case 'edit':
|
||||||
$content = self::$comments->findById( $data );
|
$content = $comments->findById( $data );
|
||||||
if ( empty( $content ) ) {
|
if ( empty( $content ) ) {
|
||||||
Session::flash( 'error', 'Unknown Comment.' );
|
Issues::add( 'error', 'Unknown Comment.' );
|
||||||
Redirect::to( 'blog' );
|
return $this->index();
|
||||||
}
|
}
|
||||||
return $plugin->formEdit( self::$posts->tableName, $content, 'blog/post/' );
|
return $plugin->formEdit( self::$posts->tableName, $content, 'blog/post/' );
|
||||||
return self::$comments->formEdit( 'blog', $content, 'blog/post/' );
|
|
||||||
case 'delete':
|
case 'delete':
|
||||||
$content = self::$comments->findById( $data );
|
$content = $comments->findById( $data );
|
||||||
if ( empty( $content ) ) {
|
if ( empty( $content ) ) {
|
||||||
Session::flash( 'error', 'Unknown Comment.' );
|
Issues::add( 'error', 'Unknown Comment.' );
|
||||||
Redirect::to( 'blog' );
|
return $this->index();
|
||||||
}
|
}
|
||||||
return $plugin->formDelete( self::$posts->tableName, $content, 'blog/post/' );
|
return $plugin->formDelete( self::$posts->tableName, $content, 'blog/post/' );
|
||||||
return self::$comments->formDelete( 'blog', $content, 'blog/post/' );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,29 +104,39 @@ class Blog extends Controller {
|
|||||||
return $this->index();
|
return $this->index();
|
||||||
}
|
}
|
||||||
$post = self::$posts->findById( $id );
|
$post = self::$posts->findById( $id );
|
||||||
|
if ( empty( $post ) ) {
|
||||||
|
$post = self::$posts->findBySlug( $id );
|
||||||
if ( empty( $post ) ) {
|
if ( empty( $post ) ) {
|
||||||
return $this->index();
|
return $this->index();
|
||||||
}
|
}
|
||||||
if ( empty( self::$comments ) ) {
|
|
||||||
self::$comments = new CommentsModel;
|
|
||||||
}
|
}
|
||||||
Debug::log( 'Controller initiated: ' . __METHOD__ . '.' );
|
Debug::log( 'Controller initiated: ' . __METHOD__ . '.' );
|
||||||
self::$title = 'Blog Post';
|
self::$title = 'Blog Post';
|
||||||
// I removed this once because i didn't realize.
|
|
||||||
// this triggers the comment post controller method when the comment form is submitted on the post viewing page
|
|
||||||
if ( Input::exists( 'contentId' ) ) {
|
if ( Input::exists( 'contentId' ) ) {
|
||||||
$this->comments( 'post', Input::post( 'contentId' ) );
|
$this->comments( 'post', Input::post( 'contentId' ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
Components::set( 'CONTENT_ID', $id );
|
Components::set( 'CONTENT_ID', $id );
|
||||||
Components::set( 'COMMENT_TYPE', 'blog' );
|
Components::set( 'COMMENT_TYPE', self::$posts->tableName );
|
||||||
|
Components::set( 'NEWCOMMENT', '' );
|
||||||
|
Components::set( 'count', '0' );
|
||||||
|
Components::set( 'COMMENTS', '' );
|
||||||
|
|
||||||
|
if ( class_exists( 'TheTempusProject\Plugins\Comments' ) ) {
|
||||||
|
$plugin = new Comments;
|
||||||
|
if ( $plugin->checkEnabled() ) {
|
||||||
|
$comments = new CommentsModel;
|
||||||
if ( App::$isLoggedIn ) {
|
if ( App::$isLoggedIn ) {
|
||||||
Components::set( 'NEWCOMMENT', Views::simpleView( 'comments.create' ) );
|
Components::set( 'NEWCOMMENT', Views::simpleView( 'comments.create' ) );
|
||||||
} else {
|
} else {
|
||||||
Components::set( 'NEWCOMMENT', '' );
|
Components::set( 'NEWCOMMENT', '' );
|
||||||
}
|
}
|
||||||
$post = self::$posts->findById( $id );
|
Components::set( 'count', $comments->count( self::$posts->tableName, $post->ID ) );
|
||||||
Components::set( 'count', self::$comments->count( self::$posts->tableName, $post->ID ) );
|
Components::set( 'COMMENTS', Views::simpleView( 'comments.list', $comments->display( 10, self::$posts->tableName, $post->ID ) ) );
|
||||||
Components::set( 'COMMENTS', Views::simpleView( 'comments.list', self::$comments->display( 10, self::$posts->tableName, $post->ID ) ) );
|
}
|
||||||
|
}
|
||||||
|
|
||||||
self::$title .= ' - ' . $post->title;
|
self::$title .= ' - ' . $post->title;
|
||||||
self::$pageDescription = strip_tags( $post->contentSummaryNoLink );
|
self::$pageDescription = strip_tags( $post->contentSummaryNoLink );
|
||||||
Views::view( 'blog.post', $post );
|
Views::view( 'blog.post', $post );
|
||||||
@ -155,4 +171,16 @@ class Blog extends Controller {
|
|||||||
self::$pageDescription = '{SITENAME} blog posts easily and conveniently sorted by years.';
|
self::$pageDescription = '{SITENAME} blog posts easily and conveniently sorted by years.';
|
||||||
Views::view( 'blog.list', self::$posts->byYear( $year ) );
|
Views::view( 'blog.list', self::$posts->byYear( $year ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function search() {
|
||||||
|
$results = [];
|
||||||
|
if ( Input::exists( 'submit' ) ) {
|
||||||
|
$dbResults = self::$posts->search( Input::post('searchTerm') );
|
||||||
|
if ( ! empty( $dbResults ) ) {
|
||||||
|
$results = $dbResults;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Components::set( 'searchResults', Views::simpleView( 'blog.list', $results ) );
|
||||||
|
Views::view( 'blog.searchResults' );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
* This houses all of the form checking functions for this plugin.
|
* This houses all of the form checking functions for this plugin.
|
||||||
*
|
*
|
||||||
* @package TP Blog
|
* @package TP Blog
|
||||||
* @version 3.0
|
* @version 5.0.1
|
||||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||||
* @link https://TheTempusProject.com
|
* @link https://TheTempusProject.com
|
||||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
* This class is used for the manipulation of the blog database table.
|
* This class is used for the manipulation of the blog database table.
|
||||||
*
|
*
|
||||||
* @package TP Blog
|
* @package TP Blog
|
||||||
* @version 3.0
|
* @version 5.0.1
|
||||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||||
* @link https://TheTempusProject.com
|
* @link https://TheTempusProject.com
|
||||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||||
@ -24,6 +24,11 @@ use TheTempusProject\Models\Comments;
|
|||||||
|
|
||||||
class Posts extends DatabaseModel {
|
class Posts extends DatabaseModel {
|
||||||
public $tableName = 'posts';
|
public $tableName = 'posts';
|
||||||
|
public $searchFields = [
|
||||||
|
'title',
|
||||||
|
'slug',
|
||||||
|
'content',
|
||||||
|
];
|
||||||
public static $comments = false;
|
public static $comments = false;
|
||||||
|
|
||||||
public $databaseMatrix = [
|
public $databaseMatrix = [
|
||||||
@ -32,6 +37,7 @@ class Posts extends DatabaseModel {
|
|||||||
[ 'edited', 'int', '10' ],
|
[ 'edited', 'int', '10' ],
|
||||||
[ 'draft', 'int', '1' ],
|
[ 'draft', 'int', '1' ],
|
||||||
[ 'title', 'varchar', '86' ],
|
[ 'title', 'varchar', '86' ],
|
||||||
|
[ 'slug', 'varchar', '64' ],
|
||||||
[ 'content', 'text', '' ],
|
[ 'content', 'text', '' ],
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -45,7 +51,7 @@ class Posts extends DatabaseModel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function newPost( $title, $post, $draft ) {
|
public function newPost( $title, $post, $slug, $draft ) {
|
||||||
if ( !Check::dataTitle( $title ) ) {
|
if ( !Check::dataTitle( $title ) ) {
|
||||||
Debug::info( 'modelBlog: illegal title.' );
|
Debug::info( 'modelBlog: illegal title.' );
|
||||||
|
|
||||||
@ -59,6 +65,7 @@ class Posts extends DatabaseModel {
|
|||||||
$fields = [
|
$fields = [
|
||||||
'author' => App::$activeUser->ID,
|
'author' => App::$activeUser->ID,
|
||||||
'draft' => $draft,
|
'draft' => $draft,
|
||||||
|
'slug' => $slug,
|
||||||
'created' => time(),
|
'created' => time(),
|
||||||
'edited' => time(),
|
'edited' => time(),
|
||||||
'content' => Sanitize::rich( $post ),
|
'content' => Sanitize::rich( $post ),
|
||||||
@ -73,7 +80,7 @@ class Posts extends DatabaseModel {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function updatePost( $id, $title, $content, $draft ) {
|
public function updatePost( $id, $title, $content, $slug, $draft ) {
|
||||||
if ( empty( self::$log ) ) {
|
if ( empty( self::$log ) ) {
|
||||||
self::$log = new Log;
|
self::$log = new Log;
|
||||||
}
|
}
|
||||||
@ -94,6 +101,7 @@ class Posts extends DatabaseModel {
|
|||||||
}
|
}
|
||||||
$fields = [
|
$fields = [
|
||||||
'draft' => $draft,
|
'draft' => $draft,
|
||||||
|
'slug' => $slug,
|
||||||
'edited' => time(),
|
'edited' => time(),
|
||||||
'content' => Sanitize::rich( $content ),
|
'content' => Sanitize::rich( $content ),
|
||||||
'title' => $title,
|
'title' => $title,
|
||||||
@ -131,39 +139,49 @@ class Posts extends DatabaseModel {
|
|||||||
}
|
}
|
||||||
$draft = '';
|
$draft = '';
|
||||||
$authorName = self::$user->getUsername( $instance->author );
|
$authorName = self::$user->getUsername( $instance->author );
|
||||||
$cleanPost = Sanitize::contentShort( $instance->content );
|
|
||||||
$postSpace = explode( ' ', $cleanPost );
|
// Summarize
|
||||||
$postLine = explode( "\n", $cleanPost );
|
if ( ! empty( $instance->slug ) ) {
|
||||||
// summary by words: 100
|
$identifier = $instance->slug;
|
||||||
$spaceSummary = implode( ' ', array_splice( $postSpace, 0, 100 ) );
|
} else {
|
||||||
// summary by lines: 5
|
$identifier = $instance->ID;
|
||||||
$lineSummary = implode( "\n", array_splice( $postLine, 0, 5 ) );
|
}
|
||||||
if ( strlen( $spaceSummary ) < strlen( $lineSummary ) ) {
|
|
||||||
$contentSummary = $spaceSummary;
|
$cleanPost = Sanitize::contentShort( $instance->content );
|
||||||
if ( count( $postSpace, 1 ) <= 100 ) {
|
// By Word
|
||||||
$contentSummaryNoLink = $contentSummary;
|
$wordsArray = explode( ' ', $cleanPost );
|
||||||
$contentSummary .= '... <a href="{ROOT_URL}blog/post/' . $instance->ID . '">Read More</a>';
|
$wordSummary = implode( ' ', array_splice( $wordsArray, 0, 100 ) );
|
||||||
}
|
// By Line
|
||||||
|
$linesArray = explode( "\n", $cleanPost );
|
||||||
|
$lineSummary = implode( "\n", array_splice( $linesArray, 0, 5 ) );
|
||||||
|
|
||||||
|
if ( strlen( $wordSummary ) < strlen( $lineSummary ) ) {
|
||||||
|
$contentSummaryNoLink = $wordSummary;
|
||||||
|
$contentSummary = $wordSummary . '... <a href="{ROOT_URL}blog/post/' . $identifier . '" class="text-decoration-none">Read More</a>';
|
||||||
} else {
|
} else {
|
||||||
// @todo: need to refine this after testing
|
|
||||||
$contentSummaryNoLink = $lineSummary;
|
$contentSummaryNoLink = $lineSummary;
|
||||||
$contentSummary = $lineSummary . '... <a href="{ROOT_URL}blog/post/' . $instance->ID . '">Read More</a>';
|
$contentSummary = $lineSummary . '... <a href="{ROOT_URL}blog/post/' . $identifier . '" class="text-decoration-none">Read More</a>';
|
||||||
|
}
|
||||||
|
|
||||||
|
$instance->contentSummaryNoLink = $contentSummaryNoLink;
|
||||||
|
$instance->contentSummary = $contentSummary;
|
||||||
|
|
||||||
|
if ( isset( $params['stripHtml'] ) && $params['stripHtml'] === true ) {
|
||||||
|
$instance->contentSummary = strip_tags( $instance->content );
|
||||||
}
|
}
|
||||||
if ( $instance->draft != '0' ) {
|
if ( $instance->draft != '0' ) {
|
||||||
$draft = ' <b>Draft</b>';
|
$draft = ' <b>Draft</b>';
|
||||||
}
|
}
|
||||||
$instance->isDraft = $draft;
|
$instance->isDraft = $draft;
|
||||||
$instance->authorName = $authorName;
|
$instance->authorName = \ucfirst( $authorName );
|
||||||
$instance->contentSummaryNoLink = $contentSummaryNoLink;
|
|
||||||
$instance->contentSummary = $contentSummary;
|
|
||||||
if ( isset( $params['stripHtml'] ) && $params['stripHtml'] === true ) {
|
|
||||||
$instance->contentSummary = strip_tags( $instance->content );
|
|
||||||
}
|
|
||||||
if ( self::$comments !== false ) {
|
if ( self::$comments !== false ) {
|
||||||
$instance->commentCount = self::$comments->count( 'blog', $instance->ID );
|
$instance->commentCount = self::$comments->count( 'blog', $instance->ID );
|
||||||
|
} else {
|
||||||
|
$instance->commentCount = 0;
|
||||||
}
|
}
|
||||||
$instance->content = Filters::applyOne( 'mentions.0', $instance->content, true );
|
$instance->content = Filters::applyOne( 'mentions.0', $instance->content, true );
|
||||||
$instance->content = Filters::applyOne( 'hashtags.0', $instance->content, true );
|
$instance->content = Filters::applyOne( 'hashtags.0', $instance->content, true );
|
||||||
|
|
||||||
$out[] = $instance;
|
$out[] = $instance;
|
||||||
if ( !empty( $end ) ) {
|
if ( !empty( $end ) ) {
|
||||||
$out = $out[0];
|
$out = $out[0];
|
||||||
@ -221,9 +239,9 @@ class Posts extends DatabaseModel {
|
|||||||
$whereClause = '*';
|
$whereClause = '*';
|
||||||
}
|
}
|
||||||
if ( empty( $limit ) ) {
|
if ( empty( $limit ) ) {
|
||||||
$postData = self::$db->getPaginated( $this->tableName, $whereClause );
|
$postData = self::$db->get( $this->tableName, $whereClause );
|
||||||
} else {
|
} else {
|
||||||
$postData = self::$db->getPaginated( $this->tableName, $whereClause, 'ID', 'DESC', [0, $limit] );
|
$postData = self::$db->get( $this->tableName, $whereClause, 'ID', 'DESC', [0, $limit] );
|
||||||
}
|
}
|
||||||
if ( !$postData->count() ) {
|
if ( !$postData->count() ) {
|
||||||
Debug::info( 'No Blog posts found.' );
|
Debug::info( 'No Blog posts found.' );
|
||||||
@ -239,7 +257,7 @@ class Posts extends DatabaseModel {
|
|||||||
} else {
|
} else {
|
||||||
$whereClause = ['draft', '=', '0'];
|
$whereClause = ['draft', '=', '0'];
|
||||||
}
|
}
|
||||||
$postData = self::$db->getPaginated( $this->tableName, $whereClause );
|
$postData = self::$db->get( $this->tableName, $whereClause );
|
||||||
if ( !$postData->count() ) {
|
if ( !$postData->count() ) {
|
||||||
Debug::info( 'No Blog posts found.' );
|
Debug::info( 'No Blog posts found.' );
|
||||||
|
|
||||||
@ -263,7 +281,7 @@ class Posts extends DatabaseModel {
|
|||||||
$firstDayUnix = date( 'U', strtotime( "first day of $year" ) );
|
$firstDayUnix = date( 'U', strtotime( "first day of $year" ) );
|
||||||
$lastDayUnix = date( 'U', strtotime( "last day of $year" ) );
|
$lastDayUnix = date( 'U', strtotime( "last day of $year" ) );
|
||||||
$whereClause = array_merge( $whereClause, ['created', '<=', $lastDayUnix, 'AND', 'created', '>=', $firstDayUnix] );
|
$whereClause = array_merge( $whereClause, ['created', '<=', $lastDayUnix, 'AND', 'created', '>=', $firstDayUnix] );
|
||||||
$postData = self::$db->getPaginated( $this->tableName, $whereClause );
|
$postData = self::$db->get( $this->tableName, $whereClause );
|
||||||
if ( !$postData->count() ) {
|
if ( !$postData->count() ) {
|
||||||
Debug::info( 'No Blog posts found.' );
|
Debug::info( 'No Blog posts found.' );
|
||||||
|
|
||||||
@ -282,7 +300,7 @@ class Posts extends DatabaseModel {
|
|||||||
$whereClause = ['draft', '=', '0', 'AND'];
|
$whereClause = ['draft', '=', '0', 'AND'];
|
||||||
}
|
}
|
||||||
$whereClause = array_merge( $whereClause, ['author' => $ID] );
|
$whereClause = array_merge( $whereClause, ['author' => $ID] );
|
||||||
$postData = self::$db->getPaginated( $this->tableName, $whereClause );
|
$postData = self::$db->get( $this->tableName, $whereClause );
|
||||||
if ( !$postData->count() ) {
|
if ( !$postData->count() ) {
|
||||||
Debug::info( 'No Blog posts found.' );
|
Debug::info( 'No Blog posts found.' );
|
||||||
|
|
||||||
@ -291,6 +309,22 @@ class Posts extends DatabaseModel {
|
|||||||
return $this->filter( $postData->results() );
|
return $this->filter( $postData->results() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function findBySlug( $slug, $includeDraft = false ) {
|
||||||
|
$whereClause = [];
|
||||||
|
if ( $includeDraft !== true ) {
|
||||||
|
$whereClause = ['draft', '=', '0', 'AND'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$whereClause = array_merge( $whereClause, ['slug', '=', $slug] );
|
||||||
|
|
||||||
|
$postData = self::$db->get( $this->tableName, $whereClause );
|
||||||
|
if ( !$postData->count() ) {
|
||||||
|
Debug::info( 'No Blog posts found.' );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return $this->filter( $postData->first() );
|
||||||
|
}
|
||||||
|
|
||||||
public function byMonth( $month, $year = 0, $includeDraft = false ) {
|
public function byMonth( $month, $year = 0, $includeDraft = false ) {
|
||||||
if ( 0 === $year ) {
|
if ( 0 === $year ) {
|
||||||
$year = date( 'Y' );
|
$year = date( 'Y' );
|
||||||
@ -311,7 +345,7 @@ class Posts extends DatabaseModel {
|
|||||||
$month = date( 'F', $firstDayUnix );
|
$month = date( 'F', $firstDayUnix );
|
||||||
$lastDayUnix = date( 'U', strtotime( "last day of $month $year" ) );
|
$lastDayUnix = date( 'U', strtotime( "last day of $month $year" ) );
|
||||||
$whereClause = array_merge( $whereClause, ['created', '<=', $lastDayUnix, 'AND', 'created', '>=', $firstDayUnix] );
|
$whereClause = array_merge( $whereClause, ['created', '<=', $lastDayUnix, 'AND', 'created', '>=', $firstDayUnix] );
|
||||||
$postData = self::$db->getPaginated( $this->tableName, $whereClause );
|
$postData = self::$db->get( $this->tableName, $whereClause );
|
||||||
if ( !$postData->count() ) {
|
if ( !$postData->count() ) {
|
||||||
Debug::info( 'No Blog posts found.' );
|
Debug::info( 'No Blog posts found.' );
|
||||||
|
|
||||||
|
@ -5,19 +5,14 @@
|
|||||||
* This houses all of the main plugin info and functionality.
|
* This houses all of the main plugin info and functionality.
|
||||||
*
|
*
|
||||||
* @package TP Blog
|
* @package TP Blog
|
||||||
* @version 3.0
|
* @version 5.0.1
|
||||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||||
* @link https://TheTempusProject.com
|
* @link https://TheTempusProject.com
|
||||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||||
*/
|
*/
|
||||||
namespace TheTempusProject\Plugins;
|
namespace TheTempusProject\Plugins;
|
||||||
|
|
||||||
use ReflectionClass;
|
|
||||||
use TheTempusProject\Classes\Installer;
|
|
||||||
use TheTempusProject\Houdini\Classes\Navigation;
|
|
||||||
use TheTempusProject\Classes\Plugin;
|
use TheTempusProject\Classes\Plugin;
|
||||||
use TheTempusProject\Models\Posts;
|
|
||||||
use TheTempusProject\TheTempusProject as App;
|
|
||||||
|
|
||||||
class Blog extends Plugin {
|
class Blog extends Plugin {
|
||||||
public $pluginName = 'TP Blog';
|
public $pluginName = 'TP Blog';
|
||||||
@ -28,11 +23,11 @@ class Blog extends Plugin {
|
|||||||
public $pluginDescription = 'A simple plugin to add a blog to your installation.';
|
public $pluginDescription = 'A simple plugin to add a blog to your installation.';
|
||||||
public $admin_links = [
|
public $admin_links = [
|
||||||
[
|
[
|
||||||
'text' => '<i class="glyphicon glyphicon-text-size"></i> Blog',
|
'text' => '<i class="fa fa-fw fa-font"></i> Blog',
|
||||||
'url' => '{ROOT_URL}admin/blog',
|
'url' => '{ROOT_URL}admin/blog',
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
public $footer_links = [
|
public $info_footer_links = [
|
||||||
[
|
[
|
||||||
'text' => 'Blog',
|
'text' => 'Blog',
|
||||||
'url' => '{ROOT_URL}blog/index',
|
'url' => '{ROOT_URL}blog/index',
|
||||||
@ -42,6 +37,7 @@ class Blog extends Plugin {
|
|||||||
'posts' => [
|
'posts' => [
|
||||||
[
|
[
|
||||||
'title' => 'Welcome',
|
'title' => 'Welcome',
|
||||||
|
'slug' => 'welcome',
|
||||||
'content' => '<p>This is just a simple message to say thank you for installing The Tempus Project. If you have any questions you can find everything through our website <a href="https://TheTempusProject.com">here</a>.</p>',
|
'content' => '<p>This is just a simple message to say thank you for installing The Tempus Project. If you have any questions you can find everything through our website <a href="https://TheTempusProject.com">here</a>.</p>',
|
||||||
'author' => 1,
|
'author' => 1,
|
||||||
'created' => '{time}',
|
'created' => '{time}',
|
||||||
@ -50,10 +46,4 @@ class Blog extends Plugin {
|
|||||||
],
|
],
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
public $posts;
|
|
||||||
|
|
||||||
public function __construct( $load = false ) {
|
|
||||||
$this->posts = new Posts;
|
|
||||||
parent::__construct( $load );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -5,14 +5,14 @@
|
|||||||
* This is the loader for the blog template.
|
* This is the loader for the blog template.
|
||||||
*
|
*
|
||||||
* @package TP Blog
|
* @package TP Blog
|
||||||
* @version 3.0
|
* @version 5.0.1
|
||||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||||
* @link https://TheTempusProject.com
|
* @link https://TheTempusProject.com
|
||||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||||
*/
|
*/
|
||||||
namespace TheTempusProject\Templates;
|
namespace TheTempusProject\Templates;
|
||||||
|
|
||||||
use TheTempusProject\Plugins\Blog;
|
use TheTempusProject\Models\Posts;
|
||||||
use TheTempusProject\Houdini\Classes\Components;
|
use TheTempusProject\Houdini\Classes\Components;
|
||||||
use TheTempusProject\Houdini\Classes\Navigation;
|
use TheTempusProject\Houdini\Classes\Navigation;
|
||||||
use TheTempusProject\Houdini\Classes\Views;
|
use TheTempusProject\Houdini\Classes\Views;
|
||||||
@ -25,10 +25,12 @@ class BlogLoader extends DefaultLoader {
|
|||||||
* needed by this template.
|
* needed by this template.
|
||||||
*/
|
*/
|
||||||
public function __construct() {
|
public function __construct() {
|
||||||
$blog = new Blog;
|
$posts = new Posts;
|
||||||
$posts = $blog->posts;
|
Components::set('SIDEBAR', Views::simpleView('blog.widgets.recent', $posts->recent(5)));
|
||||||
Components::set('SIDEBAR', Views::simpleView('blog.sidebar', $posts->recent(5)));
|
Components::set('SIDEBAR2', Views::simpleView('blog.widgets.archive', $posts->archive()));
|
||||||
Components::set('SIDEBAR2', Views::simpleView('blog.sidebar2', $posts->archive()));
|
Components::set('SIDEBARABOUT', Views::simpleView('blog.widgets.about'));
|
||||||
|
Components::set('SIDEBARSEARCH', Views::simpleView('blog.widgets.search'));
|
||||||
|
Components::set('BLOGFEATURES', '');
|
||||||
Navigation::setCrumbComponent( 'BLOG_BREADCRUMBS', Input::get( 'url' ) );
|
Navigation::setCrumbComponent( 'BLOG_BREADCRUMBS', Input::get( 'url' ) );
|
||||||
Components::set( 'BLOG_TEMPLATE_URL', Template::parse( '{ROOT_URL}app/plugins/comments/' ) );
|
Components::set( 'BLOG_TEMPLATE_URL', Template::parse( '{ROOT_URL}app/plugins/comments/' ) );
|
||||||
$this->addCss( '<link rel="stylesheet" href="{BLOG_TEMPLATE_URL}css/comments.css">' );
|
$this->addCss( '<link rel="stylesheet" href="{BLOG_TEMPLATE_URL}css/comments.css">' );
|
||||||
|
@ -4,16 +4,16 @@
|
|||||||
* app/plugins/blog/templates/blog.tpl
|
* app/plugins/blog/templates/blog.tpl
|
||||||
*
|
*
|
||||||
* @package TP Blog
|
* @package TP Blog
|
||||||
* @version 3.0
|
* @version 5.0.1
|
||||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||||
* @link https://TheTempusProject.com
|
* @link https://TheTempusProject.com
|
||||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||||
-->
|
-->
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="UTF-8">
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
<meta property="og:url" content="{CURRENT_URL}">
|
<meta property="og:url" content="{CURRENT_URL}">
|
||||||
<meta name='twitter:card' content='summary' />
|
<meta name='twitter:card' content='summary_large_image'>
|
||||||
<title>{TITLE}</title>
|
<title>{TITLE}</title>
|
||||||
<meta itemprop="name" content="{TITLE}">
|
<meta itemprop="name" content="{TITLE}">
|
||||||
<meta name="twitter:title" content="{TITLE}">
|
<meta name="twitter:title" content="{TITLE}">
|
||||||
@ -28,84 +28,110 @@
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<meta name="author" content="The Tempus Project">
|
<meta name="author" content="The Tempus Project">
|
||||||
{ROBOT}
|
{ROBOT}
|
||||||
<link rel="alternate" hreflang="en-us" href="alternateURL">
|
|
||||||
<link rel="icon" href="{ROOT_URL}images/favicon.ico">
|
<link rel="icon" href="{ROOT_URL}images/favicon.ico">
|
||||||
<!-- Required CSS -->
|
<!-- Required CSS -->
|
||||||
<link rel="stylesheet" href="{FONT_AWESOME_URL}font-awesome.min.css" crossorigin="anonymous">
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.1/css/all.min.css" crossorigin="anonymous" referrerpolicy="no-referrer">
|
||||||
<link rel="stylesheet" href="{BOOTSTRAP_CDN}css/bootstrap-theme.min.css" crossorigin="anonymous">
|
|
||||||
<link rel="stylesheet" href="{BOOTSTRAP_CDN}css/bootstrap.min.css" crossorigin="anonymous">
|
<link rel="stylesheet" href="{BOOTSTRAP_CDN}css/bootstrap.min.css" crossorigin="anonymous">
|
||||||
<!-- RSS -->
|
<!-- RSS -->
|
||||||
<link rel="alternate" href="{ROOT_URL}blog/rss" title="{TITLE} Feed" type="application/rss+xml" />
|
<link rel="alternate" href="{ROOT_URL}blog/rss" title="{TITLE} Feed" type="application/rss+xml">
|
||||||
<!-- Custom styles for this template -->
|
<!-- Custom styles for this template -->
|
||||||
{TEMPLATE_CSS_INCLUDES}
|
{TEMPLATE_CSS_INCLUDES}
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<nav class="navbar navbar-inverse navbar-fixed-top" role="navigation">
|
<!-- Navigation -->
|
||||||
<!--Brand and toggle should get grouped for better mobile display -->
|
<header class="p-3 text-bg-dark">
|
||||||
<div class="navbar-header">
|
<div class="container">
|
||||||
<a href="{ROOT_URL}" class="navbar-brand">{SITENAME}</a>
|
<div class="d-flex align-items-center position-relative">
|
||||||
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-ex1-collapse" style="">
|
<!-- Navbar Toggler (Left) -->
|
||||||
<span class="sr-only">Toggle navigation</span>
|
|
||||||
<span class="icon-bar"></span>
|
<!-- Centered Logo (Now inside normal document flow) -->
|
||||||
<span class="icon-bar"></span>
|
<a href="/" class="align-items-center text-white text-decoration-none d-flex d-md-none">
|
||||||
<span class="icon-bar"></span>
|
<img src="{ROOT_URL}{LOGO}" width="40" height="32" alt="{SITENAME} Logo" class="bi">
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<!-- Logo (Normal Position for Large Screens) -->
|
||||||
|
<a href="/" class="align-items-center text-white text-decoration-none d-none d-md-flex">
|
||||||
|
<img src="{ROOT_URL}{LOGO}" width="40" height="32" alt="{SITENAME} Logo" class="bi">
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<div class="navbar-expand-md flex-grow-1">
|
||||||
|
<div class="collapse navbar-collapse d-md-flex" id="mainMenu">
|
||||||
|
<!-- Centered Navigation -->
|
||||||
|
<div class="d-none d-md-block d-flex justify-content-center position-absolute start-50 translate-middle-x">
|
||||||
|
{topNavLeft}
|
||||||
|
</div>
|
||||||
|
<div class="d-flex justify-content-center flex-grow-1 d-md-none">
|
||||||
|
{topNavLeft}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Right-Side Content (Push to End) -->
|
||||||
|
<div class="d-flex flex-row justify-content-center align-items-center mt-3 mt-md-0 ms-md-auto">
|
||||||
|
{topNavRight}
|
||||||
|
</div>
|
||||||
|
</div> <!-- End Collapse -->
|
||||||
|
</div> <!-- End Navbar Expand -->
|
||||||
|
|
||||||
|
<button class="me-3 d-md-none btn btn-md btn-outline-light" type="button" data-bs-toggle="collapse" data-bs-target="#mainMenu" aria-controls="mainMenu" aria-expanded="false" aria-label="Toggle navigation">
|
||||||
|
<i class="fa fa-bars"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="container-fluid">
|
|
||||||
<div class="collapse navbar-collapse navbar-ex1-collapse">
|
|
||||||
{topNavLeft}
|
|
||||||
<div class="navbar-right">
|
|
||||||
<ul class="nav navbar-nav">
|
|
||||||
{topNavRight}
|
|
||||||
</ul>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</header>
|
||||||
</div>
|
|
||||||
</nav>
|
<div class="d-flex flex-column min-vh-100">
|
||||||
<div class="container-fluid">
|
<div class="flex-container flex-grow-1">
|
||||||
<div class="foot-pad">
|
|
||||||
{ISSUES}
|
{ISSUES}
|
||||||
|
<div class="container pt-4">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="container">
|
|
||||||
{ERROR}
|
{ERROR}
|
||||||
{NOTICE}
|
{NOTICE}
|
||||||
{SUCCESS}
|
{SUCCESS}
|
||||||
|
{INFO}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/ISSUES}
|
{/ISSUES}
|
||||||
<div class="row">
|
|
||||||
|
<!-- Leading Content -->
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="page-header">
|
{BLOGFEATURES}
|
||||||
<h1 class="blog-title">{SITENAME} Blog</h1>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
|
||||||
<div class="col-sm-8 blog-main">
|
<div class="pt-4">
|
||||||
{BLOG_BREADCRUMBS}
|
<div class="container">
|
||||||
|
<h3 class="pb-4 mb-4 fst-italic border-bottom context-main-border">
|
||||||
|
{SITENAME} Blog
|
||||||
|
</h3>
|
||||||
|
<div class="d-md-flex g-5">
|
||||||
|
<!-- Main Content -->
|
||||||
|
<div class="col-12 col-md-8">
|
||||||
{CONTENT}
|
{CONTENT}
|
||||||
</div>
|
</div>
|
||||||
<!-- /.blog-main -->
|
<!-- Sidebar Content -->
|
||||||
<div class="col-sm-3 col-sm-offset-1 blog-sidebar">
|
<div class="col-12 col-md-4">
|
||||||
<div class="sidebar-module">
|
<div class="position-sticky" style="top: 2rem;">
|
||||||
|
<div class="ps-md-2 ps-lg-5">
|
||||||
|
{SIDEBARABOUT}
|
||||||
|
</div>
|
||||||
|
<div class="ps-md-2 ps-lg-5">
|
||||||
|
{SIDEBARSEARCH}
|
||||||
|
</div>
|
||||||
|
<div class="ps-md-2 ps-lg-5">
|
||||||
{SIDEBAR}
|
{SIDEBAR}
|
||||||
</div>
|
</div>
|
||||||
<div class="sidebar-module">
|
<div class="ps-md-2 ps-lg-5">
|
||||||
{SIDEBAR2}
|
{SIDEBAR2}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- /.blog-sidebar -->
|
|
||||||
</div>
|
|
||||||
<!-- /.row -->
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<footer>
|
</div>
|
||||||
{FOOT}
|
{FOOT}
|
||||||
{COPY}
|
</div>
|
||||||
</footer>
|
|
||||||
<!-- Bootstrap core JavaScript and jquery -->
|
<!-- Bootstrap core JavaScript and jquery -->
|
||||||
<script src="{JQUERY_CDN}jquery.min.js" crossorigin="anonymous"></script>
|
<script language="JavaScript" crossorigin="anonymous" type="text/javascript" src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.11.6/dist/umd/popper.min.js"></script>
|
||||||
<script src="{BOOTSTRAP_CDN}js/bootstrap.min.js" crossorigin="anonymous"></script>
|
<script language="JavaScript" crossorigin="anonymous" type="text/javascript" src="{BOOTSTRAP_CDN}js/bootstrap.min.js"></script>
|
||||||
<!-- Custom javascript for this template -->
|
<!-- Custom javascript for this template -->
|
||||||
{TEMPLATE_JS_INCLUDES}
|
{TEMPLATE_JS_INCLUDES}
|
||||||
</body>
|
</body>
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
* This is the loader for the rss template.
|
* This is the loader for the rss template.
|
||||||
*
|
*
|
||||||
* @package TP Blog
|
* @package TP Blog
|
||||||
* @version 3.0
|
* @version 5.0.1
|
||||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||||
* @link https://TheTempusProject.com
|
* @link https://TheTempusProject.com
|
||||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||||
|
@ -1,31 +1,55 @@
|
|||||||
<form action="" method="post" class="form-horizontal" enctype="multipart/form-data">
|
<div class="context-main-bg context-main p-3">
|
||||||
<legend>New Blog Post</legend>
|
<legend class="text-center">Add Blog Post</legend>
|
||||||
<div class="form-group">
|
<hr>
|
||||||
<label for="title" class="col-lg-3 control-label">Title</label>
|
{ADMIN_BREADCRUMBS}
|
||||||
<div class="col-lg-3">
|
<form method="post">
|
||||||
<input type="text" class="form-check-input" name="title" id="title">
|
<fieldset>
|
||||||
</div>
|
<!-- Title -->
|
||||||
</div>
|
<div class="mb-3 row">
|
||||||
<div class="form-group">
|
<label for="title" class="col-lg-3 col-form-label text-end">Title:</label>
|
||||||
<div class="col-lg-6 col-lg-offset-3 btn-group">
|
|
||||||
<button type="button" class="btn btn-sm btn-primary" onclick="insertTag ('blogPost', 'c');">✔</button>
|
|
||||||
<button type="button" class="btn btn-sm btn-primary" onclick="insertTag ('blogPost', 'x');">✖</button>
|
|
||||||
<button type="button" class="btn btn-sm btn-primary" onclick="insertTag ('blogPost', '!');">❕</button>
|
|
||||||
<button type="button" class="btn btn-sm btn-primary" onclick="insertTag ('blogPost', '?');">❔</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="blogPost" class="col-lg-3 control-label">Post</label>
|
|
||||||
<div class="col-lg-6">
|
<div class="col-lg-6">
|
||||||
<textarea class="form-control" name="blogPost" maxlength="2000" rows="10" cols="50" id="blogPost"></textarea>
|
<input type="text" class="form-control" name="title" id="title" required>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
|
||||||
<div class="col-lg-6 col-lg-offset-3">
|
<!-- Slug -->
|
||||||
<button name="submit" value="publish" type="submit" class="btn btn-lg btn-primary">Publish</button>
|
<div class="mb-3 row">
|
||||||
<button name="submit" value="saveDraft" type="submit" class="btn btn-lg btn-primary">Save as Draft</button>
|
<label for="slug" class="col-lg-3 col-form-label text-end">URL Slug (for pretty linking):</label>
|
||||||
<button name="submit" value="preview" type="submit" class="btn btn-lg btn-primary">Preview</button>
|
<div class="col-lg-6">
|
||||||
|
<input type="text" class="form-control" name="slug" id="slug" required>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- form buttons -->
|
||||||
|
<div class="mb-3 row">
|
||||||
|
<div class="offset-3 col-lg-6">
|
||||||
|
<div class="btn-group w-100">
|
||||||
|
<button type="button" class="btn btn-sm btn-outline-primary" onclick="insertTag ('blogPost', 'c');">✔</button>
|
||||||
|
<button type="button" class="btn btn-sm btn-outline-primary" onclick="insertTag ('blogPost', 'x');">✖</button>
|
||||||
|
<button type="button" class="btn btn-sm btn-outline-primary" onclick="insertTag ('blogPost', '!');">❕</button>
|
||||||
|
<button type="button" class="btn btn-sm btn-outline-primary" onclick="insertTag ('blogPost', '?');">❔</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Message -->
|
||||||
|
<div class="mb-3 row">
|
||||||
|
<label for="blogPost" class="col-lg-3 col-form-label text-end">Post:</label>
|
||||||
|
<div class="col-lg-6">
|
||||||
|
<textarea class="form-control" name="blogPost" id="blogPost" rows="6" maxlength="2000" required></textarea>
|
||||||
|
<small class="form-text text-muted">Max: 2000 characters</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Hidden Token -->
|
||||||
<input type="hidden" name="token" value="{TOKEN}">
|
<input type="hidden" name="token" value="{TOKEN}">
|
||||||
</form>
|
</fieldset>
|
||||||
|
|
||||||
|
<!-- Submit Button -->
|
||||||
|
<div class="text-center">
|
||||||
|
<button name="submit" value="publish" type="submit" class="mx-2 btn btn-lg btn-primary">Publish</button>
|
||||||
|
<button name="submit" value="saveDraft" type="submit" class="mx-2 btn btn-lg btn-primary">Save as Draft</button>
|
||||||
|
<button name="submit" value="preview" type="submit" class="mx-2 btn btn-lg btn-primary">Preview</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
@ -1,5 +1,5 @@
|
|||||||
<legend>New Posts</legend>
|
<legend>New Posts</legend>
|
||||||
<table class="table table-striped">
|
<table class="table context-main">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th style="width: 20%"></th>
|
<th style="width: 20%"></th>
|
||||||
@ -14,9 +14,9 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<td>{title}</td>
|
<td>{title}</td>
|
||||||
<td>{contentSummary}</td>
|
<td>{contentSummary}</td>
|
||||||
<td><a href="{ROOT_URL}admin/blog/view/{ID}" class="btn btn-sm btn-primary" role="button"><i class="glyphicon glyphicon-open"></i></a></td>
|
<td><a href="{ROOT_URL}admin/blog/view/{ID}" class="btn btn-sm btn-primary"><i class="fa fa-fw fa-upload"></i></a></td>
|
||||||
<td><a href="{ROOT_URL}admin/blog/edit/{ID}" class="btn btn-sm btn-warning" role="button"><i class="glyphicon glyphicon-edit"></i></a></td>
|
<td><a href="{ROOT_URL}admin/blog/edit/{ID}" class="btn btn-sm btn-warning"><i class="fa fa-fw fa-pencil"></i></a></td>
|
||||||
<td width="30px"><a href="{ROOT_URL}admin/blog/delete/{ID}" class="btn btn-sm btn-danger" role="button"><i class="glyphicon glyphicon-trash"></i></a></td>
|
<td width="30px"><a href="{ROOT_URL}admin/blog/delete/{ID}" class="btn btn-sm btn-danger"><i class="fa fa-fw fa-trash"></i></a></td>
|
||||||
</tr>
|
</tr>
|
||||||
{/LOOP}
|
{/LOOP}
|
||||||
{ALT}
|
{ALT}
|
||||||
|
@ -1,31 +1,55 @@
|
|||||||
<form action="" method="post" class="form-horizontal" enctype="multipart/form-data">
|
<div class="context-main-bg context-main p-3">
|
||||||
<legend>Edit Blog Post</legend>
|
<legend class="text-center">Edit Blog Post</legend>
|
||||||
<div class="form-group">
|
<hr>
|
||||||
<label for="title" class="col-lg-3 control-label">Title</label>
|
{ADMIN_BREADCRUMBS}
|
||||||
<div class="col-lg-3">
|
<form method="post">
|
||||||
<input type="text" class="form-check-input" name="title" id="title" value="{title}">
|
<fieldset>
|
||||||
</div>
|
<!-- Title -->
|
||||||
</div>
|
<div class="mb-3 row">
|
||||||
<div class="form-group">
|
<label for="title" class="col-lg-3 col-form-label text-end">Title:</label>
|
||||||
<div class="col-lg-6 col-lg-offset-3 btn-group">
|
|
||||||
<button type="button" class="btn btn-sm btn-primary" onclick="insertTag ('blogPost', 'c');">✔</button>
|
|
||||||
<button type="button" class="btn btn-sm btn-primary" onclick="insertTag ('blogPost', 'x');">✖</button>
|
|
||||||
<button type="button" class="btn btn-sm btn-primary" onclick="insertTag ('blogPost', '!');">❕</button>
|
|
||||||
<button type="button" class="btn btn-sm btn-primary" onclick="insertTag ('blogPost', '?');">❔</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="blogPost" class="col-lg-3 control-label">Post</label>
|
|
||||||
<div class="col-lg-6">
|
<div class="col-lg-6">
|
||||||
<textarea class="form-control" name="blogPost" maxlength="2000" rows="10" cols="50" id="blogPost">{content}</textarea>
|
<input type="text" class="form-control" name="title" id="title" value="{title}" required>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
|
||||||
<div class="col-lg-6 col-lg-offset-3">
|
<!-- Slug -->
|
||||||
<button name="submit" value="publish" type="submit" class="btn btn-lg btn-primary">Publish</button>
|
<div class="mb-3 row">
|
||||||
<button name="submit" value="saveDraft" type="submit" class="btn btn-lg btn-primary">Save as Draft</button>
|
<label for="slug" class="col-lg-3 col-form-label text-end">URL Slug (for pretty linking):</label>
|
||||||
<button name="submit" value="preview" type="submit" class="btn btn-lg btn-primary">Preview</button>
|
<div class="col-lg-6">
|
||||||
|
<input type="text" class="form-control" name="slug" id="slug" value="{slug}" required>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- form buttons -->
|
||||||
|
<div class="mb-3 row">
|
||||||
|
<div class="offset-3 col-lg-6">
|
||||||
|
<div class="btn-group w-100">
|
||||||
|
<button type="button" class="btn btn-sm btn-outline-primary" onclick="insertTag ('blogPost', 'c');">✔</button>
|
||||||
|
<button type="button" class="btn btn-sm btn-outline-primary" onclick="insertTag ('blogPost', 'x');">✖</button>
|
||||||
|
<button type="button" class="btn btn-sm btn-outline-primary" onclick="insertTag ('blogPost', '!');">❕</button>
|
||||||
|
<button type="button" class="btn btn-sm btn-outline-primary" onclick="insertTag ('blogPost', '?');">❔</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Message -->
|
||||||
|
<div class="mb-3 row">
|
||||||
|
<label for="blogPost" class="col-lg-3 col-form-label text-end">Post:</label>
|
||||||
|
<div class="col-lg-6">
|
||||||
|
<textarea class="form-control" name="blogPost" id="blogPost" rows="6" maxlength="2000" required>{content}</textarea>
|
||||||
|
<small class="form-text text-muted">Max: 2000 characters</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Hidden Token -->
|
||||||
<input type="hidden" name="token" value="{TOKEN}">
|
<input type="hidden" name="token" value="{TOKEN}">
|
||||||
</form>
|
</fieldset>
|
||||||
|
|
||||||
|
<!-- Submit Button -->
|
||||||
|
<div class="text-center">
|
||||||
|
<button name="submit" value="publish" type="submit" class="mx-2 btn btn-lg btn-primary">Publish</button>
|
||||||
|
<button name="submit" value="saveDraft" type="submit" class="mx-2 btn btn-lg btn-primary">Save as Draft</button>
|
||||||
|
<button name="submit" value="preview" type="submit" class="mx-2 btn btn-lg btn-primary">Preview</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
@ -1,6 +1,8 @@
|
|||||||
<legend>Blog Posts</legend>
|
<div class="context-main-bg context-main p-3">
|
||||||
{PAGINATION}
|
<legend class="text-center">Blog Posts</legend>
|
||||||
<form action="{ROOT_URL}admin/blog/delete" method="post">
|
<hr>
|
||||||
|
{ADMIN_BREADCRUMBS}
|
||||||
|
<form action="{ROOT_URL}admin/blog/delete" method="post">
|
||||||
<table class="table table-striped">
|
<table class="table table-striped">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
@ -12,20 +14,20 @@
|
|||||||
<th style="width: 5%"></th>
|
<th style="width: 5%"></th>
|
||||||
<th style="width: 5%"></th>
|
<th style="width: 5%"></th>
|
||||||
<th style="width: 10%">
|
<th style="width: 10%">
|
||||||
<INPUT type="checkbox" onchange="checkAll(this)" name="check.b" value="B_[]"/>
|
<input type="checkbox" onchange="checkAll(this)" name="check.b" value="B_[]">
|
||||||
</th>
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{LOOP}
|
{LOOP}
|
||||||
<tr>
|
<tr>
|
||||||
<td><a href="{ROOT_URL}admin/blog/view/{ID}">{title}</a>{isDraft}</td>
|
<td><a href="{ROOT_URL}admin/blog/view/{ID}" class="text-decoration-none">{title}</a>{isDraft}</td>
|
||||||
<td>{authorName}</td>
|
<td>{authorName}</td>
|
||||||
<td>{commentCount}</td>
|
<td>{commentCount}</td>
|
||||||
<td>{DTC}{created}{/DTC}</td>
|
<td>{DTC}{created}{/DTC}</td>
|
||||||
<td>{DTC}{edited}{/DTC}</td>
|
<td>{DTC}{edited}{/DTC}</td>
|
||||||
<td><a href="{ROOT_URL}admin/blog/edit/{ID}" class="btn btn-sm btn-warning" role="button"><i class="glyphicon glyphicon-edit"></i></a></td>
|
<td><a href="{ROOT_URL}admin/blog/edit/{ID}" class="btn btn-sm btn-warning"><i class="fa fa-fw fa-pencil"></i></a></td>
|
||||||
<td><a href="{ROOT_URL}admin/blog/delete/{ID}" class="btn btn-sm btn-danger" role="button"><i class="glyphicon glyphicon-trash"></i></a></td>
|
<td><a href="{ROOT_URL}admin/blog/delete/{ID}" class="btn btn-sm btn-danger"><i class="fa fa-fw fa-trash"></i></a></td>
|
||||||
<td>
|
<td>
|
||||||
<input type="checkbox" value="{ID}" name="B_[]">
|
<input type="checkbox" value="{ID}" name="B_[]">
|
||||||
</td>
|
</td>
|
||||||
@ -40,6 +42,7 @@
|
|||||||
{/ALT}
|
{/ALT}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<a href="{ROOT_URL}admin/blog/create" class="btn btn-sm btn-primary" role="button">Create</a>
|
<a href="{ROOT_URL}admin/blog/create" class="btn btn-sm btn-primary">Create</a>
|
||||||
<button name="submit" value="submit" type="submit" class="btn btn-sm btn-danger">Delete</button>
|
<button name="submit" value="submit" type="submit" class="btn btn-sm btn-danger"><i class="fa fa-fw fa-trash"></i></button>
|
||||||
</form>
|
</form>
|
||||||
|
</div>
|
@ -7,7 +7,7 @@
|
|||||||
</div><!-- /.blog-post -->
|
</div><!-- /.blog-post -->
|
||||||
</div><!-- /.blog-main -->
|
</div><!-- /.blog-main -->
|
||||||
</div><!-- /.row -->
|
</div><!-- /.row -->
|
||||||
<form action="" method="post" class="form-horizontal" enctype="multipart/form-data">
|
<form method="post" enctype="multipart/form-data">
|
||||||
<legend>New Blog Post</legend>
|
<legend>New Blog Post</legend>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="title" class="col-lg-3 control-label">Title</label>
|
<label for="title" class="col-lg-3 control-label">Title</label>
|
||||||
|
@ -1,11 +1,14 @@
|
|||||||
<div class="row">
|
<div class="context-main-bg context-main p-3">
|
||||||
<div class="col-sm-8 blog-main">
|
<legend class="text-center">Blog Post: {title}</legend>
|
||||||
<div class="page-header">
|
<hr>
|
||||||
<h1>{title} <small>{DTC}{created}{/DTC} by <a href="{ROOT_URL}admin/users/view/{author}">{authorName}</a></small></h1>
|
{ADMIN_BREADCRUMBS}
|
||||||
</div>
|
<p class="blog-post-meta">{DTC date}{created}{/DTC} by <a href="{ROOT_URL}admin/users/view/{author}">{authorName}</a></p>
|
||||||
<div class="well">{content}</div>
|
<div class="well">{content}</div>
|
||||||
<a href="{ROOT_URL}admin/blog/delete/{ID}" class="btn btn-md btn-danger" role="button">Delete</a>
|
{ADMIN}
|
||||||
<a href="{ROOT_URL}admin/blog/edit/{ID}" class="btn btn-md btn-warning" role="button">Edit</a>
|
<hr>
|
||||||
<a href="{ROOT_URL}admin/comments/blog/{ID}" class="btn btn-md btn-primary" role="button">View Comments</a>
|
<a href="{ROOT_URL}admin/blog/delete/{ID}" class="btn btn-md btn-danger"><i class="fa fa-fw fa-trash"></i></a>
|
||||||
</div><!-- /.blog-main -->
|
<a href="{ROOT_URL}admin/blog/edit/{ID}" class="btn btn-md btn-warning"><i class="fa fa-fw fa-pencil"></i></a>
|
||||||
</div><!-- /.row -->
|
<a href="{ROOT_URL}admin/comments/blog/{ID}" class="btn btn-md btn-primary">View Comments</a>
|
||||||
|
<hr>
|
||||||
|
{/ADMIN}
|
||||||
|
</div>
|
7
app/plugins/blog/views/largeFeature.html
Normal file
7
app/plugins/blog/views/largeFeature.html
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<div class="p-4 p-md-5 mb-4 rounded text-bg-dark">
|
||||||
|
<div class="col-md-6 px-0">
|
||||||
|
<h1 class="display-4 fst-italic">Title of a longer featured blog post</h1>
|
||||||
|
<p class="lead my-3">Multiple lines of text that form the lede, informing new readers quickly and efficiently about what’s most interesting in this post’s contents.</p>
|
||||||
|
<p class="lead mb-0"><a href="#" class="text-white fw-bold">Continue reading...</a></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -1,18 +1,15 @@
|
|||||||
{PAGINATION}
|
|
||||||
{LOOP}
|
{LOOP}
|
||||||
<div class="blog-post">
|
<article class="blog-post context-main-bg p-2">
|
||||||
<h2 class="blog-post-title"><a href="{ROOT_URL}blog/post/{ID}">{title}</a></h2>
|
<h2 class="blog-post-title mb-1">{title}</h2>
|
||||||
<hr>
|
<p class="blog-post-meta">{DTC date}{created}{/DTC} by <a href="{ROOT_URL}home/profile/{authorName}" class="text-decoration-none">{authorName}</a></p>
|
||||||
<div class="well">
|
<div class="well">
|
||||||
<p class="blog-post-meta">
|
|
||||||
Posted on <i>{DTC date}{created}{/DTC}</i> by <a href="{ROOT_URL}home/profile/{author}"><strong>{authorName}</strong></a>
|
|
||||||
</p>
|
|
||||||
{contentSummary}
|
{contentSummary}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</article>
|
||||||
|
<hr>
|
||||||
{/LOOP}
|
{/LOOP}
|
||||||
{ALT}
|
{ALT}
|
||||||
<div class="blog-post">
|
<div class="text-center">
|
||||||
<p class="blog-post-meta">No Posts Found.</p>
|
<p class="h5">No Posts Found</p>
|
||||||
</div>
|
</div>
|
||||||
{/ALT}
|
{/ALT}
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-lg-12 col-sm-12 blog-main">
|
<div class="col-lg-12 col-sm-12 blog-main context-main-bg p-1 p-md-2 mb-2 rounded">
|
||||||
<div class="blog-post">
|
<div class="blog-post mb-5 pb-5">
|
||||||
<h2 class="blog-post-title">{title}</h2>
|
<h2 class="blog-post-title">{title}</h2>
|
||||||
<hr>
|
<hr>
|
||||||
<p class="blog-post-meta">{DTC date}{created}{/DTC} by <a href="{ROOT_URL}home/profile/{author}">{authorName}</a></p>
|
<p class="blog-post-meta">{DTC date}{created}{/DTC} by <a href="{ROOT_URL}home/profile/{authorName}" class="text-decoration-none">{authorName}</a></p>
|
||||||
{content}
|
{content}
|
||||||
{ADMIN}
|
{ADMIN}
|
||||||
<hr>
|
<hr>
|
||||||
<a href="{ROOT_URL}admin/blog/delete/{ID}" class="btn btn-md btn-danger" role="button">Delete</a>
|
<a href="{ROOT_URL}admin/blog/delete/{ID}" class="btn btn-md btn-danger"><i class="fa fa-fw fa-trash"></i></a>
|
||||||
<a href="{ROOT_URL}admin/blog/edit/{ID}" class="btn btn-md btn-warning" role="button">Edit</a>
|
<a href="{ROOT_URL}admin/blog/edit/{ID}" class="btn btn-md btn-warning"><i class="fa fa-fw fa-pencil"></i></a>
|
||||||
<hr>
|
<hr>
|
||||||
{/ADMIN}
|
{/ADMIN}
|
||||||
</div><!-- /.blog-post -->
|
</div><!-- /.blog-post -->
|
||||||
|
@ -1,15 +0,0 @@
|
|||||||
<div class="panel panel-info">
|
|
||||||
<div class="panel-heading">
|
|
||||||
<h3 class="panel-title">Recent Posts</h3>
|
|
||||||
</div>
|
|
||||||
<ul class="list-group">
|
|
||||||
{LOOP}
|
|
||||||
<li class="list-group-item">
|
|
||||||
<a href="{ROOT_URL}blog/post/{ID}">{title}</a>
|
|
||||||
</li>
|
|
||||||
{/LOOP}
|
|
||||||
{ALT}
|
|
||||||
<li class="list-group-item">No Posts to show</li>
|
|
||||||
{/ALT}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
3
app/plugins/blog/views/searchResults.html
Normal file
3
app/plugins/blog/views/searchResults.html
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<legend class="text-center my-2">Search Results</legend>
|
||||||
|
<hr>
|
||||||
|
{searchResults}
|
@ -1,18 +0,0 @@
|
|||||||
<div class="panel panel-info">
|
|
||||||
<div class="panel-heading">
|
|
||||||
<h3 class="panel-title">Recent Posts</h3>
|
|
||||||
</div>
|
|
||||||
<div class="panel-body">
|
|
||||||
<ol class="list-unstyled">
|
|
||||||
{LOOP}
|
|
||||||
<li><a href="{ROOT_URL}blog/post/{ID}">{title}</a></li>
|
|
||||||
{/LOOP}
|
|
||||||
{ALT}
|
|
||||||
<li>No Posts to show</li>
|
|
||||||
{/ALT}
|
|
||||||
</ol>
|
|
||||||
</div>
|
|
||||||
<div class="panel-footer">
|
|
||||||
<a href="{ROOT_URL}blog">View All</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
@ -1,14 +0,0 @@
|
|||||||
<div class="panel panel-info">
|
|
||||||
<div class="panel-heading">
|
|
||||||
<h3 class="panel-title">Archives</h3>
|
|
||||||
</div>
|
|
||||||
<div class="panel-body">
|
|
||||||
<ol class="list-unstyled">
|
|
||||||
{LOOP}
|
|
||||||
<li>({count}) <a href="{ROOT_URL}blog/month/{month}/{year}">{monthText} {year}</a></li>
|
|
||||||
{/LOOP}
|
|
||||||
{ALT}
|
|
||||||
{/ALT}
|
|
||||||
</ol>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
31
app/plugins/blog/views/smallFeature.html
Normal file
31
app/plugins/blog/views/smallFeature.html
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
|
||||||
|
<div class="row mb-2">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="row g-0 border rounded overflow-hidden flex-md-row mb-4 shadow-sm h-md-250 position-relative">
|
||||||
|
<div class="col p-4 d-flex flex-column position-static">
|
||||||
|
<strong class="d-inline-block mb-2 text-primary">World</strong>
|
||||||
|
<h3 class="mb-0">Featured post</h3>
|
||||||
|
<div class="mb-1 text-muted">Nov 12</div>
|
||||||
|
<p class="card-text mb-auto">This is a wider card with supporting text below as a natural lead-in to additional content.</p>
|
||||||
|
<a href="#" class="stretched-link">Continue reading</a>
|
||||||
|
</div>
|
||||||
|
<div class="col-auto d-none d-lg-block">
|
||||||
|
<svg class="bd-placeholder-img" width="200" height="250" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Placeholder: Thumbnail" preserveAspectRatio="xMidYMid slice" focusable="false"><title>Placeholder</title><rect width="100%" height="100%" fill="#55595c"><text x="50%" y="50%" fill="#eceeef" dy=".3em">Thumbnail</text></svg>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="row g-0 border rounded overflow-hidden flex-md-row mb-4 shadow-sm h-md-250 position-relative">
|
||||||
|
<div class="col p-4 d-flex flex-column position-static">
|
||||||
|
<strong class="d-inline-block mb-2 text-success">Design</strong>
|
||||||
|
<h3 class="mb-0">Post title</h3>
|
||||||
|
<div class="mb-1 text-muted">Nov 11</div>
|
||||||
|
<p class="mb-auto">This is a wider card with supporting text below as a natural lead-in to additional content.</p>
|
||||||
|
<a href="#" class="stretched-link">Continue reading</a>
|
||||||
|
</div>
|
||||||
|
<div class="col-auto d-none d-lg-block">
|
||||||
|
<svg class="bd-placeholder-img" width="200" height="250" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Placeholder: Thumbnail" preserveAspectRatio="xMidYMid slice" focusable="false"><title>Placeholder</title><rect width="100%" height="100%" fill="#55595c"><text x="50%" y="50%" fill="#eceeef" dy=".3em">Thumbnail</text></svg>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
11
app/plugins/blog/views/widgets/about.html
Normal file
11
app/plugins/blog/views/widgets/about.html
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<div class="pb-2 pb-lg-3">
|
||||||
|
<div class="card rounded context-main-bg">
|
||||||
|
<div class="card-body">
|
||||||
|
<h4 class="fst-italic">About</h4>
|
||||||
|
<p class="mb-0">
|
||||||
|
The blog is mostly here to serve ass a simple way to link to long-form content on the site.
|
||||||
|
There won't be any breaking news or tell-all stories here. Just good ole fashioned boring crap no one wants to read.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
17
app/plugins/blog/views/widgets/archive.html
Normal file
17
app/plugins/blog/views/widgets/archive.html
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<div class="pb-2 pb-lg-3">
|
||||||
|
<div class="card rounded context-main-bg">
|
||||||
|
<div class="card-header">
|
||||||
|
<h3 class="card-title">Archives</h3>
|
||||||
|
</div>
|
||||||
|
<div class="card-body context-second-bg">
|
||||||
|
<ol class="list-unstyled">
|
||||||
|
{LOOP}
|
||||||
|
<li>({count}) <a href="{ROOT_URL}blog/month/{month}/{year}" class="text-decoration-none">{monthText} {year}</a></li>
|
||||||
|
{/LOOP}
|
||||||
|
{ALT}
|
||||||
|
<li>None To Show</li>
|
||||||
|
{/ALT}
|
||||||
|
</ol>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
20
app/plugins/blog/views/widgets/recent.html
Normal file
20
app/plugins/blog/views/widgets/recent.html
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<div class="pb-2 pb-lg-3">
|
||||||
|
<div class="card rounded context-main-bg">
|
||||||
|
<div class="card-header">
|
||||||
|
<h3 class="card-title">Recent Posts</h3>
|
||||||
|
</div>
|
||||||
|
<div class="card-body context-second-bg">
|
||||||
|
<ol class="list-unstyled">
|
||||||
|
{LOOP}
|
||||||
|
<li><a href="{ROOT_URL}blog/post/{ID}" class="text-decoration-none">{title}</a></li>
|
||||||
|
{/LOOP}
|
||||||
|
{ALT}
|
||||||
|
<li>No Posts to show</li>
|
||||||
|
{/ALT}
|
||||||
|
</ol>
|
||||||
|
</div>
|
||||||
|
<div class="card-footer">
|
||||||
|
<a href="{ROOT_URL}blog" class="text-decoration-none">View All</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
18
app/plugins/blog/views/widgets/search.html
Normal file
18
app/plugins/blog/views/widgets/search.html
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<div class="pb-2 pb-lg-3">
|
||||||
|
<div class="card rounded context-main-bg">
|
||||||
|
<div class="card-body">
|
||||||
|
<form method="post" action="/blog/search">
|
||||||
|
<fieldset>
|
||||||
|
<!-- Hidden Token -->
|
||||||
|
<input type="hidden" name="token" value="{TOKEN}">
|
||||||
|
|
||||||
|
<!-- Search -->
|
||||||
|
<div class="input-group">
|
||||||
|
<input type="text" class="form-control" aria-label="Search Terms" name="searchTerm" id="searchTerm">
|
||||||
|
<button type="submit" class="btn btn-secondary bg-primary" name="submit" value="submit">Search</button>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -5,7 +5,7 @@
|
|||||||
* This is the bug report admin controller.
|
* This is the bug report admin controller.
|
||||||
*
|
*
|
||||||
* @package TP BugReports
|
* @package TP BugReports
|
||||||
* @version 3.0
|
* @version 5.0.1
|
||||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||||
* @link https://TheTempusProject.com
|
* @link https://TheTempusProject.com
|
||||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
* This is the bug reports controller.
|
* This is the bug reports controller.
|
||||||
*
|
*
|
||||||
* @package TP BugReports
|
* @package TP BugReports
|
||||||
* @version 3.0
|
* @version 5.0.1
|
||||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||||
* @link https://TheTempusProject.com
|
* @link https://TheTempusProject.com
|
||||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||||
@ -41,7 +41,7 @@ class Bugreport extends Controller {
|
|||||||
return Views::view( 'bugreport.create' );
|
return Views::view( 'bugreport.create' );
|
||||||
}
|
}
|
||||||
$result = self::$bugreport->create( App::$activeUser->ID, Input::post( 'url' ), Input::post( 'ourl' ), Input::post( 'repeat' ), Input::post( 'entry' ) );
|
$result = self::$bugreport->create( App::$activeUser->ID, Input::post( 'url' ), Input::post( 'ourl' ), Input::post( 'repeat' ), Input::post( 'entry' ) );
|
||||||
if ( true === $result ) {
|
if ( false != $result ) {
|
||||||
Session::flash( 'success', 'Your Bug Report has been received. We may contact you for more information at the email address you provided.' );
|
Session::flash( 'success', 'Your Bug Report has been received. We may contact you for more information at the email address you provided.' );
|
||||||
Redirect::to( 'home/index' );
|
Redirect::to( 'home/index' );
|
||||||
} else {
|
} else {
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
* This houses all of the form checking functions for this plugin.
|
* This houses all of the form checking functions for this plugin.
|
||||||
*
|
*
|
||||||
* @package TP BugReports
|
* @package TP BugReports
|
||||||
* @version 3.0
|
* @version 5.0.1
|
||||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||||
* @link https://TheTempusProject.com
|
* @link https://TheTempusProject.com
|
||||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
* This class is used for the manipulation of the bugreports database table.
|
* This class is used for the manipulation of the bugreports database table.
|
||||||
*
|
*
|
||||||
* @package TP BugReports
|
* @package TP BugReports
|
||||||
* @version 3.0
|
* @version 5.0.1
|
||||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||||
* @link https://TheTempusProject.com
|
* @link https://TheTempusProject.com
|
||||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||||
@ -13,7 +13,6 @@
|
|||||||
namespace TheTempusProject\Models;
|
namespace TheTempusProject\Models;
|
||||||
|
|
||||||
use TheTempusProject\Bedrock\Functions\Check;
|
use TheTempusProject\Bedrock\Functions\Check;
|
||||||
use TheTempusProject\Bedrock\Classes\Config;
|
|
||||||
use TheTempusProject\Canary\Bin\Canary as Debug;
|
use TheTempusProject\Canary\Bin\Canary as Debug;
|
||||||
use TheTempusProject\Canary\Classes\CustomException;
|
use TheTempusProject\Canary\Classes\CustomException;
|
||||||
use TheTempusProject\Classes\DatabaseModel;
|
use TheTempusProject\Classes\DatabaseModel;
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
* This houses all of the main plugin info and functionality.
|
* This houses all of the main plugin info and functionality.
|
||||||
*
|
*
|
||||||
* @package TP BugReports
|
* @package TP BugReports
|
||||||
* @version 3.0
|
* @version 5.0.1
|
||||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||||
* @link https://TheTempusProject.com
|
* @link https://TheTempusProject.com
|
||||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||||
@ -44,15 +44,16 @@ class Bugreport extends Plugin {
|
|||||||
],
|
],
|
||||||
];
|
];
|
||||||
public $permissionMatrix = [
|
public $permissionMatrix = [
|
||||||
'bugReport' => [
|
'canSendBugReports' => [
|
||||||
'pretty' => 'Can Submit Bug Reports',
|
'pretty' => 'Can Submit Bug Reports',
|
||||||
'default' => false,
|
'default' => false,
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
public $footer_links = [
|
public $contact_footer_links = [
|
||||||
[
|
[
|
||||||
'text' => 'Bug Report',
|
'text' => 'Report a Bug',
|
||||||
'url' => '{ROOT_URL}bugreport',
|
'url' => '{ROOT_URL}bugreport',
|
||||||
|
'filter' => 'loggedin',
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
public $admin_links = [
|
public $admin_links = [
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
<legend>Bug Reports</legend>
|
<div class="context-main-bg context-main p-3">
|
||||||
{PAGINATION}
|
<legend class="text-center">Bug Reports</legend>
|
||||||
<form action="{ROOT_URL}admin/bugreport/delete" method="post">
|
<hr>
|
||||||
|
{ADMIN_BREADCRUMBS}
|
||||||
|
<form action="{ROOT_URL}admin/bugreport/delete" method="post">
|
||||||
<table class="table table-striped">
|
<table class="table table-striped">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
@ -10,7 +12,7 @@
|
|||||||
<th style="width: 5%"></th>
|
<th style="width: 5%"></th>
|
||||||
<th style="width: 5%"></th>
|
<th style="width: 5%"></th>
|
||||||
<th style="width: 5%">
|
<th style="width: 5%">
|
||||||
<INPUT type="checkbox" onchange="checkAll(this)" name="check.br" value="BR_[]"/>
|
<input type="checkbox" onchange="checkAll(this)" name="check.br" value="BR_[]">
|
||||||
</th>
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
@ -20,8 +22,8 @@
|
|||||||
<td align="center">{ID}</td>
|
<td align="center">{ID}</td>
|
||||||
<td align="center">{DTC}{time}{/DTC}</td>
|
<td align="center">{DTC}{time}{/DTC}</td>
|
||||||
<td>{description}</td>
|
<td>{description}</td>
|
||||||
<td><a href="{ROOT_URL}admin/bugreport/view/{ID}" class="btn btn-sm btn-primary" role="button"><i class="glyphicon glyphicon-open"></i></a></td>
|
<td><a href="{ROOT_URL}admin/bugreport/view/{ID}" class="btn btn-sm btn-primary"><i class="fa fa-fw fa-upload"></i></a></td>
|
||||||
<td><a href="{ROOT_URL}admin/bugreport/delete/{ID}" class="btn btn-sm btn-danger" role="button"><i class="glyphicon glyphicon-trash"></i></a></td>
|
<td><a href="{ROOT_URL}admin/bugreport/delete/{ID}" class="btn btn-sm btn-danger"><i class="fa fa-fw fa-trash"></i></a></td>
|
||||||
<td>
|
<td>
|
||||||
<input type="checkbox" value="{ID}" name="BR_[]">
|
<input type="checkbox" value="{ID}" name="BR_[]">
|
||||||
</td>
|
</td>
|
||||||
@ -36,7 +38,8 @@
|
|||||||
{/ALT}
|
{/ALT}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<button name="submit" value="submit" type="submit" class="btn btn-sm btn-danger">Delete</button>
|
<button name="submit" value="submit" type="submit" class="btn btn-sm btn-danger"><i class="fa fa-fw fa-trash"></i></button>
|
||||||
</form>
|
</form>
|
||||||
<br />
|
<br>
|
||||||
<a href="{ROOT_URL}admin/bugreport/clear">clear all</a>
|
<a href="{ROOT_URL}admin/bugreport/clear">clear all</a>
|
||||||
|
</div>
|
@ -1,45 +1,49 @@
|
|||||||
<div class="container">
|
<div class="container py-4">
|
||||||
<div class="row">
|
<div class="row justify-content-center">
|
||||||
<div class="col-xs-12 col-sm-12 col-md-6 col-lg-6 col-xs-offset-0 col-sm-offset-0 col-md-offset-3 col-lg-offset-3 top-pad" >
|
<div class="col-md-8">
|
||||||
<div class="panel panel-primary">
|
{ADMIN_BREADCRUMBS}
|
||||||
<div class="panel-heading">
|
<div class="card shadow">
|
||||||
<h3 class="panel-title">Bug Report</h3>
|
<!-- Card Header -->
|
||||||
|
<div class="card-header text-center bg-dark text-white">
|
||||||
|
<h3 class="card-title mb-0">Bug Report</h3>
|
||||||
</div>
|
</div>
|
||||||
<div class="panel-body">
|
|
||||||
<div class="row">
|
<!-- Card Body -->
|
||||||
<div class=" col-md-12 col-lg-12 ">
|
<div class="card-body">
|
||||||
<table class="table table-user-primary">
|
<div class="row align-items-center">
|
||||||
|
<!-- Log Details -->
|
||||||
|
<table class="table table-borderless">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td align="left" width="200"><b>ID</b></td>
|
<th scope="row">ID:</th>
|
||||||
<td align="right">{ID}</td>
|
<td>{ID}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><b>Time submitted</b></td>
|
<th scope="row">Time submitted</th>
|
||||||
<td align="right">{DTC}{time}{/DTC}</td>
|
<td>{DTC}{time}{/DTC}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><b>Submitted by</b></td>
|
<th scope="row">URL:</th>
|
||||||
<td align="right"><a href="{ROOT_URL}admin/users/view/{userID}">{submittedBy}</a></td>
|
<td><a href="{URL}">{URL}</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><b>IP</b></td>
|
<th scope="row">Original URL</th>
|
||||||
<td align="right">{ip}</td>
|
<td><a href="{OURL}">{OURL}</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><b>URL:</b></td>
|
<th scope="row">Multiple occurrences?</th>
|
||||||
<td align="right"><a href="{URL}">{URL}</a></td>
|
<td>{repeatText}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><b>Original URL</b></td>
|
<th scope="row">IP:</th>
|
||||||
<td align="right"><a href="{OURL}">{OURL}</a></td>
|
<td>{ip}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><b>Multiple occurrences?</b></td>
|
<th scope="row">User:</th>
|
||||||
<td align="right">{repeatText}</td>
|
<td><a href="{ROOT_URL}admin/users/view/{userID}">{submittedBy}</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td align="center" colspan="2"><b>Description</b></td>
|
<th scope="row" colspan="2">Description:</th>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="2">{description}</td>
|
<td colspan="2">{description}</td>
|
||||||
@ -48,13 +52,14 @@
|
|||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
<div class="panel-footer">
|
<!-- Admin Controls -->
|
||||||
|
<div class="card-footer text-center">
|
||||||
{ADMIN}
|
{ADMIN}
|
||||||
<form action="{ROOT_URL}admin/bugreport/delete" method="post">
|
<form action="{ROOT_URL}admin/bugreport/delete" method="post">
|
||||||
<INPUT type="hidden" name="BR_" value="{ID}"/>
|
<input type="hidden" name="BR_" value="{ID}">
|
||||||
<input type="hidden" name="token" value="{TOKEN}" />
|
<input type="hidden" name="token" value="{TOKEN}">
|
||||||
<button name="submit" value="submit" type="submit" class="btn btn-sm btn-danger"><i class="glyphicon glyphicon-remove"></i></button>
|
<button name="submit" value="submit" type="submit" class="btn btn-sm btn-danger"><i class="fa fa-fw fa-trash"></i></button>
|
||||||
</form>
|
</form>
|
||||||
{/ADMIN}
|
{/ADMIN}
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,36 +1,61 @@
|
|||||||
<legend>Bug Report</legend>
|
<div class="m-2 m-lg-4">
|
||||||
<p>Thank you for visiting Our bug reporting page. We value our users' input highly and in an effort to better serve your needs, please fill out the form below to help us address this issue.</p>
|
<div class="col-12 mx-5 col-sm-10 col-lg-8 mx-auto p-4 rounded shadow-sm context-main-bg">
|
||||||
<p>We read each and every bug report submitted, and by submitting this form you allow us to send you a follow up email.</p>
|
<h2 class="text-center mb-4">Report a Bug</h2>
|
||||||
<form action="" method="post" class="form-horizontal">
|
<hr>
|
||||||
<label for="url">Page you were trying to reach:</label>
|
<p class="text-center text-sm-start">
|
||||||
<input type="url" name="url" id="url" class="form-control" aria-describedby="urlHelp">
|
Thank you for visiting our bug reporting page. We value our users' input highly and in an effort to better serve your needs, please fill out the form below to help us address this issue.
|
||||||
<p id="urlHelp" class="form-text text-muted">
|
|
||||||
What is the URL of the page you actually received the error on? (The URL is the website address. Example: {ROOT_URL}home)
|
|
||||||
</p>
|
</p>
|
||||||
<label for="ourl">Page you were on:</label>
|
<p class="text-center text-sm-start">
|
||||||
|
We read each and every bug report submitted, and by submitting this form you allow us to send you a follow-up email.
|
||||||
|
</p>
|
||||||
|
<form method="post">
|
||||||
|
<!-- Page URL -->
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="url" class="form-label">Page you were trying to reach:</label>
|
||||||
|
<input type="url" name="url" id="url" class="form-control" aria-describedby="urlHelp" required>
|
||||||
|
<small id="urlHelp" class="form-text text-muted">
|
||||||
|
This is the URL of the page you actually received the error.
|
||||||
|
</small>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Referrer URL -->
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="ourl" class="form-label">Page you were on:</label>
|
||||||
<input type="url" name="ourl" id="ourl" class="form-control" aria-describedby="ourlHelp">
|
<input type="url" name="ourl" id="ourl" class="form-control" aria-describedby="ourlHelp">
|
||||||
<p id="ourlHelp" class="form-text text-muted">
|
<small id="ourlHelp" class="form-text text-muted">
|
||||||
What is the URL of the page you were on before you received the error? (The URL is the website address. Example: {ROOT_URL}home/newhome)
|
This is the URL of the page you were on before you received the error.
|
||||||
</p>
|
</small>
|
||||||
<label for="repeat">*Has this happened more than once?</label>
|
</div>
|
||||||
|
|
||||||
|
<!-- Repeat Issue -->
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label">*Has this happened more than once?</label>
|
||||||
<div class="form-check">
|
<div class="form-check">
|
||||||
<label class="form-check-label">
|
<input class="form-check-input" type="radio" name="repeat" id="repeatNo" value="false" checked>
|
||||||
<input class="form-check-input" type="radio" name="repeat" id="repeat" value="false" checked>
|
<label class="form-check-label" for="repeatNo">No</label>
|
||||||
No
|
|
||||||
</label>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="form-check">
|
<div class="form-check">
|
||||||
<label class="form-check-label">
|
<input class="form-check-input" type="radio" name="repeat" id="repeatYes" value="true">
|
||||||
<input class="form-check-input" type="radio" name="repeat" id="repeat" value="true">
|
<label class="form-check-label" for="repeatYes">Yes</label>
|
||||||
Yes
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="entry" class="col-lg-3 control-label">Describe the problem/error as best as you can: (max:2000 characters)</label>
|
|
||||||
<div class="col-lg-6">
|
|
||||||
<textarea class="form-control" name="entry" maxlength="2000" rows="10" cols="50" id="entry"></textarea>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Description -->
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="entry" class="form-label">Describe the error you received: </label>
|
||||||
|
<textarea class="form-control" name="entry" id="entry" rows="6" maxlength="2000" aria-describedby="descHelp" required></textarea>
|
||||||
|
<small id="descHelp" class="form-text text-muted">
|
||||||
|
(max: 2000 characters)
|
||||||
|
</small>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Hidden Token -->
|
||||||
<input type="hidden" name="token" value="{TOKEN}">
|
<input type="hidden" name="token" value="{TOKEN}">
|
||||||
<button name="submit" value="submit" type="submit" class="btn btn-lg btn-primary center-block">Submit</button>
|
|
||||||
</form>
|
<!-- Submit Button -->
|
||||||
|
<div class="text-center">
|
||||||
|
<button type="submit" name="submit" value="submit" class="btn btn-primary btn-lg">Submit</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -5,7 +5,7 @@
|
|||||||
* This is the comments admin controller.
|
* This is the comments admin controller.
|
||||||
*
|
*
|
||||||
* @package TP Comments
|
* @package TP Comments
|
||||||
* @version 3.0
|
* @version 5.0.1
|
||||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||||
* @link https://TheTempusProject.com
|
* @link https://TheTempusProject.com
|
||||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||||
@ -49,9 +49,13 @@ class Comments extends AdminController {
|
|||||||
$this->index();
|
$this->index();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function viewComment( $data = null ) {
|
public function viewComments( $contentID = null ) {
|
||||||
$commentData = self::$comments->findById( $data );
|
if ( empty( $contentID ) ) {
|
||||||
if ( $commentData !== false ) {
|
Issues::add( 'error', 'Content ID not found.' );
|
||||||
|
return $this->index();
|
||||||
|
}
|
||||||
|
$contentData = self::$comments->findById( $data );
|
||||||
|
if ( empty( $contentID ) ) {
|
||||||
return Views::view( 'comments.list', $commentData );
|
return Views::view( 'comments.list', $commentData );
|
||||||
}
|
}
|
||||||
Issues::add( 'error', 'Comment not found.' );
|
Issues::add( 'error', 'Comment not found.' );
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
*
|
*
|
||||||
* This is the Moderator controller.
|
* This is the Moderator controller.
|
||||||
*
|
*
|
||||||
* @version 3.0
|
* @version 5.0.1
|
||||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||||
* @link https://TheTempusProject.com
|
* @link https://TheTempusProject.com
|
||||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
* This houses all of the form checking functions for this plugin.
|
* This houses all of the form checking functions for this plugin.
|
||||||
*
|
*
|
||||||
* @package TP Comments
|
* @package TP Comments
|
||||||
* @version 3.0
|
* @version 5.0.1
|
||||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||||
* @link https://TheTempusProject.com
|
* @link https://TheTempusProject.com
|
||||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
* of the comments table.
|
* of the comments table.
|
||||||
*
|
*
|
||||||
* @package TP Comments
|
* @package TP Comments
|
||||||
* @version 3.0
|
* @version 5.0.1
|
||||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||||
* @link https://TheTempusProject.com
|
* @link https://TheTempusProject.com
|
||||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||||
@ -170,7 +170,7 @@ class Comments extends DatabaseModel {
|
|||||||
$where = ['contentType', '=', $contentType];
|
$where = ['contentType', '=', $contentType];
|
||||||
}
|
}
|
||||||
if ( empty( $limit ) ) {
|
if ( empty( $limit ) ) {
|
||||||
$commentData = self::$db->getPaginated( $this->tableName, $where, 'created', 'DESC' );
|
$commentData = self::$db->get( $this->tableName, $where, 'created', 'DESC' );
|
||||||
} else {
|
} else {
|
||||||
$commentData = self::$db->get( $this->tableName, $where, 'created', 'DESC', [0, $limit] );
|
$commentData = self::$db->get( $this->tableName, $where, 'created', 'DESC', [0, $limit] );
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
* This houses all of the main plugin info and functionality.
|
* This houses all of the main plugin info and functionality.
|
||||||
*
|
*
|
||||||
* @package TP Comments
|
* @package TP Comments
|
||||||
* @version 3.0
|
* @version 5.0.1
|
||||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||||
* @link https://TheTempusProject.com
|
* @link https://TheTempusProject.com
|
||||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||||
@ -25,9 +25,10 @@ use TheTempusProject\Houdini\Classes\Views;
|
|||||||
use TheTempusProject\Classes\Forms;
|
use TheTempusProject\Classes\Forms;
|
||||||
use TheTempusProject\Hermes\Functions\Redirect;
|
use TheTempusProject\Hermes\Functions\Redirect;
|
||||||
use TheTempusProject\Bedrock\Functions\Session;
|
use TheTempusProject\Bedrock\Functions\Session;
|
||||||
use TheTempusProject\Models\Comments as CommentModel;
|
use TheTempusProject\Models\Comments as CommentsModel;
|
||||||
|
|
||||||
class Comments extends Plugin {
|
class Comments extends Plugin {
|
||||||
|
protected static $comments;
|
||||||
public $pluginName = 'TP Comments';
|
public $pluginName = 'TP Comments';
|
||||||
public $pluginAuthor = 'JoeyK';
|
public $pluginAuthor = 'JoeyK';
|
||||||
public $pluginWebsite = 'https://TheTempusProject.com';
|
public $pluginWebsite = 'https://TheTempusProject.com';
|
||||||
@ -61,7 +62,6 @@ class Comments extends Plugin {
|
|||||||
]
|
]
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
public $comments;
|
|
||||||
|
|
||||||
public function __construct( $load = false ) {
|
public function __construct( $load = false ) {
|
||||||
if ( !empty(App::$activePerms) ) {
|
if ( !empty(App::$activePerms) ) {
|
||||||
@ -75,11 +75,16 @@ class Comments extends Plugin {
|
|||||||
'replace' => ( App::$isMod ? '$1' : '' ),
|
'replace' => ( App::$isMod ? '$1' : '' ),
|
||||||
'enabled' => true,
|
'enabled' => true,
|
||||||
];
|
];
|
||||||
$this->getModel();
|
self::$comments = new CommentsModel;
|
||||||
parent::__construct( $load );
|
parent::__construct( $load );
|
||||||
}
|
}
|
||||||
|
|
||||||
public function formPost( $type, $content, $redirect ) {
|
public function formPost( $type, $content, $redirect ) {
|
||||||
|
if ( ! $this->checkEnabled() ) {
|
||||||
|
Debug::info( 'Comments Plugin is disabled in the control panel.' );
|
||||||
|
Issues::add( 'error', 'Comments are disabled.' );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if ( !App::$isLoggedIn ) {
|
if ( !App::$isLoggedIn ) {
|
||||||
Session::flash( 'notice', 'You must be logged in to post comments.' );
|
Session::flash( 'notice', 'You must be logged in to post comments.' );
|
||||||
return Redirect::to( $redirect . $content->ID );
|
return Redirect::to( $redirect . $content->ID );
|
||||||
@ -88,7 +93,7 @@ class Comments extends Plugin {
|
|||||||
Session::flash( 'error', [ 'There was a problem with your comment form.' => Check::userErrors() ] );
|
Session::flash( 'error', [ 'There was a problem with your comment form.' => Check::userErrors() ] );
|
||||||
return Redirect::to( $redirect . $content->ID );
|
return Redirect::to( $redirect . $content->ID );
|
||||||
}
|
}
|
||||||
if ( !$this->comments->create( $type, $content->ID, Input::post( 'comment' ) ) ) {
|
if ( !self::$comments->create( $type, $content->ID, Input::post( 'comment' ) ) ) {
|
||||||
Session::flash( 'error', [ 'There was a problem posting your comment.' => Check::userErrors() ] );
|
Session::flash( 'error', [ 'There was a problem posting your comment.' => Check::userErrors() ] );
|
||||||
} else {
|
} else {
|
||||||
Session::flash( 'success', 'Comment posted' );
|
Session::flash( 'success', 'Comment posted' );
|
||||||
@ -97,6 +102,11 @@ class Comments extends Plugin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function formEdit( $type, $content, $redirect ) {
|
public function formEdit( $type, $content, $redirect ) {
|
||||||
|
if ( ! $this->checkEnabled() ) {
|
||||||
|
Debug::info( 'Comments Plugin is disabled in the control panel.' );
|
||||||
|
Issues::add( 'error', 'Comments are disabled.' );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if ( !App::$isLoggedIn ) {
|
if ( !App::$isLoggedIn ) {
|
||||||
Session::flash( 'notice', 'You must be logged in to do that.' );
|
Session::flash( 'notice', 'You must be logged in to do that.' );
|
||||||
return Redirect::to( $type );
|
return Redirect::to( $type );
|
||||||
@ -112,7 +122,7 @@ class Comments extends Plugin {
|
|||||||
Issues::add( 'error', [ 'There was a problem editing your comment.' => Check::userErrors() ] );
|
Issues::add( 'error', [ 'There was a problem editing your comment.' => Check::userErrors() ] );
|
||||||
return Views::view( 'comments.admin.edit', $content );
|
return Views::view( 'comments.admin.edit', $content );
|
||||||
}
|
}
|
||||||
if ( !$this->comments->update( $content->ID, Input::post( 'comment' ) ) ) {
|
if ( !self::$comments->update( $content->ID, Input::post( 'comment' ) ) ) {
|
||||||
Issues::add( 'error', [ 'There was a problem editing your comment.' => Check::userErrors() ] );
|
Issues::add( 'error', [ 'There was a problem editing your comment.' => Check::userErrors() ] );
|
||||||
return Views::view( 'comments.admin.edit', $content );
|
return Views::view( 'comments.admin.edit', $content );
|
||||||
}
|
}
|
||||||
@ -121,6 +131,11 @@ class Comments extends Plugin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function formDelete( $type, $content, $redirect ) {
|
public function formDelete( $type, $content, $redirect ) {
|
||||||
|
if ( ! $this->checkEnabled() ) {
|
||||||
|
Debug::info( 'Comments Plugin is disabled in the control panel.' );
|
||||||
|
Issues::add( 'error', 'Comments are disabled.' );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if ( !App::$isLoggedIn ) {
|
if ( !App::$isLoggedIn ) {
|
||||||
Session::flash( 'notice', 'You must be logged in to do that.' );
|
Session::flash( 'notice', 'You must be logged in to do that.' );
|
||||||
return Redirect::to( $type );
|
return Redirect::to( $type );
|
||||||
@ -129,18 +144,11 @@ class Comments extends Plugin {
|
|||||||
Session::flash( 'error', 'You do not have permission to edit this comment' );
|
Session::flash( 'error', 'You do not have permission to edit this comment' );
|
||||||
return Redirect::to( $type );
|
return Redirect::to( $type );
|
||||||
}
|
}
|
||||||
if ( !$this->comments->delete( (array) $content->ID ) ) {
|
if ( !self::$comments->delete( (array) $content->ID ) ) {
|
||||||
Session::flash( 'error', 'There was an error with your request.' );
|
Session::flash( 'error', 'There was an error with your request.' );
|
||||||
} else {
|
} else {
|
||||||
Session::flash( 'success', 'Comment has been deleted' );
|
Session::flash( 'success', 'Comment has been deleted' );
|
||||||
}
|
}
|
||||||
return Redirect::to( $redirect . $content->contentID );
|
return Redirect::to( $redirect . $content->contentID );
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getModel() {
|
|
||||||
if ( empty($this->comments) ) {
|
|
||||||
$this->comments = new CommentModel;
|
|
||||||
}
|
|
||||||
return $this->comments;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<legend>New Comments</legend>
|
<legend>New Comments</legend>
|
||||||
<table class="table table-striped">
|
<table class="table context-main">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th style="width: 20%"></th>
|
<th style="width: 20%"></th>
|
||||||
@ -13,8 +13,8 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<td>{authorName}</td>
|
<td>{authorName}</td>
|
||||||
<td>{content}</td>
|
<td>{content}</td>
|
||||||
<td><a href="{ROOT_URL}admin/comments/edit/{ID}" class="btn btn-sm btn-warning" role="button"><i class="glyphicon glyphicon-edit"></i></a></td>
|
<td><a href="{ROOT_URL}admin/comments/edit/{ID}" class="btn btn-sm btn-warning"><i class="fa fa-fw fa-pencil"></i></a></td>
|
||||||
<td><a href="{ROOT_URL}admin/comments/delete/{ID}" class="btn btn-sm btn-danger" role="button"><i class="glyphicon glyphicon-trash"></i></a></td>
|
<td><a href="{ROOT_URL}admin/comments/delete/{ID}" class="btn btn-sm btn-danger"><i class="fa fa-fw fa-trash"></i></a></td>
|
||||||
</tr>
|
</tr>
|
||||||
{/LOOP}
|
{/LOOP}
|
||||||
{ALT}
|
{ALT}
|
||||||
|
@ -1,9 +1,25 @@
|
|||||||
<form action="" method="post" class="form-horizontal">
|
<div class="mb-4 mt-4">
|
||||||
<div class="form-group center-block">
|
<div class="offset-md-1 col-10 p-3 context-main-bg">
|
||||||
<div class="col-lg-4 col-lg-offset-4">
|
<legend class="text-center">Edit Comment</legend>
|
||||||
<textarea class="form-control" name="comment" maxlength="2000" rows="10" cols="50" id="comment">{content}</textarea>
|
<hr>
|
||||||
|
{ADMIN_BREADCRUMBS}
|
||||||
|
<form method="post" class="container py-4">
|
||||||
|
<fieldset>
|
||||||
|
<div class="mb-3 row">
|
||||||
|
<label for="comment" class="col-lg-5 col-form-label text-end">Comment:</label>
|
||||||
|
<div class="col-lg-3">
|
||||||
|
<textarea class="form-control" name="comment" maxlength="2000" rows="5" cols="50" id="comment">{content}</textarea>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button name="submit" value="submit" type="submit" class="btn btn-lg btn-primary center-block">Comment</button>
|
|
||||||
|
<!-- Hidden Token -->
|
||||||
<input type="hidden" name="token" value="{TOKEN}">
|
<input type="hidden" name="token" value="{TOKEN}">
|
||||||
</form>
|
|
||||||
|
<!-- Submit Button -->
|
||||||
|
<div class="text-center">
|
||||||
|
<button type="submit" name="submit" value="submit" class="btn btn-primary btn-lg">Save</button>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -1,6 +1,8 @@
|
|||||||
<legend>Recent Comments</legend>
|
<div class="context-main-bg context-main p-3">
|
||||||
{PAGINATION}
|
<legend class="text-center">Recent Comments</legend>
|
||||||
<form action="{ROOT_URL}admin/comments/delete" method="post">
|
<hr>
|
||||||
|
{ADMIN_BREADCRUMBS}
|
||||||
|
<form action="{ROOT_URL}admin/comments/delete" method="post">
|
||||||
<table class="table table-striped">
|
<table class="table table-striped">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
@ -11,7 +13,7 @@
|
|||||||
<th style="width: 5%"></th>
|
<th style="width: 5%"></th>
|
||||||
<th style="width: 5%"></th>
|
<th style="width: 5%"></th>
|
||||||
<th style="width: 5%">
|
<th style="width: 5%">
|
||||||
<INPUT type="checkbox" onchange="checkAll(this)" name="check.c" value="C_[]"/>
|
<input type="checkbox" onchange="checkAll(this)" name="check.c" value="C_[]">
|
||||||
</th>
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
@ -22,8 +24,8 @@
|
|||||||
<td><a href="{ROOT_URL}admin/blog/view/{contentID}">{contentTitle}</a></td>
|
<td><a href="{ROOT_URL}admin/blog/view/{contentID}">{contentTitle}</a></td>
|
||||||
<td>{content}</td>
|
<td>{content}</td>
|
||||||
<td>{DTC}{created}{/DTC}</td>
|
<td>{DTC}{created}{/DTC}</td>
|
||||||
<td><a href="{ROOT_URL}admin/comments/edit/{ID}" class="btn btn-sm btn-warning" role="button"><i class="glyphicon glyphicon-edit"></i></a></td>
|
<td><a href="{ROOT_URL}admin/comments/edit/{ID}" class="btn btn-sm btn-warning"><i class="fa fa-fw fa-pencil"></i></a></td>
|
||||||
<td><a href="{ROOT_URL}admin/comments/delete/{ID}" class="btn btn-sm btn-danger" role="button"><i class="glyphicon glyphicon-trash"></i></a></td>
|
<td><a href="{ROOT_URL}admin/comments/delete/{ID}" class="btn btn-sm btn-danger"><i class="fa fa-fw fa-trash"></i></a></td>
|
||||||
<td>
|
<td>
|
||||||
<input type="checkbox" value="{ID}" name="C_[]">
|
<input type="checkbox" value="{ID}" name="C_[]">
|
||||||
</td>
|
</td>
|
||||||
@ -38,6 +40,6 @@
|
|||||||
{/ALT}
|
{/ALT}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<button name="submit" value="submit" type="submit" class="btn btn-sm btn-danger">Delete</button>
|
<button name="submit" value="submit" type="submit" class="btn btn-sm btn-danger"><i class="fa fa-fw fa-trash"></i></button>
|
||||||
</form>
|
</form>
|
||||||
<br />
|
</div>
|
@ -1,8 +1,8 @@
|
|||||||
<div class="action">
|
<div class="action">
|
||||||
<a href="{ROOT_URL}{COMMENT_TYPE}/comments/edit/{ID}" class="btn btn-warning btn-xs" role="button">
|
<a href="{ROOT_URL}{COMMENT_TYPE}/comments/edit/{ID}" class="btn btn-warning btn-sm">
|
||||||
<span class="glyphicon glyphicon-pencil"></span>
|
<span class="fa fa-fw fa-pencil"></span>
|
||||||
</a>
|
</a>
|
||||||
<a href="{ROOT_URL}{COMMENT_TYPE}/comments/delete/{ID}" class="btn btn-danger btn-xs" role="button">
|
<a href="{ROOT_URL}{COMMENT_TYPE}/comments/delete/{ID}" class="btn btn-danger btn-sm">
|
||||||
<span class="glyphicon glyphicon-trash"></span>
|
<span class="fa fa-fw fa-trash"></span>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
@ -1,10 +1,14 @@
|
|||||||
<form action="" method="post" class="form-horizontal">
|
<form method="post" class="text-center mx-auto mt-4" style="max-width: 600px;">
|
||||||
<div class="form-group center-block">
|
<div class="mb-3">
|
||||||
<div class="col-lg-8 col-lg-offset-2">
|
<textarea
|
||||||
<textarea class="form-control" name="comment" maxlength="2000" rows="4" cols="50" id="comment"></textarea>
|
class="form-control"
|
||||||
|
name="comment"
|
||||||
|
maxlength="2000"
|
||||||
|
rows="4"
|
||||||
|
id="comment"
|
||||||
|
placeholder="Write your comment here..."></textarea>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<button name="submit" value="submit" type="submit" class="btn btn-lg btn-primary mb-3">Comment</button>
|
||||||
<button name="submit" value="submit" type="submit" class="btn btn-lg btn-primary center-block">Comment</button>
|
|
||||||
<input type="hidden" name="token" value="{TOKEN}">
|
<input type="hidden" name="token" value="{TOKEN}">
|
||||||
<input type="hidden" name="contentId" value="{CONTENT_ID}">
|
<input type="hidden" name="contentId" value="{CONTENT_ID}">
|
||||||
</form>
|
</form>
|
@ -1,22 +1,23 @@
|
|||||||
<div class="panel panel-info widget comments">
|
<div class="card">
|
||||||
<div class="panel-heading">
|
<div class="card-header d-flex align-items-center justify-content-between context-main-bg context-main">
|
||||||
<span class="glyphicon glyphicon-comment"></span>
|
<h3 class="card-title mb-0">
|
||||||
<h3 class="panel-title">Comments</h3>
|
<i class="fa fa-fw fa-comment"></i> Comments
|
||||||
<span class="label label-primary">{count}</span>
|
</h3>
|
||||||
|
<span class="badge bg-primary">{count}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="panel-body">
|
<div class="card-body context-second-bg">
|
||||||
<ul class="list-group">
|
<ul class="list-group list-group-flush">
|
||||||
{LOOP}
|
{LOOP}
|
||||||
<li class="list-group-item">
|
<li class="list-group-item context-main-bg context-main mb-2">
|
||||||
<div class="row">
|
<div class="d-flex align-items-start">
|
||||||
<div class="col-xs-2 col-md-1">
|
<div class="me-3">
|
||||||
<img src="{ROOT_URL}{avatar}" class="img-circle img-responsive" alt="" />
|
<img src="{ROOT_URL}{avatar}" class="rounded-circle" alt="User Avatar" style="width: 50px; height: 50px;">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xs-10 col-md-11">
|
|
||||||
<div>
|
<div>
|
||||||
<div class="mic-info">
|
<div class="mb-1">
|
||||||
By: <a href="{ROOT_URL}home/profile/{author}">{authorName}</a> on {DTC date}{created}{/DTC}
|
<small class="text-muted">
|
||||||
</div>
|
By: <a href="{ROOT_URL}home/profile/{author}" class="text-decoration-none">{authorName}</a> on {DTC date}{created}{/DTC}
|
||||||
|
</small>
|
||||||
</div>
|
</div>
|
||||||
<div class="comment-text">
|
<div class="comment-text">
|
||||||
{content}
|
{content}
|
||||||
@ -27,13 +28,9 @@
|
|||||||
</li>
|
</li>
|
||||||
{/LOOP}
|
{/LOOP}
|
||||||
{ALT}
|
{ALT}
|
||||||
<li class="list-group-item">
|
<li class="list-group-item context-main-bg mb-2">
|
||||||
<div class="row">
|
<div class="text-center">
|
||||||
<div class="col-xs-10 col-md-11">
|
<p class="mb-0">Be the first to comment.</p>
|
||||||
<div class="comment-text">
|
|
||||||
<p class="text-center">Be the first to comment.</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
{/ALT}
|
{/ALT}
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user