Merge branch 'testing' into 0.9.x

Conflicts:
	db/08to09.sql
This commit is contained in:
Brion Vibber 2010-03-04 10:16:59 -08:00
commit f969d6349c
14 changed files with 305 additions and 683 deletions

262
README
View File

@ -2,8 +2,8 @@
README README
------ ------
StatusNet 0.9.0 ("Stand") Beta 5 StatusNet 0.9.0 ("Stand")
1 Feb 2010 4 Mar 2010
This is the README file for StatusNet (formerly Laconica), the Open This is the README file for StatusNet (formerly Laconica), the Open
Source microblogging platform. It includes installation instructions, Source microblogging platform. It includes installation instructions,
@ -14,21 +14,21 @@ for administrators. Information on using StatusNet can be found in the
About About
===== =====
StatusNet (formerly Laconica) is a Free and Open Source microblogging StatusNet is a Free and Open Source microblogging platform. It helps
platform. It helps people in a community, company or group to exchange people in a community, company or group to exchange short (140
short (140 characters, by default) messages over the Web. Users can characters, by default) messages over the Web. Users can choose which
choose which people to "follow" and receive only their friends' or people to "follow" and receive only their friends' or colleagues'
colleagues' status messages. It provides a similar service to sites status messages. It provides a similar service to sites like Twitter,
like Twitter, Jaiku, Yammer, and Plurk. Google Buzz, or Yammer.
With a little work, status messages can be sent to mobile phones, With a little work, status messages can be sent to mobile phones,
instant messenger programs (GTalk/Jabber), and specially-designed instant messenger programs (GTalk/Jabber), and specially-designed
desktop clients that support the Twitter API. desktop clients that support the Twitter API.
StatusNet supports an open standard called OpenMicroBlogging StatusNet supports an open standard called OStatus
<http://openmicroblogging.org/> that lets users on different Web sites <http://ostatus.org/> that lets users in different networks follow
or in different companies subscribe to each others' notices. It each other. It enables a distributed social network spread all across
enables a distributed social network spread all across the Web. the Web.
StatusNet was originally developed for the Open Software Service, StatusNet was originally developed for the Open Software Service,
Identi.ca <http://identi.ca/>. It is shared with you in hope that you Identi.ca <http://identi.ca/>. It is shared with you in hope that you
@ -77,203 +77,51 @@ for additional terms.
New this version New this version
================ ================
This is a major feature release since version 0.8.2, released Nov 1 2009. This is a major feature release since version 0.8.3, released Feb 1
It is also a security release since 0.9.0beta4 January 27 2010. Beta 2010. It is the final release version of 0.9.0.
users are strongly encouraged to upgrade to deal with a security alert.
http://status.net/wiki/Security_alert_0000002
Notable changes this version: Notable changes this version:
- Records of deleted notices are stored without the notice content. - Support for the new distributed status update standard OStatus
- Much of the optional core featureset has been moved to plugins. <http://ostatus.org>, based on PubSubHubbub, Salmon, Webfinger,
- OpenID support moved from core to a plugin. Helps test the strength of and Activity Streams.
our plugin architecture and makes it easy to disable this - Support for location. Notices are (optionally) marked with lat-long
functionality for e.g. intranet sites. information, and can be shown on a map.
- Many additional hook events (see EVENTS.txt for details). - No fixed content size. Notice size is configurable, from 1 to
- OMB 0.1 support re-implemented using libomb. unlimited number of characters. Default is still 140!
- Re-structure database so notices, messages, bios and group - An authorization framework, allowing different levels of users.
descriptions can be over 140 characters. Limit defined by - A Web-based administration panel.
site administrator as configuration option; can be unlimited. - A moderation system that lets site moderators sandbox, silence,
- Configuration data now optionally stored in the database, which or delete uncooperative users.
overrides any settings in config files. - A flag system that lets users flag profiles for moderator review.
- Twitter integration re-implemented as a plugin. - Support for OAuth <http://oauth.net> authentication in the Twitter
- Facebook integration re-implemented as a plugin. API.
- Role-based authorization framework. Users can have named roles, and - A pluggable authentication system.
roles can have rights (e.g., to delete notices, change configuration - An authentication plugin for LDAP servers.
data, or ban uncooperative users). Default roles 'admin' (for - Many features that were core in 0.8.x are now plugins, such
configuration) and 'moderator' (for community management) added. as OpenID, Twitter integration, Facebook integration
- Plugin for PubSubHubBub (PuSH) support. - A much-improved offline processing system
- Considerable code style cleanup to meet PEAR code standards. - In-browser "realtime" updates using a number of realtime
- Made a common library for HTTP-client access which uses available servers (Meteor, Orbited, Cometd)
HTTP libraries where possible. - A plugin to provide an interface optimized for mobile browsers
- Added statuses/home_timeline method to API. - Support for Facebook Connect
- Hooks for plugins to handle notices offline, either by defining - Support for logging in with a Twitter account
their own queue handler scripts or to use a default plugin queue - Vastly improved translation with additional languages and
handler script. translation in plugins
- Plugins can now modify the database schema, adding their own tables - Support for all-SSL instances
or modifying existing ones. - Core support for "repeats" (like Twitter's "retweets")
- Groups API. - Pluggable caching system, with plugins for Memcached,
- Twitter API supports Web caching for some methods. APC, XCache, and a disk-based cache
- Twitter API refactored into one-action-per-method. - Plugin to support RSSCloud
- Realtime plugin supports a tear-off window. - A framework for adding advertisements to a public site,
- FOAF for groups. and plugins for Google AdSense and OpenX server
- Moved all JavaScript tags to just before </body> by default,
significantly speeding up apparent page load time. There are also literally thousands of bugs fixed and minor features
- Added a Realtime plugin for Orbited server. added. A full changelog is available at http://status.net/wiki/StatusNet_0.9.0.
- Added a mobile plugin to give a more mobile-phone-friendly layout
when a mobile browser is detected. Under the covers, the software has a vastly improved plugin and
- Use CSS sprites for most common icons. extension mechanism that makes writing powerful and flexible additions
- Fixes for images and buttons on Web output. to the core functionality much easier.
- New plugin requires that users validate their email before posting.
- New plugin UserFlag lets users flag other profiles for review.
- Considerably better i18n support. Use TranslateWiki to update
translations.
- Notices and profiles now store location information.
- New plugin, Geonames, for turning location names and lat/long pairs
into structured IDs and vice versa. Architecture reusable for other
systems.
- Better check of license compatibility between site licenses.
- Some improvements in XMPP output.
- Media upload in the API.
- Replies appear in the user's inbox.
- Improved the UI on the bookmarklet.
- StatusNet identities can be used as OpenID identities.
- Script to register a user.
- Script to make someone a group admin.
- Script to make someone a site admin or moderator.
- 'login' command.
- Pluggable authentication.
- LDAP authentication plugin.
- Script for console interaction with the site (!).
- Users don't see group posts from people they've blocked.
- Admin panel interface for changing site configuration.
- Users can be sandboxed (limited contributions) or silenced
(no contributions) by moderators.
- Many changes to make language usage more consistent.
- Sphinx search moved to a plugin.
- GeoURL plugin.
- Profile and group lists support hAtom.
- Massive refactoring of util.js.
- Mapstraction plugin to show maps on inbox and profile pages.
- Play/pause buttons for realtime notices.
- Support for geo microformat.
- Partial support for feed subscriptions, RSSCloud, PubSubHubBub.
- Support for geolocation in browser (Chrome, Firefox).
- Quit trying to negotiate HTML format. Always use text/html.
We lose, and so do Web standards. Boo.
- Better logging of request info.
- Better output for errors in Web interface.
- No longer store .mo files; these need to be generated.
- Minify plugin.
- Events to allow pluginizing logger.
- New framework for plugin localization.
- Gravatar plugin.
- Add support for "repeats" (similar to Twitter's "retweets").
- Support for repeats in Twitter API.
- Better notification of direct messages.
- New plugin to add "powered by StatusNet" to logo.
- Returnto works for private sites.
- Localisation updates, including new Persian translation.
- CAS authentication plugin
- Get rid of DB_DataObject native cache (big memory leaker)
- setconfig.php script to set configuration variables
- Blacklist plugin, to blacklist URLs and nicknames
- Users can set flag whether they want to share location
both in notice form (for one notice) and profile settings
(any notice)
- notice inboxes moved from normalized notice_inbox table to
denormalized inbox table
- Automatic compression of Memcache
- Memory caching pluginized
- Memcache, XCache, APC and Diskcache plugins
- A script to update user locations
- cache empty query results
- A sample plugin to show best plugin practices
- CacheLog plugin to debug cache accesses
- Require users to login to view attachments on private sites
- Plugin to use Mollom spam detection service
- Plugin for RSSCloud
- Add an array of default plugins
- A version action to give credit to contributors and plugin
developers
- Daemon to read IMAP mailbox instead of using a mailbox script
- Pass session information between SSL and non-SSL server
when SSL set to 'sometimes'
- Major refactoring of queue handlers to manage very
large hosting site (like status.net)
- SubscriptionThrottle plugin to prevent subscription spamming
- Don't enqueue into plugin or SMS queues when disabled (breaks unqueuehandler if SMS queue isn't attached)
- Improve name validation checks on local File references
- fix local file include vulnerability in doc.php
- Reusing fixed selector name for 'processing' in util.js
- Removed hAtom pattern from registration page.
- restructuring of User::registerNew() lost password munging
- Add a script to clear the cache for a given key
- buggy fetch for site owner
- Added missing concat of </li> in Realtime response
- Updated XHR binded events to work better in jQuery 1.4.1. Using .live() for event delegation instead of jQuery.data() and checking to see if an element was previously binded.
- Updated jQuery Form Plugin from v2.17 to v2.36
- Updated jQuery JavaScript Library from v1.3.2 to v1.4.1
- move schema.type.php to typeschema.php like other files
- Add Really Simple Discovery (RSD) support
- Add a robots.txt URL to the site root
- error clearing tags for profiles from memcached
- on exceptions, stomp logs the error and reenqueues
- add lat, lon, location and remove closing tag from geocode.php
- Use passed-in lat long in geocode.php
- better handling of null responses from geonames.org
- Globalized form notice data geo values
- Using jQuery chaining in FormNoticeXHR
- Using form object instead of form_id and find(). Slightly faster and easier to read.
- removed describeTable from base class, and fixed it up in pgsql
- getTableDef() mostly working in postgres
- move the schema DDL sql off into seperate files for each db we support
- plugin to limit number of registered users
- add hooks for user registration
- live fast, die young in bash scripts
- for single-user mode, retrieve either site owner or defined nickname
- method to get the site owner
- define a constant for the 'owner' role of a site
- add simple cache getter/setter static functions to Memcached_DataObject
- Adds notice author's name to @title in Realtime response
- Hides .author from XHR response in showstream
- Hides .author from XHR response in showstream
- Fix more fatal errors in queue edge cases
- Don't attempt to resend XMPP messages that can't be broadcast due to the profile being deleted.
- Wrap each bit of distrib queue handler's saving operation in a try/catch; log exceptions but let everything else continue.
- Log exceptions from queuedaemon.php if they're not already caught
- Move sessions settings to its own panel
- Fixes for status_network db object .ini and tag setter script
- Add a script to set tags for sites
- Adjust API authentication to also check for OAuth protocol params in the HTTP Authorization header, as defined in OAuth HTTP Authorization Scheme.
- Last-chance distribution if enqueueing fails
- Manual failover for stomp queues.
- lost config in index.php made all traffic go to master
- "Revert "move RW setup above user get in index.php so remember_me works""
- Revert "move RW setup above user get in index.php so remember_me works"
- move RW setup above user get in index.php so remember_me works
- hide most DB_DataObject errors
- always set up database_rw, regardless, so cached sessions work
- update mysqltimestamps on insert and update
- additional debugging data for Sessions
- 'Sign in with Twitter' button img
- Update to biz theme
- Remove redundant session token field from form (was already being added by base class).
- 'Sign in with Twitter' button img
- Can now set $config['queue']['stomp_persistent'] = false; to explicitly disable persistence when we queue items
- Showing processing indicator for form_repeat on submit instead of form
- Removed avatar from repeat of username (matches noticelist)
- Removed unused variable assignment for avatar URL and added missing fn
- Don't preemptively close existing DB connections for web views (needed to keep # of conns from going insane on multi-site queue daemons, so just doing for CLI) May, or may not, help with mystery session problems
- dropping the setcookie() call from common_ensure_session() since we're pretty sure it's unnecessary
- append '/' on cookie path for now (may still need some refactoring)
- set session cookie correctly
- Fix for Mapstraction plugin's zoomed map links
- debug log line for control channel sub
- Move faceboookapp.js to the Facebook plugin
- fix for fix for bad realtime JS load
- default 24-hour expiry on Memcached objects where not specified.
Prerequisites Prerequisites
============= =============
@ -806,7 +654,7 @@ management, but host it on a public server.
Note that this is an experimental feature; total privacy is not Note that this is an experimental feature; total privacy is not
guaranteed or ensured. Also, privacy is all-or-nothing for a site; you guaranteed or ensured. Also, privacy is all-or-nothing for a site; you
can't have some accounts or notices private, and others public. can't have some accounts or notices private, and others public.
Finally, the interaction of private sites with OpenMicroBlogging is Finally, the interaction of private sites with OStatus is
undefined. Remote users won't be able to subscribe to users on a undefined. Remote users won't be able to subscribe to users on a
private site, but users of the private site may be able to subscribe private site, but users of the private site may be able to subscribe
to users on a remote site. (Or not... it's not well tested.) The to users on a remote site. (Or not... it's not well tested.) The

View File

@ -99,7 +99,7 @@ class SitenoticeadminpanelAction extends AdminPanelAction
$result = Config::save('site', 'notice', $siteNotice); $result = Config::save('site', 'notice', $siteNotice);
if (!result) { if (!$result) {
$this->ServerError(_("Unable to save site notice.")); $this->ServerError(_("Unable to save site notice."));
} }
} }

