Merge branch 'main' into allthebookmarks-com

This commit is contained in:
Joey Kimsey
2025-02-03 10:59:02 -05:00
27 changed files with 558 additions and 52 deletions

View File

@ -73,7 +73,7 @@ class Config extends BedrockConfig {
$html .= '<div class="mb-3 row">'; $html .= '<div class="mb-3 row">';
$html .= '<h4 class="col-lg-3 col-form-label text-end">Current Image</h4>'; $html .= '<h4 class="col-lg-3 col-form-label text-end">Current Image</h4>';
$html .= '<div class="col-lg-6">'; $html .= '<div class="col-lg-6">';
$html .= '<img alt="User Avatar" src="{ROOT_URL}' . $node['value'] . '" class="img-circle img-fluid p-2 avatar-125">'; $html .= '<img alt="configured image" src="{ROOT_URL}' . $node['value'] . '" class="img-circle img-fluid p-2 avatar-125">';
$html .= '</div>'; $html .= '</div>';
} }
$html .= '</div>'; $html .= '</div>';

View File

@ -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;
} }

View File

@ -115,6 +115,8 @@ class Forms extends Check {
self::addHandler( 'adminCreateToken', __CLASS__, 'adminCreateToken' ); self::addHandler( 'adminCreateToken', __CLASS__, 'adminCreateToken' );
self::addHandler( 'apiLogin', __CLASS__, 'apiLogin' ); self::addHandler( 'apiLogin', __CLASS__, 'apiLogin' );
self::addHandler( 'updatePreference', __CLASS__, 'updatePreference' ); 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' ] );
@ -663,4 +665,28 @@ class Forms extends Check {
} }
return true; 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;
}
} }

View File

@ -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];
} }
@ -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;
} }

View File

