' . _("No bookmarks to display") . '
'; } return $html; } } trean-1.1.4/lib/Block/Mostclicked.php 0000664 0001750 0001750 00000004070 12654212671 015513 0 ustar jan jan */ class Trean_Block_Mostclicked extends Horde_Core_Block { /** */ public function __construct($app, $params = array()) { parent::__construct($app, $params); $this->_name = _("Most-clicked Bookmarks"); } /** */ protected function _params() { return array( 'rows' => array( 'name' => _("Number of bookmarks to show"), 'type' => 'enum', 'default' => '10', 'values' => array( '10' => _("10 rows"), '15' => _("15 rows"), '25' => _("25 rows") ) ), 'template' => array( 'name' => _("Template"), 'type' => 'enum', 'default' => '1line', 'values' => array( 'standard' => _("3 Line"), '2line' => _("2 Line"), '1line' => _("1 Line") ) ) ); } /** */ protected function _title() { return Horde::url($GLOBALS['registry']->getInitialPage(), true)->link() . $this->getName() . ''; } /** */ protected function _content() { $template = TREAN_TEMPLATES . '/block/' . $this->_params['template'] . '.inc'; $html = ''; $bookmarks = $GLOBALS['trean_gateway']->listBookmarks('clicks', 1, 0, $this->_params['rows']); foreach ($bookmarks as $bookmark) { ob_start(); require $template; $html .= '' . _("No bookmarks to display") . '
'; } return $html; } } trean-1.1.4/lib/Data/Json.php 0000664 0001750 0001750 00000011026 12654212671 014001 0 ustar jan jan * @package Trean */ class Trean_Data_Json extends Horde_Data_Base { protected $_extension = 'json'; protected $_contentType = 'text/json'; protected $_tagMap = array(); protected $_parentMap = array(); public function importData($contents, $header = false) { $data = array(); $json = Horde_Serialize::unserialize($contents, Horde_Serialize::JSON); return $this->_parseJson($json->children, null); } protected function _parseFolders($data) { // Need a first pass to grab all the folders foreach ($data as $child) { if ($child->type == 'text/x-moz-place-container') { if (empty($child->root)) { $this->_tagMap[$child->id] = $child->title; $this->_parentMap[$child->id] = $child->parent; } if (!empty($child->children)) { $this->_parseFolders($child->children); } } } } protected function _parseJson($data, $container) { // Need a first pass to grab all the folders $this->_parseFolders($data); return $this->_parseBookmarks($data); } protected function _parseBookmarks($data, $container = null) { $rows = array(); foreach ($data as $child) { if ($child->type == 'text/x-moz-place-container') { $rows = array_merge($this->_parseBookmarks($child->children, $child), $rows); } if ($child->type == 'text/x-moz-place') { $desc = ''; if (!empty($child->annos)) { foreach ($child->annos as $property) { switch ($property->name) { case 'Places/SmartBookmark': // Ignore "SmartBookmarks" continue 3; case 'bookmarkProperties/description': $desc = $property->value; break 2; } } } $tags = !empty($child->tags) ? explode(',', $child->tags) : array(); $current_parent = $container->parent; while (!empty($current_parent)) { if (!empty($this->_tagMap[$current_parent])) { $tags[] = $this->_tagMap[$current_parent]; } $current_parent = !empty($this->_parentMap[$current_parent]) ? $this->_parentMap[$current_parent] : false; } if (!empty($container) && empty($container->root)) { $tags[] = $container->title; } $rows[] = array( 'bookmark_url' => $child->uri, 'bookmark_title' => $child->title, 'bookmark_description' => $desc, 'bookmark_tags' => $tags, 'bookmark_dt' => !empty($child->dateAdded) ? new Horde_Date(substr($child->dateAdded, 0, 10)) : false ); } } return $rows; } /** * Takes all necessary actions for the given import step, parameters and * form values and returns the next necessary step. * * @param integer $action The current step. One of the IMPORT_* constants. * @param array $param An associative array containing needed * parameters for the current step. * * @return mixed Either the next step as an integer constant or imported * data set after the final step. * @throws Horde_Data_Exception */ public function nextStep($action, $param = array()) { switch ($action) { case Horde_Data::IMPORT_FILE: parent::nextStep($action, $param); return $this->importFile($_FILES['import_file']['tmp_name']); } } /** * Stub to return exported data. */ public function exportData($data, $method = 'REQUEST') { // TODO } /** * Stub to export data to a file. */ public function exportFile($filename, $data) { // TODO } } trean-1.1.4/lib/Factory/TagBrowser.php 0000664 0001750 0001750 00000001773 12654212671 015715 0 ustar jan jan * @package Kronolith */ class Trean_Factory_TagBrowser { /* * The injector. * * @var Horde_Injector */ protected $_injector; /** * The tag browser * * @var Trean_TagBrowser */ protected $_browser; /** * Constructor. * * @param Horde_Injector $injector The injector to use. */ public function __construct(Horde_Injector $injector) { $this->_injector = $injector; } /** * Return a Trean_TagBrowser * * @return Trean_TagBrowser */ public function create() { if (empty($_browser)) { $this->_browser = new Trean_TagBrowser($this->_injector->getInstance('Trean_Tagger')); } return $this->_browser; } } trean-1.1.4/lib/Queue/Task/Crawl.php 0000664 0001750 0001750 00000007131 12654212671 015257 0 ustar jan jan _url = $url; $this->_userTitle = $userTitle; $this->_userDesc = $userDesc; $this->_bookmarkId = $bookmarkId; $this->_userId = $userId; } /** */ public function run() { $injector = $GLOBALS['injector']; // Get Horde_Http_Client $client = $injector->getInstance('Horde_Http_Client'); // Fetch full text of $url try { $page = $client->get($this->_url); $body = $page->getBody(); } catch (Horde_Http_Exception $e) { Horde::log($e, 'ERR'); return; } $gateway = $injector->getInstance('Trean_Bookmarks'); $bookmark = $gateway->getBookmark($this->_bookmarkId); $changed = false; // update URL if we were redirected if ($page->uri && ($page->uri != $this->_url)) { $bookmark->url = $page->uri; $this->_url = $page->uri; $changed = true; } // update bookmark_http_status if ($bookmark->http_status != $page->code) { $bookmark->http_status = $page->code; $changed = true; } // submit text to ElasticSearch, under $userId's index if ($body && $page->code == 200) { try { $indexer = $injector->getInstance('Content_Indexer'); $indexer->index('horde-user-' . $this->_userId, 'trean-bookmark', $this->_bookmarkId, json_encode(array( 'title' => $this->_userTitle, 'description' => $this->_userDesc, 'url' => $this->_url, 'headers' => $page->headers, 'body' => $body, ))); } catch (Exception $e) { Horde::log($e, 'INFO'); } } if ($changed) { $bookmark->save(false); } // @TODO: crawl resources from the page to make a fully local version // (http://bugs.horde.org/ticket/10753) // Favicon if ($body) { if ($type = $page->getHeader('Content-Type') && preg_match('/.*;\s*charset="?([^" ]*)/', $type, $match)) { $charset = $match[1]; } else { $charset = null; } try { $queue = $injector->getInstance('Horde_Queue_Storage'); $queue->add(new Trean_Queue_Task_Favicon( $this->_url, $this->_bookmarkId, $this->_userId, $body, $charset )); } catch (Exception $e) { Horde::log($e, 'INFO'); } } } } trean-1.1.4/lib/Queue/Task/Favicon.php 0000664 0001750 0001750 00000012561 12654212671 015577 0 ustar jan jan _url = $url; $this->_bookmarkId = $bookmarkId; $this->_userId = $userId; $this->_body = $body; $this->_charset = $charset; } /** */ public function run() { $injector = $GLOBALS['injector']; $client = $injector->getInstance('Horde_Http_Client'); if (!$this->_body) { // Fetch full text of $url try { $page = $client->get($this->_url); $this->_body = $page->getBody(); if ($type = $page->getHeader('Content-Type') && preg_match('/.*;\s*charset="?([^" ]*)/', $type, $match)) { $this->_charset = $match[1]; } } catch (Horde_Http_Exception $e) { } } $url = parse_url($this->_url); if ($favicon = $this->_findByRel($client, $url, $this->_body, $this->_charset)) { $this->_storeFavicon($favicon); } elseif ($favicon = $this->_findByRoot($client, $url)) { $this->_storeFavicon($favicon); } elseif ($favicon = $this->_findByPath($client, $url)) { $this->_storeFavicon($favicon); } } /** * @param Horde_Http_Response_Base $response HTTP response; body of this is the favicon */ protected function _storeFavicon(Horde_Http_Response_Base $response) { global $injector; $gateway = $injector->getInstance('Trean_Bookmarks'); $bookmark = $gateway->getBookmark($this->_bookmarkId); if ($bookmark) { $bookmark->favicon_url = $response->uri; $bookmark->save(false); } // Initialize VFS $vfs = $GLOBALS['injector'] ->getInstance('Horde_Core_Factory_Vfs') ->create(); $vfs->writeData('.horde/trean/favicons/', md5($bookmark->favicon_url), $response->getBody(), true); } protected function _findByRel($client, $url, $body, $charset) { try { $dom = new Horde_Domhtml($body, $charset); foreach ($dom as $node) { if ($node instanceof DOMElement && Horde_String::lower($node->tagName) == 'link' && ($rel = Horde_String::lower($node->getAttribute('rel'))) && ($rel == 'shortcut icon' || $rel == 'icon')) { $favicon = $node->getAttribute('href'); // Make sure $favicon is a full URL. $favicon_url = parse_url($favicon); if (empty($favicon_url['scheme'])) { if (substr($favicon, 0, 1) == '/') { $favicon = $url['scheme'] . '://' . $url['host'] . $favicon; } else { $path = pathinfo($url['path']); $favicon = $url['scheme'] . '://' . $url['host'] . $path['dirname'] . '/' . $favicon; } } try { $response = $client->get($favicon); if ($this->_isValidFavicon($response)) { return $response; } } catch (Horde_Http_Exception $e) { } } } } catch (Exception $e) { } } protected function _findByRoot($client, $url) { try { $response = $client->get($url['scheme'] . '://' . $url['host'] . '/favicon.ico'); if ($this->_isValidFavicon($response)) { return $response; } } catch (Horde_Http_Exception $e) { } } protected function _findByPath($client, $url) { if (isset($url['path'])) { $path = pathinfo($url['path']); if (strlen($path['dirname'])) { try { $response = $client->get($url['scheme'] . '://' . $url['host'] . $path['dirname'] . '/favicon.ico'); if ($this->_isValidFavicon($response)) { return $response; } } catch (Horde_Http_Exception $e) { } } } } protected function _isValidFavicon($response) { return ($response->code == 200) && (substr($response->getHeader('content-type'), 0, 5) == 'image') && (strlen($response->getBody()) > 0); } } trean-1.1.4/lib/View/BookmarkList.php 0000664 0001750 0001750 00000014327 12654212671 015541 0 ustar jan jan * @package Trean */ class Trean_View_BookmarkList { /** * Tag Browser * * @var Trean_TagBrowser */ protected $_browser; /** * The loaded bookmarks. * * @var array */ protected $_bookmarks; /** * Current page * * @var int */ protected $_page = 0; /** * Bookmarks to display per page * * @var int */ protected $_perPage = 999; /** * Flag to indicate we have an empty search. * * @var boolean */ protected $_noSearch = false; /** * Flag to indicate whether or not to show the tag browser * @var boolean */ protected $_showTagBrowser = true; /** * Const'r * */ public function __construct($bookmarks = null, $browser = null) { $this->_bookmarks = $bookmarks; if ($browser) { $this->_browser = $browser; } else { $this->_browser = $GLOBALS['injector']->getInstance('Trean_TagBrowser'); } $action = Horde_Util::getFormData('actionID', ''); switch ($action) { case 'remove': $tag = Horde_Util::getFormData('tag'); if (isset($tag)) { $this->_browser->removeTag($tag); $this->_browser->save(); } break; case 'add': default: // Add new tag to the stack, save to session. $tag = Horde_Util::getFormData('tag'); if (isset($tag)) { $this->_browser->addTag($tag); $this->_browser->save(); } } // Check for empty tag search.. then do what? $this->_noSearch = $this->_browser->tagCount() < 1; } /** * Toggle showing of the tag browser */ public function showTagBrowser($showTagBrowser) { $this->_showTagBrowser = $showTagBrowser; } /** * Returns whether bookmarks currently exist. * * @return boolean True if there exist any bookmarks in the backend. */ public function hasBookmarks() { $this->_getBookmarks(); return (bool)count($this->_bookmarks) || (bool)$this->_browser->tagCount(); } /** * Renders the view. */ public function render($title = null) { if (is_null($title)) { $title = _("Bookmarks"); } $this->_getBookmarks(); $browser = ''; if ($this->_showTagBrowser) { $browser = '
* 'title' - The title for this resource.
* 'desc' - A terse description of this resource.
* 'view_url' - The URL to view this resource.
* 'app' - The Horde application this resource belongs to.
*
*/
public function searchTags($names, $max = 10, $from = 0,
$resource_type = '', $user = null, $raw = false)
{
// TODO: $max, $from, $resource_type not honored
$results = $GLOBALS['injector']
->getInstance('Trean_Tagger')
->search(
$names,
array('type' => 'bookmark', 'user' => $user));
// Check for error or if we requested the raw data array.
if ($raw) {
return $results;
}
$return = array();
$redirectUrl = Horde::url('redirect.php');
foreach ($results as $bookmark_id) {
try {
$bookmark = $GLOBALS['trean_gateway']->getBookmark($bookmark_id);
$return[] = array(
'title' => $bookmark->title,
'desc' => empty($bookmark->description) ? $bookmark->title : $bookmark->description,
'view_url' => $redirectUrl->add('b', $bookmark->id),
'app' => 'trean',
'icon' => $bookmark->favicon_url
);
} catch (Exception $e) {
}
}
return $return;
}
/**
* Returns a URL that can be used in other applications to add the currently
* displayed page as a bookmark. If javascript and DOM is available, an overlay
* is used, if javascript and no DOM, then a pop-up is used and if no javascript
* is available a URL to Trean's add.php page is returned.
*
* @param array $params A hash of 'url' and 'title' properties of the requested
* bookmark.
* @return string The URL suitable for use in a tag.
*/
public function getAddUrl($params = array())
{
$GLOBALS['no_compress'] = true;
$browser = $GLOBALS['injector']->getInstance('Horde_Browser');
if ($browser->hasFeature('javascript')) {
if ($browser->hasFeature('dom')) {
$addurl = Horde::url('add.php', true, -1)->add('iframe', 1);
$url = "javascript:(function(){o=document.createElement('div');o.id='overlay';o.style.background='#000';o.style.position='absolute';o.style.top=0;o.style.left=0;o.style.width='100%';o.style.height='100%';o.style.zIndex=5000;o.style.opacity=.8;document.body.appendChild(o);i=document.createElement('iframe');i.id='frame';i.style.zIndex=5001;i.style.border='thin solid #000';i.src='$addurl'+'&title=' + encodeURIComponent(document.title) + '&url=' + encodeURIComponent(location.href);i.style.position='absolute';i.style.width='350px';i.style.height='150px';i.style.left='100px';i.style.top='100px';document.body.appendChild(i);l=document.createElement('a');l.style.position='absolute';l.style.background='#ccc';l.style.color='#000';l.style.border='thin solid #000';l.style.display='block';l.style.top='250px';l.style.left='100px';l.style.zIndex=5001;l.style.padding='5px';l.appendChild(document.createTextNode('" . _("Close") . "'));l.onclick=function(){var o=document.getElementById('overlay');o.parentNode.removeChild(o);var i=document.getElementById('frame');i.parentNode.removeChild(i);this.parentNode.removeChild(this);};document.body.appendChild(l);})()";
} else {
$addurl = Horde::url('add.php', true, -1)->add('popup', 1);
$url = "javascript:d = new Date(); w = window.open('$addurl' + '&title=' + encodeURIComponent(document.title) + '&url=' + encodeURIComponent(location.href) + '&d=' + d.getTime(), d.getTime(), 'height=200,width=400'); w.focus();";
}
} else {
// Fallback to a regular URL
$url = Horde::url('add.php', true)->add($params);
}
return $url;
}
}
trean-1.1.4/lib/Application.php 0000664 0001750 0001750 00000007546 12654212671 014476 0 ustar jan jan
*/
/* Determine the base directories. */
if (!defined('TREAN_BASE')) {
define('TREAN_BASE', realpath(__DIR__ . '/..'));
}
if (!defined('HORDE_BASE')) {
/* If Horde does not live directly under the app directory, the HORDE_BASE
* constant should be defined in config/horde.local.php. */
if (file_exists(TREAN_BASE . '/config/horde.local.php')) {
include TREAN_BASE . '/config/horde.local.php';
} else {
define('HORDE_BASE', realpath(TREAN_BASE . '/..'));
}
}
/* Load the Horde Framework core (needed to autoload
* Horde_Registry_Application::). */
require_once HORDE_BASE . '/lib/core.php';
class Trean_Application extends Horde_Registry_Application
{
/**
*/
public $version = 'H5 (1.1.4)';
/**
* Global variables defined:
* - $trean_db: Horde_Db object
* - $trean_gateway: Trean_Bookmarks object
*/
protected function _init()
{
/* For now, autoloading the Content_* classes depend on there being a
* registry entry for the 'content' application that contains at least
* the fileroot entry. */
$GLOBALS['injector']->getInstance('Horde_Autoloader')
->addClassPathMapper(new Horde_Autoloader_ClassPathMapper_Prefix(
'/^Content_/',
$GLOBALS['registry']->get('fileroot', 'content') . '/lib/'
));
if (!class_exists('Content_Tagger')) {
throw new Horde_Exception('The Content_Tagger class could not be found. Make sure the Content application is installed.');
}
$GLOBALS['injector']->bindFactory('Trean_TagBrowser', 'Trean_Factory_TagBrowser', 'create');
// Set the timezone variable.
$GLOBALS['registry']->setTimeZone();
// Create db and gateway instances.
$GLOBALS['trean_db'] = $GLOBALS['injector']
->getInstance('Horde_Core_Factory_Db')
->create('trean', 'storage');
$GLOBALS['trean_gateway'] = $GLOBALS['injector']
->getInstance('Trean_Bookmarks');
}
/**
*/
public function perms()
{
return array(
'max_bookmarks' => array(
'title' => _("Maximum Number of Bookmarks"),
'type' => 'int'
),
);
}
/**
*/
public function menu($menu)
{
$menu->add(Horde::url('browse.php'), _("_Browse"), 'trean-browse', null, null, null, basename($_SERVER['PHP_SELF']) == 'index.php' ? 'current' : null);
$menu->add(Horde::url('data.php'), _("_Import"), 'horde-data');
}
/**
* Add additional items to the sidebar.
*
* @param Horde_View_Sidebar $sidebar The sidebar object.
*/
public function sidebar($sidebar)
{
$sidebar->addNewButton(_("_New Bookmark"), Horde::url('add.php'));
$sidebar->containers['tags'] = array(
'header' => array(
'id' => 'trean-toggle-tags',
'label' => _("Tags"),
'collapsed' => false,
),
);
$tagger = $GLOBALS['injector']->getInstance('Trean_Tagger');
$tags = $tagger->listBookmarkTags();
natcasesort($tags);
foreach ($tags as $tag) {;
$url = Horde::url('tag/' . urlencode($tag));
$row = array(
'url' => $url,
'cssClass' => 'trean-tag',
'label' => $tag,
);
$sidebar->addRow($row, 'tags');
}
}
/**
*/
public function cleanupData()
{
$GLOBALS['import_step'] = 1;
return Horde_Data::IMPORT_FILE;
}
}
trean-1.1.4/lib/Bookmark.php 0000664 0001750 0001750 00000010660 12654212671 013767 0 ustar jan jan
* @package Trean
*/
class Trean_Bookmark
{
public $id = null;
public $userId = null;
public $url = null;
public $title = '';
public $description = '';
public $clicks = 0;
public $http_status = null;
public $favicon_url;
public $dt;
public $tags = array();
/**
*/
public function __construct($bookmark = array())
{
if ($bookmark) {
$this->userId = $bookmark['user_id'];
$this->url = $bookmark['bookmark_url'];
$this->title = $bookmark['bookmark_title'];
$this->description = $bookmark['bookmark_description'];
if (!empty($bookmark['bookmark_id'])) {
$this->id = (int)$bookmark['bookmark_id'];
}
if (!empty($bookmark['bookmark_clicks'])) {
$this->clicks = (int)$bookmark['bookmark_clicks'];
}
if (!empty($bookmark['bookmark_http_status'])) {
$this->http_status = $bookmark['bookmark_http_status'];
}
if (!empty($bookmark['favicon_url'])) {
$this->favicon_url = $bookmark['favicon_url'];
}
if (!empty($bookmark['bookmark_dt'])) {
$this->dt = $bookmark['bookmark_dt'];
}
if (!empty($bookmark['bookmark_tags'])) {
$this->tags = $bookmark['bookmark_tags'];
}
}
}
/**
* Save bookmark.
*/
public function save($crawl = true)
{
if (!strlen($this->url)) {
throw new Trean_Exception('Incomplete bookmark');
}
$charset = $GLOBALS['trean_db']->getOption('charset');
$c_url = Horde_String::convertCharset($this->url, 'UTF-8', $charset);
$c_title = Horde_String::convertCharset($this->title, 'UTF-8', $charset);
$c_description = Horde_String::convertCharset($this->description, 'UTF-8', $charset);
$c_favicon_url = Horde_String::convertCharset($this->favicon_url, 'UTF-8', $charset);
if ($this->id) {
// Update an existing bookmark.
$GLOBALS['trean_db']->update('
UPDATE trean_bookmarks
SET user_id = ?,
bookmark_url = ?,
bookmark_title = ?,
bookmark_description = ?,
bookmark_clicks = ?,
bookmark_http_status = ?,
favicon_url = ?
WHERE bookmark_id = ?',
array(
$this->userId,
$c_url,
$c_title,
$c_description,
$this->clicks,
$this->http_status,
$c_favicon_url,
$this->id,
));
$GLOBALS['injector']->getInstance('Trean_Tagger')->replaceTags((string)$this->id, $this->tags, $GLOBALS['registry']->getAuth(), 'bookmark');
} else {
// Saving a new bookmark.
$bookmark_id = $GLOBALS['trean_db']->insert('
INSERT INTO trean_bookmarks (
user_id,
bookmark_url,
bookmark_title,
bookmark_description,
bookmark_clicks,
bookmark_http_status,
favicon_url,
bookmark_dt
) VALUES (?, ?, ?, ?, ?, ?, ?, ?)',
array(
$this->userId,
$c_url,
$c_title,
$c_description,
$this->clicks,
$this->http_status,
$c_favicon_url,
$this->dt,
));
$this->id = (int)$bookmark_id;
$GLOBALS['injector']->getInstance('Trean_Tagger')->tag((string)$this->id, $this->tags, $GLOBALS['registry']->getAuth(), 'bookmark');
}
if ($crawl) {
try {
$queue = $GLOBALS['injector']->getInstance('Horde_Queue_Storage');
$queue->add(new Trean_Queue_Task_Crawl(
$this->url,
$this->title,
$this->description,
$this->id,
$this->userId
));
} catch (Exception $e) {
Horde::log($e, 'INFO');
}
}
return $this->id;
}
}
trean-1.1.4/lib/Bookmarks.php 0000664 0001750 0001750 00000020600 12654212671 014145 0 ustar jan jan
* @author Chuck Hagenbuch