View File

@ -111,7 +111,11 @@ alter table queue_item rename to queue_item_old;
alter table queue_item_new rename to queue_item; alter table queue_item_new rename to queue_item;
alter table consumer alter table consumer
add column consumer_secret varchar(255) not null comment 'secret value'; add consumer_secret varchar(255) not null comment 'secret value';
alter table token
add verifier varchar(255) comment 'verifier string for OAuth 1.0a',
add verified_callback varchar(255) comment 'verified callback URL for OAuth 1.0a';
create table oauth_application ( create table oauth_application (
id integer auto_increment primary key comment 'unique identifier', id integer auto_increment primary key comment 'unique identifier',
@ -140,8 +144,47 @@ create table oauth_application_user (
constraint primary key (profile_id, application_id) constraint primary key (profile_id, application_id)
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin; ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
create table inbox (
user_id integer not null comment 'user receiving the notice' references user (id),
notice_ids blob comment 'packed list of notice ids',
constraint primary key (user_id)
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
create table conversation (
id integer auto_increment primary key comment 'unique identifier',
uri varchar(225) unique comment 'URI of the conversation',
created datetime not null comment 'date this record was created',
modified timestamp comment 'date this record was modified'
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
-- stub entry to push the autoincrement past existing notice ids
insert into conversation (id,created)
select max(id)+1, now() from notice;
alter table user_group
add uri varchar(255) unique key comment 'universal identifier',
add mainpage varchar(255) comment 'page for group info to link to',
drop index nickname;
create table local_group (
group_id integer primary key comment 'group represented' references user_group (id),
nickname varchar(64) unique key comment 'group represented',
created datetime not null comment 'date this record was created',
modified timestamp comment 'date this record was modified'
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
insert into local_group (group_id, nickname, created)
select id, nickname, created from user_group;
alter table file_to_post alter table file_to_post
add index post_id_idx (post_id); add index post_id_idx (post_id);
alter table group_inbox alter table group_inbox
add index group_inbox_notice_id_idx (notice_id); add index group_inbox_notice_id_idx (notice_id);

View File

@ -435,82 +435,119 @@ E_O_T;
E_O_T; E_O_T;
} }
/**
* Helper class for building form
*/
class Posted {
function value($name)
{
if (isset($_POST[$name])) {
return htmlspecialchars(strval($_POST[$name]));
} else {
return '';
}
}
}
function showForm() function showForm()
{ {
global $dbModules; global $dbModules;
$post = new Posted();
$dbRadios = ''; $dbRadios = '';
$checked = 'checked="checked" '; // Check the first one which exists if (isset($_POST['dbtype'])) {
$dbtype = $_POST['dbtype'];
} else {
$dbtype = null;
}
foreach ($dbModules as $type => $info) { foreach ($dbModules as $type => $info) {
if (checkExtension($info['check_module'])) { if (checkExtension($info['check_module'])) {
if ($dbtype == null || $dbtype == $type) {
$checked = 'checked="checked" ';
$dbtype = $type; // if we didn't have one checked, hit the first
} else {
$checked = '';
}
$dbRadios .= "<input type=\"radio\" name=\"dbtype\" id=\"dbtype-$type\" value=\"$type\" $checked/> $info[name]<br />\n"; $dbRadios .= "<input type=\"radio\" name=\"dbtype\" id=\"dbtype-$type\" value=\"$type\" $checked/> $info[name]<br />\n";
$checked = '';
} }
} }
echo<<<E_O_T echo<<<E_O_T
</ul> </ul>
</dd> </dd>
</dl> </dl>
<dl id="page_notice" class="system_notice">
<dt>Page notice</dt>
<dd>
<div class="instructions">
<p>Enter your database connection information below to initialize the database.</p>
</div>
</dd>
</dl>
<form method="post" action="install.php" class="form_settings" id="form_install"> <form method="post" action="install.php" class="form_settings" id="form_install">
<fieldset> <fieldset>
<legend>Connection settings</legend> <fieldset id="settings_site">
<ul class="form_data"> <legend>Site settings</legend>
<li> <ul class="form_data">
<label for="sitename">Site name</label> <li>
<input type="text" id="sitename" name="sitename" /> <label for="sitename">Site name</label>
<p class="form_guide">The name of your site</p> <input type="text" id="sitename" name="sitename" value="{$post->value('sitename')}" />
</li> <p class="form_guide">The name of your site</p>
<li> </li>
<label for="fancy-enable">Fancy URLs</label> <li>
<input type="radio" name="fancy" id="fancy-enable" value="enable" checked='checked' /> enable<br /> <label for="fancy-enable">Fancy URLs</label>
<input type="radio" name="fancy" id="fancy-disable" value="" /> disable<br /> <input type="radio" name="fancy" id="fancy-enable" value="enable" checked='checked' /> enable<br />
<p class="form_guide" id='fancy-form_guide'>Enable fancy (pretty) URLs. Auto-detection failed, it depends on Javascript.</p> <input type="radio" name="fancy" id="fancy-disable" value="" /> disable<br />
</li> <p class="form_guide" id='fancy-form_guide'>Enable fancy (pretty) URLs. Auto-detection failed, it depends on Javascript.</p>
<li> </li>
<label for="host">Hostname</label> </ul>
<input type="text" id="host" name="host" /> </fieldset>
<p class="form_guide">Database hostname</p>
</li>
<li>
<label for="dbtype">Type</label> <fieldset id="settings_db">
$dbRadios <legend>Database settings</legend>
<p class="form_guide">Database type</p> <ul class="form_data">
</li> <li>
<label for="host">Hostname</label>
<input type="text" id="host" name="host" value="{$post->value('host')}" />
<p class="form_guide">Database hostname</p>
</li>
<li>
<label for="dbtype">Type</label>
$dbRadios
<p class="form_guide">Database type</p>
</li>
<li>
<label for="database">Name</label>
<input type="text" id="database" name="database" value="{$post->value('database')}" />
<p class="form_guide">Database name</p>
</li>
<li>
<label for="dbusername">DB username</label>
<input type="text" id="dbusername" name="dbusername" value="{$post->value('dbusername')}" />
<p class="form_guide">Database username</p>
</li>
<li>
<label for="dbpassword">DB password</label>
<input type="password" id="dbpassword" name="dbpassword" value="{$post->value('dbpassword')}" />
<p class="form_guide">Database password (optional)</p>
</li>
</ul>
</fieldset>
<li> <fieldset id="settings_admin">
<label for="database">Name</label> <legend>Administrator settings</legend>
<input type="text" id="database" name="database" /> <ul class="form_data">
<p class="form_guide">Database name</p> <li>
</li> <label for="admin_nickname">Administrator nickname</label>
<li> <input type="text" id="admin_nickname" name="admin_nickname" value="{$post->value('admin_nickname')}" />
<label for="username">DB username</label> <p class="form_guide">Nickname for the initial StatusNet user (administrator)</p>
<input type="text" id="username" name="username" /> </li>
<p class="form_guide">Database username</p> <li>
</li> <label for="admin_password">Administrator password</label>
<li> <input type="password" id="admin_password" name="admin_password" value="{$post->value('admin_password')}" />
<label for="password">DB password</label> <p class="form_guide">Password for the initial StatusNet user (administrator)</p>
<input type="password" id="password" name="password" /> </li>
<p class="form_guide">Database password (optional)</p> <li>
</li> <label for="admin_password2">Confirm password</label>
<li> <input type="password" id="admin_password2" name="admin_password2" value="{$post->value('admin_password2')}" />
<label for="admin_nickname">Administrator nickname</label> </li>
<input type="text" id="admin_nickname" name="admin_nickname" /> <li>
<p class="form_guide">Nickname for the initial StatusNet user (administrator)</p> <label for="admin_email">Administrator e-mail</label>
</li> <input id="admin_email" name="admin_email" value="{$post->value('admin_email')}" />
<li> <p class="form_guide">Optional email address for the initial StatusNet user (administrator)</p>
<label for="initial_user_password">Administrator password</label> </li>
<input type="password" id="admin_password" name="admin_password" /> </ul>
<p class="form_guide">Password for the initial StatusNet user (administrator)</p> </fieldset>
</li>
</ul>
<input type="submit" name="submit" class="submit" value="Submit" /> <input type="submit" name="submit" class="submit" value="Submit" />
</fieldset> </fieldset>
</form> </form>
@ -528,13 +565,15 @@ function handlePost()
$host = $_POST['host']; $host = $_POST['host'];
$dbtype = $_POST['dbtype']; $dbtype = $_POST['dbtype'];
$database = $_POST['database']; $database = $_POST['database'];
$username = $_POST['username']; $username = $_POST['dbusername'];
$password = $_POST['password']; $password = $_POST['dbpassword'];
$sitename = $_POST['sitename']; $sitename = $_POST['sitename'];
$fancy = !empty($_POST['fancy']); $fancy = !empty($_POST['fancy']);
$adminNick = $_POST['admin_nickname']; $adminNick = $_POST['admin_nickname'];
$adminPass = $_POST['admin_password']; $adminPass = $_POST['admin_password'];
$adminPass2 = $_POST['admin_password2'];
$adminEmail = $_POST['admin_email'];
$server = $_SERVER['HTTP_HOST']; $server = $_SERVER['HTTP_HOST'];
$path = substr(dirname($_SERVER['PHP_SELF']), 1); $path = substr(dirname($_SERVER['PHP_SELF']), 1);
@ -576,6 +615,11 @@ STR;
updateStatus("No initial StatusNet user password specified.", true); updateStatus("No initial StatusNet user password specified.", true);
$fail = true; $fail = true;
} }
if ($adminPass != $adminPass2) {
updateStatus("Administrator passwords do not match. Did you mistype?", true);
$fail = true;
}
if ($fail) { if ($fail) {
showForm(); showForm();
@ -600,7 +644,7 @@ STR;
} }
// Okay, cross fingers and try to register an initial user // Okay, cross fingers and try to register an initial user
if (registerInitialUser($adminNick, $adminPass)) { if (registerInitialUser($adminNick, $adminPass, $adminEmail)) {
updateStatus( updateStatus(
"An initial user with the administrator role has been created." "An initial user with the administrator role has been created."
); );
@ -620,7 +664,7 @@ STR;
updateStatus("StatusNet has been installed at $link"); updateStatus("StatusNet has been installed at $link");
updateStatus( updateStatus(
"You can visit your <a href='$link'>new StatusNet site</a> (login as '$adminNick')." "<strong>DONE!</strong> You can visit your <a href='$link'>new StatusNet site</a> (login as '$adminNick'). If this is your first StatusNet install, you may want to poke around our <a href='http://status.net/wiki/Getting_started'>Getting Started guide</a>."
); );
} }
@ -797,19 +841,20 @@ function runDbScript($filename, $conn, $type = 'mysqli')
return true; return true;
} }
function registerInitialUser($nickname, $password) function registerInitialUser($nickname, $password, $email)
{ {
define('STATUSNET', true); define('STATUSNET', true);
define('LACONICA', true); // compatibility define('LACONICA', true); // compatibility
require_once INSTALLDIR . '/lib/common.php'; require_once INSTALLDIR . '/lib/common.php';
$user = User::register( $data = array('nickname' => $nickname,
array('nickname' => $nickname, 'password' => $password,
'password' => $password, 'fullname' => $nickname);
'fullname' => $nickname if ($email) {
) $data['email'] = $email;
); }
$user = User::register($data);
if (empty($user)) { if (empty($user)) {
return false; return false;

View File

@ -344,16 +344,18 @@ class ActivityUtils
static function getLink(DOMNode $element, $rel, $type=null) static function getLink(DOMNode $element, $rel, $type=null)
{ {
$links = $element->getElementsByTagnameNS(self::ATOM, self::LINK); $els = $element->childNodes;
foreach ($links as $link) { foreach ($els as $link) {
if ($link->localName == self::LINK && $link->namespaceURI == self::ATOM) {
$linkRel = $link->getAttribute(self::REL); $linkRel = $link->getAttribute(self::REL);
$linkType = $link->getAttribute(self::TYPE); $linkType = $link->getAttribute(self::TYPE);
if ($linkRel == $rel && if ($linkRel == $rel &&
(is_null($type) || $linkType == $type)) { (is_null($type) || $linkType == $type)) {
return $link->getAttribute(self::HREF); return $link->getAttribute(self::HREF);
}
} }
} }
@ -362,17 +364,19 @@ class ActivityUtils
static function getLinks(DOMNode $element, $rel, $type=null) static function getLinks(DOMNode $element, $rel, $type=null)
{ {
$links = $element->getElementsByTagnameNS(self::ATOM, self::LINK); $els = $element->childNodes;
$out = array(); $out = array();
foreach ($links as $link) { foreach ($els as $link) {
if ($link->localName == self::LINK && $link->namespaceURI == self::ATOM) {
$linkRel = $link->getAttribute(self::REL); $linkRel = $link->getAttribute(self::REL);
$linkType = $link->getAttribute(self::TYPE); $linkType = $link->getAttribute(self::TYPE);
if ($linkRel == $rel && if ($linkRel == $rel &&
(is_null($type) || $linkType == $type)) { (is_null($type) || $linkType == $type)) {
$out[] = $link; $out[] = $link;
}
} }
} }

View File

@ -193,16 +193,6 @@ class AdminPanelAction extends Action
$this->elementEnd('div'); $this->elementEnd('div');
} }
/**
* There is no data for aside, so, we don't output
*
* @return nothing
*/
function showAside()
{
}
/** /**
* show human-readable instructions for the page, or * show human-readable instructions for the page, or
* a success/failure on save. * a success/failure on save.

View File

@ -86,7 +86,7 @@ class ApiAction extends Action
$this->since_id = (int)$this->arg('since_id', 0); $this->since_id = (int)$this->arg('since_id', 0);
if ($this->arg('since')) { if ($this->arg('since')) {
$this->clientError(_("since parameter is disabled for performance; use since_id"), 403); header('X-StatusNet-Warning: since parameter is disabled; use since_id');
} }
return true; return true;

View File

@ -280,6 +280,7 @@ $default =
'TightUrl' => array('shortenerName' => '2tu.us', 'freeService' => true,'serviceUrl'=>'http://2tu.us/?save=y&url=%1$s'), 'TightUrl' => array('shortenerName' => '2tu.us', 'freeService' => true,'serviceUrl'=>'http://2tu.us/?save=y&url=%1$s'),
'Geonames' => null, 'Geonames' => null,
'Mapstraction' => null, 'Mapstraction' => null,
'OStatus' => null,
'WikiHashtags' => null, 'WikiHashtags' => null,
'RSSCloud' => null, 'RSSCloud' => null,
'OpenID' => null), 'OpenID' => null),

View File

@ -836,4 +836,17 @@ class OStatusPlugin extends Plugin
return true; return true;
} }
function onPluginVersion(&$versions)
{
$versions[] = array('name' => 'OStatus',
'version' => STATUSNET_VERSION,
'author' => 'Evan Prodromou, James Walker, Brion Vibber, Zach Copley',
'homepage' => 'http://status.net/wiki/Plugin:OStatus',
'rawdescription' =>
_m('Follow people across social networks that implement '.
'<a href="http://ostatus.org/">OStatus</a>.'));
return true;
}
} }

View File

@ -186,7 +186,7 @@ class OStatusInitAction extends Action
$this->clientError("No such user."); $this->clientError("No such user.");
} }
} else if ($this->group) { } else if ($this->group) {
$group = Local_group::staticGet('id', $this->group); $group = Local_group::staticGet('nickname', $this->group);
if ($group) { if ($group) {
return common_local_url('groupbyid', array('id' => $group->group_id)); return common_local_url('groupbyid', array('id' => $group->group_id));
} else { } else {

View File

@ -1,285 +0,0 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* Plugin to push RSS/Atom updates to a PubSubHubBub hub
*
* PHP version 5
*
* LICENCE: This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Plugin
* @package StatusNet
* @author Craig Andrews <candrews@integralblue.com>
* @copyright 2009 Craig Andrews http://candrews.integralblue.com
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
if (!defined('STATUSNET')) {
exit(1);
}
define('DEFAULT_HUB', 'http://pubsubhubbub.appspot.com');
require_once INSTALLDIR.'/plugins/PubSubHubBub/publisher.php';
/**
* Plugin to provide publisher side of PubSubHubBub (PuSH)
* relationship.
*
* PuSH is a real-time or near-real-time protocol for Atom
* and RSS feeds. More information here:
*
* http://code.google.com/p/pubsubhubbub/
*
* To enable, add the following line to your config.php:
*
* addPlugin('PubSubHubBub');
*
* This will use the Google default hub. If you'd like to use
* another, try:
*
* addPlugin('PubSubHubBub',
* array('hub' => 'http://yourhub.example.net/'));
*
* @category Plugin
* @package StatusNet
* @author Craig Andrews <candrews@integralblue.com>
* @copyright 2009 Craig Andrews http://candrews.integralblue.com
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
* @link http://status.net/
*/
class PubSubHubBubPlugin extends Plugin
{
/**
* URL of the hub to advertise and publish to.
*/
public $hub = DEFAULT_HUB;
/**
* Default constructor.
*/
function __construct()
{
parent::__construct();
}
/**
* Check if plugin should be active; may be mass-enabled.
* @return boolean
*/
function enabled()
{
if (common_config('site', 'private')) {
// PuSH relies on public feeds
return false;
}
// @fixme check for being on a private network?
return true;
}
/**
* Hooks the StartApiAtom event
*
* Adds the necessary bits to advertise PubSubHubBub
* for the Atom feed.
*
* @param Action $action The API action being shown.
*
* @return boolean hook value
*/
function onStartApiAtom($action)
{
if ($this->enabled()) {
$action->element('link', array('rel' => 'hub', 'href' => $this->hub), null);
}
return true;
}
/**
* Hooks the StartApiRss event
*
* Adds the necessary bits to advertise PubSubHubBub
* for the RSS 2.0 feeds.
*
* @param Action $action The API action being shown.
*
* @return boolean hook value
*/
function onStartApiRss($action)
{
if ($this->enabled()) {
$action->element('atom:link', array('rel' => 'hub',
'href' => $this->hub),
null);
}
return true;
}
/**
* Hook for a queued notice.
*
* When a notice has been queued, will ping the
* PuSH hub for each Atom and RSS feed in which
* the notice appears.
*
* @param Notice $notice The notice that's been queued
*
* @return boolean hook value
*/
function onHandleQueuedNotice($notice)
{
if (!$this->enabled()) {
return false;
}
$publisher = new Publisher($this->hub);
$feeds = array();
//public timeline feeds
$feeds[] = common_local_url('ApiTimelinePublic', array('format' => 'rss'));
$feeds[] = common_local_url('ApiTimelinePublic', array('format' => 'atom'));
//author's own feeds
$user = User::staticGet('id', $notice->profile_id);
$feeds[] = common_local_url('ApiTimelineUser',
array('id' => $user->nickname,
'format' => 'rss'));
$feeds[] = common_local_url('ApiTimelineUser',
array('id' => $user->nickname,
'format' => 'atom'));
//tag feeds
$tag = new Notice_tag();
$tag->notice_id = $notice->id;
if ($tag->find()) {
while ($tag->fetch()) {
$feeds[] = common_local_url('ApiTimelineTag',
array('tag' => $tag->tag,
'format' => 'rss'));
$feeds[] = common_local_url('ApiTimelineTag',
array('tag' => $tag->tag,
'format' => 'atom'));
}
}
//group feeds
$group_inbox = new Group_inbox();
$group_inbox->notice_id = $notice->id;
if ($group_inbox->find()) {
while ($group_inbox->fetch()) {
$group = User_group::staticGet('id', $group_inbox->group_id);
$feeds[] = common_local_url('ApiTimelineGroup',
array('id' => $group->nickname,
'format' => 'rss'));
$feeds[] = common_local_url('ApiTimelineGroup',
array('id' => $group->nickname,
'format' => 'atom'));
}
}
//feed of each user that subscribes to the notice's author
$ni = $notice->whoGets();
foreach (array_keys($ni) as $user_id) {
$user = User::staticGet('id', $user_id);
if (empty($user)) {
continue;
}
$feeds[] = common_local_url('ApiTimelineFriends',
array('id' => $user->nickname,
'format' => 'rss'));
$feeds[] = common_local_url('ApiTimelineFriends',
array('id' => $user->nickname,
'format' => 'atom'));
}
$replies = $notice->getReplies();
//feed of user replied to
foreach ($replies as $recipient) {
$user = User::staticGet('id', $recipient);
if (!empty($user)) {
$feeds[] = common_local_url('ApiTimelineMentions',
array('id' => $user->nickname,
'format' => 'rss'));
$feeds[] = common_local_url('ApiTimelineMentions',
array('id' => $user->nickname,
'format' => 'atom'));
}
}
$feeds = array_unique($feeds);
ob_start();
$ok = $publisher->publish_update($feeds);
$push_last_response = ob_get_clean();
if (!$ok) {
common_log(LOG_WARNING,
'Failure publishing ' . count($feeds) . ' feeds to hub at '.
$this->hub.': '.$push_last_response);
} else {
common_log(LOG_INFO,
'Published ' . count($feeds) . ' feeds to hub at '.
$this->hub.': '.$push_last_response);
}
return true;
}
/**
* Provide version information
*
* Adds this plugin's version data to the global
* version array, for e.g. displaying on the version page.
*
* @param array &$versions array of array of versions
*
* @return boolean hook value
*/
function onPluginVersion(&$versions)
{
$about = _m('The PubSubHubBub plugin pushes RSS/Atom updates '.
'to a <a href = "'.
'http://pubsubhubbub.googlecode.com/'.
'">PubSubHubBub</a> hub.');
if (!$this->enabled()) {
$about = '<span class="disabled" style="color:gray">' . $about . '</span> ' .
_m('(inactive on private site)');
}
$versions[] = array('name' => 'PubSubHubBub',
'version' => STATUSNET_VERSION,
'author' => 'Craig Andrews',
'homepage' =>
'http://status.net/wiki/Plugin:PubSubHubBub',
'rawdescription' =>
$about);
return true;
}
}

View File

@ -1,86 +0,0 @@
<?php
// a PHP client library for pubsubhubbub
// as defined at http://code.google.com/p/pubsubhubbub/
// written by Josh Fraser | joshfraser.com | josh@eventvue.com
// Released under Apache License 2.0
class Publisher {
protected $hub_url;
protected $last_response;
// create a new Publisher
public function __construct($hub_url) {
if (!isset($hub_url))
throw new Exception('Please specify a hub url');
if (!preg_match("|^https?://|i",$hub_url))
throw new Exception('The specified hub url does not appear to be valid: '.$hub_url);
$this->hub_url = $hub_url;
}
// accepts either a single url or an array of urls
public function publish_update($topic_urls, $http_function = false) {
if (!isset($topic_urls))
throw new Exception('Please specify a topic url');
// check that we're working with an array
if (!is_array($topic_urls)) {
$topic_urls = array($topic_urls);
}
// set the mode to publish
$post_string = "hub.mode=publish";
// loop through each topic url
foreach ($topic_urls as $topic_url) {
// lightweight check that we're actually working w/ a valid url
if (!preg_match("|^https?://|i",$topic_url))
throw new Exception('The specified topic url does not appear to be valid: '.$topic_url);
// append the topic url parameters
$post_string .= "&hub.url=".urlencode($topic_url);
}
// make the http post request and return true/false
// easy to over-write to use your own http function
if ($http_function)
return $http_function($this->hub_url,$post_string);
else
return $this->http_post($this->hub_url,$post_string);
}
// returns any error message from the latest request
public function last_response() {
return $this->last_response;
}
// default http function that uses curl to post to the hub endpoint
private function http_post($url, $post_string) {
// add any additional curl options here
$options = array(CURLOPT_URL => $url,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $post_string,
CURLOPT_USERAGENT => "PubSubHubbub-Publisher-PHP/1.0");
$ch = curl_init();
curl_setopt_array($ch, $options);
$response = curl_exec($ch);
$this->last_response = $response;
$info = curl_getinfo($ch);
curl_close($ch);
// all good
if ($info['http_code'] == 204)
return true;
return false;
}
}
?>

View File

@ -54,6 +54,8 @@ for top in $AVATARBASE $FILEBASE $BACKGROUNDBASE; do
chmod a+w $top/$nickname chmod a+w $top/$nickname
done done
php $PHPBASE/scripts/checkschema.php -s"$server"
php $PHPBASE/scripts/registeruser.php \ php $PHPBASE/scripts/registeruser.php \
-s"$server" \ -s"$server" \
-n"$nickname" \ -n"$nickname" \

View File

@ -345,10 +345,14 @@ list-style-type:none;
float:left; float:left;
text-decoration:none; text-decoration:none;
padding:4px 11px; padding:4px 11px;
border-radius-topleft:4px;
border-radius-topright:4px;
-moz-border-radius-topleft:4px; -moz-border-radius-topleft:4px;
-moz-border-radius-topright:4px; -moz-border-radius-topright:4px;
-webkit-border-top-left-radius:4px; -webkit-border-top-left-radius:4px;
-webkit-border-top-right-radius:4px; -webkit-border-top-right-radius:4px;
border-radius-topleft:0;
border-radius-topright:0;
border-width:1px; border-width:1px;
border-style:solid; border-style:solid;
border-bottom:0; border-bottom:0;
@ -359,6 +363,56 @@ float:left;
width:100%; width:100%;
} }
body[id$=adminpanel] #site_nav_local_views {
float:right;
margin-right:18.9%;
margin-right:189px;
position:relative;
width:14.01%;
width:141px;
z-index:9;
}
body[id$=adminpanel] #site_nav_local_views li {
width:100%;
margin-right:0;
margin-bottom:7px;
}
body[id$=adminpanel] #site_nav_local_views a {
display:block;
width:100%;
border-radius-toprleft:0;
-moz-border-radius-topleft:0;
-webkit-border-top-left-radius:0;
border-radius-topright:4px;
-moz-border-radius-topright:4px;
-webkit-border-top-right-radius:4px;
border-radius-bottomright:4px;
-moz-border-radius-bottomright:4px;
-webkit-border-bottom-right-radius:4px;
}
body[id$=adminpanel] #site_nav_local_views li.current {
box-shadow:none;
-moz-box-shadow:none;
-webkit-box-shadow:none;
}
body[id$=adminpanel] #content {
border-radius-topleft:7px;
border-radius-topright:7px;
-moz-border-radius-topleft:7px;
-moz-border-radius-topright:7px;
-webkit-border-top-left-radius:7px;
-webkit-border-top-right-radius:7px;
border-radius-topright:0;
-moz-border-radius-topright:0;
-webkit-border-top-right-radius:0;
}
body[id$=adminpanel] #aside_primary {
display:none;
}
#site_nav_global_primary dt, #site_nav_global_primary dt,
#site_nav_global_secondary dt { #site_nav_global_secondary dt {
display:none; display:none;
@ -452,13 +506,6 @@ width:100%;
float:left; float:left;
} }
#content.admin {
width:95.5%;
}
#content.admin #content_inner {
width:66.3%;
}
#aside_primary { #aside_primary {
width:27.917%; width:27.917%;
min-height:259px; min-height:259px;