From a515c3ce530aba411e0d8f90de071ede90318142 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Tue, 23 Jun 2009 10:43:50 -0700 Subject: [PATCH 01/49] other base directories --- scripts/setup.cfg.sample | 2 ++ scripts/setup_status_network.sh | 6 ++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/scripts/setup.cfg.sample b/scripts/setup.cfg.sample index dd3c2705fc..ef33cd6327 100644 --- a/scripts/setup.cfg.sample +++ b/scripts/setup.cfg.sample @@ -9,5 +9,7 @@ export ADMIN=root export ADMINPASS=yourpassword export SITEDB=example_net_site export AVATARBASE=/var/www/avatar.example.net +export BACKGROUNDBASE=/var/www/background.example.net +export FILEBASE=/var/www/file.example.net export PWDGEN="pwgen 20" diff --git a/scripts/setup_status_network.sh b/scripts/setup_status_network.sh index 29ee010ed9..f0bb2cae8d 100755 --- a/scripts/setup_status_network.sh +++ b/scripts/setup_status_network.sh @@ -26,5 +26,7 @@ VALUES ('$nickname', '$DBHOST', '$username', '$password', '$database', '$sitenam ENDOFCOMMANDS -mkdir $AVATARBASE/$nickname -chmod a+w $AVATARBASE/$nickname +for top in $AVATARBASE $FILEBASE $BACKGROUNDBASE; do + mkdir $top/$nickname + chmod a+w $top/$nickname +done From e22f73c72bc08aac15ae3eae66ffbb0987d6883e Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Tue, 23 Jun 2009 11:14:51 -0700 Subject: [PATCH 02/49] use /etc/laconica/setup.cfg instead of local file --- scripts/setup_status_network.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/setup_status_network.sh b/scripts/setup_status_network.sh index f0bb2cae8d..0261a7f559 100755 --- a/scripts/setup_status_network.sh +++ b/scripts/setup_status_network.sh @@ -1,6 +1,6 @@ #!/bin/bash -source ./setup.cfg +source /etc/laconica/setup.cfg export nickname=$1 export sitename=$2 From a4402eedb32d0933b11070a1f6f681d020ab270f Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Tue, 23 Jun 2009 11:22:54 -0700 Subject: [PATCH 03/49] use different name for connection and database --- scripts/setup.cfg.sample | 5 ++--- scripts/setup_status_network.sh | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/scripts/setup.cfg.sample b/scripts/setup.cfg.sample index ef33cd6327..8d03b06f5e 100644 --- a/scripts/setup.cfg.sample +++ b/scripts/setup.cfg.sample @@ -1,8 +1,7 @@ # CONFIGURATION FILE for setup_status_network.sh -# Base database name; full name will include nickname - -export DBHOST=masterdb.example.net +export DBHOST=localhost +export DBHOSTNAME=masterdb.example.net export DBBASE=_example_net export USERBASE=_example_net export ADMIN=root diff --git a/scripts/setup_status_network.sh b/scripts/setup_status_network.sh index 0261a7f559..17440640e4 100755 --- a/scripts/setup_status_network.sh +++ b/scripts/setup_status_network.sh @@ -22,7 +22,7 @@ mysql -h $DBHOST -u $ADMIN --password=$ADMINPASS $SITEDB << ENDOFCOMMANDS GRANT INSERT,SELECT,UPDATE,DELETE ON $database.* TO '$username'@'localhost' IDENTIFIED BY '$password'; GRANT INSERT,SELECT,UPDATE,DELETE ON $database.* TO '$username'@'%' IDENTIFIED BY '$password'; INSERT INTO status_network (nickname, dbhost, dbuser, dbpass, dbname, sitename, created) -VALUES ('$nickname', '$DBHOST', '$username', '$password', '$database', '$sitename', now()); +VALUES ('$nickname', '$DBHOSTNAME', '$username', '$password', '$database', '$sitename', now()); ENDOFCOMMANDS From 17319ac5ca01f2780c4deb63d37654543da3c996 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Tue, 23 Jun 2009 11:32:35 -0700 Subject: [PATCH 04/49] script to show all sites on a network --- scripts/allsites.php | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 scripts/allsites.php diff --git a/scripts/allsites.php b/scripts/allsites.php new file mode 100644 index 0000000000..d6768c2785 --- /dev/null +++ b/scripts/allsites.php @@ -0,0 +1,40 @@ +#!/usr/bin/env php +. + */ + +# Abort if called from a web server + +define('INSTALLDIR', realpath(dirname(__FILE__) . '/..')); + +$helptext = <<find()) { + while ($sn->fetch()) { + print "$sn->nickname\n"; + } +} \ No newline at end of file From ec4192edcd72e0bd0f2330a8d69b0d138a37f1f4 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Tue, 23 Jun 2009 11:34:16 -0700 Subject: [PATCH 05/49] chmod allsites.php --- scripts/allsites.php | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 scripts/allsites.php diff --git a/scripts/allsites.php b/scripts/allsites.php old mode 100644 new mode 100755 From 83b5e6be0244e8b8c971bcc11103c2e32b54efd6 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Tue, 23 Jun 2009 11:40:23 -0700 Subject: [PATCH 06/49] script to delete a status network --- scripts/delete_status_network.sh | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 scripts/delete_status_network.sh diff --git a/scripts/delete_status_network.sh b/scripts/delete_status_network.sh new file mode 100644 index 0000000000..1cf716849e --- /dev/null +++ b/scripts/delete_status_network.sh @@ -0,0 +1,21 @@ +#!/bin/bash + +source /etc/laconica/setup.cfg + +export nickname=$1 + +export database=$nickname$DBBASE + +# Create the db + +mysqladmin -h $DBHOST -u $ADMIN --password=$ADMINPASS -f drop $database + +mysql -h $DBHOST -u $ADMIN --password=$ADMINPASS $SITEDB << ENDOFCOMMANDS + +delete from status_network where nickname = '$nickname'; + +ENDOFCOMMANDS + +for top in $AVATARBASE $FILEBASE $BACKGROUNDBASE; do + rmdir $top/$nickname +done From 0032fa28f030616a345a2cdbc822235c381f2c12 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Tue, 23 Jun 2009 11:43:20 -0700 Subject: [PATCH 07/49] rm -Rf, not rmdir --- scripts/delete_status_network.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/delete_status_network.sh b/scripts/delete_status_network.sh index 1cf716849e..32187382cd 100644 --- a/scripts/delete_status_network.sh +++ b/scripts/delete_status_network.sh @@ -17,5 +17,5 @@ delete from status_network where nickname = '$nickname'; ENDOFCOMMANDS for top in $AVATARBASE $FILEBASE $BACKGROUNDBASE; do - rmdir $top/$nickname + rm -Rf $top/$nickname done From 9505ef5bb39875f6090c8ed572391cff415531fd Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Tue, 23 Jun 2009 11:45:18 -0700 Subject: [PATCH 08/49] chmod +x delete_status_network.sh --- scripts/delete_status_network.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 scripts/delete_status_network.sh diff --git a/scripts/delete_status_network.sh b/scripts/delete_status_network.sh old mode 100644 new mode 100755 From 31325f0995bb61413b07f166d253b13fb27d085d Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Tue, 23 Jun 2009 13:51:23 -0700 Subject: [PATCH 09/49] Stop Twitter gateway notices from leaking via user faves pages --- actions/showfavorites.php | 17 ++++++++++++--- classes/Fave.php | 44 ++++++++++++++++++++++++--------------- classes/Notice.php | 2 ++ classes/User.php | 4 ++-- 4 files changed, 45 insertions(+), 22 deletions(-) diff --git a/actions/showfavorites.php b/actions/showfavorites.php index 01f38a8927..b723924a5e 100644 --- a/actions/showfavorites.php +++ b/actions/showfavorites.php @@ -191,10 +191,21 @@ class ShowfavoritesAction extends CurrentUserDesignAction function showContent() { - $notice = $this->user->favoriteNotices(($this->page-1)*NOTICES_PER_PAGE, - NOTICES_PER_PAGE + 1); + $cur = common_current_user(); - if (!$notice) { + if (!empty($cur) && $cur->id == $this->user->id) { + + // Show imported/gateway notices as well as local if + // the user is looking at his own favorites + + $notice = $this->user->favoriteNotices(($this->page-1)*NOTICES_PER_PAGE, + NOTICES_PER_PAGE + 1, true); + } else { + $notice = $this->user->favoriteNotices(($this->page-1)*NOTICES_PER_PAGE, + NOTICES_PER_PAGE + 1, false); + } + + if (empty($notice)) { $this->serverError(_('Could not retrieve favorite notices.')); return; } diff --git a/classes/Fave.php b/classes/Fave.php index 572334ce4f..f4cf6256ff 100644 --- a/classes/Fave.php +++ b/classes/Fave.php @@ -37,52 +37,62 @@ class Fave extends Memcached_DataObject return Memcached_DataObject::pkeyGet('Fave', $kv); } - function stream($user_id, $offset=0, $limit=NOTICES_PER_PAGE) + function stream($user_id, $offset=0, $limit=NOTICES_PER_PAGE, $own=false) { $ids = Notice::stream(array('Fave', '_streamDirect'), - array($user_id), - 'fave:ids_by_user:'.$user_id, + array($user_id, $own), + ($own) ? 'fave:ids_by_user_own:'.$user_id : + 'fave:by_user:'.$user_id, $offset, $limit); return $ids; } - function _streamDirect($user_id, $offset, $limit, $since_id, $max_id, $since) + function _streamDirect($user_id, $own, $offset, $limit, $since_id, $max_id, $since) { $fav = new Fave(); + $qry = null; - $fav->user_id = $user_id; - - $fav->selectAdd(); - $fav->selectAdd('notice_id'); + if ($own) { + $qry = 'SELECT fave.* FROM fave '; + $qry .= 'WHERE fave.user_id = ' . $user_id . ' '; + } else { + $qry = 'SELECT fave.* FROM fave '; + $qry .= 'INNER JOIN notice ON fave.notice_id = notice.id '; + $qry .= 'WHERE fave.user_id = ' . $user_id . ' '; + $qry .= 'AND notice.is_local != ' . NOTICE_GATEWAY . ' '; + } if ($since_id != 0) { - $fav->whereAdd('notice_id > ' . $since_id); + $qry .= 'AND notice_id > ' . $since_id . ' '; } if ($max_id != 0) { - $fav->whereAdd('notice_id <= ' . $max_id); + $qry .= 'AND notice_id <= ' . $max_id . ' '; } if (!is_null($since)) { - $fav->whereAdd('modified > \'' . date('Y-m-d H:i:s', $since) . '\''); + $qry .= 'AND modified > \'' . date('Y-m-d H:i:s', $since) . '\' '; } // NOTE: we sort by fave time, not by notice time! - $fav->orderBy('modified DESC'); + $qry .= 'ORDER BY modified DESC '; if (!is_null($offset)) { - $fav->limit($offset, $limit); + $qry .= "LIMIT $offset, $limit"; } + $fav->query($qry); + $ids = array(); - if ($fav->find()) { - while ($fav->fetch()) { - $ids[] = $fav->notice_id; - } + while ($fav->fetch()) { + $ids[] = $fav->notice_id; } + $fav->free(); + unset($fav); + return $ids; } } diff --git a/classes/Notice.php b/classes/Notice.php index b6bbf66cac..6f9b73be4b 100644 --- a/classes/Notice.php +++ b/classes/Notice.php @@ -471,8 +471,10 @@ class Notice extends Memcached_DataObject if ($fave->find()) { while ($fave->fetch()) { $cache->delete(common_cache_key('fave:ids_by_user:'.$fave->user_id)); + $cache->delete(common_cache_key('fave:by_user_own:'.$fave->user_id)); if ($blowLast) { $cache->delete(common_cache_key('fave:ids_by_user:'.$fave->user_id.';last')); + $cache->delete(common_cache_key('fave:by_user_own:'.$fave->user_id.';last')); } } } diff --git a/classes/User.php b/classes/User.php index e8c8c5a75b..a01a3106f2 100644 --- a/classes/User.php +++ b/classes/User.php @@ -424,9 +424,9 @@ class User extends Memcached_DataObject } } - function favoriteNotices($offset=0, $limit=NOTICES_PER_PAGE) + function favoriteNotices($offset=0, $limit=NOTICES_PER_PAGE, $own=false) { - $ids = Fave::stream($this->id, $offset, $limit); + $ids = Fave::stream($this->id, $offset, $limit, $own); return Notice::getStreamByIds($ids); } From 3cfa2ebb05e131be3a85d9af7a14ed9466b291cb Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Tue, 23 Jun 2009 21:18:41 +0000 Subject: [PATCH 10/49] Updated default colour theme and IE6 colours for transparent values --- theme/default/css/display.css | 24 ++++++++++++------------ theme/default/css/ie.css | 6 +++--- theme/identica/css/ie.css | 6 +++--- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/theme/default/css/display.css b/theme/default/css/display.css index 7e8b84b4cc..f592e930f0 100644 --- a/theme/default/css/display.css +++ b/theme/default/css/display.css @@ -11,7 +11,7 @@ body, a:active { -background-color:#C3D6DF; +background-color:#CEE1E9; } body { font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif; @@ -29,7 +29,7 @@ input, textarea, select, border-color:#AAAAAA; } #filter_tags ul li { -border-color:#C3D6DF; +border-color:#DDDDDD; } .form_settings input.form_action-primary { @@ -40,12 +40,12 @@ input.submit, #form_notice.warning #notice_text-count, .form_settings .form_note, .entity_remote_subscribe { -background-color:#A9BF4F; +background-color:#9BB43E; } input:focus, textarea:focus, select:focus, #form_notice.warning #notice_data-text { -border-color:#A9BF4F; +border-color:#9BB43E; box-shadow:3px 3px 3px rgba(194, 194, 194, 0.3); -moz-box-shadow:3px 3px 3px rgba(194, 194, 194, 0.3); -webkit-box-shadow:3px 3px 3px rgba(194, 194, 194, 0.3); @@ -71,14 +71,14 @@ color:#002E6E; .notice, .profile { -border-top-color:#D1D9E4; +border-top-color:#C8D1D5; } .section .profile { -border-top-color:#C3D6DF; +border-top-color:#87B4C8; } #aside_primary { -background-color:#CEE1E9; +background-color:#C8D1D5; } #notice_text-count { @@ -136,13 +136,13 @@ background-color:#EFF3DC; } #anon_notice { -background-color:#C3D6DF; +background-color:#87B4C8; color:#FFFFFF; border-color:#FFFFFF; } #showstream #anon_notice { -background-color:#A9BF4F; +background-color:#9BB43E; } #export_data li a { @@ -176,13 +176,13 @@ background-color:transparent; .form_group_leave input.submit .form_user_subscribe input.submit, .form_user_unsubscribe input.submit { -background-color:#A9BF4F; +background-color:#9BB43E; color:#FFFFFF; } .form_user_unsubscribe input.submit, .form_group_leave input.submit, .form_user_authorization input.reject { -background-color:#C3D6DF; +background-color:#87B4C8; } .entity_edit a { @@ -272,7 +272,7 @@ background:transparent url(../../base/images/icons/twotone/green/news.gif) no-re .pagination .nav_prev a, .pagination .nav_next a { background-repeat:no-repeat; -border-color:#D1D9E4; +border-color:#C8D1D5; } .pagination .nav_prev a { background-image:url(../../base/images/icons/twotone/green/arrow-left.gif); diff --git a/theme/default/css/ie.css b/theme/default/css/ie.css index 6501f4e48e..cbbd49ce6c 100644 --- a/theme/default/css/ie.css +++ b/theme/default/css/ie.css @@ -1,14 +1,14 @@ /* IE specific styles */ .notice-options input.submit { -color:#fff; +color:#FFFFFF; } #site_nav_local_views a { -background-color:#ACCCDA; +background-color:#C8D1D5; } #form_notice .form_note + label { background:transparent url(../../base/images/icons/twotone/green/clip-01.gif) no-repeat 0 45%; } #form_notice #notice_data-attach { filter: alpha(opacity=0); -} \ No newline at end of file +} diff --git a/theme/identica/css/ie.css b/theme/identica/css/ie.css index 69db16aad0..97cabc30a5 100644 --- a/theme/identica/css/ie.css +++ b/theme/identica/css/ie.css @@ -1,14 +1,14 @@ /* IE specific styles */ .notice-options input.submit { -color:#fff; +color:#FFFFFF; } #site_nav_local_views a { -background-color:#D0DFE7; +background-color:#D9DADB; } #form_notice .form_note + label { background:transparent url(../../base/images/icons/twotone/green/clip-01.gif) no-repeat 0 45%; } #form_notice #notice_data-attach { filter: alpha(opacity=0); -} \ No newline at end of file +} From 2d3e990ed47ee1c7130e1febabe7133884a85c80 Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Tue, 23 Jun 2009 21:26:47 +0000 Subject: [PATCH 11/49] Using default theme design values (it was previously set to identica theme) --- lib/common.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/common.php b/lib/common.php index 76eb4a9785..8eb464d7db 100644 --- a/lib/common.php +++ b/lib/common.php @@ -95,9 +95,9 @@ $config = 'server' => $_server, 'theme' => 'default', 'design' => - array('backgroundcolor' => '#F0F2F5', + array('backgroundcolor' => '#CEE1E9', 'contentcolor' => '#FFFFFF', - 'sidebarcolor' => '#CEE1E9', + 'sidebarcolor' => '#C8D1D5', 'textcolor' => '#000000', 'linkcolor' => '#002E6E', 'backgroundimage' => null, From 8588d321201b1713a8b95704e9c6abd39eb80609 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Tue, 23 Jun 2009 15:00:10 -0700 Subject: [PATCH 12/49] pass through server and path args to daemons --- scripts/startdaemons.sh | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/scripts/startdaemons.sh b/scripts/startdaemons.sh index 053c4f8ee0..4e87694fb8 100755 --- a/scripts/startdaemons.sh +++ b/scripts/startdaemons.sh @@ -23,9 +23,19 @@ DIR=`dirname $0` DAEMONS=`php $DIR/getvaliddaemons.php` +ARGS= + +if [ $# -gt 0 ]; then + ARGS="$ARGS -s$1" +fi + +if [ $# -gt 1 ]; then + ARGS="$ARGS -p$2" +fi + for f in $DAEMONS; do echo -n "Starting $f..."; - php $DIR/$f + php $DIR/$f $ARGS echo "DONE." done From 57903bf2acafdc4d15bb9af4fba183b37ec47efe Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Tue, 23 Jun 2009 15:53:49 -0700 Subject: [PATCH 13/49] Make gateway notices available to the auth user in the API --- actions/twitapifavorites.php | 6 +++++- actions/twitapistatuses.php | 13 ++++++++++--- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/actions/twitapifavorites.php b/actions/twitapifavorites.php index e40fea91af..8256668f3d 100644 --- a/actions/twitapifavorites.php +++ b/actions/twitapifavorites.php @@ -61,7 +61,11 @@ class TwitapifavoritesAction extends TwitterapiAction $since_id = (int)$this->arg('since_id', 0); $since = $this->arg('since'); - $notice = $user->favoriteNotices(($page-1)*$count, $count); + if (!empty($this->auth_user) && $this->auth_user->id == $user->id) { + $notice = $user->favoriteNotices(($page-1)*$count, $count, true); + } else { + $notice = $user->favoriteNotices(($page-1)*$count, $count, false); + } switch($apidata['content-type']) { case 'xml': diff --git a/actions/twitapistatuses.php b/actions/twitapistatuses.php index 2bc4040638..e1fbc5c767 100644 --- a/actions/twitapistatuses.php +++ b/actions/twitapistatuses.php @@ -75,8 +75,10 @@ class TwitapistatusesAction extends TwitterapiAction { parent::handle($args); + $this->auth_user = $apidata['user']; $user = $this->get_user($apidata['api_arg'], $apidata); - $this->auth_user = $user; + + common_debug("auth user = " . $this->auth_user->nickname); if (empty($user)) { $this->clientError(_('No such user!'), 404, @@ -100,8 +102,13 @@ class TwitapistatusesAction extends TwitterapiAction $since_id = (int)$this->arg('since_id', 0); $since = $this->arg('since'); - $notice = $user->noticesWithFriends(($page-1)*$count, - $count, $since_id, $max_id,$since); + if (!empty($this->auth_user) && $this->auth_user->id == $user->id) { + $notice = $user->noticeInbox(($page-1)*$count, + $count, $since_id, $max_id, $since); + } else { + $notice = $user->noticesWithFriends(($page-1)*$count, + $count, $since_id, $max_id, $since); + } switch($apidata['content-type']) { case 'xml': From f88d767f493c5780476450d92ddb8f27a6ea6caa Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Tue, 23 Jun 2009 16:44:00 -0700 Subject: [PATCH 14/49] add args to daemons fetch --- scripts/startdaemons.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/startdaemons.sh b/scripts/startdaemons.sh index 4e87694fb8..7609abec47 100755 --- a/scripts/startdaemons.sh +++ b/scripts/startdaemons.sh @@ -20,9 +20,6 @@ # This program tries to start the daemons for Laconica. # Note that the 'maildaemon' needs to run as a mail filter. -DIR=`dirname $0` -DAEMONS=`php $DIR/getvaliddaemons.php` - ARGS= if [ $# -gt 0 ]; then @@ -33,6 +30,9 @@ if [ $# -gt 1 ]; then ARGS="$ARGS -p$2" fi +DIR=`dirname $0` +DAEMONS=`php $DIR/getvaliddaemons.php $ARGS` + for f in $DAEMONS; do echo -n "Starting $f..."; From a9bbf29ca6741437f7c27f7a7757b4969d33d279 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Tue, 23 Jun 2009 17:08:33 -0700 Subject: [PATCH 15/49] use printf instead of echo for startdaemons.sh --- scripts/startdaemons.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/scripts/startdaemons.sh b/scripts/startdaemons.sh index 7609abec47..a44362b572 100755 --- a/scripts/startdaemons.sh +++ b/scripts/startdaemons.sh @@ -35,7 +35,8 @@ DAEMONS=`php $DIR/getvaliddaemons.php $ARGS` for f in $DAEMONS; do - echo -n "Starting $f..."; + printf "Starting $f..."; php $DIR/$f $ARGS - echo "DONE." + printf "DONE.\n" + done From 98f518b9af43dd07b97373e6e71be08d553bb21b Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Wed, 24 Jun 2009 00:00:36 -0700 Subject: [PATCH 16/49] fix bug in which design background could accidentally get removed --- actions/groupdesignsettings.php | 2 -- actions/userdesignsettings.php | 2 -- 2 files changed, 4 deletions(-) diff --git a/actions/groupdesignsettings.php b/actions/groupdesignsettings.php index 7270bc8f7e..79c192ac46 100644 --- a/actions/groupdesignsettings.php +++ b/actions/groupdesignsettings.php @@ -238,7 +238,6 @@ class GroupDesignSettingsAction extends DesignSettingsAction $design->sidebarcolor = $sbcolor->intValue(); $design->textcolor = $tcolor->intValue(); $design->linkcolor = $lcolor->intValue(); - $design->backgroundimage = $filepath; $design->setDisposition($on, $off, $tile); @@ -263,7 +262,6 @@ class GroupDesignSettingsAction extends DesignSettingsAction $design->sidebarcolor = $sbcolor->intValue(); $design->textcolor = $tcolor->intValue(); $design->linkcolor = $lcolor->intValue(); - $design->backgroundimage = $filepath; $design->setDisposition($on, $off, $tile); diff --git a/actions/userdesignsettings.php b/actions/userdesignsettings.php index d6088aa9d0..6e745e96f8 100644 --- a/actions/userdesignsettings.php +++ b/actions/userdesignsettings.php @@ -149,7 +149,6 @@ class UserDesignSettingsAction extends DesignSettingsAction $design->sidebarcolor = $sbcolor->intValue(); $design->textcolor = $tcolor->intValue(); $design->linkcolor = $lcolor->intValue(); - $design->backgroundimage = $filepath; $design->setDisposition($on, $off, $tile); @@ -174,7 +173,6 @@ class UserDesignSettingsAction extends DesignSettingsAction $design->sidebarcolor = $sbcolor->intValue(); $design->textcolor = $tcolor->intValue(); $design->linkcolor = $lcolor->intValue(); - $design->backgroundimage = $filepath; $design->setDisposition($on, $off, $tile); From b702461f6942017d1ae4a08c6701998db14ce536 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Wed, 24 Jun 2009 00:27:37 -0700 Subject: [PATCH 17/49] fix bad function call (needed to be static) --- lib/imagefile.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/imagefile.php b/lib/imagefile.php index 0c93b257ed..52e4c4b227 100644 --- a/lib/imagefile.php +++ b/lib/imagefile.php @@ -72,7 +72,8 @@ class ImageFile break; case UPLOAD_ERR_INI_SIZE: case UPLOAD_ERR_FORM_SIZE: - throw new Exception(sprintf(_('That file is too big. The maximum file size is %d.'), $this->maxFileSize())); + throw new Exception(sprintf(_('That file is too big. The maximum file size is %d.'), + ImageFile::maxFileSize())); return; case UPLOAD_ERR_PARTIAL: @unlink($_FILES[$param]['tmp_name']); From d72a90161b1cb748b58454e4c885b1d789ef3eca Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Wed, 24 Jun 2009 00:43:48 -0700 Subject: [PATCH 18/49] Only show "tile background" setting once an img has been uploaded --- lib/designsettings.php | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/lib/designsettings.php b/lib/designsettings.php index 6aa6bb2f19..9650679ac5 100644 --- a/lib/designsettings.php +++ b/lib/designsettings.php @@ -132,13 +132,13 @@ class DesignSettingsAction extends AccountSettingsAction _('Off')); $this->element('p', 'form_guide', _('Turn background image on or off.')); $this->elementEnd('li'); - } - $this->elementStart('li'); - $this->checkbox('design_background-image_repeat', - _('Tile background image'), - ($design->disposition & BACKGROUND_TILE) ? true : false ); - $this->elementEnd('li'); + $this->elementStart('li'); + $this->checkbox('design_background-image_repeat', + _('Tile background image'), + ($design->disposition & BACKGROUND_TILE) ? true : false ); + $this->elementEnd('li'); + } $this->elementEnd('ul'); $this->elementEnd('fieldset'); @@ -388,7 +388,11 @@ class DesignSettingsAction extends AccountSettingsAction $original = clone($design); $design->backgroundimage = $filename; + + // default to on, no tile + $design->setDisposition(true, false, false); + $result = $design->update($original); if ($result === false) { From 83407cc3caa2de0f5fd1b60d67357e415096b6ae Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Wed, 24 Jun 2009 14:44:02 -0700 Subject: [PATCH 19/49] change foreign_user.id to bigint (for Twitter, Facebook, etc.) --- classes/Foreign_user.php | 22 ++++++++++------------ db/laconica.sql | 2 +- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/classes/Foreign_user.php b/classes/Foreign_user.php index 61727abe5e..8b3e03dfb3 100644 --- a/classes/Foreign_user.php +++ b/classes/Foreign_user.php @@ -4,42 +4,41 @@ */ require_once INSTALLDIR.'/classes/Memcached_DataObject.php'; -class Foreign_user extends Memcached_DataObject +class Foreign_user extends Memcached_DataObject { ###START_AUTOCODE /* the code below is auto generated do not remove the above tag */ public $__table = 'foreign_user'; // table name - public $id; // int(4) primary_key not_null + public $id; // bigint(8) primary_key not_null public $service; // int(4) primary_key not_null public $uri; // varchar(255) unique_key not_null - public $nickname; // varchar(255) + public $nickname; // varchar(255) public $created; // datetime() not_null public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP /* Static get */ - function staticGet($k,$v=null) - { return Memcached_DataObject::staticGet('Foreign_user',$k,$v); } + function staticGet($k,$v=NULL) { return Memcached_DataObject::staticGet('Foreign_user',$k,$v); } /* the code above is auto generated do not remove the tag below */ ###END_AUTOCODE - + // XXX: This only returns a 1->1 single obj mapping. Change? Or make // a getForeignUsers() that returns more than one? --Zach - static function getForeignUser($id, $service) { + static function getForeignUser($id, $service) { $fuser = new Foreign_user(); $fuser->whereAdd("service = $service"); $fuser->whereAdd("id = $id"); $fuser->limit(1); - + if ($fuser->find()) { $fuser->fetch(); return $fuser; } - - return null; + + return null; } - + function updateKeys(&$orig) { $parts = array(); @@ -68,5 +67,4 @@ class Foreign_user extends Memcached_DataObject return $result; } - } diff --git a/db/laconica.sql b/db/laconica.sql index 95796d5cc6..3f8918de62 100644 --- a/db/laconica.sql +++ b/db/laconica.sql @@ -277,7 +277,7 @@ create table foreign_service ( ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin; create table foreign_user ( - id int not null comment 'unique numeric key on foreign service', + id bigint not null comment 'unique numeric key on foreign service', service int not null comment 'foreign key to service' references foreign_service(id), uri varchar(255) not null unique key comment 'identifying URI', nickname varchar(255) comment 'nickname on foreign service', From 936567394ff33d47d645de8071d5c249eb62fa78 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Wed, 24 Jun 2009 14:59:36 -0700 Subject: [PATCH 20/49] script to upgrade a database from 0.7.4 to 0.8.0 --- db/074to080.sql | 109 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 db/074to080.sql diff --git a/db/074to080.sql b/db/074to080.sql new file mode 100644 index 0000000000..ff08191596 --- /dev/null +++ b/db/074to080.sql @@ -0,0 +1,109 @@ +alter table user + add column design_id integer comment 'id of a design' references design(id), + add column viewdesigns tinyint default 1 comment 'whether to view user-provided designs'; + +alter table notice add column + conversation integer comment 'id of root notice in this conversation' references notice (id), + add index notice_conversation_idx (conversation); + +alter table foreign_user + modify column id bigint not null comment 'unique numeric key on foreign service'; + +alter table foreign_link + modify column foreign_id bigint unsigned comment 'link to user on foreign service, if exists'; + +alter table user_group + add column design_id integer comment 'id of a design' references design(id); + +create table file ( + id integer primary key auto_increment, + url varchar(255) comment 'destination URL after following redirections', + mimetype varchar(50) comment 'mime type of resource', + size integer comment 'size of resource when available', + title varchar(255) comment 'title of resource when available', + date integer(11) comment 'date of resource according to http query', + protected integer(1) comment 'true when URL is private (needs login)', + filename varchar(255) comment 'if a local file, name of the file', + modified timestamp comment 'date this record was modified', + + unique(url) +) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_general_ci; + +create table file_oembed ( + file_id integer primary key comment 'oEmbed for that URL/file' references file (id), + version varchar(20) comment 'oEmbed spec. version', + type varchar(20) comment 'oEmbed type: photo, video, link, rich', + provider varchar(50) comment 'name of this oEmbed provider', + provider_url varchar(255) comment 'URL of this oEmbed provider', + width integer comment 'width of oEmbed resource when available', + height integer comment 'height of oEmbed resource when available', + html text comment 'html representation of this oEmbed resource when applicable', + title varchar(255) comment 'title of oEmbed resource when available', + author_name varchar(50) comment 'author name for this oEmbed resource', + author_url varchar(255) comment 'author URL for this oEmbed resource', + url varchar(255) comment 'URL for this oEmbed resource when applicable (photo, link)', + modified timestamp comment 'date this record was modified' + +) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_general_ci; + +create table file_redirection ( + + url varchar(255) primary key comment 'short URL (or any other kind of redirect) for file (id)', + file_id integer comment 'short URL for what URL/file' references file (id), + redirections integer comment 'redirect count', + httpcode integer comment 'HTTP status code (20x, 30x, etc.)', + modified timestamp comment 'date this record was modified' + +) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin; + +create table file_thumbnail ( + + file_id integer primary key comment 'thumbnail for what URL/file' references file (id), + url varchar(255) comment 'URL of thumbnail', + width integer comment 'width of thumbnail', + height integer comment 'height of thumbnail', + modified timestamp comment 'date this record was modified', + + unique(url) +) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin; + +create table file_to_post ( + + file_id integer comment 'id of URL/file' references file (id), + post_id integer comment 'id of the notice it belongs to' references notice (id), + modified timestamp comment 'date this record was modified', + + constraint primary key (file_id, post_id) + +) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin; + +create table design ( + id integer primary key auto_increment comment 'design ID', + backgroundcolor integer comment 'main background color', + contentcolor integer comment 'content area background color', + sidebarcolor integer comment 'sidebar background color', + textcolor integer comment 'text color', + linkcolor integer comment 'link color', + backgroundimage varchar(255) comment 'background image, if any', + disposition tinyint default 1 comment 'bit 1 = hide background image, bit 2 = display background image, bit 4 = tile background image' +) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin; + +create table group_block ( + group_id integer not null comment 'group profile is blocked from' references user_group (id), + blocked integer not null comment 'profile that is blocked' references profile (id), + blocker integer not null comment 'user making the block' references user (id), + modified timestamp comment 'date of blocking', + + constraint primary key (group_id, blocked) + +) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin; + +create table group_alias ( + + alias varchar(64) primary key comment 'additional nickname for the group', + group_id integer not null comment 'group profile is blocked from' references user_group (id), + modified timestamp comment 'date alias was created', + + index group_alias_group_id_idx (group_id) + +) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin; From e3c5d1664f8049b85198cf5c43957a237cb29bcf Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Wed, 24 Jun 2009 16:10:28 -0700 Subject: [PATCH 21/49] Take out noisy debugging statement --- actions/twitapistatuses.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/actions/twitapistatuses.php b/actions/twitapistatuses.php index e1fbc5c767..555c746cbc 100644 --- a/actions/twitapistatuses.php +++ b/actions/twitapistatuses.php @@ -78,8 +78,6 @@ class TwitapistatusesAction extends TwitterapiAction $this->auth_user = $apidata['user']; $user = $this->get_user($apidata['api_arg'], $apidata); - common_debug("auth user = " . $this->auth_user->nickname); - if (empty($user)) { $this->clientError(_('No such user!'), 404, $apidata['content-type']); From fa57e717e3bbb01e0c19fcb30f3d67bd596c730f Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Thu, 25 Jun 2009 00:25:22 +0000 Subject: [PATCH 22/49] Moved the attachment representation outside of the anchor so that onclick, it doesn't follow through on the href (e.g., it would play the video in the overlay instead) --- lib/attachmentlist.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/attachmentlist.php b/lib/attachmentlist.php index a2446a886a..60f9a27c0a 100644 --- a/lib/attachmentlist.php +++ b/lib/attachmentlist.php @@ -249,8 +249,8 @@ class Attachment extends AttachmentListItem $this->out->elementStart('div', 'entry-title'); $this->out->elementStart('a', $this->linkAttr()); $this->out->element('span', null, $this->linkTitle()); - $this->showRepresentation(); $this->out->elementEnd('a'); + $this->showRepresentation(); $this->out->elementEnd('div'); if (!empty($this->oembed->author_name) || !empty($this->oembed->provider)) { From 835799ff169387e5b686b2740020dc0e49154bb2 Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Thu, 25 Jun 2009 00:49:54 +0000 Subject: [PATCH 23/49] Separated attachment view components --- lib/attachmentlist.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/attachmentlist.php b/lib/attachmentlist.php index 60f9a27c0a..b5513ade7d 100644 --- a/lib/attachmentlist.php +++ b/lib/attachmentlist.php @@ -250,6 +250,9 @@ class Attachment extends AttachmentListItem $this->out->elementStart('a', $this->linkAttr()); $this->out->element('span', null, $this->linkTitle()); $this->out->elementEnd('a'); + $this->out->elementEnd('div'); + + $this->out->elementStart('div', 'entry-content'); $this->showRepresentation(); $this->out->elementEnd('div'); From 5f1b97e2add1b525401deef290ba29937135d073 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Wed, 24 Jun 2009 18:02:17 -0700 Subject: [PATCH 24/49] no memcached queue handler --- scripts/getvaliddaemons.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/scripts/getvaliddaemons.php b/scripts/getvaliddaemons.php index 198ea8fb9a..97c230784f 100755 --- a/scripts/getvaliddaemons.php +++ b/scripts/getvaliddaemons.php @@ -38,9 +38,6 @@ if(common_config('xmpp','enabled')) { echo "xmppdaemon.php jabberqueuehandler.php publicqueuehandler.php "; echo "xmppconfirmhandler.php "; } -if(common_config('memcached','enabled')) { - echo "memcachedqueuehandler.php "; -} if(common_config('twitterbridge','enabled')) { echo "twitterstatusfetcher.php "; } From 63f12c48a8dd7c75093587d78a8fd557330d202e Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Wed, 24 Jun 2009 19:17:41 -0700 Subject: [PATCH 25/49] make stomp server work with username and password --- lib/common.php | 8 ++- lib/queuehandler.php | 15 ++++- lib/util.php | 146 ++++++++++++++++++++++--------------------- 3 files changed, 93 insertions(+), 76 deletions(-) diff --git a/lib/common.php b/lib/common.php index 8eb464d7db..bb1a4255da 100644 --- a/lib/common.php +++ b/lib/common.php @@ -125,7 +125,13 @@ $config = array('appname' => 'laconica', # for syslog 'priority' => 'debug'), # XXX: currently ignored 'queue' => - array('enabled' => false), + array('enabled' => false, + 'subsystem' => 'db', # default to database, or 'stomp' + 'stomp_server' => null, + 'queue_basename' => 'laconica', + 'stomp_username' => null, + 'stomp_password' => null, + ), 'license' => array('url' => 'http://creativecommons.org/licenses/by/3.0/', 'title' => 'Creative Commons Attribution 3.0', diff --git a/lib/queuehandler.php b/lib/queuehandler.php index d5e0150d9c..ae403c65e2 100644 --- a/lib/queuehandler.php +++ b/lib/queuehandler.php @@ -112,12 +112,21 @@ class QueueHandler extends Daemon } function stomp_dispatch() { - require("Stomp.php"); - $con = new Stomp(common_config('queue','stomp_server')); - if (!$con->connect()) { + + // use an external message queue system via STOMP + require_once("Stomp.php"); + + $server = common_config('queue','stomp_server'); + $username = common_config('queue', 'stomp_username'); + $password = common_config('queue', 'stomp_password'); + + $con = new Stomp($server); + + if (!$con->connect($username, $password)) { $this->log(LOG_ERR, 'Failed to connect to queue server'); return false; } + $queue_basename = common_config('queue','queue_basename'); // subscribe to the relevant queue (format: basename-transport) $con->subscribe('/queue/'.$queue_basename.'-'.$this->transport()); diff --git a/lib/util.php b/lib/util.php index 1af4625167..30b767c3ef 100644 --- a/lib/util.php +++ b/lib/util.php @@ -826,89 +826,91 @@ function common_broadcast_notice($notice, $remote=false) function common_enqueue_notice($notice) { + $transports = array('omb', 'sms', 'public', 'twitter', 'facebook', 'ping'); + + if (common_config('xmpp', 'enabled')) + { + $transports[] = 'jabber'; + } + if (common_config('queue','subsystem') == 'stomp') { - // use an external message queue system via STOMP - require_once("Stomp.php"); - $con = new Stomp(common_config('queue','stomp_server')); - if (!$con->connect()) { - common_log(LOG_ERR, 'Failed to connect to queue server'); - return false; - } - $queue_basename = common_config('queue','queue_basename'); - foreach (array('jabber', 'omb', 'sms', 'public', 'twitter', 'facebook', 'ping') as $transport) { - if (!$con->send( - '/queue/'.$queue_basename.'-'.$transport, // QUEUE - $notice->id, // BODY of the message - array ( // HEADERS of the msg - 'created' => $notice->created - ))) { - common_log(LOG_ERR, 'Error sending to '.$transport.' queue'); - return false; - } - common_log(LOG_DEBUG, 'complete remote queueing notice ID = ' . $notice->id . ' for ' . $transport); - } - - //send tags as headers, so they can be used as JMS selectors - common_log(LOG_DEBUG, 'searching for tags ' . $notice->id); - $tags = array(); - $tag = new Notice_tag(); - $tag->notice_id = $notice->id; - if ($tag->find()) { - while ($tag->fetch()) { - common_log(LOG_DEBUG, 'tag found = ' . $tag->tag); - array_push($tags,$tag->tag); - } - } - $tag->free(); - - $con->send('/topic/laconica.'.$notice->profile_id, - $notice->content, - array( - 'profile_id' => $notice->profile_id, - 'created' => $notice->created, - 'tags' => implode($tags,' - ') - ) - ); - common_log(LOG_DEBUG, 'sent to personal topic ' . $notice->id); - $con->send('/topic/laconica.allusers', - $notice->content, - array( - 'profile_id' => $notice->profile_id, - 'created' => $notice->created, - 'tags' => implode($tags,' - ') - ) - ); - common_log(LOG_DEBUG, 'sent to catch-all topic ' . $notice->id); - $result = true; + common_enqueue_notice_stomp($notice, $transports); } else { - // in any other case, 'internal' - foreach (array('jabber', 'omb', 'sms', 'public', 'twitter', 'facebook', 'ping') as $transport) { - $qi = new Queue_item(); - $qi->notice_id = $notice->id; - $qi->transport = $transport; - $qi->created = $notice->created; - $result = $qi->insert(); - if (!$result) { - $last_error = &PEAR::getStaticProperty('DB_DataObject','lastError'); - common_log(LOG_ERR, 'DB error inserting queue item: ' . $last_error->message); - return false; - } - common_log(LOG_DEBUG, 'complete queueing notice ID = ' . $notice->id . ' for ' . $transport); - } + common_enqueue_notice_db($notice, $transports); } return $result; } -function common_post_inbox_transports() +function common_enqueue_notice_stomp($notice, $transports) { - $transports = array('omb', 'sms'); + // use an external message queue system via STOMP + require_once("Stomp.php"); - if (common_config('xmpp', 'enabled')) { - $transports = array_merge($transports, array('jabber', 'public')); + $server = common_config('queue','stomp_server'); + $username = common_config('queue', 'stomp_username'); + $password = common_config('queue', 'stomp_password'); + + $con = new Stomp($server); + + if (!$con->connect($username, $password)) { + common_log(LOG_ERR, 'Failed to connect to queue server'); + return false; } - return $transports; + $queue_basename = common_config('queue','queue_basename'); + + foreach ($transports as $transport) { + $result = $con->send('/queue/'.$queue_basename.'-'.$transport, // QUEUE + $notice->id, // BODY of the message + array ('created' => $notice->created)); + if (!$result) { + common_log(LOG_ERR, 'Error sending to '.$transport.' queue'); + return false; + } + common_log(LOG_DEBUG, 'complete remote queueing notice ID = ' . $notice->id . ' for ' . $transport); + } + + //send tags as headers, so they can be used as JMS selectors + common_log(LOG_DEBUG, 'searching for tags ' . $notice->id); + $tags = array(); + $tag = new Notice_tag(); + $tag->notice_id = $notice->id; + if ($tag->find()) { + while ($tag->fetch()) { + common_log(LOG_DEBUG, 'tag found = ' . $tag->tag); + array_push($tags,$tag->tag); + } + } + $tag->free(); + + $con->send('/topic/laconica.'.$notice->profile_id, + $notice->content, + array( + 'profile_id' => $notice->profile_id, + 'created' => $notice->created, + 'tags' => implode($tags,' - ') + ) + ); + common_log(LOG_DEBUG, 'sent to personal topic ' . $notice->id); + $con->send('/topic/laconica.allusers', + $notice->content, + array( + 'profile_id' => $notice->profile_id, + 'created' => $notice->created, + 'tags' => implode($tags,' - ') + ) + ); + common_log(LOG_DEBUG, 'sent to catch-all topic ' . $notice->id); + $result = true; +} + +function common_enqueue_notice_db($notice, $transports) +{ + // in any other case, 'internal' + foreach ($transports as $transport) { + common_enqueue_notice_transport($notice, $transport); + } } function common_enqueue_notice_transport($notice, $transport) From becfd6b3b5da57298137c3349efbd49fe347ccfd Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Wed, 24 Jun 2009 19:31:12 -0700 Subject: [PATCH 26/49] all daemons take an id parameter --- lib/xmppqueuehandler.php | 9 ++++----- scripts/jabberqueuehandler.php | 20 ++++++++++---------- scripts/publicqueuehandler.php | 20 ++++++++++---------- scripts/xmppconfirmhandler.php | 20 ++++++++++---------- scripts/xmppdaemon.php | 22 +++++++++++----------- 5 files changed, 45 insertions(+), 46 deletions(-) diff --git a/lib/xmppqueuehandler.php b/lib/xmppqueuehandler.php index a078cd9f7e..986e09c25e 100644 --- a/lib/xmppqueuehandler.php +++ b/lib/xmppqueuehandler.php @@ -22,7 +22,7 @@ if (!defined('LACONICA')) { exit(1); } require_once(INSTALLDIR.'/lib/queuehandler.php'); /** - * Common superclass for all XMPP-using queue handlers. They all need to + * Common superclass for all XMPP-using queue handlers. They all need to * service their message queues on idle, and forward any incoming messages * to the XMPP listener connection. So, we abstract out common code to a * superclass. @@ -30,12 +30,11 @@ require_once(INSTALLDIR.'/lib/queuehandler.php'); class XmppQueueHandler extends QueueHandler { - function start() { # Low priority; we don't want to receive messages $this->log(LOG_INFO, "INITIALIZE"); - $this->conn = jabber_connect($this->_id); + $this->conn = jabber_connect($this->_id.$this->transport()); if ($this->conn) { $this->conn->addEventHandler('message', 'forward_message', $this); $this->conn->addEventHandler('reconnect', 'handle_reconnect', $this); @@ -44,7 +43,7 @@ class XmppQueueHandler extends QueueHandler } return !is_null($this->conn); } - + function handle_reconnect(&$pl) { $this->conn->processUntil('session_start'); @@ -63,7 +62,7 @@ class XmppQueueHandler extends QueueHandler die($e->getMessage()); } } - + function forward_message(&$pl) { if ($pl['type'] != 'chat') { diff --git a/scripts/jabberqueuehandler.php b/scripts/jabberqueuehandler.php index a449932364..5b581629d3 100755 --- a/scripts/jabberqueuehandler.php +++ b/scripts/jabberqueuehandler.php @@ -20,13 +20,13 @@ define('INSTALLDIR', realpath(dirname(__FILE__) . '/..')); -$shortoptions = 'r::'; -$longoptions = array('resource::'); +$shortoptions = 'i::'; +$longoptions = array('id::'); $helptext = << 0) { - $resource = $args[0]; + $id = $args[0]; } else { - $resource = null; + $id = null; } -$handler = new JabberQueueHandler($resource); +$handler = new JabberQueueHandler($id); $handler->runOnce(); diff --git a/scripts/publicqueuehandler.php b/scripts/publicqueuehandler.php index 58ecc1745e..701d50e018 100755 --- a/scripts/publicqueuehandler.php +++ b/scripts/publicqueuehandler.php @@ -20,13 +20,13 @@ define('INSTALLDIR', realpath(dirname(__FILE__) . '/..')); -$shortoptions = 'r::'; -$longoptions = array('resource::'); +$shortoptions = 'i::'; +$longoptions = array('id::'); $helptext = << 0) { - $resource = $args[0]; + $id = $args[0]; } else { - $resource = null; + $id = null; } -$handler = new PublicQueueHandler($resource); +$handler = new PublicQueueHandler($id); $handler->runOnce(); diff --git a/scripts/xmppconfirmhandler.php b/scripts/xmppconfirmhandler.php index 883934fd6c..d6821ddefa 100755 --- a/scripts/xmppconfirmhandler.php +++ b/scripts/xmppconfirmhandler.php @@ -20,13 +20,13 @@ define('INSTALLDIR', realpath(dirname(__FILE__) . '/..')); -$shortoptions = 'r::'; -$longoptions = array('resource::'); +$shortoptions = 'i::'; +$longoptions = array('id::'); $helptext = << 0) { - $resource = $args[0]; + $id = $args[0]; } else { - $resource = null; + $id = null; } -$handler = new XmppConfirmHandler($resource); +$handler = new XmppConfirmHandler($id); $handler->runOnce(); diff --git a/scripts/xmppdaemon.php b/scripts/xmppdaemon.php index 661631937f..3eecfec29a 100755 --- a/scripts/xmppdaemon.php +++ b/scripts/xmppdaemon.php @@ -20,13 +20,13 @@ define('INSTALLDIR', realpath(dirname(__FILE__) . '/..')); -$shortoptions = 'r::'; -$longoptions = array('resource::'); +$shortoptions = 'i::'; +$longoptions = array('id::'); $helptext = <<resource = $resource; + $this->resource = $resource . 'daemon'; } else { $this->resource = common_config('xmpp', 'resource') . 'daemon'; } @@ -323,16 +323,16 @@ if (common_config('xmpp','enabled')==false) { exit(); } -if (have_option('r')) { - $resource = get_option_value('r'); -} else if (have_option('--resource')) { - $resource = get_option_value('--resource'); +if (have_option('i')) { + $id = get_option_value('i'); +} else if (have_option('--id')) { + $id = get_option_value('--id'); } else if (count($args) > 0) { - $resource = $args[0]; + $id = $args[0]; } else { - $resource = null; + $id = null; } -$daemon = new XMPPDaemon($resource); +$daemon = new XMPPDaemon($id); $daemon->runOnce(); From 6038420a69096854e386b8e9dcdc5993d7e9af8f Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Wed, 24 Jun 2009 19:35:19 -0700 Subject: [PATCH 27/49] add i argument for all daemons --- scripts/startdaemons.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/startdaemons.sh b/scripts/startdaemons.sh index a44362b572..8b7451cd7b 100755 --- a/scripts/startdaemons.sh +++ b/scripts/startdaemons.sh @@ -23,7 +23,8 @@ ARGS= if [ $# -gt 0 ]; then - ARGS="$ARGS -s$1" + ID=`echo $1 | sed s/\\\\./_/g` + ARGS="$ARGS -s$1 -i$ID" fi if [ $# -gt 1 ]; then From 246013d984245737983054abf7496aa3879cfc58 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Wed, 24 Jun 2009 19:50:45 -0700 Subject: [PATCH 28/49] different args for pid and daemon scripts --- scripts/startdaemons.sh | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/scripts/startdaemons.sh b/scripts/startdaemons.sh index 8b7451cd7b..9ead20acd6 100755 --- a/scripts/startdaemons.sh +++ b/scripts/startdaemons.sh @@ -20,24 +20,27 @@ # This program tries to start the daemons for Laconica. # Note that the 'maildaemon' needs to run as a mail filter. -ARGS= +ARGSG= +ARGSD= if [ $# -gt 0 ]; then + ARGSG="$ARGSG -s$1" ID=`echo $1 | sed s/\\\\./_/g` - ARGS="$ARGS -s$1 -i$ID" + ARGSD="$ARGSD -s$1 -i$ID" fi if [ $# -gt 1 ]; then - ARGS="$ARGS -p$2" + ARGSD="$ARGSD -p$2" + ARGSG="$ARGSG -p$2" fi DIR=`dirname $0` -DAEMONS=`php $DIR/getvaliddaemons.php $ARGS` +DAEMONS=`php $DIR/getvaliddaemons.php $ARGSG` for f in $DAEMONS; do printf "Starting $f..."; - php $DIR/$f $ARGS + php $DIR/$f $ARGSD printf "DONE.\n" done From 0c5c8348277e234f5f3d1e0b4956e698a6f95a14 Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Thu, 25 Jun 2009 03:46:52 +0000 Subject: [PATCH 29/49] Slightly more specific selector. Looks only in the notices in the content area --- js/util.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/js/util.js b/js/util.js index 65a77960a0..221c851206 100644 --- a/js/util.js +++ b/js/util.js @@ -280,13 +280,13 @@ function NoticeAttachments() { timeout : 0 }; - $('a.attachment').click(function() { + $('#content .notice a.attachment').click(function() { $().jOverlay({url: $('address .url')[0].href+'/attachment/' + ($(this).attr('id').substring('attachment'.length + 1)) + '/ajax'}); return false; }); var t; - $("body:not(#shownotice) a.thumbnail").hover( + $("body:not(#shownotice) #content .notice a.thumbnail").hover( function() { var anchor = $(this); $("a.thumbnail").children('img').hide(); From fcb43dd7112740284d2c1cb2708ac6a8a135cbdb Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Thu, 25 Jun 2009 06:55:40 +0000 Subject: [PATCH 30/49] Added class entry-content to attachment list container --- lib/attachmentlist.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/attachmentlist.php b/lib/attachmentlist.php index b5513ade7d..f6a1b59d03 100644 --- a/lib/attachmentlist.php +++ b/lib/attachmentlist.php @@ -82,7 +82,8 @@ class AttachmentList extends Widget $atts = new File; $att = $atts->getAttachments($this->notice->id); if (empty($att)) return 0; - $this->out->elementStart('dl', array('id' =>'attachments')); + $this->out->elementStart('dl', array('id' =>'attachments', + 'class' => 'entry-content')); $this->out->element('dt', null, _('Attachments')); $this->out->elementStart('dd'); $this->out->elementStart('ol', array('class' => 'attachments')); From 75d6b0707ce719a23526ed8c66de7240a9481285 Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Thu, 25 Jun 2009 07:55:52 +0000 Subject: [PATCH 31/49] Style for entity_aliases --- theme/base/css/display.css | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/theme/base/css/display.css b/theme/base/css/display.css index 8957a5b401..d01be77004 100644 --- a/theme/base/css/display.css +++ b/theme/base/css/display.css @@ -548,7 +548,8 @@ margin-bottom:18px; .entity_profile .entity_location, .entity_profile .entity_url, .entity_profile .entity_note, -.entity_profile .entity_tags { +.entity_profile .entity_tags, +.entity_profile .entity_aliases { margin-left:113px; margin-bottom:4px; } From 79547d99cf59fe9e2df94e33989d5a1d3b85be1b Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Thu, 25 Jun 2009 02:11:34 -0700 Subject: [PATCH 32/49] blow cache when new notice in conversation is saved --- classes/Notice.php | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/classes/Notice.php b/classes/Notice.php index 6f9b73be4b..8689dd427a 100644 --- a/classes/Notice.php +++ b/classes/Notice.php @@ -339,6 +339,19 @@ class Notice extends Memcached_DataObject $this->blowPublicCache($blowLast); $this->blowTagCache($blowLast); $this->blowGroupCache($blowLast); + $this->blowConversationCache($blowLast); + } + + function blowConversationCache($blowLast=false) + { + $cache = common_memcache(); + if ($cache) { + $ck = 'notice:conversation:'.$this->conversation; + $cache->delete($ck); + if ($blowLast) { + $cache->delete($ck.';last'); + } + } } function blowGroupCache($blowLast=false) From 262f864555dcad18fbdd044f753584dae5729e86 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Thu, 25 Jun 2009 02:57:16 -0700 Subject: [PATCH 33/49] don't try to load a null notice into the list --- classes/Notice.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/classes/Notice.php b/classes/Notice.php index 8689dd427a..59ffef91af 100644 --- a/classes/Notice.php +++ b/classes/Notice.php @@ -690,7 +690,10 @@ class Notice extends Memcached_DataObject if (!empty($cache)) { $notices = array(); foreach ($ids as $id) { - $notices[] = Notice::staticGet('id', $id); + $n = Notice::staticGet('id', $id); + if (!empty($n)) { + $notices[] = $n; + } } return new ArrayWrapper($notices); } else { From 3ca9e85ce4f0db7f160f9a8e989bec898bfbbf55 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Thu, 25 Jun 2009 09:43:30 -0700 Subject: [PATCH 34/49] update conversations to use newer query format --- actions/conversation.php | 12 ++------- classes/Notice.php | 53 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 54 insertions(+), 11 deletions(-) diff --git a/actions/conversation.php b/actions/conversation.php index d3fc5b6a9c..654a670f54 100644 --- a/actions/conversation.php +++ b/actions/conversation.php @@ -63,6 +63,7 @@ class ConversationAction extends Action if (empty($this->id)) { return false; } + $this->id = $this->id+0; $this->page = $this->trimmed('page'); if (empty($this->page)) { $this->page = 1; @@ -106,18 +107,10 @@ class ConversationAction extends Action function showContent() { - // FIXME this needs to be a tree, not a list - - $qry = 'SELECT * FROM notice WHERE conversation = %s '; - $offset = ($this->page-1) * NOTICES_PER_PAGE; $limit = NOTICES_PER_PAGE + 1; - $txt = sprintf($qry, $this->id); - - $notices = Notice::getStream($txt, - 'notice:conversation:'.$this->id, - $offset, $limit); + $notices = Notice::conversationStream($this->id, $offset, $limit); $ct = new ConversationTree($notices, $this); @@ -126,7 +119,6 @@ class ConversationAction extends Action $this->pagination($this->page > 1, $cnt > NOTICES_PER_PAGE, $this->page, 'conversation', array('id' => $this->id)); } - } /** diff --git a/classes/Notice.php b/classes/Notice.php index 59ffef91af..44179b2543 100644 --- a/classes/Notice.php +++ b/classes/Notice.php @@ -346,7 +346,7 @@ class Notice extends Memcached_DataObject { $cache = common_memcache(); if ($cache) { - $ck = 'notice:conversation:'.$this->conversation; + $ck = 'notice:conversation_ids:'.$this->conversation; $cache->delete($ck); if ($blowLast) { $cache->delete($ck.';last'); @@ -762,6 +762,57 @@ class Notice extends Memcached_DataObject return $ids; } + function conversationStream($id, $offset=0, $limit=20, $since_id=0, $max_id=0, $since=null) + { + $ids = Notice::stream(array('Notice', '_conversationStreamDirect'), + array($id), + 'notice:conversation_ids:'.$id, + $offset, $limit, $since_id, $max_id, $since); + + return Notice::getStreamByIds($ids); + } + + function _conversationStreamDirect($id, $offset=0, $limit=20, $since_id=0, $max_id=0, $since=null) + { + $notice = new Notice(); + + $notice->selectAdd(); // clears it + $notice->selectAdd('id'); + + $notice->whereAdd('conversation = '.$id); + + $notice->orderBy('id DESC'); + + if (!is_null($offset)) { + $notice->limit($offset, $limit); + } + + if ($since_id != 0) { + $notice->whereAdd('id > ' . $since_id); + } + + if ($max_id != 0) { + $notice->whereAdd('id <= ' . $max_id); + } + + if (!is_null($since)) { + $notice->whereAdd('created > \'' . date('Y-m-d H:i:s', $since) . '\''); + } + + $ids = array(); + + if ($notice->find()) { + while ($notice->fetch()) { + $ids[] = $notice->id; + } + } + + $notice->free(); + $notice = NULL; + + return $ids; + } + function addToInboxes() { $enabled = common_config('inboxes', 'enabled'); From 1e17f1256a1166db6bd3acd35fd437262ba27ffd Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Thu, 25 Jun 2009 16:55:19 +0000 Subject: [PATCH 35/49] Shows the selected file attachment under the form_notice textarea --- js/util.js | 9 +++++++++ theme/base/css/display.css | 5 +++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/js/util.js b/js/util.js index 221c851206..9156045bbf 100644 --- a/js/util.js +++ b/js/util.js @@ -233,6 +233,7 @@ $(document).ready(function(){ $("#form_notice").each(addAjaxHidden); NoticeReply(); NoticeAttachments(); + NoticeDataAttachSelected(); }); function NoticeReply() { @@ -310,3 +311,11 @@ function NoticeAttachments() { } ); } + +function NoticeDataAttachSelected() { + $('#notice_data-attach').change(function() { + S = '
'+$(this).val()+'
'; + NDAS = $('#notice_data-attach_selected'); + (NDAS.length > 0) ? NDAS.replaceWith(S) : $('#form_notice').append(S); + }); +} diff --git a/theme/base/css/display.css b/theme/base/css/display.css index d01be77004..bfcc9a7fa6 100644 --- a/theme/base/css/display.css +++ b/theme/base/css/display.css @@ -510,10 +510,11 @@ margin-bottom:7px; margin-left:18px; float:left; } -#form_notice .error { +#form_notice .error, +#form_notice .success { float:left; clear:both; -width:96.9%; +width:81.5%; margin-bottom:0; line-height:1.618; } From 5cc5bae4a91a6f0ac7bf3569d268e203da78274d Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Thu, 25 Jun 2009 17:00:32 +0000 Subject: [PATCH 36/49] Adds a scrollbar if the filename is too long for the attached file --- theme/base/css/display.css | 1 + 1 file changed, 1 insertion(+) diff --git a/theme/base/css/display.css b/theme/base/css/display.css index bfcc9a7fa6..c8f23e4f56 100644 --- a/theme/base/css/display.css +++ b/theme/base/css/display.css @@ -517,6 +517,7 @@ clear:both; width:81.5%; margin-bottom:0; line-height:1.618; +overflow:auto; } /* entity_profile */ From 4d56bc6a0adba63c5546d5d18a70fa2c989839be Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Thu, 25 Jun 2009 11:08:32 -0700 Subject: [PATCH 37/49] streamline the file action --- actions/file.php | 44 ++++++++++++++++++++++++++++++++------------ classes/Notice.php | 14 ++++++++++++++ 2 files changed, 46 insertions(+), 12 deletions(-) diff --git a/actions/file.php b/actions/file.php index bb245c4a77..271f57ab96 100644 --- a/actions/file.php +++ b/actions/file.php @@ -21,20 +21,40 @@ if (!defined('LACONICA')) { exit(1); } require_once(INSTALLDIR.'/actions/shownotice.php'); -class FileAction extends ShowNoticeAction +class FileAction extends Action { - function showPage() { - $source_url = common_local_url('file', array('notice' => $this->notice->id)); - $query = "select file_redirection.url as url from file join file_redirection on file.id = file_redirection.file_id where file.url = '$source_url'"; - $file = new File_redirection; - $file->query($query); - $file->fetch(); - if (empty($file->url)) { - die('nothing attached here'); - } else { - header("Location: {$file->url}"); - die(); + var $id = null; + var $filerec = null; + + function prepare($args) + { + parent::prepare($args); + $this->id = $this->trimmed('notice'); + if (empty($this->id)) { + $this->clientError(_('No notice id')); } + $notice = Notice::staticGet('id', $this->id); + if (empty($notice)) { + $this->clientError(_('No notice')); + } + $atts = $notice->attachments(); + if (empty($atts)) { + $this->clientError(_('No attachments')); + } + foreach ($atts as $att) { + if (!empty($att->filename)) { + $this->filerec = $att; + break; + } + } + if (empty($this->filerec)) { + $this->clientError(_('No uploaded attachments')); + } + return true; + } + + function handle() { + common_redirect($this->filerec->url); } } diff --git a/classes/Notice.php b/classes/Notice.php index 44179b2543..9960d3d0aa 100644 --- a/classes/Notice.php +++ b/classes/Notice.php @@ -331,6 +331,20 @@ class Notice extends Memcached_DataObject return $n_attachments; } + function attachments() { + // XXX: cache this + $att = array(); + $f2p = new File_to_post; + $f2p->post_id = $this->id; + if ($f2p->find()) { + while ($f2p->fetch()) { + $f = File::staticGet($f2p->file_id); + $att[] = clone($f); + } + } + return $att; + } + function blowCaches($blowLast=false) { $this->blowSubsCache($blowLast); From 09010c4c2b80bb94607e2946fa94bca5ff160fed Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Thu, 25 Jun 2009 11:08:55 -0700 Subject: [PATCH 38/49] show backtrace on error --- index.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/index.php b/index.php index cb26e21961..cb6a0fe603 100644 --- a/index.php +++ b/index.php @@ -48,7 +48,14 @@ function handleError($error) $logmsg .= " : ". $error->getDebugInfo(); } common_log(LOG_ERR, $logmsg); - if ($error instanceof DB_DataObject_Error) { + if(common_config('site', 'logdebug')) { + $bt = $error->getBacktrace(); + foreach ($bt as $line) { + common_log(LOG_ERR, $line); + } + } + if ($error instanceof DB_DataObject_Error || + $error instanceof DB_Error) { $msg = sprintf(_('The database for %s isn\'t responding correctly, '. 'so the site won\'t work properly. '. 'The site admins probably know about the problem, '. From 638905c270824b3c0e673ae9872937c06fbd862e Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Thu, 25 Jun 2009 11:10:34 -0700 Subject: [PATCH 39/49] avoid getting duplicate errors on upload --- actions/newnotice.php | 43 +++++++++++++++------------ classes/File.php | 5 ++-- classes/File_redirection.php | 56 +++++++++++++++--------------------- classes/File_to_post.php | 20 +++++++++---- 4 files changed, 66 insertions(+), 58 deletions(-) diff --git a/actions/newnotice.php b/actions/newnotice.php index 4a2c369f0f..3677f54c29 100644 --- a/actions/newnotice.php +++ b/actions/newnotice.php @@ -236,6 +236,7 @@ class NewnoticeAction extends Action $this->deleteFile($filename); $this->clientError(_('Max notice size is 140 chars, including attachment URL.')); } + $fileRecord = $this->rememberFile($filename, $mimetype, $short_fileurl); } $notice = Notice::saveNew($user->id, $content_shortened, 'web', 1, @@ -249,7 +250,7 @@ class NewnoticeAction extends Action } if (isset($mimetype)) { - $this->attachFile($notice, $filename, $mimetype, $short_fileurl); + $this->attachFile($notice, $fileRecord); } common_broadcast_notice($notice); @@ -304,12 +305,12 @@ class NewnoticeAction extends Action @unlink($filepath); } - function attachFile($notice, $filename, $mimetype, $short) + function rememberFile($filename, $mimetype, $short) { $file = new File; $file->filename = $filename; - $file->url = common_local_url('file', array('notice' => $notice->id)); + $file->url = File::url($filename); $filepath = File::path($filename); @@ -324,26 +325,32 @@ class NewnoticeAction extends Action $this->clientError(_('There was a database error while saving your file. Please try again.')); } - $file_redir = new File_redirection; - $file_redir->url = File::url($filename); - $file_redir->file_id = $file_id; + $this->maybeAddRedir($file_id, $short); + } - $result = $file_redir->insert(); + function maybeAddRedir($file_id, $url) + { + $file_redir = File_redirection::staticGet('url', $url); - if (!$result) { - common_log_db_error($file_redir, "INSERT", __FILE__); - $this->clientError(_('There was a database error while saving your file. Please try again.')); + if (empty($file_redir)) { + $file_redir = new File_redirection; + $file_redir->url = $url; + $file_redir->file_id = $file_id; + + $result = $file_redir->insert(); + + if (!$result) { + common_log_db_error($file_redir, "INSERT", __FILE__); + $this->clientError(_('There was a database error while saving your file. Please try again.')); + } } + } - $f2p = new File_to_post; - $f2p->file_id = $file_id; - $f2p->post_id = $notice->id; - $f2p->insert(); + function attachFile($notice, $filerec) + { + File_to_post::processNew($filerec->id, $notice->id); - if (!$result) { - common_log_db_error($f2p, "INSERT", __FILE__); - $this->clientError(_('There was a database error while saving your file. Please try again.')); - } + $this->maybeAddRedir($filerec->id, common_local_url('file', array('notice' => $this->notice->id))); } /** diff --git a/classes/File.php b/classes/File.php index b98c9e665f..5dd7cd8651 100644 --- a/classes/File.php +++ b/classes/File.php @@ -91,9 +91,10 @@ class File extends Memcached_DataObject $given_url = File_redirection::_canonUrl($given_url); if (empty($given_url)) return -1; // error, no url to process $file = File::staticGet('url', $given_url); - if (empty($file->id)) { + if (empty($file)) { $file_redir = File_redirection::staticGet('url', $given_url); - if (empty($file_redir->id)) { + if (empty($file_redir)) { + common_debug("processNew() '$given_url' not a known redirect.\n"); $redir_data = File_redirection::where($given_url); $redir_url = $redir_data['url']; if ($redir_url === $given_url) { diff --git a/classes/File_redirection.php b/classes/File_redirection.php index c173017e2d..d6fa0bcb62 100644 --- a/classes/File_redirection.php +++ b/classes/File_redirection.php @@ -66,21 +66,17 @@ class File_redirection extends Memcached_DataObject // let's see if we know this... $a = File::staticGet('url', $short_url); - if (empty($a->id)) { - $b = File_redirection::staticGet('url', $short_url); - if (empty($b->id)) { - // we'll have to figure it out - } else { - // this is a redirect to $b->file_id - $a = File::staticGet($b->file_id); - $url = $a->url; - } - } else { + + if (!empty($a)) { // this is a direct link to $a->url - $url = $a->url; - } - if (isset($url)) { - return $url; + return $a->url; + } else { + $b = File_redirection::staticGet('url', $short_url); + if (!empty($b)) { + // this is a redirect to $b->file_id + $a = File::staticGet('id', $b->file_id); + return $a->url; + } } $curlh = File_redirection::_commonCurl($short_url, $redirs); @@ -118,28 +114,22 @@ class File_redirection extends Memcached_DataObject } function makeShort($long_url) { - $long_url = File_redirection::_canonUrl($long_url); - // do we already know this long_url and have a short redirection for it? - $file = new File; - $file_redir = new File_redirection; - $file->url = $long_url; - $file->joinAdd($file_redir); - $file->selectAdd('length(file_redirection.url) as len'); - $file->limit(1); - $file->orderBy('len'); - $file->find(true); - if (!empty($file->url) && (strlen($file->url) < strlen($long_url))) { - return $file->url; - } - // if yet unknown, we must find a short url according to user settings - $short_url = File_redirection::_userMakeShort($long_url, common_current_user()); - return $short_url; + $canon = File_redirection::_canonUrl($long_url); + + $short_url = File_redirection::_userMakeShort($canon); + + // Did we get one? Is it shorter? + if (!empty($short_url) && mb_strlen($short_url) < mb_strlen($long_url)) { + return $short_url; + } else { + return $long_url; + } } - function _userMakeShort($long_url, $user) { + function _userMakeShort($long_url) { $short_url = common_shorten_url($long_url); - if ($short_url) { + if (!empty($short_url) && $short_url != $long_url) { $short_url = (string)$short_url; // store it $file = File::staticGet('url', $long_url); @@ -162,7 +152,7 @@ class File_redirection extends Memcached_DataObject } return $short_url; } - return $long_url; + return null; } function _canonUrl($in_url, $default_scheme = 'http://') { diff --git a/classes/File_to_post.php b/classes/File_to_post.php index db0a8d2169..d35febb778 100644 --- a/classes/File_to_post.php +++ b/classes/File_to_post.php @@ -25,7 +25,7 @@ require_once INSTALLDIR.'/classes/Memcached_DataObject.php'; * Table Definition for file_to_post */ -class File_to_post extends Memcached_DataObject +class File_to_post extends Memcached_DataObject { ###START_AUTOCODE /* the code below is auto generated do not remove the above tag */ @@ -44,17 +44,27 @@ class File_to_post extends Memcached_DataObject function processNew($file_id, $notice_id) { static $seen = array(); if (empty($seen[$notice_id]) || !in_array($file_id, $seen[$notice_id])) { - $f2p = new File_to_post; - $f2p->file_id = $file_id; - $f2p->post_id = $notice_id; - $f2p->insert(); + + $f2p = File_to_post::pkeyGet(array('post_id' => $notice_id, + 'file_id' => $file_id)); + if (empty($f2p)) { + $f2p = new File_to_post; + $f2p->file_id = $file_id; + $f2p->post_id = $notice_id; + $f2p->insert(); + } + if (empty($seen[$notice_id])) { $seen[$notice_id] = array($file_id); } else { $seen[$notice_id][] = $file_id; } } + } + function &pkeyGet($kv) + { + return Memcached_DataObject::pkeyGet('File_to_post', $kv); } } From c96572c0909793fd1f38def21f2577e13d98766d Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Thu, 25 Jun 2009 11:23:47 -0700 Subject: [PATCH 40/49] fix caching for conversations, again --- classes/Notice.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/classes/Notice.php b/classes/Notice.php index 9960d3d0aa..5bcfa896e0 100644 --- a/classes/Notice.php +++ b/classes/Notice.php @@ -360,7 +360,7 @@ class Notice extends Memcached_DataObject { $cache = common_memcache(); if ($cache) { - $ck = 'notice:conversation_ids:'.$this->conversation; + $ck = common_cache_key('notice:conversation_ids:'.$this->conversation); $cache->delete($ck); if ($blowLast) { $cache->delete($ck.';last'); From 0eb77e67532cbbdfd1f099303ae8e1614296b87a Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Thu, 25 Jun 2009 18:57:39 +0000 Subject: [PATCH 41/49] Added fragment identifier to the "in context" URL which points to the notice location in the Conversation page. --- lib/noticelist.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/noticelist.php b/lib/noticelist.php index 6f05c63d66..44726a17b7 100644 --- a/lib/noticelist.php +++ b/lib/noticelist.php @@ -432,7 +432,7 @@ class NoticeListItem extends Widget $this->out->elementStart('dl', 'response'); $this->out->element('dt', null, _('To')); $this->out->elementStart('dd'); - $this->out->element('a', array('href' => $convurl), + $this->out->element('a', array('href' => $convurl.'#notice-'.$this->notice->id), _('in context')); $this->out->elementEnd('dd'); $this->out->elementEnd('dl'); From 27076227620d0beca7586affa8e89154a1648d70 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Thu, 25 Jun 2009 12:52:10 -0700 Subject: [PATCH 42/49] Return clippy to his rightful place next to attachments --- lib/util.php | 35 +++++++++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/lib/util.php b/lib/util.php index 30b767c3ef..f6d50b1807 100644 --- a/lib/util.php +++ b/lib/util.php @@ -497,6 +497,22 @@ function common_linkify($url) { $attrs = array('href' => $longurl, 'rel' => 'external'); + $is_attachment = false; + $attachment_id = null; + $has_thumb = false; + + // Check to see whether there's a filename associated with this URL. + // If there is, it's an upload and qualifies as an attachment + + $localfile = File::staticGet('url', $longurl); + + if (!empty($localfile)) { + if (isset($localfile->filename)) { + $is_attachment = true; + $attachment_id = $localfile->id; + } + } + // if this URL is an attachment, then we set class='attachment' and id='attahcment-ID' // where ID is the id of the attachment for the given URL. // @@ -504,24 +520,35 @@ function common_linkify($url) { // we're currently picking up oembeds only. // I think the best option is another file_view table in the db // and associated dbobject. + $query = "select file_oembed.file_id as file_id from file join file_oembed on file.id = file_oembed.file_id where file.url='$longurl'"; $file = new File; $file->query($query); $file->fetch(); if (!empty($file->file_id)) { + $is_attachment = true; + $attachment_id = $file->file_id; + $query = "select file_thumbnail.file_id as file_id from file join file_thumbnail on file.id = file_thumbnail.file_id where file.url='$longurl'"; $file2 = new File; $file2->query($query); $file2->fetch(); - if (empty($file2->file_id)) { - $attrs['class'] = 'attachment'; - } else { + if (!empty($file2)) { + $has_thumb = true; + } + } + + // Add clippy + if ($is_attachment) { + $attrs['class'] = 'attachment'; + if ($has_thumb) { $attrs['class'] = 'attachment thumbnail'; } - $attrs['id'] = "attachment-{$file->file_id}"; + $attrs['id'] = "attachment-{$attachment_id}"; } + return XMLStringer::estring('a', $attrs, $display); } From a7cdf32df541bf73a47f1255b3e9f0a22c4724b4 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Thu, 25 Jun 2009 13:23:59 -0700 Subject: [PATCH 43/49] max public page --- actions/public.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/actions/public.php b/actions/public.php index 27153f1315..9851285c48 100644 --- a/actions/public.php +++ b/actions/public.php @@ -35,6 +35,10 @@ require_once INSTALLDIR.'/lib/publicgroupnav.php'; require_once INSTALLDIR.'/lib/noticelist.php'; require_once INSTALLDIR.'/lib/feedlist.php'; +// Farther than any human will go + +define('MAX_PUBLIC_PAGE', 100); + /** * Action for displaying the public stream * @@ -74,6 +78,10 @@ class PublicAction extends Action parent::prepare($args); $this->page = ($this->arg('page')) ? ($this->arg('page')+0) : 1; + if ($this->page > MAX_PUBLIC_PAGE) { + $this->clientError(sprintf(_("Beyond the page limit (%s)"), MAX_PUBLIC_PAGE)); + } + common_set_returnto($this->selfUrl()); return true; From d1d5347ba3a567205fef36633b52f19a24485a42 Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Thu, 25 Jun 2009 20:36:02 +0000 Subject: [PATCH 44/49] Using transparent background colour instead of solid for notice on hover --- theme/default/css/display.css | 2 +- theme/identica/css/display.css | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/theme/default/css/display.css b/theme/default/css/display.css index f592e930f0..89197bddb9 100644 --- a/theme/default/css/display.css +++ b/theme/default/css/display.css @@ -245,7 +245,7 @@ div.notice-options input { font-family:sans-serif; } #content .notices li:hover { -background-color:#FCFCFC; +background-color:rgba(240, 240, 240, 0.2); } #conversation .notices li:hover { background-color:transparent; diff --git a/theme/identica/css/display.css b/theme/identica/css/display.css index 09ad4c9724..025debf34c 100644 --- a/theme/identica/css/display.css +++ b/theme/identica/css/display.css @@ -245,7 +245,7 @@ div.notice-options input { font-family:sans-serif; } #content .notices li:hover { -background-color:#FCFCFC; +background-color:rgba(240, 240, 240, 0.2); } #conversation .notices li:hover { background-color:transparent; From 03d31911e18f8ca0ba2f8425943b4c244114a066 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Thu, 25 Jun 2009 13:51:29 -0700 Subject: [PATCH 45/49] FileAction redirections weren't being added (e.g.: /notice/$notice_id/file) --- actions/newnotice.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/actions/newnotice.php b/actions/newnotice.php index 3677f54c29..15caff6eaa 100644 --- a/actions/newnotice.php +++ b/actions/newnotice.php @@ -326,6 +326,8 @@ class NewnoticeAction extends Action } $this->maybeAddRedir($file_id, $short); + + return $file; } function maybeAddRedir($file_id, $url) @@ -350,7 +352,8 @@ class NewnoticeAction extends Action { File_to_post::processNew($filerec->id, $notice->id); - $this->maybeAddRedir($filerec->id, common_local_url('file', array('notice' => $this->notice->id))); + $this->maybeAddRedir($filerec->id, + common_local_url('file', array('notice' => $notice->id))); } /** From 6a0571d51b0cafb0dbc7caf3aa61cdfd17d6c7ce Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Thu, 25 Jun 2009 21:01:07 +0000 Subject: [PATCH 46/49] Added functionality to remove the notice data attachment --- js/util.js | 14 ++++++++++---- theme/base/css/display.css | 11 +++++++++++ 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/js/util.js b/js/util.js index 9156045bbf..e7c54b74ac 100644 --- a/js/util.js +++ b/js/util.js @@ -222,6 +222,7 @@ $(document).ready(function(){ } $("#notice_data-text").val(""); $("#notice_data-attach").val(""); + $('#notice_data-attach_selected').remove(); counter(); } $("#form_notice").removeClass("processing"); @@ -233,7 +234,7 @@ $(document).ready(function(){ $("#form_notice").each(addAjaxHidden); NoticeReply(); NoticeAttachments(); - NoticeDataAttachSelected(); + NoticeDataAttach(); }); function NoticeReply() { @@ -312,10 +313,15 @@ function NoticeAttachments() { ); } -function NoticeDataAttachSelected() { - $('#notice_data-attach').change(function() { - S = '
'+$(this).val()+'
'; +function NoticeDataAttach() { + NDA = $('#notice_data-attach'); + NDA.change(function() { + S = '
'+$(this).val()+'
'; NDAS = $('#notice_data-attach_selected'); (NDAS.length > 0) ? NDAS.replaceWith(S) : $('#form_notice').append(S); + $('#notice_data-attach_selected button').click(function(){ + $('#notice_data-attach_selected').remove(); + NDA.val(''); + }); }); } diff --git a/theme/base/css/display.css b/theme/base/css/display.css index c8f23e4f56..78fcd7ecef 100644 --- a/theme/base/css/display.css +++ b/theme/base/css/display.css @@ -517,8 +517,19 @@ clear:both; width:81.5%; margin-bottom:0; line-height:1.618; +} +#form_notice #notice_data-attach_selected code { +float:left; +width:90%; +display:block; +font-size:1.1em; +line-height:1.8; overflow:auto; } +#form_notice #notice_data-attach_selected button { +float:right; +font-size:0.8em; +} /* entity_profile */ .entity_profile { From c4da201fc01206817034207c01d9e2d051605757 Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Thu, 25 Jun 2009 21:25:41 +0000 Subject: [PATCH 47/49] IE UI update for notice_data_attach_selected --- theme/base/css/ie.css | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/theme/base/css/ie.css b/theme/base/css/ie.css index da200388eb..43fb01492a 100644 --- a/theme/base/css/ie.css +++ b/theme/base/css/ie.css @@ -19,6 +19,12 @@ display:block; width:17%; max-width:17%; } +#form_notice #notice_data-attach_selected { +width:78.5%; +} +#form_notice #notice_data-attach_selected button { +padding:0 4px; +} #anon_notice { max-width:39%; } From 74d9b0f820c588f2959457e83aaf5b9d4f2ea399 Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Fri, 26 Jun 2009 05:38:43 +0000 Subject: [PATCH 48/49] Removed unnecessary assignment to variable for background image on --- js/userdesign.go.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/js/userdesign.go.js b/js/userdesign.go.js index b54b492cce..833b19adcb 100644 --- a/js/userdesign.go.js +++ b/js/userdesign.go.js @@ -89,11 +89,10 @@ $(document).ready(function() { $('body').css({'background-image':'none'}); }); $('#design_background-image_on').focus(function() { - var bis = $('#design_background-image_onoff img')[0].src; - $('body').css({'background-image':'url('+bis+')'}); + $('body').css({'background-image':'url('+$('#design_background-image_onoff img')[0].src+')'}); }); $('#design_background-image_repeat').click(function() { ($(this)[0].checked) ? $('body').css({'background-repeat':'repeat'}) : $('body').css({'background-repeat':'no-repeat'}); }); -}); \ No newline at end of file +}); From 994768b82101fdd2a08a92e30967ded6714b87dc Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Thu, 25 Jun 2009 23:00:46 -0700 Subject: [PATCH 49/49] break up big inbox queries into lots of small ones --- classes/Group_inbox.php | 6 +++ classes/Notice.php | 110 ++++++++++++++++++++++++++------------- classes/Notice_inbox.php | 1 + classes/Profile.php | 48 +++++++++++++++++ classes/User.php | 46 +++------------- classes/User_group.php | 24 +++++++++ 6 files changed, 160 insertions(+), 75 deletions(-) diff --git a/classes/Group_inbox.php b/classes/Group_inbox.php index b80ba42729..1af7439f7f 100644 --- a/classes/Group_inbox.php +++ b/classes/Group_inbox.php @@ -14,8 +14,14 @@ class Group_inbox extends Memcached_DataObject public $created; // datetime() not_null /* Static get */ + function staticGet($k,$v=NULL) { return Memcached_DataObject::staticGet('Group_inbox',$k,$v); } /* the code above is auto generated do not remove the tag below */ ###END_AUTOCODE + + function &pkeyGet($kv) + { + return Memcached_DataObject::pkeyGet('Group_inbox', $kv); + } } diff --git a/classes/Notice.php b/classes/Notice.php index 5bcfa896e0..fdcef1bc2e 100644 --- a/classes/Notice.php +++ b/classes/Notice.php @@ -832,24 +832,60 @@ class Notice extends Memcached_DataObject $enabled = common_config('inboxes', 'enabled'); if ($enabled === true || $enabled === 'transitional') { - $inbox = new Notice_inbox(); - $UT = common_config('db','type')=='pgsql'?'"user"':'user'; - $qry = 'INSERT INTO notice_inbox (user_id, notice_id, created) ' . - "SELECT $UT.id, " . $this->id . ", '" . $this->created . "' " . - "FROM $UT JOIN subscription ON $UT.id = subscription.subscriber " . - 'WHERE subscription.subscribed = ' . $this->profile_id . ' ' . - 'AND NOT EXISTS (SELECT user_id, notice_id ' . - 'FROM notice_inbox ' . - "WHERE user_id = $UT.id " . - 'AND notice_id = ' . $this->id . ' )'; - if ($enabled === 'transitional') { - $qry .= " AND $UT.inboxed = 1"; + + $users = $this->getSubscribedUsers(); + + // FIXME: kind of ignoring 'transitional'... + // we'll probably stop supporting inboxless mode + // in 0.9.x + + foreach ($users as $id) { + $this->addToUserInbox($id, NOTICE_INBOX_SOURCE_SUB); } - $inbox->query($qry); } + return; } + function getSubscribedUsers() + { + $user = new User(); + + $qry = + 'SELECT id ' . + 'FROM user JOIN subscription '. + 'ON user.id = subscription.subscriber ' . + 'WHERE subscription.subscribed = %d '; + + $user->query(sprintf($qry, $this->profile_id)); + + $ids = array(); + + while ($user->fetch()) { + $ids[] = $user->id; + } + + $user->free(); + + return $ids; + } + + function addToUserInbox($user_id, $source) + { + $inbox = Notice_inbox::pkeyGet(array('user_id' => $user_id, + 'notice_id' => $this->id)); + if (empty($inbox)) { + $inbox = new Notice_inbox(); + $inbox->user_id = $user_id; + $inbox->notice_id = $this->id; + $inbox->source = $source; + $inbox->created = $this->created; + return $inbox->insert(); + } + + return true; + } + function saveGroups() { $enabled = common_config('inboxes', 'enabled'); @@ -888,13 +924,7 @@ class Notice extends Memcached_DataObject if ($profile->isMember($group)) { - $gi = new Group_inbox(); - - $gi->group_id = $group->id; - $gi->notice_id = $this->id; - $gi->created = common_sql_now(); - - $result = $gi->insert(); + $result = $this->addToGroupInbox($group); if (!$result) { common_log_db_error($gi, 'INSERT', __FILE__); @@ -902,27 +932,37 @@ class Notice extends Memcached_DataObject // FIXME: do this in an offline daemon - $this->addToGroupInboxes($group); + $this->addToGroupMemberInboxes($group); } } } - function addToGroupInboxes($group) + function addToGroupInbox($group) { - $inbox = new Notice_inbox(); - $UT = common_config('db','type')=='pgsql'?'"user"':'user'; - $qry = 'INSERT INTO notice_inbox (user_id, notice_id, created, source) ' . - "SELECT $UT.id, " . $this->id . ", '" . $this->created . "', " . NOTICE_INBOX_SOURCE_GROUP . " " . - "FROM $UT JOIN group_member ON $UT.id = group_member.profile_id " . - 'WHERE group_member.group_id = ' . $group->id . ' ' . - 'AND NOT EXISTS (SELECT user_id, notice_id ' . - 'FROM notice_inbox ' . - "WHERE user_id = $UT.id " . - 'AND notice_id = ' . $this->id . ' )'; - if ($enabled === 'transitional') { - $qry .= " AND $UT.inboxed = 1"; + $gi = Group_inbox::pkeyGet(array('group_id' => $group->id, + 'notice_id' => $this->id)); + + if (empty($gi)) { + + $gi = new Group_inbox(); + + $gi->group_id = $group->id; + $gi->notice_id = $this->id; + $gi->created = $this->created; + + return $gi->insert(); + } + + return true; + } + + function addToGroupMemberInboxes($group) + { + $users = $group->getUserMembers(); + + foreach ($users as $id) { + $this->addToUserInbox($id, NOTICE_INBOX_SOURCE_GROUP); } - $result = $inbox->query($qry); } function saveReplies() diff --git a/classes/Notice_inbox.php b/classes/Notice_inbox.php index 4ca2e9ae3c..940381f84c 100644 --- a/classes/Notice_inbox.php +++ b/classes/Notice_inbox.php @@ -27,6 +27,7 @@ define('INBOX_CACHE_WINDOW', 101); define('NOTICE_INBOX_SOURCE_SUB', 1); define('NOTICE_INBOX_SOURCE_GROUP', 2); +define('NOTICE_INBOX_SOURCE_REPLY', 3); define('NOTICE_INBOX_SOURCE_GATEWAY', -1); class Notice_inbox extends Memcached_DataObject diff --git a/classes/Profile.php b/classes/Profile.php index 6b27c80cb5..a0ed6b3ca3 100644 --- a/classes/Profile.php +++ b/classes/Profile.php @@ -289,4 +289,52 @@ class Profile extends Memcached_DataObject return Avatar::defaultImage($size); } } + + function getSubscriptions($offset=0, $limit=null) + { + $qry = + 'SELECT profile.* ' . + 'FROM profile JOIN subscription ' . + 'ON profile.id = subscription.subscribed ' . + 'WHERE subscription.subscriber = %d ' . + 'AND subscription.subscribed != subscription.subscriber ' . + 'ORDER BY subscription.created DESC '; + + if (common_config('db','type') == 'pgsql') { + $qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset; + } else { + $qry .= ' LIMIT ' . $offset . ', ' . $limit; + } + + $profile = new Profile(); + + $profile->query(sprintf($qry, $this->id)); + + return $profile; + } + + function getSubscribers($offset=0, $limit=null) + { + $qry = + 'SELECT profile.* ' . + 'FROM profile JOIN subscription ' . + 'ON profile.id = subscription.subscriber ' . + 'WHERE subscription.subscribed = %d ' . + 'AND subscription.subscribed != subscription.subscriber ' . + 'ORDER BY subscription.created DESC '; + + if ($offset) { + if (common_config('db','type') == 'pgsql') { + $qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset; + } else { + $qry .= ' LIMIT ' . $offset . ', ' . $limit; + } + } + + $profile = new Profile(); + + $cnt = $profile->query(sprintf($qry, $this->id)); + + return $profile; + } } diff --git a/classes/User.php b/classes/User.php index a01a3106f2..62a3f8a66e 100644 --- a/classes/User.php +++ b/classes/User.php @@ -600,50 +600,16 @@ class User extends Memcached_DataObject function getSubscriptions($offset=0, $limit=null) { - $qry = - 'SELECT profile.* ' . - 'FROM profile JOIN subscription ' . - 'ON profile.id = subscription.subscribed ' . - 'WHERE subscription.subscriber = %d ' . - 'AND subscription.subscribed != subscription.subscriber ' . - 'ORDER BY subscription.created DESC '; - - if (common_config('db','type') == 'pgsql') { - $qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset; - } else { - $qry .= ' LIMIT ' . $offset . ', ' . $limit; - } - - $profile = new Profile(); - - $profile->query(sprintf($qry, $this->id)); - - return $profile; + $profile = $this->getProfile(); + assert(!empty($profile)); + return $profile->getSubscriptions($offset, $limit); } function getSubscribers($offset=0, $limit=null) { - $qry = - 'SELECT profile.* ' . - 'FROM profile JOIN subscription ' . - 'ON profile.id = subscription.subscriber ' . - 'WHERE subscription.subscribed = %d ' . - 'AND subscription.subscribed != subscription.subscriber ' . - 'ORDER BY subscription.created DESC '; - - if ($offset) { - if (common_config('db','type') == 'pgsql') { - $qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset; - } else { - $qry .= ' LIMIT ' . $offset . ', ' . $limit; - } - } - - $profile = new Profile(); - - $cnt = $profile->query(sprintf($qry, $this->id)); - - return $profile; + $profile = $this->getProfile(); + assert(!empty($profile)); + return $profile->getSubscribers($offset, $limit); } function getTaggedSubscribers($tag, $offset=0, $limit=null) diff --git a/classes/User_group.php b/classes/User_group.php index 8a56b9e52b..9b4b01ead7 100644 --- a/classes/User_group.php +++ b/classes/User_group.php @@ -246,4 +246,28 @@ class User_group extends Memcached_DataObject return Design::staticGet('id', $this->design_id); } + function getUserMembers() + { + // XXX: cache this + + $user = new User(); + + $qry = + 'SELECT id ' . + 'FROM user JOIN group_member '. + 'ON user.id = group_member.profile_id ' . + 'WHERE group_member.group_id = %d '; + + $user->query(sprintf($qry, $this->id)); + + $ids = array(); + + while ($user->fetch()) { + $ids[] = $user->id; + } + + $user->free(); + + return $ids; + } }