diff --git a/README b/README index 4f93829601..9207f3e900 100644 --- a/README +++ b/README @@ -1136,6 +1136,32 @@ welcome: nickname of a user account that sends welcome messages to new If either of these special user accounts are specified, the users should be created before the configuration is updated. +snapshot +-------- + +The software will, by default, send statistical snapshots about the +local installation to a stats server on the laconi.ca Web site. This +data is used by the developers to prioritize development decisions. No +identifying data about users or organizations is collected. The data +is available to the public for review. Participating in this survey +helps Laconica developers take your needs into account when updating +the software. + +run: string indicating when to run the statistics. Values can be 'web' + (run occasionally at Web time), 'cron' (run from a cron script), + or 'never' (don't ever run). If you set it to 'cron', remember to + schedule the script to run on a regular basis. +frequency: if run value is 'web', how often to report statistics. + Measured in Web hits; depends on how active your site is. + Default is 10000 -- that is, one report every 10000 Web hits, + on average. +reporturl: URL to post statistics to. Defaults to Laconica developers' + report system, but if they go evil or disappear you may + need to update this to another value. Note: if you + don't want to report stats, it's much better to + set 'run' to 'never' than to set this value to something + nonsensical. + Troubleshooting =============== diff --git a/actions/facebookhome.php b/actions/facebookhome.php index 5946e6c984..00b35ef686 100644 --- a/actions/facebookhome.php +++ b/actions/facebookhome.php @@ -115,7 +115,7 @@ class FacebookhomeAction extends FacebookAction $flink->foreign_id = $this->fbuid; $flink->service = FACEBOOK_SERVICE; $flink->created = common_sql_now(); - $flink->set_flags(true, false, false); + $flink->set_flags(true, false, false, false); $flink_id = $flink->insert(); @@ -138,9 +138,6 @@ class FacebookhomeAction extends FacebookAction function setDefaults() { - // A default prefix string for notices - $this->facebook->api_client->data_setUserPreference( - FACEBOOK_NOTICE_PREFIX, 'dented: '); $this->facebook->api_client->data_setUserPreference( FACEBOOK_PROMPTED_UPDATE_PREF, 'false'); } diff --git a/actions/facebookinvite.php b/actions/facebookinvite.php index 1302064ad7..2207580f77 100644 --- a/actions/facebookinvite.php +++ b/actions/facebookinvite.php @@ -17,7 +17,9 @@ * along with this program. If not, see . */ -if (!defined('LACONICA')) { exit(1); } +if (!defined('LACONICA')) { + exit(1); +} require_once(INSTALLDIR.'/lib/facebookaction.php'); @@ -67,7 +69,7 @@ class FacebookinviteAction extends FacebookAction function showSuccessContent() { - $this->element('h2', null, sprintf(_('Thanks for inviting your friends to use %s'), + $this->element('h2', null, sprintf(_('Thanks for inviting your friends to use %s'), common_config('site', 'name'))); $this->element('p', null, _('Invitations have been sent to the following users:')); @@ -89,16 +91,6 @@ class FacebookinviteAction extends FacebookAction function showFormContent() { - - // Get a list of users who are already using the app for exclusion - $exclude_ids = $this->facebook->api_client->friends_getAppUsers(); - $exclude_ids_csv = null; - - // fbml needs these as a csv string, not an array - if ($exclude_ids) { - $exclude_ids_csv = implode(',', $exclude_ids); - } - $content = sprintf(_('You have been invited to %s'), common_config('site', 'name')) . htmlentities(''); @@ -109,36 +101,43 @@ class FacebookinviteAction extends FacebookAction 'content' => $content)); $this->hidden('invite', 'true'); $actiontext = sprintf(_('Invite your friends to use %s'), common_config('site', 'name')); - - $multi_params = array('showborder' => 'false'); + + $multi_params = array('showborder' => 'false'); $multi_params['actiontext'] = $actiontext; - - if ($exclude_ids_csv) { + $multi_params['bypass'] = 'cancel'; + + // Get a list of users who are already using the app for exclusion + $exclude_ids = $this->facebook->api_client->friends_getAppUsers(); + $exclude_ids_csv = null; + + // fbml needs these as a csv string, not an array + if ($exclude_ids) { + $exclude_ids_csv = implode(',', $exclude_ids); $multi_params['exclude_ids'] = $exclude_ids_csv; } - $multi_params['bypass'] = 'cancel'; - $this->element('fb:multi-friend-selector', $multi_params); - $this->elementEnd('fb:request-form'); - $this->element('h2', null, sprintf(_('Friends already using %s:'), - common_config('site', 'name'))); - $this->elementStart('ul', array('id' => 'facebook-friends')); - - foreach ($exclude_ids as $friend) { - $this->elementStart('li'); - $this->element('fb:profile-pic', array('uid' => $friend, 'size' => 'square')); - $this->element('fb:name', array('uid' => $friend, - 'capitalize' => 'true')); - $this->elementEnd('li'); - } + if ($exclude_ids) { - $this->elementEnd("ul"); + $this->element('h2', null, sprintf(_('Friends already using %s:'), + common_config('site', 'name'))); + $this->elementStart('ul', array('id' => 'facebook-friends')); + + foreach ($exclude_ids as $friend) { + $this->elementStart('li'); + $this->element('fb:profile-pic', array('uid' => $friend, 'size' => 'square')); + $this->element('fb:name', array('uid' => $friend, + 'capitalize' => 'true')); + $this->elementEnd('li'); + } + + $this->elementEnd("ul"); + } } - - function title() + + function title() { return sprintf(_('Send invitations')); } diff --git a/actions/facebooksettings.php b/actions/facebooksettings.php index 236460c1c9..227e123160 100644 --- a/actions/facebooksettings.php +++ b/actions/facebooksettings.php @@ -55,7 +55,7 @@ class FacebooksettingsAction extends FacebookAction $prefix = $this->trimmed('prefix'); $original = clone($this->flink); - $this->flink->set_flags($noticesync, $replysync, false); + $this->flink->set_flags($noticesync, $replysync, false, false); $result = $this->flink->update($original); $this->facebook->api_client->data_setUserPreference(FACEBOOK_NOTICE_PREFIX, diff --git a/classes/Group_inbox.php b/classes/Group_inbox.php old mode 100755 new mode 100644 diff --git a/classes/Group_member.php b/classes/Group_member.php old mode 100755 new mode 100644 diff --git a/classes/Related_group.php b/classes/Related_group.php old mode 100755 new mode 100644 diff --git a/classes/Status_network.php b/classes/Status_network.php old mode 100755 new mode 100644 diff --git a/classes/User_group.php b/classes/User_group.php old mode 100755 new mode 100644 diff --git a/classes/laconica.ini b/classes/laconica.ini index 316923af02..92bbb35d4c 100644 --- a/classes/laconica.ini +++ b/classes/laconica.ini @@ -46,6 +46,64 @@ modified = 384 notice_id = K user_id = K +[file] +id = 129 +url = 2 +mimetype = 2 +size = 1 +title = 2 +date = 1 +protected = 1 + +[file__keys] +id = N + +[file_oembed] +id = 129 +file_id = 1 +version = 2 +type = 2 +provider = 2 +provider_url = 2 +width = 1 +height = 1 +html = 34 +title = 2 +author_name = 2 +author_url = 2 +url = 2 + +[file_oembed__keys] +id = N + +[file_redirection] +id = 129 +url = 2 +file_id = 1 +redirections = 1 +httpcode = 1 + +[file_redirection__keys] +id = N + +[file_thumbnail] +id = 129 +file_id = 1 +url = 2 +width = 1 +height = 1 + +[file_thumbnail__keys] +id = N + +[file_to_post] +id = 129 +file_id = 1 +post_id = 1 + +[file_to_post__keys] +id = N + [foreign_link] user_id = 129 foreign_id = 129 @@ -392,63 +450,3 @@ modified = 384 [user_openid__keys] canonical = K display = U - -[file] -id = 129 -url = 2 -mimetype = 2 -size = 1 -title = 2 -date = 1 -protected = 1 - -[file__keys] -id = N - -[file_oembed] -id = 129 -file_id = 129 -version = 2 -type = 2 -provider = 2 -provider_url = 2 -width = 1 -height = 1 -html = 34 -title = 2 -author_name = 2 -author_url = 2 -url = 2 - -[file_oembed__keys] -id = N - -[file_redirection] -id = 129 -url = 2 -file_id = 129 -redirections = 1 -httpcode = 1 - -[file_redirection__keys] -id = N - -[file_thumbnail] -id = 129 -file_id = 129 -url = 2 -width = 1 -height = 1 - -[file_thumbnail__keys] -id = N - -[file_to_post] -id = 129 -file_id = 129 -post_id = 129 - -[file_to_post__keys] -id = N - - diff --git a/config.php.sample b/config.php.sample index 4f438dc5e1..282826a7fb 100644 --- a/config.php.sample +++ b/config.php.sample @@ -206,3 +206,12 @@ $config['sphinx']['port'] = 3312; // print "Error\n"; // exit(1); // } + +// How often to send snapshots; in # of web hits. Ideally, +// try to do this once per month (that is, make this equal to number +// of hits per month) +// $config['snapshot']['frequency'] = 10000; +// If you don't want to report statistics to the central server, uncomment. +// $config['snapshot']['run'] = 'never'; +// If you want to report statistics in a cron job instead. +// $config['snapshot']['run'] = 'cron'; diff --git a/db/laconica.sql b/db/laconica.sql index 344f0ff723..0b20bc172c 100644 --- a/db/laconica.sql +++ b/db/laconica.sql @@ -426,12 +426,12 @@ create table group_inbox ( ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin; 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), + id integer primary key auto_increment, + url varchar(255), mimetype varchar(50), + size integer, + title varchar(255), + date integer(11), + protected integer(1), unique(url) ) ENGINE=MyISAM CHARACTER SET utf8 COLLATE utf8_general_ci; @@ -447,40 +447,38 @@ create table file_oembed ( height integer, html text, title varchar(255), - author_name varchar(50), - author_url varchar(255), - url varchar(255), + author_name varchar(50), + author_url varchar(255), + url varchar(255), 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, + id integer primary key auto_increment, + url varchar(255), + file_id integer, + redirections integer, + httpcode integer, 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, + id integer primary key auto_increment, + file_id integer, + url varchar(255), + width integer, + height integer, - unique(file_id), + 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, - post_id integer, + id integer primary key auto_increment, + file_id integer, + post_id integer, unique(file_id, post_id) ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin; - - diff --git a/db/notice_source.sql b/db/notice_source.sql index f351bb0668..1508af1ec8 100644 --- a/db/notice_source.sql +++ b/db/notice_source.sql @@ -7,6 +7,7 @@ VALUES ('cliqset', 'Cliqset', 'http://www.cliqset.com/', now()), ('deskbar','Deskbar-Applet','http://www.gnome.org/projects/deskbar-applet/', now()), ('Do','Gnome Do','http://do.davebsd.com/wiki/index.php?title=Microblog_Plugin', now()), + ('eventbox','EventBox','http://thecosmicmachine.com/eventbox/ ', now()), ('Facebook','Facebook','http://apps.facebook.com/identica/', now()), ('feed2omb','feed2omb','http://projects.ciarang.com/p/feed2omb/', now()), ('gravity', 'Gravity', 'http://mobileways.de/gravity', now()), diff --git a/index.php b/index.php index c2972ec5fe..4eff99dff5 100644 --- a/index.php +++ b/index.php @@ -69,6 +69,8 @@ function main() } global $user, $action, $config; + Snapshot::check(); + if (!_have_config()) { $msg = sprintf(_("No configuration file found. Try running ". "the installation program first.")); diff --git a/lib/common.php b/lib/common.php index 3feba1d8bd..0ce46442de 100644 --- a/lib/common.php +++ b/lib/common.php @@ -159,6 +159,10 @@ $config = 'newuser' => array('subscribe' => null, 'welcome' => null), + 'snapshot' => + array('run' => 'web', + 'frequency' => 10000, + 'reporturl' => 'http://laconi.ca/stats/report'), ); $config['db'] = &PEAR::getStaticProperty('DB_DataObject','options'); diff --git a/lib/facebookaction.php b/lib/facebookaction.php index 043a078cd5..a445750f7e 100644 --- a/lib/facebookaction.php +++ b/lib/facebookaction.php @@ -38,14 +38,14 @@ require_once INSTALLDIR.'/lib/noticeform.php'; class FacebookAction extends Action { - + var $facebook = null; var $fbuid = null; var $flink = null; var $action = null; var $app_uri = null; var $app_name = null; - + /** * Constructor * @@ -60,71 +60,71 @@ class FacebookAction extends Action function __construct($output='php://output', $indent=true, $facebook=null, $flink=null) { parent::__construct($output, $indent); - + $this->facebook = $facebook; $this->flink = $flink; - + if ($this->flink) { - $this->fbuid = $flink->foreign_id; + $this->fbuid = $flink->foreign_id; $this->user = $flink->getUser(); } - + $this->args = array(); } - + function prepare($argarray) - { + { parent::prepare($argarray); - + $this->facebook = getFacebook(); $this->fbuid = $this->facebook->require_login(); - + $this->action = $this->trimmed('action'); - + $app_props = $this->facebook->api_client->Admin_getAppProperties( array('canvas_name', 'application_name')); - + $this->app_uri = 'http://apps.facebook.com/' . $app_props['canvas_name']; $this->app_name = $app_props['application_name']; $this->flink = Foreign_link::getByForeignID($this->fbuid, FACEBOOK_SERVICE); - + return true; - + } - + function showStylesheets() { // Add a timestamp to the file so Facebook cache wont ignore our changes $ts = filemtime(INSTALLDIR.'/theme/base/css/display.css'); - - $this->element('link', array('rel' => 'stylesheet', - 'type' => 'text/css', - 'href' => theme_path('css/display.css', 'base') . '?ts=' . $ts)); - + + $this->element('link', array('rel' => 'stylesheet', + 'type' => 'text/css', + 'href' => theme_path('css/display.css', 'base') . '?ts=' . $ts)); + $theme = common_config('site', 'theme'); - + $ts = filemtime(INSTALLDIR. '/theme/' . $theme .'/css/display.css'); - + $this->element('link', array('rel' => 'stylesheet', 'type' => 'text/css', 'href' => theme_path('css/display.css', null) . '?ts=' . $ts)); - + $ts = filemtime(INSTALLDIR.'/theme/base/css/facebookapp.css'); - + $this->element('link', array('rel' => 'stylesheet', 'type' => 'text/css', 'href' => theme_path('css/facebookapp.css', 'base') . '?ts=' . $ts)); } - + function showScripts() { // Add a timestamp to the file so Facebook cache wont ignore our changes $ts = filemtime(INSTALLDIR.'/js/facebookapp.js'); - + $this->element('script', array('src' => common_path('js/facebookapp.js') . '?ts=' . $ts)); } - + /** * Start an Facebook ready HTML document * @@ -138,11 +138,11 @@ class FacebookAction extends Action * @return void */ - function startHTML($type=null) - { + function startHTML($type=null) + { $this->showStylesheets(); $this->showScripts(); - + $this->elementStart('div', array('class' => 'facebook-page')); } @@ -177,18 +177,18 @@ class FacebookAction extends Action $this->showFooter(); $this->elementEnd('div'); } - + function showAside() { } function showHead($error, $success) { - + if ($error) { $this->element("h1", null, $error); } - + if ($success) { $this->element("h1", null, $success); } @@ -198,10 +198,10 @@ class FacebookAction extends Action $this->element('fb:add-section-button', array('section' => 'profile')); $this->elementEnd('span'); $this->elementEnd('fb:if-section-not-added'); - + } - + // Make this into a widget later function showLocalNav() { @@ -229,8 +229,8 @@ class FacebookAction extends Action $this->elementEnd('li'); $this->elementEnd('ul'); - } - + } + /** * Show header of the page. * @@ -245,7 +245,7 @@ class FacebookAction extends Action $this->showNoticeForm(); $this->elementEnd('div'); } - + /** * Show page, a template method. * @@ -258,7 +258,7 @@ class FacebookAction extends Action $this->showBody(); $this->endHTML(); } - + function showInstructions() { @@ -278,7 +278,7 @@ class FacebookAction extends Action $this->element('a', array('href' => common_local_url('register')), _('Register')); $this->text($loginmsg_part2); - $this->elementEnd('p'); + $this->elementEnd('p'); $this->elementEnd('dd'); $this->elementEnd('dl'); @@ -317,7 +317,7 @@ class FacebookAction extends Action $this->elementEnd('ul'); $this->submit('submit', _('Login')); - $this->elementEnd('fieldset'); + $this->elementEnd('fieldset'); $this->elementEnd('form'); $this->elementStart('p'); @@ -329,73 +329,73 @@ class FacebookAction extends Action $this->elementEnd('div'); } - - + + function updateProfileBox($notice) { // Need to include inline CSS for styling the Profile box - $app_props = $this->facebook->api_client->Admin_getAppProperties(array('icon_url')); - $icon_url = $app_props['icon_url']; + $app_props = $this->facebook->api_client->Admin_getAppProperties(array('icon_url')); + $icon_url = $app_props['icon_url']; $style = ''; + #facebook_laconica_app { + text-indent:-9999px; + height:16px; + width:16px; + display:block; + background:url('.$icon_url.') no-repeat 0 0; + float:right; + } + '; $this->xw->openMemory(); @@ -407,12 +407,12 @@ class FacebookAction extends Action $fbml_main = "$style " . $this->xw->outputMemory(false) . ""; - $this->facebook->api_client->profile_setFBML(null, $this->fbuid, $fbml, null, null, $fbml_main); + $this->facebook->api_client->profile_setFBML(null, $this->fbuid, $fbml, null, null, $fbml_main); $this->xw->openURI('php://output'); } - - + + /** * Generate pagination links * @@ -457,24 +457,24 @@ class FacebookAction extends Action $this->elementEnd('div'); } } - - function updateFacebookStatus($notice) + + function updateFacebookStatus($notice) { $prefix = $this->facebook->api_client->data_getUserPreference(FACEBOOK_NOTICE_PREFIX, $this->fbuid); $content = "$prefix $notice->content"; - + if ($this->facebook->api_client->users_hasAppPermission('status_update', $this->fbuid)) { $this->facebook->api_client->users_setStatus($content, $this->fbuid, false, true); } } - + function saveNewNotice() { $user = $this->flink->getUser(); $content = $this->trimmed('status_textarea'); - + if (!$content) { $this->showPage(_('No notice content!')); return; @@ -492,9 +492,9 @@ class FacebookAction extends Action $cmd = $inter->handle_command($user, $content_shortened); if ($cmd) { - + // XXX fix this - + $cmd->execute(new WebChannel()); return; } @@ -510,20 +510,20 @@ class FacebookAction extends Action } common_broadcast_notice($notice); - + // Also update the user's Facebook status $this->updateFacebookStatus($notice); $this->updateProfileBox($notice); - + } } -class FacebookNoticeForm extends NoticeForm +class FacebookNoticeForm extends NoticeForm { - + var $post_action = null; - + /** * Constructor * @@ -532,13 +532,13 @@ class FacebookNoticeForm extends NoticeForm * @param string $content content to pre-fill */ - function __construct($out=null, $action=null, $content=null, + function __construct($out=null, $action=null, $content=null, $post_action=null, $user=null) { parent::__construct($out, $action, $content, $user); $this->post_action = $post_action; } - + /** * Action of the form * @@ -554,7 +554,7 @@ class FacebookNoticeForm extends NoticeForm class FacebookNoticeList extends NoticeList { - + /** * constructor * @@ -565,7 +565,7 @@ class FacebookNoticeList extends NoticeList { parent::__construct($notice, $out); } - + /** * show the list of notices * @@ -619,7 +619,7 @@ class FacebookNoticeList extends NoticeList } class FacebookNoticeListItem extends NoticeListItem -{ +{ /** * constructor @@ -646,51 +646,19 @@ class FacebookNoticeListItem extends NoticeListItem function show() { $this->showStart(); + $this->showNotice(); + $this->showNoticeInfo(); - $this->out->elementStart('div', 'entry-title'); - $this->showAuthor(); - $this->showContent(); - $this->out->elementEnd('div'); - - $this->out->elementStart('div', 'entry-content'); - $this->showNoticeLink(); - $this->showNoticeSource(); - $this->showReplyTo(); - $this->out->elementEnd('div'); + // XXX: Need to update to show attachements and controls $this->showEnd(); } - function showNoticeLink() - { - $noticeurl = common_local_url('shownotice', - array('notice' => $this->notice->id)); - // XXX: we need to figure this out better. Is this right? - if (strcmp($this->notice->uri, $noticeurl) != 0 && - preg_match('/^http/', $this->notice->uri)) { - $noticeurl = $this->notice->uri; - } - - $this->out->elementStart('dl', 'timestamp'); - $this->out->element('dt', null, _('Published')); - $this->out->elementStart('dd', null); - $this->out->elementStart('a', array('rel' => 'bookmark', - 'href' => $noticeurl)); - $dt = common_date_iso8601($this->notice->created); - $this->out->element('abbr', array('class' => 'published', - 'title' => $dt), - common_date_string($this->notice->created)); - $this->out->elementEnd('a'); - $this->out->elementEnd('dd'); - $this->out->elementEnd('dl'); - } - } - class FacebookProfileBoxNotice extends FacebookNoticeListItem -{ - +{ + /** * constructor * @@ -703,36 +671,24 @@ class FacebookProfileBoxNotice extends FacebookNoticeListItem { parent::__construct($notice, $out); } - + /** - * Recipe function for displaying a single notice in the - * Facebook App's Profile + * Recipe function for displaying a single notice in the + * Facebook App profile notice box * * @return void */ function show() { - - $this->out->elementStart('div', 'entry-title'); - $this->showAuthor(); - $this->showContent(); - $this->out->elementEnd('div'); - - $this->out->elementStart('div', 'entry-content'); - - $this->showNoticeLink(); - $this->showNoticeSource(); - $this->showReplyTo(); - $this->out->elementEnd('div'); - + $this->showNotice(); + $this->showNoticeInfo(); $this->showAppLink(); - } - function showAppLink() + function showAppLink() { - + $this->facebook = getFacebook(); $app_props = $this->facebook->api_client->Admin_getAppProperties( @@ -740,7 +696,7 @@ class FacebookProfileBoxNotice extends FacebookNoticeListItem $this->app_uri = 'http://apps.facebook.com/' . $app_props['canvas_name']; $this->app_name = $app_props['application_name']; - + $this->out->elementStart('a', array('id' => 'facebook_laconica_app', 'href' => $this->app_uri)); $this->out->text($this->app_name); diff --git a/lib/snapshot.php b/lib/snapshot.php new file mode 100644 index 0000000000..4b05b502db --- /dev/null +++ b/lib/snapshot.php @@ -0,0 +1,227 @@ +. + * + * @category Stats + * @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); +} + +/** + * A snapshot of site stats that can report itself to headquarters + * + * This class will collect statistics on the site and report them to + * a statistics server of the admin's choice. (Default is the big one + * at laconi.ca.) + * + * It can either be called from a cron job, or run occasionally by the + * Web site. + * + * @category Stats + * @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 Snapshot +{ + var $stats = null; + + /** + * Constructor for a snapshot + */ + + function __construct() + { + } + + /** + * Static function for reporting statistics + * + * This function checks whether it should report statistics, based on + * the current configuation settings. If it should, it creates a new + * Snapshot object, takes a snapshot, and reports it to headquarters. + * + * @return void + */ + + static function check() + { + switch (common_config('snapshot', 'run')) { + case 'web': + // skip if we're not running on the Web. + if (!isset($_SERVER) || !array_key_exists('REQUEST_METHOD', $_SERVER)) { + break; + } + // Run once every frequency hits + // XXX: do frequency by time (once a week, etc.) rather than + // hits + if (rand() % common_config('snapshot', 'frequency') == 0) { + $snapshot = new Snapshot(); + $snapshot->take(); + $snapshot->report(); + } + break; + case 'cron': + // skip if we're running on the Web + if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) { + break; + } + common_log(LOG_INFO, 'Running snapshot from cron job'); + // We're running from the command line; assume + + $snapshot = new Snapshot(); + $snapshot->take(); + common_log(LOG_INFO, count($snapshot->stats) . " statistics being uploaded."); + $snapshot->report(); + + break; + case 'never': + break; + default: + common_log(LOG_WARNING, "Unrecognized value for snapshot run config."); + } + } + + /** + * Take a snapshot of the server + * + * Builds an array of statistical and configuration data based + * on the local database and config files. We avoid grabbing any + * information that could be personal or private. + * + * @return void + */ + + function take() + { + $this->stats = array(); + + // Some basic identification stuff + + $this->stats['version'] = LACONICA_VERSION; + $this->stats['phpversion'] = phpversion(); + $this->stats['name'] = common_config('site', 'name'); + $this->stats['root'] = common_root_url(); + + // non-identifying stats on various tables. Primary + // interest is size and rate of activity of service. + + $tables = array('user', + 'notice', + 'subscription', + 'remote_profile', + 'user_group'); + + foreach ($tables as $table) { + $this->tableStats($table); + } + + // stats on some important config options + + $this->stats['theme'] = common_config('site', 'theme'); + $this->stats['dbtype'] = common_config('db', 'type'); + $this->stats['xmpp'] = common_config('xmpp', 'enabled'); + $this->stats['inboxes'] = common_config('inboxes', 'enabled'); + $this->stats['queue'] = common_config('queue', 'enabled'); + $this->stats['license'] = common_config('license', 'url'); + $this->stats['fancy'] = common_config('site', 'fancy'); + $this->stats['private'] = common_config('site', 'private'); + $this->stats['closed'] = common_config('site', 'closed'); + $this->stats['memcached'] = common_config('memcached', 'enabled'); + $this->stats['language'] = common_config('site', 'language'); + $this->stats['timezone'] = common_config('site', 'timezone'); + + } + + /** + * Reports statistics to headquarters + * + * Posts statistics to a reporting server. + * + * @return void + */ + + function report() + { + // XXX: Use OICU2 and OAuth to make authorized requests + + $postdata = http_build_query($this->stats); + + $opts = + array('http' => + array( + 'method' => 'POST', + 'header' => 'Content-type: '. + 'application/x-www-form-urlencoded', + 'content' => $postdata, + 'user_agent' => 'Laconica/'.LACONICA_VERSION + ) + ); + + $context = stream_context_create($opts); + + $reporturl = common_config('snapshot', 'reporturl'); + + $result = @file_get_contents($reporturl, false, $context); + + return $result; + } + + /** + * Updates statistics for a single table + * + * Determines the size of a table and its oldest and newest rows. + * Goal here is to see how active a site is. Note that it + * fills up the instance stats variable. + * + * @param string $table name of table to check + * + * @return void + */ + + function tableStats($table) + { + $inst = DB_DataObject::factory($table); + + $inst->selectAdd(); + $inst->selectAdd('count(*) as cnt, '. + 'min(created) as first, '. + 'max(created) as last'); + + if ($inst->find(true)) { + $this->stats[$table.'count'] = $inst->cnt; + $this->stats[$table.'first'] = $inst->first; + $this->stats[$table.'last'] = $inst->last; + } + + $inst->free(); + unset($inst); + } +} diff --git a/scripts/reportsnapshot.php b/scripts/reportsnapshot.php new file mode 100644 index 0000000000..e332d856c0 --- /dev/null +++ b/scripts/reportsnapshot.php @@ -0,0 +1,37 @@ +#!/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(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'); + +Snapshot::check(); diff --git a/theme/base/css/facebookapp.css b/theme/base/css/facebookapp.css index 163b41fb4c..e6b1c9ee53 100644 --- a/theme/base/css/facebookapp.css +++ b/theme/base/css/facebookapp.css @@ -1,6 +1,3 @@ -@import url("display.css"); -@import url("../../identica/css/display.css"); - * { font-size:14px; font-family:"Lucida Sans Unicode", "Lucida Grande", sans-serif;