diff options
Diffstat (limited to 'plugins')
-rw-r--r-- | plugins/LinkbackPlugin.php | 94 | ||||
-rw-r--r-- | plugins/PiwikAnalyticsPlugin.php | 104 | ||||
-rw-r--r-- | plugins/TemplatePlugin.php | 344 |
3 files changed, 537 insertions, 5 deletions
diff --git a/plugins/LinkbackPlugin.php b/plugins/LinkbackPlugin.php index 77adfa87d..56a26176b 100644 --- a/plugins/LinkbackPlugin.php +++ b/plugins/LinkbackPlugin.php @@ -94,18 +94,26 @@ class LinkbackPlugin extends Plugin return $orig; } + $pb = null; + $tb = null; + if (array_key_exists('X-Pingback', $result->headers)) { - $endpoint = $result->headers['X-Pingback']; + $pb = $result->headers['X-Pingback']; } else if (preg_match('/<link rel="pingback" href="([^"]+)" ?/?>/', $result->body, $match)) { - $endpoint = $match[1]; + $pb = $match[1]; + } + + if (!empty($pb)) { + $this->pingback($result->final_url, $pb); } else { - // XXX: do Trackback lookup - return $orig; + $tb = $this->getTrackback($result->body, $result->final_url); + if (!empty($tb)) { + $this->trackback($result->final_url, $tb); + } } - $this->pingback($url, $endpoint); return $orig; } @@ -132,6 +140,82 @@ class LinkbackPlugin extends Plugin } } + // Largely cadged from trackback_cls.php by + // Ran Aroussi <ran@blogish.org>, GPL2 + // http://phptrackback.sourceforge.net/ + + function getTrackback($text, $url) + { + if (preg_match_all('/(<rdf:RDF.*?<\/rdf:RDF>)/sm', $text, $match, PREG_SET_ORDER)) { + for ($i = 0; $i < count($match); $i++) { + if (preg_match('|dc:identifier="' . preg_quote($url) . '"|ms', $match[$i][1])) { + $rdf_array[] = trim($match[$i][1]); + } + } + + // Loop through the RDFs array and extract trackback URIs + + $tb_array = array(); // <- holds list of trackback URIs + + if (!empty($rdf_array)) { + + for ($i = 0; $i < count($rdf_array); $i++) { + if (preg_match('/trackback:ping="([^"]+)"/', $rdf_array[$i], $array)) { + $tb_array[] = trim($array[1]); + break; + } + } + } + + // Return Trackbacks + + if (empty($tb_array)) { + return null; + } else { + return $tb_array[0]; + } + } + + if (preg_match_all('/(<a[^>]*?rel=[\'"]trackback[\'"][^>]*?>)/', $text, $match)) { + foreach ($match[1] as $atag) { + if (preg_match('/href=[\'"]([^\'"]*?)[\'"]/', $atag, $url)) { + return $url[1]; + } + } + } + + return null; + + } + + function trackback($url, $endpoint) + { + $profile = $this->notice->getProfile(); + + $args = array('title' => sprintf(_('%1$s\'s status on %2$s'), + $profile->nickname, + common_exact_date($this->notice->created)), + 'excerpt' => $this->notice->content, + 'url' => $this->notice->uri, + 'blog_name' => $profile->nickname); + + $fetcher = Auth_Yadis_Yadis::getHTTPFetcher(); + + $result = $fetcher->post($endpoint, + http_build_query($args), + array('User-Agent: ' . $this->userAgent())); + + if ($result->status != '200') { + common_log(LOG_WARNING, + "Trackback error for '$url' ($endpoint): ". + "$result->body"); + } else { + common_log(LOG_INFO, + "Trackback success for '$url' ($endpoint): ". + "'$result->body'"); + } + } + function userAgent() { return 'LinkbackPlugin/'.LINKBACKPLUGIN_VERSION . diff --git a/plugins/PiwikAnalyticsPlugin.php b/plugins/PiwikAnalyticsPlugin.php new file mode 100644 index 000000000..d2c52354e --- /dev/null +++ b/plugins/PiwikAnalyticsPlugin.php @@ -0,0 +1,104 @@ +<?php +/** + * Laconica, the distributed open-source microblogging tool + * + * Plugin to use Piwik Analytics + * + * PHP version 5 + * + * LICENCE: This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * @category Plugin + * @package Laconica + * @author Evan Prodromou <evan@controlyourself.ca> + * @author Tobias Diekershoff <tobias.diekershoff@gmx.net> + * @copyright 2008 Control Yourself, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://laconi.ca/ + */ + +if (!defined('LACONICA')) { + exit(1); +} + +/** + * Plugin to use Piwik Analytics (based on the Google Analytics plugin by Evan) + * + * This plugin will spoot out the correct JavaScript spell to invoke + * Piwik Analytics on a page. + * + * To use this plugin please add the following three lines to your config.php + * + * require_once('plugins/PiwikAnalyticsPlugin.php'); + * $pa = new PiwikAnalyticsPlugin("example.com/piwik/","id"); + * + * exchange example.com/piwik/ with the url to your piwik installation and + * make sure you don't forget the final / + * exchange id with the ID your laconica installation has in your Piwik analytics + * + * @category Plugin + * @package Laconica + * @author Tobias Diekershoff <tobias.diekershoff@gmx.net> + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://laconi.ca/ + * + * @see Event + */ + +class PiwikAnalyticsPlugin extends Plugin +{ + /** the base of your Piwik installation */ + var $piwikroot = null; + /** the Piwik Id of your laconica installation */ + var $piwikId = null; + + /** + * constructor + * + * @param string $root Piwik root URL + * @param string $id Piwik ID of this app + */ + + function __construct($root=null, $id=null) + { + $this->piwikroot = $root; + $this->piwikid = $id; + parent::__construct(); + } + + /** + * Called when all scripts have been shown + * + * @param Action $action Current action + * + * @return boolean ignored + */ + + function onEndShowScripts($action) + { + $js1 = 'var pkBaseURL = (("https:" == document.location.protocol) ? "https://'. + $this->piwikroot.'" : "http://'.$this->piwikroot. + '"); document.write(unescape("%3Cscript src=\'" + pkBaseURL + "piwik.js\''. + ' type=\'text/javascript\'%3E%3C/script%3E"));'; + $js2 = 'piwik_action_name = ""; piwik_idsite = '.$this->piwikid. + '; piwik_url = pkBaseURL + "piwik.php"; piwik_log(piwik_action_name, piwik_idsite, piwik_url);'; + $action->elementStart('script', array('type' => 'text/javascript')); + $action->raw($js1); + $action->elementEnd('script'); + $action->elementStart('script', array('type' => 'text/javascript')); + $action->raw($js2); + $action->elementEnd('script'); + return true; + } +}
\ No newline at end of file diff --git a/plugins/TemplatePlugin.php b/plugins/TemplatePlugin.php new file mode 100644 index 000000000..03daf6219 --- /dev/null +++ b/plugins/TemplatePlugin.php @@ -0,0 +1,344 @@ +<?php +/** + * Plugin to render old skool templates + * + * Captures rendered parts from the output buffer, passes them through a template file: tpl/index.html + * Adds an API method at index.php/template/update which lets you overwrite the template file + * Requires username/password and a single POST parameter called "template" + * The method is disabled unless the user is #1, the first user of the system + * + * @category Plugin + * @package Laconica + * @author Brian Hendrickson <brian@megapump.com> + * @copyright 2009 Megapump, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://megapump.com/ + */ + +if (!defined('LACONICA')) { + exit(1); +} + +define('TEMPLATEPLUGIN_VERSION', '0.1'); + +class TemplatePlugin extends Plugin { + + var $blocks = array(); + + function __construct() { + parent::__construct(); + } + + // capture the RouterInitialized event + // and connect a new API method + // for updating the template + function onRouterInitialized( &$m ) { + $m->connect( 'template/update', array( + 'action' => 'template', + )); + } + + + // <%styles%> + // <%scripts%> + // <%search%> + // <%feeds%> + // <%description%> + // <%head%> + function onStartShowHead( &$act ) { + $this->clear_xmlWriter($act); + $act->extraHead(); + $this->blocks['head'] = $act->xw->flush(); + $act->showStylesheets(); + $this->blocks['styles'] = $act->xw->flush(); + $act->showScripts(); + $this->blocks['scripts'] = $act->xw->flush(); + $act->showFeeds(); + $this->blocks['feeds'] = $act->xw->flush(); + $act->showOpenSearch(); + $this->blocks['search'] = $act->xw->flush(); + $act->showDescription(); + $this->blocks['description'] = $act->xw->flush(); + return false; + } + + // <%bodytext%> + function onStartShowContentBlock( &$act ) { + $this->clear_xmlWriter($act); + return true; + } + function onEndShowContentBlock( &$act ) { + $this->blocks['bodytext'] = $act->xw->flush(); + } + + // <%localnav%> + function onStartShowLocalNavBlock( &$act ) { + $this->clear_xmlWriter($act); + return true; + } + function onEndShowLocalNavBlock( &$act ) { + $this->blocks['localnav'] = $act->xw->flush(); + } + + // <%export%> + function onStartShowExportData( &$act ) { + $this->clear_xmlWriter($act); + return true; + } + function onEndShowExportData( &$act ) { + $this->blocks['export'] = $act->xw->flush(); + } + + // <%subscriptions%> + // <%subscribers%> + // <%groups%> + // <%statistics%> + // <%cloud%> + // <%groupmembers%> + // <%groupstatistics%> + // <%groupcloud%> + // <%popular%> + // <%groupsbyposts%> + // <%featuredusers%> + // <%groupsbymembers%> + function onStartShowSections( &$act ) { + global $action; + $this->clear_xmlWriter($act); + switch ($action) { + case "showstream": + $act->showSubscriptions(); + $this->blocks['subscriptions'] = $act->xw->flush(); + $act->showSubscribers(); + $this->blocks['subscribers'] = $act->xw->flush(); + $act->showGroups(); + $this->blocks['groups'] = $act->xw->flush(); + $act->showStatistics(); + $this->blocks['statistics'] = $act->xw->flush(); + $cloud = new PersonalTagCloudSection($act, $act->user); + $cloud->show(); + $this->blocks['cloud'] = $act->xw->flush(); + break; + case "showgroup": + $act->showMembers(); + $this->blocks['groupmembers'] = $act->xw->flush(); + $act->showStatistics(); + $this->blocks['groupstatistics'] = $act->xw->flush(); + $cloud = new GroupTagCloudSection($act, $act->group); + $cloud->show(); + $this->blocks['groupcloud'] = $act->xw->flush(); + break; + case "public": + $pop = new PopularNoticeSection($act); + $pop->show(); + $this->blocks['popular'] = $act->xw->flush(); + $gbp = new GroupsByPostsSection($act); + $gbp->show(); + $this->blocks['groupsbyposts'] = $act->xw->flush(); + $feat = new FeaturedUsersSection($act); + $feat->show(); + $this->blocks['featuredusers'] = $act->xw->flush(); + break; + case "groups": + $gbp = new GroupsByPostsSection($act); + $gbp->show(); + $this->blocks['groupsbyposts'] = $act->xw->flush(); + $gbm = new GroupsByMembersSection($act); + $gbm->show(); + $this->blocks['groupsbymembers'] = $act->xw->flush(); + break; + } + return false; + } + + // <%logo%> + // <%nav%> + // <%notice%> + // <%noticeform%> + function onStartShowHeader( &$act ) { + $this->clear_xmlWriter($act); + $act->showLogo(); + $this->blocks['logo'] = $act->xw->flush(); + $act->showPrimaryNav(); + $this->blocks['nav'] = $act->xw->flush(); + $act->showSiteNotice(); + $this->blocks['notice'] = $act->xw->flush(); + if (common_logged_in()) { + $act->showNoticeForm(); + } else { + $act->showAnonymousMessage(); + } + $this->blocks['noticeform'] = $act->xw->flush(); + return false; + } + + // <%secondarynav%> + // <%licenses%> + function onStartShowFooter( &$act ) { + $this->clear_xmlWriter($act); + $act->showSecondaryNav(); + $this->blocks['secondarynav'] = $act->xw->flush(); + $act->showLicenses(); + $this->blocks['licenses'] = $act->xw->flush(); + return false; + } + + // capture the EndHTML event + // and include the template + function onEndEndHTML($act) { + + global $action, $tags; + + // set the action and title values + $vars = array( + 'action'=>$action, + 'title'=>$act->title(). " - ". common_config('site', 'name') + ); + + // use the PHP template + // unless laconica config: + // $config['template']['mode'] = 'html'; + if (!(common_config('template', 'mode') == 'html')) { + $tpl_file = 'tpl/index.php'; + $tags = array_merge($vars,$this->blocks); + include $tpl_file; + return; + } + + $tpl_file = 'tpl/index.html'; + + // read the static template + $output = file_get_contents( $tpl_file ); + + $tags = array(); + + // get a list of the <%tags%> in the template + $pattern='/<%([a-z]+)%>/'; + + if ( 1 <= preg_match_all( $pattern, $output, $found )) + $tags[] = $found; + + // for each found tag, set its value from the rendered blocks + foreach( $tags[0][1] as $pos=>$tag ) { + if (isset($this->blocks[$tag])) + $vars[$tag] = $this->blocks[$tag]; + + // didn't find a block for the tag + elseif (!isset($vars[$tag])) + $vars[$tag] = ''; + } + + // replace the tags in the template + foreach( $vars as $key=>$val ) + $output = str_replace( '<%'.$key.'%>', $val, $output ); + + echo $output; + + return true; + + } + + // catching the StartShowHTML event to halt the rendering + function onStartShowHTML( &$act ) { + $this->clear_xmlWriter($act); + return true; + } + + // clear the xmlWriter + function clear_xmlWriter( &$act ) { + $act->xw->openMemory(); + $act->xw->setIndent(true); + } + +} + +/** + * Action for updating the template remotely + * + * "template/update" -- a POST method that requires a single + * parameter "template", containing the new template code + * + * @category Plugin + * @package Laconica + * @author Brian Hendrickson <brian@megapump.com> + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://megapump.com/ + * + */ + +class TemplateAction extends Action +{ + + function prepare($args) { + parent::prepare($args); + return true; + } + + function handle($args) { + + parent::handle($args); + + if (!isset($_SERVER['PHP_AUTH_USER'])) { + + // not authenticated, show login form + header('WWW-Authenticate: Basic realm="Laconica API"'); + + // cancelled the browser login form + $this->clientError(_('Authentication error!'), $code = 401); + + } else { + + $nick = $_SERVER['PHP_AUTH_USER']; + $pass = $_SERVER['PHP_AUTH_PW']; + + // check username and password + $user = common_check_user($nick,$pass); + + if ($user) { + + // verify that user is admin + if (!($user->id == 1)) + $this->clientError(_('only User #1 can update the template'), $code = 401); + + // open the old template + $tpl_file = 'tpl/index.html'; + $fp = fopen( $tpl_file, 'w+' ); + + // overwrite with the new template + fwrite($fp, $this->arg('template')); + fclose($fp); + + header('HTTP/1.1 200 OK'); + header('Content-type: text/plain'); + print "Template Updated!"; + + } else { + + // bad username and password + $this->clientError(_('Authentication error!'), $code = 401); + + } + + } + } +} + +/** + * Function for retrieving a laconica display section + * + * requires one parameter, the name of the section + * section names are listed in the comments of the TemplatePlugin class + * + * @category Plugin + * @package Laconica + * @author Brian Hendrickson <brian@megapump.com> + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://megapump.com/ + * + */ + +function section($tagname) { + global $tags; + if (isset($tags[$tagname])) + return $tags[$tagname]; +} + |