From d7d96806a4ac83fc9260e67b94cb94eea6f6d4a4 Mon Sep 17 00:00:00 2001 From: Mikael Nordfeldth Date: Fri, 10 Apr 2015 13:15:12 +0200 Subject: [PATCH 01/24] removed unused config setting --- lib/default.php | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/default.php b/lib/default.php index 9926f6aa7a..dfa3626927 100644 --- a/lib/default.php +++ b/lib/default.php @@ -330,7 +330,6 @@ $default = 'path' => null, 'sslpath' => null, ), - 'pluginlist' => array(), 'admin' => array('panels' => array('site', 'user', 'paths', 'access', 'sessions', 'sitenotice', 'license', 'plugins')), 'singleuser' => From c5715bc756b2bfc010f4f861705d40bf092304e5 Mon Sep 17 00:00:00 2001 From: Mikael Nordfeldth Date: Wed, 15 Apr 2015 23:25:12 +0200 Subject: [PATCH 02/24] File_to_post indexing and cleaning preparations --- classes/File.php | 8 ++++++++ classes/File_to_post.php | 3 ++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/classes/File.php b/classes/File.php index 242da159c2..1e296242b7 100644 --- a/classes/File.php +++ b/classes/File.php @@ -569,6 +569,14 @@ class File extends Managed_DataObject $thumbs->delete(); } } + + $f2p = new File_to_post(); + $f2p->file_id = $this->id; + if ($f2p->find()) { + while ($f2p->fetch()) { + $f2p->delete(); + } + } } // And finally remove the entry from the database diff --git a/classes/File_to_post.php b/classes/File_to_post.php index 1d2733738f..4c751ae4f3 100644 --- a/classes/File_to_post.php +++ b/classes/File_to_post.php @@ -52,6 +52,7 @@ class File_to_post extends Managed_DataObject 'file_to_post_post_id_fkey' => array('notice', array('post_id' => 'id')), ), 'indexes' => array( + 'file_id_idx' => array('file_id'), 'post_id_idx' => array('post_id'), ), ); @@ -87,7 +88,7 @@ class File_to_post extends Managed_DataObject function delete($useWhere=false) { $f = File::getKV('id', $this->file_id); - if (!empty($f)) { + if ($f instanceof File) { $f->blowCache(); } return parent::delete($useWhere); From 5f1e9e80c299c05fb7b2106cfa966efaaf233eba Mon Sep 17 00:00:00 2001 From: Mikael Nordfeldth Date: Wed, 15 Apr 2015 23:26:24 +0200 Subject: [PATCH 03/24] remove duplicate file URLs script --- scripts/remove_duplicate_file_urls.php | 59 ++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100755 scripts/remove_duplicate_file_urls.php diff --git a/scripts/remove_duplicate_file_urls.php b/scripts/remove_duplicate_file_urls.php new file mode 100755 index 0000000000..dd965991f0 --- /dev/null +++ b/scripts/remove_duplicate_file_urls.php @@ -0,0 +1,59 @@ +#!/usr/bin/env php +. + */ + +define('INSTALLDIR', realpath(dirname(__FILE__) . '/..')); + +$shortoptions = 'y'; +$longoptions = array('yes'); + +$helptext = <<query('SELECT id, url, COUNT(*) AS c FROM file GROUP BY url HAVING c > 1'); +while ($file->fetch()) { + // We've got a URL that is duplicated in the file table + $dupfile = new File(); + $dupfile->url = $file->url; + if ($dupfile->find(true)) { + // Leave one of the URLs in the database by using ->find(true) + // and only deleting starting with this fetch. + while($dupfile->fetch()) { + $dupfile->delete(); + } + } +} +print "\nDONE.\n"; From 0337a7b866276979cbeeeee1763d6553fc06f3ba Mon Sep 17 00:00:00 2001 From: Mikael Nordfeldth Date: Wed, 15 Apr 2015 23:56:23 +0200 Subject: [PATCH 04/24] file_redirection duplicates are removed too in maintenance script --- scripts/remove_duplicate_file_urls.php | 31 ++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/scripts/remove_duplicate_file_urls.php b/scripts/remove_duplicate_file_urls.php index dd965991f0..a4a7cd795b 100755 --- a/scripts/remove_duplicate_file_urls.php +++ b/scripts/remove_duplicate_file_urls.php @@ -25,7 +25,7 @@ $longoptions = array('yes'); $helptext = <<query('SELECT id, url, COUNT(*) AS c FROM file GROUP BY url HAVING c > 1'); +print "\nFound {$file->N} URLs with duplicate entries in file table"; while ($file->fetch()) { // We've got a URL that is duplicated in the file table $dupfile = new File(); $dupfile->url = $file->url; if ($dupfile->find(true)) { + print "\nDeleting duplicate entries in file table for URL: {$file->url} ["; // Leave one of the URLs in the database by using ->find(true) // and only deleting starting with this fetch. while($dupfile->fetch()) { + print "."; $dupfile->delete(); } + print "]\n"; + } else { + print "\nWarning! URL suddenly disappeared from database: {$file->url}\n"; + } +} + +$file = new File_redirection(); +$file->query('SELECT file_id, url, COUNT(*) AS c FROM file_redirection GROUP BY url HAVING c > 1'); +print "\nFound {$file->N} URLs with duplicate entries in file_redirection table"; +while ($file->fetch()) { + // We've got a URL that is duplicated in the file_redirection table + $dupfile = new File_redirection(); + $dupfile->url = $file->url; + if ($dupfile->find(true)) { + print "\nDeleting duplicate entries in file table for URL: {$file->url} ["; + // Leave one of the URLs in the database by using ->find(true) + // and only deleting starting with this fetch. + while($dupfile->fetch()) { + print "."; + $dupfile->delete(); + } + print "]\n"; + } else { + print "\nWarning! URL suddenly disappeared from database: {$file->url}\n"; } } print "\nDONE.\n"; From a55d1df585998bdcba03afe38dd60777e9aad030 Mon Sep 17 00:00:00 2001 From: Mikael Nordfeldth Date: Thu, 16 Apr 2015 00:22:09 +0200 Subject: [PATCH 05/24] Clearer warning message on non-existing file --- scripts/upgrade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/upgrade.php b/scripts/upgrade.php index 692eaac17a..126ef29036 100644 --- a/scripts/upgrade.php +++ b/scripts/upgrade.php @@ -520,7 +520,7 @@ function setFilehashOnLocalFiles() $file->filehash = hash_file(File::FILEHASH_ALG, $file->getPath()); $file->update($orig); } catch (FileNotFoundException $e) { - echo "\n WARNING: file ID {$file->id} does not exist on path '{$e->path}'. Clean up the file table?"; + echo "\n WARNING: file ID {$file->id} does not exist on path '{$e->path}'. If there is no file system error, run: php scripts/clean_file_table.php"; } } } From 1194c47c5dfe17e188e4d2c3e1766755346ce02f Mon Sep 17 00:00:00 2001 From: Mikael Nordfeldth Date: Sun, 19 Apr 2015 21:12:26 +0200 Subject: [PATCH 06/24] ksort on commands array to avoid converting to numerical array --- lib/command.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/command.php b/lib/command.php index 94e95f0ee9..830b97ee23 100644 --- a/lib/command.php +++ b/lib/command.php @@ -932,7 +932,7 @@ class HelpCommand extends Command // Give plugins a chance to add or override... Event::handle('HelpCommandMessages', array($this, &$commands)); - sort($commands); + ksort($commands); foreach ($commands as $command => $help) { $out[] = "$command - $help"; } From b75e88f65f732b23a1f471c9af04d1bfaf3130b8 Mon Sep 17 00:00:00 2001 From: Mikael Nordfeldth Date: Mon, 20 Apr 2015 00:02:13 +0200 Subject: [PATCH 07/24] Get better PEAR:DB error logging (debuginfo included) --- lib/schema.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/schema.php b/lib/schema.php index 94cde28f9d..0421bcb810 100644 --- a/lib/schema.php +++ b/lib/schema.php @@ -350,7 +350,7 @@ class Schema $res = $this->conn->query("DROP TABLE $name"); if ($_PEAR->isError($res)) { - throw new Exception($res->getMessage()); + PEAR_ErrorToPEAR_Exception($res); } return true; @@ -389,7 +389,7 @@ class Schema implode(",", $columnNames).")"); if ($_PEAR->isError($res)) { - throw new Exception($res->getMessage()); + PEAR_ErrorToPEAR_Exception($res); } return true; @@ -411,7 +411,7 @@ class Schema $res = $this->conn->query("ALTER TABLE $table DROP INDEX $name"); if ($_PEAR->isError($res)) { - throw new Exception($res->getMessage()); + PEAR_ErrorToPEAR_Exception($res); } return true; @@ -436,7 +436,7 @@ class Schema $res = $this->conn->query($sql); if ($_PEAR->isError($res)) { - throw new Exception($res->getMessage()); + PEAR_ErrorToPEAR_Exception($res); } return true; @@ -463,7 +463,7 @@ class Schema $res = $this->conn->query($sql); if ($_PEAR->isError($res)) { - throw new Exception($res->getMessage()); + PEAR_ErrorToPEAR_Exception($res); } return true; @@ -489,7 +489,7 @@ class Schema $res = $this->conn->query($sql); if ($_PEAR->isError($res)) { - throw new Exception($res->getMessage()); + PEAR_ErrorToPEAR_Exception($res); } return true; @@ -535,7 +535,7 @@ class Schema $res = $this->conn->query($sql); if ($_PEAR->isError($res)) { - throw new Exception($res->getMessage()); + PEAR_ErrorToPEAR_Exception($res); } } return $ok; @@ -1045,7 +1045,7 @@ class Schema $res = $this->conn->query($sql); if ($_PEAR->isError($res)) { - throw new Exception($res->getMessage()); + PEAR_ErrorToPEAR_Exception($res); } $out = array(); From 8a119dc970ea61811d29f22faa8ebcc108a07629 Mon Sep 17 00:00:00 2001 From: Mikael Nordfeldth Date: Mon, 20 Apr 2015 00:26:00 +0200 Subject: [PATCH 08/24] We already throw exceptions for PEAR errors --- lib/schemaupdater.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/schemaupdater.php b/lib/schemaupdater.php index ae746c10b5..38b5b93865 100644 --- a/lib/schemaupdater.php +++ b/lib/schemaupdater.php @@ -98,7 +98,6 @@ class SchemaUpdater { $checksums = array(); - PEAR::pushErrorHandling(PEAR_ERROR_EXCEPTION); try { $sv = new Schema_version(); $sv->find(); @@ -111,7 +110,6 @@ class SchemaUpdater // no dice! common_log(LOG_DEBUG, "Possibly schema_version table doesn't exist yet."); } - PEAR::popErrorHandling(); return $checksums; } @@ -124,7 +122,6 @@ class SchemaUpdater */ protected function saveChecksum($table, $checksum) { - PEAR::pushErrorHandling(PEAR_ERROR_EXCEPTION); try { $sv = new Schema_version(); $sv->table_name = $table; @@ -139,7 +136,6 @@ class SchemaUpdater // no dice! common_log(LOG_DEBUG, "Possibly schema_version table doesn't exist yet."); } - PEAR::popErrorHandling(); $this->checksums[$table] = $checksum; } } From f9f7c4675166d46afbe29132d4d293bc758a68e2 Mon Sep 17 00:00:00 2001 From: Mikael Nordfeldth Date: Mon, 20 Apr 2015 00:26:16 +0200 Subject: [PATCH 09/24] Better typing in lib/framework.php --- lib/framework.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/framework.php b/lib/framework.php index b71f365c24..4ec8b083e0 100644 --- a/lib/framework.php +++ b/lib/framework.php @@ -144,7 +144,7 @@ require_once INSTALLDIR.'/lib/action.php'; require_once INSTALLDIR.'/lib/mail.php'; //set PEAR error handling to use regular PHP exceptions -function PEAR_ErrorToPEAR_Exception($err) +function PEAR_ErrorToPEAR_Exception(PEAR_Error $err) { //DB_DataObject throws error when an empty set would be returned //That behavior is weird, and not how the rest of StatusNet works. From 529b2f6613007d2fce427cc2fef63af9bbcd7b36 Mon Sep 17 00:00:00 2001 From: Mikael Nordfeldth Date: Tue, 21 Apr 2015 23:47:55 +0200 Subject: [PATCH 10/24] deleteuser script changed to deleteprofile Delete remote profiles by providing their ID if known, or you can provide their profile URI with --uri=https://... Useful for cleaning up old, long gone and no longer desired profiles and their notices. --- scripts/{deleteuser.php => deleteprofile.php} | 36 ++++++++++++------- 1 file changed, 23 insertions(+), 13 deletions(-) rename scripts/{deleteuser.php => deleteprofile.php} (60%) diff --git a/scripts/deleteuser.php b/scripts/deleteprofile.php similarity index 60% rename from scripts/deleteuser.php rename to scripts/deleteprofile.php index 25af1c5ce2..8eed6ff97b 100755 --- a/scripts/deleteuser.php +++ b/scripts/deleteprofile.php @@ -20,15 +20,16 @@ define('INSTALLDIR', realpath(dirname(__FILE__) . '/..')); -$shortoptions = 'i::n::y'; -$longoptions = array('id=', 'nickname=', 'yes'); +$shortoptions = 'i::n::u::y'; +$longoptions = array('id=', 'nickname=', 'uri=', 'yes'); $helptext = <<getProfile(); +} else if (have_option('u', 'uri')) { + $uri = get_option_value('u', 'uri'); + $oprofile = Ostatus_profile::getKV('uri', $uri); + if (!$oprofile instanceof Ostatus_profile) { + print "Can't find profile with URI '$uri'\n"; + exit(1); + } + $profile = $oprofile->localProfile(); } else { - print "You must provide either an ID or a nickname.\n"; + print "You must provide either an ID, a URI or a nickname.\n"; exit(1); } if (!have_option('y', 'yes')) { - print "About to PERMANENTLY delete user '{$user->nickname}' ({$user->id}). Are you sure? [y/N] "; + print "About to PERMANENTLY delete profile '".$profile->getNickname()."' ({$profile->id}). Are you sure? [y/N] "; $response = fgets(STDIN); if (strtolower(trim($response)) != 'y') { print "Aborting.\n"; @@ -64,5 +74,5 @@ if (!have_option('y', 'yes')) { } print "Deleting..."; -$user->delete(); +$profile->delete(); print "DONE.\n"; From 0a0455b8d24d5dd068756418e4173925a9101e0b Mon Sep 17 00:00:00 2001 From: Mikael Nordfeldth Date: Wed, 22 Apr 2015 18:41:54 +0200 Subject: [PATCH 11/24] minor coding fixes --- plugins/InfiniteScroll/InfiniteScrollPlugin.php | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/plugins/InfiniteScroll/InfiniteScrollPlugin.php b/plugins/InfiniteScroll/InfiniteScrollPlugin.php index 44c5c5e880..986ba36075 100644 --- a/plugins/InfiniteScroll/InfiniteScrollPlugin.php +++ b/plugins/InfiniteScroll/InfiniteScrollPlugin.php @@ -27,21 +27,13 @@ * @link http://status.net/ */ -if (!defined('STATUSNET') && !defined('LACONICA')) { - exit(1); -} +if (!defined('GNUSOCIAL')) { exit(1); } class InfiniteScrollPlugin extends Plugin { - public $on_next_only = false; - function __construct() - { - parent::__construct(); - } - - function onEndShowScripts($action) + function onEndShowScripts(Action $action) { $action->inlineScript('var infinite_scroll_on_next_only = ' . ($this->on_next_only?'true':'false') . ';'); $action->inlineScript('var ajax_loader_url = "' . ($this->path('ajax-loader.gif')) . '";'); @@ -49,7 +41,7 @@ class InfiniteScrollPlugin extends Plugin $action->script($this->path('infinitescroll.js')); } - function onPluginVersion(&$versions) + function onPluginVersion(array &$versions) { $versions[] = array('name' => 'InfiniteScroll', 'version' => GNUSOCIAL_VERSION, From f642da201dfeb5acd6849e70e9f969feddf3565b Mon Sep 17 00:00:00 2001 From: Mikael Nordfeldth Date: Wed, 22 Apr 2015 19:44:58 +0200 Subject: [PATCH 12/24] Easier to modify DTD for HTMLOutputter --- lib/htmloutputter.php | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/lib/htmloutputter.php b/lib/htmloutputter.php index 3409ff8f92..5e40037952 100644 --- a/lib/htmloutputter.php +++ b/lib/htmloutputter.php @@ -28,11 +28,7 @@ * @link http://status.net/ */ -if (!defined('STATUSNET') && !defined('LACONICA')) { - exit(1); -} - -require_once INSTALLDIR.'/lib/xmloutputter.php'; +if (!defined('GNUSOCIAL')) { exit(1); } // Can include XHTML options but these are too fragile in practice. define('PAGE_TYPE_PREFS', 'text/html'); @@ -58,6 +54,9 @@ define('PAGE_TYPE_PREFS', 'text/html'); class HTMLOutputter extends XMLOutputter { + protected $DTD = array('doctype' => 'html', + 'spec' => '-//W3C//DTD XHTML 1.0 Strict//EN', + 'uri' => 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd'); /** * Constructor * @@ -120,9 +119,8 @@ class HTMLOutputter extends XMLOutputter // Required for XML documents $this->startXML(); } - $this->xw->writeDTD('html', - '-//W3C//DTD XHTML 1.0 Strict//EN', - 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd'); + + $this->writeDTD(); $language = $this->getLanguage(); @@ -138,6 +136,18 @@ class HTMLOutputter extends XMLOutputter } } + public function setDTD($doctype, $spec, $uri) + { + $this->DTD = array('doctype' => $doctype, 'spec' => $spec, 'uri' => $uri); + } + + protected function writeDTD() + { + $this->xw->writeDTD($this->DTD['doctype'], + $this->DTD['spec'], + $this->DTD['uri']); + } + function getLanguage() { // FIXME: correct language for interface From 4210096a6f45695807652ecd32e66f98580f128f Mon Sep 17 00:00:00 2001 From: Mikael Nordfeldth Date: Wed, 22 Apr 2015 19:50:56 +0200 Subject: [PATCH 13/24] MobileProfile plugin cleanup --- plugins/MobileProfile/MobileProfilePlugin.php | 266 ++++++++---------- 1 file changed, 114 insertions(+), 152 deletions(-) diff --git a/plugins/MobileProfile/MobileProfilePlugin.php b/plugins/MobileProfile/MobileProfilePlugin.php index 98fcb472fa..2efc006879 100644 --- a/plugins/MobileProfile/MobileProfilePlugin.php +++ b/plugins/MobileProfile/MobileProfilePlugin.php @@ -27,9 +27,7 @@ * @link http://status.net/ */ -if (!defined('STATUSNET')) { - exit(1); -} +if (!defined('GNUSOCIAL')) { exit(1); } define('PAGE_TYPE_PREFS_MOBILEPROFILE', 'application/vnd.wap.xhtml+xml, application/xhtml+xml, text/html;q=0.9'); @@ -59,124 +57,120 @@ class MobileProfilePlugin extends WAP20Plugin parent::__construct(); } - function onStartShowHTML($action) + public function onStartShowHTML(Action $action) { - // XXX: This should probably graduate to WAP20Plugin + // TODO: A lot of this should probably graduate to WAP20Plugin + + $httpaccept = isset($_SERVER['HTTP_ACCEPT']) ? $_SERVER['HTTP_ACCEPT'] : null; + + $cp = common_accept_to_prefs($httpaccept); + $sp = common_accept_to_prefs(PAGE_TYPE_PREFS_MOBILEPROFILE); + + $type = common_negotiate_type($cp, $sp); + + if (!$type) { + // TRANS: Client exception thrown when requesting a not supported media type. + throw new ClientException(_m('This page is not available in a '. + 'media type you accept.'), 406); + } // If they are on the mobile site, serve them MP - if ((common_config('site', 'mobileserver').'/'. - common_config('site', 'path').'/' == - $_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'])) { - + if ((common_config('site', 'mobileserver').'/'.common_config('site', 'path').'/' + == $_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'])) { $this->serveMobile = true; - } else if (isset($_COOKIE['MobileOverride'])) { + } elseif (isset($_COOKIE['MobileOverride'])) { // Cookie override is controlled by link at bottom. $this->serveMobile = (bool)$_COOKIE['MobileOverride']; - } elseif (array_key_exists('HTTP_USER_AGENT', $_SERVER)) { + } elseif (strstr('application/vnd.wap.xhtml+xml', $type) !== false) { // If they like the WAP 2.0 mimetype, serve them MP - // @fixme $type is undefined, making this if case useless and spewing errors. - // What's the intent? - //if (strstr('application/vnd.wap.xhtml+xml', $type) !== false) { - // $this->serveMobile = true; - //} else { - // If they are a mobile device that supports WAP 2.0, - // serve them MP + $this->serveMobile = true; + } elseif (array_key_exists('HTTP_USER_AGENT', $_SERVER)) { + // If they are a mobile device that supports WAP 2.0, + // serve them MP - // XXX: Browser sniffing sucks + // XXX: Browser sniffing sucks - // I really don't like going through this every page, - // perhaps use $_SESSION or cookies + // I really don't like going through this every page, + // perhaps use $_SESSION or cookies - // May be better to group the devices in terms of - // low,mid,high-end + // May be better to group the devices in terms of + // low,mid,high-end - // Or, detect the mobile devices based on their support for - // MP 1.0, 1.1, or 1.2 may be ideal. Possible? + // Or, detect the mobile devices based on their support for + // MP 1.0, 1.1, or 1.2 may be ideal. Possible? - $this->mobiledevices = array( - 'alcatel', - 'android', - 'audiovox', - 'au-mic,', - 'avantgo', - 'blackberry', - 'blazer', - 'cldc-', - 'danger', - 'epoc', - 'ericsson', - 'ericy', - 'iphone', - 'ipaq', - 'ipod', - 'j2me', - 'lg', - 'maemo', - 'midp-', - 'mobile', - 'mot', - 'netfront', - 'nitro', - 'nokia', - 'opera mini', - 'palm', - 'palmsource', - 'panasonic', - 'philips', - 'pocketpc', - 'portalmmm', - 'rover', - 'samsung', - 'sanyo', - 'series60', - 'sharp', - 'sie-', - 'smartphone', - 'sony', - 'symbian', - 'up.browser', - 'up.link', - 'up.link', - 'vodafone', - 'wap1', - 'wap2', - 'webos', - 'windows ce' - ); + $this->mobiledevices = array( + 'alcatel', + 'android', + 'audiovox', + 'au-mic,', + 'avantgo', + 'blackberry', + 'blazer', + 'cldc-', + 'danger', + 'epoc', + 'ericsson', + 'ericy', + 'iphone', + 'ipaq', + 'ipod', + 'j2me', + 'lg', + 'maemo', + 'midp-', + 'mobile', + 'mot', + 'netfront', + 'nitro', + 'nokia', + 'opera mini', + 'palm', + 'palmsource', + 'panasonic', + 'philips', + 'pocketpc', + 'portalmmm', + 'rover', + 'samsung', + 'sanyo', + 'series60', + 'sharp', + 'sie-', + 'smartphone', + 'sony', + 'symbian', + 'up.browser', + 'up.link', + 'up.link', + 'vodafone', + 'wap1', + 'wap2', + 'webos', + 'windows ce' + ); - $blacklist = array( - 'ipad', // Larger screen handles the full theme fairly well. - ); + $blacklist = array( + 'ipad', // Larger screen handles the full theme fairly well. + ); - $httpuseragent = strtolower($_SERVER['HTTP_USER_AGENT']); + $httpuseragent = strtolower($_SERVER['HTTP_USER_AGENT']); - foreach ($blacklist as $md) { - if (strstr($httpuseragent, $md) !== false) { - $this->serveMobile = false; - return true; - } + foreach ($blacklist as $md) { + if (strstr($httpuseragent, $md) !== false) { + $this->serveMobile = false; + return true; } + } - foreach ($this->mobiledevices as $md) { - if (strstr($httpuseragent, $md) !== false) { - $this->setMobileFeatures($httpuseragent); + foreach ($this->mobiledevices as $md) { + if (strstr($httpuseragent, $md) !== false) { + $this->setMobileFeatures($httpuseragent); - $this->serveMobile = true; - $this->reallyMobile = true; - break; - } + $this->serveMobile = true; + $this->reallyMobile = true; + break; } - //} - - // If they are okay with MP, and the site has a mobile server, - // redirect there - if ($this->serveMobile && - common_config('site', 'mobileserver') !== false && - (common_config('site', 'mobileserver') != - common_config('site', 'server'))) { - - // FIXME: Redirect to equivalent page on mobile site instead - common_redirect($this->_common_path(''), 302); } } @@ -184,48 +178,23 @@ class MobileProfilePlugin extends WAP20Plugin return true; } - // @fixme $type is undefined, making this if case useless and spewing errors. - // What's the intent? - //if (!$type) { - $httpaccept = isset($_SERVER['HTTP_ACCEPT']) ? - $_SERVER['HTTP_ACCEPT'] : null; + // If they are okay with MP, and the site has a mobile server, + // redirect there + if (common_config('site', 'mobileserver') !== false && + common_config('site', 'mobileserver') != common_config('site', 'server')) { - $cp = common_accept_to_prefs($httpaccept); - $sp = common_accept_to_prefs(PAGE_TYPE_PREFS_MOBILEPROFILE); - - $type = common_negotiate_type($cp, $sp); - - if (!$type) { - // TRANS: Client exception thrown when requesting a not supported media type. - throw new ClientException(_m('This page is not available in a '. - 'media type you accept.'), 406); - } - //} + // FIXME: Redirect to equivalent page on mobile site instead + common_redirect($this->_common_path(''), 302); + } header('Content-Type: '.$type); if ($this->reallyMobile) { - - $action->extraHeaders(); - if (preg_match("/.*\/.*xml/", $type)) { - // Required for XML documents - $action->startXML(); - } - $action->xw->writeDTD('html', - '-//WAPFORUM//DTD XHTML Mobile 1.0//EN', - $this->DTD); - - $language = $action->getLanguage(); - - $action->elementStart('html', array('xmlns' => 'http://www.w3.org/1999/xhtml', - 'xml:lang' => $language)); - - return false; - - } else { - return true; + $action->setDTD('html', '-//WAPFORUM//DTD XHTML Mobile 1.0//EN', $this->DTD); } + // continue + return true; } function setMobileFeatures($useragent) @@ -268,7 +237,7 @@ class MobileProfilePlugin extends WAP20Plugin return false; } - function onStartShowUAStyles($action) { + public function onStartShowUAStyles(Action $action) { if (!$this->serveMobile) { return true; } @@ -276,7 +245,7 @@ class MobileProfilePlugin extends WAP20Plugin return false; } - function onStartShowHeader($action) + public function onStartShowHeader(Action $action) { if (!$this->serveMobile) { return true; @@ -290,7 +259,7 @@ class MobileProfilePlugin extends WAP20Plugin return false; } - function _showLogo($action) + protected function _showLogo(Action $action) { $action->elementStart('address'); if (common_config('singleuser', 'enabled')) { @@ -316,23 +285,22 @@ class MobileProfilePlugin extends WAP20Plugin $action->elementEnd('address'); } - function onStartShowAside($action) + public function onStartShowAside(Action $action) { if ($this->serveMobile) { return false; } } - function onStartShowLocalNavBlock($action) + public function onStartShowLocalNavBlock(Action $action) { if ($this->serveMobile) { // @todo FIXME: "Show Navigation" / "Hide Navigation" needs i18n $action->element('a', array('href' => '#', 'id' => 'navtoggle'), 'Show Navigation'); - return true; } } - function onEndShowScripts($action) + public function onEndShowScripts(Action $action) { // @todo FIXME: "Show Navigation" / "Hide Navigation" needs i18n $action->inlineScript(' @@ -357,18 +325,12 @@ class MobileProfilePlugin extends WAP20Plugin ); if ($this->serveMobile) { - $action->inlineScript(' - $(function() { - $(".checkbox-wrapper").unbind("click"); - });' - ); + $action->inlineScript('$(function() { $(".checkbox-wrapper").unbind("click"); });'); } - - } - function onEndShowInsideFooter($action) + public function onEndShowInsideFooter(Action $action) { if ($this->serveMobile) { // TRANS: Link to switch site layout from mobile to desktop mode. Appears at very bottom of page. From 7601e10b6a99fbadf593cf4df18e914c96de93f0 Mon Sep 17 00:00:00 2001 From: Mikael Nordfeldth Date: Wed, 22 Apr 2015 20:57:05 +0200 Subject: [PATCH 14/24] getFullname function on Profile class No need to fix it for User since we shouldn't use that mostly. --- classes/Profile.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/classes/Profile.php b/classes/Profile.php index a944d5b4d2..480606890d 100644 --- a/classes/Profile.php +++ b/classes/Profile.php @@ -1380,6 +1380,11 @@ class Profile extends Managed_DataObject return $this->nickname; } + public function getFullname() + { + return $this->fullname; + } + public function getDescription() { return $this->bio; From 51ecd6be15098c1e8ac8701f846c22f9f630d5c0 Mon Sep 17 00:00:00 2001 From: Mikael Nordfeldth Date: Wed, 22 Apr 2015 21:22:02 +0200 Subject: [PATCH 15/24] Fix some ProfileAction stuff, add function profileActionPreparation Split up files with multiple classes to multiple files for autoload, sorry for baking this into this commit. --- actions/all.php | 10 +- actions/showstream.php | 68 +++--- actions/tagprofile.php | 2 - lib/accountprofileblock.php | 8 +- lib/{peopletags.php => peopletagswidget.php} | 21 +- lib/profileaction.php | 21 +- lib/profilelist.php | 218 +---------------- lib/profilelistitem.php | 242 +++++++++++++++++++ lib/profileminilist.php | 42 +--- lib/profileminilistitem.php | 76 ++++++ lib/selftagswidget.php | 43 ++++ 11 files changed, 411 insertions(+), 340 deletions(-) rename lib/{peopletags.php => peopletagswidget.php} (92%) create mode 100644 lib/profilelistitem.php create mode 100644 lib/profileminilistitem.php create mode 100644 lib/selftagswidget.php diff --git a/actions/all.php b/actions/all.php index fb0b63577a..9cab91264f 100644 --- a/actions/all.php +++ b/actions/all.php @@ -41,13 +41,9 @@ class AllAction extends ProfileAction { var $notice; - protected function prepare(array $args=array()) + protected function profileActionPreparation() { - parent::prepare($args); - - $user = common_current_user(); - - if (!empty($user) && $user->streamModeOnly()) { + if ($this->scoped instanceof Profile && $this->scoped->isLocal() && $this->scoped->getUser()->streamModeOnly()) { $stream = new InboxNoticeStream($this->target, $this->scoped); } else { $stream = new ThreadingInboxNoticeStream($this->target, $this->scoped); @@ -60,8 +56,6 @@ class AllAction extends ProfileAction // TRANS: Client error when page not found (404). $this->clientError(_('No such page.'), 404); } - - return true; } function title() diff --git a/actions/showstream.php b/actions/showstream.php index 7c38eca14a..b1271dea54 100644 --- a/actions/showstream.php +++ b/actions/showstream.php @@ -57,14 +57,12 @@ class ShowstreamAction extends ProfileAction { var $notice; - protected function prepare(array $args=array()) + protected function profileActionPreparation() { - parent::prepare($args); - if (empty($this->tag)) { - $stream = new ProfileNoticeStream($this->profile, $this->scoped); + $stream = new ProfileNoticeStream($this->target, $this->scoped); } else { - $stream = new TaggedProfileNoticeStream($this->profile, $this->tag, $this->scoped); + $stream = new TaggedProfileNoticeStream($this->target, $this->tag, $this->scoped); } $this->notice = $stream->getNotices(($this->page-1)*NOTICES_PER_PAGE, NOTICES_PER_PAGE + 1); @@ -75,7 +73,7 @@ class ShowstreamAction extends ProfileAction function title() { - $base = $this->profile->getFancyName(); + $base = $this->target->getFancyName(); if (!empty($this->tag)) { if ($this->page == 1) { // TRANS: Page title showing tagged notices in one user's timeline. @@ -106,7 +104,7 @@ class ShowstreamAction extends ProfileAction function showProfileBlock() { - $block = new AccountProfileBlock($this, $this->profile); + $block = new AccountProfileBlock($this, $this->target); $block->show(); } @@ -120,12 +118,12 @@ class ShowstreamAction extends ProfileAction if (!empty($this->tag)) { return array(new Feed(Feed::RSS1, common_local_url('userrss', - array('nickname' => $this->target->nickname, + array('nickname' => $this->target->getNickname(), 'tag' => $this->tag)), // TRANS: Title for link to notice feed. // TRANS: %1$s is a user nickname, %2$s is a hashtag. sprintf(_('Notice feed for %1$s tagged %2$s (RSS 1.0)'), - $this->target->nickname, $this->tag))); + $this->target->getNickname(), $this->tag))); } return array(new Feed(Feed::JSON, @@ -136,14 +134,14 @@ class ShowstreamAction extends ProfileAction // TRANS: Title for link to notice feed. // TRANS: %s is a user nickname. sprintf(_('Notice feed for %s (Activity Streams JSON)'), - $this->target->nickname)), + $this->target->getNickname())), new Feed(Feed::RSS1, common_local_url('userrss', - array('nickname' => $this->target->nickname)), + array('nickname' => $this->target->getNickname())), // TRANS: Title for link to notice feed. // TRANS: %s is a user nickname. sprintf(_('Notice feed for %s (RSS 1.0)'), - $this->target->nickname)), + $this->target->getNickname())), new Feed(Feed::RSS2, common_local_url('ApiTimelineUser', array( @@ -152,7 +150,7 @@ class ShowstreamAction extends ProfileAction // TRANS: Title for link to notice feed. // TRANS: %s is a user nickname. sprintf(_('Notice feed for %s (RSS 2.0)'), - $this->target->nickname)), + $this->target->getNickname())), new Feed(Feed::ATOM, common_local_url('ApiTimelineUser', array( @@ -161,24 +159,24 @@ class ShowstreamAction extends ProfileAction // TRANS: Title for link to notice feed. // TRANS: %s is a user nickname. sprintf(_('Notice feed for %s (Atom)'), - $this->target->nickname)), + $this->target->getNickname())), new Feed(Feed::FOAF, common_local_url('foaf', array('nickname' => - $this->target->nickname)), + $this->target->getNickname())), // TRANS: Title for link to notice feed. FOAF stands for Friend of a Friend. // TRANS: More information at http://www.foaf-project.org. %s is a user nickname. - sprintf(_('FOAF for %s'), $this->target->nickname))); + sprintf(_('FOAF for %s'), $this->target->getNickname()))); } function extraHead() { - if ($this->profile->bio) { + if ($this->target->bio) { $this->element('meta', array('name' => 'description', - 'content' => $this->profile->bio)); + 'content' => $this->target->getDescription())); } - if ($this->user->emailmicroid && $this->user->email && $this->profile->profileurl) { - $id = new Microid('mailto:'.$this->user->email, + if ($this->target->isLocal() && $this->target->getUser()->emailmicroid && $this->target->getUser()->email && $this->target->getUrl()) { + $id = new Microid('mailto:'.$this->target->getUser()->email, $this->selfUrl()); $this->element('meta', array('name' => 'microid', 'content' => $id->toString())); @@ -188,10 +186,10 @@ class ShowstreamAction extends ProfileAction $this->element('link', array('rel' => 'microsummary', 'href' => common_local_url('microsummary', - array('nickname' => $this->profile->nickname)))); + array('nickname' => $this->target->getNickname())))); $rsd = common_local_url('rsd', - array('nickname' => $this->profile->nickname)); + array('nickname' => $this->target->getNickname())); // RSD, http://tales.phrasewise.com/rfc/rsd $this->element('link', array('rel' => 'EditURI', @@ -200,7 +198,7 @@ class ShowstreamAction extends ProfileAction if ($this->page != 1) { $this->element('link', array('rel' => 'canonical', - 'href' => $this->profile->profileurl)); + 'href' => $this->target->getUrl())); } } @@ -284,10 +282,9 @@ class ShowstreamAction extends ProfileAction function noticeFormOptions() { $options = parent::noticeFormOptions(); - $cur = common_current_user(); - if (empty($cur) || $cur->id != $this->profile->id) { - $options['to_profile'] = $this->profile; + if (!$this->scoped instanceof Profile || $this->scoped->id != $this->target->id) { + $options['to_profile'] = $this->target; } return $options; @@ -329,20 +326,23 @@ class ProfileNoticeListItem extends DoFollowListItem // FIXME: this code is almost identical to default; need to refactor - $attrs = array('href' => $this->profile->profileurl, - 'class' => 'url'); + $attrs = array(); + if (!empty($this->target->fullname)) { + $attrs['title'] = $this->target->getFullname(); + } - if (!empty($this->profile->fullname)) { - $attrs['title'] = $this->profile->getFancyName(); + try { + $attrs = array('href' => $this->target->getUrl(), + 'class' => 'url'); + $text_tag = 'a'; + } catch (InvalidUrlException $e) { + $text_tag = 'abbr'; } $this->out->elementStart('span', 'repeat'); - - $text_link = XMLStringer::estring('a', $attrs, $this->profile->nickname); - + $text_link = XMLStringer::estring($text_tag, $attrs, $this->target->getNickname()); // TRANS: Link to the author of a repeated notice. %s is a linked nickname. $this->out->raw(sprintf(_('Repeat of %s'), $text_link)); - $this->out->elementEnd('span'); } } diff --git a/actions/tagprofile.php b/actions/tagprofile.php index 79a401c6a9..47a66d0be4 100644 --- a/actions/tagprofile.php +++ b/actions/tagprofile.php @@ -19,8 +19,6 @@ if (!defined('GNUSOCIAL')) { exit(1); } -require_once INSTALLDIR . '/lib/peopletags.php'; - class TagprofileAction extends FormAction { var $error = null; diff --git a/lib/accountprofileblock.php b/lib/accountprofileblock.php index fe11a0fc15..875acbb59c 100644 --- a/lib/accountprofileblock.php +++ b/lib/accountprofileblock.php @@ -28,13 +28,7 @@ * @link http://status.net/ */ -if (!defined('STATUSNET')) { - // This check helps protect against security problems; - // your code file can't be executed directly from the web. - exit(1); -} - -require_once INSTALLDIR.'/lib/peopletags.php'; +if (!defined('GNUSOCIAL')) { exit(1); } /** * Profile block to show for an account diff --git a/lib/peopletags.php b/lib/peopletagswidget.php similarity index 92% rename from lib/peopletags.php rename to lib/peopletagswidget.php index 40f07c06b7..1da153c85f 100644 --- a/lib/peopletags.php +++ b/lib/peopletagswidget.php @@ -25,11 +25,7 @@ * @link http://status.net/ */ -if (!defined('STATUSNET') && !defined('LACONICA')) { - exit(1); -} - -require_once INSTALLDIR.'/lib/widget.php'; +if (!defined('GNUSOCIAL')) { exit(1); } /* * Show a bunch of peopletags @@ -178,18 +174,3 @@ class PeopletagsWidget extends Widget return !empty($this->user) && $this->tagger->id == $this->user->id; } } - -class SelftagsWidget extends PeopletagsWidget -{ - function url($tag) - { - // link to self tag page - return common_local_url('selftag', array('tag' => $tag)); - } - - function label() - { - // TRANS: Label in self tags widget. - return _m('LABEL','Tags'); - } -} diff --git a/lib/profileaction.php b/lib/profileaction.php index 83b3170bed..5923640097 100644 --- a/lib/profileaction.php +++ b/lib/profileaction.php @@ -28,12 +28,7 @@ * @link http://status.net/ */ -if (!defined('STATUSNET') && !defined('LACONICA')) { - exit(1); -} - -require_once INSTALLDIR.'/lib/profileminilist.php'; -require_once INSTALLDIR.'/lib/groupminilist.php'; +if (!defined('GNUSOCIAL')) { exit(1); } /** * Profile action common superclass @@ -46,17 +41,15 @@ require_once INSTALLDIR.'/lib/groupminilist.php'; * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ -class ProfileAction extends ManagedAction +abstract class ProfileAction extends ManagedAction { var $page = null; var $tag = null; protected $target = null; // Profile that we're showing - protected function prepare(array $args=array()) + protected function doPreparation() { - parent::prepare($args); - try { $nickname_arg = $this->arg('nickname'); $nickname = common_canonical_nickname($nickname_arg); @@ -106,7 +99,13 @@ class ProfileAction extends ManagedAction $this->tag = $this->trimmed('tag'); $this->page = ($this->arg('page')) ? ($this->arg('page')+0) : 1; common_set_returnto($this->selfUrl()); - return true; + + return $this->profileActionPreparation(); + } + + protected function profileActionPreparation() + { + // No-op by default. } function isReadOnly($args) diff --git a/lib/profilelist.php b/lib/profilelist.php index 767e12bc25..177560cdf5 100644 --- a/lib/profilelist.php +++ b/lib/profilelist.php @@ -27,11 +27,7 @@ * @link http://status.net/ */ -if (!defined('STATUSNET') && !defined('LACONICA')) { - exit(1); -} - -require_once INSTALLDIR.'/lib/peopletags.php'; +if (!defined('GNUSOCIAL')) { exit(1); } /** * Widget to show a list of profiles @@ -107,215 +103,3 @@ class ProfileList extends Widget return PROFILES_PER_PAGE; } } - -class ProfileListItem extends Widget -{ - /** Current profile. */ - var $profile = null; - /** Action object using us. */ - var $action = null; - - function __construct($profile, $action) - { - parent::__construct($action); - - $this->profile = $profile; - $this->action = $action; - } - - function show() - { - if (Event::handle('StartProfileListItem', array($this))) { - $this->startItem(); - if (Event::handle('StartProfileListItemProfile', array($this))) { - $this->showProfile(); - Event::handle('EndProfileListItemProfile', array($this)); - } - if (Event::handle('StartProfileListItemActions', array($this))) { - $this->showActions(); - Event::handle('EndProfileListItemActions', array($this)); - } - $this->endItem(); - Event::handle('EndProfileListItem', array($this)); - } - } - - function startItem() - { - $this->out->elementStart('li', array('class' => 'profile', - 'id' => 'profile-' . $this->profile->id)); - } - - function showProfile() - { - $this->startProfile(); - if (Event::handle('StartProfileListItemProfileElements', array($this))) { - if (Event::handle('StartProfileListItemAvatar', array($this))) { - $aAttrs = $this->linkAttributes(); - $this->out->elementStart('a', $aAttrs); - $this->showAvatar($this->profile); - $this->out->elementEnd('a'); - Event::handle('EndProfileListItemAvatar', array($this)); - } - if (Event::handle('StartProfileListItemNickname', array($this))) { - $this->showNickname(); - Event::handle('EndProfileListItemNickname', array($this)); - } - if (Event::handle('StartProfileListItemFullName', array($this))) { - $this->showFullName(); - Event::handle('EndProfileListItemFullName', array($this)); - } - if (Event::handle('StartProfileListItemLocation', array($this))) { - $this->showLocation(); - Event::handle('EndProfileListItemLocation', array($this)); - } - if (Event::handle('StartProfileListItemHomepage', array($this))) { - $this->showHomepage(); - Event::handle('EndProfileListItemHomepage', array($this)); - } - if (Event::handle('StartProfileListItemBio', array($this))) { - $this->showBio(); - Event::handle('EndProfileListItemBio', array($this)); - } - if (Event::handle('StartProfileListItemTags', array($this))) { - $this->showTags(); - Event::handle('EndProfileListItemTags', array($this)); - } - Event::handle('EndProfileListItemProfileElements', array($this)); - } - $this->endProfile(); - } - - function startProfile() - { - $this->out->elementStart('div', 'entity_profile h-card'); - } - - function showNickname() - { - $this->out->element('a', array('href'=>$this->profile->getUrl(), - 'class'=>'p-nickname'), - $this->profile->getNickname()); - } - - function showFullName() - { - if (!empty($this->profile->fullname)) { - $this->out->element('span', 'p-name', $this->profile->fullname); - } - } - - function showLocation() - { - if (!empty($this->profile->location)) { - $this->out->element('span', 'label p-locality', $this->profile->location); - } - } - - function showHomepage() - { - if (!empty($this->profile->homepage)) { - $this->out->text(' '); - $aAttrs = $this->homepageAttributes(); - $this->out->elementStart('a', $aAttrs); - $this->out->raw($this->highlight($this->profile->homepage)); - $this->out->elementEnd('a'); - } - } - - function showBio() - { - if (!empty($this->profile->bio)) { - $this->out->elementStart('p', 'note'); - $this->out->raw($this->highlight($this->profile->bio)); - $this->out->elementEnd('p'); - } - } - - function showTags() - { - $user = common_current_user(); - if (!empty($user)) { - if ($user->id == $this->profile->id) { - $tags = new SelftagsWidget($this->out, $user, $this->profile); - $tags->show(); - } else if ($user->getProfile()->canTag($this->profile)) { - $tags = new PeopletagsWidget($this->out, $user, $this->profile); - $tags->show(); - } - } - } - - function endProfile() - { - $this->out->elementEnd('div'); - } - - function showActions() - { - $this->startActions(); - if (Event::handle('StartProfileListItemActionElements', array($this))) { - $this->showSubscribeButton(); - Event::handle('EndProfileListItemActionElements', array($this)); - } - $this->endActions(); - } - - function startActions() - { - $this->out->elementStart('div', 'entity_actions'); - $this->out->elementStart('ul'); - } - - function showSubscribeButton() - { - // Is this a logged-in user, looking at someone else's - // profile? - - $user = common_current_user(); - - if (!empty($user) && $this->profile->id != $user->id) { - $this->out->elementStart('li', 'entity_subscribe'); - if ($user->isSubscribed($this->profile)) { - $usf = new UnsubscribeForm($this->out, $this->profile); - $usf->show(); - } else { - if (Event::handle('StartShowProfileListSubscribeButton', array($this))) { - $sf = new SubscribeForm($this->out, $this->profile); - $sf->show(); - Event::handle('EndShowProfileListSubscribeButton', array($this)); - } - } - $this->out->elementEnd('li'); - } - } - - function endActions() - { - $this->out->elementEnd('ul'); - $this->out->elementEnd('div'); - } - - function endItem() - { - $this->out->elementEnd('li'); - } - - function highlight($text) - { - return htmlspecialchars($text); - } - - function linkAttributes() - { - return array('href' => $this->profile->profileurl, - 'class' => 'u-url', - 'rel' => 'contact'); - } - - function homepageAttributes() - { - return array('href' => $this->profile->homepage, - 'class' => 'u-url'); - } -} diff --git a/lib/profilelistitem.php b/lib/profilelistitem.php new file mode 100644 index 0000000000..e0b94ac76a --- /dev/null +++ b/lib/profilelistitem.php @@ -0,0 +1,242 @@ +. + * + * @category Public + * @package StatusNet + * @author Evan Prodromou + * @copyright 2008-2009 StatusNet, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + */ + +if (!defined('GNUSOCIAL')) { exit(1); } + +class ProfileListItem extends Widget +{ + /** Current profile. */ + var $profile = null; + /** Action object using us. */ + var $action = null; + + function __construct($profile, $action) + { + parent::__construct($action); + + $this->profile = $profile; + $this->action = $action; + } + + function show() + { + if (Event::handle('StartProfileListItem', array($this))) { + $this->startItem(); + if (Event::handle('StartProfileListItemProfile', array($this))) { + $this->showProfile(); + Event::handle('EndProfileListItemProfile', array($this)); + } + if (Event::handle('StartProfileListItemActions', array($this))) { + $this->showActions(); + Event::handle('EndProfileListItemActions', array($this)); + } + $this->endItem(); + Event::handle('EndProfileListItem', array($this)); + } + } + + function startItem() + { + $this->out->elementStart('li', array('class' => 'profile', + 'id' => 'profile-' . $this->profile->id)); + } + + function showProfile() + { + $this->startProfile(); + if (Event::handle('StartProfileListItemProfileElements', array($this))) { + if (Event::handle('StartProfileListItemAvatar', array($this))) { + $aAttrs = $this->linkAttributes(); + $this->out->elementStart('a', $aAttrs); + $this->showAvatar($this->profile); + $this->out->elementEnd('a'); + Event::handle('EndProfileListItemAvatar', array($this)); + } + if (Event::handle('StartProfileListItemNickname', array($this))) { + $this->showNickname(); + Event::handle('EndProfileListItemNickname', array($this)); + } + if (Event::handle('StartProfileListItemFullName', array($this))) { + $this->showFullName(); + Event::handle('EndProfileListItemFullName', array($this)); + } + if (Event::handle('StartProfileListItemLocation', array($this))) { + $this->showLocation(); + Event::handle('EndProfileListItemLocation', array($this)); + } + if (Event::handle('StartProfileListItemHomepage', array($this))) { + $this->showHomepage(); + Event::handle('EndProfileListItemHomepage', array($this)); + } + if (Event::handle('StartProfileListItemBio', array($this))) { + $this->showBio(); + Event::handle('EndProfileListItemBio', array($this)); + } + if (Event::handle('StartProfileListItemTags', array($this))) { + $this->showTags(); + Event::handle('EndProfileListItemTags', array($this)); + } + Event::handle('EndProfileListItemProfileElements', array($this)); + } + $this->endProfile(); + } + + function startProfile() + { + $this->out->elementStart('div', 'entity_profile h-card'); + } + + function showNickname() + { + $this->out->element('a', array('href'=>$this->profile->getUrl(), + 'class'=>'p-nickname'), + $this->profile->getNickname()); + } + + function showFullName() + { + if (!empty($this->profile->fullname)) { + $this->out->element('span', 'p-name', $this->profile->fullname); + } + } + + function showLocation() + { + if (!empty($this->profile->location)) { + $this->out->element('span', 'label p-locality', $this->profile->location); + } + } + + function showHomepage() + { + if (!empty($this->profile->homepage)) { + $this->out->text(' '); + $aAttrs = $this->homepageAttributes(); + $this->out->elementStart('a', $aAttrs); + $this->out->raw($this->highlight($this->profile->homepage)); + $this->out->elementEnd('a'); + } + } + + function showBio() + { + if (!empty($this->profile->bio)) { + $this->out->elementStart('p', 'note'); + $this->out->raw($this->highlight($this->profile->bio)); + $this->out->elementEnd('p'); + } + } + + function showTags() + { + $user = common_current_user(); + if (!empty($user)) { + if ($user->id == $this->profile->id) { + $tags = new SelftagsWidget($this->out, $user, $this->profile); + $tags->show(); + } else if ($user->getProfile()->canTag($this->profile)) { + $tags = new PeopletagsWidget($this->out, $user, $this->profile); + $tags->show(); + } + } + } + + function endProfile() + { + $this->out->elementEnd('div'); + } + + function showActions() + { + $this->startActions(); + if (Event::handle('StartProfileListItemActionElements', array($this))) { + $this->showSubscribeButton(); + Event::handle('EndProfileListItemActionElements', array($this)); + } + $this->endActions(); + } + + function startActions() + { + $this->out->elementStart('div', 'entity_actions'); + $this->out->elementStart('ul'); + } + + function showSubscribeButton() + { + // Is this a logged-in user, looking at someone else's + // profile? + + $user = common_current_user(); + + if (!empty($user) && $this->profile->id != $user->id) { + $this->out->elementStart('li', 'entity_subscribe'); + if ($user->isSubscribed($this->profile)) { + $usf = new UnsubscribeForm($this->out, $this->profile); + $usf->show(); + } else { + if (Event::handle('StartShowProfileListSubscribeButton', array($this))) { + $sf = new SubscribeForm($this->out, $this->profile); + $sf->show(); + Event::handle('EndShowProfileListSubscribeButton', array($this)); + } + } + $this->out->elementEnd('li'); + } + } + + function endActions() + { + $this->out->elementEnd('ul'); + $this->out->elementEnd('div'); + } + + function endItem() + { + $this->out->elementEnd('li'); + } + + function highlight($text) + { + return htmlspecialchars($text); + } + + function linkAttributes() + { + return array('href' => $this->profile->profileurl, + 'class' => 'u-url', + 'rel' => 'contact'); + } + + function homepageAttributes() + { + return array('href' => $this->profile->homepage, + 'class' => 'u-url'); + } +} diff --git a/lib/profileminilist.php b/lib/profileminilist.php index 33624a3c70..4f47487220 100644 --- a/lib/profileminilist.php +++ b/lib/profileminilist.php @@ -27,11 +27,7 @@ * @link http://status.net/ */ -if (!defined('STATUSNET') && !defined('LACONICA')) { - exit(1); -} - -require_once INSTALLDIR.'/lib/profilelist.php'; +if (!defined('GNUSOCIAL')) { exit(1); } define('PROFILES_PER_MINILIST', 8); @@ -69,39 +65,3 @@ class ProfileMiniList extends ProfileList return AVATAR_MINI_SIZE; } } - -class ProfileMiniListItem extends ProfileListItem -{ - function show() - { - $this->out->elementStart('li', 'h-card'); - if (Event::handle('StartProfileListItemProfileElements', array($this))) { - if (Event::handle('StartProfileListItemAvatar', array($this))) { - $aAttrs = $this->linkAttributes(); - $this->out->elementStart('a', $aAttrs); - $avatarUrl = $this->profile->avatarUrl(AVATAR_MINI_SIZE); - $this->out->element('img', array('src' => $avatarUrl, - 'width' => AVATAR_MINI_SIZE, - 'height' => AVATAR_MINI_SIZE, - 'class' => 'avatar u-photo', - 'alt' => $this->profile->getBestName())); - $this->out->elementEnd('a'); - Event::handle('EndProfileListItemAvatar', array($this)); - } - $this->out->elementEnd('li'); - } - } - - // default; overridden for nofollow lists - - function linkAttributes() - { - $aAttrs = parent::linkAttributes(); - - $aAttrs['title'] = $this->profile->getBestName(); - $aAttrs['rel'] = 'contact member'; // @todo: member? always? - $aAttrs['class'] = 'u-url p-name'; - - return $aAttrs; - } -} diff --git a/lib/profileminilistitem.php b/lib/profileminilistitem.php new file mode 100644 index 0000000000..c0121262eb --- /dev/null +++ b/lib/profileminilistitem.php @@ -0,0 +1,76 @@ +. + * + * @category Public + * @package StatusNet + * @author Evan Prodromou + * @copyright 2008-2009 StatusNet, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + */ + +if (!defined('GNUSOCIAL')) { exit(1); } + +/** + * Widget to show a list of profiles, good for sidebar + * + * @category Public + * @package StatusNet + * @author Evan Prodromou + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + */ + +class ProfileMiniListItem extends ProfileListItem +{ + function show() + { + $this->out->elementStart('li', 'h-card'); + if (Event::handle('StartProfileListItemProfileElements', array($this))) { + if (Event::handle('StartProfileListItemAvatar', array($this))) { + $aAttrs = $this->linkAttributes(); + $this->out->elementStart('a', $aAttrs); + $avatarUrl = $this->profile->avatarUrl(AVATAR_MINI_SIZE); + $this->out->element('img', array('src' => $avatarUrl, + 'width' => AVATAR_MINI_SIZE, + 'height' => AVATAR_MINI_SIZE, + 'class' => 'avatar u-photo', + 'alt' => $this->profile->getBestName())); + $this->out->elementEnd('a'); + Event::handle('EndProfileListItemAvatar', array($this)); + } + $this->out->elementEnd('li'); + } + } + + // default; overridden for nofollow lists + + function linkAttributes() + { + $aAttrs = parent::linkAttributes(); + + $aAttrs['title'] = $this->profile->getBestName(); + $aAttrs['rel'] = 'contact member'; // @todo: member? always? + $aAttrs['class'] = 'u-url p-name'; + + return $aAttrs; + } +} diff --git a/lib/selftagswidget.php b/lib/selftagswidget.php new file mode 100644 index 0000000000..e2530769df --- /dev/null +++ b/lib/selftagswidget.php @@ -0,0 +1,43 @@ +. + * + * @category Action + * @package StatusNet + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + */ + +if (!defined('GNUSOCIAL')) { exit(1); } + +class SelftagsWidget extends PeopletagsWidget +{ + function url($tag) + { + // link to self tag page + return common_local_url('selftag', array('tag' => $tag)); + } + + function label() + { + // TRANS: Label in self tags widget. + return _m('LABEL','Tags'); + } +} From 7e2caa0bb1982448c7050c76b85a0c4726664806 Mon Sep 17 00:00:00 2001 From: Mikael Nordfeldth Date: Wed, 22 Apr 2015 22:13:55 +0200 Subject: [PATCH 16/24] Make it easier to hide attachments list header --- lib/inlineattachmentlist.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/inlineattachmentlist.php b/lib/inlineattachmentlist.php index 9016daf3f1..410b3b838d 100644 --- a/lib/inlineattachmentlist.php +++ b/lib/inlineattachmentlist.php @@ -35,7 +35,7 @@ class InlineAttachmentList extends AttachmentList { function showListStart() { - $this->out->element('h3', null, _('Attachments')); + $this->out->element('h3', 'attachments-title', _('Attachments')); parent::showListStart(); } From 6d72800098867bd6f52cbea39140abdf93d3c6dd Mon Sep 17 00:00:00 2001 From: Mikael Nordfeldth Date: Sun, 3 May 2015 22:50:44 +0200 Subject: [PATCH 17/24] StrictTransportSecurity syntax fix --- .../StrictTransportSecurityPlugin.php | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/plugins/StrictTransportSecurity/StrictTransportSecurityPlugin.php b/plugins/StrictTransportSecurity/StrictTransportSecurityPlugin.php index 682b10cad2..91747f1543 100644 --- a/plugins/StrictTransportSecurity/StrictTransportSecurityPlugin.php +++ b/plugins/StrictTransportSecurity/StrictTransportSecurityPlugin.php @@ -27,9 +27,7 @@ * @link http://status.net/ */ -if (!defined('STATUSNET') && !defined('LACONICA')) { - exit(1); -} +if (!defined('GNUSOCIAL')) { exit(1); } class StrictTransportSecurityPlugin extends Plugin { @@ -45,7 +43,8 @@ class StrictTransportSecurityPlugin extends Plugin { $path = common_config('site', 'path'); if(common_config('site', 'ssl') == 'always' && ($path == '/' || ! $path )) { - header('Strict-Transport-Security: max-age=' . $this->max_age . + ($this->includeSubDomains?'; includeSubDomains':'')); + header('Strict-Transport-Security: max-age=' . $this->max_age + . ($this->includeSubDomains ? '; includeSubDomains' : '')); } } From cd42ee7e85053bd3a2a2f364e4d2dbd84724f5b1 Mon Sep 17 00:00:00 2001 From: Mikael Nordfeldth Date: Sun, 3 May 2015 23:05:47 +0200 Subject: [PATCH 18/24] Allow adding preload token to HSTS header Use by adding this to config.php: addPlugin('StrictTransportSecurity', array('preloadToken'=>true)); --- .../StrictTransportSecurity/StrictTransportSecurityPlugin.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/plugins/StrictTransportSecurity/StrictTransportSecurityPlugin.php b/plugins/StrictTransportSecurity/StrictTransportSecurityPlugin.php index 91747f1543..675642135c 100644 --- a/plugins/StrictTransportSecurity/StrictTransportSecurityPlugin.php +++ b/plugins/StrictTransportSecurity/StrictTransportSecurityPlugin.php @@ -33,6 +33,7 @@ class StrictTransportSecurityPlugin extends Plugin { public $max_age = 15552000; public $includeSubDomains = false; + public $preloadToken = false; function __construct() { @@ -44,7 +45,8 @@ class StrictTransportSecurityPlugin extends Plugin $path = common_config('site', 'path'); if(common_config('site', 'ssl') == 'always' && ($path == '/' || ! $path )) { header('Strict-Transport-Security: max-age=' . $this->max_age - . ($this->includeSubDomains ? '; includeSubDomains' : '')); + . ($this->includeSubDomains ? '; includeSubDomains' : '') + . ($this->preloadToken ? '; preload' : '')); } } From e1822c2b66f9d7f071a31d90253fb4a7e463b651 Mon Sep 17 00:00:00 2001 From: Mikael Nordfeldth Date: Sun, 3 May 2015 23:07:31 +0200 Subject: [PATCH 19/24] schemacheck hint in newly installed config.php --- lib/installer.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/installer.php b/lib/installer.php index 9e2936ca82..eb7c5c8690 100644 --- a/lib/installer.php +++ b/lib/installer.php @@ -424,7 +424,11 @@ abstract class Installer // database "\$config['db']['database'] = {$vals['db_database']};\n\n". ($this->db['type'] == 'pgsql' ? "\$config['db']['quote_identifiers'] = true;\n\n":''). - "\$config['db']['type'] = {$vals['db_type']};\n\n"; + "\$config['db']['type'] = {$vals['db_type']};\n\n". + + "// Uncomment below for better performance. Just remember you must run\n". + "// php scripts/checkschema.php whenever your enabled plugins change!\n". + "//\$config['db']['schemacheck'] = 'script';\n\n"; // Normalize line endings for Windows servers $cfg = str_replace("\n", PHP_EOL, $cfg); From d010c5a5818a42610beb46faf93c83b4d1e25f2e Mon Sep 17 00:00:00 2001 From: Mikael Nordfeldth Date: Sat, 9 May 2015 15:53:57 +0200 Subject: [PATCH 20/24] magnet URL linkify support --- classes/File_redirection.php | 1 + lib/util.php | 1 + 2 files changed, 2 insertions(+) diff --git a/classes/File_redirection.php b/classes/File_redirection.php index 8c64c58a80..12619b0394 100644 --- a/classes/File_redirection.php +++ b/classes/File_redirection.php @@ -322,6 +322,7 @@ class File_redirection extends Managed_DataObject break; case 'mailto': + case 'magnet': case 'aim': case 'jabber': case 'xmpp': diff --git a/lib/util.php b/lib/util.php index 14cfd96ee1..dbc036c461 100644 --- a/lib/util.php +++ b/lib/util.php @@ -896,6 +896,7 @@ function common_replace_urls_callback($text, $callback, $arg = null) { ')'. ')'. ')'. + '|(?:(?:magnet):)'. // URLs without domain name '|(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)'. //IPv4 '|(?:'. //IPv6 '\[?(?:(?:(?:[0-9A-Fa-f]{1,4}:){7}(?:(?:[0-9A-Fa-f]{1,4})|:))|(?:(?:[0-9A-Fa-f]{1,4}:){6}(?::|(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})|(?::[0-9A-Fa-f]{1,4})))|(?:(?:[0-9A-Fa-f]{1,4}:){5}(?:(?::(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|(?:(?::[0-9A-Fa-f]{1,4}){1,2})))|(?:(?:[0-9A-Fa-f]{1,4}:){4}(?::[0-9A-Fa-f]{1,4}){0,1}(?:(?::(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|(?:(?::[0-9A-Fa-f]{1,4}){1,2})))|(?:(?:[0-9A-Fa-f]{1,4}:){3}(?::[0-9A-Fa-f]{1,4}){0,2}(?:(?::(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|(?:(?::[0-9A-Fa-f]{1,4}){1,2})))|(?:(?:[0-9A-Fa-f]{1,4}:){2}(?::[0-9A-Fa-f]{1,4}){0,3}(?:(?::(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|(?:(?::[0-9A-Fa-f]{1,4}){1,2})))|(?:(?:[0-9A-Fa-f]{1,4}:)(?::[0-9A-Fa-f]{1,4}){0,4}(?:(?::(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|(?:(?::[0-9A-Fa-f]{1,4}){1,2})))|(?::(?::[0-9A-Fa-f]{1,4}){0,5}(?:(?::(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|(?:(?::[0-9A-Fa-f]{1,4}){1,2})))|(?:(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})))\]?(? Date: Sun, 10 May 2015 19:41:36 +0200 Subject: [PATCH 21/24] More automated htaccess.sample --- htaccess.sample | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/htaccess.sample b/htaccess.sample index f7513cc0c7..af6e19784d 100644 --- a/htaccess.sample +++ b/htaccess.sample @@ -45,9 +45,11 @@ - # For mod_access_compat in Apache <2.4 - #Order allow,deny - - # Use this instead for Apache >2.4 (mod_authz_host) - # Require all denied + + Order allow,deny + Deny from all + + = 2.3> + Require all denied + From bb8d377b91c959d89e9b8099a97962d5c777f61d Mon Sep 17 00:00:00 2001 From: Mikael Nordfeldth Date: Tue, 26 May 2015 13:10:37 +0200 Subject: [PATCH 22/24] Redirect to group URL for /nickname pattern --- lib/profileaction.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/profileaction.php b/lib/profileaction.php index 5923640097..bd5bb5a148 100644 --- a/lib/profileaction.php +++ b/lib/profileaction.php @@ -66,6 +66,10 @@ abstract class ProfileAction extends ManagedAction $this->user = User::getKV('nickname', $nickname); if (!$this->user) { + $group = Local_group::getKV('nickname', $nickname); + if ($group instanceof Local_group) { + common_redirect($group->getProfile()->getUrl()); + } // TRANS: Client error displayed when calling a profile action without specifying a user. $this->clientError(_('No such user.'), 404); } From 925aacec1a09ade8acaaca2c604e33d17292fe40 Mon Sep 17 00:00:00 2001 From: Mikael Nordfeldth Date: Tue, 26 May 2015 13:11:08 +0200 Subject: [PATCH 23/24] Throw exception when a Conversation is not found --- classes/Conversation.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/classes/Conversation.php b/classes/Conversation.php index 343668cc49..537c214a4c 100644 --- a/classes/Conversation.php +++ b/classes/Conversation.php @@ -108,7 +108,13 @@ class Conversation extends Managed_DataObject static public function getUrlFromNotice(Notice $notice, $anchor=true) { - $conv = self::getKV('id', $notice->conversation); + $conv = new Conversation(); + $conv->id = $notice->conversation; + $conv->find(true); + if (!$conv instanceof Conversation) { + common_debug('Conversation does not exist for notice ID: '.$notice->id); + throw new NoResultException($conv); + } return $conv->getUrl($anchor ? $notice->id : null); } From 6b717a6a6917bd024431f8d1e0835325e0194421 Mon Sep 17 00:00:00 2001 From: Mikael Nordfeldth Date: Tue, 26 May 2015 13:14:26 +0200 Subject: [PATCH 24/24] Throw exception if Local_group has no corresponding User_group --- classes/Local_group.php | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/classes/Local_group.php b/classes/Local_group.php index c0dcf02e4b..9e95102d85 100644 --- a/classes/Local_group.php +++ b/classes/Local_group.php @@ -40,16 +40,19 @@ class Local_group extends Managed_DataObject public function getProfile() { - $group = $this->getGroup(); - if (!$group instanceof User_group) { - return null; // TODO: Throw exception when other code is ready - } - return $group->getProfile(); + return $this->getGroup()->getProfile(); } public function getGroup() { - return User_group::getKV('id', $this->group_id); + $group = new User_group(); + $group->id = $this->group_id; + $group->find(true); + if (!$group instanceof User_group) { + common_log(LOG_ERR, 'User_group does not exist for Local_group: '.$this->group_id); + throw new NoResultException($group); + } + return $group; } function setNickname($nickname)