Compare commits

...

11 Commits
4.0 ... 4.1.1

Author SHA1 Message Date
e52ae78ed0 composer bump 2025-02-02 18:44:53 -05:00
5e621883ff Various changes
mobile-friendly ui updates
admin user-edit bugfix
file cleanup
added searchFields
add blog search
remove unused code
add maintenance mode config
2025-02-02 02:16:43 -05:00
b5996dc7db remove unused code 2025-02-02 01:55:15 -05:00
bc33b4cac4 cleanup and added admin images control 2025-02-02 01:55:15 -05:00
ca850bb46b UI fixes and composer bump 2025-01-27 00:26:43 -05:00
35b7be92a6 bugfixes and small features
Fixed config switches not registering the correct current value
Added better ux when image uploads are disabled
Fixed an issue where uploaded files were not being handled correctly
Added the ability to disable user registrations
Fixed some variables being unintendedly protected
2025-01-26 15:13:34 -05:00
d4751696f3 sendmail bugfix 2025-01-23 22:39:11 -05:00
fa12dd20ba add redirect link to admin 2025-01-23 22:25:33 -05:00
41a6aed209 route bugfix 2025-01-23 22:22:08 -05:00
509a10bc36 more fixes
remove unused redirects plugin after functionality was moved to core
fixed after-install links
2025-01-22 14:46:14 -05:00
5e99213601 bugfixes
improved dark mode user pref
Fixed invalid default Group
Fixed subscriptions showing when plugin was disabled
Fixed messages and notifications showing when disabled
2025-01-22 14:11:52 -05:00
149 changed files with 1595 additions and 1692 deletions

View File

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

View File

@ -35,7 +35,7 @@ class Config extends BedrockConfig {
case 'radio': case 'radio':
case 'bool': case 'bool':
case 'boolean': case 'boolean':
$fieldHtml = Forms::getSwitchHtml( $fieldname, [ 'true', 'false' ], $node['value'] ); $fieldHtml = Forms::getSwitchHtml( $fieldname, $node['value'] );
break; break;
case 'select': case 'select':
$fieldHtml = Forms::getSelectHtml( $fieldname, $options, $node['value'] ); $fieldHtml = Forms::getSelectHtml( $fieldname, $options, $node['value'] );

View File

@ -19,6 +19,7 @@ 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;
@ -208,6 +209,15 @@ class Preferences {
if ( $tempPrefsArray['type'] == 'checkbox' ) { if ( $tempPrefsArray['type'] == 'checkbox' ) {
$tempPrefsArray['type'] = 'switch'; $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'] ); $inputTypes[ $tempPrefsArray['type'] ][] = self::getFormFieldHtml( $name, $tempPrefsArray['pretty'], $tempPrefsArray['type'], $tempPrefsArray['value'], $tempPrefsArray['options'] );
} }
foreach ( $inputTypes as $skip => $items ) { foreach ( $inputTypes as $skip => $items ) {
@ -258,13 +268,13 @@ class Preferences {
} }
$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">' . $fieldTitle . '</label>'; $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 .= '<div class="col-lg-6">';
$html .= $fieldHtml; $html .= $fieldHtml;
$html .= '</div>'; $html .= '</div>';
if ( 'file' === $type ) { if ( 'file' === $type ) {
$html .= '<div class="mb-3 row">'; $html .= '<div class="mb-3 row">';
$html .= '<h4 class="col-lg-6 col-form-label text-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="User Avatar" src="{ROOT_URL}' . $defaultValue . '" class="img-circle img-fluid p-2 avatar-125">';
$html .= '</div>'; $html .= '</div>';
@ -295,6 +305,7 @@ class Preferences {
$prefsArray[$name] = $route . Upload::last(); $prefsArray[$name] = $route . Upload::last();
} else { } else {
Issues::add( 'error', [ 'There was an error with your upload.' => Check::userErrors() ] ); Issues::add( 'error', [ 'There was an error with your upload.' => Check::userErrors() ] );
unset( $prefsArray[$name] );
} }
} }
} }

View File

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

View File

@ -17,9 +17,12 @@ use TheTempusProject\Classes\AdminController;
use TheTempusProject\Models\User; use TheTempusProject\Models\User;
use TheTempusProject\Models\Comments; use TheTempusProject\Models\Comments;
use TheTempusProject\Models\Posts; use TheTempusProject\Models\Posts;
use TheTempusProject\Models\Contact;
use TheTempusProject\Plugins\Comments as CommentPlugin; use TheTempusProject\Plugins\Comments as CommentPlugin;
use TheTempusProject\Plugins\Blog as BlogPlugin; use TheTempusProject\Plugins\Blog as BlogPlugin;
use TheTempusProject\Plugins\Contact as ContactPlugin;
use TheTempusProject\Canary\Bin\Canary as Debug; 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;
@ -58,6 +61,19 @@ class Home extends AdminController {
} }
} }
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;
$users = Views::simpleView( 'admin.dashboard.users', self::$user->recent( 5 ) ); $users = Views::simpleView( 'admin.dashboard.users', self::$user->recent( 5 ) );
Components::set( 'userDash', $users ); Components::set( 'userDash', $users );

View File

