diff --git a/app/plugins/bookmarks/controllers/bookmarks.php b/app/plugins/bookmarks/controllers/bookmarks.php
new file mode 100644
index 0000000..3641faa
--- /dev/null
+++ b/app/plugins/bookmarks/controllers/bookmarks.php
@@ -0,0 +1,402 @@
+
+ * @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 );
+ }
+}
diff --git a/app/plugins/bookmarks/forms.php b/app/plugins/bookmarks/forms.php
new file mode 100644
index 0000000..d0fd2b5
--- /dev/null
+++ b/app/plugins/bookmarks/forms.php
@@ -0,0 +1,122 @@
+
+ * @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;
\ No newline at end of file
diff --git a/app/plugins/bookmarks/models/bookmarks.php b/app/plugins/bookmarks/models/bookmarks.php
new file mode 100644
index 0000000..726e4a6
--- /dev/null
+++ b/app/plugins/bookmarks/models/bookmarks.php
@@ -0,0 +1,705 @@
+
+ * @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\Canary as Debug;
+use TheTempusProject\Classes\DatabaseModel;
+use TheTempusProject\TheTempusProject as App;
+use TheTempusProject\Houdini\Classes\Filters;
+use TheTempusProject\Canary\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 = '';
+ } else {
+ if (strpos($instance->icon, 'http') !== false) {
+ $instance->iconHtml = '';
+ } else {
+ $instance->iconHtml = '
';
+ }
+ }
+ if ( empty( $instance->hiddenAt ) ) {
+ $instance->hideBtn = '
+
+
+ ';
+ } else {
+ $instance->hideBtn = '
+
+
+ ';
+ }
+ if ( empty( $instance->archivedAt ) ) {
+ $instance->archiveBtn = '
+
+
+ ';
+ } else {
+ $instance->archiveBtn = '
+
+
+ ';
+ }
+ if ( ! empty( $instance->refreshedAt ) && time() < ( $instance->refreshedAt + ( 60 * 10 ) ) ) {
+ $instance->refreshBtn = '
+
+
+ ';
+ } else {
+ $instance->refreshBtn = '
+
+
+ ';
+ }
+
+ $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;
+ }
+}
diff --git a/app/plugins/bookmarks/models/bookmarkviews.php b/app/plugins/bookmarks/models/bookmarkviews.php
new file mode 100644
index 0000000..e25d50f
--- /dev/null
+++ b/app/plugins/bookmarks/models/bookmarkviews.php
@@ -0,0 +1,149 @@
+
+ * @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\Canary\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;
+ }
+}
diff --git a/app/plugins/bookmarks/models/folders.php b/app/plugins/bookmarks/models/folders.php
new file mode 100644
index 0000000..218f6c2
--- /dev/null
+++ b/app/plugins/bookmarks/models/folders.php
@@ -0,0 +1,157 @@
+
+ * @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\Canary as Debug;
+use TheTempusProject\Classes\DatabaseModel;
+use TheTempusProject\TheTempusProject as App;
+use TheTempusProject\Houdini\Classes\Filters;
+use TheTempusProject\Canary\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;
+ }
+}
diff --git a/app/plugins/bookmarks/plugin.php b/app/plugins/bookmarks/plugin.php
new file mode 100644
index 0000000..45b5b43
--- /dev/null
+++ b/app/plugins/bookmarks/plugin.php
@@ -0,0 +1,62 @@
+
+ * @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,
+ ],
+ 'createEvents' => [
+ 'pretty' => 'Can add events to bookmarks',
+ 'default' => false,
+ ],
+ ];
+ public $main_links = [
+ [
+ 'text' => 'Bookmarks',
+ 'url' => '{ROOT_URL}bookmarks/index',
+ 'filter' => 'loggedin',
+ ],
+ ];
+ public $configMatrix = [
+ 'enabled' => [
+ 'type' => 'radio',
+ 'pretty' => 'Enable Bookmarks.',
+ 'default' => true,
+ ],
+ ];
+ public $bookmarks;
+ public $folders;
+
+ public function __construct( $load = false ) {
+ $this->bookmarks = new Bookmark;
+ $this->folders = new Folders;
+ parent::__construct( $load );
+ }
+}
diff --git a/app/plugins/bookmarks/views/bookmarks/create.html b/app/plugins/bookmarks/views/bookmarks/create.html
new file mode 100644
index 0000000..2a42103
--- /dev/null
+++ b/app/plugins/bookmarks/views/bookmarks/create.html
@@ -0,0 +1,45 @@
+
+{BookmarkBreadCrumbs}
+
Bookmark | ++ | + | + | + | |
---|---|---|---|---|---|
+ + {title} + + | ++ {privacy} + | ++ | + | + | |
+ No results to show. + | +
Title | +{title} | +
URL | +{url} | +
Type | +{linkType} | +
Privacy | +{privacy} | +
Color | +{color} | +
Description | +|
{description} | +|
Icon | +|
{iconHtml} | +|
{icon} | +|
Meta | +|
{meta} | +|
Created | +{DTC}{createdAt}{/DTC} | +
Archived | +{DTC}{archivedAt}{/DTC} | +
Hidden | +{DTC}{hiddenAt}{/DTC} | +
Last Refreshed | +{DTC}{refreshedAt}{/DTC} | +
no folders
+Title | +Privacy | +Description | ++ | + | + | |
---|---|---|---|---|---|---|
{title} | +{privacy} | +{description} | ++ | + | + | |
+ No results to show. + | +
Title | +{title} | +
Privacy | +{privacy} | +
Color | +{color} | +
Description | +|
{description} | +|
Created | +{DTC}{createdAt}{/DTC} | +
This is the members section. You can give some groups permission to access these areas. the menu is hidden for normal users and if they get a link to a member's area, the authentication system will stop them from accessing any content protected this way.
+You can even use this feature in-line with your views, hiding certain components from non-members
+