remove non-standard plugins
This commit is contained in:
@ -1,402 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* app/plugins/bugreport/controllers/bugreport.php
|
||||
*
|
||||
* This is the bug reports controller.
|
||||
*
|
||||
* @package TP BugReports
|
||||
* @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\Hermes\Functions\Redirect;
|
||||
use TheTempusProject\Bedrock\Functions\Check;
|
||||
use TheTempusProject\Bedrock\Functions\Input;
|
||||
use TheTempusProject\Bedrock\Functions\Session;
|
||||
use TheTempusProject\Houdini\Classes\Issues;
|
||||
use TheTempusProject\Houdini\Classes\Views;
|
||||
use TheTempusProject\Classes\Controller;
|
||||
use TheTempusProject\Classes\Forms;
|
||||
use TheTempusProject\Models\Bookmarks as Bookmark;
|
||||
use TheTempusProject\Models\Folders;
|
||||
use TheTempusProject\TheTempusProject as App;
|
||||
use TheTempusProject\Houdini\Classes\Components;
|
||||
use TheTempusProject\Houdini\Classes\Forms as HoudiniForms;
|
||||
use TheTempusProject\Houdini\Classes\Navigation;
|
||||
|
||||
class Bookmarks extends Controller {
|
||||
protected static $bookmarks;
|
||||
protected static $folders;
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
if ( !App::$isLoggedIn ) {
|
||||
Session::flash( 'notice', 'You must be logged in to create or manage bookmarks.' );
|
||||
return Redirect::home();
|
||||
}
|
||||
self::$bookmarks = new Bookmark;
|
||||
self::$folders = new Folders;
|
||||
self::$title = 'Bookmarks - {SITENAME}';
|
||||
self::$pageDescription = 'Add and save url bookmarks here.';
|
||||
|
||||
$folderTabs = Views::simpleView( 'bookmarks.nav.folderTabs' );
|
||||
if ( stripos( Input::get('url'), 'bookmarks/bookmarks' ) !== false ) {
|
||||
$tabsView = Navigation::activePageSelect( $folderTabs, '/bookmarks/folders/', false, true );
|
||||
$userFolderTabs = Views::simpleView('bookmarks.nav.userFolderTabs', self::$folders->simpleObjectByUser(true) );
|
||||
$userFolderTabsView = Navigation::activePageSelect( $userFolderTabs, Input::get( 'url' ), false, true );
|
||||
} else {
|
||||
$tabsView = Navigation::activePageSelect( $folderTabs, Input::get( 'url' ), false, true );
|
||||
$userFolderTabsView = '';
|
||||
}
|
||||
Components::set( 'userFolderTabs', $userFolderTabsView );
|
||||
Views::raw( $tabsView );
|
||||
}
|
||||
|
||||
public function index() {
|
||||
$bookmarks = self::$bookmarks->noFolder();
|
||||
$folders = self::$folders->byUser();
|
||||
|
||||
$panelArray = [];
|
||||
if ( !empty( $folders ) ) {
|
||||
foreach ( $folders as $folder ) {
|
||||
$panel = new \stdClass();
|
||||
$folderObject = new \stdClass();
|
||||
$folderObject->bookmarks = self::$bookmarks->byFolder( $folder->ID );
|
||||
$folderObject->ID = $folder->ID;
|
||||
$folderObject->title = $folder->title;
|
||||
$folderObject->color = $folder->color;
|
||||
$folderObject->bookmarkListRows = Views::simpleView( 'bookmarks.components.bookmarkListRows', $folderObject->bookmarks );
|
||||
$panel->panel = Views::simpleView( 'bookmarks.components.bookmarkListPanel', [$folderObject] );
|
||||
$panelArray[] = $panel;
|
||||
}
|
||||
}
|
||||
Components::set( 'foldersList', Views::simpleView( 'bookmarks.folders.list', $folders ) );
|
||||
Components::set( 'folderPanels', Views::simpleView( 'bookmarks.components.folderPanelList', $panelArray ) );
|
||||
Components::set( 'bookmarksList', Views::simpleView( 'bookmarks.bookmarks.list', $bookmarks ) );
|
||||
return Views::view( 'bookmarks.dash' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Bookmarks
|
||||
*/
|
||||
public function bookmark( $id = 0 ) {
|
||||
$bookmark = self::$bookmarks->findById( $id );
|
||||
if ( $bookmark == false ) {
|
||||
Session::flash( 'error', 'Bookmark not found.' );
|
||||
return Redirect::to( 'bookmarks/index' );
|
||||
}
|
||||
if ( $bookmark->createdBy != App::$activeUser->ID ) {
|
||||
Session::flash( 'error', 'You do not have permission to modify this bookmark.' );
|
||||
return Redirect::to( 'bookmarks/index' );
|
||||
}
|
||||
Navigation::setCrumbComponent( 'BookmarkBreadCrumbs', 'bookmarks/bookmark/' . $id );
|
||||
return Views::view( 'bookmarks.bookmarks.view', $bookmark );
|
||||
}
|
||||
|
||||
public function bookmarks( $id = null ) {
|
||||
$folder = self::$folders->findById( $id );
|
||||
if ( $folder == false ) {
|
||||
Session::flash( 'error', 'Folder not found.' );
|
||||
return Redirect::to( 'bookmarks/index' );
|
||||
}
|
||||
if ( $folder->createdBy != App::$activeUser->ID ) {
|
||||
Session::flash( 'error', 'You do not have permission to view this folder.' );
|
||||
return Redirect::to( 'bookmarks/index' );
|
||||
}
|
||||
Navigation::setCrumbComponent( 'BookmarkBreadCrumbs', 'bookmarks/bookmarks/' . $id );
|
||||
|
||||
|
||||
$bookmarks = self::$bookmarks->noFolder();
|
||||
|
||||
$panelArray = [];
|
||||
$panel = new \stdClass();
|
||||
$folderObject = new \stdClass();
|
||||
$folderObject->bookmarks = self::$bookmarks->byFolder( $folder->ID );
|
||||
$folderObject->ID = $folder->ID;
|
||||
$folderObject->title = $folder->title;
|
||||
$folderObject->color = $folder->color;
|
||||
$folderObject->bookmarkListRows = Views::simpleView( 'bookmarks.components.bookmarkListRows', $folderObject->bookmarks );
|
||||
$panel->panel = Views::simpleView( 'bookmarks.components.bookmarkListPanel', [$folderObject] );
|
||||
$panelArray[] = $panel;
|
||||
|
||||
return Views::view( 'bookmarks.components.folderPanelList', $panelArray );
|
||||
}
|
||||
|
||||
public function createBookmark( $id = null ) {
|
||||
$folderID = Input::get('folder_id') ? Input::get('folder_id') : $id;
|
||||
$folderID = Input::post('folder_id') ? Input::post('folder_id') : $id;
|
||||
$folderSelect = HoudiniForms::getFormFieldHtml( 'folder_id', 'Folder', 'select', $folderID, self::$folders->simpleByUser() );
|
||||
Components::set( 'folderSelect', $folderSelect );
|
||||
|
||||
if ( ! Input::exists() ) {
|
||||
return Views::view( 'bookmarks.bookmarks.create' );
|
||||
}
|
||||
if ( ! Forms::check( 'createBookmark' ) ) {
|
||||
Issues::add( 'error', [ 'There was an error with your form.' => Check::userErrors() ] );
|
||||
return Views::view( 'bookmarks.bookmarks.create' );
|
||||
}
|
||||
|
||||
$result = self::$bookmarks->create(
|
||||
Input::post('title'),
|
||||
Input::post('url'),
|
||||
$folderID,
|
||||
Input::post('description'),
|
||||
Input::post('color'),
|
||||
Input::post('privacy'),
|
||||
);
|
||||
|
||||
if ( ! $result ) {
|
||||
Issues::add( 'error', [ 'There was an error creating your bookmark.' => Check::userErrors() ] );
|
||||
return Views::view( 'bookmarks.bookmarks.create' );
|
||||
}
|
||||
self::$bookmarks->refreshInfo( $result );
|
||||
Session::flash( 'success', 'Your Bookmark has been created.' );
|
||||
Redirect::to( 'bookmarks/bookmarks/'. $folderID );
|
||||
}
|
||||
|
||||
public function editBookmark( $id = null ) {
|
||||
$folderID = Input::exists('folder_id') ? Input::post('folder_id') : '';
|
||||
|
||||
$bookmark = self::$bookmarks->findById( $id );
|
||||
if ( $bookmark == false ) {
|
||||
Issues::add( 'error', 'Bookmark not found.' );
|
||||
return Redirect::to( 'bookmarks/index' );
|
||||
}
|
||||
if ( $bookmark->createdBy != App::$activeUser->ID ) {
|
||||
Issues::add( 'error', 'You do not have permission to modify this bookmark.' );
|
||||
return Redirect::to( 'bookmarks/index' );
|
||||
}
|
||||
if ( empty( $folderID ) ) {
|
||||
$folderID = $bookmark->folderID;
|
||||
}
|
||||
|
||||
$folderSelect = HoudiniForms::getFormFieldHtml( 'folder_id', 'Folder', 'select', $folderID, self::$folders->simpleByUser() );
|
||||
Components::set( 'folderSelect', $folderSelect );
|
||||
Components::set( 'color', $bookmark->color );
|
||||
|
||||
if ( ! Input::exists( 'submit' ) ) {
|
||||
return Views::view( 'bookmarks.bookmarks.edit', $bookmark );
|
||||
}
|
||||
if ( ! Forms::check( 'editBookmark' ) ) {
|
||||
Issues::add( 'error', [ 'There was an error updating your bookmark.' => Check::userErrors() ] );
|
||||
return Views::view( 'bookmarks.bookmarks.edit', $bookmark );
|
||||
}
|
||||
|
||||
$result = self::$bookmarks->update(
|
||||
$id,
|
||||
Input::post('title'),
|
||||
Input::post('url'),
|
||||
$folderID,
|
||||
Input::post('description'),
|
||||
Input::post('color'),
|
||||
Input::post('privacy'),
|
||||
);
|
||||
if ( ! $result ) {
|
||||
Issues::add( 'error', [ 'There was an error updating your bookmark.' => Check::userErrors() ] );
|
||||
return Views::view( 'bookmarks.bookmarks.edit', $bookmark );
|
||||
}
|
||||
Session::flash( 'success', 'Your Bookmark has been updated.' );
|
||||
Redirect::to( 'bookmarks/folders/'. $bookmark->folderID );
|
||||
}
|
||||
|
||||
public function deleteBookmark( $id = null ) {
|
||||
$bookmark = self::$bookmarks->findById( $id );
|
||||
if ( $bookmark == false ) {
|
||||
Issues::add( 'error', 'Bookmark not found.' );
|
||||
return $this->index();
|
||||
}
|
||||
if ( $bookmark->createdBy != App::$activeUser->ID ) {
|
||||
Issues::add( 'error', 'You do not have permission to modify this bookmark.' );
|
||||
return $this->index();
|
||||
}
|
||||
$result = self::$bookmarks->delete( $id );
|
||||
if ( !$result ) {
|
||||
Session::flash( 'error', 'There was an error deleting the bookmark(s)' );
|
||||
} else {
|
||||
Session::flash( 'success', 'Bookmark deleted' );
|
||||
}
|
||||
Redirect::to( 'bookmarks/folders/'. $bookmark->folderID );
|
||||
}
|
||||
|
||||
/**
|
||||
* Folders
|
||||
*/
|
||||
public function folders( $id = null) {
|
||||
$folder = self::$folders->findById( $id );
|
||||
if ( $folder == false ) {
|
||||
$folders = self::$folders->byUser();
|
||||
return Views::view( 'bookmarks.folders.list', $folders );
|
||||
}
|
||||
if ( $folder->createdBy != App::$activeUser->ID ) {
|
||||
Session::flash( 'error', 'You do not have permission to view this folder.' );
|
||||
return Redirect::to( 'bookmarks/index' );
|
||||
}
|
||||
Navigation::setCrumbComponent( 'BookmarkBreadCrumbs', 'bookmarks/folders/' . $id );
|
||||
return Views::view( 'bookmarks.folders.view', $folder );
|
||||
}
|
||||
|
||||
public function createFolder( $id = 0 ) {
|
||||
$folderID = Input::exists('folder_id') ? Input::post('folder_id') : $id;
|
||||
$folders = self::$folders->simpleByUser();
|
||||
if ( ! empty( $folders ) ) {
|
||||
$folderSelect = HoudiniForms::getFormFieldHtml( 'folder_id', 'Folder', 'select', $folderID, $folders );
|
||||
} else {
|
||||
$folderSelect = '';
|
||||
}
|
||||
Components::set( 'folderSelect', $folderSelect );
|
||||
if ( ! Input::exists() ) {
|
||||
return Views::view( 'bookmarks.folders.create' );
|
||||
}
|
||||
if ( ! Forms::check( 'createFolder' ) ) {
|
||||
Issues::add( 'error', [ 'There was an error creating your folder.' => Check::userErrors() ] );
|
||||
return Views::view( 'bookmarks.folders.create' );
|
||||
}
|
||||
$folder = self::$folders->create( Input::post('title'), $folderID, Input::post('description'), Input::post('color'), Input::post('privacy') );
|
||||
if ( ! $folder ) {
|
||||
return Views::view( 'bookmarks.folders.create' );
|
||||
}
|
||||
Session::flash( 'success', 'Your Folder has been created.' );
|
||||
Redirect::to( 'bookmarks/folders' );
|
||||
}
|
||||
|
||||
public function editFolder( $id = null ) {
|
||||
$folder = self::$folders->findById( $id );
|
||||
|
||||
if ( $folder == false ) {
|
||||
Issues::add( 'error', 'Folder not found.' );
|
||||
return $this->index();
|
||||
}
|
||||
|
||||
if ( $folder->createdBy != App::$activeUser->ID ) {
|
||||
Issues::add( 'error', 'You do not have permission to modify this folder.' );
|
||||
return $this->index();
|
||||
}
|
||||
$folderID = ( false === Input::exists('folder_id') ) ? $folder->ID : Input::post('folder_id');
|
||||
|
||||
$folderSelect = HoudiniForms::getFormFieldHtml( 'folder_id', 'Folder', 'select', $folderID, self::$folders->simpleByUser() );
|
||||
Components::set( 'folderSelect', $folderSelect );
|
||||
Components::set( 'color', $folder->color );
|
||||
|
||||
if ( ! Input::exists( 'submit' ) ) {
|
||||
return Views::view( 'bookmarks.folders.edit', $folder );
|
||||
}
|
||||
|
||||
if ( !Forms::check( 'editFolder' ) ) {
|
||||
Issues::add( 'error', [ 'There was an error editing your folder.' => Check::userErrors() ] );
|
||||
return Views::view( 'bookmarks.folders.edit', $folder );
|
||||
}
|
||||
|
||||
$result = self::$folders->update( $id, Input::post('title'), $folderID, Input::post('description'), Input::post('color'), Input::post('privacy') );
|
||||
if ( !$result ) {
|
||||
Issues::add( 'error', [ 'There was an error updating your folder.' => Check::userErrors() ] );
|
||||
return Views::view( 'bookmarks.folders.edit', $folder );
|
||||
}
|
||||
Session::flash( 'success', 'Your Folder has been updated.' );
|
||||
Redirect::to( 'bookmarks/folders/'. $folder->ID );
|
||||
}
|
||||
|
||||
public function deleteFolder( $id = null ) {
|
||||
$folder = self::$folders->findById( $id );
|
||||
if ( $folder == false ) {
|
||||
Issues::add( 'error', 'Folder not found.' );
|
||||
return $this->index();
|
||||
}
|
||||
if ( $folder->createdBy != App::$activeUser->ID ) {
|
||||
Issues::add( 'error', 'You do not have permission to modify this folder.' );
|
||||
return $this->index();
|
||||
}
|
||||
$results = self::$bookmarks->deleteByFolder( $id );
|
||||
$result = self::$folders->delete( $id );
|
||||
if ( !$result ) {
|
||||
Session::flash( 'error', 'There was an error deleting the folder(s)' );
|
||||
} else {
|
||||
Session::flash( 'success', 'Folder deleted' );
|
||||
}
|
||||
Redirect::to( 'bookmarks/folders' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Functionality
|
||||
*/
|
||||
public function hideBookmark( $id = null ) {
|
||||
$bookmark = self::$bookmarks->findById( $id );
|
||||
if ( $bookmark == false ) {
|
||||
Session::flash( 'error', 'Bookmark not found.' );
|
||||
return Redirect::to( 'bookmarks/index' );
|
||||
}
|
||||
if ( $bookmark->createdBy != App::$activeUser->ID ) {
|
||||
Session::flash( 'error', 'You do not have permission to modify this bookmark.' );
|
||||
return Redirect::to( 'bookmarks/index' );
|
||||
}
|
||||
self::$bookmarks->hide( $id );
|
||||
Session::flash( 'success', 'Bookmark hidden.' );
|
||||
return Redirect::to( 'bookmarks/index' );
|
||||
}
|
||||
|
||||
public function archiveBookmark( $id = null ) {
|
||||
$bookmark = self::$bookmarks->findById( $id );
|
||||
if ( $bookmark == false ) {
|
||||
Session::flash( 'error', 'Bookmark not found.' );
|
||||
return Redirect::to( 'bookmarks/index' );
|
||||
}
|
||||
if ( $bookmark->createdBy != App::$activeUser->ID ) {
|
||||
Session::flash( 'error', 'You do not have permission to modify this bookmark.' );
|
||||
return Redirect::to( 'bookmarks/index' );
|
||||
}
|
||||
self::$bookmarks->archive( $id );
|
||||
Session::flash( 'success', 'Bookmark archived.' );
|
||||
return Redirect::to( 'bookmarks/index' );
|
||||
}
|
||||
|
||||
public function showBookmark( $id = null ) {
|
||||
$bookmark = self::$bookmarks->findById( $id );
|
||||
if ( $bookmark == false ) {
|
||||
Session::flash( 'error', 'Bookmark not found.' );
|
||||
return Redirect::to( 'bookmarks/index' );
|
||||
}
|
||||
if ( $bookmark->createdBy != App::$activeUser->ID ) {
|
||||
Session::flash( 'error', 'You do not have permission to modify this bookmark.' );
|
||||
return Redirect::to( 'bookmarks/index' );
|
||||
}
|
||||
self::$bookmarks->show( $id );
|
||||
Session::flash( 'success', 'Bookmark shown.' );
|
||||
return Redirect::to( 'bookmarks/index' );
|
||||
}
|
||||
|
||||
public function unarchiveBookmark( $id = null ) {
|
||||
$bookmark = self::$bookmarks->findById( $id );
|
||||
if ( $bookmark == false ) {
|
||||
Session::flash( 'error', 'Bookmark not found.' );
|
||||
return Redirect::to( 'bookmarks/index' );
|
||||
}
|
||||
if ( $bookmark->createdBy != App::$activeUser->ID ) {
|
||||
Session::flash( 'error', 'You do not have permission to modify this bookmark.' );
|
||||
return Redirect::to( 'bookmarks/index' );
|
||||
}
|
||||
self::$bookmarks->unarchive( $id );
|
||||
Session::flash( 'success', 'Bookmark un-archived.' );
|
||||
return Redirect::to( 'bookmarks/index' );
|
||||
}
|
||||
|
||||
public function refreshBookmark( $id = null ) {
|
||||
$bookmark = self::$bookmarks->findById( $id );
|
||||
if ( $bookmark == false ) {
|
||||
Session::flash( 'error', 'Bookmark not found.' );
|
||||
return Redirect::to( 'bookmarks/index' );
|
||||
}
|
||||
if ( $bookmark->createdBy != App::$activeUser->ID ) {
|
||||
Session::flash( 'error', 'You do not have permission to modify this bookmark.' );
|
||||
return Redirect::to( 'bookmarks/index' );
|
||||
}
|
||||
$info = self::$bookmarks->refreshInfo( $id );
|
||||
if ( false == $info ) {
|
||||
Session::flash( 'error', 'Issue refreshing your bookmark.' );
|
||||
return Redirect::to( 'bookmarks/bookmark/' . $bookmark->ID );
|
||||
}
|
||||
Session::flash( 'success', 'Bookmark data refreshed.' );
|
||||
return Redirect::to( 'bookmarks/bookmark/' . $bookmark->ID );
|
||||
}
|
||||
}
|
@ -1,122 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* app/plugins/bookmarks/forms.php
|
||||
*
|
||||
* This houses all of the form checking functions for this plugin.
|
||||
*
|
||||
* @package TP Bookmarks
|
||||
* @version 3.0
|
||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||
* @link https://TheTempusProject.com
|
||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||
*/
|
||||
namespace TheTempusProject\Plugins\Bookmarks;
|
||||
|
||||
use TheTempusProject\Bedrock\Functions\Input;
|
||||
use TheTempusProject\Bedrock\Functions\Check;
|
||||
use TheTempusProject\Classes\Forms;
|
||||
|
||||
class BookmarksForms extends Forms {
|
||||
/**
|
||||
* Adds these functions to the form list.
|
||||
*/
|
||||
public function __construct() {
|
||||
self::addHandler( 'createBookmark', __CLASS__, 'createBookmark' );
|
||||
self::addHandler( 'createFolder', __CLASS__, 'createFolder' );
|
||||
self::addHandler( 'editBookmark', __CLASS__, 'editBookmark' );
|
||||
self::addHandler( 'editFolder', __CLASS__, 'editFolder' );
|
||||
}
|
||||
|
||||
public static function createBookmark() {
|
||||
// if ( ! Input::exists( 'title' ) ) {
|
||||
// Check::addUserError( 'You must include a title.' );
|
||||
// return false;
|
||||
// }
|
||||
if ( ! Input::exists( 'url' ) ) {
|
||||
Check::addUserError( 'You must include a url.' );
|
||||
return false;
|
||||
}
|
||||
// if ( ! Input::exists( 'color' ) ) {
|
||||
// Check::addUserError( 'You must include a color.' );
|
||||
// return false;
|
||||
// }
|
||||
// if ( ! Input::exists( 'privacy' ) ) {
|
||||
// Check::addUserError( 'You must include a privacy.' );
|
||||
// return false;
|
||||
// }
|
||||
// if ( !self::token() ) {
|
||||
// Check::addUserError( 'token - comment out later.' );
|
||||
// return false;
|
||||
// }
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function createFolder() {
|
||||
if ( ! Input::exists( 'title' ) ) {
|
||||
Check::addUserError( 'You must include a title.' );
|
||||
return false;
|
||||
}
|
||||
// if ( ! Input::exists( 'color' ) ) {
|
||||
// Check::addUserError( 'You must include a color.' );
|
||||
// return false;
|
||||
// }
|
||||
// if ( ! Input::exists( 'privacy' ) ) {
|
||||
// Check::addUserError( 'You must include a privacy.' );
|
||||
// return false;
|
||||
// }
|
||||
// if ( ! self::token() ) {
|
||||
// Check::addUserError( 'token - comment out later.' );
|
||||
// return false;
|
||||
// }
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function editBookmark() {
|
||||
// if ( ! Input::exists( 'title' ) ) {
|
||||
// Check::addUserError( 'You must include a title.' );
|
||||
// return false;
|
||||
// }
|
||||
if ( ! Input::exists( 'url' ) ) {
|
||||
Check::addUserError( 'You must include a url.' );
|
||||
return false;
|
||||
}
|
||||
// if ( ! Input::exists( 'color' ) ) {
|
||||
// Check::addUserError( 'You must include a color.' );
|
||||
// return false;
|
||||
// }
|
||||
// if ( ! Input::exists( 'privacy' ) ) {
|
||||
// Check::addUserError( 'You must include a privacy.' );
|
||||
// return false;
|
||||
// }
|
||||
// if ( !self::token() ) {
|
||||
// Check::addUserError( 'token - comment out later.' );
|
||||
// return false;
|
||||
// }
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function editFolder() {
|
||||
if ( ! Input::exists( 'submit' ) ) {
|
||||
return false;
|
||||
}
|
||||
if ( ! Input::exists( 'title' ) ) {
|
||||
Check::addUserError( 'You must include a title.' );
|
||||
return false;
|
||||
}
|
||||
// if ( ! Input::exists( 'color' ) ) {
|
||||
// Check::addUserError( 'You must include a color.' );
|
||||
// return false;
|
||||
// }
|
||||
// if ( ! Input::exists( 'privacy' ) ) {
|
||||
// Check::addUserError( 'You must include a privacy.' );
|
||||
// return false;
|
||||
// }
|
||||
// if ( !self::token() ) {
|
||||
// Check::addUserError( 'token - comment out later.' );
|
||||
// return false;
|
||||
// }
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
new BookmarksForms;
|
@ -1,705 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* app/plugins/bookmarks/models/bookmarks.php
|
||||
*
|
||||
* This class is used for the manipulation of the bookmarks database table.
|
||||
*
|
||||
* @package TP Bookmarks
|
||||
* @version 3.0
|
||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||
* @link https://TheTempusProject.com
|
||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||
*/
|
||||
namespace TheTempusProject\Models;
|
||||
|
||||
use TheTempusProject\Bedrock\Classes\Config;
|
||||
use TheTempusProject\Bedrock\Functions\Check;
|
||||
use TheTempusProject\Canary\Bin\Canary as Debug;
|
||||
use TheTempusProject\Classes\DatabaseModel;
|
||||
use TheTempusProject\TheTempusProject as App;
|
||||
use TheTempusProject\Houdini\Classes\Filters;
|
||||
use TheTempusProject\Bedrock\Classes\CustomException;
|
||||
|
||||
class Bookmarks extends DatabaseModel {
|
||||
public $tableName = 'bookmarks';
|
||||
public $linkTypes = [
|
||||
'Open in New Tab' => 'external',
|
||||
'Open in Same Tab' => 'internal',
|
||||
];
|
||||
|
||||
public $databaseMatrix = [
|
||||
[ 'title', 'varchar', '256' ],
|
||||
[ 'url', 'text', '' ],
|
||||
[ 'color', 'varchar', '48' ],
|
||||
[ 'privacy', 'varchar', '48' ],
|
||||
[ 'folderID', 'int', '11' ],
|
||||
[ 'description', 'text', '' ],
|
||||
[ 'createdBy', 'int', '11' ],
|
||||
[ 'createdAt', 'int', '11' ],
|
||||
[ 'meta', 'text', '' ],
|
||||
[ 'icon', 'text', '' ],
|
||||
[ 'archivedAt', 'int', '11' ],
|
||||
[ 'refreshedAt', 'int', '11' ],
|
||||
[ 'hiddenAt', 'int', '11' ],
|
||||
[ 'order', 'int', '11' ],
|
||||
[ 'linkType', 'varchar', '32' ],
|
||||
];
|
||||
|
||||
/**
|
||||
* The model constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
public function create( $title, $url, $folderID = 0, $description = '', $color = 'default', $privacy = 'private', $type = 'external' ) {
|
||||
$fields = [
|
||||
'title' => $title,
|
||||
'url' => $url,
|
||||
'description' => $description,
|
||||
'color' => $color,
|
||||
'privacy' => $privacy,
|
||||
'createdBy' => App::$activeUser->ID,
|
||||
'createdAt' => time(),
|
||||
];
|
||||
if ( !empty( $folderID ) ) {
|
||||
$fields['folderID'] = $folderID;
|
||||
} else {
|
||||
$fields['folderID'] = null;
|
||||
}
|
||||
if ( ! self::$db->insert( $this->tableName, $fields ) ) {
|
||||
new CustomException( 'bookmarkCreate' );
|
||||
Debug::error( "Bookmarks: not created " . var_export($fields,true) );
|
||||
return false;
|
||||
}
|
||||
return self::$db->lastId();
|
||||
}
|
||||
|
||||
public function update( $id, $title, $url, $folderID = 0, $description = '', $color = 'default', $privacy = 'private', $type = 'external', $order = 0 ) {
|
||||
if ( !Check::id( $id ) ) {
|
||||
Debug::info( 'Bookmarks: illegal ID.' );
|
||||
return false;
|
||||
}
|
||||
$fields = [
|
||||
'title' => $title,
|
||||
'url' => $url,
|
||||
'description' => $description,
|
||||
'color' => $color,
|
||||
'privacy' => $privacy,
|
||||
// 'linkType' => $type,
|
||||
// 'order' => $order,
|
||||
];
|
||||
if ( !empty( $folderID ) ) {
|
||||
$fields['folderID'] = $folderID;
|
||||
}
|
||||
if ( !self::$db->update( $this->tableName, $id, $fields ) ) {
|
||||
new CustomException( 'bookmarkUpdate' );
|
||||
Debug::error( "Bookmarks: $id not updated" );
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function byUser( $limit = null ) {
|
||||
$whereClause = ['createdBy', '=', App::$activeUser->ID];
|
||||
if ( empty( $limit ) ) {
|
||||
$bookmarks = self::$db->get( $this->tableName, $whereClause );
|
||||
} else {
|
||||
$bookmarks = self::$db->get( $this->tableName, $whereClause, 'ID', 'DESC', [0, $limit] );
|
||||
}
|
||||
if ( !$bookmarks->count() ) {
|
||||
Debug::info( 'No Bookmarks found.' );
|
||||
return false;
|
||||
}
|
||||
return $this->filter( $bookmarks->results() );
|
||||
}
|
||||
|
||||
public function byFolder( $id, $limit = null ) {
|
||||
$whereClause = ['createdBy', '=', App::$activeUser->ID, 'AND'];
|
||||
|
||||
$whereClause = array_merge( $whereClause, [ 'folderID', '=', $id ] );
|
||||
if ( empty( $limit ) ) {
|
||||
$bookmarks = self::$db->get( $this->tableName, $whereClause );
|
||||
} else {
|
||||
$bookmarks = self::$db->get( $this->tableName, $whereClause, 'ID', 'DESC', [0, $limit] );
|
||||
}
|
||||
if ( !$bookmarks->count() ) {
|
||||
Debug::info( 'No Bookmarks found.' );
|
||||
return false;
|
||||
}
|
||||
return $this->filter( $bookmarks->results() );
|
||||
}
|
||||
|
||||
public function noFolder( $id = 0, $limit = 10 ) {
|
||||
$whereClause = ['createdBy', '=', App::$activeUser->ID, 'AND'];
|
||||
if ( !empty( $id ) ) {
|
||||
$whereClause = array_merge( $whereClause, ['folderID', '!=', $id] );
|
||||
} else {
|
||||
$whereClause = array_merge( $whereClause, [ 'folderID', 'IS', null] );
|
||||
}
|
||||
if ( empty( $limit ) ) {
|
||||
$bookmarks = self::$db->get( $this->tableName, $whereClause );
|
||||
} else {
|
||||
$bookmarks = self::$db->get( $this->tableName, $whereClause, 'ID', 'DESC', [ 0, $limit ] );
|
||||
}
|
||||
if ( !$bookmarks->count() ) {
|
||||
Debug::info( 'No Bookmarks found.' );
|
||||
return false;
|
||||
}
|
||||
return $this->filter( $bookmarks->results() );
|
||||
}
|
||||
|
||||
public function getName( $id ) {
|
||||
$bookmarks = self::findById( $id );
|
||||
if (false == $bookmarks) {
|
||||
return 'unknown';
|
||||
}
|
||||
return $bookmarks->title;
|
||||
}
|
||||
|
||||
public function getColor( $id ) {
|
||||
$bookmarks = self::findById( $id );
|
||||
if (false == $bookmarks) {
|
||||
return 'default';
|
||||
}
|
||||
return $bookmarks->color;
|
||||
}
|
||||
|
||||
public function simpleByUser() {
|
||||
$whereClause = ['createdBy', '=', App::$activeUser->ID];
|
||||
$bookmarks = self::$db->get( $this->tableName, $whereClause );
|
||||
if ( !$bookmarks->count() ) {
|
||||
Debug::warn( 'Could not find any bookmarks' );
|
||||
return false;
|
||||
}
|
||||
|
||||
$bookmarks = $bookmarks->results();
|
||||
$out = [];
|
||||
foreach ( $bookmarks as $bookmarks ) {
|
||||
$out[ $bookmarks->title ] = $bookmarks->ID;
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
|
||||
public function simpleObjectByUser() {
|
||||
$whereClause = ['createdBy', '=', App::$activeUser->ID];
|
||||
$bookmarks = self::$db->get( $this->tableName, $whereClause );
|
||||
if ( !$bookmarks->count() ) {
|
||||
Debug::warn( 'Could not find any bookmarks' );
|
||||
return false;
|
||||
}
|
||||
|
||||
$bookmarks = $bookmarks->results();
|
||||
$out = [];
|
||||
foreach ( $bookmarks as $bookmarks ) {
|
||||
$obj = new \stdClass();
|
||||
$obj->title = $bookmarks->title;
|
||||
$obj->ID = $bookmarks->ID;
|
||||
$out[] = $obj;
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
|
||||
public function deleteByFolder( $folderID ) {
|
||||
$whereClause = [ 'createdBy', '=', App::$activeUser->ID, 'AND' ];
|
||||
$whereClause = array_merge( $whereClause, [ 'folderID', '=', $folderID ] );
|
||||
$bookmarks = self::$db->get( $this->tableName, $whereClause );
|
||||
if ( ! $bookmarks->count() ) {
|
||||
Debug::info( 'No ' . $this->tableName . ' data found.' );
|
||||
return [];
|
||||
}
|
||||
foreach( $bookmarks->results() as $bookmark ) {
|
||||
$this->delete( $bookmark->ID );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private function resolveShortenedUrl( $url ) {
|
||||
$ch = curl_init($url);
|
||||
|
||||
// Set curl options
|
||||
curl_setopt($ch, CURLOPT_NOBODY, true); // We don't need the body
|
||||
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); // Follow redirects
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // Return the response
|
||||
curl_setopt($ch, CURLOPT_TIMEOUT, 30); // Set a timeout
|
||||
// curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10); // Maybe sketchy?
|
||||
// Maybe sketchy?
|
||||
// curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); // Disable SSL host verification
|
||||
// curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // Disable SSL peer verification
|
||||
// curl_setopt($ch, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2);
|
||||
|
||||
// added to support the regex site
|
||||
// curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
|
||||
|
||||
// =
|
||||
// curl_setopt($ch, CURLOPT_SSL_CIPHER_LIST, 'AES256+EECDH:AES256+EDH' );
|
||||
|
||||
|
||||
|
||||
|
||||
// Execute curl
|
||||
$response = curl_exec( $ch );
|
||||
|
||||
// Check if there was an error
|
||||
if ( curl_errno( $ch ) ) {
|
||||
|
||||
|
||||
// Get error details
|
||||
$errorCode = curl_errno($ch);
|
||||
$errorMessage = curl_error($ch);
|
||||
// Log or display the error details
|
||||
dv('cURL Error: ' . $errorMessage . ' (Error Code: ' . $errorCode . ')');
|
||||
|
||||
curl_close($ch);
|
||||
// return $url; // Return the original URL if there was an error
|
||||
|
||||
|
||||
$url = rtrim( $url, '/' );
|
||||
$ch2 = curl_init($url);
|
||||
curl_setopt($ch2, CURLOPT_NOBODY, true); // We don't need the body
|
||||
curl_setopt($ch2, CURLOPT_FOLLOWLOCATION, true); // Follow redirects
|
||||
curl_setopt($ch2, CURLOPT_RETURNTRANSFER, true); // Return the response
|
||||
curl_setopt($ch2, CURLOPT_TIMEOUT, 5); // Set a timeout
|
||||
curl_exec($ch2);
|
||||
|
||||
if ( curl_errno( $ch2 ) ) {
|
||||
|
||||
}
|
||||
curl_close( $ch );
|
||||
return $url;
|
||||
}
|
||||
|
||||
// Get the effective URL (the final destination after redirects)
|
||||
$finalUrl = curl_getinfo( $ch, CURLINFO_EFFECTIVE_URL );
|
||||
curl_close( $ch );
|
||||
|
||||
return $finalUrl;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// $headers = get_headers( $url, 1 );
|
||||
$headers = @get_headers($url, 1);
|
||||
if ( $headers === false ) {
|
||||
}
|
||||
if ( isset( $headers['Location'] ) ) {
|
||||
if (is_array($headers['Location'])) {
|
||||
return end($headers['Location']);
|
||||
} else {
|
||||
return $headers['Location'];
|
||||
}
|
||||
} else {
|
||||
return $url;
|
||||
}
|
||||
}
|
||||
|
||||
public function filter( $data, $params = [] ) {
|
||||
foreach ( $data as $instance ) {
|
||||
if ( !is_object( $instance ) ) {
|
||||
$instance = $data;
|
||||
$end = true;
|
||||
}
|
||||
$base_url = $this->getBaseUrl( $instance->url );
|
||||
|
||||
if ( empty( $instance->icon ) ) {
|
||||
$instance->iconHtml = '<i class="glyphicon glyphicon-link"></i>';
|
||||
} else {
|
||||
if (strpos($instance->icon, 'http') !== false) {
|
||||
$instance->iconHtml = '<img src="' . $instance->icon .'" />';
|
||||
} else {
|
||||
$instance->iconHtml = '<img src="' . $base_url . ltrim( $instance->icon, '/' ) .'" />';
|
||||
}
|
||||
}
|
||||
if ( empty( $instance->hiddenAt ) ) {
|
||||
$instance->hideBtn = '
|
||||
<a href="{ROOT_URL}bookmarks/hideBookmark/'.$instance->ID.'" class="btn btn-sm btn-warning" role="button">
|
||||
<i class="glyphicon glyphicon-eye-open"></i>
|
||||
</a>';
|
||||
} else {
|
||||
$instance->hideBtn = '
|
||||
<a href="{ROOT_URL}bookmarks/showBookmark/'.$instance->ID.'" class="btn btn-sm btn-default" role="button">
|
||||
<i class="glyphicon glyphicon-eye-open"></i>
|
||||
</a>';
|
||||
}
|
||||
if ( empty( $instance->archivedAt ) ) {
|
||||
$instance->archiveBtn = '
|
||||
<a href="{ROOT_URL}bookmarks/archiveBookmark/'.$instance->ID.'" class="btn btn-sm btn-info" role="button">
|
||||
<i class="glyphicon glyphicon-briefcase"></i>
|
||||
</a>';
|
||||
} else {
|
||||
$instance->archiveBtn = '
|
||||
<a href="{ROOT_URL}bookmarks/unarchiveBookmark/'.$instance->ID.'" class="btn btn-sm btn-default" role="button">
|
||||
<i class="glyphicon glyphicon-briefcase"></i>
|
||||
</a>';
|
||||
}
|
||||
if ( ! empty( $instance->refreshedAt ) && time() < ( $instance->refreshedAt + ( 60 * 10 ) ) ) {
|
||||
$instance->refreshBtn = '
|
||||
<a href="{ROOT_URL}bookmarks/refreshBookmark/'.$instance->ID.'" class="btn btn-sm btn-danger" role="button">
|
||||
<i class="glyphicon glyphicon-refresh"></i>
|
||||
</a>';
|
||||
} else {
|
||||
$instance->refreshBtn = '
|
||||
<a href="{ROOT_URL}bookmarks/refreshBookmark/'.$instance->ID.'" class="btn btn-sm btn-success" role="button">
|
||||
<i class="glyphicon glyphicon-refresh"></i>
|
||||
</a>';
|
||||
}
|
||||
|
||||
$out[] = $instance;
|
||||
if ( !empty( $end ) ) {
|
||||
$out = $out[0];
|
||||
break;
|
||||
}
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
|
||||
public function hide( $id ) {
|
||||
if ( !Check::id( $id ) ) {
|
||||
Debug::info( 'Bookmarks: illegal ID.' );
|
||||
return false;
|
||||
}
|
||||
$fields = [
|
||||
'hiddenAt' => time(),
|
||||
];
|
||||
if ( !self::$db->update( $this->tableName, $id, $fields ) ) {
|
||||
new CustomException( 'bookmarkUpdate' );
|
||||
Debug::error( "Bookmarks: $id not updated" );
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function show( $id ) {
|
||||
if ( !Check::id( $id ) ) {
|
||||
Debug::info( 'Bookmarks: illegal ID.' );
|
||||
return false;
|
||||
}
|
||||
$fields = [
|
||||
'hiddenAt' => 0,
|
||||
];
|
||||
if ( !self::$db->update( $this->tableName, $id, $fields ) ) {
|
||||
new CustomException( 'bookmarkUpdate' );
|
||||
Debug::error( "Bookmarks: $id not updated" );
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function archive( $id ) {
|
||||
if ( !Check::id( $id ) ) {
|
||||
Debug::info( 'Bookmarks: illegal ID.' );
|
||||
return false;
|
||||
}
|
||||
$fields = [
|
||||
'archivedAt' => time(),
|
||||
];
|
||||
if ( !self::$db->update( $this->tableName, $id, $fields ) ) {
|
||||
new CustomException( 'bookmarkUpdate' );
|
||||
Debug::error( "Bookmarks: $id not updated" );
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function unarchive( $id ) {
|
||||
if ( !Check::id( $id ) ) {
|
||||
Debug::info( 'Bookmarks: illegal ID.' );
|
||||
return false;
|
||||
}
|
||||
$fields = [
|
||||
'archivedAt' => 0,
|
||||
];
|
||||
if ( !self::$db->update( $this->tableName, $id, $fields ) ) {
|
||||
new CustomException( 'bookmarkUpdate' );
|
||||
Debug::error( "Bookmarks: $id not updated" );
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function extractMetaTags($htmlContent) {
|
||||
$doc = new \DOMDocument();
|
||||
@$doc->loadHTML($htmlContent);
|
||||
$metaTags = [];
|
||||
foreach ($doc->getElementsByTagName('meta') as $meta) {
|
||||
$name = $meta->getAttribute('name') ?: $meta->getAttribute('property');
|
||||
$content = $meta->getAttribute('content');
|
||||
if ($name && $content) {
|
||||
$metaTags[$name] = $content;
|
||||
}
|
||||
}
|
||||
return $metaTags;
|
||||
}
|
||||
|
||||
public function fetchUrlData($url) {
|
||||
$ch = curl_init();
|
||||
|
||||
// Set cURL options
|
||||
curl_setopt($ch, CURLOPT_URL, $url);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_HEADER, true); // Include headers in the output
|
||||
curl_setopt($ch, CURLOPT_NOBODY, false); // Include the body in the output
|
||||
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); // Follow redirects
|
||||
curl_setopt($ch, CURLOPT_TIMEOUT, 30); // Set a timeout
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); // Disable SSL host verification for testing
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // Disable SSL peer verification for testing
|
||||
|
||||
// Execute cURL request
|
||||
$response = curl_exec($ch);
|
||||
|
||||
// Check if there was an error
|
||||
if (curl_errno($ch)) {
|
||||
$errorMessage = curl_error($ch);
|
||||
curl_close($ch);
|
||||
throw new \Exception('cURL Error: ' . $errorMessage);
|
||||
}
|
||||
|
||||
// Get HTTP status code
|
||||
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
|
||||
// Separate headers and body
|
||||
$headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
|
||||
$headers = substr($response, 0, $headerSize);
|
||||
$body = substr($response, $headerSize);
|
||||
|
||||
curl_close($ch);
|
||||
|
||||
// Parse headers into an associative array
|
||||
$headerLines = explode("\r\n", trim($headers));
|
||||
$headerArray = [];
|
||||
foreach ($headerLines as $line) {
|
||||
$parts = explode(': ', $line, 2);
|
||||
if (count($parts) == 2) {
|
||||
$headerArray[$parts[0]] = $parts[1];
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
'http_code' => $httpCode,
|
||||
'headers' => $headerArray,
|
||||
'body' => $body,
|
||||
];
|
||||
}
|
||||
|
||||
private function getMetaTagsAndFavicon( $url ) {
|
||||
try {
|
||||
// $url = 'https://runescape.wiki';
|
||||
$data = $this->fetchUrlData($url);
|
||||
|
||||
// iv($data);
|
||||
|
||||
// Get headers
|
||||
$headers = $data['headers'];
|
||||
iv($headers);
|
||||
|
||||
// Get meta tags
|
||||
$metaTags = $this->extractMetaTags($data['body']);
|
||||
} catch (Exception $e) {
|
||||
dv( 'Error: ' . $e->getMessage());
|
||||
|
||||
}
|
||||
$metaInfo = [
|
||||
'url' => $url,
|
||||
'title' => null,
|
||||
'description' => null,
|
||||
'image' => null,
|
||||
'favicon' => null
|
||||
];
|
||||
$ch = curl_init($url);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
$html = curl_exec($ch);
|
||||
curl_close($ch);
|
||||
|
||||
if ($html === false) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$meta = @get_meta_tags( $url );
|
||||
|
||||
$dom = new \DOMDocument('1.0', 'utf-8');
|
||||
$dom->strictErrorChecking = false;
|
||||
$dom->loadHTML($html, LIBXML_NOERROR);
|
||||
$xml = simplexml_import_dom($dom);
|
||||
$arr = $xml->xpath('//link[@rel="shortcut icon"]');
|
||||
|
||||
// Get the title of the page
|
||||
$titles = $dom->getElementsByTagName('title');
|
||||
if ($titles->length > 0) {
|
||||
$metaInfo['title'] = $titles->item(0)->nodeValue;
|
||||
}
|
||||
|
||||
// Get the meta tags
|
||||
$metaTags = $dom->getElementsByTagName('meta');
|
||||
$metadata = [];
|
||||
foreach ($metaTags as $meta) {
|
||||
$metadata[] = [
|
||||
'name' => $meta->getAttribute('name'),
|
||||
'property' => $meta->getAttribute('property'),
|
||||
'content' => $meta->getAttribute('content')
|
||||
];
|
||||
if ($meta->getAttribute('name') === 'description') {
|
||||
$metaInfo['description'] = $meta->getAttribute('content');
|
||||
}
|
||||
if ($meta->getAttribute('itemprop') === 'image') {
|
||||
$metaInfo['google_image'] = $meta->getAttribute('content');
|
||||
}
|
||||
if ($meta->getAttribute('property') === 'og:image') {
|
||||
$metaInfo['image'] = $meta->getAttribute('content');
|
||||
}
|
||||
}
|
||||
|
||||
// Get the link tags to find the favicon
|
||||
$linkTags = $dom->getElementsByTagName('link');
|
||||
$metadata['links'] = [];
|
||||
foreach ($linkTags as $link) {
|
||||
$metadata['links'][] = [ $link->getAttribute('rel') => $link->getAttribute('href') ];
|
||||
if ( $link->getAttribute('rel') === 'icon' || $link->getAttribute('rel') === 'shortcut icon') {
|
||||
$metaInfo['favicon'] = $link->getAttribute('href');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$metaInfo['metadata'] = $metadata;
|
||||
|
||||
return $metaInfo;
|
||||
}
|
||||
|
||||
public function retrieveInfo( $url ) {
|
||||
$finalDestination = $this->resolveShortenedUrl( $url );
|
||||
$info = $this->getMetaTagsAndFavicon( $finalDestination );
|
||||
$base_url = $this->getBaseUrl( $finalDestination );
|
||||
|
||||
if ( ! empty( $info['favicon'] ) ) {
|
||||
echo 'favicon exists' . PHP_EOL;
|
||||
if ( stripos( $info['favicon'], 'http' ) !== false) {
|
||||
echo 'favicon is full url' . PHP_EOL;
|
||||
$imageUrl = $info['favicon'];
|
||||
} else {
|
||||
echo 'favicon is not full url' . PHP_EOL;
|
||||
$imageUrl = trim( $base_url, '/' ) . '/' . ltrim( $info['favicon'], '/' );
|
||||
}
|
||||
if ( $this->isValidImageUrl( $imageUrl ) ) {
|
||||
echo 'image is valid' . PHP_EOL;
|
||||
$info['favicon'] = $imageUrl;
|
||||
} else {
|
||||
echo 'image is not valid' . PHP_EOL;
|
||||
$base_info = $this->getMetaTagsAndFavicon( $base_url );
|
||||
if ( ! empty( $base_info['favicon'] ) ) {
|
||||
echo 'parent favicon exists!';
|
||||
if ( stripos( $base_info['favicon'], 'http' ) !== false) {
|
||||
echo 'parent favicon is full url' . PHP_EOL;
|
||||
$imageUrl = $base_info['favicon'];
|
||||
} else {
|
||||
echo 'parent favicon is not full url' . PHP_EOL;
|
||||
$imageUrl = trim( $base_url, '/' ) . '/' . ltrim( $base_info['favicon'], '/' );
|
||||
}
|
||||
if ( $this->isValidImageUrl( $imageUrl ) ) {
|
||||
echo 'parent favicon image is valid' . PHP_EOL;
|
||||
$info['favicon'] = $imageUrl;
|
||||
} else {
|
||||
echo 'parent favicon image is not valid' . PHP_EOL;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
echo 'favicon does not exist' . PHP_EOL;
|
||||
$base_info = $this->getMetaTagsAndFavicon( $base_url );
|
||||
if ( ! empty( $base_info['favicon'] ) ) {
|
||||
echo 'parent favicon exists!' . PHP_EOL;
|
||||
if ( stripos( $base_info['favicon'], 'http' ) !== false) {
|
||||
echo 'parent favicon is full url' . PHP_EOL;
|
||||
$imageUrl = $base_info['favicon'];
|
||||
} else {
|
||||
echo 'parent favicon is not full url' . PHP_EOL;
|
||||
$imageUrl = trim( $base_url, '/' ) . '/' . ltrim( $base_info['favicon'], '/' );
|
||||
}
|
||||
if ( $this->isValidImageUrl( $imageUrl ) ) {
|
||||
echo 'parent favicon image is valid' . PHP_EOL;
|
||||
$info['favicon'] = $imageUrl;
|
||||
} else {
|
||||
echo 'parent favicon image is not valid' . PHP_EOL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $info;
|
||||
}
|
||||
|
||||
public function refreshInfo( $id ) {
|
||||
if ( !Check::id( $id ) ) {
|
||||
Debug::info( 'Bookmarks: illegal ID.' );
|
||||
return false;
|
||||
}
|
||||
$bookmark = self::findById( $id );
|
||||
if ( $bookmark == false ) {
|
||||
Debug::info( 'Bookmarks not found.' );
|
||||
return false;
|
||||
}
|
||||
if ( $bookmark->createdBy != App::$activeUser->ID ) {
|
||||
Debug::info( 'You do not have permission to modify this bookmark.' );
|
||||
return false;
|
||||
}
|
||||
if ( time() < ( $bookmark->refreshedAt + ( 60 * 10 ) ) ) {
|
||||
Debug::info( 'You may only fetch bookmarks once every 10 minutes.' );
|
||||
return false;
|
||||
}
|
||||
|
||||
$info = $this->retrieveInfo( $bookmark->url );
|
||||
|
||||
$fields = [
|
||||
// 'refreshedAt' => time(),
|
||||
];
|
||||
|
||||
if ( empty( $bookmark->title ) && ! empty( $info['title'] ) ) {
|
||||
$fields['title'] = $info['title'];
|
||||
}
|
||||
if ( empty( $bookmark->description ) && ! empty( $info['description'] ) ) {
|
||||
$fields['description'] = $info['description'];
|
||||
}
|
||||
|
||||
if ( ( empty( $bookmark->icon ) || ! $this->isValidImageUrl( $bookmark->icon ) ) && ! empty( $info['favicon'] ) ) {
|
||||
$fields['icon'] = $info['favicon'];
|
||||
}
|
||||
$fields['meta'] = json_encode( $info['metadata'] );
|
||||
|
||||
if ( !self::$db->update( $this->tableName, $id, $fields ) ) {
|
||||
new CustomException( 'bookmarkUpdate' );
|
||||
Debug::error( "Bookmarks: $id not updated" );
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private function getBaseUrl ($url ) {
|
||||
$parsedUrl = parse_url($url);
|
||||
|
||||
if (isset($parsedUrl['scheme']) && isset($parsedUrl['host'])) {
|
||||
return $parsedUrl['scheme'] . '://' . $parsedUrl['host'] . '/';
|
||||
} else {
|
||||
return null; // URL is not valid or cannot be parsed
|
||||
}
|
||||
}
|
||||
|
||||
function isValidImageUrl($url) {
|
||||
$headers = @get_headers($url);
|
||||
if ($headers && strpos($headers[0], '200') !== false) {
|
||||
|
||||
return true;
|
||||
// Further check to ensure it's an image
|
||||
foreach ($headers as $header) {
|
||||
if (strpos(strtolower($header), 'content-type:') !== false) {
|
||||
if (strpos(strtolower($header), 'image/') !== false) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
@ -1,149 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* app/plugins/bookmarks/models/bookmarkViews.php
|
||||
*
|
||||
* This class is used for the manipulation of the bookmark_views database table.
|
||||
*
|
||||
* @package TP Bookmarks
|
||||
* @version 3.0
|
||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||
* @link https://TheTempusProject.com
|
||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||
*/
|
||||
namespace TheTempusProject\Models;
|
||||
|
||||
use TheTempusProject\Bedrock\Classes\Config;
|
||||
use TheTempusProject\Bedrock\Functions\Check;
|
||||
use TheTempusProject\Canary\Bin\Canary as Debug;
|
||||
use TheTempusProject\Classes\DatabaseModel;
|
||||
use TheTempusProject\TheTempusProject as App;
|
||||
use TheTempusProject\Houdini\Classes\Filters;
|
||||
use TheTempusProject\Bedrock\Classes\CustomException;
|
||||
|
||||
class Bookmarkviews extends DatabaseModel {
|
||||
public $tableName = 'bookmark_views';
|
||||
public $databaseMatrix = [
|
||||
[ 'title', 'varchar', '256' ],
|
||||
[ 'description', 'text', '' ],
|
||||
[ 'privacy', 'varchar', '48' ],
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
[ 'createdBy', 'int', '11' ],
|
||||
[ 'createdAt', 'int', '11' ],
|
||||
[ 'updatedAt', 'int', '11' ],
|
||||
];
|
||||
|
||||
/**
|
||||
* The model constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
public function create( $title, $description = '', $privacy = 'private' ) {
|
||||
if ( ! Check::dataTitle( $title ) ) {
|
||||
Debug::info( 'Views: illegal title.' );
|
||||
return false;
|
||||
}
|
||||
$fields = [
|
||||
'title' => $title,
|
||||
'description' => $description,
|
||||
'privacy' => $privacy,
|
||||
'createdBy' => App::$activeUser->ID,
|
||||
'createdAt' => time(),
|
||||
];
|
||||
if ( ! self::$db->insert( $this->tableName, $fields ) ) {
|
||||
new CustomException( 'viewCreate' );
|
||||
Debug::error( "Views: not created " . var_export($fields,true) );
|
||||
return false;
|
||||
}
|
||||
return self::$db->lastId();
|
||||
}
|
||||
|
||||
public function update( $id, $title, $description = '', $privacy = 'private' ) {
|
||||
if ( !Check::id( $id ) ) {
|
||||
Debug::info( 'Views: illegal ID.' );
|
||||
return false;
|
||||
}
|
||||
if ( !Check::dataTitle( $title ) ) {
|
||||
Debug::info( 'Views: illegal title.' );
|
||||
return false;
|
||||
}
|
||||
$fields = [
|
||||
'title' => $title,
|
||||
'description' => $description,
|
||||
'privacy' => $privacy,
|
||||
];
|
||||
if ( !self::$db->update( $this->tableName, $id, $fields ) ) {
|
||||
new CustomException( 'viewUpdate' );
|
||||
Debug::error( "Views: $id not updated: $fields" );
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function byUser( $limit = null ) {
|
||||
$whereClause = ['createdBy', '=', App::$activeUser->ID];
|
||||
if ( empty( $limit ) ) {
|
||||
$views = self::$db->get( $this->tableName, $whereClause );
|
||||
} else {
|
||||
$views = self::$db->get( $this->tableName, $whereClause, 'ID', 'DESC', [0, $limit] );
|
||||
}
|
||||
if ( !$views->count() ) {
|
||||
Debug::info( 'No Views found.' );
|
||||
return false;
|
||||
}
|
||||
return $this->filter( $views->results() );
|
||||
}
|
||||
|
||||
public function getName( $id ) {
|
||||
$views = self::findById( $id );
|
||||
if (false == $views) {
|
||||
return 'unknown';
|
||||
}
|
||||
return $views->title;
|
||||
}
|
||||
|
||||
public function simpleByUser() {
|
||||
$whereClause = ['createdBy', '=', App::$activeUser->ID];
|
||||
$views = self::$db->get( $this->tableName, $whereClause );
|
||||
if ( !$views->count() ) {
|
||||
Debug::warn( 'Could not find any Views' );
|
||||
return false;
|
||||
}
|
||||
|
||||
$views = $views->results();
|
||||
$out = [];
|
||||
foreach ( $views as $view ) {
|
||||
$out[ $view->title ] = $view->ID;
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
|
||||
public function simpleObjectByUser() {
|
||||
$whereClause = ['createdBy', '=', App::$activeUser->ID];
|
||||
$views = self::$db->get( $this->tableName, $whereClause );
|
||||
if ( !$views->count() ) {
|
||||
Debug::warn( 'Could not find any Views' );
|
||||
return false;
|
||||
}
|
||||
|
||||
$views = $views->results();
|
||||
$out = [];
|
||||
foreach ( $views as $view ) {
|
||||
$obj = new \stdClass();
|
||||
$obj->title = $view->title;
|
||||
$obj->ID = $view->ID;
|
||||
$out[] = $obj;
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
}
|
@ -1,157 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* app/plugins/bookmarks/models/folders.php
|
||||
*
|
||||
* This class is used for the manipulation of the folders database table.
|
||||
*
|
||||
* @package TP Bookmarks
|
||||
* @version 3.0
|
||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||
* @link https://TheTempusProject.com
|
||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||
*/
|
||||
namespace TheTempusProject\Models;
|
||||
|
||||
use TheTempusProject\Bedrock\Classes\Config;
|
||||
use TheTempusProject\Bedrock\Functions\Check;
|
||||
use TheTempusProject\Canary\Bin\Canary as Debug;
|
||||
use TheTempusProject\Classes\DatabaseModel;
|
||||
use TheTempusProject\TheTempusProject as App;
|
||||
use TheTempusProject\Houdini\Classes\Filters;
|
||||
use TheTempusProject\Bedrock\Classes\CustomException;
|
||||
|
||||
class Folders extends DatabaseModel {
|
||||
public $tableName = 'folders';
|
||||
public $databaseMatrix = [
|
||||
[ 'title', 'varchar', '256' ],
|
||||
[ 'color', 'varchar', '48' ],
|
||||
[ 'privacy', 'varchar', '48' ],
|
||||
[ 'description', 'text', '' ],
|
||||
[ 'folderID', 'int', '11' ],
|
||||
[ 'createdBy', 'int', '11' ],
|
||||
[ 'createdAt', 'int', '11' ],
|
||||
];
|
||||
|
||||
/**
|
||||
* The model constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
public function create( $title, $folderID = 0, $description = '', $color = 'default', $privacy = 'private' ) {
|
||||
if ( ! Check::dataTitle( $title ) ) {
|
||||
Debug::info( 'Folders: illegal title.' );
|
||||
return false;
|
||||
}
|
||||
$fields = [
|
||||
'title' => $title,
|
||||
'description' => $description,
|
||||
'color' => $color,
|
||||
'privacy' => $privacy,
|
||||
'createdBy' => App::$activeUser->ID,
|
||||
'createdAt' => time(),
|
||||
];
|
||||
if ( !empty( $folderID ) ) {
|
||||
$fields['folderID'] = $folderID;
|
||||
}
|
||||
if ( ! self::$db->insert( $this->tableName, $fields ) ) {
|
||||
new CustomException( 'folderCreate' );
|
||||
Debug::error( "Folders: not created " . var_export($fields,true) );
|
||||
return false;
|
||||
}
|
||||
return self::$db->lastId();
|
||||
}
|
||||
|
||||
public function update( $id, $title, $folderID = 0, $description = '', $color = 'default', $privacy = 'private' ) {
|
||||
if ( !Check::id( $id ) ) {
|
||||
Debug::info( 'Folders: illegal ID.' );
|
||||
return false;
|
||||
}
|
||||
if ( !Check::dataTitle( $title ) ) {
|
||||
Debug::info( 'Folders: illegal title.' );
|
||||
return false;
|
||||
}
|
||||
$fields = [
|
||||
'title' => $title,
|
||||
'description' => $description,
|
||||
'color' => $color,
|
||||
'privacy' => $privacy,
|
||||
];
|
||||
if ( !empty( $folderID ) ) {
|
||||
$fields['folderID'] = $folderID;
|
||||
}
|
||||
if ( !self::$db->update( $this->tableName, $id, $fields ) ) {
|
||||
new CustomException( 'folderUpdate' );
|
||||
Debug::error( "Folders: $id not updated: $fields" );
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function byUser( $limit = null ) {
|
||||
$whereClause = ['createdBy', '=', App::$activeUser->ID];
|
||||
if ( empty( $limit ) ) {
|
||||
$folders = self::$db->get( $this->tableName, $whereClause );
|
||||
} else {
|
||||
$folders = self::$db->get( $this->tableName, $whereClause, 'ID', 'DESC', [0, $limit] );
|
||||
}
|
||||
if ( !$folders->count() ) {
|
||||
Debug::info( 'No Folders found.' );
|
||||
return false;
|
||||
}
|
||||
return $this->filter( $folders->results() );
|
||||
}
|
||||
|
||||
public function getName( $id ) {
|
||||
$folder = self::findById( $id );
|
||||
if (false == $folder) {
|
||||
return 'unknown';
|
||||
}
|
||||
return $folder->title;
|
||||
}
|
||||
|
||||
public function getColor( $id ) {
|
||||
$folder = self::findById( $id );
|
||||
if (false == $folder) {
|
||||
return 'default';
|
||||
}
|
||||
return $folder->color;
|
||||
}
|
||||
|
||||
public function simpleByUser() {
|
||||
$whereClause = ['createdBy', '=', App::$activeUser->ID];
|
||||
$folders = self::$db->get( $this->tableName, $whereClause );
|
||||
if ( !$folders->count() ) {
|
||||
Debug::warn( 'Could not find any folders' );
|
||||
return false;
|
||||
}
|
||||
|
||||
$folders = $folders->results();
|
||||
$out = [];
|
||||
$out[ 'No Folder' ] = 0;
|
||||
foreach ( $folders as $folder ) {
|
||||
$out[ $folder->title ] = $folder->ID;
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
|
||||
public function simpleObjectByUser() {
|
||||
$whereClause = ['createdBy', '=', App::$activeUser->ID];
|
||||
$folders = self::$db->get( $this->tableName, $whereClause );
|
||||
if ( !$folders->count() ) {
|
||||
Debug::warn( 'Could not find any folders' );
|
||||
return false;
|
||||
}
|
||||
|
||||
$folders = $folders->results();
|
||||
$out = [];
|
||||
foreach ( $folders as $folder ) {
|
||||
$obj = new \stdClass();
|
||||
$obj->title = $folder->title;
|
||||
$obj->ID = $folder->ID;
|
||||
$out[] = $obj;
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
}
|
@ -1,50 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* app/plugins/bookmarks/plugin.php
|
||||
*
|
||||
* This houses all of the main plugin info and functionality.
|
||||
*
|
||||
* @package TP Bookmarks
|
||||
* @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 TheTempusProject\Classes\Plugin;
|
||||
use TheTempusProject\Models\Events;
|
||||
use TheTempusProject\Models\Bookmarks as Bookmark;
|
||||
use TheTempusProject\Models\Folders;
|
||||
use TheTempusProject\Houdini\Classes\Components;
|
||||
use TheTempusProject\Houdini\Classes\Template;
|
||||
|
||||
class Bookmarks extends Plugin {
|
||||
public $pluginName = 'TP Bookmarks';
|
||||
public $configName = 'bookmarks';
|
||||
public $pluginAuthor = 'JoeyK';
|
||||
public $pluginWebsite = 'https://TheTempusProject.com';
|
||||
public $modelVersion = '1.0';
|
||||
public $pluginVersion = '3.0';
|
||||
public $pluginDescription = 'A simple plugin which adds a site wide bookmark system.';
|
||||
public $permissionMatrix = [
|
||||
'useBookmarks' => [
|
||||
'pretty' => 'Can use the bookmarks feature',
|
||||
'default' => false,
|
||||
],
|
||||
];
|
||||
public $main_links = [
|
||||
[
|
||||
'text' => 'Bookmarks',
|
||||
'url' => '{ROOT_URL}bookmarks/index',
|
||||
'filter' => 'loggedin',
|
||||
],
|
||||
];
|
||||
public $configMatrix = [
|
||||
'enabled' => [
|
||||
'type' => 'radio',
|
||||
'pretty' => 'Enable Bookmarks.',
|
||||
'default' => true,
|
||||
],
|
||||
];
|
||||
}
|
@ -1,45 +0,0 @@
|
||||
<legend>Create Bookmark</legend>
|
||||
{BookmarkBreadCrumbs}
|
||||
<form action="" method="post" class="form-horizontal">
|
||||
<input type="hidden" name="token" value="{TOKEN}">
|
||||
<div class="form-group">
|
||||
<label for="title" class="col-lg-3 control-label">Title</label>
|
||||
<div class="col-lg-3">
|
||||
<input type="text" class="form-control" name="title" id="title">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="url" class="col-lg-3 control-label">URL:</label>
|
||||
<div class="col-lg-3">
|
||||
<input type="text" class="form-control" name="url" id="url">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="description" class="col-lg-3 control-label">Description:</label>
|
||||
<div class="col-lg-3">
|
||||
<textarea class="form-control" name="description" maxlength="2000" rows="10" cols="50" id="description"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
{folderSelect}
|
||||
<div class="form-group">
|
||||
<label for="privacy" class="col-lg-3 control-label">Privacy</label>
|
||||
<div class="col-lg-3 select-container" id="colorContainer">
|
||||
<select id="privacy" name="privacy" class="form-control custom-select">
|
||||
<option value="private">Private</option>
|
||||
<option value="public">Public</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="color" class="col-lg-3 control-label">Color</label>
|
||||
<div class="col-lg-3 select-container" id="colorContainer">
|
||||
{colorSelect}
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="submit" class="col-lg-3 control-label"></label>
|
||||
<div class="col-lg-3">
|
||||
<button name="submit" value="submit" type="submit" class="btn btn-lg btn-primary center-block ">Submit</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
@ -1,45 +0,0 @@
|
||||
<legend>Edit Bookmark</legend>
|
||||
{BookmarkBreadCrumbs}
|
||||
<form action="" method="post" class="form-horizontal">
|
||||
<input type="hidden" name="token" value="{TOKEN}">
|
||||
<div class="form-group">
|
||||
<label for="title" class="col-lg-3 control-label">Title</label>
|
||||
<div class="col-lg-3">
|
||||
<input type="text" class="form-control" name="title" id="title" value="{title}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="url" class="col-lg-3 control-label">URL:</label>
|
||||
<div class="col-lg-3">
|
||||
<input type="text" class="form-control" name="url" id="url" value="{url}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="description" class="col-lg-3 control-label">Description:</label>
|
||||
<div class="col-lg-3">
|
||||
<textarea class="form-control" name="description" maxlength="2000" rows="10" cols="50" id="description">{description}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
{folderSelect}
|
||||
<div class="form-group">
|
||||
<label for="privacy" class="col-lg-3 control-label">Privacy</label>
|
||||
<div class="col-lg-3 select-container" id="colorContainer">
|
||||
<select id="privacy" name="privacy" class="form-control custom-select" value="{privacy}">
|
||||
<option value="private">Private</option>
|
||||
<option value="public">Public</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="color" class="col-lg-3 control-label">Color</label>
|
||||
<div class="col-lg-3 select-container" id="colorContainer">
|
||||
{colorSelect}
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="submit" class="col-lg-3 control-label"></label>
|
||||
<div class="col-lg-3">
|
||||
<button name="submit" value="submit" type="submit" class="btn btn-lg btn-primary center-block ">Submit</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
@ -1,37 +0,0 @@
|
||||
{BookmarkBreadCrumbs}
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width: 75%">Bookmark</th>
|
||||
<th style="width: 10%"></th>
|
||||
<th style="width: 5%"></th>
|
||||
<th style="width: 5%"></th>
|
||||
<th style="width: 5%"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{LOOP}
|
||||
<tr>
|
||||
<td style="text-align: center;">
|
||||
<a href="{url}" role="button">
|
||||
{title}
|
||||
</a>
|
||||
</td>
|
||||
<td style="text-align: center;">
|
||||
{privacy}
|
||||
</td>
|
||||
<td><a href="{ROOT_URL}bookmarks/bookmarks/{ID}" class="btn btn-sm btn-primary" role="button"><i class="glyphicon glyphicon-open"></i></a></td>
|
||||
<td><a href="{ROOT_URL}bookmarks/editBookmark/{ID}" class="btn btn-sm btn-warning" role="button"><i class="glyphicon glyphicon-edit"></i></a></td>
|
||||
<td><a href="{ROOT_URL}bookmarks/deleteBookmark/{ID}" class="btn btn-sm btn-danger" role="button"><i class="glyphicon glyphicon-trash"></i></a></td>
|
||||
</tr>
|
||||
{/LOOP}
|
||||
{ALT}
|
||||
<tr>
|
||||
<td style="text-align: center;" colspan="6">
|
||||
No results to show.
|
||||
</td>
|
||||
</tr>
|
||||
{/ALT}
|
||||
</tbody>
|
||||
</table>
|
||||
<a href="{ROOT_URL}bookmarks/createBookmark" class="btn btn-sm btn-primary" role="button">Create</a>
|
@ -1,84 +0,0 @@
|
||||
{BookmarkBreadCrumbs}<br />
|
||||
<div class="container col-md-4 col-lg-4">
|
||||
<div class="row">
|
||||
<div class="panel panel-{color}">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">Bookmark</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div class="row">
|
||||
<div class="">
|
||||
<table class="table table-user-primary">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="left" width="200"><b>Title</b></td>
|
||||
<td align="right">{title}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" width="200"><b>URL</b></td>
|
||||
<td align="right">{url}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" width="200"><b>Type</b></td>
|
||||
<td align="right">{linkType}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" width="200"><b>Privacy</b></td>
|
||||
<td align="right">{privacy}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" width="200"><b>Color</b></td>
|
||||
<td align="right">{color}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" colspan="2"><b>Description</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2">{description}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" colspan="2"><b>Icon</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2">{iconHtml}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2">{icon}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" colspan="2"><b>Meta</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2">{meta}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Created</b></td>
|
||||
<td align="right">{DTC}{createdAt}{/DTC}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Archived</b></td>
|
||||
<td align="right">{DTC}{archivedAt}{/DTC}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Hidden</b></td>
|
||||
<td align="right">{DTC}{hiddenAt}{/DTC}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Last Refreshed</b></td>
|
||||
<td align="right">{DTC}{refreshedAt}{/DTC}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel-footer">
|
||||
{refreshBtn}
|
||||
{hideBtn}
|
||||
{archiveBtn}
|
||||
<a href="{ROOT_URL}bookmarks/editBookmark/{ID}" class="btn btn-sm btn-warning" role="button"><i class="glyphicon glyphicon-edit"></i></a>
|
||||
<a href="{ROOT_URL}bookmarks/deleteBookmark/{ID}" class="btn btn-sm btn-danger" role="button"><i class="glyphicon glyphicon-trash"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -1,21 +0,0 @@
|
||||
<div class="panel panel-{color}">
|
||||
<div class="panel-heading" data-target="#Collapse{ID}" data-toggle="collapse" aria-expanded="true" aria-controls="#Collapse{ID}">
|
||||
{title}
|
||||
</div>
|
||||
<div id="Collapse{ID}" class="panel-collapse collapse in" style="width:100%; position: relative;" role="tabpanel" aria-expanded="true">
|
||||
<div class="panel-body">
|
||||
<ul class="list-group">
|
||||
{bookmarkListRows}
|
||||
</ul>
|
||||
</div>
|
||||
<div class="panel-footer">
|
||||
<a href="{ROOT_URL}bookmarks/createBookmark/{ID}" class="btn btn-sm btn-success" role="button"><i class="glyphicon glyphicon-plus-sign"></i></a></td>
|
||||
<span class="pull-right">
|
||||
<a href="{ROOT_URL}bookmarks/bookmarks/{ID}" class="btn btn-sm btn-primary" role="button"><i class="glyphicon glyphicon-th-list"></i></a>
|
||||
<a href="{ROOT_URL}bookmarks/folders/{ID}" class="btn btn-sm btn-primary" role="button"><i class="glyphicon glyphicon-info-sign"></i></a></td>
|
||||
<a href="{ROOT_URL}bookmarks/editFolder/{ID}" class="btn btn-sm btn-warning" role="button"><i class="glyphicon glyphicon-edit"></i></a></td>
|
||||
<a href="{ROOT_URL}bookmarks/deleteFolder/{ID}" class="btn btn-sm btn-danger" role="button"><i class="glyphicon glyphicon-trash"></i></a></td>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -1,18 +0,0 @@
|
||||
|
||||
{LOOP}
|
||||
<li class="list-group-item list-group-item-{color}">
|
||||
<a href="{ROOT_URL}bookmarks/bookmarks/{ID}" class="btn btn-sm" role="button">{iconHtml}</a>
|
||||
<a href="{url}" class="list-group"> {title}</a>
|
||||
<span class="pull-right">
|
||||
{hideBtn}
|
||||
{archiveBtn}
|
||||
<a href="{ROOT_URL}bookmarks/editBookmark/{ID}" class="btn btn-sm btn-warning" role="button"><i class="glyphicon glyphicon-edit"></i></a>
|
||||
<a href="{ROOT_URL}bookmarks/deleteBookmark/{ID}" class="btn btn-sm btn-danger" role="button"><i class="glyphicon glyphicon-trash"></i></a>
|
||||
</span>
|
||||
</li>
|
||||
{/LOOP}
|
||||
{ALT}
|
||||
<li class="list-group-item">
|
||||
<a href="#" class="list-group">No Bookmarks</a>
|
||||
</li>
|
||||
{/ALT}
|
@ -1,10 +0,0 @@
|
||||
{LOOP}
|
||||
<div class="col-xlg-6 col-lg-6 col-md-6 col-sm-6 col-xs-6">
|
||||
{panel}
|
||||
</div>
|
||||
{/LOOP}
|
||||
{ALT}
|
||||
<div class="col-xlg-6 col-lg-6 col-md-6 col-sm-6 col-xs-6">
|
||||
<p>no folders</p>
|
||||
</div>
|
||||
{/ALT}
|
@ -1,16 +0,0 @@
|
||||
|
||||
{BookmarkBreadCrumbs}
|
||||
<div class="row">
|
||||
<div class="col-xlg-6 col-lg-6 col-md-6 col-sm-6 col-xs-6">
|
||||
<legend>Unsorted Bookmarks</legend>
|
||||
{bookmarksList}
|
||||
</div>
|
||||
<div class="col-xlg-6 col-lg-6 col-md-6 col-sm-6 col-xs-6">
|
||||
<legend>Folders List</legend>
|
||||
{foldersList}
|
||||
</div>
|
||||
</div>
|
||||
<legend>Folders</legend>
|
||||
<div class="row">
|
||||
{folderPanels}
|
||||
</div>
|
@ -1,39 +0,0 @@
|
||||
<legend>Create Folder</legend>
|
||||
{BookmarkBreadCrumbs}
|
||||
<form action="" method="post" class="form-horizontal">
|
||||
<input type="hidden" name="token" value="{TOKEN}">
|
||||
<div class="form-group">
|
||||
<label for="title" class="col-lg-3 control-label">Title</label>
|
||||
<div class="col-lg-3">
|
||||
<input type="text" class="form-control" name="title" id="title">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="description" class="col-lg-3 control-label">Description:</label>
|
||||
<div class="col-lg-3">
|
||||
<textarea class="form-control" name="description" maxlength="2000" rows="10" cols="50" id="description"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
{folderSelect}
|
||||
<div class="form-group">
|
||||
<label for="privacy" class="col-lg-3 control-label">Privacy</label>
|
||||
<div class="col-lg-3 select-container" id="colorContainer">
|
||||
<select id="privacy" name="privacy" class="form-control custom-select">
|
||||
<option value="private">Private</option>
|
||||
<option value="public">Public</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="color" class="col-lg-3 control-label">Color</label>
|
||||
<div class="col-lg-3 select-container" id="colorContainer">
|
||||
{colorSelect}
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="submit" class="col-lg-3 control-label"></label>
|
||||
<div class="col-lg-3">
|
||||
<button name="submit" value="submit" type="submit" class="btn btn-lg btn-primary center-block ">Submit</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
@ -1,39 +0,0 @@
|
||||
<legend>Edit Folder</legend>
|
||||
{BookmarkBreadCrumbs}
|
||||
<form action="" method="post" class="form-horizontal">
|
||||
<input type="hidden" name="token" value="{TOKEN}">
|
||||
<div class="form-group">
|
||||
<label for="title" class="col-lg-3 control-label">Title</label>
|
||||
<div class="col-lg-3">
|
||||
<input type="text" class="form-control" name="title" id="title" value="{title}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="description" class="col-lg-3 control-label">Description:</label>
|
||||
<div class="col-lg-3">
|
||||
<textarea class="form-control" name="description" maxlength="2000" rows="10" cols="50" id="description">{description}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
{folderSelect}
|
||||
<div class="form-group">
|
||||
<label for="privacy" class="col-lg-3 control-label">Privacy</label>
|
||||
<div class="col-lg-3 select-container" id="colorContainer">
|
||||
<select id="privacy" name="privacy" class="form-control custom-select" value="{privacy}">
|
||||
<option value="private">Private</option>
|
||||
<option value="public">Public</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="color" class="col-lg-3 control-label">Color</label>
|
||||
<div class="col-lg-3 select-container" id="colorContainer">
|
||||
{colorSelect}
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="submit" class="col-lg-3 control-label"></label>
|
||||
<div class="col-lg-3">
|
||||
<button name="submit" value="submit" type="submit" class="btn btn-lg btn-primary center-block ">Submit</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
@ -1,33 +0,0 @@
|
||||
{BookmarkBreadCrumbs}
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width: 35%">Title</th>
|
||||
<th style="width: 20%">Privacy</th>
|
||||
<th style="width: 30%">Description</th>
|
||||
<th style="width: 5%"></th>
|
||||
<th style="width: 5%"></th>
|
||||
<th style="width: 5%"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{LOOP}
|
||||
<tr>
|
||||
<td align="center">{title}</td>
|
||||
<td align="center">{privacy}</td>
|
||||
<td>{description}</td>
|
||||
<td><a href="{ROOT_URL}bookmarks/folders/{ID}" class="btn btn-sm btn-primary" role="button"><i class="glyphicon glyphicon-info-sign"></i></a></td>
|
||||
<td><a href="{ROOT_URL}bookmarks/editFolder/{ID}" class="btn btn-sm btn-warning" role="button"><i class="glyphicon glyphicon-edit"></i></a></td>
|
||||
<td><a href="{ROOT_URL}bookmarks/deleteFolder/{ID}" class="btn btn-sm btn-danger" role="button"><i class="glyphicon glyphicon-trash"></i></a></td>
|
||||
</tr>
|
||||
{/LOOP}
|
||||
{ALT}
|
||||
<tr>
|
||||
<td align="center" colspan="7">
|
||||
No results to show.
|
||||
</td>
|
||||
</tr>
|
||||
{/ALT}
|
||||
</tbody>
|
||||
</table>
|
||||
<a href="{ROOT_URL}bookmarks/createFolder" class="btn btn-sm btn-primary" role="button">Create</a>
|
@ -1,47 +0,0 @@
|
||||
{BookmarkBreadCrumbs}<br />
|
||||
<div class="container col-md-4 col-lg-4">
|
||||
<div class="row">
|
||||
<div class="panel panel-{color}">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">Bookmark Folder</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div class="row">
|
||||
<div class="">
|
||||
<table class="table table-user-primary">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="left" width="200"><b>Title</b></td>
|
||||
<td align="right">{title}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" width="200"><b>Privacy</b></td>
|
||||
<td align="right">{privacy}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" width="200"><b>Color</b></td>
|
||||
<td align="right">{color}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" colspan="2"><b>Description</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2">{description}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Created</b></td>
|
||||
<td align="right">{DTC}{createdAt}{/DTC}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel-footer">
|
||||
<a href="{ROOT_URL}bookmarks/bookmarks/{ID}" class="btn btn-sm btn-primary" role="button"><i class="glyphicon glyphicon-th-list"></i></a>
|
||||
<a href="{ROOT_URL}bookmarks/editFolder/{ID}" class="btn btn-sm btn-warning" role="button"><i class="glyphicon glyphicon-edit"></i></a>
|
||||
<a href="{ROOT_URL}bookmarks/deleteFolder/{ID}" class="btn btn-sm btn-danger" role="button"><i class="glyphicon glyphicon-trash"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -1,5 +0,0 @@
|
||||
<ul class="nav nav-tabs">
|
||||
<li><a href="{ROOT_URL}bookmarks/index/">Dashboard</a></li>
|
||||
<li><a href="{ROOT_URL}bookmarks/folders/">Folders</a></li>
|
||||
</ul>
|
||||
{userFolderTabs}
|
@ -1,9 +0,0 @@
|
||||
<ul class="nav nav-tabs">
|
||||
<li><a href="{ROOT_URL}bookmarks/folders/">All</a></li>
|
||||
{LOOP}
|
||||
<li><a href="{ROOT_URL}bookmarks/bookmarks/{ID}">{title}</a></li>
|
||||
{/LOOP}
|
||||
{ALT}
|
||||
<li></li>
|
||||
{/ALT}
|
||||
</ul>
|
@ -1,7 +0,0 @@
|
||||
<?php
|
||||
# bugTracker
|
||||
define( 'TRACKER_STATUS_IN_PROGRESS', 'In Progress' );
|
||||
define( 'TRACKER_STATUS_TESTING', 'Needs Testing' );
|
||||
define( 'TRACKER_STATUS_NEW', 'New' );
|
||||
define( 'TRACKER_STATUS_FIXED', 'Fixed' );
|
||||
define( 'TRACKER_STATUS_CLOSED', 'Closed' );
|
@ -1,206 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* app/plugins/bugtracker/controllers/admin/bugtracker.php
|
||||
*
|
||||
* This is the Bug-Tracker admin controller.
|
||||
*
|
||||
* @package TP BugTracker
|
||||
* @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\Bedrock\Functions\Check;
|
||||
use TheTempusProject\Bedrock\Functions\Upload;
|
||||
use TheTempusProject\Bedrock\Functions\Input;
|
||||
use TheTempusProject\Houdini\Classes\Issues;
|
||||
use TheTempusProject\Houdini\Classes\Views;
|
||||
use TheTempusProject\Houdini\Classes\Navigation;
|
||||
use TheTempusProject\Houdini\Classes\Components;
|
||||
use TheTempusProject\Houdini\Classes\Forms as FormGen;
|
||||
use TheTempusProject\Classes\AdminController;
|
||||
use TheTempusProject\Classes\Forms;
|
||||
use TheTempusProject\Models\Bugtracker as BugtrackerModel;
|
||||
use TheTempusProject\TheTempusProject as App;
|
||||
use TheTempusProject\Models\Comments;
|
||||
|
||||
class Bugtracker extends AdminController {
|
||||
protected static $tracker;
|
||||
protected static $comments;
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
self::$tracker = new BugtrackerModel;
|
||||
self::$title = 'Admin - Bug-Tracker';
|
||||
$view = Navigation::activePageSelect( 'nav.admin', '/admin/bugtracker' );
|
||||
Components::set( 'ADMINNAV', $view );
|
||||
}
|
||||
|
||||
public function index( $data = null ) {
|
||||
Views::view( 'bugtracker.admin.list', self::$tracker->list() );
|
||||
}
|
||||
|
||||
public function create( $data = null ) {
|
||||
$form = '';
|
||||
$form .= FormGen::getFormFieldHtml( 'title', 'Title', 'text', Input::post('title') );
|
||||
$form .= FormGen::getFormFieldHtml( 'description', 'Description', 'block', Input::post('description') );
|
||||
$form .= FormGen::getFormFieldHtml( 'bugImage', 'Screenshot', 'file', '' );
|
||||
$form .= FormGen::getFormFieldHtml( 'url', 'URL (if possible)', 'text', '' );
|
||||
$form .= FormGen::getFormFieldHtml( 'repeat', 'Has this happened more than once', 'radio' );
|
||||
Components::set( 'TRACKER_FORM', $form );
|
||||
if ( !Input::exists( 'submit' ) ) {
|
||||
return Views::view( 'bugtracker.admin.create' );
|
||||
}
|
||||
if ( !Forms::check( 'newBugTracker' ) ) {
|
||||
Issues::add( 'error', [ 'There was an error with your request.' => Check::userErrors() ] );
|
||||
return Views::view( 'bugtracker.admin.create' );
|
||||
}
|
||||
$image = '';
|
||||
if ( Input::exists( 'bugImage' ) ) {
|
||||
$folder = IMAGE_UPLOAD_DIRECTORY . App::$activeUser->username . DIRECTORY_SEPARATOR;
|
||||
if ( !Upload::image( 'bugImage', $folder ) ) {
|
||||
Issues::add( 'error', [ 'There was an error with your upload.' => Check::systemErrors() ] );
|
||||
} else {
|
||||
$route = str_replace( APP_ROOT_DIRECTORY, '', $folder );
|
||||
$image = $route . Upload::last();
|
||||
}
|
||||
}
|
||||
$result = self::$tracker->create(
|
||||
App::$activeUser->ID,
|
||||
Input::post( 'url' ),
|
||||
$image,
|
||||
Input::post( 'repeat' ),
|
||||
Input::post( 'description' ),
|
||||
Input::post( 'title' ),
|
||||
);
|
||||
if ( $result ) {
|
||||
Issues::add( 'success', 'Your tracker has been created.' );
|
||||
return $this->index();
|
||||
} else {
|
||||
Issues::add( 'error', [ 'There was an unknown error submitting your data.' => Check::userErrors() ] );
|
||||
return $this->index();
|
||||
}
|
||||
}
|
||||
|
||||
public function edit( $data = null ) {
|
||||
if ( !Input::exists( 'submit' ) ) {
|
||||
$bug = self::$tracker->findById( $data );
|
||||
$statusList = [
|
||||
TRACKER_STATUS_IN_PROGRESS => TRACKER_STATUS_IN_PROGRESS,
|
||||
TRACKER_STATUS_TESTING => TRACKER_STATUS_TESTING,
|
||||
TRACKER_STATUS_NEW => TRACKER_STATUS_NEW,
|
||||
TRACKER_STATUS_FIXED => TRACKER_STATUS_FIXED,
|
||||
TRACKER_STATUS_CLOSED => TRACKER_STATUS_CLOSED,
|
||||
];
|
||||
$form = '';
|
||||
$form .= FormGen::getFormFieldHtml( 'title', 'Title', 'text', $bug->title );
|
||||
$form .= FormGen::getFormFieldHtml( 'description', 'Description', 'block', $bug->description );
|
||||
$form .= FormGen::getFormFieldHtml( 'bugImage', 'Screenshot', 'file', $bug->image );
|
||||
$form .= FormGen::getFormFieldHtml( 'url', 'Page you were on', 'text', $bug->url );
|
||||
$form .= FormGen::getFormFieldHtml( 'repeat', 'Has this happened more than once', 'radio', $bug->repeatable );
|
||||
$form .= FormGen::getFormFieldHtml( 'status', 'Status', 'customSelect', $bug->status, $statusList );
|
||||
Components::set( 'TRACKER_FORM', $form );
|
||||
return Views::view( 'bugtracker.admin.edit', $bug );
|
||||
}
|
||||
if ( !Forms::check( 'editBugTracker' ) ) {
|
||||
Issues::add( 'error', [ 'There was an error with your form.' => Check::userErrors() ] );
|
||||
return $this->index();
|
||||
}
|
||||
$image = '';
|
||||
if ( Input::exists( 'bugImage' ) ) {
|
||||
$folder = IMAGE_UPLOAD_DIRECTORY . App::$activeUser->username . DIRECTORY_SEPARATOR;
|
||||
if ( !Upload::image( 'bugImage', $folder ) ) {
|
||||
Issues::add( 'error', [ 'There was an error with your upload.' => Check::systemErrors() ] );
|
||||
} else {
|
||||
$image = $folder . Upload::last();
|
||||
}
|
||||
}
|
||||
$tracker = self::$tracker->updateTracker(
|
||||
$data,
|
||||
Input::post( 'url' ),
|
||||
$image,
|
||||
Input::post( 'repeat' ),
|
||||
Input::post( 'description' ),
|
||||
Input::post( 'title' ),
|
||||
Input::post( 'status' )
|
||||
);
|
||||
if ( true === $tracker ) {
|
||||
Issues::add( 'success', 'Tracker Updated.' );
|
||||
return $this->index();
|
||||
}
|
||||
Issues::add( 'error', 'There was an error with your request.' );
|
||||
$this->index();
|
||||
}
|
||||
|
||||
public function view( $id = null ) {
|
||||
if ( empty( self::$comments ) ) {
|
||||
self::$comments = new Comments;
|
||||
}
|
||||
$data = self::$tracker->findById( $id );
|
||||
if ( $data === false ) {
|
||||
Issues::add( 'error', 'Tracker not found.' );
|
||||
return $this->index();
|
||||
}
|
||||
if ( Input::exists( 'contentId' ) ) {
|
||||
$this->comments( 'post', Input::post( 'contentId' ) );
|
||||
}
|
||||
if ( empty( self::$comments ) ) {
|
||||
self::$comments = new Comments;
|
||||
}
|
||||
Components::set( 'CONTENT_ID', $id );
|
||||
Components::set( 'COMMENT_TYPE', 'admin/bugtracker' );
|
||||
Components::set( 'count', self::$comments->count( 'tracker', $id ) );
|
||||
Components::set( 'NEWCOMMENT', Views::simpleView( 'comments.create' ) );
|
||||
Components::set( 'COMMENTS', Views::simpleView( 'comments.list', self::$comments->display( 10, 'tracker', $id ) ) );
|
||||
Views::view( 'bugtracker.admin.view', $data );
|
||||
}
|
||||
|
||||
public function delete( $data = null ) {
|
||||
if ( $data == null ) {
|
||||
if ( Input::exists( 'T_' ) ) {
|
||||
$data = Input::post( 'T_' );
|
||||
}
|
||||
}
|
||||
if ( !self::$tracker->delete( $data ) ) {
|
||||
Issues::add( 'error', 'There was an error with your request.' );
|
||||
} else {
|
||||
Issues::add( 'success', 'Tracker has been deleted' );
|
||||
}
|
||||
$this->index();
|
||||
}
|
||||
|
||||
public function comments( $sub = null, $data = null ) {
|
||||
if ( empty( self::$comments ) ) {
|
||||
self::$comments = new Comments;
|
||||
}
|
||||
if ( empty( $sub ) || empty( $data ) ) {
|
||||
Session::flash( 'error', 'Whoops, try again.' );
|
||||
Redirect::to( 'admin/bugtracker' );
|
||||
}
|
||||
switch ( $sub ) {
|
||||
case 'post':
|
||||
$content = self::$tracker->findById( $data );
|
||||
if ( empty( $content ) ) {
|
||||
Session::flash( 'error', 'Unknown Post.' );
|
||||
Redirect::to( 'admin/bugtracker' );
|
||||
}
|
||||
return self::$comments->formPost( 'tracker', $content, 'admin/bugtracker/view/' );
|
||||
case 'edit':
|
||||
$content = self::$comments->findById( $data );
|
||||
if ( empty( $content ) ) {
|
||||
Session::flash( 'error', 'Unknown Comment.' );
|
||||
Redirect::to( 'admin/bugtracker' );
|
||||
}
|
||||
return self::$comments->formEdit( 'tracker', $content, 'admin/bugtracker/view/' );
|
||||
case 'delete':
|
||||
$content = self::$comments->findById( $data );
|
||||
if ( empty( $content ) ) {
|
||||
Session::flash( 'error', 'Unknown Comment.' );
|
||||
Redirect::to( 'admin/bugtracker' );
|
||||
}
|
||||
return self::$comments->formDelete( 'tracker', $content, 'admin/bugtracker/view/' );
|
||||
}
|
||||
}
|
||||
}
|
@ -1,92 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* app/plugins/bugtracker/forms.php
|
||||
*
|
||||
* This houses all of the form checking functions for this plugin.
|
||||
*
|
||||
* @package TP BugTracker
|
||||
* @version 3.0
|
||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||
* @link https://TheTempusProject.com
|
||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||
*/
|
||||
namespace TheTempusProject\Plugins\Bugreport;
|
||||
|
||||
use TheTempusProject\Bedrock\Functions\Input;
|
||||
use TheTempusProject\Classes\Forms;
|
||||
|
||||
class BugTrackerForms extends Forms {
|
||||
/**
|
||||
* Adds these functions to the form list.
|
||||
*/
|
||||
public function __construct() {
|
||||
self::addHandler( 'newBugTracker', __CLASS__, 'newBugTracker' );
|
||||
self::addHandler( 'editBugTracker', __CLASS__, 'editBugTracker' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the bug tracker create form.
|
||||
*
|
||||
* @return {bool}
|
||||
*/
|
||||
public static function newBugTracker() {
|
||||
if ( !empty(Input::post( 'url' )) && !self::url( Input::post( 'url' ) ) ) {
|
||||
self::addUserError( 'Invalid url: <code>' . Input::post( 'url' ) . '</code>' );
|
||||
return false;
|
||||
}
|
||||
if ( !self::tf( Input::post( 'repeat' ) ) ) {
|
||||
self::addUserError( 'Invalid repeat value: ' . Input::post( 'repeat' ) );
|
||||
return false;
|
||||
}
|
||||
if ( !Input::exists( 'title' ) ) {
|
||||
self::addUserError( 'You must specify title' );
|
||||
return false;
|
||||
}
|
||||
if ( !self::dataTitle( Input::post( 'title' ) ) ) {
|
||||
self::addUserError( 'Invalid title' );
|
||||
return false;
|
||||
}
|
||||
if ( !Input::exists( 'description' ) ) {
|
||||
self::addUserError( 'You must specify a description' );
|
||||
return false;
|
||||
}
|
||||
// if ( !self::token() ) {
|
||||
// return false;
|
||||
// }
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the bug tracker create form.
|
||||
*
|
||||
* @return {bool}
|
||||
*/
|
||||
public static function editBugTracker() {
|
||||
if ( !empty(Input::post( 'url' )) && !self::url( Input::post( 'url' ) ) ) {
|
||||
self::addUserError( 'Invalid url.' . Input::post( 'url' ) );
|
||||
return false;
|
||||
}
|
||||
if ( !self::tf( Input::post( 'repeat' ) ) ) {
|
||||
self::addUserError( 'Invalid repeat value.' );
|
||||
return false;
|
||||
}
|
||||
if ( !Input::exists( 'title' ) ) {
|
||||
self::addUserError( 'You must specify title' );
|
||||
return false;
|
||||
}
|
||||
if ( !self::dataTitle( Input::post( 'title' ) ) ) {
|
||||
self::addUserError( 'Invalid title' );
|
||||
return false;
|
||||
}
|
||||
if ( !Input::exists( 'description' ) ) {
|
||||
self::addUserError( 'You must specify a description' );
|
||||
return false;
|
||||
}
|
||||
// if ( !self::token() ) {
|
||||
// return false;
|
||||
// }
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
new BugTrackerForms;
|
@ -1,142 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* app/plugins/bugtracker/models/bugtracker.php
|
||||
*
|
||||
* This class is used for the manipulation of the bugs database table.
|
||||
*
|
||||
* @package TP BugTracker
|
||||
* @version 3.0
|
||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||
* @link https://TheTempusProject.com
|
||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||
*/
|
||||
namespace TheTempusProject\Models;
|
||||
|
||||
use TheTempusProject\Bedrock\Functions\Check;
|
||||
use TheTempusProject\Bedrock\Classes\Config;
|
||||
use TheTempusProject\Canary\Bin\Canary as Debug;
|
||||
use TheTempusProject\Bedrock\Classes\CustomException;
|
||||
use TheTempusProject\Classes\DatabaseModel;
|
||||
use TheTempusProject\TheTempusProject as App;
|
||||
use TheTempusProject\Plugins\Bugtracker as Plugin;
|
||||
|
||||
class Bugtracker extends DatabaseModel {
|
||||
public $tableName = 'bugs';
|
||||
public $databaseMatrix = [
|
||||
[ 'userID', 'int', '11' ],
|
||||
[ 'time', 'int', '10' ],
|
||||
[ 'title', 'varchar', '128' ],
|
||||
[ 'status', 'varchar', '64' ],
|
||||
[ 'description', 'text', '' ],
|
||||
[ 'image', 'varchar', '256' ],
|
||||
[ 'repeatable', 'varchar', '5' ],
|
||||
[ 'url', 'varchar', '256' ],
|
||||
];
|
||||
public $plugin;
|
||||
|
||||
/**
|
||||
* The model constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
$this->plugin = new Plugin;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function parses the bug reports description and
|
||||
* separates it into separate keys in the array.
|
||||
*
|
||||
* @param array $data - The data being parsed.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function filter( $data, $params = [] ) {
|
||||
foreach ( $data as $instance ) {
|
||||
if ( !is_object( $instance ) ) {
|
||||
$instance = $data;
|
||||
$end = true;
|
||||
}
|
||||
$instance->submittedBy = self::$user->getUsername( $instance->userID );
|
||||
$instance->repeatText = ( 'false' == $instance->repeatable ? 'no' : 'yes' );
|
||||
$out[] = $instance;
|
||||
if ( !empty( $end ) ) {
|
||||
$out = $out[0];
|
||||
break;
|
||||
}
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs a Bug Report form.
|
||||
*
|
||||
* @param int $ID the user ID submitting the form
|
||||
* @param string $url the url
|
||||
* @param string $o_url the original url
|
||||
* @param int $repeat is repeatable?
|
||||
* @param string $description_ description of the event.
|
||||
*
|
||||
* @return null
|
||||
*/
|
||||
public function create( $ID, $url, $image, $repeat, $description, $title ) {
|
||||
if ( !$this->plugin->checkEnabled() ) {
|
||||
Debug::info( 'Bug Tracking is disabled in the config.' );
|
||||
return false;
|
||||
}
|
||||
if ( !Check::dataTitle( $title ) ) {
|
||||
Debug::info( 'bugTracker: illegal title.' );
|
||||
return false;
|
||||
}
|
||||
$fields = [
|
||||
'userID' => App::$activeUser->ID,
|
||||
'time' => time(),
|
||||
'title' => $title,
|
||||
'status' => TRACKER_STATUS_NEW,
|
||||
'description' => $description,
|
||||
'image' => $image,
|
||||
'repeatable' => $repeat,
|
||||
'url' => $url,
|
||||
];
|
||||
if ( !self::$db->insert( $this->tableName, $fields ) ) {
|
||||
new CustomException( $this->tableName );
|
||||
return false;
|
||||
}
|
||||
return self::$db->lastId();
|
||||
}
|
||||
|
||||
public function updateTracker( $ID, $url, $image, $repeat, $description, $title, $status ) {
|
||||
if ( !$this->plugin->checkEnabled() ) {
|
||||
Debug::info( 'Bug Tracking is disabled in the config.' );
|
||||
return false;
|
||||
}
|
||||
if ( empty( self::$log ) ) {
|
||||
self::$log = new Log;
|
||||
}
|
||||
if ( !Check::id( $ID ) ) {
|
||||
Debug::info( 'bugTracker: illegal ID.' );
|
||||
return false;
|
||||
}
|
||||
if ( !Check::dataTitle( $title ) ) {
|
||||
Debug::info( 'bugTracker: illegal title.' );
|
||||
return false;
|
||||
}
|
||||
$fields = [
|
||||
'url' => $url,
|
||||
'description' => $description,
|
||||
'repeatable' => $repeat,
|
||||
'title' => $title,
|
||||
'status' => $status,
|
||||
];
|
||||
if ( !empty( $image ) ) {
|
||||
$fields['image'] = $image;
|
||||
}
|
||||
if ( !self::$db->update( $this->tableName, $ID, $fields ) ) {
|
||||
new CustomException( $this->tableName );
|
||||
Debug::error( "Tracker Post: $ID not updated: $fields" );
|
||||
|
||||
return false;
|
||||
}
|
||||
self::$log->admin( "Updated Tracker Post: $ID" );
|
||||
return true;
|
||||
}
|
||||
}
|
@ -1,48 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* app/plugins/bugtracker/plugin.php
|
||||
*
|
||||
* This houses all of the main plugin info and functionality.
|
||||
*
|
||||
* @package TP BugTracker
|
||||
* @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 Bugtracker extends Plugin {
|
||||
public $pluginName = 'TP BugTracker';
|
||||
public $pluginAuthor = 'JoeyK';
|
||||
public $pluginWebsite = 'https://TheTempusProject.com';
|
||||
public $modelVersion = '1.0';
|
||||
public $pluginVersion = '3.0';
|
||||
public $pluginDescription = '';
|
||||
public $configName = 'bugtracker';
|
||||
public $configMatrix = [
|
||||
'enabled' => [
|
||||
'type' => 'radio',
|
||||
'pretty' => 'Enable Bug tracking.',
|
||||
'default' => true,
|
||||
],
|
||||
];
|
||||
public $permissionMatrix = [
|
||||
'bugTrack' => [
|
||||
'pretty' => 'Can Track Bugs',
|
||||
'default' => false,
|
||||
],
|
||||
];
|
||||
public $admin_links = [
|
||||
[
|
||||
'text' => '<i class="fa fa-fw fa-bug"></i> Bug Tracker',
|
||||
'url' => '{ROOT_URL}admin/bugtracker',
|
||||
],
|
||||
];
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
<form action="" method="post" class="form-horizontal" enctype="multipart/form-data">
|
||||
<legend>Create Bug Tracker</legend>
|
||||
{TRACKER_FORM}
|
||||
<input type="hidden" name="token" value="{TOKEN}">
|
||||
<button name="submit" value="submit" type="submit" class="btn btn-lg btn-primary center-block">Save</button><br>
|
||||
</form>
|
@ -1,30 +0,0 @@
|
||||
<legend>New Bugs</legend>
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width: 20%"></th>
|
||||
<th style="width: 65%"></th>
|
||||
<th style="width: 5%"></th>
|
||||
<th style="width: 5%"></th>
|
||||
<th style="width: 5%"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{LOOP}
|
||||
<tr>
|
||||
<td>{title}</td>
|
||||
<td>{description}</td>
|
||||
<td><a href="{ROOT_URL}admin/bugtracker/view/{ID}" class="btn btn-sm btn-primary" role="button"><i class="glyphicon glyphicon-open"></i></a></td>
|
||||
<td><a href="{ROOT_URL}admin/bugtracker/edit/{ID}" class="btn btn-sm btn-warning" role="button"><i class="glyphicon glyphicon-edit"></i></a></td>
|
||||
<td width="30px"><a href="{ROOT_URL}admin/bugtracker/delete/{ID}" class="btn btn-sm btn-danger" role="button"><i class="glyphicon glyphicon-trash"></i></a></td>
|
||||
</tr>
|
||||
{/LOOP}
|
||||
{ALT}
|
||||
<tr>
|
||||
<td align="center" colspan="5">
|
||||
No results to show.
|
||||
</td>
|
||||
</tr>
|
||||
{/ALT}
|
||||
</tbody>
|
||||
</table>
|
@ -1,6 +0,0 @@
|
||||
<form action="" method="post" class="form-horizontal" enctype="multipart/form-data">
|
||||
<legend>Edit Bug Tracker</legend>
|
||||
{TRACKER_FORM}
|
||||
<input type="hidden" name="token" value="{TOKEN}">
|
||||
<button name="submit" value="submit" type="submit" class="btn btn-lg btn-primary center-block">Save</button><br>
|
||||
</form>
|
@ -1,45 +0,0 @@
|
||||
<legend>Bug Trackers</legend>
|
||||
{PAGINATION}
|
||||
<form action="{ROOT_URL}admin/bugtracker/delete" method="post">
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width: 30%">Title</th>
|
||||
<th style="width: 40%">Description</th>
|
||||
<th style="width: 10%">Status</th>
|
||||
<th style="width: 5%">Time Submitted</th>
|
||||
<th style="width: 5%"></th>
|
||||
<th style="width: 5%"></th>
|
||||
<th style="width: 5%">
|
||||
<INPUT type="checkbox" onchange="checkAll(this)" name="check.br" value="T_[]"/>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{LOOP}
|
||||
<tr>
|
||||
<td><a href="{ROOT_URL}admin/bugtracker/view/{ID}">{title}</a></td>
|
||||
<td>{description}</td>
|
||||
<td>{status}</td>
|
||||
<td align="center">{DTC}{time}{/DTC}</td>
|
||||
<td><a href="{ROOT_URL}admin/bugtracker/edit/{ID}" class="btn btn-sm btn-warning" role="button"><i class="glyphicon glyphicon-edit"></i></a></td>
|
||||
<td><a href="{ROOT_URL}admin/bugtracker/delete/{ID}" class="btn btn-sm btn-danger" role="button"><i class="glyphicon glyphicon-trash"></i></a></td>
|
||||
<td>
|
||||
<input type="checkbox" value="{ID}" name="T_[]">
|
||||
</td>
|
||||
</tr>
|
||||
{/LOOP}
|
||||
{ALT}
|
||||
<tr>
|
||||
<td align="center" colspan="7">
|
||||
No results to show.
|
||||
</td>
|
||||
</tr>
|
||||
{/ALT}
|
||||
</tbody>
|
||||
</table>
|
||||
<button name="submit" value="submit" type="submit" class="btn btn-sm btn-danger">Delete</button>
|
||||
<a href="{ROOT_URL}admin/bugtracker/create" class="btn btn-sm btn-primary" role="button">Create</a>
|
||||
</form>
|
||||
<br />
|
||||
<a href="{ROOT_URL}admin/bugtracker/clear">clear all</a>
|
@ -1,74 +0,0 @@
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-xs-12 col-sm-12 col-md-6 col-lg-6 col-xs-offset-0 col-sm-offset-0 col-md-offset-3 col-lg-offset-3 top-pad" >
|
||||
<div class="panel panel-primary">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">Bug Tracker</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div class="row">
|
||||
<div class=" col-md-12 col-lg-12 ">
|
||||
<table class="table table-user-primary">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="center" colspan="2">Title</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2">{title}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" colspan="2">Description</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2">{description}</td>
|
||||
</tr>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<div align="center">
|
||||
<a href="{ROOT_URL}{image}"><img alt="Screenshot" src="{ROOT_URL}{image}" class="img-responsive"></a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" width="200">Status</td>
|
||||
<td align="right">{status}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" width="200">ID</td>
|
||||
<td align="right">{ID}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Time submitted</td>
|
||||
<td align="right">{DTC}{time}{/DTC}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Submitted by</td>
|
||||
<td align="right"><a href="{ROOT_URL}admin/users/view/{userID}">{submittedBy}</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>URL:</td>
|
||||
<td align="right">{URL}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Multiple occurrences?</td>
|
||||
<td align="right">{repeatText}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel-footer">
|
||||
{ADMIN}
|
||||
<a href="{ROOT_URL}admin/bugtracker/delete/{ID}" class="btn btn-md btn-danger" role="button">Delete</a>
|
||||
<a href="{ROOT_URL}admin/bugtracker/edit/{ID}" class="btn btn-md btn-warning" role="button">Edit</a>
|
||||
<a href="{ROOT_URL}admin/comments/tracker/{ID}" class="btn btn-md btn-primary" role="button">View Comments</a>
|
||||
{/ADMIN}
|
||||
</div>
|
||||
</div>
|
||||
{COMMENTS}
|
||||
{NEWCOMMENT}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -1,593 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* app/plugins/calendar/controllers/calendar.php
|
||||
*
|
||||
* This is the calendar controller.
|
||||
*
|
||||
* @package TP Calendar
|
||||
* @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\Bedrock\Functions\Check;
|
||||
use TheTempusProject\Bedrock\Functions\Input;
|
||||
use TheTempusProject\Bedrock\Functions\Session;
|
||||
use TheTempusProject\Bedrock\Functions\Date;
|
||||
use TheTempusProject\Classes\Controller;
|
||||
use TheTempusProject\Houdini\Classes\Forms as HoudiniForms;
|
||||
use TheTempusProject\Classes\Forms;
|
||||
use TheTempusProject\Houdini\Classes\Issues;
|
||||
use TheTempusProject\Houdini\Classes\Views;
|
||||
use TheTempusProject\Houdini\Classes\Template;
|
||||
use TheTempusProject\Houdini\Classes\Components;
|
||||
use TheTempusProject\Hermes\Functions\Redirect;
|
||||
use TheTempusProject\TheTempusProject as App;
|
||||
use TheTempusProject\Models\Events;
|
||||
use TheTempusProject\Models\Calendars;
|
||||
use TheTempusProject\Houdini\Classes\Navigation;
|
||||
|
||||
class Calendar extends Controller {
|
||||
protected static $events;
|
||||
protected static $calendars;
|
||||
protected static $defaultView;
|
||||
protected static $defaultCalendar;
|
||||
protected static $selectedDate;
|
||||
|
||||
public function __construct() {
|
||||
if ( !App::$isLoggedIn ) {
|
||||
Session::flash( 'notice', 'You must be logged in to create or manage calendars.' );
|
||||
return Redirect::home();
|
||||
}
|
||||
parent::__construct();
|
||||
self::$title = 'Calendar - {SITENAME}';
|
||||
self::$pageDescription = 'The {SITENAME} calendar is where you can find various features for creating and managing events and schedules.';
|
||||
self::$events = new Events;
|
||||
self::$calendars = new Calendars;
|
||||
|
||||
$prefs = App::$activePrefs;
|
||||
if ( ! empty( $prefs['calendarPreference'] ) ) {
|
||||
$view = $prefs['calendarPreference'];
|
||||
} else {
|
||||
Session::flash( 'info', 'You can select a default view for this page in your user settings in the top right.' );
|
||||
$view = 'byMonth';
|
||||
}
|
||||
self::$defaultView = $view;
|
||||
self::$selectedDate = intval( strtotime( Date::determineDateInput() ) );
|
||||
|
||||
Template::setTemplate( 'calendar' );
|
||||
|
||||
// Date Dropdown
|
||||
$dateDropdownView = Views::simpleView('calendar.nav.dateDropdown', Date::getDateBreakdown( self::$selectedDate ) );
|
||||
Components::set( 'dateDropdown', $dateDropdownView );
|
||||
|
||||
// Calendar Top Tabs
|
||||
$calendarTabs = Views::simpleView('calendar.nav.topTabs');
|
||||
$tabsView = Navigation::activePageSelect( $calendarTabs, Input::get( 'url' ), false, true );
|
||||
// must be done after top-nav gets selected
|
||||
$calendarDropdown = Views::simpleView('calendar.nav.calendarDropdown', self::$calendars->simpleObjectByUser() );
|
||||
$calendarDropdownView = Navigation::activePageSelect( $calendarDropdown, Input::get( 'url' ), false, true ); // add notebookID as second param
|
||||
Components::set( 'calendarDropdown', $calendarDropdownView);
|
||||
// must be done after dropdown gets added
|
||||
Components::set( 'CalendarNav', Template::parse( $calendarTabs ) );
|
||||
}
|
||||
public function index() {
|
||||
if ( method_exists( $this, self::$defaultView ) ) {
|
||||
Redirect::to( 'calendar/'.self::$defaultView.'/' );
|
||||
} else {
|
||||
Redirect::to( 'calendar/byMonth/' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Events
|
||||
*/
|
||||
public function event( $id = null ) {
|
||||
$event = $this->findEventOrFail( $id );
|
||||
Views::view( 'calendar.events.view', $event );
|
||||
}
|
||||
public function createEvent() {
|
||||
// get the url calendar input
|
||||
$newCalendar = Input::get('calendar_id') ? Input::get('calendar_id') : '';// for loading the form
|
||||
$calendarSelect = HoudiniForms::getFormFieldHtml( 'calendar_id', 'Calendar', 'select', $newCalendar, self::$calendars->simpleByUser() );
|
||||
Components::set( 'calendarSelect', $calendarSelect );
|
||||
|
||||
$repeatSelect = HoudiniForms::getFormFieldHtml( 'repeats', 'Frequency', 'select', 'none', self::$events->repeatOptions );
|
||||
Components::set( 'repeatSelect', $repeatSelect );
|
||||
|
||||
$dateSelect = Views::simpleView( 'calendar.dateSelect', $this->getEventBreakdown( self::$selectedDate ) );
|
||||
Components::set( 'dateSelect', $dateSelect );
|
||||
|
||||
if ( ! Input::exists() ) {
|
||||
return Views::view( 'calendar.events.create' );
|
||||
}
|
||||
|
||||
/** Attempt to save the form data somewhat */
|
||||
// get the form calendar input
|
||||
$calendarID = Input::post('calendar_id') ? Input::post('calendar_id') : ''; // for submitting the form
|
||||
$calendarSelect = HoudiniForms::getFormFieldHtml( 'calendar_id', 'Calendar', 'select', $calendarID, self::$calendars->simpleByUser() );
|
||||
Components::set( 'calendarSelect', $calendarSelect );
|
||||
|
||||
$repeatSelect = HoudiniForms::getFormFieldHtml( 'repeats', 'Frequency', 'select', Input::post('repeats'), self::$events->repeatOptions );
|
||||
Components::set( 'repeatSelect', $repeatSelect );
|
||||
|
||||
if ( ! Forms::check( 'createEvent' ) ) {
|
||||
Issues::add( 'error', [ 'There was an error with your form.' => Check::userErrors() ] );
|
||||
return Views::view( 'calendar.events.create' );
|
||||
}
|
||||
|
||||
$event_id = self::$events->create(
|
||||
$calendarID,
|
||||
Input::post('title'),
|
||||
Date::applyUtcToDate( Date::determineDateInput() ),
|
||||
Input::post('description'),
|
||||
Input::post('location'),
|
||||
Input::post('repeats'),
|
||||
Input::post('color'),
|
||||
0,
|
||||
);
|
||||
if ( ! $event_id ) {
|
||||
Issues::add( 'error', [ 'There was an error creating your event.' => Check::userErrors() ] );
|
||||
return Views::view( 'calendar.events.create' );
|
||||
}
|
||||
|
||||
if ( Input::post('repeats') != 'none' ) {
|
||||
$childrens = self::$events->generateChildEvents( $event_id, true, true );
|
||||
}
|
||||
|
||||
Session::flash( 'success', 'Your Event has been created.' );
|
||||
Redirect::to( 'calendar/'.self::$defaultView.'/'. $calendarID );
|
||||
}
|
||||
public function editEvent( $id = null ) {
|
||||
$calendar = Input::exists('calendar_id') ? Input::post('calendar_id') : '';
|
||||
$event = self::$events->findById( $id );
|
||||
$readableDate = date('Y-m-d H:i:s', $event->event_time);
|
||||
|
||||
if ( $event == false ) {
|
||||
Session::flash( 'error', 'Event not found.' );
|
||||
return Redirect::to( 'calendar/'.self::$defaultView.'/' );
|
||||
}
|
||||
if ( $event->createdBy != App::$activeUser->ID ) {
|
||||
Session::flash( 'error', 'You do not have permission to modify this event.' );
|
||||
return Redirect::to( 'calendar/'.self::$defaultView.'/' );
|
||||
}
|
||||
|
||||
$repeatSelect = HoudiniForms::getFormFieldHtml( 'repeats', 'Frequency', 'select', $event->repeats, self::$events->repeatOptions );
|
||||
Components::set( 'repeatSelect', $repeatSelect );
|
||||
|
||||
// there should be a way to do this natively
|
||||
$event_at = Date::getDateBreakdown( $event->event_time, true );
|
||||
|
||||
// $readableDate = date('Y-m-d H:i:s', $readableDate);
|
||||
$dateSelect = Views::simpleView( 'calendar.dateSelect', $event_at );
|
||||
Components::set( 'dateSelect', $dateSelect );
|
||||
Components::set( 'color', $event->color );
|
||||
|
||||
if ( ! Input::exists( 'submit' ) ) {
|
||||
return Views::view( 'calendar.events.edit', $event );
|
||||
}
|
||||
if ( ! Forms::check( 'editEvent' ) ) {
|
||||
Issues::add( 'error', [ 'There was an error updating your event.' => Check::userErrors() ] );
|
||||
return Views::view( 'calendar.events.edit', $event );
|
||||
}
|
||||
$result = self::$events->update(
|
||||
$id,
|
||||
Input::post('title'),
|
||||
Date::applyUtcToDate( Date::determineDateInput() ),
|
||||
Input::post('description'),
|
||||
Input::post('location'),
|
||||
Input::post('repeats'),
|
||||
Input::post('color'),
|
||||
);
|
||||
|
||||
if ( Input::post('repeats') != 'none' && $event->parent_id == 0 ) {
|
||||
$childrens = self::$events->generateChildEvents( $event->ID, true, true );
|
||||
}
|
||||
|
||||
if ( ! $result ) {
|
||||
Issues::add( 'error', [ 'There was an error updating your event.' => Check::userErrors() ] );
|
||||
return Views::view( 'calendar.events.edit', $event->ID );
|
||||
}
|
||||
Session::flash( 'success', 'Your Event has been updated.' );
|
||||
Redirect::to( 'calendar/'.self::$defaultView.'/'. $event->calendar_id );
|
||||
}
|
||||
public function deleteEvent( $id = null ) {
|
||||
$event = self::$events->findById( $id );
|
||||
if ( $event == false ) {
|
||||
Issues::add( 'error', 'Event not found.' );
|
||||
return $this->index();
|
||||
}
|
||||
if ( $event->createdBy != App::$activeUser->ID ) {
|
||||
Issues::add( 'error', 'You do not have permission to modify this event.' );
|
||||
return $this->index();
|
||||
}
|
||||
$result = self::$events->delete( $id );
|
||||
if ( !$result ) {
|
||||
Session::flash( 'error', 'There was an error deleting the event(s)' );
|
||||
} else {
|
||||
Session::flash( 'success', 'Event deleted' );
|
||||
}
|
||||
return $this->index();
|
||||
}
|
||||
|
||||
/**
|
||||
* Calendars
|
||||
*/
|
||||
public function calendar( $id = null ) {
|
||||
$calendar = $this->findCalendarOrFail( $id );
|
||||
Views::view( 'calendar.calendar.view', $calendar );
|
||||
}
|
||||
public function createCalendar() {
|
||||
$timezoneSelect = HoudiniForms::getTimezoneHtml( Date::getTimezone() );
|
||||
Components::set( 'timezoneSelect', $timezoneSelect );
|
||||
if ( ! Input::exists() ) {
|
||||
return Views::view( 'calendar.calendar.create' );
|
||||
}
|
||||
if ( ! Forms::check( 'createCalendar' ) ) {
|
||||
Issues::add( 'error', [ 'There was an error creating your calendar111.' => Check::userErrors() ] );
|
||||
return Views::view( 'calendar.calendar.create' );
|
||||
}
|
||||
$calendar = self::$calendars->create( Input::post('title'), Input::post('description'), Input::post('timezone'), Input::post('color') );
|
||||
if ( ! $calendar ) {
|
||||
return Views::view( 'calendar.calendar.create' );
|
||||
}
|
||||
Session::flash( 'success', 'Your Calendar has been created.' );
|
||||
Redirect::to( 'calendar/'.self::$defaultView.'/');
|
||||
}
|
||||
public function editCalendar( $id = null ) {
|
||||
$calendar = $this->findCalendarOrFail( $id );
|
||||
|
||||
$timezoneSelect = HoudiniForms::getTimezoneHtml( Date::getTimezone() );
|
||||
Components::set( 'timezoneSelect', $timezoneSelect );
|
||||
Components::set( 'color', $calendar->color );
|
||||
|
||||
if ( ! Input::exists( 'submit' ) ) {
|
||||
return Views::view( 'calendar.calendar.edit', $calendar );
|
||||
}
|
||||
|
||||
if ( !Forms::check( 'editCalendar' ) ) {
|
||||
Issues::add( 'error', [ 'There was an error editing your calendar.' => Check::userErrors() ] );
|
||||
return Views::view( 'calendar.calendar.edit', $calendar );
|
||||
}
|
||||
$result = self::$calendars->update( $id, Input::post('title'), Input::post('description'), Input::post('timezone'), Input::post('color') );
|
||||
if ( !$result ) {
|
||||
Issues::add( 'error', [ 'There was an error updating your calendar.' => Check::userErrors() ] );
|
||||
return Views::view( 'calendar.calendar.edit', $calendar );
|
||||
}
|
||||
Session::flash( 'success', 'Your Calendar has been updated.' );
|
||||
Redirect::to( 'calendar/'.self::$defaultView.'/'. $calendar->ID );
|
||||
}
|
||||
public function deleteCalendar( $id = null ) {
|
||||
$calendar = self::$calendars->findById( $id );
|
||||
if ( $calendar == false ) {
|
||||
Issues::add( 'error', 'Calendar not found.' );
|
||||
return $this->index();
|
||||
}
|
||||
if ( $calendar->createdBy != App::$activeUser->ID ) {
|
||||
Issues::add( 'error', 'You do not have permission to modify this calendar.' );
|
||||
return $this->index();
|
||||
}
|
||||
$results = self::$events->deleteByCalendar( $id );
|
||||
$result = self::$calendars->delete( $id );
|
||||
if ( !$result ) {
|
||||
Session::flash( 'error', 'There was an error deleting the calendar(s)' );
|
||||
} else {
|
||||
Session::flash( 'success', 'Calendar deleted' );
|
||||
}
|
||||
Redirect::to( 'calendar/'.self::$defaultView.'/' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Views
|
||||
*/
|
||||
public function byDay( $id = 0 ) {
|
||||
// Set base components
|
||||
Components::set( 'currentView', __FUNCTION__ );
|
||||
Components::set( 'calendarID', $id );
|
||||
|
||||
// Set components for next / back arrows
|
||||
$nextDayMonth = date( 'M', strtotime( 'tomorrow', self::$selectedDate ) );
|
||||
$nextDay = date( 'd', strtotime( 'tomorrow', self::$selectedDate ) );
|
||||
$lastDayMonth = date( 'M', strtotime( 'yesterday', self::$selectedDate ) );
|
||||
$lastDay = date( 'd', strtotime( 'yesterday', self::$selectedDate ) );
|
||||
Components::set( 'nextDayMonth', $nextDayMonth );
|
||||
Components::set( 'nextDay', $nextDay );
|
||||
Components::set( 'lastDayMonth', $lastDayMonth );
|
||||
Components::set( 'lastDay', $lastDay );
|
||||
|
||||
// Get the data
|
||||
$dayArray = self::$events->dayArray( $id, self::$selectedDate );
|
||||
|
||||
// build the results
|
||||
$selectedHour = Date::getCurrentHour();
|
||||
$day = date( 'd', self::$selectedDate );
|
||||
$month = date( 'M', self::$selectedDate );
|
||||
$year = date( 'Y', self::$selectedDate );
|
||||
$fullDay = [];
|
||||
foreach ( $dayArray as $hour => $events ) {
|
||||
Components::set( 'hour', $hour );
|
||||
$hourCell = new \stdClass();
|
||||
$hourCell->hour = $hour;
|
||||
if ( $hour == $selectedHour ) {
|
||||
$hourCell->hourSelected = ' hour-active';
|
||||
} else {
|
||||
$hourCell->hourSelected = '';
|
||||
}
|
||||
$hourCell->day = $day;
|
||||
$hourCell->month = $month;
|
||||
$hourCell->year = $year;
|
||||
$hourCell->EventCells = Views::simpleView( 'calendar.nav.row', $events );
|
||||
$fullDay[] = $hourCell;
|
||||
}
|
||||
|
||||
// Calendar Top Tabs
|
||||
Components::unset( 'calendarDropdown');
|
||||
$calendarTabs = Views::simpleView('calendar.nav.topTabs');
|
||||
$tabsView = Navigation::activePageSelect( $calendarTabs, '/calendar/byDay/', false, true );
|
||||
// must be done after top-nav gets selected
|
||||
$calendarDropdown = Views::simpleView('calendar.nav.calendarDropdown', self::$calendars->simpleObjectByUser() );
|
||||
$calendarDropdownView = Navigation::activePageSelect( $calendarDropdown, Input::get( 'url' ), false, true ); // add notebookID as second param
|
||||
Components::set( 'calendarDropdown', $calendarDropdownView);
|
||||
Components::set( 'CalendarNav', Template::parse( $tabsView ) );
|
||||
|
||||
Components::set( 'activeDate', date( 'F d, Y', self::$selectedDate ) );
|
||||
Views::view( 'calendar.byDay', $fullDay );
|
||||
}
|
||||
public function byWeek( $id = 0 ) {
|
||||
// Set base components
|
||||
Components::set( 'currentView', __FUNCTION__ );
|
||||
Components::set( 'calendarID', $id );
|
||||
|
||||
// Set components for next / back arrows
|
||||
$lastWeekMonth = date( 'M', strtotime( '-7 days', self::$selectedDate) );
|
||||
$lastWeekDay = date( 'd', strtotime( '-7 days', self::$selectedDate) );
|
||||
$lastWeekYear = date( 'Y', strtotime( '-7 days', self::$selectedDate) );
|
||||
$nextWeekMonth = date( 'M', strtotime( '+7 days', self::$selectedDate) );
|
||||
$nextWeekDay = date( 'd', strtotime( '+7 days', self::$selectedDate) );
|
||||
$nextWeekYear = date( 'Y', strtotime( '+7 days', self::$selectedDate) );
|
||||
Components::set( 'lastWeekMonth', $lastWeekMonth );
|
||||
Components::set( 'lastWeek', $lastWeekDay );
|
||||
Components::set( 'lastYear', $lastWeekYear );
|
||||
Components::set( 'nextWeekMonth', $nextWeekMonth );
|
||||
Components::set( 'nextWeek', $nextWeekDay );
|
||||
Components::set( 'nextYear', $nextWeekYear );
|
||||
|
||||
// Get the data
|
||||
$weekArray = self::$events->weekArray( $id, self::$selectedDate );
|
||||
|
||||
// build the results
|
||||
$presentMonth = date( 'F', self::$selectedDate );
|
||||
$presentDay = date( 'd', self::$selectedDate );
|
||||
foreach ( $weekArray as $week => $days ) {
|
||||
$weekFormat = [];
|
||||
foreach ( $days as $day => $events ) {
|
||||
if ( empty( $first ) ) {
|
||||
$first = true;
|
||||
if ( intval( $presentDay ) >= $day ) {
|
||||
$month = date( 'F', self::$selectedDate );
|
||||
} else {
|
||||
$month = date( 'F', strtotime( '-7 days', self::$selectedDate ) );
|
||||
}
|
||||
}
|
||||
if ( $day == '01' ) {
|
||||
$month = date( 'F', strtotime( '+7 days', self::$selectedDate ) );
|
||||
}
|
||||
Components::set( 'currentMonth', $month );
|
||||
Components::set( 'currentDay', $day );
|
||||
$dayCell = new \stdClass();
|
||||
if ( $presentDay == $day && $presentMonth == $month ) {
|
||||
$dayCell->highlightedDate = ' today';
|
||||
} else {
|
||||
$dayCell->highlightedDate = '';
|
||||
}
|
||||
$dayCell->day = $day;
|
||||
$dayCell->dayEventList = Views::simpleView( 'calendar.nav.cell', $events );
|
||||
$weekFormat[] = $dayCell;
|
||||
}
|
||||
$weekView = Views::simpleView( 'calendar.nav.week', $weekFormat );
|
||||
Components::set( $week . 'Element', $weekView );
|
||||
}
|
||||
|
||||
// Calendar Top Tabs
|
||||
Components::unset( 'calendarDropdown');
|
||||
$calendarTabs = Views::simpleView('calendar.nav.topTabs');
|
||||
$tabsView = Navigation::activePageSelect( $calendarTabs, '/calendar/byWeek/', false, true );
|
||||
// must be done after top-nav gets selected
|
||||
$calendarDropdown = Views::simpleView('calendar.nav.calendarDropdown', self::$calendars->simpleObjectByUser() );
|
||||
$calendarDropdownView = Navigation::activePageSelect( $calendarDropdown, Input::get( 'url' ), false, true ); // add notebookID as second param
|
||||
Components::set( 'calendarDropdown', $calendarDropdownView);
|
||||
Components::set( 'CalendarNav', Template::parse( $tabsView ) );
|
||||
|
||||
Components::set( 'dateWeek', 'Week of ' . date( 'F d, Y', self::$selectedDate ) );
|
||||
Views::view( 'calendar.byWeek' );
|
||||
}
|
||||
public function byMonth( $id = 0 ) {
|
||||
// Set base components
|
||||
Components::set( 'currentView', __FUNCTION__ );
|
||||
Components::set( 'calendarID', $id );
|
||||
|
||||
// Set components for next / back arrows
|
||||
$month = date( 'F', strtotime( 'first day of last month', self::$selectedDate ) );
|
||||
$lastMonthYear = date( 'Y', strtotime( 'first day of last month', self::$selectedDate ) );
|
||||
$nextMonth = date( 'F', strtotime( 'first day of next month', self::$selectedDate ) );
|
||||
$nextMonthYear = date( 'Y', strtotime( 'first day of next month', self::$selectedDate ) );
|
||||
Components::set( 'lastMonth', $month );
|
||||
Components::set( 'lastMonthYear', $lastMonthYear );
|
||||
Components::set( 'nextMonth', $nextMonth );
|
||||
Components::set( 'nextMonthYear', $nextMonthYear );
|
||||
|
||||
// Get the data
|
||||
$monthArray = self::$events->monthArray( $id, self::$selectedDate );
|
||||
|
||||
// build the results
|
||||
$lastMonth = strtotime( 'last month', self::$selectedDate );
|
||||
$presentMonth = date( 'F', self::$selectedDate );
|
||||
$presentDay = date( 'd', self::$selectedDate );
|
||||
foreach ( $monthArray as $week => $days ) {
|
||||
$weekFormat = [];
|
||||
foreach ( $days as $day => $events ) {
|
||||
if ( $day == '01' ) {
|
||||
$month = date( 'F', strtotime( '+1 month', $lastMonth ) );
|
||||
$lastMonth = strtotime( '+1 month', $lastMonth) ;
|
||||
}
|
||||
Components::set( 'currentMonth', $month );
|
||||
Components::set( 'currentDay', $day );
|
||||
$dayCell = new \stdClass();
|
||||
if ( $presentDay == $day && $presentMonth == $month ) {
|
||||
$dayCell->highlightedDate = ' today';
|
||||
} else {
|
||||
$dayCell->highlightedDate = '';
|
||||
}
|
||||
$dayCell->day = $day;
|
||||
// prevent duplicated entries for previous/next month
|
||||
if ( $lastMonth < strtotime( 'this month',self::$selectedDate ) || $lastMonth == strtotime( 'next month',self::$selectedDate )) {
|
||||
$events = [];
|
||||
}
|
||||
$dayCell->dayEventList = Views::simpleView( 'calendar.nav.cell', $events );
|
||||
$weekFormat[] = $dayCell;
|
||||
}
|
||||
|
||||
$weekView = Views::simpleView( 'calendar.nav.week', $weekFormat );
|
||||
Components::set( $week . 'Element', $weekView );
|
||||
}
|
||||
|
||||
// Calendar Top Tabs
|
||||
Components::unset( 'calendarDropdown');
|
||||
$calendarTabs = Views::simpleView('calendar.nav.topTabs');
|
||||
$tabsView = Navigation::activePageSelect( $calendarTabs, '/calendar/byMonth/', false, true );
|
||||
// must be done after top-nav gets selected
|
||||
$calendarDropdown = Views::simpleView('calendar.nav.calendarDropdown', self::$calendars->simpleObjectByUser() );
|
||||
$calendarDropdownView = Navigation::activePageSelect( $calendarDropdown, Input::get( 'url' ), false, true ); // add notebookID as second param
|
||||
Components::set( 'calendarDropdown', $calendarDropdownView);
|
||||
Components::set( 'CalendarNav', Template::parse( $tabsView ) );
|
||||
|
||||
Components::set( 'dateMonth', date( 'F Y', self::$selectedDate ) );
|
||||
Views::view( 'calendar.byMonth' );
|
||||
}
|
||||
public function byYear( $id = 0 ) {
|
||||
// Set base components
|
||||
Components::set( 'calendarID', $id );
|
||||
Components::set( 'currentView', __FUNCTION__ );
|
||||
|
||||
// Set components for next / back arrows
|
||||
$nextYear = date( 'Y', strtotime( 'next year', self::$selectedDate ) );
|
||||
$lastYear = date( 'Y', strtotime( 'last year', self::$selectedDate ) );
|
||||
Components::set( 'lastYear', $lastYear );
|
||||
Components::set( 'nextYear', $nextYear );
|
||||
|
||||
// Get the data
|
||||
$eventList = self::$events->yearArray( $id, self::$selectedDate );
|
||||
|
||||
// Calendar Top Tabs
|
||||
Components::unset( 'calendarDropdown');
|
||||
$calendarTabs = Views::simpleView('calendar.nav.topTabs');
|
||||
$tabsView = Navigation::activePageSelect( $calendarTabs, '/calendar/byYear/', false, true );
|
||||
// must be done after top-nav gets selected
|
||||
$calendarDropdown = Views::simpleView('calendar.nav.calendarDropdown', self::$calendars->simpleObjectByUser() );
|
||||
$calendarDropdownView = Navigation::activePageSelect( $calendarDropdown, Input::get( 'url' ), false, true ); // add notebookID as second param
|
||||
Components::set( 'calendarDropdown', $calendarDropdownView);
|
||||
Components::set( 'CalendarNav', Template::parse( $tabsView ) );
|
||||
|
||||
Components::set( 'dateYear', date( 'Y', self::$selectedDate ) );
|
||||
Views::view( 'calendar.byYear', $eventList );
|
||||
}
|
||||
public function events( $id = 0 ) {
|
||||
Components::set( 'currentView', __FUNCTION__ );
|
||||
Components::set( 'calendarID', $id );
|
||||
if ( ! empty( $id ) ) {
|
||||
$calendar = self::$calendars->findById( $id );
|
||||
if ( $calendar == false ) {
|
||||
Issues::add( 'error', 'Calendar not found.' );
|
||||
return $this->index();
|
||||
}
|
||||
if ( $calendar->createdBy != App::$activeUser->ID ) {
|
||||
Issues::add( 'error', 'You do not have permission to view this calendar.' );
|
||||
return $this->index();
|
||||
}
|
||||
Components::set( 'calendarName', $calendar->title );
|
||||
$eventList = self::$events->findByCalendar( $id );
|
||||
} else {
|
||||
$eventList = self::$events->userEvents( 5 );
|
||||
}
|
||||
|
||||
// Calendar Top Tabs
|
||||
Components::unset( 'calendarDropdown');
|
||||
$calendarTabs = Views::simpleView('calendar.nav.topTabs');
|
||||
$tabsView = Navigation::activePageSelect( $calendarTabs, '/calendar/events/', false, true );
|
||||
// must be done after top-nav gets selected
|
||||
$calendarDropdown = Views::simpleView('calendar.nav.calendarDropdown', self::$calendars->simpleObjectByUser() );
|
||||
$calendarDropdownView = Navigation::activePageSelect( $calendarDropdown, Input::get( 'url' ), false, true ); // add notebookID as second param
|
||||
Components::set( 'calendarDropdown', $calendarDropdownView);
|
||||
Components::set( 'CalendarNav', Template::parse( $tabsView ) );
|
||||
|
||||
Views::view( 'calendar.events.list', $eventList );
|
||||
}
|
||||
|
||||
/**
|
||||
* Support Functions
|
||||
*/
|
||||
private function findCalendarOrFail( $id = null ) {
|
||||
$calendar = self::$calendars->findById( $id );
|
||||
if ( $calendar == false ) {
|
||||
Session::flash( 'error', 'Calendar not found.' );
|
||||
Redirect::to( 'calendar/'.self::$defaultView.'/' );
|
||||
}
|
||||
if ( $calendar->createdBy != App::$activeUser->ID ) {
|
||||
Session::flash( 'error', 'Permissions Error.' );
|
||||
Redirect::to( 'calendar/'.self::$defaultView.'/' );
|
||||
}
|
||||
return $calendar;
|
||||
}
|
||||
private function findEventOrFail( $id = null ) {
|
||||
$event = self::$events->findById( $id );
|
||||
if ( $event == false ) {
|
||||
Session::flash( 'error', 'Event not found.' );
|
||||
Redirect::to( 'calendar/'.self::$defaultView.'/' );
|
||||
}
|
||||
if ( $event->createdBy != App::$activeUser->ID ) {
|
||||
Session::flash( 'error', 'Permissions Error.' );
|
||||
Redirect::to( 'calendar/'.self::$defaultView.'/' );
|
||||
}
|
||||
return $event;
|
||||
}
|
||||
private function getEventBreakdown( $start_timestamp = 0, $end_timestamp = 0, $with_timezone = false ) {
|
||||
|
||||
|
||||
|
||||
$out = new \stdClass();
|
||||
if ( empty( $end_timestamp ) ) {
|
||||
$out->allDay = 'true';
|
||||
// $out->date = ;
|
||||
// $out->time = ;
|
||||
$out->endDate = $out->date;
|
||||
$out->endTime = $out->time;
|
||||
} else {
|
||||
$out->allDay = 'false';
|
||||
|
||||
// $out->date = ;
|
||||
// $out->time = ;
|
||||
$out->endDate = $out->date;
|
||||
$out->endTime = $out->time;
|
||||
}
|
||||
|
||||
|
||||
$timestamp = intval( $timestamp );
|
||||
$init = date('Y-m-d H:i:s', $timestamp);
|
||||
if ( true === $with_timezone ) {
|
||||
$readableDate = self::applyTimezoneToTimestamp( $timestamp );
|
||||
} else {
|
||||
$readableDate = date('Y-m-d H:i:s', $timestamp);
|
||||
}
|
||||
$date = date( 'Y-m-d', strtotime( $readableDate ) );
|
||||
$time = date( 'H:i', strtotime( $readableDate ) );
|
||||
return [
|
||||
'time' => $time,
|
||||
'date' => $date,
|
||||
];
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
@ -1,153 +0,0 @@
|
||||
.calendar-container {
|
||||
margin-left: 20px;
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
.calendar-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.calendar-cell {
|
||||
flex: 1;
|
||||
border: 1px solid #ddd;
|
||||
text-align: center;
|
||||
padding: 10px 0;
|
||||
margin: 0 5px;
|
||||
}
|
||||
|
||||
.calendar-cell h4 {
|
||||
margin: 0;
|
||||
padding: 5px;
|
||||
border-radius: 4px;
|
||||
background-color: #f8f8f8;
|
||||
}
|
||||
|
||||
.hour-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.hour-body {
|
||||
display: flex; /* Add this line to use flexbox */
|
||||
flex-direction: row; /* Ensure the direction is row */
|
||||
flex: 4;
|
||||
border: 1px solid #ddd;
|
||||
text-align: center;
|
||||
padding: 10px 0;
|
||||
margin-left: 5px;
|
||||
margin-right: 5px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.hour-cell {
|
||||
flex: 1;
|
||||
border: 1px solid #ddd;
|
||||
text-align: center;
|
||||
padding: 10px 0;
|
||||
margin-left: 5px;
|
||||
margin-right: 5px;
|
||||
align-items: center;
|
||||
max-width: 250px;
|
||||
}
|
||||
|
||||
.today {
|
||||
background-color: #5cb85c !important;
|
||||
}
|
||||
|
||||
.hour-header, .hour-footer {
|
||||
flex: 0 0 10%;
|
||||
background-color: #f8f8f8;
|
||||
text-align: center;
|
||||
padding: 10px 0;
|
||||
margin: 0 5px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* Adjusting the first and last cell margins to align with the container edges */
|
||||
.calendar-cell:first-child {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.calendar-cell:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.select-container {
|
||||
color: white;
|
||||
}
|
||||
.custom-select {
|
||||
/* color: red; */
|
||||
color: #000;
|
||||
}
|
||||
.custom-select .white {
|
||||
background-color: #ffffff;
|
||||
}
|
||||
.custom-select .primary {
|
||||
background-color: #337ab7;
|
||||
}
|
||||
.custom-select .success {
|
||||
background-color: #5cb85c;
|
||||
}
|
||||
.custom-select .info {
|
||||
background-color: #5bc0de;
|
||||
}
|
||||
.custom-select .warning {
|
||||
background-color: #f0ad4e;
|
||||
}
|
||||
.custom-select .danger {
|
||||
background-color: #d9534f;
|
||||
}
|
||||
.select-container .primary {
|
||||
background-color: #337ab7;
|
||||
}
|
||||
.select-container .white {
|
||||
background-color: #ffffff;
|
||||
}
|
||||
.select-container .success {
|
||||
background-color: #5cb85c;
|
||||
}
|
||||
.select-container .info {
|
||||
background-color: #5bc0de;
|
||||
}
|
||||
.select-container .warning {
|
||||
background-color: #f0ad4e;
|
||||
}
|
||||
.select-container .danger {
|
||||
background-color: #d9534f;
|
||||
}
|
||||
|
||||
.dateDayContainer {
|
||||
width: 250px;
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.dateWeekContainer {
|
||||
width: 450px;
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.dateMonthContainer {
|
||||
width: 250px;
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.dateYearContainer {
|
||||
width: 150px;
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.hour-active {
|
||||
background-color: #217025 !important;
|
||||
/* color: #00ff0d !important; */
|
||||
background-image:none;
|
||||
}
|
@ -1,136 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* app/plugins/calendar/forms.php
|
||||
*
|
||||
* This houses all of the form checking functions for this plugin.
|
||||
*
|
||||
* @package TP Calendar
|
||||
* @version 3.0
|
||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||
* @link https://TheTempusProject.com
|
||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||
*/
|
||||
namespace TheTempusProject\Plugins\Calendar;
|
||||
|
||||
use TheTempusProject\Bedrock\Functions\Input;
|
||||
use TheTempusProject\Bedrock\Functions\Check;
|
||||
use TheTempusProject\Classes\Forms;
|
||||
|
||||
class CalendarForms extends Forms {
|
||||
/**
|
||||
* Adds these functions to the form list.
|
||||
*/
|
||||
public function __construct() {
|
||||
self::addHandler( 'calendarSelect', __CLASS__, 'calendarSelect' );
|
||||
self::addHandler( 'createEvent', __CLASS__, 'createEvent' );
|
||||
self::addHandler( 'createCalendar', __CLASS__, 'createCalendar' );
|
||||
self::addHandler( 'editEvent', __CLASS__, 'editEvent' );
|
||||
self::addHandler( 'editCalendar', __CLASS__, 'editCalendar' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the password re-send form.
|
||||
*
|
||||
* @return {bool}
|
||||
*/
|
||||
public static function calendarSelect() {
|
||||
if ( ! Input::exists( 'calendar_id' ) ) {
|
||||
Check::addUserError( 'You must include a title.' );
|
||||
return false;
|
||||
}
|
||||
// if ( !self::token() ) {
|
||||
// Check::addUserError( 'token - comment out later.' );
|
||||
// return false;
|
||||
// }
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function createEvent() {
|
||||
if ( ! Input::exists( 'title' ) ) {
|
||||
Check::addUserError( 'You must include a title.' );
|
||||
return false;
|
||||
}
|
||||
if ( ! Input::exists( 'date' ) ) {
|
||||
Check::addUserError( 'You must include a date.' );
|
||||
return false;
|
||||
}
|
||||
if ( ! Input::exists( 'time' ) ) {
|
||||
Check::addUserError( 'You must include a time.' );
|
||||
return false;
|
||||
}
|
||||
if ( ! Input::exists( 'repeats' ) ) {
|
||||
Check::addUserError( 'You must include a frequency.' );
|
||||
return false;
|
||||
}
|
||||
if ( ! Input::exists( 'calendar_id' ) ) {
|
||||
Check::addUserError( 'You must select a calendar.' );
|
||||
return false;
|
||||
}
|
||||
// if ( !self::token() ) {
|
||||
// Check::addUserError( 'token - comment out later.' );
|
||||
// return false;
|
||||
// }
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function createCalendar() {
|
||||
if ( ! Input::exists( 'title' ) ) {
|
||||
Check::addUserError( 'You must include a title.' );
|
||||
return false;
|
||||
}
|
||||
if ( ! Input::exists( 'timezone' ) ) {
|
||||
Check::addUserError( 'You must include a timezone.' );
|
||||
return false;
|
||||
}
|
||||
// if ( ! self::token() ) {
|
||||
// Check::addUserError( 'token - comment out later.' );
|
||||
// return false;
|
||||
// }
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function editEvent() {
|
||||
if ( ! Input::exists( 'title' ) ) {
|
||||
Check::addUserError( 'You must include a title.' );
|
||||
return false;
|
||||
}
|
||||
if ( ! Input::exists( 'date' ) ) {
|
||||
Check::addUserError( 'You must include a date.' );
|
||||
return false;
|
||||
}
|
||||
if ( ! Input::exists( 'time' ) ) {
|
||||
Check::addUserError( 'You must include a time.' );
|
||||
return false;
|
||||
}
|
||||
if ( ! Input::exists( 'repeats' ) ) {
|
||||
Check::addUserError( 'You must include a frequency.' );
|
||||
return false;
|
||||
}
|
||||
// if ( !self::token() ) {
|
||||
// Check::addUserError( 'token - comment out later.' );
|
||||
// return false;
|
||||
// }
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function editCalendar() {
|
||||
if ( ! Input::exists( 'submit' ) ) {
|
||||
return false;
|
||||
}
|
||||
if ( ! Input::exists( 'title' ) ) {
|
||||
Check::addUserError( 'You must include a title.' );
|
||||
return false;
|
||||
}
|
||||
if ( ! Input::exists( 'timezone' ) ) {
|
||||
Check::addUserError( 'You must include a timezone.' );
|
||||
return false;
|
||||
}
|
||||
// if ( !self::token() ) {
|
||||
// Check::addUserError( 'token - comment out later.' );
|
||||
// return false;
|
||||
// }
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
new CalendarForms;
|
@ -1,157 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* app/plugins/calendar/models/events.php
|
||||
*
|
||||
* This class is used for the manipulation of the calendars database table.
|
||||
*
|
||||
* @package TP Calendar
|
||||
* @version 3.0
|
||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||
* @link https://TheTempusProject.com
|
||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||
*/
|
||||
namespace TheTempusProject\Models;
|
||||
|
||||
use TheTempusProject\Bedrock\Classes\Config;
|
||||
use TheTempusProject\Bedrock\Functions\Check;
|
||||
use TheTempusProject\Bedrock\Functions\Date;
|
||||
use TheTempusProject\Canary\Bin\Canary as Debug;
|
||||
use TheTempusProject\Classes\DatabaseModel;
|
||||
use TheTempusProject\TheTempusProject as App;
|
||||
use TheTempusProject\Houdini\Classes\Filters;
|
||||
use TheTempusProject\Bedrock\Classes\CustomException;
|
||||
|
||||
class Calendars extends DatabaseModel {
|
||||
public $tableName = 'calendars';
|
||||
public $databaseMatrix = [
|
||||
[ 'title', 'varchar', '256' ],
|
||||
[ 'color', 'varchar', '48' ],
|
||||
[ 'privacy', 'varchar', '48' ],
|
||||
[ 'description', 'text', '' ],
|
||||
[ 'createdBy', 'int', '11' ],
|
||||
[ 'createdAt', 'int', '11' ],
|
||||
[ 'timezone', 'varchar', '256' ],
|
||||
];
|
||||
|
||||
/**
|
||||
* The model constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
public function create( $title, $description = '', $timezone = '', $color = 'default' ) {
|
||||
if ( ! Check::dataTitle( $title ) ) {
|
||||
Debug::info( 'Calendars: illegal title.' );
|
||||
return false;
|
||||
}
|
||||
if ( empty( $timezone ) ) {
|
||||
$timezone = Date::getTimezone();
|
||||
}
|
||||
$fields = [
|
||||
'title' => $title,
|
||||
'description' => $description,
|
||||
'timezone' => $timezone,
|
||||
'color' => $color,
|
||||
'createdBy' => App::$activeUser->ID,
|
||||
'createdAt' => time(),
|
||||
];
|
||||
if ( ! self::$db->insert( $this->tableName, $fields ) ) {
|
||||
new CustomException( 'calendarCreate' );
|
||||
Debug::error( "Calendar: not created " . var_export($fields,true) );
|
||||
return false;
|
||||
}
|
||||
return self::$db->lastId();
|
||||
}
|
||||
|
||||
public function update( $id, $title, $description = '', $timezone = '', $color = 'default' ) {
|
||||
if ( empty( $timezone ) ) {
|
||||
$timezone = Date::getTimezone();
|
||||
}
|
||||
if ( !Check::id( $id ) ) {
|
||||
Debug::info( 'Calendars: illegal ID.' );
|
||||
return false;
|
||||
}
|
||||
if ( !Check::dataTitle( $title ) ) {
|
||||
Debug::info( 'Calendars: illegal title.' );
|
||||
return false;
|
||||
}
|
||||
$fields = [
|
||||
'title' => $title,
|
||||
'description' => $description,
|
||||
'timezone' => $timezone,
|
||||
'color' => $color,
|
||||
];
|
||||
if ( !self::$db->update( $this->tableName, $id, $fields ) ) {
|
||||
new CustomException( 'calendarUpdate' );
|
||||
Debug::error( "Calendar: $id not updated: $fields" );
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function byUser( $limit = null ) {
|
||||
$whereClause = ['createdBy', '=', App::$activeUser->ID];
|
||||
if ( empty( $limit ) ) {
|
||||
$calendars = self::$db->get( $this->tableName, $whereClause );
|
||||
} else {
|
||||
$calendars = self::$db->get( $this->tableName, $whereClause, 'ID', 'DESC', [0, $limit] );
|
||||
}
|
||||
if ( !$calendars->count() ) {
|
||||
Debug::info( 'No Calendars found.' );
|
||||
return false;
|
||||
}
|
||||
return $this->filter( $calendars->results() );
|
||||
}
|
||||
|
||||
public function getName( $id ) {
|
||||
$calendar = self::findById( $id );
|
||||
if (false == $calendar) {
|
||||
return 'unknown';
|
||||
}
|
||||
return $calendar->title;
|
||||
}
|
||||
|
||||
public function getColor( $id ) {
|
||||
$calendar = self::findById( $id );
|
||||
if (false == $calendar) {
|
||||
return 'default';
|
||||
}
|
||||
return $calendar->color;
|
||||
}
|
||||
|
||||
public function simpleByUser() {
|
||||
$whereClause = ['createdBy', '=', App::$activeUser->ID];
|
||||
$calendars = self::$db->get( $this->tableName, $whereClause );
|
||||
if ( !$calendars->count() ) {
|
||||
Debug::warn( 'Could not find any calendars' );
|
||||
return false;
|
||||
}
|
||||
|
||||
$calendars = $calendars->results();
|
||||
$out = [];
|
||||
foreach ( $calendars as &$calendar ) {
|
||||
$out[ $calendar->title ] = $calendar->ID;
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
|
||||
public function simpleObjectByUser() {
|
||||
$whereClause = ['createdBy', '=', App::$activeUser->ID];
|
||||
$calendars = self::$db->get( $this->tableName, $whereClause );
|
||||
if ( !$calendars->count() ) {
|
||||
Debug::warn( 'Could not find any calendars' );
|
||||
return false;
|
||||
}
|
||||
|
||||
$calendars = $calendars->results();
|
||||
$out = [];
|
||||
foreach ( $calendars as &$calendar ) {
|
||||
$obj = new \stdClass();
|
||||
$obj->title = $calendar->title;
|
||||
$obj->ID = $calendar->ID;
|
||||
$out[] = $obj;
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
}
|
@ -1,509 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* app/plugins/calendar/models/events.php
|
||||
*
|
||||
* This class is used for the manipulation of the events database table.
|
||||
*
|
||||
* @package TP Calendar
|
||||
* @version 3.0
|
||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||
* @link https://TheTempusProject.com
|
||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||
*/
|
||||
namespace TheTempusProject\Models;
|
||||
|
||||
use TheTempusProject\Bedrock\Classes\Config;
|
||||
use TheTempusProject\Bedrock\Functions\Check;
|
||||
use TheTempusProject\Canary\Bin\Canary as Debug;
|
||||
use TheTempusProject\Classes\DatabaseModel;
|
||||
use TheTempusProject\TheTempusProject as App;
|
||||
use TheTempusProject\Houdini\Classes\Filters;
|
||||
use TheTempusProject\Models\Calendars;
|
||||
use TheTempusProject\Bedrock\Classes\CustomException;
|
||||
use TheTempusProject\Bedrock\Functions\Date;
|
||||
use TheTempusProject\Bedrock\Classes\Pagination;
|
||||
|
||||
class Events extends DatabaseModel {
|
||||
public $tableName = 'events';
|
||||
public $repeatOptions = [
|
||||
'Does Not Repeat' => 'none',
|
||||
'Every Day' => 'daily',
|
||||
'Every Week' => 'weekly',
|
||||
'Every Month' => 'monthly',
|
||||
'Every Year' => 'yearly',
|
||||
];
|
||||
public $databaseMatrix = [
|
||||
[ 'calendar_id', 'int', '11' ],
|
||||
[ 'title', 'varchar', '256' ],
|
||||
[ 'event_time', 'int', '11' ],
|
||||
[ 'event_ends', 'int', '11' ],
|
||||
[ 'description', 'text', '' ],
|
||||
[ 'location', 'varchar', '256' ],
|
||||
[ 'repeats', 'varchar', '48' ],
|
||||
[ 'color', 'varchar', '48' ],
|
||||
[ 'parent_id', 'int', '11' ],
|
||||
[ 'createdBy', 'int', '11' ],
|
||||
[ 'createdAt', 'int', '11' ],
|
||||
];
|
||||
protected static $calendars;
|
||||
|
||||
/**
|
||||
* The model constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
self::$calendars = new Calendars;
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves a chat form to the db.
|
||||
*
|
||||
* @param string $message -contents of the chat form.
|
||||
* @return bool
|
||||
*/
|
||||
public function create( $calendar_id, $title, $event_time, $description = '', $location = '', $repeats = 'none', $color = 'default', $parent_id = 0 ) {
|
||||
if ( ! Check::id( $calendar_id ) ) {
|
||||
Debug::info( 'calendar event: illegal calendar ID.' );
|
||||
return false;
|
||||
}
|
||||
$fields = [
|
||||
'calendar_id' => $calendar_id,
|
||||
'title' => $title,
|
||||
'event_time' => $event_time,
|
||||
'description' => $description,
|
||||
'location' => $location,
|
||||
'repeats' => $repeats,
|
||||
'color' => $color,
|
||||
'parent_id' => $parent_id,
|
||||
'createdBy' => App::$activeUser->ID,
|
||||
'createdAt' => time(),
|
||||
];
|
||||
if ( !self::$db->insert( $this->tableName, $fields ) ) {
|
||||
Debug::info( 'Events::create - failed to insert to db' );
|
||||
return false;
|
||||
}
|
||||
return self::$db->lastId();
|
||||
}
|
||||
|
||||
public function update( $id, $title, $event_time, $description = '', $location ='', $repeats = 'none', $color = 'default', $parent_id = 0, $calendar_id = '' ) {
|
||||
if ( ! Check::id( $id ) ) {
|
||||
Debug::info( 'calendar event: illegal ID.' );
|
||||
return false;
|
||||
}
|
||||
$fields = [
|
||||
'title' => $title,
|
||||
'event_time' => $event_time,
|
||||
'description' => $description,
|
||||
'location' => $location,
|
||||
'repeats' => $repeats,
|
||||
'color' => $color,
|
||||
'parent_id' => $parent_id,
|
||||
];
|
||||
if ( ! self::$db->update( $this->tableName, $id, $fields ) ) {
|
||||
new CustomException( 'calendarEventUpdate' );
|
||||
Debug::error( "Event: $id not updated: $fields" );
|
||||
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function dayArray( $calendar_id = 0, $date = 0 ) {
|
||||
$whereClause = [ 'createdBy', '=', App::$activeUser->ID, 'AND' ];
|
||||
if ( ! empty( $calendar_id ) ) {
|
||||
$whereClause = array_merge( $whereClause, [ 'calendar_id', '=', $calendar_id, 'AND' ] );
|
||||
}
|
||||
|
||||
$whereClause = array_merge( $whereClause, [
|
||||
'event_time', '>=', Date::getDayStartTimestamp( $date, true ), 'AND',
|
||||
'event_time', '<=', Date::getDayEndTimestamp( $date, true ),
|
||||
] );
|
||||
|
||||
$events = self::$db->get( $this->tableName, $whereClause );
|
||||
if ( ! $events->count() ) {
|
||||
$results = [];
|
||||
} else {
|
||||
$results = $events->results();
|
||||
}
|
||||
$events = $this->sortByEventTimeHour(
|
||||
$this->filter(
|
||||
$results
|
||||
)
|
||||
);
|
||||
// Generate day array
|
||||
$currentDay = [];
|
||||
$currentHour = Date::getDayStartTimestamp( $date );
|
||||
$lastHour = Date::getDayEndTimestamp( $date );
|
||||
while ( $currentHour <= $lastHour ) {
|
||||
$hour = date( 'H', $currentHour );
|
||||
if ( ! empty( $events[ $hour ] ) ) {
|
||||
$dailyEvents = $events[ $hour ];
|
||||
} else {
|
||||
$dailyEvents = [];
|
||||
}
|
||||
$currentDay[ $hour ] = $dailyEvents;
|
||||
$currentHour = strtotime('+1 hour', $currentHour);
|
||||
}
|
||||
return $currentDay;
|
||||
}
|
||||
|
||||
public function weekArray( $calendar_id = 0, $date = null ) {
|
||||
$whereClause = [ 'createdBy', '=', App::$activeUser->ID, 'AND' ];
|
||||
if ( ! empty( $calendar_id ) ) {
|
||||
$whereClause = array_merge( $whereClause, [ 'calendar_id', '=', $calendar_id, 'AND' ] );
|
||||
}
|
||||
|
||||
$whereClause = array_merge( $whereClause, [
|
||||
'event_time', '>=', Date::getWeekStartTimestamp( $date, true ), 'AND',
|
||||
'event_time', '<=', Date::getWeekEndTimestamp( $date, true ),
|
||||
] );
|
||||
$events = self::$db->get( $this->tableName, $whereClause );
|
||||
if ( ! $events->count() ) {
|
||||
$results = [];
|
||||
} else {
|
||||
$results = $events->results();
|
||||
}
|
||||
$events = $this->sortByEventTime(
|
||||
$this->filter(
|
||||
$results
|
||||
),
|
||||
);
|
||||
|
||||
// Generate weeks array
|
||||
$output = [];
|
||||
$currentWeek = [];
|
||||
$currentDay = Date::getWeekStartTimestamp( $date );
|
||||
$weekCounter = 1;
|
||||
$dayCounter = 1;
|
||||
|
||||
// Re-index the array using the date derived from event_time as the key
|
||||
while ( $currentDay <= Date::getWeekEndTimestamp( $date ) ) {
|
||||
$month = date( 'F', $currentDay );
|
||||
$dayOfMonth = date( 'd', $currentDay );
|
||||
if ( ! empty( $events[ $month ][ $dayOfMonth ] ) ) {
|
||||
$dailyEvents = $events[ $month ][ $dayOfMonth ];
|
||||
} else {
|
||||
$dailyEvents = [];
|
||||
}
|
||||
$currentWeek[ $dayOfMonth ] = $dailyEvents;
|
||||
$currentDay = strtotime('+1 day', $currentDay);
|
||||
}
|
||||
|
||||
// Handle any remaining days in the last week
|
||||
if ( ! empty( $currentWeek ) ) {
|
||||
$output["week$weekCounter"] = $currentWeek;
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
public function monthArray( $calendar_id = 0, $date = null ) {
|
||||
$whereClause = [ 'createdBy', '=', App::$activeUser->ID, 'AND' ];
|
||||
if ( ! empty( $calendar_id ) ) {
|
||||
$whereClause = array_merge( $whereClause, [ 'calendar_id', '=', $calendar_id, 'AND' ] );
|
||||
}
|
||||
$whereClause = array_merge( $whereClause, [
|
||||
'event_time', '>=', Date::getMonthStartTimestamp( $date, true ), 'AND',
|
||||
'event_time', '<=', Date::getMonthEndTimestamp( $date, true ),
|
||||
] );
|
||||
|
||||
$events = self::$db->get( $this->tableName, $whereClause );
|
||||
if ( ! $events->count() ) {
|
||||
$results = [];
|
||||
} else {
|
||||
$results = $events->results();
|
||||
}
|
||||
$events = $this->sortByEventTime(
|
||||
$this->filter(
|
||||
$results
|
||||
),
|
||||
);
|
||||
|
||||
// Generate weeks array
|
||||
$output = [];
|
||||
$currentWeek = [];
|
||||
$currentDay = Date::getMonthStartTimestamp( $date );
|
||||
$weekCounter = 1;
|
||||
$dayCounter = 1;
|
||||
|
||||
// Re-index the array using the date derived from event_time as the key
|
||||
while ( $currentDay <= Date::getMonthEndTimestamp( $date ) ) {
|
||||
$month = date( 'F', $currentDay );
|
||||
$dayOfMonth = date( 'd', $currentDay );
|
||||
if ( ! empty( $events[ $month ][ $dayOfMonth ] ) ) {
|
||||
$dailyEvents = $events[ $month ][ $dayOfMonth ];
|
||||
} else {
|
||||
$dailyEvents = [];
|
||||
}
|
||||
$currentWeek[$dayOfMonth] = $dailyEvents;
|
||||
if (count($currentWeek) == 7) {
|
||||
$output["week$weekCounter"] = $currentWeek;
|
||||
$currentWeek = [];
|
||||
$weekCounter++;
|
||||
}
|
||||
$currentDay = strtotime('+1 day', $currentDay);
|
||||
}
|
||||
|
||||
// Handle any remaining days in the last week
|
||||
if ( ! empty( $currentWeek ) ) {
|
||||
$output["week$weekCounter"] = $currentWeek;
|
||||
}
|
||||
while ( $weekCounter < 7 ) {
|
||||
$output["week$weekCounter"] = [];
|
||||
$weekCounter++;
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
public function yearArray( $calendar_id = 0, $date = null ) {
|
||||
if ( empty( $date ) ) {
|
||||
$date = time();
|
||||
}
|
||||
$year = date( 'Y', $date );
|
||||
$firstDayUnix = date( 'U', strtotime( "Jan 1, $year" ) );
|
||||
$lastDayUnix = date( 'U', strtotime( "December 31, $year" ) );
|
||||
$whereClause = [ 'createdBy', '=', App::$activeUser->ID, 'AND' ];
|
||||
if ( ! empty( $calendar_id ) ) {
|
||||
$whereClause = array_merge( $whereClause, [ 'calendar_id', '=', $calendar_id, 'AND' ] );
|
||||
}
|
||||
$whereClause = array_merge( $whereClause, [
|
||||
'event_time', '<=', $lastDayUnix, 'AND',
|
||||
'event_time', '>=', $firstDayUnix,
|
||||
] );
|
||||
$events = self::$db->get( $this->tableName, $whereClause );
|
||||
if ( ! $events->count() ) {
|
||||
Debug::info( 'No ' . $this->tableName . ' data found.' );
|
||||
return [];
|
||||
}
|
||||
return $this->filter( $events->results() );
|
||||
}
|
||||
|
||||
public function compareEventTime($a, $b) {
|
||||
return $a->event_time - $b->event_time;
|
||||
}
|
||||
|
||||
public function sortByEventTimeHour( $results ) {
|
||||
usort( $results, [ $this,'compareEventTime' ] );
|
||||
|
||||
$sortedResults = array();
|
||||
foreach ( $results as $result ) {
|
||||
$date = new \DateTime();
|
||||
$date->setTimestamp( $result->event_time );
|
||||
$timezone = new \DateTimeZone( Date::getTimezone() );
|
||||
$date->setTimezone( $timezone );
|
||||
$dateKey = $date->format('H');
|
||||
$sortedResults[ $dateKey ][] = $result;
|
||||
}
|
||||
return $sortedResults;
|
||||
}
|
||||
|
||||
public function sortByEventTime( $results ) {
|
||||
usort( $results, [ $this,'compareEventTime' ] );
|
||||
|
||||
$sortedResults = array();
|
||||
foreach ( $results as $result ) {
|
||||
$date = new \DateTime();
|
||||
$date->setTimestamp( $result->event_time );
|
||||
$timezone = new \DateTimeZone( Date::getTimezone() );
|
||||
$date->setTimezone( $timezone );
|
||||
$month = $date->format('F');
|
||||
$dateKey = $date->format('d');
|
||||
if ( ! isset( $sortedResults[ $month ] ) ) {
|
||||
$sortedResults[ $month ] = [];
|
||||
}
|
||||
if ( ! isset( $sortedResults[ $month ][ $dateKey ] ) ) {
|
||||
$sortedResults[ $month ][ $dateKey ] = [];
|
||||
}
|
||||
$sortedResults[ $month ][ $dateKey ][] = $result;
|
||||
}
|
||||
return $sortedResults;
|
||||
}
|
||||
|
||||
public function findByCalendar( $id ) {
|
||||
$calendar = $this->verifyCalendar( $id );
|
||||
if ( empty( $calendar ) ) {
|
||||
return [];
|
||||
}
|
||||
$whereClause = [ 'createdBy', '=', App::$activeUser->ID, 'AND' ];
|
||||
$whereClause = array_merge( $whereClause, [ 'calendar_id', '=', $id ] );
|
||||
$events = self::$db->getPaginated( $this->tableName, $whereClause );
|
||||
if ( ! $events->count() ) {
|
||||
Debug::info( 'No ' . $this->tableName . ' data found.' );
|
||||
return [];
|
||||
}
|
||||
return $this->filter( $events->results() );
|
||||
}
|
||||
|
||||
public function userEvents( $limit = 0 ) {
|
||||
$whereClause = [ 'createdBy', '=', App::$activeUser->ID ];
|
||||
$events = self::$db->getPaginated( $this->tableName, $whereClause );
|
||||
if ( ! $events->count() ) {
|
||||
Debug::info( 'No ' . $this->tableName . ' data found.' );
|
||||
return [];
|
||||
}
|
||||
return $this->filter( $events->results() );
|
||||
}
|
||||
|
||||
public function filter( $data, $params = [] ) {
|
||||
$out = [];
|
||||
foreach ( $data as $instance ) {
|
||||
if ( !is_object( $instance ) ) {
|
||||
$instance = $data;
|
||||
$end = true;
|
||||
}
|
||||
$instance->repeatsText = array_search('none', $this->repeatOptions);
|
||||
$instance->calendarName = self::$calendars->getName( $instance->calendar_id );
|
||||
if ( empty( $instance->color ) || $instance->color == 'default' || $instance->color == 'none') {
|
||||
$instance->displayColor = self::$calendars->getColor( $instance->calendar_id );
|
||||
} else {
|
||||
$instance->displayColor = $instance->color;
|
||||
}
|
||||
$out[] = $instance;
|
||||
if ( !empty( $end ) ) {
|
||||
$out = $out[0];
|
||||
break;
|
||||
}
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
|
||||
public function today( $limit = 0 ) {
|
||||
$date = time();
|
||||
$day = date('d', $date);
|
||||
$month = date('M', $date);
|
||||
$year = date( 'Y', $date );
|
||||
$firstDayUnix = date( 'U', strtotime( "00:00:00 $day $month $year" ) );
|
||||
$lastDayUnix = date( 'U', strtotime( "23:59:59 $day $month $year" ) );
|
||||
$whereClause = [ 'createdBy', '=', App::$activeUser->ID, 'AND' ];
|
||||
$whereClause = array_merge( $whereClause, [
|
||||
'event_time', '<=', $lastDayUnix, 'AND',
|
||||
'event_time', '>=', $firstDayUnix,
|
||||
] );
|
||||
if ( empty( $limit ) ) {
|
||||
$events = self::$db->get( $this->tableName, $whereClause );
|
||||
} else {
|
||||
$events = self::$db->get( $this->tableName, $whereClause, 'ID', 'DESC', [0, $limit] );
|
||||
}
|
||||
if ( ! $events->count() ) {
|
||||
Debug::info( 'No ' . $this->tableName . ' data found.' );
|
||||
return [];
|
||||
}
|
||||
return $this->filter( $events->results() );
|
||||
}
|
||||
|
||||
private function verifyCalendar( $calendar_id ) {
|
||||
if ( ! Check::id( $calendar_id ) ) {
|
||||
Debug::info( 'Invalid Calendar ID' );
|
||||
return false;
|
||||
}
|
||||
$calendar = self::$calendars->findById( $calendar_id );
|
||||
if ( $calendar == false ) {
|
||||
Debug::info( 'Calendar not found' );
|
||||
return false;
|
||||
}
|
||||
if ( $calendar->createdBy != App::$activeUser->ID ) {
|
||||
Debug::info( 'You do not have permission to view this calendar' );
|
||||
return false;
|
||||
}
|
||||
return $calendar;
|
||||
}
|
||||
|
||||
public function deleteByCalendar( $calendar_id ) {
|
||||
$calendar = $this->verifyCalendar( $calendar_id );
|
||||
if ( empty( $calendar ) ) {
|
||||
return [];
|
||||
}
|
||||
$whereClause = [ 'createdBy', '=', App::$activeUser->ID, 'AND' ];
|
||||
$whereClause = array_merge( $whereClause, [ 'calendar_id', '=', $calendar_id ] );
|
||||
$events = self::$db->get( $this->tableName, $whereClause );
|
||||
if ( ! $events->count() ) {
|
||||
Debug::info( 'No ' . $this->tableName . ' data found.' );
|
||||
return [];
|
||||
}
|
||||
foreach( $events->results() as $event ) {
|
||||
$this->deleteByParent( $event->ID );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function deleteByParent( $event_id ) {
|
||||
$whereClause = [ 'createdBy', '=', App::$activeUser->ID, 'AND' ];
|
||||
$whereClause = array_merge( $whereClause, [ 'parent_id', '=', $event_id ] );
|
||||
$events = self::$db->get( $this->tableName, $whereClause );
|
||||
if ( ! $events->count() ) {
|
||||
Debug::info( 'No ' . $this->tableName . ' data found.' );
|
||||
return [];
|
||||
}
|
||||
foreach( $events->results() as $event ) {
|
||||
$this->delete( $event->ID );
|
||||
}
|
||||
// need to delete all child events accordingly
|
||||
return true;
|
||||
}
|
||||
|
||||
public function delete( $idArray ) {
|
||||
if ( !is_array( $idArray ) ) {
|
||||
$idArray = [ $idArray ];
|
||||
}
|
||||
return parent::delete( $idArray );
|
||||
}
|
||||
|
||||
public function generateChildEvents( $event_id, $remove_existing_children = true, $remove_history = false ) {
|
||||
$event = self::findById( $event_id );
|
||||
if (empty($event)) {
|
||||
return false;
|
||||
}
|
||||
if ($event->parent_id != 0) {
|
||||
return false;
|
||||
}
|
||||
if (!in_array($event->repeats, $this->repeatOptions)) {
|
||||
return false;
|
||||
}
|
||||
$startDate = time();
|
||||
$whereClause = [
|
||||
'parent_id', '=', $event_id,
|
||||
];
|
||||
if ( $remove_history && ! $remove_existing_children) {
|
||||
$whereClause = array_merge( $whereClause, [ 'AND', 'event_time', '<=', $startDate ] );
|
||||
} elseif ( $remove_existing_children && ! $remove_history ) {
|
||||
$whereClause = array_merge( $whereClause, [ 'AND', 'event_time', '>=', $startDate ] );
|
||||
} elseif ( !$remove_existing_children && !$remove_history ) {
|
||||
return false;
|
||||
}
|
||||
self::$db->delete($this->tableName, $whereClause);
|
||||
|
||||
switch ($event->repeats) {
|
||||
case 'daily':
|
||||
return $this->generateEvents( $event, 'P90D' );
|
||||
case 'weekly':
|
||||
return $this->generateEvents( $event, 'P1W' );
|
||||
case 'monthly':
|
||||
return $this->generateEvents( $event, 'P1M' );
|
||||
case 'yearly':
|
||||
return $this->generateEvents( $event, 'P1Y' );
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private function generateEvents( $event, $interval, $years = 2 ) {
|
||||
$endDate = strtotime('+'.$years.' years');
|
||||
$interval = new \DateInterval( $interval );
|
||||
$period = new \DatePeriod(new \DateTime('@' . $event->event_time), $interval, new \DateTime('@' . $endDate));
|
||||
foreach ($period as $date) {
|
||||
if ( $date->getTimestamp() <= time() ) {
|
||||
continue;
|
||||
}
|
||||
$result = $this->create(
|
||||
$event->calendar_id,
|
||||
$event->title,
|
||||
$date->getTimestamp(),
|
||||
$event->description,
|
||||
$event->location,
|
||||
$event->repeats,
|
||||
$event->color,
|
||||
$event->ID,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,84 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* app/plugins/calendar/plugin.php
|
||||
*
|
||||
* This houses all of the main plugin info and functionality.
|
||||
*
|
||||
* @package TP Calendar
|
||||
* @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 TheTempusProject\Classes\Plugin;
|
||||
use TheTempusProject\Models\Events;
|
||||
use TheTempusProject\Models\Calendars;
|
||||
use TheTempusProject\Houdini\Classes\Components;
|
||||
use TheTempusProject\Houdini\Classes\Template;
|
||||
|
||||
class Calendar extends Plugin {
|
||||
public $pluginName = 'TP Calendar';
|
||||
public $configName = 'calendar';
|
||||
public $pluginAuthor = 'JoeyK';
|
||||
public $pluginWebsite = 'https://TheTempusProject.com';
|
||||
public $modelVersion = '1.0';
|
||||
public $pluginVersion = '3.0';
|
||||
public $pluginDescription = 'A simple plugin which adds a site wide calendar system.';
|
||||
public $permissionMatrix = [
|
||||
'useCalendar' => [
|
||||
'pretty' => 'Can use the calendar feature',
|
||||
'default' => false,
|
||||
],
|
||||
'createEvents' => [
|
||||
'pretty' => 'Can add events to calendars',
|
||||
'default' => false,
|
||||
],
|
||||
];
|
||||
public $main_links = [
|
||||
[
|
||||
'text' => 'Calendar',
|
||||
'url' => '{ROOT_URL}calendar/index',
|
||||
'filter' => 'loggedin',
|
||||
],
|
||||
];
|
||||
public $configMatrix = [
|
||||
'enabled' => [
|
||||
'type' => 'radio',
|
||||
'pretty' => 'Enable Calendar.',
|
||||
'default' => true,
|
||||
],
|
||||
];
|
||||
public $preferenceMatrix = [
|
||||
'calendarPreference' => [
|
||||
'pretty' => 'Default Calendar View',
|
||||
'type' => 'select',
|
||||
'default' => 'byMonth',
|
||||
'options' => [
|
||||
'Daily' => 'byDay',
|
||||
'Weekly' => 'byWeek',
|
||||
'Monthly' => 'byMonth',
|
||||
'Yearly' => 'byYear',
|
||||
'All Events' => 'events',
|
||||
],
|
||||
],
|
||||
'weekStart' => [
|
||||
'pretty' => 'First day of the week for the Calendar',
|
||||
'type' => 'select',
|
||||
'default' => 'sunday',
|
||||
'options' => [
|
||||
'Sunday' => '6',
|
||||
'Monday' => '7',
|
||||
],
|
||||
],
|
||||
];
|
||||
public $events;
|
||||
public $calendars;
|
||||
|
||||
public function __construct( $load = false ) {
|
||||
$this->events = new Events;
|
||||
$this->calendars = new Calendars;
|
||||
parent::__construct( $load );
|
||||
}
|
||||
}
|
@ -1,41 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* app/plugins/blog/templates/blog.inc.php
|
||||
*
|
||||
* This is the loader for the blog template.
|
||||
*
|
||||
* @package TP Blog
|
||||
* @version 3.0
|
||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||
* @link https://TheTempusProject.com
|
||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||
*/
|
||||
namespace TheTempusProject\Templates;
|
||||
|
||||
use TheTempusProject\Plugins\Calendar;
|
||||
|
||||
use TheTempusProject\Houdini\Classes\Components;
|
||||
use TheTempusProject\Houdini\Classes\Navigation;
|
||||
use TheTempusProject\Houdini\Classes\Views;
|
||||
use TheTempusProject\Houdini\Classes\Template;
|
||||
use TheTempusProject\Bedrock\Functions\Input;
|
||||
use TheTempusProject\Models\Events;
|
||||
use TheTempusProject\Models\Calendars;
|
||||
|
||||
class CalendarLoader extends DefaultLoader {
|
||||
/**
|
||||
* This is the function used to generate any components that may be
|
||||
* needed by this template.
|
||||
*/
|
||||
public function __construct() {
|
||||
$events = new Events;
|
||||
$calendars = new Calendars;
|
||||
Navigation::setCrumbComponent( 'CALENDAR_BREADCRUMBS', Input::get( 'url' ) );
|
||||
Components::set( 'todaysDate', date( 'F d, Y', time()) );
|
||||
Components::set( 'currentDay', date( 'F d, Y', time()) );
|
||||
Components::set( 'weekOf', 'Week of ' . date( 'F d, Y', strtotime( 'this week' ) ) );
|
||||
Components::set( 'year', date( 'Y', time() ));
|
||||
Components::set( 'month', date( 'F', time() ));
|
||||
parent::__construct();
|
||||
}
|
||||
}
|
@ -1,96 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<!--
|
||||
* app/plugins/calendar/templates/calendar.tpl
|
||||
*
|
||||
* @package TP Calendar
|
||||
* @version 3.0
|
||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||
* @link https://TheTempusProject.com
|
||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta property="og:url" content="{CURRENT_URL}">
|
||||
<meta name='twitter:card' content='summary' />
|
||||
<title>{TITLE}</title>
|
||||
<meta itemprop="name" content="{TITLE}">
|
||||
<meta name="twitter:title" content="{TITLE}">
|
||||
<meta property="og:title" content="{TITLE}">
|
||||
<meta name="description" content="{PAGE_DESCRIPTION}">
|
||||
<meta itemprop="description" content="{PAGE_DESCRIPTION}">
|
||||
<meta name="twitter:description" content="{PAGE_DESCRIPTION}">
|
||||
<meta property="og:description" content="{PAGE_DESCRIPTION}">
|
||||
<meta itemprop="image" content="{META_IMAGE}">
|
||||
<meta name="twitter:image" content="{META_IMAGE}">
|
||||
<meta property="og:image" content="{META_IMAGE}">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="author" content="The Tempus Project">
|
||||
{ROBOT}
|
||||
<link rel="alternate" hreflang="en-us" href="alternateURL">
|
||||
<link rel="icon" href="{ROOT_URL}images/favicon.ico">
|
||||
<!-- Required CSS -->
|
||||
<link rel="stylesheet" href="{FONT_AWESOME_URL}font-awesome.min.css" crossorigin="anonymous">
|
||||
<link rel="stylesheet" href="{BOOTSTRAP_CDN}css/bootstrap-theme.min.css" crossorigin="anonymous">
|
||||
<link rel="stylesheet" href="{BOOTSTRAP_CDN}css/bootstrap.min.css" crossorigin="anonymous">
|
||||
<!-- RSS -->
|
||||
<link rel="alternate" href="{ROOT_URL}blog/rss" title="{TITLE} Feed" type="application/rss+xml" />
|
||||
<!-- Custom styles for this template -->
|
||||
{TEMPLATE_CSS_INCLUDES}
|
||||
<link rel="stylesheet" href="{ROOT_URL}app/plugins/calendar/css/calendar.css" />
|
||||
</head>
|
||||
<body>
|
||||
<nav class="navbar navbar-inverse navbar-fixed-top" role="navigation">
|
||||
<!--Brand and toggle should get grouped for better mobile display -->
|
||||
<div class="navbar-header">
|
||||
<a href="{ROOT_URL}" class="navbar-brand">{SITENAME}</a>
|
||||
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-ex1-collapse" style="">
|
||||
<span class="sr-only">Toggle navigation</span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="container-fluid">
|
||||
<div class="collapse navbar-collapse navbar-ex1-collapse">
|
||||
{topNavLeft}
|
||||
<div class="navbar-right">
|
||||
<ul class="nav navbar-nav">
|
||||
{topNavRight}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<div class="container-fluid">
|
||||
<div class="foot-pad">
|
||||
{ISSUES}
|
||||
<div class="row">
|
||||
<div class="container">
|
||||
{ERROR}
|
||||
{NOTICE}
|
||||
{SUCCESS}
|
||||
</div>
|
||||
</div>
|
||||
{/ISSUES}
|
||||
<div class="row">
|
||||
<div class="container-fluid calendar-container">
|
||||
<div class="row">
|
||||
{CalendarNav}
|
||||
{CONTENT}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<footer>
|
||||
{COPY}
|
||||
</footer>
|
||||
<!-- Bootstrap core JavaScript and jquery -->
|
||||
<script src="{JQUERY_CDN}jquery.min.js" crossorigin="anonymous"></script>
|
||||
<script src="{BOOTSTRAP_CDN}js/bootstrap.min.js" crossorigin="anonymous"></script>
|
||||
<!-- Custom javascript for this template -->
|
||||
{TEMPLATE_JS_INCLUDES}
|
||||
</body>
|
||||
</html>
|
@ -1,25 +0,0 @@
|
||||
<h2 class="pull-left">
|
||||
<a href="{ROOT_URL}calendar/byDay/{calendarID}?day={lastDay}&month={lastDayMonth}" role="button" class="btn btn-primary">
|
||||
<i class="glyphicon glyphicon-chevron-left"></i>
|
||||
</a>
|
||||
<span class="dateDayContainer">{activeDate}</span>
|
||||
<a href="{ROOT_URL}calendar/byDay/{calendarID}?day={nextDay}&month={nextDayMonth}" role="button" class="btn btn-primary">
|
||||
<i class="glyphicon glyphicon-chevron-right"></i>
|
||||
</a>
|
||||
</h2>
|
||||
{dateDropdown}
|
||||
<div class="container-fluid">
|
||||
{LOOP}
|
||||
<div class="hour-row{hourSelected}">
|
||||
<h2 class="hour-header">{hour}:00</h2>
|
||||
{EventCells}
|
||||
<span class="hour-footer">
|
||||
<a href="{ROOT_URL}calendar/createEvent?calendar_id={calendarID}&hour={hour}&day={day}" class="btn btn-sm btn-success" role="button"><i class="glyphicon glyphicon-plus"></i></a>
|
||||
</span>
|
||||
</div>
|
||||
{/LOOP}
|
||||
{ALT}
|
||||
<div class="hour-row{hourSelected}">
|
||||
</div>
|
||||
{/ALT}
|
||||
</div>
|
@ -1,34 +0,0 @@
|
||||
<h2 class="pull-left">
|
||||
<a href="{ROOT_URL}calendar/byMonth/{calendarID}?month={lastMonth}&year={lastMonthYear}" role="button" class="btn btn-primary">
|
||||
<i class="glyphicon glyphicon-chevron-left"></i>
|
||||
</a>
|
||||
<span class="dateMonthContainer">{dateMonth}</span>
|
||||
<a href="{ROOT_URL}calendar/byMonth/{calendarID}?month={nextMonth}&year={nextMonthYear}" role="button" class="btn btn-primary">
|
||||
<i class="glyphicon glyphicon-chevron-right"></i>
|
||||
</a>
|
||||
</h2>
|
||||
{dateDropdown}
|
||||
<div class="container-fluid">
|
||||
<!-- Header -->
|
||||
<div class="row calendar-row">
|
||||
<div class="col-xs-1 calendar-cell"><h4>Sunday</h4></div>
|
||||
<div class="col-xs-1 calendar-cell"><h4>Monday</h4></div>
|
||||
<div class="col-xs-1 calendar-cell"><h4>Tuesday</h4></div>
|
||||
<div class="col-xs-1 calendar-cell"><h4>Wednesday</h4></div>
|
||||
<div class="col-xs-1 calendar-cell"><h4>Thursday</h4></div>
|
||||
<div class="col-xs-1 calendar-cell"><h4>Friday</h4></div>
|
||||
<div class="col-xs-1 calendar-cell"><h4>Saturday</h4></div>
|
||||
</div>
|
||||
<!-- Week 1 -->
|
||||
{week1Element}
|
||||
<!-- Week 2 -->
|
||||
{week2Element}
|
||||
<!-- Week 3 -->
|
||||
{week3Element}
|
||||
<!-- Week 4 -->
|
||||
{week4Element}
|
||||
<!-- Week 5 -->
|
||||
{week5Element}
|
||||
<!-- Week 6 -->
|
||||
{week6Element}
|
||||
</div>
|
@ -1,25 +0,0 @@
|
||||
|
||||
<h2 class="pull-left">
|
||||
<a href="{ROOT_URL}calendar/byWeek/{calendarID}?month={lastWeekMonth}&day={lastWeek}&year={lastYear}" role="button" class="btn btn-primary">
|
||||
<i class="glyphicon glyphicon-chevron-left"></i>
|
||||
</a>
|
||||
<span class="dateWeekContainer">{dateWeek}</span>
|
||||
<a href="{ROOT_URL}calendar/byWeek/{calendarID}?month={nextWeekMonth}&day={nextWeek}&year={nextYear}" role="button" class="btn btn-primary">
|
||||
<i class="glyphicon glyphicon-chevron-right"></i>
|
||||
</a>
|
||||
</h2>
|
||||
{dateDropdown}
|
||||
<div class="container-fluid">
|
||||
<!-- Header -->
|
||||
<div class="row calendar-row">
|
||||
<div class="col-xs-1 calendar-cell"><h4>Sunday</h4></div>
|
||||
<div class="col-xs-1 calendar-cell"><h4>Monday</h4></div>
|
||||
<div class="col-xs-1 calendar-cell"><h4>Tuesday</h4></div>
|
||||
<div class="col-xs-1 calendar-cell"><h4>Wednesday</h4></div>
|
||||
<div class="col-xs-1 calendar-cell"><h4>Thursday</h4></div>
|
||||
<div class="col-xs-1 calendar-cell"><h4>Friday</h4></div>
|
||||
<div class="col-xs-1 calendar-cell"><h4>Saturday</h4></div>
|
||||
</div>
|
||||
<!-- Week 1 -->
|
||||
{week1Element}
|
||||
</div>
|
@ -1,42 +0,0 @@
|
||||
<h2 class="pull-left">
|
||||
<a href="{ROOT_URL}calendar/byYear/{calendarID}?year={lastYear}" role="button" class="btn btn-primary">
|
||||
<i class="glyphicon glyphicon-chevron-left"></i>
|
||||
</a>
|
||||
<span class="dateYearContainer">{dateYear}</span>
|
||||
<a href="{ROOT_URL}calendar/byYear/{calendarID}?year={nextYear}" role="button" class="btn btn-primary">
|
||||
<i class="glyphicon glyphicon-chevron-right"></i>
|
||||
</a>
|
||||
</h2>
|
||||
{dateDropdown}
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width: 10%">ID</th>
|
||||
<th style="width: 20%">Time</th>
|
||||
<th style="width: 40%">Title</th>
|
||||
<th style="width: 10%"></th>
|
||||
<th style="width: 10%"></th>
|
||||
<th style="width: 10%"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{LOOP}
|
||||
<tr>
|
||||
<td style="text-align: center;">{ID}</td>
|
||||
<td style="text-align: center;">{DTC}{event_time}{/DTC}</td>
|
||||
<td style="text-align: center;">{title}</td>
|
||||
<td><a href="{ROOT_URL}calendar/event/{ID}" class="btn btn-sm btn-primary" role="button"><i class="glyphicon glyphicon-open"></i></a></td>
|
||||
<td><a href="{ROOT_URL}calendar/editEvent/{ID}" class="btn btn-sm btn-warning" role="button"><i class="glyphicon glyphicon-edit"></i></a></td>
|
||||
<td><a href="{ROOT_URL}calendar/deleteEvent/{ID}" class="btn btn-sm btn-danger" role="button"><i class="glyphicon glyphicon-trash"></i></a></td>
|
||||
</tr>
|
||||
{/LOOP}
|
||||
{ALT}
|
||||
<tr>
|
||||
<td style="text-align: center;" colspan="6">
|
||||
No results to show.
|
||||
</td>
|
||||
</tr>
|
||||
{/ALT}
|
||||
</tbody>
|
||||
</table>
|
||||
<a href="{ROOT_URL}calendar/createEvent" class="btn btn-sm btn-primary" role="button">Create</a>
|
@ -1,34 +0,0 @@
|
||||
<legend>Create Calendar</legend>
|
||||
<form action="" method="post" class="form-horizontal">
|
||||
<input type="hidden" name="token" value="{TOKEN}">
|
||||
<div class="form-group">
|
||||
<label for="title" class="col-lg-3 control-label">Title</label>
|
||||
<div class="col-lg-3">
|
||||
<input type="text" class="form-control" name="title" id="title">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="description" class="col-lg-3 control-label">Description</label>
|
||||
<div class="col-lg-3">
|
||||
<textarea class="form-control" name="description" maxlength="2000" rows="10" cols="50" id="description"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="description" class="col-lg-3 control-label">Timezone</label>
|
||||
<div class="col-lg-3">
|
||||
{timezoneSelect}
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="color" class="col-lg-3 control-label">Calendar Color</label>
|
||||
<div class="col-lg-3 select-container" id="colorContainer">
|
||||
{colorSelect}
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="submit" class="col-lg-3 control-label"></label>
|
||||
<div class="col-lg-3">
|
||||
<button name="submit" value="submit" type="submit" class="btn btn-lg btn-primary center-block ">Submit</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
@ -1,29 +0,0 @@
|
||||
<legend>Edit Calendar</legend>
|
||||
<form action="" method="post" class="form-horizontal">
|
||||
<div class="form-group">
|
||||
<label for="title" class="col-lg-3 control-label">Title</label>
|
||||
<div class="col-lg-3">
|
||||
<input type="text" class="form-check-input form-control" name="title" id="title" value="{title}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="description" class="col-lg-3 control-label">Description</label>
|
||||
<div class="col-lg-6">
|
||||
<textarea class="form-control" name="description" maxlength="2000" rows="10" cols="50" id="description">{description}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="description" class="col-lg-3 control-label">Timezone</label>
|
||||
<div class="col-lg-3">
|
||||
{timezoneSelect}
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="color" class="col-lg-3 control-label">Calendar Color</label>
|
||||
<div class="col-lg-3 select-container" id="colorContainer">
|
||||
{colorSelect}
|
||||
</div>
|
||||
</div>
|
||||
<input type="hidden" name="token" value="{TOKEN}">
|
||||
<button name="submit" value="submit" type="submit" class="btn btn-lg btn-primary center-block">Submit</button>
|
||||
</form>
|
@ -1,45 +0,0 @@
|
||||
<legend>Calendars</legend>
|
||||
<form action="{ROOT_URL}calendar/deleteCalendar" method="post">
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width: 5%">ID</th>
|
||||
<th style="width: 20%">Title</th>
|
||||
<th style="width: 50%">Description</th>
|
||||
<th style="width: 5%"></th>
|
||||
<th style="width: 5%"></th>
|
||||
<th style="width: 5%"></th>
|
||||
<th style="width: 5%"></th>
|
||||
<th style="width: 5%">
|
||||
<input type="checkbox" onchange="checkAll(this)" name="check.br" value="CAL_[]"/>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{LOOP}
|
||||
<tr>
|
||||
<td align="center">{ID}</td>
|
||||
<td align="center">{title}</td>
|
||||
<td>{description}</td>
|
||||
<td><a href="{ROOT_URL}calendar/byMonth/{ID}" class="btn btn-sm btn-primary" role="button"><i class="glyphicon glyphicon-share-alt"></i></a></td>
|
||||
<td><a href="{ROOT_URL}calendar/calendar/{ID}" class="btn btn-sm btn-primary" role="button"><i class="glyphicon glyphicon-info-sign"></i></a></td>
|
||||
<td><a href="{ROOT_URL}calendar/editCalendar/{ID}" class="btn btn-sm btn-warning" role="button"><i class="glyphicon glyphicon-edit"></i></a></td>
|
||||
<td><a href="{ROOT_URL}calendar/deleteCalendar/{ID}" class="btn btn-sm btn-danger" role="button"><i class="glyphicon glyphicon-trash"></i></a></td>
|
||||
<td>
|
||||
<input type="checkbox" value="{ID}" name="CAL_[]">
|
||||
</td>
|
||||
</tr>
|
||||
{/LOOP}
|
||||
{ALT}
|
||||
<tr>
|
||||
<td align="center" colspan="7">
|
||||
No results to show.
|
||||
</td>
|
||||
</tr>
|
||||
{/ALT}
|
||||
</tbody>
|
||||
</table>
|
||||
<a href="{ROOT_URL}calendar/createCalendar" class="btn btn-sm btn-primary" role="button">Create</a>
|
||||
<button name="submit" value="submit" type="submit" class="btn btn-sm btn-danger">Delete</button>
|
||||
</form>
|
||||
<br />
|
@ -1,42 +0,0 @@
|
||||
<div class="container col-md-4 col-lg-4">
|
||||
<div class="row">
|
||||
<div class="panel panel-primary">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">Calendar</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div class="row">
|
||||
<div class="">
|
||||
<table class="table table-user-primary">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="left" width="200"><b>Title</b></td>
|
||||
<td align="right">{title}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Created</b></td>
|
||||
<td align="right">{DTC}{createdAt}{/DTC}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" colspan="2"><b>Description</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2">{description}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>TimeZone</b></td>
|
||||
<td align="right">{timezone}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel-footer">
|
||||
<a href="{ROOT_URL}calendar/deleteCalendar/{ID}" class="btn btn-md btn-danger" role="button">Delete</a>
|
||||
<a href="{ROOT_URL}calendar/editCalendar/{ID}" class="btn btn-md btn-warning" role="button">Edit</a>
|
||||
<a href="{ROOT_URL}calendar/byMonth/{ID}" class="btn btn-md btn-primary" role="button">View Events</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -1,20 +0,0 @@
|
||||
<div class="form-group">
|
||||
<label for="day" class="col-lg-3 control-label">All-Day Event</label>
|
||||
<div class="col-lg-3">
|
||||
<input class="" type="checkbox" name="allDay" id="allDay" value="true" {CHECKED:allDay=true}>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="month" class="col-lg-3 control-label">Event Start</label>
|
||||
<div class="col-lg-3">
|
||||
<input type="date" name="date" id="date" class="form-control" value="{date}" />
|
||||
<input type="time" name="time" id="time" class="form-control" value="{time}" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="month" class="col-lg-3 control-label">Event End</label>
|
||||
<div class="col-lg-3">
|
||||
<input type="date" name="endDate" id="endDate" class="form-control" value="{endDate}" />
|
||||
<input type="time" name="endTime" id="endTime" class="form-control" value="{endTime}" />
|
||||
</div>
|
||||
</div>
|
@ -1,37 +0,0 @@
|
||||
<legend>Create Event</legend>
|
||||
<form action="" method="post" class="form-horizontal">
|
||||
<input type="hidden" name="token" value="{TOKEN}">
|
||||
{calendarSelect}
|
||||
<div class="form-group">
|
||||
<label for="title" class="col-lg-3 control-label">Title</label>
|
||||
<div class="col-lg-3">
|
||||
<input type="text" class="form-control" name="title" id="title">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="description" class="col-lg-3 control-label">Description</label>
|
||||
<div class="col-lg-3">
|
||||
<textarea class="form-control" name="description" maxlength="2000" rows="6" cols="30" id="description"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="location" class="col-lg-3 control-label">Location</label>
|
||||
<div class="col-lg-3">
|
||||
<input type="text" class="form-control" name="location" id="location">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="color" class="col-lg-3 control-label">Event Color</label>
|
||||
<div class="col-lg-3 select-container" id="colorContainer">
|
||||
{colorSelect}
|
||||
</div>
|
||||
</div>
|
||||
{dateSelect}
|
||||
{repeatSelect}
|
||||
<div class="form-group">
|
||||
<label for="submit" class="col-lg-3 control-label"></label>
|
||||
<div class="col-lg-3">
|
||||
<button name="submit" value="submit" type="submit" class="btn btn-lg btn-primary center-block">Submit</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
@ -1,31 +0,0 @@
|
||||
<legend>Edit Event</legend>
|
||||
<form action="" method="post" class="form-horizontal">
|
||||
<div class="form-group">
|
||||
<label for="title" class="col-lg-3 control-label">Title</label>
|
||||
<div class="col-lg-3">
|
||||
<input type="text" class="form-control" name="title" id="title" value="{title}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="description" class="col-lg-3 control-label">Description</label>
|
||||
<div class="col-lg-6">
|
||||
<textarea class="form-control" name="description" maxlength="2000" rows="10" cols="50" id="description">{description}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="location" class="col-lg-3 control-label">Location</label>
|
||||
<div class="col-lg-6">
|
||||
<input type="text" class="form-control" name="location" id="location" value="{location}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="color" class="col-lg-3 control-label">Event Color</label>
|
||||
<div class="col-lg-3 select-container" id="colorContainer">
|
||||
{colorSelect}
|
||||
</div>
|
||||
</div>
|
||||
{dateSelect}
|
||||
{repeatSelect}
|
||||
<input type="hidden" name="token" value="{TOKEN}">
|
||||
<button name="submit" value="submit" type="submit" class="btn btn-lg btn-primary center-block">Submit</button>
|
||||
</form>
|
@ -1,34 +0,0 @@
|
||||
{PAGINATION}
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width: 10%">ID</th>
|
||||
<th style="width: 20%">Time</th>
|
||||
<th style="width: 40%">Title</th>
|
||||
<th style="width: 10%"></th>
|
||||
<th style="width: 10%"></th>
|
||||
<th style="width: 10%"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{LOOP}
|
||||
<tr>
|
||||
<td style="text-align: center;">{ID}</td>
|
||||
<td style="text-align: center;">{DTC}{event_time}{/DTC}</td>
|
||||
<td style="text-align: center;">{title}</td>
|
||||
<td><a href="{ROOT_URL}calendar/event/{ID}" class="btn btn-sm btn-primary" role="button"><i class="glyphicon glyphicon-open"></i></a></td>
|
||||
<td><a href="{ROOT_URL}calendar/editEvent/{ID}" class="btn btn-sm btn-warning" role="button"><i class="glyphicon glyphicon-edit"></i></a></td>
|
||||
<td><a href="{ROOT_URL}calendar/deleteEvent/{ID}" class="btn btn-sm btn-danger" role="button"><i class="glyphicon glyphicon-trash"></i></a></td>
|
||||
</tr>
|
||||
{/LOOP}
|
||||
{ALT}
|
||||
<tr>
|
||||
<td style="text-align: center;" colspan="6">
|
||||
No results to show.
|
||||
</td>
|
||||
</tr>
|
||||
{/ALT}
|
||||
</tbody>
|
||||
</table>
|
||||
{PAGINATION}
|
||||
<a href="{ROOT_URL}calendar/createEvent" class="btn btn-sm btn-primary" role="button">Create</a>
|
@ -1,52 +0,0 @@
|
||||
<div class="container col-md-4 col-lg-4">
|
||||
<div class="row">
|
||||
<div class="panel panel-primary">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">Event</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div class="row">
|
||||
<table class="table table-user-primary">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="text-align: left;" width="200"><b>Title</b></td>
|
||||
<td style="text-align: right;">{title}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Created</b></td>
|
||||
<td style="text-align: right;">{DTC}{createdAt}{/DTC}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Event Time</b></td>
|
||||
<td style="text-align: right;">{DTC}{event_time}{/DTC}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align: center;" colspan="2"><b>Description</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2">{description}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Location</b></td>
|
||||
<td style="text-align: right;">{location}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Frequency</b></td>
|
||||
<td style="text-align: right;">{repeatsText}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Calendar</b></td>
|
||||
<td style="text-align: right;">{calendarName}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel-footer">
|
||||
<a href="{ROOT_URL}calendar/deleteEvent/{ID}" class="btn btn-md btn-danger" role="button">Delete</a>
|
||||
<a href="{ROOT_URL}calendar/editEvent/{ID}" class="btn btn-md btn-warning" role="button">Edit</a>
|
||||
<a href="{ROOT_URL}calendar/byMonth/{calendar_id}" class="btn btn-md btn-primary" role="button">View Events</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -1,16 +0,0 @@
|
||||
<li class="pull-right dropdown">
|
||||
<button type="button" class="btn btn-primary dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
Calendars <span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="{ROOT_URL}calendar/{currentView}/">All</a></li>
|
||||
<li role="separator" class="divider"></li>
|
||||
{LOOP}
|
||||
<li><a href="{ROOT_URL}calendar/{currentView}/{ID}">{title}</a></li>
|
||||
{/LOOP}
|
||||
<li role="separator" class="divider"></li>
|
||||
<li><a href="{ROOT_URL}calendar/createCalendar">Create Calendar</a></li>
|
||||
<li><a href="{ROOT_URL}calendar/editCalendar/{calendarID}">Edit Calendar</a></li>
|
||||
<li><a href="{ROOT_URL}calendar/deleteCalendar/{calendarID}">Delete Calendar</a></li>
|
||||
</ul>
|
||||
</li>
|
@ -1,23 +0,0 @@
|
||||
<ul class="list-group">
|
||||
{LOOP}
|
||||
<li class="list-group-item btn-{displayColor}">
|
||||
<p style="text-align: center;">{title}</p>
|
||||
<p style="text-align: center;">{DTC}{event_time}{/DTC}</p>
|
||||
<p>
|
||||
<a href="{ROOT_URL}calendar/event/{ID}" class="btn btn-sm btn-primary" role="button"><i class="glyphicon glyphicon-open"></i></a>
|
||||
<a href="{ROOT_URL}calendar/editEvent/{ID}" class="btn btn-sm btn-warning" role="button"><i class="glyphicon glyphicon-edit"></i></a>
|
||||
<a href="{ROOT_URL}calendar/deleteEvent/{ID}" class="btn btn-sm btn-danger" role="button"><i class="glyphicon glyphicon-trash"></i></a>
|
||||
</p>
|
||||
</li>
|
||||
{/LOOP}
|
||||
{ALT}
|
||||
<li class="list-group-item">
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
</li>
|
||||
{/ALT}
|
||||
<a href="{ROOT_URL}calendar/createEvent?calendar_id={calendarID}&month={currentMonth}&day={currentDay}" class="list-group-item list-group-item-success"><i class="glyphicon glyphicon-plus"></i></a>
|
||||
</ul>
|
@ -1,18 +0,0 @@
|
||||
<ul class="nav nav-pills">
|
||||
<li class="dropdown pull-right">
|
||||
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
Switch Date <span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu">
|
||||
<form action="" method="post" class="form-horizontal">
|
||||
<li><input type="date" name="date" id="date" class="form-control" value="{date}" /></li>
|
||||
<li role="separator" class="divider"></li>
|
||||
<li>
|
||||
<button name="submit" value="submit" type="submit" class="btn btn-primary center-block">
|
||||
Select Date
|
||||
</button>
|
||||
</li>
|
||||
</form>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
@ -1,12 +0,0 @@
|
||||
<span class="hour-body">
|
||||
{LOOP}
|
||||
<div class="hour-cell btn-{displayColor}">
|
||||
<p class="event-title">{title}</p>
|
||||
<a href="{ROOT_URL}calendar/event/{ID}" class="btn btn-sm btn-primary" role="button"><i class="glyphicon glyphicon-open"></i></a>
|
||||
<a href="{ROOT_URL}calendar/editEvent/{ID}" class="btn btn-sm btn-warning" role="button"><i class="glyphicon glyphicon-edit"></i></a>
|
||||
<a href="{ROOT_URL}calendar/deleteEvent/{ID}" class="btn btn-sm btn-danger" role="button"><i class="glyphicon glyphicon-trash"></i></a>
|
||||
</div>
|
||||
{/LOOP}
|
||||
{ALT}
|
||||
{/ALT}
|
||||
</span>
|
@ -1,8 +0,0 @@
|
||||
<ul class="nav nav-tabs">
|
||||
<li><a href="{ROOT_URL}calendar/byDay/{calendarID}">Daily</a></li>
|
||||
<li><a href="{ROOT_URL}calendar/byWeek/{calendarID}">Weekly</a></li>
|
||||
<li><a href="{ROOT_URL}calendar/byMonth/{calendarID}">Monthly</a></li>
|
||||
<li><a href="{ROOT_URL}calendar/byYear/{calendarID}">Yearly</a></li>
|
||||
<li><a href="{ROOT_URL}calendar/events/{calendarID}">Events</a></li>
|
||||
{calendarDropdown}
|
||||
</ul>
|
@ -1,9 +0,0 @@
|
||||
<div class="row calendar-row">
|
||||
{LOOP}
|
||||
<div class="col-xs-1 calendar-cell">
|
||||
<h4 class="{highlightedDate}">{day}</h4>{dayEventList}
|
||||
</div>
|
||||
{/LOOP}
|
||||
{ALT}
|
||||
{/ALT}
|
||||
</div>
|
@ -1,37 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* app/plugins/chat/controllers/admin/chat.php
|
||||
*
|
||||
* This is the chat admin controller.
|
||||
*
|
||||
* @package TP Chat
|
||||
* @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\Bedrock\Functions\Input;
|
||||
use TheTempusProject\Houdini\Classes\Issues;
|
||||
use TheTempusProject\Houdini\Classes\Views;
|
||||
use TheTempusProject\Houdini\Classes\Navigation;
|
||||
use TheTempusProject\Houdini\Classes\Components;
|
||||
use TheTempusProject\Classes\AdminController;
|
||||
use TheTempusProject\Models\Chat as ChatModel;
|
||||
|
||||
class Chat extends AdminController {
|
||||
protected static $chat;
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
self::$title = 'Admin - Chat';
|
||||
self::$chat = new ChatModel;
|
||||
$view = Navigation::activePageSelect( 'nav.admin', '/admin/chat' );
|
||||
Components::set( 'ADMINNAV', $view );
|
||||
}
|
||||
|
||||
public function index() {
|
||||
// Views::view( 'chat.admin.list', self::$chat->list() );
|
||||
}
|
||||
}
|
@ -1,45 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* app/controllers/api/users.php
|
||||
*
|
||||
* This is the users' api 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\Api;
|
||||
|
||||
use TheTempusProject\Models\User;
|
||||
use TheTempusProject\Classes\ApiController;
|
||||
use TheTempusProject\Houdini\Classes\Views;
|
||||
use TheTempusProject\Bedrock\Functions\Input;
|
||||
use TheTempusProject\Classes\Forms;
|
||||
use TheTempusProject\Houdini\Classes\Template;
|
||||
use TheTempusProject\Models\Chat;
|
||||
|
||||
class Messages extends ApiController {
|
||||
public static $chat;
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
self::$chat = new Chat;
|
||||
Template::setTemplate( 'api' );
|
||||
}
|
||||
|
||||
public function sendMessage() {
|
||||
$response = true;
|
||||
if ( ! Forms::check( 'newChatMessage' ) ) {
|
||||
$response = 'Invalid Form';
|
||||
} else {
|
||||
$response = self::$chat->create( Input::post( 'chatMessage' ) );
|
||||
}
|
||||
Views::view( 'api.response', ['response' => json_encode( [ 'data' => $response ], true )]);
|
||||
}
|
||||
|
||||
public function getMessages() {
|
||||
$response = Views::simpleView( 'chat.chat', self::$chat->recent( 50 ) );
|
||||
Views::view( 'api.response', ['response' => json_encode( [ 'data' => $response ], true )]);
|
||||
}
|
||||
}
|
@ -1,191 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* app/plugins/chat/controllers/chat.php
|
||||
*
|
||||
* This is the public chat controller.
|
||||
*
|
||||
* @package TP Chat
|
||||
* @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\Hermes\Functions\Redirect;
|
||||
use TheTempusProject\Bedrock\Functions\Upload;
|
||||
use TheTempusProject\Bedrock\Functions\Check;
|
||||
use TheTempusProject\Bedrock\Functions\Input;
|
||||
use TheTempusProject\Bedrock\Functions\Session;
|
||||
use TheTempusProject\Houdini\Classes\Issues;
|
||||
use TheTempusProject\Houdini\Classes\Views;
|
||||
use TheTempusProject\Classes\Controller;
|
||||
use TheTempusProject\Classes\Forms;
|
||||
use TheTempusProject\Models\Chat as ChatModel;
|
||||
use TheTempusProject\Models\Upload as UploadModel;
|
||||
use TheTempusProject\TheTempusProject as App;
|
||||
use TheTempusProject\Houdini\Classes\Components;
|
||||
use TheTempusProject\Houdini\Classes\Template;
|
||||
use TheTempusProject\Canary\Bin\Canary as Debug;
|
||||
|
||||
class Chat extends Controller {
|
||||
protected static $chat;
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
self::$chat = new ChatModel;
|
||||
Template::setTemplate( 'chat' );
|
||||
}
|
||||
|
||||
public function index() {
|
||||
if ( !App::$isMember ) {
|
||||
Session::flash( 'error', 'You do not have permission to view this page.' );
|
||||
return Redirect::home();
|
||||
}
|
||||
self::$title = '{SITENAME} Chat';
|
||||
self::$pageDescription = 'One of the privleges of membership is the ability to chat with your fellow members.';
|
||||
|
||||
if ( App::$isLoggedIn ) {
|
||||
Components::set( 'CREATE_MESSAGE', Views::simpleView( 'chat.create' ) );
|
||||
} else {
|
||||
Components::set( 'CREATE_MESSAGE', '' );
|
||||
}
|
||||
|
||||
$upload = '';
|
||||
$sharePlugin = 'TheTempusProject\Plugins\Fileshare';
|
||||
if ( class_exists( $sharePlugin ) ) {
|
||||
$plugin = new $sharePlugin;
|
||||
if ( $plugin->checkEnabled() ) {
|
||||
$upload = Views::simpleView( 'chat.upload' );
|
||||
}
|
||||
}
|
||||
Components::set( 'FILE_UPLOAD', $upload );
|
||||
|
||||
Components::set( 'CHAT', Views::simpleView( 'chat.chat' ) );
|
||||
return Views::view( 'chat.index' );
|
||||
}
|
||||
|
||||
public function sendMessage() {
|
||||
Template::setTemplate( 'api' );
|
||||
$out = [ 'response' => true ];
|
||||
if ( !Forms::check( 'newChatMessage' ) ) {
|
||||
$out = [ 'response' => false ];
|
||||
echo json_encode($out);
|
||||
return;
|
||||
}
|
||||
self::$chat->create(
|
||||
Input::post( 'chatMessage' ),
|
||||
);
|
||||
echo json_encode($out);
|
||||
return;
|
||||
}
|
||||
|
||||
public function uploadFile() {
|
||||
Template::setTemplate( 'api' );
|
||||
$out = [ 'response' => true ];
|
||||
if ( ! Forms::check( 'newFileUpload' ) ) {
|
||||
$out = [ 'response' => false ];
|
||||
echo json_encode($out);
|
||||
return;
|
||||
}
|
||||
|
||||
$sharePlugin = 'TheTempusProject\Plugins\Fileshare';
|
||||
if ( ! class_exists( $sharePlugin ) ) {
|
||||
$out = [ 'error' => 'Fileshare must be installed and enabled for this feature to work1.' ];
|
||||
echo json_encode($out);
|
||||
return;
|
||||
}
|
||||
|
||||
$plugin = new $sharePlugin;
|
||||
|
||||
if ( ! $plugin->checkEnabled() ) {
|
||||
$out = [ 'error' => 'Fileshare must be installed and enabled for this feature to work2.' ];
|
||||
echo json_encode($out);
|
||||
return;
|
||||
}
|
||||
|
||||
$folder = UPLOAD_DIRECTORY . App::$activeUser->username . DIRECTORY_SEPARATOR;
|
||||
if ( ! Upload::image( 'file', $folder ) ) {
|
||||
$out = [ 'error' => 'could not upload image' ];
|
||||
echo json_encode($out);
|
||||
return;
|
||||
}
|
||||
|
||||
$route = str_replace( APP_ROOT_DIRECTORY, '', $folder );
|
||||
$location = $route . Upload::last();
|
||||
$uploads = new UploadModel;
|
||||
$result = $uploads->create( 'Chat Upload', $location );
|
||||
|
||||
if ( ! $result ) {
|
||||
$out = [ 'error' => 'could not add upload to fileshare.' ];
|
||||
echo json_encode( $out );
|
||||
return;
|
||||
}
|
||||
|
||||
self::$chat->create(
|
||||
'Shared a file with the chat: ' .
|
||||
'<a href="/' . $location . '" target="_blank">Upload</a>'
|
||||
);
|
||||
echo json_encode($out);
|
||||
return;
|
||||
}
|
||||
|
||||
public function getMessages() {
|
||||
Template::setTemplate( 'api' );
|
||||
echo Views::simpleView( 'chat.chat', self::$chat->recent( 50 ) );
|
||||
return;
|
||||
}
|
||||
|
||||
public function getMessageEvents() {
|
||||
if ($_SERVER['HTTP_ACCEPT'] !== 'text/event-stream') {
|
||||
Debug::info( 'connection refused, wrong HTTP_ACCEPT' );
|
||||
exit();
|
||||
}
|
||||
|
||||
header("X-Accel-Buffering: no");
|
||||
header('Content-Type: text/event-stream');
|
||||
header('Cache-Control: no-cache');
|
||||
header('Connection: keep-alive');
|
||||
|
||||
// Ensure unlimited script execution time
|
||||
set_time_limit(0);
|
||||
|
||||
// Disable output buffering
|
||||
ini_set('output_buffering', 'off');
|
||||
ini_set('zlib.output_compression', false);
|
||||
|
||||
if (Input::exists('lastId')) {
|
||||
$lastId = Input::get('lastId');
|
||||
} else {
|
||||
$lastId = 0;
|
||||
}
|
||||
|
||||
while ( true ) {
|
||||
echo "id: 0\n";
|
||||
echo "event: ping\n";
|
||||
echo 'data: {"time": "' . time() . '"}';
|
||||
echo "\n\n";
|
||||
if ( connection_aborted() ) {
|
||||
Debug::info( 'getMessageEvents connection aborted' );
|
||||
break;
|
||||
}
|
||||
|
||||
$newMessages = self::$chat->sinceMessage( $lastId );
|
||||
if ( ! empty( $newMessages )) {
|
||||
foreach ( $newMessages as $message ) {
|
||||
$lastId = $message->ID;
|
||||
echo "id: {$message->ID}\n";
|
||||
echo "data: " . json_encode($message) . "\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
// If there were any messages added, flush the output buffer
|
||||
if (ob_get_contents()) {
|
||||
ob_end_flush();
|
||||
}
|
||||
flush();
|
||||
// sessions will block the end-user from sending messages unless we close the session
|
||||
session_write_close();
|
||||
sleep(1);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,116 +0,0 @@
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 20px auto;
|
||||
font-family: "Lato";
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
form {
|
||||
padding: 15px 25px;
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
form label {
|
||||
font-size: 1.5rem;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
input {
|
||||
font-family: "Lato";
|
||||
}
|
||||
|
||||
a {
|
||||
color: #0000ff;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
#chatMessages {
|
||||
text-align: left;
|
||||
margin: 0 auto;
|
||||
padding: 10px;
|
||||
height: 300px;
|
||||
border: 1px solid #a7a7a7;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
#usermsg {
|
||||
flex: 1;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #ff9800;
|
||||
}
|
||||
|
||||
#name {
|
||||
border-radius: 4px;
|
||||
border: 1px solid #ff9800;
|
||||
padding: 2px 8px;
|
||||
}
|
||||
|
||||
#submitmsg,
|
||||
#enter{
|
||||
background: #ff9800;
|
||||
border: 2px solid #e65100;
|
||||
color: white;
|
||||
padding: 4px 10px;
|
||||
font-weight: bold;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.error {
|
||||
color: #ff0000;
|
||||
}
|
||||
|
||||
#menu {
|
||||
padding: 15px 25px;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
#menu p.welcome {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
a#exit {
|
||||
color: white;
|
||||
background: #c62828;
|
||||
padding: 4px 8px;
|
||||
border-radius: 4px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.msgln {
|
||||
margin: 0 0 5px 0;
|
||||
}
|
||||
|
||||
.span.left-info {
|
||||
color: orangered;
|
||||
}
|
||||
|
||||
span .chat-time {
|
||||
color: #666;
|
||||
font-size: 80%;
|
||||
vertical-align: super;
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
.msgln b.user-name, .msgln b.user-name-left {
|
||||
font-weight: bold;
|
||||
background: #546e7a;
|
||||
color: white;
|
||||
padding: 2px 4px;
|
||||
font-size: 90%;
|
||||
border-radius: 4px;
|
||||
margin: 0 5px 0 0;
|
||||
}
|
||||
|
||||
.msgln b.user-name-left {
|
||||
background: orangered;
|
||||
}
|
@ -1,52 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* app/plugins/chat/forms.php
|
||||
*
|
||||
* This houses all of the form checking functions for this plugin.
|
||||
*
|
||||
* @package TP Chat
|
||||
* @version 3.0
|
||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||
* @link https://TheTempusProject.com
|
||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||
*/
|
||||
namespace TheTempusProject\Plugins\Chat;
|
||||
|
||||
use TheTempusProject\Bedrock\Functions\Input;
|
||||
use TheTempusProject\Bedrock\Functions\Check;
|
||||
use TheTempusProject\Classes\Forms;
|
||||
|
||||
class ChatForms extends Forms {
|
||||
/**
|
||||
* Adds these functions to the form list.
|
||||
*/
|
||||
public function __construct() {
|
||||
self::addHandler( 'newChatMessage', __CLASS__, 'newChatMessage' );
|
||||
self::addHandler( 'newFileUpload', __CLASS__, 'newFileUpload' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the new blog post form.
|
||||
*
|
||||
* @return {bool}
|
||||
*/
|
||||
public static function newChatMessage() {
|
||||
if ( !Input::exists( 'chatMessage' ) ) {
|
||||
self::addUserError( 'You must includes a message' );
|
||||
return false;
|
||||
}
|
||||
// if (!self::token()) {
|
||||
// return false;
|
||||
// }
|
||||
return true;
|
||||
}
|
||||
public static function newFileUpload() {
|
||||
if ( !Input::exists( 'file' ) ) {
|
||||
self::addUserError( 'You must includes a file' );
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
new ChatForms;
|
@ -1,116 +0,0 @@
|
||||
$(document).ready(function() {
|
||||
var chatform = $('#sendChatMessage');
|
||||
var uploadForm = $('#uploadFile');
|
||||
|
||||
chatform.bind('submit', function(event) {
|
||||
event.preventDefault(); // Prevent page reload
|
||||
var msg = $("#chatMessage").val();
|
||||
|
||||
console.log("Submitting message:", msg);
|
||||
|
||||
var ajax_params = {
|
||||
url: '/chat/sendMessage',
|
||||
type: 'POST',
|
||||
data: { chatMessage: msg },
|
||||
success: function(response) {
|
||||
console.log("Message sent successfully:", response);
|
||||
$("#chatMessage").val("");
|
||||
},
|
||||
error: function(xhr, status, error) {
|
||||
console.error("Error sending message:", error, status, xhr);
|
||||
},
|
||||
complete: function() {
|
||||
console.log("AJAX request complete");
|
||||
}
|
||||
};
|
||||
|
||||
$.ajax(ajax_params);
|
||||
return false;
|
||||
});
|
||||
|
||||
uploadForm.bind('submit', function(event) {
|
||||
event.preventDefault(); // Prevent page reload
|
||||
|
||||
var formData = new FormData(this); // Create FormData object
|
||||
|
||||
$.ajax({
|
||||
url: '/chat/uploadFile',
|
||||
type: 'POST',
|
||||
data: formData,
|
||||
processData: false, // Don't process the files
|
||||
contentType: false, // Set content type to false as jQuery will tell the server its a query string request
|
||||
success: function(response) {
|
||||
console.log("File uploaded successfully:", response);
|
||||
$("#file").val("");
|
||||
},
|
||||
error: function(xhr, status, error) {
|
||||
console.error("Error uploading file:", error, status, xhr);
|
||||
},
|
||||
complete: function() {
|
||||
console.log("AJAX request complete");
|
||||
}
|
||||
});
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
const eventSource = new EventSource('/chat/getMessageEvents');
|
||||
eventSource.onmessage = function( event ) {
|
||||
const message = JSON.parse( event.data );
|
||||
|
||||
var userPopup = "<div class='media'>" +
|
||||
"<span class='pull-left'>" +
|
||||
"<img class='media-object avatar-round-40' src='/"+message.avatar+"' alt=''>" +
|
||||
"</span>" +
|
||||
"<div class='media-body'>" +
|
||||
"<h5 class='media-heading'>" +
|
||||
"<strong>"+message.submittedByName+"</strong>" +
|
||||
"</h5>" +
|
||||
"<a href='/home/profile/"+message.submittedByName+"' class='btn btn-sm btn-primary' role='button'><i class='glyphicon glyphicon-open'></i> View Profile</a>" +
|
||||
"</div>" +
|
||||
"</div>";
|
||||
|
||||
$("#chatMessages").append(
|
||||
"<span class='chat-time'>" +
|
||||
new Date(message.submittedAt * 1000).toLocaleString('en-US', { month: 'long', day: 'numeric', hour: 'numeric', minute: 'numeric', hour12: true }) +
|
||||
// new Date(message.submittedAt * 1000).toLocaleString() +
|
||||
"</span> " +
|
||||
'<a tabindex="0" role="button" data-toggle="popover" data-html="true" data-trigger="focus" title="'+message.submittedByName+'" data-content="'+userPopup+'">' +
|
||||
message.submittedByName +
|
||||
'</a> ' +
|
||||
message.chatMessage + "<br>"
|
||||
);
|
||||
$("[data-toggle=popover]").popover();
|
||||
$("#chatMessages").scrollTop($("#chatMessages")[0].scrollHeight);
|
||||
};
|
||||
|
||||
eventSource.onerror = function(event) {
|
||||
console.error('EventSource failed:', event);
|
||||
};
|
||||
|
||||
window.addEventListener('beforeunload', function() {
|
||||
eventSource.close();
|
||||
});
|
||||
|
||||
window.addEventListener('unload', function() {
|
||||
eventSource.close();
|
||||
});
|
||||
|
||||
// function getUserProfile( id ) {
|
||||
// var ajax_params = {
|
||||
// url: '/api/users/find/' + id,
|
||||
// type: 'GET',
|
||||
// success: function(response) {
|
||||
// console.log("User retrieved:", response);
|
||||
// $("#chatMessage").val("");
|
||||
// },
|
||||
// error: function(xhr, status, error) {
|
||||
// console.error("Error retrieved user:", error, status, xhr);
|
||||
// },
|
||||
// complete: function() {
|
||||
// console.log("AJAX request complete");
|
||||
// }
|
||||
// };
|
||||
// $.ajax(ajax_params);
|
||||
// }
|
||||
});
|
@ -1,145 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* app/plugins/chat/models/chat.php
|
||||
*
|
||||
* This class is used for the manipulation of the chat database table.
|
||||
*
|
||||
* @todo make this send a confirmation email
|
||||
*
|
||||
* @package TP Chat
|
||||
* @version 3.0
|
||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||
* @link https://TheTempusProject.com
|
||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||
*/
|
||||
namespace TheTempusProject\Models;
|
||||
|
||||
use TheTempusProject\Bedrock\Classes\Config;
|
||||
use TheTempusProject\Bedrock\Functions\Check;
|
||||
use TheTempusProject\Canary\Bin\Canary as Debug;
|
||||
use TheTempusProject\Classes\DatabaseModel;
|
||||
use TheTempusProject\TheTempusProject as App;
|
||||
use TheTempusProject\Houdini\Classes\Filters;
|
||||
|
||||
class Chat extends DatabaseModel {
|
||||
public $tableName = 'chat';
|
||||
public $databaseMatrix = [
|
||||
[ 'submittedAt', 'int', '10' ],
|
||||
[ 'submittedBy', 'int', '11' ],
|
||||
[ 'chatMessage', 'text', '' ],
|
||||
];
|
||||
|
||||
/**
|
||||
* The model constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves a chat form to the db.
|
||||
*
|
||||
* @param string $message -contents of the chat form.
|
||||
* @return bool
|
||||
*/
|
||||
public function create( $message ) {
|
||||
$fields = [
|
||||
'submittedBy' => App::$activeUser->ID,
|
||||
'submittedAt' => time(),
|
||||
'chatMessage' => $message,
|
||||
];
|
||||
if ( !self::$db->insert( $this->tableName, $fields ) ) {
|
||||
Debug::info( 'Chat::create - failed to insert to db' );
|
||||
return false;
|
||||
}
|
||||
return self::$db->lastId();
|
||||
}
|
||||
|
||||
public function filter( $data, $params = [] ) {
|
||||
foreach ( $data as $instance ) {
|
||||
if ( !is_object( $instance ) ) {
|
||||
$instance = $data;
|
||||
$end = true;
|
||||
}
|
||||
$instance->chatMessage = Filters::applyOne( 'mentions.0', $instance->chatMessage, true );
|
||||
$instance->chatMessage = Filters::applyOne( 'hashtags.0', $instance->chatMessage, true );
|
||||
$user = self::$user->findById( $instance->submittedBy );
|
||||
if ( ! empty( $user ) ) {
|
||||
$instance->submittedByName = $user->username;
|
||||
$instance->profileUrl = '/home/profile/' . $user->username;
|
||||
} else {
|
||||
$instance->submittedByName = 'Unknown';
|
||||
$instance->profileUrl = '#';
|
||||
}
|
||||
$instance->avatar = self::$user->getAvatar( $instance->submittedBy );
|
||||
$out[] = $instance;
|
||||
if ( !empty( $end ) ) {
|
||||
$out = $out[0];
|
||||
break;
|
||||
}
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to clear chat from the DB.
|
||||
*
|
||||
* @todo is there a way i could check for success here I'm pretty sure this is just a bad idea?
|
||||
* @return bool
|
||||
*/
|
||||
public function clear() {
|
||||
if ( empty( self::$log ) ) {
|
||||
self::$log = new Log;
|
||||
}
|
||||
self::$db->delete( $this->tableName, ['ID', '>=', '0'] );
|
||||
self::$log->admin( 'Cleared Chat' );
|
||||
Debug::info( 'Chat Cleared' );
|
||||
return true;
|
||||
}
|
||||
|
||||
public function recent( $limit = null ) {
|
||||
if ( empty( $limit ) ) {
|
||||
$postData = self::$db->get( $this->tableName, '*' );
|
||||
} else {
|
||||
$postData = self::$db->get( $this->tableName, '*', 'ID', 'ASC', [0, $limit] );
|
||||
}
|
||||
if ( !$postData->count() ) {
|
||||
Debug::info( 'No messages found.' );
|
||||
return false;
|
||||
}
|
||||
return $this->filter( $postData->results() );
|
||||
}
|
||||
|
||||
public function sinceMessage($id = 0) {
|
||||
if (empty($id)) {
|
||||
$postData = self::$db->get($this->tableName, '*', 'ID', 'DESC', [0, 20]);
|
||||
} else {
|
||||
$postData = self::$db->get($this->tableName, ['ID', '>', $id], 'ID', 'ASC', [0, 20]);
|
||||
}
|
||||
if ( ! $postData->count() ) {
|
||||
Debug::debug( 'No messages found.' );
|
||||
return false;
|
||||
}
|
||||
|
||||
if (empty($id)) {
|
||||
$results = array_reverse($postData->results()); // Reverse the order to get ascending IDs
|
||||
} else {
|
||||
$results = $postData->results();
|
||||
}
|
||||
|
||||
return $this->filter($results);
|
||||
}
|
||||
|
||||
public function sinceMessageSingle( $id = 0 ) {
|
||||
if ( empty( $id ) ) {
|
||||
$postData = self::$db->get( $this->tableName, '*', 'ID', 'ASC', [0, 1] );
|
||||
} else {
|
||||
$postData = self::$db->get( $this->tableName, [ 'ID', '>', $id ], 'ID', 'ASC', [0, 1] );
|
||||
}
|
||||
if ( ! $postData->count() ) {
|
||||
Debug::debug( 'No messages found.' );
|
||||
return false;
|
||||
}
|
||||
return $this->filter( $postData->results() );
|
||||
}
|
||||
}
|
@ -1,55 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* app/plugins/chat/plugin.php
|
||||
*
|
||||
* This houses all of the main plugin info and functionality.
|
||||
*
|
||||
* @package TP Chat
|
||||
* @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 TheTempusProject\Classes\Plugin;
|
||||
use TheTempusProject\TheTempusProject as App;
|
||||
|
||||
class Chat extends Plugin {
|
||||
public $pluginName = 'TP Chat';
|
||||
public $configName = 'chat';
|
||||
public $pluginAuthor = 'JoeyK';
|
||||
public $pluginWebsite = 'https://TheTempusProject.com';
|
||||
public $modelVersion = '1.0';
|
||||
public $pluginVersion = '3.0';
|
||||
public $pluginDescription = 'A simple plugin which adds a site wide chat system.';
|
||||
public $permissionMatrix = [
|
||||
'chat' => [
|
||||
'pretty' => 'Can use chat',
|
||||
'default' => false,
|
||||
],
|
||||
];
|
||||
public $admin_links = [
|
||||
[
|
||||
'text' => '<i class="fa fa-fw fa-copy"></i> Chat',
|
||||
'url' => '{ROOT_URL}admin/chat',
|
||||
],
|
||||
];
|
||||
public $main_links = [
|
||||
[
|
||||
'text' => 'Chat',
|
||||
'url' => '{ROOT_URL}chat/index',
|
||||
'filter' => 'loggedin',
|
||||
],
|
||||
];
|
||||
public $configMatrix = [
|
||||
'enabled' => [
|
||||
'type' => 'radio',
|
||||
'pretty' => 'Enable Chat.',
|
||||
'default' => true,
|
||||
],
|
||||
];
|
||||
public function __construct( $load = false ) {
|
||||
parent::__construct( $load );
|
||||
}
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* app/plugins/blog/templates/blog.inc.php
|
||||
*
|
||||
* This is the loader for the blog template.
|
||||
*
|
||||
* @package TP Blog
|
||||
* @version 3.0
|
||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||
* @link https://TheTempusProject.com
|
||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||
*/
|
||||
namespace TheTempusProject\Templates;
|
||||
|
||||
use TheTempusProject\Plugins\Calendar;
|
||||
|
||||
use TheTempusProject\Houdini\Classes\Components;
|
||||
use TheTempusProject\Houdini\Classes\Navigation;
|
||||
use TheTempusProject\Houdini\Classes\Views;
|
||||
use TheTempusProject\Houdini\Classes\Template;
|
||||
use TheTempusProject\Bedrock\Functions\Input;
|
||||
|
||||
class ChatLoader extends DefaultLoader {
|
||||
/**
|
||||
* This is the function used to generate any components that may be
|
||||
* needed by this template.
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->addJs( '<script language="JavaScript" crossorigin="anonymous" type="text/javascript" src="{ROOT_URL}app/plugins/chat/js/chat.js"></script>' );
|
||||
parent::__construct();
|
||||
}
|
||||
}
|
@ -1,88 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<!--
|
||||
* app/templates/default/default.tpl
|
||||
*
|
||||
* @version 3.0
|
||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||
* @link https://TheTempusProject.com
|
||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||
-->
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<meta property="og:url" content="{CURRENT_URL}">
|
||||
<meta name='twitter:card' content='summary_large_image' />
|
||||
<title>{TITLE}</title>
|
||||
<meta itemprop="name" content="{TITLE}">
|
||||
<meta name="twitter:title" content="{TITLE}">
|
||||
<meta property="og:title" content="{TITLE}">
|
||||
<meta name="description" content="{PAGE_DESCRIPTION}">
|
||||
<meta itemprop="description" content="{PAGE_DESCRIPTION}">
|
||||
<meta name="twitter:description" content="{PAGE_DESCRIPTION}">
|
||||
<meta property="og:description" content="{PAGE_DESCRIPTION}">
|
||||
<meta itemprop="image" content="{META_IMAGE}">
|
||||
<meta name="twitter:image" content="{META_IMAGE}">
|
||||
<meta property="og:image" content="{META_IMAGE}">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
{AUTHOR}
|
||||
{ROBOT}
|
||||
<link rel="icon" href="{ROOT_URL}images/favicon.ico">
|
||||
<!-- Required CSS -->
|
||||
<link rel="stylesheet" href="{FONT_AWESOME_URL}font-awesome.min.css" crossorigin="anonymous">
|
||||
<link rel="stylesheet" href="{BOOTSTRAP_CDN}css/bootstrap-theme.min.css" crossorigin="anonymous">
|
||||
<link rel="stylesheet" href="{BOOTSTRAP_CDN}css/bootstrap.min.css" crossorigin="anonymous">
|
||||
<!-- Custom styles for this template -->
|
||||
{TEMPLATE_CSS_INCLUDES}
|
||||
</head>
|
||||
<body>
|
||||
<nav class="navbar navbar-inverse navbar-fixed-top" role="navigation">
|
||||
<!--Brand and toggle should get grouped for better mobile display but I had to account for additional menus-->
|
||||
<div class="navbar-header">
|
||||
<a href="{ROOT_URL}" class="navbar-brand">{SITENAME}</a>
|
||||
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-ex1-collapse" style="">
|
||||
<span class="sr-only">Toggle navigation</span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="container-fluid">
|
||||
<div class="collapse navbar-collapse navbar-ex1-collapse">
|
||||
{topNavLeft}
|
||||
<div class="navbar-right">
|
||||
<ul class="nav navbar-nav">
|
||||
{topNavRight}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<div class="container-fluid top-pad foot-pad">
|
||||
{ISSUES}
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
{ERROR}
|
||||
{NOTICE}
|
||||
{SUCCESS}
|
||||
{INFO}
|
||||
</div>
|
||||
</div>
|
||||
{/ISSUES}
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
{CONTENT}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<footer>
|
||||
{FOOT}
|
||||
{COPY}
|
||||
</footer>
|
||||
<!-- Bootstrap core JavaScript and jquery -->
|
||||
<script language="JavaScript" crossorigin="anonymous" type="text/javascript" src="{JQUERY_CDN}jquery.min.js"></script>
|
||||
<script language="JavaScript" crossorigin="anonymous" type="text/javascript" src="{BOOTSTRAP_CDN}js/bootstrap.min.js"></script>
|
||||
<!-- Custom javascript for this template -->
|
||||
{TEMPLATE_JS_INCLUDES}
|
||||
</body>
|
||||
</html>
|
@ -1,10 +0,0 @@
|
||||
{LOOP}
|
||||
<div class='msgln'>
|
||||
<span class='chat-time'>{DTC time}{submittedAt}{/DTC}</span> <b class='user-name'>{submittedByName}</b>: {chatMessage}<br>
|
||||
</div>
|
||||
{/LOOP}
|
||||
{ALT}
|
||||
<div class="msgln">
|
||||
No messages Found.<br>
|
||||
</div>
|
||||
{/ALT}
|
@ -1,9 +0,0 @@
|
||||
<form class="form-horizontal" id="sendChatMessage">
|
||||
<input type="hidden" name="token" value="{TOKEN}">
|
||||
<div class="form-group col-lg-10">
|
||||
<input type="text" class="form-control" name="chatMessage" id="chatMessage">
|
||||
</div>
|
||||
<div class="form-group col-lg-2">
|
||||
<button id="submitChatMessage" name="submitChatMessage" value="button" class="btn btn-sm btn-primary center-block ">Send</button>
|
||||
</div>
|
||||
</form>
|
@ -1,18 +0,0 @@
|
||||
<link rel="stylesheet" href="{ROOT_URL}app/plugins/chat/css/chat.css" crossorigin="anonymous">
|
||||
<span class="col-lg-12" id="Chat">
|
||||
<div class="panel panel-default" role="tab">
|
||||
<div class="panel-heading">
|
||||
<button type="button" class="btn btn-default btn-sm" data-target="#Collapse${id}" data-toggle="collapse" aria-expanded="true" aria-controls="#Collapse${id}">
|
||||
<i class="glyphicon glyphicon-th-list"></i> {USERNAME}
|
||||
</button>
|
||||
</div>
|
||||
<div id="Collapse${id}" class="panel-collapse collapse in" style="width:100%; position: relative;" role="tabpanel" aria-expanded="true">
|
||||
<div class="panel-body" id="chatMessages">
|
||||
</div>
|
||||
<div class="panel-footer">
|
||||
{CREATE_MESSAGE}
|
||||
{FILE_UPLOAD}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</span>
|
@ -1,9 +0,0 @@
|
||||
<form action="" method="post" class="form-horizontal" enctype="multipart/form-data" id="uploadFile">
|
||||
<input type="hidden" name="token" value="{TOKEN}">
|
||||
<div class="form-group col-lg-3 col-lg-offset-6">
|
||||
<input type="file" class="form-control" name="file" id="file">
|
||||
</div>
|
||||
<div class="form-group col-lg-3">
|
||||
<button id="submitUpload" name="submit" value="submit" class="btn btn-sm btn-primary center-block">Upload</button>
|
||||
</div>
|
||||
</form>
|
@ -1,92 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* app/plugins/contacts/controllers/contacts.php
|
||||
*
|
||||
* This is the contacts controller.
|
||||
*
|
||||
* @package TP Contacts
|
||||
* @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\Bedrock\Functions\Check;
|
||||
use TheTempusProject\Bedrock\Functions\Input;
|
||||
use TheTempusProject\Houdini\Classes\Issues;
|
||||
use TheTempusProject\Houdini\Classes\Views;
|
||||
use TheTempusProject\Classes\Forms;
|
||||
use TheTempusProject\Houdini\Classes\Forms as FormBuilder;
|
||||
use TheTempusProject\Houdini\Classes\Components;
|
||||
use TheTempusProject\Classes\Config;
|
||||
|
||||
|
||||
|
||||
use TheTempusProject\Classes\Controller;
|
||||
use TheTempusProject\TheTempusProject as App;
|
||||
use TheTempusProject\Bedrock\Functions\Session;
|
||||
use TheTempusProject\Hermes\Functions\Redirect;
|
||||
use TheTempusProject\Models\Contact;
|
||||
use TheTempusProject\Models\Phonebook;
|
||||
use TheTempusProject\Houdini\Classes\Template;
|
||||
use TheTempusProject\Houdini\Classes\Navigation;
|
||||
|
||||
class Contacts extends Controller {
|
||||
protected static $contacts;
|
||||
protected static $phonebooks;
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
if ( !App::$isLoggedIn ) {
|
||||
Session::flash( 'notice', 'You must be logged in to use this feature.' );
|
||||
return Redirect::home();
|
||||
}
|
||||
self::$contacts = new Contact;
|
||||
self::$phonebooks = new Phonebook;
|
||||
self::$title = 'Contacts - {SITENAME}';
|
||||
self::$pageDescription = 'On this page you can create and manage contacts and phonebooks.';
|
||||
}
|
||||
|
||||
public function index() {
|
||||
$phonebooks = Views::simpleView( 'contacts.phonebooks.list', self::$phonebooks->byUser() );
|
||||
Components::set( 'phonebookList', $phonebooks );
|
||||
|
||||
$contacts = Views::simpleView( 'contacts.contacts.list', self::$contacts->byUser() );
|
||||
Components::set( 'contactList', $contacts );
|
||||
|
||||
Views::view( 'contacts.dashboard' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Contacts
|
||||
*/
|
||||
public function viewContact( $id = null ) {
|
||||
// stuff here
|
||||
}
|
||||
public function createContact( $id = null ) {
|
||||
// stuff here
|
||||
}
|
||||
public function editContact( $id = null ) {
|
||||
// stuff here
|
||||
}
|
||||
public function deleteContact( $id = null ) {
|
||||
// stuff here
|
||||
}
|
||||
|
||||
/**
|
||||
* Phonebooks
|
||||
*/
|
||||
public function viewPhonebook( $id = null ) {
|
||||
// stuff here
|
||||
}
|
||||
public function createPhonebook() {
|
||||
// stuff here
|
||||
}
|
||||
public function editPhonebook( $id = null ) {
|
||||
// stuff here
|
||||
}
|
||||
public function deletePhonebook( $id = null ) {
|
||||
// stuff here
|
||||
}
|
||||
}
|
@ -1,99 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* app/plugins/notes/forms.php
|
||||
*
|
||||
* This houses all of the form checking functions for this plugin.
|
||||
*
|
||||
* @package TP Notes
|
||||
* @version 3.0
|
||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||
* @link https://TheTempusProject.com
|
||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||
*/
|
||||
namespace TheTempusProject\Plugins\Notes;
|
||||
|
||||
use TheTempusProject\Bedrock\Functions\Input;
|
||||
use TheTempusProject\Bedrock\Functions\Check;
|
||||
use TheTempusProject\Classes\Forms;
|
||||
|
||||
class ContactsForms extends Forms {
|
||||
/**
|
||||
* Adds these functions to the form list.
|
||||
*/
|
||||
public function __construct() {
|
||||
self::addHandler( 'createContact', __CLASS__, 'createContact' );
|
||||
self::addHandler( 'createPhonebook', __CLASS__, 'createPhonebook' );
|
||||
self::addHandler( 'editContact', __CLASS__, 'editContact' );
|
||||
self::addHandler( 'editPhonebook', __CLASS__, 'editPhonebook' );
|
||||
}
|
||||
|
||||
public static function createContact() {
|
||||
if ( ! Input::exists( 'submit' ) ) {
|
||||
return false;
|
||||
}
|
||||
if ( ! Input::exists( 'first_name' ) && ! Input::exists( 'last_name' ) && ! Input::exists( 'nickname' ) ) {
|
||||
Check::addUserError( 'You must include a first, last, or nick-name.' );
|
||||
return false;
|
||||
}
|
||||
// if ( !self::token() ) {
|
||||
// Check::addUserError( 'token - comment out later.' );
|
||||
// return false;
|
||||
// }
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function createPhonebook() {
|
||||
if ( ! Input::exists( 'submit' ) ) {
|
||||
return false;
|
||||
}
|
||||
if ( ! Input::exists( 'title' ) ) {
|
||||
Check::addUserError( 'You must include a title.' );
|
||||
return false;
|
||||
}
|
||||
if ( ! Input::exists( 'color' ) ) {
|
||||
Check::addUserError( 'You must include a color.' );
|
||||
return false;
|
||||
}
|
||||
// if ( ! self::token() ) {
|
||||
// Check::addUserError( 'token - comment out later.' );
|
||||
// return false;
|
||||
// }
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function editContact() {
|
||||
if ( ! Input::exists( 'submit' ) ) {
|
||||
return false;
|
||||
}
|
||||
if ( ! Input::exists( 'first_name' ) && ! Input::exists( 'last_name' ) && ! Input::exists( 'nickname' ) ) {
|
||||
Check::addUserError( 'You must include a first, last, or nick-name.' );
|
||||
return false;
|
||||
}
|
||||
// if ( !self::token() ) {
|
||||
// Check::addUserError( 'token - comment out later.' );
|
||||
// return false;
|
||||
// }
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function editPhonebook() {
|
||||
if ( ! Input::exists( 'submit' ) ) {
|
||||
return false;
|
||||
}
|
||||
if ( ! Input::exists( 'title' ) ) {
|
||||
Check::addUserError( 'You must include a title.' );
|
||||
return false;
|
||||
}
|
||||
if ( ! Input::exists( 'color' ) ) {
|
||||
Check::addUserError( 'You must include a color.' );
|
||||
return false;
|
||||
}
|
||||
// if ( !self::token() ) {
|
||||
// Check::addUserError( 'token - comment out later.' );
|
||||
// return false;
|
||||
// }
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
new ContactsForms;
|
@ -1,88 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* app/plugins/contacts/models/contact.php
|
||||
*
|
||||
* This class is used for the manipulation of the contacts database table.
|
||||
*
|
||||
* @package TP Contacts
|
||||
* @version 3.0
|
||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||
* @link https://TheTempusProject.com
|
||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||
*/
|
||||
namespace TheTempusProject\Models;
|
||||
|
||||
use TheTempusProject\Canary\Bin\Canary as Debug;
|
||||
use TheTempusProject\Classes\DatabaseModel;
|
||||
use TheTempusProject\TheTempusProject as App;
|
||||
|
||||
class Contact extends DatabaseModel {
|
||||
public $tableName = 'contacts';
|
||||
|
||||
public $databaseMatrix = [
|
||||
[ 'avatar', 'text', ''],
|
||||
[ 'first_name', 'varchar', '128'],
|
||||
[ 'middle_name', 'varchar', '128'],
|
||||
[ 'last_name', 'varchar', '128'],
|
||||
[ 'nickname', 'varchar', '128'],
|
||||
[ 'company', 'varchar', '128'],
|
||||
[ 'job_title', 'varchar', '128'],
|
||||
[ 'email', 'varchar', '128'],
|
||||
[ 'email_2', 'varchar', '128'],
|
||||
[ 'phone', 'varchar', '128'],
|
||||
[ 'phone_2', 'varchar', '128'],
|
||||
[ 'address_1_primary', 'varchar', '128'],
|
||||
[ 'address_1_secondary', 'varchar', '128'],
|
||||
[ 'city', 'varchar', '128'],
|
||||
[ 'state', 'varchar', '128'],
|
||||
[ 'zipcode', 'varchar', '128'],
|
||||
[ 'country', 'varchar', '128'],
|
||||
[ 'address_2_primary', 'varchar', '128'],
|
||||
[ 'address_2_secondary', 'varchar', '128'],
|
||||
[ 'city_2', 'varchar', '128'],
|
||||
[ 'state_2', 'varchar', '128'],
|
||||
[ 'zipcode_2', 'varchar', '128'],
|
||||
[ 'country_2', 'varchar', '128'],
|
||||
[ 'notes', 'text', ''],
|
||||
[ 'color', 'varchar', '48' ],
|
||||
[ 'icon', 'varchar', '48' ],
|
||||
[ 'createdAt', 'int', '11'],
|
||||
[ 'createdBy', 'int', '11'],
|
||||
[ 'phonebookID', 'int', '11'],
|
||||
];
|
||||
|
||||
/**
|
||||
* The model constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
public function byUser( $limit = null ) {
|
||||
$whereClause = [ 'createdBy', '=', App::$activeUser->ID ];
|
||||
if ( empty( $limit ) ) {
|
||||
$phonebooks = self::$db->get( $this->tableName, $whereClause );
|
||||
} else {
|
||||
$phonebooks = self::$db->get( $this->tableName, $whereClause, 'ID', 'DESC', [0, $limit] );
|
||||
}
|
||||
if ( !$phonebooks->count() ) {
|
||||
Debug::info( 'No Phonebooks found.' );
|
||||
return false;
|
||||
}
|
||||
return $this->filter( $phonebooks->results() );
|
||||
}
|
||||
|
||||
public function byPhonebook( $phonebookID, $limit = null ) {
|
||||
$whereClause = [ 'phonebookID', '=', $phonebookID ];
|
||||
if ( empty( $limit ) ) {
|
||||
$phonebooks = self::$db->get( $this->tableName, $whereClause );
|
||||
} else {
|
||||
$phonebooks = self::$db->get( $this->tableName, $whereClause, 'ID', 'DESC', [0, $limit] );
|
||||
}
|
||||
if ( !$phonebooks->count() ) {
|
||||
Debug::info( 'No Phonebooks found.' );
|
||||
return false;
|
||||
}
|
||||
return $this->filter( $phonebooks->results() );
|
||||
}
|
||||
}
|
@ -1,165 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* app/plugins/contacts/models/phonebook.php
|
||||
*
|
||||
* This class is used for the manipulation of the phonebook database table.
|
||||
*
|
||||
* @package TP Contacts
|
||||
* @version 3.0
|
||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||
* @link https://TheTempusProject.com
|
||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||
*/
|
||||
namespace TheTempusProject\Models;
|
||||
|
||||
use TheTempusProject\Bedrock\Classes\Config;
|
||||
use TheTempusProject\Bedrock\Functions\Check;
|
||||
use TheTempusProject\Canary\Bin\Canary as Debug;
|
||||
use TheTempusProject\Classes\DatabaseModel;
|
||||
use TheTempusProject\TheTempusProject as App;
|
||||
use TheTempusProject\Houdini\Classes\Filters;
|
||||
use TheTempusProject\Bedrock\Classes\CustomException;
|
||||
|
||||
class Phonebook extends DatabaseModel {
|
||||
public $tableName = 'phonebooks';
|
||||
|
||||
public $databaseMatrix = [
|
||||
[ 'title', 'varchar', '128' ],
|
||||
[ 'description', 'text', '' ],
|
||||
[ 'color', 'varchar', '48' ],
|
||||
[ 'icon', 'varchar', '48' ],
|
||||
[ 'createdBy', 'int', '11' ],
|
||||
[ 'createdAt', 'int', '11' ],
|
||||
];
|
||||
|
||||
/**
|
||||
* The model constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
public function create( $title, $description = '', $color = 'default', $icon = '' ) {
|
||||
if ( ! Check::dataTitle( $title ) ) {
|
||||
Debug::info( 'Phonebooks: illegal title.' );
|
||||
return false;
|
||||
}
|
||||
$fields = [
|
||||
'title' => $title,
|
||||
'description' => $description,
|
||||
'color' => $color,
|
||||
'icon' => $icon,
|
||||
'createdBy' => App::$activeUser->ID,
|
||||
'createdAt' => time(),
|
||||
];
|
||||
if ( ! self::$db->insert( $this->tableName, $fields ) ) {
|
||||
new CustomException( 'phonebookCreate' );
|
||||
Debug::error( "Phonebooks: not created " . var_export($fields,true) );
|
||||
return false;
|
||||
}
|
||||
return self::$db->lastId();
|
||||
}
|
||||
|
||||
public function update( $id, $title, $description = '', $color = 'default', $icon = '' ) {
|
||||
if ( !Check::id( $id ) ) {
|
||||
Debug::info( 'Phonebooks: illegal ID.' );
|
||||
return false;
|
||||
}
|
||||
if ( !Check::dataTitle( $title ) ) {
|
||||
Debug::info( 'Phonebooks: illegal title.' );
|
||||
return false;
|
||||
}
|
||||
$fields = [
|
||||
'title' => $title,
|
||||
'description' => $description,
|
||||
'color' => $color,
|
||||
'icon' => $icon,
|
||||
];
|
||||
if ( !self::$db->update( $this->tableName, $id, $fields ) ) {
|
||||
new CustomException( 'phonebookUpdate' );
|
||||
Debug::error( "Phonebooks: $id not updated" );
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function byUser( $limit = null ) {
|
||||
$whereClause = ['createdBy', '=', App::$activeUser->ID];
|
||||
if ( empty( $limit ) ) {
|
||||
$phonebooks = self::$db->get( $this->tableName, $whereClause );
|
||||
} else {
|
||||
$phonebooks = self::$db->get( $this->tableName, $whereClause, 'ID', 'DESC', [0, $limit] );
|
||||
}
|
||||
if ( !$phonebooks->count() ) {
|
||||
Debug::info( 'No Phonebooks found.' );
|
||||
return false;
|
||||
}
|
||||
return $this->filter( $phonebooks->results() );
|
||||
}
|
||||
|
||||
public function getName( $id ) {
|
||||
$phonebook = self::findById( $id );
|
||||
return $phonebook->title;
|
||||
}
|
||||
|
||||
public function simpleList( $param = '') {
|
||||
$whereClause = ['createdBy', '=', App::$activeUser->ID];
|
||||
$phonebooks = self::$db->get( $this->tableName, $whereClause );
|
||||
if ( !$phonebooks->count() ) {
|
||||
Debug::warn( 'Could not find any Phonebooks' );
|
||||
return [];
|
||||
}
|
||||
|
||||
$phonebooks = $phonebooks->results();
|
||||
$out = [ 'None' => '0'];
|
||||
foreach ( $phonebooks as &$phonebook ) {
|
||||
$out[ $phonebook->title ] = $phonebook->ID;
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
|
||||
public function simpleObjectByUser() {
|
||||
$whereClause = ['createdBy', '=', App::$activeUser->ID];
|
||||
$phonebooks = self::$db->get( $this->tableName, $whereClause );
|
||||
if ( !$phonebooks->count() ) {
|
||||
Debug::warn( 'Could not find any Phonebooks' );
|
||||
return false;
|
||||
}
|
||||
|
||||
$phonebooks = $phonebooks->results();
|
||||
$out = [];
|
||||
foreach ( $phonebooks as &$phonebook ) {
|
||||
$obj = new \stdClass();
|
||||
$obj->title = $phonebook->title;
|
||||
$obj->ID = $phonebook->ID;
|
||||
$out[] = $obj;
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
|
||||
public function getTree() {
|
||||
$whereClause = ['createdBy', '=', App::$activeUser->ID];
|
||||
$phonebooks = self::$db->get( $this->tableName, $whereClause );
|
||||
if ( !$phonebooks->count() ) {
|
||||
Debug::warn( 'Could not find any Phonebooks' );
|
||||
return [];
|
||||
}
|
||||
|
||||
$phonebooks = $phonebooks->results();
|
||||
$formattedPhonebooks = [];
|
||||
foreach ($phonebooks as $phonebook) {
|
||||
if ( !empty($phonebook->phonebookID) ) {
|
||||
$phonebookID = $phonebook->phonebookID;
|
||||
if ( ! isset( $formattedPhonebooks[ $phonebookID ])) {
|
||||
$formattedPhonebooks[ $phonebookID ][ 'phonebooks' ] = [];
|
||||
}
|
||||
$formattedPhonebooks[ $phonebookID ][ 'phonebooks' ][] = $phonebook;
|
||||
} else {
|
||||
$phonebookID = $phonebook->ID;
|
||||
$formattedPhonebooks[ $phonebookID ][ 'phonebook' ] = $phonebook;
|
||||
}
|
||||
}
|
||||
return $formattedPhonebooks;
|
||||
}
|
||||
|
||||
}
|
@ -1,57 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* app/plugins/contacts/plugin.php
|
||||
*
|
||||
* This houses all of the main plugin info and functionality.
|
||||
*
|
||||
* @package TP Contacts
|
||||
* @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 TheTempusProject\Classes\Plugin;
|
||||
use TheTempusProject\Models\Contact;
|
||||
use TheTempusProject\Models\Phonebook;
|
||||
use TheTempusProject\Houdini\Classes\Components;
|
||||
use TheTempusProject\Houdini\Classes\Template;
|
||||
|
||||
class Contacts extends Plugin {
|
||||
public $pluginName = 'TP Contacts';
|
||||
public $configName = 'contacts';
|
||||
public $pluginAuthor = 'JoeyK';
|
||||
public $pluginWebsite = 'https://TheTempusProject.com';
|
||||
public $modelVersion = '1.0';
|
||||
public $pluginVersion = '3.0';
|
||||
public $pluginDescription = 'A simple plugin which adds a site wide contacts system.';
|
||||
public $permissionMatrix = [
|
||||
'useContacts' => [
|
||||
'pretty' => 'Can use the contacts feature',
|
||||
'default' => false,
|
||||
],
|
||||
];
|
||||
public $main_links = [
|
||||
[
|
||||
'text' => 'Contacts',
|
||||
'url' => '{ROOT_URL}contacts/index/',
|
||||
'filter' => 'loggedin',
|
||||
],
|
||||
];
|
||||
public $configMatrix = [
|
||||
'enabled' => [
|
||||
'type' => 'radio',
|
||||
'pretty' => 'Enable Contacts.',
|
||||
'default' => true,
|
||||
],
|
||||
];
|
||||
// public $contacts;
|
||||
// public $phonebooks;
|
||||
|
||||
public function __construct( $load = false ) {
|
||||
// $this->contacts = new Contact;
|
||||
// $this->phonebooks = new Phonebook;
|
||||
parent::__construct( $load );
|
||||
}
|
||||
}
|
@ -1,162 +0,0 @@
|
||||
<legend>New Contact</legend>
|
||||
<form action="" method="post" class="form-horizontal">
|
||||
<input type="hidden" name="token" value="{TOKEN}">
|
||||
<fieldset>
|
||||
<!-- Name -->
|
||||
<div class="form-group">
|
||||
<label for="avatar" class="col-lg-3 control-label">Avatar:</label>
|
||||
<div class="col-lg-3">
|
||||
<input class="form-control" type="text" name="avatar" id="avatar">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="first_name" class="col-lg-3 control-label">First Name:</label>
|
||||
<div class="col-lg-3">
|
||||
<input class="form-control" type="text" name="first_name" id="first_name">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="middle_name" class="col-lg-3 control-label">Middle Name:</label>
|
||||
<div class="col-lg-3">
|
||||
<input class="form-control" type="text" name="middle_name" id="middle_name">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="last_name" class="col-lg-3 control-label">Last Name:</label>
|
||||
<div class="col-lg-3">
|
||||
<input class="form-control" type="text" name="last_name" id="last_name">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="nickname" class="col-lg-3 control-label">Nickname:</label>
|
||||
<div class="col-lg-3">
|
||||
<input class="form-control" type="text" name="nickname" id="nickname">
|
||||
</div>
|
||||
</div>
|
||||
<!-- Work -->
|
||||
<div class="form-group">
|
||||
<label for="company" class="col-lg-3 control-label">Company:</label>
|
||||
<div class="col-lg-3">
|
||||
<input class="form-control" type="text" name="company" id="company">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="job_title" class="col-lg-3 control-label">Job Title:</label>
|
||||
<div class="col-lg-3">
|
||||
<input class="form-control" type="text" name="job_title" id="job_title">
|
||||
</div>
|
||||
</div>
|
||||
<!-- Email -->
|
||||
<div class="form-group">
|
||||
<label for="email" class="col-lg-3 control-label">Email:</label>
|
||||
<div class="col-lg-3">
|
||||
<input class="form-control" type="text" name="email" id="email">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="email_2" class="col-lg-3 control-label">Secondary Email:</label>
|
||||
<div class="col-lg-3">
|
||||
<input class="form-control" type="text" name="email_2" id="email_2">
|
||||
</div>
|
||||
</div>
|
||||
<!-- Phone -->
|
||||
<div class="form-group">
|
||||
<label for="phone" class="col-lg-3 control-label">Phone:</label>
|
||||
<div class="col-lg-3">
|
||||
<input class="form-control" type="text" name="phone" id="phone">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="phone_2" class="col-lg-3 control-label">Secondary Phone:</label>
|
||||
<div class="col-lg-3">
|
||||
<input class="form-control" type="text" name="phone_2" id="phone_2">
|
||||
</div>
|
||||
</div>
|
||||
<!-- Addresses -->
|
||||
<div class="form-group">
|
||||
<label for="address_1_primary" class="col-lg-3 control-label">Address Line 1:</label>
|
||||
<div class="col-lg-3">
|
||||
<input class="form-control" type="text" name="address_1_primary" id="address_1_primary">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="address_1_secondary" class="col-lg-3 control-label">Address Line 2:</label>
|
||||
<div class="col-lg-3">
|
||||
<input class="form-control" type="text" name="address_1_secondary" id="address_1_secondary">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="city" class="col-lg-3 control-label">City:</label>
|
||||
<div class="col-lg-3">
|
||||
<input class="form-control" type="text" name="city" id="city">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="state" class="col-lg-3 control-label">State:</label>
|
||||
<div class="col-lg-3">
|
||||
<input class="form-control" type="text" name="state" id="state">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="zipcode" class="col-lg-3 control-label">Zipcode:</label>
|
||||
<div class="col-lg-3">
|
||||
<input class="form-control" type="text" name="zipcode" id="zipcode">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="country" class="col-lg-3 control-label">Country:</label>
|
||||
<div class="col-lg-3">
|
||||
<input class="form-control" type="text" name="country" id="country">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="address_2_primary" class="col-lg-3 control-label">Address Line 1:</label>
|
||||
<div class="col-lg-3">
|
||||
<input class="form-control" type="text" name="address_2_primary" id="address_2_primary">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="address_2_secondary" class="col-lg-3 control-label">Address Line 2:</label>
|
||||
<div class="col-lg-3">
|
||||
<input class="form-control" type="text" name="address_2_secondary" id="address_2_secondary">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="city_2" class="col-lg-3 control-label">City:</label>
|
||||
<div class="col-lg-3">
|
||||
<input class="form-control" type="text" name="city_2" id="city_2">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="state_2" class="col-lg-3 control-label">State:</label>
|
||||
<div class="col-lg-3">
|
||||
<input class="form-control" type="text" name="state_2" id="state_2">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="zipcode_2" class="col-lg-3 control-label">Zipcode:</label>
|
||||
<div class="col-lg-3">
|
||||
<input class="form-control" type="text" name="zipcode_2" id="zipcode_2">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="country_2" class="col-lg-3 control-label">Country:</label>
|
||||
<div class="col-lg-3">
|
||||
<input class="form-control" type="text" name="country_2" id="country_2">
|
||||
</div>
|
||||
</div>
|
||||
<!-- Misc -->
|
||||
<div class="form-group">
|
||||
<label for="notes" class="col-lg-3 control-label">Notes:</label>
|
||||
<div class="col-lg-3">
|
||||
<input class="form-control" type="text" name="notes" id="notes">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="submit" class="col-lg-3 control-label"></label>
|
||||
<div class="col-lg-3">
|
||||
<button name="submit" value="submit" type="submit" class="btn btn-lg btn-primary center-block">Create</button><br>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</form>
|
@ -1,162 +0,0 @@
|
||||
<legend>Edit Contact</legend>
|
||||
<form action="" method="post" class="form-horizontal">
|
||||
<input type="hidden" name="token" value="{TOKEN}">
|
||||
<fieldset>
|
||||
<!-- Name -->
|
||||
<div class="form-group">
|
||||
<label for="avatar" class="col-lg-3 control-label">Avatar:</label>
|
||||
<div class="col-lg-3">
|
||||
<input class="form-control" type="text" name="avatar" id="avatar" value="{avatar}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="first_name" class="col-lg-3 control-label">First Name:</label>
|
||||
<div class="col-lg-3">
|
||||
<input class="form-control" type="text" name="first_name" id="first_name" value="{first_name}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="middle_name" class="col-lg-3 control-label">Middle Name:</label>
|
||||
<div class="col-lg-3">
|
||||
<input class="form-control" type="text" name="middle_name" id="middle_name" value="{middle_name}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="last_name" class="col-lg-3 control-label">Last Name:</label>
|
||||
<div class="col-lg-3">
|
||||
<input class="form-control" type="text" name="last_name" id="last_name" value="{last_name}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="nickname" class="col-lg-3 control-label">Nickname:</label>
|
||||
<div class="col-lg-3">
|
||||
<input class="form-control" type="text" name="nickname" id="nickname" value="{nickname}">
|
||||
</div>
|
||||
</div>
|
||||
<!-- Work -->
|
||||
<div class="form-group">
|
||||
<label for="company" class="col-lg-3 control-label">Company:</label>
|
||||
<div class="col-lg-3">
|
||||
<input class="form-control" type="text" name="company" id="company" value="{company}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="job_title" class="col-lg-3 control-label">Job Title:</label>
|
||||
<div class="col-lg-3">
|
||||
<input class="form-control" type="text" name="job_title" id="job_title" value="{job_title}">
|
||||
</div>
|
||||
</div>
|
||||
<!-- Email -->
|
||||
<div class="form-group">
|
||||
<label for="email" class="col-lg-3 control-label">Email:</label>
|
||||
<div class="col-lg-3">
|
||||
<input class="form-control" type="text" name="email" id="email" value="{email}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="email_2" class="col-lg-3 control-label">Secondary Email:</label>
|
||||
<div class="col-lg-3">
|
||||
<input class="form-control" type="text" name="email_2" id="email_2" value="{email_2}">
|
||||
</div>
|
||||
</div>
|
||||
<!-- Phone -->
|
||||
<div class="form-group">
|
||||
<label for="phone" class="col-lg-3 control-label">Phone:</label>
|
||||
<div class="col-lg-3">
|
||||
<input class="form-control" type="text" name="phone" id="phone" value="{phone}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="phone_2" class="col-lg-3 control-label">Secondary Phone:</label>
|
||||
<div class="col-lg-3">
|
||||
<input class="form-control" type="text" name="phone_2" id="phone_2" value="{phone_2}">
|
||||
</div>
|
||||
</div>
|
||||
<!-- Addresses -->
|
||||
<div class="form-group">
|
||||
<label for="address_1_primary" class="col-lg-3 control-label">Address Line 1:</label>
|
||||
<div class="col-lg-3">
|
||||
<input class="form-control" type="text" name="address_1_primary" id="address_1_primary" value="{address_1_primary}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="address_1_secondary" class="col-lg-3 control-label">Address Line 2:</label>
|
||||
<div class="col-lg-3">
|
||||
<input class="form-control" type="text" name="address_1_secondary" id="address_1_secondary" value="{address_1_secondary}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="city" class="col-lg-3 control-label">City:</label>
|
||||
<div class="col-lg-3">
|
||||
<input class="form-control" type="text" name="city" id="city" value="{city}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="state" class="col-lg-3 control-label">State:</label>
|
||||
<div class="col-lg-3">
|
||||
<input class="form-control" type="text" name="state" id="state" value="{state}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="zipcode" class="col-lg-3 control-label">Zipcode:</label>
|
||||
<div class="col-lg-3">
|
||||
<input class="form-control" type="text" name="zipcode" id="zipcode" value="{zipcode}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="country" class="col-lg-3 control-label">Country:</label>
|
||||
<div class="col-lg-3">
|
||||
<input class="form-control" type="text" name="country" id="country" value="{country}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="address_2_primary" class="col-lg-3 control-label">Address Line 1:</label>
|
||||
<div class="col-lg-3">
|
||||
<input class="form-control" type="text" name="address_2_primary" id="address_2_primary" value="{address_2_primary}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="address_2_secondary" class="col-lg-3 control-label">Address Line 2:</label>
|
||||
<div class="col-lg-3">
|
||||
<input class="form-control" type="text" name="address_2_secondary" id="address_2_secondary" value="{address_2_secondary}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="city_2" class="col-lg-3 control-label">City:</label>
|
||||
<div class="col-lg-3">
|
||||
<input class="form-control" type="text" name="city_2" id="city_2" value="{city_2}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="state_2" class="col-lg-3 control-label">State:</label>
|
||||
<div class="col-lg-3">
|
||||
<input class="form-control" type="text" name="state_2" id="state_2" value="{state_2}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="zipcode_2" class="col-lg-3 control-label">Zipcode:</label>
|
||||
<div class="col-lg-3">
|
||||
<input class="form-control" type="text" name="zipcode_2" id="zipcode_2" value="{zipcode_2}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="country_2" class="col-lg-3 control-label">Country:</label>
|
||||
<div class="col-lg-3">
|
||||
<input class="form-control" type="text" name="country_2" id="country_2" value="{country_2}">
|
||||
</div>
|
||||
</div>
|
||||
<!-- Misc -->
|
||||
<div class="form-group">
|
||||
<label for="notes" class="col-lg-3 control-label">Notes:</label>
|
||||
<div class="col-lg-3">
|
||||
<input class="form-control" type="text" name="notes" id="notes" value="{notes}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="submit" class="col-lg-3 control-label"></label>
|
||||
<div class="col-lg-3">
|
||||
<button name="submit" value="submit" type="submit" class="btn btn-lg btn-primary center-block">Create</button><br>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</form>
|
@ -1,40 +0,0 @@
|
||||
<div class="row" style="margin-top: 30px; margin-bottom: 50px;">
|
||||
<form action="" method="post">
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width: 5%">ID</th>
|
||||
<th style="width: 15%">Nickname</th>
|
||||
<th style="width: 20%">First Name</th>
|
||||
<th style="width: 20%">Last Name</th>
|
||||
<th style="width: 15%">Email</th>
|
||||
<th style="width: 15%">Phone</th>
|
||||
<th style="width: 5%"></th>
|
||||
<th style="width: 5%"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{LOOP}
|
||||
<tr>
|
||||
<td><a href='{ROOT_URL}contacts/viewContact/{ID}'>{ID}</a></td>
|
||||
<td>{nickname}</td>
|
||||
<td>{first_name}</td>
|
||||
<td>{last_name}</td>
|
||||
<td>{email}</td>
|
||||
<td>{phone}</td>
|
||||
<td><a href="{ROOT_URL}contacts/editContact/{ID}" class="btn btn-sm btn-warning" role="button"><i class="glyphicon glyphicon-edit"></i></a></td>
|
||||
<td><a href="{ROOT_URL}contacts/deleteContact/{ID}" class="btn btn-sm btn-danger" role="button"><i class="glyphicon glyphicon-trash"></i></a></td>
|
||||
</tr>
|
||||
{/LOOP}
|
||||
{ALT}
|
||||
<tr>
|
||||
<td colspan="7">
|
||||
No Contacts
|
||||
</td>
|
||||
</tr>
|
||||
{/ALT}
|
||||
</tbody>
|
||||
</table>
|
||||
<a href="{ROOT_URL}contacts/createContact" class="btn btn-sm btn-primary" role="button">Add Contact</a>
|
||||
</form>
|
||||
</div>
|
@ -1,87 +0,0 @@
|
||||
<div class="container col-md-4 col-lg-4">
|
||||
<div class="row">
|
||||
<div class="panel panel-{color}">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">Contact</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div class="row">
|
||||
<div class="">
|
||||
<table class="table table-user-primary">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="left" width="200"><b>First Name</b></td>
|
||||
<td align="right">{first_name}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" width="200"><b>Middle Name</b></td>
|
||||
<td align="right">{middle_name}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" width="200"><b>Last Name</b></td>
|
||||
<td align="right">{last_name}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" width="200"><b>Nickname</b></td>
|
||||
<td align="right">{nickname}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" width="200"><b>Company</b></td>
|
||||
<td align="right">{company}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" width="200"><b>Job Title</b></td>
|
||||
<td align="right">{job_title}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" width="200"><b>Email</b></td>
|
||||
<td align="right">
|
||||
{email}<br />
|
||||
{email_2}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" width="200"><b>Phone</b></td>
|
||||
<td align="right">
|
||||
{phone}<br />
|
||||
{phone_2}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" width="200"><b>Address 1</b></td>
|
||||
<td align="right">
|
||||
{address_1_primary}<br />
|
||||
{address_1_secondary}<br />
|
||||
{city} {state} {country} {zipcode}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" width="200"><b>Address 2</b></td>
|
||||
<td align="right">
|
||||
{address_2_primary}<br />
|
||||
{address_2_secondary}<br />
|
||||
{city_2} {state_2} {country_2} {zipcode_2}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" colspan="2"><b>Notes</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2">{notes}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Created</b></td>
|
||||
<td align="right">{DTC}{createdAt}{/DTC}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel-footer">
|
||||
<a href="{ROOT_URL}contacts/editContact/{ID}" class="btn btn-sm btn-warning" role="button"><i class="glyphicon glyphicon-edit"></i></a>
|
||||
<a href="{ROOT_URL}contacts/deleteContact/{ID}" class="btn btn-sm btn-danger" role="button"><i class="glyphicon glyphicon-trash"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -1,3 +0,0 @@
|
||||
<legend>Contacts</legend>
|
||||
{phonebookList}
|
||||
{contactList}
|
@ -1,35 +0,0 @@
|
||||
<legend>Create Phonebook</legend>
|
||||
<form action="" method="post" class="form-horizontal">
|
||||
<input type="hidden" name="token" value="{TOKEN}">
|
||||
<div class="form-group">
|
||||
<label for="title" class="col-lg-3 control-label">Title</label>
|
||||
<div class="col-lg-3">
|
||||
<input type="text" class="form-control" name="title" id="title">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="description" class="col-lg-3 control-label">Description</label>
|
||||
<div class="col-lg-3">
|
||||
<textarea class="form-control" name="description" maxlength="2000" rows="10" cols="50" id="description"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="color" class="col-lg-3 control-label">Color</label>
|
||||
<div class="col-lg-3 select-container" id="colorContainer">
|
||||
{colorSelect}
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="dropdown" class="col-lg-3 control-label">Icon</label>
|
||||
<div class="dropdow col-lg-3">
|
||||
{iconSelect}
|
||||
</div>
|
||||
<input type="hidden" id="iconValue" name="icon" value="">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="submit" class="col-lg-3 control-label"></label>
|
||||
<div class="col-lg-3">
|
||||
<button name="submit" value="submit" type="submit" class="btn btn-lg btn-primary center-block ">Submit</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
@ -1,33 +0,0 @@
|
||||
<form action="" method="post" class="form-horizontal">
|
||||
<input type="hidden" name="token" value="{TOKEN}">
|
||||
<div class="form-group">
|
||||
<label for="title" class="col-lg-3 control-label">Title</label>
|
||||
<div class="col-lg-3">
|
||||
<input type="text" class="form-control" name="title" id="title" value="{title}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="description" class="col-lg-3 control-label">Description</label>
|
||||
<div class="col-lg-3">
|
||||
<textarea class="form-control" name="description" maxlength="2000" rows="10" cols="50" id="description">{description}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="color" class="col-lg-3 control-label">Color</label>
|
||||
<div class="col-lg-3 select-container" id="colorContainer">
|
||||
{colorSelect}
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="dropdown" class="col-lg-3 control-label">Icon</label>
|
||||
<div class="dropdow col-lg-3">
|
||||
{iconSelect}
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="submit" class="col-lg-3 control-label"></label>
|
||||
<div class="col-lg-3">
|
||||
<button name="submit" value="submit" type="submit" class="btn btn-lg btn-primary center-block ">Submit</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
@ -1,33 +0,0 @@
|
||||
<div class="row" style="margin-top: 30px; margin-bottom: 50px;">
|
||||
<form action="" method="post">
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width: 55%">Title</th>
|
||||
<th style="width: 35%">Description</th>
|
||||
<th style="width: 5%"></th>
|
||||
<th style="width: 5%"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{LOOP}
|
||||
<tr>
|
||||
<td><a href='{ROOT_URL}contacts/viewPhonebook/{ID}'>{title}</a></td>
|
||||
<td>{description}</td>
|
||||
<td><a href="{ROOT_URL}contacts/editPhonebook/{ID}" class="btn btn-sm btn-warning" role="button"><i class="glyphicon glyphicon-edit"></i></a></td>
|
||||
<td><a href="{ROOT_URL}contacts/deletePhonebook/{ID}" class="btn btn-sm btn-danger" role="button"><i class="glyphicon glyphicon-trash"></i></a></td>
|
||||
</tr>
|
||||
{/LOOP}
|
||||
{ALT}
|
||||
<tr>
|
||||
<td colspan="7">
|
||||
No Phonebooks
|
||||
</td>
|
||||
</tr>
|
||||
{/ALT}
|
||||
</tbody>
|
||||
</table>
|
||||
<a href="{ROOT_URL}contacts/createPhonebook" class="btn btn-sm btn-primary" role="button">New Phonebook</a>
|
||||
</form>
|
||||
</div>
|
||||
|
@ -1,45 +0,0 @@
|
||||
<div class="container col-md-4 col-lg-4">
|
||||
<div class="row">
|
||||
<div class="panel panel-{color}">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">Phonebook</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div class="row">
|
||||
<div class="">
|
||||
<table class="table table-user-primary">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="left" width="200"><b>Title</b></td>
|
||||
<td align="right">{title}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" width="200"><b>Icon</b></td>
|
||||
<td align="right">{icon}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" width="200"><b>Color</b></td>
|
||||
<td align="right">{color}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" colspan="2"><b>Description</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2">{description}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Created</b></td>
|
||||
<td align="right">{DTC}{createdAt}{/DTC}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel-footer">
|
||||
<a href="{ROOT_URL}contacts/editPhonebook/{ID}" class="btn btn-sm btn-warning" role="button"><i class="glyphicon glyphicon-edit"></i></a>
|
||||
<a href="{ROOT_URL}contacts/deletePhonebook/{ID}" class="btn btn-sm btn-danger" role="button"><i class="glyphicon glyphicon-trash"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -1,121 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* app/plugins/fileshare/controllers/fileshare.php
|
||||
*
|
||||
* This is the home controller for the fileshare plugin.
|
||||
*
|
||||
* @package TP FileShare
|
||||
* @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\Houdini\Classes\Views;
|
||||
use TheTempusProject\Houdini\Classes\Issues;
|
||||
use TheTempusProject\Bedrock\Functions\Input;
|
||||
use TheTempusProject\Bedrock\Functions\Upload;
|
||||
use TheTempusProject\Classes\Controller;
|
||||
use TheTempusProject\Models\Upload as UploadModel;
|
||||
use TheTempusProject\TheTempusProject as App;
|
||||
use TheTempusProject\Classes\Forms;
|
||||
use TheTempusProject\Bedrock\Functions\Session;
|
||||
use TheTempusProject\Hermes\Functions\Redirect;
|
||||
|
||||
class Fileshare extends Controller {
|
||||
protected static $uploads;
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
self::$uploads = new UploadModel;
|
||||
self::$title = 'FileShare - {SITENAME}';
|
||||
self::$pageDescription = 'Your saved Files for the site.';
|
||||
}
|
||||
|
||||
public function index() {
|
||||
$uploads = self::$uploads->getByUser();
|
||||
Views::view( 'fileshare.list', $uploads );
|
||||
}
|
||||
|
||||
public function delete( $id = null ) {
|
||||
$upload = self::$uploads->findById( $id );
|
||||
if ( $upload == false ) {
|
||||
Issues::add( 'error', 'Upload not found.' );
|
||||
return $this->index();
|
||||
}
|
||||
if ( $upload->createdBy != App::$activeUser->ID ) {
|
||||
Issues::add( 'error', 'You do not have permission to modify this upload.' );
|
||||
return $this->index();
|
||||
}
|
||||
$result = self::$uploads->delete( $id );
|
||||
if ( $result == true ) {
|
||||
Issues::add( 'success', 'Upload deleted.' );
|
||||
} else {
|
||||
Issues::add( 'notice', 'There was an problem deleting your upload.' );
|
||||
}
|
||||
return $this->index();
|
||||
}
|
||||
|
||||
public function edit( $id = null ) {
|
||||
$upload = self::$uploads->findById( $id );
|
||||
if ( $upload == false ) {
|
||||
Issues::add( 'error', 'Upload not found.' );
|
||||
return $this->index();
|
||||
}
|
||||
|
||||
if ( ! Input::exists( 'submit' ) ) {
|
||||
return Views::view( 'calendar.calendar.edit', $upload );
|
||||
}
|
||||
|
||||
if ( ! Forms::check( 'editUpload' ) ) {
|
||||
Issues::add( 'error', [ 'There was an error editing your upload.' => Check::userErrors() ] );
|
||||
return Views::view( 'fileshare.edit', $upload );
|
||||
}
|
||||
|
||||
if ( Input::exists( 'file' ) ) {
|
||||
$folder = UPLOAD_DIRECTORY . App::$activeUser->username . DIRECTORY_SEPARATOR;
|
||||
if ( ! Upload::image( 'file', $folder ) ) {
|
||||
Issues::add( 'error', [ 'There was an error with your upload.' => Check::systemErrors() ] );
|
||||
return Views::view( 'fileshare.edit', $upload );
|
||||
} else {
|
||||
$route = str_replace( APP_ROOT_DIRECTORY, '', $folder );
|
||||
$location = $route . Upload::last();
|
||||
}
|
||||
} else {
|
||||
$location = '';
|
||||
}
|
||||
|
||||
$result = self::$uploads->update( $id, Input::post('name'), $location );
|
||||
if ( ! $result ) {
|
||||
Issues::add( 'error', [ 'There was an error updating your upload.' => Check::userErrors() ] );
|
||||
return Views::view( 'fileshare.edit', $upload );
|
||||
}
|
||||
Session::flash( 'success', 'Your Upload has been updated.' );
|
||||
Redirect::to( 'fileshare/index/');
|
||||
}
|
||||
|
||||
public function upload( $id = null ) {
|
||||
if ( ! Input::exists() ) {
|
||||
return Views::view( 'fileshare.create' );
|
||||
}
|
||||
if ( ! Forms::check( 'newUpload' ) ) {
|
||||
Issues::add( 'error', [ 'There was an error creating your upload.' => Check::userErrors() ] );
|
||||
return Views::view( 'fileshare.create' );
|
||||
}
|
||||
$folder = UPLOAD_DIRECTORY . App::$activeUser->username . DIRECTORY_SEPARATOR;
|
||||
if ( ! Upload::image( 'file', $folder ) ) {
|
||||
Issues::add( 'error', [ 'There was an error with your upload.' => Check::systemErrors() ] );
|
||||
return Views::view( 'fileshare.create' );
|
||||
} else {
|
||||
$route = str_replace( APP_ROOT_DIRECTORY, '', $folder );
|
||||
$location = $route . Upload::last();
|
||||
}
|
||||
$upload = self::$uploads->create( Input::post('name'), $location );
|
||||
if ( ! $upload ) {
|
||||
return Views::view( 'fileshare.create' );
|
||||
}
|
||||
Session::flash( 'success', 'Your Upload has been saved.' );
|
||||
Redirect::to( 'fileshare/index/');
|
||||
}
|
||||
}
|
@ -1,47 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* app/plugins/fileshare/forms.php
|
||||
*
|
||||
* This houses all of the form checking functions for this plugin.
|
||||
*
|
||||
* @package TP FileShare
|
||||
* @version 3.0
|
||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||
* @link https://TheTempusProject.com
|
||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||
*/
|
||||
namespace TheTempusProject\Plugins\Feedback;
|
||||
|
||||
use TheTempusProject\Bedrock\Functions\Input;
|
||||
use TheTempusProject\Bedrock\Functions\Check;
|
||||
use TheTempusProject\Classes\Forms;
|
||||
|
||||
class FileShareForms extends Forms {
|
||||
/**
|
||||
* Adds these functions to the form list.
|
||||
*/
|
||||
public function __construct() {
|
||||
self::addHandler( 'newUpload', __CLASS__, 'newUpload' );
|
||||
self::addHandler( 'editUpload', __CLASS__, 'editUpload' );
|
||||
}
|
||||
public static function newUpload() {
|
||||
if ( ! Input::exists( 'name' ) ) {
|
||||
Check::addUserError( 'You must provide a name.' );
|
||||
return false;
|
||||
}
|
||||
if ( ! Input::exists( 'file' ) ) {
|
||||
Check::addUserError( 'You must provide a file.' );
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
public static function editUpload() {
|
||||
if ( ! Input::exists( 'name' ) ) {
|
||||
Check::addUserError( 'You must provide a name.' );
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
new FileShareForms;
|
@ -1,181 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* app/plugins/fileshare/models/upload.php
|
||||
*
|
||||
* This class is used for the manipulation of the uploads database table.
|
||||
*
|
||||
* @package TP FileShare
|
||||
* @version 3.0
|
||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||
* @link https://TheTempusProject.com
|
||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||
*/
|
||||
namespace TheTempusProject\Models;
|
||||
|
||||
use TheTempusProject\Bedrock\Classes\Config;
|
||||
use TheTempusProject\Bedrock\Functions\Check;
|
||||
use TheTempusProject\Canary\Bin\Canary as Debug;
|
||||
use TheTempusProject\Classes\DatabaseModel;
|
||||
use TheTempusProject\TheTempusProject as App;
|
||||
use TheTempusProject\Bedrock\Classes\CustomException;
|
||||
|
||||
class Upload extends DatabaseModel {
|
||||
public $tableName = 'uploads';
|
||||
public $databaseMatrix = [
|
||||
[ 'name', 'varchar', '256' ],
|
||||
[ 'location', 'text', '64' ],
|
||||
[ 'size', 'int', '20' ],
|
||||
[ 'file_type', 'varchar', '64' ],
|
||||
[ 'createdBy', 'int', '11' ],
|
||||
[ 'createdAt', 'int', '11' ],
|
||||
];
|
||||
|
||||
/**
|
||||
* The model constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
public function create( $name, $location ) {
|
||||
$info = $this->getFileInfo( $location );
|
||||
$size = $info['size'];
|
||||
$file_type = $info['file_type'];
|
||||
$fields = [
|
||||
'name' => $name,
|
||||
'location' => '/' . $location,
|
||||
'size' => $size,
|
||||
'file_type' => $file_type,
|
||||
'createdAt' => time(),
|
||||
'createdBy' => App::$activeUser->ID,
|
||||
];
|
||||
if ( ! self::$db->insert( $this->tableName, $fields ) ) {
|
||||
Debug::info( 'Uploads::create - failed to insert to db' );
|
||||
return false;
|
||||
}
|
||||
return self::$db->lastId();
|
||||
}
|
||||
|
||||
public function update( $id, $name, $location = '' ) {
|
||||
$fields = [
|
||||
'name' => $name,
|
||||
];
|
||||
if ( ! empty( $location ) ) {
|
||||
$info = $this->getFileInfo( $location );
|
||||
$fields['location'] = $location;
|
||||
$fields['size'] = $info['size'];
|
||||
$fields['file_type'] = $info['file_type'];
|
||||
}
|
||||
if ( ! self::$db->update( $this->tableName, $id, $fields ) ) {
|
||||
new CustomException( 'UploadsUpdate' );
|
||||
Debug::error( "Uploads: $id not updated: $fields" );
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function simple() {
|
||||
$uploads = self::$db->get( $this->tableName, '*' );
|
||||
if ( !$uploads->count() ) {
|
||||
Debug::warn( 'Could not find any uploads' );
|
||||
return false;
|
||||
}
|
||||
|
||||
$uploads = $uploads->results();
|
||||
$out = [];
|
||||
foreach ( $uploads as $upload ) {
|
||||
$out[ $upload->name ] = $upload->location;
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
|
||||
// public function processFileUpload() {
|
||||
|
||||
// }
|
||||
|
||||
public function getByUser( $limit = 0 ) {
|
||||
$whereClause = [
|
||||
'createdBy', '=', App::$activeUser->ID,
|
||||
];
|
||||
if ( empty( $limit ) ) {
|
||||
$uploads = self::$db->get( $this->tableName, $whereClause );
|
||||
} else {
|
||||
$uploads = self::$db->get( $this->tableName, $whereClause, 'ID', 'DESC', [0, $limit] );
|
||||
}
|
||||
if ( ! $uploads->count() ) {
|
||||
Debug::info( 'No Uploads found.' );
|
||||
return false;
|
||||
}
|
||||
return $this->filter( $uploads->results() );
|
||||
}
|
||||
|
||||
public function delete( $idArray ) {
|
||||
if ( !is_array( $idArray ) ) {
|
||||
$idArray = [ $idArray ];
|
||||
}
|
||||
|
||||
foreach ( $idArray as $id ) {
|
||||
$upload = self::findById( $id );
|
||||
if ( $upload ) {
|
||||
$fileLocation = APP_ROOT_DIRECTORY . ltrim( $upload->location, '/' );
|
||||
if (file_exists($fileLocation)) {
|
||||
if (!unlink($fileLocation)) {
|
||||
Debug::error("Failed to delete file: $fileLocation");
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
Debug::warn("File does not exist: $fileLocation");
|
||||
}
|
||||
}
|
||||
}
|
||||
return parent::delete( $idArray );
|
||||
}
|
||||
|
||||
private function getFileInfo( $imagePath )
|
||||
{
|
||||
$data = [];
|
||||
$fileLocation = APP_ROOT_DIRECTORY . ltrim( $imagePath, '/' );
|
||||
if ( file_exists( $fileLocation ) ) {
|
||||
$fileInfo = finfo_open(FILEINFO_MIME_TYPE);
|
||||
$mimeType = finfo_file($fileInfo, $fileLocation);
|
||||
finfo_close($fileInfo);
|
||||
|
||||
$fileSize = filesize($fileLocation);
|
||||
|
||||
$data['file_type'] = $mimeType;
|
||||
$data['size'] = $fileSize;
|
||||
$data['path'] = $fileLocation;
|
||||
} else {
|
||||
Debug::warn("File does not exist: $fileLocation");
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function filter( $data, $params = [] ) {
|
||||
foreach ( $data as $instance ) {
|
||||
if ( !is_object( $instance ) ) {
|
||||
$instance = $data;
|
||||
$end = true;
|
||||
}
|
||||
if (isset($instance->size)) {
|
||||
$instance->readableSize = $this->formatSize($instance->size);
|
||||
}
|
||||
$out[] = $instance;
|
||||
if ( !empty( $end ) ) {
|
||||
$out = $out[0];
|
||||
break;
|
||||
}
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
|
||||
public function formatSize($size) {
|
||||
$units = ['B', 'KB', 'MB', 'GB', 'TB'];
|
||||
$i = 0;
|
||||
while ($size >= 1024 && $i < count($units) - 1) {
|
||||
$size /= 1024;
|
||||
$i++;
|
||||
}
|
||||
return round($size, 2) . ' ' . $units[$i];
|
||||
}
|
||||
}
|
@ -1,45 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* app/plugins/fileshare/plugin.php
|
||||
*
|
||||
* This houses all of the main plugin info and functionality.
|
||||
*
|
||||
* @package TP FileShare
|
||||
* @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 TheTempusProject\TheTempusProject as App;
|
||||
use TheTempusProject\Classes\Plugin;
|
||||
use TheTempusProject\Models\Upload;
|
||||
use TheTempusProject\Houdini\Classes\Components;
|
||||
use TheTempusProject\Houdini\Classes\Views;
|
||||
|
||||
class Fileshare extends Plugin {
|
||||
public $pluginName = 'TP FileShare';
|
||||
public $configName = 'fileshare';
|
||||
public $pluginAuthor = 'JoeyK';
|
||||
public $pluginWebsite = 'https://TheTempusProject.com';
|
||||
public $modelVersion = '1.0';
|
||||
public $pluginVersion = '3.0';
|
||||
public $pluginDescription = 'A simple plugin which adds a site wide file-sharing system.';
|
||||
public $permissionMatrix = [
|
||||
'uploadFiles' => [
|
||||
'pretty' => 'Can upload files',
|
||||
'default' => false,
|
||||
],
|
||||
];
|
||||
private static $loaded = false;
|
||||
public function __construct( $load = false ) {
|
||||
parent::__construct( $load );
|
||||
if ( $this->checkEnabled() && App::$isLoggedIn ) {
|
||||
if ( ! self::$loaded ) {
|
||||
App::$topNavRightDropdown .= '<li><a href="{ROOT_URL}fileshare/index/"><i class="glyphicon glyphicon-cloud"></i> FileShare</a></li>';
|
||||
self::$loaded = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
<legend>File Upload</legend>
|
||||
<form action="" method="post" class="form-horizontal" enctype="multipart/form-data">
|
||||
<input type="hidden" name="token" value="{TOKEN}">
|
||||
<div class="form-group">
|
||||
<label for="name" class="col-lg-3 control-label">Name</label>
|
||||
<div class="col-lg-3">
|
||||
<input type="text" class="form-control" name="name" id="name">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="file" class="col-lg-3 control-label">File</label>
|
||||
<div class="col-lg-3">
|
||||
<input type="file" class="form-control" name="file" id="file">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="submit" class="col-lg-3 control-label"></label>
|
||||
<div class="col-lg-3">
|
||||
<button name="submit" value="submit" type="submit" class="btn btn-lg btn-primary center-block ">Upload</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
@ -1,22 +0,0 @@
|
||||
<legend>Edit File</legend>
|
||||
<form action="" method="post" class="form-horizontal" enctype="multipart/form-data">
|
||||
<input type="hidden" name="token" value="{TOKEN}">
|
||||
<div class="form-group">
|
||||
<label for="name" class="col-lg-3 control-label">Name</label>
|
||||
<div class="col-lg-3">
|
||||
<input type="text" class="form-control" name="name" id="name" value="{name}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="file" class="col-lg-3 control-label">File (uploading a new file will replace the existing file)</label>
|
||||
<div class="col-lg-3">
|
||||
<input type="file" class="form-control" name="file" id="file">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="submit" class="col-lg-3 control-label"></label>
|
||||
<div class="col-lg-3">
|
||||
<button name="submit" value="submit" type="submit" class="btn btn-lg btn-primary center-block ">Save</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
@ -1,24 +0,0 @@
|
||||
<div class="row">
|
||||
{LOOP}
|
||||
<div class="col-sm-6 col-md-4">
|
||||
<div class="thumbnail">
|
||||
<img src="{location}" alt="{name}">
|
||||
<div class="caption">
|
||||
<h3>{name}</h3>
|
||||
<p>{readableSize}</p>
|
||||
<p>{file_type}</p>
|
||||
<p>
|
||||
<a href="/fileshare/edit/{ID}" class="btn btn-warning" role="button">edit</a>
|
||||
<a href="/fileshare/delete/{ID}" class="btn btn-danger" role="button">Delete</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/LOOP}
|
||||
{ALT}
|
||||
<div class="col-sm-6 col-md-4">
|
||||
No Uploads Found
|
||||
</div>
|
||||
{/ALT}
|
||||
</div>
|
||||
<a href="{ROOT_URL}fileshare/upload" class="btn btn-sm btn-primary" role="button">Upload File</a>
|
@ -1,43 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* app/plugins/initiativetracker/controllers/initiative.php
|
||||
*
|
||||
* This is the home controller for the initiativetracker plugin.
|
||||
*
|
||||
* @package TP InitiativeTracker
|
||||
* @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\Houdini\Classes\Views;
|
||||
use TheTempusProject\Classes\Controller;
|
||||
use TheTempusProject\Models\Inithistory;
|
||||
use TheTempusProject\Houdini\Classes\Issues;
|
||||
use TheTempusProject\Houdini\Classes\Components;
|
||||
use TheTempusProject\TheTempusProject as App;
|
||||
|
||||
class Initiative extends Controller {
|
||||
protected static $initiativeHistory;
|
||||
|
||||
public function __construct() {
|
||||
self::$title = 'Initiative Tracker - {SITENAME}';
|
||||
self::$pageDescription = 'This is for tracking player and creature turns and initiatives.';
|
||||
self::$initiativeHistory = new Inithistory;
|
||||
if ( ! App::$isLoggedIn ) {
|
||||
Issues::add( 'info', 'If you register an account and log in, you can save your initiatives.' );
|
||||
Components::set( 'initiativeHistory', '' );
|
||||
} else {
|
||||
$history = self::$initiativeHistory->userHistory();
|
||||
$historyView = Views::simpleView( 'initiativetracker.historyElement', $history );
|
||||
Components::set( 'initiativeHistory', $historyView );
|
||||
}
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
public function index() {
|
||||
Views::view( 'initiativetracker.index' );
|
||||
}
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
.initiative-container {
|
||||
margin-bottom: 50px;
|
||||
}
|
||||
|
||||
.character-form {
|
||||
margin-bottom: 50px;
|
||||
}
|
||||
|
||||
.list-controls {
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.round-footer {
|
||||
padding-right: 15px;
|
||||
padding-bottom: 20px;
|
||||
padding-left: 15px;
|
||||
}
|
||||
|
||||
.list-controls-center,.list-controls,.character-form {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.list-controls-last {
|
||||
display: flex;
|
||||
justify-content: right;
|
||||
align-items: right;
|
||||
}
|
||||
|
||||
.list-controls-first {
|
||||
display: flex;
|
||||
justify-content: left;
|
||||
align-items: left;
|
||||
}
|
@ -1,414 +0,0 @@
|
||||
$(document).ready(function() {
|
||||
// Top Checkbox Controls
|
||||
$('input[type="checkbox"]').change(function() {
|
||||
var name = $(this).attr('name');
|
||||
if ( 'trackAC' == name ) {
|
||||
var eles = document.getElementsByClassName('ac-tracker');
|
||||
}
|
||||
if ( 'trackHP' == name ) {
|
||||
var eles = document.getElementsByClassName('hp-tracker');
|
||||
}
|
||||
if ( 'trackRounds' == name ) {
|
||||
var eles = document.getElementsByClassName('rounds-tracker');
|
||||
}
|
||||
if ($(this).is(':checked')) {
|
||||
Array.prototype.forEach.call(eles, function(ele) {
|
||||
ele.style.display = '';
|
||||
});
|
||||
} else {
|
||||
Array.prototype.forEach.call(eles, function(ele) {
|
||||
ele.style.display = 'none';
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
$(document).on('click', '.character-remove', function() {
|
||||
var characterId = $(this).closest('tr').data('character-id');
|
||||
|
||||
var allTrsWithCharacterId = document.querySelectorAll(`tr[data-round-character-id="${characterId}"]`);
|
||||
allTrsWithCharacterId.forEach(function(tr) {
|
||||
tr.remove();
|
||||
});
|
||||
var allTrsWithCharacterId = document.querySelectorAll(`tr[data-character-id="${characterId}"]`);
|
||||
allTrsWithCharacterId.forEach(function(tr) {
|
||||
tr.remove();
|
||||
});
|
||||
|
||||
findByIdAndRemove( characterId, characterInitiativeList );
|
||||
});
|
||||
|
||||
$(document).on('click', '.hp-minus', function() {
|
||||
var characterId = $(this).closest('tr').data('character-id');
|
||||
var dataValue = parseInt($(this).data('value'), 10);
|
||||
var allTrsWithCharacterId = document.querySelectorAll(`tr[data-character-id="${characterId}"]`);
|
||||
|
||||
allTrsWithCharacterId.forEach(function(tr) {
|
||||
var $input = $(tr).find('input[name="hp"]');
|
||||
var newValue = parseInt($input.val(), 10) - dataValue;
|
||||
$input.val(newValue);
|
||||
});
|
||||
|
||||
var hpIndex = findById( characterId );
|
||||
hpIndex.hp = parseInt(hpIndex.hp) - dataValue;
|
||||
});
|
||||
|
||||
$(document).on('click', '.hp-plus', function() {
|
||||
var characterId = $(this).closest('tr').data('character-id');
|
||||
var dataValue = parseInt($(this).data('value'), 10);
|
||||
var allTrsWithCharacterId = document.querySelectorAll(`tr[data-character-id="${characterId}"]`);
|
||||
|
||||
allTrsWithCharacterId.forEach(function(tr) {
|
||||
var $input = $(tr).find('input[name="hp"]');
|
||||
var newValue = parseInt($input.val(), 10) + dataValue;
|
||||
$input.val(newValue);
|
||||
});
|
||||
|
||||
var hpIndex = findById( characterId );
|
||||
hpIndex.hp = parseInt(hpIndex.hp) + dataValue;
|
||||
});
|
||||
});
|
||||
|
||||
let currentCharacter;
|
||||
let roundCount = 0;
|
||||
let roundHistory = [];
|
||||
let characterInitiativeList = [];
|
||||
|
||||
function findById(id) {
|
||||
return characterInitiativeList.find(item => item.id === id);
|
||||
}
|
||||
function findByIdAndRemove(id, array) {
|
||||
const index = array.findIndex(item => item.id === id);
|
||||
if (index !== -1) {
|
||||
array.splice(index, 1);
|
||||
}
|
||||
}
|
||||
|
||||
const resetCharBtn = document.getElementById('character-reset');
|
||||
const resetCharacter = async function (event) {
|
||||
formReset();
|
||||
}
|
||||
|
||||
const resetListBtn = document.getElementById('list-reset');
|
||||
const resetListEvent = async function (event) {
|
||||
resetList();
|
||||
}
|
||||
|
||||
const nextCharBtn = document.getElementById('list-next');
|
||||
const nextCharacter = async function (event) {
|
||||
cycleCharacter();
|
||||
}
|
||||
function cycleCharacter() {
|
||||
if ( !currentCharacter ) {
|
||||
currentCharacter = 0;
|
||||
}
|
||||
if ( currentCharacter == characterInitiativeList.length ) {
|
||||
currentCharacter = 0;
|
||||
roundCount++;
|
||||
addRoundHistory();
|
||||
updateRoundCount();
|
||||
}
|
||||
if ( !characterInitiativeList[currentCharacter] ) {
|
||||
currentCharacter = 0;
|
||||
}
|
||||
|
||||
var allTrs = document.querySelectorAll(`tr`);
|
||||
allTrs.forEach(function(tr) {
|
||||
tr.classList.remove("success");
|
||||
});
|
||||
|
||||
var allTrsWithCharacterId = document.querySelectorAll(`tr[data-character-id="${characterInitiativeList[currentCharacter].id}"]`);
|
||||
|
||||
allTrsWithCharacterId.forEach(function(tr) {
|
||||
tr.classList.add("success");
|
||||
});
|
||||
currentCharacter++;
|
||||
}
|
||||
|
||||
const clearListBtn = document.getElementById('list-clear');
|
||||
const clearListEvent = async function (event) {
|
||||
clearList();
|
||||
hideList();
|
||||
}
|
||||
|
||||
const sortCharBtn = document.getElementById('character-sort');
|
||||
const sortCharacters = async function (event) {
|
||||
event.preventDefault();
|
||||
sortthem();
|
||||
}
|
||||
function sortthem() {
|
||||
var fieldName = document.getElementById('sortBy').value;
|
||||
|
||||
clearListHTML();
|
||||
resetList();
|
||||
|
||||
var newList = sortCharacterListByField( fieldName, characterInitiativeList );
|
||||
|
||||
for (let i = 0; i < newList.length; i++) {
|
||||
addCharacterRow( newList[i] );
|
||||
}
|
||||
}
|
||||
function sortCharacterListByField( fieldName, list ) {
|
||||
if ( 'id' == fieldName ) {
|
||||
return list;
|
||||
}
|
||||
|
||||
let sortedList = [...list];
|
||||
sortedList.sort( ( a, b ) => {
|
||||
let fieldA = a[fieldName];
|
||||
let fieldB = b[fieldName];
|
||||
if ( 'type' == fieldName || 'name' == fieldName ) {
|
||||
return fieldA.localeCompare(fieldB);
|
||||
}
|
||||
if (fieldA > fieldB) {
|
||||
return -1;
|
||||
}
|
||||
if (fieldA < fieldB) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
return sortedList;
|
||||
}
|
||||
|
||||
const addCharBtn = document.getElementById('character-add');
|
||||
const addCharacter = function (event) {
|
||||
createCharacterFromForm();
|
||||
}
|
||||
function createCharacterFromForm() {
|
||||
showList();
|
||||
var id = Date.now().toString(36) + Math.random().toString(36).substring(2);;
|
||||
var name = document.getElementById('name').value;
|
||||
if ( !name ) {
|
||||
name = '4816';
|
||||
}
|
||||
var initiative = document.getElementById('initiative').value;
|
||||
if ( !initiative ) {
|
||||
initiative = getRandomInt( 1, 21 );
|
||||
}
|
||||
initiative = parseInt( initiative );
|
||||
var ac = document.getElementById('ac').value;
|
||||
if ( !ac ) {
|
||||
ac = 0;
|
||||
}
|
||||
ac = parseInt( ac );
|
||||
var hp = document.getElementById('hp').value;
|
||||
if ( !hp ) {
|
||||
hp = 0;
|
||||
}
|
||||
hp = parseInt( hp );
|
||||
var characterType = document.querySelector('input[name="characterType"]:checked').value;
|
||||
var character = {
|
||||
id: id,
|
||||
name: name,
|
||||
initiative: initiative,
|
||||
ac: ac,
|
||||
hp: hp,
|
||||
type: characterType,
|
||||
};
|
||||
characterInitiativeList.push( character );
|
||||
|
||||
// re-order the list by initiative to keep the next character working properly
|
||||
characterInitiativeList = sortCharacterListByField( 'initiative', characterInitiativeList );
|
||||
|
||||
addCharacterRow( character );
|
||||
addRoundRow( character );
|
||||
}
|
||||
|
||||
const d20Btn = document.getElementById('d20-roll');
|
||||
const rollD20 = async function (event) {
|
||||
event.preventDefault();
|
||||
var resultDiv = document.getElementById('initiative');
|
||||
resultDiv.value = getRandomInt( 1, 21 );
|
||||
}
|
||||
|
||||
const resetRoundsBtn = document.getElementById('rounds-reset');
|
||||
const resetRoundsEvent = async function (event) {
|
||||
resetRoundCount();
|
||||
}
|
||||
|
||||
const clearRoundsBtn = document.getElementById('rounds-clear');
|
||||
const clearRoundsEvent = async function (event) {
|
||||
clearRounds();
|
||||
}
|
||||
|
||||
window.addEventListener('DOMContentLoaded', (event) => {
|
||||
d20Btn.addEventListener('click', rollD20);
|
||||
addCharBtn.addEventListener('click', addCharacter);
|
||||
resetCharBtn.addEventListener('click', resetCharacter);
|
||||
resetListBtn.addEventListener('click', resetListEvent);
|
||||
clearListBtn.addEventListener('click', clearListEvent);
|
||||
nextCharBtn.addEventListener('click', nextCharacter);
|
||||
resetRoundsBtn.addEventListener('click', resetRoundsEvent);
|
||||
clearRoundsBtn.addEventListener('click', clearRoundsEvent);
|
||||
sortCharBtn.addEventListener('click', sortCharacters);
|
||||
updateRoundCount();
|
||||
});
|
||||
|
||||
function formReset() {
|
||||
document.getElementById('name').value = null;
|
||||
document.getElementById('initiative').value = null;
|
||||
document.getElementById('ac').value = null;
|
||||
document.getElementById('hp').value = null;
|
||||
}
|
||||
|
||||
function showList() {
|
||||
var tbody = document.getElementById('character-container');
|
||||
tbody.style.display = '';
|
||||
}
|
||||
|
||||
function addCharacterRow( character ) {
|
||||
var characterList = document.getElementById('character-list');
|
||||
var pcList = document.getElementById('character-list-pc');
|
||||
var npcList = document.getElementById('character-list-npc');
|
||||
var row = document.createElement('tr');
|
||||
row.setAttribute('data-character-id', character.id);
|
||||
|
||||
var hpStyle = '';
|
||||
var acStyle = '';
|
||||
|
||||
var checkbox = document.getElementById('trackHP');
|
||||
if ( !checkbox.checked ) {
|
||||
var hpStyle = 'style="display: none;"';
|
||||
}
|
||||
|
||||
var checkbox = document.getElementById('trackAC');
|
||||
if ( !checkbox.checked ) {
|
||||
var acStyle = 'style="display: none;"';
|
||||
}
|
||||
|
||||
row.innerHTML = `
|
||||
<td>${character.name}</td>
|
||||
<td class="text-center">${character.initiative}</td>
|
||||
<td class="ac-tracker text-center"${acStyle}>${character.ac}</td>
|
||||
<td class="hp-tracker text-center"${hpStyle}>
|
||||
<div class="form-group hp-tracker list-controls-center">
|
||||
<div class="input-group col-lg-6">
|
||||
<div class="input-group-btn">
|
||||
<button class="hp-minus btn btn-danger" data-value="1" aria-label="Remove 1 hp">-1</button>
|
||||
<button class="hp-minus btn btn-danger" data-value="5" aria-label="Remove 5 hp">-5</button>
|
||||
<button class="hp-minus btn btn-danger" data-value="10" aria-label="Remove 10 hp">-10</button>
|
||||
</div>
|
||||
<input type="number" class="form-control" name="hp" value="${character.hp}">
|
||||
<div class="input-group-btn">
|
||||
<button class="hp-plus btn btn-success" data-value="10" aria-label="Add 10 hp">+10</button>
|
||||
<button class="hp-plus btn btn-success" data-value="5" aria-label="Add 5 hp">+5</button>
|
||||
<button class="hp-plus btn btn-success" data-value="1" aria-label="Add 1 hp">+1</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td class="text-center">${character.type}</td>
|
||||
<td class="text-right"><button class="btn btn-danger btn-sm character-remove" aria-label="Add 10 hp"><span class="glyphicon glyphicon-trash"></span></button></td>
|
||||
`;
|
||||
|
||||
// Append the new row to the table body
|
||||
characterList.appendChild(row);
|
||||
|
||||
if ( 'pc' == character.type ) {
|
||||
var pc_row = row.cloneNode(true);
|
||||
pcList.appendChild(pc_row);
|
||||
}
|
||||
|
||||
if ( 'npc' == character.type ) {
|
||||
var npc_row = row.cloneNode(true);
|
||||
npcList.appendChild(npc_row);
|
||||
}
|
||||
}
|
||||
|
||||
function hideList() {
|
||||
var tbody = document.getElementById('character-container');
|
||||
tbody.style.display = 'none';
|
||||
}
|
||||
|
||||
function clearList() {
|
||||
characterInitiativeList = [];
|
||||
clearListHTML();
|
||||
}
|
||||
|
||||
function clearListHTML() {
|
||||
var tbody = document.getElementById('character-list');
|
||||
tbody.innerHTML = '';
|
||||
var tbody = document.getElementById('character-list-pc');
|
||||
tbody.innerHTML = '';
|
||||
var tbody = document.getElementById('character-list-npc');
|
||||
tbody.innerHTML = '';
|
||||
}
|
||||
|
||||
function resetList() {
|
||||
currentCharacter = 0;
|
||||
var allTrsWithCharacterId = document.querySelectorAll(`tr`);
|
||||
allTrsWithCharacterId.forEach(function(tr) {
|
||||
tr.classList.remove("success");
|
||||
});
|
||||
}
|
||||
|
||||
function clearRounds() {
|
||||
var headers = document.getElementById('rounds-history-header-row');
|
||||
var thElements = headers.getElementsByTagName('th');
|
||||
|
||||
// Loop through the th elements in reverse order to safely remove them without affecting the iteration
|
||||
for (var i = thElements.length - 1; i > 0; i--) {
|
||||
thElements[i].parentNode.removeChild(thElements[i]);
|
||||
}
|
||||
|
||||
var history = document.getElementById('rounds-history');
|
||||
var trElements = history.getElementsByTagName('tr');
|
||||
|
||||
for (var i = 0; i < trElements.length; i++) {
|
||||
|
||||
var elements = trElements[i].getElementsByTagName('td');
|
||||
for (var x = elements.length - 1; x > 0; x--) {
|
||||
elements[x].parentNode.removeChild(elements[x]);
|
||||
}
|
||||
|
||||
}
|
||||
roundCount = 0;
|
||||
updateRoundCount();
|
||||
}
|
||||
|
||||
function clearCharacters() {
|
||||
var history = document.getElementById('rounds-history');
|
||||
var trElements = history.getElementsByTagName('tr');
|
||||
|
||||
for (var i = 0; i < trElements.length; i++) {
|
||||
trElements[i].remove();
|
||||
}
|
||||
}
|
||||
|
||||
function resetRoundCount() {
|
||||
roundCount = 0;
|
||||
updateRoundCount();
|
||||
}
|
||||
|
||||
function updateRoundCount() {
|
||||
var round = document.getElementById('round-count');
|
||||
round.innerText = roundCount;
|
||||
}
|
||||
|
||||
function addRoundRow( character ) {
|
||||
var characterList = document.getElementById('rounds-history');
|
||||
var row = document.createElement('tr');
|
||||
|
||||
row.setAttribute('data-round-character-id', character.id);
|
||||
row.innerHTML = `<td class="char-name">${character.name}</td>`;
|
||||
characterList.appendChild(row);
|
||||
}
|
||||
|
||||
function addRoundHistory() {
|
||||
var headers = document.getElementById('rounds-history-header');
|
||||
var newHeader = document.createElement('th');
|
||||
newHeader.innerText = "Round " + roundCount;
|
||||
newHeader.classList.add("text-center");
|
||||
headers.after( newHeader );
|
||||
|
||||
for (let i = 0; i < characterInitiativeList.length; i++) {
|
||||
var char = characterInitiativeList[i];
|
||||
var newCol = document.createElement('td');
|
||||
newCol.innerText = char.hp;
|
||||
newCol.classList.add("text-center");
|
||||
|
||||
var allTrsWithCharacterId = document.querySelector(`tr[data-round-character-id="${char.id}"]`);
|
||||
var indexd = allTrsWithCharacterId.getElementsByClassName('char-name');
|
||||
indexd[0].after( newCol );
|
||||
}
|
||||
}
|
@ -1,105 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* app/plugins/feedback/models/feedback.php
|
||||
*
|
||||
* This class is used for the manipulation of the feedback database table.
|
||||
*
|
||||
* @todo make this send a confirmation email
|
||||
*
|
||||
* @package TP Feedback
|
||||
* @version 3.0
|
||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||
* @link https://TheTempusProject.com
|
||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||
*/
|
||||
namespace TheTempusProject\Models;
|
||||
|
||||
use TheTempusProject\Bedrock\Classes\Config;
|
||||
use TheTempusProject\Bedrock\Functions\Check;
|
||||
use TheTempusProject\Canary\Bin\Canary as Debug;
|
||||
use TheTempusProject\Classes\DatabaseModel;
|
||||
use TheTempusProject\Plugins\Feedback as Plugin;
|
||||
use TheTempusProject\TheTempusProject as App;
|
||||
|
||||
class Inithistory extends DatabaseModel {
|
||||
public $tableName = 'initiative_history';
|
||||
public $databaseMatrix = [
|
||||
[ 'name', 'varchar', '128' ],
|
||||
[ 'time', 'int', '10' ],
|
||||
[ 'email', 'varchar', '128' ],
|
||||
[ 'ip', 'varchar', '64' ],
|
||||
[ 'feedback', 'text', '' ],
|
||||
];
|
||||
public $plugin;
|
||||
|
||||
/**
|
||||
* The model constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
$this->plugin = new Plugin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves a feedback form to the db.
|
||||
*
|
||||
* @param string $name -the name on the form
|
||||
* @param string $email -the email provided
|
||||
* @param string $feedback -contents of the feedback form.
|
||||
* @return bool
|
||||
*/
|
||||
public function create( $name, $email, $feedback ) {
|
||||
if ( !$this->plugin->checkEnabled() ) {
|
||||
Debug::info( 'Feedback is disabled in the config.' );
|
||||
return false;
|
||||
}
|
||||
$fields = [
|
||||
'name' => $name,
|
||||
'email' => $email,
|
||||
'feedback' => $feedback,
|
||||
'time' => time(),
|
||||
'ip' => $_SERVER['REMOTE_ADDR'],
|
||||
];
|
||||
if ( !self::$db->insert( $this->tableName, $fields ) ) {
|
||||
Debug::info( 'Feedback::create - failed to insert to db' );
|
||||
return false;
|
||||
}
|
||||
return self::$db->lastId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to clear feedback from the DB.
|
||||
*
|
||||
* @todo is there a way i could check for success here I'm pretty sure this is just a bad idea?
|
||||
* @return bool
|
||||
*/
|
||||
public function clear() {
|
||||
if ( empty( self::$log ) ) {
|
||||
self::$log = new Log;
|
||||
}
|
||||
self::$db->delete( $this->tableName, ['ID', '>=', '0'] );
|
||||
self::$log->admin( 'Cleared Feedback' );
|
||||
Debug::info( 'Feedback Cleared' );
|
||||
return true;
|
||||
}
|
||||
|
||||
public function userHistory( $limit = 0 ) {
|
||||
$whereClause = [
|
||||
'userID', '=', App::$activeUser->ID,
|
||||
'AND',
|
||||
'deletedAt', '=', '0',
|
||||
'AND',
|
||||
'expiresAt', '<', time(),
|
||||
];
|
||||
if ( empty( $limit ) ) {
|
||||
$notifications = self::$db->get( $this->tableName, $whereClause );
|
||||
} else {
|
||||
$notifications = self::$db->get( $this->tableName, $whereClause, 'ID', 'DESC', [0, $limit] );
|
||||
}
|
||||
if ( !$notifications->count() ) {
|
||||
Debug::info( 'No Notifications found.' );
|
||||
return false;
|
||||
}
|
||||
return $this->filter( $notifications->results() );
|
||||
}
|
||||
}
|
@ -1,49 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* app/plugins/initiativetracker/plugin.php
|
||||
*
|
||||
* This houses all of the main plugin info and functionality.
|
||||
*
|
||||
* @package TP InitiativeTracker
|
||||
* @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 TheTempusProject\Classes\Plugin;
|
||||
|
||||
class Initiativetracker extends Plugin {
|
||||
public $pluginName = 'TP InitiativeTracker';
|
||||
public $pluginAuthor = 'JoeyK';
|
||||
public $pluginWebsite = 'https://TheTempusProject.com';
|
||||
public $modelVersion = '1.0';
|
||||
public $pluginVersion = '3.0';
|
||||
public $pluginDescription = 'A simple plugin which adds a simple initiative tracker.';
|
||||
public $configName = 'initiativeTracker';
|
||||
public $configMatrix = [
|
||||
'enabled' => [
|
||||
'type' => 'radio',
|
||||
'pretty' => 'Enable tracker usage.',
|
||||
'default' => true,
|
||||
],
|
||||
];
|
||||
public $permissionMatrix = [
|
||||
'useInitiativeTracker' => [
|
||||
'pretty' => 'Can use the tracker',
|
||||
'default' => true,
|
||||
],
|
||||
];
|
||||
public $main_links = [
|
||||
[
|
||||
'text' => 'Initiative',
|
||||
'url' => '{ROOT_URL}initiative/index',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
// need to add a way to save the initiative history ( both personal, and for the table )
|
||||
// need a way to save characters for the autofill
|
||||
// need to add a "clear" button for initiative roller
|
||||
// if you have tables, and are a DM, your group can access the initiative history
|
@ -1,210 +0,0 @@
|
||||
<link rel="stylesheet" href="{ROOT_URL}app/plugins/initiativetracker/css/initiative.css" crossorigin="anonymous">
|
||||
<script src="{ROOT_URL}app/plugins/initiativetracker/js/initiative.js" type="module" defer></script>
|
||||
|
||||
<div id="initiative-container" class="initiative-container">
|
||||
|
||||
<div class="row">
|
||||
<h2>Initiative Tracker</h2>
|
||||
</div>
|
||||
|
||||
<!-- Tracker Settings -->
|
||||
<div class="row well well-sm">
|
||||
<div class="checkbox">
|
||||
<label><input type="checkbox" name="trackHP" id="trackHP"> Track HP</label>
|
||||
</div>
|
||||
<div class="checkbox">
|
||||
<label><input type="checkbox" name="trackAC" id="trackAC"> Track AC</label>
|
||||
</div>
|
||||
<div class="checkbox">
|
||||
<label><input type="checkbox" name="trackRounds" id="trackRounds"> Track Rounds</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Character Form -->
|
||||
<div id="character-form" class="character-form row well well-sm">
|
||||
<div class="form-group col-lg-3">
|
||||
<label for="name">Name</label>
|
||||
<input type="text" class="form-control" name="name" id="name" autocomplete="on">
|
||||
</div>
|
||||
<div class="form-group col-lg-2">
|
||||
<label for="initiative">Initiative</label>
|
||||
<div class="input-group">
|
||||
<div class="input-group-btn">
|
||||
<button id="d20-roll" class="btn btn-default" aria-label="Roll a d20 for initiative.">Roll</button>
|
||||
</div>
|
||||
<input type="number" class="form-control" name="initiative" id="initiative">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group col-lg-1 ac-tracker" style="display: none;">
|
||||
<label for="ac">AC</label>
|
||||
<input type="number" class="form-control" name="ac" id="ac">
|
||||
</div>
|
||||
<div class="form-group col-lg-1 hp-tracker" style="display: none;">
|
||||
<label for="hp">HP</label>
|
||||
<input type="number" class="form-control" name="hp" id="hp">
|
||||
</div>
|
||||
<div class="form-group col-lg-2">
|
||||
<label for="pc">Type</label><br>
|
||||
<label class="radio-inline">
|
||||
<input type="radio" name="characterType" id="pc" value="pc" checked> PC
|
||||
</label>
|
||||
<label class="radio-inline">
|
||||
<input type="radio" name="characterType" id="npc" value="npc"> NPC
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-group col-lg-3">
|
||||
<button id="character-add" class="btn btn-primary">
|
||||
Add
|
||||
</button>
|
||||
<button id="character-reset" class="btn btn-danger">
|
||||
Reset
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Initiative List -->
|
||||
<div id="character-container" style="display: none;">
|
||||
|
||||
<div id="initiative-list" class="well well-sm">
|
||||
<!-- Tab Header -->
|
||||
<ul class="nav nav-tabs" role="tablist">
|
||||
<li class="active">
|
||||
<a data-target="#cmb-list" role="tab" data-toggle="tab">
|
||||
Combined
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a data-target="#pc-list" role="tab" data-toggle="tab">
|
||||
PC
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a data-target="#npc-list" role="tab" data-toggle="tab">
|
||||
NPC
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<!-- Tab panes -->
|
||||
<div class="tab-content">
|
||||
<!-- Combined List -->
|
||||
<div role="tabpanel" class="tab-pane active" id="cmb-list">
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th class="text-center">Initiative</th>
|
||||
<th class="ac-tracker text-center" style="display: none;">AC</th>
|
||||
<th class="hp-tracker text-center" style="display: none;">HP</th>
|
||||
<th class="text-center">Type</th>
|
||||
<th class="text-right"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="character-list">
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<!-- PC List -->
|
||||
<div role="tabpanel" class="tab-pane" id="pc-list">
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th class="text-center">Initiative</th>
|
||||
<th class="ac-tracker text-center" style="display: none;">AC</th>
|
||||
<th class="hp-tracker text-center" style="display: none;">HP</th>
|
||||
<th class="text-center">Type</th>
|
||||
<th class="text-right"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="character-list-pc">
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<!-- NPC List -->
|
||||
<div role="tabpanel" class="tab-pane" id="npc-list">
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th class="text-center">Initiative</th>
|
||||
<th class="ac-tracker text-center" style="display: none;">AC</th>
|
||||
<th class="hp-tracker text-center" style="display: none;">HP</th>
|
||||
<th class="text-center">Type</th>
|
||||
<th class="text-right"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="character-list-npc">
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- List Controls -->
|
||||
<div class="row list-controls row">
|
||||
<div class="form-group col-lg-3">
|
||||
<button id="list-reset" class="d4-die die-btn btn btn-warning">
|
||||
Reset Round
|
||||
</button>
|
||||
</div>
|
||||
<div class="form-group col-lg-3">
|
||||
<div class="input-group">
|
||||
<div class="input-group-btn">
|
||||
<button id="character-sort" class="btn btn-primary" aria-label="Sort the List.">Sort</button>
|
||||
</div>
|
||||
<select class="form-control" id="sortBy">
|
||||
<option value="initiative">Initiative</option>
|
||||
<option value="name">Name</option>
|
||||
<option value="ac">AC</option>
|
||||
<option value="hp">HP</option>
|
||||
<option value="type">Type</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group col-lg-3">
|
||||
<button id="list-next" class="btn btn-success">
|
||||
Next Character
|
||||
</button>
|
||||
</div>
|
||||
<div class="form-group col-lg-3 list-controls-last">
|
||||
<button id="list-clear" class="btn btn-danger">
|
||||
Clear List
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Round Controls -->
|
||||
<div class="row rounds-tracker" style="display: none;">
|
||||
<div class="panel panel-info">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">Round History</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr id="rounds-history-header-row">
|
||||
<th id="rounds-history-header">Character</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="rounds-history">
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="form-group col-lg-2">
|
||||
<button id="rounds-clear" class="d4-die die-btn btn btn-danger">
|
||||
Clear History
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel-footer round-footer">
|
||||
<b>Round Count</b>: <span id="round-count"></span>
|
||||
<span class="pull-right round-reset">
|
||||
<button id="rounds-reset" class="btn btn-warning">
|
||||
Reset Round Count
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user