@ -245,7 +245,7 @@ class Permissions {
public static function getFieldEditHtml( $name, $default, $pretty ) { public static function getFieldEditHtml( $name, $default, $pretty ) {
$fieldname = str_ireplace( '/', '-', $name ); $fieldname = str_ireplace( '/', '-', $name );
$fieldHtml = Forms::getSwitchHtml( $fieldname, [ 'true', 'false' ], $default ); $fieldHtml = Forms::getSwitchHtml( $fieldname, $default );
$html = ''; $html = '';
$html .= '<div class="mb-3 row">'; $html .= '<div class="mb-3 row">';
$html .= '<label for="' . $fieldname . '" class="col-lg-6 col-form-label text-end">' . $pretty . '</label>'; $html .= '<label for="' . $fieldname . '" class="col-lg-6 col-form-label text-end">' . $pretty . '</label>';

View File

@ -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 ) {

View File

@ -276,7 +276,7 @@ class Preferences {
$html .= '<div class="mb-3 row">'; $html .= '<div class="mb-3 row">';
$html .= '<h4 class="col-lg-6 col-form-label text-start text-lg-end">Current Image</h4>'; $html .= '<h4 class="col-lg-6 col-form-label text-start text-lg-end">Current Image</h4>';
$html .= '<div class="col-lg-6">'; $html .= '<div class="col-lg-6">';
$html .= '<img alt="User Avatar" src="{ROOT_URL}' . $defaultValue . '" class="img-circle img-fluid p-2 avatar-125">'; $html .= '<img alt="preferred image" src="{ROOT_URL}' . $defaultValue . '" class="img-circle img-fluid p-2">';
$html .= '</div>'; $html .= '</div>';
} }
$html .= '</div>'; $html .= '</div>';

View File

@ -23,8 +23,154 @@ use TheTempusProject\Bedrock\Functions\Input;
use TheTempusProject\Bedrock\Functions\Check; use TheTempusProject\Bedrock\Functions\Check;
use TheTempusProject\Hermes\Functions\Redirect; use TheTempusProject\Hermes\Functions\Redirect;
use TheTempusProject\Bedrock\Functions\Session; 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 { class Images extends AdminController {
private $directories = [
APP_ROOT_DIRECTORY . 'images',
APP_ROOT_DIRECTORY . 'app/images',
APP_ROOT_DIRECTORY . 'app/plugins'
];
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 = [
'folderName' => $folderName,
'location' => $folder,
'subdirs' => $subdirs,
];
if ( ! empty( $subdirs ) ) {
$out['folderexpand'] = '<i class="fa-solid fa-caret-down justify-content-end"></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 {
$children = $this->generateFolderHtml( $sub );
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() { public function __construct() {
parent::__construct(); parent::__construct();
@ -76,39 +222,147 @@ class Images extends AdminController {
Views::view( 'admin.images.create' ); Views::view( 'admin.images.create' );
} }
public function delete( $id = null ) { public function delete() {
if ( self::$token->delete( [ $id ] ) ) { if ( self::$token->delete( [ $id ] ) ) {
Session::flash( 'success', 'Token deleted.' ); Session::flash( 'success', 'Token deleted.' );
} }
Redirect::to( 'admin/images' ); Redirect::to( 'admin/images' );
} }
public function edit( $id = null ) { public function rename() {
$token = self::$token->findById( $id );
if ( Input::exists( 'submit' ) ) { if ( ! Input::exists( 'fileLocation' ) ) {
if ( !TTPForms::check( 'adminEditToken' ) ) { Session::flash( 'warning', 'Unknown image.' );
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/images' ); 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() ] );
} }
} }
Forms::selectOption( $token->token_type ); }
return Views::view( 'admin.images.edit', $token );
return Views::view( 'admin.images.rename' );
} }
public function index() { public function index() {
return Views::view( 'admin.images.list', self::$token->listPaginated() ); return Views::view( 'admin.images.list.combined', $this->getAllImageDetails() );
} }
public function view( $id = null ) { public function view() {
return Views::view( 'admin.images.view', self::$token->findById( $id ) ); 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;
} }
} }

View File

@ -46,6 +46,14 @@ class Group extends DatabaseModel {
'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 = [
[ [

View File

@ -47,12 +47,6 @@ class User extends DatabaseModel {
public $searchFields = [ public $searchFields = [
'username', 'username',
]; ];
public $permissionMatrix = [
'uploadImages' => [
'pretty' => 'Upload images (such as avatars)',
'default' => false,
],
];
public $preferenceMatrix = [ public $preferenceMatrix = [
'gender' => [ 'gender' => [
'pretty' => 'Gender', 'pretty' => 'Gender',

View File

@ -45,19 +45,19 @@
<!-- Navbar Toggler (Left) --> <!-- Navbar Toggler (Left) -->
<!-- Centered Logo (Now inside normal document flow) --> <!-- Centered Logo (Now inside normal document flow) -->
<a href="/" class="d-flex align-items-center text-white text-decoration-none d-md-none mx-auto"> <a href="/" class="align-items-center text-white text-decoration-none d-flex d-md-none">
<img src="{ROOT_URL}{LOGO}" width="40" height="32" alt="{SITENAME} Logo" class="bi"> <img src="{ROOT_URL}{LOGO}" width="40" height="32" alt="{SITENAME} Logo" class="bi">
</a> </a>
<!-- Logo (Normal Position for Large Screens) --> <!-- Logo (Normal Position for Large Screens) -->
<a href="/" class="d-flex align-items-center text-white text-decoration-none d-none d-md-flex"> <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"> <img src="{ROOT_URL}{LOGO}" width="40" height="32" alt="{SITENAME} Logo" class="bi">
</a> </a>
<div class="navbar-expand-md flex-grow-1"> <div class="navbar-expand-md flex-grow-1">
<div class="collapse navbar-collapse d-md-flex" id="mainMenu"> <div class="collapse navbar-collapse d-md-flex" id="mainMenu">
<!-- Centered Navigation --> <!-- Centered Navigation -->
<div class="d-none d-md-block d-flex justify-content-center w-100 position-absolute start-50 translate-middle-x"> <div class="d-none d-md-block d-flex justify-content-center position-absolute start-50 translate-middle-x">
{topNavLeft} {topNavLeft}
</div> </div>
<div class="d-flex justify-content-center flex-grow-1 d-md-none"> <div class="d-flex justify-content-center flex-grow-1 d-md-none">
@ -77,6 +77,7 @@
</div> </div>
</div> </div>
</header> </header>
<div class="d-flex flex-column min-vh-100"> <div class="d-flex flex-column min-vh-100">
<div class="flex-container flex-grow-1"> <div class="flex-container flex-grow-1">
{ISSUES} {ISSUES}

View File

@ -44,7 +44,7 @@ class Bugreport extends Plugin {
], ],
]; ];
public $permissionMatrix = [ public $permissionMatrix = [
'bugReport' => [ 'canSendBugReports' => [
'pretty' => 'Can Submit Bug Reports', 'pretty' => 'Can Submit Bug Reports',
'default' => false, 'default' => false,
], ],

View File

@ -40,7 +40,7 @@ class Contact extends Plugin {
], ],
]; ];
public $permissionMatrix = [ public $permissionMatrix = [
'contact' => [ 'canUseContactForm' => [
'pretty' => 'Can Submit Contact', 'pretty' => 'Can Submit Contact',
'default' => true, 'default' => true,
], ],

View File

@ -0,0 +1,30 @@
<div class="container py-5 context-main-bg">
<div class="d-flex justify-content-between align-items-center">
{ADMIN_BREADCRUMBS}
<a href="{ROOT_URL}admin/images/upload" class="btn btn-sm btn-primary">Create</a>
</div>
<div class="row row-cols-1 row-cols-sm-2 row-cols-md-3 g-3">
{LOOP}
<div class="col">
<div class="card h-100 shadow-sm context-other-bg">
<div class="d-flex justify-content-center align-items-center context-other-bg" style="height: 250px;">
<img src="{url}" class="img-fluid p-2" style="max-width: 100%; max-height: 100%; object-fit: contain;">
</div>
<div class="card-body context-third-bg d-flex flex-column">
<div class="flex-grow-1">
<div class="d-flex justify-content-between align-items-center">
<div class="">
<a href="{ROOT_URL}admin/images/view?fileLocation={locationSafe}" class="btn btn-sm btn-outline-primary">View</a>
<a href="{url}" class="btn btn-sm btn-outline-primary" target="_blank">Open</a>
<a href="{ROOT_URL}admin/images/rename?fileLocation={locationSafe}" class="btn btn-sm btn-outline-warning">Rename</a>
<a href="{ROOT_URL}admin/images/delete?fileLocation={locationSafe}" class="btn btn-sm btn-outline-danger">Delete</a>
</div>
<small class="text-muted">{filename}</small>
</div>
</div>
</div>
</div>
</div>
{/LOOP}
</div>
</div>

View File

@ -0,0 +1,35 @@
<div class="context-main-bg context-main p-3">
<legend class="text-center">Rename Image</legend>
<hr>
{ADMIN_BREADCRUMBS}
<form method="post">
<fieldset>
<!-- Name -->
<div class="mb-3 row">
<label for="nickname" class="col-lg-6 col-form-label text-end">Location:</label>
<div class="col-lg-2">
<input type="hidden" class="form-control" name="filelocation" id="filelocation" value="{filelocation}">
<strong>
{filelocation}
</strong>
</div>
</div>
<!-- Forward URL -->
<div class="mb-3 row">
<label for="newname" class="col-lg-6 col-form-label text-end">New filename ( Extensions cannot be modified ):</label>
<div class="col-lg-2">
<input type="text" class="form-control" name="newname" id="newname" required>
</div>
</div>
<!-- Hidden Token -->
<input type="hidden" name="token" value="{TOKEN}">
<!-- 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>

View File

@ -0,0 +1,29 @@
<div class="container p-4 context-main-bg mb-4 text-center">
<h3 class="mb-4">Image Upload</h3>
<hr>
<div class="row justify-content-center">
<div class="col-md-6">
<form method="post" enctype="multipart/form-data">
<fieldset>
<div class="mb-3 row">
<label for="avatar" class="h4 col-lg-6 col-form-label text-start text-lg-end">Image</label>
<div class="col-lg-6">
<input type="file" class="form-control" name="uploadImage" id="uploadImage">
</div>
</div>
<div class="mb-3 row">
<span class="h4 col-lg-6 col-form-label text-start text-lg-end">Destination Folder</span>
<div class="col-lg-6">
{FOLDER_SELECT}
</div>
</div>
</fieldset>
<input type="hidden" name="token" value="{TOKEN}">
<button name="submit" value="submit" type="submit" class="btn btn-lg btn-primary center-block">Update</button><br>
</form>
</div>
</div>
</div>

View File

@ -0,0 +1,66 @@
<div class="container py-4">
<div class="row justify-content-center">
<div class="col-md-8">
{ADMIN_BREADCRUMBS}
<div class="card shadow">
<!-- Card Header -->
<div class="card-header text-center bg-dark text-white">
<h3 class="card-title mb-0">{filename}</h3>
</div>
<!-- Card Body -->
<div class="card-body">
<div class="row align-items-center">
<!-- User Image -->
<div class="col-md-4 text-center">
<img src="{url}" alt="User Pic" class="img-fluid" style="max-width: 150px;">
</div>
<!-- User Details -->
<div class="col-md-8">
<table class="table table-borderless">
<tbody>
<tr>
<th scope="row">filename</th>
<td>{filename}</td>
</tr>
<tr>
<th scope="row">extension</th>
<td>{extension}</td>
</tr>
<tr>
<th scope="row">fileSize</th>
<td>{fileSize}</td>
</tr>
<tr>
<th scope="row">location</th>
<td>{location}</td>
</tr>
<tr>
<th scope="row">url</th>
<td>{url}</td>
</tr>
<tr>
<th scope="row">folder</th>
<td>{folder}</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<!-- Admin Controls -->
<div class="card-footer text-center">
{ADMIN}
<a href="{ROOT_URL}admin/images/rename?fileLocation={locationSafe}" class="btn btn-warning btn-sm me-2" data-bs-toggle="tooltip" title="Rename image">
<i class="fa fa-fw fa-pencil"></i>
</a>
<a href="{ROOT_URL}admin/images/delete?fileLocation={locationSafe}" class="btn btn-danger btn-sm" data-bs-toggle="tooltip" title="Delete image">
<i class="fa fa-fw fa-trash"></i>
</a>
{/ADMIN}
</div>
</div>
</div>
</div>
</div>

View File

@ -1,5 +1,6 @@
<div class="container p-4 context-main-bg my-4"> <div class="m-2 m-lg-4">
<h1 class="mb-4">Frequently Asked Questions</h1> <div class="context-main-bg container py-2 my-2 py-lg-4 my-lg-4">
<h2 class="text-center mb-4">Frequently Asked Questions</h2>
<hr> <hr>
<!-- Table of Contents --> <!-- Table of Contents -->

View File

@ -0,0 +1,17 @@
Folder: <strong>{FOLDER_SELECT_ROOT}</strong>
<div class="list-group mx-0 mx-auto">
{LOOP}
<label class="list-group-item d-flex justify-content-between align-items-center">
<div class="d-flex align-items-center">
<input class="form-check-input me-2" type="radio" name="folderSelect" value="{location}" data-bs-toggle="collapse" data-bs-target="#top-{folderName}">
<span>
{folderName}
</span>
</div>
{folderexpand}
</label>
<div id="top-{folderName}" class="collapse">
{subdirs}
</div>
{/LOOP}
</div>

View File

@ -0,0 +1,6 @@
<label class="list-group-item">
<input class="form-check-input me-2" type="radio" name="folderSelect" value="{location}">
<span>
{folderName}
</span>
</label>

View File

@ -0,0 +1,14 @@
{LOOP}
<label class="list-group-item d-flex justify-content-between align-items-center">
<div class="d-flex align-items-center">
<input class="form-check-input me-2" type="radio" name="folderSelect" value="{location}" data-bs-toggle="collapse" data-bs-target="#{parentfolderName}-{folderName}">
<span>
{folderName}
</span>
</div>
{folderexpand}
</label>
<div id="{parentfolderName}-{folderName}" class="collapse">
{subdirs}
</div>
{/LOOP}

View File

@ -10,7 +10,7 @@
<form method="post"> <form method="post">
<input type="hidden" name="token" value="{TOKEN}"> <input type="hidden" name="token" value="{TOKEN}">
<div class="text-center"> <div class="text-center">
<button class="btn btn-lg btn-primary center-block" type="submit" name="submit" value="submit">Generate</button><br> <button class="btn btn-lg btn-primary center-block mb-3" type="submit" name="submit" value="submit">Generate</button><br>
</div> </div>
</form> </form>
</div> </div>

View File

@ -8,7 +8,7 @@
<div class="text-center my-4"> <div class="text-center my-4">
<form method="post"> <form method="post">
<input type="hidden" name="token" value="{TOKEN}"> <input type="hidden" name="token" value="{TOKEN}">
<button class="btn btn-lg btn-primary center-block" type="submit" name="submit" value="submit">I Agree</button><br> <button class="btn btn-lg btn-primary center-block mb-3" type="submit" name="submit" value="submit">I Agree</button><br>
</form> </form>
</div> </div>
</div> </div>

View File

@ -15,7 +15,7 @@
<div class="text-center"> <div class="text-center">
<form method="post"> <form method="post">
<input type="hidden" name="token" value="{TOKEN}"> <input type="hidden" name="token" value="{TOKEN}">
<button class="btn btn-lg btn-primary center-block" type="submit" name="submit" value="submit">Check</button><br> <button class="btn btn-lg btn-primary center-block mb-3" type="submit" name="submit" value="submit">Check</button><br>
</form> </form>
</div> </div>
</div> </div>

View File

@ -3,13 +3,13 @@
<div class="col-md-10 text-center"> <div class="col-md-10 text-center">
<div class="context-main-bg my-3 pb-3 rounded"> <div class="context-main-bg my-3 pb-3 rounded">
{installer-nav} {installer-nav}
<h1 class="mt-4">Welcome to The Tempus Project Installer.</h1> <h1 class="mt-5 mb-4">Welcome to The Tempus Project Installer.</h1>
<p> <p class="lead p-3">
This installer will guide you through the process of installing and configuring The Tempus Project. Do not forget to delete this file once you have completed installation. This installer will guide you through the process of installing and configuring The Tempus Project. Do not forget to delete this file once you have completed installation.
</p> </p>
<form method="post"> <form method="post">
<input type="hidden" name="token" value="{TOKEN}"> <input type="hidden" name="token" value="{TOKEN}">
<button class="btn btn-lg btn-primary center-block" type="submit" name="submit" id="submit" value="submit">Begin Installation</button><br> <button class="btn btn-lg btn-primary center-block mb-3" type="submit" name="submit" id="submit" value="submit">Begin Installation</button><br>
</form> </form>
</div> </div>
</div> </div>

View File

@ -585,6 +585,26 @@ class TheTempusProject extends Bedrock {
Redirect::external($route->forwarded_url); Redirect::external($route->forwarded_url);
} }
} }
if ( 'home/login' !== $url ) {
if ( Config::getValue( 'maintenance/enabled' ) ) {
if ( ! self::$isLoggedIn ) {
Session::flash( 'notice', Config::getValue( 'maintenance/maintenanceMessage' ) );
Redirect::to( 'home/login' );
}
if ( self::$activeGroup->ID != 1 ) {
if ( empty( self::$activeGroup->perms['maintenanceAccess'] ) ) {
Session::flash( 'notice', Config::getValue( 'maintenance/maintenanceMessage' ) );
Redirect::to( 'home/login' );
}
}
}
} elseif ( Config::getValue( 'maintenance/enabled' ) ) {
if ( ! self::$isLoggedIn ) {
Issues::add( 'notice', Config::getValue( 'maintenance/maintenanceMessage' ) );
}
}
parent::load(); parent::load();
} }

View File

@ -2,19 +2,22 @@
"name": "thetempusproject/thetempusproject", "name": "thetempusproject/thetempusproject",
"type": "project", "type": "project",
"description": "The aim of this project is to provide a simple and stable platform for rapidly prototyping new web applications.", "description": "The aim of this project is to provide a simple and stable platform for rapidly prototyping new web applications.",
"license": "MIT",
"minimum-stability": "dev",
"keywords": "keywords":
[ [
"thetempusproject", "thetempusproject",
"php",
"mvc",
"framework" "framework"
], ],
"license": "MIT",
"homepage": "https://TheTempusProject.com", "homepage": "https://TheTempusProject.com",
"authors": "authors":
[ [
{ {
"name": "Joey Kimsey", "name": "Joey Kimsey",
"email": "Joey@thetempusproject.com", "email": "Joey@thetempusproject.com",
"homepage": "https://TheTempusProject.com", "homepage": "https://JoeyKimsey.com",
"role": "Lead Developer" "role": "Lead Developer"
} }
], ],
@ -23,9 +26,9 @@
"components/jquery": "1.9.*", "components/jquery": "1.9.*",
"fortawesome/font-awesome": "4.7", "fortawesome/font-awesome": "4.7",
"stripe/stripe-php": "^16.3", "stripe/stripe-php": "^16.3",
"thetempusproject/bedrock": "1.1.1", "thetempusproject/bedrock": "1.1.2",
"thetempusproject/canary": "1.0.6", "thetempusproject/canary": "1.0.7",
"thetempusproject/houdini": "2.0.2", "thetempusproject/houdini": "2.0.3",
"twbs/bootstrap": "5.2.3" "twbs/bootstrap": "5.2.3"
}, },
"autoload": "autoload":
@ -62,6 +65,5 @@
"robloach/component-installer": true "robloach/component-installer": true
} }
}, },
"minimum-stability": "dev",
"prefer-stable": true "prefer-stable": true
} }