@ -0,0 +1,114 @@
<?php
/**
* app/controllers/admin/tokens.php
*
* This is the admin app/user tokens 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\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 Images extends AdminController {
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() ] );
}
// if ( self::$token->create(
// Input::post( 'name' ),
// Input::post( 'notes' ),
// Input::post( 'token_type' )
// ) ) {
// Session::flash( 'success', 'Token Created' );
// Redirect::to( 'admin/images' );
// }
}
Views::view( 'admin.images.create' );
}
public function delete( $id = null ) {
if ( self::$token->delete( [ $id ] ) ) {
Session::flash( 'success', 'Token deleted.' );
}
Redirect::to( 'admin/images' );
}
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/images' );
}
}
}
Forms::selectOption( $token->token_type );
return Views::view( 'admin.images.edit', $token );
}
public function index() {
return Views::view( 'admin.images.list', self::$token->listPaginated() );
}
public function view( $id = null ) {
return Views::view( 'admin.images.view', self::$token->findById( $id ) );
}
}

View File

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

View File

@ -31,12 +31,10 @@ 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' ); return Views::view( 'admin.routes.create' );
} }

View File

@ -18,6 +18,7 @@ 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 SendMail extends AdminController { class SendMail extends AdminController {
public static $user; public static $user;
@ -27,10 +28,24 @@ class SendMail extends AdminController {
parent::__construct(); parent::__construct();
self::$title = 'Admin - Send Mail'; self::$title = 'Admin - Send Mail';
self::$user = new User; self::$user = new User;
self::$subscribe = new Subscribe;
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;
}
} 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' );

View File

@ -31,8 +31,6 @@ class Tokens extends AdminController {
parent::__construct(); parent::__construct();
self::$title = 'Admin - Tokens'; self::$title = 'Admin - Tokens';
self::$token = new Token; self::$token = new Token;
$view = Navigation::activePageSelect( 'nav.admin', '/admin/tokens' );
Components::set( 'ADMINNAV', $view );
} }
public function create() { public function create() {

View File

@ -27,6 +27,7 @@ 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\Houdini\Classes\Template;
use TheTempusProject\Bedrock\Functions\Upload;
class Users extends AdminController { class Users extends AdminController {
public static $user; public static $user;
@ -37,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() {
@ -106,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 = [
@ -114,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 {
@ -121,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();

View File

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

View File

@ -38,15 +38,15 @@ class Home extends Controller {
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' ) ) {
@ -79,13 +79,13 @@ 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::view( 'termsPage' ); Views::view( 'termsPage' );
} }
@ -98,8 +98,7 @@ class Home extends Controller {
public function privacy() { public function privacy() {
self::$title = 'Privacy Policy - {SITENAME}'; 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.'; 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.';
Components::set( 'PRIVACY', Views::simpleView( 'privacy' ) ); Views::view( 'privacy' );
Views::raw( '<div class="col-lg-8 mx-auto">{PRIVACY}</div>' );
} }
public function faq() { public function faq() {

View File

@ -1,3 +0,0 @@
<?php
// the idea is that this will be info pages for the plugin various/info
?>

View File

@ -24,20 +24,21 @@ 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(); 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( '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( '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' );
@ -46,16 +47,21 @@ class Register extends Controller {
public function index() { public function index() {
self::$title = '{SITENAME} Sign Up'; self::$title = '{SITENAME} Sign Up';
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.'; 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' ),
@ -74,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();
@ -90,7 +96,7 @@ 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() {
@ -103,7 +109,7 @@ class Register extends Controller {
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( 'confirmation_resend' ); return Views::view( 'auth.confirmation_resend' );
} }
Email::send( App::$activeUser->email, 'confirmation', App::$activeUser->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.' );
@ -115,7 +121,7 @@ class Register extends Controller {
Template::noIndex(); Template::noIndex();
if ( !isset( $code ) && !Input::exists( 'resetCode' ) ) { if ( !isset( $code ) && !Input::exists( 'resetCode' ) ) {
Issues::add( 'info', 'Please provide a reset code.' ); 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( 'passwordResetCode' ) ) { if ( Forms::check( 'passwordResetCode' ) ) {
@ -124,15 +130,15 @@ class Register extends Controller {
} }
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' );
} }
Components::set( 'resetCode', $code ); Components::set( 'resetCode', $code );
if ( ! Input::exists('password') ) { if ( ! Input::exists('password') ) {
return Views::view( 'password_reset' ); return Views::view( 'auth.password_reset' );
} }
if ( ! Forms::check( 'passwordReset' ) ) { if ( ! Forms::check( 'passwordReset' ) ) {
Issues::add( 'error', [ 'There was an error with your request.' => Check::userErrors() ] ); Issues::add( 'error', [ 'There was an error with your request.' => Check::userErrors() ] );
return Views::view( 'password_reset' ); 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 ] );

View File

@ -70,7 +70,7 @@ class Usercp extends Controller {
self::$title = 'User Control Panel'; self::$title = 'User Control Panel';
$menu = Views::simpleView( 'nav.usercp', App::$userCPlinks ); $menu = Views::simpleView( 'nav.usercp', App::$userCPlinks );
Navigation::activePageSelect( $menu, null, true, true ); Navigation::activePageSelect( $menu, null, true, true );
Views::view( 'profile', App::$activeUser ); Views::view( 'user_cp.profile', App::$activeUser );
} }
public function password() { public function password() {
@ -101,7 +101,7 @@ class Usercp extends Controller {
$menu = Views::simpleView( 'nav.usercp', App::$userCPlinks ); $menu = Views::simpleView( 'nav.usercp', App::$userCPlinks );
Navigation::activePageSelect( $menu, null, true, true ); 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....
@ -110,6 +110,12 @@ 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 ) );

View File

@ -9,32 +9,42 @@
* @license https://opensource.org/licenses/MIT [MIT LICENSE] * @license https://opensource.org/licenses/MIT [MIT LICENSE]
*/ */
.context-main { .context-main-border {
color: #fff; border-color: #f5f5f5!important;
}
.context-second {
color: #1e1e1e;
} }
.context-main-bg { .context-main-bg {
background-color: #2c2c2c; background-color: #2c2c2c;
} }
.context-second-bg { .context-second-bg {
background-color: #1e1e1e; background-color: #383838;
} }
.context-third-bg { .context-third-bg {
background-color: #3a3a3a; background-color: #3a3a3a;
} }
.context-other-bg {
background-color: #1e1e1e;
}
.context-main {
color: #fff;
}
.bg-default { .bg-default {
background-color: #2c2c2c; background-color: #2c2c2c;
} }
hr {
color: #f5f5f5;
}
.bg-none,.bg-warning { .bg-none,.bg-warning {
color: #000 !important; color: #000 !important;
} }
.context-other {
color: #000;
}
.accordion-button:not(.collapsed) { .accordion-button:not(.collapsed) {
color: #f5f5f5; color: #f5f5f5;
background-color: var(--bs-accordion-dark-active-bg); background-color: var(--bs-accordion-dark-active-bg);
@ -64,12 +74,6 @@ body {
.install-terms strong { .install-terms strong {
color: #ffffff; color: #ffffff;
} }
.context-main {
color: #ffffff;
}
.context-other {
color: #ffffff;
}
/** /**
* Terms Page * Terms Page
@ -145,6 +149,7 @@ body {
background-color: #1f1f1f; background-color: #1f1f1f;
color: #e0e0e0; color: #e0e0e0;
} }
.form-control:focus { .form-control:focus {
color: #e0e0e0; color: #e0e0e0;
border-color: #1e90ff; border-color: #1e90ff;

View File

@ -9,13 +9,34 @@
* @license https://opensource.org/licenses/MIT [MIT LICENSE] * @license https://opensource.org/licenses/MIT [MIT LICENSE]
*/ */
.context-other-bg { .context-main-border {
background-color: #eaeaea; border-color: #1e1e1e!important;
} }
.context-main-bg { .context-main-bg {
background-color: #f7f7f7; 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 */ /* Base styles for the switch container */
@ -57,7 +78,7 @@
bottom: 2.5px; bottom: 2.5px;
left: 5px; left: 5px;
transition: transform 0.3s ease-in-out; transition: transform 0.3s ease-in-out;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); box-shadow: 0 2px 4px #00000033;
} }
/* Change background color when checked */ /* Change background color when checked */
@ -70,20 +91,6 @@
transform: translateX(25px); /* Adjust based on switch width */ transform: translateX(25px); /* Adjust based on switch width */
} }
.context-main {
color: #000;
}
.context-other {
color: #fff;
}
html { html {
font-family: 'Open Sans', sans-serif; font-family: 'Open Sans', sans-serif;
position: relative; position: relative;
@ -312,3 +319,4 @@ body {
/* W3C, IE 10+/ Edge, Firefox 16+, Chrome 26+, Opera 12+, Safari 7+ */ /* W3C, IE 10+/ Edge, Firefox 16+, Chrome 26+, Opera 12+, Safari 7+ */
background: linear-gradient(to right, #2c2c2c, #1e1e1e, #1e1e1e); background: linear-gradient(to right, #2c2c2c, #1e1e1e, #1e1e1e);
} }

View File

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

View File

@ -95,12 +95,31 @@ $(document).ready(function() {
}); });
document.addEventListener('DOMContentLoaded', function () { document.addEventListener('DOMContentLoaded', function () {
const ttpDarkmode = document.getElementById('dark-mode-pref');
const toggleButton = document.getElementById('dark-mode-toggle'); const toggleButton = document.getElementById('dark-mode-toggle');
const enableButton = document.getElementById('dark-mode-toggle-button'); const enableButton = document.getElementById('dark-mode-toggle-button');
const darkModeStylesheet = document.getElementById('dark-mode-stylesheet'); const darkModeStylesheet = document.getElementById('dark-mode-stylesheet');
let currentState = '';
// Check if dark mode is saved in localStorage // Check if dark mode is set by ttp
if (localStorage.getItem('darkMode') === 'enabled') { if ( ttpDarkmode ) {
if ( 'true' == ttpDarkmode.value ) {
currentState = 'enabled';
}
if ( 'false' == ttpDarkmode.value ) {
currentState = 'disabled';
}
}
// Check if dark mode is set in localStorage
if ( '' == currentState ) {
if ( localStorage.getItem('darkMode') === 'enabled' ) {
currentState = 'enabled';
}
}
// Update current button states
if ( 'enabled' == currentState ) {
darkModeStylesheet.disabled = false; darkModeStylesheet.disabled = false;
if ( toggleButton ) { if ( toggleButton ) {
@ -112,8 +131,9 @@ document.addEventListener('DOMContentLoaded', function () {
} }
} }
// Style striped table elements
document.querySelectorAll('.table-striped').forEach((table) => { document.querySelectorAll('.table-striped').forEach((table) => {
if (localStorage.getItem('darkMode') === 'enabled') { if ( 'enabled' == currentState ) {
table.classList.add('table-dark'); table.classList.add('table-dark');
} else { } else {
table.classList.add('table-light') table.classList.add('table-light')
@ -122,7 +142,7 @@ document.addEventListener('DOMContentLoaded', function () {
if ( enableButton ) { if ( enableButton ) {
enableButton.addEventListener('click', function () { enableButton.addEventListener('click', function () {
if (darkModeStylesheet.disabled) { if ( darkModeStylesheet.disabled ) {
darkModeStylesheet.disabled = false; darkModeStylesheet.disabled = false;
localStorage.setItem('darkMode', 'enabled'); localStorage.setItem('darkMode', 'enabled');
enableButton.innerText = 'Disable Now'; enableButton.innerText = 'Disable Now';

View File

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

View File

@ -31,13 +31,16 @@ 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',

View File

@ -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.

View File

@ -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',

View File

@ -36,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;
/** /**

View File

@ -31,6 +31,10 @@ class Token extends DatabaseModel {
[ 'createdBy', 'int', '10' ], [ 'createdBy', 'int', '10' ],
[ 'expiresAt', 'int', '10' ], [ 'expiresAt', 'int', '10' ],
]; ];
public $searchFields = [
'name',
'token',
];
public $permissionMatrix = [ public $permissionMatrix = [
'addAppToken' => [ 'addAppToken' => [
'pretty' => 'Add Application Tokens', 'pretty' => 'Add Application Tokens',

View File

@ -44,6 +44,9 @@ class User extends DatabaseModel {
[ 'confirmationCode', 'varchar', '80' ], [ 'confirmationCode', 'varchar', '80' ],
[ 'prefs', 'text', '' ], [ 'prefs', 'text', '' ],
]; ];
public $searchFields = [
'username',
];
public $permissionMatrix = [ public $permissionMatrix = [
'uploadImages' => [ 'uploadImages' => [
'pretty' => 'Upload images (such as avatars)', 'pretty' => 'Upload images (such as avatars)',
@ -428,7 +431,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, '*' );
@ -546,6 +549,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];
@ -659,7 +663,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;

View File

@ -29,8 +29,6 @@ class Blog extends AdminController {
parent::__construct(); parent::__construct();
self::$posts = new Posts; self::$posts = new 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 ) {

View File

@ -171,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' );
}
} }

View File

@ -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 = [
@ -168,9 +173,11 @@ class Posts extends DatabaseModel {
$draft = ' <b>Draft</b>'; $draft = ' <b>Draft</b>';
} }
$instance->isDraft = $draft; $instance->isDraft = $draft;
$instance->authorName = $authorName; $instance->authorName = \ucfirst( $authorName );
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 );

View File

@ -37,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}',

View File

@ -26,9 +26,10 @@ class BlogLoader extends DefaultLoader {
*/ */
public function __construct() { public function __construct() {
$posts = new Posts; $posts = new Posts;
Components::set('SIDEBAR', Views::simpleView('blog.sidebar', $posts->recent(5))); Components::set('SIDEBAR', Views::simpleView('blog.widgets.recent', $posts->recent(5)));
Components::set('SIDEBAR2', Views::simpleView('blog.sidebar2', $posts->archive())); Components::set('SIDEBAR2', Views::simpleView('blog.widgets.archive', $posts->archive()));
Components::set('SIDEBARABOUT', Views::simpleView('blog.about')); Components::set('SIDEBARABOUT', Views::simpleView('blog.widgets.about'));
Components::set('SIDEBARSEARCH', Views::simpleView('blog.widgets.search'));
Components::set('BLOGFEATURES', ''); 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/' ) );

View File

@ -39,26 +39,44 @@
</head> </head>
<body> <body>
<!-- Navigation --> <!-- Navigation -->
<header class="p-3 text-bg-dark"> <header class="p-3 text-bg-dark">
<div class="container"> <div class="container">
<div class="d-flex flex-wrap align-items-center justify-content-center justify-content-lg-start"> <div class="d-flex align-items-center position-relative">
<img src="{ROOT_URL}{LOGO}" class="bi me-2" width="40" height="32" role="img" aria-label="{SITENAME} Logo"> <!-- Navbar Toggler (Left) -->
<a href="/" class="d-flex align-items-center mb-2 mb-lg-0 text-white text-decoration-none">
{SITENAME}
</a>
{topNavLeft}
<div class="text-end d-flex align-items-center">
{topNavRight}
</div>
</div>
</div>
</header>
<!-- 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">
<img src="{ROOT_URL}{LOGO}" width="40" height="32" alt="{SITENAME} Logo" class="bi">
</a>
<!-- Logo (Normal Position for Large Screens) -->
<a href="/" class="d-flex 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 w-100 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>
</div>
</div>
</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}
@ -79,24 +97,27 @@
<div class="pt-4"> <div class="pt-4">
<div class="container"> <div class="container">
<h3 class="pb-4 mb-4 fst-italic border-bottom"> <h3 class="pb-4 mb-4 fst-italic border-bottom context-main-border">
{SITENAME} Blog {SITENAME} Blog
</h3> </h3>
<div class="row g-5"> <div class="d-md-flex g-5">
<!-- Main Content --> <!-- Main Content -->
<div class="col-md-8"> <div class="col-12 col-md-8">
{CONTENT} {CONTENT}
</div> </div>
<!-- Sidebar Content --> <!-- Sidebar Content -->
<div class="col-md-4"> <div class="col-12 col-md-4">
<div class="position-sticky" style="top: 2rem;"> <div class="position-sticky" style="top: 2rem;">
<div class="p-4"> <div class="ps-md-2 ps-lg-5">
{SIDEBARABOUT} {SIDEBARABOUT}
</div> </div>
<div class="p-4"> <div class="ps-md-2 ps-lg-5">
{SIDEBARSEARCH}
</div>
<div class="ps-md-2 ps-lg-5">
{SIDEBAR} {SIDEBAR}
</div> </div>
<div class="p-4"> <div class="ps-md-2 ps-lg-5">
{SIDEBAR2} {SIDEBAR2}
</div> </div>
</div> </div>

View File

@ -1,6 +0,0 @@
<div class="p-4 mb-3 rounded context-main-bg">
<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>

View File

@ -2,7 +2,7 @@
<legend class="text-center">Add Blog Post</legend> <legend class="text-center">Add Blog Post</legend>
<hr> <hr>
{ADMIN_BREADCRUMBS} {ADMIN_BREADCRUMBS}
<form action="" method="post"> <form method="post">
<fieldset> <fieldset>
<!-- Title --> <!-- Title -->
<div class="mb-3 row"> <div class="mb-3 row">

View File

@ -2,7 +2,7 @@
<legend class="text-center">Edit Blog Post</legend> <legend class="text-center">Edit Blog Post</legend>
<hr> <hr>
{ADMIN_BREADCRUMBS} {ADMIN_BREADCRUMBS}
<form action="" method="post"> <form method="post">
<fieldset> <fieldset>
<!-- Title --> <!-- Title -->
<div class="mb-3 row"> <div class="mb-3 row">

View File

@ -21,7 +21,7 @@
<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>

View File

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

View File

@ -1,7 +1,7 @@
{LOOP} {LOOP}
<article class="blog-post"> <article class="blog-post context-main-bg p-2">
<h2 class="blog-post-title mb-1">{title}</h2> <h2 class="blog-post-title mb-1">{title}</h2>
<p class="blog-post-meta">{DTC date}{created}{/DTC} by <a href="{ROOT_URL}home/profile/{author}" class="text-decoration-none">{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>
<div class="well"> <div class="well">
{contentSummary} {contentSummary}
</div> </div>
@ -9,7 +9,7 @@
<hr> <hr>
{/LOOP} {/LOOP}
{ALT} {ALT}
<article class="blog-post"> <div class="text-center">
<p class="blog-post-meta">No Posts Found.</p> <p class="h5">No Posts Found</p>
</article> </div>
{/ALT} {/ALT}

View File

@ -1,9 +1,9 @@
<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}" class="text-decoration-none">{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>

View File

@ -1,15 +0,0 @@
<div class="card">
<div class="card-header bg-info">
<h3 class="card-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>

View File

@ -0,0 +1,3 @@
<legend class="text-center my-2">Search Results</legend>
<hr>
{searchResults}

View File

@ -1,18 +0,0 @@
<div class="card context-main-bg">
<div class="card-header">
<h3 class="card-title">Recent Posts</h3>
</div>
<div class="card-body">
<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>

View File

@ -1,11 +0,0 @@
<div class="p-4">
<h4 class="fst-italic">Archives</h4>
<ul class="list-unstyled mb-0">
{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}
</ul>
</div>

View 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>

View 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>

View 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>

View 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>

View File

@ -51,7 +51,7 @@ class Bugreport extends Plugin {
]; ];
public $contact_footer_links = [ public $contact_footer_links = [
[ [
'text' => 'Bug Report', 'text' => 'Report a Bug',
'url' => '{ROOT_URL}bugreport', 'url' => '{ROOT_URL}bugreport',
'filter' => 'loggedin', 'filter' => 'loggedin',
], ],

View File

@ -1,15 +1,20 @@
<div class="col-8 mx-auto p-4 rounded shadow-sm mb-5 context-main-bg mt-4 container"> <div class="m-2 m-lg-4">
<h2 class="text-center mb-4">Bug Report</h2> <div class="col-12 mx-5 col-sm-10 col-lg-8 mx-auto p-4 rounded shadow-sm context-main-bg">
<h2 class="text-center mb-4">Report a Bug</h2>
<hr> <hr>
<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> <p class="text-center text-sm-start">
<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> 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.
<form action="" method="post"> </p>
<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 --> <!-- Page URL -->
<div class="mb-3"> <div class="mb-3">
<label for="url" class="form-label">Page you were trying to reach:</label> <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> <input type="url" name="url" id="url" class="form-control" aria-describedby="urlHelp" required>
<small id="urlHelp" class="form-text text-muted"> <small 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) This is the URL of the page you actually received the error.
</small> </small>
</div> </div>
@ -18,7 +23,7 @@
<label for="ourl" class="form-label">Page you were on:</label> <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">
<small 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.
</small> </small>
</div> </div>
@ -37,8 +42,11 @@
<!-- Description --> <!-- Description -->
<div class="mb-3"> <div class="mb-3">
<label for="entry" class="form-label">Describe the problem/error as best as you can: (max: 2000 characters)</label> <label for="entry" class="form-label">Describe the error you received: </label>
<textarea class="form-control" name="entry" id="entry" rows="6" maxlength="2000" required></textarea> <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> </div>
<!-- Hidden Token --> <!-- Hidden Token -->
@ -50,3 +58,4 @@
</div> </div>
</form> </form>
</div> </div>
</div>

View File

@ -3,7 +3,7 @@
<legend class="text-center">Edit Comment</legend> <legend class="text-center">Edit Comment</legend>
<hr> <hr>
{ADMIN_BREADCRUMBS} {ADMIN_BREADCRUMBS}
<form action="" method="post" class="container py-4"> <form method="post" class="container py-4">
<fieldset> <fieldset>
<div class="mb-3 row"> <div class="mb-3 row">
<label for="comment" class="col-lg-5 col-form-label text-end">Comment:</label> <label for="comment" class="col-lg-5 col-form-label text-end">Comment:</label>

View File

@ -1,4 +1,4 @@
<form action="" method="post" class="text-center mx-auto mt-4" style="max-width: 600px;"> <form method="post" class="text-center mx-auto mt-4" style="max-width: 600px;">
<div class="mb-3"> <div class="mb-3">
<textarea <textarea
class="form-control" class="form-control"

View File

@ -1,14 +1,14 @@
<div class="card"> <div class="card">
<div class="card-header d-flex align-items-center justify-content-between context-second-bg context-main"> <div class="card-header d-flex align-items-center justify-content-between context-main-bg context-main">
<h3 class="card-title mb-0"> <h3 class="card-title mb-0">
<i class="fa fa-fw fa-comment"></i> Comments <i class="fa fa-fw fa-comment"></i> Comments
</h3> </h3>
<span class="badge bg-primary">{count}</span> <span class="badge bg-primary">{count}</span>
</div> </div>
<div class="card-body context-main-bg context-main"> <div class="card-body context-second-bg">
<ul class="list-group list-group-flush"> <ul class="list-group list-group-flush">
{LOOP} {LOOP}
<li class="list-group-item context-second-bg context-main mb-2"> <li class="list-group-item context-main-bg context-main mb-2">
<div class="d-flex align-items-start"> <div class="d-flex align-items-start">
<div class="me-3"> <div class="me-3">
<img src="{ROOT_URL}{avatar}" class="rounded-circle" alt="User Avatar" style="width: 50px; height: 50px;"> <img src="{ROOT_URL}{avatar}" class="rounded-circle" alt="User Avatar" style="width: 50px; height: 50px;">
@ -28,7 +28,7 @@
</li> </li>
{/LOOP} {/LOOP}
{ALT} {ALT}
<li class="list-group-item context-second-bg context-main mb-2"> <li class="list-group-item context-main-bg mb-2">
<div class="text-center"> <div class="text-center">
<p class="mb-0">Be the first to comment.</p> <p class="mb-0">Be the first to comment.</p>
</div> </div>

View File

@ -27,8 +27,6 @@ class Contact extends AdminController {
parent::__construct(); parent::__construct();
self::$title = 'Admin - Contact'; self::$title = 'Admin - Contact';
self::$contact = new ContactModel; self::$contact = new ContactModel;
$view = Navigation::activePageSelect( 'nav.admin', '/admin/contact' );
Components::set( 'ADMINNAV', $view );
} }
public function view( $id = null ) { public function view( $id = null ) {

View File

@ -0,0 +1,29 @@
<table class="table context-main">
<thead>
<tr>
<th style="width: 5%"></th>
<th style="width: 25%"></th>
<th style="width: 55%"></th>
<th style="width: 5%"></th>
<th style="width: 5%"></th>
</tr>
</thead>
<tbody>
{LOOP}
<tr>
<td>{ID}</td>
<td>{DTC}{time}{/DTC}</td>
<td>{feedback}</td>
<td><a href="{ROOT_URL}admin/contact/view/{ID}" class="btn btn-sm btn-primary"><i class="fa fa-fw fa-upload"></i></a></td>
<td><a href="{ROOT_URL}admin/contact/delete/{ID}" class="btn btn-sm btn-danger"><i class="fa fa-fw fa-trash"></i></a></td>
</tr>
{/LOOP}
{ALT}
<tr>
<td class="text-center" colspan="5">
No Contact forms to show.
</td>
</tr>
{/ALT}
</tbody>
</table>

View File

@ -1,45 +1,47 @@
<div class="context-main-bg container py-4 my-4"> <div class="m-2 m-lg-4">
<h2 class="text-center mb-4">Contact Us</h2> <div class="context-main-bg container py-2 my-2 py-lg-4 my-lg-4">
<div class="col-lg-6 offset-md-3"> <h2 class="text-center mb-4">Contact Us</h2>
<p> <div class="col-12 col-lg-6 offset-lg-3">
Here at <strong>{SITENAME}</strong>, we highly value your feedback. We constantly strive to provide our users with the highest level of quality in everything we do. <p class="text-center text-lg-start">
</p> Here at <strong>{SITENAME}</strong>, we highly value your feedback. We constantly strive to provide our users with the highest level of quality in everything we do.
<p> </p>
If you would like to provide any suggestions or comments on our service, we ask that you please fill out the quick form below and let us know what's on your mind. <p class="text-center text-lg-start">
</p> If you would like to provide any suggestions or comments on our service, we ask that you please fill out the quick form below and let us know what's on your mind.
</p>
</div>
<form method="post">
<!-- Name -->
<div class="mb-3 row">
<label for="name" class="col-lg-3 col-form-label text-lg-end">Name:</label>
<div class="col-lg-6">
<input type="text" class="form-control" name="name" id="name" required>
</div>
</div>
<!-- Email (Optional) -->
<div class="mb-3 row">
<label for="contactEmail" class="col-lg-3 col-form-label text-lg-end">E-mail: (optional)</label>
<div class="col-lg-6">
<input type="email" class="form-control" name="contactEmail" id="contactEmail">
</div>
</div>
<!-- Feedback -->
<div class="mb-3 row">
<label for="entry" class="col-lg-3 col-form-label text-lg-end">Feedback:</label>
<div class="col-lg-6">
<textarea class="form-control" name="entry" id="entry" 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}">
<!-- 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>
<form action="" method="post">
<!-- Name -->
<div class="mb-3 row">
<label for="name" class="col-lg-3 col-form-label text-end">Name:</label>
<div class="col-lg-6">
<input type="text" class="form-control" name="name" id="name" required>
</div>
</div>
<!-- Email (Optional) -->
<div class="mb-3 row">
<label for="contactEmail" class="col-lg-3 col-form-label text-end">E-mail: (optional)</label>
<div class="col-lg-6">
<input type="email" class="form-control" name="contactEmail" id="contactEmail">
</div>
</div>
<!-- Feedback -->
<div class="mb-3 row">
<label for="entry" class="col-lg-3 col-form-label text-end">Feedback:</label>
<div class="col-lg-6">
<textarea class="form-control" name="entry" id="entry" 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}">
<!-- 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>

View File

@ -19,6 +19,9 @@ use TheTempusProject\Houdini\Classes\Views;
use TheTempusProject\Houdini\Classes\Issues; use TheTempusProject\Houdini\Classes\Issues;
use TheTempusProject\Bedrock\Functions\Check; use TheTempusProject\Bedrock\Functions\Check;
use TheTempusProject\Bedrock\Functions\Input; use TheTempusProject\Bedrock\Functions\Input;
use TheTempusProject\TheTempusProject as App;
use TheTempusProject\Hermes\Functions\Redirect;
use TheTempusProject\Bedrock\Functions\Session;
class Messages extends Controller { class Messages extends Controller {
private static $message; private static $message;
@ -27,6 +30,10 @@ class Messages extends Controller {
parent::__construct(); parent::__construct();
self::$title = 'Messages'; self::$title = 'Messages';
self::$message = new Message; self::$message = new Message;
if ( ! App::$isLoggedIn ) {
Session::flash( 'error', 'You do not have permission to access this page.' );
return Redirect::home();
}
} }
public function create() { public function create() {
@ -71,8 +78,9 @@ class Messages extends Controller {
} }
public function index() { public function index() {
Views::view( 'messages.inbox', self::$message->getInbox() ); Components::set( 'message_inbox', Views::simpleView( 'messages.inbox', self::$message->getInbox() ) );
Views::view( 'messages.outbox', self::$message->getOutbox() ); Components::set( 'message_outbox', Views::simpleView( 'messages.outbox', self::$message->getOutbox() ) );
Views::view( 'messages.index' );
} }
public function read( $id = '' ) { public function read( $id = '' ) {

View File

@ -259,7 +259,9 @@ class Message extends DatabaseModel {
} }
$messageOut['fromAvatar'] = self::$user->getAvatar( $message->userFrom ); $messageOut['fromAvatar'] = self::$user->getAvatar( $message->userFrom );
$messageOut['userTo'] = self::$user->getUsername( $message->userTo ); $messageOut['userTo'] = self::$user->getUsername( $message->userTo );
$messageOut['userToPretty'] = \ucfirst( $messageOut['userTo'] );
$messageOut['userFrom'] = self::$user->getUsername( $message->userFrom ); $messageOut['userFrom'] = self::$user->getUsername( $message->userFrom );
$messageOut['userFromPretty'] = \ucfirst( $messageOut['userFrom'] );
$out[] = (object) $messageOut; $out[] = (object) $messageOut;
if ( !empty( $end ) ) { if ( !empty( $end ) ) {
$out = $out[0]; $out = $out[0];

View File

@ -1 +1 @@
<span class="label label-danger">{MESSAGE_COUNT}</span> <span class="badge bg-danger rounded-pill">{MESSAGE_COUNT}</span>

View File

@ -1,57 +1,73 @@
<div class="container py-4"> <div class="m-2 m-lg-4">
<div class="row justify-content-center"> <div class="col-12 mx-5 col-sm-10 col-lg-8 mx-auto p-4 rounded shadow-sm context-main-bg">
<div class="col-md-4"> <nav aria-label="breadcrumb">
<form action="" method="post" class="needs-validation"> <ol class="breadcrumb">
<legend class="mb-4">New Message</legend> <li class="breadcrumb-item">
<fieldset> <a href="{ROOT_URL}messages" class="text-decoration-none">
<!-- To User Field --> Messages
<div class="mb-3 row"> </a>
<label for="toUser" class="col-sm-6 col-form-label">To:</label> </li>
<div class="col-sm-6"> <li class="breadcrumb-item active" aria-current="page">
<input Create
type="text" </li>
class="form-control" </ol>
name="toUser" </nav>
id="toUser" <div class="row justify-content-center">
value="{prepopuser}" <div class="col-md-6 col-lg-6">
required> <form method="post" class="needs-validation">
<legend class="mb-3">New Message</legend>
<fieldset>
<!-- To User Field -->
<div class="mb-3 row">
<label for="toUser" class="col-sm-6 col-form-label">To:</label>
<div class="col-sm-6">
<input
type="text"
class="form-control"
name="toUser"
id="toUser"
value="{prepopuser}"
required>
</div>
</div> </div>
</div>
<!-- Subject Field --> <!-- Subject Field -->
<div class="mb-3 row"> <div class="mb-3 row">
<label for="subject" class="col-sm-6 col-form-label">Subject:</label> <label for="subject" class="col-sm-6 col-form-label">Subject:</label>
<div class="col-sm-6"> <div class="col-sm-6">
<input <input
type="text" type="text"
class="form-control" class="form-control"
name="subject" name="subject"
id="subject" id="subject"
required> required>
</div>
</div> </div>
</div>
<!-- Message Field --> <!-- Message Field -->
<div class="mb-3"> <div class="mb-3">
<label for="message" class="form-label">Message:</label> <label for="message" class="form-label">Message:</label>
<textarea <textarea
class="form-control" class="form-control"
name="message" name="message"
id="message" id="message"
rows="6" rows="6"
maxlength="2000" maxlength="2000"
required></textarea> required></textarea>
</div>
</fieldset>
<input type="hidden" name="token" value="{TOKEN}">
<div class="text-center text-md-start">
<button
type="submit"
name="submit"
value="submit"
class="btn btn-primary btn-lg">
Send
</button>
</div> </div>
</fieldset> </form>
<input type="hidden" name="token" value="{TOKEN}"> </div>
<button
type="submit"
name="submit"
value="submit"
class="btn btn-primary btn-lg">
Send
</button>
</form>
</div> </div>
</div> </div>
</div> </div>

View File

@ -1,15 +1,14 @@
<h2>Inbox</h2> <h2>Inbox</h2>
{PAGINATION}
<form action="{ROOT_URL}messages/delete" method="post"> <form action="{ROOT_URL}messages/delete" method="post">
<table class="table table-hover"> <table class="table table-striped text-center">
<thead> <thead>
<tr> <tr>
<th style="width: 20%">From</th> <th style="width: 15%">From</th>
<th style="width: 25%">Subject</th> <th style="width: 40%">Subject</th>
<th style="width: 15%">Last Reply</th> <th style="width: 20%">Last Reply</th>
<th style="width: 20%"></th>
<th style="width: 10%"></th> <th style="width: 10%"></th>
<th style="width: 10%"> <th style="width: 10%"></th>
<th style="width: 5%">
<INPUT type="checkbox" onchange="checkAll(this)" name="check.t" value="T_[]"/> <INPUT type="checkbox" onchange="checkAll(this)" name="check.t" value="T_[]"/>
</th> </th>
</tr> </tr>
@ -17,11 +16,11 @@
<tbody> <tbody>
{LOOP} {LOOP}
<tr {unreadBadge}> <tr {unreadBadge}>
<td><a href="{ROOT_URL}home/profile/{userFrom}">{userFrom}</a></td> <td><a href="{ROOT_URL}home/profile/{userFrom}" class="text-decoration-none">{userFromPretty}</a></td>
<td><a href="{ROOT_URL}messages/view/{ID}">{subject}</a></td> <td><a href="{ROOT_URL}messages/view/{ID}" class="text-decoration-none">{subject}</a></td>
<td>{DTC}{lastReply}{/DTC}</td> <td>{DTC date}{lastReply}{/DTC}</td>
<td><a href="{ROOT_URL}messages/read/{ID}">Mark as read</a></td> <td><a href="{ROOT_URL}messages/read/{ID}" class="btn btn-sm btn-info"><i class="fa-solid fa-envelope-open"></i></a></td>
<td><a href="{ROOT_URL}messages/delete/{ID}">Delete</a></td> <td><a href="{ROOT_URL}messages/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="T_[]"> <input type="checkbox" value="{ID}" name="T_[]">
</td> </td>
@ -36,5 +35,6 @@
{/ALT} {/ALT}
</tbody> </tbody>
</table> </table>
<button name="submit" value="submit" type="submit" class="btn btn-sm btn-danger">Delete</button> <a href="{ROOT_URL}messages/create" class="btn btn-sm btn-primary">New message</a> <button name="submit" value="submit" type="submit" class="btn btn-sm btn-danger"><i class="fa fa-fw fa-trash"></i></button>
<a href="{ROOT_URL}messages/create" class="btn btn-sm btn-primary">New message</a>
</form> </form>

View File

@ -0,0 +1,10 @@
<div class="m-2 m-lg-4">
<div class="col-12 col-sm-10 col-lg-8 mx-auto p-md-2 p-lg-4 rounded shadow-sm context-main-bg context-main">
<div class="my-3 p-3">
{message_inbox}
</div>
<div class="my-3 p-3">
{message_outbox}
</div>
</div>
</div>

View File

@ -1,43 +0,0 @@
<div class="container">
<div class="row">
<div class="col-sm-12 col-md-6 col-lg-6 col-sm-offset-0 col-md-offset-3 col-lg-offset-3 top-pad" >
<div class="card panel-primary">
{LOOP}
{SINGLE}
<div class="card-header">
<h3 class="card-title">{subject}</h3>
</div>
{/SINGLE}
<div class="card-body">
<div class="row">
<div class="col-md-3 col-lg-3 " align="center">
<a href="{ROOT_URL}home/profile/{userFrom}">{userFrom}</a><br>
<img alt="User Pic" src="{ROOT_URL}{fromAvatar}" class="img-circle img-responsive">
</div>
<div class=" col-md-9 col-lg-9 ">
<table class="table table-user-information">
<tbody>
<td>{message}</td>
</tbody>
</table>
</div>
</div>
</div>
<div class="card-footer">
{ADMIN}
{ID}
<span class="float-right">
{DTC}{sent}{/DTC}
</span>
{/ADMIN}
</div>
{/LOOP}
</div>
<form action="{ROOT_URL}messages/reply" method="post">
<input type="hidden" name="token" value="{TOKEN}">
<input type="hidden" name="messageID" value="{PID}">
<button name="submit" value="reply" type="submit" class="btn btn-sm btn-primary">Reply</button>
</form>
</div>
</div>
</div>

View File

@ -1,43 +1,53 @@
<div class="container"> <div class="m-2 m-lg-4">
<div class="row"> <div class="col-12 mx-5 col-sm-10 col-lg-8 mx-auto p-4 rounded shadow-sm context-main-bg context-main">
<div class="col-sm-12 col-md-6 col-lg-6 col-sm-offset-0 col-md-offset-3 col-lg-offset-3 top-pad" > <nav aria-label="breadcrumb">
<div class="card panel-primary"> <ol class="breadcrumb">
{LOOP} <li class="breadcrumb-item">
<a href="{ROOT_URL}messages" class="text-decoration-none">
Messages
</a>
</li>
<li class="breadcrumb-item active" aria-current="page">
View
</li>
</ol>
</nav>
<div class="card panel-primary col-lg-8 mx-auto text-center">
{LOOP}
{SINGLE} {SINGLE}
<div class="card-header"> <div class="card-header context-second-bg">
<h3 class="card-title">{subject}</h3> <p class="card-title context-main text-center h3">{subject}</p>
</div> </div>
{/SINGLE} {/SINGLE}
<div class="card-body"> <div class="card-body context-other-bg">
<div class="row"> <div class="row">
<div class="col-md-3 col-lg-3 " align="center"> <div class="col-4 col-lg-3 text-center">
<a href="{ROOT_URL}home/profile/{userFrom}">{userFrom}</a><br> <a href="{ROOT_URL}home/profile/{userFrom}" class="text-decoration-none">{userFromPretty}</a><br>
<img alt="User Pic" src="{ROOT_URL}{fromAvatar}" class="img-circle img-responsive"> <img alt="User Pic" src="{ROOT_URL}{fromAvatar}" class="img-circle img-fluid mt-2">
</div> </div>
<div class=" col-md-9 col-lg-9 "> <div class="col-8 col-lg-9 text-start">
<table class="table table-user-information"> {message}
<tbody>
<td>{message}</td>
</tbody>
</table>
</div> </div>
</div> </div>
</div> </div>
<div class="card-footer"> <div class="card-footer context-second-bg">
{ADMIN} {ADMIN}
{ID} <div class="d-flex justify-content-between">
<span class="float-right"> <div class="">
{DTC}{sent}{/DTC} {ID}
</span> </div>
<div class="">
{DTC}{sent}{/DTC}
</div>
</div>
{/ADMIN} {/ADMIN}
</div> </div>
{/LOOP} {/LOOP}
</div>
<form action="{ROOT_URL}messages/reply" method="post">
<input type="hidden" name="token" value="{TOKEN}">
<input type="hidden" name="messageID" value="{PID}">
<button name="submit" value="reply" type="submit" class="btn btn-sm btn-primary">Reply</button>
</form>
</div> </div>
<form action="{ROOT_URL}messages/reply" method="post">
<input type="hidden" name="token" value="{TOKEN}">
<input type="hidden" name="messageID" value="{PID}">
<button name="submit" value="reply" type="submit" class="btn btn-md btn-primary my-4">Reply</button>
</form>
</div> </div>
</div> </div>

View File

@ -1,49 +1,46 @@
<div class="dropdown nav-item mx-2"> <div class="dropdown nav-item mx-2 my-2 my-lg-0">
<a <a
href="#" href="#"
class="d-block dropdown-toggle nav-link" class="d-flex align-items-center text-white text-decoration-none dropdown-toggle"
id="messagesDropdown" id="messagesDropdown"
data-bs-toggle="dropdown" data-bs-toggle="dropdown"
aria-haspopup="true" aria-haspopup="true"
aria-expanded="false"> aria-expanded="false">
<i class="fa fa-fw fa-envelope"></i><span class="ml-3">{MBADGE}</span> <i class="fa fa-fw fa-envelope"></i><span class="">{MBADGE}</span>
</a> </a>
<ul class="dropdown-menu text-small" aria-labelledby="messagesDropdown"> <ul class="dropdown-menu dropdown-menu-dark dropdown-menu-end text-small shadow" aria-labelledby="messagesDropdown">
<li class="message-header">
<div class="media">
<div class="media-body text-center" style="padding-bottom: 10px; padding-top: 10px">
{MESSAGE_COUNT} unread message(s) total
</div>
</div>
</li>
{LOOP} {LOOP}
<li class="message-preview"> <!-- Message Item -->
<a href="{ROOT_URL}messages/view/{ID}"> <li>
<div class="media"> <a href="{ROOT_URL}messages/view/{ID}" class="dropdown-item">
<span class="float-left"> <div class="d-flex">
<img class="media-object avatar-round-40" src="{ROOT_URL}{fromAvatar}" alt=""> <h5 class="media-heading text-start">
</span> <img class="" style="width: 40px;" src="{ROOT_URL}{fromAvatar}" alt="">
<div class="media-body"> <strong>{userFrom}</strong>
<h5 class="media-heading"><strong>{userFrom}</strong> </h5>
</h5> <div class="text-end">
<p class="small text-muted"><i class="fa fa-clock-o"></i> {DTC}{lastReply}{/DTC}</p> <div class="media-body">
{summary} <p class="small text-muted mb-1"><i class="fa fa-clock-o me-1"></i> {DTC}{lastReply}{/DTC}</p>
<span>{summary}</span>
</div>
</div> </div>
</div> </div>
</a> </a>
</li> </li>
{/LOOP} {/LOOP}
{ALT} {ALT}
<li class="message-preview"> <li class="px-3 text-center">
<div class="media"> <strong>No Messages</strong>
<div class="media-body text-center" style="padding-bottom: 10px; padding-top: 10px">
<h5 class="media-heading"><strong>No Messages</strong></h5>
</div>
</div>
</li> </li>
{/ALT} {/ALT}
<li class="message-footer text-center"> <!-- Footer -->
<a href="{ROOT_URL}messages" class="dropdown-item">Read All New Messages</a> <li>
<hr class="dropdown-divider">
</li>
<li>
<a href="/messages" class="dropdown-item text-center">
Read All New Messages
</a>
</li> </li>
</ul> </ul>
</div> </div>

View File

@ -1,7 +1,6 @@
<h2>Outbox</h2> <h2>Outbox</h2>
{PAGINATION}
<form action="{ROOT_URL}messages/delete" method="post"> <form action="{ROOT_URL}messages/delete" method="post">
<table class="table table-hover"> <table class="table table-striped text-center">
<thead> <thead>
<tr> <tr>
<th style="width: 20%">To</th> <th style="width: 20%">To</th>
@ -16,10 +15,10 @@
<tbody> <tbody>
{LOOP} {LOOP}
<tr> <tr>
<td><a href="{ROOT_URL}home/profile/{userTo}">{userTo}</a></td> <td><a href="{ROOT_URL}home/profile/{userTo}" class="text-decoration-none">{userToPretty}</a></td>
<td><a href="{ROOT_URL}messages/view/{ID}">{subject}</a></td> <td><a href="{ROOT_URL}messages/view/{ID}" class="text-decoration-none">{subject}</a></td>
<td>{DTC date}{sent}{/DTC}</td> <td>{DTC date}{sent}{/DTC}</td>
<td><a href="{ROOT_URL}messages/delete/{ID}">Delete</a></td> <td><a href="{ROOT_URL}messages/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="F_[]"> <input type="checkbox" value="{ID}" name="F_[]">
</td> </td>
@ -34,5 +33,5 @@
{/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>

View File

@ -1,14 +1,18 @@
<form action="" method="post" class="form-horizontal"> <div class="context-main context-main-bg col-8 offset-2 my-3 p-3">
<legend>Reply</legend> <form method="post">
<fieldset> <legend class="text-center">Reply</legend>
<div class="form-group"> <fieldset>
<label for="message" class="col-lg-3 control-label">Message:</label> <div class="form-group">
<div class="col-lg-6"> <div class="col-6 offset-3">
<textarea class="form-control" name="message" maxlength="2000" rows="10" cols="50" id="message"></textarea> <label for="message" class="control-label">Message:</label>
<textarea class="form-control" name="message" maxlength="2000" rows="10" cols="50" id="message"></textarea>
</div>
</div> </div>
</fieldset>
<input type="hidden" name="messageID" value="{messageID}">
<input type="hidden" name="token" value="{TOKEN}">
<div class="text-center">
<button name="submit" value="submit" type="submit" class="btn btn-lg btn-primary center-block my-3">Send</button>
</div> </div>
</fieldset> </form>
<input type="hidden" name="messageID" value="{messageID}"> </div>
<input type="hidden" name="token" value="{TOKEN}">
<button name="submit" value="submit" type="submit" class="btn btn-lg btn-primary center-block">Send</button><br>
</form>

View File

@ -17,6 +17,8 @@ use TheTempusProject\Houdini\Classes\Issues;
use TheTempusProject\Classes\Controller; use TheTempusProject\Classes\Controller;
use TheTempusProject\Models\Notification as NotificationsModel; use TheTempusProject\Models\Notification as NotificationsModel;
use TheTempusProject\TheTempusProject as App; use TheTempusProject\TheTempusProject as App;
use TheTempusProject\Hermes\Functions\Redirect;
use TheTempusProject\Bedrock\Functions\Session;
class Notifications extends Controller { class Notifications extends Controller {
protected static $notifications; protected static $notifications;
@ -26,6 +28,10 @@ class Notifications extends Controller {
self::$notifications = new NotificationsModel; self::$notifications = new NotificationsModel;
self::$title = 'Notifications - {SITENAME}'; self::$title = 'Notifications - {SITENAME}';
self::$pageDescription = 'Your recent notifications'; self::$pageDescription = 'Your recent notifications';
if ( ! App::$isLoggedIn ) {
Session::flash( 'error', 'You do not have permission to access this page.' );
return Redirect::home();
}
} }
public function index() { public function index() {

View File

@ -2,8 +2,7 @@
<legend class="text-center">Send Notification</legend> <legend class="text-center">Send Notification</legend>
<hr> <hr>
{ADMIN_BREADCRUMBS} {ADMIN_BREADCRUMBS}
<form method="post" enctype="multipart/form-data">
<form action="" method="post" enctype="multipart/form-data">
<fieldset> <fieldset>
<!-- Group --> <!-- Group -->
<div class="mb-3 row"> <div class="mb-3 row">

View File

@ -1,4 +1,6 @@
<div class="col-8 mx-auto p-4 rounded shadow-sm context-main-bg my-4">
<div class="m-2 m-lg-4">
<div class="col-12 mx-5 col-sm-10 col-lg-8 mx-auto p-4 rounded shadow-sm context-main-bg">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-8"> <div class="col-md-8">
<legend class="text-center">Notifications</legend> <legend class="text-center">Notifications</legend>
@ -26,7 +28,7 @@
{/LOOP} {/LOOP}
{ALT} {ALT}
<tr> <tr>
<td colspan="7" class=" context-main"> <td colspan="3" class="text-center context-main">
No Notifications No Notifications
</td> </td>
</tr> </tr>
@ -36,3 +38,4 @@
</div> </div>
</div> </div>
</div> </div>
</div>

View File

@ -1,5 +1,5 @@
<!-- Notifications Dropdown --> <!-- Notifications Dropdown -->
<div class="dropdown nav-item mx-2"> <div class="dropdown nav-item mx-2 my-2 my-lg-0">
<a <a
href="#" href="#"
class="d-flex align-items-center text-white text-decoration-none dropdown-toggle" class="d-flex align-items-center text-white text-decoration-none dropdown-toggle"
@ -7,7 +7,7 @@
data-bs-toggle="dropdown" data-bs-toggle="dropdown"
aria-haspopup="true" aria-haspopup="true"
aria-expanded="false"> aria-expanded="false">
<i class="fa fa-fw fa-bell"></i><span class="ms-2">{NBADGE}</span> <i class="fa fa-fw fa-bell"></i><span class="">{NBADGE}</span>
</a> </a>
<ul class="dropdown-menu dropdown-menu-dark dropdown-menu-end text-small shadow" aria-labelledby="notificationsDropdown"> <ul class="dropdown-menu dropdown-menu-dark dropdown-menu-end text-small shadow" aria-labelledby="notificationsDropdown">
{LOOP} {LOOP}

View File

@ -1,40 +0,0 @@
<?php
/**
* app/plugins/redirects/plugin.php
*
* This houses all of the main plugin info and functionality.
*
* @package TP Redirects
* @version 3.0
* @author Joey Kimsey <Joey@thetempusproject.com>
* @link https://TheTempusProject.com
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
*/
namespace TheTempusProject\Plugins;
use ReflectionClass;
use TheTempusProject\Classes\Installer;
use TheTempusProject\Houdini\Classes\Navigation;
use TheTempusProject\Classes\Plugin;
use TheTempusProject\TheTempusProject as App;
class Redirects extends Plugin {
public $pluginName = 'TP Redirects';
public $pluginAuthor = 'JoeyK';
public $pluginWebsite = 'https://TheTempusProject.com';
public $modelVersion = '1.0';
public $pluginVersion = '3.0';
public $pluginDescription = 'A simple plugin which adds redirects.';
public $permissionMatrix = [
'redirects' => [
'pretty' => 'Can modify redirects',
'default' => false,
],
];
public $admin_links = [
[
'text' => '<i class="fa fa-fw fa-external-link"></i> Redirects',
'url' => '{ROOT_URL}admin/routes',
],
];
}

View File

@ -38,7 +38,9 @@ class Subscribe extends Plugin {
public function __construct( $load = false ) { public function __construct( $load = false ) {
parent::__construct( $load ); parent::__construct( $load );
if ( ! self::$loaded ) { if ( ! self::$loaded ) {
Components::append( 'FOOTER_RIGHT', Views::simpleView( 'subscribe.footer.right') ); if ( $this->checkEnabled() ) {
Components::append( 'FOOTER_RIGHT', Views::simpleView( 'subscribe.footer.right') );
}
self::$loaded = true; self::$loaded = true;
} }
} }

View File

@ -2,7 +2,7 @@
<legend class="text-center">Add Subscriber</legend> <legend class="text-center">Add Subscriber</legend>
<hr> <hr>
{ADMIN_BREADCRUMBS} {ADMIN_BREADCRUMBS}
<form action="" method="post"> <form method="post">
<fieldset> <fieldset>
<!-- Subject --> <!-- Subject -->
<div class="mb-3 row"> <div class="mb-3 row">

View File

@ -1,7 +1,7 @@
<div class="col-md-5 offset-md-1 mb-3 text-center"> <div class="col-12 col-sm-6 col-md-3 offset-0 offset-lg-2 mb-3 text-center">
<h5 class="">Subscribe</h5> <h5 class="">Subscribe</h5>
<div class="d-flex flex-column flex-sm-row gap-2 justify-content-center mx-auto"> <div class="d-flex flex-column w-75 w-sm-100 gap-2 justify-content-center mx-auto">
<form action="{ROOT_URL}subscribe/home" method="post" class="form-horizontal"> <form action="{ROOT_URL}subscribe/home" method="post">
<label for="email" class="visually-hidden">Email address</label> <label for="email" class="visually-hidden">Email address</label>
<input name="email" id="email" type="email" class="form-control my-2" placeholder="Email address" autocomplete="email"> <input name="email" id="email" type="email" class="form-control my-2" placeholder="Email address" autocomplete="email">
<input type="hidden" name="token" value="{TOKEN}"> <input type="hidden" name="token" value="{TOKEN}">

View File

@ -1,4 +1,4 @@
<form action="{ROOT_URL}subscribe/home" method="post" class="form-horizontal"> <form action="{ROOT_URL}subscribe/home" method="post">
<input type="email" placeholder="Email" id="email" name="email" autocomplete="email"> <input type="email" placeholder="Email" id="email" name="email" autocomplete="email">
<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><br> <button name="submit" value="submit" type="submit" class="btn btn-lg btn-primary center-block">Submit</button><br>

View File

@ -1,4 +1,4 @@
<form action="{ROOT_URL}home/unsubscribe" method="post" class="form-horizontal"> <form action="{ROOT_URL}home/unsubscribe" method="post">
<input type="email" placeholder="Email" id="email" name="email"> <input type="email" placeholder="Email" id="email" name="email">
<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><br> <button name="submit" value="submit" type="submit" class="btn btn-lg btn-primary center-block">Submit</button><br>

View File

@ -34,14 +34,21 @@ class AdminLoader extends DefaultLoader {
} }
$links[$key]->url = '#' . $name . 'Dropdown'; $links[$key]->url = '#' . $name . 'Dropdown';
$links[$key]->text = '<span>' . $link->text . '</span><i class="fa fa-fw fa-caret-down ms-2"></i>'; $links[$key]->text = '<span>' . $link->text . '</span><i class="fa fa-fw fa-caret-down ms-2"></i>';
$links[$key]->duuuuuuuh = Views::simpleView( 'nav.adminSub', $out ); $links[$key]->subnav = Views::simpleView( 'nav.adminSub', $out );
} else { } else {
$links[$key]->linkClasses = 'nav-link'; $links[$key]->linkClasses = 'nav-link';
$links[$key]->linkAttributes = ''; $links[$key]->linkAttributes = '';
$links[$key]->duuuuuuuh = ''; $links[$key]->subnav = '';
} }
} }
Components::set( 'ADMIN_LINKS', Views::simpleView( 'nav.admin', $links ) ); $menu = Views::simpleView( 'nav.admin', $links );
$activeMenu = Navigation::activePageSelect( $menu, Input::get( 'url' ), false, true );
Components::set( 'ADMIN_LINKS', $activeMenu );
$menu = Views::simpleView( 'nav.adminTop', Navigation::getMenuLinks( App::MAIN_MENU_NAME ) );
$activeMenu = Navigation::activePageSelect( $menu, Input::get( 'url' ), false, true );
Components::set( 'topNavLeft', $activeMenu );
Navigation::setCrumbComponent( 'ADMIN_BREADCRUMBS', Input::get( 'url' ) ); Navigation::setCrumbComponent( 'ADMIN_BREADCRUMBS', Input::get( 'url' ) );
} }
} }

View File

@ -45,7 +45,7 @@
<!-- Center Element --> <!-- Center Element -->
<div class="flex-grow-1 d-flex flex-column"> <div class="flex-grow-1 d-flex flex-column">
<!-- Top Navigation Bar --> <!-- Top Navigation Bar -->
<div class="p-3 text-bg-dark"> <div class="p-2 text-bg-dark">
<div class="d-flex flex-wrap align-items-center justify-content-center justify-content-lg-start"> <div class="d-flex flex-wrap align-items-center justify-content-center justify-content-lg-start">
{topNavLeft} {topNavLeft}
</div> </div>

View File

@ -31,6 +31,7 @@ class DefaultLoader extends Loader {
if ( self::$loaded ) { if ( self::$loaded ) {
return; return;
} }
Components::set( 'DARK_MODE_SETTING', '' );
Components::set( 'TEMPLATE_URL', Template::parse( '{ROOT_URL}app/templates/default/' ) ); Components::set( 'TEMPLATE_URL', Template::parse( '{ROOT_URL}app/templates/default/' ) );
if ( VENDOR_AUTOLOADED === true ) { if ( VENDOR_AUTOLOADED === true ) {
Components::set( 'FONT_AWESOME_URL', '/vendor/fortawesome/font-awesome/css/' ); Components::set( 'FONT_AWESOME_URL', '/vendor/fortawesome/font-awesome/css/' );
@ -54,9 +55,11 @@ class DefaultLoader extends Loader {
*/ */
if ( App::$isLoggedIn ) { if ( App::$isLoggedIn ) {
if ( ! empty( App::$activePrefs['darkMode'] ) ) { if ( ! empty( App::$activePrefs['darkMode'] ) ) {
Components::set( 'DARK_MODE_SETTING', 'true' );
$this->addCss( '<link rel="stylesheet" href="{ROOT_URL}app/css/main.css">' ); $this->addCss( '<link rel="stylesheet" href="{ROOT_URL}app/css/main.css">' );
$this->addCss( '<link rel="stylesheet" href="{ROOT_URL}app/css/main-dark.css" id="dark-mode-stylesheet">' ); $this->addCss( '<link rel="stylesheet" href="{ROOT_URL}app/css/main-dark.css" id="dark-mode-stylesheet">' );
} else { } else {
Components::set( 'DARK_MODE_SETTING', 'false' );
$this->addCss( '<link rel="stylesheet" href="{ROOT_URL}app/css/main.css">' ); $this->addCss( '<link rel="stylesheet" href="{ROOT_URL}app/css/main.css">' );
$this->addCss( '<link rel="stylesheet" href="{ROOT_URL}app/css/main-dark.css" id="dark-mode-stylesheet" disabled>' ); $this->addCss( '<link rel="stylesheet" href="{ROOT_URL}app/css/main-dark.css" id="dark-mode-stylesheet" disabled>' );
} }
@ -70,7 +73,11 @@ class DefaultLoader extends Loader {
$this->addCss( '<link rel="stylesheet" href="{ROOT_URL}app/css/main-dark.css" id="dark-mode-stylesheet" disabled>' ); $this->addCss( '<link rel="stylesheet" href="{ROOT_URL}app/css/main-dark.css" id="dark-mode-stylesheet" disabled>' );
} }
Components::set( 'topNavRight', Template::parse( App::$topNavRight . '{STATUS}' ) ); Components::set( 'topNavRight', Template::parse( App::$topNavRight . '{STATUS}' ) );
Components::set( 'topNavLeft', Views::simpleView( 'nav.main', Navigation::getMenuLinks( App::MAIN_MENU_NAME ) ) );
$menu = Views::simpleView( 'nav.main', Navigation::getMenuLinks( App::MAIN_MENU_NAME ) );
$activeMenu = Navigation::activePageSelect( $menu, Input::get( 'url' ), false, true );
Components::set( 'topNavLeft', $activeMenu );
Components::set( 'colorSelect', Views::simpleView( 'forms.colorSelect' ) ); Components::set( 'colorSelect', Views::simpleView( 'forms.colorSelect' ) );
Components::set( 'iconSelect', Views::simpleView( 'forms.iconSelect' ) ); Components::set( 'iconSelect', Views::simpleView( 'forms.iconSelect' ) );
Navigation::setCrumbComponent( 'BREADCRUMB', Input::get( 'url' ) ); Navigation::setCrumbComponent( 'BREADCRUMB', Input::get( 'url' ) );

View File

@ -39,22 +39,48 @@
</head> </head>
<body> <body>
<!-- Navigation --> <!-- Navigation -->
<header class="p-3 text-bg-dark"> <header class="p-3 text-bg-dark">
<div class="container"> <div class="container">
<div class="d-flex flex-wrap align-items-center justify-content-center justify-content-lg-start"> <div class="d-flex align-items-center position-relative">
<img src="{ROOT_URL}{LOGO}" class="bi me-2" width="40" height="32" alt="{SITENAME} Logo" aria-label="{SITENAME} Logo"> <!-- Navbar Toggler (Left) -->
<a href="/" class="d-flex align-items-center mb-2 mb-lg-0 text-white text-decoration-none">
{SITENAME} <!-- Centered Logo (Now inside normal document flow) -->
</a> <a href="/" class="align-items-center text-white text-decoration-none d-flex d-md-none">
{topNavLeft} <img src="{ROOT_URL}{LOGO}" width="40" height="32" alt="{SITENAME} Logo" class="bi">
<div class="text-end d-flex align-items-center"> </a>
{topNavRight}
</div> <!-- Logo (Normal Position for Large Screens) -->
</div> <a href="/" class="align-items-center text-white text-decoration-none d-none d-md-flex">
</div> <img src="{ROOT_URL}{LOGO}" width="40" height="32" alt="{SITENAME} Logo" class="bi">
</header> </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>
</div>
</div>
</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} {ISSUES}
<div class="container pt-4"> <div class="container pt-4">
<div class="row"> <div class="row">
@ -65,10 +91,14 @@
</div> </div>
</div> </div>
{/ISSUES} {/ISSUES}
<!-- Main Page Content -->
{CONTENT} {CONTENT}
</div> </div>
<!-- Footer -->
{FOOT} {FOOT}
</div> </div>
<!-- User Pref to control Dark mode across frontend and backend -->
<input type="hidden" name="dark-mode-pref" id="dark-mode-pref" value="{DARK_MODE_SETTING}">
<!-- Bootstrap core JavaScript and jquery --> <!-- Bootstrap core JavaScript and jquery -->
<script crossorigin="anonymous" src="{JQUERY_CDN}jquery.min.js"></script> <script crossorigin="anonymous" src="{JQUERY_CDN}jquery.min.js"></script>
<script crossorigin="anonymous" src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.11.6/dist/umd/popper.min.js"></script> <script crossorigin="anonymous" src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.11.6/dist/umd/popper.min.js"></script>

View File

@ -1,16 +1,27 @@
<div class="col-8 mx-auto p-4 rounded shadow-sm context-main-bg my-4"> <div class="m-2 m-lg-4">
<h2 class="text-center mb-4">About {SITENAME}</h2> <div class="col-12 mx-5 col-sm-10 col-lg-8 mx-auto p-4 rounded shadow-sm context-main-bg">
<p class="lead"> <h2 class="text-center mb-4">About {SITENAME}</h2>
{SITENAME} was built out of a need to create and manage my own web applications. <p class="lead text-center text-lg-start">
</p> {SITENAME} was built out of a need to create and manage web applications.
<p class="text-muted"> At the time, I had used wordpress but I didn't want or even need any of the blog functionality.
Right now, this entire system was built and managed by myself. As stated, I have used my own version of this for years, but translating it to a publicly available product is not a 1-to-1 job. There may be bugs or issues encountered while you use the product. I can't guarantee a fix for every need in every case immediately, but I do actively keep track of bugs and work hard to ensure everyone has a great experience using the app. No matter what plugins you add, no matter how you customize layout, wordpress is still a blog at its core.
</p> There is nothing inherently wrong with a blog, but when you start from a blog, everything is a post, or a plugin.
<p> Under the hood, wordpress is going to run how wordpress wants, as a web interface for accessing text records.
If you encounter any bugs, feel free to report them <a href="/bugreport" class="text-decoration-none">here</a>. Likewise, there are forms for feedback, reviews, suggestions, and a general contact form. Thanks for taking the time to check out the product! </p>
</p> <p class="text-center text-lg-start">
<div class="text-center mt-4 pb-4"> The Tempus Project was always intended to be a web application, not a blog.
{loggedin}<a href="/bugreport" class="btn btn-primary btn-lg px-5">Report a Bug</a>{/loggedin} </p>
<a href="/contact" class="btn btn-outline-secondary btn-lg px-5 ms-3">Contact Us</a> <p class="text-muted text-center text-lg-start">
Right now, this entire system was built and managed by myself. As stated, I have used my own version of this for years, but translating it to a publicly available product is not a 1-to-1 job. There may be bugs or issues encountered while you use the product. I can't guarantee a fix for every need in every case immediately, but I do actively keep track of bugs and work hard to ensure everyone has a great experience using the app.
</p>
<p class="text-center text-lg-start">
If you encounter any bugs, feel free to report them <a href="/bugreport" class="text-decoration-none">here</a>. Likewise, there are forms for feedback, reviews, suggestions, and a general contact form. Thanks for taking the time to check out the product!
</p>
<div class="text-center mt-4 pb-4">
{loggedin}
<a href="/bugreport" class="btn btn-primary px-3 btn-lg m-2">Report a Bug</a>
{/loggedin}
<a href="/contact" class="btn btn-outline-primary px-3 m-2 btn-lg">Contact Us</a>
</div>
</div> </div>
</div> </div>

View File

@ -7,7 +7,7 @@
Please be very careful with this feature. This form allows you to send an email (formatted within the default site email template) to registered emails from various sources including newsletter subscribers, call to action subscribers, and all registered user accounts. Please be very careful with this feature. This form allows you to send an email (formatted within the default site email template) to registered emails from various sources including newsletter subscribers, call to action subscribers, and all registered user accounts.
</p> </p>
</div> </div>
<form action="" method="post"> <form method="post">
<fieldset> <fieldset>
<!-- Subject --> <!-- Subject -->
<div class="mb-3 row"> <div class="mb-3 row">

View File

@ -8,6 +8,11 @@
{commentDash} {commentDash}
</div> </div>
</div> </div>
<div class="row">
<div class="col-10 offset-1">
{contactDash}
</div>
</div>
<div class="row"> <div class="row">
<div class="col-10 offset-1"> <div class="col-10 offset-1">
{blogDash} {blogDash}

View File

@ -18,8 +18,8 @@
<tbody> <tbody>
{LOOP} {LOOP}
<tr> <tr>
<td><a href="{ROOT_URL}admin/groups/view/{ID}">{name}</a></td> <td><a href="{ROOT_URL}admin/groups/view/{ID}" class="text-decoration-none">{name}</a></td>
<td><a href="{ROOT_URL}admin/groups/listmembers/{ID}">{userCount}</a></td> <td><a href="{ROOT_URL}admin/groups/listmembers/{ID}" class="text-decoration-none">{userCount}</a></td>
<td><a href="{ROOT_URL}admin/groups/edit/{ID}" class="btn btn-sm btn-warning"><i class="fa fa-fw fa-pencil"></i></a></td> <td><a href="{ROOT_URL}admin/groups/edit/{ID}" class="btn btn-sm btn-warning"><i class="fa fa-fw fa-pencil"></i></a></td>
<td><a href="{ROOT_URL}admin/groups/delete/{ID}" class="btn btn-sm btn-danger"><i class="fa fa-fw fa-trash"></i></a></td> <td><a href="{ROOT_URL}admin/groups/delete/{ID}" class="btn btn-sm btn-danger"><i class="fa fa-fw fa-trash"></i></a></td>
<td> <td>

View File

@ -1,40 +1,43 @@
<h1>{groupName} <small>user list</small></h1> <div class="context-main-bg context-main p-3">
{PAGINATION} <legend class="text-center">{groupName} <small>user list</small></legend>
<form action="{ROOT_URL}admin/users/delete" method="post"> <hr>
<table class="table table-striped"> {ADMIN_BREADCRUMBS}
<thead> <form action="{ROOT_URL}admin/users/delete" method="post">
<tr> <table class="table table-striped">
<th style="width: 5%">ID</th> <thead>
<th style="width: 55%">Username</th> <tr>
<th style="width: 25%">Joined</th> <th style="width: 5%">ID</th>
<th style="width: 5%"></th> <th style="width: 55%">Username</th>
<th style="width: 5%"></th> <th style="width: 25%">Joined</th>
<th style="width: 5%"> <th style="width: 5%"></th>
<input type="checkbox" onchange="checkAll(this)" name="check.u" value="U_[]"> <th style="width: 5%"></th>
</th> <th style="width: 5%">
</tr> <input type="checkbox" onchange="checkAll(this)" name="check.u" value="U_[]">
</thead> </th>
<tbody> </tr>
{LOOP} </thead>
<tr> <tbody>
<td>{ID}</td> {LOOP}
<td><a href='{ROOT_URL}admin/users/view/{ID}'>{username}</a></td> <tr>
<td>{DTC date}{registered}{/DTC}</td> <td>{ID}</td>
<td><a href="{ROOT_URL}admin/users/edit/{ID}" class="btn btn-sm btn-warning"><i class="fa fa-fw fa-pencil"></i></a></td> <td><a href='{ROOT_URL}admin/users/view/{ID}' class="text-decoration-none">{username}</a></td>
<td><a href="{ROOT_URL}admin/users/delete/{ID}" class="btn btn-sm btn-danger"><i class="fa fa-fw fa-trash"></i></a></td> <td>{DTC date}{registered}{/DTC}</td>
<td> <td><a href="{ROOT_URL}admin/users/edit/{ID}" class="btn btn-sm btn-warning"><i class="fa fa-fw fa-pencil"></i></a></td>
<input type="checkbox" value="{ID}" name="U_[]"> <td><a href="{ROOT_URL}admin/users/delete/{ID}" class="btn btn-sm btn-danger"><i class="fa fa-fw fa-trash"></i></a></td>
</td> <td>
</tr> <input type="checkbox" value="{ID}" name="U_[]">
{/LOOP} </td>
{ALT} </tr>
<tr> {/LOOP}
<td align="center" colspan="6"> {ALT}
No results to show. <tr>
</td> <td align="center" colspan="6">
</tr> No results to show.
{/ALT} </td>
</tbody> </tr>
</table> {/ALT}
<button name="submit" value="submit" type="submit" class="btn btn-sm btn-danger"><i class="fa fa-fw fa-trash"></i></button> </tbody>
</form> </table>
<button name="submit" value="submit" type="submit" class="btn btn-sm btn-danger"><i class="fa fa-fw fa-trash"></i></button>
</form>
</div>

View File

@ -17,7 +17,7 @@
<tbody> <tbody>
{LOOP} {LOOP}
<tr> <tr>
<td><a href="{ROOT_URL}admin/plugins/view/{name}">{name}</a></td> <td><a href="{ROOT_URL}admin/plugins/view/{name}" class="text-decoration-none">{name}</a></td>
<td>{enabled_txt}</td> <td>{enabled_txt}</td>
<td>{installStatus}</td> <td>{installStatus}</td>
<td>{version}</td> <td>{version}</td>

View File

@ -22,7 +22,7 @@
{LOOP} {LOOP}
<tr> <tr>
<td align="center">{ID}</td> <td align="center">{ID}</td>
<td><a href='{ROOT_URL}admin/routes/view/{ID}'>{nickname}</a></td> <td><a href='{ROOT_URL}admin/routes/view/{ID}' class="text-decoration-none">{nickname}</a></td>
<td>{redirect_type}</td> <td>{redirect_type}</td>
<td>{original_url}</td> <td>{original_url}</td>
<td>{forwarded_url}</td> <td>{forwarded_url}</td>

View File

@ -1,6 +1,8 @@
<div class="context-main-bg context-main p-3"> <div class="context-main-bg context-main p-3">
<legend class="text-center">Settings</legend>
<hr>
{ADMIN_BREADCRUMBS} {ADMIN_BREADCRUMBS}
<form action="" method="post" class="form-horizontal" enctype="multipart/form-data"> <form method="post" enctype="multipart/form-data">
<fieldset> <fieldset>
{configForm} {configForm}

View File

@ -3,7 +3,7 @@
<legend class="text-center">Create Token</legend> <legend class="text-center">Create Token</legend>
<hr> <hr>
{ADMIN_BREADCRUMBS} {ADMIN_BREADCRUMBS}
<form action="" method="post" class="container py-4"> <form method="post" class="container py-4">
<fieldset> <fieldset>
<div class="mb-3 row"> <div class="mb-3 row">
<label for="name" class="col-lg-5 col-form-label text-end">Name</label> <label for="name" class="col-lg-5 col-form-label text-end">Name</label>

View File

@ -3,7 +3,7 @@
<legend class="text-center">Edit Token</legend> <legend class="text-center">Edit Token</legend>
<hr> <hr>
{ADMIN_BREADCRUMBS} {ADMIN_BREADCRUMBS}
<form action="" method="post" class="container py-4"> <form method="post" class="container py-4">
<fieldset> <fieldset>
<div class="mb-3 row"> <div class="mb-3 row">
<label for="name" class="col-lg-5 col-form-label text-end">Name</label> <label for="name" class="col-lg-5 col-form-label text-end">Name</label>

View File

@ -14,7 +14,7 @@
<tbody> <tbody>
{LOOP} {LOOP}
<tr> <tr>
<td><a href='{ROOT_URL}admin/tokens/view/{ID}'>{name}</a></td> <td><a href='{ROOT_URL}admin/tokens/view/{ID}' class="text-decoration-none">{name}</a></td>
<td>{token_type}</td> <td>{token_type}</td>
<td><a href="{ROOT_URL}admin/tokens/edit/{ID}" class="btn btn-sm btn-warning"><i class="fa fa-fw fa-pencil"></i></a></td> <td><a href="{ROOT_URL}admin/tokens/edit/{ID}" class="btn btn-sm btn-warning"><i class="fa fa-fw fa-pencil"></i></a></td>
<td><a href="{ROOT_URL}admin/tokens/delete/{ID}" class="btn btn-sm btn-danger"><i class="fa fa-fw fa-trash"></i></a></td> <td><a href="{ROOT_URL}admin/tokens/delete/{ID}" class="btn btn-sm btn-danger"><i class="fa fa-fw fa-trash"></i></a></td>

View File

@ -34,7 +34,7 @@
<div class="mb-3 row"> <div class="mb-3 row">
<label for="password" class="col-lg-6 col-form-label text-end">Password:</label> <label for="password" class="col-lg-6 col-form-label text-end">Password:</label>
<div class="col-lg-2"> <div class="col-lg-2">
<input type="password" class="form-control" name="password" id="password" value="" required> <input type="password" class="form-control" name="password" id="password" value="">
</div> </div>
</div> </div>
@ -42,7 +42,7 @@
<div class="mb-3 row"> <div class="mb-3 row">
<label for="password2" class="col-lg-6 col-form-label text-end">Re-Enter Password:</label> <label for="password2" class="col-lg-6 col-form-label text-end">Re-Enter Password:</label>
<div class="col-lg-2"> <div class="col-lg-2">
<input type="password" class="form-control" name="password2" id="password2" value="" required> <input type="password" class="form-control" name="password2" id="password2" value="">
</div> </div>
</div> </div>

View File

@ -20,7 +20,7 @@
{LOOP} {LOOP}
<tr> <tr>
<td align="center">{ID}</td> <td align="center">{ID}</td>
<td><a href='{ROOT_URL}admin/users/view/{ID}'>{username}</a></td> <td><a href='{ROOT_URL}admin/users/view/{ID}' class="text-decoration-none">{usernamePretty}</a></td>
<td>{DTC date}{registered}{/DTC}</td> <td>{DTC date}{registered}{/DTC}</td>
<td><a href="{ROOT_URL}admin/users/edit/{ID}" class="btn btn-sm btn-warning"><i class="fa fa-fw fa-pencil"></i></a></td> <td><a href="{ROOT_URL}admin/users/edit/{ID}" class="btn btn-sm btn-warning"><i class="fa fa-fw fa-pencil"></i></a></td>
<td><a href="{ROOT_URL}admin/users/delete/{ID}" class="btn btn-sm btn-danger"><i class="fa fa-fw fa-trash"></i></a></td> <td><a href="{ROOT_URL}admin/users/delete/{ID}" class="btn btn-sm btn-danger"><i class="fa fa-fw fa-trash"></i></a></td>

View File

@ -5,7 +5,7 @@
<div class="card shadow"> <div class="card shadow">
<!-- Card Header --> <!-- Card Header -->
<div class="card-header text-center bg-dark text-white"> <div class="card-header text-center bg-dark text-white">
<h3 class="card-title mb-0">{username}</h3> <h3 class="card-title mb-0">{usernamePretty}</h3>
</div> </div>
<!-- Card Body --> <!-- Card Body -->
@ -27,7 +27,7 @@
</tr> </tr>
<tr> <tr>
<th scope="row">Group:</th> <th scope="row">Group:</th>
<td><a href="{ROOT_URL}admin/groups/view/{userGroup}">{groupName}</a></td> <td><a href="{ROOT_URL}admin/groups/view/{userGroup}" class="text-decoration-none">{groupName}</a></td>
</tr> </tr>
{/ADMIN} {/ADMIN}
<tr> <tr>
@ -45,7 +45,7 @@
{ADMIN} {ADMIN}
<tr> <tr>
<th scope="row">Email:</th> <th scope="row">Email:</th>
<td><a href="mailto:{email}">{email}</a></td> <td><a href="mailto:{email}" class="text-decoration-none">{email}</a></td>
</tr> </tr>
<tr> <tr>
<th scope="row">User ID:</th> <th scope="row">User ID:</th>

View File

@ -1,30 +0,0 @@
<div class="container">
<div class="row">
<div class="col-lg-9 col-md-9 col-sm-12 col-centered">
<div class="row">
<div class="col-lg-12 col-md-12 col-sm-12">
<h2>Welcome to The Tempus-Project Friends and Family Alpha.</h2>
<hr>
<p>This project is now entering its third official version and nearly its tenth year of development. What a long journey it has been to get here.</p>
<p>With that being said, I won't waste your time with a journey down memory road. If you have been sent this page, clearly I trust you, or one of our mutual friends is an asshole. Both equally possible... The main purpose of inviting you was to ask for your help.</p>
<h2>What I need</h2>
<p>With any application, there are bugs. The best developers I have had the pleasure of working with make mundane every day mistakes just like everyone else. This obviously includes myself. With any project you spend years working on, you will develop blind spots, or places where even if something was broken, you would skip right past it and never notice.</p>
<p>I would like your help in identifying these such blind spots.</p>
<h2>What you can do to help.</h2>
<p>Currently there is a bug-report form at the bottom, usable by anyone with a registered account. I have also built an administrator system that allows me to track progress of these bugs and ensure they get fixed. In addition to tracking bugs, there is a public suggestions system and a publicly viewable to-do list.</p>
<p>I will need some users to help test very specific things like permissions for various groups. I will need some trusted users to act as administrators and test features. I will also just need some people to use and interact with the site to ensure they aren't encountering any bugs.</p>
<p>There are a ton of things you can do to help!</p>
<ul>
<li>Report any bugs!!! ( there is a bug-report link at the bottom of every page )</li>
<li>Register an account</li>
<li>Subscribe to the mailing list</li>
<li>Browse blog posts</li>
<li>Make suggestions for improvements or new features</li>
<li>Leave comments on the blog and other features.</li>
<li>Keep an eye out for email or messages requesting specific help.</li>
</ul>
</div>
</div>
</div>
</div>
</div>

View File

@ -3,7 +3,7 @@
<h1 class="mb-4">Email Confirmation</h1> <h1 class="mb-4">Email Confirmation</h1>
<hr> <hr>
<p>Please enter the confirmation code you received in your email.</p> <p>Please enter the confirmation code you received in your email.</p>
<form action="" method="post" class=""> <form method="post">
<fieldset> <fieldset>
<div data-mdb-input-init class="form-outline mb-4 col-2 offset-5"> <div data-mdb-input-init class="form-outline mb-4 col-2 offset-5">
<input class="form-control" type="text" name="confirmationCode" id="confirmationCode" placeholder="Confirmation Code"> <input class="form-control" type="text" name="confirmationCode" id="confirmationCode" placeholder="Confirmation Code">
@ -12,4 +12,4 @@
<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><br> <button name="submit" value="submit" type="submit" class="btn btn-lg btn-primary center-block">Submit</button><br>
</form> </form>
</div> </div>

View File

@ -2,7 +2,7 @@
<h1 class="mb-4">Re-Send Confirmation</h1> <h1 class="mb-4">Re-Send Confirmation</h1>
<hr> <hr>
<p>Please click the resend button to resend your email confirmation. Don't forget to check the spam folder!</p> <p>Please click the resend button to resend your email confirmation. Don't forget to check the spam folder!</p>
<form action="" method="post" class=""> <form method="post">
<input type="hidden" name="resendConfirmation" value="true"> <input type="hidden" name="resendConfirmation" value="true">
<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">Resend Confirmation</button><br> <button name="submit" value="submit" type="submit" class="btn btn-lg btn-primary center-block">Resend Confirmation</button><br>

Some files were not shown because too many files have changed in this diff Show More