From 3a44885b7ffcdcbb1b5cc8e972a3f89dd02b4c74 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Fri, 22 May 2009 20:50:08 -0400 Subject: [PATCH 001/262] reformat designsettings.php --- actions/designsettings.php | 84 +++++++------------------------------- 1 file changed, 14 insertions(+), 70 deletions(-) diff --git a/actions/designsettings.php b/actions/designsettings.php index 315e5a199c..8d8e5bad88 100644 --- a/actions/designsettings.php +++ b/actions/designsettings.php @@ -33,8 +33,6 @@ if (!defined('LACONICA')) { require_once INSTALLDIR.'/lib/accountsettingsaction.php'; - - class DesignsettingsAction extends AccountSettingsAction { /** @@ -82,8 +80,8 @@ class DesignsettingsAction extends AccountSettingsAction $this->element('legend', null, _('Change background image')); $this->elementStart('ul', 'form_data'); $this->elementStart('li'); - $this->element('label', array('for' => 'design_ background-image_file'), - _('Upload file')); + $this->element('label', array('for' => 'design_ background-image_file'), + _('Upload file')); $this->element('input', array('name' => 'design_background-image_file', 'type' => 'file', 'id' => 'design_background-image_file')); @@ -101,11 +99,11 @@ class DesignsettingsAction extends AccountSettingsAction $this->elementStart('ul', 'form_data'); //This is a JSON object in the DB field. Here for testing. Remove later. - $userSwatch = '{"body":{"background-color":"#F0F2F5"}, - "#content":{"background-color":"#FFFFFF"}, - "#aside_primary":{"background-color":"#CEE1E9"}, - "html body":{"color":"#000000"}, - "a":{"color":"#002E6E"}}'; + $userSwatch = '{"body":{"background-color":"#F0F2F5"},'. + '"#content":{"background-color":"#FFFFFF"},'. + '"#aside_primary":{"background-color":"#CEE1E9"},'. + '"html body":{"color":"#000000"},'. + '"a":{"color":"#002E6E"}}'; //Default theme swatch -- Where should this be stored? $defaultSwatch = array('body' => array('background-color' => '#F0F2F5'), @@ -147,14 +145,13 @@ class DesignsettingsAction extends AccountSettingsAction 'title' => _('Reset back to default'))); $this->submit('save', _('Save'), 'submit form_action-secondary', 'save', _('Save design')); -/*TODO: Check submitted form values: -json_encode(form values) -if submitted Swatch == DefaultSwatch, don't store in DB. -else store in BD -*/ + /*TODO: Check submitted form values: + json_encode(form values) + if submitted Swatch == DefaultSwatch, don't store in DB. + else store in BD + */ $this->elementEnd('fieldset'); $this->elementEnd('form'); - } /** @@ -168,63 +165,10 @@ else store in BD function handlePost() { - /* - // CSRF protection - - $token = $this->trimmed('token'); - if (!$token || $token != common_session_token()) { - $this->showForm(_('There was a problem with your session token. '. - 'Try again, please.')); - return; - } - - $user = common_current_user(); - assert(!is_null($user)); // should already be checked - - // FIXME: scrub input - - $newpassword = $this->arg('newpassword'); - $confirm = $this->arg('confirm'); - - # Some validation - - if (strlen($newpassword) < 6) { - $this->showForm(_('Password must be 6 or more characters.')); - return; - } else if (0 != strcmp($newpassword, $confirm)) { - $this->showForm(_('Passwords don\'t match.')); - return; - } - - if ($user->password) { - $oldpassword = $this->arg('oldpassword'); - - if (!common_check_user($user->nickname, $oldpassword)) { - $this->showForm(_('Incorrect old password')); - return; - } - } - - $original = clone($user); - - $user->password = common_munge_password($newpassword, $user->id); - - $val = $user->validate(); - if ($val !== true) { - $this->showForm(_('Error saving user; invalid.')); - return; - } - - if (!$user->update($original)) { - $this->serverError(_('Can\'t save new password.')); - return; - } - - $this->showForm(_('Password saved.'), true); - */ + // TODO: implement this + return; } - /** * Add the Farbtastic stylesheet * From 2f0fe8e33ae29557911a0d1896a2c1b9725b5e55 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Fri, 22 May 2009 20:54:07 -0400 Subject: [PATCH 002/262] add design table to DB --- db/laconica.sql | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/db/laconica.sql b/db/laconica.sql index 0b20bc172c..d42c20e2a1 100644 --- a/db/laconica.sql +++ b/db/laconica.sql @@ -482,3 +482,13 @@ create table file_to_post ( unique(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' +) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin; From c63622f05e1a29c6739952e626965c18c913829c Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Fri, 22 May 2009 21:10:00 -0400 Subject: [PATCH 003/262] add design classes --- classes/Design.php | 47 ++++++++++++++++++++++++++++++++++++++++++++ classes/laconica.ini | 12 +++++++++++ 2 files changed, 59 insertions(+) create mode 100755 classes/Design.php diff --git a/classes/Design.php b/classes/Design.php new file mode 100755 index 0000000000..cca41ce0cb --- /dev/null +++ b/classes/Design.php @@ -0,0 +1,47 @@ +. + */ + +if (!defined('LACONICA')) { exit(1); } + +/** + * Table Definition for design + */ + +require_once 'classes/Memcached_DataObject'; + +class Design extends Memcached_DataObject +{ + ###START_AUTOCODE + /* the code below is auto generated do not remove the above tag */ + + public $__table = 'design'; // table name + public $id; // int(4) primary_key not_null + public $backgroundcolor; // int(4) + public $contentcolor; // int(4) + public $sidebarcolor; // int(4) + public $textcolor; // int(4) + public $linkcolor; // int(4) + public $backgroundimage; // varchar(255) + + /* Static get */ + function staticGet($k,$v=NULL) { return Memcached_DataObject::staticGet('Design',$k,$v); } + + /* the code above is auto generated do not remove the tag below */ + ###END_AUTOCODE +} diff --git a/classes/laconica.ini b/classes/laconica.ini index 92bbb35d4c..105bc9ec84 100644 --- a/classes/laconica.ini +++ b/classes/laconica.ini @@ -37,6 +37,18 @@ modified = 384 [consumer__keys] consumer_key = K +[design] +id = 129 +backgroundcolor = 1 +contentcolor = 1 +sidebarcolor = 1 +textcolor = 1 +linkcolor = 1 +backgroundimage = 2 + +[design__keys] +id = N + [fave] notice_id = 129 user_id = 129 From 21aad16b58e98f61aded9c102adaef7616a6728f Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Fri, 22 May 2009 21:10:27 -0400 Subject: [PATCH 004/262] fix x bit on Design.php --- classes/Design.php | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 classes/Design.php diff --git a/classes/Design.php b/classes/Design.php old mode 100755 new mode 100644 From 748c744a02ab12f36a275d9020c1b2b5ead9f002 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Fri, 22 May 2009 23:13:09 -0400 Subject: [PATCH 005/262] add a method to Design to show custom CSS --- classes/Design.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/classes/Design.php b/classes/Design.php index cca41ce0cb..c1b6f73e03 100644 --- a/classes/Design.php +++ b/classes/Design.php @@ -44,4 +44,14 @@ class Design extends Memcached_DataObject /* the code above is auto generated do not remove the tag below */ ###END_AUTOCODE + + function showCSS($out) + { + $out->element('stylesheet', array('type' => 'text/css'), + 'body { background-color: #' . dechex($this->backgroundcolor) . '} '."\n". + '#content { background-color #' . dechex($this->contentcolor) . '} '."\n". + '#aside_primary { background-color #'. dechex($this->sidebarcolor) .'} '."\n". + 'html body { color: #'. dechex($this->textcolor) .'} '."\n". + 'a { color: #' . dechex($this->linkcolor) . '} '."\n"); + } } From 3f5252c168de7c0a1ffb9625e3926543c5586c6e Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Fri, 22 May 2009 23:43:08 -0400 Subject: [PATCH 006/262] add fields to support designs for users --- classes/laconica.ini | 3 +++ 1 file changed, 3 insertions(+) mode change 100644 => 100755 classes/laconica.ini diff --git a/classes/laconica.ini b/classes/laconica.ini old mode 100644 new mode 100755 index 105bc9ec84..450af36215 --- a/classes/laconica.ini +++ b/classes/laconica.ini @@ -1,3 +1,4 @@ + [avatar] profile_id = 129 original = 17 @@ -425,6 +426,8 @@ urlshorteningservice = 2 inboxed = 17 created = 142 modified = 384 +design_id = 1 +viewdesigns = 17 [user__keys] id = K From 78564c21d46d56a2cf413b9ba804d5a60430f06e Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Fri, 22 May 2009 23:43:38 -0400 Subject: [PATCH 007/262] schema changes for user support of designs --- db/laconica.sql | 3 +++ 1 file changed, 3 insertions(+) diff --git a/db/laconica.sql b/db/laconica.sql index d42c20e2a1..c87340e8e0 100644 --- a/db/laconica.sql +++ b/db/laconica.sql @@ -41,6 +41,7 @@ create table sms_carrier ( /* local users */ create table user ( + id integer primary key comment 'foreign key to profile table' references profile (id), nickname varchar(64) unique key comment 'nickname or username, duped in profile', password varchar(255) comment 'salted password, can be null for OpenID users', @@ -71,6 +72,8 @@ create table user ( inboxed tinyint default 0 comment 'has an inbox been created for this user?', created datetime not null comment 'date this record was created', modified timestamp comment 'date this record was modified', + design_id integer comment 'id of a design' references design(id), + viewdesigns tinyint default 1 comment 'whether to view user-provided designs', index user_smsemail_idx (smsemail) ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_general_ci; From d92a018cd2b199213cbd66f27dbabb460d3d55c9 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sat, 23 May 2009 22:44:01 -0400 Subject: [PATCH 008/262] get a design for each page --- lib/action.php | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/lib/action.php b/lib/action.php index 6a69d26518..e8aba5b89a 100644 --- a/lib/action.php +++ b/lib/action.php @@ -224,6 +224,16 @@ class Action extends HTMLOutputter // lawsuit 'href="'.theme_path('css/ie.css', null).'?version='.LACONICA_VERSION.'" />getDesign(); + if (!empty($design)) { + $cur = common_current_user(); + if (empty($cur) || $cur->viewdesigns) { + $design->showCSS($this); + } + } + Event::handle('EndShowDesign', array($this, $design)); + } Event::handle('EndShowStyles', array($this)); } } @@ -248,7 +258,6 @@ class Action extends HTMLOutputter // lawsuit 'src' => common_path('js/jquery.joverlay.min.js')), ' '); - Event::handle('EndShowJQueryScripts', array($this)); } if (Event::handle('StartShowLaconicaScripts', array($this))) { @@ -1095,4 +1104,19 @@ class Action extends HTMLOutputter // lawsuit 'title' => _('Previous'))); } } + + /** + * A design for this action + * + * A design (colors and background) for the current page. May be + * the user's design, or a group's design, or a site design. + * + * @return array Feed object to show in head and links + */ + + function getDesign() + { + // XXX: return site design by default + return null; + } } From 4ec5ea510cd5be39c13c2cf3bc9f9c1c8ac5df82 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sat, 23 May 2009 23:09:01 -0400 Subject: [PATCH 009/262] fix return value documentation for getDesign --- lib/action.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/action.php b/lib/action.php index e8aba5b89a..55fb7c0896 100644 --- a/lib/action.php +++ b/lib/action.php @@ -1111,7 +1111,7 @@ class Action extends HTMLOutputter // lawsuit * A design (colors and background) for the current page. May be * the user's design, or a group's design, or a site design. * - * @return array Feed object to show in head and links + * @return Design a design object to use */ function getDesign() From eaac0f8e58774a67fd9257ee0cd46c786cb5718b Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sat, 23 May 2009 23:09:33 -0400 Subject: [PATCH 010/262] add an action base class for actions that show the owner's design --- lib/ownerdesignaction.php | 72 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 lib/ownerdesignaction.php diff --git a/lib/ownerdesignaction.php b/lib/ownerdesignaction.php new file mode 100644 index 0000000000..c47633bdb2 --- /dev/null +++ b/lib/ownerdesignaction.php @@ -0,0 +1,72 @@ +. + * + * @category Action + * @package Laconica + * @author Evan Prodromou + * @copyright 2009 Control Yourself, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://laconi.ca/ + */ + +if (!defined('LACONICA')) { + exit(1); +} + +/** + * Base class for actions that use the page owner's design + * + * Some pages have a clear "owner" -- like the profile page, subscriptions + * pages, etc. This superclass uses that owner's chosen design for the page + * design. + * + * @category Action + * @package Laconica + * @author Evan Prodromou + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://laconi.ca/ + * + */ + +class OwnerDesignAction extends Action { + + /** The user for this page. */ + + var $user = null; + + /** + * A design for this action + * + * if the user attribute has been set, returns that user's + * design. + * + * @return Design a design object to use + */ + + function getDesign() + { + if (empty($this->user)) { + return null; + } + + return $this->user->getDesign(); + } +} From 63ad980767fc10053eea5a5ca009dda65af42de8 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sat, 23 May 2009 23:11:36 -0400 Subject: [PATCH 011/262] current user design action --- lib/currentuserdesignaction.php | 69 +++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 lib/currentuserdesignaction.php diff --git a/lib/currentuserdesignaction.php b/lib/currentuserdesignaction.php new file mode 100644 index 0000000000..2975256557 --- /dev/null +++ b/lib/currentuserdesignaction.php @@ -0,0 +1,69 @@ +. + * + * @category Action + * @package Laconica + * @author Evan Prodromou + * @copyright 2009 Control Yourself, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://laconi.ca/ + */ + +if (!defined('LACONICA')) { + exit(1); +} + +/** + * Base class for actions that use the current user's design + * + * Some pages (settings in particular) use the current user's chosen + * design. This superclass returns that design. + * + * @category Action + * @package Laconica + * @author Evan Prodromou + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://laconi.ca/ + * + */ + +class CurrentUserDesignAction extends Action +{ + /** + * A design for this action + * + * if the user attribute has been set, returns that user's + * design. + * + * @return Design a design object to use + */ + + function getDesign() + { + $cur = common_current_user(); + + if (empty($cur)) { + return null; + } + + return $cur->getDesign(); + } +} From b0e92c75cc19a91e1ea4bbb8009f6f66dc56231b Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sat, 23 May 2009 23:16:52 -0400 Subject: [PATCH 012/262] move design items before timestamps --- db/laconica.sql | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/db/laconica.sql b/db/laconica.sql index c87340e8e0..2ad482abac 100644 --- a/db/laconica.sql +++ b/db/laconica.sql @@ -70,11 +70,12 @@ create table user ( autosubscribe tinyint default 0 comment 'automatically subscribe to users who subscribe to us', urlshorteningservice varchar(50) default 'ur1.ca' comment 'service to use for auto-shortening URLs', inboxed tinyint default 0 comment 'has an inbox been created for this user?', - created datetime not null comment 'date this record was created', - modified timestamp comment 'date this record was modified', design_id integer comment 'id of a design' references design(id), viewdesigns tinyint default 1 comment 'whether to view user-provided designs', + created datetime not null comment 'date this record was created', + modified timestamp comment 'date this record was modified', + index user_smsemail_idx (smsemail) ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_general_ci; From 91fc1e36bc268aa2bd7345206cd0e520d91aac26 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sat, 23 May 2009 23:26:29 -0400 Subject: [PATCH 013/262] update User.php with new design-related fields --- classes/User.php | 7 +++---- classes/laconica.ini | 4 ++-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/classes/User.php b/classes/User.php index ea8ba40817..22090b9867 100644 --- a/classes/User.php +++ b/classes/User.php @@ -62,14 +62,13 @@ class User extends Memcached_DataObject public $autosubscribe; // tinyint(1) public $urlshorteningservice; // varchar(50) default_ur1.ca public $inboxed; // tinyint(1) + public $design_id; // int(4) + public $viewdesigns; // tinyint(1) default_1 public $created; // datetime() not_null public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP /* Static get */ - function staticGet($k,$v=NULL) - { - return Memcached_DataObject::staticGet('User',$k,$v); - } + function staticGet($k,$v=NULL) { return Memcached_DataObject::staticGet('User',$k,$v); } /* the code above is auto generated do not remove the tag below */ ###END_AUTOCODE diff --git a/classes/laconica.ini b/classes/laconica.ini index 450af36215..07aa016fef 100755 --- a/classes/laconica.ini +++ b/classes/laconica.ini @@ -424,10 +424,10 @@ uri = 2 autosubscribe = 17 urlshorteningservice = 2 inboxed = 17 -created = 142 -modified = 384 design_id = 1 viewdesigns = 17 +created = 142 +modified = 384 [user__keys] id = K From 705abf31ee65b821f1c64921005f1814cc83733c Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sat, 23 May 2009 23:27:42 -0400 Subject: [PATCH 014/262] add getDesign to User --- classes/User.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/classes/User.php b/classes/User.php index 22090b9867..8cc8285f1e 100644 --- a/classes/User.php +++ b/classes/User.php @@ -684,4 +684,9 @@ class User extends Memcached_DataObject return ($cnt > 0); } + + function getDesign() + { + return Design::staticGet('id', $this->design_id); + } } From d7e3bab0b81fa7cd7f120e4ff53f89c70c18bad5 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sat, 23 May 2009 23:34:05 -0400 Subject: [PATCH 015/262] fix require_once in Design.php --- classes/Design.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/classes/Design.php b/classes/Design.php index c1b6f73e03..bb1e917e3e 100644 --- a/classes/Design.php +++ b/classes/Design.php @@ -23,7 +23,7 @@ if (!defined('LACONICA')) { exit(1); } * Table Definition for design */ -require_once 'classes/Memcached_DataObject'; +require_once INSTALLDIR.'/classes/Memcached_DataObject.php'; class Design extends Memcached_DataObject { From 9c2f04afc6e70032da5aeb0441e6e0a9b0ffe253 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sat, 23 May 2009 23:35:04 -0400 Subject: [PATCH 016/262] make some of the actions show the user's design --- actions/replies.php | 3 +-- actions/showfavorites.php | 5 +---- actions/usergroups.php | 3 +-- lib/galleryaction.php | 3 +-- lib/profileaction.php | 3 +-- 5 files changed, 5 insertions(+), 12 deletions(-) diff --git a/actions/replies.php b/actions/replies.php index dfb520d649..5d84f6428c 100644 --- a/actions/replies.php +++ b/actions/replies.php @@ -45,9 +45,8 @@ require_once INSTALLDIR.'/lib/feedlist.php'; * @link http://laconi.ca/ */ -class RepliesAction extends Action +class RepliesAction extends OwnerDesignAction { - var $user = null; var $page = null; /** diff --git a/actions/showfavorites.php b/actions/showfavorites.php index eed62a2ab3..839f083dd4 100644 --- a/actions/showfavorites.php +++ b/actions/showfavorites.php @@ -45,10 +45,8 @@ require_once INSTALLDIR.'/lib/feedlist.php'; * @link http://laconi.ca/ */ -class ShowfavoritesAction extends Action +class ShowfavoritesAction extends OwnerDesignAction { - /** User we're getting the faves of */ - var $user = null; /** Page of the faves we're on */ var $page = null; @@ -161,7 +159,6 @@ class ShowfavoritesAction extends Action $this->page, 'showfavorites', array('nickname' => $this->user->nickname)); } - /** * show the personal group nav * diff --git a/actions/usergroups.php b/actions/usergroups.php index e3088dcbd8..7ead6e6e49 100644 --- a/actions/usergroups.php +++ b/actions/usergroups.php @@ -46,9 +46,8 @@ require_once INSTALLDIR.'/lib/grouplist.php'; * @link http://laconi.ca/ */ -class UsergroupsAction extends Action +class UsergroupsAction extends OwnerDesignAction { - var $user = null; var $page = null; var $profile = null; diff --git a/lib/galleryaction.php b/lib/galleryaction.php index 8fa11a7562..498c828514 100644 --- a/lib/galleryaction.php +++ b/lib/galleryaction.php @@ -27,10 +27,9 @@ require_once INSTALLDIR.'/lib/profilelist.php'; define('AVATARS_PER_PAGE', 80); -class GalleryAction extends Action +class GalleryAction extends OwnerDesignAction { var $profile = null; - var $user = null; var $page = null; var $tag = null; diff --git a/lib/profileaction.php b/lib/profileaction.php index a3437ff4dd..a14d3846e6 100644 --- a/lib/profileaction.php +++ b/lib/profileaction.php @@ -47,9 +47,8 @@ require_once INSTALLDIR.'/lib/groupminilist.php'; * @link http://laconi.ca/ */ -class ProfileAction extends Action +class ProfileAction extends OwnerDesignAction { - var $user = null; var $page = null; var $profile = null; var $tag = null; From 91e088d341bc51a41ec310502f85bf0d2398bd90 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sat, 23 May 2009 23:40:11 -0400 Subject: [PATCH 017/262] make some actions CurrentUserDesignActions --- lib/mailbox.php | 8 ++++---- lib/settingsaction.php | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/mailbox.php b/lib/mailbox.php index 01bbf5721a..766510a47b 100644 --- a/lib/mailbox.php +++ b/lib/mailbox.php @@ -47,11 +47,11 @@ define('MESSAGES_PER_PAGE', 20); * @see OutboxAction */ -class MailboxAction extends PersonalAction +class MailboxAction extends CurrentUserDesignAction { var $page = null; - function prepare($args) + function prepare($args) { parent::prepare($args); @@ -265,12 +265,12 @@ class MailboxAction extends PersonalAction * Returns either the name (and link) of the API client that posted the notice, * or one of other other channels. * - * @param string $source the source of the message + * @param string $source the source of the message * * @return void */ - function showSource($source) + function showSource($source) { $source_name = _($source); switch ($source) { diff --git a/lib/settingsaction.php b/lib/settingsaction.php index db20c58043..17d3a2f64d 100644 --- a/lib/settingsaction.php +++ b/lib/settingsaction.php @@ -43,7 +43,7 @@ if (!defined('LACONICA')) { * @see Widget */ -class SettingsAction extends Action +class SettingsAction extends CurrentUserDesignAction { /** * A message for the user. From d60c399d825dc373630042d12f90c01886cc32f5 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sat, 23 May 2009 23:40:27 -0400 Subject: [PATCH 018/262] remove old, unused PersonalAction and StreamAction --- lib/attachmentlist.php | 2 -- lib/noticelist.php | 2 -- lib/personal.php | 60 ------------------------------------------ lib/stream.php | 32 ---------------------- 4 files changed, 96 deletions(-) delete mode 100644 lib/personal.php delete mode 100644 lib/stream.php diff --git a/lib/attachmentlist.php b/lib/attachmentlist.php index 9485fe3d65..8d6d19f2aa 100644 --- a/lib/attachmentlist.php +++ b/lib/attachmentlist.php @@ -46,7 +46,6 @@ if (!defined('LACONICA')) { * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://laconi.ca/ * @see Notice - * @see StreamAction * @see NoticeListItem * @see ProfileNoticeList */ @@ -203,7 +202,6 @@ class AttachmentListItem extends Widget if ($this->attachment->url !== $this->title()) $this->out->element('span', null, " ({$this->attachment->url})"); - $this->out->elementEnd('h4'); } diff --git a/lib/noticelist.php b/lib/noticelist.php index a521321719..ba35265096 100644 --- a/lib/noticelist.php +++ b/lib/noticelist.php @@ -49,7 +49,6 @@ require_once INSTALLDIR.'/lib/disfavorform.php'; * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://laconi.ca/ * @see Notice - * @see StreamAction * @see NoticeListItem * @see ProfileNoticeList */ @@ -231,7 +230,6 @@ else $this->out->elementStart('p', array('class' => 'entry-attachments', 'style' => "float: right; width: $width_att; background: url($clip) no-repeat; text-align: right; height: $height;")); $this->out->element('a', array('class' => $att_class, 'style' => "text-decoration: none; padding-top: $top; display: block; height: $height;", 'href' => $href, 'title' => "# of attachments: $count"), $count === 1 ? '' : $count); - $this->out->elementEnd('p'); } diff --git a/lib/personal.php b/lib/personal.php deleted file mode 100644 index f92732375b..0000000000 --- a/lib/personal.php +++ /dev/null @@ -1,60 +0,0 @@ -. - * - * @category Personal - * @package Laconica - * @author Evan Prodromou - * @author Sarven Capadisli - * @copyright 2008-2009 Control Yourself, Inc. - * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 - * @link http://laconi.ca/ - */ - -if (!defined('LACONICA')) { - exit(1); -} - -/** - * Base class for user profile page - * - * @category Personal - * @package Laconica - * @author Evan Prodromou - * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 - * @link http://laconi.ca/ - */ - -class PersonalAction extends Action -{ - - var $user = null; - - function isReadOnly($args) - { - return true; - } - - function handle($args) - { - parent::handle($args); - } - -} diff --git a/lib/stream.php b/lib/stream.php deleted file mode 100644 index 0cb9e0bf4f..0000000000 --- a/lib/stream.php +++ /dev/null @@ -1,32 +0,0 @@ -. - */ - -if (!defined('LACONICA')) { exit(1); } - -require_once(INSTALLDIR.'/lib/personal.php'); -require_once(INSTALLDIR.'/lib/noticelist.php'); - -class StreamAction extends PersonalAction -{ - function show_notice_list($notice) - { - $nl = new NoticeList($notice); - return $nl->show(); - } -} From 6335c9cf59b384da24506c4a3f799315fbbc4b09 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sat, 23 May 2009 23:42:19 -0400 Subject: [PATCH 019/262] make invite use the current user's design --- actions/invite.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actions/invite.php b/actions/invite.php index 7e52cdbcc6..c793f58249 100644 --- a/actions/invite.php +++ b/actions/invite.php @@ -19,7 +19,7 @@ if (!defined('LACONICA')) { exit(1); } -class InviteAction extends Action +class InviteAction extends CurrentUserDesignAction { var $mode = null; var $error = null; From b3628b78448266fda2368f1317e70d1cca45ac17 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Wed, 27 May 2009 14:49:20 -0400 Subject: [PATCH 020/262] start using design object --- actions/designsettings.php | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/actions/designsettings.php b/actions/designsettings.php index 8d8e5bad88..da88940427 100644 --- a/actions/designsettings.php +++ b/actions/designsettings.php @@ -98,28 +98,18 @@ class DesignsettingsAction extends AccountSettingsAction $this->element('legend', null, _('Change colours')); $this->elementStart('ul', 'form_data'); - //This is a JSON object in the DB field. Here for testing. Remove later. - $userSwatch = '{"body":{"background-color":"#F0F2F5"},'. - '"#content":{"background-color":"#FFFFFF"},'. - '"#aside_primary":{"background-color":"#CEE1E9"},'. - '"html body":{"color":"#000000"},'. - '"a":{"color":"#002E6E"}}'; + $design = $user->getDesign(); - //Default theme swatch -- Where should this be stored? - $defaultSwatch = array('body' => array('background-color' => '#F0F2F5'), - '#content' => array('background-color' => '#FFFFFF'), - '#aside_primary' => array('background-color' => '#CEE1E9'), - 'html body' => array('color' => '#000000'), - 'a' => array('color' => '#002E6E')); + if (empty($design)) { + $design = $this->defaultDesign(); + } - $userSwatch = ($userSwatch) ? json_decode($userSwatch, true) : $defaultSwatch; - - $s = 0; $labelSwatch = array('Background', 'Content', 'Sidebar', 'Text', 'Links'); + foreach($userSwatch as $propertyvalue => $value) { $foo = array_values($value); $this->elementStart('li'); @@ -150,6 +140,7 @@ class DesignsettingsAction extends AccountSettingsAction if submitted Swatch == DefaultSwatch, don't store in DB. else store in BD */ + $this->elementEnd('fieldset'); $this->elementEnd('form'); } From ce6285d0fc117c36716b9b3a74a11d1bfd4e45f3 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Fri, 12 Jun 2009 09:47:57 -0700 Subject: [PATCH 021/262] push length check to Notice class --- classes/Notice.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/classes/Notice.php b/classes/Notice.php index b4c86ebeb5..bca4b22c4c 100644 --- a/classes/Notice.php +++ b/classes/Notice.php @@ -123,7 +123,12 @@ class Notice extends Memcached_DataObject $profile = Profile::staticGet($profile_id); - $final = common_shorten_links($content); + $final = common_shorten_links($content); + + if (mb_strlen($final) > 140) { + common_log(LOG_INFO, 'Rejecting notice that is too long.'); + return _('Problem saving notice. Too long.'); + } if (!$profile) { common_log(LOG_ERR, 'Problem saving notice. Unknown user.'); From 1c41afbd36580e2d5ad110bfb5ae0da53a7895b2 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Fri, 12 Jun 2009 09:48:12 -0700 Subject: [PATCH 022/262] check results of add in maildaemon.php --- scripts/maildaemon.php | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/scripts/maildaemon.php b/scripts/maildaemon.php index b9facec1a5..9dd647bf46 100755 --- a/scripts/maildaemon.php +++ b/scripts/maildaemon.php @@ -66,7 +66,13 @@ class MailerDaemon return true; } $msg = $this->cleanup_msg($msg); - $this->add_notice($user, $msg); + $err = $this->add_notice($user, $msg); + if (is_string($err)) { + $this->error($from, $err); + return false; + } else { + return true; + } } function error($from, $msg) @@ -130,17 +136,15 @@ class MailerDaemon function add_notice($user, $msg) { - // should test - // $msg_shortened = common_shorten_links($msg); - // if (mb_strlen($msg_shortened) > 140) ERROR and STOP $notice = Notice::saveNew($user->id, $msg, 'mail'); if (is_string($notice)) { $this->log(LOG_ERR, $notice); - return; + return $notice; } common_broadcast_notice($notice); $this->log(LOG_INFO, 'Added notice ' . $notice->id . ' from user ' . $user->nickname); + return true; } function parse_message($fname) From 946d016df2a5e0af5e1b4b983b30c113dd02b4ea Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Sun, 14 Jun 2009 02:03:50 -0700 Subject: [PATCH 023/262] Reworked output for design settings page --- actions/designsettings.php | 162 +++++++++++++++++++++++++++++-------- lib/common.php | 7 ++ 2 files changed, 135 insertions(+), 34 deletions(-) diff --git a/actions/designsettings.php b/actions/designsettings.php index 66476e6777..8595cbc4c6 100644 --- a/actions/designsettings.php +++ b/actions/designsettings.php @@ -22,6 +22,7 @@ * @category Settings * @package Laconica * @author Sarven Capadisli + * @author Zach Copley * @copyright 2008-2009 Control Yourself, Inc. * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://laconi.ca/ @@ -104,42 +105,73 @@ class DesignsettingsAction extends AccountSettingsAction $design = $this->defaultDesign(); } - $labelSwatch = array('Background', - 'Content', - 'Sidebar', - 'Text', - 'Links'); + $this->elementStart('li'); + $this->element('label', array('for' => 'swatch-5'), _('Background')); + $this->element('input', array('name' => 'design_background', + 'type' => 'text', + 'id' => 'swatch-5', + 'class' => 'swatch', + 'maxlength' => '7', + 'size' => '7', + 'value' => $design->backgroundcolor)); + $this->elementEnd('li'); + + $this->elementStart('li'); + $this->element('label', array('for' => 'swatch-1'), _('Content')); + $this->element('input', array('name' => 'design_content', + 'type' => 'text', + 'id' => 'swatch-1', + 'class' => 'swatch', + 'maxlength' => '7', + 'size' => '7', + 'value' => $design->contentcolor)); + $this->elementEnd('li'); + + $this->elementStart('li'); + $this->element('label', array('for' => 'swatch-2'), _('Sidebar')); + $this->element('input', array('name' => 'design_sidebar', + 'type' => 'text', + 'id' => 'swatch-2', + 'class' => 'swatch', + 'maxlength' => '7', + 'size' => '7', + 'value' => $design->sidebarcolor)); + $this->elementEnd('li'); - foreach($userSwatch as $propertyvalue => $value) { - $foo = array_values($value); - $this->elementStart('li'); - $this->element('label', array('for' => 'swatch-'.$s), _($labelSwatch[$s])); - $this->element('input', array('name' => 'swatch-'.$s, //prefer swatch[$s] ? - 'type' => 'text', - 'id' => 'swatch-'.$s, - 'class' => 'swatch', - 'maxlength' => '7', - 'size' => '7', - 'value' => $foo[0])); - $this->elementEnd('li'); - $s++; - } + $this->elementStart('li'); + $this->element('label', array('for' => 'swatch-3'), _('Text')); + $this->element('input', array('name' => 'design_text', + 'type' => 'text', + 'id' => 'swatch-3', + 'class' => 'swatch', + 'maxlength' => '7', + 'size' => '7', + 'value' => $design->textcolor)); + $this->elementEnd('li'); - $this->elementEnd('ul'); - $this->elementEnd('fieldset'); + $this->elementStart('li'); + $this->element('label', array('for' => 'swatch-4'), _('Links')); + $this->element('input', array('name' => 'design_links', + 'type' => 'text', + 'id' => 'swatch-4', + 'class' => 'swatch', + 'maxlength' => '7', + 'size' => '7', + 'value' => $design->linkcolor)); - $this->element('input', array('id' => 'settings_design_reset', - 'type' => 'reset', - 'value' => 'Reset', - 'class' => 'submit form_action-primary', - 'title' => _('Reset back to default'))); - $this->submit('save', _('Save'), 'submit form_action-secondary', 'save', _('Save design')); + $this->elementEnd('li'); - /*TODO: Check submitted form values: - json_encode(form values) - if submitted Swatch == DefaultSwatch, don't store in DB. - else store in BD - */ + $this->elementEnd('ul'); + $this->elementEnd('fieldset'); + + $this->element('input', array('id' => 'settings_design_reset', + 'type' => 'reset', + 'value' => 'Reset', + 'class' => 'submit form_action-primary', + 'title' => _('Reset back to default'))); + + $this->submit('save', _('Save'), 'submit form_action-secondary', + 'save', _('Save design')); $this->elementEnd('fieldset'); $this->elementEnd('form'); @@ -156,8 +188,21 @@ class DesignsettingsAction extends AccountSettingsAction function handlePost() { - // TODO: implement this - return; + // CSRF protection + $token = $this->trimmed('token'); + if (!$token || $token != common_session_token()) { + $this->showForm(_('There was a problem with your session token. '. + 'Try again, please.')); + return; + } + + if ($this->arg('save')) { + $this->saveDesign(); + } else if ($this->arg('reset')) { + $this->resetDesign(); + } else { + $this->showForm(_('Unexpected form submission.')); + } } /** @@ -196,4 +241,53 @@ class DesignsettingsAction extends AccountSettingsAction $this->element('script', array('type' => 'text/javascript', 'src' => $farbtasticGo)); } + + /** + * Get a default user design + * + * @return Design design + */ + + function defaultDesign() + { + $defaults = common_config('site', 'design'); + + $design = new Design(); + $design->backgroundcolor = $defaults['backgroundcolor']; + $design->contentcolor = $defaults['contentcolor']; + $design->sidebarcolor = $defaults['sidebarcolor']; + $design->textcolor = $defaults['textcolor']; + $design->linkcolor = $defaults['linkcolor']; + $design->backgroundimage = $defaults['backgroundimage']; + + return $design; + } + + /** + * Save the user's design settings + * + * @return void + */ + + function saveDesign() + { + $user = common_current_user(); + + + + $this->showForm(_('Design preferences saved.'), true); + } + + /** + * Reset design settings to previous saved value if any, or + * the defaults + * + * @return void + */ + + function resetDesign() + { + $this->showForm(_('Design preferences reset.'), true); + } + } diff --git a/lib/common.php b/lib/common.php index 5aafdfe0ee..a55fb264e1 100644 --- a/lib/common.php +++ b/lib/common.php @@ -72,6 +72,13 @@ $config = 'server' => $_server, 'theme' => 'default', 'skin' => 'default', + 'design' => + array('backgroundcolor' => '#F0F2F5', + 'contentcolor' => '#FFFFFF', + 'sidebarcolor' => '#CEE1E9', + 'textcolor' => '#000000', + 'linkcolor' => '#002E6E', + 'backgroundimage' => null), 'path' => $_path, 'logfile' => null, 'logo' => null, From 754b610ac4e4478cd36e5826f6bbfcad0531b7aa Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 14 Jun 2009 12:04:45 -0700 Subject: [PATCH 024/262] added group_block table to database --- db/laconica.sql | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/db/laconica.sql b/db/laconica.sql index a11e316925..3ffe1ed814 100644 --- a/db/laconica.sql +++ b/db/laconica.sql @@ -482,3 +482,13 @@ create table file_to_post ( unique(file_id, post_id) ) 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; From 85b74d846dda8781c7e713b403c1229124480d12 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 14 Jun 2009 12:06:22 -0700 Subject: [PATCH 025/262] create DB_DataObject classes for group block --- classes/Group_block.php | 23 +++++++++++++++++++++++ classes/laconica.ini | 11 +++++++++++ 2 files changed, 34 insertions(+) create mode 100755 classes/Group_block.php mode change 100644 => 100755 classes/laconica.ini diff --git a/classes/Group_block.php b/classes/Group_block.php new file mode 100755 index 0000000000..437046a9c3 --- /dev/null +++ b/classes/Group_block.php @@ -0,0 +1,23 @@ + Date: Sun, 14 Jun 2009 12:07:12 -0700 Subject: [PATCH 026/262] fix perms on Group_block classes --- classes/Group_block.php | 0 classes/laconica.ini | 0 2 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 classes/Group_block.php mode change 100755 => 100644 classes/laconica.ini diff --git a/classes/Group_block.php b/classes/Group_block.php old mode 100755 new mode 100644 diff --git a/classes/laconica.ini b/classes/laconica.ini old mode 100755 new mode 100644 From 7c772e1d634badcbb9960f5a8c4398ae2f8cdd57 Mon Sep 17 00:00:00 2001 From: Robin Millette Date: Sun, 14 Jun 2009 15:48:46 -0400 Subject: [PATCH 027/262] Removed another bit of dead (commented out) code. --- lib/noticelist.php | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/lib/noticelist.php b/lib/noticelist.php index fadc238a4d..c312292aba 100644 --- a/lib/noticelist.php +++ b/lib/noticelist.php @@ -206,24 +206,10 @@ class NoticeListItem extends Widget return 'shownotice' !== $this->out->args['action']; } -/* - function attachmentCount($discriminant = true) { - $file_oembed = new File_oembed; - $query = "select count(*) as c from file_oembed join file_to_post on file_oembed.file_id = file_to_post.file_id where post_id=" . $this->notice->id; - $file_oembed->query($query); - $file_oembed->fetch(); - return intval($file_oembed->c); - } -*/ - - function showWithAttachment() { - } - function showNoticeInfo() { $this->out->elementStart('div', 'entry-content'); $this->showNoticeLink(); -// $this->showWithAttachment(); $this->showNoticeSource(); $this->showContext(); $this->out->elementEnd('div'); From 21e89d6f724fe8d54788a73b4b8325fdef647af3 Mon Sep 17 00:00:00 2001 From: Robin Millette Date: Sun, 14 Jun 2009 16:06:52 -0400 Subject: [PATCH 028/262] Commented all .sql fields for file/url related tables. --- db/laconica.sql | 55 +++++++++++++++++++++++++------------------------ 1 file changed, 28 insertions(+), 27 deletions(-) diff --git a/db/laconica.sql b/db/laconica.sql index a11e316925..7f52a5ef7f 100644 --- a/db/laconica.sql +++ b/db/laconica.sql @@ -427,49 +427,50 @@ create table group_inbox ( create table file ( id integer primary key auto_increment, - url varchar(255), mimetype varchar(50), - size integer, - title varchar(255), - date integer(11), - protected integer(1), + 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)', unique(url) ) ENGINE=MyISAM CHARACTER SET utf8 COLLATE utf8_general_ci; create table file_oembed ( id integer primary key auto_increment, - file_id integer, - version varchar(20), - type varchar(20), - provider varchar(50), - provider_url varchar(255), - width integer, - height integer, - html text, - title varchar(255), - author_name varchar(50), - author_url varchar(255), - url varchar(255), + file_id integer 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)', unique(file_id) ) ENGINE=MyISAM CHARACTER SET utf8 COLLATE utf8_general_ci; create table file_redirection ( id integer primary key auto_increment, - url varchar(255), - file_id integer, - redirections integer, - httpcode integer, + url varchar(255) 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.)', unique(url) ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin; create table file_thumbnail ( id integer primary key auto_increment, - file_id integer, - url varchar(255), - width integer, - height integer, + file_id integer 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', unique(file_id), unique(url) @@ -477,8 +478,8 @@ create table file_thumbnail ( create table file_to_post ( id integer primary key auto_increment, - file_id integer, - post_id integer, + 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), unique(file_id, post_id) ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin; From 9addfeacfdacf1eb8c6a90a636f468e4aeb0e9fe Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 14 Jun 2009 14:01:11 -0700 Subject: [PATCH 029/262] better handling of PEAR errors --- index.php | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/index.php b/index.php index 4eff99dff5..f5b32ea090 100644 --- a/index.php +++ b/index.php @@ -48,13 +48,18 @@ function handleError($error) $logmsg .= " : ". $error->getDebugInfo(); } common_log(LOG_ERR, $logmsg); - $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, '. - 'but you can contact them at %s to make sure. '. - 'Otherwise, wait a few minutes and try again.'), - common_config('site', 'name'), - common_config('site', 'email')); + if ($error instanceof DB_DataObject_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, '. + 'but you can contact them at %s to make sure. '. + 'Otherwise, wait a few minutes and try again.'), + common_config('site', 'name'), + common_config('site', 'email')); + } else { + $msg = _('An important error occured, probably related to email setup. '. + 'Check logfiles for more info..'); + } $dac = new DBErrorAction($msg, 500); $dac->showPage(); @@ -70,7 +75,7 @@ function main() global $user, $action, $config; Snapshot::check(); - + if (!_have_config()) { $msg = sprintf(_("No configuration file found. Try running ". "the installation program first.")); From c2dae24701a22cd2362ebe1a96828cd7945c6b5a Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 14 Jun 2009 14:52:26 -0700 Subject: [PATCH 030/262] Break profilelist into a recipe Expanded the ProfileList class so it worked more like a recipe. This helps to get rid of a lot of special cases and simplifies the code. It also makes it possible to do things like group block. --- actions/groupmembers.php | 14 +++- actions/showgroup.php | 2 +- actions/subscribers.php | 38 ++++++--- actions/subscriptions.php | 34 ++++++-- lib/peoplesearchresults.php | 17 ++-- lib/profileaction.php | 4 +- lib/profilelist.php | 160 ++++++++++++++++++++---------------- lib/profileminilist.php | 23 ++---- 8 files changed, 179 insertions(+), 113 deletions(-) diff --git a/actions/groupmembers.php b/actions/groupmembers.php index 21e5ebbaa1..53fee31292 100644 --- a/actions/groupmembers.php +++ b/actions/groupmembers.php @@ -127,7 +127,7 @@ class GroupmembersAction extends Action $members = $this->group->getMembers($offset, $limit); if ($members) { - $member_list = new ProfileList($members, null, $this); + $member_list = new GroupMemberList($members, $this->group, $this); $cnt = $member_list->show(); } @@ -138,3 +138,15 @@ class GroupmembersAction extends Action array('nickname' => $this->group->nickname)); } } + +class GroupMemberList extends ProfileList { + + var $group = null; + + function __construct($profile, $group=null, $action=null) + { + parent::__construct($profile, $action); + + $this->group = $group; + } +} diff --git a/actions/showgroup.php b/actions/showgroup.php index 29b6fa1e61..3ce45adc67 100644 --- a/actions/showgroup.php +++ b/actions/showgroup.php @@ -344,7 +344,7 @@ class ShowgroupAction extends Action $this->element('h2', null, _('Members')); - $pml = new ProfileMiniList($member, null, $this); + $pml = new ProfileMiniList($member, $this); $cnt = $pml->show(); if ($cnt == 0) { $this->element('p', null, _('(None)')); diff --git a/actions/subscribers.php b/actions/subscribers.php index 4482de9a7c..66ac00fb19 100644 --- a/actions/subscribers.php +++ b/actions/subscribers.php @@ -130,18 +130,34 @@ class SubscribersAction extends GalleryAction } } -class SubscribersList extends ProfileList +class SubscribersList extends SubscriptionList { - function showBlockForm() + function newListItem($profile) { - $bf = new BlockForm($this->out, $this->profile, - array('action' => 'subscribers', - 'nickname' => $this->owner->nickname)); - $bf->show(); - } - - function isReadOnly($args) - { - return true; + return new SubscribersListItem($profile, $this->owner, $this->action); + } +} + +class SubscribersListItem extends SubscriptionListItem +{ + function showActions() + { + $this->startActions(); + $this->showSubscribeButton(); + // Relevant code! + $this->showBlockForm(); + $this->endActions(); + } + + function showBlockForm() + { + $user = common_current_user(); + + if (!empty($user) && $this->owner->id == $user->id) { + $bf = new BlockForm($this->out, $this->profile, + array('action' => 'subscribers', + 'nickname' => $this->owner->nickname)); + $bf->show(); + } } } diff --git a/actions/subscriptions.php b/actions/subscriptions.php index 095b18ad87..4124abea4d 100644 --- a/actions/subscriptions.php +++ b/actions/subscriptions.php @@ -137,22 +137,46 @@ class SubscriptionsAction extends GalleryAction } } -class SubscriptionsList extends ProfileList +// XXX SubscriptionsList and SubscriptionList are dangerously close + +class SubscriptionsList extends SubscriptionList { - function showOwnerControls($profile) + function newListItem($profile) + { + return new SubscriptionsListItem($profile, $this->owner, $this->action); + } +} + +class SubscriptionsListItem extends SubscriptionListItem +{ + function showProfile() + { + $this->startProfile(); + $this->showAvatar(); + $this->showFullName(); + $this->showLocation(); + $this->showHomepage(); + $this->showBio(); + $this->showTags(); + // Relevant portion! + $this->showOwnerControls(); + $this->endProfile(); + } + + function showOwnerControls() { $sub = Subscription::pkeyGet(array('subscriber' => $this->owner->id, - 'subscribed' => $profile->id)); + 'subscribed' => $this->profile->id)); if (!$sub) { return; } - $this->out->elementStart('form', array('id' => 'subedit-' . $profile->id, + $this->out->elementStart('form', array('id' => 'subedit-' . $this->profile->id, 'method' => 'post', 'class' => 'form_subscription_edit', 'action' => common_local_url('subedit'))); $this->out->hidden('token', common_session_token()); - $this->out->hidden('profile', $profile->id); + $this->out->hidden('profile', $this->profile->id); $this->out->checkbox('jabber', _('Jabber'), $sub->jabber); $this->out->checkbox('sms', _('SMS'), $sub->sms); $this->out->submit('save', _('Save')); diff --git a/lib/peoplesearchresults.php b/lib/peoplesearchresults.php index d3f8408525..9d9d172993 100644 --- a/lib/peoplesearchresults.php +++ b/lib/peoplesearchresults.php @@ -56,20 +56,25 @@ class PeopleSearchResults extends ProfileList function __construct($profile, $terms, $action) { - parent::__construct($profile, $terms, $action); + parent::__construct($profile, $action); + $this->terms = array_map('preg_quote', array_map('htmlspecialchars', $terms)); + $this->pattern = '/('.implode('|',$terms).')/i'; } + function newProfileItem($profile) + { + return new PeopleSearchResultItem($profile, $this->action); + } +} + +class PeopleSearchResultItem extends ProfileListItem +{ function highlight($text) { return preg_replace($this->pattern, '\\1', htmlspecialchars($text)); } - - function isReadOnly($args) - { - return true; - } } diff --git a/lib/profileaction.php b/lib/profileaction.php index a3437ff4dd..298f34b221 100644 --- a/lib/profileaction.php +++ b/lib/profileaction.php @@ -110,7 +110,7 @@ class ProfileAction extends Action $this->element('h2', null, _('Subscriptions')); if ($profile) { - $pml = new ProfileMiniList($profile, $this->user, $this); + $pml = new ProfileMiniList($profile, $this); $cnt = $pml->show(); if ($cnt == 0) { $this->element('p', null, _('(None)')); @@ -139,7 +139,7 @@ class ProfileAction extends Action $this->element('h2', null, _('Subscribers')); if ($profile) { - $pml = new ProfileMiniList($profile, $this->user, $this); + $pml = new ProfileMiniList($profile, $this); $cnt = $pml->show(); if ($cnt == 0) { $this->element('p', null, _('(None)')); diff --git a/lib/profilelist.php b/lib/profilelist.php index a4cc235552..e2faf10af4 100644 --- a/lib/profilelist.php +++ b/lib/profilelist.php @@ -49,23 +49,19 @@ class ProfileList extends Widget { /** Current profile, profile query. */ var $profile = null; - /** Owner of this list */ - var $owner = null; /** Action object using us. */ var $action = null; - function __construct($profile, $owner=null, $action=null) + function __construct($profile, $action=null) { parent::__construct($action); $this->profile = $profile; - $this->owner = $owner; $this->action = $action; } function show() { - $this->out->elementStart('ul', 'profiles'); $cnt = 0; @@ -75,7 +71,8 @@ class ProfileList extends Widget if($cnt > PROFILES_PER_PAGE) { break; } - $this->showProfile(); + $pli = $this->newListItem($this->profile); + $pli->show(); } $this->out->elementEnd('ul'); @@ -83,16 +80,59 @@ class ProfileList extends Widget return $cnt; } - function showProfile() + function newListItem($profile) + { + return new ProfileListItem($this->profile, $this->action); + } +} + +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() + { + $this->startItem(); + $this->showProfile(); + $this->showActions(); + $this->endItem(); + } + + function startItem() { $this->out->elementStart('li', array('class' => 'profile', 'id' => 'profile-' . $this->profile->id)); + } - $user = common_current_user(); - $is_own = !is_null($user) && isset($this->owner) && ($user->id === $this->owner->id); + function showProfile() + { + $this->startProfile(); + $this->showAvatar(); + $this->showFullName(); + $this->showLocation(); + $this->showHomepage(); + $this->showBio(); + $this->endProfile(); + } + function startProfile() + { $this->out->elementStart('div', 'entity_profile vcard'); + } + function showAvatar() + { $avatar = $this->profile->getAvatar(AVATAR_STREAM_SIZE); $this->out->elementStart('a', array('href' => $this->profile->profileurl, 'class' => 'url')); @@ -108,7 +148,10 @@ class ProfileList extends Widget $this->out->raw($this->highlight($this->profile->nickname)); $this->out->elementEnd('span'); $this->out->elementEnd('a'); + } + function showFullName() + { if (!empty($this->profile->fullname)) { $this->out->elementStart('dl', 'entity_fn'); $this->out->element('dt', null, 'Full name'); @@ -119,6 +162,10 @@ class ProfileList extends Widget $this->out->elementEnd('dd'); $this->out->elementEnd('dl'); } + } + + function showLocation() + { if (!empty($this->profile->location)) { $this->out->elementStart('dl', 'entity_location'); $this->out->element('dt', null, _('Location')); @@ -127,6 +174,10 @@ class ProfileList extends Widget $this->out->elementEnd('dd'); $this->out->elementEnd('dl'); } + } + + function showHomepage() + { if (!empty($this->profile->homepage)) { $this->out->elementStart('dl', 'entity_url'); $this->out->element('dt', null, _('URL')); @@ -138,6 +189,10 @@ class ProfileList extends Widget $this->out->elementEnd('dd'); $this->out->elementEnd('dl'); } + } + + function showBio() + { if (!empty($this->profile->bio)) { $this->out->elementStart('dl', 'entity_note'); $this->out->element('dt', null, _('Note')); @@ -146,57 +201,33 @@ class ProfileList extends Widget $this->out->elementEnd('dd'); $this->out->elementEnd('dl'); } + } - # If we're on a list with an owner (subscriptions or subscribers)... - - if ($this->owner) { - # Get tags - $tags = Profile_tag::getTags($this->owner->id, $this->profile->id); - - $this->out->elementStart('dl', 'entity_tags'); - $this->out->elementStart('dt'); - if ($is_own) { - $this->out->element('a', array('href' => common_local_url('tagother', - array('id' => $this->profile->id))), - _('Tags')); - } else { - $this->out->text(_('Tags')); - } - $this->out->elementEnd('dt'); - $this->out->elementStart('dd'); - if ($tags) { - $this->out->elementStart('ul', 'tags xoxo'); - foreach ($tags as $tag) { - $this->out->elementStart('li'); - $this->out->element('span', 'mark_hash', '#'); - $this->out->element('a', array('rel' => 'tag', - 'href' => common_local_url($this->action->trimmed('action'), - array('nickname' => $this->owner->nickname, - 'tag' => $tag))), - $tag); - $this->out->elementEnd('li'); - } - $this->out->elementEnd('ul'); - } else { - $this->out->text(_('(none)')); - } - $this->out->elementEnd('dd'); - $this->out->elementEnd('dl'); - } - - if ($is_own) { - $this->showOwnerControls($this->profile); - } - + function endProfile() + { $this->out->elementEnd('div'); + } + function showActions() + { + $this->startActions(); + $this->showSubscribeButton(); + $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)) { @@ -207,33 +238,22 @@ class ProfileList extends Widget $sf->show(); } $this->out->elementEnd('li'); - $this->out->elementStart('li', 'entity_block'); - if ($user->id == $this->owner->id) { - $this->showBlockForm(); - } - $this->out->elementEnd('li'); } - - $this->out->elementEnd('ul'); - - $this->out->elementEnd('div'); - - $this->out->elementEnd('li'); } - /* Override this in subclasses. */ - - function showOwnerControls($profile) + function endActions() { - return; + $this->out->elementEnd('ul'); + $this->out->elementEnd('div'); + } + + function endItem() + { + $this->out->elementEnd('li'); } function highlight($text) { return htmlspecialchars($text); } - - function showBlockForm() - { - } } diff --git a/lib/profileminilist.php b/lib/profileminilist.php index 57496d0e97..f11cae8a5f 100644 --- a/lib/profileminilist.php +++ b/lib/profileminilist.php @@ -47,26 +47,15 @@ define('PROFILES_PER_MINILIST', 27); class ProfileMiniList extends ProfileList { - function show() + function newListItem($profile) { - $this->out->elementStart('ul', 'entities users xoxo'); - - $cnt = 0; - - while ($this->profile->fetch()) { - $cnt++; - if($cnt > PROFILES_PER_MINILIST) { - break; - } - $this->showProfile(); - } - - $this->out->elementEnd('ul'); - - return $cnt; + return new ProfileMiniListItem($profile, $this->action); } +} - function showProfile() +class ProfileMiniListItem extends ProfileListItem +{ + function show() { $this->out->elementStart('li', 'vcard'); $this->out->elementStart('a', array('title' => $this->profile->getBestName(), From b6ef8e735b8deeaf3e11a03574888a479b1679b7 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 14 Jun 2009 14:53:42 -0700 Subject: [PATCH 031/262] base class SubscriptionList for some actions --- lib/subscriptionlist.php | 131 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 lib/subscriptionlist.php diff --git a/lib/subscriptionlist.php b/lib/subscriptionlist.php new file mode 100644 index 0000000000..23da64cca8 --- /dev/null +++ b/lib/subscriptionlist.php @@ -0,0 +1,131 @@ +. + * + * @category Public + * @package Laconica + * @author Evan Prodromou + * @copyright 2008-2009 Control Yourself, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://laconi.ca/ + */ + +if (!defined('LACONICA')) { + exit(1); +} + +require_once INSTALLDIR.'/lib/profilelist.php'; + +/** + * Widget to show a list of subscriptions + * + * @category Public + * @package Laconica + * @author Zach Copley + * @author Evan Prodromou + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://laconi.ca/ + */ + +class SubscriptionList extends ProfileList +{ + /** Owner of this list */ + var $owner = null; + + function __construct($profile, $owner=null, $action=null) + { + parent::__construct($profile, $action); + + $this->owner = $owner; + } + + function newListItem($profile) + { + return new SubscriptionListItem($profile, $this->owner, $this->action); + } +} + +class SubscriptionListItem extends ProfileListItem +{ + /** Owner of this list */ + var $owner = null; + + function __construct($profile, $owner, $action) + { + parent::__construct($profile, $action); + + $this->owner = $owner; + } + + function showProfile() + { + $this->startProfile(); + $this->showAvatar(); + $this->showFullName(); + $this->showLocation(); + $this->showHomepage(); + $this->showBio(); + // Relevant portion! + $this->showTags(); + $this->endProfile(); + } + + function isOwn() + { + $user = common_current_user(); + return (!empty($user) && ($this->owner->id == $user->id)); + } + + function showTags() + { + $tags = Profile_tag::getTags($this->owner->id, $this->profile->id); + + $this->out->elementStart('dl', 'entity_tags'); + $this->out->elementStart('dt'); + if ($this->isOwn()) { + $this->out->element('a', array('href' => common_local_url('tagother', + array('id' => $this->profile->id))), + _('Tags')); + } else { + $this->out->text(_('Tags')); + } + $this->out->elementEnd('dt'); + $this->out->elementStart('dd'); + if ($tags) { + $this->out->elementStart('ul', 'tags xoxo'); + foreach ($tags as $tag) { + $this->out->elementStart('li'); + $this->out->element('span', 'mark_hash', '#'); + $this->out->element('a', array('rel' => 'tag', + 'href' => common_local_url($this->action->trimmed('action'), + array('nickname' => $this->owner->nickname, + 'tag' => $tag))), + $tag); + $this->out->elementEnd('li'); + } + $this->out->elementEnd('ul'); + } else { + $this->out->text(_('(none)')); + } + $this->out->elementEnd('dd'); + $this->out->elementEnd('dl'); + } +} From b6dee88e5d0a0ed58391ccb8868f4afbf631342a Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 14 Jun 2009 15:08:00 -0700 Subject: [PATCH 032/262] add UI for blocking a user from a group --- actions/groupmembers.php | 172 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 169 insertions(+), 3 deletions(-) diff --git a/actions/groupmembers.php b/actions/groupmembers.php index 53fee31292..079dad9e94 100644 --- a/actions/groupmembers.php +++ b/actions/groupmembers.php @@ -139,14 +139,180 @@ class GroupmembersAction extends Action } } -class GroupMemberList extends ProfileList { - +class GroupMemberList extends ProfileList +{ var $group = null; - function __construct($profile, $group=null, $action=null) + function __construct($profile, $group, $action) { parent::__construct($profile, $action); $this->group = $group; } + + function newListItem($profile) + { + return new GroupMemberListItem($profile, $this->group, $this->action); + } +} + +class GroupMemberListItem extends ProfileListItem +{ + var $group = null; + + function __construct($profile, $group, $action) + { + parent::__construct($profile, $action); + + $this->group = $group; + } + + function showActions() + { + $this->startActions(); + $this->showSubscribeButton(); + $this->showGroupBlockForm(); + $this->endActions(); + } + + function showGroupBlockForm() + { + $user = common_current_user(); + + if (!empty($user) && $user->id != $this->profile->id && $user->isAdmin($this->group)) { + $bf = new GroupBlockForm($this->out, $this->profile, + array('action' => 'groupmembers', + 'nickname' => $this->group->nickname)); + $bf->show(); + } + + } +} + +/** + * Form for blocking a user from a group + * + * @category Form + * @package Laconica + * @author Evan Prodromou + * @author Sarven Capadisli + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://laconi.ca/ + * + * @see BlockForm + */ + +class GroupBlockForm extends Form +{ + /** + * Profile of user to block + */ + + var $profile = null; + + /** + * Group to block the user from + */ + + var $group = null; + + /** + * Return-to args + */ + + var $args = null; + + /** + * Constructor + * + * @param HTMLOutputter $out output channel + * @param Profile $profile profile of user to block + * @param User_group $group group to block user from + * @param array $args return-to args + */ + + function __construct($out=null, $profile=null, $group=null, $args=null) + { + parent::__construct($out); + + $this->profile = $profile; + $this->group = $group; + $this->args = $args; + } + + /** + * ID of the form + * + * @return int ID of the form + */ + + function id() + { + // This should be unique for the page. + return 'block-' . $this->profile->id; + } + + /** + * class of the form + * + * @return string class of the form + */ + + function formClass() + { + return 'form_group_block'; + } + + /** + * Action of the form + * + * @return string URL of the action + */ + + function action() + { + return common_local_url('groupblock'); + } + + /** + * Legend of the Form + * + * @return void + */ + function formLegend() + { + $this->out->element('legend', null, _('Block user from group')); + } + + /** + * Data elements of the form + * + * @return void + */ + + function formData() + { + $this->out->hidden('blockto-' . $this->profile->id, + $this->profile->id, + 'blockto'); + $this->out->hidden('blockgroup-' . $this->group->id, + $this->group->id, + 'blockgroup'); + if ($this->args) { + foreach ($this->args as $k => $v) { + $this->out->hidden('returnto-' . $k, $v); + } + } + } + + /** + * Action elements + * + * @return void + */ + + function formActions() + { + $this->out->submit('submit', _('Block'), 'submit', null, _('Block this user')); + } } From d3a0c524cce9be65b8e45280168cf3584a60f81c Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 14 Jun 2009 15:40:42 -0700 Subject: [PATCH 033/262] Make group block work --- actions/groupblock.php | 215 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 215 insertions(+) create mode 100644 actions/groupblock.php diff --git a/actions/groupblock.php b/actions/groupblock.php new file mode 100644 index 0000000000..93662da799 --- /dev/null +++ b/actions/groupblock.php @@ -0,0 +1,215 @@ + + * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 + * @link http://laconi.ca/ + * + * Laconica - a distributed open-source microblogging tool + * Copyright (C) 2008, Controlez-Vous, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +if (!defined('LACONICA')) { + exit(1); +} + +/** + * Block a user from a group + * + * @category Action + * @package Laconica + * @author Evan Prodromou + * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 + * @link http://laconi.ca/ + */ + +class GroupblockAction extends Action +{ + var $profile = null; + var $group = null; + + /** + * Take arguments for running + * + * @param array $args $_REQUEST args + * + * @return boolean success flag + */ + + function prepare($args) + { + parent::prepare($args); + if (!common_logged_in()) { + $this->clientError(_('Not logged in.')); + return false; + } + $token = $this->trimmed('token'); + if (empty($token) || $token != common_session_token()) { + $this->clientError(_('There was a problem with your session token. Try again, please.')); + return; + } + $id = $this->trimmed('blockto'); + if (empty($id)) { + $this->clientError(_('No profile specified.')); + return false; + } + $this->profile = Profile::staticGet('id', $id); + if (empty($this->profile)) { + $this->clientError(_('No profile with that ID.')); + return false; + } + $group_id = $this->trimmed('blockgroup'); + if (empty($group_id)) { + $this->clientError(_('No group specified.')); + return false; + } + $this->group = User_group::staticGet('id', $group_id); + if (empty($this->group)) { + $this->clientError(_('No such group.')); + return false; + } + $user = common_current_user(); + if (!$user->isAdmin($this->group)) { + $this->clientError(_('Only an admin can block group members.'), 401); + return false; + } + if (Group_block::isBlocked($this->group, $this->profile)) { + $this->clientError(_('User is already blocked from group.')); + return false; + } + // XXX: could have proactive blocks, but we don't have UI for it. + if (!$this->profile->isMember($this->group)) { + $this->clientError(_('User is not a member of group.')); + return false; + } + return true; + } + + /** + * Handle request + * + * Shows a page with list of favorite notices + * + * @param array $args $_REQUEST args; handled in prepare() + * + * @return void + */ + function handle($args) + { + parent::handle($args); + if ($_SERVER['REQUEST_METHOD'] == 'POST') { + if ($this->arg('no')) { + common_redirect(common_local_url('groupmembers', + array('nickname' => $this->group->nickname)), + 303); + } elseif ($this->arg('yes')) { + $this->blockProfile(); + } elseif ($this->arg('blockto')) { + $this->showPage(); + } + } + } + + function showContent() { + $this->areYouSureForm(); + } + + function title() { + return _('Block user from group'); + } + + function showNoticeForm() { + // nop + } + + /** + * Confirm with user. + * + * Shows a confirmation form. + * + * @return void + */ + + function areYouSureForm() + { + $id = $this->profile->id; + $this->element('p', null, + sprintf(_('Are you sure you want to block user "%s" from the group "%s"? '. + 'They will be removed from the group, unable to post, and '. + 'unable to subscribe to the group in the future.'), + $this->profile->getBestName(), + $this->group->getBestName())); + $this->elementStart('form', array('id' => 'block-' . $id, + 'method' => 'post', + 'class' => 'block', + 'action' => common_local_url('groupblock'))); + $this->hidden('token', common_session_token()); + $this->hidden('blockto-' . $this->profile->id, + $this->profile->id, + 'blockto'); + $this->hidden('blockgroup-' . $this->group->id, + $this->group->id, + 'blockgroup'); + foreach ($this->args as $k => $v) { + if (substr($k, 0, 9) == 'returnto-') { + $this->hidden($k, $v); + } + } + $this->submit('no', _('No')); + $this->submit('yes', _('Yes')); + $this->elementEnd('form'); + } + + /** + * Actually block a user. + * + * @return void + */ + + function blockProfile() + { + $block = Group_block::blockProfile($this->group, $this->profile, + common_current_user()); + + if (empty($block)) { + $this->serverError(_("Database error blocking user from group.")); + return false; + } + + // Now, gotta figure where we go back to + foreach ($this->args as $k => $v) { + if ($k == 'returnto-action') { + $action = $v; + } elseif (substr($k, 0, 9) == 'returnto-') { + $args[substr($k, 9)] = $v; + } + } + + if ($action) { + common_redirect(common_local_url($action, $args), 303); + } else { + common_redirect(common_local_url('groupmembers', + array('nickname' => $this->group->nickname)), + 303); + } + } +} + From 1c87532912b63effc047da2913e55a6551d8f629 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 14 Jun 2009 15:47:39 -0700 Subject: [PATCH 034/262] The rest of the things necessary to make group block work Link to the group block form. Hide join button if the current user is blocked. --- actions/groupmembers.php | 2 +- actions/joingroup.php | 5 +++ actions/showgroup.php | 2 +- classes/Group_block.php | 76 ++++++++++++++++++++++++++++++++++++++-- classes/User_group.php | 5 +++ lib/grouplist.php | 2 +- lib/router.php | 8 ++--- 7 files changed, 91 insertions(+), 9 deletions(-) diff --git a/actions/groupmembers.php b/actions/groupmembers.php index 079dad9e94..150b60a54e 100644 --- a/actions/groupmembers.php +++ b/actions/groupmembers.php @@ -180,7 +180,7 @@ class GroupMemberListItem extends ProfileListItem $user = common_current_user(); if (!empty($user) && $user->id != $this->profile->id && $user->isAdmin($this->group)) { - $bf = new GroupBlockForm($this->out, $this->profile, + $bf = new GroupBlockForm($this->out, $this->profile, $this->group, array('action' => 'groupmembers', 'nickname' => $this->group->nickname)); $bf->show(); diff --git a/actions/joingroup.php b/actions/joingroup.php index a5d82ddc77..0e4f96eaf5 100644 --- a/actions/joingroup.php +++ b/actions/joingroup.php @@ -96,6 +96,11 @@ class JoingroupAction extends Action return false; } + if (Group_block::isBlocked($this->group, $cur->getProfile())) { + $this->clientError(_('You have been blocked from that group by the admin.'), 403); + return false; + } + return true; } diff --git a/actions/showgroup.php b/actions/showgroup.php index 3ce45adc67..537f09278b 100644 --- a/actions/showgroup.php +++ b/actions/showgroup.php @@ -283,7 +283,7 @@ class ShowgroupAction extends Action if ($cur->isMember($this->group)) { $lf = new LeaveForm($this, $this->group); $lf->show(); - } else { + } else if (!Group_block::isBlocked($this->group, $cur->getProfile())) { $jf = new JoinForm($this, $this->group); $jf->show(); } diff --git a/classes/Group_block.php b/classes/Group_block.php index 437046a9c3..d945fd57a9 100644 --- a/classes/Group_block.php +++ b/classes/Group_block.php @@ -1,10 +1,29 @@ . */ -require_once 'classes/Memcached_DataObject'; -class Group_block extends Memcached_DataObject +if (!defined('LACONICA')) { exit(1); } + +require_once INSTALLDIR.'/classes/Memcached_DataObject.php'; + +class Group_block extends Memcached_DataObject { ###START_AUTOCODE /* the code below is auto generated do not remove the above tag */ @@ -20,4 +39,57 @@ class Group_block extends Memcached_DataObject /* the code above is auto generated do not remove the tag below */ ###END_AUTOCODE + + function &pkeyGet($kv) + { + return Memcached_DataObject::pkeyGet('Group_block', $kv); + } + + static function isBlocked($group, $profile) + { + $block = Group_block::pkeyGet(array('group_id' => $group->id, + 'blocked' => $profile->id)); + return !empty($block); + } + + static function blockProfile($group, $profile, $blocker) + { + // Insert the block + + $block = new Group_block(); + + $block->query('BEGIN'); + + $block->group_id = $group->id; + $block->blocked = $profile->id; + $block->blocker = $blocker->id; + + $result = $block->insert(); + + if (!$result) { + common_log_db_error($block, 'INSERT', __FILE__); + return null; + } + + // Delete membership if any + + $member = new Group_member(); + + $member->group_id = $group->id; + $member->profile_id = $profile->id; + + if ($member->find(true)) { + $result = $member->delete(); + if (!$result) { + common_log_db_error($member, 'DELETE', __FILE__); + return null; + } + } + + // Commit, since both have been done + + $block->query('COMMIT'); + + return $block; + } } diff --git a/classes/User_group.php b/classes/User_group.php index a135015bac..1be34b60bd 100644 --- a/classes/User_group.php +++ b/classes/User_group.php @@ -137,4 +137,9 @@ class User_group extends Memcached_DataObject common_debug(common_log_objstring($this)); return $this->update($orig); } + + function getBestName() + { + return ($this->fullname) ? $this->fullname : $this->nickname; + } } diff --git a/lib/grouplist.php b/lib/grouplist.php index 1b85474998..1ded5160bd 100644 --- a/lib/grouplist.php +++ b/lib/grouplist.php @@ -166,7 +166,7 @@ class GroupList extends Widget if ($user->isMember($this->group)) { $lf = new LeaveForm($this->out, $this->group); $lf->show(); - } else { + } else if (!Group_block::isBlocked($this->group, $user->getProfile())) { $jf = new JoinForm($this->out, $this->group); $jf->show(); } diff --git a/lib/router.php b/lib/router.php index 456d1793e3..469d9a1715 100644 --- a/lib/router.php +++ b/lib/router.php @@ -101,7 +101,7 @@ class Router $main = array('login', 'logout', 'register', 'subscribe', 'unsubscribe', 'confirmaddress', 'recoverpassword', 'invite', 'favor', 'disfavor', 'sup', - 'block', 'subedit'); + 'block', 'subedit', 'groupblock'); foreach ($main as $a) { $m->connect('main/'.$a, array('action' => $a)); @@ -164,10 +164,10 @@ class Router array('action' => 'newnotice'), array('replyto' => '[A-Za-z0-9_-]+')); - $m->connect('notice/:notice/file', - array('action' => 'file'), + $m->connect('notice/:notice/file', + array('action' => 'file'), array('notice' => '[0-9]+')); - + $m->connect('notice/:notice', array('action' => 'shownotice'), array('notice' => '[0-9]+')); From 203a5aba67c3bd9e2848d90b1778240b387aeda3 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 14 Jun 2009 15:54:22 -0700 Subject: [PATCH 035/262] Some UI improvements for blocking and unblocking Add unblock to the router table, so unblocking will work at all. Block form and unblock form return to subscribers list, not subscriptions list, by default. showstream action sends its parameters to block and unblock forms to better return to the right page. --- actions/block.php | 2 +- actions/showstream.php | 8 ++++++-- actions/unblock.php | 2 +- lib/router.php | 2 +- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/actions/block.php b/actions/block.php index 34f991dc61..0efee5932c 100644 --- a/actions/block.php +++ b/actions/block.php @@ -180,7 +180,7 @@ class BlockAction extends Action if ($action) { common_redirect(common_local_url($action, $args), 303); } else { - common_redirect(common_local_url('subscriptions', + common_redirect(common_local_url('subscribers', array('nickname' => $cur->nickname)), 303); } diff --git a/actions/showstream.php b/actions/showstream.php index c1a2c337a0..641228bc73 100644 --- a/actions/showstream.php +++ b/actions/showstream.php @@ -308,10 +308,14 @@ class ShowstreamAction extends ProfileAction $blocked = $cur->hasBlocked($this->profile); $this->elementStart('li', 'entity_block'); if ($blocked) { - $ubf = new UnblockForm($this, $this->profile); + $ubf = new UnblockForm($this, $this->profile, + array('action' => 'showstream', + 'nickname' => $this->profile->nickname)); $ubf->show(); } else { - $bf = new BlockForm($this, $this->profile); + $bf = new BlockForm($this, $this->profile, + array('action' => 'showstream', + 'nickname' => $this->profile->nickname)); $bf->show(); } $this->elementEnd('li'); diff --git a/actions/unblock.php b/actions/unblock.php index 8573b2a873..6e671c9dd2 100644 --- a/actions/unblock.php +++ b/actions/unblock.php @@ -118,7 +118,7 @@ class UnblockAction extends Action if ($action) { common_redirect(common_local_url($action, $args), 303); } else { - common_redirect(common_local_url('subscriptions', + common_redirect(common_local_url('subscribers', array('nickname' => $cur->nickname)), 303); } diff --git a/lib/router.php b/lib/router.php index 12590b790d..748966567f 100644 --- a/lib/router.php +++ b/lib/router.php @@ -101,7 +101,7 @@ class Router $main = array('login', 'logout', 'register', 'subscribe', 'unsubscribe', 'confirmaddress', 'recoverpassword', 'invite', 'favor', 'disfavor', 'sup', - 'block', 'subedit'); + 'block', 'unblock', 'subedit'); foreach ($main as $a) { $m->connect('main/'.$a, array('action' => $a)); From f8da15bf41b07a46b1fbe5323e2b8136d42c5b31 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 14 Jun 2009 16:17:44 -0700 Subject: [PATCH 036/262] Allow users to be unblocked from a group List users who are blocked from joining a group. Add a form to let them be unblocked. Add an action that removes the block. Includes changes to group and groupblock classes. --- actions/blockedfromgroup.php | 313 +++++++++++++++++++++++++++++++++++ actions/groupunblock.php | 149 +++++++++++++++++ classes/Group_block.php | 20 +++ classes/User_group.php | 23 +++ lib/groupnav.php | 6 + lib/router.php | 7 +- 6 files changed, 517 insertions(+), 1 deletion(-) create mode 100644 actions/blockedfromgroup.php create mode 100644 actions/groupunblock.php diff --git a/actions/blockedfromgroup.php b/actions/blockedfromgroup.php new file mode 100644 index 0000000000..1b7b317843 --- /dev/null +++ b/actions/blockedfromgroup.php @@ -0,0 +1,313 @@ +. + * + * @category Group + * @package Laconica + * @author Evan Prodromou + * @copyright 2008-2009 Control Yourself, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://laconi.ca/ + */ + +if (!defined('LACONICA')) { + exit(1); +} + +/** + * List of profiles blocked from this group + * + * @category Group + * @package Laconica + * @author Evan Prodromou + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://laconi.ca/ + */ + +class BlockedfromgroupAction extends Action +{ + var $page = null; + + function isReadOnly($args) + { + return true; + } + + function prepare($args) + { + parent::prepare($args); + $this->page = ($this->arg('page')) ? ($this->arg('page')+0) : 1; + + $nickname_arg = $this->arg('nickname'); + $nickname = common_canonical_nickname($nickname_arg); + + // Permanent redirect on non-canonical nickname + + if ($nickname_arg != $nickname) { + $args = array('nickname' => $nickname); + if ($this->page != 1) { + $args['page'] = $this->page; + } + common_redirect(common_local_url('blockedfromgroup', $args), 301); + return false; + } + + if (!$nickname) { + $this->clientError(_('No nickname'), 404); + return false; + } + + $this->group = User_group::staticGet('nickname', $nickname); + + if (!$this->group) { + $this->clientError(_('No such group'), 404); + return false; + } + + return true; + } + + function title() + { + if ($this->page == 1) { + return sprintf(_('%s blocked profiles'), + $this->group->nickname); + } else { + return sprintf(_('%s blocked profiles, page %d'), + $this->group->nickname, + $this->page); + } + } + + function handle($args) + { + parent::handle($args); + $this->showPage(); + } + + function showPageNotice() + { + $this->element('p', 'instructions', + _('A list of the users blocked from joining this group.')); + } + + function showLocalNav() + { + $nav = new GroupNav($this, $this->group); + $nav->show(); + } + + function showContent() + { + $offset = ($this->page-1) * PROFILES_PER_PAGE; + $limit = PROFILES_PER_PAGE + 1; + + $cnt = 0; + + $blocked = $this->group->getBlocked($offset, $limit); + + if ($blocked) { + $blocked_list = new GroupBlockList($blocked, $this->group, $this); + $cnt = $blocked_list->show(); + } + + $blocked->free(); + + $this->pagination($this->page > 1, $cnt > PROFILES_PER_PAGE, + $this->page, 'blockedfromgroup', + array('nickname' => $this->group->nickname)); + } +} + +class GroupBlockList extends ProfileList +{ + var $group = null; + + function __construct($profile, $group, $action) + { + parent::__construct($profile, $action); + + $this->group = $group; + } + + function newListItem($profile) + { + return new GroupBlockListItem($profile, $this->group, $this->action); + } +} + +class GroupBlockListItem extends ProfileListItem +{ + var $group = null; + + function __construct($profile, $group, $action) + { + parent::__construct($profile, $action); + + $this->group = $group; + } + + function showActions() + { + $this->startActions(); + $this->showGroupUnblockForm(); + $this->endActions(); + } + + function showGroupUnblockForm() + { + $user = common_current_user(); + + if (!empty($user) && $user->id != $this->profile->id && $user->isAdmin($this->group)) { + $bf = new GroupUnblockForm($this->out, $this->profile, $this->group, + array('action' => 'blockedfromgroup', + 'nickname' => $this->group->nickname)); + $bf->show(); + } + } +} + +/** + * Form for unblocking a user from a group + * + * @category Form + * @package Laconica + * @author Evan Prodromou + * @author Sarven Capadisli + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://laconi.ca/ + * + * @see UnblockForm + */ + +class GroupUnblockForm extends Form +{ + /** + * Profile of user to block + */ + + var $profile = null; + + /** + * Group to block the user from + */ + + var $group = null; + + /** + * Return-to args + */ + + var $args = null; + + /** + * Constructor + * + * @param HTMLOutputter $out output channel + * @param Profile $profile profile of user to block + * @param User_group $group group to block user from + * @param array $args return-to args + */ + + function __construct($out=null, $profile=null, $group=null, $args=null) + { + parent::__construct($out); + + $this->profile = $profile; + $this->group = $group; + $this->args = $args; + } + + /** + * ID of the form + * + * @return int ID of the form + */ + + function id() + { + // This should be unique for the page. + return 'unblock-' . $this->profile->id; + } + + /** + * class of the form + * + * @return string class of the form + */ + + function formClass() + { + return 'form_group_unblock'; + } + + /** + * Action of the form + * + * @return string URL of the action + */ + + function action() + { + return common_local_url('groupunblock'); + } + + /** + * Legend of the Form + * + * @return void + */ + function formLegend() + { + $this->out->element('legend', null, _('Unblock user from group')); + } + + /** + * Data elements of the form + * + * @return void + */ + + function formData() + { + $this->out->hidden('unblockto-' . $this->profile->id, + $this->profile->id, + 'unblockto'); + $this->out->hidden('unblockgroup-' . $this->group->id, + $this->group->id, + 'unblockgroup'); + if ($this->args) { + foreach ($this->args as $k => $v) { + $this->out->hidden('returnto-' . $k, $v); + } + } + } + + /** + * Action elements + * + * @return void + */ + + function formActions() + { + $this->out->submit('submit', _('Unblock'), 'submit', null, _('Unblock this user')); + } +} diff --git a/actions/groupunblock.php b/actions/groupunblock.php new file mode 100644 index 0000000000..a0bcb01f90 --- /dev/null +++ b/actions/groupunblock.php @@ -0,0 +1,149 @@ + + * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 + * @link http://laconi.ca/ + * + * Laconica - a distributed open-source microblogging tool + * Copyright (C) 2008, Controlez-Vous, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +if (!defined('LACONICA')) { + exit(1); +} + +/** + * Unlock a user from a group + * + * @category Action + * @package Laconica + * @author Evan Prodromou + * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 + * @link http://laconi.ca/ + */ + +class GroupunblockAction extends Action +{ + var $profile = null; + var $group = null; + + /** + * Take arguments for running + * + * @param array $args $_REQUEST args + * + * @return boolean success flag + */ + + function prepare($args) + { + parent::prepare($args); + if (!common_logged_in()) { + $this->clientError(_('Not logged in.')); + return false; + } + $token = $this->trimmed('token'); + if (empty($token) || $token != common_session_token()) { + $this->clientError(_('There was a problem with your session token. Try again, please.')); + return; + } + $id = $this->trimmed('unblockto'); + if (empty($id)) { + $this->clientError(_('No profile specified.')); + return false; + } + $this->profile = Profile::staticGet('id', $id); + if (empty($this->profile)) { + $this->clientError(_('No profile with that ID.')); + return false; + } + $group_id = $this->trimmed('unblockgroup'); + if (empty($group_id)) { + $this->clientError(_('No group specified.')); + return false; + } + $this->group = User_group::staticGet('id', $group_id); + if (empty($this->group)) { + $this->clientError(_('No such group.')); + return false; + } + $user = common_current_user(); + if (!$user->isAdmin($this->group)) { + $this->clientError(_('Only an admin can unblock group members.'), 401); + return false; + } + if (!Group_block::isBlocked($this->group, $this->profile)) { + $this->clientError(_('User is not blocked from group.')); + return false; + } + return true; + } + + /** + * Handle request + * + * @param array $args $_REQUEST args; handled in prepare() + * + * @return void + */ + + function handle($args) + { + parent::handle($args); + if ($_SERVER['REQUEST_METHOD'] == 'POST') { + $this->unblockProfile(); + } + } + + /** + * Unblock a user. + * + * @return void + */ + + function unblockProfile() + { + $result = Group_block::unblockProfile($this->group, $this->profile); + + if (!$result) { + $this->serverError(_('Error removing the block.')); + return; + } + + foreach ($this->args as $k => $v) { + if ($k == 'returnto-action') { + $action = $v; + } else if (substr($k, 0, 9) == 'returnto-') { + $args[substr($k, 9)] = $v; + } + } + + if ($action) { + common_redirect(common_local_url($action, $args), 303); + } else { + common_redirect(common_local_url('blockedfromgroup', + array('nickname' => $this->group->nickname)), + 303); + } + } +} + diff --git a/classes/Group_block.php b/classes/Group_block.php index d945fd57a9..4c583d8e23 100644 --- a/classes/Group_block.php +++ b/classes/Group_block.php @@ -92,4 +92,24 @@ class Group_block extends Memcached_DataObject return $block; } + + static function unblockProfile($group, $profile) + { + $block = Group_block::pkeyGet(array('group_id' => $group->id, + 'blocked' => $profile->id)); + + if (empty($block)) { + return null; + } + + $result = $block->delete(); + + if (!$result) { + common_log_db_error($block, 'DELETE', __FILE__); + return null; + } + + return true; + } + } diff --git a/classes/User_group.php b/classes/User_group.php index 1be34b60bd..9f9977755b 100644 --- a/classes/User_group.php +++ b/classes/User_group.php @@ -125,6 +125,29 @@ class User_group extends Memcached_DataObject return $members; } + function getBlocked($offset=0, $limit=null) + { + $qry = + 'SELECT profile.* ' . + 'FROM profile JOIN group_block '. + 'ON profile.id = group_block.blocked ' . + 'WHERE group_block.group_id = %d ' . + 'ORDER BY group_block.modified DESC '; + + if ($limit != null) { + if (common_config('db','type') == 'pgsql') { + $qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset; + } else { + $qry .= ' LIMIT ' . $offset . ', ' . $limit; + } + } + + $blocked = new Profile(); + + $blocked->query(sprintf($qry, $this->id)); + return $blocked; + } + function setOriginal($filename) { $imagefile = new ImageFile($this->id, Avatar::path($filename)); diff --git a/lib/groupnav.php b/lib/groupnav.php index 90bdc10149..194247982c 100644 --- a/lib/groupnav.php +++ b/lib/groupnav.php @@ -95,6 +95,12 @@ class GroupNav extends Widget $cur = common_current_user(); if ($cur && $cur->isAdmin($this->group)) { + $this->out->menuItem(common_local_url('blockedfromgroup', array('nickname' => + $nickname)), + _('Blocked'), + sprintf(_('%s blocked users'), $nickname), + $action_name == 'blockedfromgroup', + 'nav_group_blocked'); $this->out->menuItem(common_local_url('editgroup', array('nickname' => $nickname)), _('Admin'), diff --git a/lib/router.php b/lib/router.php index 3d870e5651..e10871bc08 100644 --- a/lib/router.php +++ b/lib/router.php @@ -101,7 +101,8 @@ class Router $main = array('login', 'logout', 'register', 'subscribe', 'unsubscribe', 'confirmaddress', 'recoverpassword', 'invite', 'favor', 'disfavor', 'sup', - 'block', 'unblock', 'subedit', 'groupblock'); + 'block', 'unblock', 'subedit', + 'groupblock', 'groupunblock'); foreach ($main as $a) { $m->connect('main/'.$a, array('action' => $a)); @@ -228,6 +229,10 @@ class Router array('nickname' => '[a-zA-Z0-9]+')); } + $m->connect('group/:nickname/blocked', + array('action' => 'blockedfromgroup'), + array('nickname' => '[a-zA-Z0-9]+')); + $m->connect('group/:id/id', array('action' => 'groupbyid'), array('id' => '[0-9]+')); From 0bc9b2e730bb6368d36ba5bb3f2df1bf1432adad Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Mon, 15 Jun 2009 03:21:15 +0000 Subject: [PATCH 037/262] Cross-browser notice_attach --- lib/noticeform.php | 4 ++-- theme/base/css/display.css | 22 ++++++++++++---------- theme/base/css/ie.css | 9 +++++++++ theme/default/css/ie.css | 7 ++++++- theme/identica/css/ie.css | 7 ++++++- 5 files changed, 35 insertions(+), 14 deletions(-) diff --git a/lib/noticeform.php b/lib/noticeform.php index 3212f382ad..0ad3658566 100644 --- a/lib/noticeform.php +++ b/lib/noticeform.php @@ -148,12 +148,12 @@ class NoticeForm extends Form $this->out->element('dd', array('id' => 'notice_text-count'), '140'); $this->out->elementEnd('dl'); - $this->out->hidden('MAX_FILE_SIZE', common_config('attachments', 'file_quota')); - $this->out->element('label', array('for' => 'notice_data-attach'), _('Attach')); + $this->out->element('label', array('for' => 'notice_data-attach'),_('Attach')); $this->out->element('input', array('id' => 'notice_data-attach', 'type' => 'file', 'name' => 'attach', 'title' => _('Attach a file'))); + $this->out->hidden('MAX_FILE_SIZE', common_config('attachments', 'file_quota')); if ($this->action) { $this->out->hidden('notice_return-to', $this->action, 'returnto'); } diff --git a/theme/base/css/display.css b/theme/base/css/display.css index dc275e19f7..060fdfd0df 100644 --- a/theme/base/css/display.css +++ b/theme/base/css/display.css @@ -445,6 +445,8 @@ width:80.789%; height:67px; line-height:1.5; padding:7px 7px 16px 7px; +position:relative; +z-index:2; } #form_notice label { display:block; @@ -452,23 +454,23 @@ float:left; font-size:1.3em; margin-bottom:7px; } -#form_notice label[for=notice_data-attach] { -text-indent:-9999px; -} #form_notice label[for=notice_data-attach], #form_notice #notice_data-attach { position:absolute; top:25px; -right:49px; -width:16px; -height:16px; cursor:pointer; } -#form_notice #notice_data-attach { -text-indent:-279px; +#form_notice label[for=notice_data-attach] { +text-indent:-9999px; +left:394px; +width:16px; +height:16px; } -#form_notice #notice_submit label { -display:none; +#form_notice #notice_data-attach { +left:183px; +padding:0; + +height:16px; } #form_notice .form_note { position:absolute; diff --git a/theme/base/css/ie.css b/theme/base/css/ie.css index 8183fee679..d1b0558ec8 100644 --- a/theme/base/css/ie.css +++ b/theme/base/css/ie.css @@ -8,6 +8,15 @@ top:0; #form_notice textarea { width:78%; } +#form_notice .form_note + label { +position:absolute; +top:25px; +left:380px; +text-indent:-9999px; +height:16px; +width:16px; +display:block; +} #form_notice #notice_action-submit { width:17%; max-width:17%; diff --git a/theme/default/css/ie.css b/theme/default/css/ie.css index 2b06768ea4..6501f4e48e 100644 --- a/theme/default/css/ie.css +++ b/theme/default/css/ie.css @@ -3,7 +3,12 @@ .notice-options input.submit { color:#fff; } - #site_nav_local_views a { background-color:#ACCCDA; } +#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 2f463bb44d..69db16aad0 100644 --- a/theme/identica/css/ie.css +++ b/theme/identica/css/ie.css @@ -3,7 +3,12 @@ .notice-options input.submit { color:#fff; } - #site_nav_local_views a { background-color:#D0DFE7; } +#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 0deb2928e649c358ce1046028dcca4dabc4b3aa6 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 14 Jun 2009 21:40:47 -0700 Subject: [PATCH 038/262] add a table for group aliases --- db/laconica.sql | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/db/laconica.sql b/db/laconica.sql index bc824fc4db..b8c0824f5a 100644 --- a/db/laconica.sql +++ b/db/laconica.sql @@ -493,3 +493,13 @@ create table group_block ( 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 2d63daa71c6ec8ac5fb34004075417c4bb0c6e19 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 14 Jun 2009 21:52:31 -0700 Subject: [PATCH 039/262] Added Group_alias class --- classes/Group_alias.php | 41 +++++++++++++++++++++++++++++++++++++++++ classes/laconica.ini | 8 ++++++++ 2 files changed, 49 insertions(+) create mode 100755 classes/Group_alias.php mode change 100644 => 100755 classes/laconica.ini diff --git a/classes/Group_alias.php b/classes/Group_alias.php new file mode 100755 index 0000000000..e801e50e1d --- /dev/null +++ b/classes/Group_alias.php @@ -0,0 +1,41 @@ +. + */ + +if (!defined('LACONICA')) { exit(1); } + +require_once INSTALLDIR.'/classes/Memcached_DataObject.php'; + +class Group_alias extends Memcached_DataObject +{ + ###START_AUTOCODE + /* the code below is auto generated do not remove the above tag */ + + public $__table = 'group_alias'; // table name + public $alias; // varchar(64) primary_key not_null + public $group_id; // int(4) not_null + public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP + + /* Static get */ + function staticGet($k,$v=NULL) { return DB_DataObject::staticGet('Group_alias',$k,$v); } + + /* the code above is auto generated do not remove the tag below */ + ###END_AUTOCODE +} diff --git a/classes/laconica.ini b/classes/laconica.ini old mode 100644 new mode 100755 index 8e4e78b794..df292bbffd --- a/classes/laconica.ini +++ b/classes/laconica.ini @@ -158,6 +158,14 @@ id = K service = K uri = U +[group_alias] +alias = 130 +group_id = 129 +modified = 384 + +[group_alias__keys] +alias = K + [group_block] group_id = 129 blocked = 129 From a4055fc2f9a79aa9aa2321e132a7133c088859cd Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 14 Jun 2009 21:53:09 -0700 Subject: [PATCH 040/262] fixup perms for classes --- classes/Group_alias.php | 0 classes/laconica.ini | 0 2 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 classes/Group_alias.php mode change 100755 => 100644 classes/laconica.ini diff --git a/classes/Group_alias.php b/classes/Group_alias.php old mode 100755 new mode 100644 diff --git a/classes/laconica.ini b/classes/laconica.ini old mode 100755 new mode 100644 From 23fd58b74c7d37b56c7fee897a485729061196d5 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 14 Jun 2009 21:53:29 -0700 Subject: [PATCH 041/262] fix perms for classes/statusnet.ini --- classes/statusnet.ini | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 classes/statusnet.ini diff --git a/classes/statusnet.ini b/classes/statusnet.ini old mode 100755 new mode 100644 From ee8dd62038993c184b704df08a3ab1fbcf0c04ac Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 14 Jun 2009 22:07:27 -0700 Subject: [PATCH 042/262] try to get the right class for profileminilist --- lib/profilelist.php | 19 ++++++++++++++++--- lib/profileminilist.php | 5 +++++ 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/lib/profilelist.php b/lib/profilelist.php index e2faf10af4..bd866bed7e 100644 --- a/lib/profilelist.php +++ b/lib/profilelist.php @@ -62,8 +62,23 @@ class ProfileList extends Widget function show() { - $this->out->elementStart('ul', 'profiles'); + $this->startList(); + $this->showProfiles(); + $this->endList(); + } + function startList() + { + $this->out->elementStart('ul', 'profiles'); + } + + function endList() + { + $this->out->elementEnd('ul'); + } + + function showProfiles() + { $cnt = 0; while ($this->profile->fetch()) { @@ -75,8 +90,6 @@ class ProfileList extends Widget $pli->show(); } - $this->out->elementEnd('ul'); - return $cnt; } diff --git a/lib/profileminilist.php b/lib/profileminilist.php index f11cae8a5f..0c02e2735e 100644 --- a/lib/profileminilist.php +++ b/lib/profileminilist.php @@ -47,6 +47,11 @@ define('PROFILES_PER_MINILIST', 27); class ProfileMiniList extends ProfileList { + function startList() + { + $this->out->elementStart('ul', 'entity users xoxo'); + } + function newListItem($profile) { return new ProfileMiniListItem($profile, $this->action); From bef643352d573235aedbdd93125e93c42edb306b Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 14 Jun 2009 22:09:04 -0700 Subject: [PATCH 043/262] return count from show --- lib/profilelist.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/profilelist.php b/lib/profilelist.php index bd866bed7e..a604230f85 100644 --- a/lib/profilelist.php +++ b/lib/profilelist.php @@ -63,8 +63,9 @@ class ProfileList extends Widget function show() { $this->startList(); - $this->showProfiles(); + $cnt = $this->showProfiles(); $this->endList(); + return $cnt; } function startList() From 7097804eeb0c648391544f55e32bd66bc35bcdb1 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 14 Jun 2009 22:09:17 -0700 Subject: [PATCH 044/262] typo in profileminilist class --- lib/profileminilist.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/profileminilist.php b/lib/profileminilist.php index 0c02e2735e..09bef6f7c6 100644 --- a/lib/profileminilist.php +++ b/lib/profileminilist.php @@ -49,7 +49,7 @@ class ProfileMiniList extends ProfileList { function startList() { - $this->out->elementStart('ul', 'entity users xoxo'); + $this->out->elementStart('ul', 'entities users xoxo'); } function newListItem($profile) From 2f3c4f8812d389df40cf62b8967cf3e359ad5663 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 14 Jun 2009 22:16:24 -0700 Subject: [PATCH 045/262] add correct li for css magic for block stuff --- actions/blockedfromgroup.php | 2 ++ actions/groupmembers.php | 2 ++ 2 files changed, 4 insertions(+) diff --git a/actions/blockedfromgroup.php b/actions/blockedfromgroup.php index 1b7b317843..541ebcfd90 100644 --- a/actions/blockedfromgroup.php +++ b/actions/blockedfromgroup.php @@ -176,10 +176,12 @@ class GroupBlockListItem extends ProfileListItem $user = common_current_user(); if (!empty($user) && $user->id != $this->profile->id && $user->isAdmin($this->group)) { + $this->out->elementStart('li', 'entity_block'); $bf = new GroupUnblockForm($this->out, $this->profile, $this->group, array('action' => 'blockedfromgroup', 'nickname' => $this->group->nickname)); $bf->show(); + $this->out->elementEnd('li'); } } } diff --git a/actions/groupmembers.php b/actions/groupmembers.php index 150b60a54e..65790b7ca3 100644 --- a/actions/groupmembers.php +++ b/actions/groupmembers.php @@ -180,10 +180,12 @@ class GroupMemberListItem extends ProfileListItem $user = common_current_user(); if (!empty($user) && $user->id != $this->profile->id && $user->isAdmin($this->group)) { + $this->out->elementStart('li', 'entity_block'); $bf = new GroupBlockForm($this->out, $this->profile, $this->group, array('action' => 'groupmembers', 'nickname' => $this->group->nickname)); $bf->show(); + $this->out->elementEnd('li'); } } From e18504d1d246c48f64964e176c9134e56cd20db9 Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Mon, 15 Jun 2009 05:38:18 +0000 Subject: [PATCH 046/262] Styles for group block --- theme/base/css/display.css | 2 ++ theme/default/css/display.css | 8 +++++++- theme/identica/css/display.css | 8 +++++++- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/theme/base/css/display.css b/theme/base/css/display.css index 060fdfd0df..0cbd0d774a 100644 --- a/theme/base/css/display.css +++ b/theme/base/css/display.css @@ -618,6 +618,8 @@ display:block; .form_user_block input.submit, .form_user_unblock input.submit, +.form_group_block input.submit, +.form_group_unblock input.submit, .entity_send-a-message a, .entity_edit a, .form_user_nudge input.submit, diff --git a/theme/default/css/display.css b/theme/default/css/display.css index 34f6b3b8a6..166e62157b 100644 --- a/theme/default/css/display.css +++ b/theme/default/css/display.css @@ -57,6 +57,8 @@ a, div.notice-options input, .form_user_block input.submit, .form_user_unblock input.submit, +.form_group_block input.submit, +.form_group_unblock input.submit, .entity_send-a-message a, .form_user_nudge input.submit, .entity_nudge p, @@ -148,6 +150,8 @@ background-image:url(../../base/images/icons/icon_foaf.gif); .form_user_nudge input.submit, .form_user_block input.submit, .form_user_unblock input.submit, +.form_group_block input.submit, +.form_group_unblock input.submit, .entity_nudge p { background-position: 0 40%; background-repeat: no-repeat; @@ -177,7 +181,9 @@ background-image:url(../../base/images/icons/twotone/green/quote.gif); background-image:url(../../base/images/icons/twotone/green/mail.gif); } .form_user_block input.submit, -.form_user_unblock input.submit { +.form_user_unblock input.submit, +.form_group_block input.submit, +.form_group_unblock input.submit { background-image:url(../../base/images/icons/twotone/green/shield.gif); } diff --git a/theme/identica/css/display.css b/theme/identica/css/display.css index 8a03a4d772..cab42f16f4 100644 --- a/theme/identica/css/display.css +++ b/theme/identica/css/display.css @@ -57,6 +57,8 @@ a, div.notice-options input, .form_user_block input.submit, .form_user_unblock input.submit, +.form_group_block input.submit, +.form_group_unblock input.submit, .entity_send-a-message a, .form_user_nudge input.submit, .entity_nudge p, @@ -148,6 +150,8 @@ background-image:url(../../base/images/icons/icon_foaf.gif); .form_user_nudge input.submit, .form_user_block input.submit, .form_user_unblock input.submit, +.form_group_block input.submit, +.form_group_unblock input.submit, .entity_nudge p { background-position: 0 40%; background-repeat: no-repeat; @@ -177,7 +181,9 @@ background-image:url(../../base/images/icons/twotone/green/quote.gif); background-image:url(../../base/images/icons/twotone/green/mail.gif); } .form_user_block input.submit, -.form_user_unblock input.submit { +.form_user_unblock input.submit, +.form_group_block input.submit, +.form_group_unblock input.submit { background-image:url(../../base/images/icons/twotone/green/shield.gif); } From ecbd7718d57fc427d2aeac885d8be0321b3cf1fe Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 14 Jun 2009 23:37:24 -0700 Subject: [PATCH 047/262] Code for adding and saving group aliases Added code to add and save group aliases. Like tags, aliases are free-texted in to the group admin page. configurable max number of aliases, default is three. --- README | 8 +++++- actions/editgroup.php | 59 ++++++++++++++++++++++++++++++++++++++--- actions/newgroup.php | 51 ++++++++++++++++++++++++++++++++++- classes/User_group.php | 60 ++++++++++++++++++++++++++++++++++++++++++ lib/common.php | 2 ++ lib/groupeditform.php | 11 +++++++- 6 files changed, 185 insertions(+), 6 deletions(-) diff --git a/README b/README index 2099f94d62..8fb4a941cf 100644 --- a/README +++ b/README @@ -1196,7 +1196,6 @@ reporturl: URL to post statistics to. Defaults to Laconica developers' set 'run' to 'never' than to set this value to something nonsensical. - attachments ----------- @@ -1226,6 +1225,13 @@ user_quota: total size in bytes a user can store on this server. Each user monthly_quota: total size permitted in the current month. This is the total size in bytes that a user can upload each month. +group +----- + +Options for group functionality. + +maxaliases: maximum number of aliases a group can have. Default 3. Set + to 0 or less to prevent aliases in a group. Troubleshooting =============== diff --git a/actions/editgroup.php b/actions/editgroup.php index 39dad0465e..29a7bce437 100644 --- a/actions/editgroup.php +++ b/actions/editgroup.php @@ -171,6 +171,7 @@ class EditgroupAction extends Action $homepage = $this->trimmed('homepage'); $description = $this->trimmed('description'); $location = $this->trimmed('location'); + $aliasstring = $this->trimmed('aliases'); if (!Validate::string($nickname, array('min_length' => 1, 'max_length' => 64, @@ -201,6 +202,39 @@ class EditgroupAction extends Action return; } + if (!empty($aliasstring)) { + $aliases = array_map('common_canonical_nickname', array_unique(preg_split('/[\s,]+/', $aliasstring))); + } else { + $aliases = array(); + } + + if (count($aliases) > common_config('group', 'maxaliases')) { + $this->showForm(sprintf(_('Too many aliases! Maximum %d.'), + common_config('group', 'maxaliases'))); + return; + } + + foreach ($aliases as $alias) { + if (!Validate::string($alias, array('min_length' => 1, + 'max_length' => 64, + 'format' => NICKNAME_FMT))) { + $this->showForm(sprintf(_('Invalid alias: "%s"'), $alias)); + return; + } + if ($this->nicknameExists($alias)) { + $this->showForm(sprintf(_('Alias "%s" already in use. Try another one.'), + $alias)); + return; + } + // XXX assumes alphanum nicknames + if (strcmp($alias, $nickname) == 0) { + $this->showForm(_('Alias can\'t be the same as nickname.')); + return; + } + } + + $this->group->query('BEGIN'); + $orig = clone($this->group); $this->group->nickname = $nickname; @@ -217,6 +251,14 @@ class EditgroupAction extends Action $this->serverError(_('Could not update group.')); } + $result = $this->group->setAliases($aliases); + + if (!$result) { + $this->serverError(_('Could not create aliases.')); + } + + $this->group->query('COMMIT'); + if ($this->group->nickname != $orig->nickname) { common_redirect(common_local_url('editgroup', array('nickname' => $nickname)), @@ -229,9 +271,20 @@ class EditgroupAction extends Action function nicknameExists($nickname) { $group = User_group::staticGet('nickname', $nickname); - return (!is_null($group) && - $group != false && - $group->id != $this->group->id); + + if (!empty($group) && + $group->id != $this->group->id) { + return true; + } + + $alias = Group_alias::staticGet('alias', $nickname); + + if (!empty($alias) && + $alias->group_id != $this->group->id) { + return true; + } + + return false; } } diff --git a/actions/newgroup.php b/actions/newgroup.php index 67cd6b2f18..0289e77c25 100644 --- a/actions/newgroup.php +++ b/actions/newgroup.php @@ -123,6 +123,7 @@ class NewgroupAction extends Action $homepage = $this->trimmed('homepage'); $description = $this->trimmed('description'); $location = $this->trimmed('location'); + $aliasstring = $this->trimmed('aliases'); if (!Validate::string($nickname, array('min_length' => 1, 'max_length' => 64, @@ -153,6 +154,37 @@ class NewgroupAction extends Action return; } + if (!empty($aliasstring)) { + $aliases = array_map('common_canonical_nickname', array_unique(preg_split('/[\s,]+/', $aliasstring))); + } else { + $aliases = array(); + } + + if (count($aliases) > common_config('group', 'maxaliases')) { + $this->showForm(sprintf(_('Too many aliases! Maximum %d.'), + common_config('group', 'maxaliases'))); + return; + } + + foreach ($aliases as $alias) { + if (!Validate::string($alias, array('min_length' => 1, + 'max_length' => 64, + 'format' => NICKNAME_FMT))) { + $this->showForm(sprintf(_('Invalid alias: "%s"'), $alias)); + return; + } + if ($this->nicknameExists($alias)) { + $this->showForm(sprintf(_('Alias "%s" already in use. Try another one.'), + $alias)); + return; + } + // XXX assumes alphanum nicknames + if (strcmp($alias, $nickname) == 0) { + $this->showForm(_('Alias can\'t be the same as nickname.')); + return; + } + } + $cur = common_current_user(); // Checked in prepare() above @@ -177,6 +209,12 @@ class NewgroupAction extends Action $this->serverError(_('Could not create group.')); } + $result = $group->setAliases($aliases); + + if (!$result) { + $this->serverError(_('Could not create aliases.')); + } + $member = new Group_member(); $member->group_id = $group->id; @@ -199,7 +237,18 @@ class NewgroupAction extends Action function nicknameExists($nickname) { $group = User_group::staticGet('nickname', $nickname); - return (!is_null($group) && $group != false); + + if (!empty($group)) { + return true; + } + + $alias = Group_alias::staticGet('alias', $nickname); + + if (!empty($alias)) { + return true; + } + + return false; } } diff --git a/classes/User_group.php b/classes/User_group.php index 9f9977755b..0fcfee8c62 100644 --- a/classes/User_group.php +++ b/classes/User_group.php @@ -165,4 +165,64 @@ class User_group extends Memcached_DataObject { return ($this->fullname) ? $this->fullname : $this->nickname; } + + function getAliases() + { + $aliases = array(); + + // XXX: cache this + + $alias = new Group_alias(); + + $alias->group_id = $this->id; + + if ($alias->find()) { + while ($alias->fetch()) { + $aliases[] = $alias->alias; + } + } + + $alias->free(); + + return $aliases; + } + + function setAliases($newaliases) { + + $newaliases = array_unique($newaliases); + + $oldaliases = $this->getAliases(); + + # Delete stuff that's old that not in new + + $to_delete = array_diff($oldaliases, $newaliases); + + # Insert stuff that's in new and not in old + + $to_insert = array_diff($newaliases, $oldaliases); + + $alias = new Group_alias(); + + $alias->group_id = $this->id; + + foreach ($to_delete as $delalias) { + $alias->alias = $delalias; + $result = $alias->delete(); + if (!$result) { + common_log_db_error($alias, 'DELETE', __FILE__); + return false; + } + } + + foreach ($to_insert as $insalias) { + $alias->alias = $insalias; + $result = $alias->insert(); + if (!$result) { + common_log_db_error($alias, 'INSERT', __FILE__); + return false; + } + } + + return true; + } } diff --git a/lib/common.php b/lib/common.php index 6bf4ad21f5..b4e87445e6 100644 --- a/lib/common.php +++ b/lib/common.php @@ -198,6 +198,8 @@ $config = 'user_quota' => 50000000, 'monthly_quota' => 15000000, ), + 'group' => + array('maxaliases' => 3), ); $config['db'] = &PEAR::getStaticProperty('DB_DataObject','options'); diff --git a/lib/groupeditform.php b/lib/groupeditform.php index ca674f3c8e..7e8d6eea3a 100644 --- a/lib/groupeditform.php +++ b/lib/groupeditform.php @@ -111,7 +111,6 @@ class GroupEditForm extends Form } } - /** * Name of the form * @@ -157,6 +156,16 @@ class GroupEditForm extends Form ($this->out->arg('location')) ? $this->out->arg('location') : $this->group->location, _('Location for the group, if any, like "City, State (or Region), Country"')); $this->out->elementEnd('li'); + if (common_config('group', 'maxaliases') > 0) { + $aliases = (empty($this->group)) ? array() : $this->group->getAliases(); + $this->out->elementStart('li'); + $this->out->input('aliases', _('Aliases'), + ($this->out->arg('aliases')) ? $this->out->arg('aliases') : + (!empty($aliases)) ? implode(' ', $aliases) : '', + sprintf(_('Extra nicknames for the group, comma- or space- separated, max %d'), + common_config('group', 'maxaliases')));; + $this->out->elementEnd('li'); + } $this->out->elementEnd('ul'); } From 1b6b00a6d05ad646a9137a872af8d8fdeeaf260f Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 14 Jun 2009 23:43:47 -0700 Subject: [PATCH 048/262] Link and distribute notices tagged for a group alias Correctly link and distribute notices tagged for a group alias. Added a helper function, getForNickname(), to User_group, to make it easier to get a group by its nickname or aliases. --- classes/Notice.php | 6 +++--- classes/User_group.php | 14 ++++++++++++++ lib/util.php | 2 +- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/classes/Notice.php b/classes/Notice.php index 78786b27de..68602b1f7c 100644 --- a/classes/Notice.php +++ b/classes/Notice.php @@ -752,16 +752,16 @@ class Notice extends Memcached_DataObject foreach (array_unique($match[1]) as $nickname) { /* XXX: remote groups. */ - $group = User_group::staticGet('nickname', $nickname); + $group = User_group::getForNickname($nickname); - if (!$group) { + if (empty($group)) { continue; } // we automatically add a tag for every group name, too $tag = Notice_tag::pkeyGet(array('tag' => common_canonical_tag($nickname), - 'notice_id' => $this->id)); + 'notice_id' => $this->id)); if (is_null($tag)) { $this->saveTag($nickname); diff --git a/classes/User_group.php b/classes/User_group.php index 0fcfee8c62..1a24124bb1 100644 --- a/classes/User_group.php +++ b/classes/User_group.php @@ -225,4 +225,18 @@ class User_group extends Memcached_DataObject return true; } + + static function getForNickname($nickname) + { + $nickname = common_canonical_nickname($nickname); + $group = User_group::staticGet('nickname', $nickname); + if (!empty($group)) { + return $group; + } + $alias = Group_alias::staticGet('alias', $nickname); + if (!empty($alias)) { + return User_group::staticGet('id', $alias->group_id); + } + return null; + } } diff --git a/lib/util.php b/lib/util.php index b3a94a5a01..49c6ae108e 100644 --- a/lib/util.php +++ b/lib/util.php @@ -591,7 +591,7 @@ function common_at_link($sender_id, $nickname) function common_group_link($sender_id, $nickname) { $sender = Profile::staticGet($sender_id); - $group = User_group::staticGet('nickname', common_canonical_nickname($nickname)); + $group = User_group::getForNickname($nickname); if ($group && $sender->isMember($group)) { $attrs = array('href' => $group->permalink(), 'class' => 'url'); From dda4493af72870d61774c8389dbbab13c2dfbbc7 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 14 Jun 2009 23:51:38 -0700 Subject: [PATCH 049/262] show aliases when showing a group --- actions/showgroup.php | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/actions/showgroup.php b/actions/showgroup.php index 537f09278b..357f579d8f 100644 --- a/actions/showgroup.php +++ b/actions/showgroup.php @@ -272,6 +272,17 @@ class ShowgroupAction extends Action $this->elementEnd('dl'); } + if (common_config('group', 'maxaliases') > 0) { + $aliases = $this->group->getAliases(); + + if (!empty($aliases)) { + $this->elementStart('dl', 'entity_aliases'); + $this->element('dt', null, _('Aliases')); + $this->element('dd', 'aliases', implode(' ', $aliases)); + $this->elementEnd('dl'); + } + } + $this->elementEnd('div'); $this->elementStart('div', 'entity_actions'); From 2b8a767770119165ab9c9ce62ea3512c2fb3b049 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 15 Jun 2009 00:59:15 -0700 Subject: [PATCH 050/262] make admins of groups --- actions/groupmembers.php | 143 +++++++++++++++++++++++++++++++++++++++ lib/router.php | 4 ++ 2 files changed, 147 insertions(+) diff --git a/actions/groupmembers.php b/actions/groupmembers.php index 65790b7ca3..abfad3f0dd 100644 --- a/actions/groupmembers.php +++ b/actions/groupmembers.php @@ -171,10 +171,26 @@ class GroupMemberListItem extends ProfileListItem { $this->startActions(); $this->showSubscribeButton(); + $this->showMakeAdminForm(); $this->showGroupBlockForm(); $this->endActions(); } + function showMakeAdminForm() + { + $user = common_current_user(); + + if (!empty($user) && $user->id != $this->profile->id && $user->isAdmin($this->group) && + !$this->profile->isAdmin($this->group)) { + $this->out->elementStart('li', 'entity_make_admin'); + $maf = new MakeAdminForm($this->out, $this->profile, $this->group, + array('action' => 'groupmembers', + 'nickname' => $this->group->nickname)); + $maf->show(); + $this->out->elementEnd('li'); + } + + } function showGroupBlockForm() { $user = common_current_user(); @@ -318,3 +334,130 @@ class GroupBlockForm extends Form $this->out->submit('submit', _('Block'), 'submit', null, _('Block this user')); } } + +/** + * Form for making a user an admin for a group + * + * @category Form + * @package Laconica + * @author Evan Prodromou + * @author Sarven Capadisli + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://laconi.ca/ + */ + +class MakeAdminForm extends Form +{ + /** + * Profile of user to block + */ + + var $profile = null; + + /** + * Group to block the user from + */ + + var $group = null; + + /** + * Return-to args + */ + + var $args = null; + + /** + * Constructor + * + * @param HTMLOutputter $out output channel + * @param Profile $profile profile of user to block + * @param User_group $group group to block user from + * @param array $args return-to args + */ + + function __construct($out=null, $profile=null, $group=null, $args=null) + { + parent::__construct($out); + + $this->profile = $profile; + $this->group = $group; + $this->args = $args; + } + + /** + * ID of the form + * + * @return int ID of the form + */ + + function id() + { + // This should be unique for the page. + return 'makeadmin-' . $this->profile->id; + } + + /** + * class of the form + * + * @return string class of the form + */ + + function formClass() + { + return 'form_make_admin'; + } + + /** + * Action of the form + * + * @return string URL of the action + */ + + function action() + { + return common_local_url('makeadmin', array('nickname' => $this->group->nickname)); + } + + /** + * Legend of the Form + * + * @return void + */ + + function formLegend() + { + $this->out->element('legend', null, _('Make user an admin of the group')); + } + + /** + * Data elements of the form + * + * @return void + */ + + function formData() + { + $this->out->hidden('profileid-' . $this->profile->id, + $this->profile->id, + 'profileid'); + $this->out->hidden('groupid-' . $this->group->id, + $this->group->id, + 'groupid'); + if ($this->args) { + foreach ($this->args as $k => $v) { + $this->out->hidden('returnto-' . $k, $v); + } + } + } + + /** + * Action elements + * + * @return void + */ + + function formActions() + { + $this->out->submit('submit', _('Make Admin'), 'submit', null, _('Make this user an admin')); + } +} diff --git a/lib/router.php b/lib/router.php index e10871bc08..0fbaba9ed5 100644 --- a/lib/router.php +++ b/lib/router.php @@ -233,6 +233,10 @@ class Router array('action' => 'blockedfromgroup'), array('nickname' => '[a-zA-Z0-9]+')); + $m->connect('group/:nickname/makeadmin', + array('action' => 'makeadmin'), + array('nickname' => '[a-zA-Z0-9]+')); + $m->connect('group/:id/id', array('action' => 'groupbyid'), array('id' => '[0-9]+')); From 528ceec3fe351cfa3f5050159b2c9e37357e162a Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 15 Jun 2009 05:44:36 -0700 Subject: [PATCH 051/262] makeadmin action --- actions/makeadmin.php | 166 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 166 insertions(+) create mode 100644 actions/makeadmin.php diff --git a/actions/makeadmin.php b/actions/makeadmin.php new file mode 100644 index 0000000000..899c23ae4e --- /dev/null +++ b/actions/makeadmin.php @@ -0,0 +1,166 @@ + + * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 + * @link http://laconi.ca/ + * + * Laconica - a distributed open-source microblogging tool + * Copyright (C) 2008, Controlez-Vous, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +if (!defined('LACONICA')) { + exit(1); +} + +/** + * Make another user an admin of a group + * + * @category Action + * @package Laconica + * @author Evan Prodromou + * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 + * @link http://laconi.ca/ + */ + +class MakeadminAction extends Action +{ + var $profile = null; + var $group = null; + + /** + * Take arguments for running + * + * @param array $args $_REQUEST args + * + * @return boolean success flag + */ + + function prepare($args) + { + parent::prepare($args); + if (!common_logged_in()) { + $this->clientError(_('Not logged in.')); + return false; + } + $token = $this->trimmed('token'); + if (empty($token) || $token != common_session_token()) { + $this->clientError(_('There was a problem with your session token. Try again, please.')); + return; + } + $id = $this->trimmed('profileid'); + if (empty($id)) { + $this->clientError(_('No profile specified.')); + return false; + } + $this->profile = Profile::staticGet('id', $id); + if (empty($this->profile)) { + $this->clientError(_('No profile with that ID.')); + return false; + } + $group_id = $this->trimmed('groupid'); + if (empty($group_id)) { + $this->clientError(_('No group specified.')); + return false; + } + $this->group = User_group::staticGet('id', $group_id); + if (empty($this->group)) { + $this->clientError(_('No such group.')); + return false; + } + $user = common_current_user(); + if (!$user->isAdmin($this->group)) { + $this->clientError(_('Only an admin can make another user an admin.'), 401); + return false; + } + if ($this->profile->isAdmin($this->group)) { + $this->clientError(sprintf(_('%s is already an admin for group "%s".'), + $this->profile->getBestName(), + $this->group->getBestName()), + 401); + return false; + } + return true; + } + + /** + * Handle request + * + * @param array $args $_REQUEST args; handled in prepare() + * + * @return void + */ + + function handle($args) + { + parent::handle($args); + if ($_SERVER['REQUEST_METHOD'] == 'POST') { + $this->makeAdmin(); + } + } + + /** + * Make user an admin + * + * @return void + */ + + function makeAdmin() + { + $member = Group_member::pkeyGet(array('group_id' => $this->group->id, + 'profile_id' => $this->profile->id)); + + if (empty($member)) { + $this->serverError(_('Can\'t get membership record for %s in group %s'), + $this->profile->getBestName(), + $this->group->getBestName()); + } + + $orig = clone($member); + + $member->is_admin = 1; + + $result = $member->update($orig); + + if (!$result) { + common_log_db_error($member, 'UPDATE', __FILE__); + $this->serverError(_('Can\'t make %s an admin for group %s'), + $this->profile->getBestName(), + $this->group->getBestName()); + } + + foreach ($this->args as $k => $v) { + if ($k == 'returnto-action') { + $action = $v; + } else if (substr($k, 0, 9) == 'returnto-') { + $args[substr($k, 9)] = $v; + } + } + + if ($action) { + common_redirect(common_local_url($action, $args), 303); + } else { + common_redirect(common_local_url('groupmembers', + array('nickname' => $this->group->nickname)), + 303); + } + } +} From eb6a60ef8833d0a34768f2717f2a34fdcd52e5ce Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 15 Jun 2009 08:54:52 -0700 Subject: [PATCH 052/262] updates to Status_network --- classes/Status_network.php | 25 +++++++++++++++++++++---- classes/statusnet.ini | 5 +++-- db/site.sql | 6 +++++- 3 files changed, 29 insertions(+), 7 deletions(-) diff --git a/classes/Status_network.php b/classes/Status_network.php index f7747f71d7..d2b942bfb1 100644 --- a/classes/Status_network.php +++ b/classes/Status_network.php @@ -12,11 +12,13 @@ class Status_network extends DB_DataObject public $nickname; // varchar(64) primary_key not_null public $hostname; // varchar(255) unique_key public $pathname; // varchar(255) unique_key - public $sitename; // varchar(255) public $dbhost; // varchar(255) public $dbuser; // varchar(255) public $dbpass; // varchar(255) public $dbname; // varchar(255) + public $sitename; // varchar(255) + public $theme; // varchar(255) + public $logo; // varchar(255) public $created; // datetime() not_null public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP @@ -37,13 +39,19 @@ class Status_network extends DB_DataObject return true; } - static function setupSite($servername, $pathname) + static function setupSite($servername, $pathname, $wildcard) { global $config; - $parts = explode('.', $servername); + // XXX I18N, probably not crucial for hostnames + // XXX This probably needs a tune up - $sn = Status_network::staticGet('nickname', $parts[0]); + if (0 == strncasecmp(strrev($wildcard), strrev($servername), strlen($wildcard))) { + $parts = explode('.', $servername); + $sn = Status_network::staticGet('nickname', strtolower($parts[0])); + } else { + $sn = Status_network::staticGet('hostname', strtolower($servername)); + } if (!empty($sn)) { $dbhost = (empty($sn->dbhost)) ? 'localhost' : $sn->dbhost; @@ -52,7 +60,16 @@ class Status_network extends DB_DataObject $dbname = (empty($sn->dbname)) ? $sn->nickname : $sn->dbname; $config['db']['database'] = "mysqli://$dbuser:$dbpass@$dbhost/$dbname"; + $config['site']['name'] = $sn->sitename; + + if (!empty($sn->theme)) { + $config['site']['theme'] = $sn->theme; + } + if (!empty($sn->logo)) { + $config['site']['logo'] = $sn->logo; + } + return true; } else { return false; diff --git a/classes/statusnet.ini b/classes/statusnet.ini index a70cd41228..8123265e46 100644 --- a/classes/statusnet.ini +++ b/classes/statusnet.ini @@ -1,13 +1,14 @@ - [status_network] nickname = 130 hostname = 2 pathname = 2 -sitename = 2 dbhost = 2 dbuser = 2 dbpass = 2 dbname = 2 +sitename = 2 +theme = 2 +logo = 2 created = 142 modified = 384 diff --git a/db/site.sql b/db/site.sql index 660ba475bb..a9f64e5a5d 100644 --- a/db/site.sql +++ b/db/site.sql @@ -5,12 +5,16 @@ create table status_network ( nickname varchar(64) primary key comment 'nickname', hostname varchar(255) unique key comment 'alternate hostname if any', pathname varchar(255) unique key comment 'alternate pathname if any', - sitename varchar(255) comment 'display name', + dbhost varchar(255) comment 'database host', dbuser varchar(255) comment 'database username', dbpass varchar(255) comment 'database password', dbname varchar(255) comment 'database name', + sitename varchar(255) comment 'display name', + theme varchar(255) comment 'theme name', + logo varchar(255) comment 'site logo', + created datetime not null comment 'date this record was created', modified timestamp comment 'date this record was modified' From c077ad0775218e6aa8660ba97129ad74b5d54773 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 15 Jun 2009 10:45:50 -0700 Subject: [PATCH 053/262] Configurable avatar directory Avatar directory and path are configurable. --- README | 6 ++++++ classes/Avatar.php | 30 +++++++++++++++++++++++++++--- lib/common.php | 4 +++- 3 files changed, 36 insertions(+), 4 deletions(-) diff --git a/README b/README index 8fb4a941cf..5b6b847c89 100644 --- a/README +++ b/README @@ -1008,6 +1008,12 @@ avatar For configuring avatar access. +dir: Directory to look for avatar files and to put them into. + Defaults to avatar subdirectory of install directory; if + you change it, make sure to change path, too. +path: Path to avatars. Defaults to path for avatar subdirectory, + but you can change it if you wish. Note that this will + be included with the avatar server, too. server: If set, defines another server where avatars are stored in the root directory. Note that the 'avatar' subdir still has to be writeable. You'd typically use this to split HTTP requests on diff --git a/classes/Avatar.php b/classes/Avatar.php index db9d78e47f..5e8b315fe6 100644 --- a/classes/Avatar.php +++ b/classes/Avatar.php @@ -55,19 +55,43 @@ class Avatar extends Memcached_DataObject static function path($filename) { - return INSTALLDIR . '/avatar/' . $filename; + $dir = common_config('avatar', 'dir'); + + if ($dir[strlen($dir)-1] != '/') { + $dir .= '/'; + } + + return $dir . $filename; } static function url($filename) { - return common_path('avatar/'.$filename); + $path = common_config('avatar', 'path'); + + if ($path[strlen($path)-1] != '/') { + $path .= '/'; + } + + if ($path[0] != '/') { + $path = '/'.$path; + } + + $server = common_config('avatar', 'server'); + + if (empty($server)) { + $server = common_config('site', 'server'); + } + + // XXX: protocol + + return 'http://'.$server.$path.$filename; } function displayUrl() { $server = common_config('avatar', 'server'); if ($server) { - return 'http://'.$server.'/'.$this->filename; + return Avatar::url($this->filename); } else { return $this->url; } diff --git a/lib/common.php b/lib/common.php index b4e87445e6..ab61c812f5 100644 --- a/lib/common.php +++ b/lib/common.php @@ -108,7 +108,9 @@ $config = 'profile' => array('banned' => array()), 'avatar' => - array('server' => null), + array('server' => null, + 'dir' => INSTALLDIR . '/avatar/', + 'path' => $_path . '/avatar/'), 'public' => array('localonly' => true, 'blacklist' => array(), From 807d84d448fb453de777d7a1ef938150bb03de3e Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Mon, 15 Jun 2009 12:57:08 -0700 Subject: [PATCH 054/262] Small fix to correct the order of defined color prefs --- actions/designsettings.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/actions/designsettings.php b/actions/designsettings.php index 8595cbc4c6..dba983fdf7 100644 --- a/actions/designsettings.php +++ b/actions/designsettings.php @@ -106,10 +106,10 @@ class DesignsettingsAction extends AccountSettingsAction } $this->elementStart('li'); - $this->element('label', array('for' => 'swatch-5'), _('Background')); + $this->element('label', array('for' => 'swatch-0'), _('Background')); $this->element('input', array('name' => 'design_background', 'type' => 'text', - 'id' => 'swatch-5', + 'id' => 'swatch-0', 'class' => 'swatch', 'maxlength' => '7', 'size' => '7', From d6ff702d7f0937451c8595c7b3cbfb9f2813a07b Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 15 Jun 2009 13:34:52 -0700 Subject: [PATCH 055/262] Return network from network setup function Return the network from the network setup function. Also, special-case for when we get a server name the same as the wildcard. --- classes/Status_network.php | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/classes/Status_network.php b/classes/Status_network.php index d2b942bfb1..96b6d9a05b 100644 --- a/classes/Status_network.php +++ b/classes/Status_network.php @@ -43,12 +43,19 @@ class Status_network extends DB_DataObject { global $config; + $sn = null; + // XXX I18N, probably not crucial for hostnames // XXX This probably needs a tune up if (0 == strncasecmp(strrev($wildcard), strrev($servername), strlen($wildcard))) { - $parts = explode('.', $servername); - $sn = Status_network::staticGet('nickname', strtolower($parts[0])); + // special case for exact match + if (0 == strncmp($servername, $wildcard)) { + $sn = Status_network::staticGet('nickname', ''); + } else { + $parts = explode('.', $servername); + $sn = Status_network::staticGet('nickname', strtolower($parts[0])); + } } else { $sn = Status_network::staticGet('hostname', strtolower($servername)); } @@ -70,9 +77,9 @@ class Status_network extends DB_DataObject $config['site']['logo'] = $sn->logo; } - return true; + return $sn; } else { - return false; + return null; } } } From 2f693c4c9453fc61bea960ba8767fdf68e5130cd Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Mon, 15 Jun 2009 21:02:12 +0000 Subject: [PATCH 056/262] Updated swatch numbering --- actions/designsettings.php | 21 ++++++++++----------- js/farbtastic/farbtastic.go.js | 12 ++++++------ 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/actions/designsettings.php b/actions/designsettings.php index dba983fdf7..46a5843f87 100644 --- a/actions/designsettings.php +++ b/actions/designsettings.php @@ -106,10 +106,10 @@ class DesignsettingsAction extends AccountSettingsAction } $this->elementStart('li'); - $this->element('label', array('for' => 'swatch-0'), _('Background')); + $this->element('label', array('for' => 'swatch-1'), _('Background')); $this->element('input', array('name' => 'design_background', 'type' => 'text', - 'id' => 'swatch-0', + 'id' => 'swatch-1', 'class' => 'swatch', 'maxlength' => '7', 'size' => '7', @@ -117,10 +117,10 @@ class DesignsettingsAction extends AccountSettingsAction $this->elementEnd('li'); $this->elementStart('li'); - $this->element('label', array('for' => 'swatch-1'), _('Content')); + $this->element('label', array('for' => 'swatch-2'), _('Content')); $this->element('input', array('name' => 'design_content', 'type' => 'text', - 'id' => 'swatch-1', + 'id' => 'swatch-2', 'class' => 'swatch', 'maxlength' => '7', 'size' => '7', @@ -128,10 +128,10 @@ class DesignsettingsAction extends AccountSettingsAction $this->elementEnd('li'); $this->elementStart('li'); - $this->element('label', array('for' => 'swatch-2'), _('Sidebar')); + $this->element('label', array('for' => 'swatch-3'), _('Sidebar')); $this->element('input', array('name' => 'design_sidebar', 'type' => 'text', - 'id' => 'swatch-2', + 'id' => 'swatch-3', 'class' => 'swatch', 'maxlength' => '7', 'size' => '7', @@ -139,10 +139,10 @@ class DesignsettingsAction extends AccountSettingsAction $this->elementEnd('li'); $this->elementStart('li'); - $this->element('label', array('for' => 'swatch-3'), _('Text')); + $this->element('label', array('for' => 'swatch-4'), _('Text')); $this->element('input', array('name' => 'design_text', 'type' => 'text', - 'id' => 'swatch-3', + 'id' => 'swatch-4', 'class' => 'swatch', 'maxlength' => '7', 'size' => '7', @@ -150,15 +150,14 @@ class DesignsettingsAction extends AccountSettingsAction $this->elementEnd('li'); $this->elementStart('li'); - $this->element('label', array('for' => 'swatch-4'), _('Links')); + $this->element('label', array('for' => 'swatch-5'), _('Links')); $this->element('input', array('name' => 'design_links', 'type' => 'text', - 'id' => 'swatch-4', + 'id' => 'swatch-5', 'class' => 'swatch', 'maxlength' => '7', 'size' => '7', 'value' => $design->linkcolor)); - $this->elementEnd('li'); $this->elementEnd('ul'); diff --git a/js/farbtastic/farbtastic.go.js b/js/farbtastic/farbtastic.go.js index 0149eca7d9..4e0493b40a 100644 --- a/js/farbtastic/farbtastic.go.js +++ b/js/farbtastic/farbtastic.go.js @@ -10,19 +10,19 @@ $(document).ready(function() { function UpdateColors(S) { C = $(S).val(); switch (parseInt(S.id.slice(-1))) { - case 0: default: + case 1: default: $('body').css({'background-color':C}); break; - case 1: + case 2: $('#content').css({'background-color':C}); break; - case 2: + case 3: $('#aside_primary').css({'background-color':C}); break; - case 3: - $('body').css({'color':C}); - break; case 4: + $('html body').css({'color':C}); + break; + case 5: $('a').css({'color':C}); break; } From 6532f0dff63576c94debe521d1ff8d9f594fe422 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 15 Jun 2009 14:29:25 -0700 Subject: [PATCH 057/262] strncmp -> strcasecmp --- classes/Status_network.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/classes/Status_network.php b/classes/Status_network.php index 96b6d9a05b..bf05ad61e0 100644 --- a/classes/Status_network.php +++ b/classes/Status_network.php @@ -50,7 +50,7 @@ class Status_network extends DB_DataObject if (0 == strncasecmp(strrev($wildcard), strrev($servername), strlen($wildcard))) { // special case for exact match - if (0 == strncmp($servername, $wildcard)) { + if (0 == strcasecmp($servername, $wildcard)) { $sn = Status_network::staticGet('nickname', ''); } else { $parts = explode('.', $servername); From 01c03223c2c559deec0191dd7a100e152981e1e2 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 15 Jun 2009 15:13:24 -0700 Subject: [PATCH 058/262] Script to set up new status networks --- scripts/setup.cfg.sample | 11 +++++++++++ scripts/setup_status_network.sh | 30 ++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 scripts/setup.cfg.sample create mode 100644 scripts/setup_status_network.sh diff --git a/scripts/setup.cfg.sample b/scripts/setup.cfg.sample new file mode 100644 index 0000000000..4194bc146d --- /dev/null +++ b/scripts/setup.cfg.sample @@ -0,0 +1,11 @@ +# CONFIGURATION FILE for setup_status_network.sh + +# Base database name; full name will include nickname + +export DBBASE=_example_net +export USERBASE=_example_net +export ADMIN=root +export ADMINPASS=yourpassword +export SITEDB=example_net_site +export AVATARBASE=/var/www/avatar.example.net + diff --git a/scripts/setup_status_network.sh b/scripts/setup_status_network.sh new file mode 100644 index 0000000000..d80612b940 --- /dev/null +++ b/scripts/setup_status_network.sh @@ -0,0 +1,30 @@ +#!/bin/bash + +source ./setup.cfg + +export nickname=$1 +export sitename=$2 + +export password=`pwgen 20` +export database=$nickname$DBBASE +export username=$nickname$USERBASE + +# Create the db + +mysqladmin -u $ADMIN --password=$ADMINPASS create $database + +for f in laconica.sql sms_carrier.sql foreign_services.sql notice_source.sql; do + mysql -u $ADMIN --password=$ADMINPASS $database < ../db/$f; +done + +mysql -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()); + +ENDOFCOMMANDS + +mkdir $AVATARBASE/$nickname +chmod a+w $AVATARBASE/$nickname From 177e4adf40bd41fc711c91fc6d16729b7f1b5796 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 15 Jun 2009 15:13:49 -0700 Subject: [PATCH 059/262] change mods for setup script --- scripts/setup_status_network.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 scripts/setup_status_network.sh diff --git a/scripts/setup_status_network.sh b/scripts/setup_status_network.sh old mode 100644 new mode 100755 From 12cd87cd7b7c207b6f9c30996f0fabb019d6fd76 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Mon, 15 Jun 2009 22:50:14 +0000 Subject: [PATCH 060/262] Missing call to getProfile() caused verify_credentials to fail. --- actions/twitapiusers.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actions/twitapiusers.php b/actions/twitapiusers.php index 13a8746cd0..21a56a9a58 100644 --- a/actions/twitapiusers.php +++ b/actions/twitapiusers.php @@ -58,7 +58,7 @@ class TwitapiusersAction extends TwitterapiAction return; } - $twitter_user = $this->twitter_user_array($profile, true); + $twitter_user = $this->twitter_user_array($user->getProfile(), true); if ($apidata['content-type'] == 'xml') { $this->init_document('xml'); From fd290fc3f9a40a0d3be4e4ffc7d11846bf5295b8 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 15 Jun 2009 16:09:40 -0700 Subject: [PATCH 061/262] allow a configured base for cache keys --- README | 7 +++++++ lib/common.php | 1 + lib/util.php | 8 +++++++- 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/README b/README index 5b6b847c89..57ff72f665 100644 --- a/README +++ b/README @@ -1106,6 +1106,13 @@ database data in memcached . enabled: Set to true to enable. Default false. server: a string with the hostname of the memcached server. Can also be an array of hostnames, if you've got more than one server. +base: memcached uses key-value pairs to store data. We build long, + funny-looking keys to make sure we don't have any conflicts. The + base of the key is usually a simplified version of the site name + (like "Identi.ca" => "identica"), but you can overwrite this if + you need to. You can safely ignore it if you only have one + Laconica site using your memcached server. +port: Port to connect to; defaults to 11211. sphinx ------ diff --git a/lib/common.php b/lib/common.php index ab61c812f5..51204cedea 100644 --- a/lib/common.php +++ b/lib/common.php @@ -152,6 +152,7 @@ $config = 'memcached' => array('enabled' => false, 'server' => 'localhost', + 'base' => null, 'port' => 11211), 'ping' => array('notify' => array()), diff --git a/lib/util.php b/lib/util.php index 49c6ae108e..1d5708bd69 100644 --- a/lib/util.php +++ b/lib/util.php @@ -1322,7 +1322,13 @@ function common_session_token() function common_cache_key($extra) { - return 'laconica:' . common_keyize(common_config('site', 'name')) . ':' . $extra; + $base_key = common_config('memcached', 'base'); + + if (empty($base_key)) { + $base_key = common_keyize(common_config('site', 'name')); + } + + return 'laconica:' . $base_key . ':' . $extra; } function common_keyize($str) From fbed704f3b6a8237e815be9586eb753cc78d20c3 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 15 Jun 2009 16:22:08 -0700 Subject: [PATCH 062/262] don't show create-a-group link if not logged in --- actions/groups.php | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/actions/groups.php b/actions/groups.php index 26b52a5fcd..b49d80f377 100644 --- a/actions/groups.php +++ b/actions/groups.php @@ -100,11 +100,13 @@ class GroupsAction extends Action function showContent() { - $this->elementStart('p', array('id' => 'new_group')); - $this->element('a', array('href' => common_local_url('newgroup'), - 'class' => 'more'), - _('Create a new group')); - $this->elementEnd('p'); + if (common_logged_in()) { + $this->elementStart('p', array('id' => 'new_group')); + $this->element('a', array('href' => common_local_url('newgroup'), + 'class' => 'more'), + _('Create a new group')); + $this->elementEnd('p'); + } $offset = ($this->page-1) * GROUPS_PER_PAGE; $limit = GROUPS_PER_PAGE + 1; From 587b7a8b2ad0b260cc3159da260a4d439c2a5f0c Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 15 Jun 2009 16:40:53 -0700 Subject: [PATCH 063/262] redirect on non-canonical server name --- classes/Status_network.php | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/classes/Status_network.php b/classes/Status_network.php index bf05ad61e0..eef27d7653 100644 --- a/classes/Status_network.php +++ b/classes/Status_network.php @@ -61,6 +61,9 @@ class Status_network extends DB_DataObject } if (!empty($sn)) { + if (!empty($sn->hostname) && 0 != strcasecmp($sn->hostname, $servername)) { + $sn->redirectToHostname(); + } $dbhost = (empty($sn->dbhost)) ? 'localhost' : $sn->dbhost; $dbuser = (empty($sn->dbuser)) ? $sn->nickname : $sn->dbuser; $dbpass = $sn->dbpass; @@ -82,4 +85,29 @@ class Status_network extends DB_DataObject return null; } } + + // Code partially mooked from http://www.richler.de/en/php-redirect/ + // (C) 2006 by Heiko Richler http://www.richler.de/ + // LGPL + + function redirectToHostname() + { + $destination = 'http://'.$this->hostname; + $destination .= $_SERVER['REQUEST_URI']. + $_SERVER['QUERY_STRING']; + + $old = 'http'. + (($_SERVER['HTTPS'] == 'on') ? 'S' : ''). + '://'. + $_SERVER['HTTP_HOST']. + $_SERVER['REQUEST_URI']. + $_SERVER['QUERY_STRING']; + if ($old == $destination) { // this would be a loop! + // error_log(...) ? + return false; + } + + common_redirect($destination, 301); + // shouldn't get here + } } From 2f82a3d44c4fbb0d9c552a2652e341ec882787c1 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 15 Jun 2009 16:43:39 -0700 Subject: [PATCH 064/262] forgot some functions aren't available at status time --- classes/Status_network.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/classes/Status_network.php b/classes/Status_network.php index eef27d7653..128721f41b 100644 --- a/classes/Status_network.php +++ b/classes/Status_network.php @@ -107,7 +107,11 @@ class Status_network extends DB_DataObject return false; } - common_redirect($destination, 301); - // shouldn't get here + header('HTTP/1.1 301 Moved Permanently'); + header("Location: $destination"); + + print "$destination\n"; + + exit; } } From f80966324560d4309b3bb2d6d357719e1e90e6aa Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 15 Jun 2009 16:51:49 -0700 Subject: [PATCH 065/262] a little better query handling in redirect code --- classes/Status_network.php | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/classes/Status_network.php b/classes/Status_network.php index 128721f41b..03e8f45259 100644 --- a/classes/Status_network.php +++ b/classes/Status_network.php @@ -93,8 +93,19 @@ class Status_network extends DB_DataObject function redirectToHostname() { $destination = 'http://'.$this->hostname; - $destination .= $_SERVER['REQUEST_URI']. - $_SERVER['QUERY_STRING']; + $destination .= $_SERVER['REQUEST_URI']; + + $args = $_GET; + + if (isset($args['p'])) { + unset($args['p']); + } + + $query = http_build_query($args); + + if (strlen($query) > 0) { + $destination .= '?' . $query; + } $old = 'http'. (($_SERVER['HTTPS'] == 'on') ? 'S' : ''). From 8c24a3bc92484d19ed4ba489d2d7b1172f4b355d Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 15 Jun 2009 16:55:01 -0700 Subject: [PATCH 066/262] a little better query handling in redirect code --- classes/Status_network.php | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/classes/Status_network.php b/classes/Status_network.php index 03e8f45259..17b6887408 100644 --- a/classes/Status_network.php +++ b/classes/Status_network.php @@ -95,18 +95,6 @@ class Status_network extends DB_DataObject $destination = 'http://'.$this->hostname; $destination .= $_SERVER['REQUEST_URI']; - $args = $_GET; - - if (isset($args['p'])) { - unset($args['p']); - } - - $query = http_build_query($args); - - if (strlen($query) > 0) { - $destination .= '?' . $query; - } - $old = 'http'. (($_SERVER['HTTPS'] == 'on') ? 'S' : ''). '://'. From bd8f9a979acb1607e00499dfba223a51b57596af Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Tue, 16 Jun 2009 02:33:10 +0000 Subject: [PATCH 067/262] Converts user entry in the form of '#1B2' into '#11BB22' for user design swatches --- js/farbtastic/farbtastic.go.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/js/farbtastic/farbtastic.go.js b/js/farbtastic/farbtastic.go.js index 4e0493b40a..2f202ced1f 100644 --- a/js/farbtastic/farbtastic.go.js +++ b/js/farbtastic/farbtastic.go.js @@ -59,7 +59,9 @@ $(document).ready(function() { swatches .each(SynchColors) .blur(function() { - $(this).val($(this).val().toUpperCase()); + tv = $(this).val(); + $(this).val(tv.toUpperCase()); + (tv.length == 4) ? ((tv[0] == '#') ? $(this).val('#'+tv[1]+tv[1]+tv[2]+tv[2]+tv[3]+tv[3]) : '') : ''; }) .focus(function() { $('#color-picker').show(); From 20d93508776398627f5aff64b83bd20a362cb45d Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Mon, 15 Jun 2009 20:21:33 -0700 Subject: [PATCH 068/262] User design setting save now --- actions/designsettings.php | 250 ++++++++++++++++++++++++++----------- lib/webcolor.php | 191 ++++++++++++++++++++++++++++ 2 files changed, 370 insertions(+), 71 deletions(-) create mode 100644 lib/webcolor.php diff --git a/actions/designsettings.php b/actions/designsettings.php index dba983fdf7..0f7c271946 100644 --- a/actions/designsettings.php +++ b/actions/designsettings.php @@ -32,7 +32,8 @@ if (!defined('LACONICA')) { exit(1); } -require_once INSTALLDIR.'/lib/accountsettingsaction.php'; +require_once INSTALLDIR . '/lib/accountsettingsaction.php'; +require_once INSTALLDIR . '/lib/WebColor.php'; class DesignsettingsAction extends AccountSettingsAction { @@ -81,7 +82,7 @@ class DesignsettingsAction extends AccountSettingsAction $this->element('legend', null, _('Change background image')); $this->elementStart('ul', 'form_data'); $this->elementStart('li'); - $this->element('label', array('for' => 'design_background-image_file'), + $this->element('label', array('for' => 'design_background-image_file'), _('Upload file')); $this->element('input', array('name' => 'design_background-image_file', 'type' => 'file', @@ -105,61 +106,79 @@ class DesignsettingsAction extends AccountSettingsAction $design = $this->defaultDesign(); } - $this->elementStart('li'); - $this->element('label', array('for' => 'swatch-0'), _('Background')); - $this->element('input', array('name' => 'design_background', - 'type' => 'text', - 'id' => 'swatch-0', - 'class' => 'swatch', - 'maxlength' => '7', - 'size' => '7', - 'value' => $design->backgroundcolor)); - $this->elementEnd('li'); - - $this->elementStart('li'); - $this->element('label', array('for' => 'swatch-1'), _('Content')); - $this->element('input', array('name' => 'design_content', - 'type' => 'text', - 'id' => 'swatch-1', - 'class' => 'swatch', - 'maxlength' => '7', - 'size' => '7', - 'value' => $design->contentcolor)); - $this->elementEnd('li'); - - $this->elementStart('li'); - $this->element('label', array('for' => 'swatch-2'), _('Sidebar')); - $this->element('input', array('name' => 'design_sidebar', - 'type' => 'text', - 'id' => 'swatch-2', - 'class' => 'swatch', - 'maxlength' => '7', - 'size' => '7', - 'value' => $design->sidebarcolor)); - $this->elementEnd('li'); + try { - $this->elementStart('li'); - $this->element('label', array('for' => 'swatch-3'), _('Text')); - $this->element('input', array('name' => 'design_text', - 'type' => 'text', - 'id' => 'swatch-3', - 'class' => 'swatch', - 'maxlength' => '7', - 'size' => '7', - 'value' => $design->textcolor)); - $this->elementEnd('li'); + $bgcolor = new WebColor($design->backgroundcolor); - $this->elementStart('li'); - $this->element('label', array('for' => 'swatch-4'), _('Links')); - $this->element('input', array('name' => 'design_links', - 'type' => 'text', - 'id' => 'swatch-4', - 'class' => 'swatch', - 'maxlength' => '7', - 'size' => '7', - 'value' => $design->linkcolor)); + $this->elementStart('li'); + $this->element('label', array('for' => 'swatch-0'), _('Background')); + $this->element('input', array('name' => 'design_background', + 'type' => 'text', + 'id' => 'swatch-0', + 'class' => 'swatch', + 'maxlength' => '7', + 'size' => '7', + 'value' => '#' . $bgcolor->hexValue())); + $this->elementEnd('li'); - $this->elementEnd('li'); + + $ccolor = new WebColor($design->contentcolor); + + $this->elementStart('li'); + $this->element('label', array('for' => 'swatch-1'), _('Content')); + $this->element('input', array('name' => 'design_content', + 'type' => 'text', + 'id' => 'swatch-1', + 'class' => 'swatch', + 'maxlength' => '7', + 'size' => '7', + 'value' => '#' . $ccolor->hexValue())); + $this->elementEnd('li'); + + $sbcolor = new WebColor($design->sidebarcolor); + + $this->elementStart('li'); + $this->element('label', array('for' => 'swatch-2'), _('Sidebar')); + $this->element('input', array('name' => 'design_sidebar', + 'type' => 'text', + 'id' => 'swatch-2', + 'class' => 'swatch', + 'maxlength' => '7', + 'size' => '7', + 'value' => '#' . $sbcolor->hexValue())); + $this->elementEnd('li'); + + $tcolor = new WebColor($design->textcolor); + + $this->elementStart('li'); + $this->element('label', array('for' => 'swatch-3'), _('Text')); + $this->element('input', array('name' => 'design_text', + 'type' => 'text', + 'id' => 'swatch-3', + 'class' => 'swatch', + 'maxlength' => '7', + 'size' => '7', + 'value' => '#' . $tcolor->hexValue())); + $this->elementEnd('li'); + + $lcolor = new WebColor($design->linkcolor); + + $this->elementStart('li'); + $this->element('label', array('for' => 'swatch-4'), _('Links')); + $this->element('input', array('name' => 'design_links', + 'type' => 'text', + 'id' => 'swatch-4', + 'class' => 'swatch', + 'maxlength' => '7', + 'size' => '7', + 'value' => '#' . $lcolor->hexValue())); + + $this->elementEnd('li'); + + } catch (WebColorException $e) { + common_log(LOG_ERR, 'Bad color values in design ID: ' . + $design->id); + } $this->elementEnd('ul'); $this->elementEnd('fieldset'); @@ -169,7 +188,7 @@ class DesignsettingsAction extends AccountSettingsAction 'value' => 'Reset', 'class' => 'submit form_action-primary', 'title' => _('Reset back to default'))); - + $this->submit('save', _('Save'), 'submit form_action-secondary', 'save', _('Save design')); @@ -241,40 +260,129 @@ class DesignsettingsAction extends AccountSettingsAction $this->element('script', array('type' => 'text/javascript', 'src' => $farbtasticGo)); } - + /** * Get a default user design * - * @return Design design + * @return Design design */ - + function defaultDesign() { $defaults = common_config('site', 'design'); $design = new Design(); - $design->backgroundcolor = $defaults['backgroundcolor']; - $design->contentcolor = $defaults['contentcolor']; - $design->sidebarcolor = $defaults['sidebarcolor']; - $design->textcolor = $defaults['textcolor']; - $design->linkcolor = $defaults['linkcolor']; - $design->backgroundimage = $defaults['backgroundimage']; + + try { + + $color = new WebColor(); + + $color->parseColor($defaults['backgroundcolor']); + $design->backgroundcolor = $color->intValue(); + + $color->parseColor($defaults['contentcolor']); + $design->contentcolor = $color->intValue(); + + $color->parseColor($defaults['sidebarcolor']); + $design->sidebarcolor = $color->intValue(); + + $color->parseColor($defaults['textcolor']); + $design->sidebarcolor = $color->intValue(); + + $color->parseColor($defaults['linkcolor']); + $design->linkcolor = $color->intValue(); + + $design->backgroundimage = $defaults['backgroundimage']; + + } catch (WebColorException $e) { + common_log(LOG_ERR, _('Bad default color settings: ' . + $e->getMessage())); + } return $design; } /** - * Save the user's design settings + * Save or update the user's design settings * * @return void */ - + function saveDesign() { $user = common_current_user(); - - - + + try { + + $bgcolor = new WebColor($this->trimmed('design_background')); + $ccolor = new WebColor($this->trimmed('design_content')); + $sbcolor = new WebColor($this->trimmed('design_sidebar')); + $tcolor = new WebColor($this->trimmed('design_text')); + $lcolor = new WebColor($this->trimmed('design_links')); + + } catch (WebColorException $e) { + $this->showForm($e->getMessage()); + return; + } + + $design = User::getDesign(); + + if (!isset($design)) { + + $original = clone($design); + + $original->backgroundcolor = $bgcolor->intValue(); + $original->contentcolor = $ccolor->intValue(); + $original->sidebarcolor = $sbcolor->intValue(); + $original->textcolor = $tcolor->intValue(); + $original->linkcolor = $lcolor->intValue(); + + $result = $design->update($original); + + if ($result === false) { + common_log_db_error($design, 'UPDATE', __FILE__); + $this->showForm(_('Couldn\'t update your design.')); + return; + } + + // update design + } else { + + $user->query('BEGIN'); + + // save new design + $design = new Design(); + + $design->backgroundcolor = $bgcolor->intValue(); + $design->contentcolor = $ccolor->intValue(); + $design->sidebarcolor = $sbcolor->intValue(); + $design->textcolor = $tcolor->intValue(); + $design->linkcolor = $lcolor->intValue(); + $design->backgroundimage = $defaults['backgroundimage']; + + $id = $design->insert(); + + if (empty($id)) { + common_log_db_error($id, 'INSERT', __FILE__); + $this->showForm(_('Unable to save your design settings!')); + return; + } + + $original = clone($user); + $user->design_id = $id; + $result = $user->update($original); + + if (empty($result)) { + common_log_db_error($original, 'UPDATE', __FILE__); + $this->showForm(_('Unable to save your design settings!')); + $user->query('ROLLBACK'); + return; + } + + $user->query('COMMIT'); + + } + $this->showForm(_('Design preferences saved.'), true); } @@ -282,9 +390,9 @@ class DesignsettingsAction extends AccountSettingsAction * Reset design settings to previous saved value if any, or * the defaults * - * @return void + * @return void */ - + function resetDesign() { $this->showForm(_('Design preferences reset.'), true); diff --git a/lib/webcolor.php b/lib/webcolor.php new file mode 100644 index 0000000000..65713d26ef --- /dev/null +++ b/lib/webcolor.php @@ -0,0 +1,191 @@ +. + * + * @category Personal + * @package Laconica + * @author Zach Copley + * @copyright 2009 Control Yourself, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://laconi.ca/ + */ + +if (!defined('LACONICA')) { + exit(1); +} + +class WebColor { + + // XXX: Maybe make getters and setters for r,g,b values and tuples, + // e.g.: to support this kinda CSS representation: rgb(255,0,0) + // http://www.w3.org/TR/CSS21/syndata.html#color-units + + var $red = 0; + var $green = 0; + var $blue = 0; + + /** + * Constructor + * + * @return nothing + */ + + function __construct($color = null) + { + if (isset($color)) { + $this->parseColor($color); + } + } + + /** + * Parses input to and tries to determine whether the color + * is being specified via an integer or hex tuple and sets + * the RGB instance variables accordingly. + * + * XXX: Maybe support (r,g,b) style, and array? + * + * @param mixed $color + * + * @return nothing + */ + + function parseColor($color) { + + if (is_numeric($color)) { + $this->setIntColor($color); + } else { + + // XXX named colors + + // XXX: probably should do even more validation + + if (preg_match('/(#([0-9A-Fa-f]{3,6})\b)/u', $color) > 0) { + $this->setHexColor($color); + } else { + $errmsg = _('%s is not a valid color!'); + throw new WebColorException(sprintf($errmsg, $color)); + } + } + } + + /** + * @param string $name + * + * @return nothing + */ + + function setNamedColor($name) + { + // XXX Implement this + } + + + /** + * Sets the RGB color values from a a hex tuple + * + * @param string $hexcolor + * + * @return nothing + */ + + function setHexColor($hexcolor) { + + if ($hexcolor[0] == '#') { + $hexcolor = substr($hexcolor, 1); + } + + if (strlen($hexcolor) == 6) { + list($r, $g, $b) = array($hexcolor[0].$hexcolor[1], + $hexcolor[2].$hexcolor[3], + $hexcolor[4].$hexcolor[5]); + } elseif (strlen($hexcolor) == 3) { + list($r, $g, $b) = array($hexcolor[0].$hexcolor[0], + $hexcolor[1].$hexcolor[1], + $hexcolor[2].$hexcolor[2]); + } else { + return false; + } + + $this->red = hexdec($r); + $this->green = hexdec($g); + $this->blue = hexdec($b); + + } + + /** + * Sets the RGB color values from a 24-bit integer + * + * @param int $intcolor + * + * @return nothing + */ + + function setIntColor($intcolor) + { + // We could do 32 bit and have an alpha channel because + // Sarven wants one real bad, but nah. + + $this->red = $intcolor >> 16; + $this->green = $intcolor >> 8 & 0xFF; + $this->blue = $intcolor & 0xFF; + + } + + /** + * Returns a hex tuple of the RGB color useful for output in HTML + * + * @return string + */ + + function hexValue() { + + $hexcolor = (strlen(dechex($this->red)) < 2 ? '0' : '' ) . + dechex($this->red); + $hexcolor .= (strlen(dechex($this->green)) < 2 ? '0' : '') . + dechex($this->green); + $hexcolor .= (strlen(dechex($this->blue)) < 2 ? '0' : '') . + dechex($this->blue); + + return $hexcolor; + + } + + /** + * Returns a 24-bit packed integer representation of the RGB color + * for convenient storage in the DB + * + * XXX: probably could just use hexdec() instead + * + * @return int + */ + + function intValue() + { + $intcolor = 256 * 256 * $this->red + 256 * $this->green + $this->blue; + return $intcolor; + } + +} + +class WebColorException extends Exception +{ +} + +?> \ No newline at end of file From 94fec28610a62fcf6d33c6ec1f451dadb5ca9b18 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Mon, 15 Jun 2009 20:29:30 -0700 Subject: [PATCH 069/262] User design setting save --- actions/designsettings.php | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/actions/designsettings.php b/actions/designsettings.php index 0f7c271946..dedf19db83 100644 --- a/actions/designsettings.php +++ b/actions/designsettings.php @@ -111,10 +111,10 @@ class DesignsettingsAction extends AccountSettingsAction $bgcolor = new WebColor($design->backgroundcolor); $this->elementStart('li'); - $this->element('label', array('for' => 'swatch-0'), _('Background')); + $this->element('label', array('for' => 'swatch-1'), _('Background')); $this->element('input', array('name' => 'design_background', 'type' => 'text', - 'id' => 'swatch-0', + 'id' => 'swatch-1', 'class' => 'swatch', 'maxlength' => '7', 'size' => '7', @@ -125,10 +125,10 @@ class DesignsettingsAction extends AccountSettingsAction $ccolor = new WebColor($design->contentcolor); $this->elementStart('li'); - $this->element('label', array('for' => 'swatch-1'), _('Content')); + $this->element('label', array('for' => 'swatch-2'), _('Content')); $this->element('input', array('name' => 'design_content', 'type' => 'text', - 'id' => 'swatch-1', + 'id' => 'swatch-2', 'class' => 'swatch', 'maxlength' => '7', 'size' => '7', @@ -138,10 +138,10 @@ class DesignsettingsAction extends AccountSettingsAction $sbcolor = new WebColor($design->sidebarcolor); $this->elementStart('li'); - $this->element('label', array('for' => 'swatch-2'), _('Sidebar')); + $this->element('label', array('for' => 'swatch-3'), _('Sidebar')); $this->element('input', array('name' => 'design_sidebar', 'type' => 'text', - 'id' => 'swatch-2', + 'id' => 'swatch-3', 'class' => 'swatch', 'maxlength' => '7', 'size' => '7', @@ -151,10 +151,10 @@ class DesignsettingsAction extends AccountSettingsAction $tcolor = new WebColor($design->textcolor); $this->elementStart('li'); - $this->element('label', array('for' => 'swatch-3'), _('Text')); + $this->element('label', array('for' => 'swatch-4'), _('Text')); $this->element('input', array('name' => 'design_text', 'type' => 'text', - 'id' => 'swatch-3', + 'id' => 'swatch-4', 'class' => 'swatch', 'maxlength' => '7', 'size' => '7', @@ -164,10 +164,10 @@ class DesignsettingsAction extends AccountSettingsAction $lcolor = new WebColor($design->linkcolor); $this->elementStart('li'); - $this->element('label', array('for' => 'swatch-4'), _('Links')); + $this->element('label', array('for' => 'swatch-5'), _('Links')); $this->element('input', array('name' => 'design_links', 'type' => 'text', - 'id' => 'swatch-4', + 'id' => 'swatch-5', 'class' => 'swatch', 'maxlength' => '7', 'size' => '7', From 2c7f0534ca26b9c9461d920bb23765b282e6fdbc Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Tue, 16 Jun 2009 04:03:08 +0000 Subject: [PATCH 070/262] Typo/lowercased WebColor to webcolor in required_once --- actions/designsettings.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actions/designsettings.php b/actions/designsettings.php index dedf19db83..b7f9cda987 100644 --- a/actions/designsettings.php +++ b/actions/designsettings.php @@ -33,7 +33,7 @@ if (!defined('LACONICA')) { } require_once INSTALLDIR . '/lib/accountsettingsaction.php'; -require_once INSTALLDIR . '/lib/WebColor.php'; +require_once INSTALLDIR . '/lib/webcolor.php'; class DesignsettingsAction extends AccountSettingsAction { From e7e3709ae0294b8400b85d87f2ebeade5b31858d Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Mon, 15 Jun 2009 21:21:33 -0700 Subject: [PATCH 071/262] Throw an WebColorException if wrong # of hex chars --- lib/webcolor.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/webcolor.php b/lib/webcolor.php index 65713d26ef..aaf31d9903 100644 --- a/lib/webcolor.php +++ b/lib/webcolor.php @@ -120,7 +120,8 @@ class WebColor { $hexcolor[1].$hexcolor[1], $hexcolor[2].$hexcolor[2]); } else { - return false; + $errmsg = _('%s is not a valid color! Use 3 or 6 hex chars.'); + throw new WebColorException(sprintf($errmsg, $hexcolor)); } $this->red = hexdec($r); From 0a886868fb25ec1e2500ea2be0ea06c73cb0b2b2 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 15 Jun 2009 21:33:56 -0700 Subject: [PATCH 072/262] Add some basic memcached handling to status_network Status_network can't be a subclass of Memcached_DataObject -- the latter is too entrenched in Laconica's memc handling functions, which aren't loaded when Status_network is running! But the importance of caching these values can't be overstated. So, a considerably slimmed-down version of the Memcached_DataObject code is transcribed into Status_network. --- classes/Status_network.php | 88 +++++++++++++++++++++++++++++++++++--- 1 file changed, 82 insertions(+), 6 deletions(-) diff --git a/classes/Status_network.php b/classes/Status_network.php index 17b6887408..d54364df5a 100644 --- a/classes/Status_network.php +++ b/classes/Status_network.php @@ -1,9 +1,29 @@ . */ -class Status_network extends DB_DataObject +if (!defined('LACONICA')) { exit(1); } + +require_once INSTALLDIR.'/classes/Memcached_DataObject.php'; + +class Status_network extends Memcached_DataObject { ###START_AUTOCODE /* the code below is auto generated do not remove the above tag */ @@ -28,7 +48,10 @@ class Status_network extends DB_DataObject /* the code above is auto generated do not remove the tag below */ ###END_AUTOCODE - static function setupDB($dbhost, $dbuser, $dbpass, $dbname) + static $cache = null; + static $base = null; + + static function setupDB($dbhost, $dbuser, $dbpass, $dbname, $servers) { global $config; @@ -36,7 +59,60 @@ class Status_network extends DB_DataObject $config['db']['ini_'.$dbname] = INSTALLDIR.'/classes/statusnet.ini'; $config['db']['table_status_network'] = $dbname; - return true; + self::$cache = new Memcache(); + + if (is_array($servers)) { + foreach($servers as $server) { + self::$cache->addServer($server); + } + } else { + self::$cache->addServer($servers); + } + + self::$base = $dbname; + } + + static function cacheKey($k, $v) { + return 'laconica:' . self::$base . ':status_network:'.$k.':'.$v; + } + + static function memGet($k, $v) + { + $ck = self::cacheKey($k, $v); + + $sn = self::$cache->get($ck); + + if (empty($sn)) { + $sn = self::staticGet($k, $v); + if (!empty($sn)) { + self::$cache->set($ck, $sn); + } + } + + return $sn; + } + + function decache() + { + $keys = array('nickname', 'hostname', 'pathname'); + foreach ($keys as $k) { + $ck = self::cacheKey($k, $this->$k); + self::$cache->delete($ck); + } + } + + function update($orig=null) + { + if (is_object($orig)) { + $orig->decache(); # might be different keys + } + return parent::update($orig); + } + + function delete() + { + $this->decache(); # while we still have the values! + return parent::delete(); } static function setupSite($servername, $pathname, $wildcard) @@ -51,13 +127,13 @@ class Status_network extends DB_DataObject if (0 == strncasecmp(strrev($wildcard), strrev($servername), strlen($wildcard))) { // special case for exact match if (0 == strcasecmp($servername, $wildcard)) { - $sn = Status_network::staticGet('nickname', ''); + $sn = self::memGet('nickname', ''); } else { $parts = explode('.', $servername); - $sn = Status_network::staticGet('nickname', strtolower($parts[0])); + $sn = self::memGet('nickname', strtolower($parts[0])); } } else { - $sn = Status_network::staticGet('hostname', strtolower($servername)); + $sn = self::memGet('hostname', strtolower($servername)); } if (!empty($sn)) { From 39117bf88c7eca88824f702eabdac94e583af66b Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 15 Jun 2009 21:55:56 -0700 Subject: [PATCH 073/262] forgot to disinherit Memcached_DataObject in Status_network --- classes/Status_network.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/classes/Status_network.php b/classes/Status_network.php index d54364df5a..f8d6756b69 100644 --- a/classes/Status_network.php +++ b/classes/Status_network.php @@ -21,9 +21,7 @@ if (!defined('LACONICA')) { exit(1); } -require_once INSTALLDIR.'/classes/Memcached_DataObject.php'; - -class Status_network extends Memcached_DataObject +class Status_network extends DB_DataObject { ###START_AUTOCODE /* the code below is auto generated do not remove the above tag */ From ef99f83963ba598b1e52224ce80a7d8a8e84a96f Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Mon, 15 Jun 2009 22:13:35 -0700 Subject: [PATCH 074/262] Output custom stylesheets on design sub-Actions --- classes/Design.php | 2 +- lib/currentuserdesignaction.php | 16 ++++++++++++++++ lib/ownerdesignaction.php | 13 +++++++++++++ 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/classes/Design.php b/classes/Design.php index bb1e917e3e..4f6b2a8449 100644 --- a/classes/Design.php +++ b/classes/Design.php @@ -47,7 +47,7 @@ class Design extends Memcached_DataObject function showCSS($out) { - $out->element('stylesheet', array('type' => 'text/css'), + $out->element('style', array('type' => 'text/css'), 'body { background-color: #' . dechex($this->backgroundcolor) . '} '."\n". '#content { background-color #' . dechex($this->contentcolor) . '} '."\n". '#aside_primary { background-color #'. dechex($this->sidebarcolor) .'} '."\n". diff --git a/lib/currentuserdesignaction.php b/lib/currentuserdesignaction.php index 2975256557..40502bc776 100644 --- a/lib/currentuserdesignaction.php +++ b/lib/currentuserdesignaction.php @@ -47,6 +47,20 @@ if (!defined('LACONICA')) { class CurrentUserDesignAction extends Action { + + /** + * Show the user's design stylesheet + * + * @return nothing + */ + function showStylesheets() + { + parent::showStylesheets(); + + $design = $this->getDesign(); + $design->showCSS($this); + } + /** * A design for this action * @@ -66,4 +80,6 @@ class CurrentUserDesignAction extends Action return $cur->getDesign(); } + + } diff --git a/lib/ownerdesignaction.php b/lib/ownerdesignaction.php index c47633bdb2..b6b30a6065 100644 --- a/lib/ownerdesignaction.php +++ b/lib/ownerdesignaction.php @@ -52,6 +52,19 @@ class OwnerDesignAction extends Action { var $user = null; + /** + * Show the owner's design stylesheet + * + * @return nothing + */ + function showStylesheets() + { + parent::showStylesheets(); + + $design = $this->getDesign(); + $design->showCSS($this); + } + /** * A design for this action * From 4652f316cf9cb94fb5f0ae8003d7bb9e2bdcdaee Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Mon, 15 Jun 2009 22:27:59 -0700 Subject: [PATCH 075/262] Design class now uses WebColor class for outputting hex colors --- classes/Design.php | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/classes/Design.php b/classes/Design.php index 4f6b2a8449..9bfdcd1c35 100644 --- a/classes/Design.php +++ b/classes/Design.php @@ -17,13 +17,16 @@ * along with this program. If not, see . */ -if (!defined('LACONICA')) { exit(1); } +if (!defined('LACONICA')) { + exit(1); +} /** * Table Definition for design */ -require_once INSTALLDIR.'/classes/Memcached_DataObject.php'; +require_once INSTALLDIR . '/classes/Memcached_DataObject.php'; +require_once INSTALLDIR . '/lib/webcolor.php'; class Design extends Memcached_DataObject { @@ -47,11 +50,25 @@ class Design extends Memcached_DataObject function showCSS($out) { + try { + + $bgcolor = new WebColor($this->backgroundcolor); + $ccolor = new WebColor($this->contentcolor); + $sbcolor = new WebColor($this->sidebarcolor); + $tcolor = new WebColor($this->textcolor); + $lcolor = new WebColor($this->linkcolor); + + } catch (WebColorException $e) { + // This shouldn't happen + common_log(LOG_ERR, "Unable to create color for design $id.", + __FILE__); + } + $out->element('style', array('type' => 'text/css'), - 'body { background-color: #' . dechex($this->backgroundcolor) . '} '."\n". - '#content { background-color #' . dechex($this->contentcolor) . '} '."\n". - '#aside_primary { background-color #'. dechex($this->sidebarcolor) .'} '."\n". - 'html body { color: #'. dechex($this->textcolor) .'} '."\n". - 'a { color: #' . dechex($this->linkcolor) . '} '."\n"); + 'body { background-color: #' . $bgcolor->hexValue() . '} '."\n". + '#content { background-color #' . $ccolor->hexValue() . '} '."\n". + '#aside_primary { background-color #'. $sbcolor->hexValue() .'} '."\n". + 'html body { color: #'. $tcolor->hexValue() .'} '."\n". + 'a { color: #' . $lcolor->hexValue() . '} '."\n"); } } From f3199c1369bb017d5e1548343a0fd56bededb69b Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Mon, 15 Jun 2009 22:39:53 -0700 Subject: [PATCH 076/262] Some fixups to the CSS output of showCSS() --- classes/Design.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/classes/Design.php b/classes/Design.php index 9bfdcd1c35..f4128ee396 100644 --- a/classes/Design.php +++ b/classes/Design.php @@ -65,9 +65,9 @@ class Design extends Memcached_DataObject } $out->element('style', array('type' => 'text/css'), - 'body { background-color: #' . $bgcolor->hexValue() . '} '."\n". - '#content { background-color #' . $ccolor->hexValue() . '} '."\n". - '#aside_primary { background-color #'. $sbcolor->hexValue() .'} '."\n". + 'html, body { background-color: #' . $bgcolor->hexValue() . '} '."\n". + '#content { background-color: #' . $ccolor->hexValue() . '} '."\n". + '#aside_primary { background-color: #'. $sbcolor->hexValue() .'} '."\n". 'html body { color: #'. $tcolor->hexValue() .'} '."\n". 'a { color: #' . $lcolor->hexValue() . '} '."\n"); } From 37cafad2e071bbfe8a733bba22fb68bbf5220051 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Mon, 15 Jun 2009 22:43:06 -0700 Subject: [PATCH 077/262] Another minor tweak to showCSS() CSS output --- classes/Design.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/classes/Design.php b/classes/Design.php index f4128ee396..8bb5277619 100644 --- a/classes/Design.php +++ b/classes/Design.php @@ -66,7 +66,8 @@ class Design extends Memcached_DataObject $out->element('style', array('type' => 'text/css'), 'html, body { background-color: #' . $bgcolor->hexValue() . '} '."\n". - '#content { background-color: #' . $ccolor->hexValue() . '} '."\n". + '#content, #site_nav_local_views .current a { background-color: #' . + $ccolor->hexValue() . '} '."\n". '#aside_primary { background-color: #'. $sbcolor->hexValue() .'} '."\n". 'html body { color: #'. $tcolor->hexValue() .'} '."\n". 'a { color: #' . $lcolor->hexValue() . '} '."\n"); From c3c30aa0eafd42cf6544cb32614ffe164bfd9ca2 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Mon, 15 Jun 2009 23:18:54 -0700 Subject: [PATCH 078/262] Check to make sure a design exists before trying to display it --- lib/currentuserdesignaction.php | 5 ++++- lib/ownerdesignaction.php | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/currentuserdesignaction.php b/lib/currentuserdesignaction.php index 40502bc776..7c2520cf67 100644 --- a/lib/currentuserdesignaction.php +++ b/lib/currentuserdesignaction.php @@ -58,7 +58,10 @@ class CurrentUserDesignAction extends Action parent::showStylesheets(); $design = $this->getDesign(); - $design->showCSS($this); + + if (!empty($design)) { + $design->showCSS($this); + } } /** diff --git a/lib/ownerdesignaction.php b/lib/ownerdesignaction.php index b6b30a6065..424474f429 100644 --- a/lib/ownerdesignaction.php +++ b/lib/ownerdesignaction.php @@ -62,7 +62,10 @@ class OwnerDesignAction extends Action { parent::showStylesheets(); $design = $this->getDesign(); - $design->showCSS($this); + + if (!empty($design)) { + $design->showCSS($this); + } } /** From 93205cac099e143b7e5dd22a17f6eda6a82d49cf Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Tue, 16 Jun 2009 06:24:29 +0000 Subject: [PATCH 079/262] Connects html, body and content, navigation background colors --- js/farbtastic/farbtastic.go.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/js/farbtastic/farbtastic.go.js b/js/farbtastic/farbtastic.go.js index 2f202ced1f..9bf7408259 100644 --- a/js/farbtastic/farbtastic.go.js +++ b/js/farbtastic/farbtastic.go.js @@ -11,10 +11,10 @@ $(document).ready(function() { C = $(S).val(); switch (parseInt(S.id.slice(-1))) { case 1: default: - $('body').css({'background-color':C}); + $('html, body').css({'background-color':C}); break; case 2: - $('#content').css({'background-color':C}); + $('#content, #site_nav_local_views .current a').css({'background-color':C}); break; case 3: $('#aside_primary').css({'background-color':C}); From 5daa0e358f0a75261e3240820cd6bcf7a57504fc Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Tue, 16 Jun 2009 06:32:17 +0000 Subject: [PATCH 080/262] Using neutral colour for notice hover --- theme/default/css/display.css | 4 ++-- theme/identica/css/display.css | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/theme/default/css/display.css b/theme/default/css/display.css index 166e62157b..06cf9fb260 100644 --- a/theme/default/css/display.css +++ b/theme/default/css/display.css @@ -228,8 +228,8 @@ div.notice-options a, div.notice-options input { font-family:sans-serif; } -.notices li.hover { -background-color:#fcfcfc; +.notices li:hover { +background-color:rgba(194, 194, 194, 0.025); } .notices .notices { diff --git a/theme/identica/css/display.css b/theme/identica/css/display.css index cab42f16f4..0332a6f1e1 100644 --- a/theme/identica/css/display.css +++ b/theme/identica/css/display.css @@ -228,8 +228,8 @@ div.notice-options a, div.notice-options input { font-family:sans-serif; } -.notices li.hover { -background-color:#fcfcfc; +.notices li:hover { +background-color:rgba(194, 194, 194, 0.025); } .notices .notices { From c98179378be7c8903a6ba7a9fe37bf6683219555 Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Tue, 16 Jun 2009 07:45:19 +0000 Subject: [PATCH 081/262] Revert "Using neutral colour for notice hover" This reverts commit 5daa0e358f0a75261e3240820cd6bcf7a57504fc. --- theme/default/css/display.css | 4 ++-- theme/identica/css/display.css | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/theme/default/css/display.css b/theme/default/css/display.css index 06cf9fb260..166e62157b 100644 --- a/theme/default/css/display.css +++ b/theme/default/css/display.css @@ -228,8 +228,8 @@ div.notice-options a, div.notice-options input { font-family:sans-serif; } -.notices li:hover { -background-color:rgba(194, 194, 194, 0.025); +.notices li.hover { +background-color:#fcfcfc; } .notices .notices { diff --git a/theme/identica/css/display.css b/theme/identica/css/display.css index 0332a6f1e1..cab42f16f4 100644 --- a/theme/identica/css/display.css +++ b/theme/identica/css/display.css @@ -228,8 +228,8 @@ div.notice-options a, div.notice-options input { font-family:sans-serif; } -.notices li:hover { -background-color:rgba(194, 194, 194, 0.025); +.notices li.hover { +background-color:#fcfcfc; } .notices .notices { From 6d5d0b3472038b0a2cbe86c7df5f062853164dec Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Tue, 16 Jun 2009 00:56:32 -0700 Subject: [PATCH 082/262] Update wasn't ever getting called --- actions/designsettings.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/actions/designsettings.php b/actions/designsettings.php index b7f9cda987..c5aa8c1d37 100644 --- a/actions/designsettings.php +++ b/actions/designsettings.php @@ -325,17 +325,17 @@ class DesignsettingsAction extends AccountSettingsAction return; } - $design = User::getDesign(); + $design = $user->getDesign(); - if (!isset($design)) { + if (!empty($design)) { $original = clone($design); - $original->backgroundcolor = $bgcolor->intValue(); - $original->contentcolor = $ccolor->intValue(); - $original->sidebarcolor = $sbcolor->intValue(); - $original->textcolor = $tcolor->intValue(); - $original->linkcolor = $lcolor->intValue(); + $design->backgroundcolor = $bgcolor->intValue(); + $design->contentcolor = $ccolor->intValue(); + $design->sidebarcolor = $sbcolor->intValue(); + $design->textcolor = $tcolor->intValue(); + $design->linkcolor = $lcolor->intValue(); $result = $design->update($original); From c74a079e47e1ad71bdb92f8659626730b1b0cae3 Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Tue, 16 Jun 2009 19:40:23 +0000 Subject: [PATCH 083/262] UI updates: Added box-shadow to local views, input focus, content Removed borders from local views, content, aside_primary Some cleaning --- theme/base/css/display.css | 11 +-------- theme/default/css/display.css | 44 ++++++++++++++++++++++------------ theme/identica/css/display.css | 44 ++++++++++++++++++++++------------ 3 files changed, 59 insertions(+), 40 deletions(-) diff --git a/theme/base/css/display.css b/theme/base/css/display.css index 0cbd0d774a..3595d6aa3e 100644 --- a/theme/base/css/display.css +++ b/theme/base/css/display.css @@ -303,10 +303,6 @@ padding:4px 11px; -moz-border-radius-topright:4px; -webkit-border-top-left-radius:4px; -webkit-border-top-right-radius:4px; -border-width:1px; -border-style:solid; -border-bottom:0; -text-shadow: 2px 2px 2px #ddd; font-weight:bold; } #site_nav_local_views .nav { @@ -396,8 +392,6 @@ border-radius:7px; -moz-border-radius-topleft:0; -webkit-border-radius:7px; -webkit-border-top-left-radius:0; -border-style:solid; -border-width:1px; } #shownotice #content { min-height:0; @@ -413,13 +407,11 @@ float:left; width:27.917%; min-height:259px; float:left; -margin-left:0.385%; +margin-left:0.7%; padding:1.795%; border-radius:7px; -moz-border-radius:7px; -webkit-border-radius:7px; -border-width:1px; -border-style:solid; } #form_notice { @@ -469,7 +461,6 @@ height:16px; #form_notice #notice_data-attach { left:183px; padding:0; - height:16px; } #form_notice .form_note { diff --git a/theme/default/css/display.css b/theme/default/css/display.css index 166e62157b..148ce6e600 100644 --- a/theme/default/css/display.css +++ b/theme/default/css/display.css @@ -19,7 +19,7 @@ font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif; font-size:1em; } address { -margin-right:7.18%; +margin-right:7.1%; } input, textarea, select, option { @@ -27,7 +27,7 @@ font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif; } input, textarea, select, .entity_remote_subscribe { -border-color:#aaa; +border-color:#AAAAAA; } #filter_tags ul li { border-color:#C3D6DF; @@ -47,10 +47,13 @@ background-color:#A9BF4F; input:focus, textarea:focus, select:focus, #form_notice.warning #notice_data-text { border-color:#A9BF4F; +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); } input.submit, .entity_remote_subscribe { -color:#fff; +color:#FFFFFF; } a, @@ -79,10 +82,10 @@ background-color:#CEE1E9; } #notice_text-count { -color:#333; +color:#333333; } #form_notice.warning #notice_text-count { -color:#000; +color:#000000; } #form_notice label[for=notice_data-attach] { background:transparent url(../../base/images/icons/twotone/green/clip-01.gif) no-repeat 0 45%; @@ -92,27 +95,38 @@ opacity:0; } #form_notice.processing #notice_action-submit { -background:#fff url(../../base/images/icons/icon_processing.gif) no-repeat 47% 47%; +background:#FFFFFF url(../../base/images/icons/icon_processing.gif) no-repeat 47% 47%; cursor:wait; text-indent:-9999px; } +#content { +box-shadow:5px 7px 7px rgba(194, 194, 194, 0.3); +-moz-box-shadow:5px 7px 7px rgba(194, 194, 194, 0.3); +-webkit-box-shadow:5px 7px 7px rgba(194, 194, 194, 0.3); +} #content, #site_nav_local_views a, #aside_primary { -border-color:#fff; +border-color:#FFFFFF; } #content, #site_nav_local_views .current a { -background-color:#fff; +background-color:#FFFFFF; } #site_nav_local_views a { -background-color:rgba(255, 255, 255, 0.2); +background-color:rgba(194, 194, 194, 0.4); +box-shadow:3px 7px 5px rgba(194, 194, 194, 0.5); +-moz-box-shadow:3px 7px 5px rgba(194, 194, 194, 0.5); +-webkit-box-shadow:3px 7px 5px rgba(194, 194, 194, 0.5); } #site_nav_local_views a:hover { background-color:rgba(255, 255, 255, 0.7); } +#site_nav_local_views .current a { +text-shadow: rgba(194,194,194,0.5) 1px 1px 1px; +} .error { background-color:#F7E8E8; @@ -123,8 +137,8 @@ background-color:#EFF3DC; #anon_notice { background-color:#C3D6DF; -color:#fff; -border-color:#fff; +color:#FFFFFF; +border-color:#FFFFFF; } #showstream #anon_notice { @@ -162,7 +176,7 @@ background-color:transparent; .form_user_subscribe input.submit, .form_user_unsubscribe input.submit { background-color:#A9BF4F; -color:#fff; +color:#FFFFFF; } .form_user_unsubscribe input.submit, .form_group_leave input.submit, @@ -214,7 +228,7 @@ background:transparent url(../../base/images/icons/twotone/green/trash.gif) no-r .notices div.entry-content, .notices div.notice-options, .notices li.hover .notices div.entry-content, -.notices li.hover .notices div.notice-options { +.notices li.hover .notices div.notice-options { opacity:0.4; } .notices li.hover div.entry-content, @@ -222,14 +236,14 @@ opacity:0.4; opacity:1; } div.entry-content { -color:#333; +color:#333333; } div.notice-options a, div.notice-options input { font-family:sans-serif; } .notices li.hover { -background-color:#fcfcfc; +background-color:#FCFCFC; } .notices .notices { diff --git a/theme/identica/css/display.css b/theme/identica/css/display.css index cab42f16f4..ff538f1f12 100644 --- a/theme/identica/css/display.css +++ b/theme/identica/css/display.css @@ -19,7 +19,7 @@ font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif; font-size:1em; } address { -margin-right:7.18%; +margin-right:7.1%; } input, textarea, select, option { @@ -27,10 +27,10 @@ font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif; } input, textarea, select, .entity_remote_subscribe { -border-color:#aaa; +border-color:#AAAAAA; } #filter_tags ul li { -border-color:#ddd; +border-color:#DDDDDD; } .form_settings input.form_action-primary { @@ -47,10 +47,13 @@ background-color:#9BB43E; input:focus, textarea:focus, select:focus, #form_notice.warning #notice_data-text { 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); } input.submit, .entity_remote_subscribe { -color:#fff; +color:#FFFFFF; } a, @@ -79,10 +82,10 @@ background-color:#CEE1E9; } #notice_text-count { -color:#333; +color:#333333; } #form_notice.warning #notice_text-count { -color:#000; +color:#000000; } #form_notice label[for=notice_data-attach] { background:transparent url(../../base/images/icons/twotone/green/clip-01.gif) no-repeat 0 45%; @@ -92,27 +95,38 @@ opacity:0; } #form_notice.processing #notice_action-submit { -background:#fff url(../../base/images/icons/icon_processing.gif) no-repeat 47% 47%; +background:#FFFFFF url(../../base/images/icons/icon_processing.gif) no-repeat 47% 47%; cursor:wait; text-indent:-9999px; } +#content { +box-shadow:5px 7px 7px rgba(194, 194, 194, 0.3); +-moz-box-shadow:5px 7px 7px rgba(194, 194, 194, 0.3); +-webkit-box-shadow:5px 7px 7px rgba(194, 194, 194, 0.3); +} #content, #site_nav_local_views a, #aside_primary { -border-color:#fff; +border-color:#FFFFFF; } #content, #site_nav_local_views .current a { -background-color:#fff; +background-color:#FFFFFF; } #site_nav_local_views a { -background-color:rgba(135, 180, 200, 0.3); +background-color:rgba(194, 194, 194, 0.4); +box-shadow:3px 7px 5px rgba(194, 194, 194, 0.5); +-moz-box-shadow:3px 7px 5px rgba(194, 194, 194, 0.5); +-webkit-box-shadow:3px 7px 5px rgba(194, 194, 194, 0.5); } #site_nav_local_views a:hover { background-color:rgba(255, 255, 255, 0.7); } +#site_nav_local_views .current a { +text-shadow: rgba(194,194,194,0.5) 1px 1px 1px; +} .error { background-color:#F7E8E8; @@ -123,8 +137,8 @@ background-color:#EFF3DC; #anon_notice { background-color:#87B4C8; -color:#fff; -border-color:#fff; +color:#FFFFFF; +border-color:#FFFFFF; } #showstream #anon_notice { @@ -162,7 +176,7 @@ background-color:transparent; .form_user_subscribe input.submit, .form_user_unsubscribe input.submit { background-color:#9BB43E; -color:#fff; +color:#FFFFFF; } .form_user_unsubscribe input.submit, .form_group_leave input.submit, @@ -222,14 +236,14 @@ opacity:0.4; opacity:1; } div.entry-content { -color:#333; +color:#333333; } div.notice-options a, div.notice-options input { font-family:sans-serif; } .notices li.hover { -background-color:#fcfcfc; +background-color:#FCFCFC; } .notices .notices { From c8e3e0d7166abc5acce78d8d6c984764e4c2f7bc Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Tue, 16 Jun 2009 20:56:12 +0000 Subject: [PATCH 084/262] More contrast for tabs --- 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 148ce6e600..12efedf01b 100644 --- a/theme/default/css/display.css +++ b/theme/default/css/display.css @@ -116,7 +116,7 @@ background-color:#FFFFFF; } #site_nav_local_views a { -background-color:rgba(194, 194, 194, 0.4); +background-color:rgba(194, 194, 194, 0.5); box-shadow:3px 7px 5px rgba(194, 194, 194, 0.5); -moz-box-shadow:3px 7px 5px rgba(194, 194, 194, 0.5); -webkit-box-shadow:3px 7px 5px rgba(194, 194, 194, 0.5); diff --git a/theme/identica/css/display.css b/theme/identica/css/display.css index ff538f1f12..fb64013be6 100644 --- a/theme/identica/css/display.css +++ b/theme/identica/css/display.css @@ -116,7 +116,7 @@ background-color:#FFFFFF; } #site_nav_local_views a { -background-color:rgba(194, 194, 194, 0.4); +background-color:rgba(194, 194, 194, 0.5); box-shadow:3px 7px 5px rgba(194, 194, 194, 0.5); -moz-box-shadow:3px 7px 5px rgba(194, 194, 194, 0.5); -webkit-box-shadow:3px 7px 5px rgba(194, 194, 194, 0.5); From fcc86840369c45b0146cc1f3fcd3686e880dea6e Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Tue, 16 Jun 2009 21:10:14 +0000 Subject: [PATCH 085/262] Minor margin value change --- 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 12efedf01b..1ad823a5cd 100644 --- a/theme/default/css/display.css +++ b/theme/default/css/display.css @@ -19,7 +19,7 @@ font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif; font-size:1em; } address { -margin-right:7.1%; +margin-right:7.2%; } input, textarea, select, option { diff --git a/theme/identica/css/display.css b/theme/identica/css/display.css index fb64013be6..bc7ac80fbb 100644 --- a/theme/identica/css/display.css +++ b/theme/identica/css/display.css @@ -19,7 +19,7 @@ font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif; font-size:1em; } address { -margin-right:7.1%; +margin-right:7.2%; } input, textarea, select, option { From 3974ab633c1f75fee71a3a74f7088ca2927468c9 Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Tue, 16 Jun 2009 21:47:58 +0000 Subject: [PATCH 086/262] Brought back borders for content, navigation, aside_primary but applied transparent colour instead, hence not visible. This way, other laconica instances make use of the border if they change only the colour. --- theme/base/css/display.css | 9 ++++++++- theme/default/css/display.css | 2 +- theme/identica/css/display.css | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/theme/base/css/display.css b/theme/base/css/display.css index 3595d6aa3e..49907058e3 100644 --- a/theme/base/css/display.css +++ b/theme/base/css/display.css @@ -303,6 +303,9 @@ padding:4px 11px; -moz-border-radius-topright:4px; -webkit-border-top-left-radius:4px; -webkit-border-top-right-radius:4px; +border-width:1px; +border-style:solid; +border-bottom:0; font-weight:bold; } #site_nav_local_views .nav { @@ -392,6 +395,8 @@ border-radius:7px; -moz-border-radius-topleft:0; -webkit-border-radius:7px; -webkit-border-top-left-radius:0; +border-width:1px; +border-style:solid; } #shownotice #content { min-height:0; @@ -407,11 +412,13 @@ float:left; width:27.917%; min-height:259px; float:left; -margin-left:0.7%; +margin-left:0.5%; padding:1.795%; border-radius:7px; -moz-border-radius:7px; -webkit-border-radius:7px; +border-width:1px; +border-style:solid; } #form_notice { diff --git a/theme/default/css/display.css b/theme/default/css/display.css index 1ad823a5cd..f0d6dace8c 100644 --- a/theme/default/css/display.css +++ b/theme/default/css/display.css @@ -108,7 +108,7 @@ box-shadow:5px 7px 7px rgba(194, 194, 194, 0.3); #content, #site_nav_local_views a, #aside_primary { -border-color:#FFFFFF; +border-color:transparent; } #content, #site_nav_local_views .current a { diff --git a/theme/identica/css/display.css b/theme/identica/css/display.css index bc7ac80fbb..25a01abe0b 100644 --- a/theme/identica/css/display.css +++ b/theme/identica/css/display.css @@ -108,7 +108,7 @@ box-shadow:5px 7px 7px rgba(194, 194, 194, 0.3); #content, #site_nav_local_views a, #aside_primary { -border-color:#FFFFFF; +border-color:transparent; } #content, #site_nav_local_views .current a { From 54697e52989c8d7dc9e1295679e6c0ef676642e0 Mon Sep 17 00:00:00 2001 From: Robin Millette Date: Tue, 16 Jun 2009 19:38:27 -0400 Subject: [PATCH 087/262] Removed more dead code. --- actions/attachment.php | 42 ------------------------------------- actions/attachment_ajax.php | 41 ------------------------------------ 2 files changed, 83 deletions(-) diff --git a/actions/attachment.php b/actions/attachment.php index 16ee723d96..e4dc0e054e 100644 --- a/actions/attachment.php +++ b/actions/attachment.php @@ -98,48 +98,6 @@ class AttachmentAction extends Action return $a->title(); } - /** - * Last-modified date for page - * - * When was the content of this page last modified? Based on notice, - * profile, avatar. - * - * @return int last-modified date as unix timestamp - */ -/* - function lastModified() - { - return max(strtotime($this->notice->created), - strtotime($this->profile->modified), - ($this->avatar) ? strtotime($this->avatar->modified) : 0); - } -*/ - - /** - * An entity tag for this page - * - * Shows the ETag for the page, based on the notice ID and timestamps - * for the notice, profile, and avatar. It's weak, since we change - * the date text "one hour ago", etc. - * - * @return string etag - */ -/* - function etag() - { - $avtime = ($this->avatar) ? - strtotime($this->avatar->modified) : 0; - - return 'W/"' . implode(':', array($this->arg('action'), - common_language(), - $this->notice->id, - strtotime($this->notice->created), - strtotime($this->profile->modified), - $avtime)) . '"'; - } -*/ - - /** * Handle input * diff --git a/actions/attachment_ajax.php b/actions/attachment_ajax.php index 3d83393c51..5d6773010f 100644 --- a/actions/attachment_ajax.php +++ b/actions/attachment_ajax.php @@ -74,46 +74,5 @@ class Attachment_ajaxAction extends AttachmentAction } $this->elementEnd('div'); } - - /** - * Last-modified date for page - * - * When was the content of this page last modified? Based on notice, - * profile, avatar. - * - * @return int last-modified date as unix timestamp - */ -/* - function lastModified() - { - return max(strtotime($this->notice->created), - strtotime($this->profile->modified), - ($this->avatar) ? strtotime($this->avatar->modified) : 0); - } -*/ - - /** - * An entity tag for this page - * - * Shows the ETag for the page, based on the notice ID and timestamps - * for the notice, profile, and avatar. It's weak, since we change - * the date text "one hour ago", etc. - * - * @return string etag - */ -/* - function etag() - { - $avtime = ($this->avatar) ? - strtotime($this->avatar->modified) : 0; - - return 'W/"' . implode(':', array($this->arg('action'), - common_language(), - $this->notice->id, - strtotime($this->notice->created), - strtotime($this->profile->modified), - $avtime)) . '"'; - } -*/ } From bc1f877f6e84929b7f2722f57858cfad8508fea5 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Tue, 16 Jun 2009 19:17:37 -0700 Subject: [PATCH 088/262] Design settings now save and displays backgrounds --- actions/designsettings.php | 69 ++++++++++++++++++++++++++++++++++---- classes/Design.php | 63 ++++++++++++++++++++++++++++++---- lib/common.php | 4 +++ 3 files changed, 122 insertions(+), 14 deletions(-) diff --git a/actions/designsettings.php b/actions/designsettings.php index c5aa8c1d37..aa6915b98e 100644 --- a/actions/designsettings.php +++ b/actions/designsettings.php @@ -56,7 +56,8 @@ class DesignsettingsAction extends AccountSettingsAction function getInstructions() { - return _('Customize the way your profile looks with a background image and a colour palette of your choice.'); + return _('Customize the way your profile looks ' . + 'with a background image and a colour palette of your choice.'); } /** @@ -71,14 +72,16 @@ class DesignsettingsAction extends AccountSettingsAction { $user = common_current_user(); $this->elementStart('form', array('method' => 'post', + 'enctype' => 'multipart/form-data', 'id' => 'form_settings_design', 'class' => 'form_settings', 'action' => - common_local_url('designsettings'))); + common_local_url('designsettings'))); $this->elementStart('fieldset'); $this->hidden('token', common_session_token()); - $this->elementStart('fieldset', array('id' => 'settings_design_background-image')); + $this->elementStart('fieldset', array('id' => + 'settings_design_background-image')); $this->element('legend', null, _('Change background image')); $this->elementStart('ul', 'form_data'); $this->elementStart('li'); @@ -87,7 +90,8 @@ class DesignsettingsAction extends AccountSettingsAction $this->element('input', array('name' => 'design_background-image_file', 'type' => 'file', 'id' => 'design_background-image_file')); - $this->element('p', 'form_guide', _('You can upload your personal background image. The maximum file size is 2Mb.')); + $this->element('p', 'form_guide', _('You can upload your personal ' . + 'background image. The maximum file size is 2Mb.')); $this->element('input', array('name' => 'MAX_FILE_SIZE', 'type' => 'hidden', 'id' => 'MAX_FILE_SIZE', @@ -207,6 +211,20 @@ class DesignsettingsAction extends AccountSettingsAction function handlePost() { + // XXX: Robin's workaround for a bug in PHP where $_POST + // and $_FILE are empty in the case that the uploaded + // file is bigger than PHP is configured to handle. + + if ($_SERVER['REQUEST_METHOD'] == 'POST') { + if (empty($_POST) && $_SERVER['CONTENT_LENGTH']) { + + $msg = _('The server was unable to handle that much POST ' . + 'data (%s bytes) due to its current configuration.'); + + $this->showForm(sprintf($msg, $_SERVER['CONTENT_LENGTH'])); + } + } + // CSRF protection $token = $this->trimmed('token'); if (!$token || $token != common_session_token()) { @@ -310,8 +328,6 @@ class DesignsettingsAction extends AccountSettingsAction function saveDesign() { - $user = common_current_user(); - try { $bgcolor = new WebColor($this->trimmed('design_background')); @@ -325,6 +341,7 @@ class DesignsettingsAction extends AccountSettingsAction return; } + $user = common_current_user(); $design = $user->getDesign(); if (!empty($design)) { @@ -336,6 +353,7 @@ class DesignsettingsAction extends AccountSettingsAction $design->sidebarcolor = $sbcolor->intValue(); $design->textcolor = $tcolor->intValue(); $design->linkcolor = $lcolor->intValue(); + $design->backgroundimage = $filepath; $result = $design->update($original); @@ -358,7 +376,7 @@ class DesignsettingsAction extends AccountSettingsAction $design->sidebarcolor = $sbcolor->intValue(); $design->textcolor = $tcolor->intValue(); $design->linkcolor = $lcolor->intValue(); - $design->backgroundimage = $defaults['backgroundimage']; + $design->backgroundimage = $filepath; $id = $design->insert(); @@ -383,6 +401,43 @@ class DesignsettingsAction extends AccountSettingsAction } + // Now that we have a Design ID we can add a file to the design. + // XXX: This is an additional DB hit, but figured having the image + // associated with the Design rather than the User was worth + // it. -- Zach + + if ($_FILES['design_background-image_file']['error'] == + UPLOAD_ERR_OK) { + + $filepath = null; + + try { + $imagefile = + ImageFile::fromUpload('design_background-image_file'); + } catch (Exception $e) { + $this->showForm($e->getMessage()); + return; + } + + $filename = Design::filename($design->id, + image_type_to_extension($imagefile->type), + common_timestamp()); + + $filepath = Design::path($filename); + + move_uploaded_file($imagefile->filepath, $filepath); + + $original = clone($design); + $design->backgroundimage = $filename; + $result = $design->update($original); + + if ($result === false) { + common_log_db_error($design, 'UPDATE', __FILE__); + $this->showForm(_('Couldn\'t update your design.')); + return; + } + } + $this->showForm(_('Design preferences saved.'), true); } diff --git a/classes/Design.php b/classes/Design.php index 8bb5277619..f5c87b489c 100644 --- a/classes/Design.php +++ b/classes/Design.php @@ -64,12 +64,61 @@ class Design extends Memcached_DataObject __FILE__); } - $out->element('style', array('type' => 'text/css'), - 'html, body { background-color: #' . $bgcolor->hexValue() . '} '."\n". - '#content, #site_nav_local_views .current a { background-color: #' . - $ccolor->hexValue() . '} '."\n". - '#aside_primary { background-color: #'. $sbcolor->hexValue() .'} '."\n". - 'html body { color: #'. $tcolor->hexValue() .'} '."\n". - 'a { color: #' . $lcolor->hexValue() . '} '."\n"); + $css = 'html, body { background-color: #' . $bgcolor->hexValue() . '} ' . "\n"; + $css .= '#content, #site_nav_local_views .current a { background-color: #'; + $css .= $ccolor->hexValue() . '} '."\n"; + $css .= '#aside_primary { background-color: #'. $sbcolor->hexValue() . '} ' . "\n"; + $css .= 'html body { color: #'. $tcolor->hexValue() . '} '. "\n"; + $css .= 'a { color: #' . $lcolor->hexValue() . '} ' . "\n"; + + if (!empty($this->backgroundimage)) { + + $css .= 'body { background-image:url(' . + Design::url($this->backgroundimage) . + '); background-repeat:no-repeat; }' . "\n"; + } + + $out->element('style', array('type' => 'text/css'), $css); + } + + static function filename($id, $extension, $extra=null) + { + return $id . (($extra) ? ('-' . $extra) : '') . $extension; + } + + static function path($filename) + { + $dir = common_config('background', 'dir'); + + if ($dir[strlen($dir)-1] != '/') { + $dir .= '/'; + } + + return $dir . $filename; + } + + static function url($filename) + { + $path = common_config('background', 'path'); + + if ($path[strlen($path)-1] != '/') { + $path .= '/'; + } + + if ($path[0] != '/') { + $path = '/'.$path; + } + + $server = common_config('background', 'server'); + + if (empty($server)) { + $server = common_config('site', 'server'); + } + + // XXX: protocol + + return 'http://'.$server.$path.$filename; + } + } diff --git a/lib/common.php b/lib/common.php index 1381d80477..0e710625c7 100644 --- a/lib/common.php +++ b/lib/common.php @@ -119,6 +119,10 @@ $config = array('server' => null, 'dir' => INSTALLDIR . '/avatar/', 'path' => $_path . '/avatar/'), + 'background' => + array('server' => null, + 'dir' => INSTALLDIR . '/background/', + 'path' => $_path . '/background/'), 'public' => array('localonly' => true, 'blacklist' => array(), From 90344e55d46f07e69ff0800552d28ea90b11764a Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Tue, 16 Jun 2009 19:23:06 -0700 Subject: [PATCH 089/262] Add background dir --- .gitignore | 1 + background/.gitignore | 0 2 files changed, 1 insertion(+) create mode 100644 background/.gitignore diff --git a/.gitignore b/.gitignore index 3418d8ee54..8a7f5c65c8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ avatar/* +background/* files/* file/* _darcs/* diff --git a/background/.gitignore b/background/.gitignore new file mode 100644 index 0000000000..e69de29bb2 From befbfc9c73a75bac9d7dac4a4b7a21bd515ce1b4 Mon Sep 17 00:00:00 2001 From: Robin Millette Date: Tue, 16 Jun 2009 23:10:17 -0400 Subject: [PATCH 090/262] Moved url handling to its proper place, from newnotice to Notice.php --- actions/newnotice.php | 19 ------------------- classes/Notice.php | 19 +++++++++++++++++++ 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/actions/newnotice.php b/actions/newnotice.php index 02976a2ae2..72ccd8c325 100644 --- a/actions/newnotice.php +++ b/actions/newnotice.php @@ -231,7 +231,6 @@ class NewnoticeAction extends Action if (isset($mimetype)) { $this->storeFile($notice, $mimetype); } - $this->saveUrls($notice); common_broadcast_notice($notice); if ($this->boolean('ajax')) { @@ -284,24 +283,6 @@ class NewnoticeAction extends Action } } - /** save all urls in the notice to the db - * - * follow redirects and save all available file information - * (mimetype, date, size, oembed, etc.) - * - * @param class $notice Notice to pull URLs from - * - * @return void - */ - function saveUrls($notice, $uploaded = null) { - common_replace_urls_callback($notice->content, array($this, 'saveUrl'), $notice->id); - } - - function saveUrl($data) { - list($url, $notice_id) = $data; - $zzz = File::processNew($url, $notice_id); - } - /** * Show an Ajax-y error message * diff --git a/classes/Notice.php b/classes/Notice.php index 68602b1f7c..770b5d78b7 100644 --- a/classes/Notice.php +++ b/classes/Notice.php @@ -217,6 +217,7 @@ class Notice extends Memcached_DataObject $notice->addToInboxes(); $notice->saveGroups(); + $notice->saveUrls(); $notice->query('COMMIT'); @@ -231,6 +232,24 @@ class Notice extends Memcached_DataObject return $notice; } + /** save all urls in the notice to the db + * + * follow redirects and save all available file information + * (mimetype, date, size, oembed, etc.) + * + * @param class $notice Notice to pull URLs from + * + * @return void + */ + function saveUrls() { + common_replace_urls_callback($this->content, array($this, 'saveUrl'), $this->id); + } + + function saveUrl($data) { + list($url, $notice_id) = $data; + File::processNew($url, $notice_id); + } + static function checkDupes($profile_id, $content) { $profile = Profile::staticGet($profile_id); if (!$profile) { From 7845fe3100375f0dc7c2515cfa935187efa1c0c8 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Tue, 16 Jun 2009 21:00:53 -0700 Subject: [PATCH 091/262] typos in README; dependencies --- README | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README b/README index 57ff72f665..3279f7bbaa 100644 --- a/README +++ b/README @@ -178,8 +178,8 @@ and the URLs are listed here for your convenience. - Facebook library. Used for the Facebook application. - PEAR Services_oEmbed. Used for some multimedia integration. - PEAR HTTP_Request is an oEmbed dependency. -- PEAR Validat is an oEmbed dependency.e -- PEAR Net_URL is an oEmbed dependency.2 +- PEAR Validate is an oEmbed dependency. +- PEAR Net_URL2 is an oEmbed dependency. A design goal of Laconica is that the basic Web functionality should work on even the most restrictive commercial hosting services. From bea2fa15060e03d818db043122bf9529d2b77662 Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Wed, 17 Jun 2009 04:09:30 +0000 Subject: [PATCH 092/262] Added form option to tile background image and to turn it on and off --- actions/designsettings.php | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/actions/designsettings.php b/actions/designsettings.php index aa6915b98e..e97d01ceb7 100644 --- a/actions/designsettings.php +++ b/actions/designsettings.php @@ -97,6 +97,34 @@ class DesignsettingsAction extends AccountSettingsAction 'id' => 'MAX_FILE_SIZE', 'value' => ImageFile::maxFileSizeInt())); $this->elementEnd('li'); + + $this->elementStart('li', array('id' => 'design_background-image_onoff')); + $this->element('input', array('name' => 'design_background-image_onoff', + 'type' => 'radio', + 'id' => 'design_background-image_on', + 'class' => 'radio', + 'value' => 'true', + 'checked'=> 'checked')); + $this->element('label', array('for' => 'design_background-image_on', + 'class' => 'radio'), + _('On')); + $this->element('input', array('name' => 'design_background-image_onoff', + 'type' => 'radio', + 'id' => 'design_background-image_off', + 'class' => 'radio', + 'value' => 'false')); + $this->element('label', array('for' => 'design_background-image_off', + 'class' => 'radio'), + _('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'), + false, null, true, false); + $this->elementEnd('li'); + $this->elementEnd('ul'); $this->elementEnd('fieldset'); From a592ee6b99596d16da513c0ce8174aae3f3063cd Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Wed, 17 Jun 2009 04:33:01 +0000 Subject: [PATCH 093/262] Init styles for tile and image use on/off for user design settings --- theme/base/css/display.css | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/theme/base/css/display.css b/theme/base/css/display.css index 0cbd0d774a..5b69b4f3d5 100644 --- a/theme/base/css/display.css +++ b/theme/base/css/display.css @@ -77,7 +77,8 @@ margin:0 0 18px 0; form label { font-weight:bold; } -input.checkbox { +input.checkbox, +input.radio { position:relative; top:2px; left:0; @@ -168,7 +169,8 @@ margin-bottom:0; margin-bottom:11px; } -.form_settings input.checkbox { +.form_settings input.checkbox, +.form_settings input.radio { margin-top:3px; margin-left:0; } @@ -180,13 +182,19 @@ margin-left:11px; float:left; width:90%; } - +.form_settings label.radio { +margin-top:0; +margin-right:47px; +margin-left:11px; +width:auto; +} #form_login p.form_guide, #form_register #settings_rememberme p.form_guide, #form_openid_login #settings_rememberme p.form_guide, #settings_twitter_remove p.form_guide, -#form_search ul.form_data #q { +#form_search ul.form_data #q, +#design_background-image_onoff p.form_guide { margin-left:0; } From 7b7f11942885666bfe1f03dd6f34e36a82a08484 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Tue, 16 Jun 2009 21:36:15 -0700 Subject: [PATCH 094/262] Added background image tile flag to Design --- classes/Design.php | 19 ++++++++++--------- classes/laconica.ini | 1 + db/laconica.sql | 3 ++- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/classes/Design.php b/classes/Design.php index f5c87b489c..acc94d1969 100644 --- a/classes/Design.php +++ b/classes/Design.php @@ -41,6 +41,7 @@ class Design extends Memcached_DataObject public $textcolor; // int(4) public $linkcolor; // int(4) public $backgroundimage; // varchar(255) + public $tile; // tinyint(1) /* Static get */ function staticGet($k,$v=NULL) { return Memcached_DataObject::staticGet('Design',$k,$v); } @@ -63,23 +64,23 @@ class Design extends Memcached_DataObject common_log(LOG_ERR, "Unable to create color for design $id.", __FILE__); } - + $css = 'html, body { background-color: #' . $bgcolor->hexValue() . '} ' . "\n"; $css .= '#content, #site_nav_local_views .current a { background-color: #'; $css .= $ccolor->hexValue() . '} '."\n"; $css .= '#aside_primary { background-color: #'. $sbcolor->hexValue() . '} ' . "\n"; $css .= 'html body { color: #'. $tcolor->hexValue() . '} '. "\n"; $css .= 'a { color: #' . $lcolor->hexValue() . '} ' . "\n"; - + if (!empty($this->backgroundimage)) { - - $css .= 'body { background-image:url(' . - Design::url($this->backgroundimage) . + + $css .= 'body { background-image:url(' . + Design::url($this->backgroundimage) . '); background-repeat:no-repeat; }' . "\n"; } - + $out->element('style', array('type' => 'text/css'), $css); - + } static function filename($id, $extension, $extra=null) @@ -97,7 +98,7 @@ class Design extends Memcached_DataObject return $dir . $filename; } - + static function url($filename) { $path = common_config('background', 'path'); @@ -120,5 +121,5 @@ class Design extends Memcached_DataObject return 'http://'.$server.$path.$filename; } - + } diff --git a/classes/laconica.ini b/classes/laconica.ini index c04ae758f4..5696819848 100755 --- a/classes/laconica.ini +++ b/classes/laconica.ini @@ -46,6 +46,7 @@ sidebarcolor = 1 textcolor = 1 linkcolor = 1 backgroundimage = 2 +tile = 17 [design__keys] id = N diff --git a/db/laconica.sql b/db/laconica.sql index bd95d1ade6..1f302de167 100644 --- a/db/laconica.sql +++ b/db/laconica.sql @@ -495,7 +495,8 @@ create table design ( sidebarcolor integer comment 'sidebar background color', textcolor integer comment 'text color', linkcolor integer comment 'link color', - backgroundimage varchar(255) comment 'background image, if any' + backgroundimage varchar(255) comment 'background image, if any', + tile tinyint default 0 comment 'tile background image' ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin; create table group_block ( From 90b2b3f9d19196a6961fb7a115b48b2cbdf966ce Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Tue, 16 Jun 2009 21:37:04 -0700 Subject: [PATCH 095/262] names for Notice is_local states --- classes/Notice.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/classes/Notice.php b/classes/Notice.php index 68602b1f7c..333832d0b1 100644 --- a/classes/Notice.php +++ b/classes/Notice.php @@ -29,6 +29,11 @@ require_once INSTALLDIR.'/classes/Memcached_DataObject.php'; define('NOTICE_CACHE_WINDOW', 61); +define('NOTICE_LOCAL_PUBLIC', 1); +define('NOTICE_REMOTE_OMB', 0); +define('NOTICE_LOCAL_NONPUBLIC', -1); +define('NOTICE_GATEWAY', -2); + class Notice extends Memcached_DataObject { ###START_AUTOCODE @@ -793,7 +798,7 @@ class Notice extends Memcached_DataObject $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 . "', 2 " . + "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 312fd855324b680c45b71c683b9589f24e1b31a9 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Tue, 16 Jun 2009 21:37:19 -0700 Subject: [PATCH 096/262] names for Notice_inbox source values --- classes/Notice_inbox.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/classes/Notice_inbox.php b/classes/Notice_inbox.php index 673e187c72..367a35f1f7 100644 --- a/classes/Notice_inbox.php +++ b/classes/Notice_inbox.php @@ -25,6 +25,10 @@ require_once INSTALLDIR.'/classes/Memcached_DataObject.php'; define('INBOX_CACHE_WINDOW', 101); +define('NOTICE_INBOX_SOURCE_SUB', 1); +define('NOTICE_INBOX_SOURCE_GROUP', 2); +define('NOTICE_INBOX_SOURCE_GATEWAY', -1); + class Notice_inbox extends Memcached_DataObject { ###START_AUTOCODE From d1ae3176b638a8342f0d3cfb4ac071623c639575 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Tue, 16 Jun 2009 22:18:25 -0700 Subject: [PATCH 097/262] Enable tiling of background imgs for Designs --- actions/designsettings.php | 20 +++++++++++++------- classes/Design.php | 25 ++++++++++++++----------- lib/common.php | 3 ++- 3 files changed, 29 insertions(+), 19 deletions(-) diff --git a/actions/designsettings.php b/actions/designsettings.php index e97d01ceb7..866d8aaeb7 100644 --- a/actions/designsettings.php +++ b/actions/designsettings.php @@ -71,6 +71,12 @@ class DesignsettingsAction extends AccountSettingsAction function showContent() { $user = common_current_user(); + $design = $user->getDesign(); + + if (empty($design)) { + $design = $this->defaultDesign(); + } + $this->elementStart('form', array('method' => 'post', 'enctype' => 'multipart/form-data', 'id' => 'form_settings_design', @@ -122,7 +128,7 @@ class DesignsettingsAction extends AccountSettingsAction $this->elementStart('li'); $this->checkbox('design_background-image_repeat', _('Tile background image'), - false, null, true, false); + $design->tile); $this->elementEnd('li'); $this->elementEnd('ul'); @@ -132,12 +138,6 @@ class DesignsettingsAction extends AccountSettingsAction $this->element('legend', null, _('Change colours')); $this->elementStart('ul', 'form_data'); - $design = $user->getDesign(); - - if (empty($design)) { - $design = $this->defaultDesign(); - } - try { $bgcolor = new WebColor($design->backgroundcolor); @@ -340,6 +340,8 @@ class DesignsettingsAction extends AccountSettingsAction $design->backgroundimage = $defaults['backgroundimage']; + $deisng->tile = $defaults['tile']; + } catch (WebColorException $e) { common_log(LOG_ERR, _('Bad default color settings: ' . $e->getMessage())); @@ -369,6 +371,8 @@ class DesignsettingsAction extends AccountSettingsAction return; } + $tile = $this->boolean('design_background-image_repeat'); + $user = common_current_user(); $design = $user->getDesign(); @@ -382,6 +386,7 @@ class DesignsettingsAction extends AccountSettingsAction $design->textcolor = $tcolor->intValue(); $design->linkcolor = $lcolor->intValue(); $design->backgroundimage = $filepath; + $design->tile = $tile; $result = $design->update($original); @@ -405,6 +410,7 @@ class DesignsettingsAction extends AccountSettingsAction $design->textcolor = $tcolor->intValue(); $design->linkcolor = $lcolor->intValue(); $design->backgroundimage = $filepath; + $design->tile = $tile; $id = $design->insert(); diff --git a/classes/Design.php b/classes/Design.php index acc94d1969..4ea176677b 100644 --- a/classes/Design.php +++ b/classes/Design.php @@ -41,7 +41,7 @@ class Design extends Memcached_DataObject public $textcolor; // int(4) public $linkcolor; // int(4) public $backgroundimage; // varchar(255) - public $tile; // tinyint(1) + public $tile; // tinyint(1) /* Static get */ function staticGet($k,$v=NULL) { return Memcached_DataObject::staticGet('Design',$k,$v); } @@ -64,23 +64,26 @@ class Design extends Memcached_DataObject common_log(LOG_ERR, "Unable to create color for design $id.", __FILE__); } - + $css = 'html, body { background-color: #' . $bgcolor->hexValue() . '} ' . "\n"; $css .= '#content, #site_nav_local_views .current a { background-color: #'; $css .= $ccolor->hexValue() . '} '."\n"; $css .= '#aside_primary { background-color: #'. $sbcolor->hexValue() . '} ' . "\n"; $css .= 'html body { color: #'. $tcolor->hexValue() . '} '. "\n"; $css .= 'a { color: #' . $lcolor->hexValue() . '} ' . "\n"; - + if (!empty($this->backgroundimage)) { - - $css .= 'body { background-image:url(' . - Design::url($this->backgroundimage) . - '); background-repeat:no-repeat; }' . "\n"; + + $repeat = ($this->tile) ? 'background-repeat:repeat;' : + 'background-repeat:no-repeat;'; + + $css .= 'body { background-image:url(' . + Design::url($this->backgroundimage) . + '); ' . $repeat . ' }' . "\n"; } - + $out->element('style', array('type' => 'text/css'), $css); - + } static function filename($id, $extension, $extra=null) @@ -98,7 +101,7 @@ class Design extends Memcached_DataObject return $dir . $filename; } - + static function url($filename) { $path = common_config('background', 'path'); @@ -121,5 +124,5 @@ class Design extends Memcached_DataObject return 'http://'.$server.$path.$filename; } - + } diff --git a/lib/common.php b/lib/common.php index 0e710625c7..629fee25b2 100644 --- a/lib/common.php +++ b/lib/common.php @@ -78,7 +78,8 @@ $config = 'sidebarcolor' => '#CEE1E9', 'textcolor' => '#000000', 'linkcolor' => '#002E6E', - 'backgroundimage' => null), + 'backgroundimage' => null, + 'tile' => true), 'path' => $_path, 'logfile' => null, 'logo' => null, From 9aebcf442616c5b39ac2ea19ef011c2347a3bec3 Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Wed, 17 Jun 2009 05:18:59 +0000 Subject: [PATCH 098/262] IE7/8 CSS update for user design --- theme/base/css/ie.css | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/theme/base/css/ie.css b/theme/base/css/ie.css index d1b0558ec8..da200388eb 100644 --- a/theme/base/css/ie.css +++ b/theme/base/css/ie.css @@ -1,8 +1,6 @@ /* IE specific styles */ -legend { -margin-left:-7px; -} -input.checkbox { +input.checkbox, +input.radio { top:0; } #form_notice textarea { From a0618b0e33e20700b243d696f2bf139f1167ec93 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Tue, 16 Jun 2009 22:57:28 -0700 Subject: [PATCH 099/262] Show a background img in settings form --- actions/designsettings.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/actions/designsettings.php b/actions/designsettings.php index 866d8aaeb7..a97235e678 100644 --- a/actions/designsettings.php +++ b/actions/designsettings.php @@ -105,6 +105,12 @@ class DesignsettingsAction extends AccountSettingsAction $this->elementEnd('li'); $this->elementStart('li', array('id' => 'design_background-image_onoff')); + + if (!empty($design->backgroundimage)) { + $this->element('img', array('src' => + Design::url($design->backgroundimage))); + } + $this->element('input', array('name' => 'design_background-image_onoff', 'type' => 'radio', 'id' => 'design_background-image_on', From 7148ea86dff5754fcf0c28023cff52137843f2d9 Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Wed, 17 Jun 2009 06:23:57 +0000 Subject: [PATCH 100/262] Dynamically tile background image and turn background image on or off in user design --- actions/designsettings.php | 4 +- js/farbtastic/farbtastic.js | 329 ------------------ .../farbtastic.go.js => userdesign.go.js} | 20 +- 3 files changed, 18 insertions(+), 335 deletions(-) delete mode 100644 js/farbtastic/farbtastic.js rename js/{farbtastic/farbtastic.go.js => userdesign.go.js} (81%) diff --git a/actions/designsettings.php b/actions/designsettings.php index a97235e678..fbec3fc67f 100644 --- a/actions/designsettings.php +++ b/actions/designsettings.php @@ -305,12 +305,12 @@ class DesignsettingsAction extends AccountSettingsAction parent::showScripts(); $farbtasticPack = common_path('js/farbtastic/farbtastic.js'); - $farbtasticGo = common_path('js/farbtastic/farbtastic.go.js'); + $userDesignGo = common_path('js/userdesign.go.js'); $this->element('script', array('type' => 'text/javascript', 'src' => $farbtasticPack)); $this->element('script', array('type' => 'text/javascript', - 'src' => $farbtasticGo)); + 'src' => $userDesignGo)); } /** diff --git a/js/farbtastic/farbtastic.js b/js/farbtastic/farbtastic.js deleted file mode 100644 index 24a377803c..0000000000 --- a/js/farbtastic/farbtastic.js +++ /dev/null @@ -1,329 +0,0 @@ -// $Id: farbtastic.js,v 1.2 2007/01/08 22:53:01 unconed Exp $ -// Farbtastic 1.2 - -jQuery.fn.farbtastic = function (callback) { - $.farbtastic(this, callback); - return this; -}; - -jQuery.farbtastic = function (container, callback) { - var container = $(container).get(0); - return container.farbtastic || (container.farbtastic = new jQuery._farbtastic(container, callback)); -} - -jQuery._farbtastic = function (container, callback) { - // Store farbtastic object - var fb = this; - - // Insert markup - $(container).html('
'); - var e = $('.farbtastic', container); - fb.wheel = $('.wheel', container).get(0); - // Dimensions - fb.radius = 84; - fb.square = 100; - fb.width = 194; - - // Fix background PNGs in IE6 - if (navigator.appVersion.match(/MSIE [0-6]\./)) { - $('*', e).each(function () { - if (this.currentStyle.backgroundImage != 'none') { - var image = this.currentStyle.backgroundImage; - image = this.currentStyle.backgroundImage.substring(5, image.length - 2); - $(this).css({ - 'backgroundImage': 'none', - 'filter': "progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true, sizingMethod=crop, src='" + image + "')" - }); - } - }); - } - - /** - * Link to the given element(s) or callback. - */ - fb.linkTo = function (callback) { - // Unbind previous nodes - if (typeof fb.callback == 'object') { - $(fb.callback).unbind('keyup', fb.updateValue); - } - - // Reset color - fb.color = null; - - // Bind callback or elements - if (typeof callback == 'function') { - fb.callback = callback; - } - else if (typeof callback == 'object' || typeof callback == 'string') { - fb.callback = $(callback); - fb.callback.bind('keyup', fb.updateValue); - if (fb.callback.get(0).value) { - fb.setColor(fb.callback.get(0).value); - } - } - return this; - } - fb.updateValue = function (event) { - if (this.value && this.value != fb.color) { - fb.setColor(this.value); - } - } - - /** - * Change color with HTML syntax #123456 - */ - fb.setColor = function (color) { - var unpack = fb.unpack(color); - if (fb.color != color && unpack) { - fb.color = color; - fb.rgb = unpack; - fb.hsl = fb.RGBToHSL(fb.rgb); - fb.updateDisplay(); - } - return this; - } - - /** - * Change color with HSL triplet [0..1, 0..1, 0..1] - */ - fb.setHSL = function (hsl) { - fb.hsl = hsl; - fb.rgb = fb.HSLToRGB(hsl); - fb.color = fb.pack(fb.rgb); - fb.updateDisplay(); - return this; - } - - ///////////////////////////////////////////////////// - - /** - * Retrieve the coordinates of the given event relative to the center - * of the widget. - */ - fb.widgetCoords = function (event) { - var x, y; - var el = event.target || event.srcElement; - var reference = fb.wheel; - - if (typeof event.offsetX != 'undefined') { - // Use offset coordinates and find common offsetParent - var pos = { x: event.offsetX, y: event.offsetY }; - - // Send the coordinates upwards through the offsetParent chain. - var e = el; - while (e) { - e.mouseX = pos.x; - e.mouseY = pos.y; - pos.x += e.offsetLeft; - pos.y += e.offsetTop; - e = e.offsetParent; - } - - // Look for the coordinates starting from the wheel widget. - var e = reference; - var offset = { x: 0, y: 0 } - while (e) { - if (typeof e.mouseX != 'undefined') { - x = e.mouseX - offset.x; - y = e.mouseY - offset.y; - break; - } - offset.x += e.offsetLeft; - offset.y += e.offsetTop; - e = e.offsetParent; - } - - // Reset stored coordinates - e = el; - while (e) { - e.mouseX = undefined; - e.mouseY = undefined; - e = e.offsetParent; - } - } - else { - // Use absolute coordinates - var pos = fb.absolutePosition(reference); - x = (event.pageX || 0*(event.clientX + $('html').get(0).scrollLeft)) - pos.x; - y = (event.pageY || 0*(event.clientY + $('html').get(0).scrollTop)) - pos.y; - } - // Subtract distance to middle - return { x: x - fb.width / 2, y: y - fb.width / 2 }; - } - - /** - * Mousedown handler - */ - fb.mousedown = function (event) { - // Capture mouse - if (!document.dragging) { - $(document).bind('mousemove', fb.mousemove).bind('mouseup', fb.mouseup); - document.dragging = true; - } - - // Check which area is being dragged - var pos = fb.widgetCoords(event); - fb.circleDrag = Math.max(Math.abs(pos.x), Math.abs(pos.y)) * 2 > fb.square; - - // Process - fb.mousemove(event); - return false; - } - - /** - * Mousemove handler - */ - fb.mousemove = function (event) { - // Get coordinates relative to color picker center - var pos = fb.widgetCoords(event); - - // Set new HSL parameters - if (fb.circleDrag) { - var hue = Math.atan2(pos.x, -pos.y) / 6.28; - if (hue < 0) hue += 1; - fb.setHSL([hue, fb.hsl[1], fb.hsl[2]]); - } - else { - var sat = Math.max(0, Math.min(1, -(pos.x / fb.square) + .5)); - var lum = Math.max(0, Math.min(1, -(pos.y / fb.square) + .5)); - fb.setHSL([fb.hsl[0], sat, lum]); - } - return false; - } - - /** - * Mouseup handler - */ - fb.mouseup = function () { - // Uncapture mouse - $(document).unbind('mousemove', fb.mousemove); - $(document).unbind('mouseup', fb.mouseup); - document.dragging = false; - } - - /** - * Update the markers and styles - */ - fb.updateDisplay = function () { - // Markers - var angle = fb.hsl[0] * 6.28; - $('.h-marker', e).css({ - left: Math.round(Math.sin(angle) * fb.radius + fb.width / 2) + 'px', - top: Math.round(-Math.cos(angle) * fb.radius + fb.width / 2) + 'px' - }); - - $('.sl-marker', e).css({ - left: Math.round(fb.square * (.5 - fb.hsl[1]) + fb.width / 2) + 'px', - top: Math.round(fb.square * (.5 - fb.hsl[2]) + fb.width / 2) + 'px' - }); - - // Saturation/Luminance gradient - $('.color', e).css('backgroundColor', fb.pack(fb.HSLToRGB([fb.hsl[0], 1, 0.5]))); - - // Linked elements or callback - if (typeof fb.callback == 'object') { - // Set background/foreground color - $(fb.callback).css({ - backgroundColor: fb.color, - color: fb.hsl[2] > 0.5 ? '#000' : '#fff' - }); - - // Change linked value - $(fb.callback).each(function() { - if (this.value && this.value != fb.color) { - this.value = fb.color; - } - }); - } - else if (typeof fb.callback == 'function') { - fb.callback.call(fb, fb.color); - } - } - - /** - * Get absolute position of element - */ - fb.absolutePosition = function (el) { - var r = { x: el.offsetLeft, y: el.offsetTop }; - // Resolve relative to offsetParent - if (el.offsetParent) { - var tmp = fb.absolutePosition(el.offsetParent); - r.x += tmp.x; - r.y += tmp.y; - } - return r; - }; - - /* Various color utility functions */ - fb.pack = function (rgb) { - var r = Math.round(rgb[0] * 255); - var g = Math.round(rgb[1] * 255); - var b = Math.round(rgb[2] * 255); - return '#' + (r < 16 ? '0' : '') + r.toString(16) + - (g < 16 ? '0' : '') + g.toString(16) + - (b < 16 ? '0' : '') + b.toString(16); - } - - fb.unpack = function (color) { - if (color.length == 7) { - return [parseInt('0x' + color.substring(1, 3)) / 255, - parseInt('0x' + color.substring(3, 5)) / 255, - parseInt('0x' + color.substring(5, 7)) / 255]; - } - else if (color.length == 4) { - return [parseInt('0x' + color.substring(1, 2)) / 15, - parseInt('0x' + color.substring(2, 3)) / 15, - parseInt('0x' + color.substring(3, 4)) / 15]; - } - } - - fb.HSLToRGB = function (hsl) { - var m1, m2, r, g, b; - var h = hsl[0], s = hsl[1], l = hsl[2]; - m2 = (l <= 0.5) ? l * (s + 1) : l + s - l*s; - m1 = l * 2 - m2; - return [this.hueToRGB(m1, m2, h+0.33333), - this.hueToRGB(m1, m2, h), - this.hueToRGB(m1, m2, h-0.33333)]; - } - - fb.hueToRGB = function (m1, m2, h) { - h = (h < 0) ? h + 1 : ((h > 1) ? h - 1 : h); - if (h * 6 < 1) return m1 + (m2 - m1) * h * 6; - if (h * 2 < 1) return m2; - if (h * 3 < 2) return m1 + (m2 - m1) * (0.66666 - h) * 6; - return m1; - } - - fb.RGBToHSL = function (rgb) { - var min, max, delta, h, s, l; - var r = rgb[0], g = rgb[1], b = rgb[2]; - min = Math.min(r, Math.min(g, b)); - max = Math.max(r, Math.max(g, b)); - delta = max - min; - l = (min + max) / 2; - s = 0; - if (l > 0 && l < 1) { - s = delta / (l < 0.5 ? (2 * l) : (2 - 2 * l)); - } - h = 0; - if (delta > 0) { - if (max == r && max != g) h += (g - b) / delta; - if (max == g && max != b) h += (2 + (b - r) / delta); - if (max == b && max != r) h += (4 + (r - g) / delta); - h /= 6; - } - return [h, s, l]; - } - - // Install mousedown handler (the others are set on the document on-demand) - $('*', e).mousedown(fb.mousedown); - - // Init color - fb.setColor('#000000'); - - // Set linked elements/callback - if (callback) { - fb.linkTo(callback); - } -} \ No newline at end of file diff --git a/js/farbtastic/farbtastic.go.js b/js/userdesign.go.js similarity index 81% rename from js/farbtastic/farbtastic.go.js rename to js/userdesign.go.js index 9bf7408259..b54b492cce 100644 --- a/js/farbtastic/farbtastic.go.js +++ b/js/userdesign.go.js @@ -49,7 +49,7 @@ $(document).ready(function() { } } - function Init() { + function InitFarbtastic() { $('#settings_design_color').append('
'); $('#color-picker').hide(); @@ -75,13 +75,25 @@ $(document).ready(function() { } var f, swatches; - Init(); + InitFarbtastic(); $('#form_settings_design').bind('reset', function(){ setTimeout(function(){ swatches.each(function(){UpdateColors(this);}); $('#color-picker').remove(); swatches.unbind(); - Init(); + InitFarbtastic(); },10); }); -}); + + $('#design_background-image_off').focus(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+')'}); + }); + + $('#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 ea5d46a94d377675eb06dc57757d0e4c743f8a54 Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Wed, 17 Jun 2009 06:38:21 +0000 Subject: [PATCH 101/262] It was accidently removed --- js/farbtastic/farbtastic.js | 345 ++++++++++++++++++++++++++++++++++++ 1 file changed, 345 insertions(+) create mode 100644 js/farbtastic/farbtastic.js diff --git a/js/farbtastic/farbtastic.js b/js/farbtastic/farbtastic.js new file mode 100644 index 0000000000..d8b5ad9cdf --- /dev/null +++ b/js/farbtastic/farbtastic.js @@ -0,0 +1,345 @@ +/** + * Farbtastic Color Picker 1.2 + * © 2008 Steven Wittens + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +jQuery.fn.farbtastic = function (callback) { + $.farbtastic(this, callback); + return this; +}; + +jQuery.farbtastic = function (container, callback) { + var container = $(container).get(0); + return container.farbtastic || (container.farbtastic = new jQuery._farbtastic(container, callback)); +} + +jQuery._farbtastic = function (container, callback) { + // Store farbtastic object + var fb = this; + + // Insert markup + $(container).html('
'); + var e = $('.farbtastic', container); + fb.wheel = $('.wheel', container).get(0); + // Dimensions + fb.radius = 84; + fb.square = 100; + fb.width = 194; + + // Fix background PNGs in IE6 + if (navigator.appVersion.match(/MSIE [0-6]\./)) { + $('*', e).each(function () { + if (this.currentStyle.backgroundImage != 'none') { + var image = this.currentStyle.backgroundImage; + image = this.currentStyle.backgroundImage.substring(5, image.length - 2); + $(this).css({ + 'backgroundImage': 'none', + 'filter': "progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true, sizingMethod=crop, src='" + image + "')" + }); + } + }); + } + + /** + * Link to the given element(s) or callback. + */ + fb.linkTo = function (callback) { + // Unbind previous nodes + if (typeof fb.callback == 'object') { + $(fb.callback).unbind('keyup', fb.updateValue); + } + + // Reset color + fb.color = null; + + // Bind callback or elements + if (typeof callback == 'function') { + fb.callback = callback; + } + else if (typeof callback == 'object' || typeof callback == 'string') { + fb.callback = $(callback); + fb.callback.bind('keyup', fb.updateValue); + if (fb.callback.get(0).value) { + fb.setColor(fb.callback.get(0).value); + } + } + return this; + } + fb.updateValue = function (event) { + if (this.value && this.value != fb.color) { + fb.setColor(this.value); + } + } + + /** + * Change color with HTML syntax #123456 + */ + fb.setColor = function (color) { + var unpack = fb.unpack(color); + if (fb.color != color && unpack) { + fb.color = color; + fb.rgb = unpack; + fb.hsl = fb.RGBToHSL(fb.rgb); + fb.updateDisplay(); + } + return this; + } + + /** + * Change color with HSL triplet [0..1, 0..1, 0..1] + */ + fb.setHSL = function (hsl) { + fb.hsl = hsl; + fb.rgb = fb.HSLToRGB(hsl); + fb.color = fb.pack(fb.rgb); + fb.updateDisplay(); + return this; + } + + ///////////////////////////////////////////////////// + + /** + * Retrieve the coordinates of the given event relative to the center + * of the widget. + */ + fb.widgetCoords = function (event) { + var x, y; + var el = event.target || event.srcElement; + var reference = fb.wheel; + + if (typeof event.offsetX != 'undefined') { + // Use offset coordinates and find common offsetParent + var pos = { x: event.offsetX, y: event.offsetY }; + + // Send the coordinates upwards through the offsetParent chain. + var e = el; + while (e) { + e.mouseX = pos.x; + e.mouseY = pos.y; + pos.x += e.offsetLeft; + pos.y += e.offsetTop; + e = e.offsetParent; + } + + // Look for the coordinates starting from the wheel widget. + var e = reference; + var offset = { x: 0, y: 0 } + while (e) { + if (typeof e.mouseX != 'undefined') { + x = e.mouseX - offset.x; + y = e.mouseY - offset.y; + break; + } + offset.x += e.offsetLeft; + offset.y += e.offsetTop; + e = e.offsetParent; + } + + // Reset stored coordinates + e = el; + while (e) { + e.mouseX = undefined; + e.mouseY = undefined; + e = e.offsetParent; + } + } + else { + // Use absolute coordinates + var pos = fb.absolutePosition(reference); + x = (event.pageX || 0*(event.clientX + $('html').get(0).scrollLeft)) - pos.x; + y = (event.pageY || 0*(event.clientY + $('html').get(0).scrollTop)) - pos.y; + } + // Subtract distance to middle + return { x: x - fb.width / 2, y: y - fb.width / 2 }; + } + + /** + * Mousedown handler + */ + fb.mousedown = function (event) { + // Capture mouse + if (!document.dragging) { + $(document).bind('mousemove', fb.mousemove).bind('mouseup', fb.mouseup); + document.dragging = true; + } + + // Check which area is being dragged + var pos = fb.widgetCoords(event); + fb.circleDrag = Math.max(Math.abs(pos.x), Math.abs(pos.y)) * 2 > fb.square; + + // Process + fb.mousemove(event); + return false; + } + + /** + * Mousemove handler + */ + fb.mousemove = function (event) { + // Get coordinates relative to color picker center + var pos = fb.widgetCoords(event); + + // Set new HSL parameters + if (fb.circleDrag) { + var hue = Math.atan2(pos.x, -pos.y) / 6.28; + if (hue < 0) hue += 1; + fb.setHSL([hue, fb.hsl[1], fb.hsl[2]]); + } + else { + var sat = Math.max(0, Math.min(1, -(pos.x / fb.square) + .5)); + var lum = Math.max(0, Math.min(1, -(pos.y / fb.square) + .5)); + fb.setHSL([fb.hsl[0], sat, lum]); + } + return false; + } + + /** + * Mouseup handler + */ + fb.mouseup = function () { + // Uncapture mouse + $(document).unbind('mousemove', fb.mousemove); + $(document).unbind('mouseup', fb.mouseup); + document.dragging = false; + } + + /** + * Update the markers and styles + */ + fb.updateDisplay = function () { + // Markers + var angle = fb.hsl[0] * 6.28; + $('.h-marker', e).css({ + left: Math.round(Math.sin(angle) * fb.radius + fb.width / 2) + 'px', + top: Math.round(-Math.cos(angle) * fb.radius + fb.width / 2) + 'px' + }); + + $('.sl-marker', e).css({ + left: Math.round(fb.square * (.5 - fb.hsl[1]) + fb.width / 2) + 'px', + top: Math.round(fb.square * (.5 - fb.hsl[2]) + fb.width / 2) + 'px' + }); + + // Saturation/Luminance gradient + $('.color', e).css('backgroundColor', fb.pack(fb.HSLToRGB([fb.hsl[0], 1, 0.5]))); + + // Linked elements or callback + if (typeof fb.callback == 'object') { + // Set background/foreground color + $(fb.callback).css({ + backgroundColor: fb.color, + color: fb.hsl[2] > 0.5 ? '#000' : '#fff' + }); + + // Change linked value + $(fb.callback).each(function() { + if (this.value && this.value != fb.color) { + this.value = fb.color; + } + }); + } + else if (typeof fb.callback == 'function') { + fb.callback.call(fb, fb.color); + } + } + + /** + * Get absolute position of element + */ + fb.absolutePosition = function (el) { + var r = { x: el.offsetLeft, y: el.offsetTop }; + // Resolve relative to offsetParent + if (el.offsetParent) { + var tmp = fb.absolutePosition(el.offsetParent); + r.x += tmp.x; + r.y += tmp.y; + } + return r; + }; + + /* Various color utility functions */ + fb.pack = function (rgb) { + var r = Math.round(rgb[0] * 255); + var g = Math.round(rgb[1] * 255); + var b = Math.round(rgb[2] * 255); + return '#' + (r < 16 ? '0' : '') + r.toString(16) + + (g < 16 ? '0' : '') + g.toString(16) + + (b < 16 ? '0' : '') + b.toString(16); + } + + fb.unpack = function (color) { + if (color.length == 7) { + return [parseInt('0x' + color.substring(1, 3)) / 255, + parseInt('0x' + color.substring(3, 5)) / 255, + parseInt('0x' + color.substring(5, 7)) / 255]; + } + else if (color.length == 4) { + return [parseInt('0x' + color.substring(1, 2)) / 15, + parseInt('0x' + color.substring(2, 3)) / 15, + parseInt('0x' + color.substring(3, 4)) / 15]; + } + } + + fb.HSLToRGB = function (hsl) { + var m1, m2, r, g, b; + var h = hsl[0], s = hsl[1], l = hsl[2]; + m2 = (l <= 0.5) ? l * (s + 1) : l + s - l*s; + m1 = l * 2 - m2; + return [this.hueToRGB(m1, m2, h+0.33333), + this.hueToRGB(m1, m2, h), + this.hueToRGB(m1, m2, h-0.33333)]; + } + + fb.hueToRGB = function (m1, m2, h) { + h = (h < 0) ? h + 1 : ((h > 1) ? h - 1 : h); + if (h * 6 < 1) return m1 + (m2 - m1) * h * 6; + if (h * 2 < 1) return m2; + if (h * 3 < 2) return m1 + (m2 - m1) * (0.66666 - h) * 6; + return m1; + } + + fb.RGBToHSL = function (rgb) { + var min, max, delta, h, s, l; + var r = rgb[0], g = rgb[1], b = rgb[2]; + min = Math.min(r, Math.min(g, b)); + max = Math.max(r, Math.max(g, b)); + delta = max - min; + l = (min + max) / 2; + s = 0; + if (l > 0 && l < 1) { + s = delta / (l < 0.5 ? (2 * l) : (2 - 2 * l)); + } + h = 0; + if (delta > 0) { + if (max == r && max != g) h += (g - b) / delta; + if (max == g && max != b) h += (2 + (b - r) / delta); + if (max == b && max != r) h += (4 + (r - g) / delta); + h /= 6; + } + return [h, s, l]; + } + + // Install mousedown handler (the others are set on the document on-demand) + $('*', e).mousedown(fb.mousedown); + + // Init color + fb.setColor('#000000'); + + // Set linked elements/callback + if (callback) { + fb.linkTo(callback); + } +} \ No newline at end of file From 0e4d8c416db4c838e94df3df77c2e4b14a0e1851 Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Wed, 17 Jun 2009 07:49:41 +0000 Subject: [PATCH 102/262] Removed NoticeHover from JavaScript for speed gain. Using CSS instead to handle the notice hover state. The difference is only seen in the conversation page. --- js/util.js | 13 +------------ theme/default/css/display.css | 13 +++++++------ theme/identica/css/display.css | 13 +++++++------ 3 files changed, 15 insertions(+), 24 deletions(-) diff --git a/js/util.js b/js/util.js index fd2500d447..ce0c20d31b 100644 --- a/js/util.js +++ b/js/util.js @@ -230,21 +230,10 @@ $(document).ready(function(){ }; $("#form_notice").ajaxForm(PostNotice); $("#form_notice").each(addAjaxHidden); - NoticeHover(); NoticeReply(); NoticeAttachments(); }); - -function NoticeHover() { - function mouseHandler(e) { - $(e.target).closest('li.hentry')[(e.type === 'mouseover') ? 'addClass' : 'removeClass']('hover'); - }; - $('#content .notices').mouseover(mouseHandler); - $('#content .notices').mouseout(mouseHandler); -} - - function NoticeReply() { if ($('#notice_data-text').length > 0) { $('#content .notice').each(function() { @@ -319,4 +308,4 @@ function NoticeAttachments() { $(this).closest(".entry-title").removeClass('ov'); } ); -} +} \ No newline at end of file diff --git a/theme/default/css/display.css b/theme/default/css/display.css index f0d6dace8c..8dd5ca32cd 100644 --- a/theme/default/css/display.css +++ b/theme/default/css/display.css @@ -226,13 +226,11 @@ background:transparent url(../../base/images/icons/twotone/green/trash.gif) no-r } .notices div.entry-content, -.notices div.notice-options, -.notices li.hover .notices div.entry-content, -.notices li.hover .notices div.notice-options { +.notices div.notice-options { opacity:0.4; } -.notices li.hover div.entry-content, -.notices li.hover div.notice-options { +.notices li:hover div.entry-content, +.notices li:hover div.notice-options { opacity:1; } div.entry-content { @@ -242,9 +240,12 @@ div.notice-options a, div.notice-options input { font-family:sans-serif; } -.notices li.hover { +.notices li:hover { background-color:#FCFCFC; } +#conversation .notices li:hover { +background-color:transparent; +} .notices .notices { background-color:rgba(200, 200, 200, 0.050); diff --git a/theme/identica/css/display.css b/theme/identica/css/display.css index 25a01abe0b..975702faad 100644 --- a/theme/identica/css/display.css +++ b/theme/identica/css/display.css @@ -226,13 +226,11 @@ background:transparent url(../../base/images/icons/twotone/green/trash.gif) no-r } .notices div.entry-content, -.notices div.notice-options, -.notices li.hover .notices div.entry-content, -.notices li.hover .notices div.notice-options { +.notices div.notice-options { opacity:0.4; } -.notices li.hover div.entry-content, -.notices li.hover div.notice-options { +.notices li:hover div.entry-content, +.notices li:hover div.notice-options { opacity:1; } div.entry-content { @@ -242,9 +240,12 @@ div.notice-options a, div.notice-options input { font-family:sans-serif; } -.notices li.hover { +.notices li:hover { background-color:#FCFCFC; } +#conversation .notices li:hover { +background-color:transparent; +} .notices .notices { background-color:rgba(200, 200, 200, 0.050); From 4c640aace978a2a57b6d2d4658febde3f9826efa Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Wed, 17 Jun 2009 08:14:01 +0000 Subject: [PATCH 103/262] Updated markup yes/no form actions to be consistent with the rest of the site --- actions/block.php | 17 ++++++++++------- actions/groupblock.php | 17 ++++++++++------- theme/base/css/display.css | 3 ++- 3 files changed, 22 insertions(+), 15 deletions(-) diff --git a/actions/block.php b/actions/block.php index 0efee5932c..441016d4e9 100644 --- a/actions/block.php +++ b/actions/block.php @@ -125,16 +125,18 @@ class BlockAction extends Action function areYouSureForm() { $id = $this->profile->id; + $this->elementStart('form', array('id' => 'block-' . $id, + 'method' => 'post', + 'class' => 'form_settings form_entity_block', + 'action' => common_local_url('block'))); + $this->elementStart('fieldset'); + $this->hidden('token', common_session_token()); + $this->element('legend', _('Block user')); $this->element('p', null, _('Are you sure you want to block this user? '. 'Afterwards, they will be unsubscribed from you, '. 'unable to subscribe to you in the future, and '. 'you will not be notified of any @-replies from them.')); - $this->elementStart('form', array('id' => 'block-' . $id, - 'method' => 'post', - 'class' => 'block', - 'action' => common_local_url('block'))); - $this->hidden('token', common_session_token()); $this->element('input', array('id' => 'blockto-' . $id, 'name' => 'blockto', 'type' => 'hidden', @@ -144,8 +146,9 @@ class BlockAction extends Action $this->hidden($k, $v); } } - $this->submit('no', _('No')); - $this->submit('yes', _('Yes')); + $this->submit('form_action-no', _('No'), 'submit form_action-primary', 'no', _("Do not block this user from this group")); + $this->submit('form_action-yes', _('Yes'), 'submit form_action-secondary', 'yes', _('Block this user from this group')); + $this->elementEnd('fieldset'); $this->elementEnd('form'); } diff --git a/actions/groupblock.php b/actions/groupblock.php index 93662da799..28685b1d56 100644 --- a/actions/groupblock.php +++ b/actions/groupblock.php @@ -151,17 +151,19 @@ class GroupblockAction extends Action function areYouSureForm() { $id = $this->profile->id; + $this->elementStart('form', array('id' => 'block-' . $id, + 'method' => 'post', + 'class' => 'form_settings form_entity_block', + 'action' => common_local_url('groupblock'))); + $this->elementStart('fieldset'); + $this->hidden('token', common_session_token()); + $this->element('legend', null, _('Block user')); $this->element('p', null, sprintf(_('Are you sure you want to block user "%s" from the group "%s"? '. 'They will be removed from the group, unable to post, and '. 'unable to subscribe to the group in the future.'), $this->profile->getBestName(), $this->group->getBestName())); - $this->elementStart('form', array('id' => 'block-' . $id, - 'method' => 'post', - 'class' => 'block', - 'action' => common_local_url('groupblock'))); - $this->hidden('token', common_session_token()); $this->hidden('blockto-' . $this->profile->id, $this->profile->id, 'blockto'); @@ -173,8 +175,9 @@ class GroupblockAction extends Action $this->hidden($k, $v); } } - $this->submit('no', _('No')); - $this->submit('yes', _('Yes')); + $this->submit('form_action-no', _('No'), 'submit form_action-primary', 'no', _("Do not block this user from this group")); + $this->submit('form_action-yes', _('Yes'), 'submit form_action-secondary', 'yes', _('Block this user from this group')); + $this->elementEnd('fieldset'); $this->elementEnd('form'); } diff --git a/theme/base/css/display.css b/theme/base/css/display.css index 49907058e3..403a9c37f4 100644 --- a/theme/base/css/display.css +++ b/theme/base/css/display.css @@ -154,7 +154,8 @@ font-weight:bold; #form_invite legend, #form_notice_delete legend, #form_password_recover legend, -#form_password_change legend { +#form_password_change legend, +.form_entity_block legend { display:none; } From 85a4e32f30fcc1b081cde7c8e0267b4fd0c83e16 Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Wed, 17 Jun 2009 09:03:59 +0000 Subject: [PATCH 104/262] Updated input submit for making a user admin of a group --- theme/base/css/display.css | 3 ++- theme/base/images/icons/twotone/green/admin.gif | Bin 0 -> 100 bytes theme/default/css/display.css | 9 +++++++-- theme/identica/css/display.css | 9 +++++++-- 4 files changed, 16 insertions(+), 5 deletions(-) create mode 100644 theme/base/images/icons/twotone/green/admin.gif diff --git a/theme/base/css/display.css b/theme/base/css/display.css index 403a9c37f4..9e35d015d1 100644 --- a/theme/base/css/display.css +++ b/theme/base/css/display.css @@ -622,7 +622,8 @@ display:block; .entity_send-a-message a, .entity_edit a, .form_user_nudge input.submit, -.entity_nudge p { +.entity_nudge p, +.form_make_admin input.submit { border:0; padding-left:20px; } diff --git a/theme/base/images/icons/twotone/green/admin.gif b/theme/base/images/icons/twotone/green/admin.gif new file mode 100644 index 0000000000000000000000000000000000000000..10fa431cee5d1a5e3f07dd5846eacbbdf922a5f5 GIT binary patch literal 100 zcmZ?wbhEHb6krfwSjfZ>KSkjG|NjhNp!iSFxhOTUBsE2$JhLQ2!QIn0fI;ym3nK#q y6N3&&2}lzIlY&U!%w=!+133cyqV&)0uCgw4|B-PZbkU0Bb@yKz%nM*(um%8PTpm*Z literal 0 HcmV?d00001 diff --git a/theme/default/css/display.css b/theme/default/css/display.css index 8dd5ca32cd..935116a74f 100644 --- a/theme/default/css/display.css +++ b/theme/default/css/display.css @@ -65,7 +65,8 @@ div.notice-options input, .entity_send-a-message a, .form_user_nudge input.submit, .entity_nudge p, -.form_settings input.form_action-primary { +.form_settings input.form_action-primary, +.form_make_admin input.submit { color:#002E6E; } @@ -166,7 +167,8 @@ background-image:url(../../base/images/icons/icon_foaf.gif); .form_user_unblock input.submit, .form_group_block input.submit, .form_group_unblock input.submit, -.entity_nudge p { +.entity_nudge p, +.form_make_admin input.submit { background-position: 0 40%; background-repeat: no-repeat; background-color:transparent; @@ -200,6 +202,9 @@ background-image:url(../../base/images/icons/twotone/green/mail.gif); .form_group_unblock input.submit { background-image:url(../../base/images/icons/twotone/green/shield.gif); } +.form_make_admin input.submit { +background-image:url(../../base/images/icons/twotone/green/admin.gif); +} /* NOTICES */ .notice .attachment { diff --git a/theme/identica/css/display.css b/theme/identica/css/display.css index 975702faad..6845fda5f9 100644 --- a/theme/identica/css/display.css +++ b/theme/identica/css/display.css @@ -65,7 +65,8 @@ div.notice-options input, .entity_send-a-message a, .form_user_nudge input.submit, .entity_nudge p, -.form_settings input.form_action-primary { +.form_settings input.form_action-primary, +.form_make_admin input.submit { color:#002E6E; } @@ -166,7 +167,8 @@ background-image:url(../../base/images/icons/icon_foaf.gif); .form_user_unblock input.submit, .form_group_block input.submit, .form_group_unblock input.submit, -.entity_nudge p { +.entity_nudge p, +.form_make_admin input.submit { background-position: 0 40%; background-repeat: no-repeat; background-color:transparent; @@ -200,6 +202,9 @@ background-image:url(../../base/images/icons/twotone/green/mail.gif); .form_group_unblock input.submit { background-image:url(../../base/images/icons/twotone/green/shield.gif); } +.form_make_admin input.submit { +background-image:url(../../base/images/icons/twotone/green/admin.gif); +} /* NOTICES */ .notice .attachment { From 76cbeff33c9659cacbb57943056aabcb1517ca5c Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Wed, 17 Jun 2009 02:35:51 -0700 Subject: [PATCH 105/262] Update background image settings to use bitflags --- actions/designsettings.php | 100 ++++++++++++++++++++++--------------- classes/Design.php | 33 ++++++++++-- classes/laconica.ini | 2 +- db/laconica.sql | 2 +- lib/common.php | 2 +- 5 files changed, 93 insertions(+), 46 deletions(-) diff --git a/actions/designsettings.php b/actions/designsettings.php index fbec3fc67f..3dfaddd7bb 100644 --- a/actions/designsettings.php +++ b/actions/designsettings.php @@ -104,37 +104,52 @@ class DesignsettingsAction extends AccountSettingsAction 'value' => ImageFile::maxFileSizeInt())); $this->elementEnd('li'); - $this->elementStart('li', array('id' => 'design_background-image_onoff')); - if (!empty($design->backgroundimage)) { + + $this->elementStart('li', array('id' => 'design_background-image_onoff')); + $this->element('img', array('src' => Design::url($design->backgroundimage))); - } - $this->element('input', array('name' => 'design_background-image_onoff', - 'type' => 'radio', - 'id' => 'design_background-image_on', - 'class' => 'radio', - 'value' => 'true', - 'checked'=> 'checked')); - $this->element('label', array('for' => 'design_background-image_on', - 'class' => 'radio'), - _('On')); - $this->element('input', array('name' => 'design_background-image_onoff', - 'type' => 'radio', - 'id' => 'design_background-image_off', - 'class' => 'radio', - 'value' => 'false')); - $this->element('label', array('for' => 'design_background-image_off', - 'class' => 'radio'), - _('Off')); - $this->element('p', 'form_guide', _('Turn background image on or off.')); - $this->elementEnd('li'); + $attrs = array('name' => 'design_background-image_onoff', + 'type' => 'radio', + 'id' => 'design_background-image_on', + 'class' => 'radio', + 'value' => 'on'); + + if ($design->disposition & BACKGROUND_ON) { + $attrs['checked'] = 'checked'; + } + + $this->element('input', $attrs); + + $this->element('label', array('for' => 'design_background-image_on', + 'class' => 'radio'), + _('On')); + + $attrs = array('name' => 'design_background-image_onoff', + 'type' => 'radio', + 'id' => 'design_background-image_off', + 'class' => 'radio', + 'value' => 'off'); + + if ($design->disposition & BACKGROUND_OFF) { + $attrs['checked'] = 'checked'; + } + + $this->element('input', $attrs); + + $this->element('label', array('for' => 'design_background-image_off', + 'class' => 'radio'), + _('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->tile); + ($design->disposition & BACKGROUND_TILE) ? true : false ); $this->elementEnd('li'); $this->elementEnd('ul'); @@ -159,7 +174,6 @@ class DesignsettingsAction extends AccountSettingsAction 'value' => '#' . $bgcolor->hexValue())); $this->elementEnd('li'); - $ccolor = new WebColor($design->contentcolor); $this->elementStart('li'); @@ -346,7 +360,7 @@ class DesignsettingsAction extends AccountSettingsAction $design->backgroundimage = $defaults['backgroundimage']; - $deisng->tile = $defaults['tile']; + $deisng->disposition = $defaults['disposition']; } catch (WebColorException $e) { common_log(LOG_ERR, _('Bad default color settings: ' . @@ -377,7 +391,23 @@ class DesignsettingsAction extends AccountSettingsAction return; } - $tile = $this->boolean('design_background-image_repeat'); + $onoff = $this->arg('design_background-image_onoff'); + + $on = false; + $off = false; + $tile = false; + + if ($onoff == 'on') { + $on = true; + } else { + $off = true; + } + + $repeat = $this->boolean('design_background-image_repeat'); + + if ($repeat) { + $tile = true; + } $user = common_current_user(); $design = $user->getDesign(); @@ -392,7 +422,8 @@ class DesignsettingsAction extends AccountSettingsAction $design->textcolor = $tcolor->intValue(); $design->linkcolor = $lcolor->intValue(); $design->backgroundimage = $filepath; - $design->tile = $tile; + + $design->setDisposition($on, $off, $tile); $result = $design->update($original); @@ -416,7 +447,8 @@ class DesignsettingsAction extends AccountSettingsAction $design->textcolor = $tcolor->intValue(); $design->linkcolor = $lcolor->intValue(); $design->backgroundimage = $filepath; - $design->tile = $tile; + + $design->setDisposition($on, $off, $tile); $id = $design->insert(); @@ -481,16 +513,4 @@ class DesignsettingsAction extends AccountSettingsAction $this->showForm(_('Design preferences saved.'), true); } - /** - * Reset design settings to previous saved value if any, or - * the defaults - * - * @return void - */ - - function resetDesign() - { - $this->showForm(_('Design preferences reset.'), true); - } - } diff --git a/classes/Design.php b/classes/Design.php index 4ea176677b..5b28bf014a 100644 --- a/classes/Design.php +++ b/classes/Design.php @@ -21,6 +21,10 @@ if (!defined('LACONICA')) { exit(1); } +define('BACKGROUND_ON', 1); +define('BACKGROUND_OFF', 2); +define('BACKGROUND_TILE', 4); + /** * Table Definition for design */ @@ -41,7 +45,7 @@ class Design extends Memcached_DataObject public $textcolor; // int(4) public $linkcolor; // int(4) public $backgroundimage; // varchar(255) - public $tile; // tinyint(1) + public $disposition; // tinyint(1) default_1 /* Static get */ function staticGet($k,$v=NULL) { return Memcached_DataObject::staticGet('Design',$k,$v); } @@ -72,9 +76,11 @@ class Design extends Memcached_DataObject $css .= 'html body { color: #'. $tcolor->hexValue() . '} '. "\n"; $css .= 'a { color: #' . $lcolor->hexValue() . '} ' . "\n"; - if (!empty($this->backgroundimage)) { + if (!empty($this->backgroundimage) && + $this->disposition & BACKGROUND_ON) { - $repeat = ($this->tile) ? 'background-repeat:repeat;' : + $repeat = ($this->disposition & BACKGROUND_TILE) ? + 'background-repeat:repeat;' : 'background-repeat:no-repeat;'; $css .= 'body { background-image:url(' . @@ -125,4 +131,25 @@ class Design extends Memcached_DataObject return 'http://'.$server.$path.$filename; } + function setDisposition($on, $off, $tile) + { + if ($on) { + $this->disposition |= BACKGROUND_ON; + } else { + $this->disposition &= ~BACKGROUND_ON; + } + + if ($off) { + $this->disposition |= BACKGROUND_OFF; + } else { + $this->disposition &= ~BACKGROUND_OFF; + } + + if ($tile) { + $this->disposition |= BACKGROUND_TILE; + } else { + $this->disposition &= ~BACKGROUND_TILE; + } + } + } diff --git a/classes/laconica.ini b/classes/laconica.ini index 5696819848..1a650aba55 100755 --- a/classes/laconica.ini +++ b/classes/laconica.ini @@ -46,7 +46,7 @@ sidebarcolor = 1 textcolor = 1 linkcolor = 1 backgroundimage = 2 -tile = 17 +disposition = 17 [design__keys] id = N diff --git a/db/laconica.sql b/db/laconica.sql index 1f302de167..b018afec8e 100644 --- a/db/laconica.sql +++ b/db/laconica.sql @@ -496,7 +496,7 @@ create table design ( textcolor integer comment 'text color', linkcolor integer comment 'link color', backgroundimage varchar(255) comment 'background image, if any', - tile tinyint default 0 comment 'tile background image' + 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 ( diff --git a/lib/common.php b/lib/common.php index 629fee25b2..bcf2e5d0c7 100644 --- a/lib/common.php +++ b/lib/common.php @@ -79,7 +79,7 @@ $config = 'textcolor' => '#000000', 'linkcolor' => '#002E6E', 'backgroundimage' => null, - 'tile' => true), + 'disposition' => 1), 'path' => $_path, 'logfile' => null, 'logo' => null, From 2866d00517b1ccfd7585f5fc2da1ed2fcf52bdfd Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Wed, 17 Jun 2009 02:58:35 -0700 Subject: [PATCH 106/262] Fix sidebar color bug default design --- actions/designsettings.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/actions/designsettings.php b/actions/designsettings.php index 3dfaddd7bb..adc09c7b06 100644 --- a/actions/designsettings.php +++ b/actions/designsettings.php @@ -353,14 +353,14 @@ class DesignsettingsAction extends AccountSettingsAction $design->sidebarcolor = $color->intValue(); $color->parseColor($defaults['textcolor']); - $design->sidebarcolor = $color->intValue(); + $design->textcolor = $color->intValue(); $color->parseColor($defaults['linkcolor']); $design->linkcolor = $color->intValue(); $design->backgroundimage = $defaults['backgroundimage']; - $deisng->disposition = $defaults['disposition']; + $design->disposition = $defaults['disposition']; } catch (WebColorException $e) { common_log(LOG_ERR, _('Bad default color settings: ' . From ac3cccefb53579b01618d5ef728e883dae752fd2 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Wed, 17 Jun 2009 03:02:43 -0700 Subject: [PATCH 107/262] Default to image being on, no tile after upload --- actions/designsettings.php | 1 + 1 file changed, 1 insertion(+) diff --git a/actions/designsettings.php b/actions/designsettings.php index adc09c7b06..047059e04b 100644 --- a/actions/designsettings.php +++ b/actions/designsettings.php @@ -501,6 +501,7 @@ class DesignsettingsAction extends AccountSettingsAction $original = clone($design); $design->backgroundimage = $filename; + $design->setDisposition(true, false, false); $result = $design->update($original); if ($result === false) { From af4b18b1e2ef8aded26fc4788c571012da04d1cf Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Wed, 17 Jun 2009 03:05:48 -0700 Subject: [PATCH 108/262] Uppercase hex color values --- lib/webcolor.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/webcolor.php b/lib/webcolor.php index aaf31d9903..f3ca6e94a8 100644 --- a/lib/webcolor.php +++ b/lib/webcolor.php @@ -164,7 +164,7 @@ class WebColor { $hexcolor .= (strlen(dechex($this->blue)) < 2 ? '0' : '') . dechex($this->blue); - return $hexcolor; + return strtoupper($hexcolor); } From 2fbd141361b6ddab0e036b52fc23f2bfcdfd0075 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Wed, 17 Jun 2009 08:21:53 -0700 Subject: [PATCH 109/262] correct arguments for ProfileList --- actions/featured.php | 5 ++--- actions/peopletag.php | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/actions/featured.php b/actions/featured.php index 79eba2aa67..04365687d7 100644 --- a/actions/featured.php +++ b/actions/featured.php @@ -32,7 +32,7 @@ if (!defined('LACONICA')) { exit(1); } -require_once(INSTALLDIR.'/lib/profilelist.php'); +require_once INSTALLDIR.'/lib/profilelist.php'; require_once INSTALLDIR.'/lib/publicgroupnav.php'; /** @@ -107,7 +107,6 @@ class FeaturedAction extends Action $featured_nicks = common_config('nickname', 'featured'); - if (count($featured_nicks) > 0) { $quoted = array(); @@ -136,7 +135,7 @@ class FeaturedAction extends Action $cnt = $profile->find(); if ($cnt > 0) { - $featured = new ProfileList($profile, null, $this); + $featured = new ProfileList($profile, $this); $featured->show(); } diff --git a/actions/peopletag.php b/actions/peopletag.php index 5add754858..dd3c1c0899 100644 --- a/actions/peopletag.php +++ b/actions/peopletag.php @@ -124,7 +124,7 @@ class PeopletagAction extends Action $profile->query(sprintf($qry, $this->tag, $lim)); - $pl = new ProfileList($profile, null, $this); + $pl = new ProfileList($profile, $this); $cnt = $pl->show(); $this->pagination($this->page > 1, From 19d39b20294bad8dc14df26e76756c558a5083cf Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Wed, 17 Jun 2009 12:31:35 -0700 Subject: [PATCH 110/262] Store better data about twitter statuses We mark Twitter statuses with flags so they don't get shown in the wrong places. --- scripts/twitterstatusfetcher.php | 107 +++++++++++++++++++++++-------- 1 file changed, 81 insertions(+), 26 deletions(-) diff --git a/scripts/twitterstatusfetcher.php b/scripts/twitterstatusfetcher.php index 9287b6d733..d332fb5554 100755 --- a/scripts/twitterstatusfetcher.php +++ b/scripts/twitterstatusfetcher.php @@ -1,6 +1,6 @@ #!/usr/bin/env php + * @author Evan Prodromou + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://laconi.ca/ + */ class TwitterStatusFetcher extends Daemon { + private $_children = array(); - private $children = array(); + /** + * Name of this daemon + * + * @return string Name of the daemon. + */ function name() { return ('twitterstatusfetcher.generic'); } + /** + * Run the daemon + * + * @return void + */ + function run() { do { $flinks = $this->refreshFlinks(); - foreach ($flinks as $f){ + foreach ($flinks as $f) { // We have to disconnect from the DB before forking so // each sub-process will open its own connection and @@ -73,10 +98,11 @@ class TwitterStatusFetcher extends Daemon // Parent if (defined('SCRIPT_DEBUG')) { - common_debug("Parent: forked new status fetcher process " . $pid); + common_debug("Parent: forked new status ". + " fetcher process " . $pid); } - $this->children[] = $pid; + $this->_children[] = $pid; } else { @@ -86,41 +112,41 @@ class TwitterStatusFetcher extends Daemon } // Remove child from ps list as it finishes - while(($c = pcntl_wait($status, WNOHANG OR WUNTRACED)) > 0) { + while (($c = pcntl_wait($status, WNOHANG OR WUNTRACED)) > 0) { if (defined('SCRIPT_DEBUG')) { common_debug("Child $c finished."); } - $this->remove_ps($this->children, $c); + $this->removePs($this->_children, $c); } // Wait! We have too many damn kids. - if (sizeof($this->children) > MAXCHILDREN) { + if (sizeof($this->_children) > MAXCHILDREN) { if (defined('SCRIPT_DEBUG')) { common_debug('Too many children. Waiting...'); } - if (($c = pcntl_wait($status, WUNTRACED)) > 0){ + if (($c = pcntl_wait($status, WUNTRACED)) > 0) { if (defined('SCRIPT_DEBUG')) { common_debug("Finished waiting for $c"); } - $this->remove_ps($this->children, $c); + $this->removePs($this->_children, $c); } } } // Remove all children from the process list before restarting - while(($c = pcntl_wait($status, WUNTRACED)) > 0) { + while (($c = pcntl_wait($status, WUNTRACED)) > 0) { if (defined('SCRIPT_DEBUG')) { common_debug("Child $c finished."); } - $this->remove_ps($this->children, $c); + $this->removePs($this->_children, $c); } // Rest for a bit before we fetch more statuses @@ -137,10 +163,18 @@ class TwitterStatusFetcher extends Daemon } while (true); } - function refreshFlinks() { + /** + * Refresh the foreign links for this user + * + * @return void + */ + function refreshFlinks() + { $flink = new Foreign_link(); + $flink->service = 1; // Twitter + $flink->orderBy('last_noticesync'); $cnt = $flink->find(); @@ -166,7 +200,18 @@ class TwitterStatusFetcher extends Daemon return $flinks; } - function remove_ps(&$plist, $ps){ + /** + * Unknown + * + * @param array &$plist unknown. + * @param string $ps unknown. + * + * @return unknown + * @todo document + */ + + function removePs(&$plist, $ps) + { for ($i = 0; $i < sizeof($plist); $i++) { if ($plist[$i] == $ps) { unset($plist[$i]); @@ -178,7 +223,6 @@ class TwitterStatusFetcher extends Daemon function getTimeline($flink) { - if (empty($flink)) { common_log(LOG_WARNING, "Can't retrieve Foreign_link for foreign ID $fid"); @@ -247,23 +291,32 @@ class TwitterStatusFetcher extends Daemon return null; } + // XXX: change of screen name? + $uri = 'http://twitter.com/' . $status->user->screen_name . '/status/' . $status->id; $notice = Notice::staticGet('uri', $uri); // check to see if we've already imported the status + if (!$notice) { - $created = strftime('%Y-%m-%d %H:%M:%S', - strtotime($status->created_at));; + $notice = new Notice(); - $notice = Notice::saveNew($id, $status->text, 'twitter', - -2, null, $uri, $created); + $notice->profile_id = $id; + $notice->uri = $uri; + $notice->created = strftime('%Y-%m-%d %H:%M:%S', + strtotime($status->created_at)); + $notice->content = common_shorten_links($status->text); // XXX + $notice->rendered = common_render_content($notice->content, $notice); + $notice->source = 'twitter'; + $notice->reply_to = null; // XXX lookup reply + $notice->is_local = NOTICE_GATEWAY; - if (defined('SCRIPT_DEBUG')) { - common_debug("Saved status $status->id" . - " as notice $notice->id."); + if (Event::handle('StartNoticeSave', array(&$notice))) { + $id = $notice->insert(); + Event::handle('EndNoticeSave', array($notice)); } } @@ -271,9 +324,11 @@ class TwitterStatusFetcher extends Daemon 'user_id' => $flink->user_id))) { // Add to inbox $inbox = new Notice_inbox(); - $inbox->user_id = $flink->user_id; + + $inbox->user_id = $flink->user_id; $inbox->notice_id = $notice->id; - $inbox->created = $notice->created; + $inbox->created = $notice->created; + $inbox->source = NOTICE_INBOX_SOURCE_GATEWAY; // From a private source $inbox->insert(); } From 1505e3a4c3dda7030bb92a2071ec58af2972bed7 Mon Sep 17 00:00:00 2001 From: Robin Millette Date: Wed, 17 Jun 2009 16:21:50 -0400 Subject: [PATCH 111/262] Fixed recent attachment bug that required URLs to be posted twice to be taken into account. --- classes/File.php | 2 -- classes/Notice.php | 8 ++++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/classes/File.php b/classes/File.php index 24ab11b8eb..08320faf8f 100644 --- a/classes/File.php +++ b/classes/File.php @@ -79,7 +79,6 @@ class File extends Memcached_DataObject && ('text/html' === substr($redir_data['type'], 0, 9)) && ($oembed_data = File_oembed::_getOembed($given_url)) && isset($oembed_data['json'])) { - File_oembed::saveNew($oembed_data['json'], $file_id); } return $x; @@ -98,7 +97,6 @@ class File extends Memcached_DataObject if ($redir_url === $given_url) { $x = File::saveNew($redir_data, $given_url); $file_id = $x->id; - } else { $x = File::processNew($redir_url, $notice_id); $file_id = $x->id; diff --git a/classes/Notice.php b/classes/Notice.php index 770b5d78b7..e0bb90ba62 100644 --- a/classes/Notice.php +++ b/classes/Notice.php @@ -218,6 +218,12 @@ class Notice extends Memcached_DataObject $notice->addToInboxes(); $notice->saveGroups(); $notice->saveUrls(); + $orig2 = clone($notice); + $notice->rendered = common_render_content($final, $notice); + if (!$notice->update($orig2)) { + common_log_db_error($notice, 'UPDATE', __FILE__); + return _('Problem saving notice.'); + } $notice->query('COMMIT'); @@ -237,8 +243,6 @@ class Notice extends Memcached_DataObject * follow redirects and save all available file information * (mimetype, date, size, oembed, etc.) * - * @param class $notice Notice to pull URLs from - * * @return void */ function saveUrls() { From 28d02ec8cdd0278c802c8fee30acddecca9ca01f Mon Sep 17 00:00:00 2001 From: Robin Millette Date: Wed, 17 Jun 2009 16:44:33 -0400 Subject: [PATCH 112/262] Make oohembed endpoint configurable. --- README | 8 ++++++++ classes/File_oembed.php | 2 +- config.php.sample | 1 + lib/common.php | 1 + 4 files changed, 11 insertions(+), 1 deletion(-) diff --git a/README b/README index 3279f7bbaa..7b22e3c5e8 100644 --- a/README +++ b/README @@ -1246,6 +1246,14 @@ Options for group functionality. maxaliases: maximum number of aliases a group can have. Default 3. Set to 0 or less to prevent aliases in a group. + +oohembed +-------- + +oEmbed endpoint for multimedia attachments (links in posts). + +endpoint: oohembed endpoint using http://oohembed.com/ software. + Troubleshooting =============== diff --git a/classes/File_oembed.php b/classes/File_oembed.php index f1b2cb13c0..6bf972f8fe 100644 --- a/classes/File_oembed.php +++ b/classes/File_oembed.php @@ -53,7 +53,7 @@ class File_oembed extends Memcached_DataObject function _getOembed($url, $maxwidth = 500, $maxheight = 400, $format = 'json') { - $cmd = 'http://oohembed.com/oohembed/?url=' . urlencode($url); + $cmd = common_config('oohembed', 'endpoint') . '?url=' . urlencode($url); if (is_int($maxwidth)) $cmd .= "&maxwidth=$maxwidth"; if (is_int($maxheight)) $cmd .= "&maxheight=$maxheight"; if (is_string($format)) $cmd .= "&format=$format"; diff --git a/config.php.sample b/config.php.sample index 636f4cf8e2..ed70f85fbb 100644 --- a/config.php.sample +++ b/config.php.sample @@ -223,3 +223,4 @@ $config['sphinx']['port'] = 3312; // $config['attachments']['user_quota'] = 50000000; // $config['attachments']['monthly_quota'] = 15000000; +// $config['oohembed']['endpoint'] = 'http://oohembed.com/oohembed/'; diff --git a/lib/common.php b/lib/common.php index 51204cedea..9c015a15d2 100644 --- a/lib/common.php +++ b/lib/common.php @@ -203,6 +203,7 @@ $config = ), 'group' => array('maxaliases' => 3), + 'oohembed' => array('endpoint' => 'http://oohembed.com/oohembed/') ); $config['db'] = &PEAR::getStaticProperty('DB_DataObject','options'); From b58dc5e96117bdb4de899d37c6eb94ebf1c3dfe6 Mon Sep 17 00:00:00 2001 From: Robin Millette Date: Wed, 17 Jun 2009 16:55:01 -0400 Subject: [PATCH 113/262] Added config option to enable or disable file uploads with notices. --- README | 1 + config.php.sample | 1 + lib/common.php | 1 + lib/noticeform.php | 18 +++++++++++------- 4 files changed, 14 insertions(+), 7 deletions(-) diff --git a/README b/README index 7b22e3c5e8..5aa7270eec 100644 --- a/README +++ b/README @@ -1223,6 +1223,7 @@ supported: an array of mime types you accept to store and distribute, like 'image/gif', 'video/mpeg', 'audio/mpeg', etc. Make sure you setup your server to properly reckognize the types you want to support. +uploads: false to disable uploading files with notices (true by default). For quotas, be sure you've set the upload_max_filesize and post_max_size in php.ini to be large enough to handle your upload. In httpd.conf diff --git a/config.php.sample b/config.php.sample index ed70f85fbb..7649c52623 100644 --- a/config.php.sample +++ b/config.php.sample @@ -222,5 +222,6 @@ $config['sphinx']['port'] = 3312; // $config['attachments']['file_quota'] = 5000000; // $config['attachments']['user_quota'] = 50000000; // $config['attachments']['monthly_quota'] = 15000000; +// $config['attachments']['uploads'] = true; // $config['oohembed']['endpoint'] = 'http://oohembed.com/oohembed/'; diff --git a/lib/common.php b/lib/common.php index 9c015a15d2..bbd9f78c3e 100644 --- a/lib/common.php +++ b/lib/common.php @@ -200,6 +200,7 @@ $config = 'file_quota' => 5000000, 'user_quota' => 50000000, 'monthly_quota' => 15000000, + 'uploads' => true, ), 'group' => array('maxaliases' => 3), diff --git a/lib/noticeform.php b/lib/noticeform.php index 0ad3658566..a36b7f31f7 100644 --- a/lib/noticeform.php +++ b/lib/noticeform.php @@ -90,7 +90,9 @@ class NoticeForm extends Form $this->user = common_current_user(); } - $this->enctype = 'multipart/form-data'; + if (common_config('attachments', 'uploads')) { + $this->enctype = 'multipart/form-data'; + } } /** @@ -148,12 +150,14 @@ class NoticeForm extends Form $this->out->element('dd', array('id' => 'notice_text-count'), '140'); $this->out->elementEnd('dl'); - $this->out->element('label', array('for' => 'notice_data-attach'),_('Attach')); - $this->out->element('input', array('id' => 'notice_data-attach', - 'type' => 'file', - 'name' => 'attach', - 'title' => _('Attach a file'))); - $this->out->hidden('MAX_FILE_SIZE', common_config('attachments', 'file_quota')); + if (common_config('attachments', 'uploads')) { + $this->out->hidden('MAX_FILE_SIZE', common_config('attachments', 'file_quota')); + $this->out->element('label', array('for' => 'notice_data-attach'),_('Attach')); + $this->out->element('input', array('id' => 'notice_data-attach', + 'type' => 'file', + 'name' => 'attach', + 'title' => _('Attach a file'))); + } if ($this->action) { $this->out->hidden('notice_return-to', $this->action, 'returnto'); } From 7e25a7f3aa2a308ddfc141e2e88fd52c042cb931 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Wed, 17 Jun 2009 14:32:36 -0700 Subject: [PATCH 114/262] Output XML and JSON error msgs for API calls --- lib/twitterapi.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/twitterapi.php b/lib/twitterapi.php index 569bc6d7a2..269b60efc6 100644 --- a/lib/twitterapi.php +++ b/lib/twitterapi.php @@ -545,7 +545,7 @@ class TwitterapiAction extends Action $this->init_twitter_atom(); break; default: - $this->client_error(_('Not a supported data format.')); + $this->clientError(_('Not a supported data format.')); break; } @@ -573,13 +573,13 @@ class TwitterapiAction extends Action $this->end_twitter_rss(); break; default: - $this->client_error(_('Not a supported data format.')); + $this->clientError(_('Not a supported data format.')); break; } return; } - function client_error($msg, $code = 400, $content_type = 'json') + function clientError($msg, $code = 400, $content_type = 'json') { static $status = array(400 => 'Bad Request', @@ -666,7 +666,7 @@ class TwitterapiAction extends Action $this->show_json_objects($profile_array); break; default: - $this->client_error(_('Not a supported data format.')); + $this->clientError(_('Not a supported data format.')); return; } return; From 8992e8fa7a3c694cc9d424b3e50cf4d87519fa28 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Wed, 17 Jun 2009 14:34:04 -0700 Subject: [PATCH 115/262] Ticket 1612 - make destory (and create) favorites work via API --- actions/twitapifavorites.php | 65 ++++++++++++++++++++++++++++++++---- lib/router.php | 3 +- 2 files changed, 60 insertions(+), 8 deletions(-) diff --git a/actions/twitapifavorites.php b/actions/twitapifavorites.php index 8656adbe86..2266ba11c2 100644 --- a/actions/twitapifavorites.php +++ b/actions/twitapifavorites.php @@ -34,6 +34,11 @@ class TwitapifavoritesAction extends TwitterapiAction $user = $this->get_user($apidata['api_arg'], $apidata); if (empty($user)) { + if ($apidata['content-type'] == 'xml') { + $this->show_single_xml_status($notice); + } elseif ($apidata['content-type'] == 'json') { + $this->show_single_json_status($notice); + } $this->clientError('Not Found', 404, $apidata['content-type']); return; } @@ -91,7 +96,6 @@ class TwitapifavoritesAction extends TwitterapiAction // Check for RESTfulness if (!in_array($_SERVER['REQUEST_METHOD'], array('POST', 'DELETE'))) { - // XXX: Twitter just prints the err msg, no XML / JSON. $this->clientError(_('This method requires a POST or DELETE.'), 400, $apidata['content-type']); return; @@ -102,10 +106,9 @@ class TwitapifavoritesAction extends TwitterapiAction return; } - $user = $apidata['user']; // Always the auth user - + $user = $apidata['user']; // Always the auth user $notice_id = $apidata['api_arg']; - $notice = Notice::staticGet($notice_id); + $notice = Notice::staticGet($notice_id); if (empty($notice)) { $this->clientError(_('No status found with that ID.'), @@ -115,7 +118,7 @@ class TwitapifavoritesAction extends TwitterapiAction // XXX: Twitter lets you fave things repeatedly via api. if ($user->hasFave($notice)) { - $this->clientError(_('This notice is already a favorite!'), + $this->clientError(_('This status is already a favorite!'), 403, $apidata['content-type']); return; } @@ -123,7 +126,7 @@ class TwitapifavoritesAction extends TwitterapiAction $fave = Fave::addNew($user, $notice); if (empty($fave)) { - $this->serverError(_('Could not create favorite.')); + $this->clientError(_('Could not create favorite.')); return; } @@ -141,7 +144,55 @@ class TwitapifavoritesAction extends TwitterapiAction function destroy($args, $apidata) { parent::handle($args); - $this->serverError(_('API method under construction.'), $code=501); + + // Check for RESTfulness + if (!in_array($_SERVER['REQUEST_METHOD'], array('POST', 'DELETE'))) { + $this->clientError(_('This method requires a POST or DELETE.'), + 400, $apidata['content-type']); + return; + } + + if (!in_array($apidata['content-type'], array('xml', 'json'))) { + $this->clientError(_('API method not found!'), $code = 404); + return; + } + + $user = $apidata['user']; // Always the auth user + $notice_id = $apidata['api_arg']; + $notice = Notice::staticGet($notice_id); + + if (empty($notice)) { + $this->clientError(_('No status found with that ID.'), + 404, $apidata['content-type']); + return; + } + + $fave = new Fave(); + $fave->user_id = $this->id; + $fave->notice_id = $notice->id; + + if (!$fave->find(true)) { + $this->clientError(_('That status is not a favorite!'), + 403, $apidata['content-type']); + return; + } + + $result = $fave->delete(); + + if (!$result) { + common_log_db_error($fave, 'DELETE', __FILE__); + $this->clientError(_('Could not delete favorite.'), 404); + return; + } + + $user->blowFavesCache(); + + if ($apidata['content-type'] == 'xml') { + $this->show_single_xml_status($notice); + } elseif ($apidata['content-type'] == 'json') { + $this->show_single_json_status($notice); + } + } // XXX: these two funcs swiped from faves. diff --git a/lib/router.php b/lib/router.php index 0fbaba9ed5..8b6f636182 100644 --- a/lib/router.php +++ b/lib/router.php @@ -351,7 +351,8 @@ class Router $m->connect('api/favorites/:method/:argument', array('action' => 'api', - 'apiaction' => 'favorites')); + 'apiaction' => 'favorites', + array('method' => '(create|destroy)'))); $m->connect('api/favorites/:argument', array('action' => 'api', From 07f5797f2fd1a425027190d424e359a1b4c4c8be Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Wed, 17 Jun 2009 15:04:57 -0700 Subject: [PATCH 116/262] Make the personal tag streams actually work --- actions/showstream.php | 2 +- classes/Notice.php | 6 ++++++ classes/Profile.php | 37 +++++++++++++++++++------------------ 3 files changed, 26 insertions(+), 19 deletions(-) diff --git a/actions/showstream.php b/actions/showstream.php index 72316b2592..cd5d4bb701 100644 --- a/actions/showstream.php +++ b/actions/showstream.php @@ -370,7 +370,7 @@ class ShowstreamAction extends ProfileAction { $notice = empty($this->tag) ? $this->user->getNotices(($this->page-1)*NOTICES_PER_PAGE, NOTICES_PER_PAGE + 1) - : $this->user->getTaggedNotices(($this->page-1)*NOTICES_PER_PAGE, NOTICES_PER_PAGE + 1, 0, 0, null, $this->tag); + : $this->user->getTaggedNotices($this->tag, ($this->page-1)*NOTICES_PER_PAGE, NOTICES_PER_PAGE + 1, 0, 0, null); $pnl = new ProfileNoticeList($notice, $this); $cnt = $pnl->show(); diff --git a/classes/Notice.php b/classes/Notice.php index 6c5558d887..50242300da 100644 --- a/classes/Notice.php +++ b/classes/Notice.php @@ -375,6 +375,12 @@ class Notice extends Memcached_DataObject if ($tag->find()) { while ($tag->fetch()) { $tag->blowCache($blowLast); + $ck = 'profile:notice_ids_tagged:' . $this->profile_id . ':' . $tag->tag; + + $cache->delete($ck); + if ($blowLast) { + $cache->delete($ck . ';last'); + } } } $tag->free(); diff --git a/classes/Profile.php b/classes/Profile.php index 4a459b9740..2f432ae8ed 100644 --- a/classes/Profile.php +++ b/classes/Profile.php @@ -153,18 +153,16 @@ class Profile extends Memcached_DataObject return null; } - function getTaggedNotices($offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $before_id=0, $since=null, $tag=null) + function getTaggedNotices($tag, $offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $max_id=0, $since=null) { - // XXX: I'm not sure this is going to be any faster. It probably isn't. $ids = Notice::stream(array($this, '_streamTaggedDirect'), - array(), - 'profile:notice_ids:' . $this->id, - $offset, $limit, $since_id, $before_id, $since, $tag); - common_debug(print_r($ids, true)); + array($tag), + 'profile:notice_ids_tagged:' . $this->id . ':' . $tag, + $offset, $limit, $since_id, $max_id, $since); return Notice::getStreamByIds($ids); } - function getNotices($offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $before_id=0, $since=null) + function getNotices($offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $max_id=0, $since=null) { // XXX: I'm not sure this is going to be any faster. It probably isn't. $ids = Notice::stream(array($this, '_streamDirect'), @@ -175,18 +173,23 @@ class Profile extends Memcached_DataObject return Notice::getStreamByIds($ids); } - function _streamTaggedDirect($offset, $limit, $since_id, $before_id, $since=null, $tag=null) + function _streamTaggedDirect($tag, $offset, $limit, $since_id, $max_id, $since) { - common_debug('_streamTaggedDirect()'); + // XXX It would be nice to do this without a join + $notice = new Notice(); - $notice->profile_id = $this->id; - $query = "select id from notice join notice_tag on id=notice_id where tag='" . $notice->escape($tag) . "' and profile_id=" . $notice->escape($notice->profile_id); + + $query = + "select id from notice join notice_tag on id=notice_id where tag='". + $notice->escape($tag) . + "' and profile_id=" . $notice->escape($this->id); + if ($since_id != 0) { $query .= " and id > $since_id"; } - if ($before_id != 0) { - $query .= " and id < $before_id"; + if ($max_id != 0) { + $query .= " and id < $max_id"; } if (!is_null($since)) { @@ -198,21 +201,19 @@ class Profile extends Memcached_DataObject if (!is_null($offset)) { $query .= " limit $offset, $limit"; } + $notice->query($query); + $ids = array(); while ($notice->fetch()) { - common_debug(print_r($notice, true)); $ids[] = $notice->id; } return $ids; } - - - - function _streamDirect($offset, $limit, $since_id, $before_id, $since = null) + function _streamDirect($offset, $limit, $since_id, $max_id, $since = null) { $notice = new Notice(); From 2187ec7056a23e76c756f354bf41e3835ba8d103 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Wed, 17 Jun 2009 15:20:44 -0700 Subject: [PATCH 117/262] hide group name and aliases in group tag cloud section --- lib/grouptagcloudsection.php | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/lib/grouptagcloudsection.php b/lib/grouptagcloudsection.php index 5d68af28bf..9b7a10f6b9 100644 --- a/lib/grouptagcloudsection.php +++ b/lib/grouptagcloudsection.php @@ -32,7 +32,7 @@ if (!defined('LACONICA')) { } /** - * Personal tag cloud section + * Group tag cloud section * * @category Widget * @package Laconica @@ -64,12 +64,27 @@ class GroupTagCloudSection extends TagCloudSection $weightexpr='sum(exp(-(now() - notice_tag.created) / %s))'; } + $names = $this->group->getAliases(); + + $names = array_merge(array($this->group->nickname), $names); + + // XXX This is dumb. + + $quoted = array(); + + foreach ($names as $name) { + $quoted[] = "\"$name\""; + } + + $namestring = implode(',', $quoted); + $qry = 'SELECT notice_tag.tag, '. $weightexpr . ' as weight ' . 'FROM notice_tag JOIN notice ' . 'ON notice_tag.notice_id = notice.id ' . 'JOIN group_inbox on group_inbox.notice_id = notice.id ' . 'WHERE group_inbox.group_id = %d ' . + 'AND notice_tag.tag not in (%s) '. 'GROUP BY notice_tag.tag ' . 'ORDER BY weight DESC '; @@ -85,9 +100,9 @@ class GroupTagCloudSection extends TagCloudSection $tag = Memcached_DataObject::cachedQuery('Notice_tag', sprintf($qry, common_config('tag', 'dropoff'), - $this->group->id), + $this->group->id, + $namestring), 3600); return $tag; } - } From 85b4c24188502ce3f8cef32cfba37ab91c8a648f Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Wed, 17 Jun 2009 16:30:16 -0700 Subject: [PATCH 118/262] add dbhost argument for status network setup --- scripts/setup.cfg.sample | 1 + scripts/setup_status_network.sh | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/scripts/setup.cfg.sample b/scripts/setup.cfg.sample index 4194bc146d..450b9c30a3 100644 --- a/scripts/setup.cfg.sample +++ b/scripts/setup.cfg.sample @@ -2,6 +2,7 @@ # Base database name; full name will include nickname +export DBHOST=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 d80612b940..e1d14593fb 100755 --- a/scripts/setup_status_network.sh +++ b/scripts/setup_status_network.sh @@ -11,13 +11,13 @@ export username=$nickname$USERBASE # Create the db -mysqladmin -u $ADMIN --password=$ADMINPASS create $database +mysqladmin -h $DBHOST -u $ADMIN --password=$ADMINPASS create $database for f in laconica.sql sms_carrier.sql foreign_services.sql notice_source.sql; do - mysql -u $ADMIN --password=$ADMINPASS $database < ../db/$f; + mysql -h $DBHOST -u $ADMIN --password=$ADMINPASS $database < ../db/$f; done -mysql -u $ADMIN --password=$ADMINPASS $SITEDB << ENDOFCOMMANDS +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'; From 4fc4c0a74bd08f568a55d65660ca2e5170165905 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Wed, 17 Jun 2009 17:13:59 -0700 Subject: [PATCH 119/262] Remove stale reference to deprecated personal.php --- lib/mailbox.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/mailbox.php b/lib/mailbox.php index 766510a47b..b282ce3687 100644 --- a/lib/mailbox.php +++ b/lib/mailbox.php @@ -31,8 +31,6 @@ if (!defined('LACONICA')) { exit(1); } -require_once INSTALLDIR.'/lib/personal.php'; - define('MESSAGES_PER_PAGE', 20); /** From b0591cd98219cf523d35884015ee9f82c2aa9e09 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Wed, 17 Jun 2009 17:29:57 -0700 Subject: [PATCH 120/262] Make MailboxAction read only --- lib/mailbox.php | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/lib/mailbox.php b/lib/mailbox.php index b282ce3687..f1f6e98c19 100644 --- a/lib/mailbox.php +++ b/lib/mailbox.php @@ -295,4 +295,17 @@ class MailboxAction extends CurrentUserDesignAction return; } + /** + * Mailbox actions are read only + * + * @param array $args other arguments + * + * @return boolean + */ + + function isReadOnly($args) + { + return true; + } + } From 5854fe194a35e1bbf2feb6db415f54f33def2dd9 Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Thu, 18 Jun 2009 01:04:12 +0000 Subject: [PATCH 121/262] Placed a check to make sure there is a reply button in a notice before applying the dynamic action --- js/util.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/js/util.js b/js/util.js index ce0c20d31b..854d250609 100644 --- a/js/util.js +++ b/js/util.js @@ -235,7 +235,7 @@ $(document).ready(function(){ }); function NoticeReply() { - if ($('#notice_data-text').length > 0) { + if ($('#notice_data-text').length > 0 && $('.notice_reply').length > 0) { $('#content .notice').each(function() { var notice = $(this)[0]; $($('.notice_reply', notice)[0]).click(function() { @@ -308,4 +308,4 @@ function NoticeAttachments() { $(this).closest(".entry-title").removeClass('ov'); } ); -} \ No newline at end of file +} From 06240450ef4818a8a74748ada297d1d55d18b967 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Wed, 17 Jun 2009 18:05:12 -0700 Subject: [PATCH 122/262] Have user favorites page show user's design --- actions/showfavorites.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actions/showfavorites.php b/actions/showfavorites.php index 865045337a..01f38a8927 100644 --- a/actions/showfavorites.php +++ b/actions/showfavorites.php @@ -45,7 +45,7 @@ require_once INSTALLDIR.'/lib/feedlist.php'; * @link http://laconi.ca/ */ -class ShowfavoritesAction extends Action +class ShowfavoritesAction extends CurrentUserDesignAction { /** User we're getting the faves of */ var $user = null; From 77185dd4c67761afbe670a15928c523f4de2842b Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Thu, 18 Jun 2009 01:10:48 +0000 Subject: [PATCH 123/262] A little more specific selector for notice reply --- js/util.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/util.js b/js/util.js index 854d250609..17ae4c0719 100644 --- a/js/util.js +++ b/js/util.js @@ -235,7 +235,7 @@ $(document).ready(function(){ }); function NoticeReply() { - if ($('#notice_data-text').length > 0 && $('.notice_reply').length > 0) { + if ($('#notice_data-text').length > 0 && $('#content .notice_reply').length > 0) { $('#content .notice').each(function() { var notice = $(this)[0]; $($('.notice_reply', notice)[0]).click(function() { From d8b0fcbc50248e493dfda288fe538ea58ef66acf Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Thu, 18 Jun 2009 01:28:02 +0000 Subject: [PATCH 124/262] Removed height:100% for better background image repetition --- theme/base/css/display.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/theme/base/css/display.css b/theme/base/css/display.css index 2153ce9a01..99f2d9ece7 100644 --- a/theme/base/css/display.css +++ b/theme/base/css/display.css @@ -12,7 +12,7 @@ img { display:block; border:0; } a abbr { cursor: pointer; border-bottom:0; } table { border-collapse:collapse; } ol { list-style-position:inside; } -html { font-size: 87.5%; background-color:#fff; height:100%; } +html { font-size: 87.5%; background-color:#fff; } body { background-color:#fff; color:#000; From 00736bddd199b2a43820367c3476b9e9ec84c0db Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Thu, 18 Jun 2009 01:39:37 +0000 Subject: [PATCH 125/262] Fix for background image repetition for various page heights --- classes/Design.php | 8 ++++---- theme/base/css/display.css | 4 ++-- theme/default/css/display.css | 1 - theme/identica/css/display.css | 1 - 4 files changed, 6 insertions(+), 8 deletions(-) diff --git a/classes/Design.php b/classes/Design.php index 5b28bf014a..da4b670be0 100644 --- a/classes/Design.php +++ b/classes/Design.php @@ -69,12 +69,12 @@ class Design extends Memcached_DataObject __FILE__); } - $css = 'html, body { background-color: #' . $bgcolor->hexValue() . '} ' . "\n"; + $css = 'body { background-color: #' . $bgcolor->hexValue() . ' }' . "\n"; $css .= '#content, #site_nav_local_views .current a { background-color: #'; $css .= $ccolor->hexValue() . '} '."\n"; - $css .= '#aside_primary { background-color: #'. $sbcolor->hexValue() . '} ' . "\n"; - $css .= 'html body { color: #'. $tcolor->hexValue() . '} '. "\n"; - $css .= 'a { color: #' . $lcolor->hexValue() . '} ' . "\n"; + $css .= '#aside_primary { background-color: #'. $sbcolor->hexValue() . ' }' . "\n"; + $css .= 'html body { color: #'. $tcolor->hexValue() . ' }'. "\n"; + $css .= 'a { color: #' . $lcolor->hexValue() . ' }' . "\n"; if (!empty($this->backgroundimage) && $this->disposition & BACKGROUND_ON) { diff --git a/theme/base/css/display.css b/theme/base/css/display.css index 99f2d9ece7..e1b92edce0 100644 --- a/theme/base/css/display.css +++ b/theme/base/css/display.css @@ -12,9 +12,9 @@ img { display:block; border:0; } a abbr { cursor: pointer; border-bottom:0; } table { border-collapse:collapse; } ol { list-style-position:inside; } -html { font-size: 87.5%; background-color:#fff; } +html { font-size: 87.5%; height:100%; } body { -background-color:#fff; +background-color:#FFFFFF; color:#000; font-family:sans-serif; font-size:1em; diff --git a/theme/default/css/display.css b/theme/default/css/display.css index 935116a74f..881e264da8 100644 --- a/theme/default/css/display.css +++ b/theme/default/css/display.css @@ -9,7 +9,6 @@ @import url(../../base/css/display.css); -html, body, a:active { background-color:#C3D6DF; diff --git a/theme/identica/css/display.css b/theme/identica/css/display.css index 6845fda5f9..ad57a0f0e4 100644 --- a/theme/identica/css/display.css +++ b/theme/identica/css/display.css @@ -9,7 +9,6 @@ @import url(../../base/css/display.css); -html, body, a:active { background-color:#F0F2F5; From f36d90a7556da192df1afe5ba24fa32e276f4dc7 Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Thu, 18 Jun 2009 01:41:53 +0000 Subject: [PATCH 126/262] Minor removal --- theme/base/css/display.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/theme/base/css/display.css b/theme/base/css/display.css index e1b92edce0..d6ecef2fcc 100644 --- a/theme/base/css/display.css +++ b/theme/base/css/display.css @@ -12,7 +12,7 @@ img { display:block; border:0; } a abbr { cursor: pointer; border-bottom:0; } table { border-collapse:collapse; } ol { list-style-position:inside; } -html { font-size: 87.5%; height:100%; } +html { font-size: 87.5%; } body { background-color:#FFFFFF; color:#000; From 5d8d3e318411b8f640e2cd4f8f2cd97fa80d3c82 Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Thu, 18 Jun 2009 04:33:32 +0000 Subject: [PATCH 127/262] Updated pigeonthoughts theme to reflect 0.8 design requirements --- theme/pigeonthoughts/css/base.css | 158 +++++++++++++++++++++++---- theme/pigeonthoughts/css/display.css | 125 ++++++++++++++------- 2 files changed, 221 insertions(+), 62 deletions(-) diff --git a/theme/pigeonthoughts/css/base.css b/theme/pigeonthoughts/css/base.css index 08427d3c84..9866e2d2cc 100644 --- a/theme/pigeonthoughts/css/base.css +++ b/theme/pigeonthoughts/css/base.css @@ -12,9 +12,9 @@ img { display:block; border:0; } a abbr { cursor: pointer; border-bottom:0; } table { border-collapse:collapse; } ol { list-style-position:inside; } -html { font-size: 87.5%; background-color:#fff; } +html { font-size: 87.5%; } body { -background-color:#fff; +background-color:#FFFFFF; color:#000; font-family:sans-serif; font-size:1em; @@ -78,7 +78,8 @@ margin:0 0 18px 0; form label { font-weight:bold; } -input.checkbox { +input.checkbox, +input.radio { position:relative; top:2px; left:0; @@ -155,7 +156,8 @@ font-weight:bold; #form_invite legend, #form_notice_delete legend, #form_password_recover legend, -#form_password_change legend { +#form_password_change legend, +.form_entity_block legend { display:none; } @@ -181,13 +183,19 @@ margin-left:11px; float:left; width:90%; } - +.form_settings label.radio { +margin-top:0; +margin-right:47px; +margin-left:11px; +width:auto; +} #form_login p.form_guide, #form_register #settings_rememberme p.form_guide, #form_openid_login #settings_rememberme p.form_guide, #settings_twitter_remove p.form_guide, -#form_search ul.form_data #q { +#form_search ul.form_data #q, +#design_background-image_onoff p.form_guide { margin-left:0; } @@ -375,10 +383,10 @@ margin-bottom:1em; } #content { -width:50.009%; +width:49.009%; min-height:259px; float:left; -margin-left:18px; +padding:0 18px; } #shownotice #content { min-height:0; @@ -421,6 +429,8 @@ width:80.789%; height:46px; line-height:1.5; padding:7px 7px 16px 7px; +position:relative; +z-index:2; } #form_notice label { display:block; @@ -428,8 +438,22 @@ float:left; font-size:1.3em; margin-bottom:7px; } -#form_notice #notice_submit label { -display:none; +#form_notice label[for=notice_data-attach], +#form_notice #notice_data-attach { +position:absolute; +top:25px; +cursor:pointer; +} +#form_notice label[for=notice_data-attach] { +text-indent:-9999px; +left:394px; +width:16px; +height:16px; +} +#form_notice #notice_data-attach { +left:183px; +padding:0; +height:16px; } #form_notice .form_note { position:absolute; @@ -509,12 +533,15 @@ margin-bottom:4px; .entity_profile .entity_nickname { margin-left:11px; display:inline; -font-weight:bold; } .entity_profile .entity_nickname { margin-left:0; } - +.entity_profile .fn, +.entity_profile .nickname { +font-size:1.1em; +font-weight:bold; +} .entity_profile .entity_fn dd:before { content: "("; font-weight:normal; @@ -574,10 +601,13 @@ display:block; .form_user_block input.submit, .form_user_unblock input.submit, +.form_group_block input.submit, +.form_group_unblock input.submit, .entity_send-a-message a, .entity_edit a, .form_user_nudge input.submit, -.entity_nudge p { +.entity_nudge p, +.form_make_admin input.submit { border:0; padding-left:20px; } @@ -640,6 +670,7 @@ list-style-type:none; float:left; margin-right:7px; margin-bottom:7px; +display:inline; } .section .entities li .photo { margin-right:0; @@ -712,12 +743,17 @@ float:left; width:96.41%; border-width:1px; border-style:solid; -padding:1.795%; margin-bottom:11px; } .notices li { list-style-type:none; } +.notices .notices { +margin-top:7px; +margin-left:5%; +width:95%; +float:left; +} #aside_primary .notice, #aside_primary .profile { @@ -773,6 +809,9 @@ float:left; width:100%; overflow:hidden; } +.notice .entry-title.ov { +overflow:visible; +} #shownotice .notice .entry-title { font-size:2.2em; } @@ -797,7 +836,7 @@ clear:left; float:left; font-size:0.95em; margin-left:59px; -width:65%; +width:60%; } #showstream .notice div.entry-content, #shownotice .notice div.entry-content { @@ -827,15 +866,12 @@ display:inline-block; text-transform:lowercase; } - .notice-options { -padding-left:2%; -float:left; -width:50%; position:relative; font-size:0.95em; -width:12.5%; +width:90px; float:right; +margin-right:11px; } .notice-options a { @@ -896,6 +932,74 @@ border:0; padding:0; } +.notice .attachment { +position:relative; +padding-left:16px; +} +#attachments .attachment { +padding-left:0; +} +.notice .attachment img { +position:absolute; +top:18px; +left:0; +z-index:99; +} +#shownotice .notice .attachment img { +position:static; +} + +#attachments { +clear:both; +float:left; +width:100%; +margin-top:18px; +} +#attachments dt { +font-weight:bold; +font-size:1.3em; +margin-bottom:4px; +} + +#attachments ol li { +margin-bottom:18px; +list-style-type:decimal; +float:left; +clear:both; +} + +#jOverlayContent, +#jOverlayContent #content, +#jOverlayContent #content_inner { +width: auto !important; +margin-bottom:0; +} +#jOverlayContent #content { +padding:11px; +min-height:auto; +} +#jOverlayContent .external span { +display:block; +margin-bottom:11px; +} +#jOverlayContent button { +position:absolute; +top:0; +right:0; +width:29px; +height:29px; +text-align:center; +font-weight:bold; +padding:0; +} +#jOverlayContent h1 { +max-width:475px; +} +#jOverlayContent #content { +border-radius:7px; +-moz-border-radius:7px; +-webkit-border-radius:7px; +} #usergroups #new_group { float: left; @@ -1019,8 +1123,6 @@ margin-left:18px; } - - /* TOP_POSTERS */ .section tbody td { padding-right:11px; @@ -1140,6 +1242,18 @@ width:400px; margin-right:28px; } +#settings_design_color .form_data li { +width:33%; +} +#settings_design_color .form_data label { +float:none; +display:block; +} +#settings_design_color .form_data .swatch { +padding:11px; +margin-left:0; +} + .instructions ul { list-style-position:inside; } diff --git a/theme/pigeonthoughts/css/display.css b/theme/pigeonthoughts/css/display.css index af31cf78d6..af562964d2 100644 --- a/theme/pigeonthoughts/css/display.css +++ b/theme/pigeonthoughts/css/display.css @@ -10,7 +10,7 @@ @import url(base.css); html { -background:#fff url(../images/illustrations/illu_pigeons-01.png) no-repeat 0 100%; +background:url(../images/illustrations/illu_pigeons-01.png) no-repeat 0 100%; } body, @@ -30,10 +30,10 @@ font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif; } input, textarea, select, .entity_remote_subscribe { -border-color:#aaa; +border-color:#AAAAAA; } #filter_tags ul li { -border-color:#ddd; +border-color:#DDDDDD; } .form_settings input.form_action-primary { @@ -50,35 +50,41 @@ background-color:#8F0000; input:focus, textarea:focus, select:focus, #form_notice.warning #notice_data-text { border-color:#8F0000; +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); } input.submit, .entity_remote_subscribe { -color:#fff; +color:#FFFFFF; } a, div.notice-options input, .form_user_block input.submit, .form_user_unblock input.submit, +.form_group_block input.submit, +.form_group_unblock input.submit, .entity_send-a-message a, .form_user_nudge input.submit, .entity_nudge p, -.form_settings input.form_action-primary { -color:#000; +.form_settings input.form_action-primary, +.form_make_admin input.submit { +color:#000000; } .notice, .profile { -border-color:#000; +border-color:#000000; } .notice a, .profile a { -color:#fff; +color:#FFFFFF; } .notice:nth-child(3n-1), .profile:nth-child(3n-1) { -border-color:#fff; +border-color:#FFFFFF; } .notice:nth-child(3n-1) a, .profile:nth-child(3n-1) a { @@ -90,7 +96,7 @@ border-color:#7F1114; } .notice:nth-child(3n) a, .profile:nth-child(3n) a { -color:#000; +color:#000000; } .aside .section .notice, @@ -100,30 +106,30 @@ color:#000; .aside .section .notice:nth-child(3n), .aside .section .profile:nth-child(3n) { background-color:transparent; -color:#000; +color:#000000; } .aside .section { -border-color:#fff; -background-color:#fff; -color:#000; +border-color:#FFFFFF; +background-color:#FFFFFF; +color:#000000; } .aside .section:nth-child(n) { -border-color:#000; -background-color:#000; -color:#fff; +border-color:#000000; +background-color:#000000; +color:#FFFFFF; } .aside .section:nth-child(3n-1) { -border-color:#fff; -background-color:#fff; -color:#000; +border-color:#FFFFFF; +background-color:#FFFFFF; +color:#000000; } .aside .section:nth-child(3n) { background-color:#7F1114; border-color:#7F1114; -color:#000; +color:#000000; } .aside .section a { color:#7F1114; @@ -132,7 +138,7 @@ color:#7F1114; color:#7F1114; } .aside .section:nth-child(3n) a { -color:#fff; +color:#FFFFFF; } @@ -145,33 +151,43 @@ background:url(../images/illustrations/illu_pigeons-02.png) no-repeat 10% 100%; } #notice_text-count { -color:#333; +color:#333333; } #form_notice.warning #notice_text-count { -color:#000; +color:#000000; } +#form_notice label[for=notice_data-attach] { +background:transparent url(../../base/images/icons/twotone/green/clip-01.gif) no-repeat 0 45%; +} +#form_notice #notice_data-attach { +opacity:0; +} + #form_notice.processing #notice_action-submit { -background:#fff url(../../base/images/icons/icon_processing.gif) no-repeat 47% 47%; +background:#FFFFFF url(../../base/images/icons/icon_processing.gif) no-repeat 47% 47%; cursor:wait; text-indent:-9999px; } #content, #site_nav_local_views a { -border-color:#fff; +border-color:#FFFFFF; } #site_nav_local_views .current a { background-color:rgba(143, 0, 0, 0.8); -color:#fff; +color:#FFFFFF; } #site_nav_local_views a { -background-color:rgba(255, 255, 255, 0.3); +background-color:rgba(255, 255, 255, 0.5); } #site_nav_local_views a:hover { -background-color:#fff; +background-color:rgba(255, 255, 255, 0.9); color:#8F0000; } +#site_nav_local_views .current a { +text-shadow: rgba(194,194,194,0.5) 1px 1px 1px; +} .error { background-color:#F7E8E8; @@ -181,7 +197,7 @@ background-color:#EFF3DC; } #anon_notice { -color:#000; +color:#000000; } @@ -204,7 +220,10 @@ background-image:url(../../base/images/icons/icon_foaf.gif); .form_user_nudge input.submit, .form_user_block input.submit, .form_user_unblock input.submit, -.entity_nudge p { +.form_group_block input.submit, +.form_group_unblock input.submit, +.entity_nudge p, +.form_make_admin input.submit { background-position: 0 40%; background-repeat: no-repeat; background-color:transparent; @@ -214,7 +233,7 @@ background-color:transparent; .form_user_subscribe input.submit, .form_user_unsubscribe input.submit { background-color:#8F0000; -color:#fff; +color:#FFFFFF; } .form_user_unsubscribe input.submit, .form_group_leave input.submit, @@ -233,15 +252,22 @@ background-image:url(../../base/images/icons/twotone/green/quote.gif); background-image:url(../../base/images/icons/twotone/green/mail.gif); } .form_user_block input.submit, -.form_user_unblock input.submit { +.form_user_unblock input.submit, +.form_group_block input.submit, +.form_group_unblock input.submit { background-image:url(../../base/images/icons/twotone/green/shield.gif); } +.form_make_admin input.submit { +background-image:url(../../base/images/icons/twotone/green/admin.gif); +} /* NOTICES */ -.notices li.over { -background-color:#fcfcfc; +.notice .attachment { +background:transparent url(../../base/images/icons/twotone/green/clip-02.gif) no-repeat 0 45%; +} +#attachments .attachment { +background:none; } - .notice-options .notice_reply a, .notice-options form input.submit { background-color:transparent; @@ -263,17 +289,36 @@ background:transparent url(../../base/images/icons/twotone/green/trash.gif) no-r .notices div.notice-options { opacity:0.4; } -.notices li.hover div.entry-content, -.notices li.hover div.notice-options { +.notices li:hover div.entry-content, +.notices li:hover div.notice-options { opacity:1; } div.entry-content { -color:#333; +color:#333333; } div.notice-options a, div.notice-options input { font-family:sans-serif; } +.notices li:hover { +background-color:transparent; +} +#conversation .notices li:hover { +background-color:transparent; +} + +.notices .notices { +background-color:rgba(200, 200, 200, 0.050); +} +.notices .notices .notices { +background-color:rgba(200, 200, 200, 0.100); +} +.notices .notices .notices .notices { +background-color:rgba(200, 200, 200, 0.150); +} +.notices .notices .notices .notices .notices { +background-color:rgba(200, 200, 200, 0.300); +} /*END: NOTICES */ #new_group a { @@ -283,7 +328,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:#000; +border-color:#000000; } .pagination .nav_prev a { background-image:url(../../base/images/icons/twotone/green/arrow-left.gif); From ca537919888e2a82365265a1f6f744db182f30f1 Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Thu, 18 Jun 2009 04:54:12 +0000 Subject: [PATCH 128/262] Using notice hover only on content area --- theme/identica/css/display.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/theme/identica/css/display.css b/theme/identica/css/display.css index ad57a0f0e4..09ad4c9724 100644 --- a/theme/identica/css/display.css +++ b/theme/identica/css/display.css @@ -244,7 +244,7 @@ div.notice-options a, div.notice-options input { font-family:sans-serif; } -.notices li:hover { +#content .notices li:hover { background-color:#FCFCFC; } #conversation .notices li:hover { From 2b3746013eb5daa323b2740d30e222f0d88c2d9c Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Thu, 18 Jun 2009 04:55:41 +0000 Subject: [PATCH 129/262] Updated themes for notice hover on content area --- theme/default/css/display.css | 2 +- theme/pigeonthoughts/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 881e264da8..7e8b84b4cc 100644 --- a/theme/default/css/display.css +++ b/theme/default/css/display.css @@ -244,7 +244,7 @@ div.notice-options a, div.notice-options input { font-family:sans-serif; } -.notices li:hover { +#content .notices li:hover { background-color:#FCFCFC; } #conversation .notices li:hover { diff --git a/theme/pigeonthoughts/css/display.css b/theme/pigeonthoughts/css/display.css index af562964d2..01af500bfc 100644 --- a/theme/pigeonthoughts/css/display.css +++ b/theme/pigeonthoughts/css/display.css @@ -300,7 +300,7 @@ div.notice-options a, div.notice-options input { font-family:sans-serif; } -.notices li:hover { +#content .notices li:hover { background-color:transparent; } #conversation .notices li:hover { From dff43c03e4cdd76419a430f0942e9eacf30e13b7 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Wed, 17 Jun 2009 22:16:09 -0700 Subject: [PATCH 130/262] Add design_id to User_group --- classes/User_group.php | 7 +++++++ classes/laconica.ini | 1 + db/laconica.sql | 1 + 3 files changed, 9 insertions(+) diff --git a/classes/User_group.php b/classes/User_group.php index 1a24124bb1..8a56b9e52b 100644 --- a/classes/User_group.php +++ b/classes/User_group.php @@ -19,6 +19,7 @@ class User_group extends Memcached_DataObject public $homepage_logo; // varchar(255) public $stream_logo; // varchar(255) public $mini_logo; // varchar(255) + public $design_id; // int(4) public $created; // datetime() not_null public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP @@ -239,4 +240,10 @@ class User_group extends Memcached_DataObject } return null; } + + function getDesign() + { + return Design::staticGet('id', $this->design_id); + } + } diff --git a/classes/laconica.ini b/classes/laconica.ini index 1a650aba55..5ced158851 100755 --- a/classes/laconica.ini +++ b/classes/laconica.ini @@ -468,6 +468,7 @@ original_logo = 2 homepage_logo = 2 stream_logo = 2 mini_logo = 2 +design_id = 1 created = 142 modified = 384 diff --git a/db/laconica.sql b/db/laconica.sql index b018afec8e..8d1d47d38d 100644 --- a/db/laconica.sql +++ b/db/laconica.sql @@ -387,6 +387,7 @@ create table user_group ( homepage_logo varchar(255) comment 'homepage (profile) size logo', stream_logo varchar(255) comment 'stream-sized logo', mini_logo varchar(255) comment 'mini logo', + design_id integer comment 'id of a design' references design(id), created datetime not null comment 'date this record was created', modified timestamp comment 'date this record was modified', From ba3a484a655f93329463465d224dfc6ae6494434 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Thu, 18 Jun 2009 00:12:53 -0700 Subject: [PATCH 131/262] order notices in a conversation --- actions/conversation.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/actions/conversation.php b/actions/conversation.php index 20c68986cb..d3fc5b6a9c 100644 --- a/actions/conversation.php +++ b/actions/conversation.php @@ -217,6 +217,8 @@ class ConversationTree extends NoticeList $this->out->elementStart('ol', array('class' => 'notices')); + sort($children); + foreach ($children as $child) { $this->showNoticePlus($child); } From 57274d21ba554e43c6fcd90555388a60d3de014d Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Thu, 18 Jun 2009 02:01:06 -0700 Subject: [PATCH 132/262] Group theming. --- actions/blockedfromgroup.php | 2 +- actions/editgroup.php | 6 +- actions/groupblock.php | 17 ++-- actions/grouplogo.php | 2 +- actions/groupmembers.php | 2 +- actions/showgroup.php | 5 +- lib/accountsettingsaction.php | 2 +- {actions => lib}/designsettings.php | 129 ++-------------------------- lib/groupnav.php | 6 ++ lib/router.php | 4 +- 10 files changed, 32 insertions(+), 143 deletions(-) rename {actions => lib}/designsettings.php (79%) diff --git a/actions/blockedfromgroup.php b/actions/blockedfromgroup.php index 541ebcfd90..5c1eab3542 100644 --- a/actions/blockedfromgroup.php +++ b/actions/blockedfromgroup.php @@ -41,7 +41,7 @@ if (!defined('LACONICA')) { * @link http://laconi.ca/ */ -class BlockedfromgroupAction extends Action +class BlockedfromgroupAction extends GroupDesignAction { var $page = null; diff --git a/actions/editgroup.php b/actions/editgroup.php index 29a7bce437..6aa6f8b11f 100644 --- a/actions/editgroup.php +++ b/actions/editgroup.php @@ -23,6 +23,7 @@ * @package Laconica * @author Evan Prodromou * @author Sarven Capadisli + * @author Zach Copley * @copyright 2008-2009 Control Yourself, Inc. * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://laconi.ca/ @@ -40,14 +41,15 @@ if (!defined('LACONICA')) { * @category Group * @package Laconica * @author Evan Prodromou + * @author Zach Copley * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://laconi.ca/ */ -class EditgroupAction extends Action +class EditgroupAction extends GroupDesignAction { + var $msg; - var $group = null; function title() { diff --git a/actions/groupblock.php b/actions/groupblock.php index 28685b1d56..93662da799 100644 --- a/actions/groupblock.php +++ b/actions/groupblock.php @@ -151,19 +151,17 @@ class GroupblockAction extends Action function areYouSureForm() { $id = $this->profile->id; - $this->elementStart('form', array('id' => 'block-' . $id, - 'method' => 'post', - 'class' => 'form_settings form_entity_block', - 'action' => common_local_url('groupblock'))); - $this->elementStart('fieldset'); - $this->hidden('token', common_session_token()); - $this->element('legend', null, _('Block user')); $this->element('p', null, sprintf(_('Are you sure you want to block user "%s" from the group "%s"? '. 'They will be removed from the group, unable to post, and '. 'unable to subscribe to the group in the future.'), $this->profile->getBestName(), $this->group->getBestName())); + $this->elementStart('form', array('id' => 'block-' . $id, + 'method' => 'post', + 'class' => 'block', + 'action' => common_local_url('groupblock'))); + $this->hidden('token', common_session_token()); $this->hidden('blockto-' . $this->profile->id, $this->profile->id, 'blockto'); @@ -175,9 +173,8 @@ class GroupblockAction extends Action $this->hidden($k, $v); } } - $this->submit('form_action-no', _('No'), 'submit form_action-primary', 'no', _("Do not block this user from this group")); - $this->submit('form_action-yes', _('Yes'), 'submit form_action-secondary', 'yes', _('Block this user from this group')); - $this->elementEnd('fieldset'); + $this->submit('no', _('No')); + $this->submit('yes', _('Yes')); $this->elementEnd('form'); } diff --git a/actions/grouplogo.php b/actions/grouplogo.php index fe6127da29..8f6158daca 100644 --- a/actions/grouplogo.php +++ b/actions/grouplogo.php @@ -50,7 +50,7 @@ define('MAX_ORIGINAL', 480); * @link http://laconi.ca/ */ -class GrouplogoAction extends Action +class GrouplogoAction extends GroupDesignAction { var $mode = null; var $imagefile = null; diff --git a/actions/groupmembers.php b/actions/groupmembers.php index abfad3f0dd..d132cdf967 100644 --- a/actions/groupmembers.php +++ b/actions/groupmembers.php @@ -44,7 +44,7 @@ require_once INSTALLDIR.'/lib/publicgroupnav.php'; * @link http://laconi.ca/ */ -class GroupmembersAction extends Action +class GroupmembersAction extends GroupDesignAction { var $page = null; diff --git a/actions/showgroup.php b/actions/showgroup.php index 357f579d8f..b6a0f4844e 100644 --- a/actions/showgroup.php +++ b/actions/showgroup.php @@ -47,10 +47,9 @@ define('MEMBERS_PER_SECTION', 27); * @link http://laconi.ca/ */ -class ShowgroupAction extends Action +class ShowgroupAction extends GroupDesignAction { - /** group we're viewing. */ - var $group = null; + /** page we're viewing. */ var $page = null; diff --git a/lib/accountsettingsaction.php b/lib/accountsettingsaction.php index 86800d2a36..4ab50abcef 100644 --- a/lib/accountsettingsaction.php +++ b/lib/accountsettingsaction.php @@ -115,7 +115,7 @@ class AccountSettingsNav extends Widget 'openidsettings' => array(_('OpenID'), _('Add or remove OpenIDs')), - 'designsettings' => + 'userdesignsettings' => array(_('Design'), _('Design your profile')), 'othersettings' => diff --git a/actions/designsettings.php b/lib/designsettings.php similarity index 79% rename from actions/designsettings.php rename to lib/designsettings.php index 047059e04b..6aa6bb2f19 100644 --- a/actions/designsettings.php +++ b/lib/designsettings.php @@ -35,8 +35,11 @@ if (!defined('LACONICA')) { require_once INSTALLDIR . '/lib/accountsettingsaction.php'; require_once INSTALLDIR . '/lib/webcolor.php'; -class DesignsettingsAction extends AccountSettingsAction +class DesignSettingsAction extends AccountSettingsAction { + + var $submitaction = null; + /** * Title of the page * @@ -60,29 +63,14 @@ class DesignsettingsAction extends AccountSettingsAction 'with a background image and a colour palette of your choice.'); } - /** - * Content area of the page - * - * Shows a form for changing the password - * - * @return void - */ - - function showContent() + function showDesignForm($design) { - $user = common_current_user(); - $design = $user->getDesign(); - - if (empty($design)) { - $design = $this->defaultDesign(); - } $this->elementStart('form', array('method' => 'post', 'enctype' => 'multipart/form-data', 'id' => 'form_settings_design', 'class' => 'form_settings', - 'action' => - common_local_url('designsettings'))); + 'action' => $this->submitaction)); $this->elementStart('fieldset'); $this->hidden('token', common_session_token()); @@ -370,108 +358,7 @@ class DesignsettingsAction extends AccountSettingsAction return $design; } - /** - * Save or update the user's design settings - * - * @return void - */ - - function saveDesign() - { - try { - - $bgcolor = new WebColor($this->trimmed('design_background')); - $ccolor = new WebColor($this->trimmed('design_content')); - $sbcolor = new WebColor($this->trimmed('design_sidebar')); - $tcolor = new WebColor($this->trimmed('design_text')); - $lcolor = new WebColor($this->trimmed('design_links')); - - } catch (WebColorException $e) { - $this->showForm($e->getMessage()); - return; - } - - $onoff = $this->arg('design_background-image_onoff'); - - $on = false; - $off = false; - $tile = false; - - if ($onoff == 'on') { - $on = true; - } else { - $off = true; - } - - $repeat = $this->boolean('design_background-image_repeat'); - - if ($repeat) { - $tile = true; - } - - $user = common_current_user(); - $design = $user->getDesign(); - - if (!empty($design)) { - - $original = clone($design); - - $design->backgroundcolor = $bgcolor->intValue(); - $design->contentcolor = $ccolor->intValue(); - $design->sidebarcolor = $sbcolor->intValue(); - $design->textcolor = $tcolor->intValue(); - $design->linkcolor = $lcolor->intValue(); - $design->backgroundimage = $filepath; - - $design->setDisposition($on, $off, $tile); - - $result = $design->update($original); - - if ($result === false) { - common_log_db_error($design, 'UPDATE', __FILE__); - $this->showForm(_('Couldn\'t update your design.')); - return; - } - - // update design - } else { - - $user->query('BEGIN'); - - // save new design - $design = new Design(); - - $design->backgroundcolor = $bgcolor->intValue(); - $design->contentcolor = $ccolor->intValue(); - $design->sidebarcolor = $sbcolor->intValue(); - $design->textcolor = $tcolor->intValue(); - $design->linkcolor = $lcolor->intValue(); - $design->backgroundimage = $filepath; - - $design->setDisposition($on, $off, $tile); - - $id = $design->insert(); - - if (empty($id)) { - common_log_db_error($id, 'INSERT', __FILE__); - $this->showForm(_('Unable to save your design settings!')); - return; - } - - $original = clone($user); - $user->design_id = $id; - $result = $user->update($original); - - if (empty($result)) { - common_log_db_error($original, 'UPDATE', __FILE__); - $this->showForm(_('Unable to save your design settings!')); - $user->query('ROLLBACK'); - return; - } - - $user->query('COMMIT'); - - } + function saveBackgroundImage($design) { // Now that we have a Design ID we can add a file to the design. // XXX: This is an additional DB hit, but figured having the image @@ -510,8 +397,6 @@ class DesignsettingsAction extends AccountSettingsAction return; } } - - $this->showForm(_('Design preferences saved.'), true); } } diff --git a/lib/groupnav.php b/lib/groupnav.php index 194247982c..9e530c447c 100644 --- a/lib/groupnav.php +++ b/lib/groupnav.php @@ -113,6 +113,12 @@ class GroupNav extends Widget sprintf(_('Add or edit %s logo'), $nickname), $action_name == 'grouplogo', 'nav_group_logo'); + $this->out->menuItem(common_local_url('groupdesignsettings', array('nickname' => + $nickname)), + _('Design'), + sprintf(_('Add or edit %s design'), $nickname), + $action_name == 'groupdesignsettings', + 'nav_group_design'); } $this->out->elementEnd('ul'); } diff --git a/lib/router.php b/lib/router.php index 8b6f636182..1f39c60dc5 100644 --- a/lib/router.php +++ b/lib/router.php @@ -132,7 +132,7 @@ class Router // settings foreach (array('profile', 'avatar', 'password', 'openid', 'im', - 'email', 'sms', 'twitter', 'design', 'other') as $s) { + 'email', 'sms', 'twitter', 'userdesign', 'other') as $s) { $m->connect('settings/'.$s, array('action' => $s.'settings')); } @@ -223,7 +223,7 @@ class Router array('nickname' => '[a-zA-Z0-9]+')); } - foreach (array('members', 'logo', 'rss') as $n) { + foreach (array('members', 'logo', 'rss', 'designsettings') as $n) { $m->connect('group/:nickname/'.$n, array('action' => 'group'.$n), array('nickname' => '[a-zA-Z0-9]+')); From 3f032bc36e2c624a895c584479c8f423e62bba73 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Thu, 18 Jun 2009 02:16:39 -0700 Subject: [PATCH 133/262] Left out some new user and group theming file in the previous commit --- actions/groupdesignsettings.php | 330 ++++++++++++++++++++++++++++++++ actions/userdesignsettings.php | 208 ++++++++++++++++++++ lib/groupdesignaction.php | 87 +++++++++ 3 files changed, 625 insertions(+) create mode 100644 actions/groupdesignsettings.php create mode 100644 actions/userdesignsettings.php create mode 100644 lib/groupdesignaction.php diff --git a/actions/groupdesignsettings.php b/actions/groupdesignsettings.php new file mode 100644 index 0000000000..7270bc8f7e --- /dev/null +++ b/actions/groupdesignsettings.php @@ -0,0 +1,330 @@ +. + * + * @category Settings + * @package Laconica + * @author Sarven Capadisli + * @author Zach Copley + * @copyright 2008-2009 Control Yourself, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://laconi.ca/ + */ + +if (!defined('LACONICA')) { + exit(1); +} + +require_once INSTALLDIR . '/lib/designsettings.php'; + +class GroupDesignSettingsAction extends DesignSettingsAction +{ + var $group = null; + + /** + * Prepare to run + */ + + function prepare($args) + { + parent::prepare($args); + + if (!common_config('inboxes','enabled')) { + $this->serverError(_('Inboxes must be enabled for groups to work')); + return false; + } + + if (!common_logged_in()) { + $this->clientError(_('You must be logged in to edit a group.')); + return false; + } + + $nickname_arg = $this->trimmed('nickname'); + $nickname = common_canonical_nickname($nickname_arg); + + // Permanent redirect on non-canonical nickname + + if ($nickname_arg != $nickname) { + $args = array('nickname' => $nickname); + common_redirect(common_local_url('groupdesignsettings', $args), 301); + return false; + } + + if (!$nickname) { + $this->clientError(_('No nickname'), 404); + return false; + } + + $groupid = $this->trimmed('groupid'); + + if ($groupid) { + $this->group = User_group::staticGet('id', $groupid); + } else { + $this->group = User_group::staticGet('nickname', $nickname); + } + + if (!$this->group) { + $this->clientError(_('No such group'), 404); + return false; + } + + $cur = common_current_user(); + + if (!$cur->isAdmin($this->group)) { + $this->clientError(_('You must be an admin to edit the group'), 403); + return false; + } + + $this->submitaction = common_local_url('groupdesignsettings', + array('nickname' => $this->group->nickname)); + + return true; + } + + /** + * A design for this action + * + * if the group attribute has been set, returns that group's + * design. + * + * @return Design a design object to use + */ + + function getDesign() + { + + if (empty($this->group)) { + return null; + } + + return $this->group->getDesign(); + } + + /** + * Title of the page + * + * @return string Title of the page + */ + + function title() + { + return _('Group design'); + } + + /** + * Instructions for use + * + * @return instructions for use + */ + + function getInstructions() + { + return _('Customize the way your group looks ' . + 'with a background image and a colour palette of your choice.'); + } + + /** + * Override to show group nav stuff + * + * @return nothing + */ + + function showLocalNav() + { + $nav = new GroupNav($this, $this->group); + $nav->show(); + } + + /** + * Get the design we want to edit + * + * @return Design + */ + + function getWorkingDesign() { + + $design = null; + + if (isset($this->group)) { + $design = $this->group->getDesign(); + } + + if (empty($design)) { + $design = $this->defaultDesign(); + } + + return $design; + } + + /** + * Content area of the page + * + * Shows a form for changing the design + * + * @return void + */ + + function showContent() + { + $this->showDesignForm($this->getWorkingDesign()); + } + + /** + * Save or update the group's design settings + * + * @return void + */ + + function saveDesign() + { + try { + + $bgcolor = new WebColor($this->trimmed('design_background')); + $ccolor = new WebColor($this->trimmed('design_content')); + $sbcolor = new WebColor($this->trimmed('design_sidebar')); + $tcolor = new WebColor($this->trimmed('design_text')); + $lcolor = new WebColor($this->trimmed('design_links')); + + } catch (WebColorException $e) { + $this->showForm($e->getMessage()); + return; + } + + $onoff = $this->arg('design_background-image_onoff'); + + $on = false; + $off = false; + $tile = false; + + if ($onoff == 'on') { + $on = true; + } else { + $off = true; + } + + $repeat = $this->boolean('design_background-image_repeat'); + + if ($repeat) { + $tile = true; + } + + $design = $this->group->getDesign(); + + if (!empty($design)) { + + // update design + + $original = clone($design); + + $design->backgroundcolor = $bgcolor->intValue(); + $design->contentcolor = $ccolor->intValue(); + $design->sidebarcolor = $sbcolor->intValue(); + $design->textcolor = $tcolor->intValue(); + $design->linkcolor = $lcolor->intValue(); + $design->backgroundimage = $filepath; + + $design->setDisposition($on, $off, $tile); + + $result = $design->update($original); + + if ($result === false) { + common_log_db_error($design, 'UPDATE', __FILE__); + $this->showForm(_('Couldn\'t update your design.')); + return; + } + + } else { + + $this->group->query('BEGIN'); + + // save new design + + $design = new Design(); + + $design->backgroundcolor = $bgcolor->intValue(); + $design->contentcolor = $ccolor->intValue(); + $design->sidebarcolor = $sbcolor->intValue(); + $design->textcolor = $tcolor->intValue(); + $design->linkcolor = $lcolor->intValue(); + $design->backgroundimage = $filepath; + + $design->setDisposition($on, $off, $tile); + + $id = $design->insert(); + + if (empty($id)) { + common_log_db_error($id, 'INSERT', __FILE__); + $this->showForm(_('Unable to save your design settings!')); + return; + } + + $original = clone($this->group); + $this->group->design_id = $id; + $result = $this->group->update($original); + + if (empty($result)) { + common_log_db_error($original, 'UPDATE', __FILE__); + $this->showForm(_('Unable to save your design settings!')); + $this->group->query('ROLLBACK'); + return; + } + + $this->group->query('COMMIT'); + + } + + $this->saveBackgroundImage($design); + + $this->showForm(_('Design preferences saved.'), true); + } + + /** + * Handle input and output a page (overrided) + * + * @param array $args $_REQUEST arguments + * + * @return void + */ + + function handle($args) + { + parent::handle($args); + if (!common_logged_in()) { + $this->clientError(_('Not logged in.')); + return; + } else if (!common_is_real_login()) { + // Cookie theft means that automatic logins can't + // change important settings or see private info, and + // _all_ our settings are important + common_set_returnto($this->selfUrl()); + $user = common_current_user(); + if ($user->hasOpenID()) { + common_redirect(common_local_url('openidlogin'), 303); + } else { + common_redirect(common_local_url('login'), 303); + } + } else if ($_SERVER['REQUEST_METHOD'] == 'POST') { + $this->handlePost(); + } else { + $this->showForm(); + } + } + +} diff --git a/actions/userdesignsettings.php b/actions/userdesignsettings.php new file mode 100644 index 0000000000..d6088aa9d0 --- /dev/null +++ b/actions/userdesignsettings.php @@ -0,0 +1,208 @@ +. + * + * @category Settings + * @package Laconica + * @author Sarven Capadisli + * @author Zach Copley + * @copyright 2008-2009 Control Yourself, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://laconi.ca/ + */ + +if (!defined('LACONICA')) { + exit(1); +} + +require_once INSTALLDIR . '/lib/designsettings.php'; + +class UserDesignSettingsAction extends DesignSettingsAction +{ + + function prepare($args) + { + parent::prepare($args); + $this->submitaction = common_local_url('userdesignsettings'); + return true; + } + + /** + * Title of the page + * + * @return string Title of the page + */ + + function title() + { + return _('Profile design'); + } + + /** + * Instructions for use + * + * @return instructions for use + */ + + function getInstructions() + { + return _('Customize the way your profile looks ' . + 'with a background image and a colour palette of your choice.'); + } + + /** + * Get the design we want to edit + * + * @return Design + */ + + function getWorkingDesign() { + + $user = common_current_user(); + $design = $user->getDesign(); + + if (empty($design)) { + $design = $this->defaultDesign(); + } + + return $design; + } + + /** + * Content area of the page + * + * Shows a form for changing the design + * + * @return void + */ + + function showContent() + { + $this->showDesignForm($this->getWorkingDesign()); + } + + /** + * Save or update the user's design settings + * + * @return void + */ + + function saveDesign() + { + try { + + $bgcolor = new WebColor($this->trimmed('design_background')); + $ccolor = new WebColor($this->trimmed('design_content')); + $sbcolor = new WebColor($this->trimmed('design_sidebar')); + $tcolor = new WebColor($this->trimmed('design_text')); + $lcolor = new WebColor($this->trimmed('design_links')); + + } catch (WebColorException $e) { + $this->showForm($e->getMessage()); + return; + } + + $onoff = $this->arg('design_background-image_onoff'); + + $on = false; + $off = false; + $tile = false; + + if ($onoff == 'on') { + $on = true; + } else { + $off = true; + } + + $repeat = $this->boolean('design_background-image_repeat'); + + if ($repeat) { + $tile = true; + } + + $user = common_current_user(); + $design = $user->getDesign(); + + if (!empty($design)) { + + $original = clone($design); + + $design->backgroundcolor = $bgcolor->intValue(); + $design->contentcolor = $ccolor->intValue(); + $design->sidebarcolor = $sbcolor->intValue(); + $design->textcolor = $tcolor->intValue(); + $design->linkcolor = $lcolor->intValue(); + $design->backgroundimage = $filepath; + + $design->setDisposition($on, $off, $tile); + + $result = $design->update($original); + + if ($result === false) { + common_log_db_error($design, 'UPDATE', __FILE__); + $this->showForm(_('Couldn\'t update your design.')); + return; + } + + // update design + } else { + + $user->query('BEGIN'); + + // save new design + $design = new Design(); + + $design->backgroundcolor = $bgcolor->intValue(); + $design->contentcolor = $ccolor->intValue(); + $design->sidebarcolor = $sbcolor->intValue(); + $design->textcolor = $tcolor->intValue(); + $design->linkcolor = $lcolor->intValue(); + $design->backgroundimage = $filepath; + + $design->setDisposition($on, $off, $tile); + + $id = $design->insert(); + + if (empty($id)) { + common_log_db_error($id, 'INSERT', __FILE__); + $this->showForm(_('Unable to save your design settings!')); + return; + } + + $original = clone($user); + $user->design_id = $id; + $result = $user->update($original); + + if (empty($result)) { + common_log_db_error($original, 'UPDATE', __FILE__); + $this->showForm(_('Unable to save your design settings!')); + $user->query('ROLLBACK'); + return; + } + + $user->query('COMMIT'); + + } + + $this->saveBackgroundImage($design); + + $this->showForm(_('Design preferences saved.'), true); + } +} diff --git a/lib/groupdesignaction.php b/lib/groupdesignaction.php new file mode 100644 index 0000000000..bc95921f1b --- /dev/null +++ b/lib/groupdesignaction.php @@ -0,0 +1,87 @@ +. + * + * @category Action + * @package Laconica + * @author Zach Copley + * @copyright 2009 Control Yourself, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://laconi.ca/ + */ + +if (!defined('LACONICA')) { + exit(1); +} + +/** + * Base class for actions that use a group's design + * + * Pages related to groups can be themed with a design. + * This superclass returns that design. + * + * @category Action + * @package Laconica + * @author Zach Copley + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://laconi.ca/ + * + */ +class GroupDesignAction extends Action { + + /** The group in question */ + var $group = null; + + /** + * Show the groups's design stylesheet + * + * @return nothing + */ + function showStylesheets() + { + parent::showStylesheets(); + + $design = $this->getDesign(); + + if (!empty($design)) { + $design->showCSS($this); + } + } + + /** + * A design for this action + * + * if the group attribute has been set, returns that group's + * design. + * + * @return Design a design object to use + */ + + function getDesign() + { + + if (empty($this->group)) { + return null; + } + + return $this->group->getDesign(); + } + +} From 65b4cfbb54f5b44820dd02bb9c3c2ca98dbbd321 Mon Sep 17 00:00:00 2001 From: Robin Millette Date: Thu, 18 Jun 2009 06:02:12 -0400 Subject: [PATCH 134/262] Display more oembed info in attachment popup. --- lib/attachmentlist.php | 36 ++++++++++++++++++++++++++++++++++++ theme/base/css/display.css | 6 ++++++ 2 files changed, 42 insertions(+) diff --git a/lib/attachmentlist.php b/lib/attachmentlist.php index 45e4fa3196..a781c3092c 100644 --- a/lib/attachmentlist.php +++ b/lib/attachmentlist.php @@ -244,6 +244,42 @@ class AttachmentListItem extends Widget class Attachment extends AttachmentListItem { + function showLink() { + $this->out->elementStart('a', $this->linkAttr()); + $this->out->element('span', null, $this->linkTitle()); + $this->showRepresentation(); + $this->out->elementEnd('a'); + + if (empty($this->oembed->author_name) && empty($this->oembed->provider)) { + return; + } + + $this->out->elementStart('dl', 'oembed_info'); + + if (!empty($this->oembed->author_name)) { + $this->out->element('dt', null, _('Author:')); + + $this->out->elementStart('dd'); + if (empty($this->oembed->author_url)) { + $this->out->text($this->oembed->author_name); + } else { + $this->out->element('a', array('href' => $this->oembed->author_url), $this->oembed->author_name); + } + $this->out->elementEnd('dd'); + } + if (!empty($this->oembed->provider)) { + $this->out->element('dt', null, _('Provider:')); + $this->out->elementStart('dd'); + if (empty($this->oembed->provider_url)) { + $this->out->text($this->oembed->provider); + } else { + $this->out->element('a', array('href' => $this->oembed->provider_url), $this->oembed->provider); + } + $this->out->elementEnd('dd'); + } + $this->out->elementEnd('dl'); + } + function show() { $this->showNoticeAttachment(); } diff --git a/theme/base/css/display.css b/theme/base/css/display.css index 9e35d015d1..dd787f5e29 100644 --- a/theme/base/css/display.css +++ b/theme/base/css/display.css @@ -1276,3 +1276,9 @@ display:none; .guide { clear:both; } + +dl.oembed_info dt, +dl.oembed_info dd { +display: inline; +} + From 65457e73bfc8fe04ad57acce7800cd7640f30e7e Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Thu, 18 Jun 2009 10:49:45 -0700 Subject: [PATCH 135/262] Config option for bidirectional Twitter bridge --- config.php.sample | 3 +++ 1 file changed, 3 insertions(+) diff --git a/config.php.sample b/config.php.sample index 7649c52623..5291641087 100644 --- a/config.php.sample +++ b/config.php.sample @@ -153,6 +153,9 @@ $config['sphinx']['port'] = 3312; // Twitter integration source attribute. Note: default is Laconica // $config['integration']['source'] = 'Laconica'; +// Enable bidirectional Twitter bridge +// $config['twitterbridge']['enabled'] = true; + // Edit throttling. Off by default. If turned on, you can only post 20 notices // every 10 minutes. Admins may want to play with the settings to minimize inconvenience for // real users without getting uncontrollable floods from spammers or runaway bots. From 3f54840b51d5565fdeb7057661ff730bc0e41833 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Thu, 18 Jun 2009 11:45:48 -0700 Subject: [PATCH 136/262] Only show twitter msgs in your own inbox --- actions/all.php | 8 +++++- actions/allrss.php | 8 ++++++ actions/facebookhome.php | 58 +++++++++++++++++++--------------------- classes/Notice.php | 2 ++ classes/Notice_inbox.php | 13 ++++++--- classes/User.php | 29 +++++++++++++++++++- 6 files changed, 81 insertions(+), 37 deletions(-) diff --git a/actions/all.php b/actions/all.php index 03179a2468..80fc9d54b0 100644 --- a/actions/all.php +++ b/actions/all.php @@ -98,7 +98,13 @@ class AllAction extends ProfileAction function showContent() { - $notice = $this->user->noticesWithFriends(($this->page-1)*NOTICES_PER_PAGE, NOTICES_PER_PAGE + 1); + $cur = common_current_user(); + + if (!empty($cur) && $cur->id == $this->user->id) { + $notice = $this->user->noticeInbox(($this->page-1)*NOTICES_PER_PAGE, NOTICES_PER_PAGE + 1); + } else { + $notice = $this->user->noticesWithFriends(($this->page-1)*NOTICES_PER_PAGE, NOTICES_PER_PAGE + 1); + } $nl = new NoticeList($notice, $this); diff --git a/actions/allrss.php b/actions/allrss.php index 45f3946a61..88a4745c9e 100644 --- a/actions/allrss.php +++ b/actions/allrss.php @@ -81,6 +81,14 @@ class AllrssAction extends Rss10Action */ function getNotices($limit=0) { + $cur = common_current_user(); + + if (!empty($cur) && $cur->id == $user->id) { + $notice = $this->user->noticeInbox(0, $limit); + } else { + $notice = $this->user->noticesWithFriends(0, $limit); + } + $user = $this->user; $notice = $user->noticesWithFriends(0, $limit); $notices = array(); diff --git a/actions/facebookhome.php b/actions/facebookhome.php index 00b35ef686..f74b786d10 100644 --- a/actions/facebookhome.php +++ b/actions/facebookhome.php @@ -21,29 +21,28 @@ if (!defined('LACONICA')) { exit(1); } require_once INSTALLDIR.'/lib/facebookaction.php'; - class FacebookhomeAction extends FacebookAction { var $page = null; - + function prepare($argarray) - { + { parent::prepare($argarray); - + $this->page = $this->trimmed('page'); - + if (!$this->page) { $this->page = 1; } - + return true; } function handle($args) { - parent::handle($args); - + parent::handle($args); + // If the user has opted not to initially allow the app to have // Facebook status update permission, store that preference. Only // promt the user the first time she uses the app @@ -73,7 +72,7 @@ class FacebookhomeAction extends FacebookAction $this->updateProfileBox($notice); } - if ($this->arg('status_submit') == 'Send') { + if ($this->arg('status_submit') == 'Send') { $this->saveNewNotice(); } @@ -81,7 +80,7 @@ class FacebookhomeAction extends FacebookAction // Facebook status update permission? Then show the main page // of the app $this->showPage(); - + } else { // User hasn't authenticated yet, prompt for creds @@ -89,12 +88,12 @@ class FacebookhomeAction extends FacebookAction } } - + function login() { - + $this->showStylesheets(); - + $nickname = common_canonical_nickname($this->trimmed('nickname')); $password = $this->arg('password'); @@ -141,13 +140,12 @@ class FacebookhomeAction extends FacebookAction $this->facebook->api_client->data_setUserPreference( FACEBOOK_PROMPTED_UPDATE_PREF, 'false'); } - function showNoticeForm() { $post_action = "$this->app_uri/index.php"; - - $notice_form = new FacebookNoticeForm($this, $post_action, null, + + $notice_form = new FacebookNoticeForm($this, $post_action, null, $post_action, $this->user); $notice_form->show(); } @@ -163,9 +161,8 @@ class FacebookhomeAction extends FacebookAction function showContent() { - $notice = $this->user->noticesWithFriends(($this->page-1) * - NOTICES_PER_PAGE, NOTICES_PER_PAGE + 1); - + $notice = $this->user->noticeInbox(($this->page-1) * NOTICES_PER_PAGE, NOTICES_PER_PAGE + 1); + $nl = new NoticeList($notice, $this); $cnt = $nl->show(); @@ -176,7 +173,7 @@ class FacebookhomeAction extends FacebookAction function showNoticeList($notice) { - + $nl = new NoticeList($notice, $this); return $nl->show(); } @@ -201,16 +198,16 @@ class FacebookhomeAction extends FacebookAction $this->elementStart('ul', array('id' => 'fb-permissions-list')); $this->elementStart('li', array('id' => 'fb-permissions-item')); - + $next = urlencode("$this->app_uri/index.php"); $api_key = common_config('facebook', 'apikey'); - + $auth_url = 'http://www.facebook.com/authorize.php?api_key=' . - $api_key . '&v=1.0&ext_perm=status_update&next=' . $next . + $api_key . '&v=1.0&ext_perm=status_update&next=' . $next . '&next_cancel=' . $next . '&submit=skip'; - + $this->elementStart('span', array('class' => 'facebook-button')); - $this->element('a', array('href' => $auth_url), + $this->element('a', array('href' => $auth_url), sprintf(_('Okay, do it!'), $this->app_name)); $this->elementEnd('span'); @@ -225,7 +222,7 @@ class FacebookhomeAction extends FacebookAction $this->elementEnd('div'); } - + /** * Generate pagination links * @@ -239,11 +236,11 @@ class FacebookhomeAction extends FacebookAction */ function pagination($have_before, $have_after, $page, $action, $args=null) { - + // Does a little before-after block for next/prev page - + // XXX: Fix so this uses common_local_url() if possible. - + if ($have_before || $have_after) { $this->elementStart('div', array('class' => 'pagination')); $this->elementStart('dl', null); @@ -254,7 +251,7 @@ class FacebookhomeAction extends FacebookAction if ($have_before) { $pargs = array('page' => $page-1); $newargs = $args ? array_merge($args, $pargs) : $pargs; - $this->elementStart('li', array('class' => 'nav_prev')); + $this->elementStart('li', array('class' => 'nav_prev')); $this->element('a', array('href' => "$action?page=$newargs[page]", 'rel' => 'prev'), _('After')); $this->elementEnd('li'); @@ -274,6 +271,5 @@ class FacebookhomeAction extends FacebookAction $this->elementEnd('div'); } } - } diff --git a/classes/Notice.php b/classes/Notice.php index e621805dfc..93a1a1a4dd 100644 --- a/classes/Notice.php +++ b/classes/Notice.php @@ -406,8 +406,10 @@ class Notice extends Memcached_DataObject while ($user->fetch()) { $cache->delete(common_cache_key('notice_inbox:by_user:'.$user->id)); + $cache->delete(common_cache_key('notice_inbox:by_user_own:'.$user->id)); if ($blowLast) { $cache->delete(common_cache_key('notice_inbox:by_user:'.$user->id.';last')); + $cache->delete(common_cache_key('notice_inbox:by_user_own:'.$user->id.';last')); } } $user->free(); diff --git a/classes/Notice_inbox.php b/classes/Notice_inbox.php index 367a35f1f7..4ca2e9ae3c 100644 --- a/classes/Notice_inbox.php +++ b/classes/Notice_inbox.php @@ -47,20 +47,25 @@ class Notice_inbox extends Memcached_DataObject /* the code above is auto generated do not remove the tag below */ ###END_AUTOCODE - function stream($user_id, $offset, $limit, $since_id, $max_id, $since) + function stream($user_id, $offset, $limit, $since_id, $max_id, $since, $own=false) { return Notice::stream(array('Notice_inbox', '_streamDirect'), - array($user_id), - 'notice_inbox:by_user:'.$user_id, + array($user_id, $own), + ($own) ? 'notice_inbox:by_user:'.$user_id : + 'notice_inbox:by_user_own:'.$user_id, $offset, $limit, $since_id, $max_id, $since); } - function _streamDirect($user_id, $offset, $limit, $since_id, $max_id, $since) + function _streamDirect($user_id, $own, $offset, $limit, $since_id, $max_id, $since) { $inbox = new Notice_inbox(); $inbox->user_id = $user_id; + if (!$own) { + $inbox->whereAdd('source != ' . NOTICE_INBOX_SOURCE_GATEWAY); + } + if ($since_id != 0) { $inbox->whereAdd('notice_id > ' . $since_id); } diff --git a/classes/User.php b/classes/User.php index c7eede94e1..e8c8c5a75b 100644 --- a/classes/User.php +++ b/classes/User.php @@ -437,6 +437,33 @@ class User extends Memcached_DataObject // Complicated code, depending on whether we support inboxes yet // XXX: make this go away when inboxes become mandatory + if ($enabled === false || + ($enabled == 'transitional' && $this->inboxed == 0)) { + $qry = + 'SELECT notice.* ' . + 'FROM notice JOIN subscription ON notice.profile_id = subscription.subscribed ' . + 'WHERE subscription.subscriber = %d ' . + 'AND notice.is_local != ' . NOTICE_GATEWAY; + return Notice::getStream(sprintf($qry, $this->id), + 'user:notices_with_friends:' . $this->id, + $offset, $limit, $since_id, $before_id, + $order, $since); + } else if ($enabled === true || + ($enabled == 'transitional' && $this->inboxed == 1)) { + + $ids = Notice_inbox::stream($this->id, $offset, $limit, $since_id, $before_id, $since, false); + + return Notice::getStreamByIds($ids); + } + } + + function noticeInbox($offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $before_id=0, $since=null) + { + $enabled = common_config('inboxes', 'enabled'); + + // Complicated code, depending on whether we support inboxes yet + // XXX: make this go away when inboxes become mandatory + if ($enabled === false || ($enabled == 'transitional' && $this->inboxed == 0)) { $qry = @@ -450,7 +477,7 @@ class User extends Memcached_DataObject } else if ($enabled === true || ($enabled == 'transitional' && $this->inboxed == 1)) { - $ids = Notice_inbox::stream($this->id, $offset, $limit, $since_id, $before_id, $since); + $ids = Notice_inbox::stream($this->id, $offset, $limit, $since_id, $before_id, $since, true); return Notice::getStreamByIds($ids); } From 730c173238841cdc4d52bb074e53d4a74f7871bf Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Thu, 18 Jun 2009 18:48:19 +0000 Subject: [PATCH 137/262] Updated markup and CSS for attachment_view --- lib/attachmentlist.php | 60 +++++++++++++++++++++----------------- theme/base/css/display.css | 22 ++++++++++---- 2 files changed, 50 insertions(+), 32 deletions(-) diff --git a/lib/attachmentlist.php b/lib/attachmentlist.php index c80c0c418f..7bd441bf4d 100644 --- a/lib/attachmentlist.php +++ b/lib/attachmentlist.php @@ -210,7 +210,7 @@ class AttachmentListItem extends Widget function showRepresentation() { $thumbnail = File_thumbnail::staticGet('file_id', $this->attachment->id); if (!empty($thumbnail)) { - $this->out->element('img', array('alt' => 'nothing to say', 'src' => $thumbnail->url, 'width' => $thumbnail->width, 'height' => $thumbnail->height)); + $this->out->element('img', array('alt' => '', 'src' => $thumbnail->url, 'width' => $thumbnail->width, 'height' => $thumbnail->height)); } } @@ -244,39 +244,47 @@ class AttachmentListItem extends Widget class Attachment extends AttachmentListItem { function showLink() { + $this->out->elementStart('div', array('id' => 'attachment_view', + 'class' => 'hentry')); + $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->out->elementEnd('div'); - if (empty($this->oembed->author_name) && empty($this->oembed->provider)) { - return; - } - - $this->out->elementStart('dl', 'oembed_info'); - - if (!empty($this->oembed->author_name)) { - $this->out->element('dt', null, _('Author:')); - - $this->out->elementStart('dd'); - if (empty($this->oembed->author_url)) { - $this->out->text($this->oembed->author_name); - } else { - $this->out->element('a', array('href' => $this->oembed->author_url), $this->oembed->author_name); + if ($this->oembed->author_name || $this->oembed->provider) { + $this->out->elementStart('div', array('id' => 'oembed_info', + 'class' => 'entry-content')); + if (!empty($this->oembed->author_name)) { + $this->out->elementStart('dl', 'vcard author'); + $this->out->element('dt', null, _('Author')); + $this->out->elementStart('dd', 'fn'); + if (empty($this->oembed->author_url)) { + $this->out->text($this->oembed->author_name); + } else { + $this->out->element('a', array('href' => $this->oembed->author_url, + 'class' => 'url'), $this->oembed->author_name); + } + $this->out->elementEnd('dd'); + $this->out->elementEnd('dl'); } - $this->out->elementEnd('dd'); - } - if (!empty($this->oembed->provider)) { - $this->out->element('dt', null, _('Provider:')); - $this->out->elementStart('dd'); - if (empty($this->oembed->provider_url)) { - $this->out->text($this->oembed->provider); - } else { - $this->out->element('a', array('href' => $this->oembed->provider_url), $this->oembed->provider); + if (!empty($this->oembed->provider)) { + $this->out->elementStart('dl', 'vcard'); + $this->out->element('dt', null, _('Provider')); + $this->out->elementStart('dd', 'fn'); + if (empty($this->oembed->provider_url)) { + $this->out->text($this->oembed->provider); + } else { + $this->out->element('a', array('href' => $this->oembed->provider_url, + 'class' => 'url'), $this->oembed->provider); + } + $this->out->elementEnd('dd'); + $this->out->elementEnd('dl'); } - $this->out->elementEnd('dd'); + $this->out->elementEnd('div'); } - $this->out->elementEnd('dl'); + $this->out->elementEnd('div'); } function show() { diff --git a/theme/base/css/display.css b/theme/base/css/display.css index daf5ada1c5..8957a5b401 100644 --- a/theme/base/css/display.css +++ b/theme/base/css/display.css @@ -1018,6 +1018,22 @@ border-radius:7px; -webkit-border-radius:7px; } +#attachment_view #oembed_info { +margin-top:11px; +} +#attachment_view #oembed_info dt, +#attachment_view #oembed_info dd { +float:left; +} +#attachment_view #oembed_info dt { +clear:left; +margin-right:11px; +font-weight:bold; +} +#attachment_view #oembed_info dt:after { +content: ":"; +} + #usergroups #new_group { float: left; margin-right: 2em; @@ -1284,9 +1300,3 @@ display:none; .guide { clear:both; } - -dl.oembed_info dt, -dl.oembed_info dd { -display: inline; -} - From 23d6d19e75f273bf6e72fbcbbf8e6789f77d07ff Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Thu, 18 Jun 2009 19:03:44 +0000 Subject: [PATCH 138/262] Better attachment view check --- lib/attachmentlist.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/attachmentlist.php b/lib/attachmentlist.php index 7bd441bf4d..a2446a886a 100644 --- a/lib/attachmentlist.php +++ b/lib/attachmentlist.php @@ -253,7 +253,7 @@ class Attachment extends AttachmentListItem $this->out->elementEnd('a'); $this->out->elementEnd('div'); - if ($this->oembed->author_name || $this->oembed->provider) { + if (!empty($this->oembed->author_name) || !empty($this->oembed->provider)) { $this->out->elementStart('div', array('id' => 'oembed_info', 'class' => 'entry-content')); if (!empty($this->oembed->author_name)) { From e0fb15c185f4ca81743937c27557c9402ba59071 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Thu, 18 Jun 2009 19:19:19 +0000 Subject: [PATCH 139/262] Make sure we have a DB connection before setting its charset --- classes/Memcached_DataObject.php | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/classes/Memcached_DataObject.php b/classes/Memcached_DataObject.php index 33ac70dd04..f945e94ff3 100644 --- a/classes/Memcached_DataObject.php +++ b/classes/Memcached_DataObject.php @@ -242,13 +242,16 @@ class Memcached_DataObject extends DB_DataObject if (common_config('db', 'type') == 'mysql' && common_config('db', 'utf8')) { $conn = $DB->connection; - if ($DB instanceof DB_mysqli) { - mysqli_set_charset($conn, 'utf8'); - } else if ($DB instanceof DB_mysql) { - mysql_set_charset('utf8', $conn); + if (!empty($conn)) { + if ($DB instanceof DB_mysqli) { + mysqli_set_charset($conn, 'utf8'); + } else if ($DB instanceof DB_mysql) { + mysql_set_charset('utf8', $conn); + } } } } return $result; } + } From 597df6a2345ad61e7e0f21277d97866bdb2116a4 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Thu, 18 Jun 2009 16:19:26 -0700 Subject: [PATCH 140/262] better calculation of path --- lib/common.php | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/lib/common.php b/lib/common.php index eb8a2b8736..702da82351 100644 --- a/lib/common.php +++ b/lib/common.php @@ -55,13 +55,25 @@ require_once(INSTALLDIR.'/lib/language.php'); require_once(INSTALLDIR.'/lib/event.php'); require_once(INSTALLDIR.'/lib/plugin.php'); +function _sn_to_path($sn) +{ + $past_root = substr($sn, 1); + $last_slash = strrpos($past_root, '/'); + if ($last_slash > 0) { + $p = substr($past_root, 0, $last_slash); + } else { + $p = ''; + } + return $p; +} + // try to figure out where we are $_server = array_key_exists('SERVER_NAME', $_SERVER) ? strtolower($_SERVER['SERVER_NAME']) : null; $_path = array_key_exists('SCRIPT_NAME', $_SERVER) ? - substr($_SERVER['SCRIPT_NAME'], 1, strrpos($_SERVER['SCRIPT_NAME'], '/') - 1) : + _sn_to_path($_SERVER['SCRIPT_NAME']) : null; // default configuration, overwritten in config.php From 5d3e47e501bffb30d90d648263c78ef22b047a40 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Thu, 18 Jun 2009 16:21:03 -0700 Subject: [PATCH 141/262] remove path from install; better autodetection now --- install.php | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/install.php b/install.php index 133f2b30f6..7ceae44609 100644 --- a/install.php +++ b/install.php @@ -36,7 +36,7 @@ function main() function checkPrereqs() { $pass = true; - + if (file_exists(INSTALLDIR.'/config.php')) { ?>

Config file "config.php" already exists.

@@ -116,11 +115,6 @@ function showForm() disable

Enable fancy (pretty) URLs. Auto-detection failed, it depends on Javascript.

-
  • - - -

    Site path, following the "/" after the domain name in the URL. Empty is fine. Field should be filled automatically.

    -
  • @@ -167,7 +161,6 @@ function handlePost() $username = $_POST['username']; $password = $_POST['password']; $sitename = $_POST['sitename']; - $path = $_POST['path']; $fancy = !empty($_POST['fancy']); ?>
    @@ -176,7 +169,7 @@ function handlePost()
      "); return $res; From e506f82cdf8d88186c425a3f58e15b5126fdb248 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Thu, 18 Jun 2009 16:51:06 -0700 Subject: [PATCH 142/262] Better avatar handling - pull in any missing Twitter avatars --- config.php.sample | 3 +++ scripts/twitterstatusfetcher.php | 23 ++++++++++++++++++++--- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/config.php.sample b/config.php.sample index 5291641087..d42bac9a69 100644 --- a/config.php.sample +++ b/config.php.sample @@ -154,6 +154,9 @@ $config['sphinx']['port'] = 3312; // $config['integration']['source'] = 'Laconica'; // Enable bidirectional Twitter bridge +// +// NOTE: if you enable this you must also set $config['avatar']['path'] +// // $config['twitterbridge']['enabled'] = true; // Edit throttling. Off by default. If turned on, you can only post 20 notices diff --git a/scripts/twitterstatusfetcher.php b/scripts/twitterstatusfetcher.php index 9287b6d733..93a4ce92b7 100755 --- a/scripts/twitterstatusfetcher.php +++ b/scripts/twitterstatusfetcher.php @@ -38,6 +38,9 @@ define('SCRIPT_DEBUG', true); require_once(INSTALLDIR . '/lib/common.php'); require_once(INSTALLDIR . '/lib/daemon.php'); +// NOTE: an Avatar path MUST be set in config.php for this +// script to work: e.g.: $config['avatar']['path'] = '/laconica/avatar'; + class TwitterStatusFetcher extends Daemon { @@ -358,11 +361,11 @@ class TwitterStatusFetcher extends Daemon $oldname = $profile->getAvatar(48)->filename; - if ($newname != $oldname) { + if ($newname != $oldname || $this->missingAvatarFile($profile)) { if (defined('SCRIPT_DEBUG')) { common_debug('Avatar for Twitter user ' . - "$profile->nickname has changed."); + "$profile->nickname has changed, or was missing locally."); common_debug("old: $oldname new: $newname"); } @@ -383,6 +386,21 @@ class TwitterStatusFetcher extends Daemon } } + function missingAvatarFile($profile) { + + foreach (array(24, 48, 73) as $size) { + + $filename = $profile->getAvatar($size)->filename; + $avatarpath = Avatar::path($filename); + + if (file_exists($avatarpath) == FALSE) { + return true; + } + } + + return false; + } + function getMediatype($ext) { $mediatype = null; @@ -447,7 +465,6 @@ class TwitterStatusFetcher extends Daemon if (defined('SCRIPT_DEBUG')) { common_debug("Deleting $size avatar for $profile->nickname."); } - @unlink(INSTALLDIR . '/avatar/' . $avatar->filename); $avatar->delete(); } From cb0047b1442d8a5303abdb11cddcdd2a77b8ad8e Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Thu, 18 Jun 2009 19:21:17 -0700 Subject: [PATCH 143/262] This time, twitterstatusfetcher really DOES update changed and missing avatars! --- scripts/twitterstatusfetcher.php | 61 +++++++++++++++++++++----------- 1 file changed, 40 insertions(+), 21 deletions(-) diff --git a/scripts/twitterstatusfetcher.php b/scripts/twitterstatusfetcher.php index 93a4ce92b7..88605c3491 100755 --- a/scripts/twitterstatusfetcher.php +++ b/scripts/twitterstatusfetcher.php @@ -351,38 +351,59 @@ class TwitterStatusFetcher extends Daemon } } - function checkAvatar($user, $profile) + function checkAvatar($twitter_user, $profile) { global $config; - $path_parts = pathinfo($user->profile_image_url); - $newname = 'Twitter_' . $user->id . '_' . + $path_parts = pathinfo($twitter_user->profile_image_url); + + $newname = 'Twitter_' . $twitter_user->id . '_' . $path_parts['basename']; $oldname = $profile->getAvatar(48)->filename; - if ($newname != $oldname || $this->missingAvatarFile($profile)) { + if ($newname != $oldname) { if (defined('SCRIPT_DEBUG')) { common_debug('Avatar for Twitter user ' . - "$profile->nickname has changed, or was missing locally."); + "$profile->nickname has changed."); common_debug("old: $oldname new: $newname"); } - $img_root = substr($path_parts['basename'], 0, -11); - $ext = $path_parts['extension']; - $mediatype = $this->getMediatype($ext); + $this->updateAvatars($twitter_user, $profile); + } - foreach (array('mini', 'normal', 'bigger') as $size) { - $url = $path_parts['dirname'] . '/' . - $img_root . '_' . $size . ".$ext"; - $filename = 'Twitter_' . $user->id . '_' . - $img_root . "_$size.$ext"; + if ($this->missingAvatarFile($profile)) { - if ($this->fetchAvatar($url, $filename)) { - $this->updateAvatar($profile->id, $size, $mediatype, $filename); - } + if (defined('SCRIPT_DEBUG')) { + common_debug('Twitter user ' . $profile->nickname . + ' is missing one or more local avatars.'); + common_debug("old: $oldname new: $newname"); } + + $this->updateAvatars($twitter_user, $profile); + } + + } + + function updateAvatars($twitter_user, $profile) { + + global $config; + + $path_parts = pathinfo($twitter_user->profile_image_url); + + $img_root = substr($path_parts['basename'], 0, -11); + $ext = $path_parts['extension']; + $mediatype = $this->getMediatype($ext); + + foreach (array('mini', 'normal', 'bigger') as $size) { + $url = $path_parts['dirname'] . '/' . + $img_root . '_' . $size . ".$ext"; + $filename = 'Twitter_' . $twitter_user->id . '_' . + $img_root . "_$size.$ext"; + + $this->updateAvatar($profile->id, $size, $mediatype, $filename); + $this->fetchAvatar($url, $filename); } } @@ -451,7 +472,7 @@ class TwitterStatusFetcher extends Daemon $profile = Profile::staticGet($profile_id); - if (!$profile) { + if (empty($profile)) { if (defined('SCRIPT_DEBUG')) { common_debug("Couldn't get profile: $profile_id!"); } @@ -461,10 +482,8 @@ class TwitterStatusFetcher extends Daemon $sizes = array('mini' => 24, 'normal' => 48, 'bigger' => 73); $avatar = $profile->getAvatar($sizes[$size]); + // Delete the avatar, if present if ($avatar) { - if (defined('SCRIPT_DEBUG')) { - common_debug("Deleting $size avatar for $profile->nickname."); - } $avatar->delete(); } @@ -509,7 +528,7 @@ class TwitterStatusFetcher extends Daemon $id = $avatar->insert(); - if (!$id) { + if (empty($id)) { common_log_db_error($avatar, 'INSERT', __FILE__); return null; } From 1c2cf108118b3d5cfebd0e266099505810e6d850 Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Fri, 19 Jun 2009 15:54:24 +0000 Subject: [PATCH 144/262] Includes a sioc:reply_to link between notices. It helps with things like http://danbri.org/words/2009/06/16/415 Thanks to Toby Inkster for the patch: http://buzzword.org.uk/2009/laconica-0.7.3-sioc-reply_to.patch --- lib/rssaction.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/rssaction.php b/lib/rssaction.php index eafdbf131d..08b333d974 100644 --- a/lib/rssaction.php +++ b/lib/rssaction.php @@ -212,6 +212,11 @@ class Rss10Action extends Action $this->element('sioc:has_creator', array('rdf:resource' => $creator_uri.'#acct')); $this->element('laconica:postIcon', array('rdf:resource' => $profile->avatarUrl())); $this->element('cc:licence', array('rdf:resource' => common_config('license', 'url'))); + if ($notice->reply_to) { + $replyurl = common_local_url('shownotice', + array('notice' => $notice->reply_to)); + $this->element('sioc:reply_to', array('rdf:resource' => $replyurl)); + } $this->elementEnd('item'); $this->creators[$creator_uri] = $profile; } From 9be54a3dcf6520781c1c64897a28cfaca6fd66fb Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Fri, 19 Jun 2009 16:04:14 +0000 Subject: [PATCH 145/262] Minor indenting --- lib/rssaction.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/rssaction.php b/lib/rssaction.php index 08b333d974..6f6c9a8cb0 100644 --- a/lib/rssaction.php +++ b/lib/rssaction.php @@ -213,8 +213,7 @@ class Rss10Action extends Action $this->element('laconica:postIcon', array('rdf:resource' => $profile->avatarUrl())); $this->element('cc:licence', array('rdf:resource' => common_config('license', 'url'))); if ($notice->reply_to) { - $replyurl = common_local_url('shownotice', - array('notice' => $notice->reply_to)); + $replyurl = common_local_url('shownotice', array('notice' => $notice->reply_to)); $this->element('sioc:reply_to', array('rdf:resource' => $replyurl)); } $this->elementEnd('item'); From f5b24133cb63b8fd8ec2a989b77bd075dd77367f Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Fri, 19 Jun 2009 14:40:32 -0700 Subject: [PATCH 146/262] Add twitterstatusfetcher to the list of daemons to stop --- scripts/stopdaemons.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/stopdaemons.sh b/scripts/stopdaemons.sh index 2134b4ab00..9f1696bf28 100755 --- a/scripts/stopdaemons.sh +++ b/scripts/stopdaemons.sh @@ -24,7 +24,8 @@ SDIR=`dirname $0` DIR=`php $SDIR/getpiddir.php` for f in jabberhandler ombhandler publichandler smshandler pinghandler \ - xmppconfirmhandler xmppdaemon twitterhandler facebookhandler; do + xmppconfirmhandler xmppdaemon twitterhandler facebookhandler \ + twitterstatusfetcher; do FILES="$DIR/$f.*.pid" for ff in "$FILES" ; do From b8f3f32f3f12339c3838fcfc883815d63a36dca7 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Fri, 19 Jun 2009 20:21:57 -0700 Subject: [PATCH 147/262] Keep Twitter gateway notices from leaking thru MySQL notice search --- lib/search_engines.php | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/lib/search_engines.php b/lib/search_engines.php index 7b9dbb6182..0f405afbd3 100644 --- a/lib/search_engines.php +++ b/lib/search_engines.php @@ -118,12 +118,20 @@ class MySQLSearch extends SearchEngine } return true; } else if ('identica_notices' === $this->table) { - $this->target->whereAdd('MATCH(content) ' . - 'AGAINST (\''.addslashes($q).'\' IN BOOLEAN MODE)'); + + // Don't show imported notices + $this->target->whereAdd('notice.is_local != ' . NOTICE_GATEWAY); + if (strtolower($q) != $q) { + $this->target->whereAdd("( MATCH(content) AGAINST ('" . addslashes($q) . + "' IN BOOLEAN MODE)) OR ( MATCH(content) " . + "AGAINST ('" . addslashes(strtolower($q)) . + "' IN BOOLEAN MODE))"); + } else { $this->target->whereAdd('MATCH(content) ' . - 'AGAINST (\''.addslashes(strtolower($q)).'\' IN BOOLEAN MODE)', 'OR'); + 'AGAINST (\''.addslashes($q).'\' IN BOOLEAN MODE)'); } + return true; } else { throw new ServerException('Unknown table: ' . $this->table); @@ -138,6 +146,9 @@ class PGSearch extends SearchEngine if ('identica_people' === $this->table) { return $this->target->whereAdd('textsearch @@ plainto_tsquery(\''.addslashes($q).'\')'); } else if ('identica_notices' === $this->table) { + + // XXX: We need to filter out gateway notices (notice.is_local = -2) --Zach + return $this->target->whereAdd('to_tsvector(\'english\', content) @@ plainto_tsquery(\''.addslashes($q).'\')'); } else { throw new ServerException('Unknown table: ' . $this->table); From 054e4459b2b2701158cd183dc1eb04c454e04bff Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Sat, 20 Jun 2009 18:22:05 +0000 Subject: [PATCH 148/262] Position of max_file_size position helps IE --- lib/noticeform.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/noticeform.php b/lib/noticeform.php index a36b7f31f7..4e2a2edd61 100644 --- a/lib/noticeform.php +++ b/lib/noticeform.php @@ -151,12 +151,12 @@ class NoticeForm extends Form '140'); $this->out->elementEnd('dl'); if (common_config('attachments', 'uploads')) { - $this->out->hidden('MAX_FILE_SIZE', common_config('attachments', 'file_quota')); $this->out->element('label', array('for' => 'notice_data-attach'),_('Attach')); $this->out->element('input', array('id' => 'notice_data-attach', 'type' => 'file', 'name' => 'attach', 'title' => _('Attach a file'))); + $this->out->hidden('MAX_FILE_SIZE', common_config('attachments', 'file_quota')); } if ($this->action) { $this->out->hidden('notice_return-to', $this->action, 'returnto'); From 198afa0a1d61c4db2cf6b66e5801af506462ab9b Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sat, 20 Jun 2009 14:58:47 -0700 Subject: [PATCH 149/262] change scripts to take server and path from commandline --- lib/common.php | 25 ++++++++++++++++++------- scripts/enjitqueuehandler.php | 14 ++++++++------ scripts/facebookqueuehandler.php | 11 ++++++++--- scripts/jabberqueuehandler.php | 5 +++++ scripts/maildaemon.php | 6 +++++- scripts/ombqueuehandler.php | 11 ++++++++--- scripts/pingqueuehandler.php | 5 +++++ scripts/publicqueuehandler.php | 9 +++++++-- scripts/smsqueuehandler.php | 9 +++++++-- scripts/synctwitterfriends.php | 5 +++++ scripts/triminboxes.php | 9 +++++++-- scripts/twitterqueuehandler.php | 11 ++++++++--- scripts/twitterstatusfetcher.php | 7 ++++++- scripts/xmppconfirmhandler.php | 9 +++++++-- scripts/xmppdaemon.php | 6 +++++- 15 files changed, 109 insertions(+), 33 deletions(-) diff --git a/lib/common.php b/lib/common.php index 702da82351..17eed71cdb 100644 --- a/lib/common.php +++ b/lib/common.php @@ -67,14 +67,25 @@ function _sn_to_path($sn) return $p; } -// try to figure out where we are +// try to figure out where we are. $server and $path +// can be set by including module, else we guess based +// on HTTP info. -$_server = array_key_exists('SERVER_NAME', $_SERVER) ? - strtolower($_SERVER['SERVER_NAME']) : - null; -$_path = array_key_exists('SCRIPT_NAME', $_SERVER) ? - _sn_to_path($_SERVER['SCRIPT_NAME']) : - null; +if (isset($server)) { + $_server = $server; +} else { + $_server = array_key_exists('SERVER_NAME', $_SERVER) ? + strtolower($_SERVER['SERVER_NAME']) : + null; +} + +if (isset($path)) { + $_path = $path; +} else { + $_path = array_key_exists('SCRIPT_NAME', $_SERVER) ? + _sn_to_path($_SERVER['SCRIPT_NAME']) : + null; +} // default configuration, overwritten in config.php diff --git a/scripts/enjitqueuehandler.php b/scripts/enjitqueuehandler.php index 40f60da5d8..37fef0b04d 100755 --- a/scripts/enjitqueuehandler.php +++ b/scripts/enjitqueuehandler.php @@ -27,6 +27,11 @@ if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) { define('INSTALLDIR', realpath(dirname(__FILE__) . '/..')); define('LACONICA', true); +// Preset the server at the command line + +$server = ($argc > 2) ? $argv[2] : null; +$path = ($argc > 3) ? $argv[3] : null; + require_once(INSTALLDIR . '/lib/common.php'); require_once(INSTALLDIR . '/lib/mail.php'); require_once(INSTALLDIR . '/lib/queuehandler.php'); @@ -35,7 +40,6 @@ set_error_handler('common_error_handler'); class EnjitQueueHandler extends QueueHandler { - function transport() { return 'enjit'; @@ -60,7 +64,6 @@ class EnjitQueueHandler extends QueueHandler return "skipped"; } - # # Build an Atom message from the notice # @@ -93,8 +96,8 @@ class EnjitQueueHandler extends QueueHandler $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); - - curl_setopt($ch, CURLOPT_HEADER, 1); + + curl_setopt($ch, CURLOPT_HEADER, 1); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_POST, 1) ; curl_setopt($ch, CURLOPT_POSTFIELDS, $data); @@ -103,7 +106,7 @@ class EnjitQueueHandler extends QueueHandler # # curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); # curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0); - # curl_setopt($ch, CURLOPT_VERBOSE, 1); + # curl_setopt($ch, CURLOPT_VERBOSE, 1); $result = curl_exec($ch); @@ -115,7 +118,6 @@ class EnjitQueueHandler extends QueueHandler return $code; } - } diff --git a/scripts/facebookqueuehandler.php b/scripts/facebookqueuehandler.php index c6859cb219..c24a225964 100755 --- a/scripts/facebookqueuehandler.php +++ b/scripts/facebookqueuehandler.php @@ -27,6 +27,11 @@ if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) { define('INSTALLDIR', realpath(dirname(__FILE__) . '/..')); define('LACONICA', true); +// Preset the server at the command line + +$server = ($argc > 2) ? $argv[2] : null; +$path = ($argc > 3) ? $argv[3] : null; + require_once(INSTALLDIR . '/lib/common.php'); require_once(INSTALLDIR . '/lib/facebookutil.php'); require_once(INSTALLDIR . '/lib/queuehandler.php'); @@ -35,12 +40,12 @@ set_error_handler('common_error_handler'); class FacebookQueueHandler extends QueueHandler { - + function transport() { return 'facebook'; } - + function start() { $this->log(LOG_INFO, "INITIALIZE"); @@ -51,7 +56,7 @@ class FacebookQueueHandler extends QueueHandler { return facebookBroadcastNotice($notice); } - + function finish() { } diff --git a/scripts/jabberqueuehandler.php b/scripts/jabberqueuehandler.php index 8b6e974c0a..454c67f7be 100755 --- a/scripts/jabberqueuehandler.php +++ b/scripts/jabberqueuehandler.php @@ -27,6 +27,11 @@ if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) { define('INSTALLDIR', realpath(dirname(__FILE__) . '/..')); define('LACONICA', true); +// Preset the server at the command line + +$server = ($argc > 2) ? $argv[2] : null; +$path = ($argc > 3) ? $argv[3] : null; + require_once(INSTALLDIR . '/lib/common.php'); require_once(INSTALLDIR . '/lib/jabber.php'); require_once(INSTALLDIR . '/lib/xmppqueuehandler.php'); diff --git a/scripts/maildaemon.php b/scripts/maildaemon.php index 9dd647bf46..0b9ab0deba 100755 --- a/scripts/maildaemon.php +++ b/scripts/maildaemon.php @@ -27,6 +27,11 @@ if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) { define('INSTALLDIR', realpath(dirname(__FILE__) . '/..')); define('LACONICA', true); +// Preset the server at the command line + +$server = ($argc > 1) ? $argv[1] : null; +$path = ($argc > 2) ? $argv[2] : null; + require_once(INSTALLDIR . '/lib/common.php'); require_once(INSTALLDIR . '/lib/mail.php'); require_once('Mail/mimeDecode.php'); @@ -36,7 +41,6 @@ require_once('Mail/mimeDecode.php'); class MailerDaemon { - function __construct() { } diff --git a/scripts/ombqueuehandler.php b/scripts/ombqueuehandler.php index cdcea51dc7..6abc6d7f1e 100755 --- a/scripts/ombqueuehandler.php +++ b/scripts/ombqueuehandler.php @@ -27,6 +27,11 @@ if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) { define('INSTALLDIR', realpath(dirname(__FILE__) . '/..')); define('LACONICA', true); +// Preset the server at the command line + +$server = ($argc > 2) ? $argv[2] : null; +$path = ($argc > 3) ? $argv[3] : null; + require_once(INSTALLDIR . '/lib/common.php'); require_once(INSTALLDIR . '/lib/omb.php'); require_once(INSTALLDIR . '/lib/queuehandler.php'); @@ -35,12 +40,12 @@ set_error_handler('common_error_handler'); class OmbQueueHandler extends QueueHandler { - + function transport() { return 'omb'; } - + function start() { $this->log(LOG_INFO, "INITIALIZE"); @@ -56,7 +61,7 @@ class OmbQueueHandler extends QueueHandler return omb_broadcast_remote_subscribers($notice); } } - + function finish() { } diff --git a/scripts/pingqueuehandler.php b/scripts/pingqueuehandler.php index ada6ecdba2..372c550f5d 100644 --- a/scripts/pingqueuehandler.php +++ b/scripts/pingqueuehandler.php @@ -27,6 +27,11 @@ if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) { define('INSTALLDIR', realpath(dirname(__FILE__) . '/..')); define('LACONICA', true); +// Preset the server at the command line + +$server = ($argc > 2) ? $argv[2] : null; +$path = ($argc > 3) ? $argv[3] : null; + require_once(INSTALLDIR . '/lib/common.php'); require_once(INSTALLDIR . '/lib/ping.php'); require_once(INSTALLDIR . '/lib/queuehandler.php'); diff --git a/scripts/publicqueuehandler.php b/scripts/publicqueuehandler.php index b0fa22d438..7e09454d1a 100755 --- a/scripts/publicqueuehandler.php +++ b/scripts/publicqueuehandler.php @@ -27,6 +27,11 @@ if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) { define('INSTALLDIR', realpath(dirname(__FILE__) . '/..')); define('LACONICA', true); +// Preset the server at the command line + +$server = ($argc > 2) ? $argv[2] : null; +$path = ($argc > 3) ? $argv[3] : null; + require_once(INSTALLDIR . '/lib/common.php'); require_once(INSTALLDIR . '/lib/jabber.php'); require_once(INSTALLDIR . '/lib/xmppqueuehandler.php'); @@ -35,12 +40,12 @@ set_error_handler('common_error_handler'); class PublicQueueHandler extends XmppQueueHandler { - + function transport() { return 'public'; } - + function handle_notice($notice) { try { diff --git a/scripts/smsqueuehandler.php b/scripts/smsqueuehandler.php index 38f2f11feb..ed6dbd2ad3 100755 --- a/scripts/smsqueuehandler.php +++ b/scripts/smsqueuehandler.php @@ -27,6 +27,11 @@ if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) { define('INSTALLDIR', realpath(dirname(__FILE__) . '/..')); define('LACONICA', true); +// Preset the server at the command line + +$server = ($argc > 2) ? $argv[2] : null; +$path = ($argc > 3) ? $argv[3] : null; + require_once(INSTALLDIR . '/lib/common.php'); require_once(INSTALLDIR . '/lib/mail.php'); require_once(INSTALLDIR . '/lib/queuehandler.php'); @@ -35,7 +40,7 @@ set_error_handler('common_error_handler'); class SmsQueueHandler extends QueueHandler { - + function transport() { return 'sms'; @@ -51,7 +56,7 @@ class SmsQueueHandler extends QueueHandler { return mail_broadcast_notice_sms($notice); } - + function finish() { } diff --git a/scripts/synctwitterfriends.php b/scripts/synctwitterfriends.php index bd08ba58d6..dea3f97006 100755 --- a/scripts/synctwitterfriends.php +++ b/scripts/synctwitterfriends.php @@ -30,6 +30,11 @@ define('LACONICA', true); // Uncomment this to get useful console output //define('SCRIPT_DEBUG', true); +// Preset the server at the command line + +$server = ($argc > 1) ? $argv[1] : null; +$path = ($argc > 2) ? $argv[2] : null; + require_once(INSTALLDIR . '/lib/common.php'); // Make a lockfile diff --git a/scripts/triminboxes.php b/scripts/triminboxes.php index 0d2eaeaf09..0d545b3263 100644 --- a/scripts/triminboxes.php +++ b/scripts/triminboxes.php @@ -32,6 +32,11 @@ mb_internal_encoding('UTF-8'); define('INSTALLDIR', realpath(dirname(__FILE__) . '/..')); define('LACONICA', true); +// Preset the server at the command line + +$server = ($argc > 2) ? $argv[2] : null; +$path = ($argc > 3) ? $argv[3] : null; + require_once(INSTALLDIR . '/lib/common.php'); $user = new User(); @@ -74,10 +79,10 @@ while ($user->fetch()) { $delay = 3.0 * ($finish - $start); print "Delaying $delay seconds..."; - + // Wait to let slaves catch up usleep($delay * 1000000); - + print "DONE.\n"; } diff --git a/scripts/twitterqueuehandler.php b/scripts/twitterqueuehandler.php index 7da4f1e20a..8c8a59d6a9 100755 --- a/scripts/twitterqueuehandler.php +++ b/scripts/twitterqueuehandler.php @@ -27,6 +27,11 @@ if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) { define('INSTALLDIR', realpath(dirname(__FILE__) . '/..')); define('LACONICA', true); +// Preset the server at the command line + +$server = ($argc > 2) ? $argv[2] : null; +$path = ($argc > 3) ? $argv[3] : null; + require_once(INSTALLDIR . '/lib/common.php'); require_once(INSTALLDIR . '/lib/twitter.php'); require_once(INSTALLDIR . '/lib/queuehandler.php'); @@ -35,12 +40,12 @@ set_error_handler('common_error_handler'); class TwitterQueueHandler extends QueueHandler { - + function transport() { return 'twitter'; } - + function start() { $this->log(LOG_INFO, "INITIALIZE"); @@ -51,7 +56,7 @@ class TwitterQueueHandler extends QueueHandler { return broadcast_twitter($notice); } - + function finish() { } diff --git a/scripts/twitterstatusfetcher.php b/scripts/twitterstatusfetcher.php index 20f42cef85..2863207b0a 100755 --- a/scripts/twitterstatusfetcher.php +++ b/scripts/twitterstatusfetcher.php @@ -33,7 +33,12 @@ define('MAXCHILDREN', 2); define('POLL_INTERVAL', 60); // in seconds // Uncomment this to get useful logging -define('SCRIPT_DEBUG', true); +// define('SCRIPT_DEBUG', true); + +// Preset the server at the command line + +$server = ($argc > 2) ? $argv[2] : null; +$path = ($argc > 3) ? $argv[3] : null; require_once INSTALLDIR . '/lib/common.php'; require_once INSTALLDIR . '/lib/daemon.php'; diff --git a/scripts/xmppconfirmhandler.php b/scripts/xmppconfirmhandler.php index 7f39235fed..fee902320c 100755 --- a/scripts/xmppconfirmhandler.php +++ b/scripts/xmppconfirmhandler.php @@ -27,6 +27,11 @@ if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) { define('INSTALLDIR', realpath(dirname(__FILE__) . '/..')); define('LACONICA', true); +// Preset the server at the command line + +$server = ($argc > 2) ? $argv[2] : null; +$path = ($argc > 3) ? $argv[3] : null; + require_once(INSTALLDIR . '/lib/common.php'); require_once(INSTALLDIR . '/lib/jabber.php'); require_once(INSTALLDIR . '/lib/xmppqueuehandler.php'); @@ -39,12 +44,12 @@ class XmppConfirmHandler extends XmppQueueHandler { var $_id = 'confirm'; - + function class_name() { return 'XmppConfirmHandler'; } - + function run() { if (!$this->start()) { diff --git a/scripts/xmppdaemon.php b/scripts/xmppdaemon.php index b79fa1b3ba..468a163d27 100755 --- a/scripts/xmppdaemon.php +++ b/scripts/xmppdaemon.php @@ -27,6 +27,11 @@ if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) { define('INSTALLDIR', realpath(dirname(__FILE__) . '/..')); define('LACONICA', true); +// Preset the server at the command line + +$server = ($argc > 2) ? $argv[2] : null; +$path = ($argc > 3) ? $argv[3] : null; + require_once(INSTALLDIR . '/lib/common.php'); require_once(INSTALLDIR . '/lib/jabber.php'); require_once(INSTALLDIR . '/lib/daemon.php'); @@ -39,7 +44,6 @@ set_error_handler('common_error_handler'); class XMPPDaemon extends Daemon { - function XMPPDaemon($resource=null) { static $attrs = array('server', 'port', 'user', 'password', 'host'); From 27aaabb5f2829d983bcedb6b637558ba143b718b Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sat, 20 Jun 2009 15:49:42 -0700 Subject: [PATCH 150/262] ignore config.php.* --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 8a7f5c65c8..f4c2bba5f7 100644 --- a/.gitignore +++ b/.gitignore @@ -23,3 +23,4 @@ config-*.php good-config.php lac08.log php.log +config.php.* From 793a6a1155996a7bcdc068fc891e7063934bdb19 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sat, 20 Jun 2009 16:00:04 -0700 Subject: [PATCH 151/262] change Controlez-Vous to Control Yourself --- actions/accesstoken.php | 2 +- actions/all.php | 2 +- actions/allrss.php | 2 +- actions/api.php | 2 +- actions/avatarbynickname.php | 2 +- actions/block.php | 2 +- actions/disfavor.php | 2 +- actions/doc.php | 2 +- actions/facebookhome.php | 2 +- actions/facebookinvite.php | 2 +- actions/facebooklogin.php | 2 +- actions/facebookremove.php | 2 +- actions/facebooksettings.php | 2 +- actions/favor.php | 2 +- actions/favoritesrss.php | 2 +- actions/file.php | 2 +- actions/finishopenidlogin.php | 2 +- actions/finishremotesubscribe.php | 2 +- actions/foaf.php | 2 +- actions/groupblock.php | 2 +- actions/groupsearch.php | 2 +- actions/groupunblock.php | 2 +- actions/invite.php | 2 +- actions/logout.php | 2 +- actions/makeadmin.php | 2 +- actions/microsummary.php | 2 +- actions/noticesearch.php | 2 +- actions/noticesearchrss.php | 2 +- actions/nudge.php | 2 +- actions/openidlogin.php | 2 +- actions/opensearch.php | 2 +- actions/peoplesearch.php | 2 +- actions/postnotice.php | 2 +- actions/publicrss.php | 2 +- actions/publicxrds.php | 2 +- actions/recoverpassword.php | 2 +- actions/remotesubscribe.php | 2 +- actions/repliesrss.php | 2 +- actions/requesttoken.php | 2 +- actions/subedit.php | 2 +- actions/subscribe.php | 2 +- actions/sup.php | 2 +- actions/tag.php | 2 +- actions/tagother.php | 2 +- actions/tagrss.php | 2 +- actions/twitapiaccount.php | 2 +- actions/twitapiblocks.php | 2 +- actions/twitapidirect_messages.php | 2 +- actions/twitapifavorites.php | 2 +- actions/twitapifriendships.php | 2 +- actions/twitapihelp.php | 2 +- actions/twitapinotifications.php | 2 +- actions/twitapistatuses.php | 2 +- actions/twitapiusers.php | 2 +- actions/unblock.php | 2 +- actions/unsubscribe.php | 2 +- actions/updateprofile.php | 2 +- actions/userauthorization.php | 2 +- actions/userbyid.php | 2 +- actions/userrss.php | 2 +- actions/xrds.php | 2 +- classes/File.php | 2 +- classes/File_oembed.php | 2 +- classes/File_redirection.php | 2 +- classes/File_thumbnail.php | 2 +- classes/File_to_post.php | 2 +- classes/Group_block.php | 2 +- classes/Memcached_DataObject.php | 2 +- classes/Notice.php | 2 +- classes/Notice_tag.php | 2 +- classes/Profile.php | 2 +- classes/Profile_block.php | 2 +- classes/Remote_profile.php | 2 +- classes/Subscription.php | 2 +- index.php | 2 +- install.php | 2 +- lib/Shorturl_api.php | 2 +- lib/arraywrapper.php | 2 +- lib/channel.php | 2 +- lib/clienterroraction.php | 2 +- lib/command.php | 2 +- lib/commandinterpreter.php | 2 +- lib/common.php | 2 +- lib/daemon.php | 2 +- lib/dberroraction.php | 2 +- lib/error.php | 2 +- lib/facebookutil.php | 2 +- lib/galleryaction.php | 2 +- lib/oauthstore.php | 2 +- lib/omb.php | 2 +- lib/openid.php | 2 +- lib/peoplesearchresults.php | 2 +- lib/queuehandler.php | 2 +- lib/search_engines.php | 2 +- lib/searchaction.php | 2 +- lib/servererroraction.php | 2 +- lib/subs.php | 2 +- lib/twitter.php | 2 +- lib/twitterapi.php | 2 +- lib/util.php | 2 +- lib/xmppqueuehandler.php | 2 +- scripts/enjitqueuehandler.php | 2 +- scripts/facebookqueuehandler.php | 2 +- scripts/fixup_hashtags.php | 2 +- scripts/fixup_inboxes.php | 2 +- scripts/fixup_notices_rendered.php | 2 +- scripts/fixup_replies.php | 2 +- scripts/getpiddir.php | 2 +- scripts/getvaliddaemons.php | 2 +- scripts/inbox_users.php | 2 +- scripts/jabberqueuehandler.php | 2 +- scripts/maildaemon.php | 2 +- scripts/ombqueuehandler.php | 2 +- scripts/pingqueuehandler.php | 2 +- scripts/publicqueuehandler.php | 2 +- scripts/setpassword.php | 2 +- scripts/smsqueuehandler.php | 2 +- scripts/sphinx-cron.sh | 2 +- scripts/sphinx-indexer.sh | 2 +- scripts/startdaemons.sh | 2 +- scripts/stopdaemons.sh | 2 +- scripts/synctwitterfriends.php | 2 +- scripts/twitterqueuehandler.php | 2 +- scripts/twitterstatusfetcher.php | 2 +- scripts/uncache_users.php | 2 +- scripts/xmppconfirmhandler.php | 2 +- scripts/xmppdaemon.php | 2 +- 127 files changed, 127 insertions(+), 127 deletions(-) diff --git a/actions/accesstoken.php b/actions/accesstoken.php index 46b43c7021..01aa77574d 100644 --- a/actions/accesstoken.php +++ b/actions/accesstoken.php @@ -12,7 +12,7 @@ * @link http://laconi.ca/ * * Laconica - a distributed open-source microblogging tool - * Copyright (C) 2008, Controlez-Vous, Inc. + * Copyright (C) 2008, Control Yourself, Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by diff --git a/actions/all.php b/actions/all.php index 80fc9d54b0..f436fabd1b 100644 --- a/actions/all.php +++ b/actions/all.php @@ -1,7 +1,7 @@ Date: Sat, 20 Jun 2009 16:12:55 -0700 Subject: [PATCH 152/262] Update copyright dates in files modified in 2009 --- actions/accesstoken.php | 2 +- actions/all.php | 2 +- actions/allrss.php | 2 +- actions/api.php | 2 +- actions/avatarbynickname.php | 2 +- actions/block.php | 2 +- actions/disfavor.php | 2 +- actions/doc.php | 2 +- actions/facebookhome.php | 2 +- actions/facebookinvite.php | 2 +- actions/facebooklogin.php | 2 +- actions/facebookremove.php | 2 +- actions/facebooksettings.php | 2 +- actions/favor.php | 2 +- actions/favoritesrss.php | 2 +- actions/file.php | 2 +- actions/finishopenidlogin.php | 2 +- actions/finishremotesubscribe.php | 2 +- actions/foaf.php | 2 +- actions/groupblock.php | 2 +- actions/groupsearch.php | 2 +- actions/groupunblock.php | 2 +- actions/invite.php | 2 +- actions/logout.php | 2 +- actions/makeadmin.php | 2 +- actions/microsummary.php | 2 +- actions/noticesearch.php | 2 +- actions/noticesearchrss.php | 2 +- actions/nudge.php | 2 +- actions/openidlogin.php | 2 +- actions/opensearch.php | 2 +- actions/peoplesearch.php | 2 +- actions/postnotice.php | 2 +- actions/publicrss.php | 2 +- actions/publicxrds.php | 2 +- actions/recoverpassword.php | 2 +- actions/remotesubscribe.php | 2 +- actions/repliesrss.php | 2 +- actions/requesttoken.php | 2 +- actions/subedit.php | 2 +- actions/subscribe.php | 2 +- actions/sup.php | 2 +- actions/tag.php | 2 +- actions/tagother.php | 2 +- actions/tagrss.php | 2 +- actions/twitapiaccount.php | 2 +- actions/twitapiblocks.php | 2 +- actions/twitapidirect_messages.php | 2 +- actions/twitapifavorites.php | 2 +- actions/twitapifriendships.php | 2 +- actions/twitapihelp.php | 2 +- actions/twitapinotifications.php | 2 +- actions/twitapistatuses.php | 2 +- actions/twitapiusers.php | 2 +- actions/unblock.php | 2 +- actions/unsubscribe.php | 2 +- actions/updateprofile.php | 2 +- actions/userauthorization.php | 2 +- actions/userbyid.php | 2 +- actions/userrss.php | 2 +- actions/xrds.php | 2 +- classes/File.php | 2 +- classes/File_oembed.php | 2 +- classes/File_redirection.php | 2 +- classes/File_thumbnail.php | 2 +- classes/File_to_post.php | 2 +- classes/Group_block.php | 2 +- classes/Memcached_DataObject.php | 2 +- classes/Notice.php | 2 +- classes/Notice_tag.php | 2 +- classes/Profile.php | 2 +- classes/Profile_block.php | 2 +- classes/Remote_profile.php | 2 +- classes/Subscription.php | 2 +- index.php | 2 +- lib/Shorturl_api.php | 2 +- lib/arraywrapper.php | 2 +- lib/channel.php | 2 +- lib/clienterroraction.php | 2 +- lib/command.php | 2 +- lib/commandinterpreter.php | 2 +- lib/common.php | 2 +- lib/daemon.php | 2 +- lib/dberroraction.php | 2 +- lib/error.php | 2 +- lib/facebookutil.php | 2 +- lib/galleryaction.php | 2 +- lib/oauthstore.php | 2 +- lib/omb.php | 2 +- lib/openid.php | 2 +- lib/peoplesearchresults.php | 2 +- lib/queuehandler.php | 2 +- lib/search_engines.php | 2 +- lib/searchaction.php | 2 +- lib/servererroraction.php | 2 +- lib/subs.php | 2 +- lib/twitter.php | 2 +- lib/twitterapi.php | 2 +- lib/util.php | 2 +- lib/xmppqueuehandler.php | 2 +- scripts/enjitqueuehandler.php | 2 +- scripts/facebookqueuehandler.php | 2 +- scripts/fixup_hashtags.php | 2 +- scripts/fixup_inboxes.php | 2 +- scripts/fixup_notices_rendered.php | 2 +- scripts/fixup_replies.php | 2 +- scripts/getpiddir.php | 2 +- scripts/getvaliddaemons.php | 2 +- scripts/inbox_users.php | 2 +- scripts/jabberqueuehandler.php | 2 +- scripts/maildaemon.php | 2 +- scripts/ombqueuehandler.php | 2 +- scripts/pingqueuehandler.php | 2 +- scripts/publicqueuehandler.php | 2 +- scripts/setpassword.php | 2 +- scripts/smsqueuehandler.php | 2 +- scripts/sphinx-cron.sh | 2 +- scripts/sphinx-indexer.sh | 2 +- scripts/startdaemons.sh | 2 +- scripts/stopdaemons.sh | 2 +- scripts/synctwitterfriends.php | 2 +- scripts/twitterqueuehandler.php | 2 +- scripts/twitterstatusfetcher.php | 2 +- scripts/uncache_users.php | 2 +- scripts/xmppconfirmhandler.php | 2 +- scripts/xmppdaemon.php | 2 +- 126 files changed, 126 insertions(+), 126 deletions(-) diff --git a/actions/accesstoken.php b/actions/accesstoken.php index 01aa77574d..2a8cd17134 100644 --- a/actions/accesstoken.php +++ b/actions/accesstoken.php @@ -12,7 +12,7 @@ * @link http://laconi.ca/ * * Laconica - a distributed open-source microblogging tool - * Copyright (C) 2008, Control Yourself, Inc. + * Copyright (C) 2008, 2009, Control Yourself, Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by diff --git a/actions/all.php b/actions/all.php index f436fabd1b..f06ead2a8c 100644 --- a/actions/all.php +++ b/actions/all.php @@ -1,7 +1,7 @@ Date: Sun, 21 Jun 2009 11:11:12 -0700 Subject: [PATCH 153/262] add collecta.com link --- lib/searchaction.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/searchaction.php b/lib/searchaction.php index bb2d50572b..34fe9373f4 100644 --- a/lib/searchaction.php +++ b/lib/searchaction.php @@ -148,10 +148,10 @@ You can also try your search on other engines: * [Tweet scan](http://www.tweetscan.com/indexi.php?s=%s) * [Google](http://www.google.com/search?q=site%%3A%%%%site.server%%%%+%s) * [Yahoo](http://search.yahoo.com/search?p=site%%3A%%%%site.server%%%%+%s) - +* [Collecta](http://collecta.com/#q=%s) E_O_T -), $qe, $qe, $qe, $qe); +), $qe, $qe, $qe, $qe, $qe); $this->elementStart('dl', array('id' => 'help_search', 'class' => 'help')); $this->element('dt', null, _('Search help')); $this->elementStart('dd', 'instructions'); From 02a4ca9e2ea46cb82829dc65e76efc36b0ec470b Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 21 Jun 2009 21:38:16 -0700 Subject: [PATCH 154/262] got rid of 'skin' concept a while ago --- lib/common.php | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/common.php b/lib/common.php index a4da251578..361759d0a2 100644 --- a/lib/common.php +++ b/lib/common.php @@ -83,7 +83,6 @@ $config = array('name' => 'Just another Laconica microblog', 'server' => $_server, 'theme' => 'default', - 'skin' => 'default', 'design' => array('backgroundcolor' => '#F0F2F5', 'contentcolor' => '#FFFFFF', From 876ab059273a5f223170d6b2c0b9b4342b06c50f Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 21 Jun 2009 21:50:35 -0700 Subject: [PATCH 155/262] Add like for search --- README | 13 ++++++++++++- classes/Memcached_DataObject.php | 9 ++++++++- lib/common.php | 4 +++- lib/search_engines.php | 22 ++++++++++++++++++++++ 4 files changed, 45 insertions(+), 3 deletions(-) diff --git a/README b/README index 5aa7270eec..0c500acb86 100644 --- a/README +++ b/README @@ -1247,7 +1247,6 @@ Options for group functionality. maxaliases: maximum number of aliases a group can have. Default 3. Set to 0 or less to prevent aliases in a group. - oohembed -------- @@ -1255,6 +1254,18 @@ oEmbed endpoint for multimedia attachments (links in posts). endpoint: oohembed endpoint using http://oohembed.com/ software. +search +------ + +Some stuff for search. + +type: type of search. Ignored if PostgreSQL or Sphinx are enabled. Can either + be 'fulltext' (default) or 'like'. The former is faster and more efficient + but requires the lame old MyISAM engine for MySQL. The latter + will work with InnoDB but could be miserably slow on large + systems. We'll probably add another type sometime in the future, + with our own indexing system (maybe like MediaWiki's). + Troubleshooting =============== diff --git a/classes/Memcached_DataObject.php b/classes/Memcached_DataObject.php index 2d5a73554c..f7cbb9d5b6 100644 --- a/classes/Memcached_DataObject.php +++ b/classes/Memcached_DataObject.php @@ -193,7 +193,14 @@ class Memcached_DataObject extends DB_DataObject // unable to connect to sphinx' search daemon if (!$connected) { if ('mysql' === common_config('db', 'type')) { - $search_engine = new MySQLSearch($this, $table); + $type = common_config('search', 'type'); + if ($type == 'like') { + $search_engine = new MySQLLikeSearch($this, $table); + } else if ($type == 'fulltext') { + $search_engine = new MySQLSearch($this, $table); + } else { + throw new ServerException('Unknown search type: ' . $type); + } } else { $search_engine = new PGSearch($this, $table); } diff --git a/lib/common.php b/lib/common.php index 361759d0a2..14f5c7a7f1 100644 --- a/lib/common.php +++ b/lib/common.php @@ -228,7 +228,9 @@ $config = ), 'group' => array('maxaliases' => 3), - 'oohembed' => array('endpoint' => 'http://oohembed.com/oohembed/') + 'oohembed' => array('endpoint' => 'http://oohembed.com/oohembed/'), + 'search' => + array('type' => 'fulltext'), ); $config['db'] = &PEAR::getStaticProperty('DB_DataObject','options'); diff --git a/lib/search_engines.php b/lib/search_engines.php index c98e8ed875..5c84d7c6b2 100644 --- a/lib/search_engines.php +++ b/lib/search_engines.php @@ -131,6 +131,28 @@ class MySQLSearch extends SearchEngine } } +class MySQLLikeSearch extends SearchEngine +{ + function query($q) + { + if ('identica_people' === $this->table) { + $qry = sprintf('(nickname LIKE "%%%1$s%%" OR '. + ' fullname LIKE "%%%1$s%%" OR '. + ' location LIKE "%%%1$s%%" OR '. + ' bio LIKE "%%%1$s%%" OR '. + ' homepage LIKE "%%%1$s%%")', addslashes($q)); + } else if ('identica_notices' === $this->table) { + $qry = sprintf('content LIKE "%%%1$s%%"', addslashes($q)); + } else { + throw new ServerException('Unknown table: ' . $this->table); + } + + $this->target->whereAdd($qry); + + return true; + } +} + class PGSearch extends SearchEngine { function query($q) From 7cf0a4c6472ab05a0963c003d8c3ecb59237ee67 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 22 Jun 2009 09:31:55 -0700 Subject: [PATCH 156/262] theme dir, path configurable --- README | 13 ++++++++++--- lib/common.php | 4 +++- lib/theme.php | 38 ++++++++++++++++++++++++++++++-------- 3 files changed, 43 insertions(+), 12 deletions(-) diff --git a/README b/README index 0c500acb86..cd663d931b 100644 --- a/README +++ b/README @@ -1039,9 +1039,16 @@ theme ----- server: Like avatars, you can speed up page loading by pointing the - theme file lookup to another server (virtual or real). The - theme server's root path should map to the Laconica "theme" - subdirectory. Defaults to NULL. + theme file lookup to another server (virtual or real). + Defaults to NULL, meaning to use the site server. +dir: Directory where theme files are stored. Used to determine + whether to show parts of a theme file. Defaults to the theme + subdirectory of the install directory. +path: Path part of theme URLs, before the theme name. Relative to the + theme server. It may make sense to change this path when upgrading, + (using version numbers as the path) to make sure that all files are + reloaded by caching clients or proxies. Defaults to null, + which means to use the site path + '/theme'. xmpp ---- diff --git a/lib/common.php b/lib/common.php index 14f5c7a7f1..0333030e1d 100644 --- a/lib/common.php +++ b/lib/common.php @@ -140,7 +140,9 @@ $config = 'blacklist' => array(), 'autosource' => array()), 'theme' => - array('server' => null), + array('server' => null, + 'dir' => null, + 'path'=> null), 'throttle' => array('enabled' => false, // whether to throttle edits; false by default 'count' => 20, // number of allowed messages in timespan diff --git a/lib/theme.php b/lib/theme.php index 0d88248227..2fe6ab69b7 100644 --- a/lib/theme.php +++ b/lib/theme.php @@ -43,10 +43,14 @@ if (!defined('LACONICA')) { function theme_file($relative, $theme=null) { - if (!$theme) { + if (empty($theme)) { $theme = common_config('site', 'theme'); } - return INSTALLDIR.'/theme/'.$theme.'/'.$relative; + $dir = common_config('theme', 'dir'); + if (empty($dir)) { + $dir = INSTALLDIR.'/theme'; + } + return $dir.'/'.$theme.'/'.$relative; } /** @@ -60,13 +64,31 @@ function theme_file($relative, $theme=null) function theme_path($relative, $theme=null) { - if (!$theme) { + if (empty($theme)) { $theme = common_config('site', 'theme'); } - $server = common_config('theme', 'server'); - if ($server) { - return 'http://'.$server.'/'.$theme.'/'.$relative; - } else { - return common_path('theme/'.$theme.'/'.$relative); + + $path = common_config('theme', 'path'); + + if (empty($path)) { + $path = common_config('site', 'path') . '/theme/'; } + + if ($path[strlen($path)-1] != '/') { + $path .= '/'; + } + + if ($path[0] != '/') { + $path = '/'.$path; + } + + $server = common_config('theme', 'server'); + + if (empty($server)) { + $server = common_config('site', 'server'); + } + + // XXX: protocol + + return 'http://'.$server.$path.$theme.'/'.$relative; } From 7b269a6712ac740c961634b0c165e6f74f420236 Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Mon, 22 Jun 2009 17:18:09 +0000 Subject: [PATCH 157/262] Layout fix for IE6 --- theme/base/css/ie6.css | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/theme/base/css/ie6.css b/theme/base/css/ie6.css index 76a82c0042..dde4d6fc77 100644 --- a/theme/base/css/ie6.css +++ b/theme/base/css/ie6.css @@ -5,6 +5,12 @@ margin-left:7px; address .fn { display:none; } + +#wrap { +width:1003px; +margin:0 auto; +} + #content { width:70%; } @@ -26,5 +32,6 @@ margin-bottom:123px; width:20%; } .notice div.entry-content { -width:63%; +width:50%; +margin-left:30px; } From 4c09d10025796c824c7f5d5f08a1750e4c92ba9e Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Mon, 22 Jun 2009 12:24:59 -0700 Subject: [PATCH 158/262] Keep gateway notices from leaking thru Sphinx search-engine --- sphinx.conf.sample | 82 +++++++++++++++++++++++----------------------- 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/sphinx.conf.sample b/sphinx.conf.sample index b79adf15c0..8204b9db6c 100644 --- a/sphinx.conf.sample +++ b/sphinx.conf.sample @@ -4,68 +4,68 @@ source src1 { - type = mysql - sql_host = localhost - sql_user = USERNAME - sql_pass = PASSWORD - sql_db = identi_ca - sql_port = 3306 - sql_query = SELECT id, UNIX_TIMESTAMP(created) as created_ts, nickname, fullname, location, bio, homepage FROM profile - sql_query_info = SELECT * FROM profile where id = $id - sql_attr_timestamp = created_ts + type = mysql + sql_host = localhost + sql_user = USERNAME + sql_pass = PASSWORD + sql_db = identi_ca + sql_port = 3306 + sql_query = SELECT id, UNIX_TIMESTAMP(created) as created_ts, nickname, fullname, location, bio, homepage FROM profile + sql_query_info = SELECT * FROM profile where id = $id + sql_attr_timestamp = created_ts } source src2 { - type = mysql - sql_host = localhost - sql_user = USERNAME - sql_pass = PASSWORD - sql_db = identi_ca - sql_port = 3306 - sql_query = SELECT id, UNIX_TIMESTAMP(created) as created_ts, content FROM notice - sql_query_info = SELECT * FROM notice where id = $id - sql_attr_timestamp = created_ts + type = mysql + sql_host = localhost + sql_user = USERNAME + sql_pass = PASSWORD + sql_db = identi_ca + sql_port = 3306 + sql_query = SELECT id, UNIX_TIMESTAMP(created) as created_ts, content FROM notice + sql_query_info = SELECT * FROM notice where notice.id = $id AND notice.is_local != -2 + sql_attr_timestamp = created_ts } index identica_notices { - source = src2 - path = DIRECTORY/data/identica_notices - docinfo = extern - charset_type = utf-8 - min_word_len = 3 - stopwords = DIRECTORY/data/stopwords-en.txt + source = src2 + path = DIRECTORY/data/identica_notices + docinfo = extern + charset_type = utf-8 + min_word_len = 3 + stopwords = DIRECTORY/data/stopwords-en.txt } index identica_people { - source = src1 - path = DIRECTORY/data/identica_people - docinfo = extern - charset_type = utf-8 - min_word_len = 3 - stopwords = DIRECTORY/data/stopwords-en.txt + source = src1 + path = DIRECTORY/data/identica_people + docinfo = extern + charset_type = utf-8 + min_word_len = 3 + stopwords = DIRECTORY/data/stopwords-en.txt } indexer { - mem_limit = 32M + mem_limit = 32M } searchd { - port = 3312 - log = DIRECTORY/log/searchd.log - query_log = DIRECTORY/log/query.log - read_timeout = 5 - max_children = 30 - pid_file = DIRECTORY/log/searchd.pid - max_matches = 1000 - seamless_rotate = 1 - preopen_indexes = 0 - unlink_old = 1 + port = 3312 + log = DIRECTORY/log/searchd.log + query_log = DIRECTORY/log/query.log + read_timeout = 5 + max_children = 30 + pid_file = DIRECTORY/log/searchd.pid + max_matches = 1000 + seamless_rotate = 1 + preopen_indexes = 0 + unlink_old = 1 } From 15e4cbebab5d640b0261f0e6c0366ebb49d72d7a Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 22 Jun 2009 13:14:15 -0700 Subject: [PATCH 159/262] fixing up conversations --- scripts/fixup_conversations.php | 79 +++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100755 scripts/fixup_conversations.php diff --git a/scripts/fixup_conversations.php b/scripts/fixup_conversations.php new file mode 100755 index 0000000000..d4a47cfeef --- /dev/null +++ b/scripts/fixup_conversations.php @@ -0,0 +1,79 @@ +#!/usr/bin/env php +. + */ + +# Abort if called from a web server +if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) { + print "This script must be run from the command line\n"; + exit(); +} + +define('INSTALLDIR', realpath(dirname(__FILE__) . '/..')); +define('LACONICA', true); + +require_once(INSTALLDIR . '/lib/common.php'); + +common_log(LOG_INFO, 'Fixing up conversations.'); + +$notice = new Notice(); +$notice->whereAdd('conversation is null'); +$notice->orderBy('id'); + +$cnt = $notice->find(); + +print "Found $cnt notices.\n"; + +while ($notice->fetch()) { + + print "$notice->id =>"; + + $orig = clone($notice); + + if (empty($notice->reply_to)) { + $notice->conversation = $notice->id; + } else { + $reply = Notice::staticGet('id', $notice->reply_to); + + if (empty($reply)) { + common_log(LOG_WARNING, "Replied-to notice $notice->reply_to not found."); + $notice->conversation = $notice->id; + } else if (empty($reply->conversation)) { + common_log(LOG_WARNING, "Replied-to notice $reply->id has no conversation ID."); + $notice->conversation = $notice->id; + } else { + $notice->conversation = $reply->conversation; + } + } + + print "$notice->conversation"; + + $result = $notice->update($orig); + + if (!$result) { + common_log_db_error($notice, 'UPDATE', __FILE__); + continue; + } + + print ".\n"; +} + +ini_set("max_execution_time", "0"); +ini_set("max_input_time", "0"); +set_time_limit(0); +mb_internal_encoding('UTF-8'); From 05e51228020fecaa894523b5159bc412d48e5b19 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 22 Jun 2009 14:19:41 -0700 Subject: [PATCH 160/262] Database changes for file tables Some minor database changes for file tables. Namely: * Added a timestamp to all tables * Added a filename column for local files * Change some tables that had unnecessary auto-increment primary keys when they had another unique column that should act as the primary key * Change engine from MyISAM to InnoDB for a couple of files. Also, rebuilt the DB_DataObject files for all these tables. --- classes/File.php | 10 ++++++---- classes/File_oembed.php | 10 +++++----- classes/File_redirection.php | 10 +++++----- classes/File_thumbnail.php | 8 ++++---- classes/File_to_post.php | 6 +++--- classes/laconica.ini | 30 +++++++++++++++++------------- db/laconica.sql | 31 ++++++++++++++++++------------- 7 files changed, 58 insertions(+), 47 deletions(-) diff --git a/classes/File.php b/classes/File.php index 8905360353..800041d5d2 100644 --- a/classes/File.php +++ b/classes/File.php @@ -36,13 +36,15 @@ class File extends Memcached_DataObject /* the code below is auto generated do not remove the above tag */ public $__table = 'file'; // table name - public $id; // int(11) not_null primary_key group_by + public $id; // int(4) primary_key not_null public $url; // varchar(255) unique_key public $mimetype; // varchar(50) - public $size; // int(11) group_by + public $size; // int(4) public $title; // varchar(255) - public $date; // int(11) group_by - public $protected; // int(1) group_by + public $date; // int(4) + public $protected; // int(4) + public $filename; // varchar(255) + public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP /* Static get */ function staticGet($k,$v=NULL) { return DB_DataObject::staticGet('File',$k,$v); } diff --git a/classes/File_oembed.php b/classes/File_oembed.php index 2e8e851cd6..f9ca14e3cf 100644 --- a/classes/File_oembed.php +++ b/classes/File_oembed.php @@ -31,19 +31,19 @@ class File_oembed extends Memcached_DataObject /* the code below is auto generated do not remove the above tag */ public $__table = 'file_oembed'; // table name - public $id; // int(11) not_null primary_key group_by - public $file_id; // int(11) unique_key group_by + public $file_id; // int(4) primary_key not_null public $version; // varchar(20) public $type; // varchar(20) public $provider; // varchar(50) public $provider_url; // varchar(255) - public $width; // int(11) group_by - public $height; // int(11) group_by - public $html; // blob(65535) blob + public $width; // int(4) + public $height; // int(4) + public $html; // text() public $title; // varchar(255) public $author_name; // varchar(50) public $author_url; // varchar(255) public $url; // varchar(255) + public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP /* Static get */ function staticGet($k,$v=NULL) { return DB_DataObject::staticGet('File_oembed',$k,$v); } diff --git a/classes/File_redirection.php b/classes/File_redirection.php index 0d6e2a7004..13f02f8e5d 100644 --- a/classes/File_redirection.php +++ b/classes/File_redirection.php @@ -36,11 +36,11 @@ class File_redirection extends Memcached_DataObject /* the code below is auto generated do not remove the above tag */ public $__table = 'file_redirection'; // table name - public $id; // int(11) not_null primary_key group_by - public $url; // varchar(255) unique_key - public $file_id; // int(11) group_by - public $redirections; // int(11) group_by - public $httpcode; // int(11) group_by + public $url; // varchar(255) primary_key not_null + public $file_id; // int(4) + public $redirections; // int(4) + public $httpcode; // int(4) + public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP /* Static get */ function staticGet($k,$v=NULL) { return DB_DataObject::staticGet('File_redirection',$k,$v); } diff --git a/classes/File_thumbnail.php b/classes/File_thumbnail.php index 2908549da6..40d85b2583 100644 --- a/classes/File_thumbnail.php +++ b/classes/File_thumbnail.php @@ -31,11 +31,11 @@ class File_thumbnail extends Memcached_DataObject /* the code below is auto generated do not remove the above tag */ public $__table = 'file_thumbnail'; // table name - public $id; // int(11) not_null primary_key group_by - public $file_id; // int(11) unique_key group_by + public $file_id; // int(4) primary_key not_null public $url; // varchar(255) unique_key - public $width; // int(11) group_by - public $height; // int(11) group_by + public $width; // int(4) + public $height; // int(4) + public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP /* Static get */ function staticGet($k,$v=NULL) { return DB_DataObject::staticGet('File_thumbnail',$k,$v); } diff --git a/classes/File_to_post.php b/classes/File_to_post.php index 9362faaaed..bb5f4e6e4b 100644 --- a/classes/File_to_post.php +++ b/classes/File_to_post.php @@ -31,9 +31,9 @@ class File_to_post extends Memcached_DataObject /* the code below is auto generated do not remove the above tag */ public $__table = 'file_to_post'; // table name - public $id; // int(11) not_null primary_key group_by - public $file_id; // int(11) multiple_key group_by - public $post_id; // int(11) group_by + public $file_id; // int(4) primary_key not_null + public $post_id; // int(4) primary_key not_null + public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP /* Static get */ function staticGet($k,$v=NULL) { return DB_DataObject::staticGet('File_to_post',$k,$v); } diff --git a/classes/laconica.ini b/classes/laconica.ini index 5ced158851..7e9b2b791d 100755 --- a/classes/laconica.ini +++ b/classes/laconica.ini @@ -68,13 +68,14 @@ size = 1 title = 2 date = 1 protected = 1 +filename = 2 +modified = 384 [file__keys] id = N [file_oembed] -id = 129 -file_id = 1 +file_id = 129 version = 2 type = 2 provider = 2 @@ -86,37 +87,40 @@ title = 2 author_name = 2 author_url = 2 url = 2 +modified = 384 [file_oembed__keys] -id = N +file_id = K [file_redirection] -id = 129 -url = 2 +url = 130 file_id = 1 redirections = 1 httpcode = 1 +modified = 384 [file_redirection__keys] -id = N +url = K [file_thumbnail] -id = 129 -file_id = 1 +file_id = 129 url = 2 width = 1 height = 1 +modified = 384 [file_thumbnail__keys] -id = N +file_id = K +url = U [file_to_post] -id = 129 -file_id = 1 -post_id = 1 +file_id = 129 +post_id = 129 +modified = 384 [file_to_post__keys] -id = N +file_id = K +post_id = K [foreign_link] user_id = 129 diff --git a/db/laconica.sql b/db/laconica.sql index 8d1d47d38d..95796d5cc6 100644 --- a/db/laconica.sql +++ b/db/laconica.sql @@ -431,6 +431,7 @@ create table group_inbox ( ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin; 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', @@ -438,13 +439,15 @@ create table file ( 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=MyISAM CHARACTER SET utf8 COLLATE utf8_general_ci; +) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_general_ci; create table file_oembed ( - id integer primary key auto_increment, - file_id integer comment 'oEmbed for that URL/file' references file (id), + 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', @@ -456,37 +459,39 @@ create table file_oembed ( 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' - unique(file_id) -) ENGINE=MyISAM CHARACTER SET utf8 COLLATE utf8_general_ci; +) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_general_ci; create table file_redirection ( - id integer primary key auto_increment, - url varchar(255) comment 'short URL (or any other kind of redirect) for file (id)', + + 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' - unique(url) ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin; create table file_thumbnail ( - id integer primary key auto_increment, - file_id integer comment 'thumbnail for what URL/file' references file (id), + + 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(file_id), unique(url) ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin; create table file_to_post ( - id integer primary key auto_increment, + 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) - unique(file_id, post_id) ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin; create table design ( From 2e9fc34d4f6483ad08e6e5a1b778ee096cb6a5c1 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 22 Jun 2009 14:24:40 -0700 Subject: [PATCH 161/262] change staticGet() from DB_DataObject to Memcached_DataObject for file classes --- classes/File.php | 2 +- classes/File_oembed.php | 2 +- classes/File_redirection.php | 2 +- classes/File_thumbnail.php | 2 +- classes/File_to_post.php | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/classes/File.php b/classes/File.php index 800041d5d2..47af1c5506 100644 --- a/classes/File.php +++ b/classes/File.php @@ -47,7 +47,7 @@ class File extends Memcached_DataObject public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP /* Static get */ - function staticGet($k,$v=NULL) { return DB_DataObject::staticGet('File',$k,$v); } + function staticGet($k,$v=NULL) { return Memcached_DataObject::staticGet('File',$k,$v); } /* the code above is auto generated do not remove the tag below */ ###END_AUTOCODE diff --git a/classes/File_oembed.php b/classes/File_oembed.php index f9ca14e3cf..51ee57b296 100644 --- a/classes/File_oembed.php +++ b/classes/File_oembed.php @@ -46,7 +46,7 @@ class File_oembed extends Memcached_DataObject public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP /* Static get */ - function staticGet($k,$v=NULL) { return DB_DataObject::staticGet('File_oembed',$k,$v); } + function staticGet($k,$v=NULL) { return Memcached_DataObject::staticGet('File_oembed',$k,$v); } /* the code above is auto generated do not remove the tag below */ ###END_AUTOCODE diff --git a/classes/File_redirection.php b/classes/File_redirection.php index 13f02f8e5d..edd915c1e8 100644 --- a/classes/File_redirection.php +++ b/classes/File_redirection.php @@ -43,7 +43,7 @@ class File_redirection extends Memcached_DataObject public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP /* Static get */ - function staticGet($k,$v=NULL) { return DB_DataObject::staticGet('File_redirection',$k,$v); } + function staticGet($k,$v=NULL) { return Memcached_DataObject::staticGet('File_redirection',$k,$v); } /* the code above is auto generated do not remove the tag below */ ###END_AUTOCODE diff --git a/classes/File_thumbnail.php b/classes/File_thumbnail.php index 40d85b2583..21dcad5714 100644 --- a/classes/File_thumbnail.php +++ b/classes/File_thumbnail.php @@ -38,7 +38,7 @@ class File_thumbnail extends Memcached_DataObject public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP /* Static get */ - function staticGet($k,$v=NULL) { return DB_DataObject::staticGet('File_thumbnail',$k,$v); } + function staticGet($k,$v=NULL) { return Memcached_DataObject::staticGet('File_thumbnail',$k,$v); } /* the code above is auto generated do not remove the tag below */ ###END_AUTOCODE diff --git a/classes/File_to_post.php b/classes/File_to_post.php index bb5f4e6e4b..db0a8d2169 100644 --- a/classes/File_to_post.php +++ b/classes/File_to_post.php @@ -36,7 +36,7 @@ class File_to_post extends Memcached_DataObject public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP /* Static get */ - function staticGet($k,$v=NULL) { return DB_DataObject::staticGet('File_to_post',$k,$v); } + function staticGet($k,$v=NULL) { return Memcached_DataObject::staticGet('File_to_post',$k,$v); } /* the code above is auto generated do not remove the tag below */ ###END_AUTOCODE From 09e24af6832d6a4ce5605be23e3469c5b33a3efe Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Mon, 22 Jun 2009 21:36:04 +0000 Subject: [PATCH 162/262] Add upload location to attachments config section --- lib/common.php | 67 ++++++++++++++++++++++++++------------------------ 1 file changed, 35 insertions(+), 32 deletions(-) diff --git a/lib/common.php b/lib/common.php index 0333030e1d..b773f5f897 100644 --- a/lib/common.php +++ b/lib/common.php @@ -191,38 +191,41 @@ $config = array('run' => 'web', 'frequency' => 10000, 'reporturl' => 'http://laconi.ca/stats/report'), - 'attachments' => - array('supported' => array('image/png', - 'image/jpeg', - 'image/gif', - 'image/svg+xml', - 'audio/mpeg', - 'audio/x-speex', - 'application/ogg', - 'application/pdf', - 'application/vnd.oasis.opendocument.text', - 'application/vnd.oasis.opendocument.text-template', - 'application/vnd.oasis.opendocument.graphics', - 'application/vnd.oasis.opendocument.graphics-template', - 'application/vnd.oasis.opendocument.presentation', - 'application/vnd.oasis.opendocument.presentation-template', - 'application/vnd.oasis.opendocument.spreadsheet', - 'application/vnd.oasis.opendocument.spreadsheet-template', - 'application/vnd.oasis.opendocument.chart', - 'application/vnd.oasis.opendocument.chart-template', - 'application/vnd.oasis.opendocument.image', - 'application/vnd.oasis.opendocument.image-template', - 'application/vnd.oasis.opendocument.formula', - 'application/vnd.oasis.opendocument.formula-template', - 'application/vnd.oasis.opendocument.text-master', - 'application/vnd.oasis.opendocument.text-web', - 'application/x-zip', - 'application/zip', - 'text/plain', - 'video/mpeg', - 'video/mp4', - 'video/quicktime', - 'video/mpeg'), + 'attachments' => + array('server' => null, + 'dir' => INSTALLDIR . '/file/', + 'path' => $_path . '/file/', + 'supported' => array('image/png', + 'image/jpeg', + 'image/gif', + 'image/svg+xml', + 'audio/mpeg', + 'audio/x-speex', + 'application/ogg', + 'application/pdf', + 'application/vnd.oasis.opendocument.text', + 'application/vnd.oasis.opendocument.text-template', + 'application/vnd.oasis.opendocument.graphics', + 'application/vnd.oasis.opendocument.graphics-template', + 'application/vnd.oasis.opendocument.presentation', + 'application/vnd.oasis.opendocument.presentation-template', + 'application/vnd.oasis.opendocument.spreadsheet', + 'application/vnd.oasis.opendocument.spreadsheet-template', + 'application/vnd.oasis.opendocument.chart', + 'application/vnd.oasis.opendocument.chart-template', + 'application/vnd.oasis.opendocument.image', + 'application/vnd.oasis.opendocument.image-template', + 'application/vnd.oasis.opendocument.formula', + 'application/vnd.oasis.opendocument.formula-template', + 'application/vnd.oasis.opendocument.text-master', + 'application/vnd.oasis.opendocument.text-web', + 'application/x-zip', + 'application/zip', + 'text/plain', + 'video/mpeg', + 'video/mp4', + 'video/quicktime', + 'video/mpeg'), 'file_quota' => 5000000, 'user_quota' => 50000000, 'monthly_quota' => 15000000, From 79dcf0871fee6dfa3835d12f55d1099a716a6f4c Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 22 Jun 2009 14:55:55 -0700 Subject: [PATCH 163/262] Add Console_Getopt --- extlib/Console/Getopt.php | 290 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 290 insertions(+) create mode 100644 extlib/Console/Getopt.php diff --git a/extlib/Console/Getopt.php b/extlib/Console/Getopt.php new file mode 100644 index 0000000000..bb9d69ca22 --- /dev/null +++ b/extlib/Console/Getopt.php @@ -0,0 +1,290 @@ + | +// +----------------------------------------------------------------------+ +// +// $Id: Getopt.php,v 1.4 2007/06/12 14:58:56 cellog Exp $ + +require_once 'PEAR.php'; + +/** + * Command-line options parsing class. + * + * @author Andrei Zmievski + * + */ +class Console_Getopt { + /** + * Parses the command-line options. + * + * The first parameter to this function should be the list of command-line + * arguments without the leading reference to the running program. + * + * The second parameter is a string of allowed short options. Each of the + * option letters can be followed by a colon ':' to specify that the option + * requires an argument, or a double colon '::' to specify that the option + * takes an optional argument. + * + * The third argument is an optional array of allowed long options. The + * leading '--' should not be included in the option name. Options that + * require an argument should be followed by '=', and options that take an + * option argument should be followed by '=='. + * + * The return value is an array of two elements: the list of parsed + * options and the list of non-option command-line arguments. Each entry in + * the list of parsed options is a pair of elements - the first one + * specifies the option, and the second one specifies the option argument, + * if there was one. + * + * Long and short options can be mixed. + * + * Most of the semantics of this function are based on GNU getopt_long(). + * + * @param array $args an array of command-line arguments + * @param string $short_options specifies the list of allowed short options + * @param array $long_options specifies the list of allowed long options + * + * @return array two-element array containing the list of parsed options and + * the non-option arguments + * + * @access public + * + */ + function getopt2($args, $short_options, $long_options = null) + { + return Console_Getopt::doGetopt(2, $args, $short_options, $long_options); + } + + /** + * This function expects $args to start with the script name (POSIX-style). + * Preserved for backwards compatibility. + * @see getopt2() + */ + function getopt($args, $short_options, $long_options = null) + { + return Console_Getopt::doGetopt(1, $args, $short_options, $long_options); + } + + /** + * The actual implementation of the argument parsing code. + */ + function doGetopt($version, $args, $short_options, $long_options = null) + { + // in case you pass directly readPHPArgv() as the first arg + if (PEAR::isError($args)) { + return $args; + } + if (empty($args)) { + return array(array(), array()); + } + $opts = array(); + $non_opts = array(); + + settype($args, 'array'); + + if ($long_options) { + sort($long_options); + } + + /* + * Preserve backwards compatibility with callers that relied on + * erroneous POSIX fix. + */ + if ($version < 2) { + if (isset($args[0]{0}) && $args[0]{0} != '-') { + array_shift($args); + } + } + + reset($args); + while (list($i, $arg) = each($args)) { + + /* The special element '--' means explicit end of + options. Treat the rest of the arguments as non-options + and end the loop. */ + if ($arg == '--') { + $non_opts = array_merge($non_opts, array_slice($args, $i + 1)); + break; + } + + if ($arg{0} != '-' || (strlen($arg) > 1 && $arg{1} == '-' && !$long_options)) { + $non_opts = array_merge($non_opts, array_slice($args, $i)); + break; + } elseif (strlen($arg) > 1 && $arg{1} == '-') { + $error = Console_Getopt::_parseLongOption(substr($arg, 2), $long_options, $opts, $args); + if (PEAR::isError($error)) + return $error; + } elseif ($arg == '-') { + // - is stdin + $non_opts = array_merge($non_opts, array_slice($args, $i)); + break; + } else { + $error = Console_Getopt::_parseShortOption(substr($arg, 1), $short_options, $opts, $args); + if (PEAR::isError($error)) + return $error; + } + } + + return array($opts, $non_opts); + } + + /** + * @access private + * + */ + function _parseShortOption($arg, $short_options, &$opts, &$args) + { + for ($i = 0; $i < strlen($arg); $i++) { + $opt = $arg{$i}; + $opt_arg = null; + + /* Try to find the short option in the specifier string. */ + if (($spec = strstr($short_options, $opt)) === false || $arg{$i} == ':') + { + return PEAR::raiseError("Console_Getopt: unrecognized option -- $opt"); + } + + if (strlen($spec) > 1 && $spec{1} == ':') { + if (strlen($spec) > 2 && $spec{2} == ':') { + if ($i + 1 < strlen($arg)) { + /* Option takes an optional argument. Use the remainder of + the arg string if there is anything left. */ + $opts[] = array($opt, substr($arg, $i + 1)); + break; + } + } else { + /* Option requires an argument. Use the remainder of the arg + string if there is anything left. */ + if ($i + 1 < strlen($arg)) { + $opts[] = array($opt, substr($arg, $i + 1)); + break; + } else if (list(, $opt_arg) = each($args)) { + /* Else use the next argument. */; + if (Console_Getopt::_isShortOpt($opt_arg) || Console_Getopt::_isLongOpt($opt_arg)) { + return PEAR::raiseError("Console_Getopt: option requires an argument -- $opt"); + } + } else { + return PEAR::raiseError("Console_Getopt: option requires an argument -- $opt"); + } + } + } + + $opts[] = array($opt, $opt_arg); + } + } + + /** + * @access private + * + */ + function _isShortOpt($arg) + { + return strlen($arg) == 2 && $arg[0] == '-' && preg_match('/[a-zA-Z]/', $arg[1]); + } + + /** + * @access private + * + */ + function _isLongOpt($arg) + { + return strlen($arg) > 2 && $arg[0] == '-' && $arg[1] == '-' && + preg_match('/[a-zA-Z]+$/', substr($arg, 2)); + } + + /** + * @access private + * + */ + function _parseLongOption($arg, $long_options, &$opts, &$args) + { + @list($opt, $opt_arg) = explode('=', $arg, 2); + $opt_len = strlen($opt); + + for ($i = 0; $i < count($long_options); $i++) { + $long_opt = $long_options[$i]; + $opt_start = substr($long_opt, 0, $opt_len); + $long_opt_name = str_replace('=', '', $long_opt); + + /* Option doesn't match. Go on to the next one. */ + if ($long_opt_name != $opt) { + continue; + } + + $opt_rest = substr($long_opt, $opt_len); + + /* Check that the options uniquely matches one of the allowed + options. */ + if ($i + 1 < count($long_options)) { + $next_option_rest = substr($long_options[$i + 1], $opt_len); + } else { + $next_option_rest = ''; + } + if ($opt_rest != '' && $opt{0} != '=' && + $i + 1 < count($long_options) && + $opt == substr($long_options[$i+1], 0, $opt_len) && + $next_option_rest != '' && + $next_option_rest{0} != '=') { + return PEAR::raiseError("Console_Getopt: option --$opt is ambiguous"); + } + + if (substr($long_opt, -1) == '=') { + if (substr($long_opt, -2) != '==') { + /* Long option requires an argument. + Take the next argument if one wasn't specified. */; + if (!strlen($opt_arg) && !(list(, $opt_arg) = each($args))) { + return PEAR::raiseError("Console_Getopt: option --$opt requires an argument"); + } + if (Console_Getopt::_isShortOpt($opt_arg) || Console_Getopt::_isLongOpt($opt_arg)) { + return PEAR::raiseError("Console_Getopt: option requires an argument --$opt"); + } + } + } else if ($opt_arg) { + return PEAR::raiseError("Console_Getopt: option --$opt doesn't allow an argument"); + } + + $opts[] = array('--' . $opt, $opt_arg); + return; + } + + return PEAR::raiseError("Console_Getopt: unrecognized option --$opt"); + } + + /** + * Safely read the $argv PHP array across different PHP configurations. + * Will take care on register_globals and register_argc_argv ini directives + * + * @access public + * @return mixed the $argv PHP array or PEAR error if not registered + */ + function readPHPArgv() + { + global $argv; + if (!is_array($argv)) { + if (!@is_array($_SERVER['argv'])) { + if (!@is_array($GLOBALS['HTTP_SERVER_VARS']['argv'])) { + return PEAR::raiseError("Console_Getopt: Could not read cmd args (register_argc_argv=Off?)"); + } + return $GLOBALS['HTTP_SERVER_VARS']['argv']; + } + return $_SERVER['argv']; + } + return $argv; + } + +} + +?> From e14322672cc24adc27efc2aeaafee60ef03ab650 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 22 Jun 2009 14:56:53 -0700 Subject: [PATCH 164/262] note about Console_Getopt --- README | 1 + 1 file changed, 1 insertion(+) diff --git a/README b/README index cd663d931b..de10996006 100644 --- a/README +++ b/README @@ -180,6 +180,7 @@ and the URLs are listed here for your convenience. - PEAR HTTP_Request is an oEmbed dependency. - PEAR Validate is an oEmbed dependency. - PEAR Net_URL2 is an oEmbed dependency. +- Console_GetOpt for parsing command-line options. A design goal of Laconica is that the basic Web functionality should work on even the most restrictive commercial hosting services. From 9171f16b730176717b0b9abf84ace10b7a6dddc7 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 22 Jun 2009 15:29:24 -0700 Subject: [PATCH 165/262] add commandline.inc for parsing --- lib/common.php | 16 +++--- scripts/commandline.inc | 107 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 117 insertions(+), 6 deletions(-) create mode 100644 scripts/commandline.inc diff --git a/lib/common.php b/lib/common.php index a8c7634f62..2327dcb0e1 100644 --- a/lib/common.php +++ b/lib/common.php @@ -269,15 +269,19 @@ if (function_exists('date_default_timezone_set')) { // server-wide, then vhost-wide, then for a path, // finally for a dir (usually only need one of the last two). -$_config_files = array('/etc/laconica/laconica.php', - '/etc/laconica/'.$_server.'.php'); +if (isset($conffile)) { + $_config_files = array($conffile); +} else { + $_config_files = array('/etc/laconica/laconica.php', + '/etc/laconica/'.$_server.'.php'); -if (strlen($_path) > 0) { - $_config_files[] = '/etc/laconica/'.$_server.'_'.$_path.'.php'; + if (strlen($_path) > 0) { + $_config_files[] = '/etc/laconica/'.$_server.'_'.$_path.'.php'; + } + + $_config_files[] = INSTALLDIR.'/config.php'; } -$_config_files[] = INSTALLDIR.'/config.php'; - $_have_a_config = false; foreach ($_config_files as $_config_file) { diff --git a/scripts/commandline.inc b/scripts/commandline.inc new file mode 100644 index 0000000000..292005dcaf --- /dev/null +++ b/scripts/commandline.inc @@ -0,0 +1,107 @@ +. + */ + +// -*- mode: php -*- + +# Abort if called from a web server + +if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) { + print "This script must be run from the command line\n"; + exit(); +} + +define('LACONICA', true); + +// Set various flags so we don't time out on long-running processes + +ini_set("max_execution_time", "0"); +ini_set("max_input_time", "0"); +set_time_limit(0); +mb_internal_encoding('UTF-8'); + +// Add extlib to our path so we can get Console_Getopt + +$_extra_path = array(INSTALLDIR.'/extlib/'); + +set_include_path(implode(PATH_SEPARATOR, $_extra_path) . PATH_SEPARATOR . get_include_path()); + +require_once 'Console/Getopt.php'; + +// Note: $shortoptions and $longoptions should be pre-defined! + +$_default_shortoptions = 'qvhc:s:p:'; + +$_default_longoptions = array('quiet', 'verbose', 'help', 'conf=', 'server=', 'path='); + +if (isset($shortoptions)) { + $shortoptions .= $_default_shortoptions; +} else { + $shortoptions = $_default_shortoptions; +} + +if (isset($longoptions)) { + $longoptions = array_merge($longoptions, $_default_longoptions); +} else { + $longoptions = $_default_longoptions; +} + +$parser = new Console_Getopt(); + +list($options, $args) = $parser->getopt($argv, $shortoptions, $longoptions); + +foreach ($options as $option) { + + switch ($option[0]) { + case '--server': + case '-s': + $server = $option[1]; + break; + + case '--path': + case '-p': + $path = $option[1]; + break; + + case '--conf': + case '-c': + $conffile = $option[1]; + break; + + case '--help': + case '-h': + $_default_help_text = << Use as config file + -s --server= Use as server name + -p --path= Use as path name + -h --help Show this message and quit. + +END_OF_DEFAULT; + if (isset($helptext)) { + print $helptext; + } + print $_default_help_text; + exit(0); + } +} + +require_once INSTALLDIR . '/lib/common.php'; From 00bf031f0ba3c603b2d99808340da97897548b28 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 22 Jun 2009 15:29:43 -0700 Subject: [PATCH 166/262] change fixup_conversations to use commandline.inc --- scripts/fixup_conversations.php | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/scripts/fixup_conversations.php b/scripts/fixup_conversations.php index d4a47cfeef..2cfa422e65 100755 --- a/scripts/fixup_conversations.php +++ b/scripts/fixup_conversations.php @@ -18,16 +18,9 @@ * along with this program. If not, see . */ -# Abort if called from a web server -if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) { - print "This script must be run from the command line\n"; - exit(); -} - define('INSTALLDIR', realpath(dirname(__FILE__) . '/..')); -define('LACONICA', true); -require_once(INSTALLDIR . '/lib/common.php'); +require_once INSTALLDIR.'/scripts/commandline.inc'; common_log(LOG_INFO, 'Fixing up conversations.'); @@ -72,8 +65,3 @@ while ($notice->fetch()) { print ".\n"; } - -ini_set("max_execution_time", "0"); -ini_set("max_input_time", "0"); -set_time_limit(0); -mb_internal_encoding('UTF-8'); From c9ca46f7c125b7a012f8bc85b9a37f1ae7468c77 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 22 Jun 2009 15:35:27 -0700 Subject: [PATCH 167/262] make enjit queue handler take command-line arguments --- scripts/enjitqueuehandler.php | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/scripts/enjitqueuehandler.php b/scripts/enjitqueuehandler.php index 15ab3a4270..c17b4e27f4 100755 --- a/scripts/enjitqueuehandler.php +++ b/scripts/enjitqueuehandler.php @@ -18,23 +18,22 @@ * along with this program. If not, see . */ -# Abort if called from a web server -if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) { - print "This script must be run from the command line\n"; - exit(); -} - define('INSTALLDIR', realpath(dirname(__FILE__) . '/..')); -define('LACONICA', true); -// Preset the server at the command line +$shortoptions = 'i'; +$longoptions = array('id'); -$server = ($argc > 2) ? $argv[2] : null; -$path = ($argc > 3) ? $argv[3] : null; +$helptext = << 1) ? $argv[1] : null; +$id = NULL; + +foreach ($options as $option) { + if ($option[0] == '--id' || $option[0] == '-i') { + $id = $option[1]; + break; + } +} $handler = new EnjitQueueHandler($id); From a81350f6559a59921443d9773eccc9f8cfd96ee1 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 22 Jun 2009 15:41:52 -0700 Subject: [PATCH 168/262] functions to check options --- scripts/commandline.inc | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/scripts/commandline.inc b/scripts/commandline.inc index 292005dcaf..8da42873a2 100644 --- a/scripts/commandline.inc +++ b/scripts/commandline.inc @@ -105,3 +105,27 @@ END_OF_DEFAULT; } require_once INSTALLDIR . '/lib/common.php'; + +set_error_handler('common_error_handler'); + +function have_option($str) +{ + global $options; + foreach ($options as $option) { + if ($option[0] == $str) { + return true; + } + } + return false; +} + +function get_option_value($str) +{ + global $options; + foreach ($options as $option) { + if ($option[0] == $str) { + return $option[1]; + } + } + return null; +} \ No newline at end of file From 0b6f3870ad1f77594e8f6dda18465188400aa2e5 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 22 Jun 2009 15:42:16 -0700 Subject: [PATCH 169/262] enjitqueuehandler uses functions to check options --- scripts/enjitqueuehandler.php | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/scripts/enjitqueuehandler.php b/scripts/enjitqueuehandler.php index c17b4e27f4..2418d2d1c5 100755 --- a/scripts/enjitqueuehandler.php +++ b/scripts/enjitqueuehandler.php @@ -120,15 +120,12 @@ class EnjitQueueHandler extends QueueHandler } -mb_internal_encoding('UTF-8'); - -$id = NULL; - -foreach ($options as $option) { - if ($option[0] == '--id' || $option[0] == '-i') { - $id = $option[1]; - break; - } +if (have_option('-i')) { + $id = get_option_value('-i'); +} else if (have_option('--id')) { + $id = get_option_value('--id'); +} else { + $id = null; } $handler = new EnjitQueueHandler($id); From 6a40ba776477ec6e70a523fd3c5a4122a72c3208 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 22 Jun 2009 15:43:26 -0700 Subject: [PATCH 170/262] make enjitqueuehandler use functions and args --- scripts/enjitqueuehandler.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/enjitqueuehandler.php b/scripts/enjitqueuehandler.php index 2418d2d1c5..5091347658 100755 --- a/scripts/enjitqueuehandler.php +++ b/scripts/enjitqueuehandler.php @@ -124,6 +124,8 @@ if (have_option('-i')) { $id = get_option_value('-i'); } else if (have_option('--id')) { $id = get_option_value('--id'); +} else if (count($args) > 0) { + $id = $args[0]; } else { $id = null; } From 032b65b83ab3c76dca4d1935334915de931fef97 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 22 Jun 2009 15:43:39 -0700 Subject: [PATCH 171/262] make facebookqueuehandler use command-line functions and args --- scripts/facebookqueuehandler.php | 42 +++++++++++++++----------------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/scripts/facebookqueuehandler.php b/scripts/facebookqueuehandler.php index f9123db8ce..f01e45a3b4 100755 --- a/scripts/facebookqueuehandler.php +++ b/scripts/facebookqueuehandler.php @@ -18,29 +18,25 @@ * along with this program. If not, see . */ -# Abort if called from a web server -if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) { - print "This script must be run from the command line\n"; - exit(); -} - define('INSTALLDIR', realpath(dirname(__FILE__) . '/..')); -define('LACONICA', true); -// Preset the server at the command line +$shortoptions = 'i'; +$longoptions = array('id'); -$server = ($argc > 2) ? $argv[2] : null; -$path = ($argc > 3) ? $argv[3] : null; +$helptext = << 1) ? $argv[1] : null; +if (have_option('-i')) { + $id = get_option_value('-i'); +} else if (have_option('--id')) { + $id = get_option_value('--id'); +} else if (count($args) > 0) { + $id = $args[0]; +} else { + $id = null; +} $handler = new FacebookQueueHandler($id); From 273d9e2def8b7ad003d39ca3210b502d8981a8cb Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 22 Jun 2009 15:47:29 -0700 Subject: [PATCH 172/262] jabberqueuehandler uses commandline stuff --- scripts/jabberqueuehandler.php | 42 +++++++++++++++++----------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/scripts/jabberqueuehandler.php b/scripts/jabberqueuehandler.php index b848442fd1..be0f187a98 100755 --- a/scripts/jabberqueuehandler.php +++ b/scripts/jabberqueuehandler.php @@ -18,29 +18,26 @@ * along with this program. If not, see . */ -# Abort if called from a web server -if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) { - print "This script must be run from the command line\n"; - exit(); -} - define('INSTALLDIR', realpath(dirname(__FILE__) . '/..')); -define('LACONICA', true); -// Preset the server at the command line +$shortoptions = 'r'; +$longoptions = array('resource'); -$server = ($argc > 2) ? $argv[2] : null; -$path = ($argc > 3) ? $argv[3] : null; +$helptext = << 1) ? $argv[1] : (common_config('xmpp','resource') . '-queuehandler'); +if (have_option('-r')) { + $resource = get_option_value('-r'); +} else if (have_option('--resource')) { + $resource = get_option_value('--resource'); +} else if (count($args) > 0) { + $resource = $args[0]; +} else { + $resource = null; +} $handler = new JabberQueueHandler($resource); From d9bebfd6512353690be8bf8cc596a0656ef48ae9 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Mon, 22 Jun 2009 22:48:31 +0000 Subject: [PATCH 173/262] Attachment upload server and path now configurable --- actions/newnotice.php | 34 +++++++++++++++++++------ classes/File.php | 58 +++++++++++++++++++++++++++++++++++++------ 2 files changed, 77 insertions(+), 15 deletions(-) diff --git a/actions/newnotice.php b/actions/newnotice.php index 72ccd8c325..09652d2b36 100644 --- a/actions/newnotice.php +++ b/actions/newnotice.php @@ -257,23 +257,43 @@ class NewnoticeAction extends Action } function storeFile($notice, $mimetype) { - $filename = basename($_FILES['attach']['name']); - $destination = "file/{$notice->id}-$filename"; - if (move_uploaded_file($_FILES['attach']['tmp_name'], INSTALLDIR . "/$destination")) { + + common_debug("NewnoticeAction::storeFile()"); + + $basename = basename($_FILES['attach']['name']); + + common_debug("Basename: $basename"); + + $filename = File::filename($notice->id, $basename); + + common_debug("filename: $filename"); + + $filepath = File::path($filename); + + common_debug("filepath: $filepath"); + + if (move_uploaded_file($_FILES['attach']['tmp_name'], $filepath)) { + $file = new File; + $file->filename = $filename; + $file->url = common_local_url('file', array('notice' => $notice->id)); - $file->size = filesize(INSTALLDIR . "/$destination"); + + common_debug("file->url =". $file->url); + + $file->size = filesize($filepath); $file->date = time(); $file->mimetype = $mimetype; + if ($file_id = $file->insert()) { $file_redir = new File_redirection; - $file_redir->url = common_path($destination); + $file_redir->url = File::url($filename); $file_redir->file_id = $file_id; $file_redir->insert(); $f2p = new File_to_post; - $f2p->file_id = $file_id; - $f2p->post_id = $notice->id; + $f2p->file_id = $file_id; + $f2p->post_id = $notice->id; $f2p->insert(); } else { $this->clientError(_('There was a database error while saving your file. Please try again.')); diff --git a/classes/File.php b/classes/File.php index 47af1c5506..1de136240d 100644 --- a/classes/File.php +++ b/classes/File.php @@ -30,7 +30,7 @@ require_once INSTALLDIR.'/classes/File_to_post.php'; * Table Definition for file */ -class File extends Memcached_DataObject +class File extends Memcached_DataObject { ###START_AUTOCODE /* the code below is auto generated do not remove the above tag */ @@ -38,12 +38,12 @@ class File extends Memcached_DataObject public $__table = 'file'; // table name public $id; // int(4) primary_key not_null public $url; // varchar(255) unique_key - public $mimetype; // varchar(50) - public $size; // int(4) - public $title; // varchar(255) - public $date; // int(4) - public $protected; // int(4) - public $filename; // varchar(255) + public $mimetype; // varchar(50) + public $size; // int(4) + public $title; // varchar(255) + public $date; // int(4) + public $protected; // int(4) + public $filename; // varchar(255) public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP /* Static get */ @@ -116,7 +116,7 @@ class File extends Memcached_DataObject $x = File::staticGet($file_id); if (empty($x)) die('Impossible!'); } - + File_to_post::processNew($file_id, $notice_id); return $x; } @@ -145,5 +145,47 @@ class File extends Memcached_DataObject } return true; } + + // where should the file go? + + static function filename($notice_id, $basename) + { + return $notice_id . '-' . $basename; + } + + static function path($filename) + { + $dir = common_config('attachments', 'dir'); + + if ($dir[strlen($dir)-1] != '/') { + $dir .= '/'; + } + + return $dir . $filename; + } + + static function url($filename) + { + $path = common_config('attachments', 'path'); + + if ($path[strlen($path)-1] != '/') { + $path .= '/'; + } + + if ($path[0] != '/') { + $path = '/'.$path; + } + + $server = common_config('attachments', 'server'); + + if (empty($server)) { + $server = common_config('site', 'server'); + } + + // XXX: protocol + + return 'http://'.$server.$path.$filename; + } + } From ef88758a374a47fb377aa5ceb41b0276558d3d33 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 22 Jun 2009 15:49:08 -0700 Subject: [PATCH 174/262] ombqueuehandler uses commandline --- scripts/ombqueuehandler.php | 40 +++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/scripts/ombqueuehandler.php b/scripts/ombqueuehandler.php index 4c5890f57c..131b6513c5 100755 --- a/scripts/ombqueuehandler.php +++ b/scripts/ombqueuehandler.php @@ -18,23 +18,22 @@ * along with this program. If not, see . */ -# Abort if called from a web server -if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) { - print "This script must be run from the command line\n"; - exit(); -} - define('INSTALLDIR', realpath(dirname(__FILE__) . '/..')); -define('LACONICA', true); -// Preset the server at the command line +$shortoptions = 'i'; +$longoptions = array('id'); -$server = ($argc > 2) ? $argv[2] : null; -$path = ($argc > 3) ? $argv[3] : null; +$helptext = << 1) ? $argv[1] : null; +if (have_option('-i')) { + $id = get_option_value('-i'); +} else if (have_option('--id')) { + $id = get_option_value('--id'); +} else if (count($args) > 0) { + $id = $args[0]; +} else { + $id = null; +} $handler = new OmbQueueHandler($id); From 3cbdc684546544a2ba71ba36897b1ca24df92548 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 22 Jun 2009 15:51:03 -0700 Subject: [PATCH 175/262] better help for ombqueuehandler --- scripts/ombqueuehandler.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/ombqueuehandler.php b/scripts/ombqueuehandler.php index 131b6513c5..deb5f8d7d2 100755 --- a/scripts/ombqueuehandler.php +++ b/scripts/ombqueuehandler.php @@ -23,12 +23,12 @@ define('INSTALLDIR', realpath(dirname(__FILE__) . '/..')); $shortoptions = 'i'; $longoptions = array('id'); -$helptext = << Date: Mon, 22 Jun 2009 15:51:14 -0700 Subject: [PATCH 176/262] pingqueuehandler uses commandline --- scripts/pingqueuehandler.php | 40 ++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/scripts/pingqueuehandler.php b/scripts/pingqueuehandler.php index 84ef9be277..1bde4bc5fd 100644 --- a/scripts/pingqueuehandler.php +++ b/scripts/pingqueuehandler.php @@ -18,25 +18,22 @@ * along with this program. If not, see . */ -# Abort if called from a web server -if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) { - print "This script must be run from the command line\n"; - exit(); -} - define('INSTALLDIR', realpath(dirname(__FILE__) . '/..')); -define('LACONICA', true); -// Preset the server at the command line +$shortoptions = 'i'; +$longoptions = array('id'); -$server = ($argc > 2) ? $argv[2] : null; -$path = ($argc > 3) ? $argv[3] : null; +$helptext = << 1) ? $argv[1] : NULL; +if (have_option('-i')) { + $id = get_option_value('-i'); +} else if (have_option('--id')) { + $id = get_option_value('--id'); +} else if (count($args) > 0) { + $id = $args[0]; +} else { + $id = null; +} $handler = new PingQueueHandler($id); From 07cb587cda7f47db0b048576b79773d1ea9b6376 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 22 Jun 2009 15:53:11 -0700 Subject: [PATCH 177/262] publicqueuehandler uses commandline --- scripts/publicqueuehandler.php | 40 +++++++++++++++++----------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/scripts/publicqueuehandler.php b/scripts/publicqueuehandler.php index 017174ed8a..c10c679108 100755 --- a/scripts/publicqueuehandler.php +++ b/scripts/publicqueuehandler.php @@ -18,25 +18,22 @@ * along with this program. If not, see . */ -# Abort if called from a web server -if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) { - print "This script must be run from the command line\n"; - exit(); -} - define('INSTALLDIR', realpath(dirname(__FILE__) . '/..')); -define('LACONICA', true); -// Preset the server at the command line +$shortoptions = 'r'; +$longoptions = array('resource'); -$server = ($argc > 2) ? $argv[2] : null; -$path = ($argc > 3) ? $argv[3] : null; +$helptext = << 1) ? $argv[1] : (common_config('xmpp','resource') . '-public'); +if (have_option('-r')) { + $resource = get_option_value('-r'); +} else if (have_option('--resource')) { + $resource = get_option_value('--resource'); +} else if (count($args) > 0) { + $resource = $args[0]; +} else { + $resource = null; +} $handler = new PublicQueueHandler($resource); From f0e6e4b0ff8eec45a8c9e4b081d81b1d40c4b2bc Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 22 Jun 2009 15:55:05 -0700 Subject: [PATCH 178/262] reportsnapshot.php supports commandline --- scripts/reportsnapshot.php | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/scripts/reportsnapshot.php b/scripts/reportsnapshot.php index e332d856c0..c644b557f0 100644 --- a/scripts/reportsnapshot.php +++ b/scripts/reportsnapshot.php @@ -18,20 +18,13 @@ * along with this program. If not, see . */ -# Abort if called from a web server -if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) { - print "This script must be run from the command line\n"; - exit(1); -} - -ini_set("max_execution_time", "0"); -ini_set("max_input_time", "0"); -set_time_limit(0); -mb_internal_encoding('UTF-8'); - define('INSTALLDIR', realpath(dirname(__FILE__) . '/..')); -define('LACONICA', true); -require_once(INSTALLDIR . '/lib/common.php'); +$helptext = << Date: Mon, 22 Jun 2009 16:00:05 -0700 Subject: [PATCH 179/262] add a function to show help --- scripts/commandline.inc | 39 +++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/scripts/commandline.inc b/scripts/commandline.inc index 8da42873a2..a245b2f163 100644 --- a/scripts/commandline.inc +++ b/scripts/commandline.inc @@ -65,6 +65,28 @@ $parser = new Console_Getopt(); list($options, $args) = $parser->getopt($argv, $shortoptions, $longoptions); +function show_help() +{ + global $helptext; + + $_default_help_text = << Use as config file + -s --server= Use as server name + -p --path= Use as path name + -h --help Show this message and quit. + +END_OF_DEFAULT; + if (isset($helptext)) { + print $helptext; + } + print $_default_help_text; + exit(0); +} + foreach ($options as $option) { switch ($option[0]) { @@ -85,22 +107,7 @@ foreach ($options as $option) { case '--help': case '-h': - $_default_help_text = << Use as config file - -s --server= Use as server name - -p --path= Use as path name - -h --help Show this message and quit. - -END_OF_DEFAULT; - if (isset($helptext)) { - print $helptext; - } - print $_default_help_text; - exit(0); + show_help(); } } From 7721839efdf3a9b42ac94559425578a2285b042e Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 22 Jun 2009 16:00:19 -0700 Subject: [PATCH 180/262] setpassword.php uses commandline.inc --- scripts/setpassword.php | 31 ++++++++++++------------------- 1 file changed, 12 insertions(+), 19 deletions(-) diff --git a/scripts/setpassword.php b/scripts/setpassword.php index c417f741ab..b70689f030 100755 --- a/scripts/setpassword.php +++ b/scripts/setpassword.php @@ -18,30 +18,23 @@ * along with this program. If not, see . */ -# Abort if called from a web server -if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) { - print "This script must be run from the command line\n"; - exit(1); -} - -ini_set("max_execution_time", "0"); -ini_set("max_input_time", "0"); -set_time_limit(0); -mb_internal_encoding('UTF-8'); - define('INSTALLDIR', realpath(dirname(__FILE__) . '/..')); -define('LACONICA', true); -require_once(INSTALLDIR . '/lib/common.php'); +$helptext = << -if ($argc != 3) { - print "USAGE: setpassword.php \n"; - print "Sets the password of user with name to \n"; - exit(1); +Sets the password of user with name to + +END_OF_PASSWORD_HELP; + +require_once INSTALLDIR.'/scripts/commandline.inc'; + +if (count($args) < 2) { + show_help(); } -$nickname = $argv[1]; -$password = $argv[2]; +$nickname = $args[0]; +$password = $args[1]; if (mb_strlen($password) < 6) { print "Password must be 6 characters or more.\n"; From 164ddf01c5d9259340b0fa2f4accc7b06c2c5379 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 22 Jun 2009 16:04:35 -0700 Subject: [PATCH 181/262] Revert "note about Console_Getopt" This reverts commit e14322672cc24adc27efc2aeaafee60ef03ab650. Don't need it! --- README | 1 - 1 file changed, 1 deletion(-) diff --git a/README b/README index de10996006..cd663d931b 100644 --- a/README +++ b/README @@ -180,7 +180,6 @@ and the URLs are listed here for your convenience. - PEAR HTTP_Request is an oEmbed dependency. - PEAR Validate is an oEmbed dependency. - PEAR Net_URL2 is an oEmbed dependency. -- Console_GetOpt for parsing command-line options. A design goal of Laconica is that the basic Web functionality should work on even the most restrictive commercial hosting services. From 9fbb29111b8892d5ee1022f05019b7c99f8b8f12 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 22 Jun 2009 16:04:50 -0700 Subject: [PATCH 182/262] Revert "Add Console_Getopt" This reverts commit 79dcf0871fee6dfa3835d12f55d1099a716a6f4c. --- extlib/Console/Getopt.php | 290 -------------------------------------- 1 file changed, 290 deletions(-) delete mode 100644 extlib/Console/Getopt.php diff --git a/extlib/Console/Getopt.php b/extlib/Console/Getopt.php deleted file mode 100644 index bb9d69ca22..0000000000 --- a/extlib/Console/Getopt.php +++ /dev/null @@ -1,290 +0,0 @@ - | -// +----------------------------------------------------------------------+ -// -// $Id: Getopt.php,v 1.4 2007/06/12 14:58:56 cellog Exp $ - -require_once 'PEAR.php'; - -/** - * Command-line options parsing class. - * - * @author Andrei Zmievski - * - */ -class Console_Getopt { - /** - * Parses the command-line options. - * - * The first parameter to this function should be the list of command-line - * arguments without the leading reference to the running program. - * - * The second parameter is a string of allowed short options. Each of the - * option letters can be followed by a colon ':' to specify that the option - * requires an argument, or a double colon '::' to specify that the option - * takes an optional argument. - * - * The third argument is an optional array of allowed long options. The - * leading '--' should not be included in the option name. Options that - * require an argument should be followed by '=', and options that take an - * option argument should be followed by '=='. - * - * The return value is an array of two elements: the list of parsed - * options and the list of non-option command-line arguments. Each entry in - * the list of parsed options is a pair of elements - the first one - * specifies the option, and the second one specifies the option argument, - * if there was one. - * - * Long and short options can be mixed. - * - * Most of the semantics of this function are based on GNU getopt_long(). - * - * @param array $args an array of command-line arguments - * @param string $short_options specifies the list of allowed short options - * @param array $long_options specifies the list of allowed long options - * - * @return array two-element array containing the list of parsed options and - * the non-option arguments - * - * @access public - * - */ - function getopt2($args, $short_options, $long_options = null) - { - return Console_Getopt::doGetopt(2, $args, $short_options, $long_options); - } - - /** - * This function expects $args to start with the script name (POSIX-style). - * Preserved for backwards compatibility. - * @see getopt2() - */ - function getopt($args, $short_options, $long_options = null) - { - return Console_Getopt::doGetopt(1, $args, $short_options, $long_options); - } - - /** - * The actual implementation of the argument parsing code. - */ - function doGetopt($version, $args, $short_options, $long_options = null) - { - // in case you pass directly readPHPArgv() as the first arg - if (PEAR::isError($args)) { - return $args; - } - if (empty($args)) { - return array(array(), array()); - } - $opts = array(); - $non_opts = array(); - - settype($args, 'array'); - - if ($long_options) { - sort($long_options); - } - - /* - * Preserve backwards compatibility with callers that relied on - * erroneous POSIX fix. - */ - if ($version < 2) { - if (isset($args[0]{0}) && $args[0]{0} != '-') { - array_shift($args); - } - } - - reset($args); - while (list($i, $arg) = each($args)) { - - /* The special element '--' means explicit end of - options. Treat the rest of the arguments as non-options - and end the loop. */ - if ($arg == '--') { - $non_opts = array_merge($non_opts, array_slice($args, $i + 1)); - break; - } - - if ($arg{0} != '-' || (strlen($arg) > 1 && $arg{1} == '-' && !$long_options)) { - $non_opts = array_merge($non_opts, array_slice($args, $i)); - break; - } elseif (strlen($arg) > 1 && $arg{1} == '-') { - $error = Console_Getopt::_parseLongOption(substr($arg, 2), $long_options, $opts, $args); - if (PEAR::isError($error)) - return $error; - } elseif ($arg == '-') { - // - is stdin - $non_opts = array_merge($non_opts, array_slice($args, $i)); - break; - } else { - $error = Console_Getopt::_parseShortOption(substr($arg, 1), $short_options, $opts, $args); - if (PEAR::isError($error)) - return $error; - } - } - - return array($opts, $non_opts); - } - - /** - * @access private - * - */ - function _parseShortOption($arg, $short_options, &$opts, &$args) - { - for ($i = 0; $i < strlen($arg); $i++) { - $opt = $arg{$i}; - $opt_arg = null; - - /* Try to find the short option in the specifier string. */ - if (($spec = strstr($short_options, $opt)) === false || $arg{$i} == ':') - { - return PEAR::raiseError("Console_Getopt: unrecognized option -- $opt"); - } - - if (strlen($spec) > 1 && $spec{1} == ':') { - if (strlen($spec) > 2 && $spec{2} == ':') { - if ($i + 1 < strlen($arg)) { - /* Option takes an optional argument. Use the remainder of - the arg string if there is anything left. */ - $opts[] = array($opt, substr($arg, $i + 1)); - break; - } - } else { - /* Option requires an argument. Use the remainder of the arg - string if there is anything left. */ - if ($i + 1 < strlen($arg)) { - $opts[] = array($opt, substr($arg, $i + 1)); - break; - } else if (list(, $opt_arg) = each($args)) { - /* Else use the next argument. */; - if (Console_Getopt::_isShortOpt($opt_arg) || Console_Getopt::_isLongOpt($opt_arg)) { - return PEAR::raiseError("Console_Getopt: option requires an argument -- $opt"); - } - } else { - return PEAR::raiseError("Console_Getopt: option requires an argument -- $opt"); - } - } - } - - $opts[] = array($opt, $opt_arg); - } - } - - /** - * @access private - * - */ - function _isShortOpt($arg) - { - return strlen($arg) == 2 && $arg[0] == '-' && preg_match('/[a-zA-Z]/', $arg[1]); - } - - /** - * @access private - * - */ - function _isLongOpt($arg) - { - return strlen($arg) > 2 && $arg[0] == '-' && $arg[1] == '-' && - preg_match('/[a-zA-Z]+$/', substr($arg, 2)); - } - - /** - * @access private - * - */ - function _parseLongOption($arg, $long_options, &$opts, &$args) - { - @list($opt, $opt_arg) = explode('=', $arg, 2); - $opt_len = strlen($opt); - - for ($i = 0; $i < count($long_options); $i++) { - $long_opt = $long_options[$i]; - $opt_start = substr($long_opt, 0, $opt_len); - $long_opt_name = str_replace('=', '', $long_opt); - - /* Option doesn't match. Go on to the next one. */ - if ($long_opt_name != $opt) { - continue; - } - - $opt_rest = substr($long_opt, $opt_len); - - /* Check that the options uniquely matches one of the allowed - options. */ - if ($i + 1 < count($long_options)) { - $next_option_rest = substr($long_options[$i + 1], $opt_len); - } else { - $next_option_rest = ''; - } - if ($opt_rest != '' && $opt{0} != '=' && - $i + 1 < count($long_options) && - $opt == substr($long_options[$i+1], 0, $opt_len) && - $next_option_rest != '' && - $next_option_rest{0} != '=') { - return PEAR::raiseError("Console_Getopt: option --$opt is ambiguous"); - } - - if (substr($long_opt, -1) == '=') { - if (substr($long_opt, -2) != '==') { - /* Long option requires an argument. - Take the next argument if one wasn't specified. */; - if (!strlen($opt_arg) && !(list(, $opt_arg) = each($args))) { - return PEAR::raiseError("Console_Getopt: option --$opt requires an argument"); - } - if (Console_Getopt::_isShortOpt($opt_arg) || Console_Getopt::_isLongOpt($opt_arg)) { - return PEAR::raiseError("Console_Getopt: option requires an argument --$opt"); - } - } - } else if ($opt_arg) { - return PEAR::raiseError("Console_Getopt: option --$opt doesn't allow an argument"); - } - - $opts[] = array('--' . $opt, $opt_arg); - return; - } - - return PEAR::raiseError("Console_Getopt: unrecognized option --$opt"); - } - - /** - * Safely read the $argv PHP array across different PHP configurations. - * Will take care on register_globals and register_argc_argv ini directives - * - * @access public - * @return mixed the $argv PHP array or PEAR error if not registered - */ - function readPHPArgv() - { - global $argv; - if (!is_array($argv)) { - if (!@is_array($_SERVER['argv'])) { - if (!@is_array($GLOBALS['HTTP_SERVER_VARS']['argv'])) { - return PEAR::raiseError("Console_Getopt: Could not read cmd args (register_argc_argv=Off?)"); - } - return $GLOBALS['HTTP_SERVER_VARS']['argv']; - } - return $_SERVER['argv']; - } - return $argv; - } - -} - -?> From 18ba41e0a4edd734d0bd6a991f5f9f301cd6e908 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 22 Jun 2009 16:18:41 -0700 Subject: [PATCH 183/262] Revert "Revert "Add Console_Getopt"" This reverts commit 9fbb29111b8892d5ee1022f05019b7c99f8b8f12. --- extlib/Console/Getopt.php | 290 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 290 insertions(+) create mode 100644 extlib/Console/Getopt.php diff --git a/extlib/Console/Getopt.php b/extlib/Console/Getopt.php new file mode 100644 index 0000000000..bb9d69ca22 --- /dev/null +++ b/extlib/Console/Getopt.php @@ -0,0 +1,290 @@ + | +// +----------------------------------------------------------------------+ +// +// $Id: Getopt.php,v 1.4 2007/06/12 14:58:56 cellog Exp $ + +require_once 'PEAR.php'; + +/** + * Command-line options parsing class. + * + * @author Andrei Zmievski + * + */ +class Console_Getopt { + /** + * Parses the command-line options. + * + * The first parameter to this function should be the list of command-line + * arguments without the leading reference to the running program. + * + * The second parameter is a string of allowed short options. Each of the + * option letters can be followed by a colon ':' to specify that the option + * requires an argument, or a double colon '::' to specify that the option + * takes an optional argument. + * + * The third argument is an optional array of allowed long options. The + * leading '--' should not be included in the option name. Options that + * require an argument should be followed by '=', and options that take an + * option argument should be followed by '=='. + * + * The return value is an array of two elements: the list of parsed + * options and the list of non-option command-line arguments. Each entry in + * the list of parsed options is a pair of elements - the first one + * specifies the option, and the second one specifies the option argument, + * if there was one. + * + * Long and short options can be mixed. + * + * Most of the semantics of this function are based on GNU getopt_long(). + * + * @param array $args an array of command-line arguments + * @param string $short_options specifies the list of allowed short options + * @param array $long_options specifies the list of allowed long options + * + * @return array two-element array containing the list of parsed options and + * the non-option arguments + * + * @access public + * + */ + function getopt2($args, $short_options, $long_options = null) + { + return Console_Getopt::doGetopt(2, $args, $short_options, $long_options); + } + + /** + * This function expects $args to start with the script name (POSIX-style). + * Preserved for backwards compatibility. + * @see getopt2() + */ + function getopt($args, $short_options, $long_options = null) + { + return Console_Getopt::doGetopt(1, $args, $short_options, $long_options); + } + + /** + * The actual implementation of the argument parsing code. + */ + function doGetopt($version, $args, $short_options, $long_options = null) + { + // in case you pass directly readPHPArgv() as the first arg + if (PEAR::isError($args)) { + return $args; + } + if (empty($args)) { + return array(array(), array()); + } + $opts = array(); + $non_opts = array(); + + settype($args, 'array'); + + if ($long_options) { + sort($long_options); + } + + /* + * Preserve backwards compatibility with callers that relied on + * erroneous POSIX fix. + */ + if ($version < 2) { + if (isset($args[0]{0}) && $args[0]{0} != '-') { + array_shift($args); + } + } + + reset($args); + while (list($i, $arg) = each($args)) { + + /* The special element '--' means explicit end of + options. Treat the rest of the arguments as non-options + and end the loop. */ + if ($arg == '--') { + $non_opts = array_merge($non_opts, array_slice($args, $i + 1)); + break; + } + + if ($arg{0} != '-' || (strlen($arg) > 1 && $arg{1} == '-' && !$long_options)) { + $non_opts = array_merge($non_opts, array_slice($args, $i)); + break; + } elseif (strlen($arg) > 1 && $arg{1} == '-') { + $error = Console_Getopt::_parseLongOption(substr($arg, 2), $long_options, $opts, $args); + if (PEAR::isError($error)) + return $error; + } elseif ($arg == '-') { + // - is stdin + $non_opts = array_merge($non_opts, array_slice($args, $i)); + break; + } else { + $error = Console_Getopt::_parseShortOption(substr($arg, 1), $short_options, $opts, $args); + if (PEAR::isError($error)) + return $error; + } + } + + return array($opts, $non_opts); + } + + /** + * @access private + * + */ + function _parseShortOption($arg, $short_options, &$opts, &$args) + { + for ($i = 0; $i < strlen($arg); $i++) { + $opt = $arg{$i}; + $opt_arg = null; + + /* Try to find the short option in the specifier string. */ + if (($spec = strstr($short_options, $opt)) === false || $arg{$i} == ':') + { + return PEAR::raiseError("Console_Getopt: unrecognized option -- $opt"); + } + + if (strlen($spec) > 1 && $spec{1} == ':') { + if (strlen($spec) > 2 && $spec{2} == ':') { + if ($i + 1 < strlen($arg)) { + /* Option takes an optional argument. Use the remainder of + the arg string if there is anything left. */ + $opts[] = array($opt, substr($arg, $i + 1)); + break; + } + } else { + /* Option requires an argument. Use the remainder of the arg + string if there is anything left. */ + if ($i + 1 < strlen($arg)) { + $opts[] = array($opt, substr($arg, $i + 1)); + break; + } else if (list(, $opt_arg) = each($args)) { + /* Else use the next argument. */; + if (Console_Getopt::_isShortOpt($opt_arg) || Console_Getopt::_isLongOpt($opt_arg)) { + return PEAR::raiseError("Console_Getopt: option requires an argument -- $opt"); + } + } else { + return PEAR::raiseError("Console_Getopt: option requires an argument -- $opt"); + } + } + } + + $opts[] = array($opt, $opt_arg); + } + } + + /** + * @access private + * + */ + function _isShortOpt($arg) + { + return strlen($arg) == 2 && $arg[0] == '-' && preg_match('/[a-zA-Z]/', $arg[1]); + } + + /** + * @access private + * + */ + function _isLongOpt($arg) + { + return strlen($arg) > 2 && $arg[0] == '-' && $arg[1] == '-' && + preg_match('/[a-zA-Z]+$/', substr($arg, 2)); + } + + /** + * @access private + * + */ + function _parseLongOption($arg, $long_options, &$opts, &$args) + { + @list($opt, $opt_arg) = explode('=', $arg, 2); + $opt_len = strlen($opt); + + for ($i = 0; $i < count($long_options); $i++) { + $long_opt = $long_options[$i]; + $opt_start = substr($long_opt, 0, $opt_len); + $long_opt_name = str_replace('=', '', $long_opt); + + /* Option doesn't match. Go on to the next one. */ + if ($long_opt_name != $opt) { + continue; + } + + $opt_rest = substr($long_opt, $opt_len); + + /* Check that the options uniquely matches one of the allowed + options. */ + if ($i + 1 < count($long_options)) { + $next_option_rest = substr($long_options[$i + 1], $opt_len); + } else { + $next_option_rest = ''; + } + if ($opt_rest != '' && $opt{0} != '=' && + $i + 1 < count($long_options) && + $opt == substr($long_options[$i+1], 0, $opt_len) && + $next_option_rest != '' && + $next_option_rest{0} != '=') { + return PEAR::raiseError("Console_Getopt: option --$opt is ambiguous"); + } + + if (substr($long_opt, -1) == '=') { + if (substr($long_opt, -2) != '==') { + /* Long option requires an argument. + Take the next argument if one wasn't specified. */; + if (!strlen($opt_arg) && !(list(, $opt_arg) = each($args))) { + return PEAR::raiseError("Console_Getopt: option --$opt requires an argument"); + } + if (Console_Getopt::_isShortOpt($opt_arg) || Console_Getopt::_isLongOpt($opt_arg)) { + return PEAR::raiseError("Console_Getopt: option requires an argument --$opt"); + } + } + } else if ($opt_arg) { + return PEAR::raiseError("Console_Getopt: option --$opt doesn't allow an argument"); + } + + $opts[] = array('--' . $opt, $opt_arg); + return; + } + + return PEAR::raiseError("Console_Getopt: unrecognized option --$opt"); + } + + /** + * Safely read the $argv PHP array across different PHP configurations. + * Will take care on register_globals and register_argc_argv ini directives + * + * @access public + * @return mixed the $argv PHP array or PEAR error if not registered + */ + function readPHPArgv() + { + global $argv; + if (!is_array($argv)) { + if (!@is_array($_SERVER['argv'])) { + if (!@is_array($GLOBALS['HTTP_SERVER_VARS']['argv'])) { + return PEAR::raiseError("Console_Getopt: Could not read cmd args (register_argc_argv=Off?)"); + } + return $GLOBALS['HTTP_SERVER_VARS']['argv']; + } + return $_SERVER['argv']; + } + return $argv; + } + +} + +?> From 10cc0e157e86a51c5671630af267e4c9dd459619 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 22 Jun 2009 16:18:50 -0700 Subject: [PATCH 184/262] Revert "Revert "note about Console_Getopt"" This reverts commit 164ddf01c5d9259340b0fa2f4accc7b06c2c5379. --- README | 1 + 1 file changed, 1 insertion(+) diff --git a/README b/README index cd663d931b..de10996006 100644 --- a/README +++ b/README @@ -180,6 +180,7 @@ and the URLs are listed here for your convenience. - PEAR HTTP_Request is an oEmbed dependency. - PEAR Validate is an oEmbed dependency. - PEAR Net_URL2 is an oEmbed dependency. +- Console_GetOpt for parsing command-line options. A design goal of Laconica is that the basic Web functionality should work on even the most restrictive commercial hosting services. From 118ab60cedb071dcab03d14d9d467556f5b5b15c Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 22 Jun 2009 16:26:18 -0700 Subject: [PATCH 185/262] change sitemap.php to use commandline.inc --- scripts/sitemap.php | 133 +++++++++++++++++++++++--------------------- 1 file changed, 71 insertions(+), 62 deletions(-) diff --git a/scripts/sitemap.php b/scripts/sitemap.php index 39eb859bba..88ca2ba7aa 100755 --- a/scripts/sitemap.php +++ b/scripts/sitemap.php @@ -1,10 +1,37 @@ +#!/usr/bin/env php . + */ define('INSTALLDIR', realpath(dirname(__FILE__) . '/..')); -define('LACONICA', true); -require_once(INSTALLDIR . '/lib/common.php'); -require_once(INSTALLDIR . '/lib/util.php'); +$shortoptions = 'f:d:u:'; + +$helptext = << Use as output file + -d Use for new sitemaps + -u Use as root for URLs + +END_OF_SITEMAP_HELP; + +require_once INSTALLDIR . '/scripts/commandline.inc'; $output_paths = parse_args(); @@ -13,11 +40,11 @@ notices_map(); user_map(); index_map(); -# ------------------------------------------------------------------------------ -# Main functions: get data out and turn them into sitemaps -# ------------------------------------------------------------------------------ +// ------------------------------------------------------------------------------ +// Main functions: get data out and turn them into sitemaps +// ------------------------------------------------------------------------------ -# Generate index sitemap of all other sitemaps. +// Generate index sitemap of all other sitemaps. function index_map() { global $output_paths; @@ -26,7 +53,7 @@ function index_map() foreach (glob("$output_dir*.xml") as $file_name) { - # Just the file name please. + // Just the file name please. $file_name = preg_replace("|$output_dir|", '', $file_name); $index_urls .= sitemap( @@ -40,7 +67,7 @@ function index_map() write_file($output_paths['index_file'], sitemapindex($index_urls)); } -# Generate sitemap of standard site elements. +// Generate sitemap of standard site elements. function standard_map() { global $output_paths; @@ -61,7 +88,7 @@ function standard_map() ) ); - $docs = array('about', 'faq', 'contact', 'im', 'openid', 'openmublog', + $docs = array('about', 'faq', 'contact', 'im', 'openid', 'openmublog', 'privacy', 'source', 'badge'); foreach($docs as $title) { @@ -79,7 +106,7 @@ function standard_map() write_file($urlset_path, urlset($standard_map_urls)); } -# Generate sitemaps of all notices. +// Generate sitemaps of all notices. function notices_map() { global $output_paths; @@ -93,14 +120,14 @@ function notices_map() while ($notices->fetch()) { - # Maximum 50,000 URLs per sitemap file. + // Maximum 50,000 URLs per sitemap file. if ($notice_count == 50000) { $notice_count = 0; $map_count++; } - # remote notices have an URL - + // remote notices have an URL + if (!$notices->url && $notices->uri) { $notice = array( 'url' => ($notices->uri) ? $notices->uri : common_local_url('shownotice', array('notice' => $notices->id)), @@ -114,11 +141,11 @@ function notices_map() } } - # Make full sitemaps from the lists and save them. + // Make full sitemaps from the lists and save them. array_to_map($notice_list, 'notice'); } -# Generate sitemaps of all users. +// Generate sitemaps of all users. function user_map() { global $output_paths; @@ -132,7 +159,7 @@ function user_map() while ($users->fetch()) { - # Maximum 50,000 URLs per sitemap file. + // Maximum 50,000 URLs per sitemap file. if ($user_count == 50000) { $user_count = 0; $map_count++; @@ -140,7 +167,7 @@ function user_map() $user_args = array('nickname' => $users->nickname); - # Define parameters for generating elements. + // Define parameters for generating elements. $user = array( 'url' => common_local_url('showstream', $user_args), 'changefreq' => 'daily', @@ -183,8 +210,8 @@ function user_map() 'priority' => '0.5', ); - # Construct a element for each user facet and add it - # to our existing list of those. + // Construct a element for each user facet and add it + // to our existing list of those. $user_list[$map_count] .= url($user); $user_rss_list[$map_count] .= url($user_rss); $all_list[$map_count] .= url($all); @@ -196,9 +223,9 @@ function user_map() $user_count++; } - # Make full sitemaps from the lists and save them. - # Possible factoring: put all the lists into a master array, thus allowing - # calling with single argument (i.e., array_to_map('user')). + // Make full sitemaps from the lists and save them. + // Possible factoring: put all the lists into a master array, thus allowing + // calling with single argument (i.e., array_to_map('user')). array_to_map($user_list, 'user'); array_to_map($user_rss_list, 'user_rss'); array_to_map($all_list, 'all'); @@ -208,14 +235,14 @@ function user_map() array_to_map($foaf_list, 'foaf'); } -# ------------------------------------------------------------------------------ -# XML generation functions -# ------------------------------------------------------------------------------ +// ------------------------------------------------------------------------------ +// XML generation functions +// ------------------------------------------------------------------------------ -# Generate a element. +// Generate a element. function url($url_args) { - $url = preg_replace('/&/', '&', $url_args['url']); # escape ampersands for XML + $url = preg_replace('/&/', '&', $url_args['url']); // escape ampersands for XML $lastmod = $url_args['lastmod']; $changefreq = $url_args['changefreq']; $priority = $url_args['priority']; @@ -246,7 +273,7 @@ function url($url_args) function sitemap($sitemap_args) { - $url = preg_replace('/&/', '&', $sitemap_args['url']); # escape ampersands for XML + $url = preg_replace('/&/', '&', $sitemap_args['url']); // escape ampersands for XML $lastmod = $sitemap_args['lastmod']; if (is_null($url)) { @@ -265,7 +292,7 @@ function sitemap($sitemap_args) return $sitemap_out; } -# Generate a element. +// Generate a element. function urlset($urlset_text) { $urlset = '' . "\n" . @@ -276,7 +303,7 @@ function urlset($urlset_text) return $urlset; } -# Generate a element. +// Generate a element. function sitemapindex($sitemapindex_text) { $sitemapindex = '' . "\n" . @@ -287,49 +314,31 @@ function sitemapindex($sitemapindex_text) return $sitemapindex; } -# Generate a sitemap from an array containing elements and write it to a file. +// Generate a sitemap from an array containing elements and write it to a file. function array_to_map($url_list, $filename_prefix) { global $output_paths; if ($url_list) { - # $map_urls is a long string containing concatenated elements. + // $map_urls is a long string containing concatenated elements. while (list($map_idx, $map_urls) = each($url_list)) { $urlset_path = $output_paths['output_dir'] . "$filename_prefix-$map_idx.xml"; - + write_file($urlset_path, urlset($map_urls)); } } } -# ------------------------------------------------------------------------------ -# Internal functions -# ------------------------------------------------------------------------------ +// ------------------------------------------------------------------------------ +// Internal functions +// ------------------------------------------------------------------------------ -# Parse command line arguments. +// Parse command line arguments. function parse_args() { - $args = getopt('f:d:u:'); - - if (is_null($args[f]) && is_null($args[d]) && is_null($args[u])) { - error('Mandatory arguments: -f -d -u '); - } - - if (is_null($args[f])) { - error('You must specify an index file name with the -f option.'); - } - - if (is_null($args[d])) { - error('You must specify a directory for the output file with the -d option.'); - } - - if (is_null($args[u])) { - error('You must specify a URL for the directory where the sitemaps will be kept with the -u option.'); - } - - $index_file = $args[f]; - $output_dir = $args[d]; - $output_url = $args[u]; + $index_file = get_option_value('f'); + $output_dir = get_option_value('d'); + $output_url = get_option_value('u'); if (file_exists($output_dir)) { if (is_writable($output_dir) === false) { @@ -348,7 +357,7 @@ function parse_args() return $paths; } -# Ensure paths end with a "/". +// Ensure paths end with a "/". function trailing_slash($path) { if (preg_match('/\/$/', $path) == 0) { @@ -358,7 +367,7 @@ function trailing_slash($path) return $path; } -# Write data to disk. +// Write data to disk. function write_file($path, $data) { if (is_null($path)) { @@ -376,7 +385,7 @@ function write_file($path, $data) } } -# Display an error message and exit. +// Display an error message and exit. function error ($error_msg) { if (is_null($error_msg)) { From 8525165dc90954fcad32d44cbee4ef811eb2aece Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 22 Jun 2009 16:29:01 -0700 Subject: [PATCH 186/262] change smsqueuehandler to use commandline --- scripts/smsqueuehandler.php | 41 ++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/scripts/smsqueuehandler.php b/scripts/smsqueuehandler.php index 0366d4c4ca..c793ee550b 100755 --- a/scripts/smsqueuehandler.php +++ b/scripts/smsqueuehandler.php @@ -18,29 +18,25 @@ * along with this program. If not, see . */ -# Abort if called from a web server -if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) { - print "This script must be run from the command line\n"; - exit(); -} - define('INSTALLDIR', realpath(dirname(__FILE__) . '/..')); -define('LACONICA', true); -// Preset the server at the command line +$shortoptions = 'i::'; +$longoptions = array('id::'); -$server = ($argc > 2) ? $argv[2] : null; -$path = ($argc > 3) ? $argv[3] : null; +$helptext = << 1) ? $argv[1] : null; +if (have_option('-i')) { + $id = get_option_value('-i'); +} else if (have_option('--id')) { + $id = get_option_value('--id'); +} else if (count($args) > 0) { + $id = $args[0]; +} else { + $id = null; +} $handler = new SmsQueueHandler($id); From 1951246d67dfe41f2dfa722d1487baedf74c3081 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 22 Jun 2009 16:31:13 -0700 Subject: [PATCH 187/262] synctwitterfriends.php uses commandline.inc --- scripts/synctwitterfriends.php | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/scripts/synctwitterfriends.php b/scripts/synctwitterfriends.php index 7f418894e6..fe53ff44d6 100755 --- a/scripts/synctwitterfriends.php +++ b/scripts/synctwitterfriends.php @@ -18,24 +18,16 @@ * along with this program. If not, see . */ -// Abort if called from a web server -if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) { - print "This script must be run from the command line\n"; - exit(); -} - define('INSTALLDIR', realpath(dirname(__FILE__) . '/..')); -define('LACONICA', true); // Uncomment this to get useful console output -//define('SCRIPT_DEBUG', true); -// Preset the server at the command line +$helptext = << 1) ? $argv[1] : null; -$path = ($argc > 2) ? $argv[2] : null; +END_OF_TWITTER_HELP; -require_once(INSTALLDIR . '/lib/common.php'); +require_once INSTALLDIR.'/scripts/commandline.inc'; // Make a lockfile $lockfilename = lockFilename(); From 0582381c6631cb8b8e914cebbcf2e387b947c83f Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 22 Jun 2009 16:34:56 -0700 Subject: [PATCH 188/262] triminboxes.php uses commandline.inc --- scripts/triminboxes.php | 42 +++++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/scripts/triminboxes.php b/scripts/triminboxes.php index 0d545b3263..5575dd4fc1 100644 --- a/scripts/triminboxes.php +++ b/scripts/triminboxes.php @@ -18,31 +18,37 @@ * along with this program. If not, see . */ -# Abort if called from a web server -if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) { - print "This script must be run from the command line\n"; - exit(1); -} - -ini_set("max_execution_time", "0"); -ini_set("max_input_time", "0"); -set_time_limit(0); -mb_internal_encoding('UTF-8'); - define('INSTALLDIR', realpath(dirname(__FILE__) . '/..')); -define('LACONICA', true); -// Preset the server at the command line +$shortoptions = 'u::'; +$longoptions = array('start-user-id::'); -$server = ($argc > 2) ? $argv[2] : null; -$path = ($argc > 3) ? $argv[3] : null; +$helptext = << + --start-user-id= User ID to start after. Default is all. + +END_OF_TRIM_HELP; + +require_once INSTALLDIR.'/scripts/commandline.inc'; + +$id = null; + +if (have_option('-u')) { + $id = get_option_value('-u'); +} else if (have_option('--start-user-id')) { + $id = get_option_value('--start-user-id'); +} else { + $id = null; +} $user = new User(); -if ($argc > 1) { - $user->whereAdd('id > ' . $argv[1]); + +if (!empty($id)) { + $user->whereAdd('id > ' . $id); } + $cnt = $user->find(); while ($user->fetch()) { From 1691998de87c8f3a0d8e79d633be8ed9f956ce51 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 22 Jun 2009 16:35:10 -0700 Subject: [PATCH 189/262] make id optional for enjitqueuehandler --- scripts/enjitqueuehandler.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/enjitqueuehandler.php b/scripts/enjitqueuehandler.php index 5091347658..05e1d9366b 100755 --- a/scripts/enjitqueuehandler.php +++ b/scripts/enjitqueuehandler.php @@ -20,8 +20,8 @@ define('INSTALLDIR', realpath(dirname(__FILE__) . '/..')); -$shortoptions = 'i'; -$longoptions = array('id'); +$shortoptions = 'i::'; +$longoptions = array('id::'); $helptext = << Date: Mon, 22 Jun 2009 16:37:15 -0700 Subject: [PATCH 190/262] twitterqueuehandler.php uses commandline.inc --- scripts/twitterqueuehandler.php | 42 ++++++++++++++++----------------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/scripts/twitterqueuehandler.php b/scripts/twitterqueuehandler.php index d6fb17cc8b..826e12c75c 100755 --- a/scripts/twitterqueuehandler.php +++ b/scripts/twitterqueuehandler.php @@ -18,29 +18,25 @@ * along with this program. If not, see . */ -# Abort if called from a web server -if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) { - print "This script must be run from the command line\n"; - exit(); -} - define('INSTALLDIR', realpath(dirname(__FILE__) . '/..')); -define('LACONICA', true); -// Preset the server at the command line +$shortoptions = 'i::'; +$longoptions = array('id::'); -$server = ($argc > 2) ? $argv[2] : null; -$path = ($argc > 3) ? $argv[3] : null; +$helptext = << 1) ? $argv[1] : null; +if (have_option('-i')) { + $id = get_option_value('-i'); +} else if (have_option('--id')) { + $id = get_option_value('--id'); +} else if (count($args) > 0) { + $id = $args[0]; +} else { + $id = null; +} $handler = new TwitterQueueHandler($id); From fa5e4f88c9671456c171613a682d89c5681e576a Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 22 Jun 2009 16:39:21 -0700 Subject: [PATCH 191/262] twitterstatusfetcher.php uses commandline.inc --- scripts/twitterstatusfetcher.php | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/scripts/twitterstatusfetcher.php b/scripts/twitterstatusfetcher.php index c18261b5b9..5ffdda58fa 100755 --- a/scripts/twitterstatusfetcher.php +++ b/scripts/twitterstatusfetcher.php @@ -18,27 +18,19 @@ * along with this program. If not, see . */ -// Abort if called from a web server -if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) { - print "This script must be run from the command line\n"; - exit(); -} - define('INSTALLDIR', realpath(dirname(__FILE__) . '/..')); -define('LACONICA', true); // Tune number of processes and how often to poll Twitter // XXX: Should these things be in config.php? define('MAXCHILDREN', 2); define('POLL_INTERVAL', 60); // in seconds -// Uncomment this to get useful logging -// define('SCRIPT_DEBUG', true); +$helptext = << 2) ? $argv[2] : null; -$path = ($argc > 3) ? $argv[3] : null; +require_once INSTALLDIR.'/scripts/commandline.inc'; require_once INSTALLDIR . '/lib/common.php'; require_once INSTALLDIR . '/lib/daemon.php'; @@ -631,10 +623,6 @@ class TwitterStatusFetcher extends Daemon } } -ini_set("max_execution_time", "0"); -ini_set("max_input_time", "0"); -set_time_limit(0); -mb_internal_encoding('UTF-8'); declare(ticks = 1); $fetcher = new TwitterStatusFetcher(); From de033bce88842c931180c332d8fec3df9b5ff342 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 22 Jun 2009 16:44:20 -0700 Subject: [PATCH 192/262] uncache_users.php uses commandline.inc --- scripts/uncache_users.php | 33 +++++++++++++-------------------- 1 file changed, 13 insertions(+), 20 deletions(-) diff --git a/scripts/uncache_users.php b/scripts/uncache_users.php index e35ea81ea4..b0b576eb44 100644 --- a/scripts/uncache_users.php +++ b/scripts/uncache_users.php @@ -17,32 +17,27 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ - -# Abort if called from a web server - -if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) { - print "This script must be run from the command line\n"; - exit(); -} - -ini_set("max_execution_time", "0"); -ini_set("max_input_time", "0"); -set_time_limit(0); -mb_internal_encoding('UTF-8'); - define('INSTALLDIR', realpath(dirname(__FILE__) . '/..')); -define('LACONICA', true); -require_once(INSTALLDIR . '/lib/common.php'); +$helptext = << -$id_file = ($argc > 1) ? $argv[1] : 'ids.txt'; +Uncache users listed in an ID file, default 'ids.txt'. + +ENDOFHELP; + +require_once INSTALLDIR.'/scripts/commandline.inc'; + +$id_file = (count($args) > 1) ? $args[0] : 'ids.txt'; common_log(LOG_INFO, 'Updating user inboxes.'); $ids = file($id_file); +$memc = common_memcache(); + foreach ($ids as $id) { - + $user = User::staticGet('id', $id); if (!$user) { @@ -51,9 +46,7 @@ foreach ($ids as $id) { } $user->decache(); - - $memc = common_memcache(); - + $memc->delete(common_cache_key('user:notices_with_friends:'. $user->id)); $memc->delete(common_cache_key('user:notices_with_friends:'. $user->id . ';last')); } From 010d168aaa908073d03be66259042f921dfb861e Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 22 Jun 2009 16:44:29 -0700 Subject: [PATCH 193/262] correctly detect default short options --- scripts/commandline.inc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/commandline.inc b/scripts/commandline.inc index a245b2f163..4a7757fb98 100644 --- a/scripts/commandline.inc +++ b/scripts/commandline.inc @@ -91,22 +91,22 @@ foreach ($options as $option) { switch ($option[0]) { case '--server': - case '-s': + case 's': $server = $option[1]; break; case '--path': - case '-p': + case 'p': $path = $option[1]; break; case '--conf': - case '-c': + case 'c': $conffile = $option[1]; break; case '--help': - case '-h': + case 'h': show_help(); } } From 3fc2cfb7f81cca483be7255e20245c8fea2fe0d8 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 22 Jun 2009 16:48:04 -0700 Subject: [PATCH 194/262] fix have_options arguments --- scripts/facebookqueuehandler.php | 8 ++++---- scripts/jabberqueuehandler.php | 10 +++++----- scripts/ombqueuehandler.php | 8 ++++---- scripts/pingqueuehandler.php | 8 ++++---- scripts/publicqueuehandler.php | 8 ++++---- scripts/smsqueuehandler.php | 4 ++-- scripts/triminboxes.php | 4 ++-- scripts/twitterqueuehandler.php | 4 ++-- 8 files changed, 27 insertions(+), 27 deletions(-) diff --git a/scripts/facebookqueuehandler.php b/scripts/facebookqueuehandler.php index f01e45a3b4..05a35577fe 100755 --- a/scripts/facebookqueuehandler.php +++ b/scripts/facebookqueuehandler.php @@ -20,8 +20,8 @@ define('INSTALLDIR', realpath(dirname(__FILE__) . '/..')); -$shortoptions = 'i'; -$longoptions = array('id'); +$shortoptions = 'i::'; +$longoptions = array('id::'); $helptext = << 0) { diff --git a/scripts/jabberqueuehandler.php b/scripts/jabberqueuehandler.php index be0f187a98..a449932364 100755 --- a/scripts/jabberqueuehandler.php +++ b/scripts/jabberqueuehandler.php @@ -20,13 +20,13 @@ define('INSTALLDIR', realpath(dirname(__FILE__) . '/..')); -$shortoptions = 'r'; -$longoptions = array('resource'); +$shortoptions = 'r::'; +$longoptions = array('resource::'); $helptext = << 0) { diff --git a/scripts/ombqueuehandler.php b/scripts/ombqueuehandler.php index deb5f8d7d2..1587192b6f 100755 --- a/scripts/ombqueuehandler.php +++ b/scripts/ombqueuehandler.php @@ -20,8 +20,8 @@ define('INSTALLDIR', realpath(dirname(__FILE__) . '/..')); -$shortoptions = 'i'; -$longoptions = array('id'); +$shortoptions = 'i::'; +$longoptions = array('id::'); $helptext = << 0) { diff --git a/scripts/pingqueuehandler.php b/scripts/pingqueuehandler.php index 1bde4bc5fd..23678ea4b5 100644 --- a/scripts/pingqueuehandler.php +++ b/scripts/pingqueuehandler.php @@ -20,8 +20,8 @@ define('INSTALLDIR', realpath(dirname(__FILE__) . '/..')); -$shortoptions = 'i'; -$longoptions = array('id'); +$shortoptions = 'i::'; +$longoptions = array('id::'); $helptext = << 0) { diff --git a/scripts/publicqueuehandler.php b/scripts/publicqueuehandler.php index c10c679108..58ecc1745e 100755 --- a/scripts/publicqueuehandler.php +++ b/scripts/publicqueuehandler.php @@ -20,8 +20,8 @@ define('INSTALLDIR', realpath(dirname(__FILE__) . '/..')); -$shortoptions = 'r'; -$longoptions = array('resource'); +$shortoptions = 'r::'; +$longoptions = array('resource::'); $helptext = << 0) { diff --git a/scripts/smsqueuehandler.php b/scripts/smsqueuehandler.php index c793ee550b..94b846d987 100755 --- a/scripts/smsqueuehandler.php +++ b/scripts/smsqueuehandler.php @@ -58,8 +58,8 @@ class SmsQueueHandler extends QueueHandler } } -if (have_option('-i')) { - $id = get_option_value('-i'); +if (have_option('i')) { + $id = get_option_value('i'); } else if (have_option('--id')) { $id = get_option_value('--id'); } else if (count($args) > 0) { diff --git a/scripts/triminboxes.php b/scripts/triminboxes.php index 5575dd4fc1..b2135d6825 100644 --- a/scripts/triminboxes.php +++ b/scripts/triminboxes.php @@ -35,8 +35,8 @@ require_once INSTALLDIR.'/scripts/commandline.inc'; $id = null; -if (have_option('-u')) { - $id = get_option_value('-u'); +if (have_option('u')) { + $id = get_option_value('u'); } else if (have_option('--start-user-id')) { $id = get_option_value('--start-user-id'); } else { diff --git a/scripts/twitterqueuehandler.php b/scripts/twitterqueuehandler.php index 826e12c75c..00e735d983 100755 --- a/scripts/twitterqueuehandler.php +++ b/scripts/twitterqueuehandler.php @@ -59,8 +59,8 @@ class TwitterQueueHandler extends QueueHandler } -if (have_option('-i')) { - $id = get_option_value('-i'); +if (have_option('i')) { + $id = get_option_value('i'); } else if (have_option('--id')) { $id = get_option_value('--id'); } else if (count($args) > 0) { From 5b5da5154d5a93bd4c55f43c17c3bd1516b7cc34 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 22 Jun 2009 16:52:59 -0700 Subject: [PATCH 195/262] decache.php uses commandline.inc --- scripts/decache.php | 37 ++++++++++++++----------------------- 1 file changed, 14 insertions(+), 23 deletions(-) diff --git a/scripts/decache.php b/scripts/decache.php index b18eaa2cd3..90e1ec63c0 100644 --- a/scripts/decache.php +++ b/scripts/decache.php @@ -18,35 +18,26 @@ * along with this program. If not, see . */ -# Abort if called from a web server -if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) { - print "This script must be run from the command line\n"; - exit(1); -} - -ini_set("max_execution_time", "0"); -ini_set("max_input_time", "0"); -set_time_limit(0); -mb_internal_encoding('UTF-8'); - define('INSTALLDIR', realpath(dirname(__FILE__) . '/..')); -define('LACONICA', true); -require_once(INSTALLDIR . '/lib/common.php'); +$helptext = << [] +Clears the cache for the object in table with id +If is specified, use that instead of 'id' +ENDOFHELP; -if ($argc < 3 || $argc > 4) { - print "USAGE: decache.php
      []\n"; - print "Clears the cache for the object in table
      with id .\n\n"; - print "If is specified, use that instead of 'id'\n"; - exit(1); +require_once INSTALLDIR.'/scripts/commandline.inc'; + +if (count($args) < 2 || count($args) > 3) { + show_help(); } -$table = $argv[1]; -$id = $argv[2]; -if ($argc > 3) { - $column = $argv[3]; +$table = $args[0]; +$id = $args[1]; +if (count($args) > 2) { + $column = $args[2]; } else { - $colum = 'id'; + $column = 'id'; } $object = Memcached_DataObject::staticGet($table, $column, $id); From eced917d7965ab9b630bf0fe7ac031ac06ff7939 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 22 Jun 2009 16:54:21 -0700 Subject: [PATCH 196/262] getpiddir.php uses commandline.inc --- scripts/getpiddir.php | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/scripts/getpiddir.php b/scripts/getpiddir.php index d29c95cb08..9927cc6d95 100755 --- a/scripts/getpiddir.php +++ b/scripts/getpiddir.php @@ -18,15 +18,13 @@ * along with this program. If not, see . */ -# Abort if called from a web server -if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) { - print "This script must be run from the command line\n"; - exit(); -} - define('INSTALLDIR', realpath(dirname(__FILE__) . '/..')); -define('LACONICA', true); -require_once(INSTALLDIR . '/lib/common.php'); +$helptext = << Date: Mon, 22 Jun 2009 16:55:55 -0700 Subject: [PATCH 197/262] getvaliddaemons.php uses commandline.inc --- scripts/getvaliddaemons.php | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/scripts/getvaliddaemons.php b/scripts/getvaliddaemons.php index a45ff79aba..198ea8fb9a 100755 --- a/scripts/getvaliddaemons.php +++ b/scripts/getvaliddaemons.php @@ -25,16 +25,14 @@ * daemon names. */ -# Abort if called from a web server -if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) { - print "This script must be run from the command line\n"; - exit(); -} - define('INSTALLDIR', realpath(dirname(__FILE__) . '/..')); -define('LACONICA', true); -require_once(INSTALLDIR . '/lib/common.php'); +$helptext = << Date: Mon, 22 Jun 2009 16:57:28 -0700 Subject: [PATCH 198/262] inbox_users.php uses commandline.inc --- scripts/inbox_users.php | 54 +++++++++++++++++++---------------------- 1 file changed, 25 insertions(+), 29 deletions(-) diff --git a/scripts/inbox_users.php b/scripts/inbox_users.php index 6d3656d2ee..4883fea201 100755 --- a/scripts/inbox_users.php +++ b/scripts/inbox_users.php @@ -20,59 +20,55 @@ # Abort if called from a web server -if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) { - print "This script must be run from the command line\n"; - exit(); -} - -ini_set("max_execution_time", "0"); -ini_set("max_input_time", "0"); -set_time_limit(0); -mb_internal_encoding('UTF-8'); - define('INSTALLDIR', realpath(dirname(__FILE__) . '/..')); -define('LACONICA', true); -require_once(INSTALLDIR . '/lib/common.php'); +$helptext = << -$id_file = ($argc > 1) ? $argv[1] : 'ids.txt'; +Update users to use inbox table. Listed in an ID file, default 'ids.txt'. + +ENDOFHELP; + +require_once INSTALLDIR.'/scripts/commandline.inc'; + +$id_file = (count($args) > 1) ? $args[0] : 'ids.txt'; common_log(LOG_INFO, 'Updating user inboxes.'); $ids = file($id_file); foreach ($ids as $id) { - + $user = User::staticGet('id', $id); if (!$user) { common_log(LOG_WARNING, 'No such user: ' . $id); continue; } - + if ($user->inboxed) { common_log(LOG_WARNING, 'Already inboxed: ' . $id); continue; } - + common_log(LOG_INFO, 'Updating inbox for user ' . $user->id); - + $user->query('BEGIN'); - + $old_inbox = new Notice_inbox(); $old_inbox->user_id = $user->id; - + $result = $old_inbox->delete(); - + if (is_null($result) || $result === false) { common_log_db_error($old_inbox, 'DELETE', __FILE__); continue; } $old_inbox->free(); - + $inbox = new Notice_inbox(); - + $result = $inbox->query('INSERT INTO notice_inbox (user_id, notice_id, created) ' . 'SELECT ' . $user->id . ', notice.id, notice.created ' . 'FROM subscription JOIN notice ON subscription.subscribed = notice.profile_id ' . @@ -80,30 +76,30 @@ foreach ($ids as $id) { 'AND notice.created >= subscription.created ' . 'AND NOT EXISTS (SELECT user_id, notice_id ' . 'FROM notice_inbox ' . - 'WHERE user_id = ' . $user->id . ' ' . + 'WHERE user_id = ' . $user->id . ' ' . 'AND notice_id = notice.id) ' . 'ORDER BY notice.created DESC ' . 'LIMIT 0, 1000'); - + if (is_null($result) || $result === false) { common_log_db_error($inbox, 'INSERT', __FILE__); continue; } - + $orig = clone($user); $user->inboxed = 1; $result = $user->update($orig); - + if (!$result) { common_log_db_error($user, 'UPDATE', __FILE__); continue; } - + $user->query('COMMIT'); - + $inbox->free(); unset($inbox); - + if ($cache) { $cache->delete(common_cache_key('user:notices_with_friends:' . $user->id)); $cache->delete(common_cache_key('user:notices_with_friends:' . $user->id . ';last')); From 66316c0ce637816f172ffcc680cbb89f393f17e6 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 22 Jun 2009 17:00:53 -0700 Subject: [PATCH 199/262] fixup_utf8.php uses commandline.inc --- scripts/fixup_utf8.php | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/scripts/fixup_utf8.php b/scripts/fixup_utf8.php index 1693760914..8c9a9127fd 100644 --- a/scripts/fixup_utf8.php +++ b/scripts/fixup_utf8.php @@ -19,21 +19,18 @@ */ # Abort if called from a web server -if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) { - print "This script must be run from the command line\n"; - exit(1); -} - -ini_set("max_execution_time", "0"); -ini_set("max_input_time", "0"); -set_time_limit(0); -mb_internal_encoding('UTF-8'); define('INSTALLDIR', realpath(dirname(__FILE__) . '/..')); -define('LACONICA', true); -require_once(INSTALLDIR . '/lib/common.php'); -require_once('DB.php'); +$helptext = << + +Fixup records in a database that stored the data incorrectly (pre-0.7.4 for Laconica). + +ENDOFHELP; + +require_once INSTALLDIR.'/scripts/commandline.inc'; +require_once 'DB.php'; class UTF8FixerUpper { @@ -356,9 +353,9 @@ class UTF8FixerUpper } } -$max_date = ($argc > 1) ? $argv[1] : null; -$max_id = ($argc > 2) ? $argv[2] : null; -$min_id = ($argc > 3) ? $argv[3] : null; +$max_date = (count($args) > 0) ? $args[0] : null; +$max_id = (count($args) > 1) ? $args[1] : null; +$min_id = (count($args) > 2) ? $args[2] : null; $fixer = new UTF8FixerUpper(array('max_date' => $max_date, 'max_notice' => $max_id, From 0b638a233cb97668b340c1321c61b305966805a9 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 22 Jun 2009 17:02:40 -0700 Subject: [PATCH 200/262] maildaemon.php uses commandline.inc --- scripts/maildaemon.php | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/scripts/maildaemon.php b/scripts/maildaemon.php index dc3ab0b56e..cfb11a36fc 100755 --- a/scripts/maildaemon.php +++ b/scripts/maildaemon.php @@ -18,21 +18,16 @@ * along with this program. If not, see . */ -# Abort if called from a web server -if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) { - print "This script must be run from the command line\n"; - exit(); -} - define('INSTALLDIR', realpath(dirname(__FILE__) . '/..')); -define('LACONICA', true); -// Preset the server at the command line +$helptext = << 1) ? $argv[1] : null; -$path = ($argc > 2) ? $argv[2] : null; +END_OF_HELP; + +require_once INSTALLDIR.'/scripts/commandline.inc'; -require_once(INSTALLDIR . '/lib/common.php'); require_once(INSTALLDIR . '/lib/mail.php'); require_once('Mail/mimeDecode.php'); From ef3251634ca4d62c92a1ea65fcc04989c6bf1df4 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 22 Jun 2009 17:04:49 -0700 Subject: [PATCH 201/262] xmppconfirmhandler.php uses commandline.inc --- scripts/xmppconfirmhandler.php | 40 ++++++++++++++++------------------ 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/scripts/xmppconfirmhandler.php b/scripts/xmppconfirmhandler.php index 217481d658..883934fd6c 100755 --- a/scripts/xmppconfirmhandler.php +++ b/scripts/xmppconfirmhandler.php @@ -18,31 +18,26 @@ * along with this program. If not, see . */ -# Abort if called from a web server -if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) { - print "This script must be run from the command line\n"; - exit(); -} - define('INSTALLDIR', realpath(dirname(__FILE__) . '/..')); -define('LACONICA', true); -// Preset the server at the command line +$shortoptions = 'r::'; +$longoptions = array('resource::'); -$server = ($argc > 2) ? $argv[2] : null; -$path = ($argc > 3) ? $argv[3] : null; +$helptext = << 1) ? $argv[1] : (common_config('xmpp', 'resource').'-confirm'); +if (have_option('r')) { + $resource = get_option_value('r'); +} else if (have_option('--resource')) { + $resource = get_option_value('--resource'); +} else if (count($args) > 0) { + $resource = $args[0]; +} else { + $resource = null; +} $handler = new XmppConfirmHandler($resource); From 875e122a24987dcd46c45f0f8823ab2a49dfb031 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 22 Jun 2009 17:07:14 -0700 Subject: [PATCH 202/262] xmppdaemon.php uses commandline.inc --- scripts/xmppdaemon.php | 41 +++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/scripts/xmppdaemon.php b/scripts/xmppdaemon.php index 0f98becdac..661631937f 100755 --- a/scripts/xmppdaemon.php +++ b/scripts/xmppdaemon.php @@ -18,25 +18,23 @@ * along with this program. If not, see . */ -# Abort if called from a web server -if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) { - print "This script must be run from the command line\n"; - exit(); -} - define('INSTALLDIR', realpath(dirname(__FILE__) . '/..')); -define('LACONICA', true); -// Preset the server at the command line +$shortoptions = 'r::'; +$longoptions = array('resource::'); -$server = ($argc > 2) ? $argv[2] : null; -$path = ($argc > 3) ? $argv[3] : null; +$helptext = << 1) ? $argv[1] : (common_config('xmpp','resource') . '-listen'); +if (have_option('r')) { + $resource = get_option_value('r'); +} else if (have_option('--resource')) { + $resource = get_option_value('--resource'); +} else if (count($args) > 0) { + $resource = $args[0]; +} else { + $resource = null; +} $daemon = new XMPPDaemon($resource); From ccd9cdd6183ac479ef8e88e61814c3209b428eb3 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Tue, 23 Jun 2009 05:16:23 -0700 Subject: [PATCH 203/262] Add System_Command so MIME type fallback works for uploaded files --- extlib/System/Command.php | 587 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 587 insertions(+) create mode 100644 extlib/System/Command.php diff --git a/extlib/System/Command.php b/extlib/System/Command.php new file mode 100644 index 0000000000..f5c3ec6b92 --- /dev/null +++ b/extlib/System/Command.php @@ -0,0 +1,587 @@ + | +// | Author: Dan Allen +// +----------------------------------------------------------------------+ + +// $Id: Command.php,v 1.9 2007/04/20 21:08:48 cconstantine Exp $ + +// }}} +// {{{ includes + +require_once 'PEAR.php'; +require_once 'System.php'; + +// }}} +// {{{ constants + +define('SYSTEM_COMMAND_OK', 1); +define('SYSTEM_COMMAND_ERROR', -1); +define('SYSTEM_COMMAND_NO_SHELL', -2); +define('SYSTEM_COMMAND_INVALID_SHELL', -3); +define('SYSTEM_COMMAND_TMPDIR_ERROR', -4); +define('SYSTEM_COMMAND_INVALID_OPERATOR', -5); +define('SYSTEM_COMMAND_INVALID_COMMAND', -6); +define('SYSTEM_COMMAND_OPERATOR_PLACEMENT',-7); +define('SYSTEM_COMMAND_COMMAND_PLACEMENT', -8); +define('SYSTEM_COMMAND_NOHUP_MISSING', -9); +define('SYSTEM_COMMAND_NO_OUTPUT', -10); +define('SYSTEM_COMMAND_STDERR', -11); +define('SYSTEM_COMMAND_NONZERO_EXIT', -12); + +// }}} + +// {{{ class System_Command + +/** + * The System_Command:: class implements an abstraction for various ways + * of executing commands (directly using the backtick operator, + * as a background task after the script has terminated using + * register_shutdown_function() or as a detached process using nohup). + * + * @author Anders Johannsen + * @author Dan Allen + * @version $Revision: 1.9 $ + */ + +// }}} +class System_Command { + // {{{ properties + + /** + * Array of settings used when creating the shell command + * + * @var array + * @access private + */ + var $options = array(); + + /** + * Array of available shells to use to execute the command + * + * @var array + * @access private + */ + var $shells = array(); + + /** + * Array of available control operators used between commands + * + * @var array + * @access private + */ + var $controlOperators = array(); + + /** + * The system command to be executed + * + * @var string + * @access private + */ + var $systemCommand = null; + + /** + * Previously added part to the command string + * + * @var string + * @access private + */ + var $previousElement = null; + + /** + * Directory for writing stderr output + * + * @var string + * @access private + */ + var $tmpDir = null; + + /** + * To allow the pear error object to accumulate when building + * the command, we use the command status to keep track when + * a pear error is raised + * + * @var int + * @access private + */ + var $commandStatus = 0; + + /** + * Hold initialization PEAR_Error + * + * @var object + * @access private + **/ + var $_initError = null; + + // }}} + // {{{ constructor + + /** + * Class constructor + * + * Defines all necessary constants and sets defaults + * + * @access public + */ + function System_Command($in_shell = null) + { + // Defining constants + $this->options = array( + 'SEQUENCE' => true, + 'SHUTDOWN' => false, + 'SHELL' => $this->which($in_shell), + 'OUTPUT' => true, + 'NOHUP' => false, + 'BACKGROUND' => false, + 'STDERR' => false + ); + + // prepare the available control operators + $this->controlOperators = array( + 'PIPE' => '|', + 'AND' => '&&', + 'OR' => '||', + 'GROUP' => ';', + 'LFIFO' => '<', + 'RFIFO' => '>', + ); + + // List of allowed/available shells + $this->shells = array( + 'sh', + 'bash', + 'zsh', + 'tcsh', + 'csh', + 'ash', + 'sash', + 'esh', + 'ksh' + ); + + // Find the first available shell + if (empty($this->options['SHELL'])) { + foreach ($this->shells as $shell) { + if ($this->options['SHELL'] = $this->which($shell)) { + break; + } + } + + // see if we still have no shell + if (empty($this->options['SHELL'])) { + $this->_initError =& PEAR::raiseError(null, SYSTEM_COMMAND_NO_SHELL, null, E_USER_WARNING, null, 'System_Command_Error', true); + return; + } + } + + // Caputre a temporary directory for capturing stderr from commands + $this->tmpDir = System::tmpdir(); + if (!System::mkDir("-p {$this->tmpDir}")) { + $this->_initError =& PEAR::raiseError(null, SYSTEM_COMMAND_TMPDIR_ERROR, null, E_USER_WARNING, null, 'System_Command_Error', true); + return; + } + } + + // }}} + // {{{ setOption() + + /** + * Sets the value for an option. Each option should be set to true + * or false; except the 'SHELL' option which should be a string + * naming a shell. The options are: + * + * 'SEQUENCE' Allow a sequence command or not (right now this is always on); + * + * 'SHUTDOWN' Execute commands via a shutdown function; + * + * 'SHELL' Path to shell; + * + * 'OUTPUT' Output stdout from process; + * + * 'NOHUP' Use nohup to detach process; + * + * 'BACKGROUND' Run as a background process with &; + * + * 'STDERR' Output on stderr will raise an error, even if + * the command's exit value is zero. The output from + * stderr can be retrieved using the getDebugInfo() + * method of the Pear_ERROR object returned by + * execute().; + * + * @param string $in_option is a case-sensitive string, + * corresponding to the option + * that should be changed + * @param mixed $in_setting is the new value for the option + * @access public + * @return bool true if succes, else false + */ + function setOption($in_option, $in_setting) + { + if ($this->_initError) { + return $this->_initError; + } + + $option = strtoupper($in_option); + + if (!isset($this->options[$option])) { + PEAR::raiseError(null, SYSTEM_COMMAND_ERROR, null, E_USER_NOTICE, null, 'System_Command_Error', true); + return false; + } + + switch ($option) { + case 'OUTPUT': + case 'SHUTDOWN': + case 'SEQUENCE': + case 'BACKGROUND': + case 'STDERR': + $this->options[$option] = !empty($in_setting); + return true; + break; + + case 'SHELL': + if (($shell = $this->which($in_setting)) !== false) { + $this->options[$option] = $shell; + return true; + } + else { + PEAR::raiseError(null, SYSTEM_COMMAND_NO_SHELL, null, E_USER_NOTICE, $in_setting, 'System_Command_Error', true); + return false; + } + break; + + case 'NOHUP': + if (empty($in_setting)) { + $this->options[$option] = false; + } + else if ($location = $this->which('nohup')) { + $this->options[$option] = $location; + } + else { + PEAR::raiseError(null, SYSTEM_COMMAND_NOHUP_MISSING, null, E_USER_NOTICE, null, 'System_Command_Error', true); + return false; + } + break; + } + } + + // }}} + // {{{ pushCommand() + + /** + * Used to push a command onto the running command to be executed + * + * @param string $in_command binary to be run + * @param string $in_argument either an option or argument value, to be handled appropriately + * @param string $in_argument + * @param ... + * + * @access public + * @return boolean true on success {or System_Command_Error Exception} + */ + function pushCommand($in_command) + { + if ($this->_initError) { + return $this->_initError; + } + + if (!is_null($this->previousElement) && !in_array($this->previousElement, $this->controlOperators)) { + $this->commandStatus = -1; + $error = PEAR::raiseError(null, SYSTEM_COMMAND_COMMAND_PLACEMENT, null, E_USER_WARNING, null, 'System_Command_Error', true); + } + + // check for error here + $command = escapeshellcmd($this->which($in_command)); + if ($command === false) { + $error = PEAR::raiseError(null, SYSTEM_COMMAND_INVALID_COMMAND, null, E_USER_WARNING, null, 'System_Command_Error', true); + } + + $argv = func_get_args(); + array_shift($argv); + foreach($argv as $arg) { + if (strpos($arg, '-') === 0) { + $command .= ' ' . $arg; + } + elseif ($arg != '') { + $command .= ' ' . escapeshellarg($arg); + } + } + + $this->previousElement = $command; + $this->systemCommand .= $command; + + return isset($error) ? $error : true; + } + + // }}} + // {{{ pushOperator() + + /** + * Used to push an operator onto the running command to be executed + * + * @param string $in_operator Either string reprentation of operator or system character + * + * @access public + * @return boolean true on success {or System_Command_Error Exception} + */ + function pushOperator($in_operator) + { + if ($this->_initError) { + return $this->_initError; + } + + $operator = isset($this->controlOperators[$in_operator]) ? $this->controlOperators[$in_operator] : $in_operator; + + if (is_null($this->previousElement) || in_array($this->previousElement, $this->controlOperators)) { + $this->commandStatus = -1; + $error = PEAR::raiseError(null, SYSTEM_COMMAND_OPERATOR_PLACEMENT, null, E_USER_WARNING, null, 'System_Command_Error', true); + } + elseif (!in_array($operator, $this->controlOperators)) { + $this->commandStatus = -1; + $error = PEAR::raiseError(null, SYSTEM_COMMAND_INVALID_OPERATOR, null, E_USER_WARNING, $operator, 'System_Command_Error', true); + } + + $this->previousElement = $operator; + $this->systemCommand .= ' ' . $operator . ' '; + return isset($error) ? $error : true; + } + + // }}} + // {{{ execute() + + /** + * Executes the code according to given options + * + * @return bool true if success {or System_Command_Exception} + * + * @access public + */ + function execute() + { + if ($this->_initError) { + return $this->_initError; + } + + // if the command is empty or if the last element was a control operator, we can't continue + if (is_null($this->previousElement) || $this->commandStatus == -1 || in_array($this->previousElement, $this->controlOperators)) { + return PEAR::raiseError(null, SYSTEM_COMMAND_INVALID_COMMAND, null, E_USER_WARNING, $this->systemCommand, 'System_Command_Error', true); + } + + // Warning about impossible mix of options + if (!empty($this->options['OUTPUT'])) { + if (!empty($this->options['SHUTDOWN']) || !empty($this->options['NOHUP'])) { + return PEAR::raiseError(null, SYSTEM_COMMAND_NO_OUTPUT, null, E_USER_WARNING, null, 'System_Command_Error', true); + } + } + + // if this is not going to stdout, then redirect to /dev/null + if (empty($this->options['OUTPUT'])) { + $this->systemCommand .= ' >/dev/null'; + } + + $suffix = ''; + // run a command immune to hangups, with output to a non-tty + if (!empty($this->options['NOHUP'])) { + $this->systemCommand = $this->options['NOHUP'] . $this->systemCommand; + } + // run a background process (only if not nohup) + elseif (!empty($this->options['BACKGROUND'])) { + $suffix = ' &'; + } + + // Register to be run on shutdown + if (!empty($this->options['SHUTDOWN'])) { + $line = "system(\"{$this->systemCommand}$suffix\");"; + $function = create_function('', $line); + register_shutdown_function($function); + return true; + } + else { + // send stderr to a file so that we can reap the error message + $tmpFile = tempnam($this->tmpDir, 'System_Command-'); + $this->systemCommand .= ' 2>' . $tmpFile . $suffix; + $shellPipe = $this->which('echo') . ' ' . escapeshellarg($this->systemCommand) . ' | ' . $this->options['SHELL']; + exec($shellPipe, $result, $returnVal); + + if ($returnVal !== 0) { + // command returned nonzero; that's always an error + $return = PEAR::raiseError(null, SYSTEM_COMMAND_NONZERO_EXIT, null, E_USER_WARNING, null, 'System_Command_Error', true); + } + else if (!$this->options['STDERR']) { + // caller does not care about stderr; return success + $return = implode("\n", $result); + } + else { + // our caller cares about stderr; check stderr output + clearstatcache(); + if (filesize($tmpFile) > 0) { + // the command actually wrote to stderr + $stderr_output = file_get_contents($tmpFile); + $return = PEAR::raiseError(null, SYSTEM_COMMAND_STDERR, null, E_USER_WARNING, $stderr_output, 'System_Command_Error', true); + } else { + // total success; return stdout gathered by exec() + $return = implode("\n", $result); + } + } + + unlink($tmpFile); + return $return; + } + } + + // }}} + // {{{ which() + + /** + * Functionality similiar to unix 'which'. Searches the path + * for the specified program. + * + * @param $cmd name of the executable to search for + * + * @access private + * @return string returns the full path if found, false if not + */ + function which($in_cmd) + { + // only pass non-empty strings to System::which() + if (!is_string($in_cmd) || '' === $in_cmd) { + return(false); + } + + // explicitly pass false as fallback value + return System::which($in_cmd, false); + } + + // }}} + // {{{ reset() + + /** + * Prepare for a new command to be built + * + * @access public + * @return void + */ + function reset() + { + $this->previousElement = null; + $this->systemCommand = null; + $this->commandStatus = 0; + } + + // }}} + // {{{ errorMessage() + + /** + * Return a textual error message for a System_Command error code + * + * @param integer error code + * + * @return string error message, or false if the error code was + * not recognized + */ + function errorMessage($in_value) + { + static $errorMessages; + if (!isset($errorMessages)) { + $errorMessages = array( + SYSTEM_COMMAND_OK => 'no error', + SYSTEM_COMMAND_ERROR => 'unknown error', + SYSTEM_COMMAND_NO_SHELL => 'no shell found', + SYSTEM_COMMAND_INVALID_SHELL => 'invalid shell', + SYSTEM_COMMAND_TMPDIR_ERROR => 'could not create temporary directory', + SYSTEM_COMMAND_INVALID_OPERATOR => 'control operator invalid', + SYSTEM_COMMAND_INVALID_COMMAND => 'invalid system command', + SYSTEM_COMMAND_OPERATOR_PLACEMENT => 'invalid placement of control operator', + SYSTEM_COMMAND_COMMAND_PLACEMENT => 'invalid placement of command', + SYSTEM_COMMAND_NOHUP_MISSING => 'nohup not found on system', + SYSTEM_COMMAND_NO_OUTPUT => 'output not allowed', + SYSTEM_COMMAND_STDERR => 'command wrote to stderr', + SYSTEM_COMMAND_NONZERO_EXIT => 'non-zero exit value from command', + ); + } + + if (System_Command::isError($in_value)) { + $in_value = $in_value->getCode(); + } + + return isset($errorMessages[$in_value]) ? $errorMessages[$in_value] : $errorMessages[SYSTEM_COMMAND_ERROR]; + } + + // }}} + // {{{ isError() + + /** + * Tell whether a result code from a System_Command method is an error + * + * @param int result code + * + * @return bool whether $in_value is an error + * + * @access public + */ + function isError($in_value) + { + return (is_object($in_value) && + (strtolower(get_class($in_value)) == 'system_command_error' || + is_subclass_of($in_value, 'system_command_error'))); + } + + // }}} +} + +// {{{ class System_Command_Error + +/** + * System_Command_Error constructor. + * + * @param mixed System_Command error code, or string with error message. + * @param integer what "error mode" to operate in + * @param integer what error level to use for $mode & PEAR_ERROR_TRIGGER + * @param mixed additional debug info, such as the last query + * + * @access public + * + * @see PEAR_Error + */ + +// }}} +class System_Command_Error extends PEAR_Error +{ + // {{{ properties + + /** + * Message in front of the error message + * @var string $error_message_prefix + */ + var $error_message_prefix = 'System_Command Error: '; + + // }}} + // {{{ constructor + + function System_Command_Error($code = SYSTEM_COMMAND_ERROR, $mode = PEAR_ERROR_RETURN, + $level = E_USER_NOTICE, $debuginfo = null) + { + if (is_int($code)) { + $this->PEAR_Error(System_Command::errorMessage($code), $code, $mode, $level, $debuginfo); + } else { + $this->PEAR_Error("Invalid error code: $code", SYSTEM_COMMAND_ERROR, $mode, $level, $debuginfo); + } + } + + // }}} +} +?> From 7bcaa858af31c5c496bc5adc0c73ec333d4c1e63 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Tue, 23 Jun 2009 05:35:20 -0700 Subject: [PATCH 204/262] make file command configurable --- README | 4 ++++ actions/newnotice.php | 3 +++ lib/common.php | 3 ++- 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/README b/README index de10996006..1a57d6a80e 100644 --- a/README +++ b/README @@ -1232,6 +1232,10 @@ supported: an array of mime types you accept to store and distribute, setup your server to properly reckognize the types you want to support. uploads: false to disable uploading files with notices (true by default). +filecommand: The required MIME_Type library may need to use the 'file' + command. It tries the one in the Web server's path, but if + you're having problems with uploads, try setting this to the + correct value. Note: 'file' must accept '-b' and '-i' options. For quotas, be sure you've set the upload_max_filesize and post_max_size in php.ini to be large enough to handle your upload. In httpd.conf diff --git a/actions/newnotice.php b/actions/newnotice.php index 09652d2b36..b7d9ec1dd0 100644 --- a/actions/newnotice.php +++ b/actions/newnotice.php @@ -116,6 +116,9 @@ class NewnoticeAction extends Action function getUploadedFileType() { require_once 'MIME/Type.php'; + $cmd = &PEAR::getStaticProperty('MIME_Type', 'fileCmd'); + $cmd = common_config('attachments', 'filecommand'); + $filetype = MIME_Type::autoDetect($_FILES['attach']['tmp_name']); if (in_array($filetype, common_config('attachments', 'supported'))) { return $filetype; diff --git a/lib/common.php b/lib/common.php index 20f1ab35e1..76eb4a9785 100644 --- a/lib/common.php +++ b/lib/common.php @@ -202,7 +202,7 @@ $config = array('run' => 'web', 'frequency' => 10000, 'reporturl' => 'http://laconi.ca/stats/report'), - 'attachments' => + 'attachments' => array('server' => null, 'dir' => INSTALLDIR . '/file/', 'path' => $_path . '/file/', @@ -241,6 +241,7 @@ $config = 'user_quota' => 50000000, 'monthly_quota' => 15000000, 'uploads' => true, + 'filecommand' => '/usr/bin/file', ), 'group' => array('maxaliases' => 3), From e2becdb25138350170b58ae8f0d1ecd715533cf5 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Tue, 23 Jun 2009 07:25:18 -0700 Subject: [PATCH 205/262] use a subclass for single notice items to show attachments --- actions/shownotice.php | 28 +++++++++++++++++++++++++++- lib/noticelist.php | 13 ------------- 2 files changed, 27 insertions(+), 14 deletions(-) diff --git a/actions/shownotice.php b/actions/shownotice.php index b0d973a991..0d89af5acc 100644 --- a/actions/shownotice.php +++ b/actions/shownotice.php @@ -209,7 +209,7 @@ class ShownoticeAction extends Action function showContent() { $this->elementStart('ol', array('class' => 'notices xoxo')); - $nli = new NoticeListItem($this->notice, $this); + $nli = new SingleNoticeItem($this->notice, $this); $nli->show(); $this->elementEnd('ol'); } @@ -264,3 +264,29 @@ class ShownoticeAction extends Action } } } + +class SingleNoticeItem extends NoticeListItem +{ + /** + * recipe function for displaying a single notice. + * + * We overload to show attachments. + * + * @return void + */ + + function show() + { + $this->showStart(); + $this->showNotice(); + $this->showNoticeAttachments(); + $this->showNoticeInfo(); + $this->showNoticeOptions(); + $this->showEnd(); + } + + function showNoticeAttachments() { + $al = new AttachmentList($this->notice, $this->out); + $al->show(); + } +} diff --git a/lib/noticelist.php b/lib/noticelist.php index ad792441a3..bd4815cd6c 100644 --- a/lib/noticelist.php +++ b/lib/noticelist.php @@ -179,7 +179,6 @@ class NoticeListItem extends Widget { $this->showStart(); $this->showNotice(); - $this->showNoticeAttachments(); $this->showNoticeInfo(); $this->showNoticeOptions(); $this->showEnd(); @@ -193,18 +192,6 @@ class NoticeListItem extends Widget $this->out->elementEnd('div'); } - function showNoticeAttachments() { - if ($this->isUsedInList()) { - return; - } - $al = new AttachmentList($this->notice, $this->out); - $al->show(); - } - - function isUsedInList() { - return 'shownotice' !== $this->out->args['action']; - } - function showNoticeInfo() { $this->out->elementStart('div', 'entry-content'); From a21a9f26c5f0eb034ea389659dd63ffad400de5b Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Tue, 23 Jun 2009 07:29:43 -0700 Subject: [PATCH 206/262] append uploads to content rather than showing them double --- actions/newnotice.php | 112 ++++++++++++++++++++++++++--------- classes/File.php | 67 +++++++++++---------- classes/File_redirection.php | 70 ++-------------------- lib/noticelist.php | 4 -- lib/util.php | 65 ++++++++++++++++++++ 5 files changed, 190 insertions(+), 128 deletions(-) diff --git a/actions/newnotice.php b/actions/newnotice.php index b7d9ec1dd0..a5f87d1be7 100644 --- a/actions/newnotice.php +++ b/actions/newnotice.php @@ -224,16 +224,40 @@ class NewnoticeAction extends Action } } + if (isset($mimetype)) { + $filename = $this->saveFile($mimetype); + if (empty($filename)) { + $this->clientError(_('Couldn\'t save file.')); + } + $fileurl = File::url($filename); + $short_fileurl = common_shorten_url($fileurl); + $content_shortened .= ' ' . $short_fileurl; + if (mb_strlen($content_shortened) > 140) { + $this->deleteFile($filename); + $this->clientError(_('Max notice size is 140 chars, including attachment URL.')); + } + } + + common_debug("newnotice.php - before Notice::saveNew()"); + $notice = Notice::saveNew($user->id, $content_shortened, 'web', 1, ($replyto == 'false') ? null : $replyto); + common_debug("newnotice.php - after Notice::saveNew()"); + if (is_string($notice)) { + if (isset($filename)) { + $this->deleteFile($filename); + } $this->clientError($notice); } + common_debug("newnotice.php - after Notice::saveNew()"); + if (isset($mimetype)) { - $this->storeFile($notice, $mimetype); + $this->attachFile($notice, $filename, $mimetype, $short_fileurl); } + common_broadcast_notice($notice); if ($this->boolean('ajax')) { @@ -259,7 +283,13 @@ class NewnoticeAction extends Action } } - function storeFile($notice, $mimetype) { + function saveFile($mimetype) { + + $cur = common_current_user(); + + if (empty($cur)) { + $this->serverError(_('Somehow lost the login in saveFile')); + } common_debug("NewnoticeAction::storeFile()"); @@ -267,7 +297,7 @@ class NewnoticeAction extends Action common_debug("Basename: $basename"); - $filename = File::filename($notice->id, $basename); + $filename = File::filename($cur->getProfile(), $basename, $mimetype); common_debug("filename: $filename"); @@ -276,36 +306,62 @@ class NewnoticeAction extends Action common_debug("filepath: $filepath"); if (move_uploaded_file($_FILES['attach']['tmp_name'], $filepath)) { - - $file = new File; - $file->filename = $filename; - - $file->url = common_local_url('file', array('notice' => $notice->id)); - - common_debug("file->url =". $file->url); - - $file->size = filesize($filepath); - $file->date = time(); - $file->mimetype = $mimetype; - - if ($file_id = $file->insert()) { - $file_redir = new File_redirection; - $file_redir->url = File::url($filename); - $file_redir->file_id = $file_id; - $file_redir->insert(); - - $f2p = new File_to_post; - $f2p->file_id = $file_id; - $f2p->post_id = $notice->id; - $f2p->insert(); - } else { - $this->clientError(_('There was a database error while saving your file. Please try again.')); - } + return $filename; } else { $this->clientError(_('File could not be moved to destination directory.')); } } + function deleteFile($filename) + { + $filepath = File::path($filename); + @unlink($filepath); + } + + function attachFile($notice, $filename, $mimetype, $short) + { + $file = new File; + $file->filename = $filename; + + $file->url = common_local_url('file', array('notice' => $notice->id)); + + common_debug("file->url =". $file->url); + + $filepath = File::path($filename); + + $file->size = filesize($filepath); + $file->date = time(); + $file->mimetype = $mimetype; + + $file_id = $file->insert(); + + if (!$file_id) { + common_log_db_error($file, "INSERT", __FILE__); + $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; + + $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(); + + if (!$result) { + common_log_db_error($f2p, "INSERT", __FILE__); + $this->clientError(_('There was a database error while saving your file. Please try again.')); + } + } + /** * Show an Ajax-y error message * diff --git a/classes/File.php b/classes/File.php index 1de136240d..b98c9e665f 100644 --- a/classes/File.php +++ b/classes/File.php @@ -124,8 +124,8 @@ class File extends Memcached_DataObject function isRespectsQuota($user) { if ($_FILES['attach']['size'] > common_config('attachments', 'file_quota')) { return sprintf(_('No file may be larger than %d bytes ' . - 'and the file you sent was %d bytes. Try to upload a smaller version.'), - common_config('attachments', 'file_quota'), $_FILES['attach']['size']); + 'and the file you sent was %d bytes. Try to upload a smaller version.'), + common_config('attachments', 'file_quota'), $_FILES['attach']['size']); } $query = "select sum(size) as total from file join file_to_post on file_to_post.file_id = file.id join notice on file_to_post.post_id = notice.id where profile_id = {$user->id} and file.url like '%/notice/%/file'"; @@ -148,44 +148,49 @@ class File extends Memcached_DataObject // where should the file go? - static function filename($notice_id, $basename) - { - return $notice_id . '-' . $basename; - } + static function filename($profile, $basename, $mimetype) + { + require_once 'MIME/Type/Extension.php'; + $mte = new MIME_Type_Extension(); + $ext = $mte->getExtension($mimetype); + $nickname = $profile->nickname; + $datestamp = strftime('%Y%m%dT%H%M%S', time()); + $random = strtolower(common_confirmation_code(32)); + return "$nickname-$datestamp-$random.$ext"; + } - static function path($filename) - { - $dir = common_config('attachments', 'dir'); + static function path($filename) + { + $dir = common_config('attachments', 'dir'); - if ($dir[strlen($dir)-1] != '/') { - $dir .= '/'; - } + if ($dir[strlen($dir)-1] != '/') { + $dir .= '/'; + } - return $dir . $filename; - } + return $dir . $filename; + } - static function url($filename) - { - $path = common_config('attachments', 'path'); + static function url($filename) + { + $path = common_config('attachments', 'path'); - if ($path[strlen($path)-1] != '/') { - $path .= '/'; - } + if ($path[strlen($path)-1] != '/') { + $path .= '/'; + } - if ($path[0] != '/') { - $path = '/'.$path; - } + if ($path[0] != '/') { + $path = '/'.$path; + } - $server = common_config('attachments', 'server'); + $server = common_config('attachments', 'server'); - if (empty($server)) { - $server = common_config('site', 'server'); - } + if (empty($server)) { + $server = common_config('site', 'server'); + } - // XXX: protocol - - return 'http://'.$server.$path.$filename; - } + // XXX: protocol + return 'http://'.$server.$path.$filename; + } } diff --git a/classes/File_redirection.php b/classes/File_redirection.php index edd915c1e8..c173017e2d 100644 --- a/classes/File_redirection.php +++ b/classes/File_redirection.php @@ -25,21 +25,20 @@ require_once INSTALLDIR.'/classes/File_oembed.php'; define('USER_AGENT', 'Laconica user agent / file probe'); - /** * Table Definition for file_redirection */ -class File_redirection extends Memcached_DataObject +class File_redirection extends Memcached_DataObject { ###START_AUTOCODE /* the code below is auto generated do not remove the above tag */ public $__table = 'file_redirection'; // table name public $url; // varchar(255) primary_key not_null - public $file_id; // int(4) - public $redirections; // int(4) - public $httpcode; // int(4) + public $file_id; // int(4) + public $redirections; // int(4) + public $httpcode; // int(4) public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP /* Static get */ @@ -48,8 +47,6 @@ class File_redirection extends Memcached_DataObject /* the code above is auto generated do not remove the tag below */ ###END_AUTOCODE - - function _commonCurl($url, $redirs) { $curlh = curl_init(); curl_setopt($curlh, CURLOPT_URL, $url); @@ -86,8 +83,6 @@ class File_redirection extends Memcached_DataObject return $url; } - - $curlh = File_redirection::_commonCurl($short_url, $redirs); // Don't include body in output curl_setopt($curlh, CURLOPT_NOBODY, true); @@ -143,62 +138,7 @@ class File_redirection extends Memcached_DataObject } function _userMakeShort($long_url, $user) { - if (empty($user)) { - // common current user does not find a user when called from the XMPP daemon - // therefore we'll set one here fix, so that XMPP given URLs may be shortened - $user->urlshorteningservice = 'ur1.ca'; - } - $curlh = curl_init(); - curl_setopt($curlh, CURLOPT_CONNECTTIMEOUT, 20); // # seconds to wait - curl_setopt($curlh, CURLOPT_USERAGENT, 'Laconica'); - curl_setopt($curlh, CURLOPT_RETURNTRANSFER, true); - - switch($user->urlshorteningservice) { - case 'ur1.ca': - require_once INSTALLDIR.'/lib/Shorturl_api.php'; - $short_url_service = new LilUrl; - $short_url = $short_url_service->shorten($long_url); - break; - - case '2tu.us': - $short_url_service = new TightUrl; - require_once INSTALLDIR.'/lib/Shorturl_api.php'; - $short_url = $short_url_service->shorten($long_url); - break; - - case 'ptiturl.com': - require_once INSTALLDIR.'/lib/Shorturl_api.php'; - $short_url_service = new PtitUrl; - $short_url = $short_url_service->shorten($long_url); - break; - - case 'bit.ly': - curl_setopt($curlh, CURLOPT_URL, 'http://bit.ly/api?method=shorten&long_url='.urlencode($long_url)); - $short_url = current(json_decode(curl_exec($curlh))->results)->hashUrl; - break; - - case 'is.gd': - curl_setopt($curlh, CURLOPT_URL, 'http://is.gd/api.php?longurl='.urlencode($long_url)); - $short_url = curl_exec($curlh); - break; - case 'snipr.com': - curl_setopt($curlh, CURLOPT_URL, 'http://snipr.com/site/snip?r=simple&link='.urlencode($long_url)); - $short_url = curl_exec($curlh); - break; - case 'metamark.net': - curl_setopt($curlh, CURLOPT_URL, 'http://metamark.net/api/rest/simple?long_url='.urlencode($long_url)); - $short_url = curl_exec($curlh); - break; - case 'tinyurl.com': - curl_setopt($curlh, CURLOPT_URL, 'http://tinyurl.com/api-create.php?url='.urlencode($long_url)); - $short_url = curl_exec($curlh); - break; - default: - $short_url = false; - } - - curl_close($curlh); - + $short_url = common_shorten_url($long_url); if ($short_url) { $short_url = (string)$short_url; // store it diff --git a/lib/noticelist.php b/lib/noticelist.php index bd4815cd6c..6f05c63d66 100644 --- a/lib/noticelist.php +++ b/lib/noticelist.php @@ -336,10 +336,6 @@ class NoticeListItem extends Widget // versions (>> 0.4.x) $this->out->raw(common_render_content($this->notice->content, $this->notice)); } - $uploaded = $this->notice->getUploadedAttachment(); - if ($uploaded) { - $this->out->element('a', array('href' => $uploaded[0], 'class' => 'attachment', 'id' => 'attachment-' . $uploaded[1]), $uploaded[0]); - } $this->out->elementEnd('p'); } diff --git a/lib/util.php b/lib/util.php index 0aff893fd8..1af4625167 100644 --- a/lib/util.php +++ b/lib/util.php @@ -1377,3 +1377,68 @@ function common_database_tablename($tablename) //table prefixes could be added here later return $tablename; } + +function common_shorten_url($long_url) +{ + $user = common_current_user(); + if (empty($user)) { + // common current user does not find a user when called from the XMPP daemon + // therefore we'll set one here fix, so that XMPP given URLs may be shortened + $svc = 'ur1.ca'; + } else { + $svc = $user->urlshorteningservice; + } + + $curlh = curl_init(); + curl_setopt($curlh, CURLOPT_CONNECTTIMEOUT, 20); // # seconds to wait + curl_setopt($curlh, CURLOPT_USERAGENT, 'Laconica'); + curl_setopt($curlh, CURLOPT_RETURNTRANSFER, true); + + switch($svc) { + case 'ur1.ca': + require_once INSTALLDIR.'/lib/Shorturl_api.php'; + $short_url_service = new LilUrl; + $short_url = $short_url_service->shorten($long_url); + break; + + case '2tu.us': + $short_url_service = new TightUrl; + require_once INSTALLDIR.'/lib/Shorturl_api.php'; + $short_url = $short_url_service->shorten($long_url); + break; + + case 'ptiturl.com': + require_once INSTALLDIR.'/lib/Shorturl_api.php'; + $short_url_service = new PtitUrl; + $short_url = $short_url_service->shorten($long_url); + break; + + case 'bit.ly': + curl_setopt($curlh, CURLOPT_URL, 'http://bit.ly/api?method=shorten&long_url='.urlencode($long_url)); + $short_url = current(json_decode(curl_exec($curlh))->results)->hashUrl; + break; + + case 'is.gd': + curl_setopt($curlh, CURLOPT_URL, 'http://is.gd/api.php?longurl='.urlencode($long_url)); + $short_url = curl_exec($curlh); + break; + case 'snipr.com': + curl_setopt($curlh, CURLOPT_URL, 'http://snipr.com/site/snip?r=simple&link='.urlencode($long_url)); + $short_url = curl_exec($curlh); + break; + case 'metamark.net': + curl_setopt($curlh, CURLOPT_URL, 'http://metamark.net/api/rest/simple?long_url='.urlencode($long_url)); + $short_url = curl_exec($curlh); + break; + case 'tinyurl.com': + curl_setopt($curlh, CURLOPT_URL, 'http://tinyurl.com/api-create.php?url='.urlencode($long_url)); + $short_url = curl_exec($curlh); + break; + default: + $short_url = false; + } + + curl_close($curlh); + + return $short_url; +} \ No newline at end of file From e261a97150684c943ebd6f994f610a2c2d0ba6b6 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Tue, 23 Jun 2009 07:48:33 -0700 Subject: [PATCH 207/262] remove common_debug from newnotice --- actions/newnotice.php | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/actions/newnotice.php b/actions/newnotice.php index a5f87d1be7..4a2c369f0f 100644 --- a/actions/newnotice.php +++ b/actions/newnotice.php @@ -238,13 +238,9 @@ class NewnoticeAction extends Action } } - common_debug("newnotice.php - before Notice::saveNew()"); - $notice = Notice::saveNew($user->id, $content_shortened, 'web', 1, ($replyto == 'false') ? null : $replyto); - common_debug("newnotice.php - after Notice::saveNew()"); - if (is_string($notice)) { if (isset($filename)) { $this->deleteFile($filename); @@ -252,8 +248,6 @@ class NewnoticeAction extends Action $this->clientError($notice); } - common_debug("newnotice.php - after Notice::saveNew()"); - if (isset($mimetype)) { $this->attachFile($notice, $filename, $mimetype, $short_fileurl); } @@ -291,20 +285,12 @@ class NewnoticeAction extends Action $this->serverError(_('Somehow lost the login in saveFile')); } - common_debug("NewnoticeAction::storeFile()"); - $basename = basename($_FILES['attach']['name']); - common_debug("Basename: $basename"); - $filename = File::filename($cur->getProfile(), $basename, $mimetype); - common_debug("filename: $filename"); - $filepath = File::path($filename); - common_debug("filepath: $filepath"); - if (move_uploaded_file($_FILES['attach']['tmp_name'], $filepath)) { return $filename; } else { @@ -325,8 +311,6 @@ class NewnoticeAction extends Action $file->url = common_local_url('file', array('notice' => $notice->id)); - common_debug("file->url =". $file->url); - $filepath = File::path($filename); $file->size = filesize($filepath); From 4ca6aa1930f65120162a692c4cb86f5becb4ae7f Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Tue, 23 Jun 2009 09:16:41 -0700 Subject: [PATCH 208/262] a little sql script to drop full-text index and use innodb for profile and notice --- db/innodb.sql | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 db/innodb.sql diff --git a/db/innodb.sql b/db/innodb.sql new file mode 100644 index 0000000000..f3ab6cd690 --- /dev/null +++ b/db/innodb.sql @@ -0,0 +1,2 @@ +alter table profile drop index nickname, engine=InnoDB; +alter table notice drop index content, engine=InnoDB; From 545cbb2c82306872af4a227fd4fc7088da8e9a8c Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Tue, 23 Jun 2009 09:18:10 -0700 Subject: [PATCH 209/262] make pwgen command configurable --- scripts/setup.cfg.sample | 1 + scripts/setup_status_network.sh | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/setup.cfg.sample b/scripts/setup.cfg.sample index 450b9c30a3..72e6a21afc 100644 --- a/scripts/setup.cfg.sample +++ b/scripts/setup.cfg.sample @@ -9,4 +9,5 @@ export ADMIN=root export ADMINPASS=yourpassword export SITEDB=example_net_site export AVATARBASE=/var/www/avatar.example.net +export PWDGEN="pwdgen 20" diff --git a/scripts/setup_status_network.sh b/scripts/setup_status_network.sh index e1d14593fb..cf9f783158 100755 --- a/scripts/setup_status_network.sh +++ b/scripts/setup_status_network.sh @@ -5,7 +5,7 @@ source ./setup.cfg export nickname=$1 export sitename=$2 -export password=`pwgen 20` +export password=`$PWDGEN` export database=$nickname$DBBASE export username=$nickname$USERBASE From 009e40834c70c0e0b430552d37880a04be327465 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Tue, 23 Jun 2009 09:19:54 -0700 Subject: [PATCH 210/262] pwgen not pwdgen --- scripts/setup.cfg.sample | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/setup.cfg.sample b/scripts/setup.cfg.sample index 72e6a21afc..dd3c2705fc 100644 --- a/scripts/setup.cfg.sample +++ b/scripts/setup.cfg.sample @@ -9,5 +9,5 @@ export ADMIN=root export ADMINPASS=yourpassword export SITEDB=example_net_site export AVATARBASE=/var/www/avatar.example.net -export PWDGEN="pwdgen 20" +export PWDGEN="pwgen 20" From 4d4d951531d9fb6db008c26439eab3b0ba658d79 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Tue, 23 Jun 2009 09:20:20 -0700 Subject: [PATCH 211/262] add innodb by default to status networks --- 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 cf9f783158..29ee010ed9 100755 --- a/scripts/setup_status_network.sh +++ b/scripts/setup_status_network.sh @@ -13,7 +13,7 @@ export username=$nickname$USERBASE mysqladmin -h $DBHOST -u $ADMIN --password=$ADMINPASS create $database -for f in laconica.sql sms_carrier.sql foreign_services.sql notice_source.sql; do +for f in laconica.sql innodb.sql sms_carrier.sql foreign_services.sql notice_source.sql; do mysql -h $DBHOST -u $ADMIN --password=$ADMINPASS $database < ../db/$f; done From e744eba7ebf6f2b057bfd45a9f3b3c4626017c50 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Tue, 23 Jun 2009 09:52:31 -0700 Subject: [PATCH 212/262] oembed and thumbnail don't need sequences --- classes/File_oembed.php | 29 ++++++++++++++++------------- classes/File_thumbnail.php | 11 ++++++++--- 2 files changed, 24 insertions(+), 16 deletions(-) diff --git a/classes/File_oembed.php b/classes/File_oembed.php index 51ee57b296..69230e4a48 100644 --- a/classes/File_oembed.php +++ b/classes/File_oembed.php @@ -25,24 +25,24 @@ require_once INSTALLDIR.'/classes/Memcached_DataObject.php'; * Table Definition for file_oembed */ -class File_oembed extends Memcached_DataObject +class File_oembed extends Memcached_DataObject { ###START_AUTOCODE /* the code below is auto generated do not remove the above tag */ public $__table = 'file_oembed'; // table name public $file_id; // int(4) primary_key not_null - public $version; // varchar(20) - public $type; // varchar(20) - public $provider; // varchar(50) - public $provider_url; // varchar(255) - public $width; // int(4) - public $height; // int(4) - public $html; // text() - public $title; // varchar(255) - public $author_name; // varchar(50) - public $author_url; // varchar(255) - public $url; // varchar(255) + public $version; // varchar(20) + public $type; // varchar(20) + public $provider; // varchar(50) + public $provider_url; // varchar(255) + public $width; // int(4) + public $height; // int(4) + public $html; // text() + public $title; // varchar(255) + public $author_name; // varchar(50) + public $author_url; // varchar(255) + public $url; // varchar(255) public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP /* Static get */ @@ -51,6 +51,10 @@ class File_oembed extends Memcached_DataObject /* the code above is auto generated do not remove the tag below */ ###END_AUTOCODE + function sequenceKey() + { + return array(false, false, false); + } function _getOembed($url, $maxwidth = 500, $maxheight = 400, $format = 'json') { $cmd = common_config('oohembed', 'endpoint') . '?url=' . urlencode($url); @@ -84,4 +88,3 @@ class File_oembed extends Memcached_DataObject } } - diff --git a/classes/File_thumbnail.php b/classes/File_thumbnail.php index 21dcad5714..44b92a2fad 100644 --- a/classes/File_thumbnail.php +++ b/classes/File_thumbnail.php @@ -25,7 +25,7 @@ require_once INSTALLDIR.'/classes/Memcached_DataObject.php'; * Table Definition for file_thumbnail */ -class File_thumbnail extends Memcached_DataObject +class File_thumbnail extends Memcached_DataObject { ###START_AUTOCODE /* the code below is auto generated do not remove the above tag */ @@ -33,8 +33,8 @@ class File_thumbnail extends Memcached_DataObject public $__table = 'file_thumbnail'; // table name public $file_id; // int(4) primary_key not_null public $url; // varchar(255) unique_key - public $width; // int(4) - public $height; // int(4) + public $width; // int(4) + public $height; // int(4) public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP /* Static get */ @@ -43,6 +43,11 @@ class File_thumbnail extends Memcached_DataObject /* the code above is auto generated do not remove the tag below */ ###END_AUTOCODE + function sequenceKey() + { + return array(false, false, false); + } + function saveNew($data, $file_id) { $tn = new File_thumbnail; $tn->file_id = $file_id; From eb40fbc17ad1efb0a4c51ee00b1e9408d2af382f Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Tue, 23 Jun 2009 17:05:55 +0000 Subject: [PATCH 213/262] On XHR notice post, calls NoticeAttachment to trigger thumbnail and attachment views --- js/util.js | 1 + 1 file changed, 1 insertion(+) diff --git a/js/util.js b/js/util.js index 17ae4c0719..65a77960a0 100644 --- a/js/util.js +++ b/js/util.js @@ -217,6 +217,7 @@ $(document).ready(function(){ $('#'+li.id).css({display:'none'}); $('#'+li.id).fadeIn(2500); NoticeReply(); + NoticeAttachments(); } } $("#notice_data-text").val(""); From a515c3ce530aba411e0d8f90de071ede90318142 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Tue, 23 Jun 2009 10:43:50 -0700 Subject: [PATCH 214/262] 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 215/262] 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 216/262] 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 217/262] 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 218/262] 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 219/262] 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 220/262] 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 221/262] 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 222/262] 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 223/262] 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 224/262] 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 225/262] 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 226/262] 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 227/262] 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 228/262] 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 229/262] 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 230/262] 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 231/262] 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 232/262] 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 233/262] 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 234/262] 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 235/262] 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 236/262] 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 237/262] 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 238/262] 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 239/262] 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 240/262] 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 241/262] 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 242/262] 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 243/262] 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 244/262] 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 245/262] 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 246/262] 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 247/262] 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 248/262] 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 249/262] 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 250/262] 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 251/262] 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 252/262] 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 253/262] 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 254/262] 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 255/262] 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 256/262] 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 257/262] 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 258/262] 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 259/262] 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 260/262] 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 261/262] 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 262/262] 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; + } }